11
11
from emmet .core .openff import MoleculeSpec
12
12
from pymatgen .core import Element , Molecule
13
13
from pymatgen .io .openff import create_openff_mol
14
+ from scipy .constants import Avogadro
14
15
15
16
if TYPE_CHECKING :
16
17
import pathlib
17
18
19
+ DEFAULT_ATOMIC_MASSES = {el .Z : el .atomic_mass for el in Element }
20
+
18
21
19
22
def create_mol_spec (
20
23
smiles : str ,
@@ -145,6 +148,7 @@ def calculate_elyte_composition(
145
148
salts : dict [str , float ],
146
149
solvent_densities : dict = None ,
147
150
solvent_ratio_dimension : Literal ["mass" , "volume" ] = "mass" ,
151
+ atomic_masses : dict [int , float ] | None = None ,
148
152
) -> dict [str , float ]:
149
153
"""Calculate the normalized mass ratios of an electrolyte solution.
150
154
@@ -158,6 +162,9 @@ def calculate_elyte_composition(
158
162
Dictionary of solvent SMILES strings and their densities (g/ml).
159
163
solvent_ratio_dimension: optional, str
160
164
Whether the solvents are included with a ratio of "mass" or "volume"
165
+ atomic_masses : dict[int,float] or None (Default)
166
+ The mass of each element in the species dict. Defaults to the
167
+ most recent data from pymatgen.core.periodic_table.Element
161
168
162
169
Returns
163
170
-------
@@ -186,11 +193,11 @@ def calculate_elyte_composition(
186
193
}
187
194
188
195
# Calculate the molecular weights of the solvent
189
- masses = { el . Z : el . atomic_mass for el in Element }
196
+ atomic_masses = atomic_masses or DEFAULT_ATOMIC_MASSES
190
197
salt_mws = {}
191
198
for smile in salts :
192
199
mol = tk .Molecule .from_smiles (smile , allow_undefined_stereo = True )
193
- salt_mws [smile ] = sum (masses [atom .atomic_number ] for atom in mol .atoms )
200
+ salt_mws [smile ] = sum (atomic_masses [atom .atomic_number ] for atom in mol .atoms )
194
201
195
202
# Convert salt mole ratios to mass ratios
196
203
salt_mass_ratio = {
@@ -207,7 +214,9 @@ def calculate_elyte_composition(
207
214
return {species : mass / total_mass for species , mass in combined_mass_ratio .items ()}
208
215
209
216
210
- def counts_from_masses (species : dict [str , float ], n_mol : int ) -> dict [str , float ]:
217
+ def counts_from_masses (
218
+ species : dict [str , float ], n_mol : int , atomic_masses : dict [int , float ] | None = None
219
+ ) -> dict [str , float ]:
211
220
"""Calculate the number of mols needed to yield a given mass ratio.
212
221
213
222
Parameters
@@ -216,19 +225,21 @@ def counts_from_masses(species: dict[str, float], n_mol: int) -> dict[str, float
216
225
Dictionary of species SMILES strings and their relative mass fractions.
217
226
n_mol : float
218
227
Total number of mols. Returned array will sum to near n_mol.
219
-
228
+ atomic_masses : dict[int,float] or None (Default)
229
+ The mass of each element in the species dict. Defaults to the
230
+ most recent data from pymatgen.core.periodic_table.Element
220
231
221
232
Returns
222
233
-------
223
234
numpy.ndarray
224
235
n_mols: Number of each SMILES needed for the given mass ratio.
225
236
"""
226
- masses = { el . Z : el . atomic_mass for el in Element }
237
+ atomic_masses = atomic_masses or DEFAULT_ATOMIC_MASSES
227
238
228
239
mol_weights = []
229
240
for smile in species :
230
241
mol = tk .Molecule .from_smiles (smile , allow_undefined_stereo = True )
231
- mol_weights .append (sum (masses [atom .atomic_number ] for atom in mol .atoms ))
242
+ mol_weights .append (sum (atomic_masses [atom .atomic_number ] for atom in mol .atoms ))
232
243
233
244
mol_ratio = np .array (list (species .values ())) / np .array (mol_weights )
234
245
mol_ratio /= sum (mol_ratio )
@@ -239,7 +250,10 @@ def counts_from_masses(species: dict[str, float], n_mol: int) -> dict[str, float
239
250
240
251
241
252
def counts_from_box_size (
242
- species : dict [str , float ], side_length : float , density : float = 0.8
253
+ species : dict [str , float ],
254
+ side_length : float ,
255
+ density : float = 0.8 ,
256
+ atomic_masses : dict [int , float ] | None = None ,
243
257
) -> dict [str , float ]:
244
258
"""Calculate the number of molecules needed to fill a box.
245
259
@@ -251,25 +265,27 @@ def counts_from_box_size(
251
265
Side length of the cubic simulation box in nm.
252
266
density : int, optional
253
267
Density of the system in g/cm^3. Default is 1 g/cm^3.
268
+ atomic_masses : dict[int,float] or None (Default)
269
+ The mass of each element in the species dict. Defaults to the
270
+ most recent data from pymatgen.core.periodic_table.Element
254
271
255
272
Returns
256
273
-------
257
274
dict of str, float
258
275
Number of each species needed to fill the box with the given density.
259
276
"""
260
- masses = { el . Z : el . atomic_mass for el in Element }
277
+ atomic_masses = atomic_masses or DEFAULT_ATOMIC_MASSES
261
278
262
- na = 6.02214076e23 # Avogadro's number
263
279
volume = (side_length * 1e-7 ) ** 3 # Convert from nm3 to cm^3
264
280
total_mass = volume * density # grams
265
281
266
282
# Calculate molecular weights
267
283
mol_weights = []
268
284
for smile in species :
269
285
mol = tk .Molecule .from_smiles (smile , allow_undefined_stereo = True )
270
- mol_weights .append (sum (masses [atom .atomic_number ] for atom in mol .atoms ))
286
+ mol_weights .append (sum (atomic_masses [atom .atomic_number ] for atom in mol .atoms ))
271
287
mean_mw = np .mean (mol_weights )
272
- n_mol = (total_mass / mean_mw ) * na
288
+ n_mol = (total_mass / mean_mw ) * Avogadro
273
289
274
290
# Calculate the number of moles needed for each species
275
291
mol_ratio = np .array (list (species .values ())) / np .array (mol_weights )
0 commit comments