• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

gyrokinetics / gs2 / 2021218321

04 Sep 2025 07:44AM UTC coverage: 10.606% (+0.03%) from 10.577%
2021218321

push

gitlab-ci

David Dickinson
Merged in feature/move_more_initialisation_to_init_levels (pull request #1161)

4710 of 44407 relevant lines covered (10.61%)

125698.1 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/src/nonlinear_terms.fpp
1
!> FIXME : Add documentation
2
module nonlinear_terms
3
  !
4
  ! missing factors of B_a/B(theta) in A_perp terms??
5
  !
6

7
  use abstract_config, only: abstract_config_type, CONFIG_MAX_NAME_LEN
8
  use mp, only: mp_request_null
9
  implicit none
10

11
  private
12

13
  public :: init_nonlinear_terms, finish_nonlinear_terms
14
  public :: read_parameters, wnml_nonlinear_terms, check_nonlinear_terms
15
  public :: add_explicit_terms, split_nonlinear, time_add_explicit_terms_field
16
  public :: nonlin, accelerated, nonlinear_terms_testing, cfl_req_hand
17
  public :: cfl, time_add_explicit_terms, time_add_explicit_terms_mpi
18
  public :: calculate_current_nl_source_and_cfl_limit, nb_check_time_step_too_large
19

20
  public :: nonlinear_terms_config_type, set_nonlinear_terms_config
21
  public :: get_nonlinear_terms_config
22
  
23
  !> Public type allowing tests to access otherwise-private routines
24
  type :: nonlinear_terms_testing
25
    contains
26
      procedure, nopass :: add_nl
27
  end type nonlinear_terms_testing
28

29
  integer :: istep_last = 0
30

31
  ! knobs
32
  integer :: nonlinear_mode_switch
33

34
  integer, parameter :: nonlinear_mode_none = 1, nonlinear_mode_on = 2
35

36
#ifndef SHMEM
37
  real, dimension (:,:), allocatable :: ba, gb, bracket
38
  ! yxf_lo%ny, yxf_lo%llim_proc:yxf_lo%ulim_alloc
39

40
  real, dimension (:,:,:), allocatable :: aba, agb, abracket
41
  ! 2*ntgrid+1, 2, accelx_lo%llim_proc:accelx_lo%ulim_alloc
42

43
#else
44
  real, save, dimension (:,:), pointer :: ba => null(), gb => null(), bracket => null()
45
  ! yxf_lo%ny, yxf_lo%llim_proc:yxf_lo%ulim_alloc
46

47
  real, save, dimension (:,:,:), pointer, contiguous :: aba => null(), &
48
       agb => null(), abracket => null()
49
  ! 2*ntgrid+1, 2, accelx_lo%llim_proc:accelx_lo%ulim_alloc
50
#endif
51

52
! CFL coefficients
53
  real :: cfl, cflx, cfly
54
  !> Data on maximum velocity of the nonlinear term, the reciprocal of
55
  !> the maximum timestep that satisfies the CFL condition. This
56
  !> currently has to be module level due to potential non-blocking
57
  !> reduction. Stores max_vel_x, max_vel_y and max_vel_error
58
  !> components to allow a max reduction over each element.
59
  real, dimension(3) :: max_vel_components
60

61
  integer :: cfl_req_hand = mp_request_null
62
  logical :: use_cfl_limit, use_2d_cfl
63

64
  !> Variables related to the order based error estimate -- see config documentation
65
  real :: error_target
66
  integer :: istep_error_start
67
  logical :: use_order_based_error
68

69
  logical :: split_nonlinear
70
  logical :: include_apar, include_bpar, include_phi
71

72
  real :: time_add_explicit_terms(2) = 0., time_add_explicit_terms_mpi = 0.
73
  real :: time_add_explicit_terms_field(2) = 0.
74

75
  logical :: nonlin = .false.
76
  logical :: initialized = .false.
77
  logical :: alloc = .true.
78
  logical :: zip = .false.
79
  logical :: accelerated = .false.
80

81
  !> The "large" cfl time step limit to use when we don't
82
  !> have a valid cfl limit from the NL term.
83
  real, parameter :: dt_cfl_default_large = 1.e8
84

85
  !> Used to represent the input configuration of nonlinear_terms
86
  type, extends(abstract_config_type) :: nonlinear_terms_config_type
87
     ! namelist : nonlinear_terms_knobs
88
     ! indexed : false
89
     !> Scales the estimate CFL limit used to determine when the
90
     !> timestep should be changed. The maximum allowed timestep
91
     !> satisfies `delt < cfl * min(Delta_perp/v_perp)` where `v_perp
92
     !> * delt` is the maximum distance travelled in a single
93
     !> timestep.
94
     real :: cfl = 0.95
95
     !> Set the error threshold used to determine when the timestep should change if
96
     !> [[nonlinear_terms_knobs:use_order_based_error]] is true.
97
     real :: error_target = 0.1
98
     !> Flag for testing. If false do not include apar contribution to nonlinear term.
99
     logical :: include_apar = .true.
100
     !> Flag for testing. If false do not include bpar contribution to nonlinear term.
101
     logical :: include_bpar = .true.
102
     !> Flag for testing. If false do not include phi contribution to nonlinear term.
103
     logical :: include_phi = .true.
104
     !> Set the first timestep for which the order based error checks are made if
105
     !> [[nonlinear_terms_knobs:use_order_based_error]] is true.
106
     integer :: istep_error_start = 30
107
     !> Determines if the nonlinear terms should be calculated. Must
108
     !> be one of:
109
     !>
110
     !> - 'none' - Do not include nonlinear terms, i.e. run a linear calculation.
111
     !> - 'default' - The same as 'none'
112
     !> - 'off' - The same as 'none'
113
     !> - 'on' - Include nonlinear terms.
114
     !>
115
     !> Could consider changing this to a logical.
116
     character(len = 20) :: nonlinear_mode = 'default'
117
     !> Do we evolve the nonlinear term separately from the linear terms (true) or
118
     !> include the nonlinear term as a source in the standard algorithm (false).
119
     logical :: split_nonlinear = .false.
120
     !> If true then sum x and y cfl limiting velocities instead of taking the maximum.
121
     logical :: use_2d_cfl = .true.
122
     !> If true then use the cfl limit to set the maximum timestep allowed.
123
     logical :: use_cfl_limit = .true.
124
     !> If true then use an error estimate from comparing the nonlinear source
125
     !> calculated using 2nd and 3rd order Adams-Bashforth schemes to control
126
     !> the timestep in use. This does not disable the CFL estimate.
127
     logical :: use_order_based_error = .false.
128
     !> Not currently used, should consider removing.  Original
129
     !> documentation was "Experts only (for secondary/tertiary
130
     !> calculations)."  which suggests a close relation to the
131
     !> `eqzip` option of [[knobs]].
132
     logical :: zip = .false.
133
#include "nonlinear_terms_overrides_and_bound_auto_gen.inc"
134
  end type nonlinear_terms_config_type
135

136
  type(nonlinear_terms_config_type) :: nonlinear_terms_config
137
  
138
contains
139

140
  !> FIXME : Add documentation
141
  subroutine check_nonlinear_terms(report_unit,delt_adj)
×
142
    use gs2_time, only: code_dt_min, code_dt_max
143
    use kt_grids, only: is_box
144
    use run_parameters, only: nstep, wstar_units
145
    use theta_grid, only: nperiod
146
    implicit none
147
    integer, intent(in) :: report_unit
148
    real, intent(in) :: delt_adj
