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_3d_feec.F90
Go to the documentation of this file.
1 
5 
7 
8  !+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
9 #include "sll_assert.h"
10 #include "sll_errors.h"
11 #include "sll_memory.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 : &
35 
36  implicit none
37 
38  public :: &
40 
41  private
42  !+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
43 
46 
47  sll_real64 :: rdelta_x(3)
48  ! Information about the particles
49  sll_int32 :: no_particles
50  sll_int32 :: n_quad_points
51 
52  sll_real64, allocatable :: spline_val(:,:)
53  sll_real64, allocatable :: spline_0(:,:)
54  sll_real64, allocatable :: spline_0_deriv(:,:)
55  sll_real64, allocatable :: spline1_0(:,:)
56  sll_real64, allocatable :: spline_1(:,:)
57  sll_real64, allocatable :: spline_1_deriv(:,:)
58  sll_real64, allocatable :: spline_val_more(:,:)
59  sll_real64, allocatable :: spline_2d(:,:), spline1_2d(:,:)
60  sll_real64, allocatable :: spline1_3d(:,:,:), spline2_3d(:,:,:)
61  sll_real64, allocatable :: j1d(:)
62  sll_real64, allocatable :: quad_xw(:,:)
63 
64  sll_int32, allocatable :: index1d(:,:)
65 
66  type(sll_t_spline_pp_1d) :: spline_pp1d_0(3)
67  type(sll_t_spline_pp_1d) :: spline_pp1d_1(3)
68 
69  ! For 1d quadrature in 3d space
70  sll_int32 :: n_quad_points_line
71  sll_real64, allocatable :: quad_xw_line(:,:)
72 
73  contains
74 
75  procedure :: add_charge => add_charge_single_spline_3d_feec
76  procedure :: add_particle_mass => add_particle_mass_spline_3d_feec
77  procedure :: add_particle_mass_od => add_particle_mass_od_spline_3d_feec
78  procedure :: evaluate => evaluate_field_single_spline_3d_feec
79  procedure :: evaluate_multiple => evaluate_multiple_spline_3d_feec
80  procedure :: add_current => add_current_3d
81  procedure :: add_current_evaluate
82  procedure :: add_current_update_v_component1 => add_current_update_v_primitive_component1_spline_3d_feec
83  procedure :: add_current_update_v_component2 => add_current_update_v_primitive_component2_spline_3d_feec
84  procedure :: add_current_update_v_component3 => add_current_update_v_primitive_component3_spline_3d_feec
85  procedure :: init => init_spline_3d_feec
86  procedure :: free => free_spline_3d_feec
87 
90 
91  type :: vector
92  sll_real64, allocatable :: vals(:)
93  end type vector
94 
95 contains
96 
97 
98  !---------------------------------------------------------------------------!
100  subroutine add_charge_single_spline_3d_feec(self, position, marker_charge, degree, rho_dofs)
101  class( sll_t_particle_mesh_coupling_spline_3d_feec ), intent(inout) :: self
102  sll_real64, intent( in ) :: position(3)
103  sll_real64, intent( in ) :: marker_charge
104  sll_int32, intent( in ) :: degree(3)
105  sll_real64, intent( inout ) :: rho_dofs(:)
106  !local variables
107  sll_int32 :: box(3)
108  sll_real64 :: xi(3)
109  sll_int32 :: index3d(3)
110  sll_int32 :: index1d
111  sll_int32 :: i,j,k
112 
113 
114  call convert_x_to_xbox( self, position, xi, box )
115 
116  self%spline_0 = 0.0_f64
117  do j = 1, 3
118  call sll_s_uniform_bsplines_eval_basis( degree(j), xi(j), self%spline_0(1:degree(j)+1,j) )
119  end do
120 
121  ! Build scaling with marker_charge into spline along first dimension
122  self%spline_0(:,1) = self%spline_0(:,1)*marker_charge
123  ! 2d array combining first and second dimension
124  do j = 1, degree(2)+1
125  do i = 1, degree(1)+1
126  self%spline_2d(i,j) = self%spline_0(i,1)*self%spline_0(j,2)
127  end do
128  end do
129 
130  box = box-degree
131  call box_index( self, box(1), 1 )
132  call box_index( self, box(2), 2 )
133  call box_index( self, box(3), 3 )
134  do k = 1, degree(3)+1
135  index3d(3) = self%index1d(k,3)!modulo(box(3)+k-2,self%n_cells(3))+1
136  do j = 1, degree(2)+1
137  index3d(2) = self%index1d(j,2)!modulo(box(2)+j-2,self%n_cells(2))+1
138  do i = 1, degree(1)+1
139  index3d(1) = self%index1d(i,1)!modulo(box(1)+i-2,self%n_cells(1))+1
140  index1d = convert_index_3d_to_1d( index3d, self%n_cells )
141  rho_dofs(index1d) = rho_dofs(index1d) + &
142  (self%spline_2d(i,j) * self%spline_0(k,3))
143  !(marker_charge * self%spline_0(i,1) * self%spline_0(j,2) * &
144  !self%spline_0(k,3) )
145  end do
146  end do
147  end do
148 
149 
150  end subroutine add_charge_single_spline_3d_feec
151 
152  !---------------------------------------------------------------------------!
154  subroutine add_charge_single_spline_pp_3d_feec(self, position, marker_charge, degree, rho_dofs)
155  class( sll_t_particle_mesh_coupling_spline_3d_feec ), intent(inout) :: self
156  sll_real64, intent( in ) :: position(3)
157  sll_real64, intent( in ) :: marker_charge
158  sll_int32, intent( in ) :: degree(3)
159  sll_real64, intent( inout ) :: rho_dofs(self%n_total)
160  !local variables
161  sll_int32 :: box(3)
162  sll_real64 :: xi(3)
163  sll_int32 :: index3d(3)
164  sll_int32 :: index1d
165  sll_int32 :: i,j,k
166 
167 
168  call convert_x_to_xbox( self, position, xi, box )
169 
170  self%spline_0 = 0.0_f64
171  call sll_s_spline_pp_horner_m_3d (self%spline_pp_0, self%spline_0, degree, xi)
172 
173 
174  ! Build scaling with marker_charge into spline along first dimension
175  self%spline_0(:,1) = self%spline_0(:,1)*marker_charge
176  ! 2d array combining first and second dimension
177  do j = 1, degree(2)+1
178  do i = 1, degree(1)+1
179  self%spline_2d(i,j) = self%spline_0(i,1)*self%spline_0(j,2)
180  end do
181  end do
182 
183 
184  box = box-degree
185  call box_index( self, box(1), 1 )
186  call box_index( self, box(2), 2 )
187  call box_index( self, box(3), 3 )
188  do k = 1, degree(3)+1
189  index3d(3) = self%index1d(k,3)!modulo(box(3)+k-2,self%n_cells(3))+1
190  do j = 1, degree(2)+1
191  index3d(2) = self%index1d(j,2)!modulo(box(2)+j-2,self%n_cells(2))+1
192  do i = 1, degree(1)+1
193  index3d(1) = self%index1d(i,1)!modulo(box(1)+i-2,self%n_cells(1))+1
194  index1d = convert_index_3d_to_1d( index3d, self%n_cells )
195  rho_dofs(index1d) = rho_dofs(index1d) + &
196  (self%spline_2d(i,j) * &
197  self%spline_0(k,3) )
198  end do
199  end do
200  end do
201 
202 
204 
205  !---------------------------------------------------------------------------!
207  subroutine add_particle_mass_spline_3d_feec(self, position, marker_charge, degree, particle_mass )
208  class( sll_t_particle_mesh_coupling_spline_3d_feec ), intent(inout) :: self
209  sll_real64, intent( in ) :: position(3)
210  sll_real64, intent( in ) :: marker_charge
211  sll_int32, intent( in ) :: degree(3)
212  sll_real64, intent( inout ) :: particle_mass(:,:)
213  !local variables
214  sll_int32 :: box(3)
215  sll_real64 :: xi(3)
216  sll_int32 :: index3d(3)
217  sll_int32 :: index1d
218  sll_int32 :: i,j,k, col1, col2, col3, ind
219  sll_real64 :: splineijk, splineijkcol3
220 
221 
222  call convert_x_to_xbox( self, position, xi, box )
223 
224  ! Old version based on arbitrary degree splines
225  self%spline_0 = 0.0_f64
226  do j = 1, 3
227  call sll_s_uniform_bsplines_eval_basis( degree(j), xi(j), self%spline_0(1:degree(j)+1,j) )
228  end do
229 
230  ! 2d array combining first and second dimension
231  do j = 1, degree(2)+1
232  do i = 1, degree(1)+1
233  self%spline_2d(i,j) = self%spline_0(i,1)*self%spline_0(j,2)
234  end do
235  end do
236  ! TODO: Check if also 3d array would make sense
237 
238 
239  box = box-degree
240  call box_index( self, box(1), 1 )
241  call box_index( self, box(2), 2 )
242  call box_index( self, box(3), 3 )
243  do k = 1, degree(3)+1
244  index3d(3) = self%index1d(k,3)!modulo(box(3)+k-2,self%n_cells(3))+1
245  do j = 1, degree(2)+1
246  index3d(2) = self%index1d(j,2)!modulo(box(2)+j-2,self%n_cells(2))+1
247  do i = 1, degree(1)+1
248  index3d(1) = self%index1d(i,1)!modulo(box(1)+i-2,self%n_cells(1))+1
249  index1d = convert_index_3d_to_1d( index3d, self%n_cells )
250  ind = 1+(degree(1)+1-i)+(degree(2)+1-j)*(2*degree(1)+1)+ &
251  (degree(3)+1-k)*(2*degree(1)+1)*(2*degree(2)+1)
252  splineijk = marker_charge * self%spline_2d(i,j) *&
253  self%spline_0( k, 3)
254  do col3 = 1,degree(3)+1
255  splineijkcol3 = splineijk*self%spline_0(col3, 3)
256  do col2 = 1,degree(2)+1
257  do col1 = 1,degree(1)+1
258  particle_mass(ind, index1d) = &
259  particle_mass( ind, index1d) + &
260  splineijkcol3 * &
261  self%spline_2d(col1,col2)
262  ind = ind+1
263  end do
264  ind = ind+degree(1)
265  end do
266  ind = ind+ degree(2) * (2*degree(1)+1)
267  end do
268  end do
269  end do
270  end do
271 
272 
273  end subroutine add_particle_mass_spline_3d_feec
274 
275 
277  subroutine add_particle_mass_od_spline_3d_feec(self, position, marker_charge, degree1, degree2, particle_mass )
278  class( sll_t_particle_mesh_coupling_spline_3d_feec ), intent(inout) :: self
279  sll_real64, intent( in ) :: position(3)
280  sll_real64, intent( in ) :: marker_charge
281  sll_int32, intent( in ) :: degree1(3), degree2(3)
282  sll_real64, intent( inout ) :: particle_mass(:,:)
283  !local variables
284  sll_int32 :: box(3)
285  sll_real64 :: xi(3)
286  sll_int32 :: index3d(3)
287  sll_int32 :: index1d
288  sll_int32 :: i,j,k, col1, col2, col3, ind
289  sll_real64 :: splineijk, splineijkcol3
290 
291 
292  call convert_x_to_xbox( self, position, xi, box )
293 
294  self%spline_0 = 0.0_f64
295  self%spline1_0 = 0.0_f64
296  do j = 1, 3
297  call sll_s_uniform_bsplines_eval_basis( degree1(j), xi(j), self%spline_0(1:degree1(j)+1,j) )
298  call sll_s_uniform_bsplines_eval_basis( degree2(j), xi(j), self%spline1_0(1:degree2(j)+1,j) )
299  end do
300 
301  self%spline1_3d = 0._f64
302  !3d array
303  do k = 1, degree1(3)+1
304  do j = 1, degree1(2)+1
305  do i = 1, degree1(1)+1
306  self%spline1_3d(i,j,k) = self%spline_0(i,1)*self%spline_0(j,2)*self%spline_0(k,3)
307  end do
308  end do
309  end do
310 
311  self%spline2_3d = 0._f64
312  do k = 1, degree2(3)+1
313  do j = 1, degree2(2)+1
314  do i = 1, degree2(1)+1
315  self%spline2_3d(i,j,k) = self%spline1_0(i,1)*self%spline1_0(j,2)*self%spline1_0(k,3)
316  end do
317  end do
318  end do
319 
320 
321  box = box-degree1
322  call box_index( self, box(1), 1 )
323  call box_index( self, box(2), 2 )
324  call box_index( self, box(3), 3 )
325  do k = 1, degree1(3)+1
326  index3d(3) = self%index1d(k,3)!modulo(box(3)+k-2,self%n_cells(3))+1
327  do j = 1, degree1(2)+1
328  index3d(2) = self%index1d(j,2)!modulo(box(2)+j-2,self%n_cells(2))+1
329  do i = 1, degree1(1)+1
330  index3d(1) = self%index1d(i,1)!modulo(box(1)+i-2,self%n_cells(1))+1
331  index1d = convert_index_3d_to_1d( index3d, self%n_cells )
332  ind = 1+(degree1(1)+1-i)+(degree1(2)+1-j)*(degree1(1)+degree2(1)+1)+ &
333  (degree1(3)+1-k)*(degree1(1)+degree2(1)+1)*(degree1(2)+degree2(2)+1)
334  do col3 = 1,degree2(3)+1
335  do col2 = 1,degree2(2)+1
336  do col1 = 1,degree2(1)+1
337  particle_mass( ind, index1d)=particle_mass( ind, index1d)+&
338  self%spline1_3d(i,j,k)*self%spline2_3d(col1,col2,col3)*&
339  marker_charge
340  ind = ind+1
341  end do
342  ind = ind+degree1(1)
343  end do
344  ind = ind+degree1(2) * (degree1(1)+degree2(1)+1)
345  end do
346  end do
347  end do
348  end do
349 
351 
352 
353  !---------------------------------------------------------------------------!
355  subroutine evaluate_field_single_spline_3d_feec(self, position, degree, field_dofs, field_value)
356  class(sll_t_particle_mesh_coupling_spline_3d_feec), intent( inout ) :: self
357  sll_real64, intent( in ) :: position(3)
358  sll_int32 , intent( in ) :: degree(3)
359  sll_real64, intent( in ) :: field_dofs(:)
360  sll_real64, intent( out ) :: field_value
361  !local variables
362  sll_int32 :: i,j,k
363  sll_int32 :: box(3)
364  sll_int32 :: index3d(3)
365  sll_int32 :: index1d
366  sll_real64 :: xi(3)
367 
368  ! TODO: Optimize by sum factorization
369 
370  call convert_x_to_xbox( self, position, xi, box )
371 
372  do j = 1, 3
373  call sll_s_uniform_bsplines_eval_basis( degree(j), xi(j), self%spline_val(1:degree(j)+1,j) )
374  end do
375 
376  field_value = 0.0_f64
377  box = box-degree
378  call box_index( self, box(1), 1 )
379  call box_index( self, box(2), 2 )
380  call box_index( self, box(3), 3 )
381  do k = 1, degree(3)+1
382  index3d(3) = self%index1d(k,3)!modulo(box(3)+k-2,self%n_cells(3))+1
383  do j = 1, degree(2)+1
384  index3d(2) = self%index1d(j,2)!modulo(box(2)+j-2,self%n_cells(2))+1
385  do i = 1, degree(1)+1
386  index3d(1) = self%index1d(i,1)!modulo(box(1)+i-2,self%n_cells(1))+1
387  index1d = convert_index_3d_to_1d( index3d, self%n_cells )
388  field_value = field_value + &
389  field_dofs(index1d) * &
390  self%spline_val(i,1) * self%spline_val(j,2) * &
391  self%spline_val(k,3)
392  end do
393  end do
394  end do
395 
396 
397 
398 
400 
401  !---------------------------------------------------------------------------!
403  subroutine evaluate_field_single_spline_pp_3d_feec(self, position, degree, field_dofs_pp, field_value)
404  class(sll_t_particle_mesh_coupling_spline_3d_feec), intent( inout ) :: self
405  sll_real64, intent( in ) :: position(3)
406  sll_int32 , intent( in ) :: degree(3)
407  sll_real64, intent( in ) :: field_dofs_pp(:,:)
408  sll_real64, intent( out ) :: field_value
409 
410  sll_int32 :: box(3)
411  sll_real64 :: xi(3)
412 
413  call convert_x_to_xbox( self, position, xi, box )
414 
415  field_value = sll_f_spline_pp_horner_3d(degree, field_dofs_pp, xi, box,self%n_cells)
416 
418 
419 
420 
421  !---------------------------------------------------------------------------!
423  subroutine evaluate_multiple_spline_3d_feec(self, position, components, field_dofs, field_value)
424  class(sll_t_particle_mesh_coupling_spline_3d_feec), intent( inout ) :: self
425  sll_real64, intent( in ) :: position(3)
426  sll_int32, intent(in) :: components(:)
427  sll_real64, intent( in ) :: field_dofs(:,:)
428  sll_real64, intent(out) :: field_value(:)
429 
430 
431 
432  end subroutine evaluate_multiple_spline_3d_feec
433 
435  pure function convert_index_3d_to_1d( index3d, n_cells ) result( index1d )
436  sll_int32, intent( in ) :: index3d(3)
437  sll_int32, intent( in ) :: n_cells(3)
438  sll_int32 :: index1d
439 
440  index1d = index3d(1) + (index3d(2)-1)*n_cells(1) + (index3d(3)-1)*n_cells(1)*n_cells(2)
441 
442  end function convert_index_3d_to_1d
443 
445  subroutine convert_x_to_xbox( self, position, xi, box )
446  class( sll_t_particle_mesh_coupling_spline_3d_feec ), intent(inout) :: self
447  sll_real64, intent( in ) :: position(3)
448  sll_real64, intent( out ) :: xi(3)
449  sll_int32, intent( out ) :: box(3)
450 
451  xi = (position - self%domain(:,1)) /self%delta_x!* self%rdelta_x ! destroys perfect gauss conservation for symplectic splitting with fft solver
452  box = floor( xi ) + 1
453  xi = xi - real(box-1, f64)
454 
455  end subroutine convert_x_to_xbox
456 
458  subroutine convert_x_to_xbox_1d( self, component, position, xi, box )
459  class( sll_t_particle_mesh_coupling_spline_3d_feec ), intent(inout) :: self
460  sll_int32, intent( in ) :: component
461  sll_real64, intent( in ) :: position
462  sll_real64, intent( out ) :: xi
463  sll_int32, intent( out ) :: box
464 
465  xi = (position - self%domain(component,1))/self%delta_x(component)!* self%rdelta_x ! destroys perfect gauss conservation for symplectic splitting with fft solver
466  box = floor( xi ) + 1
467  xi = xi - real(box-1, f64)
468 
469  end subroutine convert_x_to_xbox_1d
470 
471 
473  subroutine box_index( self, box, comp )
474  class(sll_t_particle_mesh_coupling_spline_3d_feec), intent(inout) :: self
475  sll_int32, intent(in) :: box
476  sll_int32, intent(in) :: comp
477  !local variables
478  sll_int32 :: j
479 
480  do j = 1, self%spline_degree(comp)+1
481  self%index1d(j,comp) = modulo(box+j-2,self%n_cells(comp))+1
482  end do
483 
484  end subroutine box_index
485 
487  subroutine add_current_evaluate ( self, position_old, position_new, xdot, efield_dofs, j_dofs, efield_val)
488  class( sll_t_particle_mesh_coupling_spline_3d_feec ), intent(inout) :: self
489  sll_real64, intent( in ) :: position_old(3)
490  sll_real64, intent( in ) :: position_new(3)
491  sll_real64, intent( in ) :: xdot(3)
492  sll_real64, intent( in ) :: efield_dofs(:)
493  sll_real64, intent( inout ) :: j_dofs(:)
494  sll_real64, intent( out ) :: efield_val(3)
495  !local variables
496  sll_real64 :: xold(3), xnew(3), xnewtilde(3), xbox(3)
497  sll_int32 :: boxold(3), boxnew(3), sigma_counter(3), boxdiff(3), increment(3), box(3)
498  sll_real64 :: sigma_r, sigma_l, sigma, sigma_next(3), field_value(3), weight
499  sll_int32 :: j, q, bl, maxind, index_is
500  type(vector) :: sigmas(3)
501 
502  call convert_x_to_xbox( self, position_old, xold, boxold )
503  call convert_x_to_xbox( self, position_new, xnew, boxnew )
504 
505  ! Now we need to compute the normalized 1d line along which to integrate:
506  boxdiff = boxnew-boxold
507  xnewtilde = xnew + real(boxdiff,f64)
508 
509  sigma_l = 0.0_f64
510  box = boxold ! We start in the old box
511 
512  sigma_counter = 0
513 
514  efield_val = 0.0_f64
515 
516  do j = 1, 3
517  if (boxdiff(j) > 0 ) then
518  allocate ( sigmas(j)%vals(boxdiff(j)+1) )
519  do bl = 1, boxdiff(j)
520  sigmas(j)%vals(bl) = (real(bl,f64) - xold(j))/(xnewtilde(j)-xold(j))
521  end do
522  sigmas(j)%vals(boxdiff(j)+1) = 1.0_f64
523  sigma_next(j) = sigmas(j)%vals(1)
524  increment(j) = 1
525  elseif (boxdiff(j) < 0 ) then
526  allocate ( sigmas(j)%vals(-boxdiff(j)+1) )
527  do bl = boxdiff(j)+1, 0
528  sigmas(j)%vals(-bl+1) = (real(bl,f64) - xold(j))/(xnewtilde(j)-xold(j))
529  end do
530  sigmas(j)%vals(-boxdiff(j)+1) = 1.0_f64
531  sigma_next(j) = sigmas(j)%vals(1)
532  increment(j) = -1
533  else
534  sigma_next(j) = 1.0_f64
535  increment(j) = 0
536  end if
537  end do
538 
539  sigma_r = 0.0_f64
540  do while ( abs(sigma_r - 1.0_f64) > 1d-16 )
541  ! Identify index of next intersection
542  index_is = minloc(sigma_next, dim=1)
543  sigma_r = sigma_next(index_is)
544 
545  do q = 1, self%n_quad_points_line
546  sigma = sigma_l + (sigma_r-sigma_l) * self%quad_xw_line(1,q)
547  xbox = xold* (1.0_f64 - sigma) + xnewtilde * sigma - real(sigma_counter*increment, f64)
548  if (maxval(xbox) > 1.0_f64 ) then
549  print*, xbox, sigma, sigma_counter, increment
550  print*, xold, xnewtilde, sigma_r, xnewtilde * sigma - real(sigma_counter*increment, f64)
551  sll_error( 'add_current_evaluate', 'box value too large')
552  elseif (minval(xbox) < 0.0_f64 ) then
553  print*, xbox, sigma, sigma_counter, increment
554  print*, xold, xnewtilde, sigma_r, xnewtilde * sigma - real(sigma_counter*increment, f64)
555  sll_error( 'add_current_evaluate', 'box value too low')
556  end if
557 
558  weight = self%quad_xw_line(2,q)*(sigma_r-sigma_l)
559 
560  call point_add_eval (self, box, xbox, efield_dofs, xdot*weight, j_dofs, field_value )
561  efield_val = efield_val + field_value * weight
562  end do
563  if (sigma_r < 1.0_f64 ) then
564  ! Update the
565  sigma_counter(index_is) = sigma_counter(index_is)+1
566  sigma_next(index_is) = sigmas(index_is)%vals(sigma_counter(index_is)+1)
567  box(index_is) = box(index_is) + increment(index_is)
568  sigma_l = sigma_r
569  end if
570  end do
571 
572  end subroutine add_current_evaluate
573 
575  subroutine point_add_eval ( self, box_in, xbox, field_dofs, weight, j_dofs, field_value )
576  class( sll_t_particle_mesh_coupling_spline_3d_feec ), intent(inout) :: self
577  sll_int32, intent(in) :: box_in(3)
578  sll_real64, intent(in) :: xbox(3)
579  sll_real64, intent(in) :: field_dofs(:)
580  sll_real64, intent(in) :: weight(3)
581  sll_real64, intent(inout) :: j_dofs(:)
582  sll_real64, intent(out) :: field_value(3)
583  !local variables
584  sll_int32 :: i,j,k, index1d, n_total
585  sll_int32 :: box(3), index3d(3)
586  sll_real64 :: spval
587 
588  n_total = self%n_total
589  field_value = 0.0_f64
590 
591  do j = 1, 3
592  call sll_s_uniform_bsplines_eval_basis( self%spline_degree(j), xbox(j), &
593  self%spline_0(1:self%spline_degree(j)+1,j) )
594  call sll_s_uniform_bsplines_eval_basis( self%spline_degree(j)-1, xbox(j), &
595  self%spline_1(1:self%spline_degree(j),j) )
596  end do
597 
598  box = box_in-self%spline_degree
599 
600  box(1) = box(1)+1
601  call box_index( self, box(1), 1 )
602  call box_index( self, box(2), 2 )
603  call box_index( self, box(3), 3 )
604  do k = 1, self%spline_degree(3)+1
605  index3d(3) = (self%index1d(k,3)-1)*self%n_cells(1)*self%n_cells(2)
606  do j = 1, self%spline_degree(2)+1
607  index3d(2) = index3d(3) + (self%index1d(j,2)-1)*self%n_cells(1)
608  do i = 1, self%spline_degree(1)
609  index1d = index3d(2) + self%index1d(i,1)
610 
611  spval = self%spline_1(i,1) * &
612  self%spline_0(j,2) * self%spline_0(k,3)
613  field_value(1) = field_value(1) + field_dofs(index1d) * spval
614  j_dofs(index1d) = j_dofs(index1d) + &
615  weight(1) * spval
616  end do
617  end do
618  end do
619 
620  box(1) = box(1)-1
621  box(2) = box(2)+1
622  call box_index( self, box(1), 1 )
623  call box_index( self, box(2), 2 )
624  do k = 1, self%spline_degree(3)+1
625  index3d(3) = (self%index1d(k,3)-1)*self%n_cells(1)*self%n_cells(2)
626  do j = 1, self%spline_degree(2)
627  index3d(2) = index3d(3) + (self%index1d(j,2)-1)*self%n_cells(1)
628  do i = 1, self%spline_degree(1)+1
629  index1d = index3d(2) + self%index1d(i,1) + n_total
630 
631  spval = self%spline_0(i,1) * &
632  self%spline_1(j,2) * self%spline_0(k,3)
633  field_value(2) = field_value(2) + field_dofs(index1d ) * spval
634  j_dofs(index1d) = j_dofs(index1d) + &
635  weight(2) * spval
636  end do
637  end do
638  end do
639 
640  n_total = n_total*2
641 
642  box(2) = box(2)-1
643  box(3) = box(3)+1
644  call box_index( self, box(2), 2 )
645  call box_index( self, box(3), 3 )
646  do k = 1, self%spline_degree(3)
647  index3d(3) = (self%index1d(k,3)-1)*self%n_cells(1)*self%n_cells(2)
648  do j = 1, self%spline_degree(2)+1
649  index3d(2) = index3d(3) + (self%index1d(j,2)-1)*self%n_cells(1)
650  do i = 1, self%spline_degree(1)+1
651  index1d = index3d(2) + self%index1d(i,1) + n_total
652  spval = self%spline_0(i,1) * &
653  self%spline_0(j,2) * self%spline_1(k,3)
654  field_value(3) = field_value(3) + field_dofs(index1d ) * spval
655  j_dofs(index1d) = j_dofs(index1d) + &
656  weight(3) * spval
657  end do
658  end do
659  end do
660 
661 
662  end subroutine point_add_eval
663 
665  subroutine add_current_3d ( self, position_old, position_new, xdot, j_dofs)
666  class( sll_t_particle_mesh_coupling_spline_3d_feec ), intent(inout) :: self
667  sll_real64, intent( in ) :: position_old(3)
668  sll_real64, intent( in ) :: position_new(3)
669  sll_real64, intent( in ) :: xdot(3)
670  sll_real64, intent( inout ) :: j_dofs(:)
671  !local variables
672  sll_real64 :: xold(3), xnew(3), xnewtilde(3), xbox(3)
673  sll_int32 :: boxold(3), boxnew(3), sigma_counter(3), boxdiff(3), increment(3), box(3)
674  sll_real64 :: sigma_r, sigma_l, sigma, sigma_next(3), field_value(3), weight
675  sll_int32 :: j, q, bl, maxind, index_is
676  type(vector) :: sigmas(3)
677 
678 
679  call convert_x_to_xbox( self, position_old, xold, boxold )
680  call convert_x_to_xbox( self, position_new, xnew, boxnew )
681 
682  ! Now we need to compute the normalized 1d line along which to integrate:
683  boxdiff = boxnew-boxold
684  xnewtilde = xnew + real(boxdiff,f64)
685 
686  sigma_l = 0.0_f64
687  box = boxold ! We start in the old box
688 
689  sigma_counter = 0
690 
691  do j = 1, 3
692  if (boxdiff(j) > 0 ) then
693  allocate ( sigmas(j)%vals(boxdiff(j)+1) )
694  do bl = 1, boxdiff(j)
695  sigmas(j)%vals(bl) = (real(bl,f64) - xold(j))/(xnewtilde(j)-xold(j))
696  end do
697  sigmas(j)%vals(boxdiff(j)+1) = 1.0_f64
698  sigma_next(j) = sigmas(j)%vals(1)
699  increment(j) = 1
700  elseif (boxdiff(j) < 0 ) then
701  allocate ( sigmas(j)%vals(-boxdiff(j)+1) )
702  do bl = boxdiff(j)+1, 0
703  sigmas(j)%vals(-bl+1) = (real(bl,f64) - xold(j))/(xnewtilde(j)-xold(j))
704  end do
705  sigmas(j)%vals(-boxdiff(j)+1) = 1.0_f64
706  sigma_next(j) = sigmas(j)%vals(1)
707  increment(j) = -1
708  else
709  sigma_next(j) = 1.0_f64
710  increment(j) = 0
711  end if
712  end do
713 
714  sigma_r = 0.0_f64
715  do while ( abs(sigma_r - 1.0_f64) > 1d-16 )
716  ! Identify index of next intersection
717  index_is = minloc(sigma_next, dim=1)
718  sigma_r = sigma_next(index_is)
719 
720  do q = 1, self%n_quad_points_line
721  sigma = sigma_l + (sigma_r-sigma_l) * self%quad_xw_line(1,q)
722  xbox = xold* (1.0_f64 - sigma) + xnewtilde * sigma - real(sigma_counter*increment, f64)
723  if (maxval(xbox) > 1.0_f64 ) then
724  print*, xbox, sigma, sigma_counter, increment
725  print*, xold, xnewtilde, sigma_r, xnewtilde * sigma - real(sigma_counter*increment, f64)
726  sll_error( 'add_current_3d', 'box value too large')
727  elseif (minval(xbox) < 0.0_f64 ) then
728  print*, xbox, sigma, sigma_counter, increment
729  print*, xold, xnewtilde, sigma_r, xnewtilde * sigma - real(sigma_counter*increment, f64)
730  sll_error( 'add_current_3d', 'box value too low')
731  end if
732 
733  weight = self%quad_xw_line(2,q)*(sigma_r-sigma_l)
734 
735  call integrate_spline_3d(self, box, xbox, xdot*weight, j_dofs )
736  end do
737  if (sigma_r < 1.0_f64 ) then
738  ! Update the
739  sigma_counter(index_is) = sigma_counter(index_is)+1
740  sigma_next(index_is) = sigmas(index_is)%vals(sigma_counter(index_is)+1)
741  box(index_is) = box(index_is) + increment(index_is)
742  sigma_l = sigma_r
743  end if
744  end do
745  end subroutine add_current_3d
746 
748  subroutine integrate_spline_3d( self, box_in, xbox, weight, j_dofs )
749  class( sll_t_particle_mesh_coupling_spline_3d_feec ), intent(inout) :: self
750  sll_int32, intent( in ) :: box_in(3)
751  sll_real64, intent( in ) :: xbox(3)
752  sll_real64, intent( in ) :: weight(3)
753  sll_real64, intent( inout ) :: j_dofs(:)
754  !local variables
755  sll_int32 :: i,j,k, index1d
756  sll_int32 :: box(3), index3d(3)
757 
758  do j = 1, 3
759  call sll_s_uniform_bsplines_eval_basis( self%spline_degree(j), xbox(j), &
760  self%spline_0(1:self%spline_degree(j)+1,j) )
761  call sll_s_uniform_bsplines_eval_basis( self%spline_degree(j)-1, xbox(j), &
762  self%spline_1(1:self%spline_degree(j),j) )
763  end do
764 
765  box = box_in-self%spline_degree
766 
767  box(1) = box(1)+1
768  call box_index( self, box(1), 1 )
769  call box_index( self, box(2), 2 )
770  call box_index( self, box(3), 3 )
771  do k = 1, self%spline_degree(3)+1
772  index3d(3) = (self%index1d(k,3)-1)*self%n_cells(1)*self%n_cells(2)
773  do j = 1, self%spline_degree(2)+1
774  index3d(2) = index3d(3) + (self%index1d(j,2)-1)*self%n_cells(1)
775  do i = 1, self%spline_degree(1)
776  index1d = index3d(2) + self%index1d(i,1)
777 
778  j_dofs(index1d) = j_dofs(index1d) + &
779  weight(1) * self%spline_1(i,1) * &
780  self%spline_0(j,2) * self%spline_0(k,3)
781  end do
782  end do
783  end do
784 
785  box(1) = box(1)-1
786  box(2) = box(2)+1
787  call box_index( self, box(1), 1 )
788  call box_index( self, box(2), 2 )
789  do k = 1, self%spline_degree(3)+1
790  index3d(3) = (self%index1d(k,3)-1)*self%n_cells(1)*self%n_cells(2)
791  do j = 1, self%spline_degree(2)
792  index3d(2) = index3d(3) + (self%index1d(j,2)-1)*self%n_cells(1)
793  do i = 1, self%spline_degree(1)+1
794  index1d = index3d(2) + self%index1d(i,1) + self%n_total
795 
796  j_dofs(index1d) = j_dofs(index1d) + &
797  weight(2) * self%spline_0(i,1) * &
798  self%spline_1(j,2) * self%spline_0(k,3)
799  end do
800  end do
801  end do
802 
803  box(2) = box(2)-1
804  box(3) = box(3)+1
805  call box_index( self, box(2), 2 )
806  call box_index( self, box(3), 3 )
807  do k = 1, self%spline_degree(3)
808  index3d(3) = (self%index1d(k,3)-1)*self%n_cells(1)*self%n_cells(2)
809  do j = 1, self%spline_degree(2)+1
810  index3d(2) = index3d(3) + (self%index1d(j,2)-1)*self%n_cells(1)
811  do i = 1, self%spline_degree(1)+1
812  index1d = index3d(2) + self%index1d(i,1) + 2*self%n_total
813 
814  j_dofs(index1d) = j_dofs(index1d) + &
815  weight(3) * self%spline_0(i,1) * &
816  self%spline_0(j,2) * self%spline_1(k,3)
817  end do
818  end do
819  end do
820 
821 
822  end subroutine integrate_spline_3d
823 
825  subroutine add_current_spline_3d_feec (self, position_old, position_new, marker_charge, qoverm, bfield_dofs, vi, j_dofs)
826  class(sll_t_particle_mesh_coupling_spline_3d_feec), intent(inout) :: self
827  sll_real64, intent(in) :: position_old(3)
828  sll_real64, intent(in) :: position_new(3)
829  sll_real64, intent(in) :: marker_charge
830  sll_real64, intent(in) :: qoverm
831  sll_real64, intent(in) :: bfield_dofs(self%n_total*3)
832  sll_real64, intent(inout) :: vi(:)
833  sll_real64, intent(inout) :: j_dofs(self%n_total)
834 
835 
836  sll_int32 :: box(3), boxnew(3), boxold(3), local_size(3)
837  sll_int32 :: degree
838  sll_int32 :: index3d(3)
839  sll_int32 :: index1d
840  sll_int32 :: i,j,k
841  sll_real64 :: xnew(3), xold(3)
842  sll_int32 :: component
843 
844  component = 1
845  degree = self%spline_degree(component)
846  call convert_x_to_xbox( self, position_old, xold, boxold )
847  call convert_x_to_xbox( self, position_new, xnew, boxnew )
848 
849  local_size = abs(boxnew-boxold)+degree
850  local_size(2) = self%spline_degree(2)+1
851  local_size(3) = self%spline_degree(3)+1
852 
853  sll_assert_always( local_size(1) <= self%n_cells(1) )
854 
855  do i=1, degree
856  self%spline_1(i,1) = sll_f_spline_pp_horner_1d(degree, self%spline_pp1d_1(component)%poly_coeffs_fpa, xold(1), i) &
857  * self%delta_x(1)
858  self%spline_1(i,2) = sll_f_spline_pp_horner_1d(degree, self%spline_pp1d_1(component)%poly_coeffs_fpa, xnew(1), i) &
859  * self%delta_x(1)
860  end do
861 
862  if (position_old(1) < position_new(1) ) then
863  self%j1d(local_size(component)-degree+1:local_size(component)) = self%spline_1(1:degree,2)
864  self%j1d(1:local_size(component)-degree) = self%delta_x(1)
865  self%j1d(1:degree) = self%j1d(1:degree) - self%spline_1(1:degree,1)
866  else
867  self%j1d(1:local_size(component)-degree) = -self%delta_x(1)
868  self%j1d(local_size(component)-degree+1:local_size(component)) = -self%spline_1(1:degree,1)
869  self%j1d(1:degree) = self%j1d(1:degree) + self%spline_1(1:degree,2)
870  end if
871 
872  self%spline_0 = 0.0_f64
873  do j=1,3
874  if (j .ne. component ) then
875  call sll_s_uniform_bsplines_eval_basis( self%spline_degree(j), xold(j), self%spline_0(1:self%spline_degree(j)+1,j) )
876  end if
877  end do
878 
879  box = boxold-self%spline_degree
880  box(component) = min(boxnew(component), boxold(component))-degree+1
881  call box_index( self, box(1), 1 )
882  call box_index( self, box(2), 2 )
883  call box_index( self, box(3), 3 )
884  do k=1,local_size(3)
885  index3d(3) = self%index1d(k,3)!modulo(box(3)+k-2,self%n_cells(3))+1
886  do j=1,local_size(2)
887  index3d(2) = self%index1d(j,2)!modulo(box(2)+j-2,self%n_cells(2))+1
888  do i=1,local_size(1)
889  index3d(1) = self%index1d(i,1)!modulo(box(1)+i-2,self%n_cells(1))+1
890  index1d = convert_index_3d_to_1d( index3d, self%n_cells )
891  !print*, index1d, self%j1d(i), self%spline_0(j,2), self%spline_0(k,3)
892  j_dofs(index1d) = j_dofs(index1d) + &
893  marker_charge * self%j1d( i ) * &
894  self%spline_0(j,2) * self%spline_0(k,3)
895  end do
896  end do
897  end do
898 
899 
900 
901  end subroutine add_current_spline_3d_feec
902 
903 
905  subroutine add_current_update_v_primitive_component1_spline_3d_feec (self, position_old, position_new, marker_charge, qoverm, bfield_dofs, vi, j_dofs)
906  class(sll_t_particle_mesh_coupling_spline_3d_feec), intent(inout) :: self
907  sll_real64, intent(in) :: position_old(3)
908  sll_real64, intent(in) :: position_new
909  sll_real64, intent(in) :: marker_charge
910  sll_real64, intent(in) :: qoverm
911  sll_real64, intent(in) :: bfield_dofs(:)
912  sll_real64, intent(inout) :: vi(3)
913  sll_real64, intent(inout) :: j_dofs(:)
914  !local variables
915  sll_int32 :: box(3), boxnew, boxold
916  sll_real64 :: xi(3)
917  sll_int32 :: index3d(3)
918  sll_int32 :: index1d
919  sll_int32 :: i,j,k
920  sll_real64 :: xnew
921  sll_real64 :: vt(2), vtt2, vtt3
922  sll_int32 :: start1, start2
923  sll_int32 :: component
924  sll_int32 :: startjk, stride
925  sll_real64 :: splinejk
926  sll_int32 :: local_size
927  sll_int32 :: degree
928 
929  component = 1
930  start1 = 2*self%n_total
931  start2 = self%n_total
932  stride = 1
933  degree = self%spline_degree(component)
934 
935  call convert_x_to_xbox( self, position_old, xi, box )
936  call convert_x_to_xbox_1d( self, component, position_new, xnew, boxnew )
937  boxold = box(component)
938 
939  !-- For current along x1
940  local_size = abs(boxnew-boxold)+degree
941 
942  sll_assert_always( local_size <= self%n_cells(1)+degree )
943 
944  ! For j=component, we need the primitive
945  do i=1, degree
946  self%spline_1(i,1) = sll_f_spline_pp_horner_1d(degree, &
947  self%spline_pp1d_1(component)%poly_coeffs_fpa, xi(component), i) &
948  * self%delta_x(component)
949  self%spline_1(i,2) = sll_f_spline_pp_horner_1d(degree, &
950  self%spline_pp1d_1(component)%poly_coeffs_fpa, xnew, i) &
951  * self%delta_x(component)
952  end do
953 
954 
955  if (position_old(component) .le. position_new ) then
956  self%j1d(local_size-degree+1:local_size) = self%spline_1(1:degree,2)
957  self%j1d(1:local_size-degree) = self%delta_x(component)
958  self%j1d(1:degree) = self%j1d(1:degree) - self%spline_1(1:degree,1)
959  else
960  self%j1d(1:local_size-degree) = -self%delta_x(component)
961  self%j1d(local_size-degree+1:local_size) = -self%spline_1(1:degree,1)
962  self%j1d(1:degree) = self%j1d(1:degree) + self%spline_1(1:degree,2)
963  end if
964  !----
965 
966 
967  ! Achtung wir brauchen nun splines von beidem Grad
968  self%spline_0 = 0.0_f64
969  self%spline_1 = 0.0_f64
970  do j=1,3
971  if (j .ne. component ) then
972  call sll_s_spline_pp_horner_m_1d(self%spline_pp1d_0(j), self%spline_0(1:self%spline_degree(j)+1,j), self%spline_degree(j), xi(j))
973  call sll_s_spline_pp_horner_m_1d(self%spline_pp1d_1(j), self%spline_1(1:self%spline_degree(j),j), self%spline_degree(j)-1, xi(j))
974  end if
975  end do
976 
977  !box(component) = box(component)-degree+1
978  box(2:3) = box(2:3) - self%spline_degree(2:3)
979 
980  ! Define the range of the first component
981  if (boxold<boxnew) then
982  box(component) = boxold-degree+1
983  else
984  box(component) = boxnew-degree+1
985  end if
986 
987  call box_index( self, box(2), 2 )
988  call box_index( self, box(3), 3 )
989  do k = 1, self%spline_degree(3)+1
990  vtt2 = 0.0_f64
991  vtt3 = 0.0_f64
992  index3d(3) = self%index1d(k,3)!modulo(box(3)+k-2,self%n_cells(3))+1
993  do j = 1, self%spline_degree(2)+1
994  index3d(2) = self%index1d(j,2)!modulo(box(2)+j-2,self%n_cells(2))+1
995 
996  startjk = 1 + (index3d(2)-1)*self%n_cells(1) + &
997  (index3d(3)-1)*self%n_cells(1)*self%n_cells(2)
998  splinejk = self%spline_0(j, 2) * self%spline_0(k,3) * marker_charge
999 
1000  vt = 0.0_f64
1001  do i = 1, local_size
1002  index3d(1) = modulo(box(1)+i-2,self%n_cells(1))
1003  index1d = startjk+index3d(1)!convert_index_3d_to_1d( index3d, self%n_cells )
1004  j_dofs(index1d) = j_dofs(index1d) + self%j1d(i) * &
1005  splinejk
1006 
1007  vt(1) = vt(1) + bfield_dofs(start1+index1d)*self%j1d(i)
1008  vt(2) = vt(2) + bfield_dofs(start2+index1d)*self%j1d(i)
1009 
1010  end do
1011 
1012  if (j>1) then
1013  vtt2 = vtt2 + vt(1)*self%spline_1(j-1, 2)
1014  end if
1015  vtt3 = vtt3 - vt(2)*self%spline_0(j, 2)
1016 
1017  end do
1018  vi(2) = vi(2) - qoverm*vtt2*self%spline_0(k, 3)
1019  if ( k> 1) then
1020  vi(3) = vi(3) - qoverm*vtt3*self%spline_1(k-1, 3)
1021  end if
1022  end do
1023 
1024 
1025 
1027 
1029  subroutine add_current_update_v_primitive_component2_spline_3d_feec (self, position_old, position_new, marker_charge, qoverm, bfield_dofs, vi, j_dofs)
1030  class(sll_t_particle_mesh_coupling_spline_3d_feec), intent(inout) :: self
1031  sll_real64, intent(in) :: position_old(3)
1032  sll_real64, intent(in) :: position_new
1033  sll_real64, intent(in) :: marker_charge
1034  sll_real64, intent(in) :: qoverm
1035  sll_real64, intent(in) :: bfield_dofs(:)
1036  sll_real64, intent(inout) :: vi(3)
1037  sll_real64, intent(inout) :: j_dofs(:)
1038  !local variables
1039  sll_int32 :: box(3), boxnew, boxold
1040  sll_real64 :: xi(3)
1041  sll_int32 :: index3d(3)
1042  sll_int32 :: index1d
1043  sll_int32 :: i,j,k
1044  sll_real64 :: xnew
1045  sll_real64 :: vt(2), vtt2, vtt3
1046  sll_int32 :: start1, start2
1047  sll_int32 :: component, local_size
1048  sll_int32 :: stride, startjk
1049  sll_real64 :: splineik
1050  sll_int32 :: degree
1051 
1052  component = 2
1053  start1 = 2*self%n_total
1054  start2 = 0
1055  stride = self%n_cells(1)
1056  degree = self%spline_degree(component)
1057 
1058  call convert_x_to_xbox( self, position_old, xi, box )
1059  call convert_x_to_xbox_1d( self, component, position_new, xnew, boxnew )
1060  boxold = box(component)
1061 
1062  !-- For current along x2
1063  local_size = abs(boxnew-boxold)+degree
1064 
1065  sll_assert_always( local_size <= self%n_cells(2)+degree )
1066 
1067  ! For j=component, we need the primitive
1068  do i=1, degree
1069  self%spline_1(i,1) = sll_f_spline_pp_horner_1d(degree, &
1070  self%spline_pp1d_1(component)%poly_coeffs_fpa, xi(component), i) &
1071  * self%delta_x(component)
1072  self%spline_1(i,2) = sll_f_spline_pp_horner_1d(degree, &
1073  self%spline_pp1d_1(component)%poly_coeffs_fpa, xnew, i) &
1074  * self%delta_x(component)
1075  end do
1076 
1077  if (position_old(component) .le. position_new ) then
1078  self%j1d(local_size-degree+1:local_size) = self%spline_1(1:degree,2)
1079  self%j1d(1:local_size-degree) = self%delta_x(component)
1080  self%j1d(1:degree) = self%j1d(1:degree) - self%spline_1(1:degree,1)
1081  else
1082  self%j1d(1:local_size-degree) = -self%delta_x(component)
1083  self%j1d(local_size-degree+1:local_size) = -self%spline_1(1:degree,1)
1084  self%j1d(1:degree) = self%j1d(1:degree) + self%spline_1(1:degree,2)
1085  end if
1086  !----
1087 
1088 
1089  ! Achtung wir brauchen nun splines von beidem Grad
1090  self%spline_0 = 0.0_f64
1091  self%spline_1 = 0.0_f64
1092  do j=1,3
1093  if (j .ne. component ) then
1094  call sll_s_spline_pp_horner_m_1d(self%spline_pp1d_0(j), self%spline_0(1:self%spline_degree(j)+1,j), self%spline_degree(j), xi(j))
1095  call sll_s_spline_pp_horner_m_1d(self%spline_pp1d_1(j), self%spline_1(1:self%spline_degree(j),j), self%spline_degree(j)-1, xi(j))
1096  end if
1097  end do
1098 
1099  box(1) = box(1) - self%spline_degree(1)
1100  box(3) = box(3) - self%spline_degree(3)
1101 
1102  ! Define the range of the first component
1103  if (boxold<boxnew) then
1104  box(component) = boxold-degree+1
1105  else
1106  box(component) = boxnew-degree+1
1107  end if
1108 
1109  call box_index( self, box(1), 1 )
1110  call box_index( self, box(3), 3 )
1111  do k = 1, self%spline_degree(3)+1
1112  vtt2 = 0.0_f64
1113  vtt3 = 0.0_f64
1114  index3d(3) = self%index1d(k,3)!modulo(box(3)+k-2,self%n_cells(3))+1
1115  do j = 1, self%spline_degree(1)+1
1116  index3d(1) = self%index1d(j,1)!modulo(box(1)+j-2,self%n_cells(1))+1
1117 
1118  startjk = index3d(1) + &
1119  (index3d(3)-1)*self%n_cells(1)*self%n_cells(2)
1120  splineik = self%spline_0(j, 1) * self%spline_0(k,3) * marker_charge
1121 
1122  vt = 0.0_f64
1123  do i = 1, local_size
1124  index3d(2) = modulo(box(2)+i-2,self%n_cells(2))
1125  index1d = startjk+index3d(2)*stride
1126  j_dofs(index1d) = j_dofs(index1d) + self%j1d(i) * &
1127  splineik
1128 
1129  vt(1) = vt(1) + bfield_dofs(start1+index1d)*self%j1d(i)
1130  vt(2) = vt(2) + bfield_dofs(start2+index1d)*self%j1d(i)
1131  end do
1132 
1133  if (j>1) then
1134  vtt2 = vtt2 + vt(1)*self%spline_1(j-1, 1)
1135  end if
1136  vtt3 = vtt3 + vt(2)*self%spline_0(j, 1)
1137 
1138  end do
1139  vi(1) = vi(1) + qoverm*vtt2*self%spline_0(k, 3)
1140  if ( k> 1) then
1141  vi(3) = vi(3) - qoverm*vtt3*self%spline_1(k-1, 3)
1142  end if
1143  end do
1144 
1145 
1147 
1148 
1149 
1151  subroutine add_current_update_v_primitive_component3_spline_3d_feec (self, position_old, position_new, marker_charge, qoverm, bfield_dofs, vi, j_dofs)
1152  class(sll_t_particle_mesh_coupling_spline_3d_feec), intent(inout) :: self
1153  sll_real64, intent(in) :: position_old(3)
1154  sll_real64, intent(in) :: position_new
1155  sll_real64, intent(in) :: marker_charge
1156  sll_real64, intent(in) :: qoverm
1157  sll_real64, intent(in) :: bfield_dofs(:)
1158  sll_real64, intent(inout) :: vi(3)
1159  sll_real64, intent(inout) :: j_dofs(:)
1160  !local variables
1161  sll_int32 :: box(3), boxnew, boxold
1162  sll_real64 :: xi(3)
1163  sll_int32 :: index3d(3)
1164  sll_int32 :: index1d
1165  sll_int32 :: i,j,k
1166  sll_real64 :: xnew
1167  sll_real64 :: vt(2), vtt2, vtt3
1168  sll_int32 :: start1, start2
1169  sll_int32 :: component
1170  sll_int32 :: stride, startjk
1171  sll_real64 :: splineij
1172  sll_int32 :: local_size
1173  sll_int32 :: degree
1174 
1175  component = 3
1176  start1 = self%n_total
1177  start2 = 0
1178  stride = self%n_cells(1)*self%n_cells(2)
1179  degree = self%spline_degree(component)
1180 
1181  call convert_x_to_xbox( self, position_old, xi, box )
1182  call convert_x_to_xbox_1d( self, component, position_new, xnew, boxnew )
1183  boxold = box(component)
1184 
1185  !-- For current along x3
1186  local_size = abs(boxnew-boxold)+degree
1187 
1188  sll_assert_always( local_size <= self%n_cells(3)+degree )
1189 
1190  ! For j=component, we need the primitive
1191  do i=1, degree
1192  self%spline_1(i,1) = sll_f_spline_pp_horner_1d(degree, &
1193  self%spline_pp1d_1(component)%poly_coeffs_fpa, xi(component), i) &
1194  * self%delta_x(component)
1195  self%spline_1(i,2) = sll_f_spline_pp_horner_1d(degree, &
1196  self%spline_pp1d_1(component)%poly_coeffs_fpa, xnew, i) &
1197  * self%delta_x(component)
1198  end do
1199 
1200  if (position_old(component) .le. position_new ) then
1201  self%j1d(local_size-degree+1:local_size) = self%spline_1(1:degree,2)
1202  self%j1d(1:local_size-degree) = self%delta_x(component)
1203  self%j1d(1:degree) = self%j1d(1:degree) - self%spline_1(1:degree,1)
1204  else
1205  self%j1d(1:local_size-degree) = -self%delta_x(component)
1206  self%j1d(local_size-degree+1:local_size) = -self%spline_1(1:degree,1)
1207  self%j1d(1:degree) = self%j1d(1:degree) + self%spline_1(1:degree,2)
1208  end if
1209  !----
1210 
1211  ! Achtung wir brauchen nun splines von beidem Grad
1212  self%spline_0 = 0.0_f64
1213  self%spline_1 = 0.0_f64
1214  do j=1,3
1215  if (j .ne. component ) then
1216  call sll_s_spline_pp_horner_m_1d(self%spline_pp1d_0(j), self%spline_0(1:self%spline_degree(j)+1,j), self%spline_degree(j), xi(j))
1217  call sll_s_spline_pp_horner_m_1d(self%spline_pp1d_1(j), self%spline_1(1:self%spline_degree(j),j), self%spline_degree(j)-1, xi(j))
1218  end if
1219  end do
1220 
1221  box(1:2) = box(1:2) - self%spline_degree(1:2)
1222 
1223  ! Define the range of the first component
1224  if (boxold<boxnew) then
1225  box(component) = boxold-degree+1
1226  else
1227  box(component) = boxnew-degree+1
1228  end if
1229 
1230 
1231  call box_index( self, box(1), 1 )
1232  call box_index( self, box(2), 2 )
1233  do k = 1, self%spline_degree(2)+1
1234  vtt2 = 0.0_f64
1235  vtt3 = 0.0_f64
1236  index3d(2) = self%index1d(k,2)!modulo(box(2)+k-2,self%n_cells(2))+1
1237  do j = 1, self%spline_degree(1)+1
1238  index3d(1) = self%index1d(j,1)!modulo(box(1)+j-2,self%n_cells(1))+1
1239 
1240  startjk = index3d(1) + (index3d(2)-1)*self%n_cells(1)
1241  splineij = self%spline_0(j, 1) * self%spline_0(k,2) * marker_charge
1242 
1243  vt = 0.0_f64
1244  do i = 1, local_size
1245  index3d(3) = modulo(box(component)+i-2,self%n_cells(component))
1246  index1d = startjk + index3d(3)*stride
1247  j_dofs(index1d) = j_dofs(index1d) + self%j1d(i) * &
1248  splineij
1249 
1250  vt(1) = vt(1) + bfield_dofs(start1+index1d)*self%j1d(i)
1251  vt(2) = vt(2) + bfield_dofs(start2+index1d)*self%j1d(i)
1252  end do
1253 
1254  if (j>1) then
1255  vtt2 = vtt2 + vt(1)*self%spline_1(j-1, 1)
1256  end if
1257  vtt3 = vtt3 + vt(2)*self%spline_0(j, 1)
1258 
1259 
1260  end do
1261  vi(1) = vi(1) - qoverm*vtt2*self%spline_0(k, 2)
1262  if ( k> 1) then
1263  vi(2) = vi(2) + qoverm*vtt3*self%spline_1(k-1, 2)
1264  end if
1265  end do
1266 
1268 
1269 
1271  subroutine add_current_update_v_component1_spline_3d_feec (self, position_old, position_new, marker_charge, qoverm, bfield_dofs, vi, j_dofs)
1272  class(sll_t_particle_mesh_coupling_spline_3d_feec), intent(inout) :: self
1273  sll_real64, intent(in) :: position_old(3)
1274  sll_real64, intent(in) :: position_new
1275  sll_real64, intent(in) :: marker_charge
1276  sll_real64, intent(in) :: qoverm
1277  sll_real64, intent(in) :: bfield_dofs(:)
1278  sll_real64, intent(inout) :: vi(3)
1279  sll_real64, intent(inout) :: j_dofs(:)
1280  !local variables
1281  sll_int32 :: box(3), boxnew, boxold
1282  sll_real64 :: xi(3)
1283  sll_int32 :: index3d(3)
1284  sll_int32 :: index1d
1285  sll_int32 :: i,j,k
1286  sll_real64 :: xnew
1287  sll_real64 :: vt(2), vtt2, vtt3
1288  sll_int32 :: start1, start2
1289  sll_int32 :: component, local_size
1290  sll_int32 :: startjk, stride
1291  sll_real64 :: splinejk
1292  sll_int32 :: degree
1293 
1294  component = 1
1295  start1 = 2*self%n_total
1296  start2 = self%n_total
1297  stride = 1
1298  degree=self%spline_degree(component)
1299  call convert_x_to_xbox( self, position_old, xi, box )
1300  call convert_x_to_xbox_1d( self, component, position_new, xnew, boxnew )
1301  boxold = box(component)
1302 
1303  ! Achtung wir brauchen nun splines von beidem Grad
1304  self%spline_0 = 0.0_f64
1305  self%spline_1 = 0.0_f64
1306  do j=1,3
1307  if (j .ne. component ) then
1308  call sll_s_spline_pp_horner_m_1d(self%spline_pp1d_0(j), self%spline_0(1:self%spline_degree(j)+1,j), self%spline_degree(j), xi(j))
1309  call sll_s_spline_pp_horner_m_1d(self%spline_pp1d_1(j), self%spline_1(1:self%spline_degree(j),j), self%spline_degree(j)-1, xi(j))
1310  end if
1311  end do
1312 
1313  !box(component) = box(component)-degree+1
1314  box(2:3) = box(2:3) - self%spline_degree(2:3)
1315  local_size = abs(boxnew-boxold)+degree
1316 
1317  ! Define the range of the first component
1318  if (boxold<boxnew) then
1319  box(component) = boxold-degree+1
1320  else
1321  box(component) = boxnew-degree+1
1322  end if
1323 
1324  call box_index( self, box(2), 2 )
1325  call box_index( self, box(3), 3 )
1326  do k = 1, self%spline_degree(3)+1
1327  vtt2 = 0.0_f64
1328  vtt3 = 0.0_f64
1329  index3d(3) = self%index1d(k,3)!modulo(box(3)+k-2,self%n_cells(3))+1
1330  do j = 1, self%spline_degree(2)+1
1331  index3d(2) = self%index1d(j,2)!modulo(box(2)+j-2,self%n_cells(2))+1
1332 
1333  startjk = 1 + (index3d(2)-1)*self%n_cells(1) + &
1334  (index3d(3)-1)*self%n_cells(1)*self%n_cells(2)
1335  splinejk = self%spline_0(j, 2) * self%spline_0(k,3)
1336 
1337  vt = 0.0_f64
1338  self%j1d = 0.0_f64
1339  call add_current_1d(self, component, xi(component), boxold-1, xnew, boxnew-1, marker_charge, bfield_dofs, start1+startjk, start2+startjk, stride, vt, self%j1d)
1340  if (j>1) then
1341  vtt2 = vtt2 + vt(1)*self%spline_1(j-1, 2)
1342  end if
1343  vtt3 = vtt3 + vt(2)*self%spline_0(j, 2)
1344 
1345  do i = 1, local_size
1346  index3d(1) = modulo(box(1)+i-2,self%n_cells(1))+1
1347 
1348  index1d = startjk+index3d(1)-1!convert_index_3d_to_1d( index3d, self%n_cells )
1349  j_dofs(index1d) = j_dofs(index1d) + self%j1d(index3d(1)) * &
1350  splinejk
1351  end do
1352  end do
1353  vi(2) = vi(2) - qoverm*vtt2*self%spline_0(k, 3)
1354  if ( k> 1) then
1355  vi(3) = vi(3) + qoverm*vtt3*self%spline_1(k-1, 3)
1356  end if
1357  end do
1358 
1359 
1360 
1362 
1364  subroutine add_current_update_v_component2_spline_3d_feec (self, position_old, position_new, marker_charge, qoverm, bfield_dofs, vi, j_dofs)
1365  class(sll_t_particle_mesh_coupling_spline_3d_feec), intent(inout) :: self
1366  sll_real64, intent(in) :: position_old(3)
1367  sll_real64, intent(in) :: position_new
1368  sll_real64, intent(in) :: marker_charge
1369  sll_real64, intent(in) :: qoverm
1370  sll_real64, intent(in) :: bfield_dofs(:)
1371  sll_real64, intent(inout) :: vi(3)
1372  sll_real64, intent(inout) :: j_dofs(:)
1373  !local variables
1374  sll_int32 :: box(3), boxnew, boxold
1375  sll_real64 :: xi(3)
1376  sll_int32 :: index3d(3)
1377  sll_int32 :: index1d
1378  sll_int32 :: i,j,k
1379  sll_real64 :: xnew
1380  sll_real64 :: vt(2), vtt2, vtt3
1381  sll_int32 :: start1, start2
1382  sll_int32 :: component, local_size
1383  sll_int32 :: stride, startjk
1384  sll_real64 :: splineik
1385  sll_int32 :: degree
1386 
1387  component = 2
1388  start1 = 2*self%n_total
1389  start2 = 0
1390  stride = self%n_cells(1)
1391  degree=self%spline_degree(component)
1392 
1393  call convert_x_to_xbox( self, position_old, xi, box )
1394  call convert_x_to_xbox_1d( self, component, position_new, xnew, boxnew )
1395  boxold = box(component)
1396 
1397 
1398  ! Achtung wir brauchen nun splines von beidem Grad
1399  self%spline_0 = 0.0_f64
1400  self%spline_1 = 0.0_f64
1401  do j=1,3
1402  if (j .ne. component ) then
1403  call sll_s_spline_pp_horner_m_1d(self%spline_pp1d_0(j), self%spline_0(1:self%spline_degree(j)+1,j), self%spline_degree(j), xi(j))
1404  call sll_s_spline_pp_horner_m_1d(self%spline_pp1d_1(j), self%spline_1(1:self%spline_degree(j),j), self%spline_degree(j)-1, xi(j))
1405  end if
1406  end do
1407 
1408  box(1) = box(1) - self%spline_degree(1)
1409  box(3) = box(3) - self%spline_degree(3)
1410  local_size = abs(boxnew-boxold)+degree
1411 
1412  ! Define the range of the second component
1413  if (boxold<boxnew) then
1414  box(component) = boxold-degree+1
1415  else
1416  box(component) = boxnew-degree+1
1417  end if
1418 
1419 
1420  call box_index( self, box(1), 1 )
1421  call box_index( self, box(3), 3 )
1422  do k = 1, self%spline_degree(3)+1
1423  vtt2 = 0.0_f64
1424  vtt3 = 0.0_f64
1425  index3d(3) = self%index1d(k,3)!modulo(box(3)+k-2,self%n_cells(3))+1
1426  do j = 1, self%spline_degree(1)+1
1427  index3d(1) = self%index1d(j,1)!modulo(box(1)+j-2,self%n_cells(1))+1
1428 
1429  startjk = index3d(1) + &
1430  (index3d(3)-1)*self%n_cells(1)*self%n_cells(2)
1431  splineik = self%spline_0(j, 1) * self%spline_0(k,3)
1432 
1433  vt = 0.0_f64
1434  self%j1d = 0.0_f64
1435  call add_current_1d(self, component, xi(component), boxold-1, xnew, boxnew-1, marker_charge, bfield_dofs, start1+startjk, start2+startjk, stride, vt, self%j1d)
1436 
1437  if (j>1) then
1438  vtt2 = vtt2 + vt(1)*self%spline_1(j-1, 1)
1439  end if
1440  vtt3 = vtt3 + vt(2)*self%spline_0(j, 1)
1441 
1442  do i = 1, local_size
1443  index3d(2) = modulo(box(2)+i-2,self%n_cells(2))+1
1444  index1d = startjk+(index3d(2)-1)*stride!convert_index_3d_to_1d( index3d, self%n_cells )
1445  j_dofs(index1d) = j_dofs(index1d) + self%j1d(index3d(2)) * &
1446  splineik
1447 
1448  end do
1449  end do
1450  vi(1) = vi(1) + qoverm*vtt2*self%spline_0(k, 3)
1451  if ( k> 1) then
1452  vi(3) = vi(3) - qoverm*vtt3*self%spline_1(k-1, 3)
1453  end if
1454  end do
1455 
1456 
1458 
1459 
1461  subroutine add_current_update_v_component3_spline_3d_feec (self, position_old, position_new, marker_charge, qoverm, bfield_dofs, vi, j_dofs)
1462  class(sll_t_particle_mesh_coupling_spline_3d_feec), intent(inout) :: self
1463  sll_real64, intent(in) :: position_old(3)
1464  sll_real64, intent(in) :: position_new
1465  sll_real64, intent(in) :: marker_charge
1466  sll_real64, intent(in) :: qoverm
1467  sll_real64, intent(in) :: bfield_dofs(:)
1468  sll_real64, intent(inout) :: vi(3)
1469  sll_real64, intent(inout) :: j_dofs(:)
1470  !local variables
1471  sll_int32 :: box(3), boxnew, boxold
1472  sll_real64 :: xi(3)
1473  sll_int32 :: index3d(3)
1474  sll_int32 :: index1d
1475  sll_int32 :: i,j,k
1476  sll_real64 :: xnew
1477  sll_real64 :: vt(2), vtt2, vtt3
1478  sll_int32 :: start1, start2
1479  sll_int32 :: component, local_size
1480  sll_int32 :: stride, startjk
1481  sll_real64 :: splineij
1482  sll_int32 :: degree
1483 
1484  component = 3
1485  start1 = self%n_total
1486  start2 = 0
1487  stride = self%n_cells(1)*self%n_cells(2)
1488  degree=self%spline_degree(component)
1489 
1490  call convert_x_to_xbox( self, position_old, xi, box )
1491  call convert_x_to_xbox_1d( self, component, position_new, xnew, boxnew )
1492  boxold = box(component)
1493 
1494  ! Achtung wir brauchen nun splines von beidem Grad
1495  self%spline_0 = 0.0_f64
1496  self%spline_1 = 0.0_f64
1497  do j=1,3
1498  if (j .ne. component ) then
1499  call sll_s_spline_pp_horner_m_1d(self%spline_pp1d_0(j), self%spline_0(1:self%spline_degree(j)+1,j), self%spline_degree(j), xi(j))
1500  call sll_s_spline_pp_horner_m_1d(self%spline_pp1d_1(j), self%spline_1(1:self%spline_degree(j),j), self%spline_degree(j)-1, xi(j))
1501  end if
1502  end do
1503 
1504  box(1:2) = box(1:2) - self%spline_degree(1:2)
1505  local_size = abs(boxnew-boxold)+degree
1506  ! Define the range of the third component
1507  if (boxold<boxnew) then
1508  box(component) = boxold-degree+1
1509  else
1510  box(component) = boxnew-degree+1
1511  end if
1512 
1513  call box_index( self, box(1), 1 )
1514  call box_index( self, box(2), 2 )
1515  do k = 1, self%spline_degree(2)+1
1516  vtt2 = 0.0_f64
1517  vtt3 = 0.0_f64
1518  index3d(2) = self%index1d(k,2)!modulo(box(2)+k-2,self%n_cells(2))+1
1519  do j = 1, self%spline_degree(1)+1
1520  index3d(1) = self%index1d(j,1)!modulo(box(1)+j-2,self%n_cells(1))+1
1521 
1522  startjk = index3d(1) + (index3d(2)-1)*self%n_cells(1)
1523  splineij = self%spline_0(j, 1) * self%spline_0(k,2)
1524 
1525  vt = 0.0_f64
1526  self%j1d = 0.0_f64
1527  call add_current_1d(self, component, xi(component), boxold-1, xnew, boxnew-1, marker_charge, bfield_dofs, start1+startjk, start2+startjk, stride, vt, self%j1d)
1528  if (j>1) then
1529  vtt2 = vtt2 + vt(1)*self%spline_1(j-1, 1)
1530  end if
1531  vtt3 = vtt3 + vt(2)*self%spline_0(j, 1)
1532 
1533  do i = 1, local_size
1534  index3d(3) = modulo(box(component)+i-2,self%n_cells(component))+1
1535  index1d = startjk + (index3d(3)-1)*stride!convert_index_3d_to_1d( index3d, self%n_cells )
1536 
1537  j_dofs(index1d) = j_dofs(index1d) + self%j1d(index3d(3)) * &
1538  splineij
1539  end do
1540  end do
1541  vi(1) = vi(1) - qoverm*vtt2*self%spline_0(k, 2)
1542  if ( k> 1) then
1543  vi(2) = vi(2) + qoverm*vtt3*self%spline_1(k-1, 2)
1544  end if
1545  end do
1546 
1548 
1549 
1551  subroutine add_current_1d (self, component, r_old, index_old, r_new, index_new, marker_charge, bfield_dofs, start1, start2, stride, vi, j_dofs)
1552  class(sll_t_particle_mesh_coupling_spline_3d_feec), intent(inout) :: self
1553  sll_int32, intent(in) :: component
1554  sll_real64, intent(in) :: r_old
1555  sll_int32, intent(in) :: index_old
1556  sll_real64, intent(in) :: r_new
1557  sll_int32, intent(in) :: index_new
1558  !sll_real64, intent(in) :: position_old(3) !< Position at time t
1559  !sll_real64, intent(in) :: position_new(3) !< Position at time t + \Delta t
1560  sll_real64, intent(in) :: marker_charge
1561  sll_real64, intent(in) :: bfield_dofs(self%n_total*3)
1562  sll_int32, intent(in) :: start1
1563  sll_int32, intent(in) :: start2
1564  sll_int32, intent(in) :: stride
1565  sll_real64, intent(inout) :: vi(2)
1566  sll_real64, intent(inout) :: j_dofs(self%n_total)
1567  ! local variables
1568  sll_int32 :: ind
1569 
1570  if (index_old == index_new) then
1571  if (r_old < r_new) then
1572  call update_jv(self, component, r_old, r_new, index_old, marker_charge, &
1573  1.0_f64, bfield_dofs, start1, start2, stride, vi, j_dofs)
1574  else
1575  call update_jv(self, component, r_new, r_old, index_old, marker_charge, &
1576  -1.0_f64, bfield_dofs, start1, start2, stride, vi, j_dofs)
1577  end if
1578  elseif (index_old < index_new) then
1579  call update_jv (self, component, r_old, 1.0_f64, index_old, marker_charge, &
1580  1.0_f64, bfield_dofs, start1, start2, stride, vi, j_dofs)
1581  call update_jv (self, component, 0.0_f64, r_new, index_new, marker_charge, &
1582  1.0_f64, bfield_dofs, start1, start2, stride, vi, j_dofs)
1583  do ind = index_old+1, index_new-1
1584  call update_jv (self, component, 0.0_f64, 1.0_f64, ind, marker_charge, &
1585  1.0_f64, bfield_dofs, start1, start2, stride, vi, j_dofs)
1586  end do
1587  else
1588  call update_jv (self, component, r_new, 1.0_f64, index_new, marker_charge, &
1589  -1.0_f64, bfield_dofs, start1, start2, stride, vi, j_dofs)
1590  call update_jv (self, component, 0.0_f64, r_old, index_old, marker_charge, &
1591  -1.0_f64, bfield_dofs, start1, start2, stride, vi, j_dofs)
1592  do ind = index_new+1, index_old-1
1593  call update_jv (self, component, 0.0_f64, 1.0_f64, ind, marker_charge, &
1594  -1.0_f64, bfield_dofs, start1, start2, stride, vi, j_dofs)
1595  end do
1596  end if
1597 
1598 
1599  end subroutine add_current_1d
1600 
1601 
1602 
1604  subroutine update_jv(self, component, lower, upper, index, marker_charge, sign, bfield_dofs, start1, start2, stride, vi, j_dofs)
1605  class(sll_t_particle_mesh_coupling_spline_3d_feec), intent(inout) :: self
1606  sll_int32, intent(in) :: component
1607  sll_real64, intent(in) :: lower
1608  sll_real64, intent(in) :: upper
1609  sll_int32, intent(in) :: index
1610  sll_real64, intent(in) :: marker_charge
1611  sll_real64, intent(in) :: sign
1612  sll_real64, intent(inout) :: vi(2)
1613  sll_real64, intent(in) :: bfield_dofs(self%n_total*3)
1614  sll_int32, intent(in) :: start1
1615  sll_int32, intent(in) :: start2
1616  sll_int32, intent(in) :: stride
1617  sll_real64, intent(inout) :: j_dofs(self%n_total)
1618  !Local variables
1619  sll_int32 :: ind, i_grid, i_mod, j
1620  sll_real64 :: c1, c2
1621  sll_int32 :: spline_degree
1622  sll_int32 :: n_cells
1623 
1624  self%spline_val(:,1) = 0._f64
1625  self%spline_val_more(:,1) = 0._f64
1626 
1627  n_cells = self%n_cells(component)
1628  spline_degree = self%spline_degree(component)-1
1629 
1630  c1 = 0.5_f64*(upper-lower)
1631  c2 = 0.5_f64*(upper+lower)
1632 
1633  call sll_s_uniform_bsplines_eval_basis(spline_degree, c1*self%quad_xw(1,1)+c2, &
1634  self%spline_val(1:spline_degree+1,1))
1635  self%spline_val(:,1) = self%spline_val(:,1) * (self%quad_xw(2,1)*c1)
1636  do j = 2, self%n_quad_points
1637  call sll_s_uniform_bsplines_eval_basis(spline_degree, c1*self%quad_xw(1,j)+c2, &
1638  self%spline_val_more(1:spline_degree+1,1))
1639  self%spline_val(:,1) = self%spline_val(:,1) + self%spline_val_more(:,1) * (self%quad_xw(2,j)*c1)
1640  end do
1641  self%spline_val(:,1) = self%spline_val(:,1) * (sign*self%delta_x(component))
1642 
1643  ind = 1
1644  do i_grid = index - spline_degree , index
1645  i_mod = modulo(i_grid, n_cells )
1646  j_dofs(i_mod+1) = j_dofs(i_mod+1) + &
1647  (marker_charge*self%spline_val(ind,1))
1648  vi(1) = vi(1) + self%spline_val(ind,1)*bfield_dofs(i_mod*stride+start1)
1649  vi(2) = vi(2) + self%spline_val(ind,1)*bfield_dofs(i_mod*stride+start2)
1650  ind = ind + 1
1651  end do
1652 
1653  end subroutine update_jv
1654 
1655 
1656 
1658  subroutine init_spline_3d_feec ( self, n_cells, domain, spline_degree, no_particles )
1659  class(sll_t_particle_mesh_coupling_spline_3d_feec), intent( out ) :: self
1660  sll_int32, intent(in) :: n_cells(3)
1661  sll_real64, intent(in) :: domain(3,2)
1662  sll_int32, intent(in) :: spline_degree(3)
1663  sll_int32, optional, intent(in) :: no_particles
1664  !local variables
1665  sll_int32 :: maxspan, j, maxind
1666 
1667  ! Store grid information
1668  self%domain = domain
1669  self%n_cells = n_cells
1670  self%n_total = product(n_cells)
1671  self%delta_x = (self%domain(:,2)-self%domain(:,1))/real(n_cells, f64)
1672  self%rdelta_x = 1.0_f64/self%delta_x
1673 
1674  ! Store basis function information
1675  if( present(no_particles) ) then
1676  self%no_particles = no_particles
1677  else
1678  self%no_particles = 1
1679  end if
1680 
1681  ! Initialize information on the spline
1682  self%spline_degree = spline_degree
1683  maxspan = maxval(spline_degree + 1)
1684 
1685 !!!Besser n_quad_points als vektor
1686  self%n_quad_points = (maxval(self%spline_degree)+2)/2
1687  allocate( self%quad_xw(2,self%n_quad_points) )
1688  ! normalized Gauss Legendre points and weights
1689  self%quad_xw = sll_f_gauss_legendre_points_and_weights(self%n_quad_points)
1690 
1691  ! For the line integral
1692  self%n_quad_points_line = sum(self%spline_degree) -1 ! Degree of the polynomial in time for the line integral
1693  self%n_quad_points_line = ceiling(real(self%n_quad_points_line+1, f64)*0.5_f64) ! Compute the number of Gauss points needed to get exact integrals for this polynomial
1694 
1695  !print*, 'Size line quadrature', self%n_quad_points_line
1696  !self%n_quad_points_line = 3
1697  allocate( self%quad_xw_line(2,self%n_quad_points_line) )
1698  ! normalized Gauss Legendre points and weights
1699  self%quad_xw_line = sll_f_gauss_legendre_points_and_weights(self%n_quad_points_line)
1700 
1701  self%quad_xw_line(1,:) = 0.5_f64*(self%quad_xw_line(1,:)+1.0_f64)
1702  self%quad_xw_line(2,:) = 0.5_f64*self%quad_xw_line(2,:)
1703 
1704 
1705  allocate( self%spline_val(maxspan,3) )
1706  allocate( self%spline_val_more(maxspan,3) )
1707  allocate( self%spline_0(maxspan,3) )
1708  allocate( self%spline_1(maxspan-1,3) )
1709  allocate( self%spline_0_deriv(maxspan,3) )
1710  allocate( self%spline_1_deriv(maxspan-1,3) )
1711  allocate( self%spline1_0(maxspan,3) )
1712  allocate( self%j1d( maxval(self%n_cells)+maxval(self%spline_degree) ))
1713  allocate( self%spline_2d(maxspan, maxspan) )
1714  allocate( self%spline1_2d(1:maxspan, 1:maxspan) )
1715  allocate( self%spline1_3d(1:maxspan, 1:maxspan, 1:maxspan) )
1716  allocate( self%spline2_3d(1:maxspan, 1:maxspan, 1:maxspan) )
1717  allocate( self%index1d(maxspan, 3) )
1718 
1719  call sll_s_spline_pp_init_3d(self%spline_pp_0, spline_degree, n_cells)
1720  call sll_s_spline_pp_init_3d(self%spline_pp_1, spline_degree-1, n_cells)
1721  do j = 1, 3
1722  call sll_s_spline_pp_init_1d( self%spline_pp1d_0(j), spline_degree(j), n_cells(j) )
1723  call sll_s_spline_pp_init_1d( self%spline_pp1d_1(j), spline_degree(j)-1, n_cells(j) )
1724  end do
1725 
1726  end subroutine init_spline_3d_feec
1727 
1728 
1730  subroutine free_spline_3d_feec(self)
1731  class(sll_t_particle_mesh_coupling_spline_3d_feec), intent( inout ) :: self
1732  !local variable
1733  sll_int32 :: j
1734 
1735  deallocate( self%quad_xw)
1736  deallocate( self%spline_val)
1737  deallocate( self%spline_val_more)
1738  deallocate( self%spline_0)
1739  deallocate( self%spline_1)
1740  deallocate( self%j1d)
1741  deallocate( self%spline1_0 )
1742  deallocate( self%spline_2d )
1743  deallocate( self%spline1_2d )
1744  deallocate( self%spline1_3d )
1745  deallocate( self%spline2_3d )
1746 
1747  call sll_s_spline_pp_free_3d( self%spline_pp_0 )
1748  call sll_s_spline_pp_free_3d( self%spline_pp_1 )
1749 
1750  do j = 1, 3
1751  call sll_s_spline_pp_free_1d( self%spline_pp1d_0(j) )
1752  call sll_s_spline_pp_free_1d( self%spline_pp1d_1(j) )
1753  end do
1754 
1755  end subroutine free_spline_3d_feec
1756 
1757 
1759  subroutine add_current_evaluate_int ( self, position_old, position_new, vbar, bfield_dofs, j_dofs, bfield_val)
1760  class( sll_t_particle_mesh_coupling_spline_3d_feec ), intent(inout) :: self
1761  sll_real64, intent( in ) :: position_old(self%dim)
1762  sll_real64, intent( in ) :: position_new(self%dim)
1763  sll_real64, intent( in ) :: vbar(3)
1764  sll_real64, intent( in ) :: bfield_dofs(:)
1765  sll_real64, intent( inout ) :: j_dofs(:)
1766  sll_real64, intent( out ) :: bfield_val(3)
1767 
1768  sll_real64 :: xold(3), xnew(3), xnewtilde(3), xbox(3)
1769  sll_int32 :: boxold(3), boxnew(3), sigma_counter(3), boxdiff(3), increment(3), box(3)
1770  sll_real64 :: sigma_r, sigma_l, sigma, sigma_next(3), field_value(3), weight
1771  sll_int32 :: j, q, bl, maxind, index_is
1772  type(vector) :: sigmas(3)
1773 
1774  call convert_x_to_xbox( self, position_old, xold, boxold )
1775  call convert_x_to_xbox( self, position_new, xnew, boxnew )
1776 
1777  ! Now we need to compute the normalized 1d line along which to integrate:
1778  boxdiff = boxnew-boxold
1779  xnewtilde = xnew + real(boxdiff,f64)
1780 
1781  sigma_l = 0.0_f64
1782  box = boxold ! We start in the old box
1783 
1784 
1785  sigma_counter = 0
1786 
1787  bfield_val = 0.0_f64
1788 
1789  do j=1,3
1790  if (boxdiff(j) > 0 ) then
1791  allocate ( sigmas(j)%vals(boxdiff(j)+1) )
1792  do bl=1,boxdiff(j)
1793  sigmas(j)%vals(bl) = (real(bl,f64) - xold(j))/(xnewtilde(j)-xold(j))
1794  end do
1795  sigmas(j)%vals(boxdiff(j)+1) = 1.0_f64
1796  sigma_next(j) = sigmas(j)%vals(1)
1797  increment(j) = 1
1798  elseif (boxdiff(j) < 0 ) then
1799  allocate ( sigmas(j)%vals(-boxdiff(j)+1) )
1800  do bl=boxdiff(j)+1,0
1801  sigmas(j)%vals(-bl+1) = (real(bl,f64) - xold(j))/(xnewtilde(j)-xold(j))
1802  end do
1803  sigmas(j)%vals(-boxdiff(j)+1) = 1.0_f64
1804  sigma_next(j) = sigmas(j)%vals(1)
1805  increment(j) = -1
1806  else
1807  sigma_next(j) = 1.0_f64
1808  increment(j) = 0
1809  end if
1810  end do
1811 
1812  sigma_r = 0.0_f64
1813  do while ( sigma_r < 1.0_f64 )
1814  ! Identify index of next intersection
1815  index_is = minloc(sigma_next, dim=1)
1816  sigma_r = sigma_next(index_is)
1817 
1818  do q = 1, self%n_quad_points_line
1819  sigma = sigma_l + (sigma_r-sigma_l) * self%quad_xw_line(1,q)
1820  xbox = xold* (1.0_f64 - sigma) + xnewtilde * sigma - real(sigma_counter*increment, f64)
1821  if (maxval(xbox)> 1.0_f64 ) then
1822  print*, xbox, sigma, sigma_counter, increment
1823  sll_error( 'add_current_evaluate', 'box value too large')
1824  elseif (minval(xbox)< 0.0_f64 ) then
1825  print*, xbox, sigma, sigma_counter, increment
1826  print*, xold, xnewtilde, sigma_r
1827  sll_error( 'add_current_evaluate', 'box value too low')
1828  end if
1829 
1830  weight = self%quad_xw_line(2,q)*(sigma_r-sigma_l)
1831 
1832  call point_add_eval_subcyc (self, box, xbox, bfield_dofs, vbar*weight, j_dofs, field_value )
1833  bfield_val = bfield_val + field_value * weight * sigma !( 1.0_f64 - sigma )
1834  end do
1835  if (sigma_r < 1.0_f64 ) then
1836  ! Update the
1837  sigma_counter(index_is) = sigma_counter(index_is)+1
1838  sigma_next(index_is) = sigmas(index_is)%vals(sigma_counter(index_is)+1)
1839  box(index_is) = box(index_is) + increment(index_is)
1840  sigma_l = sigma_r
1841  end if
1842  end do
1843 
1844  end subroutine add_current_evaluate_int
1845 
1846 
1848  subroutine point_add_eval_subcyc ( self, box_in, xbox, field_dofs, weight, j_dofs, field_value )
1849  class( sll_t_particle_mesh_coupling_spline_3d_feec ), intent(inout) :: self
1850  sll_int32, intent(in) :: box_in(3)
1851  sll_real64, intent(in) :: xbox(3)
1852  sll_real64, intent(in) :: field_dofs(:)
1853  sll_real64, intent(in) :: weight(3)
1854  sll_real64, intent(inout) :: j_dofs(:)
1855  sll_real64, intent(out) :: field_value(3)
1856 
1857 
1858 
1859  sll_int32 :: i,j,k, index1d, n_total
1860  sll_int32 :: box(3), index3d(3)
1861  sll_real64 :: spval
1862 
1863  n_total = self%n_total
1864  field_value = 0.0_f64
1865 
1866  do j=1,3
1867  call sll_s_uniform_bsplines_eval_basis( self%spline_degree(j), xbox(j), &
1868  self%spline_0(1:self%spline_degree(j)+1,j) )
1869  call sll_s_uniform_bsplines_eval_basis( self%spline_degree(j)-1, xbox(j), &
1870  self%spline_1(1:self%spline_degree(j),j) )
1871  end do
1872 
1873  box = box_in-self%spline_degree
1874 
1875  !box(1) = box(1)+1
1876  call box_index( self, box(1), 1 )
1877  call box_index( self, box(2), 2 )
1878  call box_index( self, box(3), 3 )
1879 
1880  ! First component j_dofs
1881  do k=1,self%spline_degree(3)+1
1882  index3d(3) = (self%index1d(k,3)-1)*self%n_cells(1)*self%n_cells(2)
1883  do j=1,self%spline_degree(2)+1
1884  index3d(2) = index3d(3) + (self%index1d(j,2)-1)*self%n_cells(1)
1885  do i=2,self%spline_degree(1)+1
1886  index1d = index3d(2) + self%index1d(i,1)
1887 
1888  spval = self%spline_1(i-1,1) * &
1889  self%spline_0(j,2) * self%spline_0(k,3)
1890  j_dofs(index1d) = j_dofs(index1d) + &
1891  weight(1) * spval
1892  end do
1893  end do
1894  end do
1895  ! First component field
1896  do k=2,self%spline_degree(3)+1
1897  index3d(3) = (self%index1d(k,3)-1)*self%n_cells(1)*self%n_cells(2)
1898  do j=2,self%spline_degree(2)+1
1899  index3d(2) = index3d(3) + (self%index1d(j,2)-1)*self%n_cells(1)
1900  do i=1,self%spline_degree(1)+1
1901  index1d = index3d(2) + self%index1d(i,1)
1902  spval = self%spline_0(i,1) * &
1903  self%spline_1(j-1,2) * self%spline_1(k-1,3)
1904  field_value(1) = field_value(1) + field_dofs(index1d) * spval
1905  end do
1906  end do
1907  end do
1908  ! Second component j_dofs
1909  do k=1,self%spline_degree(3)+1
1910  index3d(3) = (self%index1d(k,3)-1)*self%n_cells(1)*self%n_cells(2)
1911  do j=2,self%spline_degree(2)+1
1912  index3d(2) = index3d(3) + (self%index1d(j,2)-1)*self%n_cells(1)
1913  do i=1,self%spline_degree(1)+1
1914  index1d = index3d(2) + self%index1d(i,1) + n_total
1915 
1916  spval = self%spline_0(i,1) * &
1917  self%spline_1(j-1,2) * self%spline_0(k,3)
1918  j_dofs(index1d) = j_dofs(index1d) + &
1919  weight(2) * spval
1920  field_value(2) = field_value(2) + field_dofs(index1d ) * spval
1921  end do
1922  enddo
1923  end do
1924  ! Second component field
1925  do k=2,self%spline_degree(3)+1
1926  index3d(3) = (self%index1d(k,3)-1)*self%n_cells(1)*self%n_cells(2)
1927  do j=1,self%spline_degree(2)+1
1928  index3d(2) = index3d(3) + (self%index1d(j,2)-1)*self%n_cells(1)
1929  do i=2,self%spline_degree(1)+1
1930  spval = self%spline_1(i-1,1) * &
1931  self%spline_0(j,2) * self%spline_1(k-1,3)
1932  field_value(2) = field_value(2) + field_dofs(index1d ) * spval
1933  end do
1934  end do
1935  end do
1936 
1937  n_total = n_total*2
1938 
1939  ! Third component j_dofs
1940  do k=2,self%spline_degree(3) +1
1941  index3d(3) = (self%index1d(k,3)-1)*self%n_cells(1)*self%n_cells(2)
1942  do j=1,self%spline_degree(2)+1
1943  index3d(2) = index3d(3) + (self%index1d(j,2)-1)*self%n_cells(1)
1944  do i=1,self%spline_degree(1)+1
1945  index1d = index3d(2) + self%index1d(i,1) + n_total
1946  spval = self%spline_0(i,1) * &
1947  self%spline_0(j,2) * self%spline_1(k-1,3)
1948  j_dofs(index1d) = j_dofs(index1d) + &
1949  weight(3) * spval
1950  end do
1951  end do
1952  end do
1953  ! Third component field
1954  do k=1,self%spline_degree(3)+1
1955  index3d(3) = (self%index1d(k,3)-1)*self%n_cells(1)*self%n_cells(2)
1956  do j=2,self%spline_degree(2)+1
1957  index3d(2) = index3d(3) + (self%index1d(j,2)-1)*self%n_cells(1)
1958  do i=2,self%spline_degree(1)+1
1959  index1d = index3d(2) + self%index1d(i,1) + n_total
1960  spval = self%spline_1(i-1,1) * &
1961  self%spline_1(j-1,2) * self%spline_0(k,3)
1962  field_value(3) = field_value(3) + field_dofs(index1d ) * spval
1963  end do
1964  end do
1965  end do
1966 
1967  end subroutine point_add_eval_subcyc
1968 
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_charge_single_spline_pp_3d_feec(self, position, marker_charge, degree, rho_dofs)
Add charge of one particle.
subroutine add_current_3d(self, position_old, position_new, xdot, j_dofs)
Add current via line integral (when x changes along all three directions)
subroutine add_current_update_v_primitive_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_p3 part in Hamiltonian splitting),...
subroutine add_current_update_v_primitive_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 integrate_spline_3d(self, box_in, xbox, weight, j_dofs)
Helper function for add_current_3d, takes care of the per box computations.
subroutine init_spline_3d_feec(self, n_cells, domain, spline_degree, no_particles)
Constructor.
subroutine add_current_spline_3d_feec(self, position_old, position_new, marker_charge, qoverm, bfield_dofs, vi, j_dofs)
Add current for one particle.
subroutine evaluate_multiple_spline_3d_feec(self, position, components, field_dofs, field_value)
Evaluate several fields at position position.
subroutine convert_x_to_xbox(self, position, xi, box)
Identify the box in which the particle is located and its normalized position within the box.
subroutine add_charge_single_spline_3d_feec(self, position, marker_charge, degree, rho_dofs)
Add charge of one particle.
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_p2 part in Hamiltonian splitting),...
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_p3 part in Hamiltonian splitting),...
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 add_current_update_v_primitive_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_p2 part in Hamiltonian splitting),...
subroutine add_current_evaluate_int(self, position_old, position_new, vbar, bfield_dofs, j_dofs, bfield_val)
Evaluates the integral int_{poisition_old}^{position_new} field(x) d x and the integrated current.
subroutine add_particle_mass_od_spline_3d_feec(self, position, marker_charge, degree1, degree2, particle_mass)
Add charge of one particle.
subroutine evaluate_field_single_spline_3d_feec(self, position, degree, field_dofs, field_value)
Evaluate field at at position position.
subroutine point_add_eval_subcyc(self, box_in, xbox, field_dofs, weight, j_dofs, field_value)
Helper function for add_current_evaluate_int, takes care of per cell computations.
subroutine add_particle_mass_spline_3d_feec(self, position, marker_charge, degree, particle_mass)
Add charge of one particle.
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 convert_x_to_xbox_1d(self, component, position, xi, box)
Identify the box in which the particle is located and its normalized position within the box (only al...
subroutine point_add_eval(self, box_in, xbox, field_dofs, weight, j_dofs, field_value)
Helper function for add_current_evaluate that takes care of the per-cell computations.
subroutine box_index(self, box, comp)
Sets the index of the splines that are involved in computations that concern splines from index box.
subroutine add_current_1d(self, component, r_old, index_old, r_new, index_new, marker_charge, bfield_dofs, start1, start2, stride, vi, j_dofs)
Add current for one particle and update v (according to H_p1 part in Hamiltonian splitting)
subroutine evaluate_field_single_spline_pp_3d_feec(self, position, degree, field_dofs_pp, field_value)
Evaluate field at at position position.
pure integer(kind=i32) function convert_index_3d_to_1d(index3d, n_cells)
Convert 3d index to 1d index (first dimension without stride)
Splines in pp form.
subroutine, public sll_s_spline_pp_init_3d(self, degree, n_cells, boundary)
Initialize sll_t_spline_pp_3d object.
subroutine, public sll_s_spline_pp_horner_m_3d(self, val, degree, x)
Perform three times a 1d hornerschema on the poly_coeffs.
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_init_1d(self, degree, n_cells, boundary)
Initialize sll_t_spline_pp_1d object (Set poly_coeffs depending on degree)
subroutine, public sll_s_spline_pp_free_1d(self)
Destructor 1d.
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.
Evaluates the integral int_{poisition_old}^{position_new} field(x) d x and the integrated current.
    Report Typos and Errors