- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hello everyone,
I have a subroutine that definitely has the computational load that could benefit from a MIC. The subroutine is being used in a molecular simulation. The idea behind the subroutine is to determine which particles are within a certain distance, and for each particle create an array that says which particles are within that distance. However because I am only updating the array inside an if statement, the compiler sees a vector dependence and won't vectorize. I am wondering if anyone here sees a way to vectorize this subroutine.
program neighbor
use ifport
implicit none
double precision, allocatable :: x(:),y(:),z(:)
double precision :: dx,dy,dz,dr2
double precision :: dens,vol,box,rcut2
double precision :: x1,y1,z1,x2,y2,z2
integer :: np
integer :: i,j
integer,allocatable :: numNeigh(:),vlist(:,:)
np = 600
allocate(numNeigh(np))
allocate(vlist(1000,np))
allocate(x(np),y(np),z(np))
dens = 1.0d0
vol = real(np)/dens
box = vol**(1.0d0/3.0)
rcut2 = 2.50d0*2.50d0
call seed(10)
numNeigh(:) = 0
vlist(:,:) = 0
!--- create arbitrary initial coordinates. Not important
do i = 1,np
x(i) = box*rand(); y(i) = box*rand(); z(i) = box*rand()
enddo
do i = 1,np
x1 = x(i); y1 = y(i); z1 = z(i)
!---would like to vectorize this inner loop
do j=1,np
if(i.eq.j)then
cycle
endif
!---calcuate distance between particles i and j
x2 = x(j); y2 = y(j); z2 = z(j)
dx = x2-x1; dy = y2-y1; dz = z2-z1
dr2 = dx**2 + dy**2 + dz**2
if(dr2.lt.rcut2)then
!---if distance is less than cutoff distance, update number of neighbors and store particle j in vlist
numNeigh(i) = numNeigh(i) + 1
vlist(numNeigh(i),i) = j
endif
enddo
enddo
stop
end program neighbor
Link Copied
1 Reply
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
A fairly standard approach to something like this is to treat it in two phases.
- Build a boolean vector showing which elements are near,
- Compress that into your neighbour list as a separate operation.
Something like this.
program neighbor
use ifport
implicit none
double precision, allocatable :: x(:),y(:),z(:)
double precision :: dx,dy,dz,dr2
double precision :: dens,vol,box,rcut2
double precision :: x1,y1,z1,x2,y2,z2
integer :: np
integer :: i,j
integer,allocatable :: numNeigh(:),vlist(:,:)
logical,allocatable :: nearEnough(:)
np = 600
allocate(numNeigh(np), nearEnough(np)) !vlist can't need more than np items for each element.
allocate(vlist(np,np))
allocate(x(np),y(np),z(np))
dens = 1.0d0
vol = real(np)/dens
box = vol**(1.0d0/3.0)
rcut2 = 2.50d0*2.50d0
call seed(10)
numNeigh(:) = 0
vlist(:,:) = 0
!--- create arbitrary initial coordinates. Not important
do i = 1,np
x(i) = box*rand(); y(i) = box*rand(); z(i) = box*rand()
enddo
! For each particle
do i = 1,np
x1 = x(i); y1 = y(i); z1 = z(i)
!---would like to vectorize this inner loop
do j=1,np
if (i .eq. j) then
nearEnough(j) = .false.
cycle
endif
!---calculate distance between particles i and j
x2 = x(j); y2 = y(j); z2 = z(j)
dx = x2-x1; dy = y2-y1; dz = z2-z1
dr2 = dx**2 + dy**2 + dz**2
nearEnough(j) = dr2 .lt. rcut2
enddo
! Now reduce
do j=1,np
if (nearEnough(j)) then
numNeigh(i) = numNeigh(i) + 1
vlist(numNeigh(i),i) = j
endif
enddo
enddo
stop
end program neighbor
The first loop now vectorizes. There are a number of other issues here, though:-
- Since distance(a,b) .eq. distance(b,a) you should be able to halve the amount of work (and remove the conditional from the interesting loop) by running it from i+1 to np, though you'll then need some more code to build the full neighbour list.
- If you parallelize the outer loop and do the halving trick the work will be imbalanced, so play with either schedule(static,1), or schedule(dynamic)
HTH
Reply
Topic Options
- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Bookmark
- Subscribe
- Printer Friendly Page