149
    if (nonlin) then
×
150
       write (report_unit, *) 
×
151
       write (report_unit, fmt="('This is a nonlinear simulation.')")
×
152
       write (report_unit, *) 
×
153
       if (wstar_units) then
×
154
          write (report_unit, *) 
×
155
          write (report_unit, fmt="('################# WARNING #######################')")
×
156
          write (report_unit, fmt="('Nonlinear runs require wstar_units = .false. in the knobs namelist.')") 
×
157
          write (report_unit, fmt="('THIS IS AN ERROR.')") 
×
158
          write (report_unit, fmt="('################# WARNING #######################')")
×
159
          write (report_unit, *) 
×
160
       end if
161
       if ( .not. is_box) then
×
162
          write (report_unit, *) 
×
163
          write (report_unit, fmt="('################# WARNING #######################')")
×
164
          write (report_unit, fmt="('Nonlinear runs must be carried out in a box.')") 
×
165
          write (report_unit, fmt="('Set grid_option to box in the kt_grids_knobs namelist.')") 
×
166
          write (report_unit, fmt="('THIS IS AN ERROR.')") 
×
167
          write (report_unit, fmt="('################# WARNING #######################')")
×
168
          write (report_unit, *) 
×
169
       end if
170

171
       if (split_nonlinear) then
×
172
          write (report_unit, *)
×
173
          write (report_unit, fmt="('################# WARNING #######################')")
×
174
          write (report_unit, fmt="('The nonlinear term will be evolved separately from')")
×
175
          write (report_unit, fmt="('the linear terms in a crude IMEX style.')")
×
176
          write (report_unit, fmt="('This is an experimental feature.')")
×
177
          write (report_unit, fmt="('################# WARNING #######################')")
×
178
          write (report_unit, *)
×
179
       end if
180

181
       if (.not. include_apar) then
×
182
          write (report_unit, *)
×
183
          write (report_unit, fmt="('################# WARNING #######################')")
×
184
          write (report_unit, fmt="('The A|| potential contributions to the nonlinear term are disabled.')")
×
185
          write (report_unit, fmt="('This is probably an error.')")
×
186
          write (report_unit, fmt="('################# WARNING #######################')")
×
187
          write (report_unit, *)
×
188
       end if
189

190
       if (.not. include_bpar) then
×
191
          write (report_unit, *)
×
192
          write (report_unit, fmt="('################# WARNING #######################')")
×
193
          write (report_unit, fmt="('The B|| potential contributions to the nonlinear term are disabled.')")
×
194
          write (report_unit, fmt="('This is probably an error.')")
×
195
          write (report_unit, fmt="('################# WARNING #######################')")
×
196
          write (report_unit, *)
×
197
       end if
198

199
       if (.not. include_phi) then
×
200
          write (report_unit, *)
×
201
          write (report_unit, fmt="('################# WARNING #######################')")
×
202
          write (report_unit, fmt="('The electrostatic potential contributions to the nonlinear term are disabled.')")
×
203
          write (report_unit, fmt="('This is probably an error.')")
×
204
          write (report_unit, fmt="('################# WARNING #######################')")
×
205
          write (report_unit, *)
×
206
       end if
207

208
       if (nperiod > 1) then
×
209
          write (report_unit, *) 
×
210
          write (report_unit, fmt="('################# WARNING #######################')")
×
211
          write (report_unit, fmt="('Nonlinear runs usually have nperiod = 1.')") 
×
212
          write (report_unit, fmt="('THIS MAY BE AN ERROR.')") 
×
213
          write (report_unit, fmt="('################# WARNING #######################')")
×
214
          write (report_unit, *) 
×
215
       end if
216

217
       if (use_cfl_limit) then
×
218
          write (report_unit, *)
×
219
          write (report_unit, fmt="('The timestep will be adjusted to satisfy the CFL limit.')")
×
220
          write (report_unit, fmt="('The maximum delt < ',f10.4,' * min(Delta_perp/v_perp). (cfl)')") cfl
×
221
          write (report_unit, *)
×
222
       else
223
          write (report_unit, *)
×
224
          write (report_unit, fmt="('################# WARNING #######################')")
×
225
          write (report_unit, fmt="('Nonlinear usually have use_cfl_limit = T')")
×
226
          write (report_unit, fmt="('################# WARNING #######################')")
×
227
          write (report_unit, *)
×
228
       end if
229

230
       if (use_order_based_error) then
×
231
          write (report_unit, *)
×
232
          write (report_unit, fmt="('The timestep will be adjusted to keep the estimated error below',e11.4)") error_target
×
233
          write (report_unit, fmt="('beginning on step',I0)") istep_error_start
×
234

235
          write (report_unit, *)
×
236
       else
237
          if (.not. use_cfl_limit) then
×
238
             write (report_unit, *)
×
239
             write (report_unit, fmt="('################# WARNING #######################')")
×
240
             write (report_unit, fmt="('Both CFL and error methods for controlling explicit timestep are disabled.')")
×
241
             write (report_unit, fmt="('THIS IS PROBABLY AN ERROR.')")
×
242
             write (report_unit, fmt="('################# WARNING #######################')")
×
243
             write (report_unit, *)
×
244
          end if
245
       end if
246

247
       write (report_unit, fmt="('The minimum delt ( code_dt_min ) = ',e11.4)") code_dt_min
×
248
       write (report_unit, fmt="('The maximum delt (code_dt_max) = ',e11.4)") code_dt_max
×
249
       write (report_unit, fmt="('When the time step needs to be changed, it is adjusted by a factor of ',f10.4)") delt_adj
×
250
       write (report_unit, fmt="('The number of time steps nstep = ',i7)") nstep
×
251
    endif
252
  end subroutine check_nonlinear_terms
×
253

254
  !> FIXME : Add documentation  
255
  subroutine wnml_nonlinear_terms(unit)
×
256
    implicit none
257
    integer, intent(in) :: unit
258
    call nonlinear_terms_config%write(unit)
×
259
  end subroutine wnml_nonlinear_terms
×
260

261
  !> FIXME : Add documentation  
262
  subroutine init_nonlinear_terms(nonlinear_terms_config_in)
×
263
    use gs2_time, only: save_dt_cfl, code_dt_cfl
264
    use gs2_transforms, only: get_accel
265
    use le_grids, only: negrid, nlambda
266
    use species, only: nspec
267
    use theta_grid, only: ntgrid
268
    use kt_grids, only: aky, akx
269
    use gs2_layouts, only: yxf_lo, accelx_lo
270
    use array_utils, only: zero_array
271
    use unit_tests, only: debug_message
272
#ifdef SHMEM
273
    use shm_mpi3, only : shm_alloc
274
#endif
275
    implicit none
276
    type(nonlinear_terms_config_type), intent(in), optional :: nonlinear_terms_config_in
277
    integer, parameter :: verb = 4
278

279
    if (initialized) return
×
280
    initialized = .true.
×
281
    
282
    call read_parameters(nonlinear_terms_config_in)
×
283

284
    cfly = maxval(aky) * 0.5 / cfl
×
285
    cflx = maxval(akx) * 0.5 / cfl
×
286
    call save_dt_cfl (dt_cfl_default_large)
×
287

288
    ! Ensure the module level max_vel is consistent with
289
    ! the selected cfl limiting timestep.
290
    max_vel_components = 1.0 / code_dt_cfl
×
291

292
    accelerated = get_accel(negrid, nlambda, nspec)
×
293

294
    if (nonlin .and. alloc) then
×
295
       call debug_message(verb, "nonlinear terms finish_init: allocations")
