Skip to content

Commit

Permalink
Merge pull request #34 from mvdh7/develop
Browse files Browse the repository at this point in the history
Merge for v0.3.1 release
  • Loading branch information
mvdh7 authored Jul 16, 2019
2 parents bf9e486 + 59c2298 commit 5eb5a59
Show file tree
Hide file tree
Showing 37 changed files with 5,398 additions and 7,415 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

[![pypi badge](https://img.shields.io/pypi/v/pytzer.svg?style=popout)](https://pypi.org/project/pytzer/)

Pitzer model for chemical activities in aqueous solutions, undergoing beta testing and development.
Pitzer model for chemical activities in aqueous solutions. Undergoing beta testing and development.

**Installation:**

Expand All @@ -15,4 +15,4 @@ The second line above is strongly recommended, but optional. It upgrades [Autogr

**Documentation:** [pytzer.readthedocs.io](https://pytzer.readthedocs.io/en/latest/), including a [quick-start guide](https://pytzer.readthedocs.io/en/latest/quick-start/).

Implemented and maintained by [Matthew P. Humphreys](https://mvdh.xyz), University of East Anglia, Norwich, UK.
Pytzer is implemented and maintained by [Matthew P. Humphreys](https://mvdh.xyz) at the University of East Anglia (Norwich, UK).
59 changes: 15 additions & 44 deletions docs/index.md
Original file line number Diff line number Diff line change
@@ -1,67 +1,38 @@
<!--<script src='https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/MathJax.js?config=TeX-MML-AM_CHTML' async></script>-->

# Pytzer v0.3.0
# Pytzer v0.3.1

**Pytzer** is a Python 3.6+ implementation of the Pitzer model for chemical activities in aqueous solutions [[P91](references/#P91)].


## Installation

If using Conda, first create and activate a new environment with Python v3.6+, NumPy v1.15+ and SciPy v1.2+. Other versions are probably fine, but untested. Activate the environment, and then enter:

```shell
pip install pytzer
pip install git+https://github.com/mvdh7/autograd#egg=autograd --upgrade --no-cache-dir
```
pip install pytzer
pip install git+https://github.com/mvdh7/autograd#egg=autograd --upgrade --no-cache-dir

The second line above is strongly recommended, but optional. It upgrades [Autograd](https://github.com/HIPS/autograd) to the latest version that has been tested with Pytzer, which eliminates some deprecation warnings that may appear when using the relatively old Autograd version available from PyPI. You could also switch `mvdh7` in the URL to `HIPS` to get the very latest Autograd straight from the horse's mouth.

See the [quick-start guide](quick-start) for more detailed instructions and examples.


## Development status

Pytzer is in beta. Tests of the accuracy of its coefficients and equations are underway, so results may change. API may change and functions may be added or removed. Use at your own peril!


## Modules

<table><tr>

<td><strong>Module</strong></td>
<td><strong>Purpose</strong></td>

</tr><tr><td><code>.io</code></td>
<td><a href="modules/io">Import and export data</a></td>

</tr><tr><td><code>.model</code></td>
<td><a href="modules/model">Implement the Pitzer model</a></td>

</tr><tr><td><code>.cflibs</code></td>
<td><a href="modules/cflibs">Define combinations of model coefficients to use</a></td>

</tr><tr><td><code>.coeffs</code></td>
<td><a href="modules/coeffs">Define functions to evaluate Pitzer model coefficients</a></td>

</tr><tr><td><code>.tables</code></td>
<td><a href="modules/tables">Store tables of coefficient values</a></td>

</tr><tr><td><code>.jfuncs</code></td>
<td><a href="modules/jfuncs">Define unsymmetrical mixing functions</a></td>

</tr><tr><td><code>.props</code></td>
<td><a href="modules/props">Define universal ionic properties</a></td>

</tr><tr><td><code>.constants</code></td>
<td><a href="modules/constants">Define physical constants</a></td>

</tr><tr><td><code>.teos10</code></td>
<td><a href="modules/teos10">Calculate properties of pure water</a></td>

</tr><tr><td><code>.meta</code></td>
<td><a href="modules/meta">Define package metadata</a></td>

</tr></table>
* `.io` - imports and exports data;
* `.model` - implements the Pitzer model;
* `.cflibs` - defines combinations of model coefficients (i.e. *coefficient libraries*) to use in the model;
* `.coefficients` - defines interaction coefficients as functions of temperature and pressure;
* `.tables` - stores tables of model coefficient values;
* `.debyehueckel` - defines functions for Debye-Hückel limiting slopes;
* `.jfuncs` - defines unsymmetrical mixing functions;
* `.properties` - defines universal solute properties;
* `.constants` - defines physicochemical constants;
* `.teos10` - calculates properties of pure water;
* `.matrix` - implements an alternative matrix-based Pitzer model;
* `.meta` - stores metadata about the Pytzer package.

## Acknowledgements

Expand Down
70 changes: 33 additions & 37 deletions docs/modules/cflibs.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ MathJax.Hub.Config({TeX: {extensions: ["[mhchem]/mhchem.js"]}});

`.cflibs` provides specific combinations of coefficients that have been used in published Pitzer models, to use with Pytzer.

To use a Pitzer model we need to define a set of coefficients that quantify the interactions between different combinations of ions. We do this by creating a **coefficient library**, which contains functions that evaluate the coefficients for every possible interaction. The functions themselves [are defined separately](../coeffs).
To use a Pitzer model we need to define a set of coefficients that quantify the interactions between different combinations of ions. We do this by creating a **coefficient library**, which contains functions that evaluate the coefficients for every possible interaction. The functions themselves [are defined separately](../coefficients).

A number of [pre-defined coefficient libraries](#pre-defined-coefficient-libraries) are included in **pytzer.cflibs**. To use these, all you need to do is assign the variable `cflib` appropriately:

Expand Down Expand Up @@ -51,7 +51,7 @@ Several ready-to-use coefficient libraries are available in this module. To deco

</tr><tr>
<td>WM13</td>
<td>$\ce{Ca^2+}$, $\ce{Cl^-}$, $\ce{H^+}$, $\ce{HSO4^-}$, $\ce{K^+}$, $\ce{Mg^2+}$, $\ce{MgOH^+}$, $\ce{Na^+}$, $\ce{OH^-}$, $\ce{SO4^2-}$</td>
<td>$\ce{Ca^2+}$, $\ce{Cl-}$, $\ce{H+}$, $\ce{HSO4-}$, $\ce{K+}$, $\ce{Mg^2+}$, $\ce{MgOH+}$, $\ce{Na+}$, $\ce{OH-}$, $\ce{SO4^2-}$</td>
<td><a href="../../references/#WM13">WM13</a></td>

</tr></table>
Expand All @@ -60,8 +60,7 @@ Several ready-to-use coefficient libraries are available in this module. To deco

## cflib methods

A few handy methods are provided as part of the **CoeffLib** class. Brief summaries are provided below, and here is a usage example of all of them together:

A few handy methods are provided as part of the **CoefficientLibrary** class. Brief summaries are provided below, and here is a usage example of all of them together:

```python
import pytzer as pz
Expand All @@ -75,7 +74,7 @@ cflib = deepcopy(pz.cflibs.M88)
cflib.get_contents()

# Add a new ion into the mix
cflib.ions = np.append(cflib.ions,'K')
cflib.ions = np.append(cflib.ions, 'K')

# Add zero-functions for all interactions with the new ion
cflib.add_zeros(cflib.ions)
Expand All @@ -84,41 +83,39 @@ cflib.add_zeros(cflib.ions)
cflib.name = 'M88-modified'

# Print out the coefficients evaluated at 298.15 K
cflib.print_coeffs(298.15,'coeff_file.txt')
cflib.print_coefficients(298.15, 'coeff_file.txt')
```

The methods are as follows:

### .add_zeros
### `.add_zeros` - add entries for missing interactions

`CoeffLib.add_zeros(ions)` adds zero-functions for all missing interactions, given a list of ions.
`CoefficientLibrary.add_zeros(ions)` adds zero-functions for all missing interactions, given a list of ions.

### .get_contents
### `.get_contents` - create lists of ions and sources

`CoeffLib.get_contents()` scans through all functions within the **CoeffLib**, and puts lists of all ions and of all sources in its **ions** and **srcs** fields.
`CoefficientLibrary.get_contents()` scans through all functions within the **CoefficientLibrary**, and puts lists of all ions and of all sources in its **ions** and **srcs** fields.

The list of ions is determined from the dict keys, while sources are determined from the function names.

### .print_coeffs

`CoeffLib.print_coeffs(T,filename)` evaluates all coefficients in a **cflib** at a single input temperature and pressure, and prints the results to a text file (`filename`).
### `.print_coefficients` - print out model coefficients

`CoefficientLibrary.print_coefficients(T,filename)` evaluates all coefficients in a **cflib** at a single input temperature and pressure, and prints the results to a text file (`filename`).

<hr />

## How a CoeffLib works
## How a CoefficientLibrary works

To modify an existing **CoeffLib**, or create a new one, it is first necessary to understand how they are used within Pytzer, as follows. A basic understanding of the workings of the Pitzer model is assumed.
To modify an existing **CoefficientLibrary**, or create a new one, it is first necessary to understand how they are used within Pytzer, as follows. A basic understanding of the workings of the Pitzer model is assumed.

A **CoeffLib** or **cflib** is an object of the class `CoeffLib` as defined within **pytzer.cflibs**. From the initalisation function we can see that it contains the following fields:
A **CoefficientLibrary** or **cflib** is an object of the class `CoefficientLibrary`. From the initalisation function we can see that it contains the following fields:

```python
class CoeffLib:
class CoefficientLibrary:

# Initialise
def __init__(self):
self.name = ''

self.dh = {} # Aosm
self.bC = {} # c-a
self.theta = {} # c-c' and a-a'
Expand All @@ -127,17 +124,16 @@ class CoeffLib:
self.lambd = {} # n-c and n-a
self.zeta = {} # n-c-a
self.mu = {} # n-n-n

self.ions = []
self.srcs = []
```

Each field is then filled with functions from **pytzer.debyehueckel**, **pytzer.coeffs** or **pytzer.jfuncs** that define the Pitzer model interaction coefficients, as follows. (Descriptions of the required contents of the functions themselves are in the separate <a href="../coeffs"><strong>pytzer.coeffs</strong> documentation</a>.)
Each field is then filled with functions from modules **debyehueckel**, **coefficients** or **jfuncs** that define the Pitzer model interaction coefficients, as follows. (Descriptions of the required contents of the functions themselves are in the separate <a href="../coefficients"><strong>coefficients</strong> documentation</a>.)


### Debye-Hückel limiting slope

The function for the Debye-Hückel limiting slope (i.e. <i>A<sub>ϕ</sub></i>) is stored as `CoeffLib.dh['Aosm']`.
The function for the Debye-Hückel limiting slope (i.e. <i>A<sub>ϕ</sub></i>) is stored as `CoefficientLibrary.dh['Aosm']`.


### Cation-anion interactions
Expand Down Expand Up @@ -212,7 +208,7 @@ import pytzer as pz
cflib = pz.cflibs.M88

# Update Na-Cl interaction function to Archer (1992)
cflib.bC['Na-Cl'] = pz.coeffs.bC_Na_Cl_A92ii
cflib.bC['Na-Cl'] = pz.coefficients.bC_Na_Cl_A92ii
```

Note that the statement to get the **cflib** (`cflib = pz.cflibs.M88`) only references, not copies, from **pytzer.cflibs**. To copy, and make changes without modifying the original, use:
Expand All @@ -226,58 +222,58 @@ cflib = deepcopy(pz.cflibs.M88)
cflib.name = 'M88-modified' # so we know it's been changed

# Update Na-Cl interaction function to Archer (1992)
cflib.bC['Na-Cl'] = pz.coeffs.bC_Na_Cl_A92ii
cflib.bC['Na-Cl'] = pz.coefficients.bC_Na_Cl_A92ii
```

<hr />

## Build your own

You can also construct your own **cflib** from scratch. In the example below, we initialise a `cflib` using the `pytzer.cflibs.CoeffLib` class. We add functions from `pytzer.coeffs` for the system Na-Ca-Cl using functions from Møller (1988). Finally, we use the method `add_zeros` to fill out any interactions that we have neglected to provide functions for with zeros.
You can also construct your own **cflib** from scratch. In the example below, we initialise a `cflib` using the `pytzer.cflibs.CoefficientLibrary` class. We add functions from `pytzer.coefficients` for the system Na-Ca-Cl using functions from Møller (1988). Finally, we use the method `add_zeros` to fill out any interactions that we have neglected to provide functions for with zeros.

```python
import pytzer as pz
import numpy as np

# Initialise
mycflib = pz.cflibs.CoeffLib()
mycflib = pz.cflibs.CoefficientLibrary()

# Debye-Hueckel limiting slope
mycflib.dh['Aosm'] = coeffs.Aosm_M88
mycflib.dh['Aosm'] = coefficients.Aosm_M88

# Cation-anion interactions (betas and Cs)
mycflib.bC['Ca-Cl' ] = coeffs.bC_Ca_Cl_M88
mycflib.bC['Na-Cl' ] = coeffs.bC_Na_Cl_M88
mycflib.bC['Ca-Cl' ] = coefficients.bC_Ca_Cl_M88
mycflib.bC['Na-Cl' ] = coefficients.bC_Na_Cl_M88

# Cation-cation and anion-anion interactions (theta)
# c-c'
mycflib.theta['Ca-Na' ] = coeffs.theta_Ca_Na_M88
mycflib.theta['Ca-Na' ] = coefficients.theta_Ca_Na_M88

# Unsymmetrical mixing functions
mycflib.jfunc = jfuncs.Harvie

# Triplet interactions (psi)
# c-c'-a
mycflib.psi['Ca-Na-Cl' ] = coeffs.psi_Ca_Na_Cl_M88
mycflib.psi['Ca-Na-Cl' ] = coefficients.psi_Ca_Na_Cl_M88

# Fill missing functions with zeros (none in this instance)
mycflib.add_zeros(np.array(['Na','Ca','Cl']))
```

To explicitly assign zeros to any interaction (i.e. the interaction is ignored by the model), you can use the appropriate zero-functions from **pytzer.coeffs**:
To explicitly assign zeros to any interaction (i.e. the interaction is ignored by the model), you can use the appropriate zero-functions from **pytzer.coefficients**:

```python
mycflib.bC['Ba-SO4'] = coeffs.bC_zero # ignore Ba-SO4 interactions
mycflib.bC['H-Na'] = coeffs.theta_zero # ignore H-Na interactions
mycflib.psi['H-Mg-OH'] = coeffs.psi_zero # ignore H-Mg-OH interactions
mycflib.bC['Ba-SO4'] = coefficients.bC_zero # ignore Ba-SO4 interactions
mycflib.bC['H-Na'] = coefficients.theta_zero # ignore H-Na interactions
mycflib.psi['H-Mg-OH'] = coefficients.psi_zero # ignore H-Mg-OH interactions
```

## Print out coefficients

You can use the function **CoeffLib.print_coeffs** to create a file containing every coefficient, evaluated at a single input temperature and pressure of your choice. For example:
You can use the function **CoefficientLibrary.print_coefficients** to create a file containing every coefficient, evaluated at a single input temperature and pressure of your choice. For example:

```python
mycflib.print_coeffs(298.15,'myCoeffs.txt')
mycflib.print_coefficients(298.15,'mycoefficients.txt')
```

would evaluate every coefficient at 298.15 K and print the results to the file **myCoeffs.txt**.
would evaluate every coefficient at 298.15 K and print the results to the file **mycoefficients.txt**.
2 changes: 1 addition & 1 deletion docs/modules/coeffs.md → docs/modules/coefficients.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ MathJax.Hub.Config({tex2jax: {inlineMath: [['$','$'], ['\\(','\\)']]}});

*The casual user has no need to explicitly call this module.*

`.coeffs` contains functions for ionic interaction coefficients.
`.coefficients` contains functions for ionic interaction coefficients.

There are six different types of coefficient functions, each representing a different interaction type. The function names begin with:

Expand Down
2 changes: 1 addition & 1 deletion docs/modules/constants.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

*The casual user has no need to explicitly call this module.*

**pytzer.constants** contains physical constants required by Pytzer.
`.constants` contains physical constants required by Pytzer.

## Universal constants

Expand Down
2 changes: 1 addition & 1 deletion docs/modules/debyehueckel.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ MathJax.Hub.Config({tex2jax: {inlineMath: [['$','$'], ['\\(','\\)']]}});

`.debyehueckel` contains functions to evaluate the Debye-Hückel limiting slope for the osmotic coefficient (i.e. $A_\phi$).

The syntax for the functions is similar to that for the [interaction coefficients](../coeffs): inputs are `tempK` and `pres`, in K and dbar respectively; outputs are the $A_\phi$ value `Aosm` and a logical validity indicator `valid`.
The syntax for the functions is similar to that for the [interaction coefficients](../coefficients): inputs are `tempK` and `pres`, in K and dbar respectively; outputs are the $A_\phi$ value `Aosm` and a logical validity indicator `valid`.

Several different calculation approaches are possible. As a function of temperature only, at a pressure of c. 1 atm:

Expand Down
40 changes: 34 additions & 6 deletions docs/modules/io.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ MathJax.Hub.Config({TeX: {extensions: ["[mhchem]/mhchem.js"]}});

## `.getmols` - import CSV dataset

Imports a table of temperature, pressure and molality data, formatted ready for Pytzer's [model functions](../model).
Imports a table of temperature, pressure and molality data, formatted ready for Pytzer's [model functions](../model). For calculations without equilibration, where the concentration of every individual solute is specified in the input file.

**Syntax:**

Expand All @@ -27,7 +27,6 @@ Imports a table of temperature, pressure and molality data, formatted ready for
* `delimiter` - column delimiter. Optional; defaults to `','`.
* `skip_top` - number of rows in `filename` above the row containing the headers described below. Optional; defaults to `0`.


The file should be in comma-separated variable (CSV) format, but if another separator is used this can be specified with `delimiter`. The contents should be formatted as follows:

* the first row provides the header for each column;
Expand Down Expand Up @@ -62,13 +61,42 @@ Note: oceanographers typically record pressure within the ocean as only due to t
**Outputs:**

* `mols` - concentrations (molality) of solutes in mol·kg<sup>−1</sup>. Each row represents a different ion, while each column characterises a different solution composition;
* `ions` - list of the solute codes, corresponding to the rows in <code>mols</code>;
* `tempK` - solution temperature in K. Each value corresponds to the matching column in <code>mols</code>;
* `pres` - solution pressure in dbar. Each value corresponds to the matching column in <code>mols</code>.
* `ions` - list of the solute codes, corresponding to the rows in `mols`;
* `tempK` - solution temperature in K. Each value corresponds to the matching column in `mols`;
* `pres` - solution pressure in dbar. Each value corresponds to the matching column in `mols`.

<hr />

## `.gettots` - import CSV dataset

Imports a table of temperature, pressure and molality data, formatted ready for Pytzer's [equilibration functions](../equilibrate). For calculations with equilibration, where some solution components are given as totals.

**Syntax:**

```python
>>> tots, mols, eles, ions, tempK, pres = pz.io.gettots(filename, delimiter=',', skip_top=0)
```

**Inputs:**

* `filename` - path and name of a text file containing a set of solution compositions and corresponding temperatures. See full decription below;
* `delimiter` - column delimiter. Optional; defaults to `','`.
* `skip_top` - number of rows in `filename` above the row containing the headers described below. Optional; defaults to `0`.

The file should be in comma-separated variable (CSV) format, and its contents follow the same rules as for the `getmols` function above. However, it may also include *total* concentrations for solutes that are in dynamic equilibria to be solved. These are indicated by prefixing the solute name with `t_` in the header row.

**Outputs:**

* `tots` - total concentrations (molality) of equilibrating solutes in mol·kg<sup>−1</sup>. Each row represents a different set of solutes, while each column characterises a different solution composition;
* `mols` - concentrations (molality) of non-equilibrating solutes in mol·kg<sup>−1</sup>. Each row represents a different solute, while each column characterises a different solution composition;
* `eles` - list of the solute codes corresponding to the rows in `tots`;
* `ions` - list of the solute codes corresponding to the rows in `mols`;
* `tempK` - solution temperature in K. Each value corresponds to the matching column in `mols`;
* `pres` - solution pressure in dbar. Each value corresponds to the matching column in `mols`.

<hr />

## .saveall - save to CSV
## `.saveall` - save to CSV

Saves the results of all calculations to a CSV file, with a format similar to that described for the input file above.

Expand Down
Loading

0 comments on commit 5eb5a59

Please sign in to comment.