14 #include "sll_assert.h"
15 #include "sll_errors.h"
16 #include "sll_memory.h"
17 #include "sll_working_precision.h"
33 sll_s_uniform_bsplines_eval_basis
74 sll_real64,
allocatable :: work(:)
75 sll_real64,
allocatable :: work2(:)
76 sll_real64,
allocatable :: work3d(:,:,:)
77 sll_real64,
allocatable :: work_d1(:)
78 sll_real64,
allocatable :: work_d2_in(:)
79 sll_real64,
allocatable :: work_d2_out(:)
80 sll_real64,
allocatable :: work_d3_in(:)
81 sll_real64,
allocatable :: work_d3_out(:)
83 sll_real64,
allocatable :: mass_line0_1(:)
84 sll_real64,
allocatable :: mass_line0_2(:)
85 sll_real64,
allocatable :: mass_line0_3(:)
86 sll_real64,
allocatable :: mass_line1_1(:)
87 sll_real64,
allocatable :: mass_line1_2(:)
88 sll_real64,
allocatable :: mass_line1_3(:)
89 sll_real64,
allocatable :: mass_line_mixed_1(:)
90 sll_real64,
allocatable :: mass_line_mixed_2(:)
91 sll_real64,
allocatable :: mass_line_mixed_3(:)
97 logical :: adiabatic_electrons = .false.
155 sll_real64,
intent(in) :: delta_t
156 sll_real64,
intent(in) :: field_in(:)
157 sll_real64,
intent(inout) :: field_out(:)
160 sll_int32 :: comp, istart, iend
167 istart = 1+(comp-1)*self%n_total
168 iend = comp*self%n_total
169 call self%inverse_mass_1(comp)%solve( self%work2(istart:iend), self%work(istart:iend) )
173 field_out = field_out + coef*self%work
181 sll_real64,
intent( in ) :: delta_t
182 sll_real64,
intent( in ) :: field_in(:)
183 sll_real64,
intent( inout ) :: field_out(:)
187 field_out = field_out - delta_t * self%work
195 sll_real64,
intent( in ) :: delta_t
196 sll_real64,
intent( inout ) :: efield(:)
197 sll_real64,
intent( inout ) :: bfield(:)
198 sll_real64,
optional :: betar
202 if(
present(betar) )
then
210 call self%multiply_ct( self%work, self%work2 )
212 self%linear_op_schur_eb%factor = -delta_t**2*factor*0.25_f64
213 call self%linear_op_schur_eb%dot( efield, self%work )
214 self%work = self%work + delta_t*factor*self%work2
220 self%linear_op_schur_eb%factor = delta_t**2*factor*0.25_f64
221 call self%linear_op_schur_eb%dot_inverse( self%work, efield )
224 self%work2 = self%work2 + efield
225 call self%compute_b_from_e( delta_t*0.5_f64, self%work2, bfield )
233 sll_real64,
intent( in ) :: field_in(:)
234 sll_real64,
intent( out ) :: field_out(:)
237 call self%poisson_fft%compute_e_from_rho( field_in, field_out )
245 sll_real64,
intent( in ) :: field_in(:)
246 sll_real64,
intent( out ) :: field_out(:)
251 field_out = - field_out
258 sll_real64,
intent( in ) :: current(:)
259 sll_real64,
intent( inout ) :: e(:)
260 sll_int32,
intent( in ),
optional :: component
262 if(
present(component) )
then
263 call self%inverse_mass_1(component)%solve( current, self%work(1:self%n_total) )
264 e = e - self%work(1:self%n_total)
266 call self%inverse_mass_1(1)%solve( current(1:self%n_total), self%work(1:self%n_total) )
267 call self%inverse_mass_1(2)%solve( current(self%n_total+1:2*self%n_total), self%work(self%n_total+1:2*self%n_total) )
268 call self%inverse_mass_1(3)%solve( current(2*self%n_total+1:3*self%n_total), self%work(2*self%n_total+1:3*self%n_total) )
278 sll_real64,
intent( in ) :: field_in(:)
279 sll_real64,
intent( inout ) :: field_out(:)
280 sll_real64,
intent( out ) :: efield_dofs(:)
282 call self%inverse_mass_0%solve( field_in, field_out )
283 call self%multiply_g( field_out, efield_dofs )
284 efield_dofs = -efield_dofs
292 sll_real64,
intent( in ) :: field_in(:)
293 sll_real64,
intent( inout ) :: field_out(:)
294 sll_real64,
intent( out ) :: efield_dofs(:)
296 call self%multiply_gt( field_in, self%work(1:self%n_total) )
297 call self%inverse_mass_0%solve( self%work(1:self%n_total), self%work2(1:self%n_total) )
298 field_out = field_out + self%work2(1:self%n_total)
300 call self%multiply_g( field_out, efield_dofs )
301 efield_dofs = -efield_dofs
310 sll_int32,
intent( in ) :: form
311 sll_int32,
intent( in ) :: component
312 sll_real64,
intent( out ) :: coefs_dofs(:)
317 sll_int32 :: i1, i2, i3,j1, j2, j3, k1, k2, k3, q(3), counter
318 sll_int32 :: degree(3)
321 sll_real64,
allocatable :: xw_gauss_d1(:,:), xw_gauss_d2(:,:), xw_gauss_d3(:,:)
322 sll_real64,
allocatable :: bspl_d1(:,:), bspl_d2(:,:), bspl_d3(:,:)
323 sll_real64 :: scratch(maxval(self%s_deg_0+1))
326 if ( form == 0 )
then
327 degree = self%s_deg_0
328 elseif (form == 1 )
then
329 degree = self%s_deg_0
330 degree(component) = self%s_deg_1(component)
331 elseif( form == 2)
then
332 degree = self%s_deg_1
333 degree(component) = self%s_deg_0(component)
334 elseif( form == 3)
then
335 degree = self%s_deg_1
337 print*,
'Wrong form.'
343 allocate(xw_gauss_d1(2,q(1)))
344 allocate(bspl_d1(q(1), degree(1)+1))
348 call sll_s_uniform_bsplines_eval_basis(degree(1),xw_gauss_d1(1,k1), scratch(1:degree(1)+1))
349 bspl_d1(k1,:) = scratch(1:degree(1)+1)
352 allocate(xw_gauss_d2(2,q(2)))
353 allocate(bspl_d2(q(2), degree(2)+1))
357 call sll_s_uniform_bsplines_eval_basis(degree(2),xw_gauss_d2(1,k2), scratch(1:degree(2)+1))
358 bspl_d2(k2,:) = scratch(1:degree(2)+1)
361 allocate(xw_gauss_d3(2,q(3)))
362 allocate(bspl_d3(q(3), degree(3)+1))
366 call sll_s_uniform_bsplines_eval_basis(degree(3),xw_gauss_d3(1,k3), scratch(1:degree(3)+1))
367 bspl_d3(k3,:) = scratch(1:degree(3)+1)
372 do i3 = 1, self%n_dofs(3)
373 do i2 = 1, self%n_dofs(2)
374 do i1 = 1, self%n_dofs(1)
377 do j3 = 1, degree(3)+1
378 do j2 = 1, degree(2)+1
379 do j1 = 1, degree(1)+1
382 c(3) = self%delta_x(3)*(xw_gauss_d3(1,k3) + real(i3 + j3 - 2,f64))
384 c(2) = self%delta_x(2)*(xw_gauss_d2(1,k2) + real(i2 + j2 - 2,f64))
386 c(1) = self%delta_x(1)*(xw_gauss_d1(1,k1) + real(i1 + j1 - 2,f64))
387 coef = coef + xw_gauss_d1(2,k1)* xw_gauss_d2(2,k2)* &
390 bspl_d1(k1,degree(1)+2-j1)*&
391 bspl_d2(k2,degree(2)+2-j2)*&
392 bspl_d3(k3,degree(3)+2-j3)
401 coefs_dofs(counter) = coef*self%volume
413 sll_int32,
intent( in ) :: form
414 sll_int32,
intent( in ) :: component
415 sll_real64,
intent( out ) :: coefs_dofs(:)
425 call self%inverse_mass_0%solve( self%work(1:self%n_total), coefs_dofs )
427 call self%inverse_mass_1(component)%solve( self%work(1:self%n_total), coefs_dofs )
429 call self%inverse_mass_2(component)%solve( self%work(1:self%n_total), coefs_dofs )
431 print*,
'L2projection for', form,
'-form not implemented.'
440 sll_real64 :: coefs(:)
442 sll_int32 :: component
453 sll_real64 :: coefs1(:)
454 sll_real64 :: coefs2(:)
456 sll_int32,
optional :: component
459 if ( form == 0 )
then
461 self%mass_line0_2, self%mass_line0_3, &
462 coefs2, self%work(1:self%n_total) )
463 elseif (form == 1 )
then
464 select case(component)
467 self%mass_line0_2, self%mass_line0_3, &
468 coefs2, self%work(1:self%n_total) )
471 self%mass_line1_2, self%mass_line0_3, &
472 coefs2, self%work(1:self%n_total) )
475 self%mass_line0_2, self%mass_line1_3, &
476 coefs2, self%work(1:self%n_total) )
478 print*,
'wrong component.'
480 elseif( form == 2)
then
481 select case(component)
484 self%mass_line1_2, self%mass_line1_3, &
485 coefs2, self%work(1:self%n_total) )
488 self%mass_line0_2, self%mass_line1_3, &
489 coefs2, self%work(1:self%n_total) )
492 self%mass_line1_2, self%mass_line0_3, &
493 coefs2, self%work(1:self%n_total) )
495 print*,
'wrong component.'
497 elseif( form == 3)
then
499 self%mass_line1_2, self%mass_line1_3, &
500 coefs2, self%work(1:self%n_total) )
502 print*,
'Wrong form.'
505 r = sum(coefs1*self%work(1:self%n_total))
513 subroutine init_3d_fem_fft( self, domain, n_dofs, s_deg_0, adiabatic_electrons, profile )
515 sll_real64,
intent(in) :: domain(3,2)
516 sll_int32,
intent(in) :: n_dofs(3)
517 sll_int32,
intent(in) :: s_deg_0(3)
518 logical,
intent(in),
optional :: adiabatic_electrons
522 sll_real64,
allocatable :: eig_values_mass_0_1(:)
523 sll_real64,
allocatable :: eig_values_mass_0_2(:)
524 sll_real64,
allocatable :: eig_values_mass_0_3(:)
525 sll_real64,
allocatable :: eig_values_mass_1_1(:)
526 sll_real64,
allocatable :: eig_values_mass_1_2(:)
527 sll_real64,
allocatable :: eig_values_mass_1_3(:)
528 sll_real64,
allocatable :: inv_eig_values_mass_0_1(:)
529 sll_real64,
allocatable :: inv_eig_values_mass_0_2(:)
530 sll_real64,
allocatable :: inv_eig_values_mass_0_3(:)
531 sll_real64,
allocatable :: inv_eig_values_mass_1_1(:)
532 sll_real64,
allocatable :: inv_eig_values_mass_1_2(:)
533 sll_real64,
allocatable :: inv_eig_values_mass_1_3(:)
536 self%n_cells = n_dofs
538 self%n_total = product(n_dofs)
539 self%n_total0 = self%n_total
540 self%n_total1 = self%n_total
542 self%Lx = domain(:,2) - domain(:,1)
543 self%delta_x = self%Lx / real(n_dofs,f64)
544 self%s_deg_0 = s_deg_0
545 self%s_deg_1 = s_deg_0 - 1
547 self%volume = product(self%delta_x)
549 if(
present( adiabatic_electrons ) )
then
550 self%adiabatic_electrons = adiabatic_electrons
553 if(
present( profile ) )
then
554 self%profile = profile
558 allocate( self%work3d(n_dofs(1), n_dofs(2), n_dofs(3)) )
559 allocate( self%work(self%n_total*3) )
560 allocate( self%work2(self%n_total*3) )
561 allocate( self%work_d1( n_dofs(1) ) )
562 allocate( self%work_d2_in( n_dofs(2) ) )
563 allocate( self%work_d2_out( n_dofs(2) ) )
564 allocate( self%work_d3_in( n_dofs(3) ) )
565 allocate( self%work_d3_out( n_dofs(3) ) )
571 allocate( self%mass_line0_1(s_deg_0(1)+1) )
572 allocate( self%mass_line1_1(s_deg_0(1)) )
573 allocate( self%mass_line0_2(s_deg_0(2)+1) )
574 allocate( self%mass_line1_2(s_deg_0(2)) )
575 allocate( self%mass_line0_3(s_deg_0(3)+1) )
576 allocate( self%mass_line1_3(s_deg_0(3)) )
577 allocate( self%mass_line_mixed_1(2*s_deg_0(1)) )
578 allocate( self%mass_line_mixed_2(2*s_deg_0(2)) )
579 allocate( self%mass_line_mixed_3(2*s_deg_0(3)) )
594 self%mass_line0_1 = self%delta_x(1) * self%mass_line0_1
595 self%mass_line1_1 = self%delta_x(1) * self%mass_line1_1
596 self%mass_line_mixed_1 = self%delta_x(1) * self%mass_line_mixed_1
598 self%mass_line0_2 = self%delta_x(2) * self%mass_line0_2
599 self%mass_line1_2 = self%delta_x(2) * self%mass_line1_2
600 self%mass_line_mixed_2 = self%delta_x(2) * self%mass_line_mixed_2
602 self%mass_line0_3 = self%delta_x(3) * self%mass_line0_3
603 self%mass_line1_3 = self%delta_x(3) * self%mass_line1_3
604 self%mass_line_mixed_3 = self%delta_x(3) * self%mass_line_mixed_3
606 allocate( eig_values_mass_0_1( n_dofs(1) ) )
607 allocate( eig_values_mass_0_2( n_dofs(2) ) )
608 allocate( eig_values_mass_0_3( n_dofs(3) ) )
609 allocate( eig_values_mass_1_1( n_dofs(1) ) )
610 allocate( eig_values_mass_1_2( n_dofs(2) ) )
611 allocate( eig_values_mass_1_3( n_dofs(3) ) )
612 allocate( inv_eig_values_mass_0_1( n_dofs(1) ) )
613 allocate( inv_eig_values_mass_0_2( n_dofs(2) ) )
614 allocate( inv_eig_values_mass_0_3( n_dofs(3) ) )
615 allocate( inv_eig_values_mass_1_1( n_dofs(1) ) )
616 allocate( inv_eig_values_mass_1_2( n_dofs(2) ) )
617 allocate( inv_eig_values_mass_1_3( n_dofs(3) ) )
620 eig_values_mass_0_1 )
622 eig_values_mass_0_2 )
624 eig_values_mass_0_3 )
626 eig_values_mass_1_1 )
628 eig_values_mass_1_2 )
630 eig_values_mass_1_3 )
632 inv_eig_values_mass_0_1(1) = 1._f64/eig_values_mass_0_1(1)
633 inv_eig_values_mass_0_1(n_dofs(1)/2+1) = 1._f64/eig_values_mass_0_1(n_dofs(1)/2+1)
634 inv_eig_values_mass_1_1(1) = 1._f64/eig_values_mass_1_1(1)
635 inv_eig_values_mass_1_1(n_dofs(1)/2+1) = 1._f64/eig_values_mass_1_1(n_dofs(1)/2+1)
636 do j = 2, n_dofs(1)/2
637 inv_eig_values_mass_0_1(j) = 1._f64/eig_values_mass_0_1(j)
638 inv_eig_values_mass_0_1(n_dofs(1)+2-j) = 1._f64/eig_values_mass_0_1(n_dofs(1)+2-j)
639 inv_eig_values_mass_1_1(j) = 1._f64/eig_values_mass_1_1(j)
640 inv_eig_values_mass_1_1(n_dofs(1)+2-j) = 1._f64/eig_values_mass_1_1(n_dofs(1)+2-j)
643 inv_eig_values_mass_0_2(1) = 1._f64/eig_values_mass_0_2(1)
644 inv_eig_values_mass_0_2(n_dofs(2)/2+1) = 1._f64/eig_values_mass_0_2(n_dofs(2)/2+1)
645 inv_eig_values_mass_1_2(1) = 1._f64/eig_values_mass_1_2(1)
646 inv_eig_values_mass_1_2(n_dofs(2)/2+1) = 1._f64/eig_values_mass_1_2(n_dofs(2)/2+1)
647 do j = 2, n_dofs(2)/2
648 inv_eig_values_mass_0_2(j) = 1._f64/eig_values_mass_0_2(j)
649 inv_eig_values_mass_0_2(n_dofs(2)+2-j) = 1._f64/eig_values_mass_0_2(n_dofs(2)+2-j)
650 inv_eig_values_mass_1_2(j) = 1._f64/eig_values_mass_1_2(j)
651 inv_eig_values_mass_1_2(n_dofs(2)+2-j) = 1._f64/eig_values_mass_1_2(n_dofs(2)+2-j)
654 inv_eig_values_mass_0_3(1) = 1._f64/eig_values_mass_0_3(1)
655 inv_eig_values_mass_0_3(n_dofs(3)/2+1) = 1._f64/eig_values_mass_0_3(n_dofs(3)/2+1)
656 inv_eig_values_mass_1_3(1) = 1._f64/eig_values_mass_1_3(1)
657 inv_eig_values_mass_1_3(n_dofs(3)/2+1) = 1._f64/eig_values_mass_1_3(n_dofs(3)/2+1)
658 do j = 2, n_dofs(3)/2
659 inv_eig_values_mass_0_3(j) = 1._f64/eig_values_mass_0_3(j)
660 inv_eig_values_mass_0_3(n_dofs(3)+2-j) = 1._f64/eig_values_mass_0_3(n_dofs(3)+2-j)
661 inv_eig_values_mass_1_3(j) = 1._f64/eig_values_mass_1_3(j)
662 inv_eig_values_mass_1_3(n_dofs(3)+2-j) = 1._f64/eig_values_mass_1_3(n_dofs(3)+2-j)
665 if(self%adiabatic_electrons)
then
666 factor = self%profile%T_e( 0._f64 )/self%profile%rho_0( 0._f64 )
667 call self%inverse_mass_0%create( n_dofs, inv_eig_values_mass_0_1*factor, inv_eig_values_mass_0_2*factor, inv_eig_values_mass_0_3*factor )
669 call self%inverse_mass_0%create( n_dofs, inv_eig_values_mass_0_1, inv_eig_values_mass_0_2, inv_eig_values_mass_0_3 )
672 call self%inverse_mass_1(1)%create( n_dofs, inv_eig_values_mass_1_1, inv_eig_values_mass_0_2, inv_eig_values_mass_0_3 )
673 call self%inverse_mass_1(2)%create( n_dofs, inv_eig_values_mass_0_1, inv_eig_values_mass_1_2, inv_eig_values_mass_0_3 )
674 call self%inverse_mass_1(3)%create( n_dofs, inv_eig_values_mass_0_1, inv_eig_values_mass_0_2, inv_eig_values_mass_1_3 )
676 call self%inverse_mass_2(1)%create( n_dofs, inv_eig_values_mass_0_1, inv_eig_values_mass_1_2, inv_eig_values_mass_1_3 )
677 call self%inverse_mass_2(2)%create( n_dofs, inv_eig_values_mass_1_1, inv_eig_values_mass_0_2, inv_eig_values_mass_1_3 )
678 call self%inverse_mass_2(3)%create( n_dofs, inv_eig_values_mass_1_1, inv_eig_values_mass_1_2, inv_eig_values_mass_0_3 )
682 call self%poisson_fft%init( self%n_dofs, self%s_deg_0, self%delta_x )
694 call self%mass1(1)%create( linop_a=self%mass1d(1,3), &
695 linop_b=self%mass1d(1,2), &
696 linop_c=self%mass1d(2,1) )
697 call self%mass1(2)%create( linop_a=self%mass1d(1,3), &
698 linop_b=self%mass1d(2,2), &
699 linop_c=self%mass1d(1,1) )
700 call self%mass1(3)%create( linop_a=self%mass1d(2,3), &
701 linop_b=self%mass1d(1,2), &
702 linop_c=self%mass1d(1,1))
704 call self%mass2(1)%create( linop_a=self%mass1d(2,3), &
705 linop_b=self%mass1d(2,2), &
706 linop_c=self%mass1d(1,1) )
707 call self%mass2(2)%create( linop_a=self%mass1d(2,3), &
708 linop_b=self%mass1d(1,2), &
709 linop_c=self%mass1d(2,1) )
710 call self%mass2(3)%create( linop_a=self%mass1d(1,3), &
711 linop_b=self%mass1d(2,2), &
712 linop_c=self%mass1d(2,1))
715 call self%linear_op_schur_eb%create( eig_values_mass_0_1, eig_values_mass_0_2, eig_values_mass_0_3, eig_values_mass_1_1, eig_values_mass_1_2, eig_values_mass_1_3, self%n_dofs, self%delta_x )
726 call self%inverse_mass_0%free()
728 call self%inverse_mass_1(j)%free()
729 call self%inverse_mass_2(j)%free()
731 call self%poisson_fft%free()
732 deallocate( self%work )
733 deallocate( self%work3d )
734 deallocate( self%work2 )
735 deallocate( self%work_d1 )
736 deallocate( self%work_d2_in )
737 deallocate( self%work_d2_out )
738 deallocate( self%work_d3_in )
739 deallocate( self%work_d3_out )
741 deallocate( self%mass_line0_1 )
742 deallocate( self%mass_line1_1 )
743 deallocate( self%mass_line0_2 )
744 deallocate( self%mass_line1_2 )
745 deallocate( self%mass_line0_3 )
746 deallocate( self%mass_line1_3 )
747 deallocate( self%mass_line_mixed_1 )
748 deallocate( self%mass_line_mixed_2 )
749 deallocate( self%mass_line_mixed_3 )
757 sll_real64,
intent( in ) :: field_in(:)
758 sll_real64,
intent( out ) :: field_out(:)
768 sll_real64,
intent( in ) :: field_in(:)
769 sll_real64,
intent( out ) :: field_out(:)
779 sll_real64,
intent( in ) :: field_in(:)
780 sll_real64,
intent( out ) :: field_out(:)
790 sll_real64,
intent( in ) :: field_in(:)
791 sll_real64,
intent( out ) :: field_out(:)
801 sll_int32,
intent( in ) :: deg(:)
802 sll_real64,
intent( in ) :: coefs_in(:)
803 sll_real64,
intent( out ) :: coefs_out(:)
805 if(
size(deg) ==1 )
then
809 self%mass_line0_2, self%mass_line0_3, &
810 coefs_in, coefs_out )
816 sll_error(
'maxwell_3d_fem_fft',
'multiply mass for other form not yet implemented')
818 else if(
size(deg) == 3 )
then
828 sll_real64,
intent( in ) :: coefs_in(:)
829 sll_real64,
intent( out ) :: coefs_out(:)
831 sll_int32:: iend, istart
836 self%mass_line0_2, self%mass_line0_3, &
837 coefs_in(istart:iend), coefs_out(istart:iend) )
839 iend = iend + self%n_total
841 self%mass_line1_2, self%mass_line0_3, &
842 coefs_in(istart:iend), coefs_out(istart:iend) )
844 iend = iend + self%n_total
846 self%mass_line0_2, self%mass_line1_3, &
847 coefs_in(istart:iend), coefs_out(istart:iend) )
855 sll_real64,
intent(in) :: coefs_in(:)
856 sll_real64,
intent(out) :: coefs_out(:)
858 sll_int32:: iend, istart
863 self%mass_line1_2, self%mass_line1_3, &
864 coefs_in(istart:iend), coefs_out(istart:iend) )
866 iend = iend + self%n_total
868 self%mass_line0_2, self%mass_line1_3, &
869 coefs_in(istart:iend), coefs_out(istart:iend) )
871 iend = iend + self%n_total
873 self%mass_line1_2, self%mass_line0_3, &
874 coefs_in(istart:iend), coefs_out(istart:iend) )
883 sll_real64,
intent(in) :: mass_line_1(:)
884 sll_real64,
intent(in) :: mass_line_2(:)
885 sll_real64,
intent(in) :: mass_line_3(:)
886 sll_real64,
intent(in) :: coefs_in(:)
887 sll_real64,
intent(out) :: coefs_out(:)
889 sll_int32 :: i,j,k,istart,iend
892 deg(1) =
size(mass_line_1)-1
893 deg(2) =
size(mass_line_2)-1
894 deg(3) =
size(mass_line_3)-1
897 iend = self%n_dofs(1)
898 do k=1,self%n_dofs(3)
899 do j=1,self%n_dofs(2)
902 mass_line_1, coefs_in(istart:iend), self%work_d1 )
906 self%work3d(:,j,k) = self%work_d1
908 iend = iend + self%n_dofs(1)
912 do k=1,self%n_dofs(3)
913 do i =1,self%n_dofs(1)
914 self%work_d2_in = self%work3d(i,:,k)
916 mass_line_2, self%work_d2_in, self%work_d2_out )
917 self%work3d(i,:,k) = self%work_d2_out
922 do j=1,self%n_dofs(2)
923 do i =1,self%n_dofs(1)
924 self%work_d3_in = self%work3d(i,j,:)
926 mass_line_3, self%work_d3_in, self%work_d3_out )
928 do k=1,self%n_dofs(3)
929 coefs_out(istart+(k-1)*self%n_dofs(1)*self%n_dofs(2)) = self%work_d3_out(k)
941 sll_int32,
intent( in ) :: deg(:)
942 sll_real64,
intent( in ) :: coefs_in(:)
943 sll_real64,
intent( out ) :: coefs_out(:)
945 sll_int32 :: i,j,k,istart,iend
948 iend = self%n_dofs(1)
949 do k=1,self%n_dofs(3)
950 do j=1,self%n_dofs(2)
951 select case ( deg(1) )
954 self%mass_line0_1, coefs_in(istart:iend), self%work_d1 )
957 self%mass_line1_1, coefs_in(istart:iend), self%work_d1 )
960 self%mass_line_mixed_1, coefs_in(istart:iend), self%work_d1 )
962 print*,
'multiply_mass is not implemented for that spline degree.'
964 self%work3d(:,j,k) = self%work_d1
966 iend = iend + self%n_dofs(1)
970 do k=1,self%n_dofs(3)
971 do i =1,self%n_dofs(1)
972 self%work_d2_in = self%work3d(i,:,k)
973 select case ( deg(2) )
976 self%mass_line0_2, self%work_d2_in, self%work_d2_out )
979 self%mass_line1_2, self%work_d2_in, self%work_d2_out )
982 self%mass_line_mixed_2, self%work_d2_in, self%work_d2_out )
984 print*,
'multiply_mass is not implemented for that spline degree.'
986 self%work3d(i,:,k) = self%work_d2_out
991 do j=1,self%n_dofs(2)
992 do i =1,self%n_dofs(1)
993 self%work_d3_in = self%work3d(i,j,:)
994 select case ( deg(3) )
997 self%mass_line0_3, self%work_d3_in, self%work_d3_out )
1000 self%mass_line1_3, self%work_d3_in, self%work_d3_out )
1003 self%mass_line_mixed_3, self%work_d3_in, self%work_d3_out )
1005 print*,
'multiply_mass is not implemented for that spline degree.'
1008 do k=1,self%n_dofs(3)
1009 coefs_out(istart+(k-1)*self%n_dofs(1)*self%n_dofs(2)) = self%work_d3_out(k)
1022 sll_int32,
intent( in ) :: form
1023 sll_real64,
intent( in ) :: coefs_in(:)
1024 sll_real64,
intent( out ) :: coefs_out(:)
1028 call self%inverse_mass_0%solve( coefs_in, coefs_out )
1030 call self%inverse_mass_1(1)%solve( coefs_in(1:self%n_total), coefs_out(1:self%n_total) )
1031 call self%inverse_mass_1(2)%solve( coefs_in(self%n_total+1:2*self%n_total), coefs_out(self%n_total+1:2*self%n_total) )
1032 call self%inverse_mass_1(3)%solve( coefs_in(2*self%n_total+1:3*self%n_total), coefs_out(2*self%n_total+1:3*self%n_total) )
1034 call self%inverse_mass_2(1)%solve( coefs_in(1:self%n_total), coefs_out(1:self%n_total) )
1035 call self%inverse_mass_2(2)%solve( coefs_in(self%n_total+1:2*self%n_total), coefs_out(self%n_total+1:2*self%n_total) )
1036 call self%inverse_mass_2(3)%solve( coefs_in(2*self%n_total+1:3*self%n_total), coefs_out(2*self%n_total+1:3*self%n_total) )
1038 print*,
'inverse_mass for', form,
'-form not implemented.'
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 linear operator of kronecker solver
This linear operator implements the compatible spline FEM operator for the curl part of Maxwell's equ...
Invert a circulant matrix based on diagonalization in Fourier space (3d version)
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 based on FFT diagno...
subroutine sll_s_compute_e_from_rho_3d_fem_fft(self, field_in, field_out)
Compute E_i from rho_i integrated over the time interval using weak Poisson's equation.
subroutine sll_s_compute_b_from_e_3d_fem_fft(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 sll_s_compute_e_from_b_3d_fem_fft(self, delta_t, field_in, field_out)
compute Ey from Bz using weak Ampere formulation
subroutine multiply_mass_2form(self, coefs_in, coefs_out)
Helper function for multiply_mass.
subroutine free_3d_fem_fft(self)
Finalization.
subroutine multiply_ct(self, field_in, field_out)
Multiply by transpose of discrete curl matrix.
subroutine sll_s_compute_rhs_fem_fft(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 sll_s_compute_phi_from_rho_3d_fem_fft(self, field_in, field_out, efield_dofs)
Compute phi from rho_i integrated over the time interval.
subroutine sll_s_compute_rho_from_e_3d_fem_fft(self, field_in, field_out)
compute rho from e using weak Gauss law ( rho = G^T M_1 e )
subroutine multiply_g(self, field_in, field_out)
Multiply by dicrete gradient matrix.
subroutine sll_s_compute_e_from_j_3d_fem_fft(self, current, E, component)
Compute E_i from j_i integrated over the time interval using weak Ampere formulation.
subroutine l2projection_3d_fem_fft(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_c(self, field_in, field_out)
Multiply by discrete curl matrix.
subroutine init_3d_fem_fft(self, domain, n_dofs, s_deg_0, adiabatic_electrons, profile)
Initialization.
subroutine multiply_gt(self, field_in, field_out)
Multiply by transpose of dicrete gradient matrix.
subroutine sll_s_compute_curl_part_3d_fem_fft(self, delta_t, efield, bfield, betar)
Solve curl part of Maxwell's equations.
subroutine multiply_mass_inverse_all(self, form, coefs_in, coefs_out)
Multiply by the inverse mass matrix.
subroutine sll_s_compute_phi_from_j_3d_fem_fft(self, field_in, field_out, efield_dofs)
Compute phi from j_i integrated over the time interval, delta_t is already included.
real(kind=f64) function inner_product_3d_fem_fft(self, coefs1, coefs2, form, component)
Compute inner product.
subroutine multiply_mass_3d_fem_fft(self, deg, coefs_in, coefs_out)
Multiply by the mass matrix.
subroutine multiply_mass_all(self, deg, coefs_in, coefs_out)
Multiply by the mass matrix.
subroutine multiply_mass_1form(self, coefs_in, coefs_out)
Helper function for multiply_mass.
real(kind=f64) function l2norm_squared_3d_fem_fft(self, coefs, form, component)
Compute square of the L2norm.
subroutine multiply_mass_3dkron(self, mass_line_1, mass_line_2, mass_line_3, coefs_in, coefs_out)
Multiply by the mass matrix.
functions for initial profile of the particle distribution function
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)
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_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_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_multiply_gt(n_dofs, delta_x, field_in, field_out)
Multiply by transpose of dicrete gradient matrix (3d version)
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.
class for a linear operator
Linear solver for FFT-based inversion of 3d tensor product of circulant matrices (extending the abstr...