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

gyrokinetics / gs2 / 1989146477

18 Aug 2025 10:42AM UTC coverage: 10.372% (+2.2%) from 8.184%
1989146477

push

gitlab-ci

David Dickinson
Merged in experimental/more_gs2_init_everywhere (pull request #1134)

4646 of 44794 relevant lines covered (10.37%)

124612.73 hits per line

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

0.0
/src/fields_implicit.f90
1
!> FIXME : Add documentation
2
module fields_implicit
3
  implicit none
4

5
  private
6
 
7
  public :: init_fields_implicit, finish_fields_implicit, reset_init
8
  public :: advance_implicit, remove_zonal_flows, init_allfields_implicit
9
  public :: field_subgath, dump_response, read_response
10
  public :: dump_response_to_file_imp
11

12
!///////////////////////////////////////////////////////
13
!// DERIVED TYPES FOR FIELD MATRIX REPRESENTATION
14
!///////////////////////////////////////////////////////
15

16
  !////////////////////////////////////////////////////////////////
17
  !// DCELL : 
18
  ! Within each supercell, there are are N_class primary cells.  Each 
19
  ! has (2*ntgrid+1)*nfield points.
20
  !> FIXME : Add documentation  
21
  type dcell_type
22
     complex, dimension(:), allocatable :: supercell
23
  end type dcell_type
24
  !----------------------------------------------------------------
25

26
  ! Within each class, there may be multiple supercells.
27

28
  ! The number of supercells in each class is M_class.
29
  
30
  ! When aminv is laid out over PEs, the supercells of each class 
31
  ! are distributed -- thus, "dcells"
32
  
33
  !////////////////////////////////////////////////////////////////
34
  !// FIELD_MATRIX_TYPE :
35
  !> FIXME : Add documentation  
36
  type :: field_matrix_type
37
     type(dcell_type), dimension (:), allocatable :: dcell
38
  end type field_matrix_type
39
  !----------------------------------------------------------------
40

41
  !////////////////////////////////////////////////////////////////
42
  !// AMINV :
43
  ! There may be supercells of different sizes or "classes".  
44
  type (field_matrix_type), dimension (:), allocatable :: aminv
45
  !----------------------------------------------------------------
46
!-------------------------------------------------------
47

48
  !> A variable to help with running benchmarks... do not set true
49
  !! unless you know what you are doing. If true, the response matrix
50
  !! will not be initialised and set to zero. The results of any 
51
  !! simulation will be garbage
52
  logical, public :: skip_initialisation = .false.
53

54
  integer, dimension(:), allocatable :: M_class, N_class
55
  integer :: i_class
56

57
  integer :: nfield, nidx
58
  logical :: initialized = .false.
59
  logical :: field_subgath
60
  logical :: dump_response=.false., read_response=.false.
61
  integer, dimension(:), allocatable :: recvcnts, displs
62
contains
63
  !> FIXME : Add documentation
64
  subroutine init_fields_implicit
×
65
    use kt_grids, only: l_links, r_links
66
    use run_parameters, only: has_phi, has_apar, has_bpar
67
    use unit_tests, only: should_print
68
    use mp, only: mp_abort
69
    implicit none
70
    logical :: debug
71

72
    if (initialized) return
×
73
    initialized = .true.
×
74

75
    debug = should_print(3)
×
76

77
    !Check we have at least one field. If not abort.
78
    !Note, we do this here rather than as soon as we read input file
79
    !as other field types may support operation with no fields (e.g. 'local' does)
80
    if(.not. (has_phi .or. has_apar .or. has_bpar)) then
×
81
       call mp_abort("Field_option='implicit' requires at least one field is non-zero",.true.)
×
82
    endif
83

84
    call setup_fields_implicit_class_arrays(l_links, r_links, M_class, N_class, i_class)
×
85
    if (debug) write(6,*) "init_fields_implicit: response_matrix"
×
86
    call init_response_matrix
×
87
  end subroutine init_fields_implicit
88

89
  subroutine finish_fields_implicit
×
90
    if (allocated(M_class)) deallocate (M_class, N_class)
×
91
  end subroutine finish_fields_implicit
×
92

93
  !> Count the number of unique supercell sizes and setup the fields
94
  !> implicit arrays M_class and N_class.
95
  subroutine setup_fields_implicit_class_arrays(l_links, r_links, M_class, N_class, i_class)
×
96
    use kt_grids, only: naky, ntheta0
97
    use mp, only: mp_abort, iproc
98
    use sorting, only: quicksort
99
    implicit none
100
    integer, dimension(:, :), intent(in) :: l_links, r_links
101
    !> N_class(i) = number of linked cells for i_th class (Size of supercell)
102
    integer, dimension(:), allocatable, intent(out) :: N_class
103
    !> M_class(i) = number of members in i_th class (How many supercells of this size)
104
    integer, dimension(:), allocatable, intent(out) :: M_class
105
    !> i_class = number of classes (unique sizes of supercell)
106
    integer, intent(out) :: i_class
107
    integer, dimension(naky*ntheta0) :: n_k, N_class_full
×
108
    integer :: k, it, ik, i, j
109
    ! Now set up class arrays for the implicit fields
110

111
    ! First count number of linked cells for each (kx, ky)
112
    k = 1
×
113
    do ik = 1, naky
×
114
       do it = 1, ntheta0
×
115
          n_k(k) = 1 + l_links(it, ik) + r_links(it, ik)
×
116
          k = k + 1
×
117
       end do
118
    end do
119

120
    ! Count how many unique values of n_k there are.  This is the number
121
    ! of classes.
122

123
    ! Sort:
124
    call quicksort(naky*ntheta0, n_k)
×
125

126
    ! Then count how many unique values there are, storing
127
    ! each unique value as it is encountered.
128
    i_class = 1
×
129
    N_class_full(i_class) = n_k(1)
×
130
    do k = 2, naky*ntheta0
×
131
       if (n_k(k) == n_k(k-1)) cycle
×
132
       i_class = i_class + 1
×
133
       N_class_full(i_class) = n_k(k)
×
134
    end do
135

136
    ! Extract the unique sizes into N_class
137
    N_class = N_class_full(1:i_class)
×
138

139
    ! Allocate M
140
    allocate (M_class(i_class))
×
141

142
    !$OMP PARALLEL DO DEFAULT(none) &
143
    !$OMP PRIVATE(j) &
144
    !$OMP SHARED(i_class, M_class, n_k, N_class) &
145
    !$OMP SCHEDULE(static)
146
    do j = 1, i_class
×
147
       ! Note this assumes N_class(j) is an exact factor of count(n_k == N_class(j))
148
       ! but we have a consistency check for this later.
149
       M_class(j) = count(n_k == N_class(j)) / N_class(j)
×
150
    end do
151
    !$OMP END PARALLEL DO
152

153
    ! Check for consistency:
154

155
    ! j is number of linked cells in class structure
156
    j = 0
×
157
    do i = 1, i_class
×
158
       j = j + N_class(i)*M_class(i)
×
159
       ! Check that we have N_class which is a factor of the matching n_k
160
       if ( abs(M_class(i) - count(n_k == N_class(i)) / (1.0 * N_class(i))) &
×
161
            > 10 * epsilon(0.0)) then
×
162
          write(*,*) 'PE ',iproc,'number of instances of supercell size not ' // &
×
163
               'an integer times the size of supercell: M,N,n_N',&
×
164
               M_class(i), N_class(i), count(n_k == N_class(i))
×
165
          call mp_abort('Problem with connected BC fields implicit arrays.')
×
166
       end if
167
    end do
168

169
    if (j /= naky*ntheta0) then
×
170
       write(*,*) 'PE ',iproc,'has j= ',j,' k= ',naky*ntheta0,' : Stopping'
×
171
       call mp_abort('problem with connnected bc')
×
172
    end if
173
  end subroutine setup_fields_implicit_class_arrays
×
174
  
175
  !> FIXME : Add documentation  
176
  subroutine init_allfields_implicit(gf_lo)
×
177
    use fields_arrays, only: phi, apar, bpar, phinew, aparnew, bparnew
178
    use dist_fn_arrays, only: g, gnew
179
    use dist_fn, only: get_init_field
180
    use init_g, only: new_field_init
181
    use array_utils, only: copy
182
    use optionals, only: get_option_with_default
183
    implicit none
184

185
    logical, intent(in), optional :: gf_lo
186
    logical :: local_gf_lo
187

188
    local_gf_lo = get_option_with_default(gf_lo, .false.)
×
189

190
    ! MAB> new field init option ported from agk
191
    if(local_gf_lo) then
×
192
       call get_init_field (phinew, aparnew, bparnew, .true.)
×
193
       !AJ Note, we do not initialise phi, apar, and bpar here 
194
       !AJ as this is now done in fields_gf_local along with a 
195
       !AJ fields redistribute.
196
       call copy(gnew, g)
×
197
    else if (new_field_init) then
×
198
       call get_init_field (phinew, aparnew, bparnew)
×
199
       call copy(phinew, phi); call copy(aparnew, apar); call copy(bparnew, bpar)
×
200
       call copy(gnew, g)
×
201
    else
202
       call getfield (phinew, aparnew, bparnew)
×
203
       call copy(phinew, phi); call copy(aparnew, apar); call copy(bparnew, bpar)
×
204
    end if
205
    ! <MAB
206

207
  end subroutine init_allfields_implicit
×
208

209
  !> FIXME : Add documentation  
210
  subroutine get_field_vector (fl, phi, apar, bpar)
×
211
    use theta_grid, only: ntgrid
212
    use dist_fn, only: getfieldeq
213
    use dist_fn_arrays, only: fieldeq, fieldeqa, fieldeqp
214
    use run_parameters, only: has_phi, has_apar, has_bpar
215
    implicit none
216
    complex, dimension (-ntgrid:,:,:), intent (in) :: phi, apar, bpar
217
    complex, dimension (:,:,:), intent (out) :: fl
218
    integer :: istart, ifin
219

220
    call getfieldeq (phi, apar, bpar, fieldeq, fieldeqa, fieldeqp)
×
221

222
    ifin = 0
×
223

224
    if (has_phi) then
×
225
       istart = ifin + 1
×
226
       ifin = (istart-1) + 2*ntgrid+1
×
227
       fl(istart:ifin,:,:) = fieldeq
×
228
    end if
229

230
    if (has_apar) then
×
231
       istart = ifin + 1
×
232
       ifin = (istart-1) + 2*ntgrid+1
×
233
       fl(istart:ifin,:,:) = fieldeqa
×
234
    end if
235

236
    if (has_bpar) then
×
237
       istart = ifin + 1
×
238
       ifin = (istart-1) + 2*ntgrid+1
×
239
       fl(istart:ifin,:,:) = fieldeqp
×
240
    end if
241

242
  end subroutine get_field_vector
×
243

244
  !> FIXME : Add documentation  
245
  subroutine get_field_solution (u)
×
246
    use fields_arrays, only: phinew, aparnew, bparnew
247
    use theta_grid, only: ntgrid
248
    use kt_grids, only: naky, ntheta0
249
    use run_parameters, only: has_phi, has_apar, has_bpar
250
    use gs2_layouts, only: jf_lo, ij_idx
251
    implicit none
252
    complex, dimension (0:), intent (in) :: u
253
    integer :: ik, it, ifield, ll, lr
254

255
    ifield = 0
×
256

257
    if (has_phi) then
×
258
       ifield = ifield + 1
×
259
       do ik = 1, naky
×
260
          do it = 1, ntheta0
×
261
             ll = ij_idx (jf_lo, -ntgrid, ifield, ik, it)
×
262
             lr = ll + 2*ntgrid
×
263
             phinew(:,it,ik) = u(ll:lr)
×
264
          end do
265
       end do
266
    endif
267

268
    if (has_apar) then
×
269
       ifield = ifield + 1
×
270
       do ik = 1, naky
×
271
          do it = 1, ntheta0
×
272
             ll = ij_idx (jf_lo, -ntgrid, ifield, ik, it)
×
273
             lr = ll + 2*ntgrid
×
274
             aparnew(:,it,ik) = u(ll:lr)
×
275
          end do
276
       end do
277
    endif
278

279
    if (has_bpar) then
×
280
       ifield = ifield + 1
×
281
       do ik = 1, naky
×
282
          do it = 1, ntheta0
×
283
             ll = ij_idx (jf_lo, -ntgrid, ifield, ik, it)
×
284
             lr = ll + 2*ntgrid
×
285
             bparnew(:,it,ik) = u(ll:lr)
×
286
          end do
287
       end do
288
    endif
289

290
  end subroutine get_field_solution
×
291

292
  !> FIXME : Add documentation  
293
  subroutine getfield (phi, apar, bpar)
×
294
    use kt_grids, only: naky, ntheta0
295
    use gs2_layouts, only: f_lo, jf_lo
296
    use theta_grid, only: ntgrid
297
    use mp, only: sum_allreduce, allgatherv, iproc, nproc
298
    implicit none
299
    complex, dimension (-ntgrid:,:,:), intent (in) :: phi, apar, bpar
300
    complex, dimension (:,:,:), allocatable :: fl
×
301
    complex, dimension (:), allocatable :: u
×
302
    complex, dimension (:), allocatable :: u_small
×
303
    integer :: jflo, ik, it, nl, nr, i, m, n, dc
304

305
    allocate (fl(nidx, ntheta0, naky))
×
306

307
    !On first call to this routine setup the receive counts (recvcnts)
308
    !and displacement arrays (displs)
309
    if ((.not.allocated(recvcnts)).and.field_subgath) then
×
310
       allocate(recvcnts(nproc),displs(nproc)) !Note there's no matching deallocate
×
311
       do i=0,nproc-1
×
312
          displs(i+1)=MIN(i*jf_lo%blocksize,jf_lo%ulim_world+1) !This will assign a displacement outside the array for procs with no data
×
313
          recvcnts(i+1)=MIN(jf_lo%blocksize,jf_lo%ulim_world-displs(i+1)+1) !This ensures that we expect no data from procs without any
×
314
       enddo
315
    endif
316

317
    ! am*u = fl, Poisson's and Ampere's law, u is phi, apar, bpar 
318
    ! u = aminv*fl
319

320
    call get_field_vector (fl, phi, apar, bpar)
×
321

322
    !Initialise array, if not gathering then have to zero entire array
323
    if(field_subgath) then
×
324
       allocate(u_small(jf_lo%llim_proc:jf_lo%ulim_proc))
×
325
    else
326
       allocate(u_small(0:nidx*ntheta0*naky-1))
×
327
    endif
328
    u_small=0.
×
329

330
    !Should this really be to ulim_alloc instead?
331
    do jflo = jf_lo%llim_proc, jf_lo%ulim_proc
×
332
       
333
       !Class index
334
       i =  jf_lo%ij(jflo)
×
335
       
336
       !Class member index (i.e. which member of the class)
337
       m = jf_lo%mj(jflo)
×
338

339
       !Get ik index
340
       ik = f_lo(i)%ik(m,1)  ! For fixed i and m, ik does not change as n varies 
×
341

342
       !Get d(istributed) cell index
343
       dc =  jf_lo%dj(i,jflo)
×
344
       
345
       !Loop over cells in class (these are the 2pi domains in flux tube/box mode)
346
       do n = 1, N_class(i)
×
347
          
348
          !Get it index
349
          it = f_lo(i)%it(m,n)
×
350
          
351
          !Get extent of current cell in extended/ballooning space domain
352
          nl = 1 + nidx*(n-1)
×
353
          nr = nl + nidx - 1
×
354
          
355
          !Perform section of matrix vector multiplication
356
          u_small(jflo)=u_small(jflo)-sum(aminv(i)%dcell(dc)%supercell(nl:nr)*fl(:, it, ik)) 
×
357
          
358
       end do
359
    end do
360

361
    !Free memory
362
    deallocate (fl)
×
363

364
    !Gather/reduce the remaining data
365
    if(field_subgath) then
×
366
       allocate (u (0:nidx*ntheta0*naky-1))
×
367
       call allgatherv(u_small,recvcnts(iproc+1),u,recvcnts,displs)
×
368
       deallocate(u_small)
×
369
    else
370
       call sum_allreduce(u_small)
×
371
    endif
372

373
    !Reshape data into field arrays and free memory
374
    if(field_subgath)then
×
375
       call get_field_solution (u)
×
376
       deallocate(u)
×
377
    else
378
       call get_field_solution (u_small)
×
379
       deallocate(u_small)
×
380
    endif
381

382
  end subroutine getfield
×
383

384
  !> FIXME : Add documentation  
385
  subroutine advance_implicit (istep, remove_zonal_flows_switch)
×
386
    use run_parameters, only: reset
387
    use fields_arrays, only: phi, apar, bpar, phinew, aparnew, bparnew
388
    use fields_arrays, only: apar_ext, time_field, time_field_mpi
389
    use antenna, only: antenna_amplitudes, no_driver
390
    use dist_fn, only: timeadv, exb_shear, collisions_advance
391
    use dist_fn_arrays, only: g, gnew, kx_shift, theta0_shift
392
    use unit_tests, only: debug_message
393
    use job_manage, only: time_message
394
    use mp, only: get_mp_times
395
    use array_utils, only: copy
396
    implicit none
397
    integer, parameter :: diagnostics = 1
398
    real :: mp_total, mp_total_after
399
    integer, intent (in) :: istep
400
    logical, intent (in) :: remove_zonal_flows_switch
401

402
    !GGH NOTE: apar_ext is initialized in this call
403
    if(.not.no_driver) call antenna_amplitudes (apar_ext)
×
404
       
405
    if (allocated(kx_shift) .or. allocated(theta0_shift)) call exb_shear (gnew, phinew, aparnew, bparnew, istep) 
×
406
    
407
    call copy(gnew, g)
×
408
    call copy(phinew, phi); call copy(aparnew, apar); call copy(bparnew, bpar)
×
409
    
410
    call debug_message(4, 'fields_implicit::advance_implicit calling timeadv 1')
×
411
    call timeadv (phi, apar, bpar, phinew, aparnew, bparnew, istep)
×
412
    call debug_message(4, 'fields_implicit::advance_implicit called timeadv 1')
×
413
    if(reset) return !Return is resetting
×
414

415
    if(.not.no_driver) aparnew = aparnew + apar_ext 
×
416
    
417
    call debug_message(4, 'fields_implicit::advance_implicit calling getfield')
×
418

419
    call time_message(.false.,time_field,' Field Solver')
×
420
    call get_mp_times(total_time = mp_total)
×
421

422
    call getfield (phinew, aparnew, bparnew)
×
423

424
    phinew   = phinew  + phi
×
425
    aparnew  = aparnew + apar
×
426
    bparnew  = bparnew + bpar
×
427

428
    call time_message(.false.,time_field,' Field Solver')
×
429
    call get_mp_times(total_time = mp_total_after)
×
430
    time_field_mpi = time_field_mpi + (mp_total_after - mp_total)
×
431

432
    if (remove_zonal_flows_switch) call remove_zonal_flows
×
433
    
434
    call debug_message(4, 'fields_implicit::advance_implicit calling timeadv')
×
435
    call timeadv (phi, apar, bpar, phinew, aparnew, bparnew, istep, diagnostics)
×
436
    call debug_message(4, 'fields_implicit::advance_implicit called timeadv')
×
437

438
    ! Advance collisions, if separate from timeadv
439
    call collisions_advance (phi, bpar, phinew, aparnew, bparnew, diagnostics)
×
440

441
  end subroutine advance_implicit
442

443
  !> FIXME : Add documentation
444
  subroutine remove_zonal_flows
×
445
    use fields_arrays, only: phinew
446
    use theta_grid, only: ntgrid
447
    use kt_grids, only: ntheta0, naky
448
    implicit none
449
    complex, dimension(:,:,:), allocatable :: phi_avg
×
450

451
    allocate(phi_avg(-ntgrid:ntgrid,ntheta0,naky))
×
452
    ! fieldline_average_phi will calculate the field line average of phinew and
453
    ! put it into phi_avg, but only for ik = 1 (the last parameter of the call)
454
    call fieldline_average_phi(phinew, phi_avg, 1)
×
455
    phinew = phinew - phi_avg
×
456
    deallocate(phi_avg)
×
457
  end subroutine remove_zonal_flows
×
458

459
  !> This generates a field line average of phi_in and writes it to
460
  !> phi_average. If ik_only is supplied, it will only calculate the
461
  !> field line average for that ky, leaving the rest of phi_avg unchanged. EGH
462
  !>
463
  !> It replaces the routines fieldlineavgphi_loc and fieldlineavgphi_tot,
464
  !> in fields.f90, which I  think are defunct, as phi is always on every processor.
465
  !>
466
  !> @note This calculation is fairly generic so should perhaps be moved out into
467
  !> a more accessible module to allow reuse (or replaced with such a method).
468
  pure subroutine fieldline_average_phi (phi_in, phi_average, ik_only)
×
469
    use theta_grid, only: ntgrid, field_line_average
470
    use kt_grids, only: ntheta0, naky
471
    use optionals, only: get_option_with_default
472
    implicit none
473
    complex, dimension (-ntgrid:,:,:), intent (in) :: phi_in
474
    complex, dimension (-ntgrid:,:,:), intent (out) :: phi_average
475
    integer, intent (in), optional :: ik_only
476
    complex :: phi_avg_line
477
    integer :: it, ik, ik_only_actual
478

479
    ik_only_actual = get_option_with_default(ik_only, -1)
×
480

481
    if (ik_only_actual > 0) then
×
482
       phi_average = 0.
×
483
       do it = 1,ntheta0
×
484
          phi_avg_line = field_line_average(phi_in(:,it,ik_only_actual))
×
485
          phi_average(:, it, ik_only_actual) = phi_avg_line
×
486
       end do
487
    else
488
       do it = 1,ntheta0
×
489
          do ik = 1,naky
×
490
             phi_average(:, it, ik) = field_line_average(phi_in(:, it, ik))
×
491
          end do
492
       end do
493
    end if
494
  end subroutine fieldline_average_phi
×
495

496
  !> FIXME : Add documentation
497
  subroutine reset_init
×
498
    use gs2_layouts, only: finish_jfields_layouts
499
    ! finish_fields_layouts name conflicts with routine in 
500
    ! this module
501
    use gs2_layouts, only: gs2lo_ffl => finish_fields_layouts
502
    use unit_tests, only: debug_message
503
    implicit none
504
    integer :: i, j
505
    integer, parameter :: verbosity=3
506
    initialized = .false.
×
507

508
    call debug_message(verbosity, &
509
      'fields_implicit::reset_init starting')
×
510
    if (.not. allocated (aminv)) return
×
511
    do i = 1, size(aminv)
×
512
       if (.not. allocated (aminv(i)%dcell)) cycle
×
513
       do j = 1, size(aminv(i)%dcell)
×
514
          if (allocated (aminv(i)%dcell(j)%supercell)) &
×
515
               deallocate(aminv(i)%dcell(j)%supercell)
×
516
       end do
517
       if (allocated (aminv(i)%dcell)) deallocate (aminv(i)%dcell)
×
518
    end do
519
    deallocate (aminv)
×
520

521
    call gs2lo_ffl
×
522
    if (allocated(recvcnts)) deallocate(recvcnts, displs)
×
523

524
    call finish_jfields_layouts
×
525
  end subroutine reset_init
526

527
  !> FIXME : Add documentation  
528
  subroutine init_response_matrix
×
529
    use mp, only: barrier, land_allreduce, proc0, nproc, iproc
530
    use fields_arrays, only: phi, apar, bpar, phinew, aparnew, bparnew
531
    use theta_grid, only: ntgrid
532
    use kt_grids, only: naky, ntheta0
533
    use dist_fn_arrays, only: g
534
    use run_parameters, only: has_phi, has_apar, has_bpar
535
    use gs2_layouts, only: init_fields_layouts, f_lo
536
    use gs2_layouts, only: init_jfields_layouts
537
    use file_utils, only: error_unit
538
    use array_utils, only: zero_array
539
    implicit none
540
    integer :: ig, ifield, it, ik, i, m, n
541
    complex, dimension(:,:), allocatable :: am
×
542
    logical :: endpoint
543
    logical :: response_was_read
544

545
    nfield = 0
×
546
    if (has_phi) nfield = nfield + 1
×
547
    if (has_apar) nfield = nfield + 1
×
548
    if (has_bpar) nfield = nfield + 1
×
549
    nidx = (2*ntgrid+1)*nfield
×
550

551
    call init_fields_layouts (nfield, nidx, naky, ntheta0, M_class, N_class, i_class, nproc, iproc)
×
552
    call init_jfields_layouts (nfield, nidx, naky, ntheta0, i_class, nproc, iproc)
×
553
    call finish_fields_layouts
×
554

555
    response_was_read = .false.
×
556

557
    !Either read the reponse
558
    if(read_response) then
×
559
        call read_response_from_file_imp(could_read = response_was_read)
×
560

561
        ! Ensure we reduce response_was_read across all processors so if _any_
562
        ! processors couldn't read the matrices we recalculate on all processors.
563
        call land_allreduce(response_was_read)
×
564
        if((.not. response_was_read) .and. proc0) write(error_unit(), &
×
565
             '("Could not find response file so reverting to calculation.")')
×
566

567
      !elseif(skip_initialisation) then
568
       !do i = i_class, 1, -1
569
          !!Pretty sure this barrier is not needed
570
          !call barrier
571
          !!       if (proc0) write(*,*) 'beginning class ',i,' with size ',nidx*N_class(i)
572
          !!Allocate matrix am. First dimension is basically theta along the entire
573
          !!connected domain for each field. Second dimension is the local section
574
          !!of the M_class(i)*N_Class(i)*(2*ntgrid+1)*nfield compound domain.
575
          !!Clearly this will 
576
          !allocate (am(nidx*N_class(i), f_lo(i)%llim_proc:f_lo(i)%ulim_alloc))
577

578

579
          !!Do we need to zero all 8 arrays on every loop? This can be more expensive than might think.
580
          !am = 0.0
581
          !call init_inverse_matrix (am, i)
582

583
          !!Free memory
584
          !deallocate (am)
585
       !end do
586
     end if
587

588

589
     !or calculate it
590
     if (.not. response_was_read) then
×
591
!
592
! keep storage cost down by doing one class at a time
593
! Note: could define a superclass (of all classes), a structure containing all am,
594
! then do this all at once.  This would be faster, especially for large runs in a
595
! sheared domain, and could be triggered by local_field_solve
596
!
597

598
!<DD> Comments
599
!A class refers to a class of connected domain.
600
!These classes are defined by the extent of the connected domain, there can be 
601
!many members of each class.
602
!There are i_class classes in total.
603
!N_class(ic) is a count of how many 2pi domains there are in members of class ic
604
!M_class(ic) is how many members of class ic there are.
605
!Sum N_class(ic)*M_class(ic) for ic=1,i_class is naky*ntheta0
606
!In comments cell refers to a 2pi domain whilst supercell is the connected domain,
607
!i.e. we have classes of supercells based on the number of cells they contain.
608

609
       do i = i_class, 1, -1
×
610
          !Pretty sure this barrier is not needed
611
          call barrier
×
612
          !       if (proc0) write(*,*) 'beginning class ',i,' with size ',nidx*N_class(i)
613
          !Allocate matrix am. First dimension is basically theta along the entire
614
          !connected domain for each field. Second dimension is the local section
615
          !of the M_class(i)*N_Class(i)*(2*ntgrid+1)*nfield compound domain.
616
          !Clearly this will 
617
          allocate (am(nidx*N_class(i), f_lo(i)%llim_proc:f_lo(i)%ulim_alloc))
×
618

619

620
          !Do we need to zero all 8 arrays on every loop? This can be more expensive than might think.
621
          call zero_array(am)
×
622
          call zero_array(g)
×
623
          call zero_array(phi) ; call zero_array(phinew)
×
624
          call zero_array(apar) ; call zero_array(aparnew)
×
625
          call zero_array(bpar) ; call zero_array(bparnew)
×
626

627
          !Loop over individual 2pi domains / cells
628
          do n = 1, N_class(i)
×
629
             !Loop over theta grid points in cell
630
             !This is like a loop over nidx as we also handle all the fields in this loop
631
             do ig = -ntgrid, ntgrid
×
632
                !Are we at a connected boundary point on the lower side (i.e. left hand end of a
633
                !tube/cell connected to the left)
634
                endpoint = n > 1
×
635
                endpoint = ig == -ntgrid .and. endpoint
×
636

637
                !Start counting fields
638
                ifield = 0
×
639

640
                !Find response to phi
641
                if (has_phi) then
×
642
                   ifield = ifield + 1
×
643
                   if (endpoint) then
×
644
                      !Do all members of supercell together
645
                      do m = 1, M_class(i)
×
646
                         ik = f_lo(i)%ik(m,n-1)
×
647
                         it = f_lo(i)%it(m,n-1)
×
648
                         phinew(ntgrid,it,ik) = 1.0
×
649
                      end do
650
                   endif
651
                   !Do all members of supercell together
652
                   do m = 1, M_class(i)
×
653
                      ik = f_lo(i)%ik(m,n)
×
654
                      it = f_lo(i)%it(m,n)
×
655
                      phinew(ig,it,ik) = 1.0
×
656
                   end do
657
                   if (.not. skip_initialisation) call init_response_row (ig, ifield, am, i, n)
×
658
                   call zero_array(phinew)
×
659
                end if
660

661
                !Find response to apar
662
                if (has_apar) then
×
663
                   ifield = ifield + 1
×
664
                   if (endpoint) then
×
665
                      !Do all members of supercell together
666
                      do m = 1, M_class(i)
×
667
                         ik = f_lo(i)%ik(m,n-1)
×
668
                         it = f_lo(i)%it(m,n-1)
×
669
                         aparnew(ntgrid,it,ik) = 1.0
×
670
                      end do
671
                   endif
672
                   !Do all members of supercell together
673
                   do m = 1, M_class(i)
×
674
                      ik = f_lo(i)%ik(m,n)
×
675
                      it = f_lo(i)%it(m,n)
×
676
                      aparnew(ig,it,ik) = 1.0
×
677
                   end do
678
                   call init_response_row (ig, ifield, am, i, n)
×
679
                   call zero_array(aparnew)
×
680
                end if
681

682
                !Find response to bpar
683
                if (has_bpar) then
×
684
                   ifield = ifield + 1
×
685
                   if (endpoint) then
×
686
                      !Do all members of supercell together
687
                      do m = 1, M_class(i)
×
688
                         ik = f_lo(i)%ik(m,n-1)
×
689
                         it = f_lo(i)%it(m,n-1)
×
690
                         bparnew(ntgrid,it,ik) = 1.0
×
691
                      end do
692
                   endif
693
                   !Do all members of supercell together
694
                   do m = 1, M_class(i)
×
695
                      ik = f_lo(i)%ik(m,n)
×
696
                      it = f_lo(i)%it(m,n)
×
697
                      bparnew(ig,it,ik) = 1.0
×
698
                   end do
699
                   call init_response_row (ig, ifield, am, i, n)
×
700
                   call zero_array(bparnew)
×
701
                end if
702
             end do
703
          end do
704

705
          !Invert the matrix
706
          call init_inverse_matrix (am, i)
×
707

708
          !Free memory
709
          deallocate (am)
×
710

711
       end do
712
    endif 
713

714
    if(dump_response) call dump_response_to_file_imp
×
715
  end subroutine init_response_matrix
×
716

717
  !> FIXME : Add documentation  
718
  subroutine init_response_row (ig, ifield, am, ic, n)
×
719
    use fields_arrays, only: phi, apar, bpar, phinew, aparnew, bparnew
720
    use theta_grid, only: ntgrid
721
    use dist_fn, only: getfieldeq, timeadv
722
    use dist_fn_arrays, only: fieldeq, fieldeqa, fieldeqp
723
    use run_parameters, only: has_phi, has_apar, has_bpar
724
    use gs2_layouts, only: f_lo, idx, idx_local
725
    implicit none
726
    integer, intent (in) :: ig, ifield, ic, n
727
    complex, dimension(:,f_lo(ic)%llim_proc:), intent (in out) :: am
×
728
    integer :: irow, istart, iflo, ik, it, ifin, m, nn
729

730
    !Find response to delta function fields
731
    !NOTE:Timeadv will loop over all iglo even though only one ik
732
    !has any amplitude, this is quite a waste. Should ideally do all
733
    !ik at once
734
    !NOTE:We currently do each independent supercell of the same length
735
    !together, this may not be so easy if we do all the ik together but it should
736
    !be possible.
737
    call timeadv (phi, apar, bpar, phinew, aparnew, bparnew, 0)
×
738
    call getfieldeq (phinew, aparnew, bparnew, fieldeq, fieldeqa, fieldeqp)
×
739

740
    !Loop over 2pi domains / cells
741
    do nn = 1, N_class(ic)
×
742

743
       !Loop over members of the current class (separate supercells/connected domains)
744
       do m = 1, M_class(ic)
×
745

746
          !Get corresponding it and ik indices
747
          it = f_lo(ic)%it(m,nn)
×
748
          ik = f_lo(ic)%ik(m,nn)
×
749
       
750
          !Work out which row of the matrix we're looking at
751
          !corresponds to iindex, i.e. which of the nindex points in the
752
          !supercell we're looking at.
753
          irow = ifield + nfield*((ig+ntgrid) + (2*ntgrid+1)*(n-1))
×
754
          
755
          !Convert iindex and m to iflo index
756
          iflo = idx (f_lo(ic), irow, m)
×
757
          
758
          !If this is part of our local iflo range then store
759
          !the response data
760
          if (idx_local(f_lo(ic), iflo)) then
×
761
             !Where abouts in the supercell does this 2pi*nfield section start
762
             istart = 0 + nidx*(nn-1)
×
763
             
764
             if (has_phi) then
×
765
                ifin = istart + nidx
×
766
                istart = istart + 1
×
767
                am(istart:ifin:nfield,iflo) = fieldeq(:,it,ik) 
×
768
             end if
769
             
770
             if (has_apar) then
×
771
                ifin = istart + nidx
×
772
                istart = istart + 1
×
773
                am(istart:ifin:nfield,iflo) = fieldeqa(:,it,ik)
×
774
             end if
775
             
776
             if (has_bpar) then
×
777
                ifin = istart + nidx
×
778
                istart = istart + 1
×
779
                am(istart:ifin:nfield,iflo) = fieldeqp(:,it,ik)
×
780
             end if
781
             
782
          end if
783
                    
784
       end do
785
    end do
786

787
  end subroutine init_response_row
×
788

789
  !> FIXME : Add documentation  
790
  subroutine init_inverse_matrix (am, ic)
×
791
    use file_utils, only: error_unit
792
    use kt_grids, only: aky, akx
793
    use theta_grid, only: ntgrid
794
    use mp, only: broadcast, send, receive, iproc, get_mp_times
795
    use job_manage, only: time_message
796
    use fields_arrays, only: time_field_invert, time_field_invert_mpi
797
    use gs2_layouts, only: f_lo, idx, idx_local, proc_id, jf_lo, ig_idx, ifield_idx, ij_idx
798
    use gs2_layouts, only: if_idx, im_idx, in_idx, local_field_solve
799
    use array_utils, only: zero_array
800
    use warning_helpers, only: is_not_zero
801
    implicit none
802
    integer, intent (in) :: ic
803
    complex, dimension(:,f_lo(ic)%llim_proc:), intent (in out) :: am
×
804
    complex, dimension(:,:), allocatable :: a_inv, lhscol, rhsrow, col_row_tmp
×
805
    complex, dimension (:), allocatable :: am_tmp
×
806
    complex :: fac
807
    integer :: i, j, k, ik, it, m, n, nn, if, ig, jsc, jf, jg, jc
808
    integer :: irow, ilo, jlo, dc, iflo, ierr
809
    logical :: iskip, jskip
810
    real :: mp_total, mp_total_after
811

812
    call time_message(.false.,time_field_invert,' Field Matrix Invert')
×
813
    call get_mp_times(total_time = mp_total)
×
814
    
815
    allocate (lhscol (nidx*N_class(ic),M_class(ic)))
×
816
    allocate (rhsrow (nidx*N_class(ic),M_class(ic)))
×
817
   
818
    !This is the length of a supercell
819
    j = nidx*N_class(ic)
×
820

821
    !Create storage space
822
    allocate (a_inv(j,f_lo(ic)%llim_proc:f_lo(ic)%ulim_alloc))
×
823
    call zero_array(a_inv)
×
824
    
825
    if (.not. skip_initialisation) then
×
826
      !Set (ifield*ig,ilo) "diagonal" to 1?
827
      do ilo = f_lo(ic)%llim_proc, f_lo(ic)%ulim_proc
×
828
         a_inv(if_idx(f_lo(ic),ilo),ilo) = 1.0
×
829
      end do
830

831
      ! Gauss-Jordan elimination, leaving out internal points at multiples of ntgrid 
832
      ! for each supercell
833
      !Loop over parallel gridpoints in supercell
834
      do i = 1, nidx*N_class(ic)
×
835
         !iskip is true iff the theta grid point(ig) corresponding to i
836
         !is at the upper end of a 2pi domain/cell and is not the rightmost gridpoint
837
         iskip = N_class(ic) > 1 !Are the multiple cells => are there connections/boundaries
×
838
         iskip = i <= nidx*N_class(ic) - nfield .and. iskip !Are we not near the upper boundary of the supercell
×
839
         iskip = mod((i+nfield-1)/nfield, 2*ntgrid+1) == 0 .and. iskip !Are we at a theta grid point corresponding to the rightmost point of a 2pi domain
×
840
         iskip = i > nfield .and. iskip !Are we not at the lower boundary of the supercell
×
841
         if (iskip) cycle
×
842
   
843
         if (local_field_solve) then
×
844
            do m = 1, M_class(ic)
×
845
               ilo = idx(f_lo(ic),i,m)
×
846
               if (idx_local(f_lo(ic),ilo)) then
×
847
                  lhscol(:,m) = am(:,ilo)
×
848
                  rhsrow(:,m) = a_inv(:,ilo)
×
849
               end if
850
            end do
851
         else
852
            allocate(col_row_tmp(nidx*N_class(ic),2)) ; col_row_tmp = 0.
×
853
            !Loop over classes (supercell lengths)
854
            do m = 1, M_class(ic)
×
855
               !Convert to f_lo index
856
               ilo = idx(f_lo(ic),i,m)
×
857
               !Is ilo on this proc?
858
               if (idx_local(f_lo(ic),ilo)) then
×
859
                  !If so store column/row
860
                  !lhscol(:,m) = am(:,ilo)
861
                  !rhsrow(:,m) = a_inv(:,ilo)
862
                  col_row_tmp(:,1) = am(:,ilo)
×
863
                  col_row_tmp(:,2) = a_inv(:,ilo)
×
864
               end if
865
               !Here we send lhscol and rhscol sections to all procs
866
               !from the one on which it is currently known
867
               !Can't do this outside m loop as proc_id depends on m
868
               !These broadcasts can be relatively expensive so local_field_solve
869
               !may be preferable
870
               !call broadcast (lhscol(:,m), proc_id(f_lo(ic),ilo))
871
               !call broadcast (rhsrow(:,m), proc_id(f_lo(ic),ilo))
872
               call broadcast (col_row_tmp, proc_id(f_lo(ic),ilo))
×
873
               lhscol(:,m) = col_row_tmp(:,1)
×
874
               rhsrow(:,m) = col_row_tmp(:,2)
×
875
            end do
876
            !All procs will have the same lhscol and rhsrow after this loop+broadcast
877
            deallocate(col_row_tmp)
×
878
         end if
879

880
         !Loop over field compound dimension
881
         do jlo = f_lo(ic)%llim_proc, f_lo(ic)%ulim_proc
×
882
            !jskip is true similarly to iskip
883
            jskip = N_class(ic) > 1 !Are there any connections?
×
884
            jskip = ig_idx(f_lo(ic), jlo) == ntgrid .and. jskip !Are we at a theta grid point corresponding to the upper boundary?
×
885
            !Get 2pi domain/cell number out of total for this supercell
886
            n = in_idx(f_lo(ic),jlo)
×
887
            jskip = n < N_class(ic) .and. jskip !Are we not in the last cell (i.e. not at the rightmost grid point/upper end of supercell)?
×
888
            if (jskip) cycle  !Skip this point if appropriate
×
889

890
            !Now get m (class number)
891
            m = im_idx(f_lo(ic),jlo)
×
892

893
            !Convert class number and cell number to ik and it
894
            ik = f_lo(ic)%ik(m,n)
×
895
            it = f_lo(ic)%it(m,n)
×
896
            
897
            !Work out what the compound theta*field index is.
898
            irow = if_idx(f_lo(ic),jlo)
×
899

900
            !If ky or kx are not 0 (i.e. skip zonal 0,0 mode) then workout the array
901
            if (is_not_zero(aky(ik)) .or. is_not_zero(akx(it))) then
×
902
               !Get factor
903
               fac = am(i,jlo)/lhscol(i,m)
×
904

905
               !Store array element
906
               am(i,jlo) = fac
×
907

908
               !Store other elements
909
               am(:i-1,jlo) = am(:i-1,jlo) - lhscol(:i-1,m)*fac
×
910
               am(i+1:,jlo) = am(i+1:,jlo) - lhscol(i+1:,m)*fac
×
911
               !WOULD the above three commands be better written as
912
               !am(:,jlo)=am(:,jlo)-lhscol(:,m)*fac
913
               !am(i,jlo)=fac
914

915
               !Fill in a_inv
916
               if (irow == i) then
×
917
                  a_inv(:,jlo) = a_inv(:,jlo)/lhscol(i,m)
×
918
               else
919
                  a_inv(:,jlo) = a_inv(:,jlo) &
×
920
                       - rhsrow(:,m)*lhscol(irow,m)/lhscol(i,m)
×
921
               end if
922
            else
923
               a_inv(:,jlo) = 0.0
×
924
            end if
925
     
926
         end do
927
      end do
928

929
      !Free memory
930
      deallocate (lhscol, rhsrow)
×
931

932
  ! fill in skipped points for each field and supercell:
933
  ! Do not include internal ntgrid points in sum over supercell
934

935
      do i = 1, nidx*N_class(ic)
×
936
         !iskip is true iff the theta grid point(ig) corresponding to i
937
         !is at the upper end of a 2pi domain/cell and is not the rightmost gridpoint
938
         iskip = N_class(ic) > 1 !Are the multiple cells => are there connections/boundaries
×
939
         iskip = i <= nidx*N_class(ic) - nfield .and. iskip  !Are we not near the upper boundary of the supercell
×
940
         iskip = mod((i+nfield-1)/nfield, 2*ntgrid+1) == 0 .and. iskip !Are we at a theta grid point corresponding to the rightmost point of a 2pi domain
×
941
         iskip = i > nfield .and. iskip !Are we not at the lower boundary of the supercell
×
942
         !Zero out skipped points
943
         if (iskip) then
×
944
            a_inv(i,:) = 0
×
945
            cycle !Seems unnexessary
×
946
         end if
947
      end do
948
  ! Make response at internal ntgrid points identical to response
949
  ! at internal -ntgrid points:
950
      do jlo = f_lo(ic)%llim_world, f_lo(ic)%ulim_world
×
951
         !jskip is true similarly to iskip
952
         jskip = N_class(ic) > 1 !Are there any connections?
×
953
         jskip = ig_idx(f_lo(ic), jlo) == ntgrid .and. jskip  !Are we at a theta grid point corresponding to the upper boundary?
×
954
         jskip = in_idx(f_lo(ic), jlo) < N_class(ic) .and. jskip  !Are we not in the last cell (i.e. not at the rightmost grid point/upper end of supercell)?
×
955
         !If we previously skipped this point then we want to fill it in from the matched/connected point
956
         if (jskip) then
×
957
            !What is the index of the matched point?
958
            ilo = jlo + nfield
×
959
            !If we have ilo on this proc send it to...
960
            if (idx_local(f_lo(ic), ilo)) then
×
961
               !jlo on this proc
962
               if (idx_local(f_lo(ic), jlo)) then
×
963
                  a_inv(:,jlo) = a_inv(:,ilo)
×
964
               !jlo on proc which has jlo
965
               else
966
                  call send(a_inv(:,ilo), proc_id(f_lo(ic), jlo))
×
967
               endif
968
            else
969
               !If this proc has jlo then get ready to receive
970
               if (idx_local(f_lo(ic), jlo)) then
×
971
                  call receive(a_inv(:,jlo), proc_id(f_lo(ic), ilo))
×
972
               end if
973
            end if
974
         end if
975
      end do
976
      !The send receives in the above loop should be able to function in a
977
      !non-blocking manner fairly easily, but probably don't cost that much
978
      !Would require WAITALL before doing am=a_inv line below
979

980
      !Update am
981
      am = a_inv
×
982
    end if ! .not. skip_initialisation
983

984
    !Free memory
985
    deallocate (a_inv)
×
986

987
! Re-sort this class of aminv for runtime application.  
988

989
    !Now allocate array to store matrices for each class
990
    if (.not.allocated(aminv)) allocate (aminv(i_class))
×
991

992
! only need this large array for particular values of jlo.
993
! To save space, count how many this is and only allocate
994
! required space:
995

996
    !Initialise counter
997
    dc = 0
×
998
! check all members of this class
999
    do ilo = f_lo(ic)%llim_world, f_lo(ic)%ulim_world
×
1000

1001
! find supercell coordinates
1002
       !i.e. what is my class of supercell and which cell am I looking at
1003
       m = im_idx(f_lo(ic), ilo)
×
1004
       n = in_idx(f_lo(ic), ilo)
×
1005

1006
! find standard coordinates
1007
       !Get theta, field, kx and ky indexes for current point
1008
       ig = ig_idx(f_lo(ic), ilo)
×
1009
       if = ifield_idx(f_lo(ic), ilo)
×
1010
       ik = f_lo(ic)%ik(m,n)
×
1011
       it = f_lo(ic)%it(m,n)
×
1012

1013
! translate to fast field coordinates
1014
       jlo = ij_idx(jf_lo, ig, if, ik, it)
×
1015
          
1016
! Locate this jlo, count it, and save address
1017
       !Is this point on this proc, if so increment counter
1018
       if (idx_local(jf_lo,jlo)) then
×
1019
! count it
1020
          dc = dc + 1
×
1021
! save dcell address
1022
           jf_lo%dj(ic,jlo) = dc
×
1023
! save supercell address
1024
          jf_lo%mj(jlo) = m
×
1025
       endif
1026
          
1027
    end do
1028

1029
! allocate dcells and supercells in this class on this PE:
1030
    !Loop over "fast field" index
1031
    do jlo = jf_lo%llim_proc, jf_lo%ulim_proc
×
1032
          
1033
       !Allocate store in this class, on this proc to store the jlo points
1034
       if (.not. allocated(aminv(ic)%dcell)) then
×
1035
          allocate (aminv(ic)%dcell(dc))
×
1036
       else
1037
          !Just check the array is the correct size
1038
          j = size(aminv(ic)%dcell)
×
1039
          if (j /= dc) then
×
1040
             ierr = error_unit()
×
1041
             write(ierr,*) 'Error (1) in init_inverse_matrix: ',&
×
1042
                  iproc,':',jlo,':',dc,':',j
×
1043
          endif
1044
       endif
1045
       
1046
       !Get the current "dcell" adress
1047
       k = jf_lo%dj(ic,jlo)
×
1048

1049
       !No dcell should be 0 but this is a guard
1050
       if (k > 0) then
×
1051
          !How long is the supercell for this class?
1052
          jc = nidx*N_class(ic)
×
1053

1054
          !Allocate storage for the supercell if required
1055
          if (.not. allocated(aminv(ic)%dcell(k)%supercell)) then
×
1056
             allocate (aminv(ic)%dcell(k)%supercell(jc))
×
1057
          else
1058
             !Just check the array is the correct size
1059
             j = size(aminv(ic)%dcell(k)%supercell)
×
1060
             if (j /= jc) then
×
1061
                ierr = error_unit()
×
1062
                write(ierr,*) 'Error (2) in init_inverse_matrix: ', &
×
1063
                     iproc,':',jlo,':',jc,':',j
×
1064
             end if
1065
          end if
1066
       end if
1067
    end do
1068

1069
! Now fill aminv for this class:
1070

1071
    !Allocate temporary supercell storage
1072
    allocate (am_tmp(nidx*N_class(ic)))
×
1073

1074
    !Loop over all grid points
1075
    do ilo = f_lo(ic)%llim_world, f_lo(ic)%ulim_world
×
1076

1077
       !Get supercell type (class) and cell index
1078
       m = im_idx(f_lo(ic), ilo)
×
1079
       n = in_idx(f_lo(ic), ilo)
×
1080
       
1081
       !Convert to theta,field,kx and ky indexes
1082
       ig = ig_idx(f_lo(ic), ilo)
×
1083
       if = ifield_idx(f_lo(ic), ilo)
×
1084
       ik = f_lo(ic)%ik(m,n)
×
1085
       it = f_lo(ic)%it(m,n)
×
1086
       
1087
       !Get fast field index
1088
       iflo = ij_idx(jf_lo, ig, if, ik, it)
×
1089
 
1090
       !If this ilo is local then...
1091
       if (idx_local(f_lo(ic),ilo)) then
×
1092
          ! send the am data to...
1093
          if (idx_local(jf_lo,iflo)) then
×
1094
             !the local proc
1095
             am_tmp = am(:,ilo)
×
1096
          else
1097
             !the remote proc
1098
             call send(am(:,ilo), proc_id(jf_lo,iflo))
×
1099
          endif
1100
       else
1101
          !Get ready to receive the data
1102
          if (idx_local(jf_lo,iflo)) then
×
1103
             call receive(am_tmp, proc_id(f_lo(ic),ilo))
×
1104
          end if
1105
       end if
1106

1107
       !If the fast field index is on this processor
1108
       if (idx_local(jf_lo, iflo)) then
×
1109
          !Get "dcell" adress
1110
          dc = jf_lo%dj(ic,iflo)
×
1111

1112
          !Loop over supercell size
1113
          do jlo = 0, nidx*N_class(ic)-1
×
1114
             !Convert to cell/2pi domain index
1115
             nn = in_idx(f_lo(ic), jlo)
×
1116
             
1117
             !Get theta grid point
1118
             jg = ig_idx(f_lo(ic), jlo)
×
1119
             !Get field index
1120
             jf = ifield_idx(f_lo(ic), jlo)
×
1121
             
1122
             !Convert index
1123
             jsc = ij_idx(f_lo(ic), jg, jf, nn) + 1
×
1124

1125
             !Store inverse matrix data in appropriate supercell position
1126
             aminv(ic)%dcell(dc)%supercell(jsc) = am_tmp(jlo+1)
×
1127
             
1128
          end do
1129
       end if
1130
    end do
1131

1132
    !Free memory
1133
    deallocate (am_tmp)
×
1134

1135
    call time_message(.false.,time_field_invert,' Field Matrix Invert')
×
1136
    call get_mp_times(total_time = mp_total_after)
×
1137
    time_field_invert_mpi = time_field_invert_mpi + (mp_total_after - mp_total)
×
1138
  end subroutine init_inverse_matrix
×
1139

1140
  !> FIXME : Add documentation  
1141
  subroutine finish_fields_layouts
×
1142
    use dist_fn, only: has_linked_boundary
1143
    use kt_grids, only: naky, ntheta0, itright
1144
    use gs2_layouts, only: f_lo, jf_lo, ik_idx, it_idx
1145
    implicit none
1146
    integer :: i, m, n, ii, ik, it, itr, jflo
1147

1148
    if (has_linked_boundary()) then
×
1149

1150
! Complication comes from having to order the supercells in each class
1151
       do ii = 1, i_class
×
1152
          m = 1
×
1153
          do it = 1, ntheta0
×
1154
             do ik = 1, naky
×
1155
                call kt2ki (i, n, ik, it)
×
1156
                ! If (ik, it) is in this class, continue:
1157
                if (i == ii) then
×
1158
                   ! Find left end of links
1159
                   if (n == 1) then
×
1160
                      f_lo(i)%ik(m,n) = ik
×
1161
                      f_lo(i)%it(m,n) = it
×
1162
                      itr = it
×
1163
                      ! Follow links to the right
1164
                      do n = 2, N_class(i)
×
1165
                         itr = itright (itr, ik)
×
1166
                         f_lo(i)%ik(m,n) = ik
×
1167
                         f_lo(i)%it(m,n) = itr
×
1168
                      end do
1169
                      m = m + 1
×
1170
                   end if
1171
                end if
1172
             end do
1173
          end do
1174
       end do
1175
       
1176
    ! initialize ij matrix
1177
       
1178
       do jflo = jf_lo%llim_proc, jf_lo%ulim_proc
×
1179
          ik = ik_idx(jf_lo, jflo)
×
1180
          it = it_idx(jf_lo, jflo)
×
1181
          
1182
          call kt2ki ( jf_lo%ij(jflo), n, ik, it)
×
1183
          
1184
       end do
1185

1186
    else
1187
       m = 0
×
1188
       do it = 1, ntheta0
×
1189
          do ik = 1, naky
×
1190
             m = m + 1
×
1191
             f_lo(1)%ik(m,1) = ik
×
1192
             f_lo(1)%it(m,1) = it
×
1193
          end do
1194
       end do
1195
       
1196
        jf_lo%ij = 1
×
1197
    end if
1198

1199
  end subroutine finish_fields_layouts
×
1200

1201
  !> FIXME : Add documentation  
1202
  subroutine kt2ki (i, n, ik, it)
×
1203
    use mp, only: mp_abort
1204
    use file_utils, only: error_unit
1205
    use kt_grids, only: l_links, r_links
1206
    implicit none
1207
    integer, intent (in) :: ik, it
1208
    integer, intent (out) :: i, n
1209
    integer :: nn, ierr
1210
!
1211
! Get size of this supercell
1212
!
1213
    nn = 1 + l_links(it, ik) + r_links(it, ik)
×
1214
!
1215
! Find i = N_class**-1(nn)
1216
!
1217
    do i = 1, i_class
×
1218
       if (N_class(i) == nn) exit
×
1219
    end do
1220
!
1221
! Consistency check:
1222
!
1223
    if (N_class(i) /= nn) then
×
1224
       ierr = error_unit()
×
1225
       write(ierr,*) 'Error in kt2ki:'
×
1226
       write(ierr,*) 'i = ',i,' ik = ',ik,' it = ',it,&
×
1227
            ' N(i) = ',N_class(i),' nn = ',nn
×
1228
       call mp_abort('Error in kt2ki')
×
1229
    end if
1230
! 
1231
! Get position in this supercell, counting from the left
1232
!
1233
    n = 1 + l_links(it, ik)
×
1234

1235
  end subroutine kt2ki
×
1236

1237
  !> A routine to dump the current response matrix to file
1238
  subroutine dump_response_to_file_imp(suffix)
×
1239
    use fields_arrays, only: get_specific_response_file_name, time_dump_response
1240
    use gs2_time, only: code_dt
1241
    use theta_grid, only: ntgrid
1242
    use kt_grids, only: naky, ntheta0, itright, get_leftmost_it
1243
    use gs2_layouts, only: f_lo, jf_lo, ij_idx, idx_local, idx, proc_id,idx_local
1244
    use mp, only: proc0, send, receive
1245
    use gs2_save, only: gs2_save_response
1246
    use job_manage, only: time_message
1247
    implicit none
1248
    character(len=*), optional, intent(in) :: suffix !If passed then use as part of file suffix
1249
    complex, dimension(:,:), allocatable :: tmp_arr, tmp_arr_full
×
1250
    complex, dimension(:), allocatable :: tmp_vec_full, tmp_vec
×
1251
    integer :: ic, im, ik, it, itmin, supercell_length, supercell_length_bound, in, ifld, ig, is_tmp
1252
    integer :: jflo, dc, nn, in_tmp, icount, it_tmp, nl, nr, ifld_tmp, ext_dom_length, ig_tmp, cur_idx
1253
    integer, dimension(:,:), allocatable :: it_to_is, leftmost_it
×
1254
    integer, dimension(:), allocatable :: tmp_ints
×
1255
    logical :: is_local
1256
    call time_message(.false.,time_dump_response,' Field Dump')
×
1257

1258
    !Make a lookup array to convert itmin (the leftmost it in a connected domain)
1259
    !to the supercell index "is" used in the local fields. This will be used to 
1260
    !ensure equivalent files can be given the same name.
1261
    allocate(it_to_is(ntheta0,naky),leftmost_it(ntheta0,naky),tmp_ints(ntheta0))
×
1262
    it_to_is=0
×
1263
    !//Note the following code is mostly borrowed from fm_init in the local fields
1264
    
1265
    !First find all the leftmost it
1266
    do ik=1,naky
×
1267
       do it=1,ntheta0
×
1268
          leftmost_it(it,ik)=get_leftmost_it(it,ik)
×
1269
       enddo
1270
    enddo
1271

1272
    !Now find supercell ids for each ky at a time
1273
    do ik=1,naky
×
1274
       tmp_ints=leftmost_it(:,ik)
×
1275
       it_tmp=0
×
1276
       is_tmp=0
×
1277
       do while(sum(tmp_ints)/=-1*ntheta0)
×
1278
          it_tmp=it_tmp+1
×
1279
          cur_idx=tmp_ints(it_tmp)
×
1280

1281
          !If we've seen this domain skip
1282
          if(cur_idx==-1)cycle
×
1283

1284
          !Increment counter
1285
          is_tmp=is_tmp+1
×
1286

1287
          !Here we store the value
1288
          it_to_is(it_tmp,ik)=is_tmp
×
1289

1290
          !Now we set all other connected locations to -1
1291
          !and store the appropriate is value
1292
          do it=1,ntheta0
×
1293
             if(tmp_ints(it)==cur_idx) then
×
1294
                tmp_ints(it)=-1
×
1295
                it_to_is(it,ik)=is_tmp
×
1296
             endif
1297
          enddo
1298
       enddo
1299
    enddo
1300

1301
    !Cleanup
1302
    deallocate(tmp_ints)
×
1303

1304
    !/End of borrowed code
1305

1306
    !Notation recap:
1307
    ! A class refers to all independent domains with the same length
1308
    ! i_class is how many classes we have
1309
    ! N_class(i_class) is how many 2Pi domains are in each member of i_class
1310
    ! M_class(i_class) is how many independent domains are in i_class
1311

1312
    allocate(tmp_vec(nfield*(2*ntgrid+1)))
×
1313
    allocate(tmp_arr(1+(2*ntgrid),nfield))
×
1314

1315
    !Loop over classes (supercell length)
1316
    do ic=1,i_class
×
1317
       !Extended domain length
1318
       ext_dom_length=1+(2*ntgrid)*N_class(ic)
×
1319
       !Work out how long the supercell is
1320
       supercell_length=nfield*ext_dom_length !Without boundary points
×
1321
       supercell_length_bound=(1+2*ntgrid)*nfield*N_class(ic) !With boundary points
×
1322

1323
       !Make storage
1324
       allocate(tmp_arr_full(supercell_length,supercell_length))
×
1325
       allocate(tmp_vec_full(supercell_length))
×
1326

1327
       !Now loop over all members of this class
1328
       do im=1,M_class(ic)
×
1329
          !Now we are thinking about a single supercell
1330
          !we can get certain properties before looping
1331
          !over the individual elements
1332
          
1333
          !Get the ik index
1334
          ik=f_lo(ic)%ik(im,1)
×
1335

1336
          !Get the leftmost it index (named itmin to match local field routines)
1337
          !This is currently used to identify the supercell like "is" is used in
1338
          !the local field routines. It would be nice to also use "is" here (or
1339
          !"itmin" there).
1340
          itmin=leftmost_it(f_lo(ic)%it(im,1),ik)
×
1341
          
1342
          !Now we have the basic properties we want to loop over the elements
1343
          !First initialise "it"
1344
          it=itmin
×
1345

1346
          !Initialise counter
1347
          icount=1
×
1348

1349
          !The order of the field, cell and theta loops below is chosen
1350
          !in order to match the data layout of the fields local matrix
1351

1352
          !Loop over the fields
1353
          do ifld=1,nfield
×
1354

1355
             !Reinitialise "it" back to the start of the supercell chain
1356
             it=itmin
×
1357

1358
             !Loop over the different it (2Pi domains)
1359
             do in=1,N_class(ic)
×
1360
                !Loop over theta
1361
                do ig=-ntgrid,ntgrid
×
1362
                   !Skip the duplicate boundary points
1363
                   if((ig==ntgrid).and.(in/=N_class(ic))) cycle
×
1364

1365
                   !Convert to jf_lo index
1366
                   jflo=ij_idx(jf_lo,ig,ifld,ik,it)
×
1367

1368
                   !See if it's local
1369
                   is_local=idx_local(jf_lo,jflo)
×
1370

1371
                   !If it's not local then we have nothing to do
1372
                   !unless we're the proc who writes (proc0).
1373
                   if(.not.(is_local.or.proc0)) cycle
×
1374

1375
                   !Now pack tmp_vec and do communications if needed
1376
                   if(is_local)then
×
1377
                      !Get dcell index
1378
                      dc=jf_lo%dj(ic,jflo)
×
1379

1380
                      !Now we pack the tmp_vec in the correct order
1381
                      !whilst ignoring the repeated boundary points
1382
                      !We need to pick the value of "n" in the right order
1383
                      it_tmp=itmin
×
1384
                      do in_tmp=1,N_class(ic)
×
1385
                         !Pick the correct n
1386
                         do nn=1,N_class(ic)
×
1387
                            if(f_lo(ic)%it(im,nn)==it_tmp) exit
×
1388
                         enddo
1389

1390
                         !Now we can get supercell range (including boundaries)
1391
                         nl=1+nidx*(nn-1)
×
1392
                         nr=nl+nidx-1
×
1393
                         
1394
                         !Extract section
1395
                         tmp_vec=aminv(ic)%dcell(dc)%supercell(nl:nr)
×
1396

1397
                         !All that remains now is to ignore the boundary points
1398
                         !To do this we just split on the field so we can ignore
1399
                         !boundary if we want
1400
                         do ifld_tmp=1,nfield
×
1401
                            nl=1+(ifld_tmp-1)*(2*ntgrid+1)
×
1402
                            nr=nl+2*ntgrid
×
1403
                            tmp_arr(:,ifld_tmp)=tmp_vec(nl:nr)
×
1404
                         enddo
1405

1406
                         !Now we need to work out where to put things in tmp_vec_full
1407
                         !In doing this we try to match the local fields data layout
1408
                         !to aid comparisons
1409
                         do ifld_tmp=1,nfield
×
1410
                            do ig_tmp=1,2*ntgrid+1
×
1411
                               !Skip boundary points
1412
                               if((ig_tmp==(2*ntgrid+1)).and.(in_tmp/=N_class(ic))) cycle
×
1413

1414
                               !Get index
1415
                               cur_idx=ig_tmp+(2*ntgrid)*(in_tmp-1)+(ifld_tmp-1)*ext_dom_length
×
1416

1417
                               !Store data
1418
                               tmp_vec_full(cur_idx)=tmp_arr(ig_tmp,ifld_tmp)
×
1419
                            enddo
1420
                         enddo
1421

1422
                         !If we're not at the last cell then increment it_tmp.
1423
                         !This check is needed to avoid trying to access itright
1424
                         !in non-box simulations where this array is not allocated.
1425
                         if(in_tmp < N_class(ic)) then
×
1426
                            it_tmp=itright(it_tmp, ik)
×
1427
                         end if
1428

1429
                      enddo
1430

1431
                      !No comms needed if on proc0
1432
                      if(.not.proc0) call send(tmp_vec_full,0)
×
1433
                   else
1434
                      !Only proc0 should get here but test anyway
1435
                      if(proc0) call receive(tmp_vec_full,proc_id(jf_lo,jflo))
×
1436
                   endif
1437

1438
                   !Now we need to store in the full array
1439
                   !May need to check index order matches local case.
1440
                   if(proc0) then
×
1441
                      tmp_arr_full(:,icount)=tmp_vec_full
×
1442
                   endif
1443

1444
                   !Increment counter
1445
                   icount=icount+1
×
1446
                enddo
1447

1448
                !If we're not at the last cell then increment it.
1449
                !This check is needed to avoid trying to access itright
1450
                !in non-box simulations where this array is not allocated.
1451
                if(in < N_class(ic)) then
×
1452
                   it=itright(it, ik)
×
1453
                end if
1454
             enddo
1455
          enddo
1456

1457
          !Now make file name
1458
          if(proc0)then
×
1459
             call gs2_save_response(tmp_arr_full, get_specific_response_file_name(ik, it_to_is(itmin, ik), code_dt, suffix), code_dt)
×
1460
          endif
1461
       end do
1462
          
1463
       deallocate(tmp_arr_full,tmp_vec_full)
×
1464
    end do
1465

1466
    !Tidy
1467
    deallocate(tmp_vec,tmp_arr,leftmost_it,it_to_is)
×
1468
    call time_message(.false.,time_dump_response,' Field Dump')
×
1469
  end subroutine dump_response_to_file_imp
×
1470

1471
  !> A routine to read the response matrix from file and populate the implicit
1472
  !> response storage, note we also allocate the response storage objects
1473
  subroutine read_response_from_file_imp(could_read, suffix)
×
1474
    use fields_arrays, only: get_specific_response_file_name, time_read_response
1475
    use gs2_time, only: code_dt
1476
    use theta_grid, only: ntgrid
1477
    use kt_grids, only: naky, ntheta0, itright, get_leftmost_it
1478
    use gs2_layouts, only: f_lo, jf_lo, ij_idx, idx_local, idx, proc_id,idx_local
1479
    use mp, only: proc0, send, receive
1480
    use gs2_save, only: gs2_restore_response
1481
    use file_utils, only: error_unit
1482
    use job_manage, only: time_message
1483
    implicit none
1484
    logical, intent(out) :: could_read
1485
    character(len=*), optional, intent(in) :: suffix !If passed then use as part of file suffix
1486
    complex, dimension(:,:), allocatable :: tmp_arr, tmp_arr_full
×
1487
    complex, dimension(:), allocatable :: tmp_vec_full, tmp_vec
×
1488
    integer :: ic, im, ik, it, itmin, supercell_length, supercell_length_bound, in, ifld, ig, is_tmp
1489
    integer :: jflo, dc, nn, in_tmp, icount, it_tmp, nl, nr, ifld_tmp, ext_dom_length, ig_tmp, cur_idx
1490
    integer :: jflo_dup, dc_dup
1491
    integer, dimension(:,:), allocatable :: it_to_is, leftmost_it
×
1492
    integer, dimension(:), allocatable :: tmp_ints
×
1493
    logical :: is_local, is_local_dup
1494
    character(len = 256) :: file_name
1495
    logical :: file_found
1496
    real :: file_time_step
1497

1498
    call time_message(.false.,time_read_response,' Field Read')
×
1499
    could_read = .true.
×
1500

1501
    !First allocate the matrix storage
1502
    call alloc_response_objects
×
1503

1504
    !Make a lookup array to convert itmin (the leftmost it in a connected domain)
1505
    !to the supercell index "is" used in the local fields. This will be used to 
1506
    !ensure equivalent files can be given the same name.
1507
    allocate(it_to_is(ntheta0,naky),leftmost_it(ntheta0,naky),tmp_ints(ntheta0))
×
1508
    it_to_is=0
×
1509
    !//Note the following code is mostly borrowed from fm_init in the local fields
1510
    
1511
    !First find all the leftmost it
1512
    do ik=1,naky
×
1513
       do it=1,ntheta0
×
1514
          leftmost_it(it,ik)=get_leftmost_it(it,ik)
×
1515
       enddo
1516
    enddo
1517

1518
    !Now find supercell ids for each ky at a time
1519
    do ik=1,naky
×
1520
       tmp_ints=leftmost_it(:,ik)
×
1521
       it_tmp=0
×
1522
       is_tmp=0
×
1523
       do while(sum(tmp_ints)/=-1*ntheta0)
×
1524
          it_tmp=it_tmp+1
×
1525
          cur_idx=tmp_ints(it_tmp)
×
1526

1527
          !If we've seen this domain skip
1528
          if(cur_idx==-1)cycle
×
1529

1530
          !Increment counter
1531
          is_tmp=is_tmp+1
×
1532

1533
          !Here we store the value
1534
          it_to_is(it_tmp,ik)=is_tmp
×
1535

1536
          !Now we set all other connected locations to -1
1537
          !and store the appropriate is value
1538
          do it=1,ntheta0
×
1539
             if(tmp_ints(it)==cur_idx) then
×
1540
                tmp_ints(it)=-1
×
1541
                it_to_is(it,ik)=is_tmp
×
1542
             endif
1543
          enddo
1544
       enddo
1545
    enddo
1546

1547
    !Cleanup
1548
    deallocate(tmp_ints)
×
1549

1550
    !/End of borrowed code
1551

1552
    !Notation recap:
1553
    ! A class refers to all independent domains with the same length
1554
    ! i_class is how many classes we have
1555
    ! N_class(i_class) is how many 2Pi domains are in each member of i_class
1556
    ! M_class(i_class) is how many independent domains are in i_class
1557

1558
    allocate(tmp_vec(nfield*(2*ntgrid+1)))
×
1559
    allocate(tmp_arr(1+(2*ntgrid),nfield))
×
1560

1561
    !Loop over classes (supercell length)
1562
    do ic=1,i_class
×
1563
       !Extended domain length
1564
       ext_dom_length=1+(2*ntgrid)*N_class(ic)
×
1565
       !Work out how long the supercell is
1566
       supercell_length=nfield*ext_dom_length !Without boundary points
×
1567
       supercell_length_bound=(1+2*ntgrid)*nfield*N_class(ic) !With boundary points
×
1568

1569
       !Make storage
1570
       allocate(tmp_arr_full(supercell_length,supercell_length))
×
1571
       allocate(tmp_vec_full(supercell_length))
×
1572

1573
       !Now loop over all members of this class
1574
       do im=1,M_class(ic)
×
1575
          tmp_arr_full=0.
×
1576
          tmp_vec_full=0.
×
1577

1578
          !Now we are thinking about a single supercell
1579
          !we can get certain properties before looping
1580
          !over the individual elements
1581
          
1582
          !Get the ik index
1583
          ik=f_lo(ic)%ik(im,1)
×
1584

1585
          !Get the leftmost it index (named itmin to match local field routines)
1586
          !This is currently used to identify the supercell like "is" is used in
1587
          !the local field routines. It would be nice to also use "is" here (or
1588
          !"itmin" there).
1589
          itmin=leftmost_it(f_lo(ic)%it(im,1),ik)
×
1590
          
1591
          !Now make file name
1592
          file_name = adjustl(get_specific_response_file_name(ik, it_to_is(itmin, ik), code_dt, suffix))
×
1593

1594
          ! First check if the expected file exists, if not then exit
1595
          inquire( file = trim(file_name), exist = file_found)
×
1596
          if (.not. file_found) then
×
1597
             if(proc0) write(error_unit(), &
×
1598
                  '("Could not find response file ",A,", reverting to calculation.")') trim(file_name)
×
1599
             could_read = .false.
×
1600
             return
×
1601
          end if
1602

1603
          if(proc0)then
×
1604
             call gs2_restore_response(tmp_arr_full, file_name, file_time_step)
×
1605
             ! Should perhaps double check that file_time_step == code_dt?
1606
          endif
1607

1608
          !Initialise counter
1609
          icount=1
×
1610

1611
          !Loop over the fields
1612
          do ifld=1,nfield
×
1613
             !Reinitialise "it" back to the start of the supercell chain
1614
             it=itmin
×
1615

1616
             !Loop over the different it (2Pi domains)
1617
             do in=1,N_class(ic)
×
1618
                !Loop over theta
1619
                do ig=-ntgrid,ntgrid
×
1620
                   !Skip the duplicate boundary points -- This is no good here. !<DD>
1621
!                   if((ig.eq.ntgrid).and.(in.ne.N_class(ic))) cycle
1622

1623
                   !Convert to jf_lo index
1624
                   jflo=ij_idx(jf_lo,ig,ifld,ik,it)
×
1625

1626
                   !See if it's local
1627
                   is_local=idx_local(jf_lo,jflo)
×
1628

1629
                   !If it's not local then we have nothing to do
1630
                   !unless we're the proc who writes (proc0).
1631
                   if(.not.(is_local.or.proc0)) cycle
×
1632

1633
                   !Get row
1634
                   if(proc0)then
×
1635
                      tmp_vec_full=tmp_arr_full(:,icount)
×
1636
                      
1637
                      !Increment counter
1638
                      if(.not.(ig==ntgrid.and.in/=N_Class(ic))) icount=icount+1
×
1639
                   endif
1640

1641
                   !Now unpack tmp_vec_full and do communications if needed
1642
                   if(is_local)then
×
1643
                      !No comms needed if local
1644
                      if(.not.proc0) call receive(tmp_vec_full,0)
×
1645

1646
                      !Get dcell index
1647
                      dc=jf_lo%dj(ic,jflo)
×
1648

1649
                      !Now we pack the tmp_vec in the correct order
1650
                      !We must fill in the boundary points
1651
                      !We need to pick the value of "n" in the right order
1652
                      it_tmp=itmin
×
1653
                      do in_tmp=1,N_class(ic)
×
1654
                         tmp_arr=0
×
1655
                         tmp_vec=0
×
1656

1657
                         !Now we need to work out where to put things in tmp_vec_full
1658
                         !In doing this we try to match the local fields data layout
1659
                         !to aid comparisons
1660
                         do ifld_tmp=1,nfield
×
1661
                            do ig_tmp=1,2*ntgrid+1
×
1662
                               !Skip boundary points
1663
                               if((ig_tmp==(2*ntgrid+1)).and.(in_tmp/=N_class(ic))) cycle
×
1664

1665
                               !Get index
1666
                               cur_idx=ig_tmp+(2*ntgrid)*(in_tmp-1)+(ifld_tmp-1)*ext_dom_length
×
1667

1668
                               !Store data
1669
                               tmp_arr(ig_tmp,ifld_tmp)=tmp_vec_full(cur_idx)
×
1670
                            enddo
1671
                         enddo
1672

1673
                         !<DD>It may be anticipated that we need to fix the boundary points
1674
                         !here but we don't actually need to do anything.
1675
                         !Because we sum over the entire supercell in getfield we only want
1676
                         !the repeated boundary point to be included once.
1677
                         !We still need to calculate the field at the repeated point but the
1678
                         !fix for that is handled at the bottom of the routine
1679
                         !In other words we don't need something of the form:
1680
                         ! !Fix boundary points
1681
                         ! if(in_tmp.ne.N_class(ic))then
1682
                         !    do ifld_tmp=1,nfield
1683
                         !       cur_idx=1+(2*ntgrid)*(in_tmp)+(ifld_tmp-1)*ext_dom_length
1684
                         !       tmp_arr(2*ntgrid+1,ifld_tmp)=tmp_vec_full(cur_idx)
1685
                         !    enddo
1686
                         ! endif
1687

1688
                         !Store in correct order
1689
                         do ifld_tmp=1,nfield
×
1690
                            nl=1+(ifld_tmp-1)*(2*ntgrid+1)
×
1691
                            nr=nl+2*ntgrid
×
1692
                            tmp_vec(nl:nr)=tmp_arr(:,ifld_tmp)
×
1693
                         enddo
1694

1695
                         !Pick the correct n
1696
                         do nn=1,N_class(ic)
×
1697
                            if(f_lo(ic)%it(im,nn)==it_tmp) exit
×
1698
                         enddo
1699

1700
                         !Now we can get supercell range (including boundaries)
1701
                         nl=1+nidx*(nn-1)
×
1702
                         nr=nl+nidx-1
×
1703

1704
                         !Store section
1705
                         aminv(ic)%dcell(dc)%supercell(nl:nr)=tmp_vec
×
1706

1707
                         !If we're not at the last cell then increment it_tmp.
1708
                         !This check is needed to avoid trying to access itright
1709
                         !in non-box simulations where this array is not allocated.
1710
                         if(in_tmp < N_class(ic)) then
×
1711
                            it_tmp=itright(it_tmp, ik)
×
1712
                         end if
1713

1714
                      enddo
1715
                   else
1716
                      !Only proc0 should get here but test anyway
1717
                      if(proc0) call send(tmp_vec_full,proc_id(jf_lo,jflo))
×
1718
                   endif
1719
                enddo
1720

1721
                !If we're not at the last cell then increment it.
1722
                !This check is needed to avoid trying to access itright
1723
                !in non-box simulations where this array is not allocated.
1724
                if(in < N_class(ic)) then
×
1725
                   it=itright(it, ik)
×
1726
                end if
1727
             enddo
1728
          enddo
1729

1730
          !Now we need to fill in the repeated boundary points
1731

1732
          !If there are no boundary points then advance
1733
          if(N_class(ic)==1) cycle
×
1734
          it=itmin
×
1735
          do in=1,N_class(ic)-1
×
1736
             do ifld=1,nfield
×
1737
                !First get the index of the point we want to fill
1738
                jflo=ij_idx(jf_lo,ntgrid,ifld,ik,it)
×
1739

1740
                !Now we get the index of the point which has this data
1741
                jflo_dup=ij_idx(jf_lo,-ntgrid,ifld,ik,itright(it, ik))
×
1742

1743
                !Now get locality
1744
                is_local=idx_local(jf_lo,jflo)
×
1745
                is_local_dup=idx_local(jf_lo,jflo_dup)
×
1746

1747
                !Get dcell values
1748
                if(is_local) dc=jf_lo%dj(ic,jflo)
×
1749
                if(is_local_dup) dc_dup=jf_lo%dj(ic,jflo_dup)
×
1750

1751
                !Now copy/communicate
1752
                if(is_local)then
×
1753
                   if(is_local_dup)then
×
1754
                      aminv(ic)%dcell(dc)%supercell=aminv(ic)%dcell(dc_dup)%supercell
×
1755
                   else
1756
                      call receive(aminv(ic)%dcell(dc)%supercell,proc_id(jf_lo,jflo_dup))
×
1757
                   endif
1758
                elseif(is_local_dup)then
×
1759
                   call send(aminv(ic)%dcell(dc_dup)%supercell,proc_id(jf_lo,jflo))
×
1760
                endif
1761
             enddo
1762

1763
             !Increment it -- note we don't need to guard against access to itright
1764
             !here as for non-box runs we won't enter the outer in=1,N_class(ic)-1
1765
             !loop as N_class(ic) == 1
1766
             it=itright(it,ik)
×
1767
          enddo
1768
       end do
1769
       
1770
       !Free
1771
       deallocate(tmp_arr_full,tmp_vec_full)
×
1772
    end do
1773

1774
    !Tidy
1775
    deallocate(tmp_vec,tmp_arr,leftmost_it,it_to_is)
×
1776
    call time_message(.false.,time_read_response,' Field Read')
×
1777
  end subroutine read_response_from_file_imp
×
1778

1779
  !> A subroutine to allocate the response matrix storage objects
1780
  subroutine alloc_response_objects
×
1781
    use gs2_layouts, only: jf_lo, f_lo, im_idx, in_idx, ig_idx, ifield_idx, ij_idx, idx_local
1782
    use theta_grid, only: ntgrid
1783
    implicit none
1784
    integer :: ic, idc, sc_len, ilo, dc, im, in, ig, ifld, ik, it, jlo
1785

1786
    !Top level, one object for each class (length of supercell)
1787
    if(.not.allocated(aminv)) allocate(aminv(i_class))
×
1788

1789
    !Loop over each class
1790
    do ic=1,i_class
×
1791
       !Get the supercell length
1792
       sc_len=(2*ntgrid+1)*nfield*N_class(ic)
×
1793

1794
       !Count how many dcell we have locally and fill related data
1795
       dc=0
×
1796
       do ilo=f_lo(ic)%llim_world,f_lo(ic)%ulim_world
×
1797
          !i.e. what is my class of supercell and which cell am I looking at
1798
          im = im_idx(f_lo(ic), ilo)
×
1799
          in = in_idx(f_lo(ic), ilo)
×
1800

1801
          ! find standard coordinates
1802
          !Get theta, field, kx and ky indexes for current point
1803
          ig = ig_idx(f_lo(ic), ilo)
×
1804
          ifld = ifield_idx(f_lo(ic), ilo)
×
1805
          ik = f_lo(ic)%ik(im,in)
×
1806
          it = f_lo(ic)%it(im,in)
×
1807
          
1808
          ! translate to fast field coordinates
1809
          jlo = ij_idx(jf_lo, ig, ifld, ik, it)
×
1810
          
1811
          ! Locate this jlo, count it, and save address
1812
          !Is this point on this proc, if so increment counter
1813
          if (idx_local(jf_lo,jlo)) then
×
1814
             ! count it
1815
             dc = dc + 1
×
1816
             ! save dcell address
1817
             jf_lo%dj(ic,jlo) = dc
×
1818
             ! save supercell address
1819
             jf_lo%mj(jlo) = im
×
1820
          endif
1821
       enddo
1822

1823
       !Next level, one object for each point in the class
1824
       if(.not. allocated(aminv(ic)%dcell))then
×
1825
          allocate(aminv(ic)%dcell(dc))
×
1826
       endif
1827

1828
       !Now loop over each point and allocate storage for the response data
1829
       do idc=1,dc
×
1830
          !Bottom level, this is actually where data is stored
1831
          if(.not. allocated(aminv(ic)%dcell(idc)%supercell)) then
×
1832
             allocate(aminv(ic)%dcell(idc)%supercell(sc_len))
×
1833
          endif
1834
       enddo
1835
    enddo
1836

1837
  end subroutine alloc_response_objects
×
1838
end module fields_implicit
×
1839

×
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