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_cl_3d_feec.F90
Go to the documentation of this file.
1 
5 
7 
8  !+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
9 #include "sll_assert.h"
10 #include "sll_memory.h"
11 #include "sll_errors.h"
12 #include "sll_working_precision.h"
13 
16 
17  use sll_m_low_level_bsplines, only: &
18  sll_s_uniform_bsplines_eval_basis, &
19  sll_s_uniform_bsplines_eval_deriv
20 
23 
24  use sll_m_splines_pp, only: &
32 
33  implicit none
34 
35  public :: &
38 
39  private
40  !+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
41 
44 
45  sll_real64 :: rdelta_x(3)
46  ! Information about the particles
47  sll_int32 :: no_particles
48  sll_int32 :: n_quad_points
49 
50  sll_real64, allocatable :: spline_val(:,:)
51  sll_real64, allocatable :: spline_0(:,:)
52  sll_real64, allocatable :: spline1_0(:,:)
53  sll_real64, allocatable :: spline_1(:,:)
54  sll_real64, allocatable :: spline_2d(:,:)
55  sll_real64, allocatable :: spline1_2d(:,:)
56  sll_real64, allocatable :: spline1_3d(:,:,:)
57  sll_real64, allocatable :: spline2_3d(:,:,:)
58  sll_real64, allocatable :: spline_val_more(:,:)
59  sll_real64, allocatable :: j1d(:)
60 
61  sll_real64, allocatable :: quad_xw(:,:)
62 
63  sll_int32, allocatable :: index1d(:,:)
64 
65  sll_int32 :: n_total0
66  sll_int32 :: n_total1
67 
68  ! For 1d quadrature in 3d space
69  sll_int32 :: n_quad_points_line
70  sll_real64, allocatable :: quad_xw_line(:,:)
71 
72  contains
73 
74  procedure :: add_charge => add_charge_single_spline_cl_3d_feec
75  procedure :: add_particle_mass => add_particle_mass_spline_cl_3d_feec
76  procedure :: add_particle_mass_od => add_particle_mass_od_spline_cl_3d_feec
77  procedure :: evaluate => evaluate_field_single_spline_cl_3d_feec
78  procedure :: evaluate_multiple => evaluate_multiple_spline_cl_3d_feec
80  procedure :: add_current_evaluate
81  procedure :: add_current_update_v_component1 => add_current_update_v_component1_spline_3d_feec
82  procedure :: add_current_update_v_component2 => add_current_update_v_component2_spline_3d_feec
83  procedure :: add_current_update_v_component3 => add_current_update_v_component3_spline_3d_feec
84 
85  procedure :: init => init_spline_cl_3d_feec
86  procedure :: free => free_spline_cl_3d_feec
88 
89  type :: vector
90  sll_real64, allocatable :: vals(:)
91  end type vector
92 
93 contains
94 
95 
96  !---------------------------------------------------------------------------!
98  subroutine add_charge_single_spline_cl_3d_feec(self, position, marker_charge, degree, rho_dofs)
99  class( sll_t_particle_mesh_coupling_spline_cl_3d_feec ), intent(inout) :: self
100  sll_real64, intent( in ) :: position(3)
101  sll_real64, intent( in ) :: marker_charge
102  sll_int32, intent( in ) :: degree(3)
103  sll_real64, intent( inout ) :: rho_dofs(:)
104  !local variables
105  sll_int32 :: box(3)
106  sll_real64 :: xi(3)
107  sll_int32 :: index3d(3)
108  sll_int32 :: index1d
109  sll_int32 :: i,j,k
110 
111 
112  call convert_x_to_xbox( self, position, xi, box )
113 
114  self%spline_val = 0.0_f64
115  if(degree(1)==self%spline_degree(1)) then
116  call sll_s_uniform_bsplines_eval_basis_clamped( self%spline_pp_0%spline1, self%n_cells(1), degree(1), xi(1), box(1), self%spline_val(1:degree(1)+1,1) )
117  else if(degree(1)==self%spline_degree(1)-1) then
118  call sll_s_uniform_bsplines_eval_basis_clamped( self%spline_pp_1%spline1, self%n_cells(1), degree(1), xi(1), box(1), self%spline_val(1:degree(1)+1,1) )
119  end if
120 
121  do j=2,3
122  call sll_s_uniform_bsplines_eval_basis( degree(j), xi(j), self%spline_val(1:degree(j)+1,j) )
123  end do
124 
125  box(2:3) = box(2:3)-degree(2:3)
126  call box_index( self, box(2), 2 )
127  call box_index( self, box(3), 3 )
128  do k = 1, degree(3)+1
129  index3d(3) = (self%index1d(k,3)-1)*(self%n_cells(1)+degree(1))*self%n_cells(2)
130  do j = 1, degree(2)+1
131  index3d(2) = index3d(3) + (self%index1d(j,2)-1)*(self%n_cells(1)+degree(1))
132  do i = 1, degree(1)+1
133  index1d = index3d(2) + box(1)+i-1
134  rho_dofs(index1d) = rho_dofs(index1d) + &
135  marker_charge * self%spline_val(i,1) *&
136  self%spline_val(j,2) * self%spline_val(k,3)
137  end do
138  end do
139  end do
140 
141 
143 
144 
145  !---------------------------------------------------------------------------!
147  subroutine add_particle_mass_spline_cl_3d_feec(self, position, marker_charge, degree, particle_mass )
148  class( sll_t_particle_mesh_coupling_spline_cl_3d_feec ), intent(inout) :: self
149  sll_real64, intent( in ) :: position(3)
150  sll_real64, intent( in ) :: marker_charge
151  sll_int32, intent( in ) :: degree(3)
152  sll_real64, intent( inout ) :: particle_mass(:,:)
153  !local variables
154  sll_int32 :: box(3)
155  sll_real64 :: xi(3)
156  sll_int32 :: index3d(3)
157  sll_int32 :: index1d
158  sll_int32 :: i,j,k, col1, col2, col3, ind
159 
160 
161  call convert_x_to_xbox( self, position, xi, box )
162 
163  self%spline_val = 0.0_f64
164  if(degree(1)==self%spline_degree(1)) then
165  call sll_s_uniform_bsplines_eval_basis_clamped( self%spline_pp_0%spline1, self%n_cells(1), degree(1), xi(1), box(1), self%spline_val(1:degree(1)+1,1) )
166  else if(degree(1)==self%spline_degree(1)-1) then
167  call sll_s_uniform_bsplines_eval_basis_clamped( self%spline_pp_1%spline1, self%n_cells(1), degree(1), xi(1), box(1), self%spline_val(1:degree(1)+1,1) )
168  end if
169 
170  do j = 2, 3
171  call sll_s_uniform_bsplines_eval_basis( degree(j), xi(j), self%spline_val(1:degree(j)+1,j) )
172  end do
173 
174  !3d array
175  do k = 1, degree(3)+1
176  do j = 1, degree(2)+1
177  do i = 1, degree(1)+1
178  self%spline1_3d(i,j,k) = self%spline_val(i,1)*self%spline_val(j,2)*self%spline_val( k, 3)
179  end do
180  end do
181  end do
182 
183 
184  box(2:3) = box(2:3)-degree(2:3)
185  call box_index( self, box(2), 2 )
186  call box_index( self, box(3), 3 )
187  do k = 1, degree(3)+1
188  index3d(3) = (self%index1d(k,3)-1)*(self%n_cells(1)+degree(1))*self%n_cells(2)
189  do j = 1, degree(2)+1
190  index3d(2) = index3d(3) + (self%index1d(j,2)-1)*(self%n_cells(1)+degree(1))
191  do i = 1, degree(1)+1
192  index1d = index3d(2) + box(1)+i-1
193  ind = 1+(degree(1)+1-i)+(degree(2)+1-j)*(2*degree(1)+1)+ &
194  (degree(3)+1-k)*(2*degree(1)+1)*(2*degree(2)+1)
195  do col3 = 1, degree(3)+1
196  do col2 = 1, degree(2)+1
197  do col1 = 1, degree(1)+1
198  particle_mass(ind, index1d) = particle_mass( ind, index1d) +&
199  self%spline1_3d(i, j, k) * self%spline1_3d(col1, col2, col3)*&
200  marker_charge
201  ind = ind+1
202  end do
203  ind = ind+degree(1)
204  end do
205  ind = ind+degree(2) * (2*degree(1)+1)
206  end do
207  end do
208  end do
209  end do
210 
211 
213 
214 
216  subroutine add_particle_mass_od_spline_cl_3d_feec(self, position, marker_charge, degree1, degree2, particle_mass )
217  class( sll_t_particle_mesh_coupling_spline_cl_3d_feec ), intent(inout) :: self
218  sll_real64, intent( in ) :: position(3)
219  sll_real64, intent( in ) :: marker_charge
220  sll_int32, intent( in ) :: degree1(3), degree2(3)
221  sll_real64, intent( inout ) :: particle_mass(:,:)
222  !local variables
223  sll_int32 :: box(3)
224  sll_real64 :: xi(3)
225  sll_int32 :: index3d(3)
226  sll_int32 :: index1d
227  sll_int32 :: i,j,k, col1, col2, col3, ind
228 
229  call convert_x_to_xbox( self, position, xi, box )
230 
231  self%spline_0 = 0.0_f64
232  self%spline1_0 = 0.0_f64
233 
234  if(degree1(1)==self%spline_degree(1)) then
235  call sll_s_uniform_bsplines_eval_basis_clamped( self%spline_pp_0%spline1, self%n_cells(1), degree1(1), xi(1), box(1), self%spline_0(1:degree1(1)+1,1) )
236  else if(degree1(1)==self%spline_degree(1)-1) then
237  call sll_s_uniform_bsplines_eval_basis_clamped( self%spline_pp_1%spline1, self%n_cells(1), degree1(1), xi(1), box(1), self%spline_0(1:degree1(1)+1,1) )
238  end if
239 
240  if(degree2(1)==self%spline_degree(1)) then
241  call sll_s_uniform_bsplines_eval_basis_clamped( self%spline_pp_0%spline1, self%n_cells(1), degree2(1), xi(1), box(1), self%spline1_0(1:degree2(1)+1,1) )
242  else if(degree2(1)==self%spline_degree(1)-1) then
243  call sll_s_uniform_bsplines_eval_basis_clamped( self%spline_pp_1%spline1, self%n_cells(1), degree2(1), xi(1), box(1), self%spline1_0(1:degree2(1)+1,1) )
244  end if
245 
246  do j = 2, 3
247  call sll_s_uniform_bsplines_eval_basis( degree1(j), xi(j), self%spline_0(1:degree1(j)+1,j) )
248  call sll_s_uniform_bsplines_eval_basis( degree2(j), xi(j), self%spline1_0(1:degree2(j)+1,j) )
249  end do
250 
251  self%spline1_3d=0._f64
252  !3d array
253  do k =1, degree1(3)+1
254  do j = 1, degree1(2)+1
255  do i = 1, degree1(1)+1
256  self%spline1_3d(i,j,k) = self%spline_0(i,1)*self%spline_0(j,2)*self%spline_0(k,3)
257  end do
258  end do
259  end do
260  self%spline2_3d=0._f64
261  do k = 1, degree2(3)+1
262  do j = 1, degree2(2)+1
263  do i = 1, degree2(1)+1
264  self%spline2_3d(i,j,k) = self%spline1_0(i,1)*self%spline1_0(j,2)*self%spline1_0(k,3)
265  end do
266  end do
267  end do
268 
269  box(2:3) = box(2:3)-degree1(2:3)
270  call box_index( self, box(2), 2 )
271  call box_index( self, box(3), 3 )
272  do k = 1, degree1(3)+1
273  index3d(3) = (self%index1d(k,3)-1)*(self%n_cells(1)+degree1(1))*self%n_cells(2)
274  do j = 1, degree1(2)+1
275  index3d(2) = index3d(3) + (self%index1d(j,2)-1)*(self%n_cells(1)+degree1(1))
276  do i = 1, degree1(1)+1
277  index1d = index3d(2) + box(1)+i-1
278  ind = 1+(degree1(1)+1-i)+(degree1(2)+1-j)*(degree1(1)+degree2(1)+1)+ &
279  (degree1(3)+1-k)*(degree1(1)+degree2(1)+1)*(degree1(2)+degree2(2)+1)
280  do col3 = 1, degree2(3)+1
281  do col2 = 1, degree2(2)+1
282  do col1 = 1, degree2(1)+1
283  particle_mass( ind, index1d) = particle_mass( ind, index1d) +&
284  self%spline1_3d(i, j, k) * self%spline2_3d(col1, col2, col3)*&
285  marker_charge
286  ind = ind+1
287  end do
288  ind = ind+degree1(1)
289  end do
290  ind = ind+degree1(2) * (degree1(1)+degree2(1)+1)
291  end do
292  end do
293  end do
294  end do
295 
297 
298 
299  !---------------------------------------------------------------------------!
301  subroutine evaluate_field_single_spline_cl_3d_feec(self, position, degree, field_dofs, field_value)
302  class(sll_t_particle_mesh_coupling_spline_cl_3d_feec), intent( inout ) :: self
303  sll_real64, intent( in ) :: position(3)
304  sll_int32 , intent( in ) :: degree(3)
305  sll_real64, intent( in ) :: field_dofs(:)
306  sll_real64, intent( out ) :: field_value
307  !local variables
308  sll_int32 :: i,j,k
309  sll_int32 :: box(3)
310  sll_int32 :: index3d(3)
311  sll_int32 :: index1d
312  sll_real64 :: xi(3)
313 
314  call convert_x_to_xbox( self, position, xi, box )
315 
316  self%spline_val = 0.0_f64
317  if(degree(1)==self%spline_degree(1)) then
318  call sll_s_uniform_bsplines_eval_basis_clamped( self%spline_pp_0%spline1, self%n_cells(1), degree(1), xi(1), box(1), self%spline_val(1:degree(1)+1,1) )
319  else if(degree(1)==self%spline_degree(1)-1) then
320  call sll_s_uniform_bsplines_eval_basis_clamped( self%spline_pp_1%spline1, self%n_cells(1), degree(1), xi(1), box(1), self%spline_val(1:degree(1)+1,1) )
321  end if
322 
323  do j=2,3
324  call sll_s_uniform_bsplines_eval_basis( degree(j), xi(j), self%spline_val(1:degree(j)+1,j) )
325  end do
326 
327  field_value = 0.0_f64
328  box(2:3) = box(2:3)-degree(2:3)
329  call box_index( self, box(2), 2 )
330  call box_index( self, box(3), 3 )
331  do k = 1, degree(3)+1
332  index3d(3) = (self%index1d(k,3)-1)*(self%n_cells(1)+degree(1))*self%n_cells(2)
333  do j = 1, degree(2)+1
334  index3d(2) = index3d(3) + (self%index1d(j,2)-1)*(self%n_cells(1)+degree(1))
335  do i = 1, degree(1)+1
336  index1d = index3d(2) + box(1)+i-1
337  field_value = field_value + field_dofs(index1d) * &
338  self%spline_val(i,1)*self%spline_val(j,2)*self%spline_val(k,3)
339  end do
340  end do
341  end do
342 
344 
346  subroutine evaluate_multiple_spline_cl_3d_feec(self, position, components, field_dofs, field_value)
347  class(sll_t_particle_mesh_coupling_spline_cl_3d_feec), intent( inout ) :: self
348  sll_real64, intent( in ) :: position(3)
349  sll_int32, intent(in) :: components(:)
350  sll_real64, intent( in ) :: field_dofs(:,:)
351  sll_real64, intent(out) :: field_value(:)
352 
353 
354  print*, 'evaluate_multiple_spline_cl_3d is not yet implemented'
355 
357 
358 
359  !---------------------------------------------------------------------------!
361  subroutine add_current_evaluate ( self, position_old, position_new, xdot, efield_dofs, j_dofs, efield_val)
362  class( sll_t_particle_mesh_coupling_spline_cl_3d_feec ), intent(inout) :: self
363  sll_real64, intent( in ) :: position_old(3)
364  sll_real64, intent( in ) :: position_new(3)
365  sll_real64, intent( in ) :: xdot(3)
366  sll_real64, intent( in ) :: efield_dofs(:)
367  sll_real64, intent( inout ) :: j_dofs(:)
368  sll_real64, intent( out ) :: efield_val(3)
369  !local variables
370  sll_real64 :: xold(3), xnew(3), xnewtilde(3), xbox(3)
371  sll_int32 :: boxold(3), boxnew(3), sigma_counter(3), boxdiff(3), increment(3), box(3)
372  sll_real64 :: sigma_r, sigma_l, sigma, sigma_next(3), field_value(3), weight
373  sll_int32 :: j, q, bl, maxind, index_is
374  type(vector) :: sigmas(3)
375 
376  call convert_x_to_xbox( self, position_old, xold, boxold )
377  call convert_x_to_xbox( self, position_new, xnew, boxnew )
378 
379  ! Now we need to compute the normalized 1d line along which to integrate:
380  boxdiff = boxnew-boxold
381  xnewtilde = xnew + real(boxdiff,f64)
382 
383  sigma_l = 0.0_f64
384  box = boxold ! We start in the old box
385 
386  sigma_counter = 0
387 
388  efield_val = 0.0_f64
389 
390  do j = 1, 3
391  if (boxdiff(j) > 0 ) then
392  allocate ( sigmas(j)%vals(boxdiff(j)+1) )
393  do bl = 1, boxdiff(j)
394  sigmas(j)%vals(bl) = (real(bl,f64) - xold(j))/(xnewtilde(j)-xold(j))
395  end do
396  sigmas(j)%vals(boxdiff(j)+1) = 1.0_f64
397  sigma_next(j) = sigmas(j)%vals(1)
398  increment(j) = 1
399  elseif (boxdiff(j) < 0 ) then
400  allocate ( sigmas(j)%vals(-boxdiff(j)+1) )
401  do bl = boxdiff(j)+1, 0
402  sigmas(j)%vals(-bl+1) = (real(bl,f64) - xold(j))/(xnewtilde(j)-xold(j))
403  end do
404  sigmas(j)%vals(-boxdiff(j)+1) = 1.0_f64
405  sigma_next(j) = sigmas(j)%vals(1)
406  increment(j) = -1
407  else
408  sigma_next(j) = 1.0_f64
409  increment(j) = 0
410  end if
411  end do
412 
413  sigma_r = 0.0_f64
414  do while ( sigma_r < 1.0_f64 )
415  ! Identify index of next intersection
416  index_is = minloc(sigma_next, dim=1)
417  sigma_r = sigma_next(index_is)
418 
419  do q = 1, self%n_quad_points_line
420  sigma = sigma_l + (sigma_r-sigma_l) * self%quad_xw_line(1,q)
421  xbox = xold* (1.0_f64 - sigma) + xnewtilde * sigma - real(sigma_counter*increment, f64)
422  if (maxval(xbox) > 1.0_f64 ) then
423  print*, 'box error 1', xbox, sigma, sigma_counter, increment
424  xbox = min(xbox, 1._f64)
425  elseif (minval(xbox) < 0.0_f64 ) then
426  print*, 'box error 2', xbox, sigma, sigma_counter, increment
427  xbox = max(xbox, 0._f64)
428  end if
429 
430  weight = self%quad_xw_line(2,q)*(sigma_r-sigma_l)
431 
432  call point_add_eval (self, box, xbox, efield_dofs, xdot*weight, j_dofs, field_value )
433  efield_val = efield_val + field_value * weight
434  end do
435  if (sigma_r < 1.0_f64 ) then
436  ! Update the index
437  sigma_counter(index_is) = sigma_counter(index_is)+1
438  sigma_next(index_is) = sigmas(index_is)%vals(sigma_counter(index_is)+1)
439  box(index_is) = box(index_is) + increment(index_is)
440  sigma_l = sigma_r
441  end if
442  end do
443 
444  end subroutine add_current_evaluate
445 
446 
448  subroutine point_add_eval ( self, box_in, xbox, field_dofs, weight, j_dofs, field_value )
449  class( sll_t_particle_mesh_coupling_spline_cl_3d_feec ), intent(inout) :: self
450  sll_int32, intent(in) :: box_in(3)
451  sll_real64, intent(in) :: xbox(3)
452  sll_real64, intent(in) :: field_dofs(:)
453  sll_real64, intent(in) :: weight(3)
454  sll_real64, intent(inout) :: j_dofs(:)
455  sll_real64, intent(out) :: field_value(3)
456  !local variables
457  sll_int32 :: i,j,k, index1d
458  sll_int32 :: box(3), index3d(3), deg
459  sll_real64 :: spval
460 
461  field_value = 0.0_f64
462 
463  deg=self%spline_degree(1)
464  call sll_s_uniform_bsplines_eval_basis_clamped( self%spline_pp_0%spline1, self%n_cells(1), deg, xbox(1), box_in(1), self%spline_0(1:deg+1,1) )
465 
466  deg=self%spline_degree(1)-1
467  call sll_s_uniform_bsplines_eval_basis_clamped( self%spline_pp_1%spline1, self%n_cells(1), deg, xbox(1), box_in(1), self%spline_1(1:deg+1,1) )
468 
469  do j = 2, 3
470  call sll_s_uniform_bsplines_eval_basis( self%spline_degree(j), xbox(j), &
471  self%spline_0(1:self%spline_degree(j)+1,j) )
472  call sll_s_uniform_bsplines_eval_basis( self%spline_degree(j)-1, xbox(j), &
473  self%spline_1(1:self%spline_degree(j),j) )
474  end do
475 
476  box(1) = box_in(1)
477  box(2:3) = box_in(2:3)-self%spline_degree(2:3)
478 
479  deg = self%spline_degree(1)-1
480 
481  call box_index( self, box(2), 2 )
482  call box_index( self, box(3), 3 )
483  do k = 1, self%spline_degree(3)+1
484  index3d(3) = (self%index1d(k,3)-1)*(self%n_cells(1)+deg)*self%n_cells(2)
485  do j = 1, self%spline_degree(2)+1
486  index3d(2) = index3d(3) + (self%index1d(j,2)-1)*(self%n_cells(1)+deg)
487  do i = 1, self%spline_degree(1)
488  index1d = index3d(2) + box(1)+i-1
489 
490  spval = self%spline_1(i,1) * &
491  self%spline_0(j,2) * self%spline_0(k,3)
492  field_value(1) = field_value(1) + field_dofs(index1d) * spval
493  j_dofs(index1d) = j_dofs(index1d) + &
494  weight(1) * spval
495  end do
496  end do
497  end do
498 
499  box(2) = box(2)+1
500  deg = self%spline_degree(1)
501  call box_index( self, box(2), 2 )
502  do k = 1, self%spline_degree(3)+1
503  index3d(3) = (self%index1d(k,3)-1)*(self%n_cells(1)+deg)*self%n_cells(2)
504  do j = 1, self%spline_degree(2)
505  index3d(2) = index3d(3) + (self%index1d(j,2)-1)*(self%n_cells(1)+deg)
506  do i = 1, self%spline_degree(1)+1
507  index1d = index3d(2) + box(1)+i-1 + self%n_total1
508 
509  spval = self%spline_0(i,1) * &
510  self%spline_1(j,2) * self%spline_0(k,3)
511  field_value(2) = field_value(2) + field_dofs(index1d ) * spval
512  j_dofs(index1d) = j_dofs(index1d) + &
513  weight(2) * spval
514  end do
515  end do
516  end do
517 
518  box(2) = box(2)-1
519  box(3) = box(3)+1
520  call box_index( self, box(2), 2 )
521  call box_index( self, box(3), 3 )
522  do k = 1, self%spline_degree(3)
523  index3d(3) = (self%index1d(k,3)-1)*(self%n_cells(1)+deg)*self%n_cells(2)
524  do j = 1, self%spline_degree(2)+1
525  index3d(2) = index3d(3) + (self%index1d(j,2)-1)*(self%n_cells(1)+deg)
526  do i = 1, self%spline_degree(1)+1
527  index1d = index3d(2) + box(1)+i-1 + self%n_total1+self%n_total0
528 
529  spval = self%spline_0(i,1) * &
530  self%spline_0(j,2) * self%spline_1(k,3)
531  field_value(3) = field_value(3) + field_dofs(index1d ) * spval
532  j_dofs(index1d) = j_dofs(index1d) + &
533  weight(3) * spval
534  end do
535  end do
536  end do
537 
538 
539  end subroutine point_add_eval
540 
541 
543  subroutine add_current_cl_3d ( self, position_old, position_new, xdot, j_dofs)
544  class( sll_t_particle_mesh_coupling_spline_cl_3d_feec ), intent(inout) :: self
545  sll_real64, intent( in ) :: position_old(3)
546  sll_real64, intent( in ) :: position_new(3)
547  sll_real64, intent( in ) :: xdot(3)
548  sll_real64, intent( inout ) :: j_dofs(:)
549  !local variables
550  sll_real64 :: xold(3), xnew(3), xnewtilde(3), xbox(3)
551  sll_int32 :: boxold(3), boxnew(3), sigma_counter(3), boxdiff(3), increment(3), box(3)
552  sll_real64 :: sigma_r, sigma_l, sigma, sigma_next(3), field_value(3), weight
553  sll_int32 :: j, q, bl, maxind, index_is
554  type(vector) :: sigmas(3)
555 
556  call convert_x_to_xbox( self, position_old, xold, boxold )
557  call convert_x_to_xbox( self, position_new, xnew, boxnew )
558 
559  ! Now we need to compute the normalized 1d line along which to integrate:
560  boxdiff = boxnew-boxold
561  xnewtilde = xnew + real(boxdiff,f64)
562  sigma_l = 0.0_f64
563  box = boxold ! We start in the old box
564  sigma_counter = 0
565 
566  do j = 1, 3
567  if (boxdiff(j) > 0 ) then
568  allocate ( sigmas(j)%vals(boxdiff(j)+1) )
569  do bl = 1, boxdiff(j)
570  sigmas(j)%vals(bl) = (real(bl,f64) - xold(j))/(xnewtilde(j)-xold(j))
571  end do
572  sigmas(j)%vals(boxdiff(j)+1) = 1.0_f64
573  sigma_next(j) = sigmas(j)%vals(1)
574  increment(j) = 1
575  elseif (boxdiff(j) < 0 ) then
576  allocate ( sigmas(j)%vals(-boxdiff(j)+1) )
577  do bl = boxdiff(j)+1, 0
578  sigmas(j)%vals(-bl+1) = (real(bl,f64) - xold(j))/(xnewtilde(j)-xold(j))
579  end do
580  sigmas(j)%vals(-boxdiff(j)+1) = 1.0_f64
581  sigma_next(j) = sigmas(j)%vals(1)
582  increment(j) = -1
583  else
584  sigma_next(j) = 1.0_f64
585  increment(j) = 0
586  end if
587  end do
588 
589  sigma_r = 0.0_f64
590  do while ( sigma_r < 1.0_f64 )
591  ! Identify index of next intersection
592  index_is = minloc(sigma_next, dim=1)
593  sigma_r = sigma_next(index_is)
594 
595  do q = 1, self%n_quad_points_line
596  sigma = sigma_l + (sigma_r-sigma_l) * self%quad_xw_line(1,q)
597  xbox = xold* (1.0_f64 - sigma) + xnewtilde * sigma - real(sigma_counter*increment, f64)
598  if (maxval(xbox) > 1.0_f64 ) then
599  print*, 'box error1', xbox, sigma, sigma_counter, increment
600  xbox = min(xbox, 1._f64)
601  elseif (minval(xbox) < 0.0_f64 ) then
602  print*, 'box error2', xbox, sigma, sigma_counter, increment
603  xbox = max(xbox, 0._f64)
604  end if
605 
606  weight = self%quad_xw_line(2,q)*(sigma_r-sigma_l)
607  call integrate_spline_cl_3d(self, box, xbox, xdot*weight, j_dofs )
608  end do
609  if (sigma_r < 1.0_f64 ) then
610  ! Update the index
611  sigma_counter(index_is) = sigma_counter(index_is)+1
612  sigma_next(index_is) = sigmas(index_is)%vals(sigma_counter(index_is)+1)
613  box(index_is) = box(index_is) + increment(index_is)
614  sigma_l = sigma_r
615  end if
616  end do
617  end subroutine add_current_cl_3d
618 
619 
621  subroutine integrate_spline_cl_3d( self, box_in, xbox, weight, j_dofs )
622  class( sll_t_particle_mesh_coupling_spline_cl_3d_feec ), intent(inout) :: self
623  sll_int32, intent( in ) :: box_in(3)
624  sll_real64, intent( in ) :: xbox(3)
625  sll_real64, intent( in ) :: weight(3)
626  sll_real64, intent( inout ) :: j_dofs(:)
627  !local variables
628  sll_int32 :: i,j,k, index1d
629  sll_int32 :: box(3), index3d(3), deg
630 
631  deg=self%spline_degree(1)
632  call sll_s_uniform_bsplines_eval_basis_clamped( self%spline_pp_0%spline1, self%n_cells(1), deg, xbox(1), box_in(1), self%spline_0(1:deg+1,1) )
633 
634  deg=self%spline_degree(1)-1
635  call sll_s_uniform_bsplines_eval_basis_clamped( self%spline_pp_1%spline1, self%n_cells(1), deg, xbox(1), box_in(1), self%spline_1(1:deg+1,1) )
636 
637 
638  do j = 2, 3
639  call sll_s_uniform_bsplines_eval_basis( self%spline_degree(j), xbox(j), &
640  self%spline_0(1:self%spline_degree(j)+1,j) )
641  call sll_s_uniform_bsplines_eval_basis( self%spline_degree(j)-1, xbox(j), &
642  self%spline_1(1:self%spline_degree(j),j) )
643  end do
644 
645  box(1) = box_in(1)
646  box(2:3) = box_in(2:3)-self%spline_degree(2:3)
647 
648  call box_index( self, box(2), 2 )
649  call box_index( self, box(3), 3 )
650  do k = 1, self%spline_degree(3)+1
651  index3d(3) = (self%index1d(k,3)-1)*(self%n_dofs(1)-1)*self%n_cells(2)
652  do j = 1, self%spline_degree(2)+1
653  index3d(2) = index3d(3) + (self%index1d(j,2)-1)*(self%n_dofs(1)-1)
654  do i = 1, self%spline_degree(1)
655  index1d = index3d(2) + box(1)+i-1
656 
657  j_dofs(index1d) = j_dofs(index1d) + &
658  weight(1) * self%spline_1(i,1) * &
659  self%spline_0(j,2) * self%spline_0(k,3)
660  end do
661  end do
662  end do
663 
664  box(2) = box(2)+1
665  call box_index( self, box(2), 2 )
666  do k = 1, self%spline_degree(3)+1
667  index3d(3) = (self%index1d(k,3)-1)*self%n_dofs(1)*self%n_cells(2)
668  do j = 1, self%spline_degree(2)
669  index3d(2) = index3d(3) + (self%index1d(j,2)-1)*self%n_dofs(1)
670  do i = 1, self%spline_degree(1)+1
671  index1d = index3d(2) + box(1)+i-1 + self%n_total1
672 
673  j_dofs(index1d) = j_dofs(index1d) + &
674  weight(2) * self%spline_0(i,1) * &
675  self%spline_1(j,2) * self%spline_0(k,3)
676  end do
677  end do
678  end do
679 
680  box(2) = box(2)-1
681  box(3) = box(3)+1
682  call box_index( self, box(2), 2 )
683  call box_index( self, box(3), 3 )
684  do k = 1, self%spline_degree(3)
685  index3d(3) = (self%index1d(k,3)-1)*self%n_dofs(1)*self%n_cells(2)
686  do j = 1, self%spline_degree(2)+1
687  index3d(2) = index3d(3) + (self%index1d(j,2)-1)*self%n_dofs(1)
688  do i = 1, self%spline_degree(1)+1
689  index1d = index3d(2) + box(1)+i-1 + self%n_total1+self%n_total0
690  j_dofs(index1d) = j_dofs(index1d) + &
691  weight(3) * self%spline_0(i,1) * &
692  self%spline_0(j,2) * self%spline_1(k,3)
693  end do
694  end do
695  end do
696 
697 
698  end subroutine integrate_spline_cl_3d
699 
700 
702  subroutine add_current_update_v_component1_spline_3d_feec (self, position_old, position_new, marker_charge, qoverm, bfield_dofs, vi, j_dofs)
703  class(sll_t_particle_mesh_coupling_spline_cl_3d_feec), intent(inout) :: self
704  sll_real64, intent(in) :: position_old(3)
705  sll_real64, intent(in) :: position_new
706  sll_real64, intent(in) :: marker_charge
707  sll_real64, intent(in) :: qoverm
708  sll_real64, intent(in) :: bfield_dofs(:)
709  sll_real64, intent(inout) :: vi(3)
710  sll_real64, intent(inout) :: j_dofs(:)
711  !local variables
712  sll_int32 :: box(3), boxnew, boxold
713  sll_real64 :: xi(3)
714  sll_int32 :: index3d(3)
715  sll_int32 :: index1d
716  sll_int32 :: i,j,k
717  sll_real64 :: xnew
718  sll_real64 :: vt(2), vtt2, vtt3
719  sll_int32 :: start1, start2
720  sll_int32 :: local_size
721  sll_int32 :: startjk, stride(2)
722  sll_real64 :: splinejk
723 
724  start1 = self%n_total0+self%n_total1
725  start2 = self%n_total0
726  stride = 1
727 
728  call convert_x_to_xbox( self, position_old, xi, box )
729  call convert_x_to_xbox_1d( self, 1, position_new, xnew, boxnew )
730  boxold = box(1)
731 
732  ! Achtung wir brauchen nun splines von beidem Grad
733  self%spline_0 = 0.0_f64
734  self%spline_1 = 0.0_f64
735  call sll_s_spline_pp_horner_m_1d(self%spline_pp_0%spline2, self%spline_0(1:self%spline_degree(2)+1,2), self%spline_degree(2), xi(2))
736  call sll_s_spline_pp_horner_m_1d(self%spline_pp_1%spline2, self%spline_1(1:self%spline_degree(2),2), self%spline_degree(2)-1, xi(2))
737 
738  call sll_s_spline_pp_horner_m_1d(self%spline_pp_0%spline3, self%spline_0(1:self%spline_degree(3)+1,3), self%spline_degree(3), xi(3))
739  call sll_s_spline_pp_horner_m_1d(self%spline_pp_1%spline3, self%spline_1(1:self%spline_degree(3),3), self%spline_degree(3)-1, xi(3))
740 
741  box(2:3) = box(2:3) - self%spline_degree(2:3)
742  local_size = abs(boxnew-boxold)+self%spline_degree(1)
743 
744  call box_index( self, box(2), 2 )
745  call box_index( self, box(3), 3 )
746  do k = 1, self%spline_degree(3)+1
747  vtt2 = 0.0_f64
748  vtt3 = 0.0_f64
749  index3d(3) = self%index1d(k,3)
750  do j = 1, self%spline_degree(2)+1
751  index3d(2) = self%index1d(j,2)
752 
753  startjk = 1 + (index3d(2)-1)*(self%n_dofs(1)-1) + &
754  (index3d(3)-1)*(self%n_dofs(1)-1)*self%n_cells(2)
755  splinejk = self%spline_0(j, 2) * self%spline_0(k,3)
756 
757  vt = 0.0_f64
758  self%j1d = 0.0_f64
759  call add_current_1d(self, 1, xi(1), boxold, xnew, boxnew, marker_charge, bfield_dofs, start1+startjk, start2+startjk, stride, vt, self%j1d)
760  if (j>1) then
761  vtt2 = vtt2 + vt(1)*self%spline_1(j-1, 2)
762  end if
763  vtt3 = vtt3 + vt(2)*self%spline_0(j, 2)
764 
765  do i = 1, self%spline_degree(1) !local_size?
766  index3d(1) = box(1)+i-1
767  index1d = startjk+index3d(1)-1
768  j_dofs(index1d) = j_dofs(index1d) + self%j1d(index3d(1)) * &
769  splinejk
770  end do
771  end do
772  vi(2) = vi(2) - qoverm*vtt2*self%spline_0(k, 3)
773  if ( k> 1) then
774  vi(3) = vi(3) + qoverm*vtt3*self%spline_1(k-1, 3)
775  end if
776  end do
777 
779 
780 
782  subroutine add_current_update_v_component2_spline_3d_feec (self, position_old, position_new, marker_charge, qoverm, bfield_dofs, vi, j_dofs)
783  class(sll_t_particle_mesh_coupling_spline_cl_3d_feec), intent(inout) :: self
784  sll_real64, intent(in) :: position_old(3)
785  sll_real64, intent(in) :: position_new
786  sll_real64, intent(in) :: marker_charge
787  sll_real64, intent(in) :: qoverm
788  sll_real64, intent(in) :: bfield_dofs(:)
789  sll_real64, intent(inout) :: vi(3)
790  sll_real64, intent(inout) :: j_dofs(:)
791  !local variables
792  sll_int32 :: box(3), boxnew, boxold
793  sll_real64 :: xi(3)
794  sll_int32 :: index3d(3)
795  sll_int32 :: index1d
796  sll_int32 :: i,j,k
797  sll_real64 :: xnew
798  sll_real64 :: vt(2), vtt2, vtt3
799  sll_int32 :: start1, start2
800  sll_int32 :: local_size
801  sll_int32 :: stride(2), startjk0, startjk1
802  sll_real64 :: splineik
803 
804  start1 = self%n_total0+self%n_total1
805  start2 = 0
806  stride(1) = self%n_dofs(1)-1
807  stride(2) = self%n_dofs(1)
808 
809  call convert_x_to_xbox( self, position_old, xi, box )
810  call convert_x_to_xbox_1d( self, 2, position_new, xnew, boxnew )
811  boxold = box(2)
812 
813 
814  ! Achtung wir brauchen nun splines von beidem Grad
815  self%spline_0 = 0.0_f64
816  self%spline_1 = 0.0_f64
817  call sll_s_uniform_bsplines_eval_basis_clamped( self%spline_pp_0%spline1, self%n_cells(1), &
818  self%spline_degree(1), xi(1), box(1), &
819  self%spline_0(1:self%spline_degree(1)+1,1) )
820  call sll_s_uniform_bsplines_eval_basis_clamped( self%spline_pp_1%spline1, self%n_cells(1), &
821  self%spline_degree(1)-1, xi(1), box(1), &
822  self%spline_1(1:self%spline_degree(1),1) )
823 
824  call sll_s_spline_pp_horner_m_1d(self%spline_pp_0%spline3, self%spline_0(1:self%spline_degree(3)+1,3), self%spline_degree(3), xi(3))
825  call sll_s_spline_pp_horner_m_1d(self%spline_pp_1%spline3, self%spline_1(1:self%spline_degree(3),3), self%spline_degree(3)-1, xi(3))
826 
827  box(3) = box(3) - self%spline_degree(3)
828  local_size = abs(boxnew-boxold)+self%spline_degree(2)
829  ! Define the range of the first component
830  if (boxold<boxnew) then
831  box(2) = boxold-self%spline_degree(2)+1
832  else
833  box(2) = boxnew-self%spline_degree(2)+1
834  end if
835 
836  call box_index( self, box(3), 3 )
837  do k = 1, self%spline_degree(3)+1
838  vtt2 = 0.0_f64
839  vtt3 = 0.0_f64
840  index3d(3) = self%index1d(k,3)
841  do j = 1, self%spline_degree(1)+1
842  index3d(1) = box(1)+j-1
843 
844  startjk0 = index3d(1) + &
845  (index3d(3)-1)*self%n_dofs(1)*self%n_cells(2)
846  startjk1 = index3d(1)-1 + &
847  (index3d(3)-1)*(self%n_dofs(1)-1)*self%n_cells(2)
848  splineik = self%spline_0(j, 1) * self%spline_0(k,3)
849 
850  vt = 0.0_f64
851  self%j1d = 0.0_f64
852  call add_current_1d(self, 2, xi(2), boxold-1, xnew, boxnew-1, marker_charge, bfield_dofs, start1+startjk1, start2+startjk0, stride, vt, self%j1d)
853 
854  if (j>1) then
855  vtt2 = vtt2 + vt(1)*self%spline_1(j-1, 1)
856  end if
857  vtt3 = vtt3 + vt(2)*self%spline_0(j, 1)
858 
859  do i=1,local_size
860  index3d(2) = modulo(box(2)+i-2,self%n_cells(2))+1
861  index1d = startjk0+(index3d(2)-1)*stride(2)
862  j_dofs(index1d) = j_dofs(index1d) + self%j1d(index3d(2)) * &
863  splineik
864 
865  end do
866  end do
867  vi(1) = vi(1) + qoverm*vtt2*self%spline_0(k, 3)
868  if ( k> 1) then
869  vi(3) = vi(3) - qoverm*vtt3*self%spline_1(k-1, 3)
870  end if
871  end do
872 
873 
875 
876 
878  subroutine add_current_update_v_component3_spline_3d_feec (self, position_old, position_new, marker_charge, qoverm, bfield_dofs, vi, j_dofs)
879  class(sll_t_particle_mesh_coupling_spline_cl_3d_feec), intent(inout) :: self
880  sll_real64, intent(in) :: position_old(3)
881  sll_real64, intent(in) :: position_new
882  sll_real64, intent(in) :: marker_charge
883  sll_real64, intent(in) :: qoverm
884  sll_real64, intent(in) :: bfield_dofs(:)
885  sll_real64, intent(inout) :: vi(3)
886  sll_real64, intent(inout) :: j_dofs(:)
887  !local variables
888  sll_int32 :: box(3), boxnew, boxold
889  sll_real64 :: xi(3)
890  sll_int32 :: index3d(3)
891  sll_int32 :: index1d
892  sll_int32 :: i,j,k
893  sll_real64 :: xnew
894  sll_real64 :: vt(2), vtt2, vtt3
895  sll_int32 :: start1, start2
896  sll_int32 :: local_size
897  sll_int32 :: stride(2), startjk0, startjk1
898  sll_real64 :: splineij
899 
900  start1 = self%n_total0
901  start2 = 0
902  stride(1) = (self%n_dofs(1)-1)*self%n_cells(2)
903  stride(2) = self%n_dofs(1)*self%n_cells(2)
904 
905  call convert_x_to_xbox( self, position_old, xi, box )
906  call convert_x_to_xbox_1d( self, 3, position_new, xnew, boxnew )
907  boxold = box(3)
908 
909  ! Achtung wir brauchen nun splines von beidem Grad
910  self%spline_0 = 0.0_f64
911  self%spline_1 = 0.0_f64
912  call sll_s_uniform_bsplines_eval_basis_clamped( self%spline_pp_0%spline1, self%n_cells(1), &
913  self%spline_degree(1), xi(1), box(1), &
914  self%spline_0(1:self%spline_degree(1)+1,1) )
915  call sll_s_uniform_bsplines_eval_basis_clamped( self%spline_pp_1%spline1, self%n_cells(1), &
916  self%spline_degree(1)-1, xi(1), box(1), &
917  self%spline_1(1:self%spline_degree(1),1) )
918 
919  call sll_s_spline_pp_horner_m_1d(self%spline_pp_0%spline2, self%spline_0(1:self%spline_degree(2)+1,2), self%spline_degree(2), xi(2))
920  call sll_s_spline_pp_horner_m_1d(self%spline_pp_1%spline2, self%spline_1(1:self%spline_degree(2),2), self%spline_degree(2)-1, xi(2))
921 
922  box(2) = box(2) - self%spline_degree(2)
923  local_size = abs(boxnew-boxold)+self%spline_degree(3)
924  ! Define the range of the third component
925  if (boxold<boxnew) then
926  box(3) = boxold-self%spline_degree(3)+1
927  else
928  box(3) = boxnew-self%spline_degree(3)+1
929  end if
930 
931  call box_index( self, box(2), 2 )
932  do k = 1, self%spline_degree(2)+1
933  vtt2 = 0.0_f64
934  vtt3 = 0.0_f64
935  index3d(2) = self%index1d(k,2)
936  do j = 1, self%spline_degree(1)+1
937  index3d(1) = box(1)+j-1
938 
939  startjk0 = index3d(1) + (index3d(2)-1)*self%n_dofs(1)
940  startjk1 = index3d(1)-1 + (index3d(2)-1)*(self%n_dofs(1)-1)
941  splineij = self%spline_0(j, 1) * self%spline_0(k,2)
942 
943  vt = 0.0_f64
944  self%j1d = 0.0_f64
945  call add_current_1d(self, 3, xi(3), boxold-1, xnew, boxnew-1, marker_charge, bfield_dofs, start1+startjk1, start2+startjk0, stride, vt, self%j1d)
946  if (j>1) then
947  vtt2 = vtt2 + vt(1)*self%spline_1(j-1, 1)
948  end if
949  vtt3 = vtt3 + vt(2)*self%spline_0(j, 1)
950 
951  do i = 1, local_size
952  index3d(3) = modulo(box(3)+i-2,self%n_cells(3))+1
953  index1d = startjk0 + (index3d(3)-1)*stride(2)
954 
955  j_dofs(index1d) = j_dofs(index1d) + self%j1d(index3d(3)) * &
956  splineij
957  end do
958 
959  end do
960  vi(1) = vi(1) - qoverm*vtt2*self%spline_0(k, 2)
961  if ( k> 1) then
962  vi(2) = vi(2) + qoverm*vtt3*self%spline_1(k-1, 2)
963  end if
964  end do
965 
967 
968 
970  subroutine add_current_1d (self, component, r_old, index_old, r_new, index_new, marker_charge, bfield_dofs, start1, start2, stride, vi, j_dofs)
971  class(sll_t_particle_mesh_coupling_spline_cl_3d_feec), intent(inout) :: self
972  sll_int32, intent(in) :: component
973  sll_real64, intent(in) :: r_old
974  sll_int32, intent(in) :: index_old
975  sll_real64, intent(in) :: r_new
976  sll_int32, intent(in) :: index_new
977  sll_real64, intent(in) :: marker_charge
978  sll_real64, intent(in) :: bfield_dofs(self%n_total0+self%n_total1*2)
979  sll_int32, intent(in) :: start1
980  sll_int32, intent(in) :: start2
981  sll_int32, intent(in) :: stride(2)
982  sll_real64, intent(inout) :: vi(2)
983  sll_real64, intent(inout) :: j_dofs(:)
984  ! local variables
985  sll_int32 :: ind
986 
987  if (index_old == index_new) then
988  if (r_old < r_new) then
989  call update_jv(self, component, r_old, r_new, index_old, marker_charge, &
990  1.0_f64, bfield_dofs, start1, start2, stride, vi, j_dofs)
991  else
992  call update_jv(self, component, r_new, r_old, index_old, marker_charge, &
993  -1.0_f64, bfield_dofs, start1, start2, stride, vi, j_dofs)
994  end if
995  elseif (index_old < index_new) then
996  call update_jv (self, component, r_old, 1.0_f64, index_old, marker_charge, &
997  1.0_f64, bfield_dofs, start1, start2, stride, vi, j_dofs)
998  call update_jv (self, component, 0.0_f64, r_new, index_new, marker_charge, &
999  1.0_f64, bfield_dofs, start1, start2, stride, vi, j_dofs)
1000  do ind = index_old+1, index_new-1
1001  call update_jv (self, component, 0.0_f64, 1.0_f64, ind, marker_charge, &
1002  1.0_f64, bfield_dofs, start1, start2, stride, vi, j_dofs)
1003  end do
1004  else
1005  call update_jv (self, component, r_new, 1.0_f64, index_new, marker_charge, &
1006  -1.0_f64, bfield_dofs, start1, start2, stride, vi, j_dofs)
1007  call update_jv (self, component, 0.0_f64, r_old, index_old, marker_charge, &
1008  -1.0_f64, bfield_dofs, start1, start2, stride, vi, j_dofs)
1009  do ind = index_new+1, index_old-1
1010  call update_jv (self, component, 0.0_f64, 1.0_f64, ind, marker_charge, &
1011  -1.0_f64, bfield_dofs, start1, start2, stride, vi, j_dofs)
1012  end do
1013  end if
1014 
1015 
1016  end subroutine add_current_1d
1017 
1018 
1020  subroutine update_jv(self, component, lower, upper, index, marker_charge, sign, bfield_dofs, start1, start2, stride, vi, j_dofs)
1021  class(sll_t_particle_mesh_coupling_spline_cl_3d_feec), intent(inout) :: self
1022  sll_int32, intent(in) :: component
1023  sll_real64, intent(in) :: lower
1024  sll_real64, intent(in) :: upper
1025  sll_int32, intent(in) :: index
1026  sll_real64, intent(in) :: marker_charge
1027  sll_real64, intent(in) :: sign
1028  sll_real64, intent(inout) :: vi(2)
1029  sll_real64, intent(in) :: bfield_dofs(self%n_total0+self%n_total1*2)
1030  sll_int32, intent(in) :: start1
1031  sll_int32, intent(in) :: start2
1032  sll_int32, intent(in) :: stride(2)
1033  sll_real64, intent(inout) :: j_dofs(:)
1034  !Local variables
1035  sll_int32 :: ind, i_grid, i_mod, j
1036  sll_real64 :: c1, c2
1037  sll_int32 :: spline_degree
1038  sll_int32 :: n_cells
1039 
1040  self%spline_val(:,1) = 0._f64
1041  self%spline_val_more(:,1) = 0._f64
1042 
1043  n_cells = self%n_cells(component)
1044  spline_degree = self%spline_degree(component)-1
1045 
1046  c1 = 0.5_f64*(upper-lower)
1047  c2 = 0.5_f64*(upper+lower)
1048 
1049  if( component == 1 ) then
1050  call sll_s_uniform_bsplines_eval_basis_clamped( self%spline_pp_1%spline1, n_cells, &
1051  spline_degree, c1*self%quad_xw(1,1)+c2, index, &
1052  self%spline_val(1:spline_degree+1,1) )
1053  self%spline_val(:,1) = self%spline_val(:,1) * (self%quad_xw(2,1)*c1)
1054  do j=2,self%n_quad_points
1055  call sll_s_uniform_bsplines_eval_basis_clamped( self%spline_pp_1%spline1, n_cells, &
1056  spline_degree, c1*self%quad_xw(1,j)+c2, index, &
1057  self%spline_val_more(1:spline_degree+1,1))
1058  self%spline_val(:,1) = self%spline_val(:,1) + self%spline_val_more(:,1) * (self%quad_xw(2,j)*c1)
1059  end do
1060  self%spline_val(:,1) = self%spline_val(:,1) * (sign*self%delta_x(component))
1061 
1062  ind = 1
1063  do i_grid = index-1, index-1+spline_degree
1064  j_dofs(i_grid+1) = j_dofs(i_grid+1) + &
1065  (marker_charge*self%spline_val(ind,1))
1066  vi(1) = vi(1) + self%spline_val(ind,1)*bfield_dofs(i_grid*stride(1)+start1)
1067  vi(2) = vi(2) + self%spline_val(ind,1)*bfield_dofs(i_grid*stride(2)+start2)
1068  ind = ind + 1
1069  end do
1070  else
1071 
1072  call sll_s_uniform_bsplines_eval_basis(spline_degree, c1*self%quad_xw(1,1)+c2, &
1073  self%spline_val(1:spline_degree,1))
1074  self%spline_val(:,1) = self%spline_val(:,1) * (self%quad_xw(2,1)*c1)
1075  do j=2,self%n_quad_points
1076  call sll_s_uniform_bsplines_eval_basis(spline_degree, c1*self%quad_xw(1,j)+c2, &
1077  self%spline_val_more(1:spline_degree,1))
1078  self%spline_val(:,1) = self%spline_val(:,1) + self%spline_val_more(:,1) * (self%quad_xw(2,j)*c1)
1079  end do
1080  self%spline_val(:,1) = self%spline_val(:,1) * (sign*self%delta_x(component))
1081 
1082  ind = 1
1083  do i_grid = index - spline_degree, index
1084  i_mod = modulo(i_grid, n_cells )
1085  j_dofs(i_mod+1) = j_dofs(i_mod+1) + &
1086  (marker_charge*self%spline_val(ind,1))
1087  vi(1) = vi(1) + self%spline_val(ind,1)*bfield_dofs(i_mod*stride(1)+start1)
1088  vi(2) = vi(2) + self%spline_val(ind,1)*bfield_dofs(i_mod*stride(2)+start2)
1089  ind = ind + 1
1090  end do
1091  end if
1092 
1093  end subroutine update_jv
1094 
1095 
1096  function convert_index_3d_to_1d( index3d, n_cells, degree ) result( index1d )
1097  sll_int32, intent( in ) :: index3d(3)
1098  sll_int32, intent( in ) :: n_cells(3)
1099  sll_int32 :: degree
1100  sll_int32 :: index1d
1101 
1102  index1d = index3d(1) + (index3d(2)-1)*(n_cells(1)+degree) + (index3d(3)-1)*(n_cells(1)+degree)*n_cells(2)
1103 
1104  end function convert_index_3d_to_1d
1105 
1106 
1107  subroutine convert_x_to_xbox( self, position, xi, box )
1108  class( sll_t_particle_mesh_coupling_spline_cl_3d_feec ), intent(inout) :: self
1109  sll_real64, intent( in ) :: position(3)
1110  sll_real64, intent( out ) :: xi(3)
1111  sll_int32, intent( out ) :: box(3)
1112 
1113  xi = (position - self%domain(:,1)) * self%rdelta_x
1114  box = floor( xi ) + 1
1115  xi = xi - real(box-1, f64)
1116 
1117  if( box(1) == self%n_cells(1) + 1 ) then
1118  if( xi(1) == 0._f64)then
1119  xi(1) = 1._f64
1120  box(1) = self%n_cells(1)
1121  else
1122  print*, 'box,x, xbox', box, position(1), xi(1)
1123  sll_error('convert_x_to_xbox', 'box1 value to high' )
1124  end if
1125  else if( box(1) > self%n_cells(1) + 1 ) then
1126  print*, 'box,x, xbox', box, position(1), xi(1)
1127  sll_error('convert_x_to_xbox', 'box1 value to high' )
1128  else if( box(1) <= 0 ) then
1129  print*, 'box,x, xbox', box, position(1), xi(1)
1130  sll_error('convert_x_to_xbox', 'box1 value to low' )
1131  end if
1132 
1133  end subroutine convert_x_to_xbox
1134 
1135 
1136  subroutine convert_x_to_xbox_1d( self, component, position, xi, box )
1137  class( sll_t_particle_mesh_coupling_spline_cl_3d_feec ), intent(inout) :: self
1138  sll_int32, intent( in ) :: component
1139  sll_real64, intent( in ) :: position
1140  sll_real64, intent( out ) :: xi
1141  sll_int32, intent( out ) :: box
1142 
1143  xi = (position - self%domain(component,1))/self%delta_x(component)!* self%rdelta_x ! destroys perfect gauss conservation for symplectic splitting with fft solver
1144  box = floor( xi ) + 1
1145  xi = xi - real(box-1, f64)
1146 
1147  if( component ==1 .and. box == self%n_cells(1) + 1 ) then
1148  if( xi == 0._f64)then
1149  xi = 1._f64
1150  box = self%n_cells(1)
1151  else
1152  print*, 'box,x, xbox', box, position, xi
1153  sll_error('convert_x_to_xbox', 'box1 value to high' )
1154  end if
1155  end if
1156 
1157  end subroutine convert_x_to_xbox_1d
1158 
1159 
1160  subroutine box_index( self, box, comp )
1161  class(sll_t_particle_mesh_coupling_spline_cl_3d_feec), intent(inout) :: self
1162  sll_int32, intent(in) :: box
1163  sll_int32, intent(in) :: comp
1164  !local variables
1165  sll_int32 :: j
1166 
1167  do j = 1, self%spline_degree(comp)+1
1168  self%index1d(j,comp) = modulo(box+j-2,self%n_cells(comp))+1
1169  end do
1170 
1171  end subroutine box_index
1172 
1174  subroutine sll_s_uniform_bsplines_eval_basis_clamped( spline, n_cells, degree, xi, box, spline_val )
1175  type(sll_t_spline_pp_1d), intent( in ) :: spline
1176  sll_int32, intent( in ) :: n_cells
1177  sll_int32, intent( in ) :: degree
1178  sll_real64, intent( in ) :: xi
1179  sll_int32, intent( in ) :: box
1180  sll_real64, intent( out ) :: spline_val(:)
1181  !local variables
1182  sll_int32 :: i
1183 
1184  if(box >= 1 .and. box <= degree-1)then
1185  do i=1, degree+1
1186  spline_val(i) = sll_f_spline_pp_horner_1d( degree, spline%poly_coeffs_boundary_left(:,:,box), xi, i)
1187  end do
1188  else if (box >= degree .and. box <= n_cells-degree+1)then
1189  call sll_s_uniform_bsplines_eval_basis( degree, xi, spline_val )
1190  else if(box >= n_cells-degree+2 .and. box <= n_cells)then
1191  do i=1, degree+1
1192  spline_val(i) = sll_f_spline_pp_horner_1d( degree, spline%poly_coeffs_boundary_right(:,:,box-1-n_cells+degree), xi, i)
1193  end do
1194  else
1195  print*, 'box, xbox', box, xi
1196  sll_error( "uniform_bsplines_eval_basis_clamped", "box out of range" )
1197  end if
1198 
1200 
1201 
1203  subroutine init_spline_cl_3d_feec ( self, n_cells, domain, spline_degree, boundary, no_particles )
1204  class(sll_t_particle_mesh_coupling_spline_cl_3d_feec), intent( out ) :: self
1205  sll_int32, intent(in) :: n_cells(3)
1206  sll_real64, intent(in) :: domain(3,2)
1207  sll_int32, intent(in) :: spline_degree(3)
1208  sll_int32, intent(in) :: boundary(3)
1209  sll_int32, optional, intent(in) :: no_particles
1210  !local variables
1211  sll_int32 :: maxspan, j, maxind
1212 
1213 
1214  ! Store cells information
1215  self%domain = domain
1216  self%n_cells = n_cells
1217  self%n_dofs = n_cells + spline_degree
1218  self%n_total = product(n_cells)
1219  self%n_total0 = (n_cells(1)+spline_degree(1))*n_cells(2)*n_cells(3)
1220  self%n_total1 = (n_cells(1)+spline_degree(1)-1)*n_cells(2)*n_cells(3)
1221  self%delta_x = (self%domain(:,2)-self%domain(:,1))/real(n_cells, f64)
1222  self%rdelta_x = 1.0_f64/self%delta_x
1223 
1224  ! Store basis function information
1225  if( present(no_particles) )then
1226  self%no_particles = no_particles
1227  else
1228  self%no_particles = 1
1229  end if
1230 
1231  ! Initialize information on the spline
1232  self%spline_degree = spline_degree
1233  maxspan = maxval(spline_degree + 1)
1234 
1235  self%n_quad_points = (maxval(self%spline_degree)+2)/2
1236  allocate( self%quad_xw(2,self%n_quad_points) )
1237  ! normalized Gauss Legendre points and weights
1238  self%quad_xw = sll_f_gauss_legendre_points_and_weights(self%n_quad_points)
1239 
1240  ! For the line integral
1241  self%n_quad_points_line = ceiling(real(sum(self%spline_degree), f64)*0.5_f64)
1242  allocate( self%quad_xw_line(2,self%n_quad_points_line) )
1243  ! normalized Gauss Legendre points and weights
1244  self%quad_xw_line = sll_f_gauss_legendre_points_and_weights(self%n_quad_points_line)
1245 
1246  self%quad_xw_line(1,:) = 0.5_f64*(self%quad_xw_line(1,:)+1.0_f64)
1247  self%quad_xw_line(2,:) = 0.5_f64*self%quad_xw_line(2,:)
1248 
1249  allocate( self%spline_val(maxspan,3) )
1250  allocate( self%spline_0(maxspan,3) )
1251  allocate( self%spline1_0(maxspan,3) )
1252  allocate( self%spline_1(maxspan,3) )
1253  allocate( self%spline_2d(maxspan, maxspan) )
1254  allocate( self%spline1_2d(1:maxspan, 1:maxspan) )
1255  allocate( self%spline1_3d(1:maxspan, 1:maxspan, 1:maxspan) )
1256  allocate( self%spline2_3d(1:maxspan, 1:maxspan, 1:maxspan) )
1257  allocate( self%index1d(maxspan, 3) )
1258 
1259  allocate( self%spline_val_more(maxspan,3) )
1260  allocate( self%j1d( maxval(self%n_dofs)+maxval(self%spline_degree) ))
1261 
1262  call sll_s_spline_pp_init_3d(self%spline_pp_0, spline_degree, n_cells, boundary)
1263  call sll_s_spline_pp_init_3d(self%spline_pp_1, spline_degree-1, n_cells, boundary)
1264 
1265  end subroutine init_spline_cl_3d_feec
1266 
1267 
1269  subroutine free_spline_cl_3d_feec(self)
1270  class(sll_t_particle_mesh_coupling_spline_cl_3d_feec), intent( inout ) :: self
1271 
1272  deallocate( self%spline_val)
1273  deallocate( self%spline_0)
1274  deallocate( self%spline1_0 )
1275  deallocate( self%spline_1 )
1276  deallocate( self%spline_2d )
1277  deallocate( self%spline1_2d )
1278  deallocate( self%spline1_3d )
1279  deallocate( self%spline2_3d )
1280 
1281  call sll_s_spline_pp_free_3d( self%spline_pp_0 )
1282  call sll_s_spline_pp_free_3d( self%spline_pp_1 )
1283 
1284  end subroutine free_spline_cl_3d_feec
1285 
1286 
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.
Particle mesh coupling for 3d with splines of arbitrary degree placed on a uniform tensor product mes...
subroutine add_current_update_v_component2_spline_3d_feec(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 add_particle_mass_od_spline_cl_3d_feec(self, position, marker_charge, degree1, degree2, particle_mass)
Add the contribution of one particle to the off-diagonal parts of the approximate mass matrix.
subroutine point_add_eval(self, box_in, xbox, field_dofs, weight, j_dofs, field_value)
Helper function for add_current_evaluate.
subroutine add_current_update_v_component1_spline_3d_feec(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 evaluate_multiple_spline_cl_3d_feec(self, position, components, field_dofs, field_value)
Evaluate several fields at position position.
subroutine update_jv(self, component, lower, upper, index, marker_charge, sign, bfield_dofs, start1, start2, stride, vi, j_dofs)
Helper function for add_current_update_v.
subroutine init_spline_cl_3d_feec(self, n_cells, domain, spline_degree, boundary, no_particles)
Initializer.
integer(kind=i32) function convert_index_3d_to_1d(index3d, n_cells, degree)
subroutine add_current_1d(self, component, r_old, index_old, r_new, index_new, marker_charge, bfield_dofs, start1, start2, stride, vi, j_dofs)
Helper function for add_current_update_v.
subroutine, public sll_s_uniform_bsplines_eval_basis_clamped(spline, n_cells, degree, xi, box, spline_val)
Helper function to evaluate uniform clamped basis splines.
subroutine add_current_update_v_component3_spline_3d_feec(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 add_charge_single_spline_cl_3d_feec(self, position, marker_charge, degree, rho_dofs)
Add charge of one particle.
subroutine integrate_spline_cl_3d(self, box_in, xbox, weight, j_dofs)
Helper function for add_current.
subroutine add_current_cl_3d(self, position_old, position_new, xdot, j_dofs)
Add current with integration over x.
subroutine evaluate_field_single_spline_cl_3d_feec(self, position, degree, field_dofs, field_value)
Evaluate field at at position position.
subroutine add_particle_mass_spline_cl_3d_feec(self, position, marker_charge, degree, particle_mass)
Add the contribution of one particle to the diagonal parts fo the approximate mass matrix.
Splines in pp form.
subroutine, public sll_s_spline_pp_init_3d(self, degree, n_cells, boundary)
Initialize sll_t_spline_pp_3d object.
real(kind=f64) function, public sll_f_spline_pp_horner_3d(degree, pp_coeffs, x, indices, n_cells)
Perform a 3d hornerschema on the pp_coeffs at the indices.
subroutine, public sll_s_spline_pp_free_3d(self)
Destructor 3d.
subroutine, public sll_s_spline_pp_horner_m_1d(self, val, degree, x)
Perform a 1d hornerschema on the poly_coeffs.
real(kind=f64) function, public sll_f_spline_pp_horner_1d(degree, pp_coeffs, x, index)
Perform a 1d hornerschema on the pp_coeffs at index.
Particle mesh coupling in 3d based on (arbitrary degree) spline on a tensor product uniform mesh.
    Report Typos and Errors