! $Id$
!
! This module contains subroutines for particle-mesh related
! operations.
!
!** AUTOMATIC CPARAM.INC GENERATION ************************************
! Declare (for generation of cparam.inc) the number of f array
! variables and auxiliary variables added by this module
!
! CPARAM logical, parameter :: lparticles_blocks = .false.
!
!***********************************************************************
module Particles_map
!
use Cdata
use General, only: keep_compiler_quiet
use Messages
use Particles_cdata
use Particles_mpicomm
!
implicit none
!
include "particles_map.h"
!
interface interpolate_linear
module procedure interpolate_linear_range
module procedure interpolate_linear_scalar
endinterface
!
public :: distribute_particles, collect_particles
public :: pm_interpolation, pm_assignment
public :: map_particles
!
! Data types for particles in cell.
!
type, public :: particle
integer :: proc ! Parent process rank if a ghost particle; -1, otherwise.
integer :: id ! Index in the fp array.
real :: weight ! Weight contributed to a cell in code mass unit.
real :: eps ! Particle-to-gas density ratio.
real, dimension(3) :: x, xi ! Particle position in real space and in index space.
real, dimension(3) :: v, dv ! Particle velocity and its change.
endtype particle
!
type, public :: pic
real :: rho ! Gas density.
real, dimension(3) :: u, du ! Gas velocity and its change.
integer :: np ! Number of particles in the cell.
type(particle), dimension(:), pointer :: p ! Particles in the cell.
endtype pic
!
! Module variables
!
real, dimension(:,:), allocatable :: xi
real, dimension(3) :: dxi_diag = 0.0
real :: rinf = 0.0
!
contains
!***********************************************************************
!***********************************************************************
! PUBLIC PROCEDURES GO BELOW HERE.
!***********************************************************************
!***********************************************************************
subroutine initialize_particles_map()
!
! Perform any post-parameter-read initialization.
!
! 28-apr-16/ccyang: coded.
!
! Note: Currently, this subroutine is called after modules
! Particles_mpicomm and Particles.
!
! Check the particle-mesh interpolation method.
!
lparticlemesh_gab = .false.
!
pm: select case (particle_mesh)
!
case ('ngp', 'NGP') pm
! Nearest-Grid-Point
rinf = 0.0
lparticlemesh_cic = .false.
lparticlemesh_tsc = .false.
if (lroot) print *, 'initialize_particles_map: selected nearest-grid-point for particle-mesh method. '
!
case ('cic', 'CIC') pm
! Cloud-In-Cell
rinf = 0.5
lparticlemesh_cic = .true.
lparticlemesh_tsc = .false.
if (lroot) print *, 'initialize_particles_map: selected cloud-in-cell for particle-mesh method. '
!
case ('tsc', 'TSC') pm
! Triangular-Shaped-Cloud
rinf = 1.0
lparticlemesh_cic = .false.
lparticlemesh_tsc = .true.
if (lroot) print *, 'initialize_particles_map: selected triangular-shaped-cloud for particle-mesh method. '
!
case ('3rd') pm
! Third-order kernel
rinf = 1.5
lparticlemesh_cic = .false.
lparticlemesh_tsc = .false.
if (lroot) print *, 'initialize_particles_map: selected third-order kernel for particle-mesh method. '
case ('6th') pm
! Third-order kernel
rinf = 3.0
lparticlemesh_cic = .false.
lparticlemesh_tsc = .false.
if (lroot) print *, 'initialize_particles_map: selected sixth-order kernel for particle-mesh method. '
case ('etsc', 'ETSC') pm
! Extended TSC with radius 2
rinf = 2.0
lparticlemesh_cic = .false.
lparticlemesh_tsc = .false.
if (lroot) print *, 'initialize_particles_map: ', &
'selected extended triangular-shaped-cloud with radius 2 for particle-mesh method. '
case ('etsc2', 'ETSC2') pm
! Extended TSC with radius 3
rinf = 3.0
lparticlemesh_cic = .false.
lparticlemesh_tsc = .false.
if (lroot) print *, 'initialize_particles_map: ', &
'selected extended triangular-shaped-cloud with radius 3 for particle-mesh method. '
case default pm
call fatal_error('initialize_particles_map', "unknown particle-mesh type '" // trim(particle_mesh) // "'")
!
endselect pm
!
dxi_diag = merge((/rinf, rinf, rinf/), (/0.0, 0.0, 0.0/), lactive_dimension)
!
endsubroutine initialize_particles_map
!***********************************************************************
subroutine collect_particles(f, fp, npsend, sendlist, ghost, cell, ngp_send, ngp_recv, lupdate_par, lupdate_gas, lpmbr)
!
! Collect the change in velocities and deallocate the working arrays.
!
! 08-may-16/ccyang: coded.
! 21-jun-17/ccyang: accommodated Particles_mass.
!
! Input/Output Arguments
! f, fp
! The f and fp arrays.
! Input Arguments
! npsend
! Number of particles that are required to be communicated.
! sendlist
! Indices of the particles to be communicated; deallocated when
! done.
! ghost
! Received particles from other processes; deallocated when
! done.
! cell
! Complete final paricle-in-cell information.
! ngp_send
! The i-th element is the number of particles to be sent from
! this process to process pointed to by iproc_comm(i).
! The zeroth is that to be sent to itself.
! ngp_recv
! The i-th element is the number of particles to be received
! from process pointed to by iproc(i).
! The zeroth is that to be received from itself.
! lupdate_par
! Update the particle velocities or not.
! lupdate_gas
! Update the gas velocity or not.
! lpmbr
! Use particle-mesh back reaction or not.
!
real, dimension(mx,my,mz,mfarray), intent(inout) :: f
real, dimension(mpar_loc,mparray), intent(inout) :: fp
type(particle), dimension(:), pointer :: ghost
integer, dimension(:), pointer :: sendlist
type(pic), dimension(nx,ny,nz), intent(inout) :: cell
integer, dimension(0:nproc_comm), intent(in) :: ngp_send, ngp_recv
integer, intent(in) :: npsend
logical, intent(in) :: lupdate_par, lupdate_gas, lpmbr
!
type(particle), dimension(:), allocatable :: packet
real, dimension(npar_loc,3) :: dmv
integer :: stat, j
!
! Collect change in particle velocities.
!
par: if (lupdate_par) then
call pic_unset_particles(cell, ghost, dmv)
call ghost_particles_collect(ghost, ngp_send, ngp_recv, dmv)
if (lparticles_mass) then
forall(j = 1:3) fp(1:npar_loc,ivpx+j-1) = fp(1:npar_loc,ivpx+j-1) + dmv(:,j) / fp(1:npar_loc,imp)
else
fp(1:npar_loc,ivpx:ivpz) = fp(1:npar_loc,ivpx:ivpz) + dmv / mp_swarm
endif
endif par
!
! Collect change in gas velocity.
!
gas: if (lupdate_gas) then
pmbr: if (lpmbr) then
allocate(packet(npsend), stat=stat)
if (stat /= 0) call fatal_error_local('collect_particles', 'unable to allocate working array packet.')
call pack_particles(fp, sendlist, packet)
forall(j = 1:3) packet%v(j) = dmv(sendlist,j) ! Use v to send dmv.
call ghost_particles_send(npsend, packet, xi(sendlist,:), ngp_send, ngp_recv, ghost)
call back_reaction(f, cell, npar_loc + size(ghost), (/(dmv(:,j), ghost%v(j), j = 1, 3)/), &
(/(xi(:,j), ghost%xi(j), j = 1, 3)/))
deallocate(packet, stat=stat)
if (stat /= 0) call warning('collect_particles', 'unable to deallocate working array packet.')
else pmbr
call pic_unset_gas(f, cell)
endif pmbr
endif gas
!
! Deallocate the particles.
!
call pic_deallocate(int(nw), cell)
deallocate(sendlist, ghost, stat=stat)
if (stat /= 0) call warning('collect_particles', 'unable to deallocate ghost particles.')
!
endsubroutine collect_particles
!***********************************************************************
subroutine distribute_particles(f, fp, npsend, sendlist, ghost, cell, ngp_send, ngp_recv)
!
! Distributes weighted particles into each cell.
!
! 08-may-16/ccyang: coded.
! 21-jun-17/ccyang: accommodated Particles_mass.
!
! Input Arguments
! f, fp
! The f and fp arrays.
! Output Arguments
! npsend
! Number of particles that are required to be communicated.
! sendlist
! Indices of the particles to be communicated; needs to be
! deallocated when done.
! ghost
! Received particles from other processes; needs to be
! deallocated when done.
! cell
! Complete initial paricle-in-cell information.
! ngp_send
! The i-th element is the number of particles to be sent from
! this process to process pointed to by iproc_comm(i).
! The zeroth is that to be sent to itself.
! ngp_recv
! The i-th element is the number of particles to be received
! from process pointed to by iproc(i).
! The zeroth is that to be received from itself.
!
real, dimension(mx,my,mz,mfarray), intent(in) :: f
real, dimension(mpar_loc,mparray), intent(in) :: fp
integer, intent(out) :: npsend
integer, dimension(:), pointer :: sendlist
type(particle), dimension(:), pointer :: ghost
type(pic), dimension(nx,ny,nz), intent(out) :: cell
integer, dimension(0:nproc_comm), intent(out) :: ngp_send, ngp_recv
!
type(particle), dimension(:), allocatable :: packet
integer :: ngp, stat
integer, dimension(:), allocatable :: gproc
real, dimension(:,:), allocatable :: xi_ghost, xp_ghost, v_ghost
real, dimension(npar_loc,3) :: fpx, fpv
integer :: i
!
! Assign gas properties.
!
call pic_set_gas(f, cell)
!
! Send ghost particles.
!
call ghost_particles_count(xi, sendlist, ngp_send, ngp_recv)
npsend = size(sendlist)
ngp = sum(ngp_recv)
allocate(packet(npsend), ghost(ngp), stat=stat)
if (stat /= 0) call fatal_error_local('distribute_particles', 'unable to allocate ghost particles')
call pack_particles(fp, sendlist, packet)
call ghost_particles_send(npsend, packet, xi(sendlist,:), ngp_send, ngp_recv, ghost)
!
! Count particles in each cell.
!
cell%np = 0
call pic_count_particles(npar_loc, xi, cell)
allocate(xi_ghost(ngp,3), stat=stat)
do i=1,3; xi_ghost(:,i)=ghost%xi(i); enddo
call pic_count_particles(ngp, xi_ghost, cell)
call pic_allocate(int(nw), cell)
!
! Distribute particles into cells.
!
cell%np = 0
allocate(gproc(ngp), stat=stat)
gproc=ghost%proc
allocate(xp_ghost(ngp,3), stat=stat)
do i=1,3; xp_ghost(:,i)=ghost%x(i); enddo
allocate(v_ghost(ngp,3), stat=stat)
do i=1,3; v_ghost(:,i)=ghost%v(i); enddo
fpx=fp(1:npar_loc,ixp:izp)
fpv=fp(1:npar_loc,ivpx:ivpz)
if (lparticles_mass) then
call pic_set_particles(npar_loc, spread(-1,1,npar_loc), xi, fpx, fpv, cell, fp(1:npar_loc,imp))
call pic_set_particles(ngp, gproc, xi_ghost, xp_ghost, v_ghost, cell, ghost%weight)
else
call pic_set_particles(npar_loc, spread(-1,1,npar_loc), xi, fpx, fpv, cell)
call pic_set_particles(ngp, gproc, xi_ghost, xp_ghost, v_ghost, cell)
endif
call pic_set_eps(cell)
!
endsubroutine distribute_particles
!***********************************************************************
subroutine map_nearest_grid(fp, ineargrid)
!
! Update the coordinates in index space, and round them into ineargrid.
!
! 27-apr-16/ccyang: coded
!
use Grid, only: real_to_index
!
real, dimension(mpar_loc,mparray), intent(in) :: fp
integer, dimension(mpar_loc,3), intent(inout) :: ineargrid
!
logical :: lflag
integer :: istat
real, dimension(npar_loc,3) :: fpx
!
! Check the status and size of xi.
!
lflag = .true.
xisize: if (allocated(xi)) then
if (size(xi, 1) == npar_loc) then
lflag = .false.
else
deallocate (xi)
endif
endif xisize
!
! (Re)allocate xi as necessary.
!
alloc: if (lflag) then
allocate(xi(npar_loc,3), stat=istat)
if (istat > 0) then
call fatal_error_local('map_nearest_grid', 'unable to allocate xi. ')
return
endif
endif alloc
!
! Find the coordinates in index space.
!
fpx = fp(1:npar_loc,ixp:izp)
call real_to_index(npar_loc, fpx, xi)
ineargrid(1:npar_loc,:) = nint(xi)
!
endsubroutine map_nearest_grid
!***********************************************************************
subroutine map_particles(f, cell)
!
! Assign the properties of the particles onto the grid for diagnostics.
!
! 08-may-16/ccyang: coded.
!
real, dimension(mx,my,mz,mfarray), intent(inout) :: f
type(pic), dimension(nx,ny,nz), intent(in) :: cell
!
integer :: ix, iy, iz, j, l, m, n
real :: dz1, dyz1, dv1, total_weight
!
! Loop over each cell.
!
zscan: do n = n1, n2
iz = n - nghost
dz1 = merge(dz_1(n), 1.0, nzgrid > 1)
!
yscan: do m = m1, m2
iy = m - nghost
dyz1 = dz1 * merge(dy_1(m), 1.0, nygrid > 1)
!
xscan: do l = l1, l2
ix = l - nghost
total_weight = sum(cell(ix,iy,iz)%p%weight)
!
! Assign rhop
!
rhop: if (irhop > 0) then
if (total_weight > 0.0) then
dv1 = dyz1 * merge(dx_1(l), 1.0, nxgrid > 1)
f(l,m,n,irhop) = dv1 * total_weight
else
f(l,m,n,irhop) = 0.0
endif
endif rhop
!
! Assign uup
!
uup: if (iuup > 0) then
if (total_weight > 0.0) then
forall(j = 1:3) &
f(l,m,n,iuup+j-1) = sum(cell(ix,iy,iz)%p%weight * (cell(ix,iy,iz)%p%v(j) + cell(ix,iy,iz)%p%dv(j))) &
/ total_weight
else
f(l,m,n,iupx:iupz) = 0.0
endif
endif uup
!
enddo xscan
enddo yscan
enddo zscan
!
endsubroutine map_particles
!***********************************************************************
subroutine map_xxp_grid(f, fp, ineargrid, lmapsink_opt)
!
! Assign particles to rhop and uup.
!
! 08-may-16/ccyang: coded.
!
real, dimension(mx,my,mz,mfarray), intent(inout) :: f
real, dimension(mpar_loc,mparray), intent(in) :: fp
integer, dimension(mpar_loc,3), intent(in) :: ineargrid
logical, intent(in), optional :: lmapsink_opt
!
type(pic), dimension(nx,ny,nz) :: cell
type(particle), dimension(:), pointer :: ghost
integer, dimension(:), pointer :: sendlist
integer, dimension(0:nproc_comm) :: ngp_send, ngp_recv
integer :: npsend, stat
!
! Sanity check.
!
call keep_compiler_quiet(ineargrid)
if (irhop == 0 .and. iuup == 0) return
if (present(lmapsink_opt)) call fatal_error('map_xxp_grid', 'lmapsink_opt is not implemented. ')
if (lparticles_blocks) call fatal_error('map_xxp_grid', 'particles_blocks version is not implemented yet. ')
!
! Find np.
!
if (inp /= 0) call find_np(f, ineargrid)
!
! Module Particles_drag has done this on the fly.
!
if (lrun .and. lparticles_drag .and. it > 1) return
!
! Distribute the particles.
!
nullify(ghost)
call distribute_particles(f, fp, npsend, sendlist, ghost, cell, ngp_send, ngp_recv)
!
! Delegate to map_particles.
!
call map_particles(f, cell)
!
! Release the working arrays.
!
call pic_deallocate(int(nw), cell)
deallocate(sendlist, ghost, stat=stat)
if (stat /= 0) call warning('map_xxp_grid', 'unable to deallocate ghost particles.')
!
endsubroutine map_xxp_grid
!***********************************************************************
subroutine sort_particles_imn(fp, ineargrid, ipar, dfp, f)
!
! Sort the particles by pencils.
!
! 27-apr-16/ccyang: coded.
!
real, dimension(mpar_loc,mparray), intent(inout) :: fp
integer, dimension(mpar_loc,3), intent(inout) :: ineargrid
integer, dimension(mpar_loc), intent(inout) :: ipar
real, dimension(mx,my,mz,mfarray), intent(in), optional :: f
real, dimension(mpar_loc,mpvar), intent(inout), optional :: dfp
!
integer, dimension(npar_loc) :: k_sorted
integer :: i, k
!
if (present(f)) call keep_compiler_quiet(f)
!
! Sanity check.
!
if (lparticles_potential) call fatal_error('sort_particles_imn', 'particles_potential is not supported. ')
!
! Count particles in each pencil.
!
npar_imn = 0
cnt: do k = 1, npar_loc
i = imn_array(ineargrid(k,2), ineargrid(k,3))
npar_imn(i) = npar_imn(i) + 1
enddo cnt
!
! Calculate the beginning index for the particles in each pencil.
!
k1_imn(1) = 1
do i = 2, ny * nz
k1_imn(i) = k1_imn(i-1) + npar_imn(i-1)
enddo
k2_imn = k1_imn - 1
!
! Distribute the particles in each pencil.
!
dist: do k = 1, npar_loc
i = imn_array(ineargrid(k,2), ineargrid(k,3))
k2_imn(i) = k2_imn(i) + 1
k_sorted(k2_imn(i)) = k
enddo dist
!
! Reset k1_imn and k2_imn for pencils with no particles.
!
reset: where(npar_imn == 0)
k1_imn = 0
k2_imn = 0
endwhere reset
!
! Reorganize the particle data.
!
fp(1:npar_loc,:) = fp(k_sorted,:)
if (present(dfp)) dfp(1:npar_loc,:) = dfp(k_sorted,:)
xi = xi(k_sorted,:)
ineargrid(1:npar_loc,:) = ineargrid(k_sorted,:)
ipar(1:npar_loc) = ipar(k_sorted)
!
endsubroutine sort_particles_imn
!***********************************************************************
!***********************************************************************
! LOCAL SUBROUTINES GO BELOW HERE.
!***********************************************************************
!***********************************************************************
subroutine back_reaction(f, cell, np, dmv, xi)
!
! Particle-mesh the momentum changes in particles back to the gas and
! update the gas velocity.
!
! 20-sep-15/ccyang: coded.
!
real, dimension(mx,my,mz,mfarray), intent(inout) :: f
type(pic), dimension(nx,ny,nz), intent(in) :: cell
integer, intent(in) :: np
real, dimension(np,3), intent(in) :: dmv, xi
!
real, dimension(mx,my,mz) :: dp
integer :: i
!
! Operate on each component.
!
comp: do i = 1, 3
call pm_assignment(np, dmv(:,i), xi, dp)
f(l1:l2,m1:m2,n1:n2,iuu+i-1) = f(l1:l2,m1:m2,n1:n2,iuu+i-1) - dp(l1:l2,m1:m2,n1:n2) / cell%rho + cell%du(i)
enddo comp
!
endsubroutine back_reaction
!***********************************************************************
pure subroutine block_of_influence(xi, lower_corner, upper_corner, prune, domain)
!
! Check the block of influence from a particle and return the two
! diagonal corners of the block in terms of the cell indices.
!
! If the optional argument prune is present and is .true., the portion
! outside of the domain will be trimmed off the block.
!
! If the optional argument domain is present and is .true., the corners
! of the block are in terms of the domain sides: The value -1 denote
! outside of the lower boundary, 0 inside the domain, and +1 outside of
! the upper boundary.
!
! 10-sep-15/ccyang: coded.
!
real, dimension(3), intent(in) :: xi
integer, dimension(3), intent(out) :: lower_corner, upper_corner
logical, intent(in), optional :: prune, domain
!
!##ccyang
! integer, dimension(3), parameter :: xi1 = (/ l1, m1, n1 /)
! integer, dimension(3), parameter :: xi2 = (/ l2, m2, n2 /)
integer, dimension(3) :: xi1, xi2
xi1 = (/ l1, m1, n1 /)
xi2 = (/ l2, m2, n2 /)
!##ccyang
!
! Find the indices of the corners.
!
lower_corner = nint(xi - dxi_diag)
upper_corner = nint(xi + dxi_diag)
!
! Trim the block, if requested.
!
opt1: if (present(prune)) then
clip: if (prune) then
lower_corner = min(max(lower_corner, xi1), xi2)
upper_corner = min(max(upper_corner, xi1), xi2)
endif clip
endif opt1
!
! Convert to domain sides, if requested.
!
opt2: if (present(domain)) then
conv: if (domain) then
lower_corner = check_side(lower_corner, xi1, xi2)
upper_corner = check_side(upper_corner, xi1, xi2)
endif conv
endif opt2
!
endsubroutine block_of_influence
!***********************************************************************
pure subroutine find_np(f, ineargrid)
!
! Count particles in each cell.
!
! 10-may-16/ccyang: coded.
!
real, dimension(mx,my,mz,mfarray), intent(inout) :: f
integer, dimension(mpar_loc,3), intent(in) :: ineargrid
!
integer :: ix0, iy0, iz0, k
!
f(:,:,:,inp) = 0.0
incr: do k = 1, npar_loc
ix0 = ineargrid(k,1)
iy0 = ineargrid(k,2)
iz0 = ineargrid(k,3)
f(ix0,iy0,iz0,inp) = f(ix0,iy0,iz0,inp) + 1.0
enddo incr
!
endsubroutine find_np
!***********************************************************************
subroutine ghost_particles_collect(ghost, ngp_send, ngp_recv, dmv)
!
! Communicate the momentum change of the ghost particles and add it to
! dmv.
!
! 28-feb-16/ccyang: coded.
!
use Mpicomm, only: mpisend_int, mpirecv_int, mpisend_real, mpirecv_real
!
type(particle), dimension(:), intent(in) :: ghost
integer, dimension(0:nproc_comm), intent(in) :: ngp_send, ngp_recv
real, dimension(npar_loc,3), intent(inout) :: dmv
!
integer, parameter :: tag = 100
integer, dimension(maxval(ngp_send)) :: id
integer, dimension(maxval(ngp_recv)) :: ibuf
real, dimension(3*maxval(ngp_send)) :: dp
real, dimension(3*maxval(ngp_recv)) :: rbuf
integer :: ip, iproc_target, nsend, nrecv
integer :: i, j, k, n3s, n3r
!
! Shake hands with each process.
!
j = 0
proc: do ip = 0, nproc_comm
if (ip > 0) then
iproc_target = iproc_comm(ip)
else
iproc_target = iproc
endif
nsend = ngp_recv(ip)
nrecv = ngp_send(ip)
k = j + nsend
j = j + 1
n3s = 3 * nsend
n3r = 3 * nrecv
if (any(ghost(j:k)%proc /= iproc_target)) &
call fatal_error_local('ghost_particles_collect', 'inconsistant number of particles to be sent. ')
ibuf(1:nsend) = ghost(j:k)%id
rbuf(1:n3s) = (/ ghost(j:k)%dv(1), ghost(j:k)%dv(2), ghost(j:k)%dv(3) /)
!
! Send the particles.
!
comm: if (iproc_target > iproc) then
call mpisend_int(ibuf, nsend, iproc_target, tag+iproc_target)
call mpisend_real(rbuf, n3s, iproc_target, tag+iproc_target)
call mpirecv_int(id, nrecv, iproc_target, tag+iproc)
call mpirecv_real(dp, n3r, iproc_target, tag+iproc)
elseif (iproc_target < iproc) then comm
call mpirecv_int(id, nrecv, iproc_target, tag+iproc)
call mpirecv_real(dp, n3r, iproc_target, tag+iproc)
call mpisend_int(ibuf, nsend, iproc_target, tag+iproc_target)
call mpisend_real(rbuf, n3s, iproc_target, tag+iproc_target)
else comm
id(1:nrecv) = ibuf(1:nsend)
dp(1:n3r) = rbuf(1:n3s)
endif comm
!
! Collect the change of particle momenta.
!
do i = 1, nrecv
dmv(id(i),:) = dmv(id(i),:) + dp(i:n3r:nrecv)
enddo
j = k
enddo proc
!
endsubroutine ghost_particles_collect
!***********************************************************************
subroutine ghost_particles_count(xi, ighost, ngp_send, ngp_recv)
!
! Count the ghost particles to be communicated.
!
! 28-feb-16/ccyang: coded.
!
use Mpicomm, only: mpisend_int, mpirecv_int
use Sub, only: get_where
!
real, dimension(npar_loc,3), intent(in) :: xi
integer, dimension(:), pointer :: ighost
integer, dimension(0:nproc_comm), intent(out) :: ngp_send, ngp_recv
!
integer, parameter :: tag = 100
logical, dimension(npar_loc) :: lghost
integer, dimension(-1:1,-1:1,-1:1) :: neighbor_send
integer :: ip, iproc_target, j
real, dimension(3) :: xloc
!
! Tag the particles near the domain boundary and count the directions to be sent.
!
lghost = .false.
ngp_send = 0
par: do ip = 1, npar_loc
xloc = xi(ip,:)
call tag_send_directions(xloc, neighbor_send)
cnt: if (any(neighbor_send >= 0)) then
lghost(ip) = .true.
forall(j = 0:nproc_comm) ngp_send(j) = ngp_send(j) + count(neighbor_send == j)
endif cnt
enddo par
!
! Get the indices of the would-be ghost particles.
!
call get_where(lghost, ighost)
!
! Communicate the number of ghost particles.
!
ngp_recv(0) = ngp_send(0)
proc: do ip = 1, nproc_comm
iproc_target = iproc_comm(ip)
comm: if (iproc_target > iproc) then
call mpisend_int(ngp_send(ip), iproc_target, tag + iproc_target)
call mpirecv_int(ngp_recv(ip), iproc_target, tag + iproc)
else comm
call mpirecv_int(ngp_recv(ip), iproc_target, tag + iproc)
call mpisend_int(ngp_send(ip), iproc_target, tag + iproc_target)
endif comm
enddo proc
!
endsubroutine ghost_particles_count
!***********************************************************************
subroutine ghost_particles_send(np, packet, xi, ngp_send, ngp_recv, ghost)
!
! Send particles near the boundary.
!
! 28-feb-16/ccyang: coded.
! 21-jun-17/ccyang: accommodated Particles_mass.
!
use Grid, only: real_to_index
use Mpicomm, only: mpisend_int, mpirecv_int, mpisend_real, mpirecv_real
!
integer, intent(in) :: np
type(particle), dimension(np), intent(in) :: packet
real, dimension(np,3), intent(in) :: xi
integer, dimension(0:nproc_comm), intent(in) :: ngp_send, ngp_recv
type(particle), dimension(:), intent(out) :: ghost
!
type :: buffer
integer, dimension(:), pointer :: ibuf
real, dimension(:), pointer :: rbuf
endtype buffer
!
integer, parameter :: tag = 100
real, dimension(:,:), allocatable :: xigp
integer, dimension(-1:1,-1:1,-1:1) :: neighbor_send
type(buffer), dimension(0:nproc_comm) :: sendbuf
integer, dimension(maxval(ngp_recv)) :: ibuf
integer, dimension(0:nproc_comm) :: ngp
real, dimension(7*maxval(ngp_recv)) :: rbuf
real, dimension(3) :: xp, xloc
integer :: nattr, neighbor, nsend, nrecv, stat
integer :: ip, iproc_target, i, j, k, m, n
!
! Set number of attributes to send.
!
nattr = 6
if (lparticles_mass) nattr = nattr + 1
!
! Allocate buffers.
!
alloc: do ip = 0, nproc_comm
allocate(sendbuf(ip)%ibuf(ngp_send(ip)), sendbuf(ip)%rbuf(nattr*ngp_send(ip)), stat=stat)
if (stat /= 0) call fatal_error_local('ghost_particles_send', 'cannot allocate the send buffers. ')
enddo alloc
!
! Prepare the buffers.
!
ngp = 0
par: do ip = 1, np
xloc = xi(ip,:)
call tag_send_directions(xloc, neighbor_send)
zscan: do k = -1, 1
xscan: do i = -1, 1
yscan: do j = -1, 1
neighbor = neighbor_send(i,j,k)
valid: if (neighbor >= 0) then
n = ngp(neighbor)
sendbuf(neighbor)%ibuf(n+1) = packet(ip)%id
xp = packet(ip)%x
call wrap_particle_position(xp, (/i,j,k/))
if (lparticles_mass) then
sendbuf(neighbor)%rbuf(nattr*n+1:nattr*(n+1)) = (/ xp, packet(ip)%v, packet(ip)%weight /)
else
sendbuf(neighbor)%rbuf(nattr*n+1:nattr*(n+1)) = (/ xp, packet(ip)%v /)
endif
ngp(neighbor) = n + 1
endif valid
enddo yscan
enddo xscan
enddo zscan
enddo par
!
n = 0
proc: do ip = 0, nproc_comm
nsend = ngp(ip)
nrecv = ngp_recv(ip)
m = nattr * nrecv
if (nsend /= ngp_send(ip)) call fatal_error_local('ghost_particles_send', 'inconsistant number of particles to be sent. ')
!
! Send the particles.
!
if (ip > 0) then
iproc_target = iproc_comm(ip)
else
iproc_target = iproc
endif
!
comm: if (ip == 0) then
ibuf(1:nrecv) = sendbuf(ip)%ibuf
rbuf(1:m) = sendbuf(ip)%rbuf
elseif (iproc_target > iproc) then comm
call mpisend_int(sendbuf(ip)%ibuf, nsend, iproc_target, tag+iproc_target)
call mpisend_real(sendbuf(ip)%rbuf, nattr*nsend, iproc_target, tag+iproc_target)
call mpirecv_int(ibuf, nrecv, iproc_target, tag+iproc)
call mpirecv_real(rbuf, m, iproc_target, tag+iproc)
elseif (iproc_target < iproc) then comm
call mpirecv_int(ibuf, nrecv, iproc_target, tag+iproc)
call mpirecv_real(rbuf, m, iproc_target, tag+iproc)
call mpisend_int(sendbuf(ip)%ibuf, nsend, iproc_target, tag+iproc_target)
call mpisend_real(sendbuf(ip)%rbuf, nattr*nsend, iproc_target, tag+iproc_target)
endif comm
!
! Assemble the particle data.
!
j = n + 1
k = n + nrecv
ghost(j:k)%proc = iproc_target
ghost(j:k)%id = ibuf(1:nrecv)
if (lparticles_mass) ghost(j:k)%weight = rbuf(7:m:nattr)
comp: forall(i = 1:3)
ghost(j:k)%x(i) = rbuf(i:m:nattr)
ghost(j:k)%v(i) = rbuf(i+3:m:nattr)
endforall comp
n = k
enddo proc
!
! Convert the particle positions in real space to those in index space.
!
allocate(xigp(n,3))
call real_to_index(n, (/ ghost%x(1), ghost%x(2), ghost%x(3) /), xigp)
forall(i = 1:3) ghost%xi(i) = xigp(:,i)
!
! Deallocate working arrays.
!
deallocate(xigp, stat=stat)
if (stat /= 0) call warning('ghost_particles_send', 'cannot deallocate xigp. ')
dealloc: do ip = 0, nproc_comm
deallocate(sendbuf(ip)%ibuf, sendbuf(ip)%rbuf, stat=stat)
if (stat /= 0) call warning('ghost_particles_send', 'cannot deallocate the send buffers. ')
enddo dealloc
!
endsubroutine ghost_particles_send
!***********************************************************************
subroutine pack_particles(fp, list, packet)
!
! Pack the information of selected particles into a packet.
!
! 18-sep-15/ccyang: coded.
! 21-jun-17/ccyang: pack particle mass if present.
!
real, dimension(mpar_loc,mparray), intent(in) :: fp
integer, dimension(:), intent(in) :: list
type(particle), dimension(size(list)), intent(out) :: packet
!
integer :: i
!
packet%proc = iproc
packet%id = list
if (lparticles_mass) then
packet%weight = fp(list, imp)
else
packet%weight = 0.0
endif
packet%eps = 0.0
comp: forall(i = 1:3)
packet%x(i) = fp(list, ixp+i-1)
packet%v(i) = fp(list, ivpx+i-1)
packet%dv(i) = 0.0
endforall comp
!
endsubroutine pack_particles
!***********************************************************************
subroutine pic_allocate(n, cell)
!
! Allocate space for particles given known number of particles.
!
! 08-feb-15/ccyang: coded.
!
integer, intent(in) :: n
type(pic), dimension(n), intent(inout) :: cell
!
integer :: i, istat
!
! Loop over each cell.
!
loop: do i = 1, n
allocate(cell(i)%p(cell(i)%np), stat=istat)
if (istat /= 0) call fatal_error_local('pic_allocate', 'unable to allocate particle array.')
enddo loop
!
endsubroutine pic_allocate
!***********************************************************************
pure subroutine pic_count_particles(npar, xi, cell)
!
! Count and accumulate the number of particles that have influence in
! each cell.
!
! 11-feb-15/ccyang: coded.
!
integer, intent(in) :: npar
real, dimension(npar,3), intent(in) :: xi
type(pic), dimension(nx,ny,nz), intent(inout) :: cell
!
integer, dimension(3) :: xi1, xi2
real, dimension(3) :: xitmp
integer :: ip, ix, iy, iz, l, m, n
!
par: do ip = 1, npar
xitmp = xi(ip,:)
call block_of_influence(xitmp, xi1, xi2, prune=.true.)
zscan: do n = xi1(3), xi2(3)
iz = n - nghost
yscan: do m = xi1(2), xi2(2)
iy = m - nghost
xscan: do l = xi1(1), xi2(1)
ix = l - nghost
cell(ix,iy,iz)%np = cell(ix,iy,iz)%np + 1
enddo xscan
enddo yscan
enddo zscan
enddo par
!
endsubroutine pic_count_particles
!***********************************************************************
subroutine pic_deallocate(n, cell)
!
! Deallocate space for particles.
!
! 09-feb-15/ccyang: coded.
!
integer, intent(in) :: n
type(pic), dimension(n), intent(inout) :: cell
!
integer :: i, istat
!
! Loop over each cell.
!
loop: do i = 1, n
dealloc: if (associated(cell(i)%p)) then
deallocate(cell(i)%p, stat=istat)
if (istat /= 0) call warning('pic_deallocate', 'unable to deallocate particle array')
nullify(cell(i)%p)
endif dealloc
enddo loop
!
endsubroutine pic_deallocate
!***********************************************************************
pure subroutine pic_set_eps(cell)
!
! Find and set the particle-to-gas density ratios.
!
! 11-feb-15/ccyang: coded
!
type(pic), dimension(nx,ny,nz), intent(inout) :: cell
!
integer :: ix, iy, iz, l, m, n
real :: dz1, dyz1, dv1
!
! Loop over each cell.
!
zscan: do n = n1, n2
iz = n - nghost
dz1 = merge(dz_1(n), 1.0, nzgrid > 1)
yscan: do m = m1, m2
iy = m - nghost
dyz1 = dz1 * merge(dy_1(m), 1.0, nygrid > 1)
xscan: do l = l1, l2
ix = l - nghost
dv1 = dyz1 * merge(dx_1(l), 1.0, nxgrid > 1)
cell(ix,iy,iz)%p%eps = dv1 / cell(ix,iy,iz)%rho * cell(ix,iy,iz)%p%weight
enddo xscan
enddo yscan
enddo zscan
!
endsubroutine pic_set_eps
!***********************************************************************
subroutine pic_set_gas(f, cell)
!
! Assigns gas properties to each cell.
!
! 08-feb-15/ccyang: coded.
!
use Particles_sub, only: get_gas_density
!
real, dimension(mx,my,mz,mfarray), intent(in) :: f
type(pic), dimension(nx,ny,nz), intent(inout) :: cell
!
integer :: ix, iy, iz, l, m, n
!
! Loop over each cell.
!
zscan: do n = n1, n2
iz = n - nghost
yscan: do m = m1, m2
iy = m - nghost
xscan: do l = l1, l2
ix = l - nghost
cell(ix,iy,iz)%rho = get_gas_density(f, l, m, n)
if (iuu /= 0) then
cell(ix,iy,iz)%u = f(l,m,n,iux:iuz)
else
cell(ix,iy,iz)%u = 0.0
endif
cell(ix,iy,iz)%du = 0.0
enddo xscan
enddo yscan
enddo zscan
!
endsubroutine pic_set_gas
!***********************************************************************
pure subroutine pic_set_particles(npar, proc, xi, xp, vp, cell, mass)
!
! Set the properties of the particles in each cell.
!
! 20-sep-15/ccyang: coded.
! 21-jun-17/ccyang: added optional argument mass.
!
use Particles_sub, only: weigh_particle
!
integer, intent(in) :: npar
integer, dimension(npar), intent(in) :: proc
real, dimension(npar,3), intent(in) :: xi, xp, vp
type(pic), dimension(nx,ny,nz), intent(inout) :: cell
real, dimension(npar), intent(in), optional :: mass
!
real, dimension(3) :: dxi, xitmp
integer, dimension(3) :: xi1, xi2
integer :: np, ip, ix, iy, iz, l, m, n
real :: mp
!
! Weigh and distribute particles to the cells.
!
par: do ip = 1, npar
if (present(mass)) then
mp = mass(ip)
else
mp = mp_swarm
endif
!
xitmp = xi(ip,:)
call block_of_influence(xitmp, xi1, xi2, prune=.true.)
!
zscan: do n = xi1(3), xi2(3)
iz = n - nghost
dxi(3) = xi(ip,3) - real(n)
!
yscan: do m = xi1(2), xi2(2)
iy = m - nghost
dxi(2) = xi(ip,2) - real(m)
!
xscan: do l = xi1(1), xi2(1)
ix = l - nghost
dxi(1) = xi(ip,1) - real(l)
!
np = cell(ix,iy,iz)%np + 1
cell(ix,iy,iz)%p(np)%proc = proc(ip)
cell(ix,iy,iz)%p(np)%id = ip
cell(ix,iy,iz)%p(np)%weight = mp * weigh_particle(dxi(1), dxi(2), dxi(3))
cell(ix,iy,iz)%p(np)%xi = xi(ip,:)
cell(ix,iy,iz)%p(np)%x = xp(ip,:)
cell(ix,iy,iz)%p(np)%v = vp(ip,:)
cell(ix,iy,iz)%p(np)%dv = 0.0
cell(ix,iy,iz)%np = np
enddo xscan
enddo yscan
enddo zscan
enddo par
!
endsubroutine pic_set_particles
!***********************************************************************
subroutine pic_unset_gas(f, cell)
!
! Add the change of the gas velocity back to the f-array.
!
! 12-feb-15/ccyang: coded.
!
real, dimension(mx,my,mz,mfarray), intent(inout) :: f
type(pic), dimension(nx,ny,nz), intent(in) :: cell
!
integer :: k
!
! Loop over each compnent.
!
forall(k = 1:3) f(l1:l2,m1:m2,n1:n2,iuu+k-1) = f(l1:l2,m1:m2,n1:n2,iuu+k-1) + cell%du(k)
!
endsubroutine pic_unset_gas
!***********************************************************************
pure subroutine pic_unset_particles(cell, ghost, dmv)
!
! Collect the change of particle momenta over each cell into dmv and
! ghost%dv.
!
! 10-jun-15/ccyang: coded.
!
type(pic), dimension(nx,ny,nz), intent(in) :: cell
type(particle), dimension(:), intent(inout) :: ghost
real, dimension(npar_loc,3), intent(out) :: dmv
!
real, dimension(3) :: dp
integer :: id, ix, iy, iz, j
!
! Initialization.
!
dmv = 0.0
forall(j = 1:3) ghost%dv(j) = 0.0
!
! Process each cell.
!
zscan: do iz = 1, nz
yscan: do iy = 1, ny
xscan: do ix = 1, nx
par: do j = 1, cell(ix,iy,iz)%np
id = cell(ix,iy,iz)%p(j)%id
dp = cell(ix,iy,iz)%p(j)%weight * cell(ix,iy,iz)%p(j)%dv
if (cell(ix,iy,iz)%p(j)%proc < 0) then
dmv(id,:) = dmv(id,:) + dp
else
ghost(id)%dv = ghost(id)%dv + dp
endif
enddo par
enddo xscan
enddo yscan
enddo zscan
!
endsubroutine pic_unset_particles
!***********************************************************************
pure subroutine pm_assignment(np, fp, xi, fg)
!
! Assign the property fp at (particle) positions xi in index space onto
! fg on the grid. Note that fp is converted to density in fg, being
! divided by the cell volume. Also, ghost particles should be
! included in the total number np.
!
! 20-sep-15/ccyang: coded.
!
use Particles_sub, only: weigh_particle
!
integer, intent(in) :: np
real, dimension(mx,my,mz), intent(out) :: fg
real, dimension(np,3), intent(in) :: xi
real, dimension(np), intent(in) :: fp
!
integer, dimension(3) :: xi1, xi2
real, dimension(3) :: dxi, xitmp
integer :: ip, l, m, n
real :: w, dz1, dyz1, dv1
!
! Make the assignment.
!
fg = 0.0
loop: do ip = 1, np
xitmp = xi(ip,:)
call block_of_influence(xitmp, xi1, xi2)
zscan: do n = xi1(3), xi2(3)
dxi(3) = xi(ip,3) - real(n)
dz1 = merge(dz_1(n), 1.0, nzgrid > 1)
yscan: do m = xi1(2), xi2(2)
dxi(2) = xi(ip,2) - real(m)
dyz1 = dz1 * merge(dy_1(m), 1.0, nygrid > 1)
xscan: do l = xi1(1), xi2(1)
dxi(1) = xi(ip,1) - real(l)
dv1 = dyz1 * merge(dx_1(l), 1.0, nxgrid > 1)
w = weigh_particle(dxi(1), dxi(2), dxi(3))
fg(l,m,n) = fg(l,m,n) + dv1 * w * fp(ip)
enddo xscan
enddo yscan
enddo zscan
enddo loop
!
endsubroutine pm_assignment
!***********************************************************************
pure subroutine pm_interpolation(np, fg, xi, fp)
!
! Interpolate the field fg on the grid to fp at the (particle)
! positions xi in index space. Ghost cells are assumed updated.
!
! 05-jun-15/ccyang: coded.
!
use Particles_sub, only: weigh_particle
!
integer, intent(in) :: np
real, dimension(mx,my,mz), intent(in) :: fg
real, dimension(np,3), intent(in) :: xi
real, dimension(np), intent(out) :: fp
!
integer, dimension(3) :: xi1, xi2
real, dimension(3) :: dxi
integer :: ip, l, m, n
real :: w, a
!
! Make the interpolation.
!
loop: do ip = 1, np
a = 0.0
call block_of_influence(xi(ip,:), xi1, xi2)
zscan: do n = xi1(3), xi2(3)
dxi(3) = xi(ip,3) - real(n)
yscan: do m = xi1(2), xi2(2)
dxi(2) = xi(ip,2) - real(m)
xscan: do l = xi1(1), xi2(1)
dxi(1) = xi(ip,1) - real(l)
w = weigh_particle(dxi(1), dxi(2), dxi(3))
a = a + w * fg(l,m,n)
enddo xscan
enddo yscan
enddo zscan
fp(ip) = a
enddo loop
!
endsubroutine pm_interpolation
!***********************************************************************
subroutine tag_send_directions(xi, neighbor_send)
!
! Specifies the directions and the process ranks a particle needs to be
! sent.
!
! 28-feb-16/ccyang: coded.
!
! Input Argument
! xi
! The position of the particle in local index space.
! Output Argument
! neighbor_send
! The element (i,j,k) contains the index to iproc_comm in the
! direction (i,j,k), 0 if send to itself, -1 if not a valid
! direction.
!
use General, only: find_proc
use Mpicomm, only: index_to_iproc_comm
!
real, dimension(3), intent(in) :: xi
integer, dimension(-1:1,-1:1,-1:1), intent(out) :: neighbor_send
!
real, parameter :: xi0 = nghost + 0.5
logical, dimension(-1:1,-1:1,-1:1) :: lsend
integer, dimension(3) :: side1, side2
logical :: lflag
integer :: ipxn, ipyn1, ipyn2, ipzn
integer :: ix, iy, iz, n
real :: eta
!
! Disable all directions initially.
!
neighbor_send = -1
!
! Find the block of influence from the particle.
!
call block_of_influence(xi, side1, side2, domain=.true.)
!
! Check if the block boundary is outside of the local domain in each direction.
!
xscan: do ix = side1(1), side2(1)
shear: if (is_shear_boundary(ix)) then
! Is a shear boundary.
if (.not. lequidist(2)) &
call fatal_error_local('tag_send_directions', 'not implemented for shear with nonequidistant y grid. ')
if (llast_proc_x) then
ipxn = 0
else
ipxn = nprocx - 1
endif
eta = modulo(xi(2) - xi0 + real(ny * ipy) + real(ix) * deltay / dy, real(nygrid)) - 0.5
ipyn1 = find_ipy(eta - rinf)
ipyn2 = find_ipy(eta + rinf)
lflag = ipyn1 /= ipyn2
ipyn1 = modulo(ipyn1, nprocy)
ipyn2 = modulo(ipyn2, nprocy)
zscan1: do iz = side1(3), side2(3)
ipzn = modulo(ipz + iz, nprocz)
setn: if (lflag) then
neighbor_send(ix,-1,iz) = find_proc(ipxn,ipyn1,ipzn)
neighbor_send(ix,+1,iz) = find_proc(ipxn,ipyn2,ipzn)
else setn
neighbor_send(ix,0,iz) = find_proc(ipxn,ipyn1,ipzn)
endif setn
enddo zscan1
else shear
! Is not a shear boundary.
zscan2: do iz = side1(3), side2(3)
yscan: do iy = side1(2), side2(2)
if (ix == 0 .and. iz == 0 .and. iy == 0) cycle
n = neighbors_par(ix,iy,iz)
if (n >= 0) neighbor_send(ix,iy,iz) = n
enddo yscan
enddo zscan2
endif shear
enddo xscan
!
! Transform the process ranks to indices to iproc_comm.
!
lsend = neighbor_send >= 0
neighbor_send = index_to_iproc_comm(neighbor_send, lsend)
if (any(lsend .and. neighbor_send < 0)) &
call fatal_error_local('tag_send_directions', 'sending particles to non-neighbor process')
!
endsubroutine tag_send_directions
!***********************************************************************
subroutine wrap_particle_position(xp, sides)
!
! Updates the position of a particle if it will be sent over to the
! opposite side of the computational domain.
!
! 14-sep-15/ccyang: coded.
!
! Input/Output Argument
! xp(i)
! The i-th component of the particle position.
! Input Argument
! sides(i)
! The side in the i-th dimension the particle is sent over,
! where only +1, 0, and -1 are accepted.
!
use Grid, only: inverse_grid
!
real, dimension(3), intent(inout) :: xp
integer, dimension(3), intent(in) :: sides
!
logical :: lflag
real, dimension(1) :: xi
integer :: n
!
! Directions in x.
!
lflag = .false.
xdir: if (lfirst_proc_x .and. sides(1) == -1) then
xp(1) = xp(1) + Lxyz(1)
lflag = .true.
elseif (llast_proc_x .and. sides(1) == +1) then xdir
xp(1) = xp(1) - Lxyz(1)
lflag = .true.
endif xdir
!
! Directions in y with shear
!
ydir: if (lshear .and. nygrid > 1 .and. lflag) then
xp(2) = xyz0(2) + modulo(xp(2) + real(sides(1)) * deltay - xyz0(2), lxyz(2))
call inverse_grid(2, (/xp(2)/), xi)
n = nint(xi(1) + real(sides(2)) * rinf) - nghost
if (n < 1) then
xp(2) = xp(2) + lxyz(2)
elseif (n > nygrid) then
xp(2) = xp(2) - lxyz(2)
endif
!
! or without shear.
!
elseif (lfirst_proc_y .and. sides(2) == -1) then ydir
xp(2) = xp(2) + Lxyz(2)
elseif (llast_proc_y .and. sides(2) == +1) then ydir
xp(2) = xp(2) - Lxyz(2)
endif ydir
!
! Directions in z.
!
if (lfirst_proc_z .and. sides(3) == -1) then
xp(3) = xp(3) + Lxyz(3)
elseif (llast_proc_z .and. sides(3) == +1) then
xp(3) = xp(3) - Lxyz(3)
endif
!
endsubroutine wrap_particle_position
!***********************************************************************
!***********************************************************************
! LOCAL FUNCTIONS GO BELOW HERE.
!***********************************************************************
!***********************************************************************
elemental integer function check_side(n, n1, n2)
!
! Return -1, if n < n1; 0, if n1 <= n <= n2; +1, otherwise.
!
! 08-feb-15/ccyang: coded
!
integer, intent(in) :: n, n1, n2
!
if (n < n1) then
check_side = -1
else if (n <= n2) then
check_side = 0
else
check_side = 1
endif
!
endfunction check_side
!***********************************************************************
pure integer function find_ipy(eta)
!
! Helper function for subroutine tag_send_directions.
!
! 01-mar-16/ccyang: coded.
!
real, intent(in) :: eta
!
integer :: k
!
k = floor(eta + 0.5)
find_ipy = (k - modulo(k, ny)) / ny
!
endfunction find_ipy
!***********************************************************************
logical function is_shear_boundary(xside)
!
! Returns .true. if the x-boundary in the xside side is a shear
! boundary, where xside can only be +1, 0, or -1.
!
! 13-sep-15/ccyang: coded.
!
integer, intent(in) :: xside
!
is_shear_boundary = lshear .and. nygrid > 1 .and. &
(lfirst_proc_x .and. xside == -1 .or. llast_proc_x .and. xside == +1)
!
endfunction is_shear_boundary
!***********************************************************************
!***********************************************************************
! DUMMY PROCEDURES GO BELOW HERE.
!***********************************************************************
!***********************************************************************
subroutine boundcond_neighbour_list()
!
! 26-apr-16/ccyang: dummy.
!
call fatal_error('boundcond_neighbour_list', 'not implemented. ')
!
endsubroutine boundcond_neighbour_list
!***********************************************************************
subroutine cleanup_interpolated_quantities()
!
! 27-apr-16/ccyang: dummy.
!
if (interp%luu .or. interp%loo .or. interp%lTT .or. interp%lrho .or. interp%lgradTT .or. interp%lbb .or. interp%lee .or. &
interp%lpp .or. interp%lspecies .or. interp%lnu) &
call fatal_error('cleanup_interpolated_quantities', 'interp is not implemented. ')
!
endsubroutine cleanup_interpolated_quantities
!***********************************************************************
subroutine fill_bricks_with_blocks(a, ab, marray, ivar)
!
! 28-apr-16/ccyang: dummy.
!
integer, intent(in) :: marray, ivar
real, dimension(mxb,myb,mzb,marray,0:nblockmax-1), intent(in) :: ab
real, dimension(mx,my,mz,marray), intent(in) :: a
!
call keep_compiler_quiet(a)
call keep_compiler_quiet(ab(:,:,:,:,0))
call keep_compiler_quiet(marray)
call keep_compiler_quiet(ivar)
!
call fatal_error('fill_bricks_with_blocks', 'only implemented for block domain decomposition. ')
!
endsubroutine fill_bricks_with_blocks
!***********************************************************************
subroutine fill_blocks_with_bricks(a, ab, marray, ivar)
!
! 28-apr-16/ccyang: dummy.
!
integer, intent(in) :: marray, ivar
real, dimension(mxb,myb,mzb,marray,0:nblockmax-1), intent(in) :: ab
real, dimension(mx,my,mz,marray), intent(in) :: a
!
call keep_compiler_quiet(a)
call keep_compiler_quiet(ab(:,:,:,:,0))
call keep_compiler_quiet(marray)
call keep_compiler_quiet(ivar)
!
call fatal_error('fill_blocks_with_bricks', 'only implemented for block domain decomposition. ')
!
endsubroutine fill_blocks_with_bricks
!***********************************************************************
subroutine interpolate_linear_range(f, ivar1, ivar2, xxp, gp, inear, iblock, ipar)
!
! 29-mar-16/ccyang: dummy.
!
real, dimension(mx,my,mz,mfarray), intent(in) :: f
integer, dimension(3), intent(in) :: inear
real, dimension(3), intent(in) :: xxp
integer, intent(in) :: ivar1, ivar2, iblock, ipar
real, dimension(ivar2-ivar1+1), intent(out) :: gp
!
gp = 0.0
!
call keep_compiler_quiet(f)
call keep_compiler_quiet(ivar1)
call keep_compiler_quiet(ivar2)
call keep_compiler_quiet(xxp)
call keep_compiler_quiet(inear)
call keep_compiler_quiet(iblock)
call keep_compiler_quiet(ipar)
!
call fatal_error_local('interpolate_linear_range', 'not implemented. ')
!
endsubroutine interpolate_linear_range
!***********************************************************************
subroutine interpolate_linear_scalar(f, ivar, xxp, gp, inear, iblock, ipar)
!
! 29-mar-16/ccyang: dummy.
!
real, dimension(mx,my,mz,mfarray), intent(in) :: f
integer, dimension(3), intent(in) :: inear
real, dimension(3), intent(in) :: xxp
integer, intent(in) :: ivar, iblock, ipar
real, intent(out) :: gp
!
gp = 0.0
!
call keep_compiler_quiet(f)
call keep_compiler_quiet(ivar)
call keep_compiler_quiet(xxp)
call keep_compiler_quiet(gp)
call keep_compiler_quiet(inear)
call keep_compiler_quiet(iblock)
call keep_compiler_quiet(ipar)
!
call fatal_error_local('interpolate_linear_scalar', 'not implemented. ')
!
endsubroutine interpolate_linear_scalar
!***********************************************************************
subroutine interpolate_quadratic(f, ivar1, ivar2, xxp, gp, inear, iblock, ipar)
!
! 30-mar-16/ccyang: dummy.
!
real, dimension(mx,my,mz,mfarray), intent(in) :: f
integer, dimension(3), intent(in) :: inear
real, dimension(3), intent(in) :: xxp
integer, intent(in) :: ivar1, ivar2, iblock, ipar
real, dimension(ivar2-ivar1+1), intent(in) :: gp
!
call keep_compiler_quiet(f)
call keep_compiler_quiet(ivar1)
call keep_compiler_quiet(ivar2)
call keep_compiler_quiet(xxp)
call keep_compiler_quiet(gp)
call keep_compiler_quiet(inear)
call keep_compiler_quiet(iblock)
call keep_compiler_quiet(ipar)
!
call fatal_error_local('interpolate_quadratic', 'not implemented. ')
!
endsubroutine interpolate_quadratic
!***********************************************************************
subroutine interpolate_quadratic_spline(f, ivar1, ivar2, xxp, gp, inear, iblock, ipar)
!
! 30-mar-16/ccyang: dummy.
!
real, dimension(mx,my,mz,mfarray), intent(in) :: f
integer, dimension(3), intent(in) :: inear
real, dimension(3), intent(in) :: xxp
integer, intent(in) :: ivar1, ivar2, iblock, ipar
real, dimension(ivar2-ivar1+1), intent(in) :: gp
!
call keep_compiler_quiet(f)
call keep_compiler_quiet(ivar1)
call keep_compiler_quiet(ivar2)
call keep_compiler_quiet(xxp)
call keep_compiler_quiet(gp)
call keep_compiler_quiet(inear)
call keep_compiler_quiet(iblock)
call keep_compiler_quiet(ipar)
!
call fatal_error_local('interpolate_quadratic_spline', 'not implemented. ')
!
endsubroutine interpolate_quadratic_spline
!***********************************************************************
subroutine interpolate_quantities(f, fp, p, ineargrid)
!
! 27-apr-16/ccyang: dummy.
!
real, dimension(mx,my,mz,mfarray), intent(in) :: f
real, dimension(mpar_loc,mparray), intent(in) :: fp
integer, dimension(mpar_loc,3), intent(in) :: ineargrid
type(pencil_case), intent(in) :: p
!
call keep_compiler_quiet(f)
call keep_compiler_quiet(fp)
call keep_compiler_quiet(ineargrid)
call keep_compiler_quiet(p)
!
if (interp%luu .or. interp%loo .or. interp%lTT .or. interp%lrho .or. interp%lgradTT .or. interp%lbb .or. interp%lee .or. &
interp%lpp .or. interp%lspecies .or. interp%lnu) &
call fatal_error('interpolate_quantities', 'interp is not implemented. ')
!
endsubroutine interpolate_quantities
!***********************************************************************
subroutine interpolation_consistency_check()
!
! 27-apr-16/ccyang: dummy.
!
if (interp%luu .or. interp%loo .or. interp%lTT .or. interp%lrho .or. interp%lgradTT .or. interp%lbb .or. interp%lee .or. &
interp%lpp .or. interp%lspecies .or. interp%lnu) &
call fatal_error('interpolation_consistency_check', 'interp is not implemented. ')
!
endsubroutine interpolation_consistency_check
!***********************************************************************
subroutine map_vvp_grid(f, fp, ineargrid)
!
! 30-mar-16/ccyang: dummy.
!
real, dimension(mx,my,mz,mfarray), intent(in) :: f
real, dimension(mpar_loc,mparray), intent(in) :: fp
integer, dimension(mpar_loc,3), intent(in) :: ineargrid
!
call keep_compiler_quiet(f)
call keep_compiler_quiet(fp)
call keep_compiler_quiet(ineargrid)
!
endsubroutine map_vvp_grid
!***********************************************************************
subroutine shepherd_neighbour_block(fp, ineargrid, kshepherdb, kneighbour, iblock)
!
! 26-apr-16/ccyang: dummy.
!
real, dimension(mpar_loc,mparray), intent(in) :: fp
integer, dimension(mpar_loc,3), intent(in) :: ineargrid
integer, dimension(nxb,nyb,nzb), intent(in) :: kshepherdb
integer, dimension(:), intent(in) :: kneighbour
integer, intent(in) :: iblock
!
call keep_compiler_quiet(fp)
call keep_compiler_quiet(ineargrid)
call keep_compiler_quiet(kshepherdb)
call keep_compiler_quiet(kneighbour)
call keep_compiler_quiet(iblock)
!
call fatal_error('shepherd_neighbour_block', 'not implemented. ')
!
endsubroutine shepherd_neighbour_block
!***********************************************************************
subroutine shepherd_neighbour_pencil(fp, ineargrid, kshepherd, kneighbour)
!
! 26-apr-16/ccyang: dummy.
!
real, dimension(mpar_loc,mparray), intent(in) :: fp
integer, dimension(mpar_loc,3), intent(in) :: ineargrid
integer, dimension(nx), intent(in) :: kshepherd
integer, dimension(:), intent(in) :: kneighbour
!
call keep_compiler_quiet(fp)
call keep_compiler_quiet(ineargrid)
call keep_compiler_quiet(kshepherd)
call keep_compiler_quiet(kneighbour)
!
call fatal_error('shepherd_neighbour_pencil', 'not implemented. ')
!
endsubroutine shepherd_neighbour_pencil
!***********************************************************************
subroutine shepherd_neighbour_pencil3d(fp, ineargrid_c, kshepherd_c, kneighbour_c)
!
! 26-apr-16/ccyang: dummy.
!
real, dimension(mpar_loc,mparray) :: fp
integer, dimension(:,:,:) :: kshepherd_c
integer, dimension(mpar_loc,3) :: ineargrid_c
integer, dimension(mpar_loc) :: kneighbour_c
!
call keep_compiler_quiet(fp)
call keep_compiler_quiet(kshepherd_c)
call keep_compiler_quiet(ineargrid_c)
call keep_compiler_quiet(kneighbour_c)
!
call fatal_error('shepherd_neighbour_pencil3d', 'not implemented. ')
!
endsubroutine shepherd_neighbour_pencil3d
!***********************************************************************
subroutine sort_particles_iblock(fp, ineargrid, ipar, dfp)
!
! 26-apr-16/ccyang: dummy.
!
real, dimension(mpar_loc,mparray), intent(in) :: fp
integer, dimension(mpar_loc,3), intent(in) :: ineargrid
integer, dimension(mpar_loc), intent(in) :: ipar
real, dimension(mpar_loc,mpvar), intent(in), optional :: dfp
!
call keep_compiler_quiet(fp)
call keep_compiler_quiet(ineargrid)
call keep_compiler_quiet(ipar)
if (present(dfp)) call keep_compiler_quiet(dfp)
!
call fatal_error('sort_particles_iblock', 'only implemented for block domain decomposition. ')
!
endsubroutine sort_particles_iblock
!***********************************************************************
endmodule Particles_map