Coverage for /home/caleb/Documents/University/CHE3123/thermo/thermo/elements.py : 59%

Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
# -*- coding: utf-8 -*- Copyright (C) 2016, Caleb Bell <Caleb.Andrew.Bell@gmail.com>
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.'''
'atom_fractions', 'similarity_variable', 'atoms_to_Hill', 'simple_formula_parser', 'CAS_by_number', 'periods', 'groups', 'blocks']
'''CAS numbers of the elements, indexed by atomic numbers off-by-one up to 118.'''
'''Periods of the elements, indexed by atomic numbers off-by-one up to 118.'''
'''Groups of the elements, indexed by atomic numbers off-by-one up to 118. Lanthanides and Actinides are set to None.'''
'''Blocks of the elements, stored in a dictionary with four keys and lists. Indexed by atomic numbers off-by-one up to 118.'''
'''Periodic Table object for use in dealing with elements.
Parameters ---------- elements : list[Element] List of Element objects
Notes ----- Can be checked to sese if an element in in this, can be iterated over, and as a current length of 118 elements.
See Also -------- periodic_table Element
References ---------- .. [1] N M O'Boyle, M Banck, C A James, C Morley, T Vandermeersch, and G R Hutchison. "Open Babel: An open chemical toolbox." J. Cheminf. (2011), 3, 33. DOI:10.1186/1758-2946-3-33 ''' 'name_to_elements', 'CAS_to_elements']
for i in [self.symbol_to_elements, self.number_to_elements, self.name_to_elements, self.CAS_to_elements]: if key in i: return True return False
return 118
return iter([self.number_to_elements[i] for i in range(1,119)])
for i in [self.symbol_to_elements, self.number_to_elements, self.name_to_elements, self.CAS_to_elements]: if key in i: return i[key] raise KeyError('Key is not in the periodic table.')
return self.__getitem__(key)
'''Class for storing data on chemical elements. Supports most common properties. If a property is not available, it is set to None.
Attributes ---------- number : int Atomic number name : str name symbol : str Elemental symbol MW : float Molecular weight CAS : str CAS number period : str Period in the periodic table group : str Group in the periodic table block : str Block in the periodic table AReneg : float Allred and Rochow electronegativity rcov : float Covalent radius, [Angstrom] rvdw : float Van der Waals radius, [Angstrom] maxbonds : float Maximum valence of a bond with this element elneg : float Pauling electronegativity ionization : float Ionization potential, [eV] ionization : float elaffinity affinity, [eV] protons : int Number of protons electrons : int Number of electrons of the element in the ground state
''' 'rvdw', 'maxbonds', 'elneg', 'ionization', 'elaffinity', 'period', 'group', 'block', 'protons', 'electrons']
maxbonds, elneg, ionization, elaffinity, period, group, block):
'''Load the file from OpenBabel with element data, and store it as both a list of elements first, and then as an instance of Periodic Table.'''
CAS=CAS_by_number[number-1], AReneg=AReneg, rcov=rcov, rvdw=rvdw, maxbonds=maxbonds, elneg=elneg, ionization=ionization, elaffinity=elaffinity, block=block, period=period, group=group)
'''Single instance of the PeriodicTable class'''
r'''Calculates molecular weight of a molecule given a dictionary of its atoms and their counts, in the format {symbol: count}.
.. math:: MW = \sum_i n_i MW_i
Parameters ---------- atoms : dict dictionary of counts of individual atoms, indexed by symbol with proper capitalization, [-]
Returns ------- MW : float Calculated molecular weight [g/mol]
Notes ----- Elemental data is from rdkit, with CAS numbers added. An exception is raised if an incorrect element symbol is given. Elements up to 118 are supported.
Examples -------- >>> molecular_weight({'H': 12, 'C': 20, 'O': 5}) # DNA 332.30628
References ---------- .. [1] RDKit: Open-source cheminformatics; http://www.rdkit.org ''' MW = 0 for i in atoms: if i in periodic_table: MW += periodic_table[i].MW*atoms[i] else: raise Exception('Molecule includes unknown atoms') return MW
r'''Calculates the mass fractions of each element in a compound, given a dictionary of its atoms and their counts, in the format {symbol: count}.
.. math:: w_i = \frac{n_i MW_i}{\sum_i n_i MW_i}
Parameters ---------- atoms : dict dictionary of counts of individual atoms, indexed by symbol with proper capitalization, [-] MW : float, optional Molecular weight, [g/mol]
Returns ------- mfracs : dict dictionary of mass fractions of individual atoms, indexed by symbol with proper capitalization, [-]
Notes ----- Molecular weight is optional, but speeds up the calculation slightly. It is calculated using the function `molecular_weight` if not specified.
Elemental data is from rdkit, with CAS numbers added. An exception is raised if an incorrect element symbol is given. Elements up to 118 are supported.
Examples -------- >>> mass_fractions({'H': 12, 'C': 20, 'O': 5}) {'H': 0.03639798802478244, 'C': 0.7228692758981262, 'O': 0.24073273607709128}
References ---------- .. [1] RDKit: Open-source cheminformatics; http://www.rdkit.org ''' if not MW: MW = molecular_weight(atoms) mfracs = {} for i in atoms: if i in periodic_table: mfracs[i] = periodic_table[i].MW*atoms[i]/MW else: raise Exception('Molecule includes unknown atoms') return mfracs
r'''Calculates the atomic fractions of each element in a compound, given a dictionary of its atoms and their counts, in the format {symbol: count}.
.. math:: a_i = \frac{n_i}{\sum_i n_i}
Parameters ---------- atoms : dict dictionary of counts of individual atoms, indexed by symbol with proper capitalization, [-]
Returns ------- afracs : dict dictionary of atomic fractions of individual atoms, indexed by symbol with proper capitalization, [-]
Notes ----- No actual data on the elements is used, so incorrect or custom compounds would not raise an error.
Examples -------- >>> atom_fractions({'H': 12, 'C': 20, 'O': 5}) {'H': 0.32432432432432434, 'C': 0.5405405405405406, 'O': 0.13513513513513514}
References ---------- .. [1] RDKit: Open-source cheminformatics; http://www.rdkit.org ''' count = sum(atoms.values()) afracs = {} for i in atoms: afracs[i] = atoms[i]/count return afracs
r'''Calculates the similarity variable of an compound, as defined in [1]_. Currently only applied for certain heat capacity estimation routines.
.. math:: \alpha = \frac{N}{MW} = \frac{\sum_i n_i}{\sum_i n_i MW_i}
Parameters ---------- atoms : dict dictionary of counts of individual atoms, indexed by symbol with proper capitalization, [-] MW : float, optional Molecular weight, [g/mol]
Returns ------- similarity_variable : float similarity variable as defined in [1]_, [mol/g]
Notes ----- Molecular weight is optional, but speeds up the calculation slightly. It is calculated using the function `molecular_weight` if not specified.
Examples -------- >>> similarity_variable({'H': 32, 'C': 15}) 0.22125872677371825
References ---------- .. [1] Laštovka, Václav, Nasser Sallamie, and John M. Shaw. "A Similarity Variable for Estimating the Heat Capacity of Solid Organic Compounds: Part I. Fundamentals." Fluid Phase Equilibria 268, no. 1-2 (June 25, 2008): 51-60. doi:10.1016/j.fluid.2008.03.019. ''' if not MW: MW = molecular_weight(atoms) return sum(atoms.values())/MW
r'''Determine the Hill formula of a compound, given a dictionary of its atoms and their counts, in the format {symbol: count}.
Parameters ---------- atoms : dict dictionary of counts of individual atoms, indexed by symbol with proper capitalization, [-]
Returns ------- Hill_formula : str Hill formula, [-]
Notes ----- The Hill system is as follows:
If the chemical has 'C' in it, this is listed first, and then if it has 'H' in it as well as 'C', then that goes next. All elements are sorted alphabetically afterwards, including 'H' if 'C' is not present. All elements are followed by their count, unless it is 1.
Examples -------- >>> atoms_to_Hill({'H': 5, 'C': 2, 'Br': 1}) 'C2H5Br'
References ---------- .. [1] Hill, Edwin A. “ON A SYSTEM OF INDEXING CHEMICAL LITERATURE; ADOPTED BY THE CLASSIFICATION DIVISION OF THE U. S. PATENT OFFICE.1.” Journal of the American Chemical Society 22, no. 8 (August 1, 1900): 478-94. doi:10.1021/ja02046a005. ''' def str_ele_count(ele): if atoms[ele] == 1: count = '' else: count = str(atoms[ele]) return count atoms = atoms.copy() s = '' if 'C' in atoms.keys(): s += 'C' + str_ele_count('C') del atoms['C'] if 'H' in atoms.keys(): s += 'H' + str_ele_count('H') del atoms['H'] for ele in sorted(atoms.keys()): s += ele + str_ele_count(ele) else: for ele in sorted(atoms.keys()): s += ele + str_ele_count(ele) return s
r'''Basic formula parser, primarily for obtaining element counts from formulas as formated in PubChem. Handles formulas with integer counts, but no brackets, no hydrates, no charges, no isotopes, and no group multipliers.
Strips charges from the end of a formula first. Accepts repeated chemical units. Performs no sanity checking that elements are actually elements. As it uses regular expressions for matching, errors are mostly just ignored.
Parameters ---------- formula : str Formula string, very simply formats only.
Returns ------- atoms : dict dictionary of counts of individual atoms, indexed by symbol with proper capitalization, [-]
Notes ----- Inspiration taken from the thermopyl project, at https://github.com/choderalab/thermopyl.
Examples -------- >>> simple_formula_parser('CO2') {'C': 1, 'O': 2} ''' formula = formula.split('+')[0].split('-')[0] groups = _formula_p1.split(formula)[1::2] cnt = Counter() for group in groups: ele, count = _formula_p2.split(group)[1:] cnt[ele] += int(count) if count.isdigit() else 1 return dict(cnt) |