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

gyrokinetics / gs2 / 1821477209

16 May 2025 02:50PM UTC coverage: 8.139% (+0.2%) from 7.92%
1821477209

push

gitlab-ci

David Dickinson
Merged in bugfix/use_uv_in_coverage_test_to_install_packages (pull request #1142)

3704 of 45511 relevant lines covered (8.14%)

122643.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 antenna, only: init_antenna
66
    use theta_grid, only: init_theta_grid
67
    use kt_grids, only: init_kt_grids, l_links, r_links
68
    use gs2_layouts, only: init_gs2_layouts
69
    use run_parameters, only: has_phi, has_apar, has_bpar
70
    use unit_tests, only: should_print
71
    use mp, only: mp_abort
72
    implicit none
73
    logical :: debug
74

75
    if (initialized) return
×
76
    initialized = .true.
×
77

78
    debug = should_print(3)
×
79

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

87
    if (debug) write(6,*) "init_fields_implicit: gs2_layouts"
×
88
    call init_gs2_layouts
×
89
    if (debug) write(6,*) "init_fields_implicit: theta_grid"
×
90
    call init_theta_grid
×
91
    if (debug) write(6,*) "init_fields_implicit: kt_grids"
×
92
    call init_kt_grids
×
93
    call setup_fields_implicit_class_arrays(l_links, r_links, M_class, N_class, i_class)
×
94
    if (debug) write(6,*) "init_fields_implicit: response_matrix"
×
95
    call init_response_matrix
×
96
    if (debug) write(6,*) "init_fields_implicit: antenna"
×
97
    call init_antenna
×
98
  end subroutine init_fields_implicit
99

100
  subroutine finish_fields_implicit
×
101
    if (allocated(M_class)) deallocate (M_class, N_class)
×
102
  end subroutine finish_fields_implicit
×
103

104
  !> Count the number of unique supercell sizes and setup the fields
105
  !> implicit arrays M_class and N_class.
106
  subroutine setup_fields_implicit_class_arrays(l_links, r_links, M_class, N_class, i_class)
×
107
    use kt_grids, only: naky, ntheta0
108
    use mp, only: mp_abort, iproc
109
    use sorting, only: quicksort
110
    implicit none
111
    integer, dimension(:, :), intent(in) :: l_links, r_links
112
    !> N_class(i) = number of linked cells for i_th class (Size of supercell)
113
    integer, dimension(:), allocatable, intent(out) :: N_class
114
    !> M_class(i) = number of members in i_th class (How many supercells of this size)
115
    integer, dimension(:), allocatable, intent(out) :: M_class
116
    !> i_class = number of classes (unique sizes of supercell)
117
    integer, intent(out) :: i_class
118
    integer, dimension(naky*ntheta0) :: n_k, N_class_full
×
119
    integer :: k, it, ik, i, j
120
    ! Now set up class arrays for the implicit fields
121

122
    ! First count number of linked cells for each (kx, ky)
123
    k = 1
×
124
    do ik = 1, naky
×
125
       do it = 1, ntheta0
×
126
          n_k(k) = 1 + l_links(it, ik) + r_links(it, ik)
×
127
          k = k + 1
×
128
       end do
129
    end do
130

131
    ! Count how many unique values of n_k there are.  This is the number
132
    ! of classes.
133

134
    ! Sort:
135
    call quicksort(naky*ntheta0, n_k)
×
136

137
    ! Then count how many unique values there are, storing
138
    ! each unique value as it is encountered.
139
    i_class = 1
×
140
    N_class_full(i_class) = n_k(1)
×
141
    do k = 2, naky*ntheta0
×
142
       if (n_k(k) == n_k(k-1)) cycle
×
143
       i_class = i_class + 1
×
144
       N_class_full(i_class) = n_k(k)
×
145
    end do
146

147
    ! Extract the unique sizes into N_class
148
    N_class = N_class_full(1:i_class)
×
149

150
    ! Allocate M
151
    allocate (M_class(i_class))
×
152

153
    !$OMP PARALLEL DO DEFAULT(none) &
154
    !$OMP PRIVATE(j) &
155
    !$OMP SHARED(i_class, M_class, n_k, N_class) &
156
    !$OMP SCHEDULE(static)
157
    do j = 1, i_class
×
158
       ! Note this assumes N_class(j) is an exact factor of count(n_k == N_class(j))
159
       ! but we have a consistency check for this later.
160
       M_class(j) = count(n_k == N_class(j)) / N_class(j)
×
161
    end do
162
    !$OMP END PARALLEL DO
163

164
    ! Check for consistency:
165

166
    ! j is number of linked cells in class structure
167
    j = 0
×
168
    do i = 1, i_class
×
169
       j = j + N_class(i)*M_class(i)
×
170
       ! Check that we have N_class which is a factor of the matching n_k
171
       if ( abs(M_class(i) - count(n_k == N_class(i)) / (1.0 * N_class(i))) &
×
172
            > 10 * epsilon(0.0)) then
×
173
          write(*,*) 'PE ',iproc,'number of instances of supercell size not ' // &
×
174
               'an integer times the size of supercell: M,N,n_N',&
×
175
               M_class(i), N_class(i), count(n_k == N_class(i))
×
176
          call mp_abort('Problem with connected BC fields implicit arrays.')
×
177
       end if
178
    end do
179

180
    if (j /= naky*ntheta0) then
×
181
       write(*,*) 'PE ',iproc,'has j= ',j,' k= ',naky*ntheta0,' : Stopping'
×
182
       call mp_abort('problem with connnected bc')
×
183
    end if
184
  end subroutine setup_fields_implicit_class_arrays
×
185
  
186
  !> FIXME : Add documentation  
187
  subroutine init_allfields_implicit(gf_lo)
×
188
    use fields_arrays, only: phi, apar, bpar, phinew, aparnew, bparnew
189
    use dist_fn_arrays, only: g, gnew
190
    use dist_fn, only: get_init_field
191
    use init_g, only: new_field_init
192
    use array_utils, only: copy
193
    use optionals, only: get_option_with_default
194
    implicit none
195

196
    logical, intent(in), optional :: gf_lo
197
    logical :: local_gf_lo
198

199
    local_gf_lo = get_option_with_default(gf_lo, .false.)
×
200

201
    ! MAB> new field init option ported from agk
202
    if(local_gf_lo) then
×
203
       call get_init_field (phinew, aparnew, bparnew, .true.)
×
204
       !AJ Note, we do not initialise phi, apar, and bpar here 
205
       !AJ as this is now done in fields_gf_local along with a 
206
       !AJ fields redistribute.
207
       call copy(gnew, g)
×
208
    else if (new_field_init) then
×
209
       call get_init_field (phinew, aparnew, bparnew)
×
210
       call copy(phinew, phi); call copy(aparnew, apar); call copy(bparnew, bpar)
×
211
       call copy(gnew, g)
×
212
    else
213
       call getfield (phinew, aparnew, bparnew)
×
214
       call copy(phinew, phi); call copy(aparnew, apar); call copy(bparnew, bpar)
×
215
    end if
216
    ! <MAB
217

218
  end subroutine init_allfields_implicit
×
219

220
  !> FIXME : Add documentation  
221
  subroutine get_field_vector (fl, phi, apar, bpar)
×
222
    use theta_grid, only: ntgrid
223
    use dist_fn, only: getfieldeq
224
    use dist_fn_arrays, only: fieldeq, fieldeqa, fieldeqp
225
    use run_parameters, only: has_phi, has_apar, has_bpar
226
    implicit none
227
    complex, dimension (-ntgrid:,:,:), intent (in) :: phi, apar, bpar
228
    complex, dimension (:,:,:), intent (out) :: fl
229
    integer :: istart, ifin
230

231
    call getfieldeq (phi, apar, bpar, fieldeq, fieldeqa, fieldeqp)
×
232

233
    ifin = 0
×
234

235
    if (has_phi) then
×
236
       istart = ifin + 1
×
237
       ifin = (istart-1) + 2*ntgrid+1
×
238
       fl(istart:ifin,:,:) = fieldeq
×
239
    end if
240

241
    if (has_apar) then
×
242
       istart = ifin + 1
×
243
       ifin = (istart-1) + 2*ntgrid+1
×
244
       fl(istart:ifin,:,:) = fieldeqa
×
245
    end if
246

247
    if (has_bpar) then
×
248
       istart = ifin + 1
×
249
       ifin = (istart-1) + 2*ntgrid+1
×
250
       fl(istart:ifin,:,:) = fieldeqp
×
251
    end if
252

253
  end subroutine get_field_vector
×
254

255
  !> FIXME : Add documentation  
256
  subroutine get_field_solution (u)
×
257
    use fields_arrays, only: phinew, aparnew, bparnew
258
    use theta_grid, only: ntgrid
259
    use kt_grids, only: naky, ntheta0
260
    use run_parameters, only: has_phi, has_apar, has_bpar
261
    use gs2_layouts, only: jf_lo, ij_idx
262
    implicit none
263
    complex, dimension (0:), intent (in) :: u
264
    integer :: ik, it, ifield, ll, lr
265

266
    ifield = 0
×
267

268
    if (has_phi) 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
             phinew(:,it,ik) = u(ll:lr)
×
275
          end do
276
       end do
277
    endif
278

279
    if (has_apar) 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
             aparnew(:,it,ik) = u(ll:lr)
×
286
          end do
287
       end do
288
    endif
289

290
    if (has_bpar) then
×
291
       ifield = ifield + 1
×
292
       do ik = 1, naky
×
293
          do it = 1, ntheta0
×
294
             ll = ij_idx (jf_lo, -ntgrid, ifield, ik, it)
×
295
             lr = ll + 2*ntgrid
×
296
             bparnew(:,it,ik) = u(ll:lr)
×
297
          end do
298
       end do
299
    endif
300

301
  end subroutine get_field_solution
×
302

303
  !> FIXME : Add documentation  
304
  subroutine getfield (phi, apar, bpar)
×
305
    use kt_grids, only: naky, ntheta0
306
    use gs2_layouts, only: f_lo, jf_lo
307
    use theta_grid, only: ntgrid
308
    use mp, only: sum_allreduce, allgatherv, iproc, nproc
309
    implicit none
310
    complex, dimension (-ntgrid:,:,:), intent (in) :: phi, apar, bpar
311
    complex, dimension (:,:,:), allocatable :: fl
×
312
    complex, dimension (:), allocatable :: u
×
313
    complex, dimension (:), allocatable :: u_small
×
314
    integer :: jflo, ik, it, nl, nr, i, m, n, dc
315

316
    allocate (fl(nidx, ntheta0, naky))
×
317

318
    !On first call to this routine setup the receive counts (recvcnts)
319
    !and displacement arrays (displs)
320
    if ((.not.allocated(recvcnts)).and.field_subgath) then
×
321
       allocate(recvcnts(nproc),displs(nproc)) !Note there's no matching deallocate
×
322
       do i=0,nproc-1
×
323
          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
×
324
          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
×
325
       enddo
326
    endif
327

328
    ! am*u = fl, Poisson's and Ampere's law, u is phi, apar, bpar 
329
    ! u = aminv*fl
330

331
    call get_field_vector (fl, phi, apar, bpar)
×
332

333
    !Initialise array, if not gathering then have to zero entire array
334
    if(field_subgath) then
×
335
       allocate(u_small(jf_lo%llim_proc:jf_lo%ulim_proc))
×
336
    else
337
       allocate(u_small(0:nidx*ntheta0*naky-1))
×
338
    endif
339
    u_small=0.
×
340

341
    !Should this really be to ulim_alloc instead?
342
    do jflo = jf_lo%llim_proc, jf_lo%ulim_proc
×
343
       
344
       !Class index
345
       i =  jf_lo%ij(jflo)
×
346
       
347
       !Class member index (i.e. which member of the class)
348
       m = jf_lo%mj(jflo)
×
349

350
       !Get ik index
351
       ik = f_lo(i)%ik(m,1)  ! For fixed i and m, ik does not change as n varies 
×
352

353
       !Get d(istributed) cell index
354
       dc =  jf_lo%dj(i,jflo)
×
355
       
356
       !Loop over cells in class (these are the 2pi domains in flux tube/box mode)
357
       do n = 1, N_class(i)
×
358
          
359
          !Get it index
360
          it = f_lo(i)%it(m,n)
×
361
          
362
          !Get extent of current cell in extended/ballooning space domain
363
          nl = 1 + nidx*(n-1)
×
364
          nr = nl + nidx - 1
×
365
          
366
          !Perform section of matrix vector multiplication
367
          u_small(jflo)=u_small(jflo)-sum(aminv(i)%dcell(dc)%supercell(nl:nr)*fl(:, it, ik)) 
×
368
          
369
       end do
370
    end do
371

372
    !Free memory
373
    deallocate (fl)
×
374

375
    !Gather/reduce the remaining data
376
    if(field_subgath) then
×
377
       allocate (u (0:nidx*ntheta0*naky-1))
×
378
       call allgatherv(u_small,recvcnts(iproc+1),u,recvcnts,displs)
×
379
       deallocate(u_small)
×
380
    else
381
       call sum_allreduce(u_small)
×
382
    endif
383

384
    !Reshape data into field arrays and free memory
385
    if(field_subgath)then
×
386
       call get_field_solution (u)
×
387
       deallocate(u)
×
388
    else
389
       call get_field_solution (u_small)
×
390
       deallocate(u_small)
×
391
    endif
392

393
  end subroutine getfield
×
394

395
  !> FIXME : Add documentation  
396
  subroutine advance_implicit (istep, remove_zonal_flows_switch)
×
397
    use run_parameters, only: reset
398
    use fields_arrays, only: phi, apar, bpar, phinew, aparnew, bparnew
399
    use fields_arrays, only: apar_ext, time_field, time_field_mpi
400
    use antenna, only: antenna_amplitudes, no_driver
401
    use dist_fn, only: timeadv, exb_shear, collisions_advance
402
    use dist_fn_arrays, only: g, gnew, kx_shift, theta0_shift
403
    use unit_tests, only: debug_message
404
    use job_manage, only: time_message
405
    use mp, only: get_mp_times
406
    use array_utils, only: copy
407
    implicit none
408
    integer, parameter :: diagnostics = 1
409
    real :: mp_total, mp_total_after
410
    integer, intent (in) :: istep
411
    logical, intent (in) :: remove_zonal_flows_switch
412

413
    !GGH NOTE: apar_ext is initialized in this call
414
    if(.not.no_driver) call antenna_amplitudes (apar_ext)
×
415
       
416
    if (allocated(kx_shift) .or. allocated(theta0_shift)) call exb_shear (gnew, phinew, aparnew, bparnew, istep) 
×
417
    
418
    call copy(gnew, g)
×
419
    call copy(phinew, phi); call copy(aparnew, apar); call copy(bparnew, bpar)
×
420
    
421
    call debug_message(4, 'fields_implicit::advance_implicit calling timeadv 1')
×
422
    call timeadv (phi, apar, bpar, phinew, aparnew, bparnew, istep)
×
423
    call debug_message(4, 'fields_implicit::advance_implicit called timeadv 1')
×
424
    if(reset) return !Return is resetting
×
425

426
    if(.not.no_driver) aparnew = aparnew + apar_ext 
×
427
    
428
    call debug_message(4, 'fields_implicit::advance_implicit calling getfield')
×
429

430
    call time_message(.false.,time_field,' Field Solver')
×
431
    call get_mp_times(total_time = mp_total)
×
432

433
    call getfield (phinew, aparnew, bparnew)
×
434

435
    phinew   = phinew  + phi
×
436
    aparnew  = aparnew + apar
×
437
    bparnew  = bparnew + bpar
×
438

439
    call time_message(.false.,time_field,' Field Solver')
×
440
    call get_mp_times(total_time = mp_total_after)
×
441
    time_field_mpi = time_field_mpi + (mp_total_after - mp_total)
×
442

443
    if (remove_zonal_flows_switch) call remove_zonal_flows
×
444
    
445
    call debug_message(4, 'fields_implicit::advance_implicit calling timeadv')
×
446
    call timeadv (phi, apar, bpar, phinew, aparnew, bparnew, istep, diagnostics)
×
447
    call debug_message(4, 'fields_implicit::advance_implicit called timeadv')
×
448

449
    ! Advance collisions, if separate from timeadv
450
    call collisions_advance (phi, bpar, phinew, aparnew, bparnew, diagnostics)
×
451

452
  end subroutine advance_implicit
453

454
  !> FIXME : Add documentation
455
  subroutine remove_zonal_flows
×
456
    use fields_arrays, only: phinew
457
    use theta_grid, only: ntgrid
458
    use kt_grids, only: ntheta0, naky
459
    implicit none
460
    complex, dimension(:,:,:), allocatable :: phi_avg
×
461

462
    allocate(phi_avg(-ntgrid:ntgrid,ntheta0,naky))
×
463
    ! fieldline_average_phi will calculate the field line average of phinew and
464
    ! put it into phi_avg, but only for ik = 1 (the last parameter of the call)
465
    call fieldline_average_phi(phinew, phi_avg, 1)
×
466
    phinew = phinew - phi_avg
×
467
    deallocate(phi_avg)
×
468
  end subroutine remove_zonal_flows
×
469

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

490
    ik_only_actual = get_option_with_default(ik_only, -1)
×
491

492
    if (ik_only_actual > 0) then
×
493
       phi_average = 0.
×
494
       do it = 1,ntheta0
×
495
          phi_avg_line = field_line_average(phi_in(:,it,ik_only_actual))
×
496
          phi_average(:, it, ik_only_actual) = phi_avg_line
×
497
       end do
498
    else
499
       do it = 1,ntheta0
×
500
          do ik = 1,naky
×
501
             phi_average(:, it, ik) = field_line_average(phi_in(:, it, ik))
×
502
          end do
503
       end do
504
    end if
505

506
  end subroutine fieldline_average_phi
×
507

508
  !> FIXME : Add documentation
509
  subroutine reset_init
×
510
    use gs2_layouts, only: finish_jfields_layouts
511
    ! finish_fields_layouts name conflicts with routine in 
512
    ! this module
513
    use gs2_layouts, only: gs2lo_ffl => finish_fields_layouts
514
    use unit_tests, only: debug_message
515
    implicit none
516
    integer :: i, j
517
    integer, parameter :: verbosity=3
518
    initialized = .false.
×
519

520
    call debug_message(verbosity, &
521
      'fields_implicit::reset_init starting')
×
522
    if (.not. allocated (aminv)) return
×
523
    do i = 1, size(aminv)
×
524
       if (.not. allocated (aminv(i)%dcell)) cycle
×
525
       do j = 1, size(aminv(i)%dcell)
×
526
          if (allocated (aminv(i)%dcell(j)%supercell)) &
×
527
               deallocate(aminv(i)%dcell(j)%supercell)
×
528
       end do
529
       if (allocated (aminv(i)%dcell)) deallocate (aminv(i)%dcell)
×
530
    end do
531
    deallocate (aminv)
×
532

533
    call gs2lo_ffl
×
534
    if (allocated(recvcnts)) deallocate(recvcnts, displs)
×
535

536
    call finish_jfields_layouts
×
537
  end subroutine reset_init
538

539
  !> FIXME : Add documentation  
540
  subroutine init_response_matrix
×
541
    use mp, only: barrier, land_allreduce, proc0, nproc, iproc
542
    use fields_arrays, only: phi, apar, bpar, phinew, aparnew, bparnew
543
    use theta_grid, only: ntgrid
544
    use kt_grids, only: naky, ntheta0
545
    use dist_fn_arrays, only: g
546
    use run_parameters, only: has_phi, has_apar, has_bpar
547
    use gs2_layouts, only: init_fields_layouts, f_lo
548
    use gs2_layouts, only: init_jfields_layouts
549
    use file_utils, only: error_unit
550
    use array_utils, only: zero_array
551
    implicit none
552
    integer :: ig, ifield, it, ik, i, m, n
553
    complex, dimension(:,:), allocatable :: am
×
554
    logical :: endpoint
555
    logical :: response_was_read
556

557
    nfield = 0
×
558
    if (has_phi) nfield = nfield + 1
×
559
    if (has_apar) nfield = nfield + 1
×
560
    if (has_bpar) nfield = nfield + 1
×
561
    nidx = (2*ntgrid+1)*nfield
×
562

563
    call init_fields_layouts (nfield, nidx, naky, ntheta0, M_class, N_class, i_class, nproc, iproc)
×
564
    call init_jfields_layouts (nfield, nidx, naky, ntheta0, i_class, nproc, iproc)
×
565
    call finish_fields_layouts
×
566

567
    response_was_read = .false.
×
568

569
    !Either read the reponse
570
    if(read_response) then
×
571
        call read_response_from_file_imp(could_read = response_was_read)
×
572

573
        ! Ensure we reduce response_was_read across all processors so if _any_
574
        ! processors couldn't read the matrices we recalculate on all processors.
575
        call land_allreduce(response_was_read)
×
576
        if((.not. response_was_read) .and. proc0) write(error_unit(), &
×
577
             '("Could not find response file so reverting to calculation.")')
×
578

579
      !elseif(skip_initialisation) then
580
       !do i = i_class, 1, -1
581
          !!Pretty sure this barrier is not needed
582
          !call barrier
583
          !!       if (proc0) write(*,*) 'beginning class ',i,' with size ',nidx*N_class(i)
584
          !!Allocate matrix am. First dimension is basically theta along the entire
585
          !!connected domain for each field. Second dimension is the local section
586
          !!of the M_class(i)*N_Class(i)*(2*ntgrid+1)*nfield compound domain.
587
          !!Clearly this will 
588
          !allocate (am(nidx*N_class(i), f_lo(i)%llim_proc:f_lo(i)%ulim_alloc))
589

590

591
          !!Do we need to zero all 8 arrays on every loop? This can be more expensive than might think.
592
          !am = 0.0
593
          !call init_inverse_matrix (am, i)
594

595
          !!Free memory
596
          !deallocate (am)
597
       !end do
598
     end if
599

600

601
     !or calculate it
602
     if (.not. response_was_read) then
×
603
!
604
! keep storage cost down by doing one class at a time
605
! Note: could define a superclass (of all classes), a structure containing all am,
606
! then do this all at once.  This would be faster, especially for large runs in a
607
! sheared domain, and could be triggered by local_field_solve
608
!
609

610
!<DD> Comments
611
!A class refers to a class of connected domain.
612
!These classes are defined by the extent of the connected domain, there can be 
613
!many members of each class.
614
!There are i_class classes in total.
615
!N_class(ic) is a count of how many 2pi domains there are in members of class ic
616
!M_class(ic) is how many members of class ic there are.
617
!Sum N_class(ic)*M_class(ic) for ic=1,i_class is naky*ntheta0
618
!In comments cell refers to a 2pi domain whilst supercell is the connected domain,
619
!i.e. we have classes of supercells based on the number of cells they contain.
620

621
       do i = i_class, 1, -1
×
622
          !Pretty sure this barrier is not needed
623
          call barrier
×
624
          !       if (proc0) write(*,*) 'beginning class ',i,' with size ',nidx*N_class(i)
625
          !Allocate matrix am. First dimension is basically theta along the entire
626
          !connected domain for each field. Second dimension is the local section
627
          !of the M_class(i)*N_Class(i)*(2*ntgrid+1)*nfield compound domain.
628
          !Clearly this will 
629
          allocate (am(nidx*N_class(i), f_lo(i)%llim_proc:f_lo(i)%ulim_alloc))
×
630

631

632
          !Do we need to zero all 8 arrays on every loop? This can be more expensive than might think.
633
          call zero_array(am)
×
634
          call zero_array(g)
×
635
          call zero_array(phi) ; call zero_array(phinew)
×
636
          call zero_array(apar) ; call zero_array(aparnew)
×
637
          call zero_array(bpar) ; call zero_array(bparnew)
×
638

639
          !Loop over individual 2pi domains / cells
640
          do n = 1, N_class(i)
×
641
             !Loop over theta grid points in cell
642
             !This is like a loop over nidx as we also handle all the fields in this loop
643
             do ig = -ntgrid, ntgrid
×
644
                !Are we at a connected boundary point on the lower side (i.e. left hand end of a
645
                !tube/cell connected to the left)
646
                endpoint = n > 1
×
647
                endpoint = ig == -ntgrid .and. endpoint
×
648

649
                !Start counting fields
650
                ifield = 0
×
651

652
                !Find response to phi
653
                if (has_phi) then
×
654
                   ifield = ifield + 1
×
655
                   if (endpoint) then
×
656
                      !Do all members of supercell together
657
                      do m = 1, M_class(i)
×
658
                         ik = f_lo(i)%ik(m,n-1)
×
659
                         it = f_lo(i)%it(m,n-1)
×
660
                         phinew(ntgrid,it,ik) = 1.0
×
661
                      end do
662
                   endif
663
                   !Do all members of supercell together
664
                   do m = 1, M_class(i)
×
665
                      ik = f_lo(i)%ik(m,n)
×
666
                      it = f_lo(i)%it(m,n)
×
667
                      phinew(ig,it,ik) = 1.0
×
668
                   end do
669
                   if (.not. skip_initialisation) call init_response_row (ig, ifield, am, i, n)
×
670
                   call zero_array(phinew)
×
671
                end if
672

673
                !Find response to apar
674
                if (has_apar) then
×
675
                   ifield = ifield + 1
×
676
                   if (endpoint) then
×
677
                      !Do all members of supercell together
678
                      do m = 1, M_class(i)
×
679
                         ik = f_lo(i)%ik(m,n-1)
×
680
                         it = f_lo(i)%it(m,n-1)
×
681
                         aparnew(ntgrid,it,ik) = 1.0
×
682
                      end do
683
                   endif
684
                   !Do all members of supercell together
685
                   do m = 1, M_class(i)
×
686
                      ik = f_lo(i)%ik(m,n)
×
687
                      it = f_lo(i)%it(m,n)
×
688
                      aparnew(ig,it,ik) = 1.0
×
689
                   end do
690
                   call init_response_row (ig, ifield, am, i, n)
×
691
                   call zero_array(aparnew)
×
692
                end if
693

694
                !Find response to bpar
695
                if (has_bpar) then
×
696
                   ifield = ifield + 1
×
697
                   if (endpoint) then
×
698
                      !Do all members of supercell together
699
                      do m = 1, M_class(i)
×
700
                         ik = f_lo(i)%ik(m,n-1)
×
701
                         it = f_lo(i)%it(m,n-1)
×
702
                         bparnew(ntgrid,it,ik) = 1.0
×
703
                      end do
704
                   endif
705
                   !Do all members of supercell together
706
                   do m = 1, M_class(i)
×
707
                      ik = f_lo(i)%ik(m,n)
×
708
                      it = f_lo(i)%it(m,n)
×
709
                      bparnew(ig,it,ik) = 1.0
×
710
                   end do
711
                   call init_response_row (ig, ifield, am, i, n)
×
712
                   call zero_array(bparnew)
×
713
                end if
714
             end do
715
          end do
716

717
          !Invert the matrix
718
          call init_inverse_matrix (am, i)
×
719

720
          !Free memory
721
          deallocate (am)
×
722

723
       end do
724
    endif 
725

726
    if(dump_response) call dump_response_to_file_imp
×
727
  end subroutine init_response_matrix
×
728

729
  !> FIXME : Add documentation  
730
  subroutine init_response_row (ig, ifield, am, ic, n)
×
731
    use fields_arrays, only: phi, apar, bpar, phinew, aparnew, bparnew
732
    use theta_grid, only: ntgrid
733
    use dist_fn, only: getfieldeq, timeadv
734
    use dist_fn_arrays, only: fieldeq, fieldeqa, fieldeqp
735
    use run_parameters, only: has_phi, has_apar, has_bpar
736
    use gs2_layouts, only: f_lo, idx, idx_local
737
    implicit none
738
    integer, intent (in) :: ig, ifield, ic, n
739
    complex, dimension(:,f_lo(ic)%llim_proc:), intent (in out) :: am
×
740
    integer :: irow, istart, iflo, ik, it, ifin, m, nn
741

742
    !Find response to delta function fields
743
    !NOTE:Timeadv will loop over all iglo even though only one ik
744
    !has any amplitude, this is quite a waste. Should ideally do all
745
    !ik at once
746
    !NOTE:We currently do each independent supercell of the same length
747
    !together, this may not be so easy if we do all the ik together but it should
748
    !be possible.
749
    call timeadv (phi, apar, bpar, phinew, aparnew, bparnew, 0)
×
750
    call getfieldeq (phinew, aparnew, bparnew, fieldeq, fieldeqa, fieldeqp)
×
751

752
    !Loop over 2pi domains / cells
753
    do nn = 1, N_class(ic)
×
754

755
       !Loop over members of the current class (separate supercells/connected domains)
756
       do m = 1, M_class(ic)
×
757

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

799
  end subroutine init_response_row
×
800

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

824
    call time_message(.false.,time_field_invert,' Field Matrix Invert')
×
825
    call get_mp_times(total_time = mp_total)
×
826
    
827
    allocate (lhscol (nidx*N_class(ic),M_class(ic)))
×
828
    allocate (rhsrow (nidx*N_class(ic),M_class(ic)))
×
829
   
830
    !This is the length of a supercell
831
    j = nidx*N_class(ic)
×
832

833
    !Create storage space
834
    allocate (a_inv(j,f_lo(ic)%llim_proc:f_lo(ic)%ulim_alloc))
×
835
    call zero_array(a_inv)
×
836
    
837
    if (.not. skip_initialisation) then
×
838
      !Set (ifield*ig,ilo) "diagonal" to 1?
839
      do ilo = f_lo(ic)%llim_proc, f_lo(ic)%ulim_proc
×
840
         a_inv(if_idx(f_lo(ic),ilo),ilo) = 1.0
×
841
      end do
842

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

892
         !Loop over field compound dimension
893
         do jlo = f_lo(ic)%llim_proc, f_lo(ic)%ulim_proc
×
894
            !jskip is true similarly to iskip
895
            jskip = N_class(ic) > 1 !Are there any connections?
×
896
            jskip = ig_idx(f_lo(ic), jlo) == ntgrid .and. jskip !Are we at a theta grid point corresponding to the upper boundary?
×
897
            !Get 2pi domain/cell number out of total for this supercell
898
            n = in_idx(f_lo(ic),jlo)
×
899
            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)?
