Report Typos and Errors    
Semi-Lagrangian Library
Modular library for kinetic and gyrokinetic simulations of plasmas in fusion energy devices.
sll_m_accumulators.F90
Go to the documentation of this file.
1 !**************************************************************
2 ! Copyright INRIA
3 ! Authors :
4 ! CALVI project team
5 !
6 ! This code SeLaLib (for Semi-Lagrangian-Library)
7 ! is a parallel library for simulating the plasma turbulence
8 ! in a tokamak.
9 !
10 ! This software is governed by the CeCILL-B license
11 ! under French law and abiding by the rules of distribution
12 ! of free software. You can use, modify and redistribute
13 ! the software under the terms of the CeCILL-B license as
14 ! circulated by CEA, CNRS and INRIA at the following URL
15 ! "http://www.cecill.info".
16 !**************************************************************
17 
20 !+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
21 #include "sll_memory.h"
22 #include "sll_working_precision.h"
23 
24  use sll_m_cartesian_meshes, only: &
26 
27  implicit none
28 
29  public :: &
51  sll_o_delete, &
54 
55  private
56 !+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
57 
58  ! The idea of having this data structure is to precompute the values of
59  ! the electric field, store them redundantly on a cell-based structure and
60  ! reduce the memory thrashing that would inevitably occur if we were to
61  ! compute the values of the electric field from the potential repeatedly.
62  ! These costs ought to be amortized if the number of points to be advected,
63  ! or particles to be advanced (per cell) is relatively large compared with
64  ! the cost of filling out this data structure.
65  !
66  ! The values of the electric field within the structure in 2D are named
67  ! like this:
68  ! NW (north-west) NE (north-east)
69  ! +--------------------+
70  ! | |
71  ! | |
72  ! | |
73  ! | |
74  ! | cell(i) |
75  ! | |
76  ! | |
77  ! | |
78  ! | |
79  ! +--------------------+
80  ! SW (south-west) SE (south-east)
81  !
82  ! Each corner represents a point with two electric field components defined:
83  ! ex and ey (x-component and y-component of the field respectively).
84 
86  sll_real64 :: q_sw
87  sll_real64 :: q_se
88  sll_real64 :: q_nw
89  sll_real64 :: q_ne
91 
93  type(sll_t_cartesian_mesh_2d), pointer :: mesh
94  type(sll_t_charge_accumulator_cell_2d), dimension(:), pointer :: q_acc
96 
98  type(sll_t_charge_accumulator_2d), pointer :: q
100 
102  sll_real64 :: q_im1j
103  sll_real64 :: q_ij
104  sll_real64 :: q_ip1j
105  sll_real64 :: q_ip2j
106 
107  sll_real64 :: q_im1jm1
108  sll_real64 :: q_ijm1
109  sll_real64 :: q_ip1jm1
110  sll_real64 :: q_ip2jm1
111 
112  sll_real64 :: q_im1jp1
113  sll_real64 :: q_ijp1
114  sll_real64 :: q_ip1jp1
115  sll_real64 :: q_ip2jp1
116 
117  sll_real64 :: q_im1jp2
118  sll_real64 :: q_ijp2
119  sll_real64 :: q_ip1jp2
120  sll_real64 :: q_ip2jp2
122 
124  type(sll_t_cartesian_mesh_2d), pointer :: mesh
125  type(charge_accumulator_cell_2d_cs), dimension(:), pointer :: q_acc
127 
129  type(sll_t_charge_accumulator_2d_cs), pointer :: q
131 
133  sll_real64 :: ex_sw
134  sll_real64 :: ex_se
135  sll_real64 :: ex_nw
136  sll_real64 :: ex_ne
137  sll_real64 :: ey_sw
138  sll_real64 :: ey_se
139  sll_real64 :: ey_nw
140  sll_real64 :: ey_ne
142 
144  type(sll_t_cartesian_mesh_2d), pointer :: mesh
145  type(sll_t_field_accumulator_cell), dimension(:), pointer :: e_acc
147 
148  type sll_t_field_accumulator_cs! needed for the Cubic Spline interpolation
149  sll_real64 :: ex_im1j, ey_im1j
150  sll_real64 :: ex_ij, ey_ij
151  sll_real64 :: ex_ip1j, ey_ip1j
152  sll_real64 :: ex_ip2j, ey_ip2j
153 
154  sll_real64 :: ex_im1jm1, ey_im1jm1
155  sll_real64 :: ex_ijm1, ey_ijm1
156  sll_real64 :: ex_ip1jm1, ey_ip1jm1
157  sll_real64 :: ex_ip2jm1, ey_ip2jm1
158 
159  sll_real64 :: ex_im1jp1, ey_im1jp1
160  sll_real64 :: ex_ijp1, ey_ijp1
161  sll_real64 :: ex_ip1jp1, ey_ip1jp1
162  sll_real64 :: ex_ip2jp1, ey_ip2jp1
163 
164  sll_real64 :: ex_im1jp2, ey_im1jp2
165  sll_real64 :: ex_ijp2, ey_ijp2
166  sll_real64 :: ex_ip1jp2, ey_ip1jp2
167  sll_real64 :: ex_ip2jp2, ey_ip2jp2
169 
171  type(sll_t_cartesian_mesh_2d), pointer :: mesh
172  type(sll_t_field_accumulator_cs), dimension(:), pointer :: e_acc
174 
175  interface sll_o_delete
176  module procedure delete_charge_accumulator_2d
177  end interface sll_o_delete
178 
179  interface operator(+)
180  module procedure q_acc_add, q_acc_add_cs
181  end interface operator(+)
182 
183 contains
184 
185  subroutine sll_s_charge_accumulator_2d_init(acc, mesh_2d)
186  type(sll_t_charge_accumulator_2d) :: acc
187  type(sll_t_cartesian_mesh_2d), target :: mesh_2d
188  sll_int32 :: num_cells1
189  sll_int32 :: num_cells2
190  sll_int32 :: num_cells_total
191  sll_int32 :: ierr
192 
193  acc%mesh => mesh_2d
194  num_cells1 = mesh_2d%num_cells1
195  num_cells2 = mesh_2d%num_cells2
196  num_cells_total = num_cells1*num_cells2
197  sll_allocate(acc%q_acc(num_cells_total), ierr)
199 
200  end subroutine sll_s_charge_accumulator_2d_init
201 
202  function sll_f_new_charge_accumulator_2d(mesh_2d) result(acc)
203  type(sll_t_cartesian_mesh_2d), pointer :: mesh_2d
204  type(sll_t_charge_accumulator_2d), pointer :: acc
205  sll_int32 :: ierr
206 
207  if (.not. associated(mesh_2d)) then
208  print *, 'ERROR: sll_f_new_charge_accumulator_2d(), passed mesh is not ', &
209  'associated. Exiting...'
210  stop
211  end if
212 
213  sll_allocate(acc, ierr)
214  call sll_s_charge_accumulator_2d_init(acc, mesh_2d)
215 
217 
218  function q_acc_add(q1, q2) result(res)
220  type(sll_t_charge_accumulator_cell_2d), intent(in) :: q1
221  type(sll_t_charge_accumulator_cell_2d), intent(in) :: q2
222 
223  res%q_sw = q1%q_sw + q2%q_sw
224  res%q_se = q1%q_se + q2%q_se
225  res%q_nw = q1%q_nw + q2%q_nw
226  res%q_ne = q1%q_ne + q2%q_ne
227  end function q_acc_add
228 
229  function q_acc_add_cs(q1, q2) result(res)
230  type(charge_accumulator_cell_2d_cs) :: res
231  type(charge_accumulator_cell_2d_cs), intent(in) :: q1
232  type(charge_accumulator_cell_2d_cs), intent(in) :: q2
233 
234  res%q_im1j = q1%q_im1j + q2%q_im1j
235  res%q_ij = q1%q_ij + q2%q_ij
236  res%q_ip1j = q1%q_ip1j + q2%q_ip1j
237  res%q_ip2j = q1%q_ip2j + q2%q_ip2j
238 
239  res%q_im1jm1 = q1%q_im1jm1 + q2%q_im1jm1
240  res%q_ijm1 = q1%q_ijm1 + q2%q_ijm1
241  res%q_ip1jm1 = q1%q_ip1jm1 + q2%q_ip1jm1
242  res%q_ip2jm1 = q1%q_ip2jm1 + q2%q_ip2jm1
243 
244  res%q_im1jp1 = q1%q_im1jp1 + q2%q_im1jp1
245  res%q_ijp1 = q1%q_ijp1 + q2%q_ijp1
246  res%q_ip1jp1 = q1%q_ip1jp1 + q2%q_ip1jp1
247  res%q_ip2jp1 = q1%q_ip2jp1 + q2%q_ip2jp1
248 
249  res%q_im1jp2 = q1%q_im1jp2 + q2%q_im1jp2
250  res%q_ijp2 = q1%q_ijp2 + q2%q_ijp2
251  res%q_ip1jp2 = q1%q_ip1jp2 + q2%q_ip1jp2
252  res%q_ip2jp2 = q1%q_ip2jp2 + q2%q_ip2jp2
253  end function q_acc_add_cs
254 
256  type(sll_t_charge_accumulator_2d) :: acc
257  sll_int32 :: i
258  sll_int32 :: num_cells
259 
260  num_cells = acc%mesh%num_cells1*acc%mesh%num_cells2
261 
262  do i = 1, num_cells
263  acc%q_acc(i)%q_sw = 0.0_f64
264  acc%q_acc(i)%q_se = 0.0_f64
265  acc%q_acc(i)%q_nw = 0.0_f64
266  acc%q_acc(i)%q_ne = 0.0_f64
267  end do
269 
271  type(sll_t_charge_accumulator_2d), pointer :: acc
272  sll_int32 :: ierr
273 
274  if (.not. associated(acc)) then
275  print *, 'delete_charge_accumulator_2d(): ', &
276  'ERROR, pointer was not associated.'
277  stop
278  end if
279 
280  if (associated(acc%q_acc)) then
281  sll_deallocate(acc%q_acc, ierr)
282  end if
283  sll_deallocate(acc, ierr)
284  end subroutine delete_charge_accumulator_2d
285 
286  subroutine sll_s_charge_accumulator_2d_cs_init(acc, mesh_2d)
287  type(sll_t_cartesian_mesh_2d), target :: mesh_2d
288  type(sll_t_charge_accumulator_2d_cs) :: acc
289  sll_int32 :: num_cells1
290  sll_int32 :: num_cells2
291  sll_int32 :: num_cells_total
292  sll_int32 :: ierr
293 
294  acc%mesh => mesh_2d
295  num_cells1 = mesh_2d%num_cells1
296  num_cells2 = mesh_2d%num_cells2
297  num_cells_total = num_cells1*num_cells2
298  sll_allocate(acc%q_acc(num_cells_total), ierr)
301 
302  function sll_f_new_charge_accumulator_2d_cs(mesh_2d) result(acc)
303  type(sll_t_cartesian_mesh_2d), pointer :: mesh_2d
304  type(sll_t_charge_accumulator_2d_cs), pointer :: acc
305  sll_int32 :: ierr
306 
307  if (.not. associated(mesh_2d)) then
308  print *, 'ERROR: sll_f_new_charge_accumulator_2d(), passed mesh is not ', &
309  'associated. Exiting...'
310  stop
311  end if
312 
313  sll_allocate(acc, ierr)
314  call sll_s_charge_accumulator_2d_cs_init(acc, mesh_2d)
315 
317 
319  type(sll_t_charge_accumulator_2d_cs) :: acc
320  sll_int32 :: i
321  sll_int32 :: num_cells
322 
323  num_cells = acc%mesh%num_cells1*acc%mesh%num_cells2
324 
325  do i = 1, num_cells
326  acc%q_acc(i)%q_im1j = 0.0_f64; acc%q_acc(i)%q_im1jm1 = 0.0_f64
327  acc%q_acc(i)%q_ij = 0.0_f64; acc%q_acc(i)%q_ijm1 = 0.0_f64
328  acc%q_acc(i)%q_ip1j = 0.0_f64; acc%q_acc(i)%q_ip1jm1 = 0.0_f64
329  acc%q_acc(i)%q_ip2j = 0.0_f64; acc%q_acc(i)%q_ip2jm1 = 0.0_f64
330 
331  acc%q_acc(i)%q_im1jp1 = 0.0_f64; acc%q_acc(i)%q_im1jp2 = 0.0_f64
332  acc%q_acc(i)%q_ijp1 = 0.0_f64; acc%q_acc(i)%q_ijp2 = 0.0_f64
333  acc%q_acc(i)%q_ip1jp1 = 0.0_f64; acc%q_acc(i)%q_ip1jp2 = 0.0_f64
334  acc%q_acc(i)%q_ip2jp1 = 0.0_f64; acc%q_acc(i)%q_ip2jp2 = 0.0_f64
335  end do
337 
339  type(sll_t_charge_accumulator_2d_cs), pointer :: acc
340  sll_int32 :: ierr
341 
342  if (.not. associated(acc)) then
343  print *, 'delete_charge_accumulator_2d(): ', &
344  'ERROR, pointer was not associated.'
345  stop
346  end if
347 
348  if (associated(acc%q_acc)) then
349  sll_deallocate(acc%q_acc, ierr)
350  end if
351  sll_deallocate(acc, ierr)
352  end subroutine delete_charge_accumulator_2d_cs
353 
354  subroutine sll_s_field_accumulator_2d_init(E_acc, mesh_2d)
355  type(sll_t_electric_field_accumulator) :: e_acc
356  type(sll_t_cartesian_mesh_2d), target :: mesh_2d
357  sll_int32 :: num_cells1
358  sll_int32 :: num_cells2
359  sll_int32 :: num_cells_total
360  sll_int32 :: ierr
361 
362  e_acc%mesh => mesh_2d
363  num_cells1 = mesh_2d%num_cells1
364  num_cells2 = mesh_2d%num_cells2
365  num_cells_total = num_cells1*num_cells2
366  sll_allocate(e_acc%e_acc(num_cells_total), ierr)
368 
369  end subroutine sll_s_field_accumulator_2d_init
370 
371  function sll_f_new_field_accumulator_2d(mesh_2d) result(E_acc)
372  type(sll_t_cartesian_mesh_2d), pointer :: mesh_2d
373  type(sll_t_electric_field_accumulator), pointer :: e_acc
374  sll_int32 :: ierr
375 
376  if (.not. associated(mesh_2d)) then
377  print *, 'ERROR: sll_f_new_charge_accumulator_2d(), passed mesh is not ', &
378  'associated. Exiting...'
379  stop
380  end if
381 
382  sll_allocate(e_acc, ierr)
383  call sll_s_field_accumulator_2d_init(e_acc, mesh_2d)
384 
385  end function sll_f_new_field_accumulator_2d
386 
387  subroutine sll_s_field_accumulator_cs_2d_init(E_acc, mesh_2d)
388  type(sll_t_cartesian_mesh_2d), target :: mesh_2d
390  sll_int32 :: num_cells1
391  sll_int32 :: num_cells2
392  sll_int32 :: num_cells_total
393  sll_int32 :: ierr
394 
395  e_acc%mesh => mesh_2d
396  num_cells1 = mesh_2d%num_cells1
397  num_cells2 = mesh_2d%num_cells2
398  num_cells_total = num_cells1*num_cells2
399  sll_allocate(e_acc%e_acc(num_cells_total), ierr)
401 
403 
404  function sll_f_new_field_accumulator_cs_2d(mesh_2d) result(E_acc)
405  type(sll_t_cartesian_mesh_2d), pointer :: mesh_2d
406  type(sll_t_electric_field_accumulator_cs), pointer :: e_acc
407  sll_int32 :: ierr
408 
409  if (.not. associated(mesh_2d)) then
410  print *, 'ERROR: sll_f_new_charge_accumulator_2d(), passed mesh is not ', &
411  'associated. Exiting...'
412  stop
413  end if
414 
415  sll_allocate(e_acc, ierr)
416 
417  call sll_s_field_accumulator_cs_2d_init(e_acc, mesh_2d)
418 
420 
422  type(sll_t_electric_field_accumulator) :: e_acc
423  sll_int32 :: i
424  sll_int32 :: num_cells
425 
426  num_cells = e_acc%mesh%num_cells1*e_acc%mesh%num_cells2
427  do i = 1, num_cells
428  e_acc%e_acc(i)%Ex_sw = 0.0_f64
429  e_acc%e_acc(i)%Ex_se = 0.0_f64
430  e_acc%e_acc(i)%Ex_nw = 0.0_f64
431  e_acc%e_acc(i)%Ex_ne = 0.0_f64
432  e_acc%e_acc(i)%Ey_sw = 0.0_f64
433  e_acc%e_acc(i)%Ey_se = 0.0_f64
434  e_acc%e_acc(i)%Ey_nw = 0.0_f64
435  e_acc%e_acc(i)%Ey_ne = 0.0_f64
436  end do
438 
440 ! ------------- CS is for Cubic Spline -------------
442  sll_int32 :: i
443  sll_int32 :: num_cells
444 
445  num_cells = e_acc%mesh%num_cells1*e_acc%mesh%num_cells2
446  do i = 1, num_cells
447  e_acc%e_acc(i)%Ex_im1j = 0.0_f64; e_acc%e_acc(i)%Ey_im1j = 0.0_f64
448  e_acc%e_acc(i)%Ex_ij = 0.0_f64; e_acc%e_acc(i)%Ey_ij = 0.0_f64
449  e_acc%e_acc(i)%Ex_ip1j = 0.0_f64; e_acc%e_acc(i)%Ey_ip1j = 0.0_f64
450  e_acc%e_acc(i)%Ex_ip2j = 0.0_f64; e_acc%e_acc(i)%Ey_ip2j = 0.0_f64
451  e_acc%e_acc(i)%Ex_im1jm1 = 0.0_f64; e_acc%e_acc(i)%Ey_im1jm1 = 0.0_f64
452  e_acc%e_acc(i)%Ex_ijm1 = 0.0_f64; e_acc%e_acc(i)%Ey_ijm1 = 0.0_f64
453  e_acc%e_acc(i)%Ex_ip1jm1 = 0.0_f64; e_acc%e_acc(i)%Ey_ip1jm1 = 0.0_f64
454  e_acc%e_acc(i)%Ex_ip2jm1 = 0.0_f64; e_acc%e_acc(i)%Ey_ip2jm1 = 0.0_f64
455  e_acc%e_acc(i)%Ex_im1jp1 = 0.0_f64; e_acc%e_acc(i)%Ey_im1jp1 = 0.0_f64
456  e_acc%e_acc(i)%Ex_ijp1 = 0.0_f64; e_acc%e_acc(i)%Ey_ijp1 = 0.0_f64
457  e_acc%e_acc(i)%Ex_ip1jp1 = 0.0_f64; e_acc%e_acc(i)%Ey_ip1jp1 = 0.0_f64
458  e_acc%e_acc(i)%Ex_ip2jp1 = 0.0_f64; e_acc%e_acc(i)%Ey_ip2jp1 = 0.0_f64
459  e_acc%e_acc(i)%Ex_im1jp2 = 0.0_f64; e_acc%e_acc(i)%Ey_im1jp2 = 0.0_f64
460  e_acc%e_acc(i)%Ex_ijp2 = 0.0_f64; e_acc%e_acc(i)%Ey_ijp2 = 0.0_f64
461  e_acc%e_acc(i)%Ex_ip1jp2 = 0.0_f64; e_acc%e_acc(i)%Ey_ip1jp2 = 0.0_f64
462  e_acc%e_acc(i)%Ex_ip2jp2 = 0.0_f64; e_acc%e_acc(i)%Ey_ip2jp2 = 0.0_f64
463  end do
465 
466  subroutine sll_s_sum_accumulators(tab, n_threads, n_cells)
467  sll_int32, intent(in) :: n_threads, n_cells
468  type(sll_t_charge_accumulator_2d_ptr), dimension(:), pointer, intent(inout) :: tab
469  sll_int32 :: i, j
470 
471  do i = 1, n_cells
472  do j = 2, n_threads
473  tab(1)%q%q_acc(i) = tab(1)%q%q_acc(i) + tab(j)%q%q_acc(i)
474  end do
475  end do
476  end subroutine sll_s_sum_accumulators
477 
478  subroutine sll_s_sum_accumulators_cs(tab, n_threads, n_cells)
479  sll_int32, intent(in) :: n_threads, n_cells
480  type(sll_t_charge_accumulator_2d_cs_ptr), dimension(:), pointer, intent(inout) :: tab
481  sll_int32 :: i, j
482 
483  do i = 1, n_cells
484  do j = 2, n_threads
485  tab(1)%q%q_acc(i) = tab(1)%q%q_acc(i) + tab(j)%q%q_acc(i)
486  end do
487  end do
488  end subroutine sll_s_sum_accumulators_cs
489 
490  ! The above are the only routines that should live here. Something like taking
491  ! a list of particules and accumulating the charge, will change the charge but
492  ! not the particles so it could legitimately live here. This would introduce
493  ! a dependency on the particle group module. At the same time, a particle
494  ! pusher would take the accumulators and change the particle list, thus it
495  ! would be tempting to put it in the particle group module, but this would
496  ! introduce the opposite dependency. Hence
497 
498 !!$ subroutine sll_accumulate_charge_on_cell( &
499 !!$ particle, &
500 !!$ charge )
501 !!$
502 !!$ type(sll_particle_2d), intent(in) :: particle
503 !!$ type(charge_accumulator_cell), intent(inout) :: charge
504 !!$ sll_int64 :: j
505 !!$
506 !!$ charge%q_sw = charge%q_sw + &
507 !!$ particle%q * (1._f64 - particle%dx) * (1._f64 - particle%dy)
508 !!$
509 !!$ charge%q_se = charge%q_se + &
510 !!$ particle%q * particle%dx * (1._f64 - particle%dy)
511 !!$
512 !!$ charge%q_nw = charge%q_nw + &
513 !!$ particle%q * (1._f64 - particle%dx) * particle%dy
514 !!$
515 !!$ charge%q_ne = charge%q_ne + &
516 !!$ particle%q * particle%dx * particle%dy
517 !!$
518 !!$ end subroutine sll_accumulate_charge_on_cell
519 
520 !!$ EDWIN CG
521 !!$ ! The following is a pseudo-accumulator. It is written for use while some
522 !!$ ! problems with the parallel loading of the previous accumulator are resolved.
523 !!$ ! This one is only useful to precompute the values of the electric field in
524 !!$ ! a structure that can have the same layout as the potential array.
525 !!$ type :: efield_2d_point
526 !!$ sll_real64 :: ex
527 !!$ sll_real64 :: ey
528 !!$ end type efield_2d_point
529 
530 end module sll_m_accumulators
Particle deposition routines.
subroutine, public sll_s_sum_accumulators(tab, n_threads, n_cells)
subroutine, public sll_s_reset_field_accumulator_to_zero(E_acc)
type(charge_accumulator_cell_2d_cs) function q_acc_add_cs(q1, q2)
subroutine, public sll_s_sum_accumulators_cs(tab, n_threads, n_cells)
subroutine, public sll_s_reset_field_accumulator_cs_to_zero(E_acc)
type(sll_t_charge_accumulator_2d) function, pointer, public sll_f_new_charge_accumulator_2d(mesh_2d)
subroutine, public sll_s_reset_charge_accumulator_to_zero(acc)
subroutine, public sll_s_charge_accumulator_2d_init(acc, mesh_2d)
subroutine, public sll_s_field_accumulator_2d_init(E_acc, mesh_2d)
type(sll_t_electric_field_accumulator) function, pointer, public sll_f_new_field_accumulator_2d(mesh_2d)
subroutine, public sll_s_charge_accumulator_2d_cs_init(acc, mesh_2d)
type(sll_t_charge_accumulator_cell_2d) function q_acc_add(q1, q2)
type(sll_t_charge_accumulator_2d_cs) function, pointer, public sll_f_new_charge_accumulator_2d_cs(mesh_2d)
subroutine, public sll_s_reset_charge_accumulator_to_zero_cs(acc)
type(sll_t_electric_field_accumulator_cs) function, pointer, public sll_f_new_field_accumulator_cs_2d(mesh_2d)
subroutine delete_charge_accumulator_2d(acc)
subroutine delete_charge_accumulator_2d_cs(acc)
subroutine, public sll_s_field_accumulator_cs_2d_init(E_acc, mesh_2d)
Cartesian mesh basic types.
    Report Typos and Errors