@@ -30,31 +30,34 @@ vector direction between atoms pairs will have to be written here.
3030Implement the Virial equation
3131-----------------------------
3232
33- Let us add the following method to the *Utilities * class.
33+ Let us add the following method to the *Measurements * class.
3434
35- .. label :: start_Utilities_class
35+ .. label :: start_Measurements_class
3636
3737.. code-block :: python
3838
3939 def calculate_pressure (self ):
4040 """ Evaluate p based on the Virial equation (Eq. 4.4.2 in Frenkel-Smit,
4141 Understanding molecular simulation: from algorithms to applications, 2002)"""
4242 # Compute the ideal contribution
43- Ndof = self .dimensions* self .total_number_atoms- self .dimensions
44- volume = np.prod(self .box_size[:self .dimensions])
43+ Nat = np.sum(self .number_atoms) # total number of atoms
44+ dimension = 3 # 3D is the only possibility here
45+ Ndof = dimension* Nat- dimension
46+ volume = np.prod(self .box_size[:3 ]) # box volume
4547 try :
4648 self .calculate_temperature() # this is for later on, when velocities are computed
4749 temperature = self .temperature
4850 except :
4951 temperature = self .desired_temperature # for MC, simply use the desired temperature
50- p_ideal = Ndof* temperature/ (volume* self .dimensions )
52+ p_ideal = Ndof* temperature/ (volume* dimension )
5153 # Compute the non-ideal contribution
52- distances_forces = np.sum(self .compute_force(return_vector = False )* self .evaluate_rij_matrix())
53- p_nonideal = distances_forces/ (volume* self .dimensions)
54+ distances_forces = np.sum(self .compute_force(return_vector = False ) \
55+ * self .evaluate_rij_matrix())
56+ p_nonideal = distances_forces/ (volume* dimension)
5457 # Final pressure
5558 self .pressure = p_ideal+ p_nonideal
5659
57- .. label :: end_Utilities_class
60+ .. label :: end_Measurements_class
5861
5962To evaluate all the vectors between all the particles, let us also add the
6063*evaluate_rij_matrix * method to the *Utilities * class:
@@ -65,95 +68,75 @@ To evaluate all the vectors between all the particles, let us also add the
6568
6669 def evaluate_rij_matrix (self ):
6770 """ Matrix of vectors between all particles."""
68- box_size = self .box_size[: 3 ]
69- half_box_size = self .box_size[:3 ]/ 2.0
70- rij_matrix = np.zeros((self .total_number_atoms, self .total_number_atoms ,3 ))
71- positions_j = self .atoms_positions
72- for Ni in range (self .total_number_atoms - 1 ):
73- position_i = self .atoms_positions[Ni]
74- rij_xyz = (np.remainder(position_i - positions_j + half_box_size, box_size ) - half_box_size )
71+ Nat = np.sum( self .number_atoms)
72+ Box = self .box_size[:3 ]
73+ rij_matrix = np.zeros((Nat, Nat ,3 ))
74+ pos_j = self .atoms_positions
75+ for Ni in range (Nat - 1 ):
76+ pos_i = self .atoms_positions[Ni]
77+ rij_xyz = (np.remainder(pos_i - pos_j + Box / 2.0 , Box ) - Box / 2.0 )
7578 rij_matrix[Ni] = rij_xyz
76- # use nan_to_num to avoid "nan" values in 2D
77- return np.nan_to_num(rij_matrix)
79+ return rij_matrix
7880
7981 .. label :: end_Utilities_class
8082
8183Test the code
8284-------------
8385
84- Let us test the outputed pressure. An interesting test is to contront the output from
85- our code with some data from the litterature. Let us used the same parameters
86- as in Ref. :cite: `woodMonteCarloEquation1957 `, where Monte Carlo simulations
87- are used to simulate argon bulk phase. All we have to do is to apply our current
88- code using their parameters, i.e. :math: `\sigma = 3.405 ~\text {Å}`, :math: `\epsilon = 0.238 ~\text {kcal/mol}`,
89- and :math: `T = 55 ~^\circ \text {C}`. More details are given in the first illustration, :ref: `project1-label `.
90-
91- On the side note, a relatively small cut-off as well as a small number of atoms were
92- chosen to make the calculation faster.
86+ Let us test the outputed pressure.
9387
9488.. label :: start_test_7a_class
9589
9690.. code-block :: python
9791
98- import numpy as np
9992 from MonteCarlo import MonteCarlo
100- from scipy import constants as cst
10193 from pint import UnitRegistry
102- from reader import import_data
103-
104- # Initialize the unit registry
10594 ureg = UnitRegistry()
106-
107- # Constants
108- kB = cst.Boltzmann * ureg.J / ureg.kelvin # Boltzmann constant
109- Na = cst.Avogadro / ureg.mole # Avogadro's number
110- R = kB * Na # Gas constant
111-
112- # Parameters taken from Wood1957
113- tau = 2 # Ratio between volume / reduced volume
114- epsilon = (119.76 * ureg.kelvin * kB * Na).to(ureg.kcal / ureg.mol) # kcal/mol
115- r_star = 3.822 * ureg.angstrom # Angstrom
116- sigma = r_star / 2 ** (1 / 6 ) # Angstrom
117- N_atom = 50 # Number of atoms
118- m_argon = 39.948 * ureg.gram / ureg.mol # g/mol
119- T = 328.15 * ureg.degK # 328 K or 55°C
120- volume_star = r_star** 3 * Na * 2 ** (- 0.5 )
121- cut_off = sigma * 2.5 # Angstrom
122- displace_mc = sigma / 5 # Angstrom
123- volume = N_atom * volume_star * tau / Na # Angstrom^3
124- box_size = volume** (1 / 3 ) # Angstrom
125-
126- # Initialize and run the Monte Carlo simulation
95+ import os
96+
97+ # Define atom number of each group
98+ nmb_1= 50
99+ # Define LJ parameters (sigma)
100+ sig_1 = 3 * ureg.angstrom
101+ # Define LJ parameters (epsilon)
102+ eps_1 = 0.1 * ureg.kcal/ ureg.mol
103+ # Define atom mass
104+ mss_1 = 10 * ureg.gram/ ureg.mol
105+ # Define box size
106+ L = 20 * ureg.angstrom
107+ # Define a cut off
108+ rc = 2.5 * sig_1
109+ # Pick the desired temperature
110+ T = 300 * ureg.kelvin
111+ # choose the displace_mc
112+ displace_mc = sig_1/ 4
113+
114+ # Initialize the prepare object
127115 mc = MonteCarlo(
128- maximum_steps = 15000 ,
129- dumping_period = 1000 ,
130- thermo_period = 1000 ,
116+ ureg = ureg,
117+ maximum_steps = 100 ,
118+ thermo_period = 10 ,
119+ dumping_period = 10 ,
120+ number_atoms = [nmb_1],
121+ epsilon = [eps_1], # kcal/mol
122+ sigma = [sig_1], # A
123+ atom_mass = [mss_1], # g/mol
124+ box_dimensions = [L, L, L], # A
125+ cut_off = rc,
131126 thermo_outputs = " Epot-press" ,
132- neighbor = 50 ,
133- number_atoms = [N_atom],
134- epsilon = [epsilon.magnitude],
135- sigma = [sigma.magnitude],
136- atom_mass = [m_argon.magnitude],
137- box_dimensions = [box_size.magnitude, box_size.magnitude, box_size.magnitude],
138- displace_mc = displace_mc.magnitude,
139- desired_temperature = T.magnitude,
140- cut_off = cut_off.magnitude,
141- data_folder = " Outputs/" ,
127+ desired_temperature = T, # K
128+ neighbor = 20 ,
129+ displace_mc = displace_mc,
142130 )
131+
132+ # Run the Monte Carlo simulation
143133 mc.run()
144134
145135 # Test function using pytest
146- def test_pV_over_RT ():
147- # Import the data and calculate pV / RT
148- pressure_data = np.array(import_data(" Outputs/simulation.log" )[1 :])[0 ][:,2 ][10 :] # Skip initial values
149- pressure_atm = np.mean(pressure_data) # atm
150- pressure_Pa = (pressure_atm * ureg.atm).to(ureg.pascal) # Pa
151- volume = (volume_star * tau / Na).to(ureg.meter** 3 ) # m3
152- pV_over_RT = (pressure_Pa * volume / (R * T) * Na).magnitude
153-
154- # Assert that pV_over_RT is close to 1.5
155- assert np.isclose(pV_over_RT, 1.5 , atol = 1.0 ), f " Test failed: pV/Rt = { pV_over_RT} , expected close to 1.5 "
156- print (f " pV/RT = { pV_over_RT:.2f } --- (The expected value from Wood1957 is 1.5) " )
136+ def test_output_files ():
137+ assert os.path.exists(" Outputs/dump.mc.lammpstrj" ), " Test failed: dump file was not created"
138+ assert os.path.exists(" Outputs/simulation.log" ), " Test failed: log file was not created"
139+ print (" Test passed" )
157140
158141 # If the script is run directly, execute the tests
159142 if __name__ == " __main__" :
@@ -162,13 +145,3 @@ chosen to make the calculation faster.
162145 pytest.main([" -s" , __file__ ])
163146
164147 .. label :: end_test_7a_class
165-
166- Which should return a value for :math: `p V / R T` that is close to the expected value
167- of 1.5 by Wood and Parker for :math: `\tau = V/V^* = 2 ` (see Fig. 4 in Ref. :cite: `woodMonteCarloEquation1957 `):
168-
169- .. code-block :: bw
170-
171- (...)
172- p v / R T = 1.56 --- (The expected value from Wood1957 is 1.5)
173-
174- The exact value will vary from one simulation to the other due to noise.
0 commit comments