diff --git a/README.md b/README.md index b2c1859..7e98c62 100644 --- a/README.md +++ b/README.md @@ -21,6 +21,11 @@ One-line install using [pip](https://pypi.python.org/pypi/pip): pip install ionize +Alternatively, if you're installing from source: +- Clone the repository, and `cd` into the `ionize` directory. +- Install the dependencies with `pip3 install -r requirements.txt` +- Install `ionize` using `python3 setup.py install` + Tutorial -------- Want to use **ionize**? Read the [tutorial][tutorial]. diff --git a/docs/source/conf.py b/docs/source/conf.py index 9f09c9b..9ea0a4b 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -17,7 +17,7 @@ import sys import os -import mock +import unittest.mock as mock MOCK_MODULES = ['numpy', 'scipy', 'scipy.optimize', 'numpy.linalg', 'Bio', 'Bio.SeqUtils', 'Bio.SeqUtils.IsoelectricPoint', 'Bio.SeqUtils.ProtParam'] diff --git a/ionize/Ion/__init__.py b/ionize/Ion/__init__.py index dc75100..c79818b 100644 --- a/ionize/Ion/__init__.py +++ b/ionize/Ion/__init__.py @@ -1,13 +1,9 @@ """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 ..constants import reference_temperature from .fixed_state import fixed_state diff --git a/ionize/Solution/titrate.py b/ionize/Solution/titrate.py index 9870a12..5f7b6a6 100644 --- a/ionize/Solution/titrate.py +++ b/ionize/Solution/titrate.py @@ -5,6 +5,7 @@ import warnings from copy import deepcopy +from ..Ion.BaseIon import BaseIon from ..Ion import Ion from ..Database import Database from ..constants import atmospheric_CO2 @@ -45,25 +46,46 @@ def titrate(self, titrant, target, titration_property='pH'): To titrate to a target property other than pH, simply set the property to a property of the Solution class. """ + from . import Solution if isinstance(titrant, str): titrant = database.load(titrant) - att = getattr(self, titration_property) - if isinstance(att, numbers.Number): - def min_func(c): - return getattr(self + (titrant, c), titration_property)-target + if isinstance(titrant, BaseIon): + att = getattr(self, titration_property) + if isinstance(att, numbers.Number): + def min_func(c): + return getattr(self + (titrant, c), titration_property)-target + else: + def min_func(c): + return getattr(self + (titrant, c), titration_property)()-target + + with warnings.catch_warnings(): + warnings.simplefilter("ignore") + c, r = brentq(min_func, 0, 55, full_output=True) + + if r.converged: + return (self + (titrant, c)) + else: + raise RuntimeError('Solver did not converge.') + elif isinstance(titrant, Solution): + att = getattr(self, titration_property) + if isinstance(att, numbers.Number): + def min_func(c): + return getattr((self*(1-c) + titrant*c), titration_property)-target + else: + def min_func(c): + return getattr((self*(1-c) + titrant*c), titration_property)()-target + + with warnings.catch_warnings(): + warnings.simplefilter("ignore") + c, r = brentq(min_func, 0, 1, full_output=True) + + if r.converged: + return (self*(1-c)+titrant*c) + else: + raise RuntimeError('Solver did not converge.') else: - def min_func(c): - return getattr(self + (titrant, c), titration_property)()-target - - with warnings.catch_warnings(): - warnings.simplefilter("ignore") - c, r = brentq(min_func, 0, 55, full_output=True) - - if r.converged: - return (self + (titrant, c)) - else: - raise RuntimeError('Solver did not converge.') + raise TypeError('Titrant must be an Ion, an ion name string, or a Solution.') def equilibrate_CO2(self, partial_pressure=atmospheric_CO2): diff --git a/ionize/__version__.py b/ionize/__version__.py index 58d478a..19b4f1d 100644 --- a/ionize/__version__.py +++ b/ionize/__version__.py @@ -1 +1 @@ -__version__ = '1.2.0' +__version__ = '1.3.0' diff --git a/ionize/tests.py b/ionize/tests.py index 0840c4f..d009f97 100644 --- a/ionize/tests.py +++ b/ionize/tests.py @@ -274,6 +274,13 @@ def test_titrate(self): self.assertAlmostEqual(base.titrate('hydrochloric acid', pH).pH, pH) + def test_solution_titrate(self): + """Test titration with a solution.""" + base = Solution(['tris'], [0.1]) + titrant = Solution('hydrochloric acid', 0.2) + for pH in (1, 3, 5, 7): + self.assertAlmostEqual(base.titrate(titrant, pH).pH, pH) + def test_solution_properties(self): for buf in self.solutions: buf.conductivity() diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..f487342 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,7 @@ +pandas>=1.0.1 +pypandoc>=1.4 +numpy>=1.18.1 +scipy>=1.4.1 +Click>=7.0 +biopython>=0.0.6 +simplejson>=3.17.2