×
296
       if (accelerated) then
×
297
#ifndef SHMEM
298
          allocate (     aba(2*ntgrid+1, 2, accelx_lo%llim_proc:accelx_lo%ulim_alloc))
×
299
          allocate (     agb(2*ntgrid+1, 2, accelx_lo%llim_proc:accelx_lo%ulim_alloc))
×
300
          allocate (abracket(2*ntgrid+1, 2, accelx_lo%llim_proc:accelx_lo%ulim_alloc))
×
301
#else
302
          call shm_alloc(aba, [ 1, 2*ntgrid+1, 1, 2, accelx_lo%llim_proc, accelx_lo%ulim_alloc ])
303
          call shm_alloc(agb, [ 1, 2*ntgrid+1, 1, 2, accelx_lo%llim_proc, accelx_lo%ulim_alloc ])
304
          call shm_alloc(abracket, [ 1, 2*ntgrid+1, 1, 2, accelx_lo%llim_proc, accelx_lo%ulim_alloc ])
305
#endif
306
          call zero_array(aba) ; call zero_array(agb) ; call zero_array(abracket)
×
307
       else
308
#ifndef SHMEM
309
          allocate (     ba(yxf_lo%ny,yxf_lo%llim_proc:yxf_lo%ulim_alloc))
×
310
          allocate (     gb(yxf_lo%ny,yxf_lo%llim_proc:yxf_lo%ulim_alloc))
×
311
          allocate (bracket(yxf_lo%ny,yxf_lo%llim_proc:yxf_lo%ulim_alloc))
×
312
#else
313
          call shm_alloc(ba, [ 1,yxf_lo%ny,yxf_lo%llim_proc,yxf_lo%ulim_alloc ])
314
          call shm_alloc(gb, [ 1,yxf_lo%ny,yxf_lo%llim_proc,yxf_lo%ulim_alloc ])
315
          call shm_alloc(bracket, [ 1,yxf_lo%ny,yxf_lo%llim_proc,yxf_lo%ulim_alloc ])
316
#endif
317
          call zero_array(ba) ; call zero_array(gb) ; call zero_array(bracket)
×
318
       end if
319
       alloc = .false.
×
320
    end if
321
  end subroutine init_nonlinear_terms
322

323
  !> FIXME : Add documentation  
324
  subroutine read_parameters(nonlinear_terms_config_in)
×
325
    use file_utils, only: error_unit
326
    use text_options, only: text_option, get_option_value
327
    implicit none
328
    type(nonlinear_terms_config_type), intent(in), optional :: nonlinear_terms_config_in
329
    type (text_option), dimension (4), parameter :: nonlinearopts = &
330
         [ text_option('default', nonlinear_mode_none), &
331
            text_option('none', nonlinear_mode_none), &
332
            text_option('off', nonlinear_mode_none), &
333
            text_option('on', nonlinear_mode_on) ]
334
    character(len = 20) :: nonlinear_mode
335
    integer :: ierr
336

337
    if (present(nonlinear_terms_config_in)) nonlinear_terms_config = nonlinear_terms_config_in
×
338

339
    call nonlinear_terms_config%init(name = 'nonlinear_terms_knobs', requires_index = .false.)
×
340

341
    ! Copy out internal values into module level parameters
342
    associate(self => nonlinear_terms_config)
343
#include "nonlinear_terms_copy_out_auto_gen.inc"
344
    end associate
345

346
    ierr = error_unit()
×
347
    call get_option_value &
348
         (nonlinear_mode, nonlinearopts, nonlinear_mode_switch, &
349
         ierr, "nonlinear_mode in nonlinear_terms_knobs",.true.)
×
350

351
    nonlin = nonlinear_mode_switch == nonlinear_mode_on
×
352
  end subroutine read_parameters
×
353

354
  !> FIXME : Add documentation  
355
  subroutine add_explicit_terms (g1, g2, g3, phi, apar, bpar, istep, bd)
×
356
    use theta_grid, only: ntgrid
357
    use gs2_layouts, only: g_lo
358
    use gs2_time, only: save_dt_cfl
359
    use job_manage, only: time_message
360
    use mp, only: get_mp_times
361
    implicit none
362
    complex, dimension (-ntgrid:,:,g_lo%llim_proc:), intent (in out) :: g1, g2, g3
363
    complex, dimension (-ntgrid:,:,:), intent (in) :: phi,    apar,    bpar
364
    integer, intent (in) :: istep
365
    real, intent (in) :: bd
366
    logical, parameter :: nl = .true.
367
    real :: mp_total_after, mp_total
368
    call time_message(.false., time_add_explicit_terms, 'Explicit terms')
×
369
    call get_mp_times(total_time = mp_total)
×
370
    if (nonlin .and. istep /= 0) call add_explicit (g1, g2, g3, phi, apar, bpar, istep, bd, nl)
×
371
    call time_message(.false., time_add_explicit_terms, 'Explicit terms')
×
372
    call get_mp_times(total_time = mp_total_after)
×
373
    time_add_explicit_terms_mpi = time_add_explicit_terms_mpi + (mp_total_after - mp_total)
×
374
  end subroutine add_explicit_terms
×
375

376
  !> FIXME : Add documentation  
377
  subroutine add_explicit (g1, g2, g3, phi, apar, bpar, istep, bd,  nl)
×
378
    use theta_grid, only: ntgrid
379
    use gs2_layouts, only: g_lo, ik_idx, it_idx, il_idx, is_idx
380
    use dist_fn_arrays, only: g
381
    use gs2_time, only: code_dt, check_time_step_too_large
382
    use run_parameters, only: reset, immediate_reset
383
    use unit_tests, only: debug_message
384
    use mp, only: nb_max_allreduce, max_allreduce
385
    use array_utils, only: copy, zero_array
386
    implicit none
387
    complex, dimension (-ntgrid:,:,g_lo%llim_proc:), intent (in out) :: g1, g2, g3
388
    complex, dimension (-ntgrid:,:,:), intent (in) :: phi, apar, bpar
389
    integer, intent (in) :: istep
390
    real, intent (in) :: bd
391
    logical, intent (in), optional :: nl
392
    integer, parameter :: verb = 4
393
    integer :: iglo, ik
394
    real :: error, target_dt
395

396
    call debug_message(verb, 'nonlinear_terms::add_explicit starting')
×
397

398
    if (istep <= 0) return
×
399

400
    call debug_message(verb, 'nonlinear_terms::add_explicit copying old terms')
×
401

402
    ! The following if statement ensures that the nonlinear term is calculated only once
403
    ! per timestep. It guards against calculating the nonlinear term in two cases:
404
    !   1. the second call to `timeadv` in a usual timestep
405
    !   2. both calls to `timeadv` after the CFL condition check has triggered a reset
406
    !      of this timestep (when `immediate_reset = .true.`). As the nonlinear term is
407
    !      independent of `delt`, it does not need to be calculated again.
408
    !
409
    ! N.B. When `immediate_reset = .false.`, the timestep is completed even though the
410
    ! CFL condition is broken. `delt` and the response matrix are changed at the end of
411
    ! the timestep; the following timestep is "normal", and the nonlinear term is
412
    ! calculated.
413
    if (istep /= istep_last) then
×
414

415
       istep_last = istep
×
416

417
       ! Shuffle time history along -- this is a place pointers might help
418
       ! avoid some copying.
419
       ! Should we only need to do this if we have a nonlinear simulation?
420
       ! It's possible we might have other explicit sources, in which case we
