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

gyrokinetics / gs2 / 1969696739

06 Aug 2025 10:44AM UTC coverage: 8.203%. Remained the same
1969696739

push

gitlab-ci

David Dickinson
Merged in minor/update_utils_and_make_field_line_average_pure (pull request #1102)

3691 of 44998 relevant lines covered (8.2%)

124041.53 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
  pure 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
  end subroutine fieldline_average_phi
×
506

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

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

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

535
    call finish_jfields_layouts
×
536
  end subroutine reset_init
537

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

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

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

566
    response_was_read = .false.
×
567

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

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

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

589

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

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

599

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

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

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

630

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

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

648
                !Start counting fields
649
                ifield = 0
×
650

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

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

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

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

719
          !Free memory
720
          deallocate (am)
×
721

722
       end do
723
    endif 
724

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

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

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

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

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

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

798
  end subroutine init_response_row
×
799

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

995
    !Free memory
996
    deallocate (a_inv)
×
997

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

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

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

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

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

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

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

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

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

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

1080
! Now fill aminv for this class:
1081

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

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

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

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

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

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

1143
    !Free memory
1144
    deallocate (am_tmp)
×
1145

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

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

1159
    if (has_linked_boundary()) then
×
1160

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

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

1210
  end subroutine finish_fields_layouts
×
1211

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

1246
  end subroutine kt2ki
×
1247

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

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

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

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

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

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

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

1312
    !Cleanup
1313
    deallocate(tmp_ints)
×
1314

1315
    !/End of borrowed code
1316

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

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

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

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

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

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

1357
          !Initialise counter
1358
          icount=1
×
1359

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

1440
                      enddo
1441

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

1558
    !Cleanup
1559
    deallocate(tmp_ints)
×
1560

1561
    !/End of borrowed code
1562

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

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

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

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

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

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

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

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

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

1619
          !Initialise counter
1620
          icount=1
×
1621

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

1848
  end subroutine alloc_response_objects
×
1849
end module fields_implicit
×
1850

×
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