Report Typos and Errors    
Semi-Lagrangian Library
Modular library for kinetic and gyrokinetic simulations of plasmas in fusion energy devices.
sll_m_spline_fem_utilities.F90
Go to the documentation of this file.
1 
8 
10  !+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
11 #include "sll_assert.h"
12 #include "sll_memory.h"
13 #include "sll_working_precision.h"
14 
15  use sll_m_low_level_bsplines, only: &
16  sll_s_uniform_bsplines_eval_basis
17 
19 
20  use sll_m_constants, only : &
22 
25 
26  implicit none
27 
28  public :: &
47 
48 
49  private
50  !+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
51 
52  abstract interface
53  function sll_i_profile_function_1d( x ) result(res)
55  sll_real64, intent(in) :: x
56  sll_real64 :: res
57  end function sll_i_profile_function_1d
58  end interface
59 
60 contains
61 
62  !---------------------------------------------------------------------------!
64  subroutine sll_s_spline_fem_mass_line ( degree, mass_line )
65  sll_int32, intent(in ) :: degree
66  sll_real64, intent( out) :: mass_line(degree+1)
67 
68  !local variables
69  sll_int32 :: q, j, int, quad
70  sll_real64, allocatable :: quad_xw(:,:), spline_val(:,:)
71 
72  q = degree+1
73 
74  allocate(quad_xw(2, q))
75  allocate(spline_val( degree+1, q ))
76 
77  quad_xw = sll_f_gauss_legendre_points_and_weights( q , 0.0_f64, 1.0_f64 )
78 
79 
80  do j=1,q
81  call sll_s_uniform_bsplines_eval_basis( degree, quad_xw(1,j), spline_val(:,j) )
82  end do
83 
84  mass_line = 0.0_f64
85  do j=1,degree+1
86  do int= j, degree+1
87  do quad = 1, q
88  mass_line(j) = mass_line(j) + &
89  spline_val(int,quad) * spline_val(int-j+1,quad)*quad_xw(2,quad)
90  end do
91  end do
92  end do
93 
94 
95  end subroutine sll_s_spline_fem_mass_line
96 
98  subroutine sll_s_spline_fem_mass_line_boundary ( degree, spline, mass_line )
99  sll_int32, intent(in ) :: degree
100  type(sll_t_spline_pp_1d), intent(in) :: spline
101  sll_real64, intent( out) :: mass_line(:)
102 
103  !local variables
104  sll_int32 :: q, j, int, quad
105  sll_real64, allocatable :: quad_xw(:,:), spline_val(:,:),spline_val_b(:,:)
106 
107  q = degree+1
108 
109  allocate(quad_xw(2, q))
110  allocate(spline_val( degree+1, q ))
111  allocate(spline_val_b( degree+1, q ))
112  spline_val_b=0._f64
113  spline_val=0._f64
114 
115  quad_xw = sll_f_gauss_legendre_points_and_weights( q , 0.0_f64, 1.0_f64 )
116 
117 
118  select case(degree)
119  case(0)
120  print*, 'fem_utilities:degree 0 not implemented'
121  case(1)
122  do quad = 1, q
123  do int = 1, degree+1
124  spline_val(int,quad) = sll_f_spline_pp_horner_1d( degree, spline%poly_coeffs, quad_xw(1,quad), int)
125  end do
126  end do
127 
128  !first interval
129  mass_line = 0.0_f64
130  do j = 1, degree
131  do int = j, degree+1
132  do quad = 1, q
133  mass_line(int) = mass_line(int) + &
134  spline_val(j,quad) * spline_val(int,quad) * quad_xw(2,quad)
135  end do
136  end do
137  end do
138  case(2)
139  do quad = 1, q
140  do int = 1, degree+1
141  spline_val_b(int,quad) = sll_f_spline_pp_horner_1d( degree, spline%poly_coeffs_boundary_left(:,:,1), quad_xw(1,quad), int)
142  end do
143  end do
144 
145  mass_line = 0.0_f64
146  !first interval
147  do j = 1, degree
148  do int = j, degree+1
149  do quad = 1, q
150  mass_line(int-j+1+q*(j-1)) = mass_line(int-j+1+q*(j-1)) + &
151  spline_val_b(j,quad) * spline_val_b(int,quad) * quad_xw(2,quad)
152  end do
153  end do
154  end do
155 
156 
157  do quad = 1, q
158  do int = 1, degree+1
159  spline_val(int,quad) = sll_f_spline_pp_horner_1d( degree, spline%poly_coeffs, quad_xw(1,quad), int)
160  end do
161  end do
162 
163  !last interval
164  do j = degree, degree
165  do int = 1, degree+1
166  do quad = 1, q
167  mass_line(int+q*(j-1)) = mass_line(int+q*(j-1)) + &
168  spline_val(1,quad) * spline_val(int,quad) * quad_xw(2,quad)
169  end do
170  end do
171  end do
172 
173  case(3)
174  do quad = 1, q
175  do int = 1, degree+1
176  spline_val_b(int,quad) = sll_f_spline_pp_horner_1d( degree, spline%poly_coeffs_boundary_left(:,:,1), quad_xw(1,quad), int)
177  end do
178  end do
179 
180  mass_line = 0.0_f64
181  !first interval
182  do j = 1, degree
183  do int = j, degree+1
184  do quad = 1, q
185  mass_line(int-j+1+q*(j-1)) = mass_line(int-j+1+q*(j-1)) + &
186  spline_val_b(j,quad) * spline_val_b(int,quad) * quad_xw(2,quad)
187  end do
188  end do
189  end do
190 
191  spline_val_b = 0._f64
192  do quad = 1, q
193  do int = 1, degree+1
194  spline_val_b(int,quad) = sll_f_spline_pp_horner_1d( degree, spline%poly_coeffs_boundary_left(:,:,2), quad_xw(1,quad), int)
195  end do
196  end do
197 
198  !second interval
199  do j = 1, degree-1
200  do int = j, degree+1
201  do quad = 1, q
202  mass_line(int-j+1+q*j)=mass_line(int-j+1+q*j) + &
203  spline_val_b(j,quad) * spline_val_b(int,quad) * quad_xw(2,quad)
204  end do
205  end do
206  end do
207 
208  do quad = 1, q
209  do int = 1, degree+1
210  spline_val(int,quad) = sll_f_spline_pp_horner_1d( degree, spline%poly_coeffs, quad_xw(1,quad), int)
211  end do
212  end do
213 
214  !last interval
215  do j = degree, degree
216  do int = 1, degree+1
217  do quad = 1, q
218  mass_line(int+q*(j-1)) = mass_line(int+q*(j-1)) + &
219  spline_val(1,quad) * spline_val(int,quad) * quad_xw(2,quad)
220  end do
221  end do
222  end do
223 
224  case default
225  print*, "for chosen spline degree, no boundary mass_line is implemented"
226  end select
227 
228 
230 
231  !---------------------------------------------------------------------------!
232  !for use of affine transformation
234  subroutine sll_s_spline_fem_mass_line_boundary_full ( deg, profile, spline, row, n_cells, mass_line )
235  sll_int32, intent( in ) :: deg
236  procedure(sll_i_profile_function_1d) :: profile
237  type(sll_t_spline_pp_1d), intent(in) :: spline
238  sll_int32, intent( in ) :: row
239  sll_int32, intent( in ) :: n_cells
240  sll_real64, intent( out) :: mass_line((7*deg**2-deg-2)/2)
241  !local variables
242  sll_int32 :: q, j, int, ind1, quad, interval, ind4
243  sll_real64, allocatable :: quad_xw(:,:),spline_val_b(:,:,:), spline_val(:,:)
244  sll_real64 :: c
245 
246  q = min(3*deg+1,10)
247 
248  if(deg==0)then
249  print*, 'fem_utilities:degree 0 not implemented'
250  stop
251  end if
252 
253  allocate(quad_xw(2, q))
254  allocate(spline_val( deg+1, q ))
255  allocate(spline_val_b( deg+1, q, 2*deg-1 ))
256 
257  quad_xw = sll_f_gauss_legendre_points_and_weights( q , 0.0_f64, 1.0_f64 )
258  spline_val=0._f64
259  do quad = 1, q
260  call sll_s_uniform_bsplines_eval_basis( deg, quad_xw(1,quad), spline_val(:, quad) )
261  end do
262 
263  spline_val_b=0._f64
264  do interval = 1, deg-1
265  do quad = 1, q
266  do int = 1, deg+1
267  spline_val_b(int,quad,interval) = sll_f_spline_pp_horner_1d( deg, spline%poly_coeffs_boundary_left(:,:,interval), quad_xw(1,quad), int)
268  end do
269  end do
270  end do
271  do interval = deg, 2*deg-1
272  spline_val_b(:,:,interval) = spline_val
273  end do
274 
275  if(row<=2*deg)then
276  ind4 = 1
277  else if(row>n_cells-deg+1 .and. row<= n_cells+deg)then
278  ind4 = -1
279  end if
280  mass_line = 0.0_f64
281 
282  !interval
283  do interval = 1, 2*deg-1
284  !row
285  do j = interval, min(interval+deg,2*deg-1)
286  !column
287  do int = interval, deg+interval
288  if(j <= deg+1)then
289  ind1 = int + ((j-1)*(2*deg+j))/2 !position in first dimension in massline
290  else if( j > deg+1 .and. j < 2*deg)then
291  ind1 = int + (j-deg-1)*2*deg + (3*deg**2+deg)/2 !position in first dimension in massline
292  end if
293  do quad = 1, q
294  c = (real(ind4,f64)*quad_xw(1,quad)+real(row-1+ind4*(interval-1),f64))/real(n_cells,f64)
295  mass_line(ind1) = mass_line(ind1) + &
296  spline_val_b(j-interval+1,quad,interval) * spline_val_b(int+1-interval,quad,interval) * quad_xw(2,quad)*profile(c)
297  end do
298  end do
299  end do
300  end do
301 
303 
304 
305 
306  !---------------------------------------------------------------------------!
307  !for use of affine transformation
309  subroutine sll_s_spline_fem_mass_line_full ( deg, profile, mass_line, row, n_cells )
310  sll_int32, intent(in ) :: deg
311  procedure(sll_i_profile_function_1d) :: profile
312  sll_real64, intent( out) :: mass_line(2*deg+1)
313  sll_int32, intent(in) :: row
314  sll_int32, intent(in) :: n_cells
315  !local variables
316  sll_int32 :: j, int, quad, q, ind2, ind3, ind4
317  sll_real64, allocatable :: quad_xw(:,:), spline_val(:,:)
318  sll_real64 :: c
319 
320  q = min(3*deg+1,10)
321 
322  allocate(quad_xw(2, q))
323  allocate(spline_val( deg+1, q ))
324 
325  quad_xw = sll_f_gauss_legendre_points_and_weights( q , 0.0_f64, 1.0_f64 )
326  spline_val=0._f64
327  do quad = 1, q
328  call sll_s_uniform_bsplines_eval_basis( deg, quad_xw(1,quad), spline_val(:,quad) )
329  end do
330 
331  mass_line = 0.0_f64
332  do j = 1, deg
333  do int = j, deg
334  ind2 = deg+1-int+j !spline1
335  ind3 = deg+1-int !spline2
336  ind4 = int-j !left cellborder
337  do quad = 1, q
338  c = (quad_xw(1,quad)+ real( row-1+ind4-((row-1+ind4)/n_cells)*n_cells,f64 ))/real(n_cells,f64)
339 
340  mass_line(deg+1-j)=mass_line(deg+1-j)+ &
341  spline_val(ind2,quad)*spline_val(ind3,quad)*quad_xw(2,quad)*profile(c)
342  end do
343  end do
344  end do
345  do j=1,deg+1
346  do int= j, deg+1
347  ind2 = int-j+1 !spline1
348  ind3 = int !spline2
349  ind4 = deg+j-int !left cellborder
350  do quad = 1, q
351  c = (quad_xw(1,quad)+ real( row-1+ind4-((row-1+ind4)/n_cells)*n_cells,f64 ))/real(n_cells,f64)
352 
353  mass_line(j+deg) = mass_line(j+deg) + &
354  spline_val(ind2,quad)*spline_val(ind3,quad)*quad_xw(2,quad)*profile(c)
355  end do
356  end do
357  end do
358 
359  end subroutine sll_s_spline_fem_mass_line_full
360 
361 
362  !---------------------------------------------------------------------------!
363  !for use of affine transformation
365  subroutine sll_s_spline_fem_mixedmass_line_boundary( deg1, deg2, profile, spline1, spline2, row, n_cells, mass_line )
366  sll_int32, intent( in ) :: deg1
367  sll_int32, intent( in ) :: deg2
368  procedure(sll_i_profile_function_1d) :: profile
369  type(sll_t_spline_pp_1d), intent( in ) :: spline1
370  type(sll_t_spline_pp_1d), intent( in ) :: spline2
371  sll_int32, intent( in ) :: row
372  sll_int32, intent( in ) :: n_cells
373  sll_real64, intent( out) :: mass_line( (deg1+deg2)**2+(2*deg2+deg1-deg1**2)/2 )
374  !local variables
375  sll_int32 :: q, j, k, int, ind1, quad, interval, ind4
376  sll_real64, allocatable :: quad_xw(:,:),spline_val1(:,:), spline_val2(:,:)
377  sll_real64, allocatable :: bspl_b1(:,:,:), bspl_b2(:,:,:)
378  sll_real64 :: c
379 
380  q = max(deg1,deg2)+1
381 
382  allocate( quad_xw(2, q) )
383  allocate( spline_val1( deg1+1, q ) )
384  allocate( spline_val2( deg2+1, q ) )
385 
386  allocate( bspl_b1(deg1+1, q, deg1+deg2) )
387  allocate( bspl_b2(deg2+1, q, deg1+deg2) )
388 
389  quad_xw = sll_f_gauss_legendre_points_and_weights( q , 0.0_f64, 1.0_f64 )
390  spline_val1=0._f64
391  spline_val2=0._f64
392  do quad = 1, q
393  call sll_s_uniform_bsplines_eval_basis( deg1, quad_xw(1,quad), spline_val1(:, quad) )
394  call sll_s_uniform_bsplines_eval_basis( deg2, quad_xw(1,quad), spline_val2(:, quad) )
395  end do
396 
397  do interval = 1, deg1-1
398  do k = 1, q
399  do j = 1, deg1+1
400  bspl_b1(j,k,interval) = sll_f_spline_pp_horner_1d( deg1, spline1%poly_coeffs_boundary_left(:,:,interval), quad_xw(1,k), j)
401  end do
402  end do
403  end do
404  if( deg1 == 0 ) then
405  do interval = 1, deg2
406  bspl_b1(:,:,interval)=spline_val1
407  end do
408  else
409  do interval = deg1, deg1+deg2
410  bspl_b1(:,:,interval)=spline_val1
411  end do
412  end if
413 
414  do interval = 1, deg2-1
415  do k = 1, q
416  do j = 1, deg2+1
417  bspl_b2(j,k,interval) = sll_f_spline_pp_horner_1d( deg2, spline2%poly_coeffs_boundary_left(:,:,interval), quad_xw(1,k), j)
418  end do
419  end do
420  end do
421  if( deg2 == 0 ) then
422  do interval = 1, deg1
423  bspl_b2(:,:,interval)=spline_val2
424  end do
425  else
426  do interval = deg2, deg1+deg2
427  bspl_b2(:,:,interval)=spline_val2
428  end do
429  end if
430 
431  if( row <= deg1+deg2 )then
432  ind4 = 1
433  else if( row > n_cells - deg2 .and. row <= n_cells+deg1 )then
434  ind4= -1
435  end if
436  mass_line = 0.0_f64
437 
438  !interval
439  do interval = 1, deg1+deg2
440  !row
441  do j = interval, min(interval+deg1,deg1+deg2)
442  !column
443  do int = interval, deg2+interval
444  if(j <= deg1+1)then
445  ind1 = int + ((j-1)*(2*deg2+j))/2 !position in first dimension in massline
446  else if( j > deg1+1 .and. j < deg1+deg2)then
447  ind1 = int + (j-deg1-1)*(deg1+deg2) + (deg1*(2*deg2+deg1+1))/2 !position in first dimension in massline
448  end if
449  do quad = 1, q
450  c = (real(ind4,f64)*quad_xw(1,quad)+real(row-1+ind4*(interval-1),f64))/real(n_cells,f64)
451  mass_line(ind1) = mass_line(ind1) + &
452  quad_xw(2,quad)* &
453  bspl_b1(j-interval+1, quad, interval)* &
454  bspl_b2(int-interval+1, quad, interval)* &
455  profile(c)
456  end do
457  end do
458  end do
459  end do
460 
462 
463 
465  subroutine sll_s_spline_fem_mixedmass_line_full ( deg1, deg2, profile, mass_line, cell, n_cells)
466  sll_int32, intent(in ) :: deg1, deg2
467  procedure(sll_i_profile_function_1d) :: profile
468  sll_real64, intent( out) :: mass_line(deg1+deg2+1)
469  sll_int32, intent(in) :: cell
470  sll_int32, intent(in) :: n_cells
471  !local variables
472  sll_int32 :: q, j, int, k, l, limit, ind1, ind2, ind3, ind4
473  sll_real64, allocatable :: quad_xw(:,:), spline_val_1(:,:), spline_val_2(:,:)
474  sll_real64 :: c
475 
476  q = min(deg1+deg2+1,10)
477 
478  allocate(quad_xw(2, q))
479  allocate(spline_val_1( deg1+1, q ))
480  allocate(spline_val_2( deg2+1, q ))
481 
482  quad_xw = sll_f_gauss_legendre_points_and_weights( q , 0.0_f64, 1.0_f64 )
483 
484 
485  do k = 1, q
486  call sll_s_uniform_bsplines_eval_basis( deg1, quad_xw(1,k), spline_val_1(:,k) )
487  call sll_s_uniform_bsplines_eval_basis( deg2, quad_xw(1,k), spline_val_2(:,k) )
488  end do
489 
490  mass_line = 0.0_f64
491  do j = 1, deg1+deg2+1
492  if(j <= deg2)then
493  limit = deg2
494  ind1 = deg2+1-j
495  else
496  limit = deg1+deg2+1
497  ind1 = j
498  end if
499  ! loop over spline cells
500  do int = j, min(limit, j+deg2)
501  if(j <= deg2)then
502  ind2 = deg1+1-int+j !spline1
503  ind3 = deg2+1-int !spline2
504  ind4 = int-j !left cellborder
505  else
506  ind2 = limit-int+1 !spline1
507  ind3 = deg2+1-int+j !spline2
508  ind4 = int-deg2-1 !left cellborder
509  end if
510  do l = 1, q
511  k = 1 - (-1)**l * l/2 + modulo(l+1,2)*q
512  c = (quad_xw(1,k)+ real( cell-1+ind4-((cell-1+ind4)/n_cells)*n_cells,f64 ))/real(n_cells,f64)
513  !jacobian= map%jacobian( [c, 0._f64, 0._f64] )
514 
515  mass_line(ind1)=mass_line(ind1)+ &
516  spline_val_1(ind2,k)*spline_val_2(ind3,k)*quad_xw(2,k)*profile(c)!*abs(jacobian)
517  end do
518  end do
519  end do
520 
522 
523  !---------------------------------------------------------------------------!
525  subroutine sll_s_spline_fem_mixedmass_line ( deg, mass_line )
526  sll_int32, intent(in ) :: deg
527  sll_real64, intent( out) :: mass_line(deg*2)
528 
529  !local variables
530  sll_int32 :: q, j, int, quad
531  sll_real64, allocatable :: quad_xw(:,:), spline_val_0(:,:), spline_val_1(:,:)
532 
533  q = min(3*deg+1,10)
534 
535  allocate(quad_xw(2, q))
536  allocate(spline_val_0( deg+1, q ))
537  allocate(spline_val_1( deg, q ))
538 
539  quad_xw = sll_f_gauss_legendre_points_and_weights( q , 0.0_f64, 1.0_f64 )
540 
541 
542  do j=1,q
543  call sll_s_uniform_bsplines_eval_basis( deg, quad_xw(1,j), spline_val_0(:,j) )
544  call sll_s_uniform_bsplines_eval_basis( deg-1, quad_xw(1,j), spline_val_1(:,j) )
545  end do
546 
547  mass_line = 0.0_f64
548  do j=2,deg+1
549  do int= j, deg+1
550  do quad = 1, q
551  mass_line(j+deg-1) = mass_line(j+deg-1) + &
552  spline_val_0(int,quad) * spline_val_1(int-j+1,quad)*quad_xw(2,quad)
553  end do
554  end do
555  end do
556 
557  do j=-deg+1,0
558  do int= 1, deg+j
559  do quad = 1, q
560  mass_line(j+deg) = mass_line(j+deg) + &
561  spline_val_0(int,quad) * spline_val_1(int-j,quad)*quad_xw(2,quad)
562  end do
563  end do
564  end do
565 
566 
567  end subroutine sll_s_spline_fem_mixedmass_line
568 
569 
571  subroutine sll_s_spline_fem_compute_mass_eig( n_cells, degree, mass_line, eig_values_mass )
572  sll_int32, intent( in ) :: n_cells
573  sll_int32, intent( in ) :: degree
574  sll_real64, intent( in ) :: mass_line(0:degree)
575  sll_real64, intent( out ) :: eig_values_mass(n_cells)
576 
577  sll_int32 :: j,k
578  sll_real64 :: factor
579 
580 
581  factor = sll_p_twopi/real(n_cells,f64)
582  do k=0, n_cells-1
583  eig_values_mass(k+1) = mass_line(0)
584  do j=1,degree
585  eig_values_mass(k+1) = eig_values_mass(k+1)+ &
586  mass_line(j) * 2.0_f64 * cos( factor*real(k*j,f64))
587  end do
588  end do
589 
590  end subroutine sll_s_spline_fem_compute_mass_eig
591 
593  subroutine sll_s_spline_fem_multiply_mass ( n_cells, degree, mass, invec, outvec )
594  sll_int32, intent( in ) :: n_cells
595  sll_int32, intent( in ) :: degree
596  sll_real64, intent( in ) :: mass(degree+1)
597  sll_real64, intent( in ) :: invec(:)
598  sll_real64, intent( out ) :: outvec(:)
599 
600  !local variables
601  sll_int32 :: row, column, ind
602 
603  ind = 1
604  ! For the first degree rows we need to put the first part to the back due to periodic boundaries
605  do row = 1, degree
606  outvec(row) = mass(1)*invec(row)
607  do column = 1,row-1
608  outvec(row) = outvec(row) + mass(column+1)*(invec(row+column) + &
609  invec(row-column))
610  end do
611  do column = row,degree
612  outvec(row) = outvec(row) + mass(column+1)*(invec(row+column) + &
613  invec(row-column+n_cells))
614  end do
615  end do
616 
617  do row = degree+1, n_cells-degree
618  outvec(row) = mass(1)*invec(row)
619  do column = 1, degree
620  outvec(row) = outvec(row) + mass(column+1)*(invec(row+column) + &
621  invec(row-column))
622  end do
623  end do
624 
625  ! For the last degree rows, we need to put the second part to the front due to periodic boundaries
626  do row = n_cells-degree+1, n_cells
627  outvec(row) = mass(1)*invec(row)
628  do column = 1,n_cells-row
629  outvec(row) = outvec(row) + mass(column+1)*(invec(row+column) + &
630  invec(row-column))
631  end do
632  do column = n_cells-row+1,degree
633  outvec(row) = outvec(row) + mass(column+1)*(invec(row+column-n_cells) + &
634  invec(row-column))
635  end do
636  end do
637 
638 
639  end subroutine sll_s_spline_fem_multiply_mass
640 
641 
643  subroutine sll_s_spline_fem_multiply_massmixed ( n_cells, degree, mass, invec, outvec )
644  sll_int32, intent( in ) :: n_cells
645  sll_int32, intent( in ) :: degree
646  sll_real64, intent( in ) :: mass(degree*2)
647  sll_real64, intent( in ) :: invec(:)
648  sll_real64, intent( out ) :: outvec(:)
649 
650  !local variables
651  sll_int32 :: row, column, ind
652 
653  ind = 1
654  outvec = 0.0_f64
655  ! For the first degree rows we need to put the first part to the back due to periodic boundaries
656  do row = 1, degree-1
657  do column=-row+1,degree
658  outvec(row) = outvec(row) + mass(degree+column)*invec(row+column)
659  end do
660  do column = -degree+1,-row
661  outvec(row) = outvec(row) + mass(degree+column)*invec(row+column+n_cells)
662  end do
663  end do
664 
665  do row = degree, n_cells-degree
666  do column = -degree+1, degree
667  outvec(row) = outvec(row) + mass(degree+column)*invec(row+column)
668  end do
669  end do
670 
671  ! For the last degree rows, we need to put the second part to the front due to periodic boundaries
672  do row = n_cells-degree+1, n_cells
673  do column = -degree+1, n_cells-row
674  outvec(row) = outvec(row) + mass(degree+column)*invec(row+column)
675  end do
676  do column = n_cells-row+1, degree
677  outvec(row) = outvec(row) + mass(degree+column)*invec(row+column-n_cells)
678  end do
679  end do
680 
681 
683 
684 
689  subroutine sll_s_spline_fem_interpolation_eigenvalues(degree, ndofs, eig)
690  sll_int32, intent(in) :: degree
691  sll_int32, intent(in) :: ndofs
692  sll_real64, intent(out) :: eig(ndofs)
693 
694  ! local variables
695  sll_int32 :: k
696  sll_int32 :: p
697  sll_real64 :: spline_coeff(degree+1)
698  sll_real64 :: ni !1/n_dofs in double precision
699  ni=1.0_f64/real(ndofs,f64)
700 
701  if ( modulo( degree, 2) == 0 ) then
702  call sll_s_uniform_bsplines_eval_basis( degree, 0.5_f64, spline_coeff )
703  else
704  call sll_s_uniform_bsplines_eval_basis( degree, 0.0_f64, spline_coeff )
705  end if
706  print*, 'spline_coeffs', spline_coeff
707 
708  eig(1) = 1.0_f64
709 
710  do k=1,(ndofs+1)/2-1
711  ! real part
712  eig(k+1) = spline_coeff(degree+1)
713  do p=1,degree
714  eig(k+1) = eig(k+1) + cos(sll_p_twopi*real(k*p,f64)*ni)*spline_coeff(degree+1-p)
715  end do
716  ! imaginary part
717  eig(ndofs-k+1) = 0.0_f64
718  do p=1,degree
719  eig(ndofs-k+1) = eig(ndofs-k+1) - sin(sll_p_twopi*real(k*p,f64)*ni)*spline_coeff(degree+1-p)
720  end do
721  end do
722 
723  if ( modulo( ndofs, 2) == 0 ) then
724  eig(ndofs/2+1) = spline_coeff(degree+1)
725  do p=1,degree
726  eig(ndofs/2+1) = eig(ndofs/2+1) + cos(sll_p_twopi*real(p,f64))*spline_coeff(degree+1-p)
727  end do
728  end if
729 
731 
733  subroutine sll_s_multiply_g_1d( n_dofs, delta_x, in, out )
734  sll_int32, intent( in ) :: n_dofs
735  sll_real64, intent( in ) :: delta_x
736  sll_real64, intent( in ) :: in(:)
737  sll_real64, intent( out ) :: out(:)
738  !local variables
739  sll_int32 :: i
740 
741  ! treat Periodic point
742  out(1) = ( in(1) - in(n_dofs) )/delta_x
743  do i = 2, n_dofs
744  out(i) = ( in(i) - in(i-1) )/delta_x
745  end do
746 
747  end subroutine sll_s_multiply_g_1d
748 
749 
750 
752  subroutine sll_s_multiply_gt_1d( n_dofs, delta_x, in, out)
753  sll_int32, intent( in ) :: n_dofs
754  sll_real64, intent( in ) :: delta_x
755  sll_real64, intent( in ) :: in(:)
756  sll_real64, intent( out ) :: out(:)
757  !local variables
758  sll_int32 :: i
759 
760  do i= 1, n_dofs-1
761  out(i) = ( in(i) - in(i+1) )/delta_x
762  end do
763  ! treat Periodic point
764  out(n_dofs) = ( in(n_dofs) - in(1) )/delta_x
765 
766  end subroutine sll_s_multiply_gt_1d
767 
768 
769 
771  subroutine sll_s_multiply_g( n_dofs, delta_x, field_in, field_out )
772  sll_int32, intent( in ) :: n_dofs(3)
773  sll_real64, intent( in ) :: delta_x(3)
774  sll_real64, intent( in ) :: field_in(:)
775  sll_real64, intent( out ) :: field_out(:)
776 
777  sll_real64 :: coef
778  sll_int32 :: jump, jump_end
779  sll_int32 :: ind3d, ind1d
780  sll_int32 :: i,j,k
781 
782  coef = 1.0_f64/ delta_x(1)
783  jump = 1
784  jump_end = 1-n_dofs(1)
785 
786  ind3d = 0
787  do k=1,n_dofs(3)
788  do j=1,n_dofs(2)
789  ind3d = ind3d + 1
790  field_out(ind3d) = coef * ( field_in(ind3d) - field_in(ind3d-jump_end) )
791  do i=2,n_dofs(1)
792  ind3d = ind3d + 1
793  field_out(ind3d) = coef * ( field_in(ind3d) - field_in(ind3d-jump) )
794  end do
795  end do
796  end do
797 
798  coef = 1.0_f64/ delta_x(2)
799  jump = n_dofs(1)
800  jump_end = (1-n_dofs(2))*n_dofs(1)
801 
802  ind1d = 0
803  do k=1,n_dofs(3)
804  do i=1,n_dofs(1)
805  ind3d = ind3d + 1
806  ind1d = ind1d + 1
807  field_out(ind3d) = coef * ( field_in(ind1d) - field_in(ind1d-jump_end) )
808  end do
809  do j=2,n_dofs(2)
810  do i=1,n_dofs(1)
811  ind3d = ind3d + 1
812  ind1d = ind1d + 1
813  field_out(ind3d) = coef * ( field_in(ind1d) - field_in(ind1d-jump) )
814  end do
815  end do
816  end do
817 
818  coef = 1.0_f64/ delta_x(3)
819  jump = n_dofs(1)*n_dofs(2)
820  jump_end = (1-n_dofs(3))*n_dofs(1)*n_dofs(2)
821 
822  ind1d = 0
823  do j=1,n_dofs(2)
824  do i=1,n_dofs(1)
825  ind3d = ind3d + 1
826  ind1d = ind1d + 1
827  field_out(ind3d) = coef * ( field_in(ind1d) - field_in(ind1d-jump_end) )
828  end do
829  end do
830  do k=2,n_dofs(3)
831  do j=1,n_dofs(2)
832  do i=1,n_dofs(1)
833  ind3d = ind3d + 1
834  ind1d = ind1d + 1
835  field_out(ind3d) = coef * ( field_in(ind1d) - field_in(ind1d-jump) )
836  end do
837  end do
838  end do
839 
840 
841  end subroutine sll_s_multiply_g
842 
843 
845  subroutine sll_s_multiply_gt( n_dofs, delta_x, field_in, field_out )
846  sll_int32, intent( in ) :: n_dofs(3)
847  sll_real64, intent( in ) :: delta_x(3)
848  sll_real64, intent( in ) :: field_in(:)
849  sll_real64, intent( out ) :: field_out(:)
850 
851  sll_real64 :: coef
852  sll_int32 :: jump, jump_end
853  sll_int32 :: ind3d, ind1d
854  sll_int32 :: i,j,k
855 
856  coef = 1.0_f64/ delta_x(1)
857  jump = 1
858  jump_end = 1-n_dofs(1)
859 
860  ind3d = 0
861  do k=1,n_dofs(3)
862  do j=1,n_dofs(2)
863  do i=1,n_dofs(1)-1
864  ind3d = ind3d + 1
865  field_out(ind3d) = &
866  coef * ( field_in(ind3d) - field_in(ind3d+jump) )
867  end do
868  ind3d = ind3d + 1
869  field_out(ind3d) = coef * ( field_in(ind3d) - field_in(ind3d+jump_end) )
870  end do
871  end do
872 
873  coef = 1.0_f64/ delta_x(2)
874  jump = n_dofs(1)
875  jump_end = (1-n_dofs(2))*n_dofs(1)
876 
877  ind1d = 0
878  do k=1,n_dofs(3)
879  do j=1,n_dofs(2)-1
880  do i=1,n_dofs(1)
881  ind3d = ind3d + 1
882  ind1d = ind1d + 1
883 
884  field_out(ind1d) = field_out(ind1d) + &
885  coef * ( field_in(ind3d) - field_in(ind3d+jump) )
886  end do
887  end do
888  do i=1,n_dofs(1)
889  ind3d = ind3d + 1
890  ind1d = ind1d + 1
891 
892  field_out(ind1d) = field_out(ind1d) + &
893  coef * ( field_in(ind3d) - field_in(ind3d+jump_end) )
894  end do
895  end do
896 
897  coef = 1.0_f64/ delta_x(3)
898  jump = n_dofs(1)*n_dofs(2)
899  jump_end = (1-n_dofs(3))*n_dofs(1)*n_dofs(2)
900 
901  ind1d = 0
902  do k=1,n_dofs(3)-1
903  do j=1,n_dofs(2)
904  do i=1,n_dofs(1)
905  ind3d = ind3d + 1
906  ind1d = ind1d + 1
907 
908  field_out(ind1d) = field_out(ind1d) + &
909  coef * ( field_in(ind3d) - field_in(ind3d+jump) )
910  end do
911  end do
912  end do
913  do j=1,n_dofs(2)
914  do i=1,n_dofs(1)
915  ind3d = ind3d + 1
916  ind1d = ind1d + 1
917 
918  field_out(ind1d) = field_out(ind1d) + &
919  coef * ( field_in(ind3d) - field_in(ind3d+jump_end) )
920  end do
921  end do
922 
923  end subroutine sll_s_multiply_gt
924 
925 
927  subroutine sll_s_multiply_c( n_dofs, delta_x, field_in, field_out )
928  sll_int32, intent( in ) :: n_dofs(3)
929  sll_real64, intent( in ) :: delta_x(3)
930  sll_real64, intent( in ) :: field_in(:)
931  sll_real64, intent( out ) :: field_out(:)
932 
933  ! local variables
934  sll_real64 :: coef(2)
935  sll_int32 :: stride(2), jump(2), indp(2), n_total
936  sll_int32 :: i,j,k, ind3d, ind3d_1, ind3d_2
937 
938  n_total = product(n_dofs)
939 
940  ! TODO: Avoid the IF for periodic boundaries
941  ! First component
942  coef(1) = 1.0_f64/ delta_x(2)
943  coef(2) = -1.0_f64/ delta_x(3)
944 
945  stride(1) = n_dofs(1)
946  stride(2) = n_dofs(1)*n_dofs(2)
947 
948  jump(1) = n_total
949  jump(2) = 2*n_total
950 
951  ind3d = 0
952  do k=1,n_dofs(3)
953  if (k == 1) then
954  indp(2) = stride(2)*(n_dofs(3)-1)
955  else
956  indp(2) = - stride(2)
957  end if
958  do j=1,n_dofs(2)
959  if ( j==1 ) then
960  indp(1) = stride(1)*(n_dofs(2)-1)
961  else
962  indp(1) = - stride(1)
963  end if
964  do i=1,n_dofs(1)
965  ind3d = ind3d + 1
966 
967  ind3d_1 = ind3d +indp(1)+jump(2)
968  ind3d_2 = ind3d +indp(2)+jump(1)
969 
970  field_out(ind3d) = &
971  coef(1) * ( field_in( ind3d+jump(2) ) -&
972  field_in( ind3d_1 )) + &
973  coef(2) * ( field_in(ind3d+jump(1) ) - &
974  field_in( ind3d_2 ))
975  end do
976  end do
977  end do
978 
979  ! Second component
980  coef(1) = 1.0_f64/ delta_x(3)
981  coef(2) = -1.0_f64/ delta_x(1)
982 
983  stride(2) = 1
984  stride(1) = n_dofs(1)*n_dofs(2)
985 
986  jump(1) = n_total
987  jump(2) = -n_total
988 
989  do k=1,n_dofs(3)
990  if (k == 1) then
991  indp(1) = stride(1)*(n_dofs(3)-1)
992  else
993  indp(1) = - stride(1)
994  end if
995  do j=1,n_dofs(2)
996  do i=1,n_dofs(1)
997  if ( i==1 ) then
998  indp(2) = stride(2)*(n_dofs(1)-1)
999  else
1000  indp(2) = - stride(2)
1001  end if
1002  ind3d = ind3d + 1
1003 
1004  ind3d_1 = ind3d +indp(1)+jump(2)
1005  ind3d_2 = ind3d +indp(2)+jump(1)
1006 
1007  field_out(ind3d) = &
1008  coef(1) * ( field_in( ind3d+jump(2) ) -&
1009  field_in( ind3d_1 ) )+ &
1010  coef(2) * ( field_in(ind3d+jump(1) ) - &
1011  field_in( ind3d_2 ))
1012  end do
1013  end do
1014  end do
1015 
1016  ! Third component
1017  coef(1) = 1.0_f64/ delta_x(1)
1018  coef(2) = -1.0_f64/ delta_x(2)
1019 
1020  stride(1) = 1
1021  stride(2) = n_dofs(1)
1022 
1023  jump(1) = -2*n_total
1024  jump(2) = -n_total
1025 
1026  do k=1,n_dofs(3)
1027  do j=1,n_dofs(2)
1028  if (j == 1) then
1029  indp(2) = stride(2)*(n_dofs(2)-1)
1030  else
1031  indp(2) = - stride(2)
1032  end if
1033  do i=1,n_dofs(1)
1034  if ( i==1 ) then
1035  indp(1) = stride(1)*(n_dofs(1)-1)
1036  else
1037  indp(1) = - stride(1)
1038  end if
1039  ind3d = ind3d + 1
1040 
1041  ind3d_1 = ind3d +indp(1)+jump(2)
1042  ind3d_2 = ind3d +indp(2)+jump(1)
1043 
1044  field_out(ind3d) = &
1045  coef(1) * ( field_in( ind3d+jump(2) ) -&
1046  field_in( ind3d_1 ) )+ &
1047  coef(2) * ( field_in(ind3d+jump(1) ) - &
1048  field_in( ind3d_2 ) )
1049  end do
1050  end do
1051  end do
1052 
1053  end subroutine sll_s_multiply_c
1054 
1055 
1057  subroutine sll_s_multiply_ct( n_dofs, delta_x, field_in, field_out )
1058  sll_int32, intent( in ) :: n_dofs(3)
1059  sll_real64, intent( in ) :: delta_x(3)
1060  sll_real64, intent( in ) :: field_in(:)
1061  sll_real64, intent( out ) :: field_out(:)
1062 
1063  ! local variables
1064  sll_real64 :: coef(2)
1065  sll_int32 :: stride(2), jump(2), indp(2), n_total
1066  sll_int32 :: i,j,k, ind3d, ind3d_1, ind3d_2
1067 
1068  n_total = product(n_dofs)
1069  ! TODO: Avoid the IF for periodic boundaries
1070  ! First component
1071  coef(1) = -1.0_f64/ delta_x(2)
1072  coef(2) = 1.0_f64/ delta_x(3)
1073 
1074  stride(1) = n_dofs(1)
1075  stride(2) = n_dofs(1)*n_dofs(2)
1076 
1077  jump(1) = n_total
1078  jump(2) = 2*n_total
1079 
1080  ind3d = 0
1081  do k=1,n_dofs(3)
1082  if (k == n_dofs(3)) then
1083  indp(2) = -stride(2)*(n_dofs(3)-1)
1084  else
1085  indp(2) = stride(2)
1086  end if
1087  do j=1,n_dofs(2)
1088  if ( j== n_dofs(2)) then
1089  indp(1) = -stride(1)*(n_dofs(2)-1)
1090  else
1091  indp(1) = stride(1)
1092  end if
1093  do i=1,n_dofs(1)
1094  ind3d = ind3d + 1
1095 
1096  ind3d_1 = ind3d +indp(1)+jump(2)
1097  ind3d_2 = ind3d +indp(2)+jump(1)
1098 
1099  field_out(ind3d) = &
1100  coef(1) * ( field_in( ind3d+jump(2) ) -&
1101  field_in( ind3d_1 )) + &
1102  coef(2) * ( field_in(ind3d+jump(1) ) - &
1103  field_in( ind3d_2 ))
1104  end do
1105  end do
1106  end do
1107 
1108  ! Second component
1109  coef(1) = -1.0_f64/ delta_x(3)
1110  coef(2) = 1.0_f64/ delta_x(1)
1111 
1112  stride(2) = 1
1113  stride(1) = n_dofs(1)*n_dofs(2)
1114 
1115  jump(1) = n_total
1116  jump(2) = -n_total
1117 
1118  do k=1,n_dofs(3)
1119  if (k == n_dofs(3)) then
1120  indp(1) = -stride(1)*(n_dofs(3)-1)
1121  else
1122  indp(1) = stride(1)
1123  end if
1124  do j=1,n_dofs(2)
1125  do i=1,n_dofs(1)
1126  if ( i==n_dofs(1) ) then
1127  indp(2) = -stride(2)*(n_dofs(1)-1)
1128  else
1129  indp(2) = stride(2)
1130  end if
1131  ind3d = ind3d + 1
1132 
1133  ind3d_1 = ind3d +indp(1)+jump(2)
1134  ind3d_2 = ind3d +indp(2)+jump(1)
1135 
1136  field_out(ind3d) = &
1137  coef(1) * ( field_in( ind3d+jump(2) ) -&
1138  field_in( ind3d_1 ) )+ &
1139  coef(2) * ( field_in(ind3d+jump(1) ) - &
1140  field_in( ind3d_2 ))
1141  end do
1142  end do
1143  end do
1144 
1145  ! Third component
1146  coef(1) = -1.0_f64/ delta_x(1)
1147  coef(2) = 1.0_f64/ delta_x(2)
1148 
1149  stride(1) = 1
1150  stride(2) = n_dofs(1)
1151 
1152  jump(1) = -2*n_total
1153  jump(2) = -n_total
1154 
1155  do k=1,n_dofs(3)
1156  do j=1,n_dofs(2)
1157  if (j == n_dofs(2)) then
1158  indp(2) = -stride(2)*(n_dofs(2)-1)
1159  else
1160  indp(2) = stride(2)
1161  end if
1162  do i=1,n_dofs(1)
1163  if ( i==n_dofs(1) ) then
1164  indp(1) = -stride(1)*(n_dofs(1)-1)
1165  else
1166  indp(1) = stride(1)
1167  end if
1168  ind3d = ind3d + 1
1169 
1170  ind3d_1 = ind3d +indp(1)+jump(2)
1171  ind3d_2 = ind3d +indp(2)+jump(1)
1172 
1173  field_out(ind3d) = &
1174  coef(1) * ( field_in( ind3d+jump(2) ) -&
1175  field_in( ind3d_1 ) )+ &
1176  coef(2) * ( field_in(ind3d+jump(1) ) - &
1177  field_in( ind3d_2 ) )
1178  end do
1179  end do
1180  end do
1181 
1182  end subroutine sll_s_multiply_ct
1183 
1184 
1185 end module sll_m_spline_fem_utilities
Fortran module where set some physical and mathematical constants.
real(kind=f64), parameter, public sll_p_twopi
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.
Utilites for Maxwell solver's with spline finite elements.
subroutine, public sll_s_multiply_g(n_dofs, delta_x, field_in, field_out)
Multiply by dicrete gradient matrix (3d version)
subroutine, public sll_s_multiply_g_1d(n_dofs, delta_x, in, out)
Multiplication of the input vector in by the derivative matrix G.
subroutine, public sll_s_spline_fem_multiply_massmixed(n_cells, degree, mass, invec, outvec)
Multiplication of the mix mass matrix given by a mass line mass.
subroutine, public sll_s_spline_fem_multiply_mass(n_cells, degree, mass, invec, outvec)
Multiply the vector invec with the spline FEM mass matrix with mass line mass.
subroutine, public sll_s_spline_fem_mass_line_boundary_full(deg, profile, spline, row, n_cells, mass_line)
Function computing the boundary part for a mass matrix with clamped splines of degree (full version w...
subroutine, public sll_s_multiply_c(n_dofs, delta_x, field_in, field_out)
Multiply by discrete curl matrix.
subroutine, public sll_s_multiply_ct(n_dofs, delta_x, field_in, field_out)
Multiply by transpose of discrete curl matrix.
subroutine, public sll_s_spline_fem_mixedmass_line_full(deg1, deg2, profile, mass_line, cell, n_cells)
Helper function to find line of mass matrix ( N_i^p N_j^{p-1}))
subroutine, public sll_s_multiply_gt(n_dofs, delta_x, field_in, field_out)
Multiply by transpose of dicrete gradient matrix (3d version)
subroutine, public sll_s_multiply_gt_1d(n_dofs, delta_x, in, out)
Multiplication of the input vector in by the transposed derivative matrix G^T
subroutine, public sll_s_spline_fem_mass_line_boundary(degree, spline, mass_line)
Function computing the boundary part for a mass matrix with clamped splines of degree.
subroutine, public sll_s_spline_fem_interpolation_eigenvalues(degree, ndofs, eig)
Compute the eigenvalues of the interpolation matrix for splines of degree degree (with first grid poi...
subroutine, public sll_s_spline_fem_mixedmass_line_boundary(deg1, deg2, profile, spline1, spline2, row, n_cells, mass_line)
Function computing the boundary part for a mass matrix with clamped splines of degree (full version w...
subroutine, public sll_s_spline_fem_mixedmass_line(deg, mass_line)
Helper function to find line of mass matrix ( N_i^p N_j^{p-1}))
subroutine, public sll_s_spline_fem_mass_line(degree, mass_line)
Computes the mass line for a mass matrix with degree splines.
subroutine, public sll_s_spline_fem_mass_line_full(deg, profile, mass_line, row, n_cells)
Helper function to find line of mass matrix (full version without symmetry part)
subroutine, public sll_s_spline_fem_compute_mass_eig(n_cells, degree, mass_line, eig_values_mass)
Compute eigenvalues of mass matrix with given line mass_line.
Splines in pp form.
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.
Module to select the kind parameter.
    Report Typos and Errors