421
       ! probably always need to do this shuffling, however in that case this
422
       ! subroutine probably best belongs in a different module.
423
       call copy(g2, g3)
×
424
       call copy(g1, g2)
×
425

426
       call debug_message(verb, 'nonlinear_terms::add_explicit copied old terms')
×
427

428
       ! if running nonlinearly, then compute the nonlinear term at grid points
429
       ! and store it in g1
430
       if (present(nl)) then
×
431
          call debug_message(verb, 'nonlinear_terms::add_explicit calling add_nl')
×
432

433
          ! If we're not using various limits then we'd like to zero
434
          ! out the maximum velocity however, we later take 1/max_vel
435
          ! so let's just set it small.
436
          max_vel_components = epsilon(0.0)
×
437

438
          call add_nl (g, g1, phi, apar, bpar)
×
439

440
          ! takes g1 at grid points and returns 2*g1 at cell centers
441
          call nl_center (g1, bd)
×
442

443
          ! Currently the module level max_vel_components contains the
444
          ! maximum x and y velocities found from the nonlinear term
445
          ! on this processor. This can be used to find the cfl
446
          ! limting time step.
447

448
          ! Reset the x and y components of max_vel_components if we
449
          ! don't want to consider the cfl limit
450
          if (.not. use_cfl_limit) then
×
451
             max_vel_components(1:2) = epsilon(0.0)
×
452
          end if
453

454
          ! Calculate the effective maximum velocity based on the error
455
          ! based time step limit (really we estimate the maximum time step
456
          ! to keep our errors below our target and then convert to an
457
          ! effective velocity).
458
          if (use_order_based_error .and. (istep > istep_error_start)) then
×
459
             ! Get the current order based error estimate
460
             error = estimate_error(g1, g2, g3)
×
461

462
             ! Based on the current error estimate and the expected error scaling
463
             ! work out what time step we expect to give us the target error.
464
             ! Note that we don't scale by cfl here as the user has direct control
465
             ! over error_target already. Also note that by taking the square root
466
             ! we are assuming that the error looks like dt^2. We should probably
467
             ! look at what order schemes we're actually comparing to determine
468
             ! the appropriate dependency.
469
             target_dt =code_dt*sqrt(error_target/(error))
×
470

471
             ! Now we have an error limited time step lets convert this
472
             ! to an effective maximum velocity
473
             max_vel_components(3) = 1.0/target_dt
×
474
          end if
475

476
          ! Now we can reduce our local limiting velocities to get
477
          ! a global value for the maximum velocity. We only need to
478
          ! reduce if at least one time limit check is active.
479
          if (use_cfl_limit .or. use_order_based_error) then
×
480
             ! Estimate the global cfl limit based on max_vel calculated
481
             ! in `add_nl`.If immediate_reset is true, check the max
482
             ! allreduce immediately.  If not, overlap comms and work,
483
             ! and check for reset at the end of the timestep.
484
             if(immediate_reset)then
×
485
                call max_allreduce(max_vel_components)
×
486
                ! This call can update the value of reset.
487
                call set_cfl_time_step_and_check_if_too_large
×
488
             else
489
                ! Do a nonblocking reduce and check later in
490
                ! [[gs2_reinit:check_time_step]].
491
                call nb_max_allreduce(max_vel_components, cfl_req_hand)
×
492
             end if
493
          else
494
             ! If we don't have any checks active then we better make sure that the
495
             ! limiting time step is set. We will have set max_vel earlier to
496
             ! epsilon(0.0) so we can just use the usual routine to set this, but
497
             ! can skip communications. Really we probably just need to do this once
498
             ! but for now just put this here to be on the safe side. The cost should
499
             ! be low.
500
             call set_cfl_time_step_and_check_if_too_large
×
501
          end if
502

503
          if(reset) then
×
504
             return !Return if resetting
×
505
          endif
506

507
       else
508
          call zero_array(g1)
×
509
       end if
510
    end if
511

512
    if (zip) then
×
513
       do iglo = g_lo%llim_proc, g_lo%ulim_proc
×
514
          ik = ik_idx(g_lo,iglo)
×
515
          if (ik /= 1) then
×
516
             g (:,1,iglo) = 0.
×
517
             g (:,2,iglo) = 0.
×
518
             g1(:,1,iglo) = 0.
×
519
             g1(:,2,iglo) = 0.
×
520
          end if
521
       end do
522
    end if
523

524
    istep_last = istep
×
525
  end subroutine add_explicit
526

527
  !> Get an estimate of the error on the NL source term by comparing
528
  !> 2nd and 3rd order calculations of the source term.
529
  !>
530
  !> Here we're calculating g at t+code_dt using g(t) = g1, g(t-dt1) = g2
531
  !> and g(t-dt2) = g3 using 2nd and 3rd order methods and comparing
532
  !> the difference to estimate the error.
533
  real function estimate_error(g1, g2, g3) result(error)
×
534
    use gs2_time, only: get_adams_bashforth_coefficients, time_history_available
535
    use mp, only: max_allreduce
536
    use array_utils, only: gs2_max_abs
537
    implicit none
538
    complex, dimension(:, :, :), intent(in) :: g1, g2, g3
539
    complex, dimension(:, :, :), allocatable :: source_order_3, source_order_2
×
540
    real, dimension(2) :: intermediate_error
541
    real, dimension(:), allocatable :: coeff_3rd, coeff_2nd
×
542

543
    allocate(coeff_3rd(min(time_history_available(), 3)))
×
544
    allocate(coeff_2nd(min(time_history_available(), 2)))
×
545

546
    ! Check that we actually have 3rd and 2nd order coefficients.
547
    ! This could fail on the first two time steps of a simulation, for
548
    ! example, where we don't have enough time history to allow a
549
    ! 2nd/3rd order calculation. For now just return an error of
550
    ! error_target times cfl squared. This is chosen such the target
551
    ! timestep remains the current timestep.
552
    if ( (size(coeff_3rd) /= 3) .or. (size(coeff_2nd) /= 2) ) then
×
553
       error = error_target *cfl*cfl
×
554
       return
×
555
    end if
556

557
    ! Calculate the coefficients required for variable time step schemes
558
    coeff_3rd = get_adams_bashforth_coefficients(maximum_order = 3)
×
559
    coeff_2nd = get_adams_bashforth_coefficients(maximum_order = 2)
×
560

561
    ! Calculate the source terms using 3rd and 2nd order methods
562
    allocate(source_order_3, mold = g1)
×
563
    allocate(source_order_2, mold = g1)
×
564
    source_order_3 = coeff_3rd(1) * g1 + coeff_3rd(2) * g2 + coeff_3rd(3) * g3
×
565
    source_order_2 = coeff_2nd(1) * g1 + coeff_2nd(2) * g2
×
566

567
    ! Here we find the maximum absolute error
568
    intermediate_error(1) = gs2_max_abs(source_order_3 - source_order_2)
×
569

570
    ! Now we find the maximum of source_order_2 to scale the absolute
571
    ! error with.  Note we use this rather than source_order_3 as the
572
    ! higher order method has a smaller region of stability so is
573
    ! perhaps more likely to blow up.
574
    intermediate_error(2) = gs2_max_abs(source_order_2)
×
575

576
    ! Reduce over all processors
577
    call max_allreduce(intermediate_error)
×
578

579
    ! Now we form a crude relative error by dividing by the maximum
580
    ! source value. We do this rather than forming the true relative
581
    ! error (i.e. dividing the entire absolute difference by the source)
582
    ! to avoid issues with dividing by small numbers. This will tend to
