RMPCDMD
single_dimer.f90
Go to the documentation of this file.
1 ! This file is part of RMPCDMD
2 ! Copyright (c) 2015-2018 Pierre de Buyl and contributors
3 ! License: BSD 3-clause (see file LICENSE)
4 
31 
32 program single_dimer
33  use rmpcdmd_module
34  use hdf5
35  use h5md_module
36  use threefry_module
37  use parsetext
38  use iso_c_binding
39  use omp_lib
40  implicit none
41 
42  type(cell_system_t) :: solvent_cells
43  type(particle_system_t) :: solvent
44  type(particle_system_t) :: colloids
45  type(neighbor_list_t) :: neigh
46  type(lj_params_t) :: solvent_colloid_lj
47  type(lj_params_t) :: colloid_lj
48  type(lj_params_t) :: walls_colloid_lj
49 
50  integer, parameter :: N_species = 1
51  integer, parameter :: N_colloid_species = 2
52 
53  integer :: rho
54  integer :: N
55  integer :: error
56 
57  double precision :: max_cut
58  double precision :: epsilon(n_species, n_colloid_species)
59  double precision :: sigma(n_species, n_colloid_species), sigma_cut(n_species, n_colloid_species)
60  double precision :: mass(n_colloid_species)
61  logical :: do_zwall
62  logical :: do_rattle, do_harmonic
63  double precision :: harmonic_k
64  double precision :: wall_sigma(3, n_species), wall_epsilon(3, n_species), wall_shift(3)
65 
66  double precision :: e1, e2, e3, e_wall
67  double precision :: tau, dt , T
68  double precision :: d
69  double precision :: skin, co_max, so_max
70  integer :: N_MD_steps, N_loop
71  integer :: n_extra_sorting
72  integer :: loop_i_last_sort
73 
74  type(pto) :: config
75 
76  integer :: i, L(3)
77  integer :: j, k
78  type(timer_t), target :: varia, main
79  double precision :: total_time
80  double precision :: theta
81  type(timer_list_t) :: timer_list
82  integer(HID_T) :: timers_group
83 
84  type(threefry_rng_t), allocatable :: state(:)
85  integer :: n_threads
86  type(h5md_file_t) :: hfile
87  type(h5md_element_t) :: dummy_element
88  integer(HID_T) :: params_group
89  integer(HID_T) :: box_group
90  type(thermo_t) :: thermo_data
91  double precision :: temperature, kin_e
92  double precision :: v_com(3)
93  double precision :: com_pos(3)
94  double precision :: unit_r(3)
95  type(particle_system_io_t) :: dimer_io
96 
97  integer, parameter :: block_length = 8
98  type(axial_correlator_t) :: axial_cf
99  integer(HID_T) :: correlator_group
100 
101  integer :: equilibration_loops
102  integer :: colloid_sampling
103  logical :: sampling
104  type(args_t) :: args
105 
106  character(len=144) :: initial_condition, fluid_wall
107 
108  args = get_input_args()
109  call ptparse(config, args%input_file, 11)
110 
111  n_threads = omp_get_max_threads()
112  allocate(state(n_threads))
113  call threefry_rng_init(state, args%seed)
114 
115  call main%init('main')
116  call varia%init('varia')
117 
118  call timer_list%init(13)
119  call timer_list%append(varia)
120 
121  call h5open_f(error)
122  call hfile%create(args%output_file, 'RMPCDMD::single_dimer', &
123  rmpcdmd_revision, 'Pierre de Buyl')
124  call h5gcreate_f(hfile%id, 'parameters', params_group, error)
125  call hdf5_util_write_dataset(params_group, 'seed', args%seed)
126 
127  l = ptread_ivec(config, 'L', 3, loc=params_group)
128  rho = ptread_i(config, 'rho', loc=params_group)
129  n = rho *l(1)*l(2)*l(3)
130 
131  t = ptread_d(config, 'T', loc=params_group)
132  d = ptread_d(config, 'd', loc=params_group)
133  do_rattle = ptread_l(config, 'do_rattle', loc=params_group)
134  do_harmonic = ptread_l(config, 'do_harmonic', loc=params_group)
135  harmonic_k = ptread_d(config, 'harmonic_k', loc=params_group)
136 
137  tau = ptread_d(config, 'tau', loc=params_group)
138  n_md_steps = ptread_i(config, 'N_MD', loc=params_group)
139  colloid_sampling = ptread_i(config, 'colloid_sampling', loc=params_group)
140  if (modulo(n_md_steps, colloid_sampling) /= 0) then
141  error stop 'colloid_sampling must divide N_MD with no remainder'
142  end if
143  dt = tau / n_md_steps
144  n_loop = ptread_i(config, 'N_loop', loc=params_group)
145  equilibration_loops = ptread_i(config, 'equilibration_loops', loc=params_group)
146 
147  sigma(1,:) = ptread_dvec(config, 'sigma', n_colloid_species, loc=params_group)
148 
149  ! solvent index first, colloid index second, in solvent_colloid_lj
150  epsilon(1,:) = ptread_dvec(config, 'epsilon', n_colloid_species, loc=params_group)
151 
152  sigma_cut = sigma*2**(1.d0/6.d0)
153  max_cut = maxval(sigma_cut)
154 
155  call solvent_colloid_lj% init(epsilon, sigma, sigma_cut)
156 
157  call colloid_lj%init(&
158  reshape([2*sigma(1,1), sigma(1,2)+sigma(1,2), sigma(1,2)+sigma(1,2), 2*sigma(1,2)], [2, 2]),&
159  reshape([2*epsilon(1,1), epsilon(1,1)+epsilon(1,2), epsilon(1,1)+epsilon(1,2), 2*epsilon(1,2)], [2, 2]),&
160  reshape([2*sigma_cut(1,1), sigma_cut(1,1)+sigma_cut(1,2), sigma(1,1)+sigma_cut(1,2), 2*sigma_cut(1,2)], [2, 2]))
161 
162  ! no wall in x and y
163  wall_sigma = -1
164  wall_shift = 0
165 
166  do_zwall = ptread_l(config, 'do_zwall', loc=params_group)
167  fluid_wall = 'PERIODIC'
168  if (do_zwall) then
169  wall_sigma(3,:) = ptread_d(config, 'wall_sigma', loc=params_group)
170  wall_shift(3) = ptread_d(config, 'wall_shift', loc=params_group)
171  wall_epsilon = ptread_d(config, 'wall_epsilon', loc=params_group)
172  call walls_colloid_lj% init(wall_epsilon, &
173  wall_sigma, 3.d0**(1.d0/6.d0)*wall_sigma, wall_shift)
174  fluid_wall = ptread_s(config, 'fluid_wall', loc=params_group)
175  end if
176 
177  initial_condition = ptread_s(config, 'initial_condition', loc=params_group)
178 
179  mass(1) = rho * sigma(1,1)**3 * 4 * 3.14159265/3
180  mass(2) = rho * sigma(1,2)**3 * 4 * 3.14159265/3
181 
182  call solvent% init(n, n_species, system_name='solvent')
183 
184  call colloids% init(2, n_colloid_species, mass, system_name='colloids')
185 
186  call thermo_data%init(hfile, n_buffer=50, step=n_md_steps, time=n_md_steps*dt)
187 
188  call h5gclose_f(params_group, error)
189  call ptkill(config)
190 
191  call axial_cf%init(block_length, n_loop, n_loop*n_md_steps)
192 
193  colloids% species(1) = 1
194  colloids% species(2) = 2
195  colloids% vel = 0
196  colloids% force = 0
197 
198  dimer_io%force_info%store = .false.
199  dimer_io%id_info%store = .false.
200  dimer_io%position_info%store = .true.
201  dimer_io%position_info%mode = ior(h5md_linear,h5md_store_time)
202  dimer_io%position_info%step = colloid_sampling
203  dimer_io%position_info%time = colloid_sampling*dt
204  dimer_io%image_info%store = .true.
205  dimer_io%image_info%mode = ior(h5md_linear,h5md_store_time)
206  dimer_io%image_info%step = colloid_sampling
207  dimer_io%image_info%time = colloid_sampling*dt
208  dimer_io%velocity_info%store = .true.
209  dimer_io%velocity_info%mode = ior(h5md_linear,h5md_store_time)
210  dimer_io%velocity_info%step = colloid_sampling
211  dimer_io%velocity_info%time = colloid_sampling*dt
212  dimer_io%species_info%store = .true.
213  dimer_io%species_info%mode = h5md_fixed
214  call dimer_io%init(hfile, 'dimer', colloids)
215 
216  do k = 1, solvent%Nmax
217  solvent% vel(1,k) = threefry_normal(state(1))*sqrt(t)
218  solvent% vel(2,k) = threefry_normal(state(1))*sqrt(t)
219  solvent% vel(3,k) = threefry_normal(state(1))*sqrt(t)
220  end do
221  solvent% vel = solvent% vel - spread(sum(solvent% vel, dim=2)/solvent% Nmax, 2, solvent% Nmax)
222  solvent% force = 0
223  solvent% species = 1
224 
225  call solvent_cells%init(l, 1.d0)
226 
227  solvent_cells%bc = periodic_bc
228  if (trim(fluid_wall) == 'PERIODIC') then
229  solvent_cells%bc(3) = periodic_bc
230  else if (trim(fluid_wall) == 'SPECULAR') then
231  solvent_cells%bc(3) = specular_bc
232  else if (trim(fluid_wall) == 'BOUNCE_BACK') then
233  solvent_cells%bc(3) = bounce_back_bc
234  else
235  error stop 'unknown value for parameter fluid_wall'
236  end if
237 
238  if (initial_condition == 'CENTER') then
239  colloids% pos(:,1) = solvent_cells% edges/2.0
240  colloids% pos(:,2) = solvent_cells% edges/2.0
241  colloids% pos(1,2) = colloids% pos(1,2) + d
242  else if (initial_condition == 'PLANAR_RANDOM') then
243  theta = threefry_double(state(1))*2*pi
244  colloids%pos(3,:) = solvent_cells%edges(3)/2
245  colloids% pos(1,1) = solvent_cells%edges(1)/2.0 + d*cos(theta)/2
246  colloids% pos(2,1) = solvent_cells%edges(2)/2.0 + d*sin(theta)/2
247  colloids% pos(1,2) = solvent_cells%edges(1)/2.0 - d*cos(theta)/2
248  colloids% pos(2,2) = solvent_cells%edges(2)/2.0 - d*sin(theta)/2
249  else
250  error stop 'Unknown initial condition IC'
251  end if
252 
253  call h5gcreate_f(dimer_io%group, 'box', box_group, error)
254  call h5md_write_attribute(box_group, 'dimension', 3)
255  call dummy_element%create_fixed(box_group, 'edges', solvent_cells%edges)
256  call h5gclose_f(box_group, error)
257 
258  call solvent% random_placement(solvent_cells% edges, colloids, solvent_colloid_lj, state(1))
259 
260  call solvent% sort(solvent_cells)
261 
262  call neigh% init(colloids% Nmax, int(300*maxval(sigma)**3))
263 
264  skin = 1.5
265  n_extra_sorting = 0
266  loop_i_last_sort = 0
267 
268  call neigh% make_stencil(solvent_cells, max_cut+skin)
269 
270  call neigh% update_list(colloids, solvent, max_cut+skin, solvent_cells, solvent_colloid_lj)
271 
272  e1 = compute_force(colloids, solvent, neigh, solvent_cells% edges, solvent_colloid_lj)
273  e2 = compute_force_n2(colloids, solvent_cells% edges, colloid_lj)
274  if (do_harmonic) then
275  e3 = compute_harmonic()
276  else
277  e3 = 0
278  end if
279 
280  if (do_zwall) then
281  e_wall = lj93_zwall(colloids, solvent_cells% edges, walls_colloid_lj)
282  else
283  e_wall = 0
284  end if
285  solvent% force_old = solvent% force
286  colloids% force_old = colloids% force
287 
288  call h5fflush_f(hfile%id, h5f_scope_global_f, error)
289  write(*,*) 'Running for', equilibration_loops, '+', n_loop, 'loops'
290  write(*,*) 'mass', mass
291  call main%tic()
292  sampling = .false.
293  do i = 0, n_loop+equilibration_loops
294  if (i==equilibration_loops) sampling = .true.
295  if (modulo(i,20) == 0) write(*,'(i05)',advance='no') i
296  md_loop: do j = 1, n_md_steps
297  if ((do_zwall) .and. (solvent_cells%bc(3)/=periodic_bc)) then
298  call cell_md_pos_zwall(solvent_cells, solvent, dt, md_flag=.true.)
299  else
300  call cell_md_pos(solvent_cells, solvent, dt, md_flag=.true.)
301  end if
302 
303  call varia%tic()
304  ! Extra copy for rattle
305  if (do_rattle) &
306  colloids% pos_rattle = colloids% pos
307  do k=1, colloids% Nmax
308  colloids% pos(:,k) = colloids% pos(:,k) &
309  + dt * colloids% vel(:,k) + &
310  dt**2 * colloids% force(:,k) / (2 * colloids% mass(k))
311  end do
312 
313  if (do_rattle) &
314  call rattle_dimer_pos(colloids, d, dt, solvent_cells% edges)
315 
316  call varia%tac()
317 
318  so_max = cell_maximum_displacement(solvent_cells, solvent, delta_t=dt*(n_md_steps*i+j - loop_i_last_sort))
319  co_max = colloids% maximum_displacement()
320 
321  if ( (co_max >= skin*0.1d0) .or. (so_max >= skin*0.89d0) ) then
322  call varia%tic()
323 
324  if ((do_zwall) .and. (solvent_cells%bc(2)/=periodic_bc)) then
325  call cell_md_pos_zwall(solvent_cells, solvent, &
326  (n_md_steps*i+j - loop_i_last_sort)*dt, md_flag=.false.)
327  else
328  call cell_md_pos(solvent_cells, solvent, &
329  (n_md_steps*i+j - loop_i_last_sort)*dt, md_flag=.false.)
330  end if
331  call cell_md_vel(solvent_cells, solvent, &
332  (n_md_steps*i+j - loop_i_last_sort)*dt, md_flag=.false.)
333 
334  call apply_pbc(solvent, solvent_cells% edges)
335  call apply_pbc(colloids, solvent_cells% edges)
336  call varia%tac()
337  call solvent% sort(solvent_cells)
338  loop_i_last_sort = n_md_steps*i + j
339  call neigh% update_list(colloids, solvent, max_cut + skin, solvent_cells, solvent_colloid_lj)
340  call varia%tic()
341  !$omp parallel do
342  do k = 1, solvent%Nmax
343  solvent% pos_old(:,k) = solvent% pos(:,k)
344  end do
346 
347  colloids% pos_old = colloids% pos
348  n_extra_sorting = n_extra_sorting + 1
349  call varia%tac()
350  end if
351 
352  call varia%tic()
353  call switch(solvent% force, solvent% force_old)
354  call switch(colloids% force, colloids% force_old)
355 
356  !$omp parallel do
357  do k = 1, solvent%Nmax
358  solvent% force(:,k) = 0
359  end do
360  colloids% force = 0
361  call varia%tac()
362  e1 = compute_force(colloids, solvent, neigh, solvent_cells% edges, solvent_colloid_lj)
363  e2 = compute_force_n2(colloids, solvent_cells% edges, colloid_lj)
364  e3 = compute_harmonic()
365  if (do_zwall) e_wall = lj93_zwall(colloids, solvent_cells% edges, walls_colloid_lj)
366 
367  call cell_md_vel(solvent_cells, solvent, dt, md_flag=.true.)
368 
369  call varia%tic()
370  do k=1, colloids% Nmax
371  colloids% vel(:,k) = colloids% vel(:,k) + &
372  dt * ( colloids% force(:,k) + colloids% force_old(:,k) ) / (2 * colloids% mass(k))
373  end do
374 
375  if (do_rattle) &
376  call rattle_dimer_vel(colloids, d, dt, solvent_cells% edges)
377  call varia%tac()
378 
379  if (sampling) then
380  v_com = sum(colloids%vel, dim=2)/2
381  unit_r = rel_pos(colloids%pos(:,1), colloids%pos(:,2), solvent_cells%edges)
382  unit_r = unit_r / norm2(unit_r)
383  call axial_cf%add_fast((i-equilibration_loops)*n_md_steps+j-1, v_com, unit_r)
384  end if
385 
386  if ((sampling) .and. (modulo(j, colloid_sampling)==0)) then
387  call dimer_io%position%append(colloids%pos)
388  call dimer_io%velocity%append(colloids%vel)
389  call dimer_io%image%append(colloids%image)
390  end if
391 
392  end do md_loop
393 
394  call varia%tic()
395 
396  if (sampling) then
397  temperature = compute_temperature(solvent, solvent_cells)
398  kin_e = (colloids% mass(1)*sum(colloids% vel(:,1)**2) + &
399  colloids% mass(2)*sum(colloids% vel(:,2)**2))/2 + &
400  sum(solvent% vel**2)/2
401  v_com = (sum(solvent% vel, dim=2) + &
402  mass(1)*colloids%vel(:,1) + mass(2)*colloids%vel(:,2)) / &
403  (solvent%Nmax + mass(1) + mass(2))
404 
405  call thermo_data%append(hfile, temperature, e1+e2+e3+e_wall, kin_e, e1+e2+e3+kin_e+e_wall, v_com)
406 
407  com_pos = ( colloids%pos(:,1)+colloids%image(:,1)*solvent_cells%edges + &
408  colloids%pos(:,2)+colloids%image(:,2)*solvent_cells%edges)/2
409  call axial_cf%add(i-equilibration_loops, com_pos, unit_r)
410 
411  end if
412 
413  call solvent_cells%random_shift(state(1))
414  call varia%tac()
415 
416  call cell_md_pos(solvent_cells, solvent, ((i+1)*n_md_steps - loop_i_last_sort)*dt, md_flag=.false.)
417  call cell_md_vel(solvent_cells, solvent, ((i+1)*n_md_steps - loop_i_last_sort)*dt, md_flag=.false.)
418 
419  call apply_pbc(solvent, solvent_cells% edges)
420  call apply_pbc(colloids, solvent_cells% edges)
421  call solvent% sort(solvent_cells)
422  loop_i_last_sort = n_md_steps*(i+1)
423  call neigh% update_list(colloids, solvent, max_cut+skin, solvent_cells, solvent_colloid_lj)
424  call varia%tic()
425  !$omp parallel do
426  do k = 1, solvent%Nmax
427  solvent% pos_old(:,k) = solvent% pos(:,k)
428  end do
429  colloids% pos_old = colloids% pos
430  call varia%tac()
431 
432  call simple_mpcd_step(solvent, solvent_cells, state)
434 
435  end do
436  call main%tac()
437  write(*,*) ''
438 
439  write(*,*) 'n extra sorting', n_extra_sorting
440 
441  ! create a group for block correlators and write the data
442 
443  call h5gcreate_f(hfile%id, 'block_correlators', correlator_group, error)
444  call axial_cf%write(correlator_group, n_md_steps, n_md_steps*dt, 1, dt)
445  call h5gclose_f(correlator_group, error)
446 
447  ! Store timing data
448  call timer_list%append(solvent%time_stream)
449  call timer_list%append(solvent%time_step)
450  call timer_list%append(solvent%time_count)
451  call timer_list%append(solvent%time_sort)
452  call timer_list%append(solvent%time_ct)
453  call timer_list%append(solvent%time_md_pos)
454  call timer_list%append(solvent%time_md_vel)
455  call timer_list%append(solvent%time_max_disp)
456  call timer_list%append(colloids%time_self_force)
457  call timer_list%append(neigh%time_update)
458  call timer_list%append(neigh%time_force)
459  call timer_list%append(colloids%time_max_disp)
460 
461  call h5gcreate_f(hfile%id, 'timers', timers_group, error)
462  call timer_list%write(timers_group, total_time)
463  call h5md_write_dataset(timers_group, 'total', total_time)
464  call h5md_write_dataset(timers_group, main%name, main%total)
465  call h5gclose_f(timers_group, error)
466 
467  call dimer_io%close()
468  call hfile%close()
469  call h5close_f(error)
470 
471 contains
472 
473  subroutine compute_cell_wise_max_v
474  integer :: i, j
475  double precision :: local_max_v
476 
477  local_max_v = 0
478  !$omp parallel do private(i, j) reduction(max:local_max_v)
479  do i = 1, solvent_cells%N
480  local_max_v = 0
481  do j = solvent_cells%cell_start(i), solvent_cells%cell_start(i) + solvent_cells%cell_count(i) - 1
482  local_max_v = max(local_max_v, norm2(solvent%vel(:,j)))
483  end do
484  end do
485  solvent_cells%max_v = local_max_v
486 
487  end subroutine compute_cell_wise_max_v
488 
489  function compute_harmonic() result(e)
490  double precision :: e
491 
492  double precision :: f(3), x12(3), dist
493 
494  x12 = rel_pos(colloids%pos(:,1), colloids%pos(:,2), solvent_cells%edges)
495  dist = norm2(x12)
496 
497  f = harmonic_k * (dist - d) * x12 / dist
498  colloids%force(:,1) = colloids%force(:,1) - f
499  colloids%force(:,2) = colloids%force(:,2) + f
500 
501  e = harmonic_k * (dist - d)**2 / 2
502 
503  ! U = k/2 * (dist - d)**2
504  ! f = k * (dist-d) * d dist / d x
505 
506  end function compute_harmonic
507 
508 end program single_dimer
program single_dimer
Simulate a single dimer colloid.
double precision function compute_harmonic()
subroutine compute_cell_wise_max_v