1 """Contains fundamental constants in atomic units.
3 Copyright (C) 2013, Joshua More and Michele Ceriotti
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http.//www.gnu.org/licenses/>.
20 Constants: Class whose members are fundamental constants.
21 Elements: Class which contains the mass of different elements
22 Units: Class which contains the methods needed to transform
23 between different systems of units.
27 from ipi
.utils
.messages
import verbosity
, info
29 __all__
= ['Constants', 'Elements', 'unit_to_internal', 'unit_to_user']
33 """Class whose members are fundamental constants.
36 kb: Boltzmann constant.
37 hbar: Reduced Planck's constant.
38 amu: Atomic mass unit.
47 """Class which contains the mass of different elements.
50 mass_list: A dictionary containing the masses of different elements.
51 Has the form {"label": Mass in a.m.u.}. Note that the generic "X"
52 label is assumed to be an electron.
56 "X" : 1.0000/Constants
.amu
,
59 "Z" : 1.382943, #an interpolated H-D atom, based on y=1/sqrt(m) scaling
181 def mass(cls
, label
):
182 """Function to access the mass_list attribute.
184 Note that this does not require an instance of the Elements class to be
185 created, as this is a class method. Therefore using Elements.mass(label)
186 will give the mass of the element with the atomic symbol given by label.
189 label: The atomic symbol of the atom whose mass is required.
192 A float giving the mass of the atom with atomic symbol label.
196 return cls
.mass_list
[label
]*Constants
.amu
198 info("Unknown element given, you must specify the mass", verbosity
.low
)
201 # these are the conversion FROM the unit stated to internal (atomic) units
208 "atomic_unit" : 1.00,
209 "electronvolt" : 0.036749326,
210 "j/mol" : 0.00000038087989,
211 "cal/mol" : 0.0000015946679,
212 "kelvin" : 3.1668152e-06
216 "atomic_unit" : 1.00,
217 "kelvin" : 3.1668152e-06
221 "atomic_unit" : 1.00,
222 "second" : 4.1341373e+16
224 "frequency" : { # NB Internally, ANGULAR frequencies are used.
226 "atomic_unit" : 1.00,
227 "inversecm" : 4.5563353e-06,
228 "hertz*rad" : 2.4188843e-17,
229 "hertz" : 1.5198298e-16
231 "ms-momentum" : { # TODO fill up units here (mass-scaled momentum)
237 "atomic_unit" : 1.00,
238 "angstrom" : 1.8897261,
239 "meter" : 1.8897261e+10
243 "atomic_unit" : 1.00,
244 "angstrom3" : 6.748334231,
248 "atomic_unit" : 1.00,
257 "atomic_unit" : 1.00,
258 "dalton" : 1.00*Constants
.amu
,
259 "electronmass" : 1.00
263 "atomic_unit" : 1.00,
264 "bar" : 3.398827377e-9,
265 "atmosphere" : 3.44386184e-9,
266 "pascal" : 3.398827377e-14
270 "atomic_unit" : 1.00,
275 "atomic_unit" : 1.00,
281 # a list of magnitude prefixes
284 "yotta" : 1e24
, "zetta" : 1e21
, "exa" : 1e18
, "peta" : 1e15
,
285 "tera" : 1e12
, "giga" : 1e9
, "mega" : 1e6
, "kilo" : 1e3
,
286 "milli" : 1e-3, "micro" : 1e-6, "nano" : 1e-9, "pico" : 1e-12,
287 "femto" : 1e-15, "atto" : 1e-18, "zepto" : 1e-21, "yocto" : 1e-24
290 # builds a RE to match prefix and split out the base unit
292 for key
in UnitPrefix
:
293 UnitPrefixRE
= UnitPrefixRE
+ key
+ "|"
294 UnitPrefixRE
= " *(" + UnitPrefixRE
[1:] + ")(.*) *"
295 UnitPrefixRE
= re
.compile(UnitPrefixRE
)
297 ########################################################################
298 # Atomic units are used EVERYWHERE internally. In order to quickly #
299 # interface with any "outside" unit, we set up a simple conversion #
301 ########################################################################
303 def unit_to_internal(family
, unit
, number
):
304 """Converts a number of given dimensions and units into internal units.
307 family: The dimensionality of the number.
308 unit: The units 'number' is originally in.
309 number: The value of the parameter in the units 'unit'.
312 The number in internal units.
315 ValueError: Raised if the user specified units aren't given in the
317 IndexError: Raised if the programmer specified dimensionality for the
318 parameter isn't in UnitMap. Shouldn't happen, for obvious reasons.
319 TypeError: Raised if the prefix is correct, but the base unit is not, in
320 the user specified unit string.
323 if not (family
== "number" or family
in UnitMap
):
324 raise IndexError(family
+ " is an undefined units kind.")
325 if family
== "number":
333 m
= UnitPrefixRE
.match(unit
);
335 raise ValueError("Unit " + unit
+ " is not structured with a prefix+base syntax.")
339 if not prefix
in UnitPrefix
:
340 raise TypeError(prefix
+ " is not a valid unit prefix.")
341 if not base
in UnitMap
[family
]:
342 raise TypeError(base
+ " is an undefined unit for kind " + family
+ ".")
344 return number
*UnitMap
[family
][base
]*UnitPrefix
[prefix
]
346 def unit_to_user(family
, unit
, number
):
347 """Converts a number of given dimensions from internal to user units.
350 family: The dimensionality of the number.
351 unit: The units 'number' should be changed to.
352 number: The value of the parameter in internal units.
355 The number in the user specified units
358 return number
/unit_to_internal(family
, unit
, 1.0)