583
    ! underestimate the real relative error.
584
    error = intermediate_error(1) / intermediate_error(2)
×
585
  end function estimate_error
×
586

587
  !> Takes input array evaluated at theta grid points
588
  !! and overwrites it with array evaluated at cell centers
589
  !! note that there is an extra factor of 2 in output array
590
  subroutine nl_center (gtmp, bd)
×
591
    !
592
    !CMR, 13/10/2014
593
    ! Fixing some (cosmetic) issues from prior to R3021.
594
    ! (1) forbid(-ntgrid:ntgrid) refers to grid points at cell boundaries
595
    !     gtmp(-ntgrid:ntgrid-1) refers to cell centers
596
    !     => applying forbid to output gtmp did not zero the correct things!!!
597
    ! (2) totally trapped particles are special, so return source without upwinding is fine
598
    !     BUT source for other trapped particles should NOT enter forbidden region.
599
    !     if ig or ig+1 forbidden (i.e. ig+1 or ig is bounce point) now return gtmp(ig,:,iglo)=0
600
    !
601
    use gs2_layouts, only: g_lo, il_idx
602
    use theta_grid, only: ntgrid
603
    use le_grids, only: grid_has_trapped_particles, jend, is_ttp
604
    use mp, only: mp_abort
605

606
    implicit none
607
    real, intent (in) :: bd    
608
    complex, dimension (-ntgrid:,:,g_lo%llim_proc:), intent (in out) :: gtmp
609
    integer :: iglo, il, ig
610
    logical :: trapped
611

612
    trapped = grid_has_trapped_particles()
×
613

614
    ! factor of one-half appears elsewhere
615
    !$OMP PARALLEL DO DEFAULT(none) &
616
    !$OMP PRIVATE(iglo, il, ig) &
617
    !$OMP SHARED(g_lo, gtmp, ntgrid, is_ttp, jend, trapped, bd) &
618
    !$OMP SCHEDULE(static)
619
    do iglo = g_lo%llim_proc, g_lo%ulim_proc
×
620
       il = il_idx(g_lo, iglo)
×
621

622
       do ig = -ntgrid, ntgrid-1
×
623
          !
624
          !CMR, 7/10/2014: 
625
          ! loop sets gtmp to value at upwinded cell center RIGHT of theta(ig)
626
          !           except for ttp where upwinding makes no sense!
627
          !
628
          ! Note this cycle doesn't skip when ig is in the forbidden region
629
          ! even if the pitch angle is greater than the totally trapped one
630
          ! at this location. This ensures that whilst we leave the (allowed)
631
          ! totally trapped source alone we still zero the NL source for forbidden
632
          ! points. Previously we cycled simply if the pitch angle index was larger
633
          ! than the totally trapped one. When there are multiple totally trapped
634
          ! pitch angles this may not be equivalent.
635
          if (is_ttp(ig, il)) cycle
×
636
          ! The below might be better off using forbid instead of checking jend
637
          if ( trapped .and. ( il > jend(ig) .or. il > jend(ig+1)) ) then
×
638
             !
639
             !CMR, 7/10/2014: 
640
             !   if either ig or ig+1 is forbidden, no source possible in a cell RIGHT of theta(ig) 
641
             !   => gtmp(ig,1:2,iglo)=0
642
             !
643
             gtmp(ig,1:2,iglo) = 0.0
×
644
          else 
645
             !
646
             !CMR, 7/10/2014: 
647
             !    otherwise ig and ig+1 BOTH allowed, and upwinding in cell RIGHT of theta(ig) is fine
648
             !
649
             gtmp(ig,1,iglo) = (1.+bd)*gtmp(ig+1,1,iglo) + (1.-bd)*gtmp(ig,1,iglo)
×
650
             gtmp(ig,2,iglo) = (1.-bd)*gtmp(ig+1,2,iglo) + (1.+bd)*gtmp(ig,2,iglo)
×
651

652
          endif
653
       end do
654
    end do
655
    !$OMP END PARALLEL DO
656
  end subroutine nl_center
×
657

658
  !> Calculates the current nonlinear source term by calling add_nl
659
  !> and the associated cfl limit.
660
  subroutine calculate_current_nl_source_and_cfl_limit(g_in, g1, phi, apar, bpar, &
×
661
       max_vel_local, need_to_adjust, calculate_cfl_limit)
662
    use optionals, only: get_option_with_default
663
    implicit none
664
    complex, dimension (:,:,:), intent (in) :: g_in
665
    complex, dimension (:,:,:), intent (out) :: g1
666
    complex, dimension (:,:,:), intent (in) :: phi, apar, bpar
667
    real, intent(out) :: max_vel_local
668
    logical, intent(in) :: need_to_adjust
669
    logical, intent(in), optional :: calculate_cfl_limit
670

671
    use_cfl_limit = get_option_with_default(calculate_cfl_limit, .true.)
×
672
    call add_nl(g_in, g1, phi, apar, bpar, need_to_adjust)
×
673

674
    if (use_cfl_limit) then
×
675
       ! This code may need changing if the handling of the cfl limit changes
676
       max_vel_local = get_max_vel(max_vel_components)
×
677
    else
678
       max_vel_local = 1.0e-8
×
679
    end if
680

681
  end subroutine calculate_current_nl_source_and_cfl_limit
×
682

683
  !> Calculate the nonlinear term and part of the corresponding CFL condition
684
  subroutine add_nl (g_in, g1, phi, apar, bpar, adjust)
×
685
    use theta_grid, only: ntgrid, kxfac
686
    use gs2_layouts, only: g_lo, ik_idx, it_idx
687
    use dist_fn_arrays, only: g_adjust, from_g_gs2
688
    use gs2_transforms, only: transform2, inverse2
689
    use kt_grids, only: aky, akx
690
    use constants, only: zi
691
    use unit_tests, only: debug_message
692
    use optionals, only: get_option_with_default
693
    use array_utils, only: copy, gs2_max_abs
694
    implicit none
695
    complex, dimension (-ntgrid:,:,g_lo%llim_proc:), intent (in) :: g_in
696
    complex, dimension (-ntgrid:,:,g_lo%llim_proc:), intent (out) :: g1
697
    !> Local array used to store the adjusted input dfn if needed. Saves
698
    !> calling g_adjust twice.
699
    complex, dimension (-ntgrid:ntgrid, 2, g_lo%llim_proc:g_lo%ulim_alloc) :: g2
×
700
    complex, dimension (-ntgrid:,:,:), intent (in) :: phi, apar, bpar
701
    logical, intent(in), optional :: adjust
702
    logical :: should_adjust
703
    integer, parameter :: verb = 4
704
    integer :: iglo, ik, it
705
    real :: max_vel_x, max_vel_y
706
    
707
    call debug_message(verb, 'nonlinear_terms::add_nl starting')
×
708
    should_adjust = get_option_with_default(adjust, .true.)
×
709

710
    !Form g1=i*kx*chi
711
    call load_kx_phi(g1, phi)    
×
712
    call load_kx_bpar(g1, bpar)    
×
713
    call load_kx_apar(g1, apar)    
×
714

715
    call debug_message(verb, 'nonlinear_terms::add_nl calling transform2')
×
716

717
    !Transform to real space
718
    if (accelerated) then
×
719
       call transform2 (g1, aba)
×
720
       max_vel_y = gs2_max_abs(aba)
×
721
    else
722
       call transform2 (g1, ba)
×
723
       max_vel_y = gs2_max_abs(ba)
×
724
    end if
725
    max_vel_y = max_vel_y * cfly
