4 #include "sll_working_precision.h"
7 sll_s_uniform_bsplines_eval_basis
32 sll_int32 :: n_dofs(3)
33 sll_int32 :: degree(3)
34 sll_real64 :: delta_x(3)
36 sll_real64,
allocatable :: eig_values_dtm1d_1(:)
37 sll_real64,
allocatable :: eig_values_dtm1d_2(:)
38 sll_real64,
allocatable :: eig_values_dtm1d_3(:)
39 sll_comp64,
allocatable :: eig_values_d1(:)
40 sll_comp64,
allocatable :: eig_values_d2(:)
41 sll_comp64,
allocatable :: eig_values_d3(:)
42 sll_real64,
allocatable :: eig_values_mass_0_1(:)
43 sll_real64,
allocatable :: eig_values_mass_0_2(:)
44 sll_real64,
allocatable :: eig_values_mass_0_3(:)
54 sll_comp64,
allocatable :: array1d_x(:)
55 sll_comp64,
allocatable :: array1d_y(:)
56 sll_comp64,
allocatable :: array1d_z(:)
57 sll_comp64,
allocatable :: scratch(:,:,:)
58 sll_comp64,
allocatable :: scratchx(:,:,:)
59 sll_comp64,
allocatable :: scratchy(:,:,:)
77 sll_real64,
intent(in) :: x(3)
85 sll_real64,
intent(in) :: rho(:)
86 sll_real64,
intent(out) :: efield(:)
88 sll_int32 :: n_dofs(3), ntotal
89 sll_int32 :: i,j,k, ind
90 sll_real64 :: factor1jk, factor2jk, eig_val
93 ntotal = product(n_dofs)
101 self%array1d_x(i) = cmplx( rho(ind), 0_f64, kind=f64)
105 self%scratch(i,j,k) = self%array1d_x(i)
112 self%array1d_y(j) = self%scratch(i,j,k)
116 self%scratch(i,j,k) = self%array1d_y(j)
123 self%array1d_z(k) = self%scratch(i,j,k)
127 self%scratch(i,j,k) = self%array1d_z(k)
136 factor1jk = self%eig_values_dtm1d_2(j)*self%eig_values_mass_0_3(k) + &
137 self%eig_values_dtm1d_3(k)*self%eig_values_mass_0_2(j)
138 factor2jk = self%eig_values_mass_0_2(j) * self%eig_values_mass_0_3(k)
140 if ( i == 1 .and. j==1 .and. k==1 )
then
141 self%scratch(i,j,k) = cmplx(0.0_f64, 0.0_f64, f64)
143 eig_val = factor2jk * self%eig_values_dtm1d_1(i) + &
144 factor1jk * self%eig_values_mass_0_1(i)
145 self%scratch(i,j,k) = self%scratch(i,j,k) / cmplx(eig_val, 0.0_f64 , f64)
148 self%scratchx(i,j,k) = -self%scratch(i,j,k)* self%eig_values_d1(i)
149 self%scratchy(i,j,k) = -self%scratch(i,j,k)* self%eig_values_d2(j)
150 self%scratch(i,j,k) = -self%scratch(i,j,k)* self%eig_values_d3(k)
160 call ifft3d( self, self%scratchx, efield(1:ntotal) )
161 call ifft3d( self, self%scratchy, efield(1+ntotal:2*ntotal) )
162 call ifft3d( self, self%scratch, efield(1+2*ntotal:3*ntotal) )
169 sll_real64,
intent(in) :: rho(:)
170 sll_real64,
intent(out) :: phi(:)
172 sll_int32 :: n_dofs(3)
173 sll_int32 :: i,j,k, ind
174 sll_real64 :: factor1jk, factor2jk, eig_val
185 self%array1d_x(i) = cmplx( rho(ind), 0_f64, kind=f64)
189 self%scratch(i,j,k) = self%array1d_x(i)
196 self%array1d_y(j) = self%scratch(i,j,k)
200 self%scratch(i,j,k) = self%array1d_y(j)
207 self%array1d_z(k) = self%scratch(i,j,k)
211 self%scratch(i,j,k) = self%array1d_z(k)
220 factor1jk = self%eig_values_dtm1d_2(j)*self%eig_values_mass_0_3(k) + &
221 self%eig_values_dtm1d_3(k)*self%eig_values_mass_0_2(j)
222 factor2jk = self%eig_values_mass_0_2(j) * self%eig_values_mass_0_3(k)
224 if ( i == 1 .and. j==1 .and. k==1 )
then
225 self%scratch(i,j,k) = cmplx(0.0_f64, 0.0_f64, f64)
227 eig_val = factor2jk * self%eig_values_dtm1d_1(i) + &
228 factor1jk * self%eig_values_mass_0_1(i)
229 self%scratch(i,j,k) = self%scratch(i,j,k) / cmplx(eig_val, 0.0_f64, f64)
235 call ifft3d( self, self%scratch, phi )
250 subroutine init_fft( self, n_dofs, degree, delta_x)
252 sll_int32,
intent( in ) :: n_dofs(3)
253 sll_int32,
intent( in ) :: degree(3)
254 sll_real64,
intent( in ) :: delta_x(3)
257 sll_real64 :: mass_line0_1(degree(1)+1)
258 sll_real64 :: mass_line1_1(degree(1))
259 sll_real64 :: mass_line0_2(degree(2)+1)
260 sll_real64 :: mass_line1_2(degree(2))
261 sll_real64 :: mass_line0_3(degree(3)+1)
262 sll_real64 :: mass_line1_3(degree(3))
263 sll_real64 :: eig_values_mass_1_1(n_dofs(1))
264 sll_real64 :: eig_values_mass_1_2(n_dofs(2))
265 sll_real64 :: eig_values_mass_1_3(n_dofs(3))
271 allocate(self%array1d_x(n_dofs(1)))
272 allocate(self%array1d_y(n_dofs(2)))
273 allocate(self%array1d_z(n_dofs(3)))
274 allocate(self%scratch(n_dofs(1), n_dofs(2), n_dofs(3)))
275 allocate(self%scratchx(n_dofs(1), n_dofs(2), n_dofs(3)))
276 allocate(self%scratchy(n_dofs(1), n_dofs(2), n_dofs(3)))
298 allocate( self%eig_values_mass_0_1(n_dofs(1)) )
302 allocate( self%eig_values_mass_0_2(n_dofs(2)) )
306 allocate( self%eig_values_mass_0_3(n_dofs(3)) )
311 allocate( self%eig_values_d1(n_dofs(1)) )
312 allocate( self%eig_values_dtm1d_1(n_dofs(1)) )
314 self%eig_values_d1(1) = cmplx(0.0_f64, 0.0_f64, f64)
315 self%eig_values_dtm1d_1(1) = 0.0_f64
317 angle =
sll_p_twopi*real(j-1,f64)/real(n_dofs(1), f64)
319 self%eig_values_d1(j) = cmplx((1.0_f64 - cos(angle))/delta_x(1),sin(angle)/delta_x(1), f64 )
320 self%eig_values_dtm1d_1(j) = 2.0_f64/delta_x(1)**2*(1.0_f64-cos(angle))* eig_values_mass_1_1(j)
324 allocate( self%eig_values_d2(n_dofs(2)) )
325 allocate( self%eig_values_dtm1d_2(n_dofs(2)) )
327 self%eig_values_d2(1) = cmplx(0.0_f64, 0.0_f64, f64)
328 self%eig_values_dtm1d_2(1) = 0.0_f64
330 angle =
sll_p_twopi*real(j-1,f64)/real(n_dofs(2), f64)
332 self%eig_values_d2(j) = cmplx((1.0_f64 - cos(angle))/delta_x(2),sin(angle)/delta_x(2), f64 )
333 self%eig_values_dtm1d_2(j) = 2.0_f64/delta_x(2)**2*(1.0_f64-cos(angle))* eig_values_mass_1_2(j)
337 allocate( self%eig_values_d3(n_dofs(3)) )
338 allocate( self%eig_values_dtm1d_3(n_dofs(3)) )
341 self%eig_values_d3(1) = cmplx(0.0_f64, 0.0_f64, f64)
342 self%eig_values_dtm1d_3(1) = 0.0_f64
344 angle =
sll_p_twopi*real(j-1,f64)/real(n_dofs(3), f64)
346 self%eig_values_d3(j) = cmplx((1.0_f64 - cos(angle))/delta_x(3),sin(angle)/delta_x(3), f64 )
347 self%eig_values_dtm1d_3(j) = 2.0_f64/delta_x(3)**2*(1.0_f64-cos(angle))* eig_values_mass_1_3(j)
352 self%delta_x = delta_x
363 sll_real64,
intent(out) :: coefs_dofs(:)
366 sll_int32 :: i1, i2, i3,j1, j2, j3, k1, k2, k3, k, counter
368 sll_real64 :: xw_gauss_d1(2,self%degree(1)+1)
369 sll_real64 :: xw_gauss_d2(2,self%degree(2)+1)
370 sll_real64 :: xw_gauss_d3(2,self%degree(3)+1)
371 sll_real64 :: bspl_d1(self%degree(1)+1, self%degree(1)+1)
372 sll_real64 :: bspl_d2(self%degree(2)+1, self%degree(2)+1)
373 sll_real64 :: bspl_d3(self%degree(3)+1, self%degree(3)+1)
376 volume = product(self%delta_x)
382 do k=1,self%degree(1)+1
383 call sll_s_uniform_bsplines_eval_basis(self%degree(1),xw_gauss_d1(1,k), bspl_d1(k,:))
388 do k=1,self%degree(2)+1
389 call sll_s_uniform_bsplines_eval_basis(self%degree(2),xw_gauss_d2(1,k), bspl_d2(k,:))
394 do k=1,self%degree(3)+1
395 call sll_s_uniform_bsplines_eval_basis(self%degree(3),xw_gauss_d3(1,k), bspl_d3(k,:))
402 do i3 = 1, self%n_dofs(3)
403 do i2 = 1, self%n_dofs(2)
404 do i1 = 1, self%n_dofs(1)
407 do j1 = 1, self%degree(1)+1
408 do j2 = 1, self%degree(2)+1
409 do j3 = 1, self%degree(3)+1
411 do k1=1, self%degree(1)+1
412 do k2=1, self%degree(2)+1
413 do k3=1, self%degree(3)+1
414 coef = coef + xw_gauss_d1(2,k1)* xw_gauss_d2(2,k2)* &
416 func([self%delta_x(1)*(xw_gauss_d1(1,k1) + real(i1 + j1 - 2,f64)), self%delta_x(2)*(xw_gauss_d2(1,k2) + real(i2 + j2 - 2,f64)), self%delta_x(3)*(xw_gauss_d3(1,k3) + real(i3 + j3 - 2,f64))] ) * &
417 bspl_d1(k1,self%degree(1)+2-j1)*&
418 bspl_d2(k2,self%degree(2)+2-j2)*&
419 bspl_d3(k3,self%degree(3)+2-j3)
428 coefs_dofs(counter) = coef*volume
441 sll_comp64,
intent( inout ) :: inval(:,:,:)
442 sll_real64,
intent( out ) :: outval(:)
444 sll_int32 :: i,j,k,ind
445 sll_int32 :: n_dofs(3)
453 self%array1d_z(k) = inval(i,j,k)
457 inval(i,j,k) = self%array1d_z(k)
465 self%array1d_y(j) = inval(i,j,k)
469 inval(i,j,k) = self%array1d_y(j)
478 self%array1d_x(i) = inval(i,j,k)
484 outval(ind) = real( self%array1d_x(i), kind=f64 )
Fortran module where set some physical and mathematical constants.
real(kind=f64), parameter, public sll_p_twopi
subroutine, public sll_s_fft_free(plan)
Delete a plan.
integer, parameter, public sll_p_fft_forward
Flag to specify forward FFT (negative sign) [value -1].
subroutine, public sll_s_fft_exec_c2c_1d(plan, array_in, array_out)
Compute fast Fourier transform in complex to complex mode.
subroutine, public sll_s_fft_init_c2c_1d(plan, nx, array_in, array_out, direction, normalized, aligned, optimization)
Create new 1d complex to complex plan.
integer, parameter, public sll_p_fft_backward
Flag to specify backward FFT (positive sign) [value 1].
Gauss-Legendre integration.
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.
subroutine compute_phi_from_rho_fft(self, rho, phi)
subroutine free_fft(self)
subroutine init_fft(self, n_dofs, degree, delta_x)
subroutine compute_rhs_from_function_fft(self, func, coefs_dofs)
Compute the FEM right-hand-side for a given function f and periodic splines of given degree Its compo...
subroutine ifft3d(self, inval, outval)
Helper function for 3d fft.
subroutine compute_e_from_rho_fft(self, rho, efield)
Utilites for Maxwell solver's with spline finite elements.
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_compute_mass_eig(n_cells, degree, mass_line, eig_values_mass)
Compute eigenvalues of mass matrix with given line mass_line.
Module to select the kind parameter.
Type for FFT plan in SeLaLib.