×
900
            if (jskip) cycle  !Skip this point if appropriate
×
901

902
            !Now get m (class number)
903
            m = im_idx(f_lo(ic),jlo)
×
904

905
            !Convert class number and cell number to ik and it
906
            ik = f_lo(ic)%ik(m,n)
×
907
            it = f_lo(ic)%it(m,n)
×
908
            
909
            !Work out what the compound theta*field index is.
910
            irow = if_idx(f_lo(ic),jlo)
×
911

912
            !If ky or kx are not 0 (i.e. skip zonal 0,0 mode) then workout the array
913
            if (is_not_zero(aky(ik)) .or. is_not_zero(akx(it))) then
×
914
               !Get factor
915
               fac = am(i,jlo)/lhscol(i,m)
×
916

917
               !Store array element
918
               am(i,jlo) = fac
×
919

920
               !Store other elements
921
               am(:i-1,jlo) = am(:i-1,jlo) - lhscol(:i-1,m)*fac
×
922
               am(i+1:,jlo) = am(i+1:,jlo) - lhscol(i+1:,m)*fac
×
923
               !WOULD the above three commands be better written as
924
               !am(:,jlo)=am(:,jlo)-lhscol(:,m)*fac
925
               !am(i,jlo)=fac
926

927
               !Fill in a_inv
