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