Skip to content

Commit

Permalink
Merge pull request #63 from lewisamarshall/development
Browse files Browse the repository at this point in the history
Documentation Update
  • Loading branch information
lewisamarshall committed Nov 22, 2015
2 parents fcb4905 + a4d31f9 commit cd1a7db
Show file tree
Hide file tree
Showing 28 changed files with 189 additions and 53 deletions.
17 changes: 17 additions & 0 deletions .codeclimate.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
languages:
Python: true

exclude_paths:
- "docs/*"

ratings:
paths:
- "**.py"

engines:
fixme:
enabled: true
pep8:
enabled: true
radon:
enabled: true
6 changes: 6 additions & 0 deletions docs/source/Aqueous.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
The Aqueous Class
=============

.. autoclass:: ionize.Aqueous
:members:
:inherited-members:
5 changes: 5 additions & 0 deletions docs/source/Database.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
The **ionize** Database
=======================

.. autoclass:: ionize.Database
:members:
3 changes: 2 additions & 1 deletion docs/source/Ion.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@ The Ion Class
=============

.. autoclass:: ionize.Ion
:members: robinson_stokes_mobility, ionization_fraction, effective_mobility, molar_conductivity, set_T
:members:
:inherited-members:
6 changes: 6 additions & 0 deletions docs/source/Nucleic_Acid.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
The NucleicAcid Class
=============

.. autoclass:: ionize.NucleicAcid
:members:
:inherited-members:
10 changes: 10 additions & 0 deletions docs/source/Protein.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
The Protein Class
=============

.. autoclass:: ionize.Protein
:members:
:inherited-members:

.. autoclass:: ionize.Peptide
:members:
:inherited-members:
10 changes: 6 additions & 4 deletions docs/source/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,17 @@
import sys
import os
import mock

MOCK_MODULES = ['numpy', 'scipy', 'scipy.optimize']
MOCK_MODULES = ['numpy', 'scipy', 'scipy.optimize', 'numpy.linalg', 'Bio',
'Bio.SeqUtils', 'Bio.SeqUtils.IsoelectricPoint',
'Bio.SeqUtils.ProtParam']
for mod_name in MOCK_MODULES:
sys.modules[mod_name] = mock.Mock()

# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
sys.path.insert(0, os.path.abspath('../..'))
import ionize

# -- General configuration ------------------------------------------------

Expand Down Expand Up @@ -63,9 +65,9 @@
# built documents.
#
# The short X.Y version.
version = '0.2.0c'
version = '.'.join(ionize.__version__.split('.')[:-1])
# The full version, including alpha/beta/rc tags.
release = '0.2.0c'
release = ionize.__version__

# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
Expand Down
5 changes: 5 additions & 0 deletions docs/source/constants.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
Constants
=============

.. automodule:: ionize.constants
:members:
6 changes: 0 additions & 6 deletions docs/source/database.rst

This file was deleted.

7 changes: 6 additions & 1 deletion docs/source/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,12 @@ Contents:

Ion
Solution
database
Nucleic_Acid
Protein
Database
Aqueous
utils
constants



Expand Down
4 changes: 4 additions & 0 deletions docs/source/utils.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Utilities
=============

.. autofunction:: ionize.deserialize
17 changes: 14 additions & 3 deletions ionize/Database/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@


class Database(object):
"""A database containing ion information."""

