• Home
  • History
  • Annotate
Name Date Size #Lines LOC

..03-May-2022-

.ci/H18-Sep-2021-155136

.gh-pages-skeleton/H18-Sep-2021-

.jupyter/H18-Sep-2021-1913

benchmarks/H18-Sep-2021-12895

chempy/H18-Sep-2021-20,47216,993

chempy.egg-info/H03-May-2022-467364

conda-recipe/H18-Sep-2021-6151

examples/H03-May-2022-8,1588,072

joss-paper/H18-Sep-2021-182165

scripts/H03-May-2022-528386

.drone.ymlH A D18-Sep-20215.1 KiB130122

.git-blame-ignore-revsH A D18-Sep-2021129 22

.gitignoreH A D18-Sep-2021450 3635

.travis.ymlH A D30-Dec-20201.1 KiB4034

AUTHORSH A D30-Dec-202038 21

CHANGES.rstH A D18-Sep-20217.5 KiB256213

CONTRIBUTING.rstH A D18-Sep-20211.5 KiB3024

LICENSEH A D30-Dec-20201.3 KiB2419

MANIFEST.inH A D30-Dec-202071 54

PKG-INFOH A D18-Sep-202121.5 KiB467364

README.rstH A D30-Dec-202017.1 KiB439337

conftest.pyH A D18-Sep-2021624 2016

environment.ymlH A D30-Dec-2020478 2827

index.ipynbH A D30-Dec-20202.4 KiB6160

postBuildH A D30-Dec-2020907 1811

setup.cfgH A D18-Sep-2021851 4438

setup.pyH A D18-Sep-20214.9 KiB155132

README.rst