×
726

727
    call debug_message(verb, 'nonlinear_terms::add_nl calculated dphi/dx')
×
728
    
729
    !Form g1=i*ky*g_wesson
730
    call copy(g_in, g1)
×
731
    if (should_adjust) call g_adjust(g1, phi, bpar, direction = from_g_gs2)
×
732
    call copy(g1, g2)
×
733

734
    !$OMP PARALLEL DO DEFAULT(none) &
735
    !$OMP PRIVATE(iglo, ik) &
736
    !$OMP SHARED(g_lo, g1, aky) &
737
    !$OMP SCHEDULE(static)
738
    do iglo = g_lo%llim_proc, g_lo%ulim_proc
×
739
       ik = ik_idx(g_lo,iglo)
×
740
       g1(:,:,iglo)=g1(:,:,iglo)*zi*aky(ik)
×
741
    enddo
742
    !$OMP END PARALLEL DO
743

744
    !Transform to real space
745
    if (accelerated) then
×
746
       call transform2 (g1, agb)
×
747
    else
748
       call transform2 (g1, gb)
×
749
    end if
750

751
    call debug_message(verb, 'nonlinear_terms::add_nl calculated dg/dy')
×
752

753
    call calculate_bracket(.true.)
×
754
    
755
    call debug_message(verb, 'nonlinear_terms::add_nl calculated dphi/dx.dg/dy')
×
756

757
    !Form g1=i*ky*chi
758
    call load_ky_phi(g1, phi)
×
759
    call load_ky_bpar(g1, bpar)
×
760
    call load_ky_apar(g1, apar)
×
761

762
    call debug_message(verb, 'nonlinear_terms::add_nl calculated dphi/dy')
×
763

764
    !Transform to real space    
765
    if (accelerated) then
×
766
       call transform2 (g1, aba)
×
767
       max_vel_x = gs2_max_abs(aba)
×
768
    else
769
       call transform2 (g1, ba)
×
770
       max_vel_x = gs2_max_abs(ba)
×
771
    end if
772
    max_vel_x = max_vel_x * cflx
×
773

774
    !Form g1=i*kx*g_wesson noting that g2 holds our starting g_wesson
775

776
    !$OMP PARALLEL DO DEFAULT(none) &
777
    !$OMP PRIVATE(iglo, it) &
778
    !$OMP SHARED(g_lo, g2, akx) &
779
    !$OMP SCHEDULE(static)
780
    do iglo = g_lo%llim_proc, g_lo%ulim_proc
×
781
       it = it_idx(g_lo,iglo)
×
782
       g2(:,:,iglo) = g2(:,:,iglo) * zi * akx(it)
×
783
    enddo
784
    !$OMP END PARALLEL DO
785

786
    !Transform to real space
787
    if (accelerated) then
×
788
       call transform2 (g2, agb)
×
789
    else
790
       call transform2 (g2, gb)
×
791
    end if
792

793
    call debug_message(verb, 'nonlinear_terms::add_nl calculated dg/dx')
×
794

795
    call calculate_bracket(.false.)
×
796
    
797
    call debug_message(verb, &
798
      'nonlinear_terms::add_nl calculated dphi/dx.dg/dy.dphi/dy.dg/dx')
×
799

800
    !Transform NL source back to spectral space
801
    if (accelerated) then
×
802
       call inverse2 (abracket, g1)
×
803
    else
804
       call inverse2 (bracket, g1)
×
805
    end if
806

807
    !Store local max vel components for future max reduce
808
    max_vel_components(1) = max_vel_x
×
809
    max_vel_components(2) = max_vel_y
×
810

811
    ! Scale by kxfac
812
    !$OMP PARALLEL DO DEFAULT(none) &
813
    !$OMP PRIVATE(iglo) &
814
    !$OMP SHARED(g_lo, g1, kxfac) &
815
    !$OMP SCHEDULE(static)
816
    do iglo = g_lo%llim_proc, g_lo%ulim_proc
×
817
       g1(:, :, iglo) = g1(:, :, iglo) * kxfac
×
818
    end do
819
    !$OMP END PARALLEL DO
820

821
    call debug_message(verb, &
822
      'nonlinear_terms::add_nl calculated nonlinear term')
×
823

824
  end subroutine add_nl
×
825

826
  !> FIXME : Add documentation    
827
  subroutine load_kx_phi(g1, phi)
×
828
    use theta_grid, only: ntgrid
829
    use gs2_layouts, only: g_lo, ik_idx, it_idx
830
    use dist_fn_arrays, only: aj0
831
    use run_parameters, only: has_phi, fphi
832
    use kt_grids, only: akx
833
    use constants, only: zi
834
    use array_utils, only: zero_array
835
    implicit none
836
    complex, dimension (-ntgrid:,:,g_lo%llim_proc:), intent (in out) :: g1
837
    complex, dimension (-ntgrid:,:,:), intent (in) :: phi      
838
    complex, dimension(-ntgrid:ntgrid) :: fac
×
839
    integer :: iglo, it, ik
840

841
    if (has_phi .and. include_phi) then
×
842
       !$OMP PARALLEL DO DEFAULT(none) &
843
       !$OMP PRIVATE(iglo, it, ik, fac) &
844
       !$OMP SHARED(g_lo, g1, akx, aj0, phi, fphi) &
845
       !$OMP SCHEDULE(static)
846
       do iglo = g_lo%llim_proc, g_lo%ulim_proc
×
847
          it = it_idx(g_lo,iglo)
×
848
          ik = ik_idx(g_lo,iglo)
×
849
          fac = zi*akx(it)*aj0(:,iglo)*phi(:,it,ik)*fphi
×
850
          g1(:,1,iglo) = fac
×
851
          g1(:,2,iglo) = fac
×
852
       end do
853
       !$OMP END PARALLEL DO
854
    else
855
       call zero_array(g1)
×
856
    endif
857
  end subroutine load_kx_phi
×
858

859
  !> FIXME : Add documentation    
860
  subroutine load_ky_phi(g1, phi)
×
861
    use theta_grid, only: ntgrid
862
    use gs2_layouts, only: g_lo, ik_idx, it_idx
863
    use dist_fn_arrays, only: aj0
864
    use run_parameters, only: has_phi, fphi
865
    use kt_grids, only: aky
866
    use constants, only: zi
867
    use array_utils, only: zero_array
868
    implicit none
869
    complex, dimension (-ntgrid:,:,g_lo%llim_proc:), intent (in out) :: g1
870
    complex, dimension (-ntgrid:,:,:), intent (in) :: phi      
871
    complex, dimension(-ntgrid:ntgrid) :: fac
×
872
    integer :: iglo, it, ik
873

874
    if (has_phi .and. include_phi) then
×
875
       !$OMP PARALLEL DO DEFAULT(none) &
876
       !$OMP PRIVATE(iglo, it, ik, fac) &
877
       !$OMP SHARED(g_lo, g1, aky, aj0, phi, fphi) &
878
       !$OMP SCHEDULE(static)
879
       do iglo = g_lo%llim_proc, g_lo%ulim_proc
×
880
          it = it_idx(g_lo,iglo)
×
881
          ik = ik_idx(g_lo,iglo)
×
882
          fac = zi*aky(ik)*aj0(:,iglo)*phi(:,it,ik)*fphi
×
883
          g1(:,1,iglo) = fac
×
884
          g1(:,2,iglo) = fac
×
885
       end do
886
       !$OMP END PARALLEL DO
887
    else
888
       call zero_array(g1)
×
889
    endif
890

