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_2d.F90
Go to the documentation of this file.
1 
6 
7 !+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
8 #include "sll_assert.h"
9 #include "sll_errors.h"
10 #include "sll_memory.h"
11 #include "sll_working_precision.h"
12 
13  use sll_m_low_level_bsplines, only: &
14  sll_s_uniform_bsplines_eval_basis
15 
20 
21  use sll_m_particle_group_base, only: &
23 
25 
26  implicit none
27 
28  public :: &
32 
33  private
34 !+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
35 
38  type(sll_t_spline_pp_2d) spline_pp
39  ! Information about the 2d mesh
40  sll_real64 :: delta_x2(2)
41  sll_real64 :: domain2(2,2)
42 
43  ! Information about the particles
44  sll_int32 :: no_particles
45  sll_int32 :: n_span
46 ! sll_int32 :: smoothing_type !< Defines whether we use Galerkin or collocation in order to decide on scaling when accumulating
47  sll_real64 :: scaling
48 
49  sll_int32, allocatable :: n_grid(:)
50  ! Internal work space
51  sll_real64, allocatable :: spline_val(:,:)
52 
53  contains
55  procedure :: add_charge => add_charge_single_spline_2d
56  procedure :: add_charge_pp => add_charge_single_spline_pp_2d
57  !procedure :: accumulate_j_from_klimontovich => accumulate_j_from_klimontovich_spline_2d !> Accumulate a component of the current density
58  procedure :: add_particle_mass => add_particle_mass_spline_2d
59  procedure :: add_particle_mass_full => add_particle_mass_spline_2d
60  procedure :: evaluate_pp => evaluate_field_single_spline_pp_2d
61  procedure :: evaluate => evaluate_field_single_spline_2d
62  procedure :: evaluate_multiple => evaluate_multiple_spline_2d
63  procedure :: add_current_update_v => add_current_update_v_spline_2d
64  procedure :: add_current_update_v_pp => add_current_update_v_spline_pp_2d
67  procedure :: init => init_spline_2d
68  procedure :: free => free_spline_2d
69 
70 
72 
73 contains
74  !---------------------------------------------------------------------------!
76  subroutine compute_shape_factor_spline_2d(self, position, indices)
77  class( sll_t_particle_mesh_coupling_spline_2d), intent(inout) :: self
78  sll_real64, intent( in ) :: position(2)
79  sll_int32, intent( out ) :: indices(2)
80 
81  ! local variables
82  sll_real64 :: xi(2)
83 
84 
85  xi(1:2) = (position(1:2) - self%domain2(:,1)) /&
86  self%delta_x2
87  indices = ceiling(xi(1:2))
88  xi(1:2) = xi(1:2) - real(indices -1,f64)
89  indices = indices - self%spline_degree
90  call sll_s_uniform_bsplines_eval_basis(self%spline_degree, xi(1), self%spline_val(1:self%n_span,1))
91  call sll_s_uniform_bsplines_eval_basis(self%spline_degree, xi(2), self%spline_val(1:self%n_span,2))
92  !self%spline_val(1:self%n_span,1) = sll_f_uniform_b_splines_at_x(self%spline_degree, xi(1))
93  !self%spline_val(1:self%n_span,2) = sll_f_uniform_b_splines_at_x(self%spline_degree, xi(2))
94 
95  end subroutine compute_shape_factor_spline_2d
96 
97  !---------------------------------------------------------------------------!
99  subroutine add_charge_single_spline_pp_2d(self, position, marker_charge, rho_dofs)
100  class( sll_t_particle_mesh_coupling_spline_2d), intent(inout) :: self
101  sll_real64, intent( in ) :: position(self%dim)
102  sll_real64, intent( in ) :: marker_charge
103  sll_real64, intent(inout) :: rho_dofs(self%n_dofs )
104 
105  !local variables
106  sll_real64 :: xi(2)
107  sll_int32 :: indices(2)
108  sll_int32 :: i1, i2, index2d
109  sll_int32 :: index1d(2)
110 
111  xi(1:2) = (position(1:2) - self%domain2(:,1)) /self%delta_x2
112  indices = floor(xi(1:2))+1
113  xi(1:2) = xi(1:2) - real(indices -1,f64)
114  indices = indices - self%spline_degree
115 
116  call sll_s_spline_pp_horner_m_2d(self%spline_pp, self%spline_val,[self%spline_degree,self%spline_degree], xi)
117 
118  do i1 = 1, self%n_span
119  index1d(1) = indices(1)+i1-2
120  do i2 = 1, self%n_span
121  index1d(2) = indices(2)+i2-2
122  index2d = index_1dto2d_column_major(self,index1d)
123  rho_dofs(index2d) = rho_dofs(index2d) +&
124  ( marker_charge* self%scaling * &
125  self%spline_val(i1,1) * self%spline_val(i2,2))
126  end do
127  end do
128 
129  end subroutine add_charge_single_spline_pp_2d
130 
131  !---------------------------------------------------------------------------!
133  subroutine add_charge_single_spline_2d(self, position, marker_charge, rho_dofs)
134  class( sll_t_particle_mesh_coupling_spline_2d), intent(inout) :: self
135  sll_real64, intent( in ) :: position(self%dim)
136  sll_real64, intent( in ) :: marker_charge
137  sll_real64, intent(inout) :: rho_dofs(self%n_dofs )
138 
139  !local variables
140  sll_int32 :: i1, i2, index2d
141  sll_int32 :: index1d(2)
142  sll_int32 :: indices(2)
143 
144 
145  call compute_shape_factor_spline_2d(self, position, indices)
146  do i1 = 1, self%n_span
147  index1d(1) = indices(1)+i1-2
148  do i2 = 1, self%n_span
149  index1d(2) = indices(2)+i2-2
150  index2d = index_1dto2d_column_major(self,index1d)
151  rho_dofs(index2d) = rho_dofs(index2d) +&
152  ( marker_charge* self%scaling * &
153  self%spline_val(i1,1) * self%spline_val(i2,2))
154  end do
155  end do
156 
157  end subroutine add_charge_single_spline_2d
158 
159 
161  subroutine add_current_spline_2d( self, position_old, position_new, marker_charge, j_dofs )
162  class( sll_t_particle_mesh_coupling_spline_2d ), intent(inout) :: self
163  sll_real64, intent( in ) :: position_old(self%dim)
164  sll_real64, intent( in ) :: position_new(self%dim)
165  sll_real64, intent( in ) :: marker_charge
166  sll_real64, intent( inout ) :: j_dofs(self%n_dofs)
167 
168 
169 
170  sll_error('add_particles_mass_spline_2d','add_current not implemented')
171 
172  end subroutine add_current_spline_2d
173 
174 
176  subroutine add_current_evaluate_spline_2d(self, position_old, position_new, marker_charge, vbar, field_dofs, j_dofs, field)
177  class( sll_t_particle_mesh_coupling_spline_2d ), intent(inout) :: self
178  sll_real64, intent( in ) :: position_old(self%dim)
179  sll_real64, intent( in ) :: position_new(self%dim)
180  sll_real64, intent( in ) :: marker_charge
181  sll_real64, intent( in ) :: vbar
182  sll_real64, intent( in ) :: field_dofs(self%n_dofs)
183  sll_real64, intent( inout ) :: j_dofs(self%n_dofs)
184  sll_real64, intent( out ) :: field
185 
186  sll_error('add_particles_mass_spline_2d','add_current not implemented')
187 
188  end subroutine add_current_evaluate_spline_2d
189 
190  !---------------------------------------------------------------------------!
192  subroutine add_current_update_v_spline_2d (self, position_old, position_new, marker_charge, qoverm, bfield_dofs, vi, j_dofs)
193  class(sll_t_particle_mesh_coupling_spline_2d), intent(inout) :: self
194  sll_real64, intent(in) :: position_old(self%dim)
195  sll_real64, intent(in) :: position_new(self%dim)
196  sll_real64, intent(in) :: marker_charge
197  sll_real64, intent(in) :: qoverm
198  sll_real64, intent(in) :: bfield_dofs(:)
199  sll_real64, intent(inout) :: vi(:)
200  sll_real64, intent(inout) :: j_dofs(:)
201 
202  print*, 'add_current_update_v_spline_2d not implemented.'
203 
204  end subroutine add_current_update_v_spline_2d
205 
206 
207  subroutine add_particle_mass_spline_2d(self, position, marker_charge, particle_mass)
208  class(sll_t_particle_mesh_coupling_spline_2d), intent( inout ) :: self
209  sll_real64, intent( in ) :: position(self%dim)
210  sll_real64, intent( in ) :: marker_charge
211  sll_real64, intent( inout ) :: particle_mass(:,:)
212 
213  sll_error('add_particles_mass_spline_2d','add_particle_mass not implemented')
214 
215  end subroutine add_particle_mass_spline_2d
216 
217 
218  !---------------------------------------------------------------------------!
220  subroutine add_current_update_v_spline_pp_2d (self, position_old, position_new, marker_charge, qoverm, bfield_dofs, vi, j_dofs)
221  class(sll_t_particle_mesh_coupling_spline_2d), intent(inout) :: self
222  sll_real64, intent(in) :: position_old(self%dim)
223  sll_real64, intent(in) :: position_new(self%dim)
224  sll_real64, intent(in) :: marker_charge
225  sll_real64, intent(in) :: qoverm
226  sll_real64, intent(in) :: bfield_dofs(:)
227  sll_real64, intent(inout) :: vi(:)
228  sll_real64, intent(inout) :: j_dofs(:)
229 
230  print*, 'add_current_update_v_spline_pp_2d not implemented.'
231 
232  end subroutine add_current_update_v_spline_pp_2d
233 
234 !!$ !---------------------------------------------------------------------------!
235 !!$ subroutine accumulate_j_from_klimontovich_spline_2d(self, particle_group,&
236 !!$ j_dofs, component, i_weight)
237 !!$ class( sll_t_particle_mesh_coupling_spline_2d), intent(in) :: self !< kernel smoother object
238 !!$ class( sll_c_particle_group_base), intent(in) :: particle_group !< particle group
239 !!$ sll_real64, intent(inout) :: j_dofs(:) !< spline coefficients ofcomponent \a component accumulated current density
240 !!$ sll_int32, intent(in) :: component !< component of \a j_dofs to be accumulated.
241 !!$ sll_int32, optional , intent( in ) :: i_weight !< No. of the weight that should be used in the accumulation.
242 !!$
243 !!$ !local variables
244 !!$ sll_int32 :: i_part, i1, i2, index2d
245 !!$ sll_int32 :: index1d(2)
246 !!$ sll_real64 :: vpart(3)
247 !!$ sll_real64 :: wi(1)
248 !!$ sll_int32 :: i_wi
249 !!$
250 !!$ i_wi = 1
251 !!$ if(present(i_weight)) i_wi = i_weight
252 !!$
253 !!$ do i_part = 1, particle_group%n_particles
254 !!$ wi = particle_group%get_charge(i_part, i_wi)
255 !!$ do i1 = 1, self%n_span
256 !!$ index1d(1) = self%index_grid(1,i_part)+i1-2
257 !!$ do i2 = 1, self%n_span
258 !!$ index1d(2) = self%index_grid(2,i_part)+i2-2
259 !!$ index2d = index_1dto2d_column_major(self,index1d)
260 !!$ vpart = particle_group%get_v(i_part)
261 !!$ j_dofs(index2d) = j_dofs(index2d) +&
262 !!$ (wi(1) * &
263 !!$ vpart(component) * &
264 !!$ self%values_grid(i1,1,i_part) *&
265 !!$ self%values_grid(i2,2,i_part))
266 !!$ end do
267 !!$ end do
268 !!$ end do
269 !!$
270 !!$ if (self%smoothing_type == sll_p_collocation) then
271 !!$ j_dofs = j_dofs /product(self%delta_x2)
272 !!$ end if
273 !!$
274 !!$ end subroutine accumulate_j_from_klimontovich_spline_2d
275 
276 
277  !---------------------------------------------------------------------------!
279  subroutine evaluate_field_single_spline_pp_2d(self, position, field_dofs_pp, field_value)
280  class( sll_t_particle_mesh_coupling_spline_2d), intent(inout) :: self
281  sll_real64, intent( in ) :: position(self%dim)
282  sll_real64, intent(in) :: field_dofs_pp(:,:)
283  sll_real64, intent(out) :: field_value
284 
285  !local variables
286  sll_real64 :: xi(2)
287  sll_int32 :: indices(2)
288 
289  xi(1:2) = (position(1:2) - self%domain2(:,1)) /self%delta_x2
290  indices = floor(xi(1:2))+1
291  xi(1:2) = xi(1:2) - real(indices -1,f64)
292 
293  field_value = sll_f_spline_pp_horner_2d([self%spline_degree,self%spline_degree], field_dofs_pp, xi, indices,self%n_grid)
294 
296 
297 
298  !---------------------------------------------------------------------------!
300  subroutine evaluate_field_single_spline_2d(self, position, field_dofs, field_value)
301  class( sll_t_particle_mesh_coupling_spline_2d), intent(inout) :: self
302  sll_real64, intent( in ) :: position(self%dim)
303  sll_real64, intent(in) :: field_dofs(self%n_dofs)
304  sll_real64, intent(out) :: field_value
305 
306  !local variables
307  sll_int32 :: i1, i2, index2d
308  sll_int32 :: index1d(2)
309  sll_int32 :: indices(2)
310 
311 
312  call compute_shape_factor_spline_2d(self, position, indices)
313 
314 
315  field_value = 0.0_f64
316  do i1 = 1, self%n_span
317  index1d(1) = indices(1)+i1-2
318  do i2 = 1, self%n_span
319  index1d(2) = indices(2)+i2-2
320  index2d = index_1dto2d_column_major(self,index1d)
321  field_value = field_value + &
322  field_dofs(index2d) * &
323  self%spline_val(i1,1) *&
324  self%spline_val(i2,2)
325  end do
326  end do
327 
328  end subroutine evaluate_field_single_spline_2d
329 
330  !---------------------------------------------------------------------------!
332  subroutine evaluate_multiple_spline_2d(self, position, components, field_dofs, field_value)
333  class( sll_t_particle_mesh_coupling_spline_2d), intent(inout) :: self
334  sll_real64, intent( in ) :: position(self%dim)
335  sll_int32, intent(in) :: components(:)
336  sll_real64, intent(in) :: field_dofs(:,:)
337  sll_real64, intent(out) :: field_value(:)
338 
339  !local variables
340  sll_int32 :: i1, i2, index2d
341  sll_int32 :: index1d(2)
342  sll_int32 :: indices(2)
343 
344 
345  call compute_shape_factor_spline_2d(self, position, indices)
346 
347 
348  field_value = 0.0_f64
349  do i1 = 1, self%n_span
350  index1d(1) = indices(1)+i1-2
351  do i2 = 1, self%n_span
352  index1d(2) = indices(2)+i2-2
353  index2d = index_1dto2d_column_major(self,index1d)
354  field_value = field_value + &
355  field_dofs(index2d,components) * &
356  self%spline_val(i1,1) *&
357  self%spline_val(i2,2)
358  end do
359  end do
360 
361  end subroutine evaluate_multiple_spline_2d
362 
363  !-------------------------------------------------------------------------------------------
365  subroutine free_spline_2d(self)
366  class(sll_t_particle_mesh_coupling_spline_2d), intent( inout ) :: self
367  deallocate(self%n_grid)
368  deallocate(self%spline_val)
369 
370  call sll_s_spline_pp_free_2d(self%spline_pp)
371 
372  end subroutine free_spline_2d
373 
374 
375  !-------------------------------------------------------------------------------------------
376 
377  subroutine init_spline_2d(self, domain, n_grid, no_particles, spline_degree, smoothing_type)
378  class( sll_t_particle_mesh_coupling_spline_2d), intent(out) :: self
379  sll_int32, intent(in) :: n_grid(2)
380  sll_real64, intent(in) :: domain(2,2)
381  sll_int32, intent(in) :: no_particles
382  sll_int32, intent(in) :: spline_degree
383  sll_int32, intent(in) :: smoothing_type
384 
385  !local variables
386  sll_int32 :: ierr
387 
388  self%dim = 2
389 
390  ! Store grid information
391  self%domain2 = domain
392  sll_allocate(self%n_grid(2), ierr)
393  self%n_grid = n_grid
394  self%n_dofs = product(n_grid)
395  self%delta_x2 = (domain(:,2)-domain(:,1))/real(n_grid, f64)
396 
397  ! Store basis function information
398  self%no_particles = no_particles
399 
400  ! Initialize information on the spline
401  self%spline_degree = spline_degree
402  self%n_span = spline_degree + 1
403 
404  ! Initialize information on smoothing type
405  if (smoothing_type == sll_p_collocation) then
406  self%scaling = 1.0_f64/product(self%delta_x2)
407  elseif (smoothing_type == sll_p_galerkin) then
408  self%scaling = 1.0_f64
409  else
410  print*, 'Smoothing Type ', smoothing_type, ' not implemented for kernel_smoother_spline_2d.'
411  end if
412 
413  allocate( self%spline_val(self%n_span, 2), stat = ierr)
414  sll_assert( ierr == 0)
415 
416  call sll_s_spline_pp_init_2d(self%spline_pp,[spline_degree,spline_degree],n_grid)
417 
418  end subroutine init_spline_2d
419 
421  subroutine sll_s_new_particle_mesh_coupling_spline_2d_ptr(smoother, domain, n_grid, no_particles, spline_degree, smoothing_type)
422  class( sll_c_particle_mesh_coupling_1d), pointer, intent(out) :: smoother
423  sll_int32, intent(in) :: n_grid(2)
424  sll_real64, intent(in) :: domain(2,2)
425  sll_int32, intent(in) :: no_particles
426  sll_int32, intent(in) :: spline_degree
427  sll_int32, intent(in) :: smoothing_type
428 
429  !local variables
430  sll_int32 :: ierr
431 
432  sll_allocate( sll_t_particle_mesh_coupling_spline_2d :: smoother, ierr)
433  select type (smoother)
435  call smoother%init( domain, n_grid, no_particles, spline_degree, smoothing_type)
436  end select
437 
439 
440 
442  subroutine sll_s_new_particle_mesh_coupling_spline_2d(smoother, domain, n_grid, no_particles, spline_degree, smoothing_type)
443  class( sll_c_particle_mesh_coupling_1d), allocatable, intent(out) :: smoother
444  sll_int32, intent(in) :: n_grid(2)
445  sll_real64, intent(in) :: domain(2,2)
446  sll_int32, intent(in) :: no_particles
447  sll_int32, intent(in) :: spline_degree
448  sll_int32, intent(in) :: smoothing_type
449 
450  !local variables
451  sll_int32 :: ierr
452 
453  sll_allocate( sll_t_particle_mesh_coupling_spline_2d :: smoother, ierr)
454  select type (smoother)
456  call smoother%init( domain, n_grid, no_particles, spline_degree, smoothing_type)
457  end select
458 
460 
461 
462 
463 
464  function index_1dto2d_column_major(self, index1d) result(index2d)
465  class( sll_t_particle_mesh_coupling_spline_2d), intent(in) :: self
466  sll_int32, intent(inout) :: index1d(2)
467  sll_int32 :: index2d
468 
469  index1d(1) = modulo(index1d(1), self%n_grid(1))
470  index1d(2) = modulo(index1d(2), self%n_grid(2))
471  index2d = index1d(1) + index1d(2)*self%n_grid(1) + 1
472 
473  end function index_1dto2d_column_major
474 
Low level arbitrary degree splines.
Base class for kernel smoothers for accumulation and field evaluation in PIC.
integer(kind=i32), parameter, public sll_p_collocation
Kernel smoother for 2d with splines of arbitrary degree placed on a uniform mesh.
subroutine compute_shape_factor_spline_2d(self, position, indices)
Helper function computing shape factor.
subroutine add_particle_mass_spline_2d(self, position, marker_charge, particle_mass)
subroutine evaluate_multiple_spline_2d(self, position, components, field_dofs, field_value)
Evaluate multiple fields at position position.
subroutine evaluate_field_single_spline_pp_2d(self, position, field_dofs_pp, field_value)
Evaluate field at at position position using horner scheme.
subroutine init_spline_2d(self, domain, n_grid, no_particles, spline_degree, smoothing_type)
subroutine add_current_evaluate_spline_2d(self, position_old, position_new, marker_charge, vbar, field_dofs, j_dofs, field)
Add current with integration over x.
subroutine add_current_update_v_spline_pp_2d(self, position_old, position_new, marker_charge, qoverm, bfield_dofs, vi, j_dofs)
Add current and update v for single particle.
subroutine, public sll_s_new_particle_mesh_coupling_spline_2d(smoother, domain, n_grid, no_particles, spline_degree, smoothing_type)
Constructor for abstract type (allocatable)
subroutine evaluate_field_single_spline_2d(self, position, field_dofs, field_value)
Evaluate field with given dofs at position position.
integer(kind=i32) function index_1dto2d_column_major(self, index1d)
subroutine add_current_spline_2d(self, position_old, position_new, marker_charge, j_dofs)
Add current with integration over x.
subroutine, public sll_s_new_particle_mesh_coupling_spline_2d_ptr(smoother, domain, n_grid, no_particles, spline_degree, smoothing_type)
Constructor for abstract type (pointer)
subroutine add_current_update_v_spline_2d(self, position_old, position_new, marker_charge, qoverm, bfield_dofs, vi, j_dofs)
Add current and update v for single particle.
subroutine add_charge_single_spline_2d(self, position, marker_charge, rho_dofs)
Add charge of single particle.
subroutine add_charge_single_spline_pp_2d(self, position, marker_charge, rho_dofs)
Add charge of single particle.
Splines in pp form.
real(kind=f64) function, public sll_f_spline_pp_horner_2d(degree, pp_coeffs, x, indices, n_cells)
Perform a 2d hornerschema on the pp_coeffs at the indices.
subroutine, public sll_s_spline_pp_horner_m_2d(self, val, degree, x)
Perform two times a 1d hornerschema on the poly_coeffs.
subroutine, public sll_s_spline_pp_init_2d(self, degree, n_cells, boundary)
Initialize sll_t_spline_pp_2d object.
subroutine, public sll_s_spline_pp_free_2d(self)
Destructor 2d.
    Report Typos and Errors