Report Typos and Errors    
Semi-Lagrangian Library
Modular library for kinetic and gyrokinetic simulations of plasmas in fusion energy devices.
sll_m_particle_mesh_coupling_spline_smooth_1d.F90
Go to the documentation of this file.
1 
6 
7 !+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
8 #include "sll_assert.h"
9 #include "sll_memory.h"
10 #include "sll_working_precision.h"
11 #include "sll_errors.h"
12 
15 
16  use sll_m_low_level_bsplines, only: &
17  sll_s_uniform_bsplines_eval_basis
18 
23 
26 
27  use sll_m_particle_group_base, only: &
29 
30  use sll_m_splines_pp, only: &
32 
33 
34  implicit none
35 
36  public :: &
40 
41  private
42 !+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
43 
44 
47 
48  contains
49  procedure :: add_charge => add_charge_single_smoothened_spline_1d
50  procedure :: add_particle_mass => add_particle_mass_spline_smooth_1d
51  procedure :: add_particle_mass_full => add_particle_mass_full_spline_smooth_1d
53  procedure :: add_current_update_v => add_current_update_v_smoothened_spline_1d
54 
56 
57  procedure :: evaluate_int => evaluate_int_smoothened_spline_1d
58 
60 
61 contains
62 
63  !---------------------------------------------------------------------------!
65  subroutine add_charge_single_smoothened_spline_1d(self, position, marker_charge, rho_dofs)
66  class( sll_t_particle_mesh_coupling_spline_smooth_1d ), intent(inout) :: self
67  sll_real64, intent( in ) :: position(self%dim)
68  sll_real64, intent( in ) :: marker_charge
69  sll_real64, intent( inout ) :: rho_dofs(self%n_dofs)
70 
71  !local variables
72  sll_int32 :: i1, q
73  sll_int32 :: index1d, index
74  sll_real64 :: xi(1), pos, scaling, weight
75  sll_int32 :: n_quad_points
76  !sll_real64, allocatable :: quad_xw(:,:)
77  sll_real64 :: integ(1:self%n_span)
78 
79  xi(1) = (position(1) - self%domain(1))/self%delta_x
80  index = floor(xi(1))+1
81  xi(1) = xi(1) - real(index-1, f64)
82  !index = index - self%spline_degree
83 
84  ! Quadrature formula
85  n_quad_points = self%n_quadp1_points!(self%spline_degree+3)/2
86  !allocate( quad_xw(2, n_quad_points) )
87  !quad_xw = sll_f_gauss_legendre_points_and_weights(n_quad_points)
88  !quad_xw(1,:) = (quad_xw(1,:) + 1.0_f64)*0.5_f64
89  !quad_xw(2,:) = quad_xw(2,:)*0.5_f64
90 
91  scaling = 1.0_f64 - xi(1)
92  weight = marker_charge * self%scaling * scaling
93  ! First and third interval
94  do q = 1, n_quad_points
95  pos = xi(1)+ scaling * self%quads1_xw(1,q)
96  call sll_s_uniform_bsplines_eval_basis(self%spline_degree, pos, self%spline_val)
97  ! First interval
98  integ = self%quads1_xw(2,q)*self%spline_val*scaling * self%quads1_xw(1,q)
99 
100  do i1 = 1, self%n_span
101  index1d = modulo(index- self%spline_degree+i1-3,self%n_cells)+1
102  rho_dofs(index1d) = rho_dofs(index1d) + weight * integ(i1)!&
103  !(marker_charge * integ(i1)* self%scaling * scaling * self%delta_x)
104  end do
105  ! Third interval
106  integ = self%quads1_xw(2,q)*self%spline_val*(1.0_f64-scaling * self%quads1_xw(1,q))
107 
108  do i1 = 1, self%n_span
109  index1d = modulo(index- self%spline_degree+i1-2,self%n_cells)+1
110  rho_dofs(index1d) = rho_dofs(index1d) +weight * integ(i1) !&
111  !(marker_charge * integ(i1)* self%scaling * scaling * self%delta_x)
112  end do
113  end do
114 
115  weight = marker_charge * self%scaling * xi(1)
116  ! Second and fourth interval
117  do q = 1, n_quad_points
118  pos = xi(1) * self%quads1_xw(1,q)
119  call sll_s_uniform_bsplines_eval_basis(self%spline_degree, pos, self%spline_val)
120  ! Second interval
121  integ = self%quads1_xw(2,q)*self%spline_val*(scaling + xi(1) * self%quads1_xw(1,q))
122 
123  do i1 = 1, self%n_span
124  index1d = modulo(index- self%spline_degree+i1-2,self%n_cells)+1
125  rho_dofs(index1d) = rho_dofs(index1d) +weight * integ(i1)
126  end do
127  ! Fourth interval
128  integ = self%quads1_xw(2,q)*self%spline_val* xi(1)*(1.0_f64-self%quads1_xw(1,q))
129 
130  do i1 = 1, self%n_span
131  index1d = modulo(index- self%spline_degree+i1-1,self%n_cells)+1
132  rho_dofs(index1d) = rho_dofs(index1d) +weight * integ(i1)
133  end do
134  end do
136 
137 
138  !---------------------------------------------------------------------------!
140  subroutine add_current_update_v_smoothened_spline_1d (self, position_old, position_new, marker_charge, qoverm, bfield_dofs, vi, j_dofs)
141  class(sll_t_particle_mesh_coupling_spline_smooth_1d), intent(inout) :: self
142  sll_real64, intent(in) :: position_old(self%dim)
143  sll_real64, intent(in) :: position_new(self%dim)
144  sll_real64, intent(in) :: marker_charge
145  sll_real64, intent(in) :: qoverm
146  sll_real64, intent(in) :: bfield_dofs(:)
147  sll_real64, intent(inout) :: vi(:)
148  sll_real64, intent(inout) :: j_dofs(:)
149 
150  ! local variables
151  sll_real64 :: xi
152  sll_int32 :: index_old, index_new, ind
153  sll_real64 :: r_old, r_new
154 
155  ! Read out particle position and velocity
156  ! Compute index_old, the index of the last DoF on the grid the particle contributes to, and r_old, its position (normalized to cell size one).
157  xi = (position_old(1) - self%domain(1)) /&
158  self%delta_x
159  index_old = floor(xi)
160  r_old = xi - real(index_old,f64)
161 
162  ! Compute the new box index index_new and normalized position r_old.
163  xi = (position_new(1) - self%domain(1)) /&
164  self%delta_x
165  index_new = floor(xi)
166  r_new = xi - real(index_new ,f64)
167 
168  ! Evaluate the integral over x with prime function of the smoothing kernel S at old and new position
169  ! We only account for the support of the kernel S
170  call update_smoothened_single_spline_1d(self, [r_old], index_old, marker_charge, qoverm, &
171  j_dofs, bfield_dofs, vi(2))
172  call update_smoothened_single_spline_1d(self, [r_new], index_new, -marker_charge, -qoverm, &
173  j_dofs, bfield_dofs, vi(2))
174 
175  ! Now, we have to add the part where one of the prime functions is already 1 but the other is not yet
176  ! (when both are one they just cancel out each other and we do not have any contribution)
177  ! In this part, we can reuse the old update_jv routines since the prime of the kernel is just the 1
178 
179 
180  ! This version does the same based on the primitive
181 !!$ if (index_old == index_new) then
182 !!$ call self%update_jv_pp(r_old, r_new, index_old+1, marker_charge, &
183 !!$ qoverm, vi(2), j_dofs, bfield_dofs)
184 !!$ elseif (index_old < index_new) then
185 !!$ call self%update_jv_pp (r_old, 1.0_f64, index_old+1, marker_charge, &
186 !!$ qoverm, vi(2), j_dofs, bfield_dofs)
187 !!$ call self%update_jv_pp (0.0_f64, r_new, index_new+1, marker_charge, &
188 !!$ qoverm, vi(2), j_dofs, bfield_dofs)
189 !!$ do ind = index_old+2, index_new
190 !!$ call self%update_jv_pp (0.0_f64, 1.0_f64, ind, marker_charge, &
191 !!$ qoverm, vi(2), j_dofs, bfield_dofs)
192 !!$ end do
193 !!$ else
194 !!$ call self%update_jv_pp (1.0_f64, r_new, index_new+1, marker_charge, qoverm, &
195 !!$ vi(2), j_dofs, bfield_dofs)
196 !!$ call self%update_jv_pp (r_old, 0.0_f64, index_old+1, marker_charge, qoverm, &
197 !!$ vi(2), j_dofs, bfield_dofs)
198 !!$ do ind = index_new+2, index_old
199 !!$ call self%update_jv_pp (1.0_f64, 0.0_f64, ind, marker_charge, qoverm, &
200 !!$ vi(2), j_dofs, bfield_dofs)
201 !!$ end do
202 !!$ end if
203  ! Version without primitive
204  if (index_old == index_new) then
205  if (r_old < r_new) then
206  call self%update_jv(r_old, r_new, index_old+1, marker_charge, &
207  qoverm, 1.0_f64, vi(2), j_dofs, bfield_dofs)
208  else
209  call self%update_jv(r_new, r_old, index_old+1, marker_charge, qoverm, &
210  -1.0_f64, vi(2), j_dofs, bfield_dofs)
211  end if
212  elseif (index_old < index_new) then
213  call self%update_jv (r_old, 1.0_f64, index_old+1, marker_charge, &
214  qoverm, 1.0_f64, vi(2), j_dofs, bfield_dofs)
215  call self%update_jv (0.0_f64, r_new, index_new+1, marker_charge, &
216  qoverm, 1.0_f64, vi(2), j_dofs, bfield_dofs)
217  do ind = index_old+2, index_new
218  call self%update_jv (0.0_f64, 1.0_f64, ind, marker_charge, &
219  qoverm, 1.0_f64, vi(2), j_dofs, bfield_dofs)
220  end do
221  else
222  call self%update_jv (r_new, 1.0_f64, index_new+1, marker_charge, qoverm, &
223  -1.0_f64, vi(2), j_dofs, bfield_dofs)
224  call self%update_jv (0.0_f64, r_old, index_old+1, marker_charge, qoverm, &
225  -1.0_f64, vi(2), j_dofs, bfield_dofs)
226  do ind = index_new+2, index_old
227  call self%update_jv (0.0_f64, 1.0_f64, ind, marker_charge, qoverm, &
228  -1.0_f64, vi(2), j_dofs, bfield_dofs)
229  end do
230  end if
231 
233 
234 
235  !---------------------------------------------------------------------------!
237  subroutine update_smoothened_single_spline_1d(self, position_normalized, box, marker_charge, qoverm, rho_dofs, bfield_dofs, vi)
238  class( sll_t_particle_mesh_coupling_spline_smooth_1d ), intent(inout) :: self
239  sll_real64, intent( in ) :: position_normalized(self%dim)
240  sll_int32, intent( in ) :: box
241  sll_real64, intent( in ) :: marker_charge
242  sll_real64, intent(in) :: qoverm
243  sll_real64, intent( inout ) :: rho_dofs(self%n_dofs)
244  sll_real64, intent(inout) :: vi
245  sll_real64, intent(in) :: bfield_dofs(self%n_dofs)
246 
247  !local variables
248  sll_int32 :: i1, q
249  sll_int32 :: index1d, index
250  sll_real64 :: xi(1), pos, scaling, weight, pos_hat
251  sll_int32 :: n_quad_points
252  !sll_real64, allocatable :: quad_xw(:,:)
253  sll_real64 :: integ(1:self%n_span)
254 
255  xi(1) = position_normalized(1)
256  index = box +1
257 
258  ! Quadrature formula
259  n_quad_points = self%n_quads2_points!(self%spline_degree+4)/2
260  !allocate( quad_xw(2, n_quad_points) )
261  !quad_xw = sll_f_gauss_legendre_points_and_weights(n_quad_points)
262  !quad_xw(1,:) = (quad_xw(1,:) + 1.0_f64)*0.5_f64
263  !quad_xw(2,:) = quad_xw(2,:)*0.5_f64
264 
265  scaling = 1.0_f64 - xi(1)
266  weight = marker_charge * self%scaling * scaling * self%delta_x
267  ! First and third interval
268  do q = 1, n_quad_points
269  pos = xi(1)+ scaling * self%quads2_xw(1,q)
270  pos_hat = scaling * self%quads2_xw(1,q)
271  call sll_s_uniform_bsplines_eval_basis(self%spline_degree, pos, self%spline_val)
272  ! First interval
273  integ = self%quads2_xw(2,q)*self%spline_val* pos_hat**2*0.5_f64
274 
275  do i1 = 1, self%n_span
276  index1d = modulo(index- self%spline_degree+i1-3,self%n_cells)+1
277  rho_dofs(index1d) = rho_dofs(index1d) + weight * integ(i1)
278  vi = vi - qoverm * integ(i1) * bfield_dofs(index1d) * self%delta_x * scaling
279  end do
280  ! Third interval
281  pos_hat = self%quads2_xw(1,q)* scaling
282  integ = self%quads2_xw(2,q)*self%spline_val* (pos_hat + (1.0_f64-pos_hat**2)*0.5_f64)
283 
284  do i1 = 1, self%n_span
285  index1d = modulo(index- self%spline_degree+i1-2,self%n_cells)+1
286  rho_dofs(index1d) = rho_dofs(index1d) +weight * integ(i1)
287  vi = vi - qoverm * integ(i1) * bfield_dofs(index1d) * self%delta_x * scaling
288  end do
289  end do
290 
291  weight = marker_charge * self%scaling * xi(1) * self%delta_x
292  ! Second and fourth interval
293  do q = 1, n_quad_points
294  pos = xi(1) * self%quads2_xw(1,q)
295  call sll_s_uniform_bsplines_eval_basis(self%spline_degree, pos, self%spline_val)
296  ! Second interval
297  pos_hat = 1.0_f64 - xi(1) * (1.0_f64 - self%quads2_xw(1,q))
298  integ = self%quads2_xw(2,q)*self%spline_val* pos_hat**2*0.5_f64
299 
300  do i1 = 1, self%n_span
301  index1d = modulo(index- self%spline_degree+i1-2,self%n_cells)+1
302  rho_dofs(index1d) = rho_dofs(index1d) +weight * integ(i1)
303  vi = vi - qoverm * integ(i1) * bfield_dofs(index1d) * self%delta_x * xi(1)
304  end do
305  ! Fourth interval
306  !pos_hat = xi(1) * (1.0_f64 - self%quads2_xw(1,q))
307  pos_hat = scaling + xi(1) * self%quads2_xw(1,q)
308  integ = self%quads2_xw(2,q)*self%spline_val*(pos_hat + (1.0_f64-pos_hat**2)*0.5_f64)
309 
310  do i1 = 1, self%n_span
311  index1d = modulo(index- self%spline_degree+i1-1,self%n_cells)+1
312  rho_dofs(index1d) = rho_dofs(index1d) +weight * integ(i1)
313  vi = vi - qoverm * integ(i1) * bfield_dofs(index1d) * self%delta_x * xi(1)
314  end do
315  end do
317 
318 
319  !---------------------------------------------------------------------------!
321  subroutine evaluate_int_prime_smoothened_single_spline_1d(self, position_normalized, box, field_dofs, field_int )
322  class( sll_t_particle_mesh_coupling_spline_smooth_1d ), intent(inout) :: self
323  sll_real64, intent( in ) :: position_normalized(self%dim)
324  sll_int32, intent( in ) :: box
325  sll_real64, intent(inout) :: field_int
326  sll_real64, intent(in) :: field_dofs(self%n_dofs)
327 
328  !local variables
329  sll_int32 :: i1, q
330  sll_int32 :: index1d, index
331  sll_real64 :: xi(1), pos, scaling, weight, pos_hat
332  sll_int32 :: n_quad_points
333  !sll_real64, allocatable :: quad_xw(:,:)
334  sll_real64 :: integ(1:self%n_span)
335 
336  !xi(1) = (position(1) - self%domain(1))/self%delta_x
337  !index = floor(xi(1))+1
338  !xi(1) = xi(1) - real(index-1, f64)
339  xi(1) = position_normalized(1)
340  index = box+1
341 
342  ! Quadrature formula
343  n_quad_points = self%n_quads2_points
344 
345  scaling = 1.0_f64 - xi(1)
346  weight = self%scaling * scaling * self%delta_x
347  ! First and third interval
348  do q = 1, n_quad_points
349  pos = xi(1)+ scaling * self%quads2_xw(1,q)
350  pos_hat = scaling * self%quads2_xw(1,q)
351  call sll_s_uniform_bsplines_eval_basis(self%spline_degree, pos, self%spline_val)
352  ! First interval
353  integ = self%quads2_xw(2,q)*self%spline_val* pos_hat**2*0.5_f64
354 
355  do i1 = 1, self%n_span
356  index1d = modulo(index- self%spline_degree+i1-3,self%n_cells)+1
357  field_int = field_int + integ(i1) * field_dofs(index1d) * self%delta_x * scaling
358  end do
359  ! Third interval
360  pos_hat = self%quads2_xw(1,q)* scaling
361  integ = self%quads2_xw(2,q)*self%spline_val* (pos_hat + (1.0_f64-pos_hat**2)*0.5_f64)
362 
363  do i1 = 1, self%n_span
364  index1d = modulo(index- self%spline_degree+i1-2,self%n_cells)+1
365  field_int = field_int + integ(i1) * field_dofs(index1d) * self%delta_x * scaling
366  end do
367  end do
368 
369  weight = self%scaling * xi(1) * self%delta_x
370  ! Second and fourth interval
371  do q = 1, n_quad_points
372  pos = xi(1) * self%quads2_xw(1,q)
373  call sll_s_uniform_bsplines_eval_basis(self%spline_degree, pos, self%spline_val)
374  ! Second interval
375  pos_hat = 1.0_f64 - xi(1) * (1.0_f64 - self%quads2_xw(1,q))
376  integ = self%quads2_xw(2,q)*self%spline_val* pos_hat**2*0.5_f64
377 
378  do i1 = 1, self%n_span
379  index1d = modulo(index- self%spline_degree+i1-2,self%n_cells)+1
380  field_int = field_int + integ(i1) * field_dofs(index1d) * self%delta_x * xi(1)
381  end do
382  ! Fourth interval
383  pos_hat = scaling + xi(1) * self%quads2_xw(1,q)
384  integ = self%quads2_xw(2,q)*self%spline_val*(pos_hat + (1.0_f64-pos_hat**2)*0.5_f64)
385 
386  do i1 = 1, self%n_span
387  index1d = modulo(index- self%spline_degree+i1-1,self%n_cells)+1
388  field_int = field_int + integ(i1) * field_dofs(index1d) * self%delta_x * xi(1)
389  end do
390  end do
391 
393 
396  subroutine evaluate_int_simple_smoothened_spline_1d(self, lower, upper, index, sign, field_dofs, field_int)
397  class(sll_t_particle_mesh_coupling_spline_1d), intent(inout) :: self
398  sll_real64, intent(in) :: lower
399  sll_real64, intent(in) :: upper
400  sll_int32, intent(in) :: index
401  sll_real64, intent(in) :: sign
402  sll_real64, intent(in) :: field_dofs(self%n_dofs)
403  sll_real64, intent(inout) :: field_int
404 
405  !Local variables
406  sll_int32 :: ind, i_grid, i_mod, n_cells, j
407  sll_real64 :: c1, c2
408 
409 
410  n_cells = self%n_cells
411 
412  c1 = 0.5_f64*(upper-lower)
413  c2 = 0.5_f64*(upper+lower)
414 
415  call sll_s_uniform_bsplines_eval_basis(self%spline_degree, c1*self%quad_xw(1,1)+c2, &
416  self%spline_val)
417  !alternative version with horner and pp-form
418  !call sll_s_spline_pp_horner_m_1d(self%spline_pp, self%spline_val, self%spline_degree, c1*self%quad_xw(1,1)+c2)
419  self%spline_val = self%spline_val * (self%quad_xw(2,1)*c1)
420  do j=2,self%n_quad_points
421  call sll_s_uniform_bsplines_eval_basis(self%spline_degree, c1*self%quad_xw(1,j)+c2, &
422  self%spline_val_more)
423  !alternative version with horner and pp-form
424  !call sll_s_spline_pp_horner_m_1d(self%spline_pp, self%spline_val_more, self%spline_degree, c1*self%quad_xw(1,j)+c2)
425  self%spline_val = self%spline_val + self%spline_val_more * (self%quad_xw(2,j)*c1)
426  end do
427  self%spline_val = self%spline_val * (sign*self%delta_x)
428 
429  ind = 1
430  do i_grid = index - self%spline_degree , index
431  i_mod = modulo(i_grid, n_cells ) + 1
432  field_int = field_int + self%spline_val(ind)*field_dofs(i_mod)
433  ind = ind + 1
434  end do
435 
437 
438 
439  !---------------------------------------------------------------------------!
441  subroutine evaluate_field_single_smoothened_spline_1d(self, position, field_dofs, field_value)
442  class(sll_t_particle_mesh_coupling_spline_smooth_1d), intent( inout ) :: self
443  sll_real64, intent( in ) :: position(self%dim)
444  sll_real64, intent( in ) :: field_dofs(self%n_dofs)
445  sll_real64, intent( out ) :: field_value
446 
447  !local variables
448  sll_int32 :: j
449  sll_int32 :: index
450  sll_real64 :: dx
451  sll_real64 :: field_val
452  sll_real64 :: scaling
453  !sll_real64 :: quad_xw(2,self%n_quadp1_points)
454 
455  !quad_xw = self%quadp1_xw
456  !quad_xw(1,:) = (quad_xw(1,:) + 1.0_f64)*0.5_f64
457  !quad_xw(2,:) = quad_xw(2,:)*0.5_f64
458 
459 
460  dx = (position(1) - self%domain(1))/self%delta_x
461  index = floor(dx)
462  dx = dx - real(index, f64)
463 
464  field_value = 0.0_f64
465  ! First interval
466  scaling = 1.0_f64-dx
467  do j=1,self%n_quadp1_points
468  call self%evaluate_simple &
469  ( [position(1)+(self%quads1_xw(1,j)*scaling-1.0_f64)*self%delta_x], field_dofs, field_val)
470  field_value = field_value + self%quads1_xw(2,j)*scaling* (self%quads1_xw(1,j)*scaling) * field_val
471  end do
472 
473  ! Second interval
474  do j=1,self%n_quadp1_points
475  call self%evaluate_simple &
476  ( [position(1)+(self%quads1_xw(1,j)-1.0_f64)*dx*self%delta_x], field_dofs, field_val)
477  field_value = field_value + self%quads1_xw(2,j)*dx* (self%quads1_xw(1,j)*dx+scaling) * field_val
478  end do
479 
480  ! Third interval
481  do j=1,self%n_quadp1_points
482  call self%evaluate_simple &
483  ( [position(1)+self%quads1_xw(1,j)*scaling*self%delta_x], field_dofs, field_val)
484  field_value = field_value + self%quads1_xw(2,j)*scaling* (1.0_f64-self%quads1_xw(1,j)*scaling) * field_val
485  end do
486 
487  ! Fourth interval
488  do j=1,self%n_quadp1_points
489  call self%evaluate_simple &
490  ( [position(1)+(1.0_f64+dx*(self%quads1_xw(1,j)-1.0_f64))*self%delta_x], field_dofs, field_val)
491  field_value = field_value + self%quads1_xw(2,j)*dx* ((1.0_f64-self%quads1_xw(1,j))*dx) * field_val
492  end do
493 
494 
496 
497 
498 
499 
500  !---------------------------------------------------------------------------!
502  subroutine add_current_evaluate_smoothened_spline_1d (self, position_old, position_new, marker_charge, vbar, field_dofs, j_dofs, field)
503  class( sll_t_particle_mesh_coupling_spline_smooth_1d ), intent(inout) :: self
504  sll_real64, intent( in ) :: position_old(self%dim)
505  sll_real64, intent( in ) :: position_new(self%dim)
506  sll_real64, intent( in ) :: marker_charge
507  sll_real64, intent( in ) :: vbar
508  sll_real64, intent( in ) :: field_dofs(self%n_dofs)
509  sll_real64, intent( inout ) :: j_dofs(self%n_dofs)
510  sll_real64, intent( out ) :: field
511 
512  sll_real64 :: fields(2)
513 
514  fields(2) = 0.0_f64
515 
516  call add_current_update_v_smoothened_spline_1d(self, position_old, position_new, marker_charge, &
517  -1.0_f64, field_dofs,fields, j_dofs)
518  field = fields(2)/vbar
519 
520 
522 
523 
524  !---------------------------------------------------------------------------!
526  subroutine evaluate_int_smoothened_spline_1d (self, position_old, position_new, vbar, field_dofs, field)
527  class( sll_t_particle_mesh_coupling_spline_smooth_1d ), intent(inout) :: self
528  sll_real64, intent( in ) :: position_old(self%dim)
529  sll_real64, intent( in ) :: position_new(self%dim)
530  sll_real64, intent( in ) :: vbar
531  sll_real64, intent( in ) :: field_dofs(self%n_dofs)
532  sll_real64, intent( out ) :: field
533 
534  sll_real64 :: xi
535  sll_int32 :: index_old, index_new, ind
536  sll_real64 :: r_old, r_new
537 
538  ! Read out particle position and velocity
539  ! Compute index_old, the index of the last DoF on the grid the particle contributes to, and r_old, its position (normalized to cell size one).
540  xi = (position_old(1) - self%domain(1)) /&
541  self%delta_x
542  index_old = floor(xi)
543  r_old = xi - real(index_old,f64)
544 
545  ! Compute the new box index index_new and normalized position r_old.
546  xi = (position_new(1) - self%domain(1)) /&
547  self%delta_x
548  index_new = floor(xi)
549  r_new = xi - real(index_new ,f64)
550 
551  field = 0.0_f64
552  call evaluate_int_prime_smoothened_single_spline_1d(self, [r_new], index_new, field_dofs, field )
553  field = -field;
554  call evaluate_int_prime_smoothened_single_spline_1d(self, [r_old], index_old, field_dofs, field )
555 
556  ! Account for the part where one of the prime function is constantly one
557  if (index_old == index_new) then
558  if (r_old < r_new) then
559  !call self%update_jv(r_old, r_new, index_old+1, marker_charge, &
560  ! qoverm, 1.0_f64, vi(2), j_dofs, bfield_dofs)
561  call evaluate_int_simple_smoothened_spline_1d (self, r_old, r_new, index_old+1, &
562  1.0_f64, field_dofs, field)
563  else
564  !call self%update_jv(r_new, r_old, index_old+1, marker_charge, qoverm, &
565  ! -1.0_f64, vi(2), j_dofs, bfield_dofs)
566  call evaluate_int_simple_smoothened_spline_1d (self, r_new, r_old, index_old+1, &
567  -1.0_f64, field_dofs, field)
568  end if
569  elseif (index_old < index_new) then
570  call evaluate_int_simple_smoothened_spline_1d (self, r_old, 1.0_f64, index_old+1, &
571  1.0_f64, field_dofs, field)
572  call evaluate_int_simple_smoothened_spline_1d (self, 0.0_f64, r_new, index_new+1, &
573  1.0_f64, field_dofs, field)
574  !call self%update_jv (r_old, 1.0_f64, index_old+1, marker_charge, &
575  ! qoverm, 1.0_f64, vi(2), j_dofs, bfield_dofs)
576  !call self%update_jv (0.0_f64, r_new, index_new+1, marker_charge, &
577  ! qoverm, 1.0_f64, vi(2), j_dofs, bfield_dofs)
578  do ind = index_old+2, index_new
579  call evaluate_int_simple_smoothened_spline_1d (self, 0.0_f64, 1.0_f64, ind, &
580  1.0_f64, field_dofs, field)
581  !call self%update_jv (0.0_f64, 1.0_f64, ind, marker_charge, &
582  ! qoverm, 1.0_f64, vi(2), j_dofs, bfield_dofs)
583  end do
584  else
585  call evaluate_int_simple_smoothened_spline_1d (self, r_new, 1.0_f64, index_new+1, &
586  -1.0_f64, field_dofs, field)
587  call evaluate_int_simple_smoothened_spline_1d (self, 0.0_f64, r_old, index_old+1, &
588  -1.0_f64, field_dofs, field)
589  !call self%update_jv (r_new, 1.0_f64, index_new+1, marker_charge, qoverm, &
590  ! -1.0_f64, vi(2), j_dofs, bfield_dofs)
591  !call self%update_jv (0.0_f64, r_old, index_old+1, marker_charge, qoverm, &
592  ! -1.0_f64, vi(2), j_dofs, bfield_dofs)
593  do ind = index_new+2, index_old
594  call evaluate_int_simple_smoothened_spline_1d (self, 0.0_f64, 1.0_f64, ind, &
595  -1.0_f64, field_dofs, field)
596  !call self%update_jv (0.0_f64, 1.0_f64, ind, marker_charge, qoverm, &
597  ! -1.0_f64, vi(2), j_dofs, bfield_dofs)
598  end do
599  end if
600 
601  field = field/vbar
602 
603  end subroutine evaluate_int_smoothened_spline_1d
604 
605 
606  !-------------------------------------------------------------------------------------------
607 
608  subroutine sll_s_new_particle_mesh_coupling_spline_smooth_1d_ptr(smoother, domain, n_cells, no_particles, spline_degree, smoothing_type)
609  class( sll_c_particle_mesh_coupling_1d), pointer, intent(out) :: smoother
610  sll_int32, intent(in) :: n_cells
611  sll_real64, intent(in) :: domain(2)
612  sll_int32, intent(in) :: no_particles
613  sll_int32, intent(in) :: spline_degree
614  sll_int32, intent(in) :: smoothing_type
615 
616  !local variables
617  sll_int32 :: ierr
618 
619 
620  sll_allocate( sll_t_particle_mesh_coupling_spline_smooth_1d :: smoother , ierr)
621  sll_assert( ierr == 0)
622 
623  select type( smoother )
625  call smoother%init( domain, n_cells, no_particles, spline_degree, smoothing_type )
626  end select
627 
629 
630  !----------------------------------------------------------------------------------
631 
632  subroutine sll_s_new_particle_mesh_coupling_spline_smooth_1d(smoother, domain, n_cells, no_particles, spline_degree, smoothing_type)
633  class( sll_c_particle_mesh_coupling_1d), allocatable, intent(out):: smoother
634  sll_int32, intent(in) :: n_cells
635  sll_real64, intent(in) :: domain(2)
636  sll_int32, intent(in) :: no_particles
637  sll_int32, intent(in) :: spline_degree
638  sll_int32, intent(in) :: smoothing_type
639 
640  !local variables
641  sll_int32 :: ierr
642 
643 
644  allocate( sll_t_particle_mesh_coupling_spline_smooth_1d :: smoother , stat=ierr)
645  sll_assert( ierr == 0)
646 
647  select type( smoother )
649  call smoother%init( domain, n_cells, no_particles, spline_degree, smoothing_type )
650  end select
651 
653 !---------------------------------------------------------------------------!
655  subroutine add_particle_mass_spline_smooth_1d(self, position, marker_charge, particle_mass)
656  class( sll_t_particle_mesh_coupling_spline_smooth_1d ), intent(inout) :: self
657  sll_real64, intent( in ) :: position(self%dim)
658  sll_real64, intent( in ) :: marker_charge
659  sll_real64, intent( inout ) :: particle_mass(:,:)
660 
661  !local variables
662  sll_int32 :: i1, column
663  sll_int32 :: index1d, index
664  sll_real64 :: xi(1)
665  sll_real64 :: scratch(1:self%n_span+2)
666 
667  sll_assert( size(particle_mass,1) == self%n_span+2 )
668  sll_assert( size(particle_mass,2) == self%n_dofs )
669 
670  xi(1) = (position(1) - self%domain(1))/self%delta_x
671  index = ceiling(xi(1))
672  xi(1) = xi(1) - real(index-1, f64)
673  index = index - self%spline_degree-1
674 
675  scratch = 0.0_f64
676  call add_charge_box(self, xi, scratch)
677 
678 
679  do i1 = 1, self%n_span+2
680  index1d = modulo(index+i1-2,self%n_cells)+1
681  do column = i1, self%n_span+2
682  particle_mass(column-i1+1, index1d) = particle_mass( column-i1+1, index1d) + &
683  marker_charge * scratch(i1) * scratch(column)
684  ! Note: No scaling since Galerkin function
685  end do
686  end do
687 
688 
690 !---------------------------------------------------------------------------!
693  subroutine add_particle_mass_full_spline_smooth_1d(self, position, marker_charge, particle_mass)
694  class( sll_t_particle_mesh_coupling_spline_smooth_1d ), intent(inout) :: self
695  sll_real64, intent( in ) :: position(self%dim)
696  sll_real64, intent( in ) :: marker_charge
697  sll_real64, intent( inout ) :: particle_mass(:,:)
698 
699  !local variables
700  sll_int32 :: i1, column, ind
701  sll_int32 :: index1d, index
702  sll_real64 :: xi(1)
703  sll_real64 :: scratch(1:self%n_span+2)
704 
705  sll_assert( size(particle_mass,1) == 2*self%n_span+3 )
706  sll_assert( size(particle_mass,2) == self%n_dofs )
707 
708  xi(1) = (position(1) - self%domain(1))/self%delta_x
709  index = ceiling(xi(1))
710  xi(1) = xi(1) - real(index-1, f64)
711  index = index - self%spline_degree-1
712 
713  scratch = 0.0_f64
714  call add_charge_box(self, xi, scratch)
715 
716 
717  do i1 = 1, self%n_span+2
718  index1d = modulo(index+i1-2,self%n_cells)+1
719  ind = 1+(self%n_span+2-i1)
720  do column = 1, self%n_span+2
721  particle_mass(ind, index1d) = particle_mass( ind, index1d) + &
722  marker_charge * scratch(i1) * scratch(column)
723  ! Note: No scaling since Galerkin function
724  ind = ind+1
725  end do
726  end do
727 
728 
730 
731 
732  !---------------------------------------------------------------------------!
734  subroutine add_charge_box(self, position, rho_dofs)
735  class( sll_t_particle_mesh_coupling_spline_smooth_1d ), intent(inout) :: self
736  sll_real64, intent( in ) :: position(self%dim)
737  sll_real64, intent( inout ) :: rho_dofs(self%n_span+2)
738 
739  !local variables
740  sll_int32 :: i1, q
741  sll_int32 :: index1d
742  sll_real64 :: xi(1), pos, scaling, weight
743  sll_int32 :: n_quad_points
744  sll_real64 :: integ(1:self%n_span)
745 
746  xi(1) = position(1)
747 
748  ! Quadrature formula
749  n_quad_points = self%n_quadp1_points
750 
751  scaling = 1.0_f64 - xi(1)
752  weight = scaling
753  ! First and third interval
754  do q = 1, n_quad_points
755  pos = xi(1)+ scaling * self%quads1_xw(1,q)
756  call sll_s_uniform_bsplines_eval_basis(self%spline_degree, pos, self%spline_val)
757  ! First interval
758  integ = self%quads1_xw(2,q)*self%spline_val*scaling * self%quads1_xw(1,q)
759 
760  do i1 = 1, self%n_span
761  index1d = i1
762  !index1d = modulo(index- self%spline_degree+i1-3,self%n_cells)+1
763  rho_dofs(index1d) = rho_dofs(index1d) + weight * integ(i1)!&
764  !(marker_charge * integ(i1)* self%scaling * scaling * self%delta_x)
765  end do
766  ! Third interval
767  integ = self%quads1_xw(2,q)*self%spline_val*(1.0_f64-scaling * self%quads1_xw(1,q))
768 
769  do i1 = 1, self%n_span
770  index1d = i1+1
771  !index1d = modulo(index- self%spline_degree+i1-2,self%n_cells)+1
772  rho_dofs(index1d) = rho_dofs(index1d) +weight * integ(i1) !&
773  !(marker_charge * integ(i1)* self%scaling * scaling * self%delta_x)
774  end do
775  end do
776 
777  weight = xi(1)
778  ! Second and fourth interval
779  do q = 1, n_quad_points
780  pos = xi(1) * self%quads1_xw(1,q)
781  call sll_s_uniform_bsplines_eval_basis(self%spline_degree, pos, self%spline_val)
782  ! Second interval
783  integ = self%quads1_xw(2,q)*self%spline_val*(scaling + xi(1) * self%quads1_xw(1,q))
784 
785  do i1 = 1, self%n_span
786  index1d = i1+1
787  !index1d = modulo(index- self%spline_degree+i1-2,self%n_cells)+1
788  rho_dofs(index1d) = rho_dofs(index1d) +weight * integ(i1) !+&
789  !(marker_charge * integ(i1)* self%scaling * xi(1) * self%delta_x)
790  end do
791  ! Fourth interval
792  integ = self%quads1_xw(2,q)*self%spline_val* xi(1)*(1.0_f64-self%quads1_xw(1,q))
793 
794  do i1 = 1, self%n_span
795  index1d = i1+2
796  !index1d = modulo(index- self%spline_degree+i1-1,self%n_cells)+1
797  rho_dofs(index1d) = rho_dofs(index1d) +weight * integ(i1) !+&
798  !(marker_charge * integ(i1)* self%scaling * xi(1) * self%delta_x)
799  end do
800  end do
801 
802  end subroutine add_charge_box
803 
real(kind=f64) function, dimension(2, 1:npoints), public sll_f_gauss_legendre_points_and_weights(npoints, a, b)
Returns a 2d array of size (2,npoints) containing gauss-legendre points and weights in the interval [...
Low level arbitrary degree splines.
Base class for kernel smoothers for accumulation and field evaluation in PIC.
integer(kind=i32), parameter, public sll_p_collocation
Kernel smoother for 1d with splines of arbitrary degree placed on a uniform mesh.
Kernel smoother for 2d with splines of arbitrary degree placed on a uniform mesh.
subroutine add_charge_single_smoothened_spline_1d(self, position, marker_charge, rho_dofs)
Evaluates the integral int_{poisition_old}^{position_new} field(x) d x.
subroutine add_particle_mass_spline_smooth_1d(self, position, marker_charge, particle_mass)
Add particle mass for one particle (upper triangular version)
subroutine evaluate_field_single_smoothened_spline_1d(self, position, field_dofs, field_value)
Evaluate field with smoothing at at position position.
subroutine evaluate_int_smoothened_spline_1d(self, position_old, position_new, vbar, field_dofs, field)
Add current for one particle and evaluate the field (according to iterative part in discrete gradient...
subroutine evaluate_int_simple_smoothened_spline_1d(self, lower, upper, index, sign, field_dofs, field_int)
Helper function to evaluate the integrated efield in one interval (without smoothing kernel) (similar...
subroutine update_smoothened_single_spline_1d(self, position_normalized, box, marker_charge, qoverm, rho_dofs, bfield_dofs, vi)
Integration over the prime function of the smoothing kernel S (for v update and j accumulation)
subroutine add_particle_mass_full_spline_smooth_1d(self, position, marker_charge, particle_mass)
Add particle mass for one particle (full matrix) WARNING: THIS FUNCTION SEEMS TO HAVE BUGS.
subroutine add_current_evaluate_smoothened_spline_1d(self, position_old, position_new, marker_charge, vbar, field_dofs, j_dofs, field)
Add current for one particle and evaluate the field (according to iterative part in discrete gradient...
subroutine add_charge_box(self, position, rho_dofs)
Add charge of one particle with smoothing.
subroutine add_current_update_v_smoothened_spline_1d(self, position_old, position_new, marker_charge, qoverm, bfield_dofs, vi, j_dofs)
Add current for one particle and update v (according to H_p1 part in Hamiltonian splitting)
subroutine, public sll_s_new_particle_mesh_coupling_spline_smooth_1d_ptr(smoother, domain, n_cells, no_particles, spline_degree, smoothing_type)
subroutine, public sll_s_new_particle_mesh_coupling_spline_smooth_1d(smoother, domain, n_cells, no_particles, spline_degree, smoothing_type)
subroutine evaluate_int_prime_smoothened_single_spline_1d(self, position_normalized, box, field_dofs, field_int)
Integration over the prime function of the smoothing kernel S (for evaluation only)
Splines in pp form.
subroutine, public sll_s_spline_pp_horner_primitive_1d(val, degree, pp_coeffs, x)
Perform a 1d hornerschema on the pp_coeffs evaluate at x.
    Report Typos and Errors