891
  end subroutine load_ky_phi
×
892

893
  ! should I use vpa or vpac in next two routines??
894

895
  !> FIXME : Add documentation    
896
  subroutine load_kx_apar(g1, apar)
×
897
    use theta_grid, only: ntgrid
898
    use gs2_layouts, only: g_lo, ik_idx, it_idx, is_idx
899
    use dist_fn_arrays, only: vpa, aj0
900
    use species, only: spec
901
    use run_parameters, only: has_apar, fapar
902
    use kt_grids, only: akx
903
    use constants, only: zi
904
    implicit none
905
    complex, dimension (-ntgrid:,:,g_lo%llim_proc:), intent (in out) :: g1
906
    complex, dimension (-ntgrid:,:,:), intent (in) :: apar
907
    complex, dimension(-ntgrid:ntgrid) :: fac    
×
908
    integer :: iglo, it, ik, is
909

910
    if(.not. (include_apar .and. has_apar) ) return
×
911

912
    !$OMP PARALLEL DO DEFAULT(none) &
913
    !$OMP PRIVATE(iglo, it, ik, is, fac) &
914
    !$OMP SHARED(g_lo, g1, vpa, akx, aj0, spec, apar, fapar) &
915
    !$OMP SCHEDULE(static)
916
    do iglo = g_lo%llim_proc, g_lo%ulim_proc
×
917
       it = it_idx(g_lo,iglo)
×
918
       ik = ik_idx(g_lo,iglo)
×
919
       is = is_idx(g_lo,iglo)
×
920

921
       fac = zi*akx(it)*aj0(:,iglo)*spec(is)%stm*apar(:,it,ik)*fapar
×
922
       g1(:,1,iglo) = g1(:,1,iglo) - fac*vpa(:,1,iglo)
×
923
       g1(:,2,iglo) = g1(:,2,iglo) - fac*vpa(:,2,iglo)
×
924
    end do
925
    !$OMP END PARALLEL DO
926
  end subroutine load_kx_apar
927

928
  !> FIXME : Add documentation    
929
  subroutine load_ky_apar(g1, apar)
×
930
    use theta_grid, only: ntgrid
931
    use gs2_layouts, only: g_lo, ik_idx, it_idx, is_idx
932
    use dist_fn_arrays, only: vpa, aj0
933
    use species, only: spec
934
    use run_parameters, only: has_apar, fapar
935
    use kt_grids, only: aky
936
    use constants, only: zi
937
    implicit none
938
    complex, dimension (-ntgrid:,:,g_lo%llim_proc:), intent (in out) :: g1
939
    complex, dimension (-ntgrid:,:,:), intent (in) :: apar            
940
    complex, dimension(-ntgrid:ntgrid) :: fac    
×
941
    integer :: iglo, it, ik, is
942

943
    if(.not. (include_apar .and. has_apar)) return
×
944

945
    !$OMP PARALLEL DO DEFAULT(none) &
946
    !$OMP PRIVATE(iglo, it, ik, is, fac) &
947
    !$OMP SHARED(g_lo, g1, vpa, aky, aj0, spec, apar, fapar) &
948
    !$OMP SCHEDULE(static)
949
    do iglo = g_lo%llim_proc, g_lo%ulim_proc
×
950
       it = it_idx(g_lo,iglo)
×
951
       ik = ik_idx(g_lo,iglo)
×
952
       is = is_idx(g_lo,iglo)
×
953

954
       fac = zi*aky(ik)*aj0(:,iglo)*spec(is)%stm*apar(:,it,ik)*fapar
×
955
       g1(:,1,iglo) = g1(:,1,iglo) - fac*vpa(:,1,iglo)
×
956
       g1(:,2,iglo) = g1(:,2,iglo) - fac*vpa(:,2,iglo)
×
957
    end do
958
    !$OMP END PARALLEL DO
959
  end subroutine load_ky_apar
960

961
  !> FIXME : Add documentation    
962
  subroutine load_kx_bpar(g1, bpar)
×
963
    use theta_grid, only: ntgrid
964
    use gs2_layouts, only: g_lo, ik_idx, it_idx, is_idx
965
    use dist_fn_arrays, only: vperp2, aj1
966
    use species, only: spec
967
    use run_parameters, only: has_bpar, fbpar
968
    use kt_grids, only: akx
969
    use constants, only: zi
970
    implicit none
971
    complex, dimension (-ntgrid:,:,g_lo%llim_proc:), intent (in out) :: g1
972
    complex, dimension (-ntgrid:,:,:), intent (in) :: bpar      
973
    complex, dimension(-ntgrid:ntgrid) :: fac    
×
974
    integer :: iglo, it, ik, is
975

976
    if (.not. (include_bpar .and. has_bpar)) return
×
977

978
    ! Is this factor of two from the old normalization?
979

980
    !$OMP PARALLEL DO DEFAULT(none) &
981
    !$OMP PRIVATE(iglo, it, ik, is, fac) &
982
    !$OMP SHARED(g_lo, g1, akx, aj1, vperp2, spec, bpar, fbpar) &
983
    !$OMP SCHEDULE(static)
984
    do iglo = g_lo%llim_proc, g_lo%ulim_proc
×
985
       it = it_idx(g_lo,iglo)
×
986
       ik = ik_idx(g_lo,iglo)
×
987
       is = is_idx(g_lo,iglo)
×
988
       fac = zi*akx(it)*aj1(:,iglo) &
×
989
            *2.0*vperp2(:,iglo)*spec(is)%tz*bpar(:,it,ik)*fbpar
×
990
       g1(:,1,iglo) = g1(:,1,iglo) + fac
×
991
       g1(:,2,iglo) = g1(:,2,iglo) + fac
×
992
    end do
993
    !$OMP END PARALLEL DO
994
  end subroutine load_kx_bpar
995

996
  !> FIXME : Add documentation    
997
  subroutine load_ky_bpar(g1, bpar)
×
998
    use theta_grid, only: ntgrid
999
    use gs2_layouts, only: g_lo, ik_idx, it_idx, is_idx
1000
    use dist_fn_arrays, only: vperp2, aj1
1001
    use species, only: spec
1002
    use run_parameters, only: has_bpar, fbpar
1003
    use kt_grids, only: aky
1004
    use constants, only: zi
1005
    implicit none
1006
    complex, dimension (-ntgrid:,:,g_lo%llim_proc:), intent (in out) :: g1
1007
    complex, dimension (-ntgrid:,:,:), intent (in) :: bpar
1008
    complex, dimension(-ntgrid:ntgrid) :: fac
×
1009
    integer :: iglo, it, ik, is
1010

1011
    if (.not. (include_bpar .and. has_bpar)) return
×
1012

1013
    ! Is this factor of two from the old normalization?
1014

1015
    !$OMP PARALLEL DO DEFAULT(none) &
1016
    !$OMP PRIVATE(iglo, it, ik, is, fac) &
1017
    !$OMP SHARED(g_lo, g1, aky, aj1, vperp2, spec, bpar, fbpar) &
1018
    !$OMP SCHEDULE(static)
1019
    do iglo = g_lo%llim_proc, g_lo%ulim_proc
×
1020
       it = it_idx(g_lo,iglo)
×
1021
       ik = ik_idx(g_lo,iglo)
×
1022
       is = is_idx(g_lo,iglo)
×
1023
       fac =  zi*aky(ik)*aj1(:,iglo) &
×
1024
            *2.0*vperp2(:,iglo)*spec(is)%tz*bpar(:,it,ik)*fbpar
