Coverage for examples/LJchain.py: 98%
85 statements
« prev ^ index » next coverage.py v7.9.1, created at 2025-06-14 15:55 +0200
« prev ^ index » next coverage.py v7.9.1, created at 2025-06-14 15:55 +0200
1""" Example of a simulation of a Lennard-Jones chain with 10 beads per chain """
3import h5py
4import matplotlib.pyplot as plt
5import numpy as np
6import pandas as pd
8import gamdpy as gp
10# Generate configuration with a FCC lattice
11rho = 1.0
12configuration = gp.Configuration(D=3, compute_flags={'Fsq':True, 'lapU':True, 'Vol':True})
13configuration.make_positions(N=2000, rho=rho)
14configuration['m'] = 1.0
15configuration.randomize_velocities(temperature=1.44)
17# Make bonds
18bond_potential = gp.harmonic_bond_function
19bond_params = [[1.00, 3000.], ]
20bond_indices = [[i, i + 1, 0] for i in range(0, configuration.N - 1, 1) if
21 i % 10 != 9] # 10 bead chains (last molecule: N % 10)
22bonds = gp.Bonds(bond_potential, bond_params, bond_indices)
24# Make pair potential
25pair_func = gp.apply_shifted_force_cutoff(gp.LJ_12_6_sigma_epsilon)
26sig, eps, cut = 1.0, 1.0, 2.5
27exclusions = bonds.get_exclusions(configuration)
28pair_pot = gp.PairPotential(pair_func, params=[sig, eps, cut], exclusions=exclusions, max_num_nbs=1000)
30# Define molecules (to be implemented)
31molecules_A = [np.arange(0, 10) + j for j in range(0, configuration.N // 2, 10)]
32molecules_B = [np.arange(0, 10) + j for j in range(configuration.N // 2, configuration.N, 10)]
33# molecules = Molecules([molecules_A, molecules_B], names=['H2O', 'Hexaflourobenzene'])
34# molecules.check_identical() # Maybe make check in __init__ and print warning if not all molecules of a type are identical
35# molecules.get_numbe_particles()
36# molecules.get_resulting_force() # Requires atomic forces to be calculated
37#print(molecules_A[:3])
40# Make integrator
41dt = 0.002 # timestep
42num_blocks = 16 # Do simulation in this many 'blocks'
43steps_per_block = 2048 # ... each of this many steps
44running_time = dt * num_blocks * steps_per_block
45temperature = 0.7
46filename = 'Data/LJchain10_Rho1.00_T0.700.h5'
47Ttarget_function = gp.make_function_ramp(value0=10.000, x0=running_time * (1 / 8),
48 value1=temperature, x1=running_time * (1 / 4))
49integrator0 = gp.integrators.NVT(Ttarget_function, tau=0.2, dt=dt)
51compute_plan = gp.get_default_compute_plan(configuration)
52print(compute_plan)
54runtime_actions = [gp.MomentumReset(100),
55 gp.TrajectorySaver(),
56 gp.ScalarSaver(32, {'Fsq':True, 'lapU':True}), ]
59sim = gp.Simulation(configuration, [pair_pot, bonds], integrator0, runtime_actions,
60 num_timeblocks=num_blocks, steps_per_timeblock=steps_per_block,
61 compute_plan=compute_plan, storage=filename)
63print('High Temperature followed by cooling and equilibration:')
64for block in sim.run_timeblocks():
65 if block % 10 == 0:
66 print(f'{block=:4} {sim.status(per_particle=True)}')
67print(sim.summary())
69integrator = gp.integrators.NVT(temperature=temperature, tau=0.2, dt=dt)
70sim = gp.Simulation(configuration, [pair_pot, bonds], integrator, runtime_actions,
71 num_timeblocks=num_blocks, steps_per_timeblock=steps_per_block,
72 compute_plan=compute_plan, storage=filename)
74# Setup on-the-fly calculation of Radial Distribution Function
75calc_rdf = gp.CalculatorRadialDistribution(configuration, bins=1000)
77print('Production:')
78for block in sim.run_timeblocks():
79 if block % 10 == 0:
80 print(f'{block=:4} {sim.status(per_particle=True)}')
81 calc_rdf.update()
82print(sim.summary())
84columns = ['U', 'W', 'K', 'lapU', 'Fsq', 'Vol']
85with h5py.File(filename, "r") as f:
86 data = np.array(gp.extract_scalars(f, columns, first_block=1))
87df = pd.DataFrame(data.T, columns=columns)
88df['t'] = np.arange(len(df['U'])) * dt * sim.output['scalar_saver'].attrs["steps_between_output"]
89gp.plot_scalars(df, configuration.N, configuration.D, figsize=(10, 8), block=False)
91mu = np.mean(df['U']) / configuration.N
92mw = np.mean(df['W']) / configuration.N
93cvex = np.var(df['U']) / temperature ** 2 / configuration.N
95print('gamdpy:')
96print(f'Potential energy: {mu:.4f}')
97print(f'Excess heat capacity: {cvex:.3f}')
98print(f'Virial {mw:.4f}')
100with h5py.File(filename, "r") as f:
101 dynamics = gp.tools.calc_dynamics(f, first_block=0, qvalues=[7.118])
102fig, axs = plt.subplots(3, 1, figsize=(8, 9), sharex=True)
103fig.subplots_adjust(hspace=0.00) # Remove vertical space between axes
104axs[0].set_ylabel('MSD')
105axs[1].set_ylabel('Non Gaussian parameter')
106axs[2].set_ylabel('Intermediate scattering function')
107axs[2].set_xlabel('Time')
108axs[0].grid(linestyle='--', alpha=0.5)
109axs[1].grid(linestyle='--', alpha=0.5)
110axs[2].grid(linestyle='--', alpha=0.5)
112axs[0].loglog(dynamics['times'], dynamics['msd'], 'o--')
113axs[1].semilogx(dynamics['times'], dynamics['alpha2'], 'o--')
114axs[2].semilogx(dynamics['times'], dynamics['Fs'], 'o--')
115if __name__ == "__main__":
116 plt.show(block=False)
118rdf = calc_rdf.read()
119rdf['rdf'] = np.mean(rdf['rdf'], axis=0)
120fig, axs = plt.subplots(1, 1, figsize=(8, 4))
121axs.set_ylabel('RDF')
122axs.set_xlabel('Distance')
123axs.grid(linestyle='--', alpha=0.5)
124axs.plot(rdf['distances'], rdf['rdf'], '-')
125axs.set_xlim((0.5, 3.5))
126if __name__ == "__main__":
127 plt.show(block=True)