928
               if (irow == i) then
×
929
                  a_inv(:,jlo) = a_inv(:,jlo)/lhscol(i,m)
×
930
               else
931
                  a_inv(:,jlo) = a_inv(:,jlo) &
×
932
                       - rhsrow(:,m)*lhscol(irow,m)/lhscol(i,m)
×
933
               end if
934
            else
935
               a_inv(:,jlo) = 0.0
×
936
            end if
937
     
938
         end do
939
      end do
940

941
      !Free memory
942
      deallocate (lhscol, rhsrow)
×
943

944
  ! fill in skipped points for each field and supercell:
945
  ! Do not include internal ntgrid points in sum over supercell
946

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

992
      !Update am
993
      am = a_inv
×
994
    end if ! .not. skip_initialisation
995

996
    !Free memory
997
    deallocate (a_inv)
×
998

999
! Re-sort this class of aminv for runtime application.  
1000

1001
    !Now allocate array to store matrices for each class
1002
    if (.not.allocated(aminv)) allocate (aminv(i_class))
×
1003

1004
! only need this large array for particular values of jlo.
1005
! To save space, count how many this is and only allocate
1006
! required space:
1007

1008
    !Initialise counter
1009
    dc = 0
×
1010
! check all members of this class
1011
    do ilo = f_lo(ic)%llim_world, f_lo(ic)%ulim_world
