44 type(threefry_rng_t),
intent(inout) :: state
45 double precision :: n(3)
48 double precision :: s, alpha
51 do while (.not. s_lt_one)
52 n(1) = threefry_double(state)
53 n(2) = threefry_double(state)
56 if ( s<1.d0 ) s_lt_one = .true.
58 alpha = 2.d0 * sqrt(1.d0 - s)
71 subroutine simple_mpcd_step(particles, cells, state, alpha, thermostat, T, hydro)
75 type(threefry_rng_t),
intent(inout) :: state(:)
76 double precision,
intent(in),
optional :: alpha
77 logical,
intent(in),
optional :: thermostat
78 double precision,
intent(in),
optional :: T
79 logical,
intent(in),
optional :: hydro
81 integer :: i, start, n
82 integer :: cell_idx, n_effective
83 double precision :: local_v(3), omega(3,3), vec(3)
84 double precision :: virtual_v(3)
85 double precision :: sin_alpha, cos_alpha
86 double precision :: t_factor
88 logical :: do_thermostat, do_hydro
90 if (
present(thermostat))
then 91 do_thermostat = thermostat
95 stop
'no temperature given for thermostat in simple_mpcd_step' 98 do_thermostat = .false.
101 if (
present(hydro))
then 107 if ((.not. do_hydro) .and. (.not. thermostat))
then 108 stop .not.
'requiring do_hydro without thermostat in simple_mpcd_step' 111 if (
present(alpha))
then 112 sin_alpha = sin(alpha)
113 cos_alpha = cos(alpha)
119 call particles%time_step%tic()
121 thread_id = omp_get_thread_num() + 1
127 do cell_idx = 1, cells% N
128 if (cells% cell_count(cell_idx) <= 1) cycle
130 start = cells% cell_start(cell_idx)
131 n = cells% cell_count(cell_idx)
135 do i = start, start + n - 1
136 if (particles%species(i) > 0)
then 137 local_v = local_v + particles% vel(:, i)
138 n_effective = n_effective + 1
141 if (n_effective <= 1) cycle
142 local_v = local_v / n_effective
144 if (do_thermostat)
then 146 do i = start, start + n - 1
147 if (particles%species(i) <= 0) cycle
148 vec(1) = threefry_normal(state(thread_id))*t_factor
149 vec(2) = threefry_normal(state(thread_id))*t_factor
150 vec(3) = threefry_normal(state(thread_id))*t_factor
151 particles% vel(:, i) = vec
152 virtual_v = virtual_v + particles% vel(:, i)
154 virtual_v = local_v - virtual_v / n_effective
156 do i = start, start + n - 1
157 if (particles%species(i) <= 0) cycle
158 particles% vel(:, i) = particles% vel(:, i) + virtual_v
165 cos_alpha+vec(1)**2*(1-cos_alpha), vec(1)*vec(2)*(1-cos_alpha) - vec(3)*sin_alpha, &
166 vec(1)*vec(3)*(1-cos_alpha) + vec(2)*sin_alpha ,&
167 vec(2)*vec(1)*(1-cos_alpha) + vec(3)*sin_alpha , cos_alpha+vec(2)**2*(1-cos_alpha) ,&
168 vec(2)*vec(3)*(1-cos_alpha) - vec(1)*sin_alpha,&
169 vec(3)*vec(1)*(1-cos_alpha) - vec(2)*sin_alpha, vec(3)*vec(2)*(1-cos_alpha) + vec(1)*sin_alpha,&
170 cos_alpha + vec(3)**2*(1-cos_alpha) &
173 do i = start, start + n - 1
174 particles% vel(:, i) = local_v + matmul(omega, (particles% vel(:, i)-local_v))
181 call particles%time_step%tac()
193 subroutine wall_mpcd_step(particles, cells, state, wall_temperature, wall_v, wall_n, &
194 thermostat, bulk_temperature, alpha, keep_cell_v)
199 type(threefry_rng_t),
intent(inout) :: state(:)
200 double precision,
optional,
intent(in) :: wall_temperature(2)
201 double precision,
optional,
intent(in) :: wall_v(3,2)
202 integer,
optional,
intent(in) :: wall_n(2)
203 logical,
intent(in),
optional :: thermostat
204 double precision,
intent(in),
optional :: bulk_temperature
205 double precision,
intent(in),
optional :: alpha
206 logical,
intent(in),
optional :: keep_cell_v
208 integer :: i, start, n
210 double precision :: local_v(3), omega(3,3), vec(3)
211 double precision :: sin_alpha, cos_alpha
215 double precision :: virtual_v(3), t_factor
216 logical :: all_present, all_absent
217 logical :: do_thermostat, do_cell_v
220 all_present =
present(wall_temperature) .and.
present(wall_v) .and.
present(wall_n)
221 all_absent = .not.
present(wall_temperature) .and. .not.
present(wall_v) .and. .not.
present(wall_n)
222 if ( .not. (all_present .or. all_absent) ) &
223 error stop
'wall parameters must be all present or all absent in wall_mpcd_step' 225 if (
present(thermostat))
then 226 do_thermostat = thermostat
227 if (do_thermostat)
then 228 if (
present(bulk_temperature))
then 229 t_factor = sqrt(bulk_temperature)
231 error stop
'thermostat requested but no temperature given in wall_mpcd_step' 233 if (
present(keep_cell_v))
then 234 do_cell_v = keep_cell_v
240 do_thermostat = .false.
243 if (
present(keep_cell_v))
then 244 if (.not.
present(thermostat))
then 245 stop
'requiring keep_cell_v and not setting thermostat in wall_mpcd_step' 247 if ((.not. keep_cell_v) .and. (.not. do_thermostat))
then 248 stop .not..not.
'requiring keep_cell_v and thermostat in wall_mpcd_step' 252 if (
present(alpha))
then 253 sin_alpha = sin(alpha)
254 cos_alpha = cos(alpha)
260 call particles%time_step%tic()
262 thread_id = omp_get_thread_num() + 1
264 do cell_idx = 1, cells% N
265 if (cells% cell_count(cell_idx) <= 1) cycle
267 start = cells% cell_start(cell_idx)
268 n = cells% cell_count(cell_idx)
273 if (all_present .and. (cell(3) == 1))
then 275 else if (all_present .and. (cell(3) == cells% L(3)))
then 281 if (wall_idx > 0)
then 282 if (n < wall_n(wall_idx))
then 283 n_virtual = wall_n(wall_idx) - n
284 virtual_v(1) = threefry_normal(state(thread_id))
285 virtual_v(2) = threefry_normal(state(thread_id))
286 virtual_v(3) = threefry_normal(state(thread_id))
287 virtual_v = virtual_v * sqrt(n_virtual*wall_temperature(wall_idx))
292 do i = start, start + n - 1
293 local_v = local_v + particles% vel(:, i)
295 if (n_virtual > 0)
then 296 local_v = (local_v + virtual_v) / wall_n(wall_idx)
298 local_v = local_v / n
301 if (do_thermostat)
then 303 do i = start, start + n - 1
304 vec(1) = threefry_normal(state(thread_id))
305 vec(2) = threefry_normal(state(thread_id))
306 vec(3) = threefry_normal(state(thread_id))
307 particles% vel(:, i) = vec*t_factor
308 virtual_v = virtual_v + particles% vel(:, i)
311 virtual_v = local_v - virtual_v / dble(n)
312 do i = start, start + n - 1
313 particles% vel(:, i) = particles% vel(:, i) + virtual_v
320 cos_alpha+vec(1)**2*(1-cos_alpha), vec(1)*vec(2)*(1-cos_alpha) - vec(3)*sin_alpha, &
321 vec(1)*vec(3)*(1-cos_alpha) + vec(2)*sin_alpha ,&
322 vec(2)*vec(1)*(1-cos_alpha) + vec(3)*sin_alpha , cos_alpha+vec(2)**2*(1-cos_alpha) ,&
323 vec(2)*vec(3)*(1-cos_alpha) - vec(1)*sin_alpha,&
324 vec(3)*vec(1)*(1-cos_alpha) - vec(2)*sin_alpha, vec(3)*vec(2)*(1-cos_alpha) + vec(1)*sin_alpha,&
325 cos_alpha + vec(3)**2*(1-cos_alpha) &
328 do i = start, start + n - 1
329 particles%vel(:,i) = local_v + matmul(omega, particles%vel(:,i)-local_v)
335 call particles%time_step%tac()
346 type(
profile_t),
intent(inout),
optional :: tz
348 double precision :: te
350 integer :: i, start, n, n_effective
351 integer :: cell_idx, count
353 double precision :: local_v(3), local_kin
356 if (
present(tz))
then 358 if (.not. (
allocated(tz% data) .and.
allocated(tz% count))) error stop
'profile_t: data not allocated' 363 call particles%time_ct%tic()
369 do cell_idx = 1, cells% N
370 if (cells% cell_count(cell_idx) <= 1) cycle
372 start = cells% cell_start(cell_idx)
373 n = cells% cell_count(cell_idx)
379 do i = start, start + n - 1
380 if (particles%species(i) > 0)
then 381 local_v = local_v + particles% vel(:, i)
382 n_effective = n_effective + 1
386 if (n_effective <= 1) cycle
388 local_v = local_v / n
389 do i = start, start + n - 1
390 if (particles%species(i) > 0)
then 391 local_kin = local_kin + sum((particles% vel(:, i)-local_v)**2)
394 local_kin = local_kin / dble(3*(n_effective-1))
399 call tz% bin(cells% origin(3) + (cell(3)+0.5d0)*cells% a, local_kin)
403 call particles%time_ct%tac()
416 if (.not.
allocated(rhoz% data)) error stop
'histogram_t: data not allocated' 418 do i = 1, particles% Nmax
419 call rhoz% bin(particles% pos(3, i))
431 if (.not.
allocated(vx% data)) error stop
'histogram_t: data not allocated' 433 do i = 1, particles% Nmax
434 call vx% bin(particles% pos(3, i), particles% vel(1, i))
443 double precision,
intent(in) :: dt
445 integer :: i, jump(3)
446 double precision :: edges(3)
450 do i = 1, particles% Nmax
451 particles% pos(:,i) = particles% pos(:,i) + particles% vel(:,i)*dt
452 jump = floor(particles% pos(:,i) / edges)
453 particles% image(:,i) = particles% image(:,i) + jump
454 particles% pos(:,i) = particles% pos(:,i) - jump * edges
467 double precision,
intent(in) :: dt
468 double precision,
intent(in):: g
470 integer :: i, bc(3), im(3)
471 double precision :: delta, L(3), gvec(3)
472 double precision,
dimension(3) :: old_pos, old_vel
473 double precision,
dimension(3) :: new_pos, new_vel
474 double precision :: t_c, t_b, t_ab
475 logical :: y_out, z_out
482 call particles%time_stream%tic()
484 do i = 1, particles% Nmax
485 old_pos = particles% pos(:,i)
486 old_vel = particles% vel(:,i)
487 new_pos = old_pos + old_vel*dt + gvec*dt**2/2
490 y_out = ((new_pos(2)<0) .or. (new_pos(2)>l(2)))
491 z_out = ((new_pos(3)<0) .or. (new_pos(3)>l(3)))
498 particles%flags(i) = ibset(particles%flags(i),
wall_bit)
499 particles%vel(:,i) = new_vel
502 particles%pos(:,i) = new_pos
504 call particles%time_stream%tac()
512 double precision,
dimension(3),
intent(inout) :: x0, v0, x, v
513 integer,
dimension(3),
intent(inout) :: im
514 double precision,
intent(in) :: L(3), t
515 integer,
intent(in) :: bc(3)
516 double precision,
intent(in),
optional :: g
518 double precision,
dimension(3) :: gvec
519 double precision :: t_collision, t_remainder, tt
520 integer :: i, coll_dim, actual_bc
524 if (
present(g)) gvec(1) = g
528 t_collision = huge(t_collision)
531 tt = (l(i)-x0(i))/v0(i)
532 if ( (tt>0) .and. (tt<t_collision) )
then 538 if ( (tt>0) .and. (tt<t_collision) )
then 545 if (coll_dim==0)
return 547 t_remainder = t - t_collision
549 x = x0 + v0*t_collision + gvec*t_collision**2 / 2
550 v = v0 + gvec*t_collision
555 v(coll_dim) = -v(coll_dim)
558 x(coll_dim) = x(coll_dim) - jump(coll_dim)*l(coll_dim)
559 im(coll_dim) = im(coll_dim) + jump(coll_dim)
562 wall_loop:
do while (.true.)
565 if (v(coll_dim)>0)
then 566 t_collision = (l(coll_dim)-x(coll_dim))/v(coll_dim)
568 t_collision = -x(coll_dim)/v(coll_dim)
570 if ((t_collision < 0) .or. (t_collision > t_remainder))
exit wall_loop
571 x = x + v*t_collision + gvec*t_collision**2 / 2
572 v = v + gvec*t_collision
573 t_remainder = t_remainder - t_collision
577 v(coll_dim) = -v(coll_dim)
580 x(coll_dim) = x(coll_dim) - jump(coll_dim)*l(coll_dim)
581 im(coll_dim) = im(coll_dim) + jump(coll_dim)
585 t_collision = t_remainder
586 x = x + v*t_collision + gvec*t_collision**2 / 2 + im*l
587 v = v + gvec*t_collision
595 integer,
intent(in) :: i
609 integer,
intent(in) :: from, to
610 double precision,
intent(in) :: rate, tau
611 type(threefry_rng_t),
intent(inout) :: state(:)
613 integer :: cell_idx, start, n, i, pick, s
614 double precision :: local_rate
618 thread_id = omp_get_thread_num() + 1
621 if ( (c%cell_count(cell_idx) <= 1) .or. .not. c%is_reac(cell_idx) ) cycle
623 start = c%cell_start(cell_idx)
624 n = c%cell_count(cell_idx)
627 do i = start, start + n - 1
630 local_rate = local_rate + 1
635 local_rate = local_rate*rate
636 if (threefry_double(state(thread_id)) < (1 - exp(-local_rate*tau)))
then 650 integer,
intent(in) :: from, to
651 double precision,
intent(in) :: rate, tau, delta_u
652 type(threefry_rng_t),
intent(inout) :: state(:)
654 integer :: cell_idx, start, n, i, pick, s
655 double precision :: local_rate
657 double precision :: kin, com_v(3), factor
660 thread_id = omp_get_thread_num() + 1
662 cell_loop:
do cell_idx = 1, c%N
663 if ( (c%cell_count(cell_idx) <= 1) .or. .not. c%is_reac(cell_idx) ) cycle
665 start = c%cell_start(cell_idx)
666 n = c%cell_count(cell_idx)
670 do i = start, start + n - 1
673 local_rate = local_rate + 1
676 com_v = com_v + p%vel(:,i)
681 do i = start, start + n - 1
682 kin = kin + sum((p%vel(:,i)-com_v)**2)
686 if ( (local_rate > 0) .and. (kin > delta_u) )
then 687 local_rate = local_rate*rate
688 if (threefry_double(state(thread_id)) < (1 - exp(-local_rate*tau)))
then 690 factor = sqrt((kin - delta_u)/kin)
691 do i = start, start + n - 1
692 p%vel(:,i) = com_v + factor*(p%vel(:,i)-com_v)
705 double precision,
intent(in) :: dt
708 double precision :: delta, L(3)
709 double precision,
dimension(3) :: old_pos, old_vel
710 double precision,
dimension(3) :: new_pos, new_vel
711 double precision :: t_c, t_b, t_ab
716 call particles%time_stream%tic()
718 particles_loop:
do i = 1, particles% Nmax
719 old_pos = particles%pos(:,i)
720 old_vel = particles%vel(:,i)
721 new_pos = old_pos + old_vel*dt + particles%force(:,i)*dt**2 / 2
724 if (new_pos(3)<0)
then 725 t_c = -old_pos(3)/old_vel(3)
727 else if (new_pos(3)>l(3))
then 728 t_c = (l(3)-old_pos(3))/old_vel(3)
735 new_pos = new_pos - old_vel*2*(dt-t_c)
737 particles%flags(i) = ibset(particles%flags(i),
wall_bit)
740 particles%pos(:,i) = new_pos
741 particles%vel(:,i) = new_vel
742 end do particles_loop
743 call particles%time_stream%tac()
752 type(threefry_rng_t),
intent(inout) :: state(:)
753 double precision,
intent(in) :: T
755 integer :: i, start, n
756 integer :: cell_idx, n_effective
757 double precision :: local_v(3)
758 double precision :: t_factor, local_kin
762 call particles%time_step%tic()
764 thread_id = omp_get_thread_num() + 1
766 do cell_idx = 1, cells% N
767 if (cells% cell_count(cell_idx) <= 1) cycle
769 start = cells% cell_start(cell_idx)
770 n = cells% cell_count(cell_idx)
774 do i = start, start + n - 1
775 if (particles%species(i) > 0)
then 776 local_v = local_v + particles% vel(:, i)
777 n_effective = n_effective + 1
780 if (n_effective <= 1) cycle
781 local_v = local_v / n_effective
784 do i = start, start + n - 1
785 if (particles%species(i) > 0)
then 786 local_kin = local_kin + sum((particles%vel(:,i) - local_v)**2)
789 t_factor = sqrt(3*(n_effective-1)*t/local_kin)
791 do i = start, start + n - 1
792 if (particles%species(i) > 0) &
793 particles% vel(:, i) = local_v + t_factor*(particles% vel(:, i)-local_v)
799 call particles%time_step%tac()
pure integer function, dimension(dim), public compact_h_to_p(h, m)
subroutine, public wall_mpcd_step(particles, cells, state, wall_temperature, wall_v, wall_n, thermostat, bulk_temperature, alpha, keep_cell_v)
Collisions in partially filled cells at the walls use the rule of Lamura et al (2001) ...
subroutine, public bulk_reaction_endothermic(p, c, from, to, rate, tau, state, delta_u)
Apply a endothermic bulk unimolecular RMPCD reaction.
subroutine, public compute_rho(particles, rhoz)
Compute density profile along z.
integer, parameter, public periodic_bc
double precision function, public compute_temperature(particles, cells, tz)
Compute the temperature of a mpcd solvent.
subroutine, public mpcd_stream_periodic(particles, cells, dt)
Stream MPCD particles in a periodic system.
subroutine, public simple_mpcd_step(particles, cells, state, alpha, thermostat, T, hydro)
Perform a collision.
subroutine, public bulk_reaction(p, c, from, to, rate, tau, state)
Apply a bulk unimolecular RMPCD reaction.
integer, parameter, public specular_bc
subroutine, public compute_vx(particles, vx)
Compute x-velocity profile along z.
integer, parameter, public wall_bit
Compute compact Hilbert indices.
Container for a profile, e.g. v(x)
subroutine, public mpcd_stream_nogravity_zwall(particles, cells, dt)
double precision function, dimension(3), public rand_sphere(state)
Return random point on the surface of a sphere.
Routines to perform MPCD dynamics.
subroutine, public rescale_cells(particles, cells, state, T)
Rescale the kinetic energy of all cells.
subroutine yzwall_collision(x0, v0, x, v, im, L, t, bc, g)
Collide a particle in y and z with constant acceleration in x.
Container for a histogram, e.g. p(x)
pure integer function change_23(i)
Return 2 for 3 and 3 for 2.
subroutine, public mpcd_stream_xforce_yzwall(particles, cells, dt, g)
Stream MPCD particles with a force in the x-direction and specular or bounce-back conditions in y...
integer, parameter, public bounce_back_bc