1ChemPy
2======
3
4.. image:: http://hera.physchem.kth.se:8080/api/badges/bjodah/chempy/status.svg
5   :target: http://hera.physchem.kth.se:8080/bjodah/chempy
6   :alt: Build status
7.. image:: https://img.shields.io/pypi/v/chempy.svg
8   :target: https://pypi.python.org/pypi/chempy
9   :alt: PyPI version
10.. image:: https://img.shields.io/badge/python-3.8,3.9-blue.svg
11   :target: https://www.python.org/
12   :alt: Python version
13.. image:: https://img.shields.io/pypi/l/chempy.svg
14   :target: https://github.com/bjodah/chempy/blob/master/LICENSE
15   :alt: License
16.. image:: http://img.shields.io/badge/benchmarked%20by-asv-green.svg?style=flat
17   :target: http://hera.physchem.kth.se/~chempy/benchmarks
18   :alt: airspeedvelocity
19.. image:: http://hera.physchem.kth.se/~chempy/branches/master/htmlcov/coverage.svg
20   :target: http://hera.physchem.kth.se/~chempy/branches/master/htmlcov
21   :alt: coverage
22.. image:: http://joss.theoj.org/papers/10.21105/joss.00565/status.svg
23   :target: https://doi.org/10.21105/joss.00565
24   :alt: Journal of Open Source Software DOI
25
26.. contents::
27
28
29About ChemPy
30------------
31ChemPy is a `Python <https://www.python.org>`_ package useful for
32chemistry (mainly physical/inorganic/analytical chemistry). Currently it includes:
33
34- Numerical integration routines for chemical kinetics (ODE solver front-end)
35- Integrated rate expressions (and convenience fitting routines)
36- Solver for equilibria (including multiphase systems)
37- Relations in physical chemistry:
38
39  - Debye-Hückel expressions
40  - Arrhenius & Eyring equation
41  - Einstein-Smoluchowski equation
42
43- Properties (pure python implementations from the literature)
44
45  - water density as function of temperature
46  - water permittivity as function of temperature and pressure
47  - water diffusivity as function of temperature
48  - water viscosity as function of temperature
49  - sulfuric acid density as function of temperature & weight fraction H₂SO₄
50  - More to come... (and contributions are most welcome!)
51
52
53Documentation
54-------------
55The easiest way to get started is to have a look at the examples in this README,
56and also the jupyter notebooks_. In addition there is auto-generated API documentation
57for the latest `stable release here <https://bjodah.github.io/chempy/latest>`_
58(and `here are <http://hera.physchem.kth.se/~chempy/branches/master/html>`_ the API docs for the development version).
59
60.. _notebooks: http://hera.physchem.kth.se/~chempy/branches/master/examples
61
62Installation
63------------
64Simplest way to install ChemPy and its (optional) dependencies is to use the
65`conda package manager <https://conda.pydata.org/docs/>`_::
66
67   $ conda install -c bjodah chempy pytest
68   $ pytest -rs -W ignore::chempy.ChemPyDeprecationWarning --pyargs chempy
69
70currently conda packages are only provided for Linux. On Windows and OS X
71you will need to use ``pip`` instead::
72
73   $ python3 -m pip install chempy pytest
74   $ python3 -m pytest -rs -W ignore::chempy.ChemPyDeprecationWarning --pyargs chempy
75
76there will a few tests which will be skipped due to some missing optional
77backends in addition to those in SciPy (used for solving systems of non-linear
78equations and ordinary differential equations).
79
80If you are still using Python 2 you can use the long-term-support 0.6.x branch
81of ChemPy which will continue to receive bugfixes::
82
83   $ python2 -m pip install "chempy<0.7"
84
85
86Optional dependencies
87~~~~~~~~~~~~~~~~~~~~~
88If you used ``conda`` to install ChemPy you can skip this section.
89But if you use ``pip`` the default installation is achieved by writing::
90
91   $ python3 -m pip install --user --upgrade chempy pytest
92   $ python3 -m pytest -rs --pyargs chempy
93
94you can skip the ``--user`` flag if you have got root permissions.
95You may be interested in using additional backends (in addition to those provided by SciPy)
96for solving ODE-systems and non-linear optimization problems::
97
98   $ python3 -m pip install chempy[all]
99
100Note that this option will install the following libraries
101(some of which require additional libraries to be present on your system):
102
103- `pygslodeiv2 <https://github.com/bjodah/pygslodeiv2>`_: solving initial value problems, requires GSL_. (>=1.16).
104- `pyodeint <https://github.com/bjodah/pyodeint>`_: solving initial value problems, requires boost_ (>=1.65.0).
105- `pycvodes <https://github.com/bjodah/pycvodes>`_: solving initial value problems, requires SUNDIALS_ (>=5.3.0).
106- `pykinsol <https://github.com/bjodah/pykinsol>`_: solving non-linear root-finding, requires SUNDIALS_ (>=5.3.0).
107- `pycompilation <https://github.com/bjodah/pycompilation>`_: python front-end for calling compilers, requires gcc/clang/icpc.
108- `pycodeexport <https://github.com/bjodah/pycodeexport>`_: package for code-generation, used when generating C++ code.
109
110.. _GSL: https://www.gnu.org/software/gsl/
111.. _boost: http://www.boost.org/
112.. _SUNDIALS: https://computation.llnl.gov/projects/sundials
113
114if you want to see what packages need to be installed on a Debian based system you may look at this
115`Dockerfile <scripts/environment/Dockerfile>`_.
116
117Using Docker
118~~~~~~~~~~~~
119If you have `Docker <https://www.docker.com>`_ installed, you may use it to host a jupyter
120notebook server::
121
122  $ ./scripts/host-jupyter-using-docker.sh . 8888
123
124the first time you run the command, some dependencies will be downloaded. When the installation
125is complete there will be a link visible which you can open in your browser. You can also run
126the test suite using the same docker-image::
127
128  $ ./scripts/host-jupyter-using-docker.sh . 0
129
130there will be a few skipped test (due to some dependencies not being installed by default) and
131quite a few warnings.
132
133
134Examples
135--------
136See demonstration scripts in `examples/ <https://github.com/bjodah/chempy/tree/master/examples>`_,
137and some rendered jupyter notebooks_.
138You may also browse the documentation for more examples. Below you will find a few code snippets:
139
140Parsing formulae
141~~~~~~~~~~~~~~~~
142.. code:: python
143
144   >>> from chempy import Substance
145   >>> ferricyanide = Substance.from_formula('Fe(CN)6-3')
146   >>> ferricyanide.composition == {0: -3, 26: 1, 6: 6, 7: 6}  # 0 for charge
147   True
148   >>> print(ferricyanide.unicode_name)
149   Fe(CN)₆³⁻
150   >>> print(ferricyanide.latex_name + ", " + ferricyanide.html_name)
151   Fe(CN)_{6}^{3-}, Fe(CN)<sub>6</sub><sup>3-</sup>
152   >>> print('%.3f' % ferricyanide.mass)
153   211.955
154
155
156as you see, in composition, the atomic numbers (and 0 for charge) is used as
157keys and the count of each kind became respective value.
158
159Balancing stoichiometry of a chemical reaction
160~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
161.. code:: python
162
163   >>> from chempy import balance_stoichiometry  # Main reaction in NASA's booster rockets:
164   >>> reac, prod = balance_stoichiometry({'NH4ClO4', 'Al'}, {'Al2O3', 'HCl', 'H2O', 'N2'})
165   >>> from pprint import pprint
166   >>> pprint(dict(reac))
167   {'Al': 10, 'NH4ClO4': 6}
168   >>> pprint(dict(prod))
169   {'Al2O3': 5, 'H2O': 9, 'HCl': 6, 'N2': 3}
170   >>> from chempy import mass_fractions
171   >>> for fractions in map(mass_fractions, [reac, prod]):
172   ...     pprint({k: '{0:.3g} wt%'.format(v*100) for k, v in fractions.items()})
173   ...
174   {'Al': '27.7 wt%', 'NH4ClO4': '72.3 wt%'}
175   {'Al2O3': '52.3 wt%', 'H2O': '16.6 wt%', 'HCl': '22.4 wt%', 'N2': '8.62 wt%'}
176
177
178ChemPy can also balance reactions where the reacting species are more complex and
179are better described in other terms than their molecular formula. A silly, yet
180illustrative example would be how to make pancakes without any partially used packages:
181
182.. code:: python
183
184   >>> substances = {s.name: s for s in [
185   ...     Substance('pancake', composition=dict(eggs=1, spoons_of_flour=2, cups_of_milk=1)),
186   ...     Substance('eggs_6pack', composition=dict(eggs=6)),
187   ...     Substance('milk_carton', composition=dict(cups_of_milk=4)),
188   ...     Substance('flour_bag', composition=dict(spoons_of_flour=60))
189   ... ]}
190   >>> pprint([dict(_) for _ in balance_stoichiometry({'eggs_6pack', 'milk_carton', 'flour_bag'},
191   ...                                                {'pancake'}, substances=substances)])
192   [{'eggs_6pack': 10, 'flour_bag': 2, 'milk_carton': 15}, {'pancake': 60}]
193
194
195ChemPy can even handle reactions with linear dependencies (underdetermined systems), e.g.:
196
197.. code:: python
198
199   >>> pprint([dict(_) for _ in balance_stoichiometry({'C', 'O2'}, {'CO2', 'CO'})])  # doctest: +SKIP
200   [{'C': x1 + 2, 'O2': x1 + 1}, {'CO': 2, 'CO2': x1}]
201
202
203the ``x1`` object above is an instance of SymPy's Symbol_. If we prefer to get a solution
204with minimal (non-zero) integer coefficients we can pass ``underdetermined=None``:
205
206.. code:: python
207
208   >>> pprint([dict(_) for _ in balance_stoichiometry({'C', 'O2'}, {'CO2', 'CO'}, underdetermined=None)])
209   [{'C': 3, 'O2': 2}, {'CO': 2, 'CO2': 1}]
210
211
212note however that even though this solution is in some sense "canonical",
213it is merely one of an inifite number of solutions (``x1`` from earlier may be any integer).
214
215
216.. _Symbol: http://docs.sympy.org/latest/modules/core.html#sympy.core.symbol.Symbol
217
218
219Balancing reactions
220~~~~~~~~~~~~~~~~~~~
221.. code:: python
222
223   >>> from chempy import Equilibrium
224   >>> from sympy import symbols
225   >>> K1, K2, Kw = symbols('K1 K2 Kw')
226   >>> e1 = Equilibrium({'MnO4-': 1, 'H+': 8, 'e-': 5}, {'Mn+2': 1, 'H2O': 4}, K1)
227   >>> e2 = Equilibrium({'O2': 1, 'H2O': 2, 'e-': 4}, {'OH-': 4}, K2)
228   >>> coeff = Equilibrium.eliminate([e1, e2], 'e-')
229   >>> coeff
230   [4, -5]
231   >>> redox = e1*coeff[0] + e2*coeff[1]
232   >>> print(redox)
233   32 H+ + 4 MnO4- + 20 OH- = 26 H2O + 4 Mn+2 + 5 O2; K1**4/K2**5
234   >>> autoprot = Equilibrium({'H2O': 1}, {'H+': 1, 'OH-': 1}, Kw)
235   >>> n = redox.cancel(autoprot)
236   >>> n
237   20
238   >>> redox2 = redox + n*autoprot
239   >>> print(redox2)
240   12 H+ + 4 MnO4- = 6 H2O + 4 Mn+2 + 5 O2; K1**4*Kw**20/K2**5
241
242Working with units
243~~~~~~~~~~~~~~~~~~
244Functions and objects useful
245for working with units are available from the ``chempy.units`` module. Here is an
246example of how ChemPy can check consistency of units:
247
248.. code:: python
249
250   >>> from chempy import Reaction
251   >>> r = Reaction.from_string("H2O -> H+ + OH-; 1e-4/M/s")
252   Traceback (most recent call last):
253   ...
254   ValueError: Unable to convert between units of "1/M" and "dimensionless"
255   >>> r = Reaction.from_string("H2O -> H+ + OH-; 1e-4/s")
256   >>> from chempy.units import to_unitless, default_units as u
257   >>> to_unitless(r.param, 1/u.minute)
258   0.006
259
260right now the ``.units`` module wraps the quantities_ package with some minor
261additions and work-arounds. However, there is no guarantee that the underlying
262package will not change in a future version of ChemPy (there are many packages
263for dealing with units in the scientific Python ecosystem).
264
265.. _quantities: http://python-quantities.readthedocs.io/en/latest/
266
267
268Chemical equilibria
269~~~~~~~~~~~~~~~~~~~
270If we want to predict pH of a bicarbonate solution we simply just need pKa and pKw values:
271
272.. code:: python
273
274   >>> from collections import defaultdict
275   >>> from chempy.equilibria import EqSystem
276   >>> eqsys = EqSystem.from_string("""HCO3- = H+ + CO3-2; 10**-10.3
277   ... H2CO3 = H+ + HCO3-; 10**-6.3
278   ... H2O = H+ + OH-; 10**-14/55.4
279   ... """)  # pKa1(H2CO3) = 6.3 (implicitly incl. CO2(aq)), pKa2=10.3 & pKw=14
280   >>> arr, info, sane = eqsys.root(defaultdict(float, {'H2O': 55.4, 'HCO3-': 1e-2}))
281   >>> conc = dict(zip(eqsys.substances, arr))
282   >>> from math import log10
283   >>> print("pH: %.2f" % -log10(conc['H+']))
284   pH: 8.30
285
286here is another example for ammonia:
287
288.. code:: python
289
290   >>> from chempy import Equilibrium
291   >>> from chempy.chemistry import Species
292   >>> water_autop = Equilibrium({'H2O'}, {'H+', 'OH-'}, 10**-14)  # unit "molar" assumed
293   >>> ammonia_prot = Equilibrium({'NH4+'}, {'NH3', 'H+'}, 10**-9.24)  # same here
294   >>> substances = [Species.from_formula(f) for f in 'H2O OH- H+ NH3 NH4+'.split()]
295   >>> eqsys = EqSystem([water_autop, ammonia_prot], substances)
296   >>> print('\n'.join(map(str, eqsys.rxns)))  # "rxns" short for "reactions"
297   H2O = H+ + OH-; 1e-14
298   NH4+ = H+ + NH3; 5.75e-10
299   >>> init_conc = defaultdict(float, {'H2O': 1, 'NH3': 0.1})
300   >>> x, sol, sane = eqsys.root(init_conc)
301   >>> assert sol['success'] and sane
302   >>> print(', '.join('%.2g' % v for v in x))
303   1, 0.0013, 7.6e-12, 0.099, 0.0013
304
305
306Concepts
307~~~~~~~~~
308ChemPy collects equations and utility functions for working with
309concepts such as `ionic strength <https://en.wikipedia.org/wiki/Ionic_strength>`_:
310
311.. code:: python
312
313   >>> from chempy.electrolytes import ionic_strength
314   >>> ionic_strength({'Fe+3': 0.050, 'ClO4-': 0.150}) == .3
315   True
316
317note how ChemPy parsed the charges from the names of the substances. There are
318also e.g. empirical equations and convenience classes for them available, e.g.:
319
320.. code:: python
321
322   >>> from chempy.henry import Henry
323   >>> kH_O2 = Henry(1.2e-3, 1800, ref='carpenter_1966')
324   >>> print('%.1e' % kH_O2(298.15))
325   1.2e-03
326
327to get more information about e.g. this class, you may can look at the `API documentation`_.
328
329.. _API documentation: https://bjodah.github.io/chempy/latest/chempy.html#module-chempy.henry
330
331
332Chemical kinetics (system of ordinary differential equations)
333~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
334A common task when modelling problems in chemistry is to investigate the time dependence
335of a system. This branch of study is known as
336`chemical kinetics <https://en.wikipedia.org/wiki/Chemical_kinetics>`_, and ChemPy has
337some classes and functions for working with such problems:
338
339.. code:: python
340
341   >>> from chempy import ReactionSystem  # The rate constants below are arbitrary
342   >>> rsys = ReactionSystem.from_string("""2 Fe+2 + H2O2 -> 2 Fe+3 + 2 OH-; 42
343   ...     2 Fe+3 + H2O2 -> 2 Fe+2 + O2 + 2 H+; 17
344   ...     H+ + OH- -> H2O; 1e10
345   ...     H2O -> H+ + OH-; 1e-4""")  # "[H2O]" = 1.0 (actually 55.4 at RT)
346   >>> from chempy.kinetics.ode import get_odesys
347   >>> odesys, extra = get_odesys(rsys)
348   >>> from collections import defaultdict
349   >>> import numpy as np
350   >>> tout = sorted(np.concatenate((np.linspace(0, 23), np.logspace(-8, 1))))
351   >>> c0 = defaultdict(float, {'Fe+2': 0.05, 'H2O2': 0.1, 'H2O': 1.0, 'H+': 1e-2, 'OH-': 1e-12})
352   >>> result = odesys.integrate(tout, c0, atol=1e-12, rtol=1e-14)
353   >>> import matplotlib.pyplot as plt
354   >>> fig, axes = plt.subplots(1, 2, figsize=(12, 5))
355   >>> for ax in axes:
356   ...     _ = result.plot(names=[k for k in rsys.substances if k != 'H2O'], ax=ax)
357   ...     _ = ax.legend(loc='best', prop={'size': 9})
358   ...     _ = ax.set_xlabel('Time')
359   ...     _ = ax.set_ylabel('Concentration')
360   >>> _ = axes[1].set_ylim([1e-13, 1e-1])
361   >>> _ = axes[1].set_xscale('log')
362   >>> _ = axes[1].set_yscale('log')
363   >>> _ = fig.tight_layout()
364   >>> _ = fig.savefig('examples/kinetics.png', dpi=72)
365
366.. image:: https://raw.githubusercontent.com/bjodah/chempy/master/examples/kinetics.png
367
368Properties
369~~~~~~~~~~
370One of the fundamental tasks in science is the careful collection of data about the world
371around us. ChemPy contains a growing collection of parametrizations from the scientific
372literature with relevance in chemistry. Here is how you use one of these formulations:
373
374.. code:: python
375
376   >>> from chempy import Substance
377   >>> from chempy.properties.water_density_tanaka_2001 import water_density as rho
378   >>> from chempy.units import to_unitless, default_units as u
379   >>> water = Substance.from_formula('H2O')
380   >>> for T_C in (15, 25, 35):
381   ...     concentration_H2O = rho(T=(273.15 + T_C)*u.kelvin, units=u)/water.molar_mass(units=u)
382   ...     print('[H2O] = %.2f M (at %d °C)' % (to_unitless(concentration_H2O, u.molar), T_C))
383   ...
384   [H2O] = 55.46 M (at 15 °C)
385   [H2O] = 55.35 M (at 25 °C)
386   [H2O] = 55.18 M (at 35 °C)
387
388
389Run notebooks using binder
390~~~~~~~~~~~~~~~~~~~~~~~~~~
391Using only a web-browser (and an internet connection) it is possible to explore the
392notebooks here: (by the courtesy of the people behind mybinder)
393
394.. image:: http://mybinder.org/badge.svg
395   :target: https://mybinder.org/v2/gh/bjodah/chempy/f5f2546e79e165ba8fb258fc87d83a7fbdcbad64?filepath=index.ipynb
396   :alt: Binder
397
398
399Citing
400------
401If you make use of ChemPy in e.g. academic work you may cite the following peer-reviewed publication:
402
403.. image:: http://joss.theoj.org/papers/10.21105/joss.00565/status.svg
404   :target: https://doi.org/10.21105/joss.00565
405   :alt: Journal of Open Source Software DOI
406
407Depending on what underlying solver you are using you should also cite the appropriate paper
408(you can look at the list of references in the JOSS article). If you need to reference,
409in addition to the paper, a specific point version of ChemPy (for e.g. reproducibility)
410you can get per-version DOIs from the zendodo archive:
411
412.. image:: https://zenodo.org/badge/8840/bjodah/chempy.svg
413   :target: https://zenodo.org/badge/latestdoi/8840/bjodah/chempy
414   :alt: Zenodo DOI
415
416Licensing
417---------
418The source code is Open Source and is released under the very permissive
419`"simplified (2-clause) BSD license" <https://opensource.org/licenses/BSD-2-Clause>`_.
420See `LICENSE <LICENSE>`_ for further details.
421
422See also
423--------
424- `SymPy <https://github.com/sympy/sympy>`_
425- `pyneqsys <https://github.com/bjodah/pyneqsys>`_
426- `pyodesys <https://github.com/bjodah/pyodesys>`_
427- `thermo <https://github.com/CalebBell/thermo>`_
428
429Contributing
430------------
431Contributors are welcome to suggest improvements at https://github.com/bjodah/chempy
432(see further details `here <CONTRIBUTING.rst>`_).
433
434
435Author
436------
437Björn I. Dahlgren, contact:
438 - gmail address: bjodah
439