_default_source = os.path.join(os.getcwd(),
os.path.dirname(__file__),
Expand All @@ -27,6 +28,7 @@ def _open(self):
self._data = json.load(fp)

def load(self, name):
"""Return an ion from the database based on the name."""
name = name.lower()
if name in self.data:
data = {key: value for
Expand All @@ -36,16 +38,28 @@ def load(self, name):
raise NameError('Ion {} not found in database.'.format(name))

def search(self, searchstring):
"""Return each name in the database that matches the searchstring.
The searchstring can be a regular expression.
"""
return tuple(sorted([str(key) for key in self.data.keys()
if re.search(searchstring, key)]))

def keys(self):
"""Return the keys of the database as a list."""
return sorted(self.data.keys())

def serialize(self):
"""Return a JSON formatted serialization of the database."""
return json.dumps(self.data)

def __getitem__(self, key):
"""Return the ion that matches the key."""
return self.load(key)

def __iter__(self):
"""Retern a generator that yields each ion in the Database."""

for key in self.keys():
yield self[key]

Expand All @@ -54,6 +68,3 @@ def __repr__(self):

def __str__(self):
return 'Database: {} entries'.format(len(self.keys()))

def serialize(self):
return json.dumps(self.data)
2 changes: 1 addition & 1 deletion ionize/Ion/BaseIon.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ def serialize(self, nested=False, compact=False):
def save(self, filename):
"""Save a serialized Ion to a file."""
with open(filename, 'w') as file:
json.dump(self.serialize(), file)
file.write(self.serialize())

def mobility(self):
"""The effective mobility of the ion.
Expand Down
5 changes: 5 additions & 0 deletions ionize/Ion/ionization.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,11 @@ def ionization_fraction(self, pH=None, ionic_strength=None, temperature=None):


def charge(self, pH=None, ionic_strength=None, temperature=None, moment=1):
"""Return the time-averaged charge of the charge of the ion.
Use the moment argument to control which moment of the average charge is
calculated.
"""
fraction = self.ionization_fraction(pH, ionic_strength, temperature)
return np.sum(fraction * self.valence**moment)

Expand Down
6 changes: 6 additions & 0 deletions ionize/Ion/mobility.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ def mobility(self, pH=None, ionic_strength=None, temperature=None):


def actual_mobility(self, ionic_strength=None, temperature=None):
"""Return the mobility for each charge state."""
try:
return self.onsager_fuoss_mobility()
except AttributeError:
Expand All @@ -47,6 +48,10 @@ def actual_mobility(self, ionic_strength=None, temperature=None):


def absolute_mobility(self, temperature=None):
"""Return the mobility of each charge state.
Absolulte mobility does not take ionic strength into account.
"""
_, _, temperature = \
self._resolve_context(None, None, temperature)

Expand Down Expand Up @@ -101,6 +106,7 @@ def robinson_stokes_mobility(self, ionic_strength=None, temperature=None):


def onsager_fuoss_mobility(self):
"""Return the onsager fuoss corrected mobility of each charge state."""
_, ionic_strength, temperature = \
self._resolve_context(None, None, None)

Expand Down
4 changes: 2 additions & 2 deletions ionize/IonComplex/IonComplex.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
from ..Ion import Ion, fixed_state
from ..Ion import BaseIon, fixed_state


@fixed_state
class IonComplex(Ion):
class IonComplex(BaseIon):

_state = ('name', 'members')

Expand Down
37 changes: 29 additions & 8 deletions ionize/Solution/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,9 +55,8 @@ class Solution(object):
"""

_solvent = Aqueous
# TODO: move these into solvent.
_hydronium = Ion('H+', [1], [100], [362E-9])
_hydroxide = Ion('OH-', [-1], [-100], [-205E-9])
_hydronium = None
_hydroxide = None

_pH = 7. # Normal pH units.
_ionic_strength = 0. # Expected in molar.
Expand All @@ -76,14 +75,23 @@ def _name_lookup(self):

@property
def ions(self):
"""Return a tuple of the ions in the solution."""
return tuple(self._contents.keys())

@property
def concentrations(self):
"""Return a numpy array of the ion concentrations in the solution."""
return np.array(list(self._contents.values()))

pH = property(operator.attrgetter("_pH"))
ionic_strength = property(operator.attrgetter("_ionic_strength"))
@property
def pH(self):
"""The pH of the solution."""
return self._pH

@property
def ionic_strength(self):
"""The ionic strength of the solution."""
return self._ionic_strength

def __init__(self, ions=[], concentrations=[], temperature=None):
"""Initialize a solution object."""
Expand Down Expand Up @@ -111,6 +119,9 @@ def __init__(self, ions=[], concentrations=[], temperature=None):
assert concentration >= 0, 'Concentrations must be positive.'
self._contents[ion] = concentration

# TODO: move these into database.
self._hydronium = Ion('H+', [1], [100], [362E-9])
self._hydroxide = Ion('OH-', [-1], [-100], [-205E-9])
self._hydronium = copy.copy(self._hydronium)
self._hydroxide = copy.copy(self._hydroxide)
self._hydronium.context(self)
Expand All @@ -123,8 +134,11 @@ def __init__(self, ions=[], concentrations=[], temperature=None):
def temperature(self, temperature=None):
"""Set or get the temperature of the solution.
If a temperature is supplied, returns a context manager that reverts
to the original temperature.
If no argument is supplied, returns the current temperature of the
solution.
If a numerical temperature is supplied, returns a context manager that
reverts to the original temperature.
"""
if temperature is None:
return self._temperature
Expand Down Expand Up @@ -156,6 +170,10 @@ def _cOH(self):
return cOH

def concentration(self, ion):
"""Return the concentration of the input ion.
The input may be an Ion or an ion name as a string.
"""
if ion in ('H+', self._hydronium):
return self._cH()
elif ion in ('OH-', self._hydroxide):
Expand Down Expand Up @@ -237,14 +255,17 @@ def __getitem__(self, item):
raise KeyError(item)

def serialize(self, nested=False, compact=False):
"""Return a JSON-formatted serialization of the object."""
serial = {'__solution__': True}
serial['concentrations'] = self.concentrations
serial['ions'] = self.ions
return _serialize(serial, nested, compact)

# TODO: Figure out why this dumps text.
def save(self, filename):
"""Save the solution to file."""
with open(filename, 'w') as file:
json.dump(self.serialize(), file)
file.write(self.serialize())

from .equilibrium import _equilibrate
from .conductivity import conductivity, hydroxide_conductivity, \
Expand Down
1 change: 1 addition & 0 deletions ionize/Solution/conservation.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ def jovin(self):


def gas(self):
"""Return the Gas conservation function value of the solution."""
alberty = self.alberty()
jovin = self.jovin()
gas = [alberty - jovin / self._hydronium.mobility(self.pH),
Expand Down
2 changes: 1 addition & 1 deletion ionize/Solution/debye.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
def debye(self, temperature=None):
"""Return the Debye length of the solution.
Uses the Debye-Huckel approximation for the calculation
Uses the Debye-Huckel approximation for the calculation.
"""
if temperature is None:
temperature = self.temperature()
Expand Down
9 changes: 4 additions & 5 deletions ionize/Solution/equilibrium.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,8 @@ def calculate_pH(self, ionic_strength):
# Set up the matrix of Ls, the multiplication
# of acidity coefficients for each ion.
l_matrix = np.array([np.resize(ion.acidity_product(ionic_strength),
[max_columns])
for ion in self.ions])
[max_columns])
for ion in self.ions])

