Report Typos and Errors    
Semi-Lagrangian Library
Modular library for kinetic and gyrokinetic simulations of plasmas in fusion energy devices.
sll_pif_general.F90
Go to the documentation of this file.
1 !**************************************************************
2 ! Author: Jakob Ameres, jakob.ameres@tum.de
3 !**************************************************************
4 
6 #include "sll_working_precision.h"
7 #include "sll_memory.h"
8 #include "sll_assert.h"
9 
11  use sll_m_timer
12  use sll_m_sobol
13  use sll_m_prob
15  use sll_m_pic_visu
19 
20  implicit none
21 
22  sll_int32, parameter :: sobol_offset = 10 !Default sobol offset, skip zeros
23 
24 !------type--------
25  sll_real64, dimension(:, :), allocatable :: particle
26  sll_real64, dimension(:), allocatable :: weight_const, prior_weight !initial weight if needed
27  sll_real64, dimension(:), allocatable :: rk_d, rk_c
28  type(pif_fieldsolver) :: solver
29  sll_real64 :: efield
30 !stencils
31  sll_int32, dimension(:), allocatable :: maskx, maskv, maskxw, maskxv
32  sll_int32 :: maskw
33  sll_int32 :: tstep
34 
35 !----Problem parameter----
36  sll_int32 :: dimx
37  sll_real64 :: boxlen
38  sll_real64 :: qm
39 
40 !----Solver parameters----
41  sll_real64 :: dt
42  sll_int32 :: tsteps
43  sll_int32 :: npart, npart_loc
44  sll_int32 :: collisions = sll_collisions_none
45  sll_int32 :: controlvariate = sll_controlvariate_none !SLL_CONTROLVARIATE_MAXWELLIAN
46 
47 !results
48  sll_real64, dimension(:), allocatable :: kineticenergy, fieldenergy, energy, energy_error, weight_sum, weight_var, moment_error
49  sll_real64, dimension(:, :), allocatable ::moment, moment_var
50  sll_comp64, dimension(:), allocatable :: rhs, solution
51 !--------------
52 
53 !------MPI---------
54  sll_int32 :: coll_rank, coll_size
55 
56 !------MPI----------
57 
58  sll_int32 ::ierr, idx, jdx
59 
60 !-----------------
61  npart = 1e6
62  dt = 0.1
63  tsteps = 100
64  qm = -1 !electrons
65 
66  dimx = 2
67  boxlen = 4*sll_p_pi
68 
70  call sll_collective_barrier(sll_v_world_collective)
71  !really global variables
74  call sll_collective_barrier(sll_v_world_collective)
75 
76  if (coll_rank == 0) then
77  print *, "Size of MPI-Collective: ", coll_size
78  end if
79 
80 !Determine MPI particle distribution scheme
81 
82  npart_loc = npart/coll_size
83 
84 !print*, "#Core ", coll_rank, " handles particles", coll_rank*nparticles +1, "-", (coll_rank+1)*nparticles
85 !call sll_collective_barrier(sll_v_world_collective)
86  if (coll_rank == 0) print *, "#Total Number of particles: ", npart_loc*coll_size
87 
88 !--------------------------------------
89  call init_particle_masks()
90 
91  solver%dimx = dimx
92 !Load some particles
93 
94  call solver%set_box_len(boxlen)
95  call solver%init(10)
96 
98  call init_diagnostics()
99 
100  call init_particle()
102 
103 !Set weights for strong landau damping
104  particle(maskw, :) = (1 - 0.4*sum(cos(0.5*particle(maskx, :) + sll_p_pi/3.0), 1))
105  particle(maskw, :) = particle(maskw, :)/prior_weight
106 
107  sll_allocate(weight_const(npart_loc), ierr)
108  weight_const = particle(maskw, :)
109 
110 !Match some moments
111  do idx = 1, size(maskv)
112  call match_moment_1d_weight_linear_real64(particle(maskv(idx), :), particle(maskw, :), 0.0_f64, 1.0_f64, npart)
113  end do
114 
115 !Initial field solve
116  sll_allocate(rhs(solver%problemsize()), ierr)
117  sll_allocate(solution(solver%problemsize()), ierr)
118 
119  if (coll_rank == 0) print *, "# TIME IMPULSE ERR.(abs.) ENERGY ERROR(rel.)"
120  do tstep = 1, tsteps
121  call symplectic_rungekutta()
122  if (coll_rank == 0) print *, "#", dt*(tstep - 1), abs(moment(1, tstep))/npart, energy_error(tstep)
123 
124  !if ( (gnuplot_inline_output.eqv. .true.) .AND. coll_rank==0 .AND. mod(timestep-1,timesteps/100)==0 ) then
125 ! call energies_electrostatic_gnuplot_inline(kineticenergy(1:tstep), fieldenergy(1:tstep),&
126 ! moment_error(1:tstep),dt)
127  ! else
128 
129  ! endif
130  end do
131 
132  call write_result()
133 
134  call sll_s_halt_collective()
135 !--------------------------------------------------------------
136 contains
137 
138 !Fills particle vector with random numbers, of users choice
139  subroutine init_particle
140  sll_int32 :: idx
141  sll_int64 :: seed
142 
143  sll_allocate(particle(2*dimx + 1, npart_loc), ierr)
144 
145 !Generate random numbers
146  seed = sobol_offset + coll_rank*npart_loc
147  do idx = 1, npart_loc
148 !call i8_sobol_generate ( int(dimx,8) , npart, SOBOL_OFFSET , particle(1:2*dimx,:))
149  call i8_sobol(int(2*dimx, 8), seed, particle(1:2*dimx, idx))
150  end do
151  end subroutine
152 
153 !allocates space
154  subroutine init_diagnostics
155  sll_clear_allocate(kineticenergy(tsteps), ierr)
156  sll_clear_allocate(fieldenergy(tsteps), ierr)
157  sll_clear_allocate(energy(tsteps), ierr)
158  sll_clear_allocate(energy_error(tsteps), ierr)
159  sll_clear_allocate(moment(dimx, tsteps), ierr)
160  sll_clear_allocate(moment_error(tsteps), ierr)
161  sll_clear_allocate(moment_var(dimx, tsteps), ierr)
162  sll_clear_allocate(weight_sum(tsteps), ierr)
163  sll_clear_allocate(weight_var(tsteps), ierr)
164  end subroutine
165 
166 !reads tstep
168  sll_int32 :: idx
169 
170  kineticenergy(tstep) = sum(sum(particle(maskv, :)**2, 1)*particle(maskw, :))/npart
171  call sll_collective_globalsum(sll_v_world_collective, kineticenergy)
172 
173  fieldenergy(tstep) = abs(dot_product(solution, rhs))
174 ! fieldenergy(tstep)=abs(Efield)
175  energy(tstep) = kineticenergy(tstep) + fieldenergy(tstep)
176  energy_error(tstep) = abs(energy(2) - energy(tstep))/abs(energy(1))
177 
178  do idx = 1, size(particle, 2)
179  moment(:, tstep) = moment(:, tstep) + (particle(maskv, idx)*particle(maskw, idx))
180  end do
181  call sll_collective_globalsum(sll_v_world_collective, moment(:, tstep))
182 
183  moment_error(tstep) = sqrt(sum((moment(:, 1) - moment(:, tstep))**2))
184 
185  weight_sum(tstep) = sum(particle(maskw, :))/npart
186  call sll_collective_globalsum(sll_v_world_collective, weight_sum, 0)
187 
188  end subroutine
189 
191  sll_int32 :: idx, jdx
192 
193 !scale to boxlength
194  particle(maskx, :) = particle(maskx, :)*boxlen
195 !load sll_m_gaussian profile
196  do idx = 1, size(particle, 2)
197  do jdx = 1, size(maskv)
198  call normal_cdf_inv(particle(maskv(jdx), idx), 0.0_f64, 1.0_f64, particle(maskv(jdx), idx))
199  end do
200  end do
201 
202 !set temperature and impulse
203  do idx = 1, size(maskv)
204 ! print *, sum(particle(maskv(idx),:))/npart
205  call match_moment_1d_linear_real64(particle(maskv(idx), :), 0.0_f64, 1.0_f64)
206 ! print *, sum(particle(maskv(idx),:))/npart
207  end do
208 
209  sll_allocate(prior_weight(1:npart_loc), ierr)
210  prior_weight = 1.0/boxlen**dimx
211 
212  end subroutine
213 
214 !Only for separable lagrangian
216  sll_int32 :: rkidx
217  sll_real64 :: t !time
218  sll_assert(size(rk_d) == size(rk_c))
219 
220  !Loop over all stages
221  do rkidx = 1, size(rk_d);
222  !Set control variate if used
223  call update_weight()
224 
225  !Charge assignement, get right hand side
226  rhs = solver%get_rhs_particle(particle(maskxw, :))/npart
227  !mpi allreduce
228  call sll_collective_globalsum(sll_v_world_collective, rhs)
229 
230  solution = solver%solve_poisson(rhs)
231 
232  if (rkidx == 1) then
233  call calculate_diagnostics()
234  end if
235 
236  particle(maskv, :) = particle(maskv, :) - &
237  rk_c(rkidx)*dt*qm*(-solver%eval_gradient(particle(maskx, :), solution));
238  particle(maskx, :) = particle(maskx, :) + rk_d(rkidx)*dt*particle(maskv, :);
239  ! xx=mod(xx,repmat(L,1,npart));
240 
241  ! CV_new=CV(xx,vx);
242  ! weight=forward_weight_CV(weight, CV_old, CV_new);CV_old=CV_new;
243 
244  t = (tstep - 1)*dt + sum(rk_d(1:rkidx))*dt;
245  end do
246  t = (tstep)*dt;
247  end subroutine
248 
249  subroutine set_symplectic_rungekutta_coeffs(rk_order)
250  sll_int32, intent(in) :: rk_order
251  sll_real64 :: rk4sx = ((2**(1/3) + 2**(-1/3) - 1)/6)
252 
253  sll_allocate(rk_c(rk_order), ierr)
254  sll_allocate(rk_d(rk_order), ierr)
255 
256  SELECT CASE (rk_order)
257  CASE (1)
258  !euler not symplectic
259  rk_d = 1
260  rk_c = 1
261  CASE (2)
262  rk_d = (/0.5, 0.5/)
263  rk_c = (/0.0, 1.0/)
264  CASE (3)
265  rk_d(:) = (/2.0/3.0, -2.0/3.0, 1.0/)
266  rk_c(:) = (/7.0/24.0, 3/4.0, -1.0/24.0/)
267  CASE (4)
268  rk_d = (/2.0*rk4sx + 1.0, -4.0*rk4sx - 1.0, 2.0*rk4sx + 1.0, 0.0_f64/)
269  rk_c = (/rk4sx + 0.5, -rk4sx, -rk4sx, rk4sx + 0.5/)
270  END SELECT
271 
272  print *, "Symplectic Runge Kutta of order:", rk_order
273  print *, "D_COEFFS:", rk_d
274  print *, "C_COEFFS:", rk_c
275 
276  end subroutine set_symplectic_rungekutta_coeffs
277 
278  subroutine init_particle_masks()
279  sll_int32 :: idx
280 
281  !allocate stencils
282  sll_allocate(maskx(dimx), ierr)
283  sll_allocate(maskxw(dimx + 1), ierr)
284  sll_allocate(maskv(dimx), ierr)
285  sll_allocate(maskxv(dimx*2), ierr)
286 
287  maskx = (/(idx, idx=1, dimx)/)
288  maskv = (/(idx, idx=dimx + 1, 2*dimx)/)
289  maskw = 2*dimx + 1
290  maskxw(1:dimx) = maskx
291  maskxw(dimx + 1) = maskw
292  maskxv(1:dimx) = maskx
293  maskxv(dimx + 1:2*dimx) = maskv
294 
295  end subroutine init_particle_masks
296 
297 !Updates the weights for use with control variate
298  subroutine update_weight()
299 
300  if (controlvariate /= 0) then
301 
302  if (collisions /= 0) then
303 !particle(maskw,:)=initial_prior - (particle(maskw,:)-initial control_variate(particle(maskxv,:))
304  print *, "not implemented"
305  else
306 !no collisions, characteristics are conserved
307  particle(maskw, :) = weight_const(:) - control_variate(particle(maskxv, :))/prior_weight(:)
308  end if
309 
310  end if
311  end subroutine
312 
313  function control_variate(particle) result(cv)
314  sll_real64, dimension(:, :), intent(in) :: particle !(x,v)
315  sll_real64, dimension(size(particle, 2)) :: cv
316 
317 !Standard maxwellian control variate
318  SELECT CASE (controlvariate)
319  CASE (sll_controlvariate_none)
320  !This should not happen
321  cv = 1
322  CASE (sll_controlvariate_standard)
323  cv = sqrt(2*sll_p_pi)**(-size(maskv))*exp(-0.5*sum(particle(maskv, :), 1)**2)
324  CASE (sll_controlvariate_maxwellian)
325  cv = sqrt(2*sll_p_pi)**(-size(maskv))*exp(-0.5*sum(particle(maskv, :), 1)**2)
326  END SELECT
327 
328  end function
329 
330  subroutine write_result()
331  !character(len=*), intent(in) :: filename
332  character(len=*), parameter :: filename = "pif"
333 
334 ! sll_real64, dimension(:), intent(in) :: kinetic_energy, electrostatic_energy, impulse,&
335 ! particleweight_mean,particleweight_var, perror_mean , perror_var
336  integer :: idx, file_id, file_id_err
337 ! sll_real64, dimension(size(kinetic_energy)) :: total_energy
338 
339  if (coll_rank == 0) then
340 
341  call sll_new_file_id(file_id, ierr)
342 
343  !Write Data File
344  ! open(file_id, file = plot_name//"_"//fin//'.dat' )
345  open (file_id, file='./'//filename//'.csv')
346 
347 ! write (file_id, *) "#Full 1d1v Electrostatic PIC"
348 ! write (file_id,*) "#Time steps:", timesteps
349 ! write (file_id,*) "#Time stepwidth:", timestepwidth
350 ! write (file_id,*) "#Marko particles:", coll_size*nparticles
351 ! write (file_id,*) "#Particle Pusher:", particle_pusher
352 ! write (file_id,*) "#Finite Elements: 2^(", log(real(mesh_cells,i64))/log(2.0_f64),")"
353 ! write (file_id,*) "#Size of MPI Collective: ", coll_size
354 
355  write (file_id, *) ' \"time\", \"kineticenergy\", \"fieldenergy\", \"energy_error\", \"moment_error\"'
356 
357 ! "impulse ", &
358 ! "vthermal ", "weightmean ", "weightvar ", "perrormean ", "perrorvar "
359  do idx = 1, tsteps
360  write (file_id, *) (idx - 1)*dt, ",", kineticenergy(idx), ",", fieldenergy(idx), ",", &
361  fieldenergy(idx), ",", energy_error(idx), ",", moment_error(idx)
362  end do
363  close (file_id)
364  end if
365  end subroutine
366 
367 end program sll_pif_general
Parallelizing facility.
integer(kind=i32) function, public sll_f_get_collective_rank(col)
Determines the rank of the calling process in the communicator.
subroutine, public sll_s_halt_collective()
Ends the paralell environment.
subroutine, public sll_s_boot_collective(required)
Starts the paralell environment.
type(sll_t_collective_t), pointer, public sll_v_world_collective
Control of subset assignment. Processes with the same color are in the same new communicator.
integer(kind=i32) function, public sll_f_get_collective_size(col)
Determines the size of the group associated with a communicator.
subroutine match_moment_1d_linear_real64(x, mean, mom2)
This module provides some routines for plotting during PIC simulations.
We can now use the functions.
Definition: sll_m_timer.F90:40
subroutine update_weight()
subroutine write_result()
subroutine init_diagnostics
subroutine init_particle
program sll_pif_general
subroutine init_particle_prior_maxwellian()
subroutine calculate_diagnostics
real(kind=f64) function, dimension(size(particle, 2)) control_variate(particle)
subroutine symplectic_rungekutta()
subroutine init_particle_masks()
subroutine set_symplectic_rungekutta_coeffs(rk_order)
    Report Typos and Errors