×
1012

1013
! find supercell coordinates
1014
       !i.e. what is my class of supercell and which cell am I looking at
1015
       m = im_idx(f_lo(ic), ilo)
×
1016
       n = in_idx(f_lo(ic), ilo)
×
1017

1018
! find standard coordinates
1019
       !Get theta, field, kx and ky indexes for current point
1020
       ig = ig_idx(f_lo(ic), ilo)
×
1021
       if = ifield_idx(f_lo(ic), ilo)
×
1022
       ik = f_lo(ic)%ik(m,n)
×
1023
       it = f_lo(ic)%it(m,n)
×
1024

1025
! translate to fast field coordinates
1026
       jlo = ij_idx(jf_lo, ig, if, ik, it)
×
1027
          
1028
! Locate this jlo, count it, and save address
1029
       !Is this point on this proc, if so increment counter
1030
       if (idx_local(jf_lo,jlo)) then
×
1031
! count it
1032
          dc = dc + 1
×
1033
! save dcell address
1034
           jf_lo%dj(ic,jlo) = dc
×
1035
! save supercell address
1036
          jf_lo%mj(jlo) = m
×
1037
       endif
1038
          
1039
    end do
1040

1041
! allocate dcells and supercells in this class on this PE:
1042
    !Loop over "fast field" index
