diff --git a/README.md b/README.md index e1c3186..1da2892 100644 --- a/README.md +++ b/README.md @@ -51,6 +51,7 @@ expertise in these fields. #### Contributors - [Jake Anderson](https://github.com/jaketanderson) +- [Kenneth Ngo](https://github.com/KennethQNgo) ### Acknowledgments and license diff --git a/docs/source/chapters/chapter1.rst b/docs/source/chapters/chapter1.rst index 632d616..d6ca95d 100644 --- a/docs/source/chapters/chapter1.rst +++ b/docs/source/chapters/chapter1.rst @@ -325,8 +325,8 @@ any *AssertionError*: .. code-block:: bw - Utilities does not inherit from MonteCarlo, as expected MonteCarlo correctly inherits from Utilities + Utilities does not inherit from MonteCarlo, as expected Alternatively, this test can also be launched using *Pytest* by typing in a terminal: diff --git a/docs/source/chapters/chapter2.rst b/docs/source/chapters/chapter2.rst index 0e3dcd5..8c79a70 100644 --- a/docs/source/chapters/chapter2.rst +++ b/docs/source/chapters/chapter2.rst @@ -4,9 +4,9 @@ Setting Up the Simulation ========================== To streamline the simulation process, all user-specified parameters will be -non-dimensionalized. By removing units from the calculations, we simplify -complex operations like force evaluation, making the code more efficient and -easier to manage. This non-dimensionalization is handled within the *Prepare* +nondimensionalized. By removing units from the calculations, we simplify +complex operations like force evaluation, making the code more efficient, and +easier to manage. This nondimensionalization is handled within the *Prepare* class. While this step may not be the most thrilling aspect of the simulation, it is @@ -80,7 +80,7 @@ Four atom parameters are provided to the *Prepare* class: - the LJ parameters :math:`\sigma` and :math:`\epsilon`, - and the number of atoms. -All these quantities must be supplied as lists. This will be useful later when +All these quantities must be provided as lists of values. This will be useful later when we want to mix atoms of different types within the same simulation box. Modify the *Prepare* class as follows: diff --git a/docs/source/chapters/chapter4.rst b/docs/source/chapters/chapter4.rst index e471092..66a2e2a 100644 --- a/docs/source/chapters/chapter4.rst +++ b/docs/source/chapters/chapter4.rst @@ -82,13 +82,13 @@ following *run()* method to the *MinimizeEnergy* class: self.displacement = 0.01 # pick a random initial displacement (dimentionless) # *step* loops for 0 to *maximum_steps*+1 for self.step in range(0, self.maximum_steps+1): - # First, meevaluate the initial energy and max force + # First, evaluate the initial energy and max force self.update_neighbor_lists() # Rebuild neighbor list, if necessary self.update_cross_coefficients() # Recalculate the cross coefficients, if necessary # Compute Epot/MaxF/force - if hasattr(self, 'Epot') is False: # If self.Epot does not exists yet, calculate it + if hasattr(self, 'Epot') is False: # If self.Epot does not exist yet, calculate it self.Epot = self.compute_potential() - if hasattr(self, 'MaxF') is False: # If self.MaxF does not exists yet, calculate it + if hasattr(self, 'MaxF') is False: # If self.MaxF does not exist yet, calculate it forces = self.compute_force() self.MaxF = np.max(np.abs(forces)) init_Epot = self.Epot diff --git a/docs/source/chapters/chapter5.rst b/docs/source/chapters/chapter5.rst index 3c04c34..3593c99 100644 --- a/docs/source/chapters/chapter5.rst +++ b/docs/source/chapters/chapter5.rst @@ -12,11 +12,11 @@ VMD :cite:`humphrey1996vmd` or Ovito :cite:`stukowski2009visualization`. Create logger ------------- -Let us create a function named *log_simulation_data()* to a file named *logger.py*. -With the logger, some output are being printed in a file, as well as in the terminal. +Let us create a function named *log_simulation_data()* in a file named *logger.py*. +With the logger, various outputs are being printed to a file, as well as to the terminal. The period of printing, which is a multiple of the simulation steps, will be set by a new parameter named *thermo_period* (integer). All quantities are -converted into *real* units before getting outputed (see :ref:`chapter2-label`). +converted into *real* units before getting outputted (see :ref:`chapter2-label`). .. label:: start_logger_class @@ -56,7 +56,7 @@ converted into *real* units before getting outputed (see :ref:`chapter2-label`). return logger def log_simulation_data(code): - # TOFIX: ceurrently, MaxF is returned dimensionless + # TOFIX: currently, MaxF is returned dimensionless # Setup the logger with the folder name, overwriting the log if code.step is 0 logger = setup_logger(code.data_folder, overwrite=(code.step == 0)) @@ -87,10 +87,10 @@ converted into *real* units before getting outputed (see :ref:`chapter2-label`). .. label:: end_logger_class -For simplicify, the *logger* uses the |logging| library, which provides a +For simplicity, the *logger* uses the |logging| library, which provides a flexible framework for emitting log messages from Python programs. Depending on -the value of *thermo_outputs*, different informations are printed, such as -*step*, *Epot*, or/and *MaxF*. +the value of *thermo_outputs*, different information are printed, such as +*step*, *Epot*, and/or *MaxF*. .. |logging| raw:: html @@ -185,7 +185,7 @@ Add the same lines at the top of the *MinimizeEnergy.py* file: .. label:: end_MinimizeEnergy_class Finally, let us make sure that *thermo_period*, *dumping_period*, and *thermo_outputs* -parameters are passed the InitializeSimulation method: +parameters are passed to the InitializeSimulation method: .. label:: start_InitializeSimulation_class @@ -244,7 +244,7 @@ during energy minimization. Test the code ------------- -One can use a test similar as the previous ones. Let us ask our code to print +One can use a test similar to the previous ones. Let us ask our code to print information in the *dump* and the *log* files, and then let us assert that the files were indeed created without the *Outputs/* folder: @@ -316,10 +316,10 @@ simulation. The content of the *simulation.log* file should resemble: 75 -1.22 3.77 100 -2.10 1.28 -The data from the *simulation.log* can be used to generate plots using softwares -line XmGrace, GnuPlot, or Python/Pyplot. For the later, one can use a simple data +The data from the *simulation.log* can be used to generate plots using software +like XmGrace, GnuPlot, or Python/Pyplot. For the latter, one can use a simple data reader to import the data from *simulation.log* into Python. Copy the -following lines in a new file named *reader.py*: +following lines into a new file named *reader.py*: .. label:: start_reader_class diff --git a/docs/source/chapters/chapter6.rst b/docs/source/chapters/chapter6.rst index c5dc7fa..1a4e91e 100644 --- a/docs/source/chapters/chapter6.rst +++ b/docs/source/chapters/chapter6.rst @@ -51,11 +51,11 @@ Let us add a method named *monte_carlo_move* to the *MonteCarlo* class: # When needed, recalculate neighbor/coeff lists self.update_neighbor_lists() self.update_cross_coefficients() - # If self.Epot does not exists yet, calculate it + # If self.Epot does not exist yet, calculate it # It should only be necessary when step = 0 if hasattr(self, 'Epot') is False: self.Epot = self.compute_potential() - # Make a copy of the initial atoms positions and initial energy + # Make a copy of the initial atom positions and initial energy initial_Epot = self.Epot initial_positions = copy.deepcopy(self.atoms_positions) # Pick an atom id randomly diff --git a/docs/source/chapters/chapter7.rst b/docs/source/chapters/chapter7.rst index 0d0a8e8..dab514e 100644 --- a/docs/source/chapters/chapter7.rst +++ b/docs/source/chapters/chapter7.rst @@ -85,7 +85,7 @@ To evaluate all the vectors between all the particles, let us also add the Test the code ------------- -Let us test the outputed pressure. +Let us test the outputted pressure. .. label:: start_test_7a_class diff --git a/docs/source/chapters/chapter8.rst b/docs/source/chapters/chapter8.rst index 9148e43..c1edf85 100644 --- a/docs/source/chapters/chapter8.rst +++ b/docs/source/chapters/chapter8.rst @@ -5,13 +5,13 @@ Monte Carlo insert Here, a *Monte Carlo* simulation is implemented in the Grand Canonical ensemble, where the number of atoms in the system fluctuates. The principle of the -simulation resemble the Monte Carlo move from :ref:`chapter6-label`: +simulation resembles the Monte Carlo move from :ref:`chapter6-label`: -- 1) We start from a given intial configuration, and measure the potential +- 1) We start from a given initial configuration, and measure the potential energy, :math:`E_\text{pot}^\text{initial}`. - 2) A random number is chosen, and depending on its value, either a new particle - will tried to be inserted, or an existing particle will tried to be deleted. -- 3) The energy of the system after the insersion/deletion, + will try to be inserted, or an existing particle will try to be deleted. +- 3) The energy of the system after the insertion/deletion, :math:`E_\text{pot}^\text{trial}`, is measured. - 4) We then decide to keep or reject the move by calculating the difference in energy between the trial and the initial configurations: @@ -97,7 +97,7 @@ Then, let us write the *monte_carlo_insert()* method: trial_Epot = self.compute_potential() Lambda = self.calculate_Lambda(self.atom_mass[self.inserted_type]) beta = 1/self.desired_temperature - Nat = np.sum(self.number_atoms) # NUmber atoms, should it relly be N? of N (type) ? + Nat = np.sum(self.number_atoms) # Number atoms, should it really be N? of N (type) ? Vol = np.prod(self.box_size[:3]) # box volume # dimension of 3 is enforced in the power of the Lambda self.acceptation_probability = np.min([1, Vol/(Lambda**3*Nat) \ @@ -129,7 +129,7 @@ Let us add the very similar *monte_carlo_delete()* method: trial_Epot = self.compute_potential() Lambda = self.calculate_Lambda(self.atom_mass[self.inserted_type]) beta = 1/self.desired_temperature - Nat = np.sum(self.number_atoms) # NUmber atoms, should it relly be N? of N (type) ? + Nat = np.sum(self.number_atoms) # Number atoms, should it really be N? of N (type) ? Vol = np.prod(self.box_size[:3]) # box volume # dimension of 3 is enforced in the power of the Lambda self.acceptation_probability = np.min([1, (Lambda**3 *(Nat-1)/Vol) \ @@ -145,7 +145,7 @@ Complete the *__init__* method as follows: .. code-block:: python - class MonteCarlo(Outputs): + class MonteCarlo(Measurements): def __init__(self, (...) displace_mc = None, @@ -160,7 +160,7 @@ and .. code-block:: python - class MonteCarlo(Outputs): + class MonteCarlo(Measurements): def __init__(self, (...) self.displace_mc = displace_mc @@ -169,7 +169,7 @@ and .. label:: end_MonteCarlo_class -Let us also normalised the "desired_mu": +Let us also normalize the "desired_mu": .. label:: start_MonteCarlo_class @@ -300,4 +300,4 @@ potential *desired_mu*: .. label:: end_test_9a_class The evolution of the potential energy as a function of the -number of steps are written in the *Outputs/Epot.dat*. +number of steps is written in the *Outputs/Epot.dat*. diff --git a/docs/source/projects/project1.rst b/docs/source/projects/project1.rst index 6eca333..717afcd 100644 --- a/docs/source/projects/project1.rst +++ b/docs/source/projects/project1.rst @@ -98,7 +98,7 @@ Within the Python script, write: .. code-block:: python - epsilon = (119.76*ureg.kelvin*cst.Boltzmann*cst.N_A).to(ureg.kcal/ureg.mol) + epsilon = (119.76*ureg.kelvin*kB*Na).to(ureg.kcal/ureg.mol) r_star = 3.822*ureg.angstrom sigma = r_star / 2**(1/6) m_argon = 39.948*ureg.gram/ureg.mol @@ -161,17 +161,17 @@ statistical mechanics that describes how the state variables of a system, such a pressure :math:`p`, volume :math:`V`, and temperature :math:`T`, are interrelated. Here, let us extract the pressure of the fluid for different density values. -To easily launch multiple simulation in parallel, let us create a +To easily launch multiple simulations in parallel, let us create a function called *launch_MC_code* that will be used to call our Monte Carlo script with a chosen value of :math:`\tau = v / v^*`. -Create a new function, so that the current script ressemble the following: +Create a new function so that the current script resembles the following: .. code-block:: python def launch_MC_code(tau): - epsilon = (119.76*ureg.kelvin*cst.Boltzmann*cst.N_A).to(ureg.kcal/ureg.mol) + epsilon = (119.76*ureg.kelvin*kB*Na).to(ureg.kcal/ureg.mol) r_star = 3.822*ureg.angstrom sigma = r_star / 2**(1/6) m_argon = 39.948*ureg.gram/ureg.mol @@ -217,7 +217,7 @@ simulation with too much overlap between the atoms: ) em.run() -Then, let us start the Monte carlo simulation. As initial positions for the atoms, +Then, let us start the Monte Carlo simulation. For the initial positions of the atoms, let us use the last positions from the *em* run, i.e. *initial_positions = em.atoms_positions*em.reference_distance*: @@ -256,12 +256,12 @@ i.e. *initial_positions = em.atoms_positions*em.reference_distance*: mc.run() Finally, it is possible to call the *launch_MC_code* function using -*multiprocessing*, and perform the simulation for multiple value of :math:`\tau` +*multiprocessing*, and perform the simulation for multiple values of :math:`\tau` at the same time (if your computer has enough CPU core, if not, perform these calculations in serial): .. code-block:: python - +A if __name__ == "__main__": tau_values = np.round(np.logspace(-0.126, 0.882, 10),2) pool = multiprocessing.Pool() @@ -287,7 +287,7 @@ with those of Ref. :cite:`woodMonteCarloEquation1957`: :class: only-dark Figure: Equation of state of the argon fluid as calculated using the Monte -carlo code (disks), and compared with the results from Ref. :cite:`woodMonteCarloEquation1957`. -Normalised pressure, :math:`p V / RT` as a function of the normalised volume, +Carlo code (disks), and compared with the results from Ref. :cite:`woodMonteCarloEquation1957`. +Normalized pressure, :math:`p V / RT` as a function of the normalized volume, :math:`V / V^*`, where :math:`V^*` is the molar volume. For benchmark purposes, the data obtained using LAMMPS were also added.