RMPCDMD
single_body.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 
57 
58 program single_body
59  use rmpcdmd_module
60  use hdf5
61  use h5md_module
62  use threefry_module
63  use parsetext
64  use iso_c_binding
65  use omp_lib
66  implicit none
67 
68  type(cell_system_t) :: solvent_cells
69  type(particle_system_t) :: solvent
70  type(particle_system_t) :: colloids
71  type(neighbor_list_t) :: neigh
72  type(lj_params_t) :: solvent_colloid_lj
73  type(lj_params_t) :: colloid_lj
74  type(lj_params_t) :: walls_colloid_lj
75 
76  integer, parameter :: N_species = 2
77 
78  integer :: rho
79  integer :: N
80  integer :: error
81 
82  double precision :: max_cut
83  double precision :: epsilon(2,2)
84  double precision :: sigma, sigma_v(2,2), sigma_cut(2,2)
85  double precision :: mass(2)
86  double precision :: wall_sigma(3, n_species), wall_epsilon(3, n_species), wall_shift(3)
87 
88  double precision :: e1, e2, e3, e_wall
89  double precision :: tau, dt , T
90  double precision :: mpcd_alpha
91  double precision :: prob, reaction_radius
92  double precision :: bulk_rate
93  double precision :: skin, co_max, so_max
94  integer :: N_MD_steps, N_loop, collide_every
95  integer :: n_extra_sorting
96  double precision :: loop_i_last_sort
97 
98  type(pto) :: config
99 
100  integer :: i, L(3)
101  integer :: j, k, cell_idx
102 
103  double precision :: total_time
104  type(timer_t), target :: varia, main, time_flag, time_refuel, time_change
105  type(timer_t), target :: so_timer
106  type(timer_t), target :: bulk_reac_timer
107  type(timer_t), target :: q_timer
108  type(timer_list_t) :: timer_list
109  integer(HID_T) :: timers_group
110 
111  type(threefry_rng_t), allocatable :: state(:)
112  integer :: n_threads
113  type(h5md_file_t) :: hfile
114  type(h5md_file_t) :: input_data_file
115  type(h5md_element_t) :: dummy_element
116  integer(HID_T) :: fields_group, params_group
117  integer(HID_T) :: connectivity_group
118  integer(HID_T) :: box_group
119  integer(HID_T) :: tmp_id
120  integer(HID_T) :: pos_dset
121  type(thermo_t) :: thermo_data
122  double precision :: temperature, kin_e
123  double precision :: v_com(3), x(3)
124  double precision :: wall_v(3,2)
125  double precision :: tmp_mass
126  type(particle_system_io_t) :: janus_io
127  type(particle_system_io_t) :: solvent_io
128 
129  integer, dimension(N_species) :: n_solvent
130  type(h5md_element_t) :: n_solvent_el
131 
132  type(h5md_element_t) :: q_el, omega_body_el, janus_pos_el, janus_vel_el, u_el
133  double precision, dimension(3) :: one_x, one_y, one_z
134 
135  double precision :: polar_r_max
136  type(polar_fields_t) :: polar
137  type(planar_fields_t) :: planar
138  integer :: planar_n(2)
139  double precision :: planar_size(2)
140  integer(HID_T) :: polar_id
141  integer(HID_T) :: planar_id
142 
143  logical :: do_rattle, do_read_links, do_lennard_jones, do_elastic, do_quaternion, do_solvent_io
144  logical :: do_hydro
145  logical :: do_thermostat
146  logical :: do_ywall
147  integer, allocatable :: links(:,:)
148  double precision, allocatable :: links_d(:)
149  double precision :: link_treshold
150  integer :: i_link
151  double precision :: dist, rattle_pos_tolerance, rattle_vel_tolerance
152  double precision :: elastic_k
153  double precision :: unit_r(3)
154  double precision :: com_pos(3)
155  double precision :: alpha, beta, z0
156  type(rigid_body_t) :: rigid_janus
157  double precision :: quaternion_treshold
158  character(len=144) :: fluid_wall
159 
160  integer, parameter :: block_length = 8
161  type(axial_correlator_t) :: axial_cf
162  type(correlator_t) :: omega_cf
163  integer(HID_T) :: correlator_group
164 
165  integer :: equilibration_loops
166  integer :: colloid_sampling, coordinates_sampling
167  logical :: sampling
168  logical :: collision_step
169 
170  type(args_t) :: args
171  character(len=144) :: data_filename
172  character(len=144) :: links_file
173  character(len=144) :: data_group
174  logical :: attr_exists
175 
176  args = get_input_args()
177  call ptparse(config, args%input_file, 11)
178 
179  n_threads = omp_get_max_threads()
180  allocate(state(n_threads))
181  call threefry_rng_init(state, args%seed)
182 
183  call main%init('main')
184  call varia%init('varia')
185  call so_timer%init('so_timer')
186  call time_flag%init('flag')
187  call time_refuel%init('refuel')
188  call time_change%init('change')
189  call bulk_reac_timer%init('bulk_reac')
190  call q_timer%init('quaternion_vv')
191 
192  call timer_list%init(26)
193  call timer_list%append(varia)
194  call timer_list%append(so_timer)
195  call timer_list%append(time_flag)
196  call timer_list%append(time_refuel)
197  call timer_list%append(time_change)
198  call timer_list%append(bulk_reac_timer)
199  call timer_list%append(q_timer)
200 
201  call h5open_f(error)
202  call hfile%create(args%output_file, 'RMPCDMD::single_body', &
203  rmpcdmd_revision, 'Pierre de Buyl')
204  call h5gcreate_f(hfile%id, 'parameters', params_group, error)
205  call hdf5_util_write_dataset(params_group, 'seed', args%seed)
206 
207 
208  prob = ptread_d(config,'probability', loc=params_group)
209  bulk_rate = ptread_d(config,'bulk_rate', loc=params_group)
210 
211  l = ptread_ivec(config, 'L', 3, loc=params_group)
212  rho = ptread_i(config, 'rho', loc=params_group)
213  n = rho *l(1)*l(2)*l(3)
214 
215  t = ptread_d(config, 'T', loc=params_group)
216  do_hydro = ptread_l(config, 'do_hydro', loc=params_group)
217  do_thermostat = ptread_l(config, 'do_thermostat', loc=params_group)
218 
219  mpcd_alpha = ptread_d(config,'alpha', loc=params_group)
220 
221  dt = ptread_d(config, 'dt', loc=params_group)
222  n_md_steps = ptread_i(config, 'N_MD', loc=params_group)
223 
224  collide_every = ptread_i(config, 'collide_every', loc=params_group)
225  tau = dt*n_md_steps*collide_every
226  call hdf5_util_write_dataset(params_group, 'tau', tau)
227 
228  colloid_sampling = ptread_i(config, 'colloid_sampling', loc=params_group)
229  coordinates_sampling = ptread_i(config, 'coordinates_sampling', loc=params_group)
230  do_solvent_io = ptread_l(config, 'do_solvent_io', loc=params_group)
231  if (modulo(n_md_steps, colloid_sampling) /= 0) then
232  error stop 'colloid_sampling must divide N_MD with no remainder'
233  end if
234  n_loop = ptread_i(config, 'N_loop', loc=params_group)
235  equilibration_loops = ptread_i(config, 'equilibration_loops', loc=params_group)
236 
237  call thermo_data%init(hfile, n_buffer=50, step=n_md_steps, time=n_md_steps*dt)
238 
239  do_rattle = ptread_l(config, 'do_rattle', loc=params_group)
240  do_lennard_jones = ptread_l(config, 'do_lennard_jones', loc=params_group)
241  rattle_pos_tolerance = ptread_d(config, 'rattle_pos_tolerance', loc=params_group)
242  rattle_vel_tolerance = ptread_d(config, 'rattle_vel_tolerance', loc=params_group)
243 
244  do_quaternion = ptread_l(config, 'do_quaternion', loc=params_group)
245  quaternion_treshold = ptread_d(config, 'quaternion_treshold', loc=params_group)
246 
247  do_elastic = ptread_l(config, 'do_elastic', loc=params_group)
248  if (do_elastic) elastic_k = ptread_d(config, 'elastic_k', loc=params_group)
249 
250  sigma = ptread_d(config, 'sigma_colloid', loc=params_group)
251  sigma_v = sigma
252  sigma_cut = sigma_v*2**(1.d0/6.d0)
253  mass = rho * sigma**3 * 4 * 3.14159265/3
254 
255  epsilon = ptread_d(config, 'epsilon_colloid', loc=params_group)
256 
257  call colloid_lj% init(epsilon, sigma_v, sigma_cut)
258 
259  ! no wall in x and z
260  wall_sigma = -1
261  wall_shift = 0
262 
263  do_ywall = ptread_l(config, 'do_ywall', loc=params_group)
264  fluid_wall = 'PERIODIC'
265  if (do_ywall) then
266  wall_sigma(3,:) = ptread_d(config, 'wall_sigma', loc=params_group)
267  wall_shift(3) = ptread_d(config, 'wall_shift', loc=params_group)
268  wall_epsilon = ptread_d(config, 'wall_epsilon', loc=params_group)
269  call walls_colloid_lj% init(wall_epsilon, &
270  wall_sigma, 3.d0**(1.d0/6.d0)*wall_sigma, wall_shift)
271  fluid_wall = ptread_s(config, 'fluid_wall', loc=params_group)
272  end if
273 
274  ! solvent index first, colloid index second, in solvent_colloid_lj
275  sigma = ptread_d(config, 'sigma', loc=params_group)
276  sigma_v = sigma
277  sigma_cut = sigma_v*2**(1.d0/6.d0)
278  max_cut = maxval(sigma_cut)
279 
280  epsilon(:,1) = ptread_dvec(config, 'epsilon_C', 2, loc=params_group)
281  epsilon(:,2) = ptread_dvec(config, 'epsilon_N', 2, loc=params_group)
282 
283  call solvent_colloid_lj% init(epsilon, sigma_v, sigma_cut)
284 
285  call solvent% init(n, n_species, system_name='solvent') !there will be 2 species of solvent particles
286 
287  data_filename = ptread_s(config, 'data_filename', loc=params_group)
288  data_group = ptread_s(config, 'data_group', loc=params_group)
289  link_treshold = ptread_d(config, 'link_treshold', loc=params_group)
290  do_read_links = ptread_l(config, 'do_read_links', loc=params_group)
291  if (do_read_links) links_file = ptread_s(config, 'links_file', loc=params_group)
292 
293  polar_r_max = ptread_d(config, 'polar_r_max', loc=params_group)
294 
295  reaction_radius = ptread_d(config, 'reaction_radius', loc=params_group)
296 
297  planar_n = ptread_ivec(config, 'planar_n', 2, loc=params_group)
298  planar_size = ptread_dvec(config, 'planar_size', 2, loc=params_group)
299  call planar%init(n_species, planar_n(1), -planar_size(1), planar_size(1), planar_n(2), -planar_size(2), planar_size(2), 1.d0)
300 
301  call h5gclose_f(params_group, error)
302  call ptkill(config)
303 
304  call solvent_cells%init(l, 1.d0, &
305  has_walls= ( (trim(fluid_wall) == 'SPECULAR') &
306  .or. (trim(fluid_wall) == 'BOUNCE_BACK')) )
307 
308  wall_v = 0
309  solvent_cells%bc = periodic_bc
310  if (trim(fluid_wall) == 'PERIODIC') then
311  solvent_cells%bc(3) = periodic_bc
312  else if (trim(fluid_wall) == 'SPECULAR') then
313  solvent_cells%bc(3) = specular_bc
314  else if (trim(fluid_wall) == 'BOUNCE_BACK') then
315  solvent_cells%bc(3) = bounce_back_bc
316  else
317  error stop 'unknown value for parameter fluid_wall'
318  end if
319 
320  call axial_cf%init(block_length, n_loop, n_loop*n_md_steps)
321 
322  call colloids%init_from_file(data_filename, data_group, h5md_fixed)
323 
324  ! center colloid in simulation box
325  com_pos = sum(colloids%pos, dim=2) / size(colloids%pos, dim=2)
326  do i = 1, size(colloids%pos, dim=2)
327  colloids%pos(:,i) = colloids%pos(:,i) + (solvent_cells%edges/2 - com_pos)
328  end do
329 
330  call input_data_file%open(data_filename, h5f_acc_rdonly_f)
331 
332  call h5aexists_by_name_f(input_data_file%particles, trim(data_group)//'/position', 'alpha', attr_exists, error)
333  ! If the parameters alpha,beta,gamma are present, read them
334  ! Only alpha is checked, if someone puts in alpha and not the rest, long hdf5 error log will show
335  if (attr_exists) then
336  call h5oopen_f(input_data_file%particles, trim(data_group)//'/position', pos_dset, error)
337  call h5md_read_attribute(pos_dset, 'alpha', alpha)
338  call h5md_read_attribute(pos_dset, 'beta', beta)
339  call h5md_read_attribute(pos_dset, 'z0', z0)
340  call h5oclose_f(pos_dset, error)
341  end if
342 
343  call input_data_file%close()
344 
345  colloids%image = 0
346  colloids%vel = 0
347  colloids%force = 0
348  colloids%mass = mass
349 
350  if (do_read_links) then
351  call read_links(links_file, i_link, links, links_d)
352  else
353  i_link = 0
354  do i = 1, colloids%Nmax
355  do j = i+1, colloids%Nmax
356  x = rel_pos(colloids%pos(:,i), colloids%pos(:,j), solvent_cells%edges)
357  dist = norm2(x)
358  if (dist < link_treshold) then
359  ! count link
360  i_link = i_link + 1
361  end if
362  end do
363  end do
364  allocate(links(2,i_link), links_d(i_link))
365 
366  i_link = 0
367  do i = 1, colloids%Nmax
368  do j = i+1, colloids%Nmax
369  x = rel_pos(colloids%pos(:,i), colloids%pos(:,j), solvent_cells%edges)
370  dist = norm2(x)
371  if (dist < link_treshold) then
372  ! add link
373  i_link = i_link + 1
374  links(1, i_link) = i
375  links(2, i_link) = j
376  links_d(i_link) = dist
377  end if
378  end do
379  end do
380  end if
381 
382  call rigid_janus%init(colloids, 1, colloids%Nmax, solvent_cells%edges)
383 
384  write(*,*) 'number of links:', i_link
385 
386  janus_io%force_info%store = .true.
387  janus_io%force_info%mode = ior(h5md_linear,h5md_store_time)
388  janus_io%force_info%step = n_md_steps*coordinates_sampling
389  janus_io%force_info%time = n_md_steps*coordinates_sampling*dt
390  janus_io%id_info%store = .false.
391  janus_io%position_info%store = .true.
392  janus_io%position_info%mode = ior(h5md_linear,h5md_store_time)
393  janus_io%position_info%step = janus_io%force_info%step
394  janus_io%position_info%time = janus_io%force_info%time
395  janus_io%image_info%store = .true.
396  janus_io%image_info%mode = ior(h5md_linear,h5md_store_time)
397  janus_io%image_info%step = janus_io%force_info%step
398  janus_io%image_info%time = janus_io%force_info%time
399  janus_io%velocity_info%store = .true.
400  janus_io%velocity_info%mode = ior(h5md_linear,h5md_store_time)
401  janus_io%velocity_info%step = janus_io%force_info%step
402  janus_io%velocity_info%time = janus_io%force_info%time
403  janus_io%species_info%store = .true.
404  janus_io%species_info%mode = h5md_fixed
405  call janus_io%init(hfile, 'janus', colloids)
406 
407  if (do_solvent_io) then
408  solvent_io%force_info%store = .false.
409  solvent_io%id_info%store = .false.
410  solvent_io%position_info%store = .true.
411  solvent_io%position_info%mode = ior(h5md_linear,h5md_store_time)
412  solvent_io%position_info%step = n_loop*n_md_steps
413  solvent_io%position_info%time = n_loop*n_md_steps*dt
414  solvent_io%image_info%store = .true.
415  solvent_io%image_info%mode = ior(h5md_linear,h5md_store_time)
416  solvent_io%image_info%step = n_loop*n_md_steps
417  solvent_io%image_info%time = n_loop*n_md_steps*dt
418  solvent_io%velocity_info%store = .true.
419  solvent_io%velocity_info%mode = ior(h5md_linear,h5md_store_time)
420  solvent_io%velocity_info%step = n_loop*n_md_steps
421  solvent_io%velocity_info%time = n_loop*n_md_steps*dt
422  solvent_io%species_info%store = .true.
423  solvent_io%species_info%mode = ior(h5md_linear,h5md_store_time)
424  solvent_io%species_info%step = n_loop*n_md_steps
425  solvent_io%species_info%time = n_loop*n_md_steps*dt
426  call solvent_io%init(hfile, 'solvent', solvent)
427  end if
428 
429  do k = 1, solvent%Nmax
430  solvent% vel(1,k) = threefry_normal(state(1))*sqrt(t)
431  solvent% vel(2,k) = threefry_normal(state(1))*sqrt(t)
432  solvent% vel(3,k) = threefry_normal(state(1))*sqrt(t)
433  end do
434  solvent% vel = solvent% vel - spread(sum(solvent% vel, dim=2)/solvent% Nmax, 2, solvent% Nmax)
435  solvent% force = 0
436  solvent% species = 1
437 
438  call n_solvent_el%create_time(hfile%observables, 'n_solvent', &
439  n_solvent, h5md_linear, step=n_md_steps, &
440  time=n_md_steps*dt)
441 
442  if (do_quaternion) then
443  call q_el%create_time(hfile%observables, 'q', &
444  rigid_janus%q, ior(h5md_linear, h5md_store_time), step=colloid_sampling, time=colloid_sampling*dt)
445  call omega_body_el%create_time(hfile%observables, 'omega_body', &
446  rigid_janus%omega_body, ior(h5md_linear, h5md_store_time), step=colloid_sampling, time=colloid_sampling*dt)
447  call omega_cf%init(block_length, get_n_blocks(block_length, 8, n_loop), dim=3)
448  end if
449 
450  call u_el%create_time(hfile%observables, 'u', &
451  unit_r, ior(h5md_linear, h5md_store_time), step=colloid_sampling, &
452  time=colloid_sampling*dt)
453 
454  call janus_pos_el%create_time(hfile%observables, 'janus_pos', &
455  rigid_janus%pos, ior(h5md_linear, h5md_store_time), step=colloid_sampling, &
456  time=colloid_sampling*dt)
457 
458  call janus_vel_el%create_time(hfile%observables, 'janus_vel', &
459  rigid_janus%vel, ior(h5md_linear, h5md_store_time), step=colloid_sampling, &
460  time=colloid_sampling*dt)
461 
462  call h5gcreate_f(janus_io%group, 'box', box_group, error)
463  call h5md_write_attribute(box_group, 'dimension', 3)
464  call dummy_element%create_fixed(box_group, 'edges', solvent_cells%edges)
465  call h5gclose_f(box_group, error)
466 
467  if (do_solvent_io) then
468  call h5gcreate_f(solvent_io%group, 'box', box_group, error)
469  call h5md_write_attribute(box_group, 'dimension', 3)
470  call dummy_element%create_fixed(box_group, 'edges', solvent_cells%edges)
471  call h5gclose_f(box_group, error)
472  end if
473 
474  call h5gcreate_f(hfile%id, 'fields', fields_group, error)
475 
476  call h5gcreate_f(hfile%id, 'connectivity', connectivity_group, error)
477  call h5md_write_dataset(connectivity_group, 'janus_links', links-1)
478  call h5dopen_f(connectivity_group, 'janus_links', tmp_id, error)
479  call h5md_write_attribute(tmp_id, 'particles_group', 'janus')
480  call h5dclose_f(tmp_id, error)
481  call h5gclose_f(connectivity_group, error)
482 
483  call solvent% random_placement(solvent_cells% edges, colloids, solvent_colloid_lj, state(1))
484 
485  call solvent% sort(solvent_cells)
486 
487  call polar%init(n_species, 64, sigma, polar_r_max, 64)
488  call timer_list%append(polar%time_polar_update)
489  call timer_list%append(planar%timer)
490  call neigh% init(colloids% Nmax, int(500*max(sigma,1.15d0)**3))
491 
492  skin = 1.5
493  n_extra_sorting = 0
494  loop_i_last_sort = 0
495 
496  call neigh% make_stencil(solvent_cells, max_cut+skin)
497 
498  call neigh% update_list(colloids, solvent, max_cut+skin, solvent_cells, solvent_colloid_lj)
499 
500  e1 = compute_force(colloids, solvent, neigh, solvent_cells% edges, solvent_colloid_lj)
501  if (do_lennard_jones) then
502  e2 = compute_force_n2(colloids, solvent_cells% edges, colloid_lj)
503  else
504  e2 = 0
505  end if
506  if (do_elastic) then
507  e3 = elastic_network(colloids, links, links_d, elastic_k, solvent_cells%edges)
508  else
509  e3 = 0
510  end if
511  if (do_ywall) then
512  e_wall = lj93_zwall(colloids, solvent_cells% edges, walls_colloid_lj)
513  else
514  e_wall = 0
515  end if
516 
517  solvent% force_old = solvent% force
518  colloids% force_old = colloids% force
519  if (do_quaternion) call rigid_janus%compute_force_torque(colloids)
520 
521  write(*,*) 'Box size', l
522  write(*,*) 'Fluid particles', n
523  write(*,*) 'MPCD tau', tau
524 
525  write(*,*) 'Running for', equilibration_loops, '+', n_loop, 'loops'
526  call main%tic()
527  sampling = .false.
528  do i = 0, n_loop+equilibration_loops
529  if (i==equilibration_loops) sampling = .true.
530  if (modulo(i,32) == 0) write(*,'(i08)',advance='no') i
531  md_loop: do j = 1, n_md_steps
532  if ((do_ywall) .and. (solvent_cells%bc(3)/=periodic_bc)) then
533  call cell_md_pos_zwall(solvent_cells, solvent, dt, md_flag=.true.)
534  else
535  call cell_md_pos(solvent_cells, solvent, dt, md_flag=.true.)
536  end if
537 
538  if (do_rattle) then
539  call varia%tic()
540  ! Extra copy for rattle
541  colloids% pos_rattle = colloids% pos
542  do k=1, colloids% Nmax
543  colloids% pos(:,k) = colloids% pos(:,k) + dt * colloids% vel(:,k) + &
544  dt**2 * colloids% force(:,k) / (2 * colloids% mass(colloids%species(k)))
545  end do
546  call varia%tac()
547 
548  call rattle_body_pos(colloids, links, links_d, dt, solvent_cells% edges, rattle_pos_tolerance)
549 
550  com_pos = modulo(sum((colloids%pos(:,:)+ &
551  colloids%image(:,:)*spread(solvent_cells%edges, dim=2, ncopies=colloids%Nmax) ) &
552  , dim=2)/ colloids%Nmax, solvent_cells%edges)
553 
554  else if (do_quaternion) then
555  call q_timer%tic()
556  call rigid_janus%vv1(colloids, dt, quaternion_treshold, solvent_cells%edges)
557  com_pos = modulo(rigid_janus%pos, solvent_cells%edges)
558  call q_timer%tac()
559  end if
560 
561  so_max = cell_maximum_displacement(solvent_cells, solvent, delta_t=dt*(n_md_steps*i+j - loop_i_last_sort))
562  co_max = colloids% maximum_displacement()
563 
564  if ( (co_max >= skin*0.1d0) .or. (so_max >= skin*0.9d0) ) then
565  if ((do_ywall) .and. (solvent_cells%bc(3)/=periodic_bc)) then
566  call cell_md_pos_zwall(solvent_cells, solvent, (n_md_steps*i+j - loop_i_last_sort)*dt, md_flag=.false.)
567  else
568  call cell_md_pos(solvent_cells, solvent, (n_md_steps*i+j - loop_i_last_sort)*dt, md_flag=.false.)
569  end if
570  call cell_md_vel(solvent_cells, solvent, (n_md_steps*i+j - loop_i_last_sort)*dt, md_flag=.false.)
571 
572  call apply_pbc(solvent, solvent_cells% edges)
573  call apply_pbc(colloids, solvent_cells% edges)
574  call solvent% sort(solvent_cells)
575  loop_i_last_sort = n_md_steps*i + j
576  call neigh% update_list(colloids, solvent, max_cut + skin, solvent_cells, solvent_colloid_lj)
577  call so_timer%tic()
578  !$omp parallel do
579  do k = 1, solvent%Nmax
580  solvent% pos_old(:,k) = solvent% pos(:,k)
581  end do
583  call so_timer%tac()
584  call varia%tic()
585  colloids% pos_old = colloids% pos
586  n_extra_sorting = n_extra_sorting + 1
587  call varia%tac()
588  end if
589 
590  call varia%tic()
591  call switch(solvent% force, solvent% force_old)
592  call switch(colloids% force, colloids% force_old)
593  call varia%tac()
594 
595  call so_timer%tic()
596  !$omp parallel do private(cell_idx, k)
597  do cell_idx = 1, solvent_cells%N
598  if (solvent_cells%is_md(cell_idx)) then
599  do k = solvent_cells%cell_start(cell_idx), &
600  solvent_cells%cell_start(cell_idx) + solvent_cells%cell_count(cell_idx) - 1
601  solvent%force(:,k) = 0
602  end do
603  end if
604  end do
605  call so_timer%tac()
606  colloids% force = 0
607 
608  e1 = compute_force(colloids, solvent, neigh, solvent_cells% edges, solvent_colloid_lj)
609  if (do_lennard_jones) e2 = compute_force_n2(colloids, solvent_cells% edges, colloid_lj)
610  if (do_elastic) e3 = elastic_network(colloids, links, links_d, elastic_k, solvent_cells%edges)
611  if (do_ywall) e_wall = lj93_zwall(colloids, solvent_cells% edges, walls_colloid_lj)
612 
613  call cell_md_vel(solvent_cells, solvent, dt, md_flag=.true.)
614 
615  if (do_quaternion) then
616  call q_timer%tic()
617  call rigid_janus%compute_force_torque(colloids)
618  call rigid_janus%vv2(colloids, dt)
619  call q_timer%tac()
620  else if (do_rattle) then
621  call varia%tic()
622  do k = 1, colloids%Nmax
623  colloids% vel(:,k) = colloids% vel(:,k) + &
624  dt * ( colloids% force(:,k) + colloids% force_old(:,k) ) / (2 * colloids%mass(colloids%species(k)))
625  end do
626  call varia%tac()
627  end if
628 
629  if (do_rattle) then
630  call rattle_body_vel(colloids, links, links_d, dt, solvent_cells% edges, rattle_vel_tolerance)
631  end if
632 
633  if (sampling) then
634  v_com = sum(colloids%vel, dim=2)/colloids%Nmax
635  com_pos = sum((colloids%pos(:,:)+ &
636  colloids%image(:,:)*spread(solvent_cells%edges, dim=2, ncopies=colloids%Nmax) ) &
637  , dim=2)/ colloids%Nmax
638  if (do_rattle .and. (.not. do_quaternion)) then
639  rigid_janus%pos = com_pos
640  rigid_janus%vel = v_com
641  end if
642  unit_r = get_unit_r()
643  call axial_cf%add_fast((i-equilibration_loops)*n_md_steps+j-1, v_com, unit_r)
644  end if
645 
646  if ((sampling) .and. (modulo(j, colloid_sampling)==0)) then
647  call u_el%append(unit_r)
648  call janus_pos_el%append(rigid_janus%pos)
649  call janus_vel_el%append(rigid_janus%vel)
650  if (do_quaternion) then
651  call q_el%append(rigid_janus%q)
652  call omega_body_el%append(rigid_janus%omega_body)
653  end if
654  end if
655 
656  call time_flag%tic()
657  call flag_particles
658  call time_flag%tac()
659  call time_change%tic()
660  call change_species
661  call time_change%tac()
662 
663  end do md_loop
664 
665  collision_step = (modulo(i, collide_every) == 0)
666 
667  if (sampling) then
668  temperature = compute_temperature(solvent, solvent_cells)
669  kin_e = 0
670  v_com = 0
671  call so_timer%tic()
672  !$omp parallel do private(k) reduction(+:kin_e) reduction(+:v_com)
673  do k = 1, solvent%Nmax
674  kin_e = kin_e + sum(solvent%vel(:,k)**2)
675  v_com = v_com + solvent%vel(:,k)
676  end do
677  call so_timer%tac()
678  call varia%tic()
679  tmp_mass = solvent%Nmax
680  do k = 1, colloids%Nmax
681  v_com = v_com + colloids%mass(colloids%species(k)) * colloids%vel(:,k)
682  tmp_mass = tmp_mass + colloids%mass(colloids%species(k))
683  kin_e = kin_e + colloids%mass(colloids%species(k)) * sum(colloids%vel(:,k)**2)
684  end do
685  v_com = v_com / tmp_mass
686  kin_e = kin_e / 2
687 
688  call thermo_data%append(hfile, temperature, e1+e2+e3+e_wall, kin_e, e1+e2+e3+e_wall+kin_e, v_com)
689  call axial_cf%add(i-equilibration_loops, com_pos, unit_r)
690  call varia%tac()
691  end if
692 
693  if (collision_step) call solvent_cells%random_shift(state(1))
694 
695  call cell_md_pos(solvent_cells, solvent, ((i+1)*n_md_steps - loop_i_last_sort)*dt, md_flag=.false.)
696  call cell_md_vel(solvent_cells, solvent, ((i+1)*n_md_steps - loop_i_last_sort)*dt, md_flag=.false.)
697 
698  call apply_pbc(solvent, solvent_cells% edges)
699  call apply_pbc(colloids, solvent_cells% edges)
700  call solvent% sort(solvent_cells)
701  loop_i_last_sort = n_md_steps*(i+1)
702  call neigh% update_list(colloids, solvent, max_cut+skin, solvent_cells, solvent_colloid_lj)
703  !$omp parallel do
704  do k = 1, solvent%Nmax
705  solvent% pos_old(:,k) = solvent% pos(:,k)
706  end do
707  colloids% pos_old = colloids% pos
708 
709  if (collision_step) call wall_mpcd_step(solvent, solvent_cells, state, &
710  wall_temperature=[t, t], wall_v=wall_v, wall_n=[rho, rho], &
711  alpha=mpcd_alpha, keep_cell_v=do_hydro, thermostat=do_thermostat, &
712  bulk_temperature=t)
714 
715  call bulk_reac_timer%tic()
716  call bulk_reaction(solvent, solvent_cells, 2, 1, bulk_rate, n_md_steps*dt, state)
717  call bulk_reac_timer%tac()
718 
719  if (sampling) then
720  call so_timer%tic()
721  n_solvent = 0
722  !$omp parallel do private(k,j) reduction(+:n_solvent)
723  do k = 1, solvent%Nmax
724  j = solvent%species(k)
725  if (j <= 0) cycle
726  n_solvent(j) = n_solvent(j) + 1
727  end do
728  call so_timer%tac()
729  call n_solvent_el%append(n_solvent)
730 
731  call varia%tic()
732  v_com = sum(colloids%vel, dim=2)/colloids%Nmax
733  call varia%tac()
734  call polar%update(com_pos, v_com, unit_r/norm2(unit_r), solvent, solvent_cells)
735  one_x = qrot(rigid_janus%q, [1.d0, 0.d0, 0.d0])
736  one_y = qrot(rigid_janus%q, [0.d0, 1.d0, 0.d0])
737  one_z = qrot(rigid_janus%q, [0.d0, 0.d0, 1.d0])
738  com_pos = modulo(com_pos, solvent_cells%edges)
739  call planar%update(com_pos, v_com, one_x, one_y, one_z, qrot(rigid_janus%q, rigid_janus%omega_body), &
740  solvent, solvent_cells)
741 
742  if (do_quaternion) call omega_cf%add(i-equilibration_loops, correlate_block_dot, xvec=rigid_janus%omega_body)
743 
744  if ((i > equilibration_loops) .and. (modulo(i-equilibration_loops, coordinates_sampling)==0)) then
745  call janus_io%position%append(colloids%pos)
746  call janus_io%force%append(colloids%force)
747  call janus_io%velocity%append(colloids%vel)
748  call janus_io%image%append(colloids%image)
749  end if
750  end if
751 
752  end do
753  call main%tac()
754  write(*,*) ''
755 
756  write(*,*) 'n extra sorting', n_extra_sorting
757 
758  ! create a group for block correlators and write the data
759 
760  call h5gcreate_f(hfile%id, 'block_correlators', correlator_group, error)
761  call axial_cf%write(correlator_group, n_md_steps, n_md_steps*dt, 1, dt)
762  if (do_quaternion) &
763  call write_correlator_block(correlator_group, 'omega_body_autocorrelation', omega_cf, n_md_steps, n_md_steps*dt)
764  call h5gclose_f(correlator_group, error)
765 
766  ! write solvent coordinates for last step
767 
768  call thermo_data%append(hfile, temperature, e1+e2+e3+e_wall, kin_e, e1+e2+e3+e_wall+kin_e, v_com, add=.false., force=.true.)
769  if (do_solvent_io) then
770  call solvent_io%position%append(solvent%pos)
771  call solvent_io%velocity%append(solvent%vel)
772  call solvent_io%image%append(solvent%image)
773  call solvent_io%species%append(solvent%species)
774  call solvent_io%close()
775  end if
776 
777  ! store polar fields
778 
779  where (polar%count>0)
780  polar%v(1,:,:,:) = polar%v(1,:,:,:) / polar%count
781  polar%v(2,:,:,:) = polar%v(2,:,:,:) / polar%count
782  end where
783  call h5md_write_dataset(fields_group, 'polar_concentration', dble(polar%count)/n_loop)
784  call h5oopen_f(fields_group, 'polar_concentration', polar_id, error)
785  call h5md_write_attribute(polar_id, 'r_min', polar%r_min)
786  call h5md_write_attribute(polar_id, 'r_max', polar%r_max)
787  call h5md_write_attribute(polar_id, 'dr', polar%dr)
788  call h5md_write_attribute(polar_id, 'dtheta', polar%dtheta)
789  call h5oclose_f(polar_id, error)
790 
791  call h5md_write_dataset(fields_group, 'polar_velocity', polar%v)
792  call h5oopen_f(fields_group, 'polar_velocity', polar_id, error)
793  call h5md_write_attribute(polar_id, 'r_min', polar%r_min)
794  call h5md_write_attribute(polar_id, 'r_max', polar%r_max)
795  call h5md_write_attribute(polar_id, 'dr', polar%dr)
796  call h5md_write_attribute(polar_id, 'dtheta', polar%dtheta)
797  call h5oclose_f(polar_id, error)
798 
799  ! store planar fields
800 
801  where (planar%count>0)
802  planar%v(1,:,:,:) = planar%v(1,:,:,:) / planar%count
803  planar%v(2,:,:,:) = planar%v(2,:,:,:) / planar%count
804  end where
805  call h5md_write_dataset(fields_group, 'planar_concentration', planar%count/n_loop)
806  call h5oopen_f(fields_group, 'planar_concentration', planar_id, error)
807  call h5md_write_attribute(planar_id, 'x_min', planar%x_min)
808  call h5md_write_attribute(planar_id, 'dx', planar%dx)
809  call h5md_write_attribute(planar_id, 'y_min', planar%y_min)
810  call h5md_write_attribute(planar_id, 'dy', planar%dy)
811  call h5md_write_attribute(planar_id, 'thickness', planar%thickness)
812  call h5oclose_f(planar_id, error)
813 
814  call h5md_write_dataset(fields_group, 'planar_velocity', planar%v)
815  call h5oopen_f(fields_group, 'planar_velocity', planar_id, error)
816  call h5md_write_attribute(planar_id, 'x_min', planar%x_min)
817  call h5md_write_attribute(planar_id, 'dx', planar%dx)
818  call h5md_write_attribute(planar_id, 'y_min', planar%y_min)
819  call h5md_write_attribute(planar_id, 'dy', planar%dy)
820  call h5md_write_attribute(planar_id, 'thickness', planar%thickness)
821  call h5oclose_f(planar_id, error)
822 
823  ! Store timing data
824  call timer_list%append(solvent%time_stream)
825  call timer_list%append(solvent%time_step)
826  call timer_list%append(solvent%time_count)
827  call timer_list%append(solvent%time_sort)
828  call timer_list%append(solvent%time_ct)
829  call timer_list%append(solvent%time_md_pos)
830  call timer_list%append(solvent%time_md_vel)
831  call timer_list%append(solvent%time_max_disp)
832  call timer_list%append(solvent%time_apply_pbc)
833  call timer_list%append(colloids%time_self_force)
834  call timer_list%append(colloids%time_rattle_pos)
835  call timer_list%append(colloids%time_rattle_vel)
836  call timer_list%append(colloids%time_elastic)
837  call timer_list%append(colloids%time_apply_pbc)
838  call timer_list%append(neigh%time_update)
839  call timer_list%append(neigh%time_force)
840  call timer_list%append(colloids%time_max_disp)
841 
842  call h5gcreate_f(hfile%id, 'timers', timers_group, error)
843  call timer_list%write(timers_group, total_time)
844  call h5md_write_dataset(timers_group, 'total', total_time)
845  call h5md_write_dataset(timers_group, main%name, main%total)
846  call h5gclose_f(timers_group, error)
847 
848  call h5gclose_f(fields_group, error)
849  call janus_io%close()
850  call n_solvent_el%close()
851  if (do_quaternion) then
852  call q_el%close()
853  call omega_body_el%close()
854  end if
855  call u_el%close()
856  call janus_pos_el%close()
857  call janus_vel_el%close()
858  call hfile%close()
859  call h5close_f(error)
860 
861 contains
862 
863  subroutine flag_particles
864  double precision :: dist_to_C_sq
865  integer :: i, r, s
866  double precision :: x(3)
867 
868  !$omp parallel
869  !$omp do private(i, s, r, x, dist_to_C_sq)
870  do i = 1, colloids%Nmax
871  if (colloids%species(i)==1) then
872  do s = 1,neigh% n(i)
873  r = neigh%list(s,i)
874  if (solvent% species(r) == 1) then
875  x = rel_pos(colloids% pos(:,i),solvent% pos(:,r),solvent_cells% edges)
876  dist_to_c_sq = dot_product(x, x)
877  if (dist_to_c_sq < solvent_colloid_lj%cut_sq(1,1)) then
878  !$omp atomic
879  solvent%flags(r) = ior(solvent%flags(r), reac_mask)
880  end if
881  end if
882  end do
883  end if
884  end do
885  !$omp end do
886  !$omp end parallel
887 
888  end subroutine flag_particles
889 
890  subroutine change_species
891  integer :: m, thread_id, i
892  double precision :: dist
893 
894  !$omp parallel private(thread_id)
895  thread_id = omp_get_thread_num() + 1
896  !$omp do private(i, m, dist)
897  do i = 1, solvent_cells%N
898  change_loop: do m = solvent_cells%cell_start(i), solvent_cells%cell_start(i) + solvent_cells%cell_count(i) - 1
899  if (solvent%species(m) /= 1) cycle change_loop
900  if ((btest(solvent%flags(m), reac_bit)) .and. (.not. btest(solvent%flags(m), md_bit))) then
901  dist = norm2(rel_pos(modulo(rigid_janus%pos, solvent_cells%edges), solvent%pos(:,m), solvent_cells%edges))
902  if (dist > reaction_radius) then
903  if (threefry_double(state(thread_id)) < prob) solvent%species(m) = 2
904  solvent%flags(m) = ibclr(solvent%flags(m), reac_bit)
905  end if
906  end if
907  end do change_loop
908  end do
909  !$omp end do
910  !$omp end parallel
911 
912  end subroutine change_species
913 
914  subroutine refuel
915  double precision :: dist_to_C_sq
916  double precision :: dist_to_N_sq
917  double precision :: far
918  double precision :: x(3)
919  integer :: n
920 
921  far = (l(1)*0.45)**2
922 
923  !$omp parallel do private(x, dist_to_C_sq, dist_to_N_sq)
924  do n = 1,solvent% Nmax
925  if (solvent% species(n) == 2) then
926  x = rel_pos(colloids% pos(:,1), solvent% pos(:,n), solvent_cells% edges)
927  dist_to_c_sq = dot_product(x, x)
928  x= rel_pos(colloids% pos(:,2), solvent% pos(:,n), solvent_cells% edges)
929  dist_to_n_sq = dot_product(x, x)
930  if ((dist_to_c_sq > far) .and. (dist_to_n_sq > far)) then
931  solvent% species(n) = 1
932  end if
933  end if
934  end do
935  end subroutine refuel
936 
937  subroutine read_links(filename, n_links, links, links_d)
938  character(len=*), intent(in) :: filename
939  integer, intent(out) :: n_links
940  integer, allocatable, intent(out) :: links(:,:)
941  double precision, allocatable, intent(out) :: links_d(:)
942 
943  integer :: i, iostat
944  integer :: i1, i2
945  double precision :: l
946 
947  n_links = 0
948  open(11, file=filename)
949  count_loop: do while (.true.)
950  read(11, *, iostat=iostat) i1, i2, l
951  if (iostat.lt.0) exit count_loop
952  n_links = n_links + 1
953  end do count_loop
954  close(11)
955 
956  allocate(links(2, n_links), links_d(n_links))
957  open(11, file=filename)
958  do i = 1, n_links
959  read(11, *, iostat=iostat) i1, i2, l
960  links(1, i) = i1+1
961  links(2, i) = i2+1
962  links_d(i) = l
963  end do
964  close(11)
965 
966  end subroutine read_links
967 
968  function get_unit_r() result(u_r)
969  double precision :: u_r(3)
970  double precision :: r1(3), r2(3), r3(3)
971  double precision, parameter :: one_y(3) = [0.d0, 1.d0, 0.d0]
972 
973  if (do_quaternion) then
974  u_r = qrot(rigid_janus%q, one_y)
975  else if (attr_exists) then
976  r1 = rel_pos(colloids%pos(:,1), com_pos, solvent_cells%edges)
977  r2 = rel_pos(colloids%pos(:,2), com_pos, solvent_cells%edges)
978  r3 = rel_pos(colloids%pos(:,3), com_pos, solvent_cells%edges)
979  u_r = (r1 + alpha*r2 + beta*r3) / z0
980  else
981  u_r = one_y
982  end if
983 
984  end function get_unit_r
985 
986  subroutine compute_cell_wise_max_v
987  integer :: i, j
988  double precision :: local_max_v
989 
990  local_max_v = 0
991  !$omp parallel do private(i, j) reduction(max:local_max_v)
992  do i = 1, solvent_cells%N
993  local_max_v = 0
994  do j = solvent_cells%cell_start(i), solvent_cells%cell_start(i) + solvent_cells%cell_count(i) - 1
995  local_max_v = max(local_max_v, norm2(solvent%vel(:,j)))
996  end do
997  end do
998  solvent_cells%max_v = local_max_v
999 
1000  end subroutine compute_cell_wise_max_v
1001 
1002 end program single_body
double precision function, dimension(3) get_unit_r()
program single_body
Simulate a single colloidal rigid-body particle.
Definition: single_body.f90:58
subroutine flag_particles
subroutine change_species
subroutine read_links(filename, n_links, links, links_d)
subroutine compute_cell_wise_max_v
subroutine refuel