#!/usr/bin/env python3
#
# constants.py
"""
Scientific constants.
"""
#
# Copyright (c) 2019-2021 Dominic Davis-Foster <dominic@davis-foster.co.uk>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
# MA 02110-1301, USA.
#
# Based on ChemPy (https://github.com/bjodah/chempy)
# | Copyright (c) 2015-2018, Björn Dahlgren
# | All rights reserved.
# |
# | Redistribution and use in source and binary forms, with or without modification,
# | are permitted provided that the following conditions are met:
# |
# | Redistributions of source code must retain the above copyright notice, this
# | list of conditions and the following disclaimer.
# |
# | Redistributions in binary form must reproduce the above copyright notice, this
# | list of conditions and the following disclaimer in the documentation and/or
# | other materials provided with the distribution.
# |
# | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
# | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
# | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
# | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
# | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
# | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
# stdlib
from typing import Dict, NamedTuple, Optional
# 3rd party
import quantities # type: ignore[import]
__all__ = [
"Constant",
"avogadro_number",
"plancks_constant",
"speed_of_light",
"electron_radius",
"neutron_mass",
"atomic_mass_constant",
"faraday_constant",
"vacuum_permittivity",
"boltzmann_constant",
"molar_gas_constant",
"prefixes",
]
_anions = { # Incomplete
"F-": "fluoride",
"Cl-": "chloride",
"Br-": "bromide",
"I-": "iodide",
"OH-": "hydroxide",
"CN-": "cyanide",
"SCN-": "thiocyanate",
"CO3-2": "carbonate",
"C2O4-2": "oxalate",
"HCO3-": "hydrogencarbonate",
"NO3-": "nitrate",
"NO2-": "nitrite",
"PO4-3": "phospahte",
"HPO4-2": "hydrogenphospahte",
"H2PO4-": "dihydrogenphospahte",
"P-3": "phosphide",
"SO4-2": "sulphate",
"HSO4-": "hydrogensulphate",
"SO3-2": "sulphite",
"HSO3-": "hydrogensulphite",
"S-2": "sulfide",
"ClO-": "hypochlorite",
"ClO2-": "chlorite",
"ClO3-": "chlorate",
"ClO4-": "perchlorate",
"CrO4-2": "chromate(VI)",
"Cr2O7-2": "dichromate(VI)",
"MnO4-2": "manganate(VI)",
"MnO4-": "permanganate(VII)",
"FeO4-2": "ferrate(VI)",
"OsO4-2": "osmate(VI)",
"Bo3-3": "borate",
"BiO3-": "bismuthate(V)",
}
_cations = { # Incomplete
"H3O+": "hydronium",
}
_cation_oxidation_states = { # This needs to be reviewed, just from the top of my head
"Cr": (2, 3),
"Fe": (2, 3),
"Mn": (2,),
"Co": (2, 3),
"Ni": (2, 3),
"Cu": (1, 2, 3),
"Ag": (1, 2),
"Au": (3,),
"Zn": (2,),
"Cd": (2,),
"Hg": (1, 2), # Tricky: Hg2+2
"Al": (3,),
"Ga": (3,),
"In": (3,),
"Tl": (1, 3),
"Sn": (2, 4),
"Pb": (2, 4),
"Bi": (3,),
"Sb": (3,),
}
[docs]class Constant(NamedTuple):
"""
Represents a scientific constant.
"""
#: The name of the constant.
name: str
#: The value of the constant.
value: float
#: The constant's unit.
unit: quantities.quantity.Quantity
#: An optional symbol for the constant. Default :py:obj:`None`.
symbol: Optional[str] = None
[docs] def as_quantity(self) -> quantities.quantity.Quantity:
"""
Returns the constant as a :class:`quantities.quantity.Quantity` object.
"""
return self.value * self.unit
[docs] def __float__(self) -> float:
"""
Returns the constant as a float (without the unit).
"""
return float(self.value)
[docs] def __int__(self) -> int:
"""
Returns the constant as an integer (without the unit).
"""
return int(self.value)
# The following from periodictable
# Public Domain data
# Author: Paul Kienzle
#: Avogadro's constant (Avogadro's number)
avogadro_number = avogadro_constant = Constant(
name="Avogadro constant", value=6.02214179e23, unit=1 / quantities.mol, symbol="N<sub>A</sub>"
) # (30)
#: Planck's constant
plancks_constant = planck_constant = Constant(
name="Planck's constant",
value=4.13566733e-15 * (10**34),
unit=quantities.electron_volt / quantities.second,
symbol='h'
) # (10)
#: The speed of light in a vacuum.
speed_of_light = Constant(
name="Speed of light", value=299792458, unit=quantities.m / quantities.second, symbol='c'
) # (exact)
#: Electron Radius
electron_radius = Constant(name="Electron radius", value=2.8179402894e-15, unit=quantities.m, symbol="rₑ") # (58)
# From NIST Reference on Constants, Units, and Uncertainty
# http://physics.nist.gov/cuu/index.html
# neutron mass = 1.008 664 915 97(43) u
# atomic mass constant m_u = 1.660 538 782(83) x 10-27 kg
#: Neutron mass
neutron_mass = Constant(
name="Neutron mass", value=1.00866491597, unit=quantities.atomic_mass_unit, symbol="n<sup>o</sup>"
) # (43)
#: The atomic mass constant.
atomic_mass_constant = float(quantities.atomic_mass_unit.rescale(quantities.kg))
#: Faraday constant
faraday_constant = Constant(
name="Faraday constant",
value=96485.3321233100184,
unit=quantities.coulomb * (1 / quantities.mol),
symbol='F'
)
#: Vacuum permittivity
vacuum_permittivity = Constant(
"Vacuum permittivity", value=8.8541878128e-12, unit=quantities.farad / quantities.metre, symbol="ε₀"
)
#: Boltzmann constant
boltzmann_constant = Constant(
name="Boltzmann constant",
value=1.380649e-23,
unit=quantities.joule / quantities.kelvin,
symbol="k<sub>B</sub>"
)
#: Molar gas constant
molar_gas_constant = Constant(
name="Molar gas constant",
value=8.31446261815324,
unit=quantities.joule / quantities.kelvin / quantities.mol,
symbol='R'
)
#: Numerical IUPAC prefixes (e.g. **mono-**).
prefixes: Dict[int, str] = {
1: "mono",
2: "di",
3: "tri",
4: "tetra",
5: "penta",
6: "hexa",
7: "hepta",
8: "octa",
9: "nona",
10: "deca",
11: "undeca",
12: "dodeca",
13: "trideca",
14: "tetradeca",
15: "pentadeca",
16: "hexadeca",
17: "heptadeca",
18: "octadeca",
19: "nonadeca",
20: "icosa",
21: "henicosa",
22: "docosa",
23: "tricosa",
30: "triaconta",
31: "hentriaconta",
32: "dotriaconta",
40: "tetraconta",
50: "pentaconta",
60: "hexaconta",
70: "heptaconta",
80: "octaconta",
90: "nonaconta",
100: "hecta",
200: "dicta",
300: "tricta",
400: "tetracta",
500: "pentacta",
600: "hexacta",
700: "heptacta",
800: "octacta",
900: "nonacta",
1000: "kilia",
2000: "dilia",
3000: "trilia",
4000: "tetralia",
5000: "pentalia",
6000: "hexalia",
7000: "heptalia",
8000: "octalia",
9000: "nonalia",
}