1043
    do jlo = jf_lo%llim_proc, jf_lo%ulim_proc
×
1044
          
1045
       !Allocate store in this class, on this proc to store the jlo points
1046
       if (.not. allocated(aminv(ic)%dcell)) then
×
1047
          allocate (aminv(ic)%dcell(dc))
×
1048
       else
1049
          !Just check the array is the correct size
1050
          j = size(aminv(ic)%dcell)
×
1051
          if (j /= dc) then
×
1052
             ierr = error_unit()
×
1053
             write(ierr,*) 'Error (1) in init_inverse_matrix: ',&
×
1054
                  iproc,':',jlo,':',dc,':',j
×
1055
          endif
1056
       endif
1057
       
1058
       !Get the current "dcell" adress
1059
       k = jf_lo%dj(ic,jlo)
×
1060

1061
       !No dcell should be 0 but this is a guard
1062
       if (k > 0) then
×
1063
          !How long is the supercell for this class?
1064
          jc = nidx*N_class(ic)
×
1065

1066
          !Allocate storage for the supercell if required
1067
          if (.not. allocated(aminv(ic)%dcell(k)%supercell)) then
×
1068
             allocate (aminv(ic)%dcell(k)%supercell(jc))
×
1069
          else
1070
             !Just check the array is the correct size
1071
             j = size(aminv(ic)%dcell(k)%supercell)
×
1072
             if (j /= jc) then
×
1073
                ierr = error_unit()
×
1074
                write(ierr,*) 'Error (2) in init_inverse_matrix: ', &
×
1075
                     iproc,':',jlo,':',jc,':',j
×
1076
             end if
1077
          end if
1078
       end if
1079
    end do
1080

1081
! Now fill aminv for this class:
1082

1083
    !Allocate temporary supercell storage
1084
    allocate (am_tmp(nidx*N_class(ic)))
×
1085

1086
    !Loop over all grid points
1087
    do ilo = f_lo(ic)%llim_world, f_lo(ic)%ulim_world
×
1088

1089
       !Get supercell type (class) and cell index
1090
       m = im_idx(f_lo(ic), ilo)
×
1091
       n = in_idx(f_lo(ic), ilo)
×
1092
       
1093
       !Convert to theta,field,kx and ky indexes
1094
       ig = ig_idx(f_lo(ic), ilo)
×
1095
       if = ifield_idx(f_lo(ic), ilo)
×
1096
       ik = f_lo(ic)%ik(m,n)
×
1097
       it = f_lo(ic)%it(m,n)
×
1098
       
1099
       !Get fast field index
1100
       iflo = ij_idx(jf_lo, ig, if, ik, it)
×
1101
 
1102
       !If this ilo is local then...
1103
       if (idx_local(f_lo(ic),ilo)) then
×
1104
          ! send the am data to...
1105
          if (idx_local(jf_lo,iflo)) then
×
1106
             !the local proc
1107
             am_tmp = am(:,ilo)
×
1108
          else
1109
             !the remote proc
1110
             call send(am(:,ilo), proc_id(jf_lo,iflo))
×
1111
          endif
1112
       else
1113
          !Get ready to receive the data
1114
          if (idx_local(jf_lo,iflo)) then
×
1115
             call receive(am_tmp, proc_id(f_lo(ic),ilo))
×
1116
          end if
1117
       end if
1118

1119
       !If the fast field index is on this processor
1120
       if (idx_local(jf_lo, iflo)) then
×
1121
          !Get "dcell" adress
1122
          dc = jf_lo%dj(ic,iflo)
×
1123

1124
          !Loop over supercell size
1125
          do jlo = 0, nidx*N_class(ic)-1
×
1126
             !Convert to cell/2pi domain index
1127
             nn = in_idx(f_lo(ic), jlo)
×
1128
             
1129
             !Get theta grid point
1130
             jg = ig_idx(f_lo(ic), jlo)
×
1131
             !Get field index
1132
             jf = ifield_idx(f_lo(ic), jlo)
×
1133
             
1134
             !Convert index
1135
             jsc = ij_idx(f_lo(ic), jg, jf, nn) + 1
×
1136

1137
             !Store inverse matrix data in appropriate supercell position
1138
             aminv(ic)%dcell(dc)%supercell(jsc) = am_tmp(jlo+1)
×
1139
             
1140
          end do
1141
       end if
1142
    end do
1143

1144
    !Free memory
1145
    deallocate (am_tmp)
×
1146

1147
    call time_message(.false.,time_field_invert,' Field Matrix Invert')
×
1148
    call get_mp_times(total_time = mp_total_after)
×
1149
    time_field_invert_mpi = time_field_invert_mpi + (mp_total_after - mp_total)
×
1150
  end subroutine init_inverse_matrix
×
1151

1152
  !> FIXME : Add documentation  
1153
  subroutine finish_fields_layouts
×
1154
    use dist_fn, only: has_linked_boundary
1155
    use kt_grids, only: naky, ntheta0, itright
1156
    use gs2_layouts, only: f_lo, jf_lo, ik_idx, it_idx
1157
    implicit none
1158
    integer :: i, m, n, ii, ik, it, itr, jflo
1159

1160
    if (has_linked_boundary()) then
×
1161

1162
! Complication comes from having to order the supercells in each class
1163
       do ii = 1, i_class
×
1164
          m = 1
×
1165
          do it = 1, ntheta0
×
1166
             do ik = 1, naky
×
1167
                call kt2ki (i, n, ik, it)
×
1168
                ! If (ik, it) is in this class, continue:
1169
                if (i == ii) then
×
1170
                   ! Find left end of links
1171
                   if (n == 1) then
×
1172
                      f_lo(i)%ik(m,n) = ik
×
1173
                      f_lo(i)%it(m,n) = it
×
1174
                      itr = it
×
1175
                      ! Follow links to the right
1176
                      do n = 2, N_class(i)
×
1177
                         itr = itright (itr, ik)
×
1178
                         f_lo(i)%ik(m,n) = ik
×
1179
                         f_lo(i)%it(m,n) = itr
×
1180
                      end do
1181
                      m = m + 1
×
1182
                   end if
1183
                end if
1184
             end do
1185
          end do
1186
       end do
1187
       
1188
    ! initialize ij matrix
1189
       
1190
       do jflo = jf_lo%llim_proc, jf_lo%ulim_proc
×
1191
          ik = ik_idx(jf_lo, jflo)
×
1192
          it = it_idx(jf_lo, jflo)
×
1193
          
1194
          call kt2ki ( jf_lo%ij(jflo), n, ik, it)
×
1195
          
1196
       end do
1197

1198
    else
1199
       m = 0
×
1200
       do it = 1, ntheta0
×
1201
          do ik = 1, naky
×
1202
             m = m + 1
×
1203
             f_lo(1)%ik(m,1) = ik
×
1204
             f_lo(1)%it(m,1) = it
×
1205
          end do
1206
       end do
1207
       
1208
        jf_lo%ij = 1
×
1209
    end if
1210

1211
  end subroutine finish_fields_layouts
×
1212

1213
  !> FIXME : Add documentation  
1214
  subroutine kt2ki (i, n, ik, it)