# Construct Q vector.
Q = 1.0
Expand All @@ -50,8 +50,7 @@ def calculate_pH(self, ionic_strength):
# Convolve with water dissociation.
Q = np.convolve(Q, [-self._solvent.dissociation(ionic_strength,
self.temperature()),
0.0, 1.0])

0.0, 1.0])

# Construct P matrix
PMat = []
Expand All @@ -70,7 +69,7 @@ def calculate_pH(self, ionic_strength):

# Multiply P matrix by concentrations, and sum.
P = np.sum(np.array(PMat, ndmin=2) *
np.array(self.concentrations)[:, np.newaxis], 0)
np.array(self.concentrations)[:, np.newaxis], 0)
# Construct polynomial. Change the shapes as needed, then reverse the order
if len(P) < len(Q):
P.resize(Q.shape)
Expand Down
10 changes: 6 additions & 4 deletions ionize/Solution/titrate.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,11 +48,11 @@ def titrate(self, titrant, target, titration_property='pH', return_c=False):

att = getattr(self, titration_property)
if isinstance(att, numbers.Number):
min_func = lambda c:\
getattr(self + (titrant, c), titration_property)-target
def min_func(c):
return getattr(self + (titrant, c), titration_property)-target
else:
min_func = lambda c: \
getattr(self + (titrant, c), titration_property)()-target
def min_func(c):
return getattr(self + (titrant, c), titration_property)()-target

with warnings.catch_warnings():
warnings.simplefilter("ignore")
Expand All @@ -68,8 +68,10 @@ def titrate(self, titrant, target, titration_property='pH', return_c=False):


def equilibrate_CO2(self):
"""Titrates the CO2 in solution to equilibrium with earth's atmosphere."""
CO2 = database['carbonic acid']
CO2.context(self)
# TODO: move to constants
atmospheric_CO2 = 0.0004
eq = atmospheric_CO2 * self._solvent.henry_CO2(self.temperature())

Expand Down
Loading

0 comments on commit cd1a7db

Please sign in to comment.