Report Typos and Errors    
Semi-Lagrangian Library
Modular library for kinetic and gyrokinetic simulations of plasmas in fusion energy devices.
sll_m_dg_interpolator_1d.F90
Go to the documentation of this file.
1 
10 !+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
11 #include "sll_assert.h"
12 #include "sll_errors.h"
13 #include "sll_memory.h"
14 #include "sll_working_precision.h"
15 
17  sll_p_periodic
18 
22 
26 
27  use sll_m_interpolators_1d_base, only: &
29 
30  implicit none
31 
32  public :: &
43 
44  private
45  !+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
46 
47  sll_int32, parameter :: sll_p_dg_gauss_legendre = 101
48  sll_int32, parameter :: sll_p_dg_gauss_lobatto = 102
49  sll_int32, parameter :: sll_p_dg_uniform = 103
50 
53 
54  sll_int32 :: n_cells
55  sll_int32 :: degree
56  sll_int32 :: n_total
57  sll_real64 :: cell_size
58 
59  sll_real64, pointer :: positions(:)
60  sll_real64, pointer :: quadrature_points(:)
61  sll_real64, pointer :: quadrature_inv_diffs(:, :)
62  sll_real64, pointer :: quadrature_weights(:)
63  sll_real64, pointer :: quadrature_inv_weights(:)
64  sll_real64, pointer :: weights1(:, :)
65  sll_real64, pointer :: weights2(:, :)
66 
68 
69 contains
70 
71  subroutine sll_s_dg_interpolator_1d_init(self, n_cells, degree, x_min, x_max, type)
72  class(sll_t_dg_interpolator_1d), intent(inout) :: self
73  sll_int32, intent(in) :: n_cells
74  sll_int32, intent(in) :: degree
75  sll_real64, intent(in) :: x_min
76  sll_real64, intent(in) :: x_max
77  sll_int32, intent(in) :: type !< descriptor telling if gauss-lobatto, gauss-legendre or uniform points shall be used as points within the cells
78 
79  sll_int32 :: ierr, j, i
80 
81  self%n_cells = n_cells
82  self%degree = degree
83  self%n_total = n_cells*degree
84 
85  sll_allocate(self%positions(self%n_total), ierr)
86  sll_allocate(self%quadrature_points(self%degree), ierr)
87  sll_allocate(self%quadrature_weights(self%degree), ierr)
88  sll_allocate(self%quadrature_inv_weights(self%degree), ierr)
89  sll_allocate(self%weights1(self%degree, self%degree), ierr)
90  sll_allocate(self%weights2(self%degree, self%degree), ierr)
91  sll_allocate(self%quadrature_inv_diffs(self%degree, self%degree), ierr)
92 
93  if (type == sll_p_dg_gauss_legendre) then
94  ! Gauss-Legendre points and weights for each cell
95  self%quadrature_points = sll_f_gauss_legendre_points(self%degree, 0.0_f64, 1.0_f64)
96  self%quadrature_weights = sll_f_gauss_legendre_weights(self%degree, 0.0_f64, 1.0_f64)
97  elseif (type == sll_p_dg_gauss_lobatto) then
98  ! Gauss-Lobatto points and weights for each cell
99  self%quadrature_points = sll_f_gauss_lobatto_points(self%degree, 0.0_f64, 1.0_f64)
100  self%quadrature_weights = sll_f_gauss_lobatto_weights(self%degree, 0.0_f64, 1.0_f64)
101  elseif (type == sll_p_dg_uniform) then
102  ! Uniform points and weights for each cell
103  do j = 1, self%degree
104  self%quadrature_points(j) = real(j - 1, f64)/real(self%degree - 1, f64)
105  end do
106  self%quadrature_weights = 1.0_f64/(self%degree - 1)
107  self%quadrature_weights(1) = 0.5_f64/(self%degree - 1)
108  self%quadrature_weights(self%degree) = self%quadrature_weights(1)
109  else
110  sll_error('sll_s_dg_interpolator_1d_init', 'Wrong type of points.')
111  end if
112 
113  ! Compute cell size
114  self%cell_size = (x_max - x_min)/n_cells
115 
116  do j = 1, n_cells
117  self%positions(1 + (j - 1)*degree:j*degree) = x_min + &
118  (real(j - 1, f64) + self%quadrature_points)*self%cell_size
119  end do
120 
121  ! cache the inverse differences of the points which are
122  ! used repeatedly during lagrange polynomial evaluation
123  do i = 1, self%degree
124  do j = 1, self%degree
125  if (i /= j) then
126  self%quadrature_inv_diffs(j, i) = 1.0_f64/(self%quadrature_points(i) - self%quadrature_points(j))
127  else
128  ! this value should never be accessed
129  self%quadrature_inv_diffs(j, i) = 1.0_f64
130  end if
131  end do
132  end do
133 
134  ! cache the inverse weights which are
135  ! used repeatedly during interpolation
136  do i = 1, self%degree
137  self%quadrature_inv_weights(i) = 1.0_f64/self%quadrature_weights(i)
138  end do
139  end subroutine sll_s_dg_interpolator_1d_init
140 
142  class(sll_t_dg_interpolator_1d), intent(inout) :: self
143 
144  sll_int32 :: ierr
145 
146  sll_deallocate(self%positions, ierr)
147  sll_deallocate(self%quadrature_points, ierr)
148  sll_deallocate(self%quadrature_inv_diffs, ierr)
149  sll_deallocate(self%quadrature_weights, ierr)
150  sll_deallocate(self%quadrature_inv_weights, ierr)
151  sll_deallocate(self%weights1, ierr)
152  sll_deallocate(self%weights2, ierr)
153  end subroutine sll_s_dg_interpolator_1d_free
154 
155 !DIR$ ATTRIBUTES INLINE :: sll_s_dg_interpolator_1d_interpolate_array_disp_periodic
156  subroutine sll_s_dg_interpolator_1d_interpolate_array_disp_periodic(self, num_pts, data, alpha, output_array)
157  class(sll_t_dg_interpolator_1d), intent(inout) :: self
158  sll_int32, intent(in) :: num_pts
159  sll_real64, intent(in) :: alpha
160  sll_real64, dimension(:), intent(in) :: data
161  sll_real64, dimension(num_pts), intent(out) :: output_array
162 
163  sll_int32 :: i, j, k, r, q, ind1, ind2, degree, n_cells
164  sll_real64 :: beta, alph
165  sll_real64, pointer :: quadrature_points(:)
166  sll_real64, pointer :: quadrature_weights(:)
167  sll_real64, pointer :: quadrature_inv_weights(:)
168  sll_real64, pointer :: weights1(:, :)
169  sll_real64, pointer :: weights2(:, :)
170  sll_real64, pointer :: quadrature_inv_diffs(:, :)
171 
172  sll_assert(num_pts == self%n_total)
173 
174  ! Normalize displacement
175  beta = alpha/self%cell_size
176  q = floor(beta)
177  alph = beta - real(q, f64)
178 
179  ! cache nested values to avoid subsequent dereferencing
180  degree = self%degree
181  n_cells = self%n_cells
182  quadrature_points => self%quadrature_points
183  quadrature_inv_diffs => self%quadrature_inv_diffs
184  quadrature_weights => self%quadrature_weights
185  quadrature_inv_weights => self%quadrature_inv_weights
186  weights1 => self%weights1
187  weights2 => self%weights2
188 
189  ! Precompute the weights
190 
191 ! do j=1, degree
192 ! do k =1, degree
193 ! weights1(j,k) = 0.0_f64
194 ! weights2(j,k) = 0.0_f64
195 ! do r=1,degree
196 !! self%weights1(j,k) = self%weights1(j,k) + self%quadrature_weights(r)*&
197 !! lagrange_poly( self, k, alph + (1.0_f64-alph)*self%quadrature_points(r)) *&
198 !! lagrange_poly( self, j, (1.0_f64-alph)*self%quadrature_points(r))
199 !! self%weights2(j,k) = self%weights2(j,k) + self%quadrature_weights(r)*&
200 !! lagrange_poly( self, k, alph*self%quadrature_points(r)) *&
201 !! lagrange_poly( self, j, alph*(self%quadrature_points(r)-1.0_f64)+1.0_f64 )
202 ! weights1(j,k) = weights1(j,k) + quadrature_weights(r)*&
203 ! lagrange_poly_opt( quadrature_points, quadrature_inv_diffs, degree, k, alph + (1.0_f64-alph)*quadrature_points(r)) *&
204 ! lagrange_poly_opt( quadrature_points, quadrature_inv_diffs, degree, j, (1.0_f64-alph)*quadrature_points(r))
205 ! weights2(j,k) = weights2(j,k) + quadrature_weights(r)*&
206 ! lagrange_poly_opt( quadrature_points, quadrature_inv_diffs, degree, k, alph *quadrature_points(r)) *&
207 ! lagrange_poly_opt( quadrature_points, quadrature_inv_diffs, degree, j, alph*(quadrature_points(r)-1.0_f64)+1.0_f64 )
208 ! end do
209 ! weights1(j,k) = weights1(j,k) * (1.0_f64-alph)
210 ! weights2(j,k) = weights2(j,k) * alph
211 ! end do
212 ! end do
213 
214  weights1(:, :) = 0.0_f64
215  do j = 1, degree
216  do k = 1, degree
217  do r = 1, degree
218  weights1(k, j) = weights1(k, j) + quadrature_weights(r)* &
219  lagrange_poly_opt(quadrature_points, quadrature_inv_diffs, degree, k, alph + (1.0_f64 - alph)*quadrature_points(r))* &
220  lagrange_poly_opt(quadrature_points, quadrature_inv_diffs, degree, j, (1.0_f64 - alph)*quadrature_points(r))
221  end do
222  weights1(k, j) = weights1(k, j)*(1.0_f64 - alph)
223  end do
224  end do
225 
226  weights2(:, :) = 0.0_f64
227  do j = 1, degree
228  do k = 1, degree
229  do r = 1, degree
230  weights2(k, j) = weights2(k, j) + quadrature_weights(r)* &
231  lagrange_poly_opt(quadrature_points, quadrature_inv_diffs, degree, k, alph*quadrature_points(r))* &
232  lagrange_poly_opt(quadrature_points, quadrature_inv_diffs, degree, j, alph*(quadrature_points(r) - 1.0_f64) + 1.0_f64)
233  end do
234  weights2(k, j) = weights2(k, j)*alph
235  end do
236  end do
237 
238  ! Interpolate
239  output_array(:) = 0.0_f64
240  do i = 1, n_cells
241  do j = 1, degree
242 ! output_array((i-1)*degree+j) = 0.0_f64
243  ind1 = modulo(i - 1 + q, self%n_cells)*degree
244  ind2 = modulo(i + q, self%n_cells)*degree
245  do k = 1, degree
246  output_array((i - 1)*degree + j) = output_array((i - 1)*degree + j) + &
247  data(ind1 + k)*weights1(k, j) + data(ind2 + k)*weights2(k, j)
248  end do
249 ! output_array((i-1)*degree+j) = output_array((i-1)*degree+j)/quadrature_weights(j)
250  output_array((i - 1)*degree + j) = output_array((i - 1)*degree + j)*quadrature_inv_weights(j)
251  end do
252  end do
254 
256 !DIR$ ATTRIBUTES INLINE :: sll_s_dg_interpolator_1d_interpolate_array_disp_halo
257  subroutine sll_s_dg_interpolator_1d_interpolate_array_disp_halo(self, data, alpha, weights1, weights2, output_array)
258  class(sll_t_dg_interpolator_1d), intent(inout) :: self
259  sll_real64, intent(in) :: alpha
260  sll_real64, intent(in) :: data(:)
261  sll_real64, intent(inout) :: weights1(self%degree, self%degree)
262  sll_real64, intent(inout) :: weights2(self%degree, self%degree)
263  sll_real64, intent(inout) :: output_array(self%n_total)
264 
265  sll_int32 :: i, j, k, r, q, ind1, ind2, num_pts, degree, n_cells
266  sll_real64 :: alph
267  sll_real64, pointer :: quadrature_points(:)
268  sll_real64, pointer :: quadrature_weights(:)
269  sll_real64, pointer :: quadrature_inv_weights(:)
270  sll_real64, pointer :: quadrature_inv_diffs(:, :)
271 
272  ! cache nested values to avoid subsequent dereferencing
273  n_cells = self%n_cells
274  degree = self%degree
275  quadrature_points => self%quadrature_points
276  quadrature_weights => self%quadrature_weights
277  quadrature_inv_weights => self%quadrature_inv_weights
278  quadrature_inv_diffs => self%quadrature_inv_diffs
279 
280  ! Normalize displacement
281  !beta = alpha/self%cell_size
282  !q = floor( beta )
283  !alph = beta - real(q, f64 )
284  alph = alpha
285 
286  ! --- Precompute the weights
287 
288  ! optimizations: split loops, changed storage order of weights (j,k) -> (k,j)
289 
290 ! weights1(:,:) = 0.0_f64
291 ! weights2(:,:) = 0.0_f64
292 ! do j=1, degree
293 ! do k =1, degree
294 !! weights1(j,k) = 0.0_f64
295 !! weights2(j,k) = 0.0_f64
296 ! do r=1,degree
297 !! weights1(j,k) = weights1(j,k) + self%quadrature_weights(r)*&
298 !! lagrange_poly( self, k, alph + (1.0_f64-alph)*self%quadrature_points(r)) *&
299 !! lagrange_poly( self, j, (1.0_f64-alph)*self%quadrature_points(r))
300 !! weights2(j,k) = weights2(j,k) + self%quadrature_weights(r)*&
301 !! lagrange_poly( self, k, alph*self%quadrature_points(r)) *&
302 !! lagrange_poly( self, j, alph*(self%quadrature_points(r)-1.0_f64)+1.0_f64 )
303 !
304 ! weights1(k,j) = weights1(k,j) + quadrature_weights(r)*&
305 ! lagrange_poly_opt( quadrature_points, quadrature_inv_diffs, degree, k, alph + (1.0_f64-alph)*quadrature_points(r)) *&
306 ! lagrange_poly_opt( quadrature_points, quadrature_inv_diffs, degree, j, (1.0_f64-alph)*quadrature_points(r))
307 ! weights2(k,j) = weights2(k,j) + quadrature_weights(r)*&
308 ! lagrange_poly_opt( quadrature_points, quadrature_inv_diffs, degree, k, alph* quadrature_points(r)) *&
309 ! lagrange_poly_opt( quadrature_points, quadrature_inv_diffs, degree, j, alph*(quadrature_points(r)-1.0_f64)+1.0_f64 )
310 ! end do
311 ! weights1(k,j) = weights1(k,j) * (1.0_f64-alph)
312 ! weights2(k,j) = weights2(k,j) * alph
313 ! end do
314 ! end do
315 
316  weights1(:, :) = 0.0_f64
317  do j = 1, degree
318  do k = 1, degree
319  do r = 1, degree
320  weights1(k, j) = weights1(k, j) + quadrature_weights(r)* &
321  lagrange_poly_opt(quadrature_points, quadrature_inv_diffs, degree, k, alph + (1.0_f64 - alph)*quadrature_points(r))* &
322  lagrange_poly_opt(quadrature_points, quadrature_inv_diffs, degree, j, (1.0_f64 - alph)*quadrature_points(r))
323  end do
324  weights1(k, j) = weights1(k, j)*(1.0_f64 - alph)
325  end do
326  end do
327 
328  weights2(:, :) = 0.0_f64
329  do j = 1, degree
330  do k = 1, degree
331  do r = 1, degree
332  weights2(k, j) = weights2(k, j) + quadrature_weights(r)* &
333  lagrange_poly_opt(quadrature_points, quadrature_inv_diffs, degree, k, alph*quadrature_points(r))* &
334  lagrange_poly_opt(quadrature_points, quadrature_inv_diffs, degree, j, alph*(quadrature_points(r) - 1.0_f64) + 1.0_f64)
335  end do
336  weights2(k, j) = weights2(k, j)*alph
337  end do
338  end do
339 
340  ! Interpolate
341  output_array(:) = 0.0_f64
342  do i = 1, n_cells
343  do j = 1, degree
344  ind1 = (i - 1)*degree
345  ind2 = i*degree
346  !ind1 = modulo( i-1+q, n_cells )* degree
347  !ind2 = modulo( i+q, n_cells )*degree
348  !ind1 = i-1
349  do k = 1, degree
350 ! output_array((i-1)*degree+j) = output_array((i-1)*degree+j) + &
351 ! data(ind1+k)*weights1(j,k) + data(ind2+k)*weights2(j,k)
352  output_array((i - 1)*degree + j) = output_array((i - 1)*degree + j) + &
353  data(ind1 + k)*weights1(k, j) + data(ind2 + k)*weights2(k, j)
354  end do
355  !output_array((i-1)*degree+j) = output_array((i-1)*degree+j)/quadrature_weights(j)
356  output_array((i - 1)*degree + j) = output_array((i - 1)*degree + j)*quadrature_inv_weights(j)
357  end do
358  end do
360 
361  subroutine sll_s_dg_interpolator_1d_dg_to_equi_cell(self, npoints, output_array)
362  type(sll_t_dg_interpolator_1d), intent(in) :: self
363  sll_int32, intent(in) :: npoints
364  sll_real64, intent(out) :: output_array(:, :)
365 
366  sll_int32 :: j, idx, degree
367  sll_real64 :: delta
368  sll_real64, pointer :: quadrature_points(:)
369  sll_real64, pointer :: quadrature_inv_diffs(:, :)
370 
371  delta = 1.0_f64/real(npoints - 1, f64);
372  degree = self%degree
373  quadrature_points => self%quadrature_points
374  quadrature_inv_diffs => self%quadrature_inv_diffs
375 
376  do j = 1, npoints
377  do idx = 1, degree
378 ! output_array(idx,j) = lagrange_poly( self, idx, real(j-1,f64)*delta )
379  output_array(idx, j) = lagrange_poly_opt(quadrature_points, quadrature_inv_diffs, degree, idx, real(j - 1, f64)*delta)
380  end do
381  end do
383 
384  subroutine sll_s_dg_interpolator_1d_dg_to_equi_cell_staggered(self, npoints, output_array)
385  type(sll_t_dg_interpolator_1d), intent(in) :: self
386  sll_int32, intent(in) :: npoints
387  sll_real64, intent(out) :: output_array(:, :)
388 
389  sll_int32 :: j, idx, degree
390  sll_real64 :: delta
391  sll_real64, pointer :: quadrature_points(:)
392  sll_real64, pointer :: quadrature_inv_diffs(:, :)
393 
394  delta = 1.0_f64/real(npoints, f64);
395  degree = self%degree
396  quadrature_points => self%quadrature_points
397  quadrature_inv_diffs => self%quadrature_inv_diffs
398 
399  do j = 1, npoints
400  do idx = 1, degree
401 ! output_array(idx,j) = lagrange_poly( self, idx, real(j-1,f64)*delta )
402  output_array(idx, j) = lagrange_poly_opt(quadrature_points, quadrature_inv_diffs, degree, idx, (real(j - 1, f64) + 0.5_f64)*delta)
403  end do
404  end do
406 
410  function lagrange_poly(self, idx, x) result(r)
411  type(sll_t_dg_interpolator_1d), intent(in) :: self
412  sll_int32, intent(in) :: idx
413  sll_real64, intent(in) :: x
414  sll_real64 :: r
415 
416  sll_int32 :: j
417 
418  r = 1.0_f64
419  do j = 1, self%degree
420  if (j .ne. idx) then
421  r = r*(x - self%quadrature_points(j))/(self%quadrature_points(idx) - self%quadrature_points(j))
422  end if
423  end do
424  end function lagrange_poly
425 
427 !DIR$ ATTRIBUTES FORCEINLINE :: lagrange_poly_opt
428  function lagrange_poly_opt(quadrature_points, quadrature_inv_diffs, degree, idx, x) result(r)
429  sll_real64, intent(in) :: quadrature_points(:)
430  sll_real64, intent(in) :: quadrature_inv_diffs(:, :)
431  sll_int32, intent(in) :: degree
432  sll_int32, intent(in) :: idx
433  sll_real64, intent(in) :: x
434 
435  sll_real64 :: r
436  sll_int32 :: j
437 
438  r = 1.0_f64
439  do j = 1, degree
440  if (j .ne. idx) then
441  r = r*(x - quadrature_points(j))*quadrature_inv_diffs(j, idx)
442  end if
443  end do
444  end function lagrange_poly_opt
445 
446 ! function lagrange_poly_opt_bak( quadrature_points, degree, idx, x ) result(r)
447 ! sll_real64, intent(in) :: quadrature_points(:)
448 ! sll_int32, intent(in) :: degree
449 ! sll_int32, intent(in) :: idx
450 ! sll_real64, intent(in) :: x
451 !
452 ! sll_real64 :: r
453 ! sll_int32 :: j
454 !
455 ! r = 1.0_f64
456 ! do j=1,degree
457 ! if (j .ne. idx) then
458 ! r = r * (x-quadrature_points(j))/(quadrature_points(idx)-quadrature_points(j))
459 ! end if
460 ! end do
461 ! end function lagrange_poly_opt_bak
462 
463 end module sll_m_dg_interpolator_1d
Interpolator 1d using dg interpolation.
real(kind=f64) function lagrange_poly_opt(quadrature_points, quadrature_inv_diffs, degree, idx, x)
Evaluate Lagrange polynomial, optimized version.
subroutine, public sll_s_dg_interpolator_1d_interpolate_array_disp_halo(self, data, alpha, weights1, weights2, output_array)
Interpolation routine with halo cells.
subroutine, public sll_s_dg_interpolator_1d_dg_to_equi_cell_staggered(self, npoints, output_array)
subroutine, public sll_s_dg_interpolator_1d_interpolate_array_disp_periodic(self, num_pts, data, alpha, output_array)
subroutine, public sll_s_dg_interpolator_1d_dg_to_equi_cell(self, npoints, output_array)
integer(kind=i32), parameter, public sll_p_dg_gauss_lobatto
subroutine, public sll_s_dg_interpolator_1d_init(self, n_cells, degree, x_min, x_max, type)
subroutine, public sll_s_dg_interpolator_1d_free(self)
integer(kind=i32), parameter, public sll_p_dg_uniform
real(kind=f64) function lagrange_poly(self, idx, x)
Evaluate Lagrange polynomial, original version. Suffers from repeated dereferencing,...
integer(kind=i32), parameter, public sll_p_dg_gauss_legendre
real(kind=f64) function, dimension(1:npoints), public sll_f_gauss_legendre_points(npoints, a, b)
real(kind=f64) function, dimension(1:npoints), public sll_f_gauss_legendre_weights(npoints, a, b)
real(kind=f64) function, dimension(n), public sll_f_gauss_lobatto_points(n, a, b)
Returns a 1d array of size (n) containing gauss-lobatto points in the interval [a,...
real(kind=f64) function, dimension(n), public sll_f_gauss_lobatto_weights(n, a, b)
Returns a 1d array of size (n) containing gauss-lobatto weights in the interval [a,...
Module for 1D interpolation and reconstruction.
Abstract class for 1D interpolation and reconstruction.
    Report Typos and Errors