×
1215
    use mp, only: mp_abort
1216
    use file_utils, only: error_unit
1217
    use kt_grids, only: l_links, r_links
1218
    implicit none
1219
    integer, intent (in) :: ik, it
1220
    integer, intent (out) :: i, n
1221
    integer :: nn, ierr
1222
!
1223
! Get size of this supercell
1224
!
1225
    nn = 1 + l_links(it, ik) + r_links(it, ik)
×
1226
!
1227
! Find i = N_class**-1(nn)
1228
!
1229
    do i = 1, i_class
×
1230
       if (N_class(i) == nn) exit
×
1231
    end do
1232
!
1233
! Consistency check:
1234
!
1235
    if (N_class(i) /= nn) then
×
1236
       ierr = error_unit()
×
1237
       write(ierr,*) 'Error in kt2ki:'
×
1238
       write(ierr,*) 'i = ',i,' ik = ',ik,' it = ',it,&
×
1239
            ' N(i) = ',N_class(i),' nn = ',nn
×
1240
       call mp_abort('Error in kt2ki')
×
1241
    end if
1242
! 
1243
! Get position in this supercell, counting from the left
1244
!
1245
    n = 1 + l_links(it, ik)
×
1246

1247
  end subroutine kt2ki
×
1248

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

1270
    !Make a lookup array to convert itmin (the leftmost it in a connected domain)
1271
    !to the supercell index "is" used in the local fields. This will be used to 
1272
    !ensure equivalent files can be given the same name.
1273
    allocate(it_to_is(ntheta0,naky),leftmost_it(ntheta0,naky),tmp_ints(ntheta0))
×
1274
    it_to_is=0
×
1275
    !//Note the following code is mostly borrowed from fm_init in the local fields
1276
    
1277
    !First find all the leftmost it
1278
    do ik=1,naky
×
1279
       do it=1,ntheta0
×
1280
          leftmost_it(it,ik)=get_leftmost_it(it,ik)
×
1281
       enddo
1282
    enddo
1283

1284
    !Now find supercell ids for each ky at a time
1285
    do ik=1,naky
×
1286
       tmp_ints=leftmost_it(:,ik)
×
1287
       it_tmp=0
×
1288
       is_tmp=0
×
1289
       do while(sum(tmp_ints)/=-1*ntheta0)
×
1290
          it_tmp=it_tmp+1
×
1291
          cur_idx=tmp_ints(it_tmp)
×
1292

1293
          !If we've seen this domain skip
1294
          if(cur_idx==-1)cycle
×
1295

1296
          !Increment counter
1297
          is_tmp=is_tmp+1
×
1298

1299
          !Here we store the value
1300
          it_to_is(it_tmp,ik)=is_tmp
×
1301

1302
          !Now we set all other connected locations to -1
1303
          !and store the appropriate is value
1304
          do it=1,ntheta0
×
1305
             if(tmp_ints(it)==cur_idx) then
×
1306
                tmp_ints(it)=-1
×
1307
                it_to_is(it,ik)=is_tmp
×
1308
             endif
1309
          enddo
1310
       enddo
1311
    enddo
1312

1313
    !Cleanup
1314
    deallocate(tmp_ints)
×
1315

1316
    !/End of borrowed code
1317

1318
    !Notation recap:
1319
    ! A class refers to all independent domains with the same length
1320
    ! i_class is how many classes we have
1321
    ! N_class(i_class) is how many 2Pi domains are in each member of i_class
1322
    ! M_class(i_class) is how many independent domains are in i_class
1323

1324
    allocate(tmp_vec(nfield*(2*ntgrid+1)))
×
1325
    allocate(tmp_arr(1+(2*ntgrid),nfield))
×
1326

1327
    !Loop over classes (supercell length)
1328
    do ic=1,i_class
×
1329
       !Extended domain length
1330
       ext_dom_length=1+(2*ntgrid)*N_class(ic)
×
1331
       !Work out how long the supercell is
1332
       supercell_length=nfield*ext_dom_length !Without boundary points
×
1333
       supercell_length_bound=(1+2*ntgrid)*nfield*N_class(ic) !With boundary points
×
1334

1335
       !Make storage
1336
       allocate(tmp_arr_full(supercell_length,supercell_length))
×
1337
       allocate(tmp_vec_full(supercell_length))
×
1338

1339
       !Now loop over all members of this class
1340
       do im=1,M_class(ic)
×
1341
          !Now we are thinking about a single supercell
1342
          !we can get certain properties before looping
1343
          !over the individual elements
1344
          
1345
          !Get the ik index
1346
          ik=f_lo(ic)%ik(im,1)
×
1347

1348
          !Get the leftmost it index (named itmin to match local field routines)
1349
          !This is currently used to identify the supercell like "is" is used in
1350
          !the local field routines. It would be nice to also use "is" here (or
1351
          !"itmin" there).
1352
          itmin=leftmost_it(f_lo(ic)%it(im,1),ik)
×
1353
          
1354
          !Now we have the basic properties we want to loop over the elements
1355
          !First initialise "it"
1356
          it=itmin
×
1357

1358
          !Initialise counter
1359
          icount=1
×
1360

1361
          !The order of the field, cell and theta loops below is chosen
1362
          !in order to match the data layout of the fields local matrix
1363

1364
          !Loop over the fields
1365
          do ifld=1,nfield
×
1366

1367
             !Reinitialise "it" back to the start of the supercell chain
1368
             it=itmin
×
1369

1370
             !Loop over the different it (2Pi domains)
1371
             do in=1,N_class(ic)
×
1372
                !Loop over theta
1373
                do ig=-ntgrid,ntgrid
×
1374
                   !Skip the duplicate boundary points
1375
                   if((ig==ntgrid).and.(in/=N_class(ic))) cycle
×
1376

1377
                   !Convert to jf_lo index
1378
                   jflo=ij_idx(jf_lo,ig,ifld,ik,it)
×
1379

1380
                   !See if it's local
1381
                   is_local=idx_local(jf_lo,jflo)
×
1382

1383
                   !If it's not local then we have nothing to do
1384
                   !unless we're the proc who writes (proc0).
1385
                   if(.not.(is_local.or.proc0)) cycle
×
1386

1387
                   !Now pack tmp_vec and do communications if needed
1388
                   if(is_local)then
×
1389
                      !Get dcell index
1390
                      dc=jf_lo%dj(ic,jflo)
×
1391

1392
                      !Now we pack the tmp_vec in the correct order
1393
                      !whilst ignoring the repeated boundary points
1394
                      !We need to pick the value of "n" in the right order
1395
                      it_tmp=itmin
×
1396
                      do in_tmp=1,N_class(ic)
×
1397
                         !Pick the correct n
1398
                         do nn=1,N_class(ic)
×
1399
                            if(f_lo(ic)%it(im,nn)==it_tmp) exit
×
1400
                         enddo
1401

1402
                         !Now we can get supercell range (including boundaries)
1403
                         nl=1+nidx*(nn-1)
×
1404
                         nr=nl+nidx-1
×
1405
                         
1406
                         !Extract section
1407
                         tmp_vec=aminv(ic)%dcell(dc)%supercell(nl:nr)
×
1408

1409
                         !All that remains now is to ignore the boundary points
1410
                         !To do this we just split on the field so we can ignore
1411
                         !boundary if we want
1412
                         do ifld_tmp=1,nfield
×
1413
                            nl=1+(ifld_tmp-1)*(2*ntgrid+1)
×
1414
                            nr=nl+2*ntgrid
×
1415
                            tmp_arr(:,ifld_tmp)=tmp_vec(nl:nr)
×
1416
                         enddo
1417

1418
                         !Now we need to work out where to put things in tmp_vec_full
1419
                         !In doing this we try to match the local fields data layout
1420
                         !to aid comparisons
1421
                         do ifld_tmp=1,nfield
×
1422
                            do ig_tmp=1,2*ntgrid+1
×
1423
                               !Skip boundary points
1424
                               if((ig_tmp==(2*ntgrid+1)).and.(in_tmp/=N_class(ic))) cycle
×
1425

1426
                               !Get index
1427
                               cur_idx=ig_tmp+(2*ntgrid)*(in_tmp-1)+(ifld_tmp-1)*ext_dom_length
×
1428

1429
                               !Store data
1430
                               tmp_vec_full(cur_idx)=tmp_arr(ig_tmp,ifld_tmp)
×
1431
                            enddo
1432
                         enddo
