12 #include "sll_assert.h"
13 #include "sll_errors.h"
14 #include "sll_memory.h"
15 #include "sll_working_precision.h"
43 sll_s_uniform_bsplines_eval_basis
101 sll_real64,
allocatable :: work0(:)
102 sll_real64,
allocatable :: work01(:)
103 sll_real64,
allocatable :: work1(:)
104 sll_real64,
allocatable :: work12(:)
105 sll_real64,
allocatable :: work2(:)
106 sll_real64,
allocatable :: work22(:)
108 sll_real64,
allocatable :: work3d(:,:,:)
109 sll_real64,
allocatable :: work_d1(:)
110 sll_real64,
allocatable :: work_d2_in(:)
111 sll_real64,
allocatable :: work_d2_out(:)
112 sll_real64,
allocatable :: work_d3_in(:)
113 sll_real64,
allocatable :: work_d3_out(:)
137 logical :: adiabatic_electrons = .false.
193 sll_real64,
intent(in) :: delta_t
194 sll_real64,
intent(in) :: field_in(:)
195 sll_real64,
intent(inout) :: field_out(:)
198 call self%multiply_mass( [2], field_in, self%work2 )
199 call self%multiply_ct( self%work2, self%work1 )
201 call self%multiply_mass_inverse( 1, self%work1, self%work12 )
204 field_out = field_out + delta_t*self%work12
212 sll_real64,
intent(in) :: delta_t
213 sll_real64,
intent(in) :: field_in(:)
214 sll_real64,
intent(inout) :: field_out(:)
216 call self%multiply_c( field_in, self%work2 )
218 field_out = field_out - delta_t * self%work2
226 sll_real64,
intent(in) :: delta_t
227 sll_real64,
intent(inout) :: efield(:)
228 sll_real64,
intent(inout) :: bfield(:)
229 sll_real64,
optional :: betar
233 if(
present(betar) )
then
245 call self%multiply_mass( [2], bfield, self%work2 )
246 call self%multiply_ct( self%work2, self%work1 )
249 self%linear_op_schur_eb%sign = -delta_t**2*0.25_f64*factor
250 call self%linear_op_schur_eb%dot( efield, self%work12 )
251 self%work12 = self%work12 + delta_t*factor*self%work1
257 self%linear_op_schur_eb%sign = delta_t**2*0.25_f64*factor
258 call self%linear_solver_schur_eb%set_guess( efield )
259 call self%linear_solver_schur_eb%solve( self%work12, efield)
262 self%work1 = self%work1 + efield
263 call self%compute_B_from_E( delta_t*0.5_f64, self%work1, bfield)
271 sll_real64,
intent( in ) :: field_in(:)
272 sll_real64,
intent( out ) :: field_out(:)
274 call self%poisson_solver%solve( field_in, self%work0 )
276 call self%multiply_g( self%work0, field_out )
277 field_out = -field_out
286 sll_real64,
intent( in ) :: field_in(:)
287 sll_real64,
intent( out ) :: field_out(:)
289 call self%multiply_mass( [1], field_in, self%work1 )
290 call self%multiply_gt( self%work1, field_out )
291 field_out = - field_out
299 sll_real64,
intent( in ) :: current(:)
300 sll_real64,
intent( inout ) :: e(:)
301 sll_int32,
intent( in ),
optional :: component
305 if(
present(component) )
then
306 if (component == 1)
then
307 call self%mass_1_solver(component)%solve( current, self%work01 )
310 call self%mass_1_solver(component)%solve( current, self%work0 )
311 do i = 1, self%n_dofs(2)*self%n_dofs(3)
312 self%work0(1+(i-1)*self%n_dofs(1)) = 0._f64
313 self%work0(i*self%n_dofs(1)) = 0._f64
319 call self%multiply_mass_inverse( 1, current, self%work1 )
329 sll_real64,
intent( in ) :: field_in(:)
330 sll_real64,
intent( inout ) :: field_out(:)
331 sll_real64,
intent( out ) :: efield_dofs(:)
333 call self%multiply_mass_inverse( 0, field_in, field_out )
334 call self%multiply_g( field_out, efield_dofs )
335 efield_dofs = -efield_dofs
343 sll_real64,
intent( in ) :: field_in(:)
344 sll_real64,
intent( inout ) :: field_out(:)
345 sll_real64,
intent( out ) :: efield_dofs(:)
347 call self%multiply_gt( field_in, self%work0 )
348 call self%multiply_mass_inverse( 0, self%work0, self%work1(1:self%n_total0) )
349 field_out = field_out + self%work1(1:self%n_total0)
351 call self%multiply_g( field_out, efield_dofs )
352 efield_dofs = -efield_dofs
361 sll_int32,
intent( in ) :: form
362 sll_int32,
intent( in ) :: component
363 sll_real64,
intent( out ) :: coefs_dofs(:)
368 sll_int32 :: i1, i2, i3, j1, j2, j3, k1, k2, k3
369 sll_int32 :: degree(3), q(3), index1d
370 sll_real64,
allocatable :: xw_gauss_d1(:,:), xw_gauss_d2(:,:), xw_gauss_d3(:,:)
371 sll_real64,
allocatable :: bspl_d1(:,:), bspl_d2(:,:), bspl_d3(:,:)
376 if ( form == 0 )
then
377 degree = self%s_deg_0
378 elseif (form == 1 )
then
379 degree = self%s_deg_0
380 degree(component) = self%s_deg_1(component)
381 elseif( form == 2)
then
382 degree = self%s_deg_1
383 degree(component) = self%s_deg_0(component)
384 elseif( form == 3)
then
385 degree = self%s_deg_1
387 print*,
'Wrong form.'
390 allocate(xw_gauss_d3(2,q(3)))
391 allocate(bspl_d3(degree(3)+1, q(3)))
395 call sll_s_uniform_bsplines_eval_basis(degree(3),xw_gauss_d3(1,k3), bspl_d3(:,k3))
399 allocate(xw_gauss_d2(2, q(2)))
400 allocate(bspl_d2(degree(2)+1, q(2)))
404 call sll_s_uniform_bsplines_eval_basis(degree(2),xw_gauss_d2(1,k2), bspl_d2(:,k2))
408 allocate(xw_gauss_d1(2,q(1)))
409 allocate(bspl_d1(degree(1)+1, q(1)))
412 if( degree(1) == self%s_deg_0(1) )
then
423 do i3 = 1, self%n_cells(3)
424 do i2 = 1, self%n_cells(2)
426 do i1 = 1, degree(1)-1
428 do j3 = 1, degree(3)+1
429 do j2 = 1, degree(2)+1
430 do j1 = 1, degree(1)+1
431 index1d=i1+j1-1+modulo(i2-degree(2)+j2-2,self%n_cells(2))*self%n_dofs(1)+modulo(i3-degree(3)+j3-2,self%n_cells(3))*self%n_dofs(1)*self%n_cells(2)
436 coefs_dofs(index1d) = coefs_dofs(index1d) + &
437 self%volume * xw_gauss_d1(2,k1)* xw_gauss_d2(2,k2)* &
439 func1([ self%delta_x(1)*(xw_gauss_d1(1,k1)+ real(i1 - 1,f64)), self%delta_x(2)*(xw_gauss_d2(1,k2) + real(i2-1,f64)), self%delta_x(3)*(xw_gauss_d3(1,k3) + real(i3-1,f64))] ) * &
451 do i1 = degree(1), self%n_cells(1)+1-degree(1)
453 do j3 = 1, degree(3)+1
454 do j2 = 1, degree(2)+1
455 do j1 = 1, degree(1)+1
456 index1d=i1+j1-1+modulo(i2-degree(2)+j2-2,self%n_cells(2))*self%n_dofs(1)+modulo(i3-degree(3)+j3-2,self%n_cells(3))*self%n_dofs(1)*self%n_cells(2)
461 coefs_dofs(index1d) = coefs_dofs(index1d) + &
462 self%volume * xw_gauss_d1(2,k1)* xw_gauss_d2(2,k2)* &
464 func1([ self%delta_x(1)*(xw_gauss_d1(1,k1)+ real(i1 - 1,f64)), self%delta_x(2)*(xw_gauss_d2(1,k2) + real(i2-1,f64)), self%delta_x(3)*(xw_gauss_d3(1,k3) + real(i3-1,f64))] ) * &
476 do i1 = self%n_cells(1)-degree(1)+2, self%n_cells(1)
478 do j3 = 1, degree(3)+1
479 do j2 = 1, degree(2)+1
480 do j1 = 1, degree(1)+1
481 index1d=i1+j1-1+modulo(i2-degree(2)+j2-2,self%n_cells(2))*self%n_dofs(1)+modulo(i3-degree(3)+j3-2,self%n_cells(3))*self%n_dofs(1)*self%n_cells(2)
486 coefs_dofs(index1d) = coefs_dofs(index1d) + &
487 self%volume * xw_gauss_d1(2,k1)* xw_gauss_d2(2,k2)* &
489 func1([ self%delta_x(1)*(xw_gauss_d1(1,k1)+ real(i1 - 1,f64)), self%delta_x(2)*(xw_gauss_d2(1,k2) + real(i2-1,f64)), self%delta_x(3)*(xw_gauss_d3(1,k3) + real(i3-1,f64))] ) * &
490 sll_f_spline_pp_horner_1d( degree(1), self%spline0_pp%poly_coeffs_boundary_right(:,:,i1-self%n_cells(1)+degree(1)-1), xw_gauss_d1(1,k1), j1)*&
504 else if (degree(1) == self%s_deg_1(1))
then
515 do i3 = 1, self%n_cells(3)
516 do i2 = 1, self%n_cells(2)
518 do i1 = 1, degree(1)-1
520 do j3 = 1, degree(3)+1
521 do j2 = 1, degree(2)+1
522 do j1 = 1, degree(1)+1
523 index1d=i1+j1-1+modulo(i2-degree(2)+j2-2,self%n_cells(2))*(self%n_dofs(1)-1)+modulo(i3-degree(3)+j3-2,self%n_cells(3))*(self%n_dofs(1)-1)*self%n_cells(2)
528 coefs_dofs(index1d) = coefs_dofs(index1d) + &
529 self%volume * xw_gauss_d1(2,k1)* xw_gauss_d2(2,k2)* &
531 func1([ self%delta_x(1)*(xw_gauss_d1(1,k1)+ real(i1 - 1,f64)), self%delta_x(2)*(xw_gauss_d2(1,k2) + real(i2-1,f64)), self%delta_x(3)*(xw_gauss_d3(1,k3) + real(i3-1,f64))] ) * &
543 do i1 = degree(1), self%n_cells(1)+1-degree(1)
545 do j3 = 1, degree(3)+1
546 do j2 = 1, degree(2)+1
547 do j1 = 1, degree(1)+1
548 index1d=i1+j1-1+modulo(i2-degree(2)+j2-2,self%n_cells(2))*(self%n_dofs(1)-1)+modulo(i3-degree(3)+j3-2,self%n_cells(3))*(self%n_dofs(1)-1)*self%n_cells(2)
553 coefs_dofs(index1d) = coefs_dofs(index1d) + &
554 self%volume * xw_gauss_d1(2,k1)* xw_gauss_d2(2,k2)* &
556 func1([ self%delta_x(1)*(xw_gauss_d1(1,k1)+ real(i1 - 1,f64)), self%delta_x(2)*(xw_gauss_d2(1,k2) + real(i2-1,f64)), self%delta_x(3)*(xw_gauss_d3(1,k3) + real(i3-1,f64))] ) * &
568 do i1 = self%n_cells(1)-degree(1)+2, self%n_cells(1)
570 do j3 = 1, degree(3)+1
571 do j2 = 1, degree(2)+1
572 do j1 = 1, degree(1)+1
573 index1d=i1+j1-1+modulo(i2-degree(2)+j2-2,self%n_cells(2))*(self%n_dofs(1)-1)+modulo(i3-degree(3)+j3-2,self%n_cells(3))*(self%n_dofs(1)-1)*self%n_cells(2)
578 coefs_dofs(index1d) = coefs_dofs(index1d) + &
579 self%volume * xw_gauss_d1(2,k1)* xw_gauss_d2(2,k2)* &
581 func1([ self%delta_x(1)*(xw_gauss_d1(1,k1)+ real(i1 - 1,f64)), self%delta_x(2)*(xw_gauss_d2(1,k2) + real(i2-1,f64)), self%delta_x(3)*(xw_gauss_d3(1,k3) + real(i3-1,f64))] ) * &
582 sll_f_spline_pp_horner_1d( degree(1), self%spline1_pp%poly_coeffs_boundary_right(:,:,i1-self%n_cells(1)+degree(1)-1), xw_gauss_d1(1,k1), j1)*&
596 print*,
"error in compute rhs"
605 sll_int32,
intent( in ) :: form
606 sll_int32,
intent( in ) :: component
607 sll_real64,
intent( out ) :: coefs_dofs(:)
614 if(
present(func2) .and.
present(func3) )
then
619 call sll_s_compute_rhs_fem( self, 1, 2, self%work1(1+self%n_total1:self%n_total1+self%n_total0), func2 )
620 call sll_s_compute_rhs_fem( self, 1, 3, self%work1(1+self%n_total1+self%n_total0:self%n_total1+2*self%n_total0), func3 )
621 call self%multiply_mass_inverse( 1, self%work1, coefs_dofs )
625 call sll_s_compute_rhs_fem( self, 2, 2, self%work2(1+self%n_total0:self%n_total0+self%n_total1), func2 )
626 call sll_s_compute_rhs_fem( self, 2, 3, self%work2(1+self%n_total0+self%n_total1:self%n_total0+2*self%n_total1), func3 )
627 call self%multiply_mass_inverse( 2, self%work2, coefs_dofs )
629 print*,
'L2projection for', form,
'-form not implemented.'
637 call self%multiply_mass_inverse( 0, self%work0, coefs_dofs )
639 if( component == 1)
then
642 call self%mass_1_solver(component)%solve( self%work01, coefs_dofs )
646 call self%mass_1_solver(component)%solve( self%work0, coefs_dofs )
647 do j = 1, self%n_dofs(2)*self%n_dofs(3)
648 coefs_dofs(1+(j-1)*self%n_dofs(1)) = 0._f64
649 coefs_dofs(j*self%n_dofs(1)) = 0._f64
653 if( component == 1)
then
656 call self%mass_2_solver(component)%solve( self%work0, coefs_dofs )
657 do j = 1, self%n_dofs(2)*self%n_dofs(3)
658 coefs_dofs(1+(j-1)*self%n_dofs(1)) = 0._f64
659 coefs_dofs(j*self%n_dofs(1)) = 0._f64
664 call self%mass_2_solver(component)%solve( self%work01, coefs_dofs )
667 print*,
'L2projection for', form,
'-form not implemented.'
679 sll_real64 :: coefs(:)
681 sll_int32 :: component
693 sll_real64 :: coefs1(:)
694 sll_real64 :: coefs2(:)
696 sll_int32,
optional :: component
701 if ( form == 0 )
then
702 call self%multiply_mass( [0], coefs2, self%work0 )
703 r = sum(coefs1*self%work0)
704 elseif (form == 1 )
then
707 if( component == 1)
then
709 r = sum(coefs1*self%work01)
712 r = sum(coefs1*self%work0)
714 elseif( form == 2)
then
717 if( component == 1)
then
719 r = sum(coefs1*self%work0)
722 r = sum(coefs1*self%work01)
724 elseif( form == 3)
then
727 r = sum(coefs1*self%work0)
729 print*,
'Wrong form.'
736 subroutine init_3d_fem( self, domain, n_cells, s_deg_0, boundary, mass_tolerance, poisson_tolerance, solver_tolerance, adiabatic_electrons, profile )
738 sll_real64,
intent(in) :: domain(3,2)
739 sll_int32,
intent(in) :: n_cells(3)
740 sll_int32,
intent(in) :: s_deg_0(3)
741 sll_int32,
intent( in ) :: boundary(3)
742 sll_real64,
intent(in),
optional :: mass_tolerance
743 sll_real64,
intent(in),
optional :: poisson_tolerance
744 sll_real64,
intent(in),
optional :: solver_tolerance
745 logical,
intent(in),
optional :: adiabatic_electrons
748 sll_int32 :: j,k, deg(3)
749 sll_real64 :: mass_line_b0((s_deg_0(1)+1)*s_deg_0(1)), mass_line_b1(s_deg_0(1)*(s_deg_0(1)-1))
750 sll_real64,
allocatable :: mass_line_0(:), mass_line_1(:), mass_line_mixed(:)
752 if(
present( mass_tolerance) )
then
753 self%mass_solver_tolerance = mass_tolerance
755 self%mass_solver_tolerance = 1d-12
757 if(
present( poisson_tolerance) )
then
758 self%poisson_solver_tolerance = poisson_tolerance
760 self%poisson_solver_tolerance = 1d-12
762 if (
present( solver_tolerance) )
then
763 self%solver_tolerance = solver_tolerance
765 self%solver_tolerance = 1d-12
768 if(
present( adiabatic_electrons ) )
then
769 self%adiabatic_electrons = adiabatic_electrons
772 if(
present( profile ) )
then
773 self%profile = profile
776 self%n_cells = n_cells
777 self%n_dofs = n_cells
778 self%n_dofs(1) = n_cells(1)+s_deg_0(1)
779 self%n_total = product(n_cells)
780 self%n_total0 = product(self%n_dofs)
781 self%n_total1 = (self%n_dofs(1)-1)*n_cells(2)*n_cells(3)
782 self%Lx = domain(:,2) - domain(:,1)
783 self%delta_x = self%Lx / real(n_cells, f64)
784 self%s_deg_0 = s_deg_0
785 self%s_deg_1 = s_deg_0 - 1
786 self%volume = product(self%delta_x)
788 allocate( self%spline0_pp )
789 allocate( self%spline1_pp )
795 allocate(self%work0(1:self%n_total0))
796 allocate(self%work01(1:self%n_total1))
797 allocate(self%work1(1:self%n_total1+2*self%n_total0))
798 allocate(self%work12(1:self%n_total1+2*self%n_total0))
799 allocate(self%work2(1:self%n_total0+2*self%n_total1))
800 allocate(self%work22(1:self%n_total0+2*self%n_total1))
801 allocate( self%work_d2_in( n_cells(2) ) )
802 allocate( self%work_d2_out( n_cells(2) ) )
803 allocate( self%work_d3_in( n_cells(3) ) )
804 allocate( self%work_d3_out( n_cells(3) ) )
811 allocate( mass_line_0(s_deg_0(1)+1) )
812 allocate( mass_line_1(s_deg_0(1)) )
821 self%mass1d(1,1)%arr_a = self%mass1d(1,1)%arr_a*self%delta_x(1)
822 self%mass1d(2,1)%arr_a = self%mass1d(2,1)%arr_a*self%delta_x(1)
823 call self%mass1d_solver(1,1)%create( self%mass1d(1,1) )
824 call self%mass1d_solver(2,1)%create( self%mass1d(2,1) )
826 deallocate( mass_line_0 )
827 deallocate( mass_line_1 )
832 allocate( mass_line_0(s_deg_0(j)+1) )
833 allocate( mass_line_1(s_deg_0(j)) )
834 allocate( mass_line_mixed(s_deg_0(j)*2) )
840 self%mass1d(1,j)%arr_a = self%mass1d(1,j)%arr_a*self%delta_x(j)
841 self%mass1d(2,j)%arr_a = self%mass1d(2,j)%arr_a*self%delta_x(j)
842 call self%mass1d_solver(1,j)%create( self%mass1d(1,j) )
843 call self%mass1d_solver(2,j)%create( self%mass1d(2,j) )
850 deallocate( mass_line_0 )
851 deallocate( mass_line_1 )
852 deallocate( mass_line_mixed )
857 self%mass1d_solver(k,j)%atol = self%mass_solver_tolerance
863 call self%mass1(1)%create( linop_a=self%mass1d(1,3), &
864 linop_b=self%mass1d(1,2), &
865 linop_c=self%mass1d(2,1) )
866 call self%mass1(2)%create( linop_a=self%mass1d(1,3), &
867 linop_b=self%mass1d(2,2), &
868 linop_c=self%mass1d(1,1) )
869 call self%mass1(3)%create( linop_a=self%mass1d(2,3), &
870 linop_b=self%mass1d(1,2), &
871 linop_c=self%mass1d(1,1))
872 call self%mass2(1)%create( linop_a=self%mass1d(2,3), &
873 linop_b=self%mass1d(2,2), &
874 linop_c=self%mass1d(1,1) )
875 call self%mass2(2)%create( linop_a=self%mass1d(2,3), &
876 linop_b=self%mass1d(1,2), &
877 linop_c=self%mass1d(2,1) )
878 call self%mass2(3)%create( linop_a=self%mass1d(1,3), &
879 linop_b=self%mass1d(2,2), &
880 linop_c=self%mass1d(2,1) )
883 if(self%adiabatic_electrons)
then
889 call self%mass0_solver%create( self%mass0 )
890 self%mass0_solver%atol = self%mass_solver_tolerance
893 call self%mass1_operator%create( 3, 3 )
894 call self%mass2_operator%create( 3, 3 )
897 call self%mass1_operator%set( j, j, self%mass1(j) )
898 call self%mass2_operator%set( j, j, self%mass2(j) )
901 call self%preconditioner_fft%init( self%Lx, n_cells, s_deg_0, .true. )
904 call self%mass1_operator%dot(self%work12, self%work1)
905 do j = 1, self%n_dofs(2)*self%n_dofs(3)
906 self%work1(self%n_total1+1+(j-1)*self%n_dofs(1)) = 1._f64
907 self%work1(self%n_total1+j*self%n_dofs(1)) = 1._f64
908 self%work1(self%n_total1+self%n_total0+1+(j-1)*self%n_dofs(1)) = 1._f64
909 self%work1(self%n_total1+self%n_total0+j*self%n_dofs(1)) = 1._f64
911 self%work1 = 1._f64/sqrt(self%work1)
914 call self%mass2_operator%dot(self%work22, self%work2)
915 do j = 1, self%n_dofs(2)*self%n_dofs(3)
916 self%work2(1+(j-1)*self%n_dofs(1)) = 1._f64
917 self%work2(j*self%n_dofs(1)) = 1._f64
919 self%work2 = 1._f64/sqrt(self%work2)
921 call self%preconditioner1%create( self%preconditioner_fft%inverse_mass1_3d, self%work1, 2*self%n_total0+self%n_total1 )
922 call self%preconditioner2%create( self%preconditioner_fft%inverse_mass2_3d, self%work2, 2*self%n_total1+self%n_total0 )
929 call self%mass1_solver%create( self%mass1_operator, self%preconditioner1)
930 call self%mass2_solver%create( self%mass2_operator, self%preconditioner2)
931 self%mass1_solver%atol = self%mass_solver_tolerance
932 self%mass2_solver%atol = self%mass_solver_tolerance
937 call self%mass_1_solver(1)%create( linear_solver_a=self%mass1d_solver(2,1), &
938 linear_solver_b=self%mass1d_solver(1,2), &
939 linear_solver_c=self%mass1d_solver(1,3) )
940 call self%mass_1_solver(2)%create( linear_solver_a=self%mass1d_solver(1,1), &
941 linear_solver_b=self%mass1d_solver(2,2), &
942 linear_solver_c=self%mass1d_solver(1,3) )
943 call self%mass_1_solver(3)%create( linear_solver_a=self%mass1d_solver(1,1), &
944 linear_solver_b=self%mass1d_solver(1,2), &
945 linear_solver_c=self%mass1d_solver(2,3))
946 call self%mass_2_solver(1)%create( linear_solver_a=self%mass1d_solver(1,1), &
947 linear_solver_b=self%mass1d_solver(2,2), &
948 linear_solver_c=self%mass1d_solver(2,3) )
949 call self%mass_2_solver(2)%create( linear_solver_a=self%mass1d_solver(2,1), &
950 linear_solver_b=self%mass1d_solver(1,2), &
951 linear_solver_c=self%mass1d_solver(2,3) )
952 call self%mass_2_solver(3)%create( linear_solver_a=self%mass1d_solver(2,1), &
953 linear_solver_b=self%mass1d_solver(2,2), &
954 linear_solver_c=self%mass1d_solver(1,3) )
959 call self%linear_op_schur_eb%create( self%mass1_operator, self%mass2_operator, self%n_dofs, self%delta_x, self%s_deg_0 )
960 call self%linear_solver_schur_eb%create( self%linear_op_schur_eb, self%preconditioner1 )
961 self%linear_solver_schur_eb%atol = self%solver_tolerance
966 call self%poisson_matrix%create( self%mass1_operator, self%s_deg_0, self%n_dofs, self%delta_x)
967 call self%poisson_solver%create( self%poisson_matrix)
968 self%poisson_solver%atol = self%poisson_solver_tolerance
975 sll_real64,
intent(in) :: x(3)
976 sll_int32,
optional,
intent(in) :: component(:)
978 profile_m0 = product(self%Lx) * self%profile%rho_0( x(1) )/ self%profile%T_e( x(1) )
984 sll_real64,
intent(in) :: x(3)
985 sll_int32,
optional,
intent(in) :: component(:)
993 sll_real64,
intent(in) :: x
1005 sll_real64,
intent(in) :: domain(3,2)
1006 sll_int32,
intent(in) :: n_cells(3)
1007 sll_int32,
intent(in) :: s_deg_0(3)
1008 sll_int32,
intent( in ) :: boundary(3)
1009 character(len=*),
intent(in) :: nml_file
1010 logical,
intent(in),
optional :: adiabatic_electrons
1013 character(len=256) :: file_prefix
1014 sll_int32 :: input_file
1015 sll_int32 :: io_stat, io_stat0, io_stat1, rank, file_id
1016 sll_real64 :: mass_tolerance
1017 sll_real64 :: poisson_tolerance
1018 sll_real64 :: maxwell_tolerance
1020 namelist /output/ file_prefix
1021 namelist /maxwell_solver/ mass_tolerance, poisson_tolerance
1022 namelist /time_solver/ maxwell_tolerance
1026 if(
present( adiabatic_electrons) )
then
1027 self%adiabatic_electrons = adiabatic_electrons
1030 if(
present( profile ) )
then
1031 self%profile = profile
1035 open(newunit = input_file, file=nml_file, status=
'old',iostat=io_stat)
1036 if (io_stat /= 0)
then
1037 if (rank == 0 )
then
1038 print*,
'sll_m_maxwell_cl_3d_fem: Input file does not exist. Set default tolerance.'
1039 open(newunit=file_id, file=trim(file_prefix)//
'_parameters_used.dat', position =
'append', status=
'old', action=
'write', iostat=io_stat)
1040 write(file_id, *)
'mass solver tolerance:', 1d-12
1041 write(file_id, *)
'poisson solver tolerance:', 1d-12
1044 call self%init( domain, n_cells, s_deg_0, boundary )
1046 read(input_file, output,iostat=io_stat0)
1047 read(input_file, maxwell_solver,iostat=io_stat)
1048 read(input_file, time_solver,iostat=io_stat1)
1049 if (io_stat /= 0 .and. io_stat1 /= 0)
then
1050 if (rank == 0 )
then
1051 print*,
'sll_m_maxwell_cl_3d_fem: Input parameter does not exist. Set default tolerance.'
1052 open(newunit=file_id, file=trim(file_prefix)//
'_parameters_used.dat', position =
'append', status=
'old', action=
'write', iostat=io_stat)
1053 write(file_id, *)
'mass solver tolerance:', 1d-12
1054 write(file_id, *)
'poisson solver tolerance:', 1d-12
1057 call self%init( domain, n_cells, s_deg_0, boundary )
1058 else if (io_stat /= 0 .and. io_stat1 == 0)
then
1059 call self%init( domain, n_cells, s_deg_0, boundary, solver_tolerance=maxwell_tolerance )
1060 else if (io_stat == 0 .and. io_stat1 /= 0)
then
1061 if (rank == 0 )
then
1062 open(newunit=file_id, file=trim(file_prefix)//
'_parameters_used.dat', position =
'append', status=
'old', action=
'write', iostat=io_stat)
1063 write(file_id, *)
'mass solver tolerance:', mass_tolerance
1064 write(file_id, *)
'poisson solver tolerance:', poisson_tolerance
1067 call self%init( domain, n_cells, s_deg_0, boundary, mass_tolerance, poisson_tolerance )
1069 if (rank == 0 )
then
1070 open(newunit=file_id, file=trim(file_prefix)//
'_parameters_used.dat', position =
'append', status=
'old', action=
'write', iostat=io_stat)
1071 write(file_id, *)
'mass solver tolerance:', mass_tolerance
1072 write(file_id, *)
'poisson solver tolerance:', poisson_tolerance
1075 call self%init( domain, n_cells, s_deg_0, boundary, mass_tolerance, poisson_tolerance, maxwell_tolerance )
1086 call self%mass0_solver%free()
1087 call self%mass1_solver%free()
1088 call self%mass2_solver%free()
1089 call self%mass1_operator%free()
1090 call self%mass2_operator%free()
1091 call self%poisson_solver%free()
1092 call self%poisson_matrix%free()
1093 call self%linear_solver_schur_eb%free()
1094 call self%linear_op_schur_eb%free()
1099 deallocate(self%work0)
1100 deallocate(self%work01)
1101 deallocate(self%work1)
1102 deallocate(self%work12)
1103 deallocate(self%work2)
1104 deallocate(self%work22)
1112 sll_real64,
intent( in ) :: field_in(:)
1113 sll_real64,
intent( out ) :: field_out(:)
1123 sll_real64,
intent( in ) :: field_in(:)
1124 sll_real64,
intent( out ) :: field_out(:)
1134 sll_real64,
intent( in ) :: field_in(:)
1135 sll_real64,
intent( out ) :: field_out(:)
1145 sll_real64,
intent( in ) :: field_in(:)
1146 sll_real64,
intent( out ) :: field_out(:)
1156 sll_int32,
intent( in ) :: deg(:)
1157 sll_real64,
intent( in ) :: coefs_in(:)
1158 sll_real64,
intent( out ) :: coefs_out(:)
1161 if(
size(deg) == 1 )
then
1164 call self%mass0%dot( coefs_in, coefs_out )
1166 call self%mass1_operator%dot( coefs_in, coefs_out )
1168 call self%mass2_operator%dot( coefs_in, coefs_out )
1170 print*,
'multiply mass for other form not yet implemented'
1173 else if(
size(deg) == 3 )
then
1183 sll_int32,
intent( in ) :: deg(:)
1184 sll_real64,
intent( in ) :: coefs_in(:)
1185 sll_real64,
intent( out ) :: coefs_out(:)
1187 sll_int32 :: i,j,k,istart,iend
1190 allocate( self%work3d(self%n_dofs(1), self%n_cells(2), self%n_cells(3)) )
1191 allocate( self%work_d1( self%n_dofs(1) ) )
1193 iend = self%n_dofs(1)
1194 do k = 1, self%n_cells(3)
1195 do j = 1, self%n_cells(2)
1196 call self%mass1d(deg(1),1)%dot( coefs_in(istart:iend), self%work_d1 )
1197 self%work3d(:,j,k) = self%work_d1
1199 iend = iend + self%n_dofs(1)
1203 do k = 1, self%n_cells(3)
1204 do i = 1, self%n_dofs(1)
1205 self%work_d2_in = self%work3d(i,:,k)
1206 call self%mass1d(deg(2),2)%dot( self%work_d2_in, self%work_d2_out )
1207 self%work3d(i,:,k) = self%work_d2_out
1212 do j = 1, self%n_cells(2)
1213 do i = 1, self%n_dofs(1)
1214 self%work_d3_in = self%work3d(i,j,:)
1215 call self%mass1d(deg(3),3)%dot( self%work_d3_in, self%work_d3_out )
1216 do k = 1, self%n_cells(3)
1217 coefs_out(istart+(k-1)*self%n_dofs(1)*self%n_cells(2)) = self%work_d3_out(k)
1222 else if (deg(1) == 2)
then
1223 allocate( self%work3d(self%n_dofs(1)-1, self%n_cells(2), self%n_cells(3)) )
1224 allocate( self%work_d1( self%n_dofs(1)-1 ) )
1226 iend = self%n_dofs(1)-1
1227 do k = 1, self%n_cells(3)
1228 do j = 1, self%n_cells(2)
1229 call self%mass1d(deg(1),1)%dot( coefs_in(istart:iend), self%work_d1 )
1230 self%work3d(:,j,k) = self%work_d1
1232 iend = iend + self%n_dofs(1)-1
1236 do k = 1, self%n_cells(3)
1237 do i = 1, self%n_dofs(1)-1
1238 self%work_d2_in = self%work3d(i,:,k)
1239 call self%mass1d(deg(2),2)%dot( self%work_d2_in, self%work_d2_out )
1240 self%work3d(i,:,k) = self%work_d2_out
1245 do j = 1, self%n_cells(2)
1246 do i = 1, self%n_dofs(1)-1
1247 self%work_d3_in = self%work3d(i,j,:)
1248 call self%mass1d(deg(3),3)%dot( self%work_d3_in, self%work_d3_out )
1249 do k = 1, self%n_cells(3)
1250 coefs_out(istart+(k-1)*(self%n_dofs(1)-1)*self%n_cells(2)) = self%work_d3_out(k)
1255 else if(deg(1) == 3)
then
1256 allocate( self%work3d(self%n_dofs(1), self%n_cells(2), self%n_cells(3)) )
1257 allocate( self%work_d1( self%n_dofs(1) ) )
1259 iend = self%n_dofs(1)-1
1260 do k = 1, self%n_cells(3)
1261 do j = 1, self%n_cells(2)
1262 call self%mass1d(deg(1),1)%dot( coefs_in(istart:iend), self%work_d1 )
1263 self%work3d(:,j,k) = self%work_d1
1265 iend = iend + self%n_dofs(1)-1
1269 do k = 1, self%n_cells(3)
1270 do i = 1, self%n_dofs(1)
1271 self%work_d2_in = self%work3d(i,:,k)
1272 call self%mass1d(deg(2),2)%dot( self%work_d2_in, self%work_d2_out )
1273 self%work3d(i,:,k) = self%work_d2_out
1278 do j = 1, self%n_cells(2)
1279 do i = 1, self%n_dofs(1)
1280 self%work_d3_in = self%work3d(i,j,:)
1281 call self%mass1d(deg(3),3)%dot( self%work_d3_in, self%work_d3_out )
1282 do k = 1, self%n_cells(3)
1283 coefs_out(istart+(k-1)*self%n_dofs(1)*self%n_cells(2)) = self%work_d3_out(k)
1289 deallocate( self%work3d )
1290 deallocate( self%work_d1 )
1298 sll_int32,
intent( in ) :: form
1299 sll_real64,
intent( in ) :: coefs_in(:)
1300 sll_real64,
intent( out ) :: coefs_out(:)
1304 sll_assert(form>=0 .and. form<=3)
1307 call self%mass0_solver%solve( coefs_in, coefs_out )
1308 do j = 1, self%n_dofs(2)*self%n_dofs(3)
1309 coefs_out(1+(j-1)*self%n_dofs(1)) = 0._f64
1310 coefs_out(j*self%n_dofs(1)) = 0._f64
1313 call self%mass1_solver%solve( coefs_in, coefs_out )
1314 do j = 1, self%n_dofs(2)*self%n_dofs(3)
1315 coefs_out(self%n_total1+1+(j-1)*self%n_dofs(1)) = 0._f64
1316 coefs_out(self%n_total1+j*self%n_dofs(1)) = 0._f64
1317 coefs_out(self%n_total1+self%n_total0+1+(j-1)*self%n_dofs(1)) = 0._f64
1318 coefs_out(self%n_total1+self%n_total0+j*self%n_dofs(1)) = 0._f64
1321 call self%mass2_solver%solve( coefs_in, coefs_out )
1322 do j = 1, self%n_dofs(2)*self%n_dofs(3)
1323 coefs_out(1+(j-1)*self%n_dofs(1)) = 0._f64
1324 coefs_out(j*self%n_dofs(1)) = 0._f64
1327 print*,
'multiply inverse mass for other form not yet implemented'
1336 sll_real64,
intent( in ) :: efield_dofs(:)
1337 sll_real64,
intent( in ) :: bfield_dofs(:)
1338 sll_real64,
intent( out ) :: energy
1340 sll_real64 :: field_energy(6)
1342 field_energy(1) = self%l2norm_squared &
1343 ( efield_dofs(1:self%n_total1), 1, 1 )
1344 field_energy(2) = self%l2norm_squared &
1345 ( efield_dofs(self%n_total1+1:self%n_total1+self%n_total0), 1, 2 )
1346 field_energy(3) = self%l2norm_squared &
1347 ( efield_dofs(self%n_total1+self%n_total0+1:self%n_total1+self%n_total0*2), 1, 3 )
1348 field_energy(4) = self%l2norm_squared &
1349 ( bfield_dofs(1:self%n_total0), 2, 1 )
1350 field_energy(5) = self%l2norm_squared &
1351 ( bfield_dofs(self%n_total0+1:self%n_total0+self%n_total1), 2, 2 )
1352 field_energy(6) =self%l2norm_squared &
1353 ( bfield_dofs(self%n_total0+self%n_total1+1:self%n_total0+self%n_total1*2), 2, 3 )
1355 energy = 0.5_f64*sum(field_energy)
integer(kind=i32) function, public sll_f_get_collective_rank(col)
Determines the rank of the calling process in the communicator.
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.
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 [...
module for a block linear operator
module for a linear operator of kronecker solver
module for conjugate gradient method in pure form
module for kronecker linear solver
Low level arbitrary degree splines.
module for Compressed Sparse Row Matrix (CSR)
Module interface to solve Maxwell's equations in 3D.
Module interface to solve Maxwell's equations in 3D The linear systems are solved using PLAF.
subroutine multiply_c(self, field_in, field_out)
Multiply by discrete curl matrix.
subroutine l2projection_3d_fem(self, form, component, coefs_dofs, func1, func2, func3)
Compute the L2 projection of a given function f on periodic splines of given degree.
subroutine multiply_gt(self, field_in, field_out)
Multiply by transpose of dicrete gradient matrix.
real(kind=f64) function inner_product_3d_fem(self, coefs1, coefs2, form, component)
Compute inner product.
subroutine compute_field_energy(self, efield_dofs, bfield_dofs, energy)
Compute field energy.
subroutine sll_s_compute_phi_from_rho_3d_fem(self, field_in, field_out, efield_dofs)
Compute phi from rho_i integrated over the time interval.
subroutine multiply_mass_3d_fem(self, deg, coefs_in, coefs_out)
Multiply by the mass matrix.
subroutine sll_s_compute_curl_part_3d_fem(self, delta_t, efield, bfield, betar)
Solve curl part of Maxwell's equations.
subroutine sll_s_compute_e_from_j_3d_fem(self, current, E, component)
Compute E_i from j_i integrated over the time interval using weak Ampere formulation,...
subroutine multiply_mass_inverse_3d_fem(self, form, coefs_in, coefs_out)
Multiply by the inverse mass matrix.
subroutine free_3d_fem(self)
Finalization.
subroutine sll_s_compute_e_from_b_3d_fem(self, delta_t, field_in, field_out)
compute E from B using weak Ampere formulation
subroutine multiply_mass_3dkron(self, deg, coefs_in, coefs_out)
Multiply by the mass matrix.
real(kind=f64) function l2norm_squared_3d_fem(self, coefs, form, component)
Compute square of the L2norm.
subroutine sll_s_compute_phi_from_j_3d_fem(self, field_in, field_out, efield_dofs)
Compute phi from j_i integrated over the time interval, delta_t is already included.
subroutine init_from_file_3d_fem(self, domain, n_cells, s_deg_0, boundary, nml_file, adiabatic_electrons, profile)
Initialization from nml file.
subroutine sll_s_compute_b_from_e_3d_fem(self, delta_t, field_in, field_out)
Compute B from E using strong 3D Faraday equation for spline coefficients.
subroutine multiply_g(self, field_in, field_out)
Multiply by dicrete gradient matrix.
subroutine sll_s_compute_rhs_fem(self, form, component, coefs_dofs, func1, func2, func3)
Compute the FEM right-hand-side for a given function f and periodic splines of given degree Its compo...
subroutine multiply_ct(self, field_in, field_out)
Multiply by transpose of discrete curl matrix.
subroutine init_3d_fem(self, domain, n_cells, s_deg_0, boundary, mass_tolerance, poisson_tolerance, solver_tolerance, adiabatic_electrons, profile)
Initialization.
subroutine sll_s_compute_e_from_rho_3d_fem(self, field_in, field_out)
compute e from rho using weak Poisson's equation ( rho = G^T M_1 G \phi, e = G \phi )
subroutine sll_s_compute_rho_from_e_3d_fem(self, field_in, field_out)
compute rho from e using weak Gauss law ( rho = G^T M_1 e )
Module interface to solve Maxwell's equations with coordinate transformation in 3D The linear systems...
Module interface to solve Maxwell's equations with coordinate transformation in 3D The linear systems...
functions for initial profile of the particle distribution function
Utilites for Maxwell solver's with spline finite elements using sparse matrices.
subroutine, public sll_s_multiply_ct_clamped(n_dofs, delta_x, s_deg_0, field_in, field_out)
Multiply by transpose of discrete curl matrix.
subroutine, public sll_s_spline_fem_mass3d_clamped(n_cells, deg, component, matrix, profile, spline, n_cells_min, n_cells_max)
Set up 3d clamped mass matrix for specific spline degrees and profile function.
subroutine, public sll_s_multiply_g_clamped(n_dofs, delta_x, s_deg_0, field_in, field_out)
Multiply by dicrete gradient matrix.
subroutine, public sll_s_multiply_c_clamped(n_dofs, delta_x, s_deg_0, field_in, field_out)
Multiply by discrete curl matrix.
subroutine, public sll_s_multiply_gt_clamped(n_dofs, delta_x, s_deg_0, field_in, field_out)
Multiply by transpose of dicrete gradient matrix.
Utilites for 3D Maxwell solvers with spline finite elements.
subroutine, public sll_s_spline_fem_mass3d(n_cells, deg, component, matrix, profile, n_cells_min, n_cells_max)
Set up 3d mass matrix for specific spline degrees and profile function.
Utilites for Maxwell solver's with spline finite elements using sparse matrix linear solvers.
subroutine, public sll_s_spline_fem_mass1d(n_cells, s_deg, mass_line, matrix)
Set up 1d mass matrix (sparsity pattern and values)
subroutine, public sll_s_spline_fem_mixedmass1d_clamped_full(n_cells, deg1, deg2, matrix, profile, spline1, spline2)
Set up 1d mixed mass matrix for specific spline degrees and profile function.
subroutine, public sll_s_spline_fem_mixedmass1d(n_cells, s_deg, mass_line, matrix)
subroutine, public sll_s_spline_fem_mass1d_clamped(n_cells, s_deg, mass_line, mass_line_b, matrix)
Set up 1d mass matrix (sparsity pattern and values)
Utilites for Maxwell solver's with spline finite elements.
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_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_pp_init_1d(self, degree, n_cells, boundary)
Initialize sll_t_spline_pp_1d object (Set poly_coeffs depending on degree)
subroutine, public sll_s_spline_pp_free_1d(self)
Destructor 1d.
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.
real(kind=f64) function profile_0(x)
real(kind=f64) function profile_m0(x)
real(kind=f64) function profile_mix(x)
class for a linear operator_block
class for a linear operator
class for the cg linear solver
class for the kronecker linear solver
arbitrary degree 1d spline