RMPCDMD
single_dimer_pbc.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 
32 
34  use rmpcdmd_module
35  use hdf5
36  use h5md_module
37  use threefry_module
38  use parsetext
39  use iso_c_binding
40  use omp_lib
41  implicit none
42 
43  type(cell_system_t) :: solvent_cells
44  type(particle_system_t) :: solvent
45  type(particle_system_t) :: colloids
46  type(neighbor_list_t) :: neigh
47  type(lj_params_t) :: solvent_colloid_lj
48  type(lj_params_t) :: colloid_lj
49 
50  integer, parameter :: N_species = 2
51 
52  integer :: rho
53  integer :: N
54  integer :: error
55 
56  double precision :: sigma_N, sigma_C, max_cut
57  double precision :: epsilon(2,2)
58  double precision :: sigma(2,2), sigma_cut(2,2)
59  double precision :: mass(2)
60 
61  double precision :: e1, e2
62  double precision :: tau, dt , T
63  double precision :: d,prob
64  double precision :: skin, co_max, so_max
65  integer :: N_MD_steps, N_loop, collide_every
66  integer :: n_extra_sorting
67 
68  type(pto) :: config
69 
70  integer :: i, L(3)
71  integer :: j, k
72  type(timer_t), target :: varia, main, time_flag, time_refuel, time_change
73  double precision :: total_time
74  type(timer_list_t) :: timer_list
75  integer(HID_T) :: timers_group
76 
77  type(threefry_rng_t), allocatable :: state(:)
78  integer :: n_threads
79  type(h5md_file_t) :: hfile
80  type(h5md_element_t) :: dummy_element
81  integer(HID_T) :: fields_group, params_group
82  integer(HID_T) :: box_group
83  type(thermo_t) :: thermo_data
84  double precision :: temperature, kin_e
85  double precision :: v_com(3)
86  double precision :: com_pos(3)
87  double precision :: unit_r(3)
88  type(particle_system_io_t) :: dimer_io
89  type(particle_system_io_t) :: solvent_io
90  double precision :: bulk_rate
91  logical :: bulk_rmpcd
92 
93  integer, dimension(N_species) :: n_solvent
94  type(h5md_element_t) :: n_solvent_el
95 
96  integer, parameter :: block_length = 8
97  type(axial_correlator_t) :: axial_cf
98  integer(HID_T) :: correlator_group
99 
100  integer :: equilibration_loops
101  integer :: colloid_sampling
102  logical :: sampling
103  logical :: collision_step
104  logical :: do_hydro, do_thermostat
105 
106  type(histogram_t) :: z_hist
107  type(h5md_element_t) :: z_hist_el
108  double precision :: cyl_shell_rmin, cyl_shell_rmax
109  type(args_t) :: args
110 
111  args = get_input_args()
112  call ptparse(config, args%input_file, 11)
113 
114  n_threads = omp_get_max_threads()
115  allocate(state(n_threads))
116  call threefry_rng_init(state, args%seed)
117 
118  call main%init('main')
119  call varia%init('varia')
120  call time_flag%init('flag')
121  call time_refuel%init('refuel')
122  call time_change%init('change')
123 
124  call timer_list%init(16)
125  call timer_list%append(varia)
126  call timer_list%append(time_flag)
127  call timer_list%append(time_refuel)
128  call timer_list%append(time_change)
129 
130  call h5open_f(error)
131  call hfile%create(args%output_file, 'RMPCDMD::single_dimer_pbc', &
132  rmpcdmd_revision, 'Pierre de Buyl')
133  call h5gcreate_f(hfile%id, 'parameters', params_group, error)
134  call hdf5_util_write_dataset(params_group, 'seed', args%seed)
135  prob = ptread_d(config,'probability', loc=params_group)
136  bulk_rmpcd = ptread_l(config, 'bulk_rmpcd', loc=params_group)
137  bulk_rate = ptread_d(config, 'bulk_rate', loc=params_group)
138 
139  l = ptread_ivec(config, 'L', 3, loc=params_group)
140  rho = ptread_i(config, 'rho', loc=params_group)
141  n = rho *l(1)*l(2)*l(3)
142 
143  t = ptread_d(config, 'T', loc=params_group)
144  d = ptread_d(config, 'd', loc=params_group)
145 
146  dt = ptread_d(config, 'dt', loc=params_group)
147  n_md_steps = ptread_i(config, 'N_MD', loc=params_group)
148 
149  collide_every = ptread_i(config, 'collide_every', loc=params_group)
150  tau = dt*n_md_steps*collide_every
151 
152  n_loop = ptread_i(config, 'N_loop', loc=params_group)
153  equilibration_loops = ptread_i(config, 'equilibration_loops', loc=params_group)
154 
155  colloid_sampling = ptread_i(config, 'colloid_sampling', loc=params_group)
156  if (modulo(n_md_steps, colloid_sampling) /= 0) then
157  error stop 'colloid_sampling must divide N_MD with no remainder'
158  end if
159 
160  sigma_c = ptread_d(config, 'sigma_C', loc=params_group)
161  sigma_n = ptread_d(config, 'sigma_N', loc=params_group)
162 
163  ! solvent index first, colloid index second, in solvent_colloid_lj
164  epsilon(:,1) = ptread_dvec(config, 'epsilon_C', 2, loc=params_group)
165  epsilon(:,2) = ptread_dvec(config, 'epsilon_N', 2, loc=params_group)
166 
167  sigma(:,1) = sigma_c
168  sigma(:,2) = sigma_n
169  sigma_cut = sigma*2**(1.d0/6.d0)
170  max_cut = maxval(sigma_cut)
171 
172  call solvent_colloid_lj% init(epsilon, sigma, sigma_cut)
173 
174  epsilon(1,1) = ptread_d(config, 'epsilon_C_C', loc=params_group)
175  epsilon(1,2) = ptread_d(config, 'epsilon_N_C', loc=params_group)
176  epsilon(2,1) = epsilon(1,2)
177  epsilon(2,2) = ptread_d(config, 'epsilon_N_N', loc=params_group)
178 
179  sigma(1,1) = 2*sigma_c
180  sigma(1,2) = sigma_c + sigma_n
181  sigma(2,1) = sigma_c + sigma_n
182  sigma(2,2) = 2*sigma_n
183  sigma_cut = sigma*2**(1.d0/6.d0)
184 
185  call colloid_lj% init(epsilon, sigma, sigma_cut)
186 
187  mass(1) = rho * sigma_c**3 * 4 * 3.14159265/3
188  mass(2) = rho * sigma_n**3 * 4 * 3.14159265/3
189 
190  call solvent% init(n,2, system_name='solvent') !there will be 2 species of solvent particles
191 
192  call colloids% init(2,2, mass, system_name='colloids') !there will be 2 species of colloids
193 
194  call thermo_data%init(hfile, n_buffer=50, step=n_md_steps, time=n_md_steps*dt)
195 
196  do_hydro = ptread_l(config, 'do_hydro', loc=params_group)
197  do_thermostat = ptread_l(config, 'do_thermostat', loc=params_group)
198 
199  call h5gclose_f(params_group, error)
200  call ptkill(config)
201 
202  call axial_cf%init(block_length, n_loop, n_loop*n_md_steps)
203 
204  colloids% species(1) = 1
205  colloids% species(2) = 2
206  colloids% vel = 0
207  colloids% force = 0
208 
209  dimer_io%force_info%store = .false.
210  dimer_io%id_info%store = .false.
211  dimer_io%position_info%store = .true.
212  dimer_io%position_info%mode = ior(h5md_linear,h5md_store_time)
213  dimer_io%position_info%step = colloid_sampling
214  dimer_io%position_info%time = colloid_sampling*dt
215  dimer_io%image_info%store = .true.
216  dimer_io%image_info%mode = ior(h5md_linear,h5md_store_time)
217  dimer_io%image_info%step = colloid_sampling
218  dimer_io%image_info%time = colloid_sampling*dt
219  dimer_io%velocity_info%store = .true.
220  dimer_io%velocity_info%mode = ior(h5md_linear,h5md_store_time)
221  dimer_io%velocity_info%step = colloid_sampling
222  dimer_io%velocity_info%time = colloid_sampling*dt
223  dimer_io%species_info%store = .true.
224  dimer_io%species_info%mode = h5md_fixed
225  call dimer_io%init(hfile, 'dimer', colloids)
226 
227  solvent_io%force_info%store = .false.
228  solvent_io%id_info%store = .false.
229  solvent_io%position_info%store = .true.
230  solvent_io%position_info%mode = ior(h5md_linear,h5md_store_time)
231  solvent_io%position_info%step = n_loop*n_md_steps
232  solvent_io%position_info%time = n_loop*n_md_steps*dt
233  solvent_io%image_info%store = .true.
234  solvent_io%image_info%mode = ior(h5md_linear,h5md_store_time)
235  solvent_io%image_info%step = n_loop*n_md_steps
236  solvent_io%image_info%time = n_loop*n_md_steps*dt
237  solvent_io%velocity_info%store = .true.
238  solvent_io%velocity_info%mode = ior(h5md_linear,h5md_store_time)
239  solvent_io%velocity_info%step = n_loop*n_md_steps
240  solvent_io%velocity_info%time = n_loop*n_md_steps*dt
241  solvent_io%species_info%store = .true.
242  solvent_io%species_info%mode = ior(h5md_linear,h5md_store_time)
243  solvent_io%species_info%step = n_loop*n_md_steps
244  solvent_io%species_info%time = n_loop*n_md_steps*dt
245  call solvent_io%init(hfile, 'solvent', solvent)
246 
247  do k = 1, solvent%Nmax
248  solvent% vel(1,k) = threefry_normal(state(1))*sqrt(t)
249  solvent% vel(2,k) = threefry_normal(state(1))*sqrt(t)
250  solvent% vel(3,k) = threefry_normal(state(1))*sqrt(t)
251  end do
252  solvent% vel = solvent% vel - spread(sum(solvent% vel, dim=2)/solvent% Nmax, 2, solvent% Nmax)
253  solvent% force = 0
254  solvent% species = 1
255 
256  call solvent_cells%init(l, 1.d0)
257  colloids% pos(:,1) = solvent_cells% edges/2.0
258  colloids% pos(:,2) = solvent_cells% edges/2.0
259  colloids% pos(1,2) = colloids% pos(1,2) + d
260 
261  call n_solvent_el%create_time(hfile%observables, 'n_solvent', &
262  n_solvent, h5md_linear, step=n_md_steps, &
263  time=n_md_steps*dt)
264 
265  call h5gcreate_f(dimer_io%group, 'box', box_group, error)
266  call h5md_write_attribute(box_group, 'dimension', 3)
267  call dummy_element%create_fixed(box_group, 'edges', solvent_cells%edges)
268  call h5gclose_f(box_group, error)
269 
270  call h5gcreate_f(solvent_io%group, 'box', box_group, error)
271  call h5md_write_attribute(box_group, 'dimension', 3)
272  call dummy_element%create_fixed(box_group, 'edges', solvent_cells%edges)
273  call h5gclose_f(box_group, error)
274 
275  call solvent% random_placement(solvent_cells% edges, colloids, solvent_colloid_lj, state(1))
276 
277  call solvent% sort(solvent_cells)
278 
279  call neigh% init(colloids% Nmax, int(300*max(sigma_c,sigma_n)**3))
280 
281  skin = 1
282  n_extra_sorting = 0
283 
284  call neigh% make_stencil(solvent_cells, max_cut+skin)
285 
286  call neigh% update_list(colloids, solvent, max_cut+skin, solvent_cells, solvent_colloid_lj)
287 
288  cyl_shell_rmin = max(sigma_n, sigma_c)
289  cyl_shell_rmax = cyl_shell_rmin + 2
290  call h5gcreate_f(hfile%id, 'fields', fields_group, error)
291  call z_hist%init(-5.d0, 5.d0+d, 100)
292  call z_hist_el%create_time(fields_group, 'cylindrical_shell_histogram', z_hist%data, &
293  h5md_linear, step=n_md_steps, time=n_md_steps*dt)
294  call h5md_write_attribute(z_hist_el%id, 'r_min', cyl_shell_rmin)
295  call h5md_write_attribute(z_hist_el%id, 'r_max', cyl_shell_rmax)
296  call h5md_write_attribute(z_hist_el%id, 'xmin', z_hist%xmin)
297  call h5md_write_attribute(z_hist_el%id, 'dx', z_hist%dx)
298  call h5gclose_f(fields_group, error)
299 
300  e1 = compute_force(colloids, solvent, neigh, solvent_cells% edges, solvent_colloid_lj)
301  e2 = compute_force_n2(colloids, solvent_cells% edges, colloid_lj)
302  solvent% force_old = solvent% force
303  colloids% force_old = colloids% force
304 
305  call h5fflush_f(hfile%id, h5f_scope_global_f, error)
306 
307  write(*,*) 'Box size', l
308  write(*,*) 'Fluid particles', n
309  if (do_hydro) then
310  write(*,*) 'MPCD tau', tau
311  else
312  write(*,*) 'RS resampling time', tau
313  end if
314  write(*,*) 'Dimer mass', mass
315 
316  write(*,*) 'Running for', equilibration_loops, '+', n_loop, 'loops'
317 
318  call main%tic()
319  sampling = .false.
320  do i = 0, n_loop+equilibration_loops
321  if (i==equilibration_loops) sampling = .true.
322  if (modulo(i,20) == 0) write(*,'(i05)',advance='no') i
323  md_loop: do j = 1, n_md_steps
324  call md_pos(solvent, dt)
325 
326  call varia%tic()
327  ! Extra copy for rattle
328  colloids% pos_rattle = colloids% pos
329  do k=1, colloids% Nmax
330  colloids% pos(:,k) = colloids% pos(:,k) + dt * colloids% vel(:,k) + &
331  dt**2 * colloids% force(:,k) / (2 * colloids% mass(k))
332  end do
333 
334  call rattle_dimer_pos(colloids, d, dt, solvent_cells% edges)
335  call varia%tac()
336 
337  so_max = solvent% maximum_displacement()
338  co_max = colloids% maximum_displacement()
339 
340  if ( (co_max >= skin*0.1d0) .or. (so_max >= skin*0.89d0) ) then
341  call varia%tic()
342  call apply_pbc(solvent, solvent_cells% edges)
343  call apply_pbc(colloids, solvent_cells% edges)
344  call varia%tac()
345  call solvent% sort(solvent_cells)
346  call neigh% update_list(colloids, solvent, max_cut + skin, solvent_cells, solvent_colloid_lj)
347  call varia%tic()
348  !$omp parallel do
349  do k = 1, solvent%Nmax
350  solvent% pos_old(:,k) = solvent% pos(:,k)
351  end do
352  colloids% pos_old = colloids% pos
353  n_extra_sorting = n_extra_sorting + 1
354  call varia%tac()
355  end if
356 
357  call varia%tic()
358  call switch(solvent% force, solvent% force_old)
359  call switch(colloids% force, colloids% force_old)
360 
361  !$omp parallel do
362  do k = 1, solvent%Nmax
363  solvent% force(:,k) = 0
364  end do
365  colloids% force = 0
366  call varia%tac()
367  e1 = compute_force(colloids, solvent, neigh, solvent_cells% edges, solvent_colloid_lj)
368  e2 = compute_force_n2(colloids, solvent_cells% edges, colloid_lj)
369 
370  call md_vel(solvent, dt)
371 
372  call varia%tic()
373  do k=1, colloids% Nmax
374  colloids% vel(:,k) = colloids% vel(:,k) + &
375  dt * ( colloids% force(:,k) + colloids% force_old(:,k) ) / (2 * colloids% mass(k))
376  end do
377 
378  call rattle_dimer_vel(colloids, d, dt, solvent_cells% edges)
379  call varia%tac()
380 
381  if (sampling) then
382  v_com = sum(colloids%vel, dim=2)/2
383  unit_r = rel_pos(colloids%pos(:,1), colloids%pos(:,2), solvent_cells%edges)
384  unit_r = unit_r / norm2(unit_r)
385  call axial_cf%add_fast((i-equilibration_loops)*n_md_steps+j-1, v_com, unit_r)
386  end if
387 
388  if ((sampling) .and. (modulo(j, colloid_sampling)==0)) then
389  call dimer_io%position%append(colloids%pos)
390  call dimer_io%velocity%append(colloids%vel)
391  call dimer_io%image%append(colloids%image)
392  end if
393 
394  call time_flag%tic()
395  call flag_particles_nl
396  call time_flag%tac()
397  call time_change%tic()
398  call change_species
399  call time_change%tac()
400 
401  end do md_loop
402 
403  collision_step = (modulo(i, collide_every) == 0)
404 
405  call varia%tic()
406 
407  if (sampling) then
408  temperature = compute_temperature(solvent, solvent_cells)
409  kin_e = (colloids% mass(1)*sum(colloids% vel(:,1)**2) + &
410  colloids% mass(2)*sum(colloids% vel(:,2)**2))/2 + &
411  sum(solvent% vel**2)/2
412  v_com = (sum(solvent% vel, dim=2) + &
413  mass(1)*colloids%vel(:,1) + mass(2)*colloids%vel(:,2)) / &
414  (solvent%Nmax + mass(1) + mass(2))
415 
416  call thermo_data%append(hfile, temperature, e1+e2, kin_e, e1+e2+kin_e, v_com)
417 
418  com_pos = ( colloids%pos(:,1)+colloids%image(:,1)*solvent_cells%edges + &
419  colloids%pos(:,2)+colloids%image(:,2)*solvent_cells%edges)/2
420  call axial_cf%add(i-equilibration_loops, com_pos, unit_r)
421 
422  end if
423 
424  if (collision_step) call solvent_cells%random_shift(state(1))
425  call varia%tac()
426 
427  call apply_pbc(solvent, solvent_cells% edges)
428  call apply_pbc(colloids, solvent_cells% edges)
429  call solvent% sort(solvent_cells)
430  call neigh% update_list(colloids, solvent, max_cut+skin, solvent_cells, solvent_colloid_lj)
431  call varia%tic()
432  !$omp parallel do
433  do k = 1, solvent%Nmax
434  solvent% pos_old(:,k) = solvent% pos(:,k)
435  end do
436  colloids% pos_old = colloids% pos
437  call varia%tac()
438 
439  if (collision_step) call simple_mpcd_step(solvent, solvent_cells, state, &
440  thermostat=do_thermostat, t=t, hydro=do_hydro)
441 
442  call time_refuel%tic()
443  if (bulk_rmpcd) then
444  call bulk_reaction(solvent, solvent_cells, 2, 1, bulk_rate, tau, state)
445  else
446  call refuel
447  end if
448 
449  call time_refuel%tac()
450 
451  n_solvent = 0
452  do k = 1, solvent%Nmax
453  j = solvent%species(k)
454  if (j <= 0) continue
455  n_solvent(j) = n_solvent(j) + 1
456  end do
457  call n_solvent_el%append(n_solvent)
458 
459  z_hist%data = 0
460  call compute_cylindrical_shell_histogram(z_hist, colloids%pos(:,1), colloids%pos(:,2), &
461  solvent_cells%edges, 2, cyl_shell_rmin, cyl_shell_rmax, solvent)
462  call z_hist_el%append(z_hist%data)
463 
464  end do
465  call main%tac()
466  write(*,*) ''
467 
468  write(*,*) 'n extra sorting', n_extra_sorting
469 
470  ! create a group for block correlators and write the data
471 
472  call h5gcreate_f(hfile%id, 'block_correlators', correlator_group, error)
473  call axial_cf%write(correlator_group, n_md_steps, n_md_steps*dt, 1, dt)
474  call h5gclose_f(correlator_group, error)
475 
476  ! write solvent coordinates for last step
477 
478  call solvent_io%position%append(solvent%pos)
479  call solvent_io%velocity%append(solvent%vel)
480  call solvent_io%image%append(solvent%image)
481  call solvent_io%species%append(solvent%species)
482 
483  ! Store timing data
484  call timer_list%append(solvent%time_stream)
485  call timer_list%append(solvent%time_step)
486  call timer_list%append(solvent%time_count)
487  call timer_list%append(solvent%time_sort)
488  call timer_list%append(solvent%time_ct)
489  call timer_list%append(solvent%time_md_pos)
490  call timer_list%append(solvent%time_md_vel)
491  call timer_list%append(solvent%time_max_disp)
492  call timer_list%append(colloids%time_self_force)
493  call timer_list%append(neigh%time_update)
494  call timer_list%append(neigh%time_force)
495  call timer_list%append(colloids%time_max_disp)
496 
497  call h5gcreate_f(hfile%id, 'timers', timers_group, error)
498  call timer_list%write(timers_group, total_time)
499  call h5md_write_dataset(timers_group, 'total', total_time)
500  call h5md_write_dataset(timers_group, main%name, main%total)
501  call h5gclose_f(timers_group, error)
502 
503  call dimer_io%close()
504  call solvent_io%close()
505  call z_hist_el%close()
506  call n_solvent_el%close()
507  call hfile%close()
508  call h5close_f(error)
509 
510 contains
511 
512  subroutine flag_particles_nl
513  double precision :: dist_to_C_sq
514  integer :: r, s
515  double precision :: x(3)
516 
517  do s = 1,neigh% n(1)
518  r = neigh%list(s,1)
519  if (solvent% species(r) == 1) then
520  x = rel_pos(colloids% pos(:,1),solvent% pos(:,r),solvent_cells% edges)
521  dist_to_c_sq = dot_product(x, x)
522  if (dist_to_c_sq < solvent_colloid_lj%cut_sq(1,1)) then
523  solvent% flags(r) = ibset(solvent% flags(r), reac_bit)
524  end if
525  end if
526  end do
527 
528  end subroutine flag_particles_nl
529 
530  subroutine change_species
531  double precision :: dist_to_C_sq
532  double precision :: dist_to_N_sq
533  integer :: m
534  double precision :: x(3)
535  integer :: thread_id
536 
537  !$omp parallel private(thread_id)
538  thread_id = omp_get_thread_num() + 1
539  !$omp do private(x, dist_to_C_sq, dist_to_N_sq)
540  do m = 1, solvent% Nmax
541  if (btest(solvent% flags(m), reac_bit)) then
542  x = rel_pos(colloids% pos(:,1), solvent% pos(:,m), solvent_cells% edges)
543  dist_to_c_sq = dot_product(x, x)
544  x = rel_pos(colloids% pos(:,2), solvent% pos(:,m), solvent_cells% edges)
545  dist_to_n_sq = dot_product(x, x)
546  if ( &
547  (dist_to_c_sq > solvent_colloid_lj%cut_sq(1,1)) &
548  .and. &
549  (dist_to_n_sq > solvent_colloid_lj%cut_sq(1,2)) &
550  ) &
551  then
552  if (threefry_double(state(thread_id)) <= prob) then
553  solvent% species(m) = 2
554  end if
555  solvent%flags(m) = ibclr(solvent%flags(m), reac_bit)
556  end if
557  end if
558  end do
559  !$omp end do
560  !$omp end parallel
561  end subroutine change_species
562 
563  subroutine refuel
564  double precision :: dist_to_C_sq
565  double precision :: dist_to_N_sq
566  double precision :: far
567  double precision :: x(3)
568  integer :: n
569 
570  far = (l(1)*0.45)**2
571 
572  !$omp parallel do private(x, dist_to_C_sq, dist_to_N_sq)
573  do n = 1,solvent% Nmax
574  if (solvent% species(n) == 2) then
575  x = rel_pos(colloids% pos(:,1), solvent% pos(:,n), solvent_cells% edges)
576  dist_to_c_sq = dot_product(x, x)
577  x= rel_pos(colloids% pos(:,2), solvent% pos(:,n), solvent_cells% edges)
578  dist_to_n_sq = dot_product(x, x)
579  if ((dist_to_c_sq > far) .and. (dist_to_n_sq > far)) then
580  solvent% species(n) = 1
581  end if
582  end if
583  end do
584  end subroutine refuel
585 
586 end program single_dimer_pbc
subroutine change_species
subroutine flag_particles_nl
program single_dimer_pbc
Simulate a single dimer nanomotor.
subroutine refuel