RMPCDMD
chemotactic_cell.f90
Go to the documentation of this file.
1 ! This file is part of RMPCDMD
2 ! Copyright (c) 2016-2017 Pierre de Buyl and contributors
3 ! License: BSD 3-clause (see file LICENSE)
4 
39 
41  use rmpcdmd_module
42  use hdf5
43  use h5md_module
44  use threefry_module
45  use parsetext
46  use iso_c_binding
47  use omp_lib
48  implicit none
49 
50  type(threefry_rng_t), allocatable :: state(:)
51 
52  integer, parameter :: N_species = 3
53 
54  type(cell_system_t) :: solvent_cells
55  type(particle_system_t) :: solvent
56  type(particle_system_t) :: colloids
57  type(neighbor_list_t) :: neigh
58  type(lj_params_t) :: solvent_colloid_lj
59  type(lj_params_t) :: colloid_lj
60  type(lj_params_t) :: walls_colloid_lj
61 
62  type(profile_t) :: vx
63 
64  integer :: rho
65  integer :: N
66  integer :: error
67  integer :: N_colloids
68  integer, parameter :: n_bins_conc = 90
69  double precision :: conc_z_cyl(n_bins_conc)
70 
71  double precision :: sigma_N, sigma_C, max_cut, alpha, sigma_sphere
72  double precision :: shift(3)
73  double precision :: track_y_shift
74  double precision :: sigma(3,2), sigma_cut(3,2), epsilon(3,2)
75  double precision,allocatable :: mass(:)
76 
77  double precision :: v_com(3), wall_v(3,2), wall_t(2)
78  double precision :: local_mass, total_mass
79 
80  double precision :: e1, e2, e_wall
81  double precision :: tau, dt , T
82  double precision :: d,prob
83  double precision :: skin, co_max, so_max
84  integer :: N_MD_steps, N_loop
85  integer :: colloid_sampling
86  integer :: n_extra_sorting
87  double precision :: kin_e, temperature
88  integer, dimension(N_species) :: n_solvent, catalytic_change, bulk_change
89  type(h5md_element_t) :: n_solvent_el, catalytic_change_el, bulk_change_el
90  type(h5md_element_t) :: omega_el
91 
92  double precision :: colloid_pos(3,2)
93  double precision :: com_pos(3)
94  type(h5md_file_t) :: hfile
95  type(h5md_element_t) :: dummy_element
96  integer(HID_T) :: fields_group, params_group
97  type(h5md_element_t) :: rho_xy_el
98  type(thermo_t) :: thermo_data
99  type(particle_system_io_t) :: dimer_io
100  type(particle_system_io_t) :: solvent_io
101  integer(HID_T) :: box_group
102  type(h5md_element_t) :: elem_vx, elem_vx_count
103 
104  type(pto) :: config
105  integer :: i, L(3), n_threads
106  integer :: j, k, m
107  integer :: i_release, i_block
108 
109  type(timer_t), target :: flag_timer, change_timer, buffer_timer, varia
110  type(timer_t), target :: main
111  double precision :: total_time
112  type(timer_list_t) :: timer_list
113  integer(HID_T) :: timers_group
114 
115  integer, allocatable :: rho_xy(:,:,:)
116 
117  integer, parameter :: block_length = 8
118  type(axial_correlator_t) :: axial_cf
119  type(correlator_t) :: omega_acf
120  integer(HID_T) :: correlator_group
121 
122  double precision :: unit_r(3), omega(3), rel_v(3), norm_xy
123 
124  double precision :: g(3) !gravity
125  logical :: fixed, on_track, stopped, N_in_front, dimer, N_type
126  logical :: store_rho_xy
127  double precision :: store_rho_xy_z(2)
128  integer :: buffer_length
129  logical :: sampling
130  integer :: equilibration_loops
131  double precision :: max_speed, z, Lz
132  integer :: steps_fixed
133  type(args_t) :: args
134 
135  args = get_input_args()
136  call ptparse(config, args%input_file, 11)
137 
138  call flag_timer%init('flag')
139  call change_timer%init('change')
140  call buffer_timer%init('buffer')
141  call main%init('main')
142  call varia%init('varia')
143 
144  call timer_list%init(14)
145  call timer_list%append(flag_timer)
146  call timer_list%append(change_timer)
147  call timer_list%append(buffer_timer)
148  call timer_list%append(varia)
149 
150  n_threads = omp_get_max_threads()
151  allocate(state(n_threads))
152  call threefry_rng_init(state, args%seed)
153 
154  call h5open_f(error)
155 
156  call hfile%create(args%output_file, 'RMPCDMD::chemotactic_cell', rmpcdmd_revision, 'Pierre de Buyl')
157  call h5gcreate_f(hfile%id, 'parameters', params_group, error)
158  call hdf5_util_write_dataset(params_group, 'seed', args%seed)
159 
160  g = 0
161  g(1) = ptread_d(config, 'g', loc=params_group)
162  buffer_length = ptread_i(config, 'buffer_length', loc=params_group)
163  max_speed = ptread_d(config,'max_speed', loc=params_group)
164  prob = ptread_d(config,'probability', loc=params_group)
165  alpha = ptread_d(config,'alpha', loc=params_group)
166  store_rho_xy = ptread_l(config, 'store_rho_xy', loc=params_group)
167  store_rho_xy_z = ptread_dvec(config, 'store_rho_xy_z', 2, loc=params_group)
168  dimer = ptread_l(config, 'dimer', loc=params_group)
169  n_type = ptread_l(config, 'N_type', loc=params_group)
170  if (dimer) then
171  n_colloids = 2
172  else
173  n_colloids = 1
174  end if
175  l = ptread_ivec(config, 'L', 3, loc=params_group)
176  l(1) = l(1) + buffer_length
177 
178  rho = ptread_i(config, 'rho', loc=params_group)
179  n = rho *l(1)*l(2)*l(3)
180 
181  t = ptread_d(config, 'T', loc=params_group)
182  d = ptread_d(config, 'd', loc=params_group)
183  n_in_front = ptread_l(config, 'N_in_front', loc=params_group)
184  track_y_shift = ptread_d(config, 'track_y_shift', loc=params_group)
185 
186  wall_v = 0
187  wall_t = [t, t]
188 
189  tau = ptread_d(config, 'tau', loc=params_group)
190  n_md_steps = ptread_i(config, 'N_MD', loc=params_group)
191  colloid_sampling = ptread_i(config, 'colloid_sampling', loc=params_group)
192  if (modulo(n_md_steps, colloid_sampling) /= 0) then
193  error stop 'colloid_sampling must divide N_MD with no remainder'
194  end if
195  dt = tau / n_md_steps
196  n_loop = ptread_i(config, 'N_loop', loc=params_group)
197  steps_fixed = ptread_i(config, 'steps_fixed', loc=params_group)
198  equilibration_loops = ptread_i(config, 'equilibration_loops', loc=params_group)
199 
200  sigma_c = ptread_d(config, 'sigma_C', loc=params_group)
201  sigma_n = ptread_d(config, 'sigma_N', loc=params_group)
202 
203  epsilon(:,1) = ptread_dvec(config, 'epsilon_C', n_species, loc=params_group)
204  epsilon(:,2) = ptread_dvec(config, 'epsilon_N', n_species, loc=params_group)
205  sigma(:,1) = sigma_c
206  sigma(:,2) = sigma_n
207 
208  sigma_cut = sigma*2**(1.d0/6.d0)
209  max_cut = maxval(sigma_cut)
210 
211  call solvent_colloid_lj% init(epsilon, sigma, sigma_cut)
212  epsilon = 1.d0
213  sigma(1,1) = 2*sigma_c
214  sigma(1,2) = sigma_c + sigma_n
215  sigma(2,1) = sigma_c + sigma_n
216  sigma(2,2) = 2*sigma_n
217  sigma_cut = sigma*2**(1.d0/6.d0)
218  call colloid_lj% init(epsilon(1:2,:), sigma(1:2,:), sigma_cut(1:2,:))
219 
220 
221  sigma(1,:) = -1
222  epsilon = 1.d0
223  sigma(2,:) = [sigma_c, sigma_n]
224  shift(2) = max(sigma_c, sigma_n)*2**(1./6.) + 0.25
225  sigma(3,:) = [sigma_c, sigma_n]
226  shift(3) = max(sigma_c, sigma_n)*2**(1./6.) + 0.25
227  sigma_cut = sigma*3**(1.d0/6.d0)
228  call walls_colloid_lj% init(epsilon(1:3,:), sigma(1:3,:), sigma_cut(1:3,:), shift)
229 
230  if (n_type) then
231  sigma_sphere = sigma_n
232  else
233  sigma_sphere = sigma_c
234  end if
235 
236  allocate(mass(n_colloids))
237  if (dimer) then
238  mass(1) = rho * sigma_c**3 * 4 * 3.14159265/3
239  mass(2) = rho * sigma_n**3 * 4 * 3.14159265/3
240  else
241  mass = rho * sigma_sphere**3 * 4 * 3.14159265/3
242  end if
243 
244  call solvent% init(n,n_species, system_name='solvent')
245 
246  call colloids% init(n_colloids,2, mass, system_name='colloids') !there will be 2 species of colloids
247 
248  call thermo_data%init(hfile, n_buffer=50, step=n_md_steps, time=n_md_steps*dt)
249 
250  call ptkill(config)
251 
252  call axial_cf%init(block_length, n_loop*n_md_steps/colloid_sampling, n_loop*n_md_steps)
253  call omega_acf%init(block_length, get_n_blocks(block_length, n_blocks_max=7, &
254  n_samples=n_loop*n_md_steps/colloid_sampling))
255 
256  if (dimer) then
257  colloids% species(1) = 1
258  colloids% species(2) = 2
259  else
260  if (n_type) then
261  colloids% species = 2
262  else
263  colloids% species = 1
264  end if
265  end if
266  colloids% vel = 0
267  colloids% force = 0
268 
269  dimer_io%force_info%store = .false.
270  dimer_io%id_info%store = .false.
271  dimer_io%position_info%store = .true.
272  dimer_io%position_info%mode = ior(h5md_linear,h5md_store_time)
273  dimer_io%position_info%step = colloid_sampling
274  dimer_io%position_info%time = colloid_sampling*dt
275  dimer_io%image_info%store = .true.
276  dimer_io%image_info%mode = ior(h5md_linear,h5md_store_time)
277  dimer_io%image_info%step = colloid_sampling
278  dimer_io%image_info%time = colloid_sampling*dt
279  dimer_io%velocity_info%store = .true.
280  dimer_io%velocity_info%mode = ior(h5md_linear,h5md_store_time)
281  dimer_io%velocity_info%step = colloid_sampling
282  dimer_io%velocity_info%time = colloid_sampling*dt
283  dimer_io%species_info%store = .true.
284  dimer_io%species_info%mode = h5md_fixed
285  call dimer_io%init(hfile, 'dimer', colloids)
286 
287  solvent_io%force_info%store = .false.
288  solvent_io%id_info%store = .false.
289  solvent_io%position_info%store = .true.
290  solvent_io%position_info%mode = ior(h5md_linear,h5md_store_time)
291  solvent_io%position_info%step = n_loop*n_md_steps
292  solvent_io%position_info%time = n_loop*n_md_steps*dt
293  solvent_io%image_info%store = .true.
294  solvent_io%image_info%mode = ior(h5md_linear,h5md_store_time)
295  solvent_io%image_info%step = n_loop*n_md_steps
296  solvent_io%image_info%time = n_loop*n_md_steps*dt
297  solvent_io%velocity_info%store = .true.
298  solvent_io%velocity_info%mode = ior(h5md_linear,h5md_store_time)
299  solvent_io%velocity_info%step = n_loop*n_md_steps
300  solvent_io%velocity_info%time = n_loop*n_md_steps*dt
301  solvent_io%species_info%store = .true.
302  solvent_io%species_info%mode = ior(h5md_linear,h5md_store_time)
303  solvent_io%species_info%step = n_loop*n_md_steps
304  solvent_io%species_info%time = n_loop*n_md_steps*dt
305  call solvent_io%init(hfile, 'solvent', solvent)
306 
307  solvent% force = 0
308  solvent% species = 1
309  call solvent_cells%init(l, 1.d0,has_walls = .true.)
310  call vx% init(0.d0, solvent_cells% edges(3), l(3))
311 
312  if (store_rho_xy) allocate(rho_xy(n_species, l(2), l(1)))
313  call h5gcreate_f(hfile%id, 'fields', fields_group, error)
314  if (store_rho_xy) then
315  call rho_xy_el%create_time(fields_group, 'rho_xy', rho_xy, ior(h5md_linear,h5md_store_time), &
316  step=n_md_steps, time=n_md_steps*dt)
317  call h5md_write_attribute(rho_xy_el%id, 'zmin', store_rho_xy_z(1))
318  call h5md_write_attribute(rho_xy_el%id, 'zmax', store_rho_xy_z(2))
319  end if
320  call elem_vx% create_time(fields_group, 'vx', vx% data, ior(h5md_time, h5md_store_time))
321  call elem_vx_count% create_time(fields_group, 'vx_count', vx% count, ior(h5md_time, h5md_store_time))
322 
323  call h5gclose_f(fields_group, error)
324 
325  call n_solvent_el%create_time(hfile%observables, 'n_solvent', &
326  n_solvent, ior(h5md_linear,h5md_store_time), step=n_md_steps, &
327  time=n_md_steps*dt)
328  call catalytic_change_el%create_time(hfile%observables, 'catalytic_change', &
329  catalytic_change, ior(h5md_linear,h5md_store_time), step=n_md_steps, &
330  time=n_md_steps*dt)
331  call bulk_change_el%create_time(hfile%observables, 'bulk_change', &
332  bulk_change, ior(h5md_linear,h5md_store_time), step=n_md_steps, &
333  time=n_md_steps*dt)
334  call omega_el%create_time(hfile%observables, 'omega', &
335  omega(3), ior(h5md_linear,h5md_store_time), step=colloid_sampling, &
336  time=colloid_sampling*dt)
337 
338  if (dimer) then
339  colloids% pos(3,:) = solvent_cells% edges(3)/2.d0
340  if (n_in_front) then
341  colloids% pos(1,1) = sigma_c*2**(1.d0/6.d0) + 1
342  colloids% pos(1,2) = colloids% pos(1,1) + d
343  colloids% pos(2,:) = solvent_cells% edges(2)/2.d0 + track_y_shift
344  else
345  colloids% pos(1,2) = sigma_n*2**(1.d0/6.d0) + 1
346  colloids% pos(1,1) = colloids% pos(1,2) + d
347  colloids% pos(2,:) = solvent_cells% edges(2)/2.d0 + track_y_shift
348  end if
349  else
350  colloids% pos(3,:) = solvent_cells% edges(3)/2.d0
351  colloids% pos(2,:) = solvent_cells% edges(2)/2.d0 + track_y_shift
352  colloids% pos(1,:) = sigma_sphere*2**(1.d0/6.d0) + 1
353  end if
354 
355  call h5gcreate_f(dimer_io%group, 'box', box_group, error)
356  call h5md_write_attribute(box_group, 'dimension', 3)
357  call dummy_element%create_fixed(box_group, 'edges', solvent_cells%edges)
358  call h5gclose_f(box_group, error)
359 
360  call h5gcreate_f(solvent_io%group, 'box', box_group, error)
361  call h5md_write_attribute(box_group, 'dimension', 3)
362  call dummy_element%create_fixed(box_group, 'edges', solvent_cells%edges)
363  call h5gclose_f(box_group, error)
364 
365  call solvent% random_placement(solvent_cells% edges, colloids, solvent_colloid_lj, state(1))
366 
367  lz = solvent_cells%edges(3)
368  do i=1, solvent% Nmax
369  z = solvent%pos(3,i)
370  solvent% vel(1,i) = threefry_normal(state(1))*sqrt(t) + &
371  max_speed*z*(lz-z)/(lz/2)**2
372  solvent% vel(2,i) = threefry_normal(state(1))*sqrt(t)
373  solvent% vel(3,i) = threefry_normal(state(1))*sqrt(t)
374  end do
375 
376  do m = 1, solvent% Nmax
377  if (solvent% pos(2,m) < (l(2)/2.d0)) then
378  solvent% species(m) = 1
379  else
380  solvent% species(m) = 3
381  end if
382  end do
383 
384  call solvent% sort(solvent_cells)
385 
386  call neigh% init(colloids% Nmax, 10*int(300*max(sigma_c,sigma_n)**3))
387 
388  skin = 1.5
389  n_extra_sorting = 0
390 
391  call neigh% make_stencil(solvent_cells, max_cut+skin)
392 
393  call neigh% update_list(colloids, solvent, max_cut+skin, solvent_cells)
394 
395  solvent% force(2:3,:) = 0
396  solvent% force(1,:) = g(1)
397  e1 = compute_force(colloids, solvent, neigh, solvent_cells% edges, solvent_colloid_lj)
398  e2 = compute_force_n2(colloids, solvent_cells% edges, colloid_lj)
399  e_wall = lj93_zwall(colloids, solvent_cells% edges, walls_colloid_lj)
400  solvent% force_old = solvent% force
401  colloids% force_old = colloids% force
402  catalytic_change = 0
403 
404  i = 0
405  if (buffer_length>0) then
406  fixed = .true.
407  on_track = .true.
408  else
409  fixed = .false.
410  on_track = .false.
411  end if
412  stopped = .false.
413 
414  if (buffer_length > 0) then
415  solvent_cells%bc = [periodic_bc, specular_bc, bounce_back_bc]
416  else
417  solvent_cells%bc = [periodic_bc, periodic_bc, bounce_back_bc]
418  walls_colloid_lj%sigma(2,:) = -1
419  end if
420 
421  sampling = .false.
422  i_release = 0
423  i = 0
424  i_block = 0
425  write(*,*) 'Running for', n_loop, 'loops'
426  !start RMPCDMD
427  call main%tic()
428  setup: do while (.not. stopped)
429  if (modulo(i,20) == 0) write(*,'(i09)',advance='no') i
430  md_loop: do j = 1, n_md_steps
431  call mpcd_stream_xforce_yzwall(solvent, solvent_cells, dt, g(1))
432 
433  colloids% pos_rattle = colloids% pos
434 
435  do k=1, colloids% Nmax
436  colloids% pos(:,k) = colloids% pos(:,k) + dt * colloids% vel(:,k) + &
437  dt**2 * colloids% force(:,k) / (2 * colloids% mass(k))
438  end do
439 
440  if (dimer) then
441  call rattle_dimer_pos(colloids, d, dt, solvent_cells% edges)
442  end if
443 
444  if ((.not. on_track) .and. (buffer_length/=0))then
445  do k=1, colloids% Nmax
446  if (colloids% pos(1,k) > solvent_cells% edges(1)) then
447  stopped = .true.
448  end if
449  end do
450  end if
451 
452  so_max = solvent% maximum_displacement()
453  co_max = colloids% maximum_displacement()
454 
455  if ( (co_max >= skin*0.1) .or. (so_max >= skin*0.9) ) then
456  call apply_pbc(colloids, solvent_cells% edges)
457  call apply_pbc(solvent, solvent_cells% edges)
458  call solvent% sort(solvent_cells)
459  call neigh% update_list(colloids, solvent, max_cut + skin, solvent_cells)
460  call varia%tic()
461  !$omp parallel do
462  do k = 1, solvent%Nmax
463  solvent% pos_old(:,k) = solvent% pos(:,k)
464  end do
465  colloids% pos_old = colloids% pos
466  call varia%tac()
467  n_extra_sorting = n_extra_sorting + 1
468  end if
469 
470  call buffer_particles(solvent,solvent_cells%edges)
471 
472  call switch(solvent% force, solvent% force_old)
473  call switch(colloids% force, colloids% force_old)
474 
475  !$omp parallel do
476  do k = 1, solvent%Nmax
477  solvent%force(:,k) = g
478  end do
479  colloids% force = 0
480  e1 = compute_force(colloids, solvent, neigh, solvent_cells% edges, solvent_colloid_lj)
481  e2 = compute_force_n2(colloids, solvent_cells% edges, colloid_lj)
482  if (.not. on_track) then
483  e_wall = lj93_zwall(colloids, solvent_cells% edges, walls_colloid_lj)
484  end if
485  if (on_track) then
486  colloids% force(2,:) = 0
487  colloids% force(3,:) = 0
488  if (fixed) then
489  colloids% force(1,:) = 0
490  end if
491  end if
492 
493  call md_vel(solvent, dt)
494 
495  do k=1, colloids% Nmax
496  colloids% vel(:,k) = colloids% vel(:,k) + &
497  dt * ( colloids% force(:,k) + colloids% force_old(:,k) ) / (2 * colloids% mass(k))
498  end do
499  if (dimer) then
500  call rattle_dimer_vel(colloids, d, dt, solvent_cells% edges)
501  end if
502 
503  if (.not.fixed) then
504  ! this should be solved for a single passive colloid
505  if ((.not. n_type) .or. (dimer)) then
506  if (.not. on_track) then
507  call flag_particles
508  call change_species
509  end if
510  end if
511  end if
512 
513  com_pos = (colloids%pos(:,1)+colloids%image(:,1)*solvent_cells%edges + &
514  colloids%pos(:,2)+colloids%image(:,2)*solvent_cells%edges) / 2
515  unit_r = rel_pos(colloids%pos(:,1), colloids%pos(:,2), solvent_cells%edges)
516  norm_xy = norm2(unit_r(1:2))
517  rel_v = colloids%vel(:,1)-colloids%vel(:,2)
518  omega = cross(unit_r, rel_v) / norm_xy**2
519  unit_r = unit_r / norm2(unit_r)
520 
521  if (sampling) then
522  v_com = sum(colloids%vel, dim=2)/2
523  call axial_cf%add_fast((i-i_release)*n_md_steps+j-1, v_com, unit_r)
524  end if
525 
526  if ((sampling) .and. (modulo(j, colloid_sampling)==0)) then
527  ! correlators
528  call axial_cf%add(i_block, com_pos, unit_r)
529  call omega_acf%add(i_block, correlate_block_dot, x=omega(3))
530  i_block = i_block + 1
531  ! colloid trajectory
532  call dimer_io%position%append(colloids%pos)
533  call dimer_io%velocity%append(colloids%vel)
534  call dimer_io%image%append(colloids%image)
535  call omega_el%append(omega(3))
536  end if
537 
538  end do md_loop
539 
540  call solvent_cells%random_shift(state(1))
541 
542  call apply_pbc(colloids, solvent_cells% edges)
543  call apply_pbc(solvent, solvent_cells% edges)
544  call solvent% sort(solvent_cells)
545  call neigh% update_list(colloids, solvent, max_cut+skin, solvent_cells)
546  solvent% pos_old = solvent% pos
547  colloids% pos_old = colloids% pos
548 
549  call wall_mpcd_step(solvent, solvent_cells, state, &
550  wall_temperature=wall_t, wall_v=wall_v, wall_n=[rho, rho], alpha=alpha)
551 
552  call compute_vx(solvent, vx)
553  if ((sampling) .and. (modulo(i-i_release+1, 50) == 0)) then
554  call vx% norm()
555  call elem_vx% append(vx% data, i-i_release+1, (i-i_release+1)*tau)
556  call elem_vx_count% append(vx% count, i-i_release+1, (i-i_release+1)*tau)
557  call vx% reset()
558  end if
559 
560  call varia%tic()
561  if ((sampling) .and. (store_rho_xy)) then
562  call compute_rho_xy
563  call rho_xy_el%append(rho_xy)
564  end if
565  call varia%tac()
566 
567  temperature = compute_temperature(solvent, solvent_cells)
568  total_mass = 0
569  kin_e = sum(solvent% vel**2)/2
570  v_com = sum(solvent% vel, dim=2)
571  do k = 1, colloids% Nmax
572  m = colloids%species(k)
573  if (m==0) cycle
574  local_mass = colloids%mass(m)
575  kin_e = kin_e + local_mass*sum(colloids% vel(:,k)**2)/2
576  v_com = v_com + local_mass*colloids%vel(:,k)
577  total_mass = total_mass + local_mass
578  end do
579  v_com = v_com / (solvent%Nmax + total_mass)
580 
581  n_solvent = 0
582  do k = 1, solvent%Nmax
583  m = solvent%species(k)
584  if (m <= 0) cycle
585  n_solvent(m) = n_solvent(m) + 1
586  end do
587 
588  if (sampling) then
589  call thermo_data%append(hfile, temperature, e1+e2+e_wall, kin_e, e1+e2+e_wall+kin_e, v_com)
590  call n_solvent_el%append(n_solvent)
591  call catalytic_change_el%append(catalytic_change)
592  call bulk_change_el%append(bulk_change)
593  end if
594 
595  call h5fflush_f(hfile%id, h5f_scope_global_f, error)
596 
597  if (fixed) then
598  if (i >= steps_fixed) then
599  write(*,*) 'fixed', fixed
600  fixed = .false.
601  end if
602  end if
603 
604  if (on_track) then
605  if (dimer) then
606  if ((colloids% pos(1,1) > (buffer_length+sigma_c)) &
607  .and. (colloids% pos(1,2) > (buffer_length+sigma_n))) then
608  on_track = .false.
609  end if
610  else
611  if (colloids% pos(1,1) > (buffer_length+sigma_sphere)) then
612  on_track = .false.
613  end if
614  end if
615  end if
616 
617  i = i+1
618  if ( &
619  ((.not. sampling) .and. (buffer_length == 0) .and. (i >= equilibration_loops)) .or. &
620  ((i_release==0) .and. (buffer_length > 0) .and. (.not. fixed)) ) then
621  i_release = i
622  sampling = .true.
623  write(*,*) 'i_release =', i_release
624  end if
625  if (i-i_release > n_loop) exit setup
626  end do setup
627  call main%tac()
628 
629  call thermo_data%append(hfile, temperature, e1+e2+e_wall, kin_e, e1+e2+e_wall+kin_e, v_com, add=.false., force=.true.)
630 
631  write(*,*) 'n extra sorting', n_extra_sorting
632 
633  ! create a group for block correlators and write the data
634 
635  call h5gcreate_f(hfile%id, 'block_correlators', correlator_group, error)
636 
637  call axial_cf%write(correlator_group, colloid_sampling, colloid_sampling*dt, 1, dt)
638 
639  call write_correlator_block(correlator_group, 'planar_angular_velocity_autocorrelation', &
640  omega_acf, colloid_sampling, colloid_sampling*dt)
641 
642  call h5gclose_f(correlator_group, error)
643 
644  call solvent_io%position%append(solvent%pos)
645  call solvent_io%velocity%append(solvent%vel)
646  call solvent_io%image%append(solvent%image)
647  call solvent_io%species%append(solvent%species)
648 
649  call h5gcreate_f(hfile%id, 'timers', timers_group, error)
650  call timer_list%append(solvent%time_stream)
651  call timer_list%append(solvent%time_md_vel)
652  call timer_list%append(solvent%time_step)
653  call timer_list%append(solvent%time_count)
654  call timer_list%append(solvent%time_sort)
655  call timer_list%append(solvent%time_ct)
656  call timer_list%append(solvent%time_max_disp)
657  call timer_list%append(solvent%time_apply_pbc)
658  call timer_list%append(neigh%time_update)
659  call timer_list%append(neigh%time_force)
660 
661  call timer_list%write(timers_group, total_time)
662 
663  call h5md_write_dataset(timers_group, 'total', total_time)
664  call h5md_write_dataset(timers_group, main%name, main%total)
665 
666  call h5gclose_f(timers_group, error)
667 
668  if (store_rho_xy) call rho_xy_el%close()
669  call elem_vx% close()
670  call elem_vx_count% close()
671  call dimer_io%close()
672  call hfile%close()
673  call h5close_f(error)
674 
675 contains
676 
677  subroutine flag_particles
678  double precision :: dist_to_C_sq
679  integer :: r, s
680  double precision :: x(3)
681 
682  call flag_timer%tic()
683  !$omp parallel do private(s, r, x, dist_to_C_sq)
684  do s = 1,neigh% n(1)
685  r = neigh%list(s,1)
686  if ((solvent% species(r)==1) .and. (.not. btest(solvent%flags(r), reac_bit))) then
687  x = rel_pos(colloids% pos(:,1),solvent% pos(:,r),solvent_cells% edges)
688  dist_to_c_sq = dot_product(x, x)
689  if (dist_to_c_sq < solvent_colloid_lj%cut_sq(1,1)) then
690  solvent%flags(r) = ibset(solvent%flags(r), reac_bit)
691  end if
692  end if
693  end do
694  call flag_timer%tac()
695 
696  end subroutine flag_particles
697 
698  subroutine change_species
699  double precision :: dist_to_C_sq
700  double precision :: dist_to_N_sq
701  integer :: m
702  double precision :: x(3)
703  integer :: thread_id
704 
705  call change_timer%tic()
706  catalytic_change = 0
707  !$omp parallel private(thread_id)
708  thread_id = omp_get_thread_num() + 1
709  !$omp do private(x, dist_to_C_sq, dist_to_N_sq) reduction(+:catalytic_change)
710  do m = 1, solvent% Nmax
711  if (btest(solvent%flags(m), reac_bit)) then
712  if (dimer) then
713  x = rel_pos(colloids% pos(:,1), solvent% pos(:,m), solvent_cells% edges)
714  dist_to_c_sq = dot_product(x, x)
715  x = rel_pos(colloids% pos(:,2), solvent% pos(:,m), solvent_cells% edges)
716  dist_to_n_sq = dot_product(x, x)
717  if ( &
718  (dist_to_c_sq > solvent_colloid_lj%cut_sq(1,1)) &
719  .and. &
720  (dist_to_n_sq > solvent_colloid_lj%cut_sq(1,2)) &
721  ) &
722  then
723  if (threefry_double(state(thread_id)) <= prob) then
724  solvent% species(m) = 2
725  catalytic_change(1) = catalytic_change(1) - 1
726  catalytic_change(2) = catalytic_change(2) + 1
727  end if
728  solvent%flags(m) = ibclr(solvent%flags(m), reac_bit)
729  end if
730  else
731  x = rel_pos(colloids% pos(:,1), solvent% pos(:,m), solvent_cells% edges)
732  dist_to_c_sq = dot_product(x, x)
733  if (dist_to_c_sq > solvent_colloid_lj%cut_sq(1,1)) then
734  if (threefry_double(state(thread_id)) <= prob) then
735  solvent% species(m) = 2
736  catalytic_change(1) = catalytic_change(1) - 1
737  catalytic_change(2) = catalytic_change(2) + 1
738  end if
739  solvent%flags(m) = ibclr(solvent%flags(m), reac_bit)
740  end if
741  end if
742  end if
743  end do
744  !$omp end do
745  !$omp end parallel
746  call change_timer%tac()
747 
748  end subroutine change_species
749 
751  double precision :: dimer_orient(3),x(3),y(3),z(3)
752  double precision :: solvent_pos(3,solvent% nmax)
753  double precision :: dz,r,theta,x_pos,y_pos,z_pos
754  integer :: o
755  integer :: check
756  logical :: far_enough_from_wall
757  double precision :: range_min1(3),range_min2(3),range_max1(3),range_max2(3)
758 
759  dz = 2.d0*d/n_bins_conc
760  dimer_orient = colloids% pos(:,2) - colloids% pos(:,1)
761  z = dimer_orient/sqrt(dot_product(dimer_orient,dimer_orient))
762 
763  x = (/0.d0, 1.d0, -dimer_orient(2)/dimer_orient(3)/)
764  x = x/sqrt(dot_product(x,x))
765  y = (/z(2)*x(3)-z(3)*x(2),z(3)*x(1)-z(1)*x(3),z(1)*x(2)-z(2)*x(1)/)
766  conc_z_cyl = 0
767 
768  range_min1 = colloids%pos(:,1) - d/2.0*z - (/0.d0,0.d0,1.d0/)*2*max_cut
769  range_min2 = colloids%pos(:,1) - d/2.0*z + (/0.d0,0.d0,1.d0/)*2*max_cut
770  range_max1 = colloids%pos(:,1) + 3.d0*d/2.0*z - (/0.d0,0.d0,1.d0/)*2*max_cut
771  range_max2 = colloids%pos(:,1) - 3.d0*d/2.0*z + (/0.d0,0.d0,1.d0/)*2*max_cut
772 
773  if ( (range_min1(3)<solvent_cells%edges(3)).and.(range_min1(3)>0).and. &
774  (range_max1(3)<solvent_cells%edges(3)).and.(range_max1(3)>0).and. &
775  (range_min2(3)<solvent_cells%edges(3)).and.(range_min2(3)>0).and. &
776  (range_max2(3)<solvent_cells%edges(3)).and.(range_max2(3)>0) ) then
777  far_enough_from_wall = .true.
778  else
779  far_enough_from_wall = .false.
780  end if
781  if (far_enough_from_wall) then
782  do o = 1, solvent% Nmax
783  solvent_pos(:,o) = solvent% pos(:,o) - colloids% pos(:,1)
784  x_pos = dot_product(x,solvent_pos(:,o))
785  y_pos = dot_product(y, solvent_pos(:,o))
786  z_pos = dot_product(z, solvent_pos(:,o))
787  solvent_pos(:,o) = (/x_pos,y_pos,z_pos/)
788  end do
789  do o = 1, solvent% Nmax
790  r = sqrt(solvent_pos(1,o)**2 + solvent_pos(2,o)**2)
791  theta = atan(solvent_pos(2,o)/solvent_pos(1,o))
792  solvent_pos(1,o) = r
793  solvent_pos(2,o) = theta
794  if ((solvent_pos(1,o) < 2*max_cut).and.(solvent_pos(3,o)<1.5d0*d).and.(solvent_pos(3,o)>-0.5d0*d)) then
795  if (solvent% species(o)==2) then
796  check = floor((solvent_pos(3,o)+0.5d0*d)/dz)
797  check = check+1
798  conc_z_cyl(check) = conc_z_cyl(check) + 1
799  end if
800  end if
801  end do
802  colloid_pos(:,1) = 0
803  colloid_pos(3,1) = colloids% pos(3,1)
804  colloid_pos(:,2) = 0
805  colloid_pos(3,2) = d + colloids% pos(3,1)
806  else
807  conc_z_cyl = 0
808  colloid_pos = 0
809  end if
810  end subroutine concentration_field_cylindrical
811 
812  subroutine buffer_particles(particles,edges)
813  type(particle_system_t), intent(inout) :: particles
814  double precision, intent(in) :: edges(3)
815 
816  integer :: k, s
817 
818  call buffer_timer%tic()
819  bulk_change = 0
820  !$omp parallel do private(s) reduction(+:bulk_change)
821  do k = 1, particles% Nmax
822  s = particles% species(k)
823  if (s <= 0) continue
824  if ((particles% pos(1,k) > 0) .and. (particles% pos(1,k) < buffer_length)) then
825  if (particles% pos(2,k) < edges(2)/2.d0) then
826  bulk_change(s) = bulk_change(s) - 1
827  particles% species(k) = 1
828  s = 1
829  bulk_change(s) = bulk_change(s) + 1
830  else
831  bulk_change(s) = bulk_change(s) - 1
832  particles% species(k) = 3
833  s = 3
834  bulk_change(s) = bulk_change(s) + 1
835  end if
836  end if
837  end do
838  call buffer_timer%tac()
839 
840  end subroutine buffer_particles
841 
842  subroutine compute_rho_xy
843  integer :: i, s, ix, iy
844  double precision :: z
845 
846  rho_xy = 0
847  do i = 1, solvent%Nmax
848  s = solvent%species(i)
849  if (s <= 0) cycle
850  z = solvent%pos(3,i)
851  if ((z >= store_rho_xy_z(1)) .and. (z <= store_rho_xy_z(2))) then
852  ix = modulo(floor(solvent%pos(1,i)/solvent_cells%a), l(1)) + 1
853  iy = modulo(floor(solvent%pos(2,i)/solvent_cells%a), l(2)) + 1
854  rho_xy(s, iy, ix) = rho_xy(s, iy, ix) + 1
855  end if
856  end do
857 
858  end subroutine compute_rho_xy
859 
860 end program chemotactic_cell
subroutine flag_particles
subroutine concentration_field_cylindrical
program chemotactic_cell
Model a chemotactic experiment in a microfluidic channel.
subroutine buffer_particles(particles, edges)
subroutine change_species
subroutine compute_rho_xy