18 #include "sll_assert.h"
19 #include "sll_memory.h"
20 #include "sll_working_precision.h"
23 sll_s_uniform_bsplines_eval_basis
52 sll_real64 :: delta_x(2)
54 sll_int32 :: n_dofs(2)
58 sll_real64,
allocatable :: wsave(:)
59 sll_real64,
allocatable :: work(:)
60 sll_real64,
allocatable :: work2d(:,:)
61 sll_real64,
allocatable :: work_d1(:)
62 sll_real64,
allocatable :: work_d2_in(:)
63 sll_real64,
allocatable :: work_d2_out(:)
64 sll_real64,
allocatable :: work2(:)
65 sll_real64,
allocatable :: mass_line_0(:,:)
66 sll_real64,
allocatable :: mass_line_1(:,:)
67 sll_real64,
allocatable :: mass_line_mixed(:,:)
113 sll_real64,
intent(in) :: x(2)
121 sll_real64,
intent(in) :: efield(:)
122 sll_real64,
intent(inout) :: rho(:)
139 sll_real64,
intent(in) :: delta_t
140 sll_real64,
intent(in) :: field_in(:)
141 sll_real64,
intent(inout) :: field_out(:)
144 sll_int32 :: comp, istart, iend
151 istart = 1+(comp-1)*self%n_total
152 iend = comp*self%n_total
153 call self%inverse_mass_1(comp)%solve( self%work2(istart:iend), self%work(istart:iend) )
157 field_out = field_out + coef*self%work
165 sll_real64,
intent(in) :: delta_t
166 sll_real64,
intent(in) :: field_in(:)
167 sll_real64,
intent(inout) :: field_out(:)
171 field_out = field_out - delta_t * self%work
180 sll_real64,
dimension(:),
intent(in) :: current
181 sll_int32,
intent(in) :: component
182 sll_real64,
dimension(:),
intent(inout) :: e
184 call self%inverse_mass_1(component)%solve( current, self%work(1:self%n_total) )
186 e = e - self%work(1:self%n_total)
196 sll_real64,
dimension(:),
intent(in) :: rho
197 sll_real64,
dimension(:),
intent(out) :: e
200 call self%poisson_fft%compute_e_from_rho( rho, e )
209 sll_int32 :: component
211 sll_real64,
intent(out) :: coefs_dofs(:)
214 sll_int32 :: i1, i2, j1, j2, k1, k2, k, counter
215 sll_int32 :: degree(2)
217 sll_real64,
allocatable :: xw_gauss_d1(:,:), xw_gauss_d2(:,:)
218 sll_real64,
allocatable :: bspl_d1(:,:), bspl_d2(:,:)
221 if ( form == 0 )
then
222 degree = self%s_deg_0
223 elseif (form == 1 )
then
224 degree = self%s_deg_0
225 if (component<3)
then
226 degree(component) = self%s_deg_1
228 elseif( form == 2)
then
229 degree = self%s_deg_1
230 if (component<3)
then
231 degree(component) = self%s_deg_0
233 elseif( form == 3)
then
234 degree = self%s_deg_1
236 print*,
'Wrong form.'
241 allocate(xw_gauss_d1(2,degree(1)+1))
242 allocate(bspl_d1(degree(1)+1, degree(1)+1))
246 call sll_s_uniform_bsplines_eval_basis(degree(1),xw_gauss_d1(1,k), bspl_d1(k,:))
249 allocate(xw_gauss_d2(2,degree(2)+1))
250 allocate(bspl_d2(degree(2)+1, degree(2)+1))
254 call sll_s_uniform_bsplines_eval_basis(degree(2),xw_gauss_d2(1,k), bspl_d2(k,:))
260 do i2 = 1, self%n_dofs(2)
261 do i1 = 1, self%n_dofs(1)
264 do j1 = 1, degree(1)+1
265 do j2 = 1, degree(2)+1
271 coef = coef + xw_gauss_d1(2,k1)* xw_gauss_d2(2,k2)* &
272 func([self%delta_x(1)*(xw_gauss_d1(1,k1) + real(i1 + j1 - 2, f64)), &
273 self%delta_x(2)*(xw_gauss_d2(1,k2) + real(i2 + j2 - 2, f64))] ) * &
274 bspl_d1(k1,degree(1)+2-j1)*&
275 bspl_d2(k2,degree(2)+2-j2)
284 coefs_dofs(counter) = coef*self%volume
297 sll_int32 :: component
299 sll_real64,
intent(out) :: coefs_dofs(:)
310 call self%inverse_mass_1(component)%solve( self%work(1:self%n_total), coefs_dofs )
312 call self%inverse_mass_2(component)%solve( self%work(1:self%n_total), coefs_dofs )
314 print*,
'L2projection for', form,
'-form not implemented.'
325 sll_real64 :: coefs_dofs(:)
326 sll_int32 :: component
339 sll_real64 :: coefs1_dofs(:)
340 sll_real64 :: coefs2_dofs(:)
341 sll_int32 :: component
346 if ( form == 0 )
then
348 self%mass_line_0(:,2), &
349 coefs2_dofs, self%work(1:self%n_total) )
350 elseif (form == 1 )
then
351 select case(component)
354 self%mass_line_0(:,2), &
355 coefs2_dofs, self%work(1:self%n_total) )
358 self%mass_line_1(:,2), &
359 coefs2_dofs, self%work(1:self%n_total) )
362 self%mass_line_0(:,2), &
363 coefs2_dofs, self%work(1:self%n_total) )
365 print*,
'wrong component.'
367 elseif( form == 2)
then
368 select case(component)
371 self%mass_line_1(:,2), &
372 coefs2_dofs, self%work(1:self%n_total) )
375 self%mass_line_0(:,2), &
376 coefs2_dofs, self%work(1:self%n_total) )
379 self%mass_line_1(:,2), &
380 coefs2_dofs, self%work(1:self%n_total) )
382 print*,
'wrong component.'
384 elseif( form == 3)
then
386 self%mass_line_1(:,2), &
387 coefs2_dofs, self%work(1:self%n_total) )
389 print*,
'Wrong form.'
392 r = sum(coefs1_dofs*self%work(1:self%n_total))
400 sll_real64,
intent(in) :: domain(2,2)
401 sll_int32,
intent(in) :: n_dofs(2)
403 sll_int32,
intent(in) :: s_deg_0
407 sll_real64 :: mass_line_0(s_deg_0+1), mass_line_1(s_deg_0), mass_line_mixed(s_deg_0*2)
408 sll_real64,
allocatable :: eig_values_mass_0_1(:)
409 sll_real64,
allocatable :: eig_values_mass_0_2(:)
410 sll_real64,
allocatable :: eig_values_mass_1_1(:)
411 sll_real64,
allocatable :: eig_values_mass_1_2(:)
414 self%n_total = product(n_dofs)
416 self%Lx = domain(:,2) - domain(:,1)
417 self%delta_x = self%Lx /real( n_dofs, f64 )
418 self%s_deg_0 = s_deg_0
419 self%s_deg_1 = s_deg_0 - 1
421 self%volume = product(self%delta_x)
424 allocate( self%work2d(n_dofs(1), n_dofs(2)) )
425 allocate( self%work(self%n_total*3) )
426 allocate( self%work2(self%n_total*3) )
427 allocate( self%work_d1( n_dofs(1) ) )
428 allocate( self%work_d2_in( n_dofs(2) ) )
429 allocate( self%work_d2_out( n_dofs(2) ) )
435 allocate( self%mass_line_0(s_deg_0+1,2) )
436 allocate( self%mass_line_1(s_deg_0,2) )
437 allocate( self%mass_line_mixed(2*s_deg_0,2) )
445 self%mass_line_0(:,j) = self%delta_x(j) * mass_line_0
446 self%mass_line_1(:,j) = self%delta_x(j) * mass_line_1
447 self%mass_line_mixed(:,j) = self%delta_x(j) * mass_line_mixed
450 allocate( eig_values_mass_0_1( n_dofs(1) ) )
451 allocate( eig_values_mass_0_2( n_dofs(2) ) )
452 allocate( eig_values_mass_1_1( n_dofs(1) ) )
453 allocate( eig_values_mass_1_2( n_dofs(2) ) )
455 eig_values_mass_0_1 )
457 eig_values_mass_0_2 )
459 eig_values_mass_1_1 )
461 eig_values_mass_1_2 )
463 call self%inverse_mass_1(1)%create( n_dofs, eig_values_mass_1_1, eig_values_mass_0_2 )
464 call self%inverse_mass_1(2)%create( n_dofs, eig_values_mass_0_1, eig_values_mass_1_2 )
465 call self%inverse_mass_1(3)%create( n_dofs, eig_values_mass_0_1, eig_values_mass_0_2 )
467 call self%inverse_mass_2(1)%create( n_dofs, eig_values_mass_0_1, eig_values_mass_1_2 )
468 call self%inverse_mass_2(2)%create( n_dofs, eig_values_mass_1_1, eig_values_mass_0_2 )
469 call self%inverse_mass_2(3)%create( n_dofs, eig_values_mass_1_1, eig_values_mass_1_2 )
473 call self%poisson_fft%init( self%n_dofs, self%s_deg_0, self%delta_x )
483 deallocate(self%work)
492 sll_real64,
intent(in) :: field_in(:)
493 sll_real64,
intent(inout) :: field_out(:)
495 sll_real64 :: coef(2)
496 sll_int32 :: stride(2), jump(2), indp(2)
497 sll_int32 :: i,j, ind2d, ind2d_1, ind2d_2
502 coef(1) = 1.0_f64/ self%delta_x(2)
505 stride(1) = self%n_dofs(1)
506 stride(2) = self%n_dofs(1)*self%n_dofs(2)
509 jump(2) = 2*self%n_total
513 do j=1,self%n_dofs(2)
515 indp(1) = stride(1)*(self%n_dofs(2)-1)
517 indp(1) = - stride(1)
519 do i=1,self%n_dofs(1)
522 ind2d_1 = ind2d +indp(1)+jump(2)
524 coef(1) * ( field_in( ind2d+jump(2) ) -&
533 coef(2) = -1.0_f64/ self%delta_x(1)
538 jump(1) = self%n_total
542 do j=1,self%n_dofs(2)
543 do i=1,self%n_dofs(1)
545 indp(2) = stride(2)*(self%n_dofs(1)-1)
547 indp(2) = - stride(2)
551 ind2d_2 = ind2d +indp(2)+jump(1)
554 coef(2) * ( field_in(ind2d+jump(1) ) - &
561 coef(1) = 1.0_f64/ self%delta_x(1)
562 coef(2) = -1.0_f64/ self%delta_x(2)
565 stride(2) = self%n_dofs(1)
567 jump(1) = -2*self%n_total
568 jump(2) = -self%n_total
571 do j=1,self%n_dofs(2)
573 indp(2) = stride(2)*(self%n_dofs(2)-1)
575 indp(2) = - stride(2)
577 do i=1,self%n_dofs(1)
579 indp(1) = stride(1)*(self%n_dofs(1)-1)
581 indp(1) = - stride(1)
585 ind2d_1 = ind2d +indp(1)+jump(2)
586 ind2d_2 = ind2d +indp(2)+jump(1)
589 coef(1) * ( field_in( ind2d+jump(2) ) -&
590 field_in( ind2d_1 ) )+ &
591 coef(2) * ( field_in(ind2d+jump(1) ) - &
592 field_in( ind2d_2 ) )
603 sll_real64,
intent(in) :: field_in(:)
604 sll_real64,
intent(inout) :: field_out(:)
606 sll_real64 :: coef(2)
607 sll_int32 :: stride(2), jump(2), indp(2)
608 sll_int32 :: i,j, ind2d, ind2d_1, ind2d_2
613 coef(1) = -1.0_f64/ self%delta_x(2)
616 stride(1) = self%n_dofs(1)
620 jump(2) = 2*self%n_total
624 do j=1,self%n_dofs(2)
625 if ( j== self%n_dofs(2))
then
626 indp(1) = -stride(1)*(self%n_dofs(2)-1)
630 do i=1,self%n_dofs(1)
633 ind2d_1 = ind2d +indp(1)+jump(2)
636 coef(1) * ( field_in( ind2d+jump(2) ) -&
645 coef(2) = 1.0_f64/ self%delta_x(1)
650 jump(1) = self%n_total
654 do j=1,self%n_dofs(2)
655 do i=1,self%n_dofs(1)
656 if ( i==self%n_dofs(1) )
then
657 indp(2) = -stride(2)*(self%n_dofs(1)-1)
662 ind2d_2 = ind2d +indp(2)+jump(1)
665 coef(2) * ( field_in(ind2d+jump(1) ) - &
672 coef(1) = -1.0_f64/ self%delta_x(1)
673 coef(2) = 1.0_f64/ self%delta_x(2)
676 stride(2) = self%n_dofs(1)
678 jump(1) = -2*self%n_total
679 jump(2) = -self%n_total
682 do j=1,self%n_dofs(2)
683 if (j == self%n_dofs(2))
then
684 indp(2) = -stride(2)*(self%n_dofs(2)-1)
688 do i=1,self%n_dofs(1)
689 if ( i==self%n_dofs(1) )
then
690 indp(1) = -stride(1)*(self%n_dofs(1)-1)
696 ind2d_1 = ind2d +indp(1)+jump(2)
697 ind2d_2 = ind2d +indp(2)+jump(1)
700 coef(1) * ( field_in( ind2d+jump(2) ) -&
701 field_in( ind2d_1 ) )+ &
702 coef(2) * ( field_in(ind2d+jump(1) ) - &
703 field_in( ind2d_2 ) )
714 sll_real64,
intent(in) :: field_in(:)
715 sll_real64,
intent(inout) :: field_out(:)
718 sll_int32 :: jump, jump_end
719 sll_int32 :: ind2d, ind2d_1
723 coef = 1.0_f64/ self%delta_x(1)
725 jump_end = 1-self%n_dofs(1)
729 do j=1,self%n_dofs(2)
730 do i=1,self%n_dofs(1)-1
734 coef * ( field_in(ind2d) - field_in(ind2d+jump) )
738 field_out(ind2d) = coef * ( field_in(ind2d) - field_in(ind2d+jump_end) )
741 coef = 1.0_f64/ self%delta_x(2)
742 jump = self%n_dofs(1)
743 jump_end = (1-self%n_dofs(2))*self%n_dofs(1)
746 do j=1,self%n_dofs(2)-1
747 do i=1,self%n_dofs(1)
749 ind2d_1 = ind2d_1 + 1
751 field_out(ind2d_1) = field_out(ind2d_1) + &
752 coef * ( field_in(ind2d) - field_in(ind2d+jump) )
755 do i=1,self%n_dofs(1)
757 ind2d_1 = ind2d_1 + 1
759 field_out(ind2d_1) = field_out(ind2d_1) + &
760 coef * ( field_in(ind2d) - field_in(ind2d+jump_end) )
770 sll_real64,
intent(in) :: coefs_in(:)
771 sll_real64,
intent(out) :: coefs_out(:)
773 sll_int32:: iend, istart
778 self%mass_line_0(:,2), &
779 coefs_in(istart:iend), coefs_out(istart:iend) )
781 iend = iend + self%n_total
783 self%mass_line_1(:,2), &
784 coefs_in(istart:iend), coefs_out(istart:iend) )
786 iend = iend + self%n_total
788 self%mass_line_0(:,2), &
789 coefs_in(istart:iend), coefs_out(istart:iend) )
797 sll_real64,
intent(in) :: coefs_in(:)
798 sll_real64,
intent(out) :: coefs_out(:)
800 sll_int32:: iend, istart
805 self%mass_line_1(:,2), &
806 coefs_in(istart:iend), coefs_out(istart:iend) )
808 iend = iend + self%n_total
810 self%mass_line_0(:,2), &
811 coefs_in(istart:iend), coefs_out(istart:iend) )
813 iend = iend + self%n_total
815 self%mass_line_1(:,2), &
816 coefs_in(istart:iend), coefs_out(istart:iend) )
826 sll_real64,
intent(in) :: mass_line_1(:)
827 sll_real64,
intent(in) :: mass_line_2(:)
828 sll_real64,
intent(in) :: coefs_in(:)
829 sll_real64,
intent(out) :: coefs_out(:)
832 sll_int32 :: i,j,istart,iend
835 deg(1) =
size(mass_line_1)-1
836 deg(2) =
size(mass_line_2)-1
839 iend = self%n_dofs(1)
840 do j=1,self%n_dofs(2)
842 mass_line_1, coefs_in(istart:iend), self%work_d1 )
843 self%work2d(:,j) = self%work_d1
845 iend = iend + self%n_dofs(1)
849 do i =1,self%n_dofs(1)
850 self%work_d2_in = self%work2d(i,:)
852 mass_line_2, self%work_d2_in, self%work_d2_out )
853 do j=1,self%n_dofs(2)
854 coefs_out(istart+(j-1)*self%n_dofs(1)) = self%work_d2_out(j)
865 sll_int32,
intent( in ) :: deg(2)
866 sll_real64,
intent(in) :: coefs_in(:)
867 sll_real64,
intent(out) :: coefs_out(:)
870 sll_int32 :: i,j,istart,iend
873 iend = self%n_dofs(1)
874 do j=1,self%n_dofs(2)
875 select case ( deg(1) )
878 self%mass_line_0(:,1), coefs_in(istart:iend), self%work_d1 )
881 self%mass_line_1(:,1), coefs_in(istart:iend), self%work_d1 )
884 self%mass_line_mixed(:,1), coefs_in(istart:iend), self%work_d1 )
886 print*,
'not implemented.'
888 self%work2d(:,j) = self%work_d1
890 iend = iend + self%n_dofs(1)
894 do i =1,self%n_dofs(1)
895 self%work_d2_in = self%work2d(i,:)
896 select case ( deg(2) )
899 self%mass_line_0(:,2), self%work_d2_in, self%work_d2_out )
902 self%mass_line_1(:,2), self%work_d2_in, self%work_d2_out )
905 self%mass_line_mixed(:,2), self%work_d2_in, self%work_d2_out )
907 print*,
'not implemented.'
911 do j=1,self%n_dofs(2)
912 coefs_out(istart+(j-1)*self%n_dofs(1)) = self%work_d2_out(j)
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 [...
Invert a circulant matrix based on diagonalization in Fourier space (2d version)
Low level arbitrary degree splines.
Module interface to solve Maxwell's equations in 2D The linear systems are solved based on FFT diagno...
subroutine multiply_mass_1form(self, coefs_in, coefs_out)
subroutine compute_rho_from_e_2d_fem(self, efield, rho)
compute rho from e using weak Gauss law ( rho = G^T M_1 e )
subroutine sll_s_compute_fem_rhs(self, func, component, form, coefs_dofs)
Compute the FEM right-hand-side for a given function f and periodic splines of given degree Its compo...
subroutine sll_s_compute_b_from_e_2d_fem(self, delta_t, field_in, field_out)
Compute Bz from Ey using strong 1D Faraday equation for spline coefficients $B_z^{new}(x_j) = B_z^{ol...
subroutine multiply_c(self, field_in, field_out)
Multiply by discrete curl matrix.
subroutine sll_s_compute_e_from_b_2d_fem(self, delta_t, field_in, field_out)
compute Ey from Bz using weak Ampere formulation
subroutine sll_s_compute_e_from_rho_2d_fem(self, rho, E)
subroutine l2projection_2d_fem(self, func, component, form, coefs_dofs)
Compute the L2 projection of a given function f on periodic splines of given degree.
subroutine multiply_mass_2dkron(self, mass_line_1, mass_line_2, coefs_in, coefs_out)
Multiply by the mass matrix.
real(kind=f64) function inner_product_2d_fem(self, coefs1_dofs, coefs2_dofs, component, form)
subroutine init_2d_fem(self, domain, n_dofs, s_deg_0)
subroutine multiply_gt(self, field_in, field_out)
Multiply by transpose of dicrete gradient matrix.
subroutine multiply_ct(self, field_in, field_out)
Multiply by transpose of discrete curl matrix.
real(kind=f64) function l2norm_squared_2d_fem(self, coefs_dofs, component, form)
Compute square of the L2norm.
subroutine free_2d_fem(self)
subroutine compute_e_from_j_2d_fem(self, current, component, E)
Compute E_i from j_i integrated over the time interval using weak Ampere formulation.
subroutine multiply_mass_all(self, deg, coefs_in, coefs_out)
Multiply by the mass matrix.
subroutine multiply_mass_2form(self, coefs_in, coefs_out)
Utilites for Maxwell solver's with spline finite elements.
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_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_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.
Data type for a linear solver inverting a 2d tensor product of circulant matrices based on FFT.