×
1025
       g1(:,1,iglo) = g1(:,1,iglo) + fac
×
1026
       g1(:,2,iglo) = g1(:,2,iglo) + fac
×
1027
    end do
1028
    !$OMP END PARALLEL DO
1029
  end subroutine load_ky_bpar
1030

1031
  !> Calculate (d Chi /dx).(d g_wesson/dy) and store in bracket if is_first_term = .true.
1032
  !> else calculate (d Chi /dy).(d g_wesson/dx) and subtract from bracket
1033
  !>
1034
  !> @note The final bracket value must be scaled by kxfac to produce
1035
  !> the correct value to be used.
1036
  subroutine calculate_bracket(is_first_term)
×
1037
    use gs2_layouts, only: accelx_lo, yxf_lo
1038
    implicit none
1039
    logical, intent(in) :: is_first_term
1040
    integer :: iyxf
1041
    if (is_first_term) then
×
1042
       if (accelerated) then
×
1043
          !$OMP PARALLEL DO DEFAULT(none) &
1044
          !$OMP PRIVATE(iyxf) &
1045
          !$OMP SHARED(accelx_lo, agb, aba, abracket) &
1046
          !$OMP SCHEDULE(static)
1047
          do iyxf = accelx_lo%llim_proc, accelx_lo%ulim_proc
×
1048
             abracket(:, :, iyxf) = aba(:, :, iyxf)*agb(:, :, iyxf)
×
1049
          end do
1050
          !$OMP END PARALLEL DO
1051
       else
1052
          !$OMP PARALLEL DO DEFAULT(none) &
1053
          !$OMP PRIVATE(iyxf) &
1054
          !$OMP SHARED(yxf_lo, bracket, ba, gb) &
1055
          !$OMP SCHEDULE(static)
1056
          do iyxf = yxf_lo%llim_proc, yxf_lo%ulim_proc
×
1057
             bracket(:, iyxf) = ba(:, iyxf)*gb(:, iyxf)
×
1058
          end do
1059
          !$OMP END PARALLEL DO
1060
       endif
1061
    else
1062
       if (accelerated) then
×
1063
          !$OMP PARALLEL DO DEFAULT(none) &
1064
          !$OMP PRIVATE(iyxf) &
1065
          !$OMP SHARED(accelx_lo, agb, aba, abracket) &
1066
          !$OMP SCHEDULE(static)
1067
          do iyxf = accelx_lo%llim_proc, accelx_lo%ulim_proc
×
1068
             abracket(:, :, iyxf) = abracket(:, :, iyxf) - aba(:, :, iyxf)*agb(:, :, iyxf)
×
1069
          end do
1070
          !$OMP END PARALLEL DO
1071
       else
1072
          !$OMP PARALLEL DO DEFAULT(none) &
1073
          !$OMP PRIVATE(iyxf) &
1074
          !$OMP SHARED(yxf_lo, bracket, ba, gb) &
1075
          !$OMP SCHEDULE(static)
1076
          do iyxf = yxf_lo%llim_proc, yxf_lo%ulim_proc
×
1077
             bracket(:, iyxf) = bracket(:, iyxf) - ba(:, iyxf)*gb(:, iyxf)
×
1078
          end do
1079
          !$OMP END PARALLEL DO
1080
       endif
1081
    endif
1082
  end subroutine calculate_bracket
×
1083

1084
  !> Finish nonblocking calculation of the maximum velocity
1085
  !> and set the cfl limit.
1086
  subroutine nb_check_time_step_too_large
×
1087
    use run_parameters, only: immediate_reset
1088
    implicit none
1089
    if (immediate_reset) return
×
1090
    call finish_nonblocking_max_vel_reduction
×
1091
    call set_cfl_time_step_and_check_if_too_large
×
1092
  end subroutine nb_check_time_step_too_large
1093

1094
  !> Finish nonblocking calculation of the maximum velocity
1095
  !>
1096
  !> This receives the mpi_iallreduce of the maximum velocity.
1097
  subroutine finish_nonblocking_max_vel_reduction
×
1098
    use mp, only: wait, mp_request_null
1099
    implicit none
1100

1101
    ! Wait for the nonblocking maximum operation used to find
1102
    ! the maximum velocity.
1103
    if (cfl_req_hand == mp_request_null) return
×
1104
    call wait(cfl_req_hand)
×
1105
    cfl_req_hand = mp_request_null
×
1106
  end subroutine finish_nonblocking_max_vel_reduction
1107

1108
  !> Given the max_vel_components array return the limiting max_vel
1109
  real pure function get_max_vel(components) result(max_vel)
×
1110
    real, dimension(3), intent(in) :: components
1111
    real :: max_vel_cfl, max_vel_error
1112
    if (use_2d_cfl) then
×
1113
       max_vel_cfl = components(1) + components(2)
×
1114
    else
1115
       max_vel_cfl = maxval(components(1:2))
×
1116
    end if
1117
    max_vel_error = components(3)
×
1118
    max_vel = max(max_vel_cfl, max_vel_error)
×
1119
  end function get_max_vel
×
1120

1121
  !> Calculates the cfl limit from the module level max_vel value
1122
  !> saves it using [[gs2_time:save_dt_cfl]] and then sets the reset
1123
  !> flag based on checking if the current time step is too large.
1124
  subroutine set_cfl_time_step_and_check_if_too_large
×
1125
    use run_parameters, only: reset
1126
    use gs2_time, only: save_dt_cfl, check_time_step_too_large
1127
    implicit none
1128
    real :: dt_cfl, max_vel
1129

1130
    max_vel = get_max_vel(max_vel_components)
×
1131

1132
    ! Estimate the global cfl limit based on max_vel.
1133
    if (max_vel <= 0.0) then
×
1134
       ! We should only end up here in unusual cases (likely
1135
       ! tests) as we initialise max_vel > 0 so the only way
1136
       ! we get here is if the estimated NL velocity limit is
1137
       ! exactly 0.
1138
       dt_cfl = dt_cfl_default_large
×
1139
    else
1140
       dt_cfl = 1./max_vel
×
1141
    end if
1142

1143
    call save_dt_cfl (dt_cfl)
×
1144

1145
    ! Now check to see if we've violated the cfl condition.
1146
    call check_time_step_too_large(reset)
×
1147
  end subroutine set_cfl_time_step_and_check_if_too_large
×
1148

1149
  !> FIXME : Add documentation
1150
  subroutine finish_nonlinear_terms
×
1151
#ifdef SHMEM
1152
    use shm_mpi3, only : shm_free
1153
#endif
1154
    implicit none
1155

1156
#ifndef SHMEM
1157
    if (allocated(aba)) deallocate (aba, agb, abracket)
×
1158
    if (allocated(ba)) deallocate (ba, gb, bracket)
×
1159
#else
1160
    if (associated(aba)) call shm_free(aba)
1161
    if (associated(agb)) call shm_free(agb)
1162
    if (associated(abracket)) call shm_free(abracket)
1163
    if (associated(ba)) then
1164
       call shm_free(ba)
1165
    endif
1166
    if (associated(gb)) then
1167
       call shm_free(gb)
1168
    endif
1169
    if (associated(bracket)) then
1170
       call shm_free(bracket)
1171
    endif
1172
#endif
1173
    nonlin = .false. ; alloc = .true. ; zip = .false. ; accelerated = .false.
×
1174
    initialized = .false.
×
1175
  end subroutine finish_nonlinear_terms
×
1176

1177
#include "nonlinear_terms_auto_gen.inc"
1178
end module nonlinear_terms
×
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc