Source code for ionize.Ion

"""Module containing the Ion class."""
from __future__ import division
import warnings
from math import copysign
import json
import numpy as np

from .BaseIon import BaseIon
from ..constants import reference_temperature, boltzmann, kelvin, \
                        elementary_charge
from .fixed_state import fixed_state


@fixed_state
[docs]class Ion(BaseIon): """An Ion describes a charged species in solution. Ion is the most commonly used subclass of BaseIon. It is used to represent small ions that have a set of known valence states with distinct pKas. Ions are immutable. Example:: acid = ionize.Ion('acid', [-1], [3], [30e-9], molecular_weight=19) acid.mobility(pH=7) acid.diffusivity(pH=7) :param name: The name of the ion. :param valence: An iterable of the integer valence states. :param reference_pKa: An iterable of the pKas associated with the valence states at the reference temperature. :param reference_mobility: An iterable of the fully ionized mobility of each valence state at infinite dilution in m^2/V/s at the reference temperature. :param reference_temperature: The temperature at which other parameters are measured. Defaults to 25 degrees C. :param enthalpy: The enthalpy change on dissociation for each valence state. This is optional, but allows more accurate models for calculating temperature-dependance of properties. :param heat_capacity: The change in heat capacity on dissociation for each valence state. This optional parameter further improves the accuracy of temperature-dependant property calculation. :param nightingale_data: Mobiliity correction data for small ions where hydration shell dynamics are important. :param molecular_weight: The molecular weight of uncharged species, in Daltons. :param alias: An iterable of alias strings that can be used to refer to the ion. """ _state = {'name': 'The ion name.', 'valence': 'The valence of each state.', 'reference_pKa': 'The pKas of each ionization state at the reference state.', 'reference_mobility': 'The mobility of each ionization at the reference state.', 'reference_temperature': 'The temperature at whcih properties were measured.', 'enthalpy': 'The change in enthalpy on ionization.', 'heat_capacity': 'The change in heat capacity on ionization.', 'nightingale_data': 'Temperature dependance data for small ions.', 'molecular_weight': 'The ion molecular weight', 'alias': 'Alternative chemical names.'} # The reference properties of the ion are stored in private variables. _valence = None _reference_pKa = None _reference_mobility = None _reference_temperature = reference_temperature _pKa = None _absolute_mobility = None _enthalpy = None _heat_capacity = None _nightingale_data = None _molecular_weight = None _alias = None # Polynomial function is a derived parameter. _nightingale_function = None def __init__(self, name, valence, reference_pKa, reference_mobility, reference_temperature=None, enthalpy=None, heat_capacity=None, nightingale_data=None, molecular_weight=None, alias=None): """Initialize an Ion object.""" self._name = str(name) if alias is not None: self._alias = tuple(alias) self._valence = np.int_(valence) if len(self.valence) > 1: assert np.all(np.diff(self.valence) > 0), \ 'Valences must be sorted.' self._reference_pKa = np.float_(reference_pKa) self._reference_mobility = np.float_(reference_mobility) if reference_temperature is not None: self._reference_temperature = float(reference_temperature) if enthalpy is not None: self._enthalpy = np.float_(enthalpy) assert self.enthalpy.size == self.reference_pKa.size if heat_capacity is not None: self._heat_capacity = np.float_(heat_capacity) self._molecular_weight = molecular_weight for prop in ('reference_pKa', 'reference_mobility', 'enthalpy', 'heat_capacity'): if getattr(self, prop) is not None: template = 'In {}, valence is {}, while {} is {}. Wrong size.' assert getattr(self, prop).size == self.valence.size, \ template.format(self.name, self.valence, prop, getattr(self, prop)) assert np.all((self.reference_mobility / self.valence) > 0.), \ 'Mobilities must be signed. {}, {}'.format(self.reference_mobility, self.valence) if nightingale_data is not None: self._nightingale_data = nightingale_data self._nightingale_function = \ np.poly1d(self.nightingale_data['fit']) def _valence_zero(self): """Create a list of charge states with 0 inserted.""" return np.sort(np.append(self.valence, [0])) from .acidity import pKa, acidity, _clark_glew_pKa, \ _clark_glew_acidity, _vant_hoff_acidity, _vant_hoff_pKa from .ionization import acidity_product, ionization_fraction, charge from .mobility import absolute_mobility, actual_mobility, \ mobility, robinson_stokes_mobility, onsager_fuoss_mobility from .transport import molar_conductivity, diffusivity