41 integer,
parameter :: N_species = 1
42 integer,
parameter :: N_species_colloids = 1
44 type(threefry_rng_t),
allocatable :: state(:)
46 type(cell_system_t) :: solvent_cells
47 type(particle_system_t) :: solvent
48 type(particle_system_t) :: colloids
49 type(neighbor_list_t) :: neigh
50 type(lj_params_t) :: solvent_colloid_lj
53 type(histogram_t) :: rhoz
55 type(h5md_element_t) :: elem_tz, elem_tz_count
56 type(h5md_element_t) :: elem_rhoz
57 double precision,
allocatable :: v_xz(:,:,:), v_xyz(:,:,:,:)
58 integer,
allocatable :: v_xz_count(:,:), v_xyz_count(:,:,:)
59 type(h5md_element_t) :: v_xz_el
65 double precision :: epsilon(n_species,n_species_colloids)
66 double precision :: sigma(n_species,n_species_colloids), sigma_cut(n_species,n_species_colloids)
67 double precision :: mass(n_species_colloids)
68 double precision :: max_cut
70 double precision :: v_com(3), wall_v(3,2), wall_t(2)
72 double precision :: e1, e2
73 double precision :: tau, dt , T, alpha
74 double precision :: skin, co_max, so_max
75 integer :: N_MD_steps, N_loop
76 integer :: vxz_interval
78 integer :: n_extra_sorting
79 double precision :: kin_e, temperature
81 type(h5md_file_t) :: hfile
82 type(h5md_element_t) :: dummy_element
83 integer(HID_T) :: fields_group
84 type(h5md_element_t) :: vx_el
85 type(thermo_t) :: thermo_data
86 type(particle_system_io_t) :: sphere_io
87 type(particle_system_io_t) :: solvent_io
88 integer(HID_T) :: box_group
91 integer :: L(3), n_threads
94 type(timer_t) :: flag_timer, change_timer, varia
95 integer(HID_T) :: timers_group
98 double precision :: k, trap_center(3)
102 args = get_input_args()
103 call ptparse(config, args%input_file, 11)
105 call flag_timer%init(
'flag')
106 call change_timer%init(
'change')
107 call varia%init(
'varia')
109 n_threads = omp_get_max_threads()
110 allocate(state(n_threads))
111 call threefry_rng_init(state, args%seed)
115 l = ptread_ivec(config,
'L', 3)
116 if (modulo(l(2),2) /= 0) error stop
'non-even Ly is not supported' 117 rho = ptread_i(config,
'rho')
118 n = rho *l(1)*l(2)*l(3)
119 tau =ptread_d(config,
'tau')
120 alpha = ptread_d(config,
'alpha')
122 n_md_steps = ptread_i(config,
'N_MD')
123 dt = tau / n_md_steps
124 n_loop = ptread_i(config,
'N_loop')
125 n_therm = ptread_i(config,
'N_therm')
126 vxz_interval = ptread_i(config,
'vxz_interval')
128 wall_t = ptread_dvec(config,
'wall_T', 2)
129 t = ptread_d(config,
'T')
131 k = ptread_d(config,
'k')
133 sigma = ptread_d(config,
'sigma')
134 epsilon = ptread_d(config,
'epsilon')
136 sigma_cut = sigma*2**(1.d0/6.d0)
137 max_cut = maxval(sigma_cut)
139 call solvent_colloid_lj% init(epsilon, sigma, sigma_cut)
141 mass(1) = rho * sigma(1,1)**3 * 4 * 3.14159265/3
143 call solvent% init(n,n_species)
145 move = ptread_l(config,
'move')
146 call colloids% init(1, n_species_colloids, mass)
147 colloids% species(1) = 1
150 call hfile%create(args%output_file,
'RMPCDMD::single_sphere_thermo_trap', &
151 rmpcdmd_revision,
'Pierre de Buyl')
152 call thermo_data%init(hfile, n_buffer=50, step=n_md_steps, time=n_md_steps*dt)
156 sphere_io%id_info%store = .false.
157 sphere_io%force_info%store = .true.
158 sphere_io%force_info%mode = ior(h5md_linear,h5md_store_time)
159 sphere_io%force_info%step = n_md_steps
160 sphere_io%force_info%time = n_md_steps*dt
161 sphere_io%position_info%store = .true.
162 sphere_io%position_info%mode = ior(h5md_linear,h5md_store_time)
163 sphere_io%position_info%step = n_md_steps
164 sphere_io%position_info%time = n_md_steps*dt
165 sphere_io%image_info%store = .true.
166 sphere_io%image_info%mode = ior(h5md_linear,h5md_store_time)
167 sphere_io%image_info%step = n_md_steps
168 sphere_io%image_info%time = n_md_steps*dt
169 sphere_io%velocity_info%store = .true.
170 sphere_io%velocity_info%mode = ior(h5md_linear,h5md_store_time)
171 sphere_io%velocity_info%step = n_md_steps
172 sphere_io%velocity_info%time = n_md_steps*dt
173 sphere_io%species_info%store = .true.
174 sphere_io%species_info%mode = h5md_fixed
175 call sphere_io%init(hfile,
'sphere', colloids)
177 solvent_io%force_info%store = .false.
178 solvent_io%id_info%store = .false.
179 solvent_io%position_info%store = .true.
180 solvent_io%position_info%mode = ior(h5md_linear,h5md_store_time)
181 solvent_io%position_info%step = n_loop*n_md_steps
182 solvent_io%position_info%time = n_loop*n_md_steps*dt
183 solvent_io%image_info%store = .true.
184 solvent_io%image_info%mode = ior(h5md_linear,h5md_store_time)
185 solvent_io%image_info%step = n_loop*n_md_steps
186 solvent_io%image_info%time = n_loop*n_md_steps*dt
187 solvent_io%velocity_info%store = .true.
188 solvent_io%velocity_info%mode = ior(h5md_linear,h5md_store_time)
189 solvent_io%velocity_info%step = n_loop*n_md_steps
190 solvent_io%velocity_info%time = n_loop*n_md_steps*dt
191 solvent_io%species_info%store = .true.
192 solvent_io%species_info%mode = ior(h5md_linear,h5md_store_time)
193 solvent_io%species_info%step = n_loop*n_md_steps
194 solvent_io%species_info%time = n_loop*n_md_steps*dt
195 call solvent_io%init(hfile,
'solvent', solvent)
199 call solvent_cells%init(l, 1.d0, has_walls=.true.)
201 trap_center = solvent_cells%edges/2
202 colloids%pos(:,1) = trap_center
206 call vx% init(0.d0, solvent_cells% edges(3), l(3))
207 call tz% init(0.d0, solvent_cells% edges(3), l(3))
208 call rhoz% init(0.d0, solvent_cells% edges(3), l(3))
210 allocate(v_xz_count(l(3), l(1)))
211 allocate(v_xyz_count(l(3), l(2), l(1)))
212 allocate(v_xz(2, l(3), l(1)))
213 allocate(v_xyz(3, l(3), l(2), l(1)))
215 call h5gcreate_f(hfile%id,
'fields', fields_group, error)
216 call vx_el%create_time(fields_group,
'vx', vx%data, ior(h5md_linear,h5md_store_time), &
217 step=n_md_steps, time=n_md_steps*dt)
218 call elem_tz% create_time(fields_group,
'tz', tz% data, ior(h5md_time, h5md_store_time))
219 call elem_tz_count% create_time(fields_group,
'tz_count', tz% count, ior(h5md_time, h5md_store_time))
220 call elem_rhoz% create_time(fields_group,
'rhoz', rhoz% data, ior(h5md_time, h5md_store_time))
221 call v_xz_el%create_time(fields_group,
'v_xz', v_xz, ior(h5md_time, h5md_store_time))
223 call h5gcreate_f(sphere_io%group,
'box', box_group, error)
224 call h5md_write_attribute(box_group,
'dimension', 3)
225 call dummy_element%create_fixed(box_group,
'edges', solvent_cells%edges)
226 call h5gclose_f(box_group, error)
228 call h5gcreate_f(solvent_io%group,
'box', box_group, error)
229 call h5md_write_attribute(box_group,
'dimension', 3)
230 call dummy_element%create_fixed(box_group,
'edges', solvent_cells%edges)
231 call h5gclose_f(box_group, error)
233 call solvent% random_placement(solvent_cells% edges, colloids, solvent_colloid_lj, state(1))
234 solvent% pos_old = solvent% pos
236 do i=1, solvent% Nmax
237 solvent% vel(1,i) = threefry_normal(state(1))*sqrt(t)
238 solvent% vel(2,i) = threefry_normal(state(1))*sqrt(t)
239 solvent% vel(3,i) = threefry_normal(state(1))*sqrt(t)
242 call solvent% sort(solvent_cells)
245 call neigh% init(colloids% Nmax, 25*floor((max_cut+skin)**2)*rho)
249 call neigh% make_stencil(solvent_cells, max_cut+skin+0.1)
250 call neigh% update_list(colloids, solvent, max_cut+skin, solvent_cells)
254 e1 = compute_force(colloids, solvent, neigh, solvent_cells% edges, solvent_colloid_lj)
256 solvent% force_old = solvent% force
257 colloids% force_old = colloids% force
266 write(*,*)
'Running for', n_loop+n_therm,
'loops' 268 setup:
do i = 1, n_loop+n_therm
269 if (modulo(i,50) == 0)
write(*,
'(i09)',advance=
'no') i
270 md_loop:
do j = 1, n_md_steps
271 call mpcd_stream_nogravity_zwall(solvent, solvent_cells, dt)
274 if (move) colloids% pos = colloids% pos + dt * colloids% vel + &
275 dt**2 * colloids% force / (2*colloids% mass(1))
277 so_max = solvent% maximum_displacement()
278 co_max = colloids% maximum_displacement()
280 if ( (co_max >= skin*0.1) .or. (so_max >= skin*0.9) )
then 281 call apply_pbc(colloids, solvent_cells% edges)
282 call apply_pbc(solvent, solvent_cells% edges)
283 call solvent% sort(solvent_cells)
284 call neigh% update_list(colloids, solvent, max_cut+skin, solvent_cells)
286 solvent% pos_old = solvent% pos
287 colloids% pos_old = colloids% pos
289 n_extra_sorting = n_extra_sorting + 1
292 call switch(solvent% force, solvent% force_old)
293 call switch(colloids% force, colloids% force_old)
296 do ijk = 1, solvent%Nmax
297 solvent% force(:,ijk) = 0
300 e1 = compute_force(colloids, solvent, neigh, solvent_cells% edges, solvent_colloid_lj)
303 call md_vel(solvent, dt)
304 if (move) colloids% vel = colloids% vel + &
305 dt * ( colloids% force + colloids% force_old ) / (2 * colloids% mass(1))
309 call solvent_cells%random_shift(state(1))
311 call apply_pbc(colloids, solvent_cells% edges)
312 call apply_pbc(solvent, solvent_cells% edges)
313 call solvent% sort(solvent_cells)
314 call neigh% update_list(colloids, solvent, max_cut+skin, solvent_cells)
315 solvent%pos_old = solvent% pos
316 colloids%pos_old = colloids% pos
319 call wall_mpcd_step(solvent, solvent_cells, state, &
320 wall_temperature=wall_t, wall_v=wall_v, wall_n=[rho, rho], alpha=alpha)
323 temperature = compute_temperature(solvent, solvent_cells, tz)
324 kin_e = colloids% mass(1)*sum(colloids% vel(:,1)**2)/2 + &
325 sum(solvent% vel**2)/2
326 v_com = (sum(solvent% vel, dim=2) + mass(1)*colloids%vel(:,1)) / (solvent%Nmax + mass(1))
327 call thermo_data%append(hfile, temperature, e1, kin_e, e1+kin_e, v_com)
328 call compute_rho(solvent, rhoz)
331 call compute_vx(solvent, vx)
333 call vx_el%append(vx%data)
336 call elem_tz% append(tz% data, i, i*tau)
337 call elem_tz_count% append(tz% count, i, i*tau)
339 rhoz% data = rhoz% data / rhoz% dx
340 call elem_rhoz% append(rhoz% data, i, i*tau)
343 if (modulo(i-n_therm, vxz_interval)==0)
then 345 call v_xz_el%append(v_xz, i, i*tau)
351 call sphere_io%position%append(colloids%pos)
352 call sphere_io%velocity%append(colloids%vel)
353 call sphere_io%force%append(colloids%force)
354 call sphere_io%image%append(colloids%image)
359 call thermo_data%append(hfile, temperature, e1+e2, kin_e, e1+e2+kin_e, v_com, add=.false., force=.true.)
362 write(*,*)
'n extra sorting', n_extra_sorting
364 call solvent_io%position%append(solvent%pos)
365 call solvent_io%velocity%append(solvent%vel)
366 call solvent_io%image%append(solvent%image)
367 call solvent_io%species%append(solvent%species)
370 call dummy_element%create_fixed(fields_group,
'v_xyz', v_xyz)
371 call h5gclose_f(fields_group, error)
373 call h5gcreate_f(hfile%id,
'timers', timers_group, error)
374 call h5md_write_dataset(timers_group, solvent%time_stream%name, solvent%time_stream%total)
375 call h5md_write_dataset(timers_group, solvent%time_md_vel%name, solvent%time_md_vel%total)
376 call h5md_write_dataset(timers_group, solvent%time_step%name, solvent%time_step%total)
377 call h5md_write_dataset(timers_group, solvent%time_count%name, solvent%time_count%total)
378 call h5md_write_dataset(timers_group, solvent%time_sort%name, solvent%time_sort%total)
379 call h5md_write_dataset(timers_group, solvent%time_ct%name, solvent%time_ct%total)
380 call h5md_write_dataset(timers_group, solvent%time_max_disp%name, solvent%time_max_disp%total)
381 call h5md_write_dataset(timers_group, solvent%time_apply_pbc%name, solvent%time_apply_pbc%total)
382 call h5md_write_dataset(timers_group, neigh%time_update%name, neigh%time_update%total)
383 call h5md_write_dataset(timers_group, varia%name, varia%total)
384 call h5md_write_dataset(timers_group, neigh%time_force%name, neigh%time_force%total)
386 call h5md_write_dataset(timers_group,
'total', solvent%time_stream%total + &
387 solvent%time_step%total + solvent%time_count%total + solvent%time_sort%total + &
388 solvent%time_ct%total + solvent%time_md_vel%total + solvent%time_max_disp%total + &
389 flag_timer%total + change_timer%total + solvent%time_apply_pbc%total+ &
390 neigh%time_update%total + varia%total + neigh%time_force%total)
392 call h5gclose_f(timers_group, error)
395 call elem_tz_count%close()
396 call elem_rhoz%close()
397 call sphere_io%close()
399 call h5close_f(error)
404 type(particle_system_t),
intent(inout) :: p
405 double precision,
intent(in) :: k, x0(3)
406 double precision :: e
412 p%force(:,i) = p%force(:,i) - k * (p%pos(:,i)-x0)
413 e = e + k * sum( (p%pos(:,i)-x0)**2 ) / 2
421 integer :: cell_idx, n, start, wall_idx, cell(3)
422 double precision :: local_v(3), local_k, local_T, factor
424 do cell_idx = 1, solvent_cells% N
425 if (solvent_cells% cell_count(cell_idx) <= 1) cycle
427 start = solvent_cells% cell_start(cell_idx)
428 n = solvent_cells% cell_count(cell_idx)
431 cell = compact_h_to_p(cell_idx - 1, solvent_cells% M) + 1
432 if (cell(3) == 1)
then 434 else if (cell(3) == solvent_cells% L(3))
then 440 if (wall_idx==-1) cycle
441 local_t = wall_t(wall_idx)
444 do i = start, start + n - 1
445 local_v = local_v + solvent% vel(:, i)
447 local_v = local_v / n
450 do i = start, start + n - 1
451 local_k = local_k + sum((solvent% vel(:, i)-local_v)**2)/2
453 local_k = local_k/(3*(n-1))
454 factor = sqrt(local_t/(2*local_k))
456 do i = start, start + n - 1
457 solvent% vel(:, i) = local_v + factor*(solvent% vel(:, i)-local_v)
465 integer :: i, s, ix, iy, iz
467 do i = 1, solvent%Nmax
468 s = solvent%species(i)
470 ix = modulo(floor(solvent%pos(1,i)/solvent_cells%a), l(1)) + 1
471 iy = modulo(floor(solvent%pos(2,i)/solvent_cells%a), l(2)) + 1
472 iz = modulo(floor(solvent%pos(3,i)/solvent_cells%a), l(3)) + 1
473 v_xyz_count(iz, iy, ix) = v_xyz_count(iz, iy, ix) + 1
474 v_xyz(:, iz, iy, ix) = v_xyz(:, iz, iy, ix) + solvent%vel(:, i)
475 if ( (iy == l(2)/2) .or. (iy == 1+l(2)/2) )
then 476 v_xz_count(iz, ix) = v_xz_count(iz, ix) + 1
477 v_xz(1, iz, ix) = v_xz(1, iz, ix) + solvent%vel(1, i)
478 v_xz(2, iz, ix) = v_xz(2, iz, ix) + solvent%vel(3, i)
489 if (v_xz_count(j, i) > 0)
then 490 v_xz(:, j, i) = v_xz(:, j, i) / v_xz_count(j, i)
503 if (v_xyz_count(k, j, i) > 0)
then 504 v_xyz(:, k, j, i) = v_xyz(:, k, j, i) / v_xyz_count(k, j, i)
double precision function compute_force_harmonic_trap(p, k, x0)
subroutine rescale_at_walls
subroutine compute_vxz_and_vxyz
program single_sphere_thermo_trap
Simulate a thermal gradient with an embedded colloidal sphere.