1433

1434
                         !If we're not at the last cell then increment it_tmp.
1435
                         !This check is needed to avoid trying to access itright
1436
                         !in non-box simulations where this array is not allocated.
1437
                         if(in_tmp < N_class(ic)) then
×
1438
                            it_tmp=itright(it_tmp, ik)
×
1439
                         end if
1440

1441
                      enddo
1442

1443
                      !No comms needed if on proc0
1444
                      if(.not.proc0) call send(tmp_vec_full,0)
×
1445
                   else
1446
                      !Only proc0 should get here but test anyway
1447
                      if(proc0) call receive(tmp_vec_full,proc_id(jf_lo,jflo))
×
1448
                   endif
1449

1450
                   !Now we need to store in the full array
1451
                   !May need to check index order matches local case.
1452
                   if(proc0) then
×
1453
                      tmp_arr_full(:,icount)=tmp_vec_full
×
1454
                   endif
1455

1456
                   !Increment counter
1457
                   icount=icount+1
×
1458
                enddo
1459

1460
                !If we're not at the last cell then increment it.
1461
                !This check is needed to avoid trying to access itright
1462
                !in non-box simulations where this array is not allocated.
1463
                if(in < N_class(ic)) then
×
1464
                   it=itright(it, ik)
×
1465
                end if
1466
             enddo
1467
          enddo
1468

1469
          !Now make file name
1470
          if(proc0)then
×
1471
             call gs2_save_response(tmp_arr_full, get_specific_response_file_name(ik, it_to_is(itmin, ik), code_dt, suffix), code_dt)
×
1472
          endif
1473
       end do
1474
          
1475
       deallocate(tmp_arr_full,tmp_vec_full)
×
1476
    end do
1477

1478
    !Tidy
1479
    deallocate(tmp_vec,tmp_arr,leftmost_it,it_to_is)
×
1480
    call time_message(.false.,time_dump_response,' Field Dump')
×
1481
  end subroutine dump_response_to_file_imp
×
1482

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

1510
    call time_message(.false.,time_read_response,' Field Read')
×
1511
    could_read = .true.
×
1512

1513
    !First allocate the matrix storage
1514
    call alloc_response_objects
×
1515

1516
    !Make a lookup array to convert itmin (the leftmost it in a connected domain)
1517
    !to the supercell index "is" used in the local fields. This will be used to 
1518
    !ensure equivalent files can be given the same name.
1519
    allocate(it_to_is(ntheta0,naky),leftmost_it(ntheta0,naky),tmp_ints(ntheta0))
×
1520
    it_to_is=0
×
1521
    !//Note the following code is mostly borrowed from fm_init in the local fields
1522
    
1523
    !First find all the leftmost it
1524
    do ik=1,naky
×
1525
       do it=1,ntheta0
×
1526
          leftmost_it(it,ik)=get_leftmost_it(it,ik)
×
1527
       enddo
1528
    enddo
1529

1530
    !Now find supercell ids for each ky at a time
1531
    do ik=1,naky
×
1532
       tmp_ints=leftmost_it(:,ik)
×
1533
       it_tmp=0
×
1534
       is_tmp=0
×
1535
       do while(sum(tmp_ints)/=-1*ntheta0)
×
1536
          it_tmp=it_tmp+1
×
1537
          cur_idx=tmp_ints(it_tmp)
×
1538

1539
          !If we've seen this domain skip
1540
          if(cur_idx==-1)cycle
×
1541

1542
          !Increment counter
1543
          is_tmp=is_tmp+1
×
1544

1545
          !Here we store the value
1546
          it_to_is(it_tmp,ik)=is_tmp
×
1547

1548
          !Now we set all other connected locations to -1
1549
          !and store the appropriate is value
1550
          do it=1,ntheta0
×
1551
             if(tmp_ints(it)==cur_idx) then
×
1552
                tmp_ints(it)=-1
×
1553
                it_to_is(it,ik)=is_tmp
×
1554
             endif
1555
          enddo
1556
       enddo
1557
    enddo
1558

1559
    !Cleanup
1560
    deallocate(tmp_ints)
×
1561

1562
    !/End of borrowed code
1563

1564
    !Notation recap:
1565
    ! A class refers to all independent domains with the same length
1566
    ! i_class is how many classes we have
1567
    ! N_class(i_class) is how many 2Pi domains are in each member of i_class
1568
    ! M_class(i_class) is how many independent domains are in i_class
1569

1570
    allocate(tmp_vec(nfield*(2*ntgrid+1)))
×
1571
    allocate(tmp_arr(1+(2*ntgrid),nfield))
×
1572

1573
    !Loop over classes (supercell length)
1574
    do ic=1,i_class
×
1575
       !Extended domain length
1576
       ext_dom_length=1+(2*ntgrid)*N_class(ic)
×
1577
       !Work out how long the supercell is
1578
       supercell_length=nfield*ext_dom_length !Without boundary points
×
1579
       supercell_length_bound=(1+2*ntgrid)*nfield*N_class(ic) !With boundary points
×
1580

1581
       !Make storage
1582
       allocate(tmp_arr_full(supercell_length,supercell_length))
×
1583
       allocate(tmp_vec_full(supercell_length))
×
1584

1585
       !Now loop over all members of this class
1586
       do im=1,M_class(ic)
×
1587
          tmp_arr_full=0.
×
1588
          tmp_vec_full=0.
×
1589

1590
          !Now we are thinking about a single supercell
1591
          !we can get certain properties before looping
1592
          !over the individual elements
1593
          
1594
          !Get the ik index
1595
          ik=f_lo(ic)%ik(im,1)
×
1596

1597
          !Get the leftmost it index (named itmin to match local field routines)
1598
          !This is currently used to identify the supercell like "is" is used in
1599
          !the local field routines. It would be nice to also use "is" here (or
1600
          !"itmin" there).
1601
          itmin=leftmost_it(f_lo(ic)%it(im,1),ik)
×
1602
          
1603
          !Now make file name
1604
          file_name = adjustl(get_specific_response_file_name(ik, it_to_is(itmin, ik), code_dt, suffix))
×
1605

1606
          ! First check if the expected file exists, if not then exit
1607
          inquire( file = trim(file_name), exist = file_found)
×
1608
          if (.not. file_found) then
×
1609
             if(proc0) write(error_unit(), &
×
1610
                  '("Could not find response file ",A,", reverting to calculation.")') trim(file_name)
×
1611
             could_read = .false.
×
1612
             return
×
1613
          end if
1614

1615
          if(proc0)then
×
1616
             call gs2_restore_response(tmp_arr_full, file_name, file_time_step)
×
1617
             ! Should perhaps double check that file_time_step == code_dt?
1618
          endif
1619

1620
          !Initialise counter
1621
          icount=1
×
1622

1623
          !Loop over the fields
1624
          do ifld=1,nfield
×
1625
             !Reinitialise "it" back to the start of the supercell chain
1626
             it=itmin
×
1627

1628
             !Loop over the different it (2Pi domains)
1629
             do in=1,N_class(ic)
×
1630
                !Loop over theta
1631
                do ig=-ntgrid,ntgrid
×
1632
                   !Skip the duplicate boundary points -- This is no good here. !<DD>
1633
!                   if((ig.eq.ntgrid).and.(in.ne.N_class(ic))) cycle
1634

1635
                   !Convert to jf_lo index
1636
                   jflo=ij_idx(jf_lo,ig,ifld,ik,it)
×
1637

1638
                   !See if it's local
1639
                   is_local=idx_local(jf_lo,jflo)
×
1640

1641
                   !If it's not local then we have nothing to do
1642
                   !unless we're the proc who writes (proc0).
1643
                   if(.not.(is_local.or.proc0)) cycle
×
1644

1645
                   !Get row
1646
                   if(proc0)then
×
1647
                      tmp_vec_full=tmp_arr_full(:,icount)
×
1648
                      
1649
                      !Increment counter
1650
                      if(.not.(ig==ntgrid.and.in/=N_Class(ic))) icount=icount+1
×
1651
                   endif
1652

1653
                   !Now unpack tmp_vec_full and do communications if needed
1654
                   if(is_local)then
×
1655
                      !No comms needed if local
1656
                      if(.not.proc0) call receive(tmp_vec_full,0)
×
1657

1658
                      !Get dcell index
1659
                      dc=jf_lo%dj(ic,jflo)
×
1660

