RMPCDMD
neighbor_list.f90
Go to the documentation of this file.
1 ! This file is part of RMPCDMD
2 ! Copyright (c) 2015-2017 Pierre de Buyl and contributors
3 ! License: BSD 3-clause (see file LICENSE)
4 
10 
12  use common
13  use hilbert
14  use cell_system
15  use particle_system
16  use interaction
17  implicit none
18  private
19 
21  public :: compute_force_n2
22 
24  integer :: npoints
25  integer :: nmax
26  integer, allocatable :: list(:, :)
27  integer, allocatable :: n(:)
28  integer, allocatable :: stencil(:,:)
29  type(timer_t) :: time_update, time_force
30  contains
31  procedure :: init
32  procedure :: update_list
33  procedure :: make_stencil
34  end type neighbor_list_t
35 
36 contains
37 
38  subroutine init(this, Npoints, Nmax)
39  class(neighbor_list_t), intent(out) :: this
40  integer, intent(in) :: Npoints
41  integer, intent(in) :: Nmax
42 
43  this% Nmax = nmax
44  this% Npoints = npoints
45  allocate(this% list(nmax, npoints))
46  allocate(this% n(npoints))
47  this% list = 0
48  this% n = 0
49 
50  call this%time_update%init('neigh list update')
51  call this%time_force%init('neigh list force')
52 
53  end subroutine init
54 
55  pure function next_cell(p) result(cell)
56  integer, intent(in) :: p(3)
57  integer :: cell(3)
58 
59  integer :: i
60 
61  cell = p
62  cell(1) = cell(1) + 1
63 
64  do i = 1, 2
65  if (cell(i) .eq. 3) then
66  cell(i) = -2
67  cell(i+1) = cell(i+1) + 1
68  end if
69  end do
70 
71  end function next_cell
72 
73  !! Update the neighbor list
74  !!
75  !! Loop over the stencil for neighboring cells.
76  subroutine update_list(this, system1, system2, radius, cells, lj)
77  class(neighbor_list_t), intent(inout) :: this
78  type(particle_system_t), intent(in) :: system1
79  type(particle_system_t), intent(in) :: system2
80  type(cell_system_t), intent(inout) :: cells
81  double precision, intent(in) :: radius
82  type(lj_params_t), intent(in), optional :: lj
83 
84  integer :: cell(3), M(3), actual_cell(3)
85  integer :: neigh_idx, i, cell_i, cell_n, cell_start, list_idx
86  integer :: j, stencil_size
87  integer :: s, si
88  double precision :: x(3), y(3), L(3)
89  double precision :: rsq, radiussq
90  logical :: actual_cell_md, actual_cell_noreac, do_lj
91 
92  l = cells% L * cells% a
93  radiussq = radius**2
94  m = cells% M
95  stencil_size = size(this% stencil, dim=2)
96  cells%is_md = .false.
97  cells%is_reac = .true.
98  if (present(lj)) then
99  do_lj = .true.
100  else
101  do_lj = .false.
102  end if
103 
104  call this%time_update%tic()
105  !$omp parallel do &
106  !$omp private(x, cell, list_idx, j, actual_cell, neigh_idx, cell_n, cell_start, &
107  !$omp cell_i, y, rsq, actual_cell_md, actual_cell_noreac, i, si, s)
108  do i = 1, system1% Nmax
109  x = system1% pos(:, i)
110  si = system1%species(i)
111  cell = cells%cartesian_indices(x) + 1
112  list_idx = 0
113 
114  stencil: do j = 1, stencil_size
115  ! 0-based index for hilbert routine
116  actual_cell = modulo(cell + this% stencil(:,j) - 1 , cells% L)
117  actual_cell_md = .false.
118  actual_cell_noreac = .false.
119  neigh_idx = compact_p_to_h( actual_cell, m ) + 1
120  cell_n = cells% cell_count(neigh_idx)
121  cell_start = cells% cell_start(neigh_idx)
122 
123  do cell_i = cell_start, cell_start + cell_n - 1
124  s = system2%species(cell_i)
125  if (s <= 0) cycle
126  y = system2% pos(:, cell_i)
127  rsq = sum(rel_pos(x, y, l)**2)
128 
129  if (rsq .lt. radiussq) then
130  list_idx = list_idx + 1
131  actual_cell_md = .true.
132  if (do_lj) then
133  if (rsq <= lj%cut_sq(s, si)) actual_cell_noreac = .true.
134  end if
135  if (list_idx .gt. this% Nmax) then
136  error stop 'maximum of neighbor list reached'
137  end if
138  this% list(list_idx, i) = cell_i
139  end if
140  end do
141  if (actual_cell_md) then
142  !$omp atomic write
143  cells%is_md(neigh_idx) = .true.
144  if (actual_cell_noreac) then
145  !$omp atomic write
146  cells%is_reac(neigh_idx) = .false.
147  end if
148  end if
149 
150  end do stencil
151 
152  this% n(i) = list_idx
153 
154  end do
155  call this%time_update%tac()
156 
157  end subroutine update_list
158 
159  function compute_force(ps1, ps2, n_list, L, lj_params) result(e)
160  type(particle_system_t), intent(inout) :: ps1
161  type(particle_system_t), intent(inout) :: ps2
162  type(neighbor_list_t), intent(inout) :: n_list
163  double precision, intent(in) :: L(3)
164  type(lj_params_t), intent(in) :: lj_params
165  double precision :: e
166 
167  integer :: i, j
168  integer :: idx
169  integer :: MASK
170  integer :: n_species1, n_species2
171  double precision :: x(3), d(3), f(3), f1(3)
172  integer :: s1, s2
173  double precision :: r_sq
174 
175  n_species1 = ps1% n_species
176  n_species2 = ps2% n_species
177 
178  e = 0
179 
180  !$omp parallel do
181  do i = 1, ps2%Nmax
182  if (btest(ps2%flags(i), md_bit)) then
183  ps2%flags(i) = ibset(ps2%flags(i), past_md_bit)
184  else
185  ps2%flags(i) = ibclr(ps2%flags(i), past_md_bit)
186  end if
187  ps2%flags(i) = ibclr(ps2%flags(i), md_bit)
188  end do
189 
190  call n_list%time_force%tic()
191  !$omp parallel do private(x, s1, f1, j, idx, s2, d, r_sq, f, MASK) &
192  !$omp& reduction(+:e)
193  do i = 1, ps1% Nmax
194  if (ps1% species(i) <= 0) continue
195  x = ps1% pos(:, i)
196  s1 = ps1% species(i)
197  f1 = 0
198  do j = 1, n_list% n(i)
199  idx = n_list% list(j, i)
200  s2 = ps2% species(idx)
201  if (s2 <= 0) cycle
202  d = rel_pos(x, ps2% pos(:, idx), l)
203  r_sq = sum(d**2)
204  if ( r_sq <= lj_params% cut_sq(s2, s1) ) then
205  f = lj_force(d, r_sq, lj_params% epsilon(s2, s1), lj_params% sigma(s2, s1))
206  e = e + lj_energy(r_sq, lj_params% epsilon(s2, s1), &
207  lj_params% sigma(s2, s1), lj_params% cut_energy(s2, s1))
208  f1 = f1 + f
209  !$omp atomic
210  ps2%force(1, idx) = ps2% force(1,idx) - f(1)
211  !$omp atomic
212  ps2%force(2, idx) = ps2% force(2,idx) - f(2)
213  !$omp atomic
214  ps2%force(3, idx) = ps2% force(3,idx) - f(3)
215  mask = md_mask
216  if (s1 == 1) mask = ior(mask, catalyzed_mask)
217  !$omp atomic
218  ps2%flags(idx) = ior(ps2%flags(idx), mask)
219  end if
220  end do
221  ps1% force(:, i) = ps1% force(:, i) + f1
222  end do
223  call n_list%time_force%tac()
224 
225  end function compute_force
226 
227  function compute_force_n2(ps, L, lj_params) result(e)
228  type(particle_system_t), intent(inout) :: ps
229  double precision, intent(in) :: L(3)
230  type(lj_params_t), intent(in) :: lj_params
231  double precision :: e
232 
233  integer :: i, j
234  integer :: n_species
235  double precision :: x(3), d(3), f(3)
236  integer :: s1, s2
237  double precision :: r_sq
238 
239  n_species = ps% n_species
240 
241  e = 0
242 
243  call ps%time_self_force%tic()
244  do i = 1, ps% Nmax
245  s1 = ps% species(i)
246  if (s1 <= 0) continue
247  x = ps% pos(:, i)
248  do j = i + 1, ps% Nmax
249  s2 = ps% species(j)
250  if (s2 <= 0) continue
251  d = rel_pos(x, ps% pos(:, j), l)
252  r_sq = sum(d**2)
253  if ( r_sq <= lj_params% cut_sq(s1, s2) ) then
254  f = lj_force(d, r_sq, lj_params% epsilon(s2,s1), lj_params% sigma(s2,s1))
255  ps% force(:, i) = ps% force(:, i) + f
256  ps% force(:, j) = ps% force(:, j) - f
257  e = e + lj_energy(r_sq, lj_params% epsilon(s2,s1), &
258  lj_params% sigma(s2,s1), lj_params% cut_energy(s2,s1))
259  end if
260  end do
261  end do
262  call ps%time_self_force%tac()
263 
264  end function compute_force_n2
265 
266  !! Prepare a stencil of neighboring cells
267  !!
268  !! Precomputing the stencil of cells for the neighbor list is described in P. J. in 't Veld,
269  !! S. J. Plimpton and G. S. Grest. Comp. Phys. Commun. 179, 320-329 (2008) but for regular
270  !! Molecular Dynamics. The present version is suited for MPCD solvent.
271  subroutine make_stencil(this, cells, cut)
272  class(neighbor_list_t), intent(inout) :: this
273  type(cell_system_t), intent(in) :: cells
274  double precision :: cut
275 
276  integer :: max_i, count
277  integer :: i,j,k
278  double precision :: a
279 
280  a = cells% a
281 
282  max_i = floor(cut / a) + 1
283 
284  count = 0
285  do i = -max_i, max_i
286  do j = -max_i, max_i
287  do k = -max_i, max_i
288  if (closest( [i,j,k], [0,0,0] ) < cut) count = count + 1
289  end do
290  end do
291  end do
292 
293  if (allocated(this% stencil)) deallocate(this% stencil)
294  allocate(this% stencil(3, count))
295 
296  count = 0
297  do i = -max_i, max_i
298  do j = -max_i, max_i
299  do k = -max_i, max_i
300  if (closest( [i,j,k], [0,0,0] ) < cut) then
301  count = count + 1
302  this% stencil(:,count) = [i,j,k]
303  end if
304  end do
305  end do
306  end do
307 
308  end subroutine make_stencil
309 
310  pure function closest(x1, x2) result(c)
311  integer, dimension(3), intent(in) :: x1, x2
312  double precision :: c
313 
314  integer :: i, dist_sq
315 
316  dist_sq = 0
317  do i = 1, 3
318  dist_sq = dist_sq + max( 0, abs(x1(i) - x2(i)) - 1)**2
319  end do
320  c = sqrt(dble(dist_sq))
321 
322  end function closest
323 
324 end module neighbor_list
Derived type and routines for neighbor listing.
pure elemental double precision function, public lj_energy(r_sq, epsilon, sigma, cut_energy)
pure double precision function closest(x1, x2)
pure integer function, dimension(3) next_cell(p)
pure integer function, public compact_p_to_h(p, m)
Definition: hilbert.f90:242
integer, parameter, public catalyzed_mask
Definition: common.f90:60
integer, parameter, public md_mask
Definition: common.f90:58
integer, parameter, public md_bit
Definition: common.f90:50
subroutine make_stencil(this, cells, cut)
Data for particles.
double precision function, public compute_force(ps1, ps2, n_list, L, lj_params)
subroutine init(this, L, a, has_walls)
Definition: cell_system.f90:50
double precision function, public compute_force_n2(ps, L, lj_params)
Compute compact Hilbert indices.
Definition: hilbert.f90:9
subroutine update_list(this, system1, system2, radius, cells, lj)
Utility routines.
Definition: common.f90:12
integer, parameter, public past_md_bit
Definition: common.f90:52
integer, parameter dim
Definition: hilbert.f90:15
pure double precision function, dimension(3), public lj_force(d, r_sq, epsilon, sigma)
Definition: interaction.f90:84
pure double precision function, dimension(3), public rel_pos(x, y, L)
Return x-y distance with minimum image convention.
Definition: common.f90:163
Spatial cells.
Definition: cell_system.f90:11
Lennard-Jones potential definition.
Definition: interaction.f90:10