1# -*- coding: utf-8 -*- 2# MolMod is a collection of molecular modelling tools for python. 3# Copyright (C) 2007 - 2019 Toon Verstraelen <Toon.Verstraelen@UGent.be>, Center 4# for Molecular Modeling (CMM), Ghent University, Ghent, Belgium; all rights 5# reserved unless otherwise stated. 6# 7# This file is part of MolMod. 8# 9# MolMod is free software; you can redistribute it and/or 10# modify it under the terms of the GNU General Public License 11# as published by the Free Software Foundation; either version 3 12# of the License, or (at your option) any later version. 13# 14# MolMod is distributed in the hope that it will be useful, 15# but WITHOUT ANY WARRANTY; without even the implied warranty of 16# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17# GNU General Public License for more details. 18# 19# You should have received a copy of the GNU General Public License 20# along with this program; if not, see <http://www.gnu.org/licenses/> 21# 22# -- 23"""Conversion from and to atomic units 24 25 Internally the MolMod package works always in atomic units. This unit system 26 is consistent, like the SI unit system one does not need conversion factors 27 in the middle of a computation once all values are converted to atomic units. 28 This facilitates the programming and reduces accidental bugs due to 29 forgetting these conversion factor in the body of the code. 30 31 References for the conversion values: 32 33 * B. J. Mohr and B. N. Taylor, 34 CODATA recommended values of the fundamental physical 35 constants: 1998, Rev. Mod. Phys. 72(2), 351 (2000) 36 * The NIST Reference on Constants, Units, and Uncertainty 37 (http://physics.nist.gov/cuu/Constants/index.html) 38 * 1 calorie = 4.184 Joules 39 40 Naming conventions in this module: unit is the value of one external unit 41 in internal - i.e. atomic - units. e.g. If you want to have a distance of 42 five angstrom in internal units: ``5*angstrom``. If you want to convert a 43 length of 5 internal units to angstrom: ``5/angstrom``. It is recommended to 44 perform this kind of conversions, only when data is read from the input and 45 data is written to the output. 46 47 An often recurring question is how to convert a frequency in internal units 48 to a spectroscopic wavenumber in inverse centimeters. This is how it can be 49 done:: 50 51 >>> from molmod import centimeter, lightspeed 52 >>> invcm = lightspeed/centimeter 53 >>> freq = 0.00320232 54 >>> print freq/invcm 55 56 These are the conversion constants defined in this module: 57 58""" 59 60 61from __future__ import division 62 63from molmod.constants import avogadro 64 65 66def parse_unit(expression): 67 """Evaluate a python expression string containing constants 68 69 Argument: 70 | ``expression`` -- A string containing a numerical expressions 71 including unit conversions. 72 73 In addition to the variables in this module, also the following 74 shorthands are supported: 75 76 """ 77 try: 78 g = globals() 79 g.update(shorthands) 80 return float(eval(str(expression), g)) 81 except: 82 raise ValueError("Could not interpret '%s' as a unit or a measure." % expression) 83 84 85# *** Generic *** 86au = 1.0 87 88 89# *** Charge *** 90 91coulomb = 1.0/1.602176462e-19 92 93# Mol 94 95mol = avogadro 96 97# *** Mass *** 98 99kilogram = 1.0/9.10938188e-31 100 101gram = 1.0e-3*kilogram 102miligram = 1.0e-6*kilogram 103unified = 1.0e-3*kilogram/mol 104amu = unified 105 106# *** Length *** 107 108meter = 1.0/0.5291772083e-10 109 110decimeter = 1.0e-1*meter 111centimeter = 1.0e-2*meter 112milimeter = 1.0e-3*meter 113micrometer = 1.0e-6*meter 114nanometer = 1.0e-9*meter 115angstrom = 1.0e-10*meter 116picometer = 1.0e-12*meter 117 118# *** Volume *** 119 120liter = decimeter**3 121 122# *** Energy *** 123 124joule = 1/4.35974381e-18 125 126calorie = 4.184*joule 127kjmol = 1.0e3*joule/mol 128kcalmol = 1.0e3*calorie/mol 129electronvolt = (1.0/coulomb)*joule 130rydberg = 0.5 131 132# *** Force *** 133 134newton = joule/meter 135 136# *** Angles *** 137 138deg = 0.017453292519943295 139rad = 1.0 140 141# *** Time *** 142 143second = 1/2.418884326500e-17 144 145nanosecond = 1e-9*second 146femtosecond = 1e-15*second 147picosecond = 1e-12*second 148 149# *** Frequency *** 150 151hertz = 1/second 152 153# *** Pressure *** 154 155pascal = newton/meter**2 156bar = 100000*pascal 157atm = 1.01325*bar 158 159# *** Temperature *** 160 161kelvin = 1.0 162 163# *** Dipole *** 164 165debye = 0.39343031369146675 # = 1e-21*coulomb*meter**2/second/lightspeed 166 167# *** Current *** 168 169ampere = coulomb/second 170 171 172# Shorthands for the parse functions 173 174shorthands = { 175 "C": coulomb, 176 "kg": kilogram, 177 "g": gram, 178 "mg": miligram, 179 "u": unified, 180 "m": meter, 181 "cm": centimeter, 182 "mm": milimeter, 183 "um": micrometer, 184 "nm": nanometer, 185 "A": angstrom, 186 "pm": picometer, 187 "l": liter, 188 "J": joule, 189 "cal": calorie, 190 "eV": electronvolt, 191 "N": newton, 192 "s": second, 193 "Hz": hertz, 194 "ns": nanosecond, 195 "fs": femtosecond, 196 "ps": picosecond, 197 "Pa": pascal, 198 "K": kelvin, 199 # atomic units 200 "e": au, 201} 202 203 204# automatically spice up the docstrings 205 206lines = [ 207 " ================ ==================", 208 " Name Value ", 209 " ================ ==================", 210] 211 212for key, value in sorted(globals().items()): 213 if not isinstance(value, float): 214 continue 215 lines.append(" %16s %.10e" % (key, value)) 216lines.append(" ================ ==================") 217 218__doc__ += "\n".join(lines) 219 220 221lines = [ 222 " ================ ==================", 223 " Short name Value ", 224 " ================ ==================", 225] 226 227for key, value in sorted(shorthands.items()): 228 if not isinstance(value, float): 229 continue 230 lines.append(" %16s %.10e" % (key, value)) 231lines.append(" ================ ==================") 232 233parse_unit.__doc__ += "\n".join(lines) 234 235del lines 236