@@ -95,13 +95,15 @@ Modify the *Prepare* class as follows:
9595
9696 class Prepare :
9797 def __init__ (self ,
98- number_atoms = [10 ], # List - no unit
99- epsilon = [0.1 ], # List - Kcal/mol
100- sigma = [3 ], # List - Angstrom
101- atom_mass = [10 ], # List - g/mol
98+ ureg , # Pint unit registry
99+ number_atoms , # List - no unit
100+ epsilon , # List - Kcal/mol
101+ sigma , # List - Angstrom
102+ atom_mass , # List - g/mol
102103 potential_type = " Lennard-Jones" ,
103104 * args ,
104105 ** kwargs ):
106+ self .ureg = ureg
105107 self .number_atoms = number_atoms
106108 self .epsilon = epsilon
107109 self .sigma = sigma
@@ -116,7 +118,7 @@ Here, the four lists *number_atoms* :math:`N`, *epsilon* :math:`\epsilon`,
116118:math: `10 `, :math: `0.1 ~\text {[Kcal/mol]}`, :math: `3 ~\text {[Å]}`, and
117119:math: `10 ~\text {[g/mol]}`, respectively.
118120
119- The type of potential is also specified, with Lennard-Jones being closen as
121+ The type of potential is also specified, with Lennard-Jones being chosen as
120122the default option.
121123
122124All the parameters are assigned to *self *, allowing other methods to access
@@ -136,25 +138,33 @@ unit system to the *LJ* unit system:
136138
137139 def calculate_LJunits_prefactors (self ):
138140 """ Calculate the Lennard-Jones units prefactors."""
139- # Define the reference distance, energy, and mass
140- self .reference_distance = self .sigma[0 ] # Angstrom
141- self .reference_energy = self .epsilon[0 ] # kcal/mol
142- self .reference_mass = self .atom_mass[0 ] # g/mol
143-
144- # Calculate the prefactor for the time
145- mass_kg = self .atom_mass[0 ]/ cst.kilo/ cst.Avogadro # kg
146- epsilon_J = self .epsilon[0 ]* cst.calorie* cst.kilo/ cst.Avogadro # J
147- sigma_m = self .sigma[0 ]* cst.angstrom # m
148- time_s = np.sqrt(mass_kg* sigma_m** 2 / epsilon_J) # s
149- self .reference_time = time_s / cst.femto # fs
150-
151- # Calculate the prefactor for the temperature
141+ # First define constants
152142 kB = cst.Boltzmann* cst.Avogadro/ cst.calorie/ cst.kilo # kcal/mol/K
153- self .reference_temperature = self .epsilon[0 ]/ kB # K
154-
155- # Calculate the prefactor for the pressure
156- pressure_pa = epsilon_J/ sigma_m** 3 # Pa
157- self .reference_pressure = pressure_pa/ cst.atm # atm
143+ kB *= self .ureg.kcal/ self .ureg.mol/ self .ureg.kelvin
144+ Na = cst.Avogadro/ self .ureg.mol
145+ # Define the reference distance, energy, and mass
146+ self .ref_length = self .sigma[0 ] # Angstrom
147+ self .ref_energy = self .epsilon[0 ] # kcal/mol
148+ self .ref_mass = self .atom_mass[0 ] # g/mol
149+ # Optional: assert that units were correctly provided by users
150+ assert self .ref_length.units == self .ureg.angstrom, \
151+ f " Error: Provided sigma has wrong units, should be angstrom "
152+ assert self .ref_energy.units == self .ureg.kcal/ self .ureg.mol, \
153+ f " Error: Provided epsilon has wrong units, should be kcal/mol "
154+ assert self .ref_mass.units == self .ureg.g/ self .ureg.mol, \
155+ f " Error: Provided mass has wrong units, should be g/mol "
156+ # Calculate the prefactor for the time (in femtosecond)
157+ self .ref_time = np.sqrt(self .ref_mass \
158+ * self .ref_length** 2 / self .ref_energy).to(self .ureg.femtosecond)
159+ # Calculate the prefactor for the temperature (in Kelvin)
160+ self .ref_temperature = self .ref_energy/ kB # Kelvin
161+ # Calculate the prefactor for the pressure (in Atmosphere)
162+ self .ref_pressure = (self .ref_energy \
163+ / self .ref_length** 3 / Na).to(self .ureg.atmosphere)
164+ # Regroup all the reference quantities in list, for practicality
165+ self .ref_quantities = [self .ref_length, self .ref_energy,
166+ self .ref_mass, self .ref_time, self .ref_pressure]
167+ self .ref_units = [ref.units for ref in self .ref_quantities]
158168
159169 .. label :: end_Prepare_class
160170
@@ -192,23 +202,26 @@ Let us take advantage of the calculated reference values and normalize the
192202three inputs of the *Prepare * class that have physical dimensions, i.e.,
193203*epsilon *, *sigma *, and *atom_mass *.
194204
195- Create a new method called *nondimensionalize_units_0 * within the *Prepare *
205+ Create a new method called *nondimensionalize_units * within the *Prepare *
196206class:
197207
198208.. label :: start_Prepare_class
199209
200210.. code-block :: python
201211
202- def nondimensionalize_units_0 (self ):
203- # Normalize LJ properties
204- epsilon, sigma, atom_mass = [], [], []
205- for e0, s0, m0 in zip (self .epsilon, self .sigma, self .atom_mass):
206- epsilon.append(e0/ self .reference_energy)
207- sigma.append(s0/ self .reference_distance)
208- atom_mass.append(m0/ self .reference_mass)
209- self .epsilon = epsilon
210- self .sigma = sigma
211- self .atom_mass = atom_mass
212+ def nondimensionalize_units (self , quantities_to_normalise ):
213+ for quantity in quantities_to_normalise:
214+ if isinstance (quantity, list ):
215+ for i, element in enumerate (quantity):
216+ assert element.units in self .ref_units, \
217+ f " Error: Units not part of the reference units "
218+ ref_value = self .ref_quantities[self .ref_units.index(element.units)]
219+ quantity[i] = element/ ref_value
220+ assert quantity[i].units == self .ureg.dimensionless, \
221+ f " Error: Quantities are not properly nondimensionalized "
222+ quantity[i] = quantity[i].magnitude # get rid of ureg
223+ else :
224+ print (" NON ANTICIPATED!" )
212225
213226 .. label :: end_Prepare_class
214227
@@ -218,7 +231,7 @@ will be used to nondimensionalize units in future classes. We anticipate that
218231each element is normalized with the corresponding reference value. The
219232*zip() * function allows us to loop over all three lists at once.
220233
221- Let us also call the *nondimensionalize_units_0 * from the *__init__() * method
234+ Let us also call the *nondimensionalize_units * from the *__init__() * method
222235of the *Prepare * class:
223236
224237.. label :: start_Prepare_class
@@ -228,7 +241,7 @@ of the *Prepare* class:
228241 def __init__ (self ,
229242 (...)
230243 self .calculate_LJunits_prefactors()
231- self .nondimensionalize_units_0( )
244+ self .nondimensionalize_units([ self .epsilon, self .sigma, self .atom_mass] )
232245
233246 .. label :: end_Prepare_class
234247
@@ -288,7 +301,7 @@ Let us call the *identify_atom_properties* from the *__init__()* method:
288301
289302 def __init__ (self ,
290303 (...)
291- self .nondimensionalize_units_0( )
304+ self .nondimensionalize_units([ self .epsilon, self .sigma, self .atom_mass] )
292305 self .identify_atom_properties()
293306
294307 .. label :: end_Prepare_class
@@ -306,13 +319,25 @@ type 1, and 3 atoms of type 2:
306319
307320 import numpy as np
308321 from Prepare import Prepare
309-
310- # Initialize the Prepare object
322+ from pint import UnitRegistry
323+ ureg = UnitRegistry()
324+
325+ # Define atom number of each group
326+ nmb_1, nmb_2= [2 , 3 ]
327+ # Define LJ parameters (sigma)
328+ sig_1, sig_2 = [3 , 4 ]* ureg.angstrom
329+ # Define LJ parameters (epsilon)
330+ eps_1, eps_2 = [0.2 , 0.4 ]* ureg.kcal/ ureg.mol
331+ # Define atom mass
332+ mss_1, mss_2 = [10 , 20 ]* ureg.gram/ ureg.mol
333+
334+ # Initialize the prepare object
311335 prep = Prepare(
312- number_atoms = [2 , 3 ],
313- epsilon = [0.2 , 0.4 ], # kcal/mol
314- sigma = [3 , 4 ], # A
315- atom_mass = [10 , 20 ], # g/mol
336+ ureg = ureg,
337+ number_atoms = [nmb_1, nmb_2],
338+ epsilon = [eps_1, eps_2], # kcal/mol
339+ sigma = [sig_1, sig_2], # A
340+ atom_mass = [mss_1, mss_2], # g/mol
316341 )
317342
318343 # Test function using pytest
0 commit comments