RMPCDMD
cell_system.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 hilbert
13  implicit none
14 
15  private
16 
17  public :: cell_system_t
19 
21  integer :: l(3)
22  double precision :: edges(3)
23  integer :: n
24  double precision :: a
25  double precision :: origin(3)
26  integer, allocatable :: cell_count(:)
27  integer, allocatable :: cell_count_tmp(:,:)
28  integer, allocatable :: cell_start(:)
29  logical, allocatable :: is_md(:)
30  logical, allocatable :: is_reac(:)
31  double precision :: max_v
32  integer :: m(3)
33  integer :: bc(3)
34  logical :: has_walls
35  contains
36  procedure :: init
37  procedure :: count_particles
38  procedure :: sort_particles
39  procedure :: random_shift
40  procedure :: cartesian_indices
41  end type cell_system_t
42 
43  integer, parameter :: periodic_bc = 1
44  integer, parameter :: bounce_back_bc = 2
45  integer, parameter :: specular_bc = 3
46 
47 contains
48 
49  subroutine init(this, L, a, has_walls)
50  use omp_lib
51  class(cell_system_t), intent(out) :: this
52  integer, intent(in) :: L(3)
53  double precision, intent(in) :: a
54  logical, intent(in), optional :: has_walls
55 
56  integer :: i
57 
58  this%L = l
59  this% edges = l*a
60  if (present(has_walls)) then
61  this% has_walls = has_walls
62  else
63  this% has_walls = .false.
64  end if
65  if (this% has_walls) then
66  this%L(3) = l(3) + 1
67  end if
68  this%a = a
69  this%M = 1
70  this%origin = 0.d0
71 
72  do i=1, 3
73  do while ( 2**this%M(i) < l(i) )
74  this%M(i) = this%M(i)+1
75  end do
76  end do
77  this%N = 2**this%M(1)*2**this%M(2)*2**this%M(3)
78  allocate(this%cell_count(this%N))
79  allocate(this%cell_count_tmp(this%N, omp_get_max_threads()))
80  allocate(this%cell_start(this%N))
81  allocate(this%is_md(this%N))
82  allocate(this%is_reac(this%N))
83 
84  end subroutine init
85 
86  subroutine count_particles(this, position)
87  use omp_lib
88  class(cell_system_t), intent(inout) :: this
89  double precision, intent(in) :: position(:, :)
90 
91  integer :: i, idx, N_particles, thread_max
92  integer :: p(3)
93  integer :: L(3)
94  logical :: nowalls
95  integer :: thread_id
96 
97  n_particles = size(position, 2)
98  thread_max = omp_get_max_threads()
99 
100  l = this% L
101  nowalls = .not. this% has_walls
102 
103  this%cell_count_tmp = 0
104 
105  !$omp parallel private(thread_id)
106  thread_id = omp_get_thread_num() + 1
107  !$omp do private(i, p, idx)
108  do i=1, n_particles
109  p = this%cartesian_indices(position(:,i))
110  idx = compact_p_to_h(p, this%M) + 1
111  this%cell_count_tmp(idx, thread_id) = this%cell_count_tmp(idx, thread_id) + 1
112  end do
113  !$omp end do
114  !$omp end parallel
115 
116  !$omp parallel do private(thread_id)
117  do i = 1, this%N
118  this%cell_count(i) = 0
119  do thread_id=1, thread_max
120  this%cell_count(i) = this%cell_count(i) + this%cell_count_tmp(i, thread_id)
121  end do
122  end do
123 
124  this%cell_start(1) = 1
125  do i=2, this%N
126  this%cell_start(i) = this%cell_start(i-1) + this%cell_count(i-1)
127  end do
128 
129  end subroutine count_particles
130 
131  subroutine sort_particles(this, position_old, position_new)
132  class(cell_system_t), intent(inout) :: this
133  double precision, intent(in) :: position_old(:, :)
134  double precision, intent(out) :: position_new(:, :)
135 
136  integer :: i, idx, N, start, p(3)
137 
138  n = size(position_old, 2)
139 
140  !$omp parallel do private(p, idx, start)
141  do i=1, n
142  p = this%cartesian_indices(position_old(:,i))
143  idx = compact_p_to_h(p, this%M) + 1
144  !$omp atomic capture
145  start = this%cell_start(idx)
146  this%cell_start(idx) = this%cell_start(idx) + 1
147  !$omp end atomic
148  position_new(:, start) = position_old(:, i)
149  end do
150 
151  end subroutine sort_particles
152 
153  subroutine random_shift(this, state)
154  use threefry_module
155  implicit none
156  class(cell_system_t), intent(inout) :: this
157  type(threefry_rng_t), intent(inout) :: state
158 
159  this%origin(1) = threefry_double(state) - 1
160  this%origin(2) = threefry_double(state) - 1
161  this%origin(3) = threefry_double(state) - 1
162 
163  end subroutine random_shift
164 
165  function cartesian_indices(this, position) result(p)
166  class(cell_system_t), intent(in) :: this
167  double precision, intent(in) :: position(3)
168  integer :: p(3)
169 
170  p = floor( (position / this%a) - this%origin )
171  if (p(1) == this%L(1)) p(1) = 0
172  if (p(2) == this%L(2)) p(2) = 0
173  if ( (.not. this%has_walls) .and. (p(3) == this%L(3)) ) p(3) = 0
174 
175  end function cartesian_indices
176 
177 end module cell_system
pure integer function, public compact_p_to_h(p, m)
Definition: hilbert.f90:242
integer, parameter, public periodic_bc
Definition: cell_system.f90:43
subroutine random_shift(this, state)
subroutine sort_particles(this, position_old, position_new)
integer, parameter, public specular_bc
Definition: cell_system.f90:45
subroutine init(this, L, a, has_walls)
Definition: cell_system.f90:50
Compute compact Hilbert indices.
Definition: hilbert.f90:9
subroutine count_particles(this, position)
Definition: cell_system.f90:87
Spatial cells.
Definition: cell_system.f90:11
integer function, dimension(3) cartesian_indices(this, position)
integer, parameter, public bounce_back_bc
Definition: cell_system.f90:44