Source code for cmmdft.units_constants

#! /usr/bin/env python
# -*- coding: utf-8 -*-
#
# Copyright (C) 2019 - 2026 Louis Vanduyfhuys <Louis.Vanduyfhuys@UGent.be>
# Center for Molecular Modeling (CMM), Ghent University, Ghent, Belgium;
# all rights reserved unless otherwise stated.
#
# This file is part of a library developed by Louis Vanduyfhuys at
# the Center for Molecular Modeling. Usage of this package should be 
# authorized by prof. Van Vanduyfhuys.

# This file has been retrieved from the MolMod package, which is/was a 
# collection of molecular modelling tools for python.

import ast
import operator as op

# define which operations among units are allowed
ALLOWED_OPERATORS = {
    ast.Add: op.add,
    ast.Sub: op.sub,
    ast.Mult: op.mul,
    ast.Div: op.truediv,
    ast.Pow: op.pow,
    ast.USub: op.neg,
}

# Constants in atomic units
boltzmann = 3.1668154051341965e-06
avogadro = 6.0221415e23
lightspeed = 137.03599975303575
planck = 6.2831853071795864769


[docs] def parse_unit(expression): """Evaluate a python expression string containing constants Argument: | ``expression`` -- A string containing a numerical expressions including unit conversions. """ try: node = ast.parse(expression, mode='eval').body g = globals() g.update(shorthands) return _eval_ast(node, g) except: raise ValueError(f"Invalid expression '{expression}'")
def _eval_ast(node, g): '''Recursive evaluation of the string''' if isinstance(node, ast.Constant): return node.value elif isinstance(node, ast.BinOp): # evaluate a binary operation (e.g., a + b) left = _eval_ast(node.left, g) right = _eval_ast(node.right, g) op_type = type(node.op) if op_type in ALLOWED_OPERATORS: return ALLOWED_OPERATORS[op_type](left, right) else: raise ValueError(f"Invalid operation '{op_type}'") elif isinstance(node, ast.UnaryOp): # evaluate a unary operation (e.g., -a) operand = _eval_ast(node.operand, g) op_type = type(node.op) if op_type in ALLOWED_OPERATORS: return ALLOWED_OPERATORS[op_type](operand) else: raise ValueError(f"Invalid operation '{op_type}'") elif isinstance(node, ast.Name): # replace variable name with its value if node.id in g: return g[node.id] else: raise ValueError(f"Unknown unit '{node.id}'") else: raise ValueError(f"Unsupported expression: {ast.dump(node)}") # Units in atomic units # *** Generic *** au = 1.0 # *** Charge *** coulomb = 1.0/1.602176462e-19 # Mol mol = avogadro # *** Mass *** kilogram = 1.0/9.10938188e-31 gram = 1.0e-3*kilogram miligram = 1.0e-6*kilogram unified = 1.0e-3*kilogram/mol amu = unified # *** Length *** meter = 1.0/0.5291772083e-10 decimeter = 1.0e-1*meter centimeter = 1.0e-2*meter milimeter = 1.0e-3*meter micrometer = 1.0e-6*meter nanometer = 1.0e-9*meter angstrom = 1.0e-10*meter picometer = 1.0e-12*meter # *** Volume *** liter = decimeter**3 # *** Energy *** joule = 1/4.35974381e-18 calorie = 4.184*joule kjmol = 1.0e3*joule/mol kcalmol = 1.0e3*calorie/mol electronvolt = (1.0/coulomb)*joule rydberg = 0.5 # *** Force *** newton = joule/meter # *** Angles *** deg = 0.017453292519943295 rad = 1.0 # *** Time *** second = 1/2.418884326500e-17 nanosecond = 1e-9*second femtosecond = 1e-15*second picosecond = 1e-12*second # *** Frequency *** hertz = 1/second # *** Pressure *** pascal = newton/meter**2 bar = 100000*pascal atm = 1.01325*bar # *** Temperature *** kelvin = 1.0 # *** Dipole *** debye = 0.39343031369146675 # = 1e-21*coulomb*meter**2/second/lightspeed # *** Current *** ampere = coulomb/second # Shorthands for the parse functions shorthands = { "C": coulomb, "kg": kilogram, "g": gram, "mg": miligram, "u": unified, "m": meter, "cm": centimeter, "mm": milimeter, "um": micrometer, "nm": nanometer, "A": angstrom, "pm": picometer, "l": liter, "J": joule, "cal": calorie, "eV": electronvolt, "N": newton, "s": second, "Hz": hertz, "ns": nanosecond, "fs": femtosecond, "ps": picosecond, "Pa": pascal, "K": kelvin, # atomic units "e": au, }
[docs] class convert_units(object):
[docs] def __init__(self, mass_guest, mass_host, volume_host): """ """ rho_stp = (mass_guest/amu)*1e-3/22.414 #g/cm**3 rho_host = (mass_host/gram)/(volume_host/centimeter**3) #g/cm**3 self.output_dict = {'wt%' : mass_host/mass_guest/100, 'mg/g' : mass_host/mass_guest/1000, 'cm3/cm3' : mass_guest*rho_host/mass_host/rho_stp, 'mol/mol': 1, 'mol/g' : mass_host/amu, 'mol/kg' : mass_host/amu/1000, 'au/uc' : 1, } self.input_dict = {key:item for key,item in self.output_dict.items()}
[docs] def conversion_factor(self, input='mol/mol', output='mol/mol'): """ input: a string of the unit of the input output: a string of the desired unit output supported adorption units: wt%, cm3/cm3, mol/mol, mol/g, mol/kg """ unit_list = ['wt%', 'cm3/cm3', 'mol/mol', 'mol/g', 'mol/kg', 'au/uc', 'mg/g'] assert input in unit_list and output in unit_list, "input must be a tuple where the first element is the value of the unit and the second is a string containing the unit type" return self.input_dict[input]/self.output_dict[output]