! fpois2d class for QuickPIC Open Source 1.0 ! update: 04/18/2016 module fpois2d_class use perrors_class use parallel_pipe_class use spect2d_class use ufield2d_class use fpois2d_lib implicit none private public :: fpois2d, get_pois2table type fpois2d private ! nd = system length in each direction ! a = half-width of particle in each direction ! anorm = normalization constant for poisson solver ! ffc = complex table for poisson solver ! ffg = real table for poisson solver class(spect2d), pointer, public :: sp => null() class(perrors), pointer, public :: err => null() class(parallel_pipe), pointer, public :: p => null() integer, dimension(2) :: nd real, dimension(2) :: a real :: anorm complex, dimension(:,:), pointer :: ffc => null() real, dimension(:,:,:), pointer :: ffg => null() contains generic :: new => init_fpois2d generic :: del => end_fpois2d generic :: potential => ipotd2 generic :: smoothf => ismoothfd2 generic :: elfield => ippoisd23 generic :: bfield => ibfieldd2 generic :: bfield_qp => jpbpoisd23n_qp procedure, private :: init_fpois2d procedure, private :: end_fpois2d procedure, private :: ipotd2, ismoothfd2, ippoisd23, ibfieldd2 procedure, private :: jpbpoisd23n_qp end type ! type fpois2d_link type (fpois2d_link), pointer :: next => null() type (fpois2d), pointer :: table => null() integer :: refcount end type fpois2d_link ! character(len=10), save :: class = 'fpois2d:' character(len=128), save :: erstr ! link list for poisson tables integer, save :: numtables = 0 type (fpois2d_link), target, save :: table_list contains ! subroutine init_fpois2d(this,pp,perr,psp,nx,ny,ax,ay,affp) implicit none class(fpois2d), intent(inout) :: this class(spect2d), intent(in), pointer :: psp class(perrors), intent(in), pointer :: perr class(parallel_pipe), intent(in), pointer :: pp integer, intent(in) :: nx, ny real, intent(in) :: ax, ay, affp ! local data character(len=18), save :: sname = 'init_fpois2d:' this%sp => psp this%err => perr this%p => pp if ((ax < 0.) .or. (ay < 0.)) then write (erstr,*) 'invalid ax or ay=', ax, ay call this%err%equit(class//sname//erstr) return endif call this%err%werrfl2(class//sname//' started') select case (this%sp%getpsolver()) case (1) this%nd = (/nx,ny/); this%a = (/ax,ay/) this%anorm = affp allocate(this%ffc(ny,(nx-1)/this%p%getlnvp()+1)) call ippoisd2init(this,ax,ay,affp,nx,ny,this%p%getlkstrt()) case default this%nd = (/nx,ny/); this%a = (/ax,ay/) this%anorm = affp allocate(this%ffc(ny,(nx-1)/this%p%getlnvp()+1)) call ippoisd2init(this,ax,ay,affp,nx,ny,this%p%getlkstrt()) end select call this%err%werrfl2(class//sname//' ended') end subroutine init_fpois2d ! subroutine end_fpois2d(this) implicit none class(fpois2d), intent(inout) :: this character(len=18), save :: sname = 'end_fpois2d' call this%err%werrfl2(class//sname//' started') if(associated(this%ffc)) deallocate(this%ffc) if(associated(this%ffg)) deallocate(this%ffg) call this%err%werrfl2(class//sname//' ended') return end subroutine end_fpois2d ! subroutine ippoisd2init(this,ax,ay,affp,nx,ny,kstrt) ! this subroutine initializes ffd table implicit none class(fpois2d), intent(in) :: this integer, intent(in) :: nx, ny, kstrt real, intent(in) :: ax, ay, affp ! local data integer :: isign = 0, nyv, kxp2, nyd real :: we complex, dimension(:,:), pointer:: ffd real, dimension(1,1) :: q real, dimension(2,1,1) :: fxy character(len=14), save :: sname = 'ippoisd2init:' call this%err%werrfl2(class//sname//' started') ffd => this%ffc nyv = size(q,1) nyd = size(ffd,1); kxp2 = size(ffd,2); call MPPOISD22(q,fxy,isign,ffd,ax,ay,affp,we,nx,ny,kstrt,nyv,kxp2,& &nyd) call this%err%werrfl2(class//sname//' ended') end subroutine ippoisd2init ! subroutine ipotd2(this,q,fx,we) ! this subroutine solves poisson's equation for potential with ! dirichlet (zero potential) boundary conditions and 1d partition ! this = fpois2d descriptor ! q = input charge density array, in fourier space ! fx = output potential array, in fourier space ! we = output potential energy implicit none class(fpois2d), intent(in) :: this real, intent(inout) :: we class(ufield2d), intent(inout) :: q, fx ! local data integer :: isign = 1 real, dimension(:,:,:), pointer :: pq => null(), pfx => null() character(len=8), save :: sname = 'ipotd2:' call this%err%werrfl2(class//sname//' started') select case (this%sp%getpsolver()) case (1) pq => q%getrf(); pfx => fx%getrf() call ippoisd2(this,pq,pfx,isign,we) case default pq => q%getrf(); pfx => fx%getrf() call ippoisd2(this,pq,pfx,isign,we) end select call this%err%werrfl2(class//sname//' ended') end subroutine ipotd2 ! subroutine ippoisd2(this,q,fx,isign,we) ! this subroutine solves poisson's equation for potential or smoothing ! with dirichlet (zero potential) boundary conditions and 1d partition ! this = poisson solver descriptor, includes table pointers ! q = input charge density array, in fourier space ! fx = output potential array, in fourier space ! isign = (1,2) = solve for (potential,smooth) ! we = output potential energy implicit none class(fpois2d), intent(in) :: this integer, intent(in) :: isign real, intent(inout) :: we real, dimension(:,:,:), pointer, intent(inout) :: q, fx ! local data integer :: nx, ny, nyv, kxp2, nyd complex, dimension(:,:), pointer :: ffc character(len=10), save :: sname = 'ippoisd2:' call this%err%werrfl2(class//sname//' started') ! unpack common arguments ffc => this%ffc nx = this%nd(1); ny = this%nd(2) nyv = size(q,2); nyd = size(ffc,1) kxp2 = size(q,3)-1; if (isign==1) then call MPPOTPD2(q(1,:,:),fx(1,:,:),ffc,we,nx,ny,this%p%getlkstrt(),& &nyv,kxp2,nyd) else if (isign==2) then call MPPSMOOTHD2(q(1,:,:),fx(1,:,:),ffc,nx,ny,this%p%getlkstrt(),& &nyv,kxp2,nyd) endif call this%err%werrfl2(class//sname//' ended') end subroutine ippoisd2 ! subroutine ismoothfd2(this,f,fs) ! this subroutine provides smoothing for fourier transformed data with ! 1d partition ! this = fpois2d descriptor ! f = input data, in fourier space ! fs = output data, in fourier space implicit none class(fpois2d), intent(in) :: this class(ufield2d), intent(inout) :: f, fs ! local data integer :: isign = 2 real :: we real, dimension(:,:,:), pointer :: pf, pfs character(len=12), save :: sname = 'ismoothfd2:' call this%err%werrfl2(class//sname//' started') select case (this%sp%getpsolver()) case (1) pf => f%getrf(); pfs => fs%getrf() call ippoisd2(this,pf,pfs,isign,we) case default pf => f%getrf(); pfs => fs%getrf() call ippoisd2(this,pf,pfs,isign,we) end select call this%err%werrfl2(class//sname//' ended') end subroutine ismoothfd2 ! subroutine ippoisd23(this,q,fxy,we) ! this subroutine solves poisson's equation for electric field ! with dirichlet (zero potential) boundary conditions and 1d partition ! this = fpois2d descriptor, includes table pointers ! q = input charge density array, in fourier space ! fxy = output electric field array, in fourier space ! we = output potential energy ! kstrt = starting data block number, a global variable implicit none class(fpois2d), intent(in) :: this class(ufield2d), intent(inout) :: q, fxy real, intent(inout) :: we ! local data integer :: isign = -1, nx, ny, nyv, kxp2, nyd real :: ax, ay, affp real, dimension(:,:,:), pointer :: pq real, dimension(:,:,:), pointer :: pfxy complex, dimension(:,:), pointer :: ffc character(len=11), save :: sname = 'ippoisd23:' call this%err%werrfl2(class//sname//' started') pq => q%getrf(); pfxy => fxy%getrf() if ((size(pfxy,1) < 2) .or. (size(pfxy,1) > 3)) then write (erstr,*) 'invalid vector size=', size(pfxy,1) call this%err%equit(class//sname//erstr) return endif ! unpack common arguments ffc => this%ffc nx = this%nd(1); ny = this%nd(2) ! choose the proper solver select case (this%sp%getpsolver()) case (1) nyv = size(pq,2); nyd = size(ffc,1) kxp2 = size(pq,3)-1; select case (size(pfxy,1)) case (2) call MPPOISD22(pq(1,:,:),pfxy,isign,ffc,ax,ay,affp,we,nx,ny,& &this%p%getlkstrt(),nyv,kxp2,nyd) case (3) call MPPOISD23(pq(1,:,:),pfxy,isign,ffc,ax,ay,affp,we,nx,ny,& &this%p%getlkstrt(),nyv,kxp2,nyd) end select case default nyv = size(pq,2); nyd = size(ffc,1) kxp2 = size(ffc,2); select case (size(pfxy,1)) case (2) call MPPOISD22(pq(1,:,:),pfxy,isign,ffc,ax,ay,affp,we,nx,ny,& &this%p%getlkstrt(),nyv,kxp2,nyd) case (3) call MPPOISD23(pq(1,:,:),pfxy,isign,ffc,ax,ay,affp,we,nx,ny,& &this%p%getlkstrt(),nyv,kxp2,nyd) end select end select call this%err%werrfl2(class//sname//' ended') end subroutine ippoisd23 ! subroutine ibfieldd2(this,cu,bxy,ci,wm) ! this subroutine solves poisson's equation for magnetic field ! with dirichlet (zero potential) boundary conditions and 1d partition ! this = fpois2d descriptor, includes table pointers ! cu = input current density array, in fourier space ! bxy = output magnetic field array, in fourier space ! ci = reciprical of velocity of light ! wm = output magnetic energy implicit none class(fpois2d), intent(in) :: this real, intent(in) :: ci real, intent(inout) :: wm class(ufield2d), intent(inout) :: cu, bxy ! local data integer :: isign = -1 real, dimension(:,:,:), pointer :: pcu, pbxy character(len=11), save :: sname = 'ibfieldd2:' call this%err%werrfl2(class//sname//' started') select case (this%sp%getpsolver()) case (1) pcu => cu%getrf(); pbxy => bxy%getrf() call jpbpoisd23(this,pcu,pbxy,isign,ci,wm) case default pcu => cu%getrf(); pbxy => bxy%getrf() call jpbpoisd23(this,pcu,pbxy,isign,ci,wm) end select call this%err%werrfl2(class//sname//' ended') end subroutine ibfieldd2 ! subroutine jpbpoisd23(this,cu,bxy,isign,ci,wm) ! this subroutine solves poisson's equation for magnetic field or ! vector potential or smoothing with dirichlet (zero potential) boundary ! conditions and 1d partition ! this = fpois2d descriptor, includes table pointers ! cu = input current density array, in fourier space ! bxy = output magnetic field array, in fourier space ! isign = (-1,1,2) = solve for (magnetic field,vector potential,smooth) ! ci = reciprical of velocity of light ! wm = output magnetic energy ! kstrt = starting data block number, a global variable implicit none class(fpois2d), intent(in) :: this integer, intent(in) :: isign real, intent(in) :: ci real, intent(inout) :: wm real, dimension(:,:,:), pointer, intent(inout) :: cu, bxy ! local data integer :: nx, ny, nyv, kxp2, j2blok, nyd real :: ax, ay, affp real, dimension(1,1,1) :: dxy complex, dimension(:,:), pointer :: ffc character(len=12), save :: sname = 'jpbpoisd23:' call this%err%werrfl2(class//sname//' started') if ((size(cu,1) < 2) .or. (size(cu,1) > 3)) then write (erstr,*) 'invalid cu vector size=', size(cu,1) call this%err%equit(class//sname//erstr) return endif if (size(cu,1) /= size(bxy,1)) then if ((size(cu,1)==2).and.((size(bxy,1)/=1).or.(isign/=(-1))))& &then write (erstr,*) 'invalid bxy vector size=', size(bxy,1) call this%err%equit(class//sname//erstr) return endif endif ! unpack common arguments ffc => this%ffc nx = this%nd(1); ny = this%nd(2) nyv = size(cu,2); nyd = size(ffc,1) kxp2 = size(cu,3)-1; select case (size(cu,1)) case (3) call MPPBBPOISD23(cu,bxy,ffc,ci,wm,nx,ny,this%p%getlkstrt(),nyv,& &kxp2,nyd) end select call this%err%werrfl2(class//sname//' ended') end subroutine jpbpoisd23 ! subroutine jpbpoisd23n_qp(this,cu,dcu,amu,bxy,ci,c,dex,wm) ! this = poisson solver descriptor ! cu = input current density array, in fourier space ! bxy = output magnetic field array, in fourier space ! isign = (-1,1,2) = solve for (magnetic field,vector potential,smooth) ! ci = reciprical of velocity of light ! wm = output magnetic energy ! kstrt = starting data block number, a global variable implicit none class(fpois2d), intent(in) :: this real, intent(in) :: ci, c, dex real, intent(inout) :: wm class(ufield2d), intent(inout) :: cu, dcu, amu, bxy ! local data integer :: isign = 1 real, dimension(:,:,:), pointer :: pcu, pdcu, pamu, pbxy integer :: nx, ny, nyv, kxp2, j2blok, nyd real :: ax, ay, affp real, dimension(1,1,1) :: dxy complex, dimension(:,:), pointer :: ffc character(len=20), save :: sname = 'jpbpoisd23n_qp:' call this%err%werrfl2(class//sname//' started') pcu => cu%getrf() pdcu => dcu%getrf() pamu => amu%getrf() pbxy => bxy%getrf() if ((size(pcu,1) < 2) .or. (size(pcu,1) > 3)) then write (erstr,*) 'invalid cu vector size=', size(pcu,1) call this%err%equit(class//sname//erstr) return endif ! unpack common arguments ffc => this%ffc nx = this%nd(1); ny = this%nd(2) ! choose the proper solver select case (this%sp%getpsolver()) case (1) nyv = size(pcu,2); nyd = size(ffc,1) kxp2 = size(ffc,2); j2blok = 1 call PBPOISD22N_QP(pcu,pdcu,pamu,pbxy,dxy,isign,ffc,ax,ay,& &affp,ci,wm,nx,ny,this%p%getlkstrt(),nyv,kxp2,j2blok,nyd,c,dex) case default nyv = size(pcu,2); nyd = size(ffc,1) kxp2 = size(ffc,2); j2blok = 1 call PBPOISD22N_QP(pcu,pdcu,pamu,pbxy,dxy,isign,ffc,ax,ay,& &affp,ci,wm,nx,ny,this%p%getlkstrt(),nyv,kxp2,j2blok,nyd,c,dex) end select call this%err%werrfl2(class//sname//' ended') end subroutine jpbpoisd23n_qp ! function get_pois2table(pp,perr,psp,ax,ay,affp) result(table) implicit none class(spect2d), intent(in), pointer :: psp class(perrors), intent(in), pointer :: perr class(parallel_pipe), intent(in), pointer :: pp real, intent(in) :: ax, ay, affp type (fpois2d), pointer :: table ! local data type (fpois2d_link), pointer :: link => null() type (fpois2d), pointer :: ltable => null() integer :: nx, ny, ierr = 0 character(len=18), save :: sname = 'get_pois2table:' call perr%werrfl2(class//sname//' started') nullify(table) if (numtables==0) then nullify(table_list%next,table_list%table) table_list%refcount = 0 endif nx = 2**psp%getindx() ny = 2**psp%getindy() link => table_list table => link%table ! search link list of table to see if required table already exists do while (associated(table)) ! found it if ((nx==table%nd(1)).and.(ny==table%nd(2)).and.(ax==table%a(1))& &.and.(ay==table%a(2)).and.(affp==table%anorm).and.(psp%getpsolver()& &==table%sp%getpsolver())) then link%refcount = link%refcount + 1 call perr%werrfl2(class//sname//' ended') return ! check next table, create new empty table if end is reached else if (associated(link%next)) then link => link%next else allocate(link%next) link => link%next nullify(link%next,link%table) link%refcount = 0 endif table => link%table endif end do ! allocate table entries allocate(ltable) link%table => ltable table => link%table call table%new(pp,perr,psp,nx,ny,ax,ay,affp) link%refcount = 1 numtables = numtables + 1 call perr%werrfl2(class//sname//' ended') end function get_pois2table ! end module fpois2d_class