! ufield3d class for QuickPIC Open Source 1.0 ! update: 04/18/2016 module ufield3d_class use perrors_class use parallel_pipe_class use spect3d_class use ufield3d_lib use ufield2d_class use hdf5io_class use mpi implicit none private public :: ufield3d type ufield3d private ! dim = dimension of the field ! nd1, nd2, nd3 = size of global array data in each dimension ! nvpx, nvpy, nvpz = number of processors in each dimension ! nd1p, nd2p, nd3p = size of local array data in each dimension (without guardcell) ! rf = pointer of the local 3d field array ! noff = smallest global gridpoint in y ! class(spect3d), pointer, public :: sp => null() class(perrors), pointer, public :: err => null() class(parallel_pipe), pointer, public :: p => null() integer :: dim integer, dimension(2) :: noff integer :: nd1, nvpx, nd1p integer :: nd2, nvpy, nd2p integer :: nd3, nvpz, nd3p real, dimension(:,:,:,:), pointer :: rf => null() contains generic :: new => init_ufield3d generic :: del => end_ufield3d generic :: pcg => copyguard_pipe generic :: ag => acopyguard generic :: cp => copyin generic :: cb => copyout generic :: ca => copyadd generic :: wr => writehdf5_3d, writehdf5_2dslice generic :: as => asc,asa generic :: add => sum generic :: sub => minus generic :: mult => multiply final :: final_ufield3d procedure, private :: init_ufield3d procedure, private :: end_ufield3d procedure :: getdim procedure :: getnd1, getnvpx, getnd1p procedure :: getnd2, getnvpy, getnd2p procedure :: getnd3, getnvpz, getnd3p procedure :: getrf, getnoff procedure, private :: copyguard_pipe, acopyguard procedure, private :: copyin, copyout, copyadd procedure, private :: writehdf5_3d, writehdf5_2dslice procedure, private :: asc, asa, sum, minus, multiply end type character(len=10), save :: class = 'ufield3d:' character(len=128), save :: erstr contains ! subroutine init_ufield3d(this,pp,perr,psp,dim,nvpx,nvpy,nvpz) implicit none class(ufield3d), intent(inout) :: this integer, intent(in) :: dim integer, intent(in) :: nvpx,nvpy,nvpz class(spect3d), intent(in), pointer :: psp class(perrors), intent(in), pointer :: perr class(parallel_pipe), intent(in), pointer :: pp ! local data character(len=18), save :: sname = 'init_ufield3d:' integer :: nd1,nd2,nd3 call perr%werrfl2(class//sname//' started') this%sp => psp this%err => perr this%p => pp this%dim = dim nd1 = 2**psp%getindx() nd2 = 2**psp%getindy() nd3 = 2**psp%getindz() this%nd1 = nd1 this%nd2 = nd2 this%nd3 = nd3 ! make sure data is a multiple of the number of processors if ((((this%nd2/nvpy)*nvpy)/=this%nd2) .and. (((nvpy/this%nd2)*& &this%nd2)/=nvpy)) then write (erstr,*) 'data, proc number not multiples:', this%nd2& &, nvpy call this%err%equit(class//sname//erstr) return endif ! save number of processors in each dimension this%nvpx = 0 this%nvpy = nvpy this%nvpz = nvpz this%nd1p = nd1 this%nd2p = nd2/nvpy this%nd3p = nd3/nvpz this%noff(1) = (pp%getlkstrt()-1)*nd2/nvpy this%noff(2) = pp%getstageid()*nd3/pp%getnstage() allocate(this%rf(dim,this%nd1p+2,this%nd2p+1,this%nd3p+1)) this%rf(:,:,:,:) = 0.0 call perr%werrfl2(class//sname//' ended') end subroutine init_ufield3d ! subroutine end_ufield3d(this) implicit none class(ufield3d), intent(inout) :: this ! local data character(len=18), save :: sname = 'end_ufield3d:' call this%err%werrfl2(class//sname//' started') if (associated(this%rf)) deallocate(this%rf) call this%err%werrfl2(class//sname//' ended') end subroutine end_ufield3d ! subroutine final_ufield3d(this) implicit none type(ufield3d), intent(inout) :: this ! local data character(len=18), save :: sname = 'final_ufield3d:' call this%err%werrfl2(class//sname//' started') if (associated(this%rf)) deallocate(this%rf) call this%err%werrfl2(class//sname//' ended') end subroutine final_ufield3d ! function getnvpy(this) implicit none class(ufield3d), intent(in) :: this integer :: getnvpy getnvpy = this%nvpy end function getnvpy ! function getnvpx(this) implicit none class(ufield3d), intent(in) :: this integer :: getnvpx getnvpx = this%nvpx end function getnvpx ! function getnvpz(this) implicit none class(ufield3d), intent(in) :: this integer :: getnvpz getnvpz = this%nvpz end function getnvpz ! function getnd2(this) implicit none class(ufield3d), intent(in) :: this integer :: getnd2 getnd2 = this%nd2 end function getnd2 ! function getnd1(this) implicit none class(ufield3d), intent(in) :: this integer :: getnd1 getnd1 = this%nd1 end function getnd1 ! function getnd3(this) implicit none class(ufield3d), intent(in) :: this integer :: getnd3 getnd3 = this%nd3 end function getnd3 ! function getnd3p(this) implicit none class(ufield3d), intent(in) :: this integer :: getnd3p getnd3p = this%nd3p end function getnd3p ! function getnd2p(this) implicit none class(ufield3d), intent(in) :: this integer :: getnd2p getnd2p = this%nd2p end function getnd2p ! function getnd1p(this) implicit none class(ufield3d), intent(in) :: this integer :: getnd1p getnd1p = this%nd1p end function getnd1p ! function getdim(this) implicit none class(ufield3d), intent(in) :: this integer :: getdim getdim = this%dim end function getdim ! function getnoff(this) implicit none class(ufield3d), intent(in) :: this integer, dimension(2) :: getnoff getnoff = this%noff end function getnoff ! function getrf(this) implicit none class(ufield3d), intent(in) :: this real, dimension(:,:,:,:), pointer :: getrf getrf => this%rf end function getrf ! subroutine copyguard_pipe(this,rtag,stag,rid,sid) implicit none class(ufield3d), intent(inout) :: this integer, intent(in) :: rtag, stag integer, intent(inout) :: rid, sid ! local data integer :: nvpy, nvpz, kyp, kzp, ngds = 1 real, dimension(:,:,:,:), pointer :: f character(len=18), save :: sname = 'copyguard:' integer :: nxv, nypmx, nzpmx, ierr real, dimension(:,:,:), pointer :: scs call this%err%werrfl2(class//sname//' started') f => this%rf nxv = size(f,1)*size(f,2); nypmx = size(f,3); nzpmx = size(f,4) nvpy=this%p%getlnvp(); kyp = this%nd2p; kzp= this%nd3p nvpz=this%p%getnstage() allocate(scs(size(f,1)*size(f,2),size(f,4),2*ngds)) select case (this%sp%getpsolver()) case (1) select case (this%sp%getinorder()) case (1) call PCGUARD32L(f,scs,this%p%getkstrt(),nvpy,nvpz,nxv,nypmx,nzpmx,& &1,1,kyp,kzp,ngds,rtag,stag,rid,sid,ierr) if (this%p%getstageid() == 0) then sid = MPI_REQUEST_NULL endif if (this%p%getstageid() == this%p%getnstage()-1) then rid = MPI_REQUEST_NULL endif case default call PCGUARD32L(f,scs,this%p%getkstrt(),nvpy,nvpz,nxv,nypmx,nzpmx,& &1,1,kyp,kzp,ngds,rtag,stag,rid,sid,ierr) if (this%p%getstageid() == 0) then sid = MPI_REQUEST_NULL endif if (this%p%getstageid() == this%p%getnstage()-1) then rid = MPI_REQUEST_NULL endif end select case default call PCGUARD32L(f,scs,this%p%getkstrt(),nvpy,nvpz,nxv,nypmx,nzpmx,& &1,1,kyp,kzp,ngds,rtag,stag,rid,sid,ierr) if (this%p%getstageid() == 0) then sid = MPI_REQUEST_NULL endif if (this%p%getstageid() == this%p%getnstage()-1) then rid = MPI_REQUEST_NULL endif end select call this%err%werrfl2(class//sname//' ended') deallocate(scs) end subroutine copyguard_pipe ! subroutine acopyguard(this,rtag,stag,id) implicit none class(ufield3d), intent(inout) :: this integer, intent(in) :: rtag, stag integer, intent(inout) :: id ! local data integer :: nvpy, nvpz, nx, kyp, kzp, ngds = 1 real, dimension(:,:,:,:), pointer :: f character(len=18), save :: sname = 'acopyguard:' integer :: nxv, nypmx, nzpmx, ierr real, dimension(:,:,:,:), pointer :: scs, scr call this%err%werrfl2(class//sname//' started') f => this%rf nxv = size(f,2); nypmx = size(f,3); nzpmx = size(f,4) nvpy=this%p%getlnvp(); kyp = this%nd2p; kzp= this%nd3p nvpz=this%p%getnstage(); nx = this%nd1p if (size(f,1) == 1) then allocate(scs(size(f,2),size(f,4),2*ngds,1),scr(size(f,2),size(f,3),& &ngds,1)) else if (size(f,1) == 3) then allocate(scs(size(f,1),size(f,2),size(f,4),2*ngds)) end if select case (this%sp%getpsolver()) case (1) select case (this%sp%getinorder()) case (1) if (size(f,1) == 1) then call PAGUARD32L(f,scs,scr,this%p%getkstrt(),nvpy,nvpz,nx,nxv,& &nypmx,nzpmx,1,1,kyp,kzp,ngds,rtag,stag,id,ierr) if (this%p%getstageid() == this%p%getnstage() - 1) then id = MPI_REQUEST_NULL endif else if (size(f,1) == 3) then call PACGUARD32L(f,scs,this%p%getlkstrt(),nvpy,nvpz,nx,nxv,& &nypmx,nzpmx,1,1,kyp,kzp,ngds) end if case default call PAGUARD32L(f,scs,scr,this%p%getkstrt(),nvpy,nvpz,nx,nxv,& &nypmx,nzpmx,1,1,kyp,kzp,ngds,rtag,stag,id,ierr) end select case default call PAGUARD32L(f,scs,scr,this%p%getkstrt(),nvpy,nvpz,nx,nxv,& &nypmx,nzpmx,1,1,kyp,kzp,ngds,rtag,stag,id,ierr) end select deallocate(scs,scr) call this%err%werrfl2(class//sname//' ended') end subroutine acopyguard ! subroutine copyin(this,fd2d,lpos,sdim,ddim) ! copy 2d field to 3d field at the local longitudinal position lpos implicit none class(ufield3d), intent(inout) :: this class(ufield2d), intent(in), target :: fd2d integer, intent(in) :: lpos integer, dimension(:), intent(in):: sdim, ddim ! local data character(len=18), save :: sname = 'copyin:' real, dimension(:,:,:), pointer :: rf2d integer :: i,j,k,rank,nd1,nd2 call this%err%werrfl2(class//sname//' started') rf2d => fd2d%getrf() rank = size(sdim) nd1 = size(this%rf,2) nd2 = size(this%rf,3) !$OMP PARALLEL DO PRIVATE(i,j,k) do k = 1, nd2 do j = 1, nd1 do i = 1, rank this%rf(ddim(i),j,k,lpos) = rf2d(sdim(i),j,k) enddo enddo enddo !$OMP END PARALLEL DO call this%err%werrfl2(class//sname//' ended') end subroutine copyin ! subroutine copyout(this,fd2d,lpos,sdim,ddim) ! copy 3d field from the local longitudinal position lpos to a 2d field implicit none class(ufield3d), intent(inout) :: this class(ufield2d), intent(in), target :: fd2d integer, intent(in) :: lpos integer, dimension(:), intent(in):: sdim, ddim ! local data character(len=18), save :: sname = 'copyout:' real, dimension(:,:,:), pointer :: rf2d integer :: i,j,k,rank,nd1,nd2 call this%err%werrfl2(class//sname//' started') rf2d => fd2d%getrf() rank = size(sdim) nd1 = size(this%rf,2) nd2 = size(this%rf,3) !$OMP PARALLEL DO PRIVATE(i,j,k) do k = 1, nd2 do j = 1, nd1 do i = 1, rank rf2d(ddim(i),j,k) = this%rf(sdim(i),j,k,lpos) enddo enddo enddo !$OMP END PARALLEL DO call this%err%werrfl2(class//sname//' ended') end subroutine copyout ! subroutine copyadd(this,fd2d,lpos,sdim,ddim) ! copy 3d field from the local longitudinal position lpos to a 2d field implicit none class(ufield3d), intent(inout) :: this class(ufield2d), intent(in), target :: fd2d integer, intent(in) :: lpos integer, dimension(:), intent(in):: sdim, ddim ! local data character(len=18), save :: sname = 'copyadd:' real, dimension(:,:,:), pointer :: rf2d integer :: i,j,k,rank,nd1,nd2 call this%err%werrfl2(class//sname//' started') rf2d => fd2d%getrf() rank = size(sdim) nd1 = size(this%rf,2) nd2 = size(this%rf,3) !$OMP PARALLEL DO PRIVATE(i,j,k) do k = 1, nd2 do j = 1, nd1 do i = 1, rank rf2d(ddim(i),j,k) = rf2d(ddim(i),j,k) + this%rf(sdim(i),j,k,lpos) enddo enddo enddo !$OMP END PARALLEL DO call this%err%werrfl2(class//sname//' ended') end subroutine copyadd ! subroutine writehdf5_3d(this,file,dim,rtag,stag,id) implicit none class(ufield3d), intent(inout) :: this class(hdf5file), intent(in) :: file integer, intent(in) :: dim, rtag, stag integer, intent(inout) :: id ! local data integer, dimension(3) :: gsize, lsize integer, dimension(2) :: noff integer :: ierr character(len=18), save :: sname = 'writehdf5_3d:' call this%err%werrfl2(class//sname//' started') gsize = (/this%nd1,this%nd2,this%nd3/) lsize = (/this%nd1p,this%nd2p,this%nd3p/) noff = this%noff call pwfield_pipe(this%p,this%err,file,this%rf(dim,:,:,:),gsize,lsize,& &noff,rtag,stag,id,ierr) call this%err%werrfl2(class//sname//' ended') end subroutine writehdf5_3d ! subroutine writehdf5_2dslice(this,file,dim,slice,spos,rtag,stag,id) ! spos = global position of the slice implicit none class(ufield3d), intent(inout) :: this class(hdf5file), intent(in) :: file integer, intent(in) :: dim, rtag, stag, slice, spos integer, intent(inout) :: id ! local data integer, dimension(2) :: gsize, lsize integer, dimension(2) :: noff integer :: ks, lpos, ierr character(len=18), save :: sname = 'writehdf5_2dslice:' call this%err%werrfl2(class//sname//' started') noff = this%noff select case (slice) case (1) gsize = (/this%nd2,this%nd3/) if (this%p%getnstage() == 1) then lsize = (/this%nd2p,this%nd3p/) call pwfield_pipe(this%p,this%err,file,this%rf(dim,spos,:,:),& &gsize,lsize,noff,rtag,stag,id,ierr) else if (this%p%getstageid() == 0) then lsize = (/this%nd2p,this%nd3p+1/) call pwfield_pipe(this%p,this%err,file,this%rf(dim,spos,:,:),& &gsize,lsize,noff,rtag,stag,id,ierr) else if (this%p%getstageid() /= (this%p%getnstage()-1)) then lsize = (/this%nd2p,this%nd3p/) call pwfield_pipe(this%p,this%err,file,this%rf(dim,spos,:,2:),& &gsize,lsize,noff+(/0,1/),rtag,stag,id,ierr) else lsize = (/this%nd2p,this%nd3p-1/) call pwfield_pipe(this%p,this%err,file,this%rf(dim,spos,:,2:),& &gsize,lsize,noff+(/0,1/),rtag,stag,id,ierr) end if end if case (2) ks = (spos-1)/this%nd2p if (this%p%getlkstrt() == ks + 1) then gsize = (/this%nd1,this%nd3/) if (this%p%getnstage() == 1) then lsize = (/this%nd1p,this%nd3p/) lpos = spos - ks*this%nd2p call wfield_pipe(this%p,this%err,file,this%rf(dim,:,lpos,:),& &gsize,lsize,noff,rtag,stag,id,ierr) else if (this%p%getstageid() == 0) then lsize = (/this%nd1p,this%nd3p+1/) lpos = spos - ks*this%nd2p call wfield_pipe(this%p,this%err,file,this%rf(dim,:,lpos,:),& &gsize,lsize,noff,rtag,stag,id,ierr) else if (this%p%getstageid() /= (this%p%getnstage()-1)) then lsize = (/this%nd1p,this%nd3p/) lpos = spos - ks*this%nd2p call wfield_pipe(this%p,this%err,file,this%rf(dim,:,lpos,2:),& &gsize,lsize,noff+(/0,1/),rtag,stag,id,ierr) else lsize = (/this%nd1p,this%nd3p-1/) lpos = spos - ks*this%nd2p call wfield_pipe(this%p,this%err,file,this%rf(dim,:,lpos,2:),& &gsize,lsize,noff+(/0,1/),rtag,stag,id,ierr) end if end if else id = MPI_REQUEST_NULL endif case (3) ks = (spos-1)/this%nd3p if (this%p%getstageid() == ks) then gsize = (/this%nd1,this%nd2/) lsize = (/this%nd1p,this%nd2p/) lpos = spos - ks*this%nd3p call pwfield(this%p,this%err,file,this%rf(dim,:,:,lpos),& &gsize,lsize,noff(1),ierr) endif id = MPI_REQUEST_NULL end select call this%err%werrfl2(class//sname//' ended') end subroutine writehdf5_2dslice ! subroutine sum(this,a1,a2) implicit none class(ufield3d),intent(inout) :: this class(ufield3d), target, intent(in) :: a1,a2 ! local data character(len=18), save :: sname = 'sum:' integer :: i,j,k,l real, dimension(:,:,:,:), pointer :: rf1 => null(), rf2 => null(),& &rf3 => null() call this%err%werrfl2(class//sname//' started') rf1 => this%rf rf2 => a1%rf rf3 => a2%rf !$OMP PARALLEL DO PRIVATE(i,j,k,l) do l = 1, size(rf1,4) do k = 1, size(rf1,3) do j = 1, size(rf1,2) do i = 1, size(rf1,1) rf1(i,j,k,l) = rf2(i,j,k,l) + rf3(i,j,k,l) enddo enddo enddo enddo !$OMP END PARALLEL DO call this%err%werrfl2(class//sname//' ended') end subroutine sum ! subroutine minus(this,a1,a2) implicit none class(ufield3d),intent(inout) :: this class(ufield3d), target, intent(in) :: a1,a2 ! local data character(len=18), save :: sname = 'minus:' integer :: i,j,k,l real, dimension(:,:,:,:), pointer :: rf1 => null(), rf2 => null(),& &rf3 => null() call this%err%werrfl2(class//sname//' started') rf1 => this%rf rf2 => a1%rf rf3 => a2%rf !$OMP PARALLEL DO PRIVATE(i,j,k) do l = 1, size(rf1,4) do k = 1, size(rf1,3) do j = 1, size(rf1,2) do i = 1, size(rf1,1) rf1(i,j,k,l) = rf2(i,j,k,l) - rf3(i,j,k,l) enddo enddo enddo enddo !$OMP END PARALLEL DO call this%err%werrfl2(class//sname//' ended') end subroutine minus ! subroutine multiply(this,a1,value) implicit none class(ufield3d), intent(inout) :: this class(ufield3d), target, intent(in) :: a1 real, intent(in) :: value ! local data character(len=18), save :: sname = 'multiply:' integer :: i,j,k,l real, dimension(:,:,:,:), pointer :: rf1 => null(), rf2 => null() call this%err%werrfl2(class//sname//' started') rf1 => this%rf rf2 => a1%rf !$OMP PARALLEL DO PRIVATE(i,j,k) do l = 1, size(rf1,4) do k = 1, size(rf1,3) do j = 1, size(rf1,2) do i = 1, size(rf1,1) rf1(i,j,k,l) = rf2(i,j,k,l) * value enddo enddo enddo enddo !$OMP END PARALLEL DO call this%err%werrfl2(class//sname//' ended') end subroutine multiply ! subroutine asc(this,value) implicit none class(ufield3d), intent(inout) :: this real, intent(in) :: value ! local data character(len=18), save :: sname = 'asc:' integer :: i,j,k,l real, dimension(:,:,:,:), pointer :: rf => null() call this%err%werrfl2(class//sname//' started') rf => this%rf !$OMP PARALLEL DO PRIVATE(i,j,k) do l = 1, size(rf,4) do k = 1, size(rf,3) do j = 1, size(rf,2) do i = 1, size(rf,1) rf(i,j,k,l) = value enddo enddo enddo enddo !$OMP END PARALLEL DO call this%err%werrfl2(class//sname//' ended') end subroutine asc ! subroutine asa(this,that) implicit none class(ufield3d), intent(inout) :: this class(ufield3d), target, intent(in) :: that ! local data character(len=18), save :: sname = 'asa:' integer :: i,j,k,l real, dimension(:,:,:,:), pointer :: rf1 => null(), rf2 => null() call this%err%werrfl2(class//sname//' started') rf1 => this%rf rf2 => that%rf !$OMP PARALLEL DO PRIVATE(i,j,k) do l = 1, size(rf1,4) do k = 1, size(rf1,3) do j = 1, size(rf1,2) do i = 1, size(rf1,1) rf1(i,j,k,l) = rf2(i,j,k,l) enddo enddo enddo enddo !$OMP END PARALLEL DO ! deallocate(rf2) call this%err%werrfl2(class//sname//' ended') end subroutine asa ! end module ufield3d_class