1661
                      !Now we pack the tmp_vec in the correct order
1662
                      !We must fill in the boundary points
1663
                      !We need to pick the value of "n" in the right order
1664
                      it_tmp=itmin
×
1665
                      do in_tmp=1,N_class(ic)
×
1666
                         tmp_arr=0
×
1667
                         tmp_vec=0
×
1668

1669
                         !Now we need to work out where to put things in tmp_vec_full
1670
                         !In doing this we try to match the local fields data layout
1671
                         !to aid comparisons
1672
                         do ifld_tmp=1,nfield
×
1673
                            do ig_tmp=1,2*ntgrid+1
×
1674
                               !Skip boundary points
1675
                               if((ig_tmp==(2*ntgrid+1)).and.(in_tmp/=N_class(ic))) cycle
×
1676

1677
                               !Get index
1678
                               cur_idx=ig_tmp+(2*ntgrid)*(in_tmp-1)+(ifld_tmp-1)*ext_dom_length
×
1679

1680
                               !Store data
1681
                               tmp_arr(ig_tmp,ifld_tmp)=tmp_vec_full(cur_idx)
×
1682
                            enddo
1683
                         enddo
1684

1685
                         !<DD>It may be anticipated that we need to fix the boundary points
1686
                         !here but we don't actually need to do anything.
1687
                         !Because we sum over the entire supercell in getfield we only want
1688
                         !the repeated boundary point to be included once.
1689
                         !We still need to calculate the field at the repeated point but the
1690
                         !fix for that is handled at the bottom of the routine
1691
                         !In other words we don't need something of the form:
1692
                         ! !Fix boundary points
1693
                         ! if(in_tmp.ne.N_class(ic))then
1694
                         !    do ifld_tmp=1,nfield
1695
                         !       cur_idx=1+(2*ntgrid)*(in_tmp)+(ifld_tmp-1)*ext_dom_length
1696
                         !       tmp_arr(2*ntgrid+1,ifld_tmp)=tmp_vec_full(cur_idx)
1697
                         !    enddo
1698
                         ! endif
1699

1700
                         !Store in correct order
1701
                         do ifld_tmp=1,nfield
×
1702
                            nl=1+(ifld_tmp-1)*(2*ntgrid+1)
×
1703
                            nr=nl+2*ntgrid
×
1704
                            tmp_vec(nl:nr)=tmp_arr(:,ifld_tmp)
×
1705
                         enddo
1706

1707
                         !Pick the correct n
1708
                         do nn=1,N_class(ic)
×
1709
                            if(f_lo(ic)%it(im,nn)==it_tmp) exit
×
1710
                         enddo
1711

1712
                         !Now we can get supercell range (including boundaries)
1713
                         nl=1+nidx*(nn-1)
×
1714
                         nr=nl+nidx-1
×
1715

1716
                         !Store section
1717
                         aminv(ic)%dcell(dc)%supercell(nl:nr)=tmp_vec
×
1718

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

1726
                      enddo
1727
                   else
1728
                      !Only proc0 should get here but test anyway
1729
                      if(proc0) call send(tmp_vec_full,proc_id(jf_lo,jflo))
×
1730
                   endif
1731
                enddo
1732

1733
                !If we're not at the last cell then increment it.
1734
                !This check is needed to avoid trying to access itright
1735
                !in non-box simulations where this array is not allocated.
1736
                if(in < N_class(ic)) then
×
1737
                   it=itright(it, ik)
×
1738
                end if
1739
             enddo
1740
          enddo
1741

1742
          !Now we need to fill in the repeated boundary points
1743

1744
          !If there are no boundary points then advance
1745
          if(N_class(ic)==1) cycle
×
1746
          it=itmin
×
1747
          do in=1,N_class(ic)-1
×
1748
             do ifld=1,nfield
×
1749
                !First get the index of the point we want to fill
1750
                jflo=ij_idx(jf_lo,ntgrid,ifld,ik,it)
×
1751

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

1755
                !Now get locality
1756
                is_local=idx_local(jf_lo,jflo)
×
1757
                is_local_dup=idx_local(jf_lo,jflo_dup)
×
1758

1759
                !Get dcell values
1760
                if(is_local) dc=jf_lo%dj(ic,jflo)
×
1761
                if(is_local_dup) dc_dup=jf_lo%dj(ic,jflo_dup)
×
1762

1763
                !Now copy/communicate
1764
                if(is_local)then
×
1765
                   if(is_local_dup)then
×
1766
                      aminv(ic)%dcell(dc)%supercell=aminv(ic)%dcell(dc_dup)%supercell
×
1767
                   else
1768
                      call receive(aminv(ic)%dcell(dc)%supercell,proc_id(jf_lo,jflo_dup))
×
1769
                   endif
1770
                elseif(is_local_dup)then
×
1771
                   call send(aminv(ic)%dcell(dc_dup)%supercell,proc_id(jf_lo,jflo))
×
1772
                endif
1773
             enddo
1774

1775
             !Increment it -- note we don't need to guard against access to itright
1776
             !here as for non-box runs we won't enter the outer in=1,N_class(ic)-1
1777
             !loop as N_class(ic) == 1
1778
             it=itright(it,ik)
×
1779
          enddo
1780
       end do
1781
       
1782
       !Free
1783
       deallocate(tmp_arr_full,tmp_vec_full)
×
1784
    end do
1785

1786
    !Tidy
1787
    deallocate(tmp_vec,tmp_arr,leftmost_it,it_to_is)
×
1788
    call time_message(.false.,time_read_response,' Field Read')
×
1789
  end subroutine read_response_from_file_imp
×
1790

1791
  !> A subroutine to allocate the response matrix storage objects
1792
  subroutine alloc_response_objects
×
1793
    use gs2_layouts, only: jf_lo, f_lo, im_idx, in_idx, ig_idx, ifield_idx, ij_idx, idx_local
1794
    use theta_grid, only: ntgrid
1795
    implicit none
1796
    integer :: ic, idc, sc_len, ilo, dc, im, in, ig, ifld, ik, it, jlo
1797

1798
    !Top level, one object for each class (length of supercell)
1799
    if(.not.allocated(aminv)) allocate(aminv(i_class))
×
1800

1801
    !Loop over each class
1802
    do ic=1,i_class
×
1803
       !Get the supercell length
1804
       sc_len=(2*ntgrid+1)*nfield*N_class(ic)
×
1805

1806
       !Count how many dcell we have locally and fill related data
1807
       dc=0
×
1808
       do ilo=f_lo(ic)%llim_world,f_lo(ic)%ulim_world
×
1809
          !i.e. what is my class of supercell and which cell am I looking at
1810
          im = im_idx(f_lo(ic), ilo)
×
1811
          in = in_idx(f_lo(ic), ilo)
×
1812

1813
          ! find standard coordinates
1814
          !Get theta, field, kx and ky indexes for current point
1815
          ig = ig_idx(f_lo(ic), ilo)
×
1816
          ifld = ifield_idx(f_lo(ic), ilo)
×
1817
          ik = f_lo(ic)%ik(im,in)
×
1818
          it = f_lo(ic)%it(im,in)
×
1819
          
1820
          ! translate to fast field coordinates
1821
          jlo = ij_idx(jf_lo, ig, ifld, ik, it)
×
1822
          
1823
          ! Locate this jlo, count it, and save address
1824
          !Is this point on this proc, if so increment counter
1825
          if (idx_local(jf_lo,jlo)) then
×
1826
             ! count it
1827
             dc = dc + 1
×
1828
             ! save dcell address
1829
             jf_lo%dj(ic,jlo) = dc
×
1830
             ! save supercell address
1831
             jf_lo%mj(jlo) = im
×
1832
          endif
1833
       enddo
1834

1835
       !Next level, one object for each point in the class
1836
       if(.not. allocated(aminv(ic)%dcell))then
×
1837
          allocate(aminv(ic)%dcell(dc))
×
1838
       endif
1839

1840
       !Now loop over each point and allocate storage for the response data
1841
       do idc=1,dc
×
1842
          !Bottom level, this is actually where data is stored
1843
          if(.not. allocated(aminv(ic)%dcell(idc)%supercell)) then
×
1844
             allocate(aminv(ic)%dcell(idc)%supercell(sc_len))
×
1845
          endif
1846
       enddo
1847
    enddo
1848

1849
  end subroutine alloc_response_objects
×
1850
end module fields_implicit
×
1851

×
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