diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml new file mode 100644 index 00000000..378a2342 --- /dev/null +++ b/.github/workflows/docs.yml @@ -0,0 +1,17 @@ +name: docs +on: + push: + branches: + - develop +permissions: + contents: write +jobs: + deploy: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-python@v4 + with: + python-version: 3.x + - run: pip install mkdocs-material + - run: mkdocs gh-deploy --force diff --git a/.github/workflows/python-package.yml b/.github/workflows/python-package.yml index 9c3bafd9..0a25f0ce 100644 --- a/.github/workflows/python-package.yml +++ b/.github/workflows/python-package.yml @@ -8,25 +8,19 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - python-version: [3.7, 3.8, 3.9] + python-version: [3.7, 3.8, 3.9, "3.10", "3.11"] steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v2 + uses: actions/setup-python@v4 with: python-version: ${{ matrix.python-version }} - name: Install dependencies run: | python -m pip install --upgrade pip - pip install flake8 pytest - if [ -f requirements.txt ]; then pip install -r requirements.txt; fi - - name: Lint with flake8 - run: | - # stop the build if there are Python syntax errors or undefined names - flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics - # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide - flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics + pip install pytest pandas openpyxl + pip install . - name: Test with pytest run: | pytest diff --git a/.misc/coverage.svg b/.misc/coverage.svg index 5cc1bb57..f9eb6b47 100644 --- a/.misc/coverage.svg +++ b/.misc/coverage.svg @@ -15,7 +15,7 @@ coverage coverage - 42% - 42% + 55% + 55% diff --git a/.misc/coverage.txt b/.misc/coverage.txt index 73e8c4f1..7c061a67 100644 --- a/.misc/coverage.txt +++ b/.misc/coverage.txt @@ -2,40 +2,56 @@ Name Stmts Miss Cover ---------------------------------------------------------------- pytzer/__init__.py 15 0 100% pytzer/constants.py 14 0 100% -pytzer/convert.py 30 6 80% +pytzer/convert.py 30 19 37% pytzer/debyehueckel.py 69 9 87% -pytzer/dissociation.py 152 70 54% +pytzer/dissociation.py 175 54 69% pytzer/equilibrate/__init__.py 41 15 63% -pytzer/equilibrate/components.py 352 140 60% +pytzer/equilibrate/components.py 364 86 76% pytzer/equilibrate/stoichiometric.py 118 1 99% -pytzer/equilibrate/thermodynamic.py 83 17 80% -pytzer/io.py 37 5 86% +pytzer/equilibrate/thermodynamic.py 83 10 88% +pytzer/get.py 37 5 86% +pytzer/libraries/Clegg22.py 88 0 100% +pytzer/libraries/Clegg23.py 158 0 100% pytzer/libraries/Clegg94.py 11 0 100% pytzer/libraries/Greenberg89.py 25 0 100% pytzer/libraries/Harvie84.py 259 0 100% -pytzer/libraries/MarChemSpec.py 111 0 100% +pytzer/libraries/HeMorse93.py 274 0 100% +pytzer/libraries/Humphreys22.py 77 0 100% pytzer/libraries/MarChemSpec25.py 107 0 100% +pytzer/libraries/MarChemSpec.py 111 0 100% pytzer/libraries/Millero98.py 255 0 100% pytzer/libraries/Moller88.py 17 0 100% -pytzer/libraries/ParameterLibrary.py 247 13 95% +pytzer/libraries/MyMarChemSpecCO2.py 43 0 100% +pytzer/libraries/ParameterLibrary.py 333 96 71% pytzer/libraries/Seawater.py 257 0 100% -pytzer/libraries/Waters13.py 95 0 100% +pytzer/libraries/Waters13.py 98 0 100% +pytzer/libraries/Waters13_Clegg22.py 110 0 100% +pytzer/libraries/Waters13_Humphreys22.py 99 0 100% pytzer/libraries/Waters13_MarChemSpec25.py 95 0 100% -pytzer/libraries/__init__.py 21 0 100% +pytzer/libraries/__init__.py 35 0 100% +pytzer/matrix.py 48 36 25% pytzer/meta.py 12 1 92% -pytzer/model.py 111 2 98% -pytzer/parameters.py 6323 5012 21% -pytzer/prepare.py 113 98 13% +pytzer/model.py 117 6 95% +pytzer/parameters/__init__.py 6382 4403 31% +pytzer/parameters/heMorse1993.py 165 70 58% +pytzer/parameters/holmesMesmer1992.py 33 26 21% +pytzer/parameters/pabalanPitzer1987.py 57 33 42% +pytzer/parameters/spencer1990.py 33 26 21% +pytzer/prepare.py 113 94 17% pytzer/properties.py 5 0 100% pytzer/teos10.py 41 10 76% pytzer/unsymmetrical.py 46 1 98% tests/__init__.py 0 0 100% -tests/test_CRP94.py 11 0 100% -tests/test_M88.py 16 0 100% -tests/test_convert.py 25 0 100% +tests/test_CRP94.py 34 0 100% +tests/test_CWTD23_params.py 238 2 99% +tests/test_CWTD23_solver.py 51 1 98% +tests/test_HWT22_params.py 125 9 93% +tests/test_HWT22_solver.py 104 0 100% +tests/test_M88.py 14 0 100% tests/test_jax_settings.py 4 0 100% tests/test_model.py 41 0 100% +tests/test_pKs.py 13 0 100% tests/test_stoichiometric.py 130 0 100% tests/test_unsymmetrical.py 33 0 100% ---------------------------------------------------------------- -TOTAL 9322 5400 42% +TOTAL 11237 5013 55% diff --git a/.readthedocs.yml b/.readthedocs.yml deleted file mode 100644 index 634b5117..00000000 --- a/.readthedocs.yml +++ /dev/null @@ -1,19 +0,0 @@ -# .readthedocs.yml -# Read the Docs configuration file -# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details - -# Required -version: 2 - -# Build documentation with MkDocs -mkdocs: - configuration: mkdocs.yml - -# # Optionally build your docs in additional formats such as PDF and ePub -# formats: all - -# Optionally set the version of Python and requirements required to build your docs -python: - version: 3.8 - install: - - requirements: docs/requirements.txt diff --git a/README.md b/README.md index 5d6cfd0d..0657bb1b 100644 --- a/README.md +++ b/README.md @@ -1,14 +1,13 @@ # Pytzer ![Tests](https://github.com/mvdh7/pytzer/workflows/Tests/badge.svg) -[![Coverage](https://github.com/mvdh7/pytzer/blob/master/.misc/coverage.svg)](https://github.com/mvdh7/pytzer/blob/master/.misc/coverage.txt) +[![Coverage](https://github.com/mvdh7/pytzer/blob/main/.misc/coverage.svg)](https://github.com/mvdh7/pytzer/blob/main/.misc/coverage.txt) [![pypi badge](https://img.shields.io/pypi/v/pytzer.svg?style=popout)](https://pypi.org/project/pytzer/) [![DOI](https://img.shields.io/badge/DOI-10.5281%2Fzenodo.2637914-informational)](https://doi.org/10.5281/zenodo.2637914) -[![Docs](https://readthedocs.org/projects/pytzer/badge/?version=latest&style=flat)](https://pytzer.readthedocs.io/en/latest/) [![License: GPL v3](https://img.shields.io/badge/License-GPLv3-blue.svg)](https://www.gnu.org/licenses/gpl-3.0) [![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black) -Pytzer is a Python implementation of the Pitzer model for chemical activities in aqueous solutions [[P91](https://pytzer.readthedocs.io/en/jax/refs/#p)] plus solvers to determine the equilibrium state of the system. +Pytzer is a Python implementation of the Pitzer model for chemical activities in aqueous solutions [[P91](https://mvdh.xyz/pytzer/refs/#p)] plus solvers to determine the equilibrium state of the system. **Pytzer is in beta! Use at your own peril.** @@ -35,25 +34,17 @@ Once installed, you will need to set the environment variable `JAX_ENABLE_X64=Tr conda env config vars set JAX_ENABLE_X64=True -### For development - -Use the [environment.yml](https://github.com/mvdh7/pytzer/blob/master/environment.yml) file to create a new environment with Conda: - - conda env create -f environment.yml - -Then, fork and/or clone this repo to somewhere that your Python can see it. - ## Documentation -A work in progress at [pytzer.readthedocs.io](https://pytzer.readthedocs.io/en/latest/). +A work in progress at [mvdh.xyz/pytzer](https://mvdh.xyz/pytzer). ## Citation -Pytzer is maintained by [Dr Matthew P. Humphreys](https://humphreys.science) at the [NIOZ Royal Netherlands Institute for Sea Research](https://www.nioz.nl/en) (Texel, the Netherlands). +Pytzer is maintained by [Dr Matthew P. Humphreys](https://seaco2.group) at the [NIOZ Royal Netherlands Institute for Sea Research](https://www.nioz.nl/en) (Texel, the Netherlands). For now, the appropriate citation is: -> Humphreys, Matthew P. and Schiller, Abigail J. (2021). Pytzer: the Pitzer model for chemical activities and equilibria in aqueous solutions in Python (beta). *Zenodo.* [doi:10.5281/zenodo.2637914](https://doi.org/10.5281/zenodo.2637914). +> Humphreys, Matthew P. and Schiller, Abigail J. (2023). Pytzer: the Pitzer model for chemical activities and equilibria in aqueous solutions in Python (beta). *Zenodo.* [doi:10.5281/zenodo.2637914](https://doi.org/10.5281/zenodo.2637914). Please report which version of Pytzer you are using. You can find this in Python with: diff --git a/docs/equilibrate.md b/docs/equilibrate.md index f99c7172..f5421137 100644 --- a/docs/equilibrate.md +++ b/docs/equilibrate.md @@ -4,7 +4,9 @@ There are two 'layers' of solver in Pytzer: stoichiometric and thermodynamic. The stoichiometric solver determines the molality of each solute given a set of total molalities and fixed stoichiometric equilibrium constants. It uses a Newton-Raphson iterative method that is fully compatible with JAX. -The thermodynamic solver wraps the stoichiometric solver and adjusts the stoichiometric equilibrium constants to agree with thermodynamic constraints. Because it uses [`scipy.optimize.root`](https://docs.scipy.org/doc/scipy/reference/generated/scipy.optimize.root.html), it cannot be differentiated or compiled with JAX. +The thermodynamic solver wraps the stoichiometric solver and adjusts the stoichiometric equilibrium constants to agree with thermodynamic constraints. Because it uses [`scipy.optimize.root`](https://docs.scipy.org/doc/scipy/reference/generated/scipy.optimize.root.html), it cannot be yet[^1] differentiated or compiled with JAX. + +[^1]: We are planning to merge the two solvers together, making the entire program grad-able and jit-able by JAX, in a future release. You can solve equilibria using the following functions. Lower-level approaches with more fine control are possible, but not yet documented. diff --git a/docs/index.md b/docs/index.md index a374e099..eb0d4497 100644 --- a/docs/index.md +++ b/docs/index.md @@ -1,18 +1,17 @@ # Pytzer -![Tests](https://github.com/mvdh7/pytzer/workflows/Tests/badge.svg) -[![Coverage](img/coverage.svg)](https://github.com/mvdh7/pytzer/blob/master/.misc/coverage.txt) + -Pytzer is a Python implementation of the Pitzer model for chemical activities in aqueous solutions [[P91](refs/#p)] plus solvers to determine the equilibrium state of the system. +Pytzer is a Python implementation of the Pitzer model for chemical activities in aqueous solutions ([P91](refs/#p)) plus an equilibrium solver. ## Installation -Consult the [README.md on GitHub](https://github.com/mvdh7/pytzer/tree/master#pytzer) for up-to-date installation instructions. +Consult the [README.md on GitHub](https://github.com/mvdh7/pytzer/tree/main#pytzer) for up-to-date installation instructions. ## Development status @@ -22,7 +21,7 @@ Pytzer is in beta. Tests of the accuracy of its parameters and equations are un A manuscript describing Pytzer is in preparation. In the meantime, please cite: -> Humphreys, Matthew P. and Schiller, Abigail J. (2021). Pytzer: the Pitzer model for chemical activities and equilibria in aqueous solutions in Python (beta). *Zenodo.* [doi:10.5281/zenodo.2637914](https://doi.org/10.5281/zenodo.2637914). +> Humphreys, Matthew P. and Schiller, Abigail J. (2023). Pytzer: the Pitzer model for chemical activities and equilibria in aqueous solutions in Python (beta). *Zenodo.* [doi:10.5281/zenodo.2637914](https://doi.org/10.5281/zenodo.2637914). Please report the version you are using. You can find this in Python with: @@ -33,7 +32,7 @@ pz.hello() ## Acknowledgements -Pytzer is maintained by [Dr Matthew P. Humphreys](https://humphreys.science) at the NIOZ Royal Netherlands Institute for Sea Research (Texel, the Netherlands). Its initial development at the University of East Anglia was funded indirectly by the Natural Environment Research Council (NERC, UK). +Pytzer is maintained by [Dr Matthew P. Humphreys](https://seaco2.group) at the NIOZ Royal Netherlands Institute for Sea Research (Texel, the Netherlands). Its initial development at the University of East Anglia was funded indirectly by the Natural Environment Research Council (NERC, UK). Pytzer contains many functions and coefficients representing the effects of different solute interactions on solution properties that have been empirically determined from painstaking experiments and data compilations by hundreds of researchers over the course at least a century. We have done our best to list the small selection of this enormous body of work brought together here in the [references](refs). diff --git a/docs/params.md b/docs/params.md index aea71ac0..7947b571 100644 --- a/docs/params.md +++ b/docs/params.md @@ -14,9 +14,11 @@ from pytzer.libraries import Seawater The options are: + * `Clegg22`: [CHW22](../refs/#c) * `Clegg94`: [CRP94](../refs/#c) * `Greenberg89`: [GM89](../refs/#m) * `Harvie84`: [HMW84](../refs/#h) + * `Humphreys22`: [HWT22](../refs/#h) * `MarChemSpec` * `MarChemSpec25` * `Millero98`: [MP98](../refs/#m), a.k.a. MIAMI diff --git a/docs/refs.md b/docs/refs.md index f893a518..31b43cde 100644 --- a/docs/refs.md +++ b/docs/refs.md @@ -11,27 +11,38 @@ ??? citation "AW90: Archer & Wang (1990) *J. Phys. Chem. Ref. Data*" Archer, D. G., and Wang, P. (1990). The Dielectric Constant of Water and Debye‐Hückel Limiting Law Slopes. *Journal of Physical and Chemical Reference Data* 19, 371–411. [doi:10.1063/1.555853](https://doi.org/10.1063/1.555853) +### B + +??? citation "BH61: Bates & Hetzer (1961) *J. Phys. Chem.*" + Bates, R. G., and Hetzer, H. B. (1961). Dissociation constant of the protonated acid form of 2-amino-2-(hydroxymethyl)-1, 3-propanediol \[tris-hydroxymethyl\]-aminomethane and related thermodynamic quantities from 0 to 50°. *Journal of Physical Chemistry* 65(4), 667–671. [doi:10.1021/j100822a017](https://doi.org/10.1021/j100822a017) + ### C ??? citation "CB90: Clegg & Brimblecombe (1989) *J. Phys. Chem.*" Clegg, S. L., and Brimblecombe, P. (1989). Solubility of Ammonia in Pure Aqueous and Multicomponent Solutions. *Journal of Physical Chemistry* 93(20), 7237-7248. [doi:10.1021/j100357a041](https://doi.org/10.1021/j100357a041) +??? citation "CHW22: Clegg et al. (2022) *Mar. Chem.*" + Clegg, S. L., Humphreys, M. P., Waters, J. F., Turner, D. R., and Dickson, A. G. (2022). Chemical speciation models based upon the Pitzer activity coefficient equations, including the propagation of uncertainties. II. Tris buffers in artificial seawater at 25 °C, and an assessment of the seawater ‘Total’ pH scale. *Marine Chemistry* 244, 104096. [doi:10.1016/j.marchem.2022.104096](https://doi.org/10.1016/j.marchem.2022.104096) + ??? citation "CMR93: Campbell et al. (1993) *Mar. Chem.*" Campbell, D. M., Millero, F. J., Roy, R., Roy, L., Lawson, M., Vogel, K. M., et al. (1993). The standard potential for the hydrogen-silver, silver chloride electrode in synthetic seawater. *Marine Chemistry* 44, 221–233. [doi:10.1016/0304-4203(93)90204-2](https://doi.org/10.1016/0304-4203(93)90204-2) ??? citation "CRP94: Clegg et al. (1994) *J. Chem. Soc., Faraday Trans.*" Clegg, S. L., Rard, J. A., and Pitzer, K. S. (1994). Thermodynamic properties of 0–6 mol kg–1 aqueous sulfuric acid from 273.15 to 328.15 K. *Journal of the Chemical Society, Faraday Transactions* 90, 1875–1894. [doi:10.1039/FT9949001875](https://doi.org/10.1039/FT9949001875) +??? citation "CWTD23: Clegg et al. (2023) *Mar. Chem.*" + Clegg, S. L., Waters, J., F., Turner, D. R., and Dickson, A. G. (2023). Chemical speciation models based upon the Pitzer activity coefficient equations, including the propagation of uncertainties. III. Seawater from the freezing point to 45 °C, including acid-base equilibria. *Marine Chemistry* 250, 104196. [doi:10.1016/j.marchem.2022.104196](https://doi.org/10.1016/j.marchem.2022.104196) + ### D -??? note "D90: Dickson (1990) *J. Chem. Thermodyn.*" - Dickson, A. G. (1990). Standard potential of the reaction: AgCl(s) + 0.5 H2(g) = Ag(s) + HCl(aq), and the standard acidity constant of the ion HSO4 in synthetic sea water from 273.15 to 318.15 K. *Journal of Chemical Thermodynamics* 22, 113–127. doi:10.1016/0021-9614(90)90074-Z. +??? citation "D90: Dickson (1990) *J. Chem. Thermodyn.*" + Dickson, A. G. (1990). Standard potential of the reaction: AgCl(s) + 0.5 H2(g) = Ag(s) + HCl(aq), and the standard acidity constant of the ion HSO4 in synthetic sea water from 273.15 to 318.15 K. *Journal of Chemical Thermodynamics* 22, 113–127. [doi:10.1016/0021-9614(90)90074-Z](https://doi.org/10.1016/0021-9614(90)90074-Z) ??? citation "dLP83: de Lima & Pitzer (1983) *J. Solution Chem.*" de Lima, M. C. P., and Pitzer, K. S. (1983). Thermodynamics of saturated electrolyte mixtures of NaCl with Na2SO4 and with MgCl2. *Journal of Solution Chemistry* 12, 187–199. [doi:10.1007/BF00648056](https://doi.org/10.1007/BF00648056) -??? note "DR79: Dickson & Riley (1979) *Mar. Chem.*" - Dickson, A. G., and Riley, J. P. (1979). The estimation of acid dissociation constants in sea-water media from potentiometric titrations with strong base. II. The dissociation of phosphoric acid. *Marine Chemistry* 7, 101–109. doi:10.1016/0304-4203(79)90002-1. +??? citation "DR79: Dickson & Riley (1979) *Mar. Chem.*" + Dickson, A. G., and Riley, J. P. (1979). The estimation of acid dissociation constants in sea-water media from potentiometric titrations with strong base. II. The dissociation of phosphoric acid. *Marine Chemistry* 7, 101–109. [doi:10.1016/0304-4203(79)90002-1](https://doi.org/10.1016/0304-4203(79)90002-1) ### F @@ -44,16 +55,22 @@ ??? citation "GM89: Greenberg & Møller (1989) *Geochim. Cosmochim. Acta*" Greenberg, J. P., and Møller, N. (1989). The prediction of mineral solubilities in natural waters: A chemical equilibrium model for the Na-K-Ca-Cl-SO4-H2O system to high concentration from 0 to 250°C. *Geochimica et Cosmochimica Acta* 53, 2503–2518. [doi:10.1016/0016-7037(89)90124-5](https://doi.org/10.1016/0016-7037(89)90124-5) -??? note "GP89: Goyet & Poisson (1989) *Deep-Sea Res. Pt. A*" - Goyet, C., and Poisson, A. (1989). New determination of carbonic acid dissociation constants in seawater as a function of temperature and salinity. *Deep-Sea Research Part A* 36, 1635–1654. doi:10.1016/0198-0149(89)90064-2. +??? citation "GP89: Goyet & Poisson (1989) *Deep-Sea Res. Pt. A*" + Goyet, C., and Poisson, A. (1989). New determination of carbonic acid dissociation constants in seawater as a function of temperature and salinity. *Deep-Sea Research Part A* 36, 1635–1654. [doi:10.1016/0198-0149(89)90064-2](https://doi.org/10.1016/0198-0149(89)90064-2) ??? citation "GT17: Gallego-Urrea & Turner (2017) *Mar. Chem.*" Gallego-Urrea, J. A., and Turner, D. R. (2017). Determination of pH in estuarine and brackish waters: Pitzer parameters for Tris buffers and dissociation constants for *m*-cresol purple at 298.15K. *Marine Chemistry* 195, 84–89. [doi:10.1016/j.marchem.2017.07.004](https://doi.org/10.1016/j.marchem.2017.07.004) ### H -??? note "H73: Hansson (1973) *Deep-Sea Res.*" - Hansson, I. (1973). A new set of acidity constants for carbonic acid and boric acid in sea water. *Deep-Sea Research* 20, 461–478. doi:10.1016/0011-7471(73)90100-9. +??? citation "H73: Hansson (1973) *Deep-Sea Res.*" + Hansson, I. (1973). A new set of acidity constants for carbonic acid and boric acid in sea water. *Deep-Sea Research* 20, 461–478. [doi:10.1016/0011-7471(73)90100-9](https://doi.org/10.1016/0011-7471(73)90100-9) + +??? citation "HBS87: Holmes et al. (1987) *J. Chem. Thermodyn.*" + Holmes, H. F., Busey, R. H., Simonson, J. M., Mesmer, R. E., Archer, D. G., and Wood, R. H. (1987). The enthalpy of dilution of HCl(aq) to 648 K and 40 MPa thermodynamic properties. *Journal of Chemical Thermodynamics* 19(8), 863-890. [doi:10.1016/0021-9614(87)90033-4](https://doi.org/10.1016/0021-9614(87)90033-4) + +??? citation "HEW82: Harvie et al. (1982) *Geochim. Cosmochim. Acta*" + Harvie, C. E., Eugster, H. P., and Weare, J. H. (1982). Mineral equilibria in the 6-component sea-water system, Na-K-Mg-Ca-SO4-Cl-H2O at 25°C. 2. Compositions of the saturated solutions. *Geochimica et Cosmochimica Acta* 46, 1603-1618. [doi:10.1016/0016-7037(82)90317-9](https://doi.org/10.1016/0016-7037(82)90317-9) ??? citation "HFM89: Hershey et al. (1989) *J. Solution Chem.*" Hershey, J. P., Fernandez, M., and Millero, F. J. (1989). The dissociation of phosphoric acid in NaCl and NaMgCl solutions at 25°C. *Journal of Solution Chemistry* 18(9), 875–891. [doi:10.1007/BF00685063](https://doi.org/10.1007/BF00685063) @@ -70,12 +87,24 @@ ??? citation "HM86: Holmes & Mesmer (1986) *J. Solution Chem.*" Holmes, H. F., and Mesmer, R. E. (1986). Thermodynamics of aqueous solutions of the alkali metal sulfates. *Journal of Solution Chemistry* 15, 495–517. [doi:10.1007/BF00644892](https://doi.org/10.1007/BF00644892) +??? citation "HM92: Holmes & Mesmer (1992) *J. Chem. Thermodyn.*" + Holmes, H. F., and Mesmer, R. E. (1992). Isopiestic studies of H2SO4(aq) at elevated temperatures: Thermodynamic properties. *Journal of Chemical Thermodynamics* 24(3), 317-328. [doi:10.1016/S0021-9614(05)80072-2](https://doi.org/10.1016/S0021-9614(05)80072-2) + +??? citation "HM93: He & Morse (1993) *Geochim. Cosmochim. Acta*" + He, S., and Morse, J. W. (1993). The carbonic acid system and calcite solubility in aqueous Na-K-Ca-Mg-Cl-SO4 solutions from 0 to 90°C. *Geochimica et Cosmochimica Acta* 57(15), 3533-3554. [doi:10.1016/0016-7037(93)90137-L](https://doi.org/10.1016/0016-7037(93)90137-L) + ??? citation "HPM88: Hershey et al. (1988) *Geochim. Cosmochim. Acta*" Hershey, J. P., Plese, T., and Millero, F. J. (1988). The p*K*1\* for the dissociation of H2S in various ionic media. *Geochimica et Cosmochimica Acta* 52, 2047–2051. [doi:10.1016/0016-7037(88)90183-4](https://doi.org/10.1016/0016-7037(88)90183-4) ??? citation "HPR93: Hovey et al. (1993) *J. Chem. Thermodyn.*" Hovey, J. K., Pitzer, K. S., and Rard, J. A. (1993). Thermodynamics of Na2SO4(aq) at temperatures *T* from 273 K to 373 K and of {(1-*y*)H2SO4+*y*Na2SO4}(aq) at *T* = 298.15 K. *Journal of Chemical Thermodynamics* 25(1), 173–192. [doi:10.1006/jcht.1993.1016](https://doi.org/10.1006/jcht.1993.1016) +??? citation "HW80: Harvie & Weare (1980) *Geochim. Cosmochim. Acta*" + Harvie, C. E., and Weare, J. H. (1980). The prediction of mineral solubilities in natural-waters - the Na-K-Mg-Ca-Cl-SO4-H2O system from zero to high-concentration at 25°C. *Geochimica et Cosmochimica Acta* 44, 981-997. [doi:10.1016/0016-7037(80)90287-2](https://doi.org/10.1016/0016-7037(80)90287-2) + +??? citation "HWT22: Humphreys et al. (2022) *Mar. Chem.*" + Humphreys, M. P., Waters, J. F., Turner, D. R., Dickson, A. G., and Clegg, S. L. (2022). Chemical speciation models based upon the Pitzer activity coefficient equations, including the propagation of uncertainties. I. Artificial seawater from 0 to 45 °C. *Marine Chemistry* 244, 104095. [doi:10.1016/j.marchem.2022.104095](https://doi.org/10.1016/j.marchem.2022.104095) + ### J ??? citation "JESS: May et al. (2011) *J. Chem. Eng. Data*" @@ -83,7 +112,7 @@ ### K -??? note "KRCB77: Khoo et al. (1977) *Anal. Chem.*" +??? citation "KRCB77: Khoo et al. (1977) *Anal. Chem.*" Khoo, K. H., Ramette, R. W., Culberson, C. H., and Bates, R. G. (1977). Determination of hydrogen ion concentrations in seawater from 5 to 40C: standard potentials at salinities from 20 to 45 per mille. *Analytical Chemistry* 49, 29–34. [doi:10.1021/ac50009a016](https://doi.org/10.1021/ac50009a016). ### L @@ -125,6 +154,15 @@ ??? citation "P91: Pitzer (1991) *Activity Coefficients in Electrolyte Solutions*" Pitzer, K. S. (1991). “Ion Interaction Approach: Theory and Data Correlation,” in *Activity Coefficients in Electrolyte Solutions, 2nd Edition*, ed. K. S. Pitzer (CRC Press, Florida, USA), 75–153. +??? citation "PB82: Plummer & Busenberg (1982) *Geochim. Cosmochim. Acta*" + Plummer, L. N., and Busenberg, E. (1982). The solubilities of calcite, aragonite and vaterite in CO2-H2O solutions between 0 and 90°C, and an evaluation of the aqueous model for the system CaCO3-CO2-H2O. *Geochimica et Cosmochimica Acta* 46(6), 1011-1040. [doi:10.1016/0016-7037(82)90056-4](https://doi.org/10.1016/0016-7037(82)90056-4) + +??? citation "POS85: Pitzer et al. (1985) *J. Chem. Eng. Data*" + Pitzer, K. S., Olsen, J., Simonson, J. M., Roy, R. N., Gibbons, J. J., and Rowe, L. (1985). Thermodynamics of aqueous magnesium and calcium bicarbonates and mixtures with chloride. *Journal of Chemical and Engineering Data* 30, 14-17. [doi:10.1021/je00039a005](https://doi.org/10.1021/je00039a005) + +??? citation "PPFD88: Plummer et al. (1988) *PHRQPITZ manual*" + Plummer, L. N., Parkhurst, D. L., Fleming, G. W., and Dunkle, S. A. (1988). A computer program incorporating Pitzer's equations for calculation of geochemical reactions in brines. Water-Resources Investigations Report 88-4153, U.S. Geological Survey. pp. 309. [doi:10.3133/wri884153](https://doi.org/10.3133/wri884153) + ??? citation "PMR97: Pierrot et al. (1997) *J. Solution Chem.*" Pierrot, D., Millero, F. J., Roy, L. N., Roy, R. N., Doneski, A., and Niederschmidt, J. (1997). The activity coefficients of HCl in HCl−Na2SO4 solutions from 0 to 50°C and ionic strengths up to 6 molal. *Journal of Solution Chemistry* 26(1), 31–45. [doi:10.1007/BF02439442](https://doi.org/10.1007/BF02439442) @@ -157,14 +195,17 @@ ??? citation "RM81i: Rard & Miller (1981) *J. Chem. Eng. Data*" Rard, J. A., and Miller, D. G. (1981). Isopiestic Determination of the Osmotic Coefficients of Aqueous Na2SO4, MgSO4, and Na2SO4-MgSO4 at 25 °C. *Journal of Chemical & Engineering Data* 26, 33–38. [doi:10.1021/je00023a013](https://doi.org/10.1021/je00023a013) -??? note "RRV93: Roy et al. (1993) *Mar. Chem.*" - Roy, R. N., Roy, L. N., Vogel, K. M., Porter-Moore, C., Pearson, T., Good, C. E., et al. (1993). The dissociation constants of carbonic acid in seawater at salinities 5 to 45 and temperatures 0 to 45°C. *Marine Chemistry* 44, 249–267. doi:10.1016/0304-4203(93)90207-5. +??? citation "RRV93: Roy et al. (1993) *Mar. Chem.*" + Roy, R. N., Roy, L. N., Vogel, K. M., Porter-Moore, C., Pearson, T., Good, C. E., et al. (1993). The dissociation constants of carbonic acid in seawater at salinities 5 to 45 and temperatures 0 to 45°C. *Marine Chemistry* 44, 249–267. [doi:10.1016/0304-4203(93)90207-5](https://doi.org/10.1016/0304-4203(93)90207-5) ??? citation "RZM91: Roy et al. (1991) *J. Solution Chem.*" Roy, R. N., Zhang, J.-Z., and Millero, F. J. (1991). The ionization of sulfurous acid in Na−Mg−Cl solutions at 25°C. *Journal of Solution Chemistry* 20(4), 361–373. [doi:10.1007/BF00650763](https://doi.org/10.1007/BF00650763) ### S +??? citation "SMW90: Spencer et al. (1990) *Geochim. Cosmochim. Acta*" + Spencer, R. J., Møller, N., and Weare, J. H. (1990). The prediction of mineral solubilities in natural waters: A chemical equilibrium model for the Na-K-Ca-Mg-Cl-SO4-H2O system at temperatures below 25°C. *Geochimica et Cosmochimica Acta* 54(3), 575-590. [doi:10.1016/0016-7037(90)90354-N](https://doi.org/10.1016/0016-7037(90)90354-N) + ??? citation "SRG87: Simonson et al. (1987) *J. Chem. Eng. Data*" Simonson, J. M., Roy, R. N., and Gibbons, J. J. (1987). Thermodynamics of Aqueous Mixed Potassium Carbonate, Bicarbonate, and Chloride Solutions to 368 K. *Journal of Chemical & Engineering Data* 32(1), 41–45. [doi:10.1021/je00047a011](https://doi.org/10.1021/je00047a011) diff --git a/docs/requirements.txt b/docs/requirements.txt deleted file mode 100644 index d00dc16b..00000000 --- a/docs/requirements.txt +++ /dev/null @@ -1 +0,0 @@ -mkdocs-material==7.1.0 diff --git a/docs/versions.md b/docs/versions.md index 0046cb5a..c4c211e2 100644 --- a/docs/versions.md +++ b/docs/versions.md @@ -4,6 +4,14 @@ Switches from Autograd to [JAX](https://jax.readthedocs.io/en/latest/) for faster automatic differentiation and JIT compilation. +### 0.5.3 (24 Oct 2023) + +!!! new-version "Changes in v0.5.3" + * Created new `Humphreys22` parameter library and validated its calculations against [HWT22](../refs/#h). + * Created new `Clegg22` parameter library (but its calculations against [CHW22](../refs/#c) still need validating). + * Created new `Clegg23` parameter library and validated its calculations against [CWTD23](../refs/#c). + * Renamed `io` module as `get`. + ### 0.5.2 (31 Aug 2021) !!! new-version "Changes in v0.5.2" diff --git a/mkdocs.yml b/mkdocs.yml index 012e68ad..dbb42825 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -1,7 +1,7 @@ site_name: Pytzer site_author: Matthew P. Humphreys site_description: "Pytzer: the Pitzer model for chemical activities in aqueous solutions in Python" -copyright: Copyright © 2019–2021 Matthew P. Humphreys (GNU GPLv3). +copyright: Copyright © 2019–2022 Matthew P. Humphreys (GNU GPLv3). repo_url: https://github.com/mvdh7/pytzer repo_name: mvdh7/pytzer @@ -10,7 +10,7 @@ theme: language: en palette: scheme: default - primary: blue grey + primary: pink accent: teal font: text: Roboto Slab @@ -36,7 +36,7 @@ nav: # - Example workflows: workflows.md # - Conventions: name-conventions.md # - Main Pytzer modules: - # - .io – import and export data: modules/io.md + # - .get – import and export data: modules/io.md # - .model – the Pitzer model: modules/model.md # - .equilibrate - equilibrium solvers: modules/equilibrate.md # - Behind the scenes: diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 00000000..5d0afc40 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,39 @@ +[build-system] +requires = [ + "setuptools", + "pytzer", + "jax", + "jaxlib", + "numpy", + "scipy", +] +build-backend = "setuptools.build_meta" + +[project] +name = "pytzer" +description = "The Pitzer model for chemical activities and equilibria in aqueous solutions in Python" +readme = "README.md" +dependencies = [ + "pytzer", + "jax", + "jaxlib", + "numpy", + "scipy", +] +classifiers = [ + "Development Status :: 4 - Beta", + "Programming Language :: Python :: 3.7", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "License :: OSI Approved :: GNU General Public License v3 (GPLv3)", + "Operating System :: OS Independent", + "Natural Language :: English", + "Intended Audience :: Science/Research", + "Topic :: Scientific/Engineering :: Chemistry", +] +dynamic = ["version"] + +[tool.setuptools.dynamic] +version = {attr = "pytzer.meta.version"} diff --git a/pytest.ini b/pytest.ini index e8ae73ec..a76fd3e8 100644 --- a/pytest.ini +++ b/pytest.ini @@ -1,4 +1,4 @@ # pytest.ini [pytest] -norecursedirs= .* *.egg* build dist +norecursedirs= .* *.egg* build dist tests/archive minversion = 6.0 diff --git a/pytzer/__init__.py b/pytzer/__init__.py index 694e4b39..5bd5f8a0 100644 --- a/pytzer/__init__.py +++ b/pytzer/__init__.py @@ -1,5 +1,5 @@ # Pytzer: Pitzer model for chemical activities in aqueous solutions. -# Copyright (C) 2019--2021 Matthew P. Humphreys (GNU GPLv3) +# Copyright (C) 2019--2023 Matthew P. Humphreys (GNU GPLv3) # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -13,15 +13,21 @@ # # You should have received a copy of the GNU General Public License # along with this program. If not, see . -"""Pitzer model for chemical activities in aqueous solutions.""" +""" +Pytzer +====== +Pytzer is an implementation of the Pitzer model for chemical activities in aqueous +solutions in Python, including an equilibrium solver. +""" from . import ( constants, convert, debyehueckel, dissociation, equilibrate, - io, + get, libraries, + matrix, meta, model, parameters, @@ -39,7 +45,7 @@ from .equilibrate.components import find_solutes from .equilibrate.stoichiometric import solve as solve_stoichiometric from .equilibrate.thermodynamic import solve as solve_thermodynamic -from .io import solve_df +from .get import solve_df from .libraries import ParameterLibrary from .meta import hello, update_func_J from .model import ( diff --git a/pytzer/constants.py b/pytzer/constants.py index f22bba2c..16f9242a 100644 --- a/pytzer/constants.py +++ b/pytzer/constants.py @@ -1,5 +1,5 @@ # Pytzer: Pitzer model for chemical activities in aqueous solutions. -# Copyright (C) 2019--2021 Matthew P. Humphreys (GNU GPLv3) +# Copyright (C) 2019--2023 Matthew P. Humphreys (GNU GPLv3) """Define universal constants.""" # Set constant values diff --git a/pytzer/convert.py b/pytzer/convert.py index 8d25f0c2..e5e7b371 100644 --- a/pytzer/convert.py +++ b/pytzer/convert.py @@ -1,5 +1,5 @@ # Pytzer: Pitzer model for chemical activities in aqueous solutions. -# Copyright (C) 2019--2021 Matthew P. Humphreys (GNU GPLv3) +# Copyright (C) 2019--2023 Matthew P. Humphreys (GNU GPLv3) from collections import OrderedDict from jax import numpy as np from . import constants, properties diff --git a/pytzer/debyehueckel.py b/pytzer/debyehueckel.py index faa62261..fc175027 100644 --- a/pytzer/debyehueckel.py +++ b/pytzer/debyehueckel.py @@ -1,5 +1,5 @@ # Pytzer: Pitzer model for chemical activities in aqueous solutions. -# Copyright (C) 2019--2021 Matthew P. Humphreys (GNU GPLv3) +# Copyright (C) 2019--2023 Matthew P. Humphreys (GNU GPLv3) """Calculate Debye-Hueckel limiting slopes.""" from jax import numpy as np from . import teos10 @@ -146,9 +146,9 @@ def _gm1drho(tempK, presMPa): + b[4] / (tempK - 215) ** 0.25 + np.exp( b[5] / tempK - + b[6] / tempK ** 2 + + b[6] / tempK**2 + b[7] * presMPa / tempK - + b[8] * presMPa / tempK ** 2 + + b[8] * presMPa / tempK**2 ) ) return gm1drho @@ -168,14 +168,14 @@ def _D(tempK, presMPa, rho): k = 1.380658e-16 mu = 1.84e-18 A = ( - (al + _g(tempK, presMPa, rho) * mu ** 2 / (3 * k * tempK)) + (al + _g(tempK, presMPa, rho) * mu**2 / (3 * k * tempK)) * 4 * np.pi * NA * rho / (3 * Mw) ) - return (1 + 9 * A + 3 * np.sqrt(9 * A ** 2 + 2 * A + 1)) / 4 + return (1 + 9 * A + 3 * np.sqrt(9 * A**2 + 2 * A + 1)) / 4 def Aosm_AW90(tempK, pres): @@ -190,7 +190,7 @@ def Aosm_AW90(tempK, pres): rho = teos10.rho(tempK, presPa) * 1e-3 Aosm = ( np.sqrt(2e-3 * np.pi * rho * NA) - * (100 * e ** 2 / (4 * np.pi * _D(tempK, presMPa, rho) * E0 * k * tempK)) ** 1.5 + * (100 * e**2 / (4 * np.pi * _D(tempK, presMPa, rho) * E0 * k * tempK)) ** 1.5 / 3 ) valid = np.logical_and( diff --git a/pytzer/dissociation.py b/pytzer/dissociation.py index bbb3b4af..4a3e9941 100644 --- a/pytzer/dissociation.py +++ b/pytzer/dissociation.py @@ -1,6 +1,8 @@ # Pytzer: Pitzer model for chemical activities in aqueous solutions. -# Copyright (C) 2019--2021 Matthew P. Humphreys (GNU GPLv3) -"""Evaluate thermodynamic equilibrium constants.""" +# Copyright (C) 2019--2023 Matthew P. Humphreys (GNU GPLv3) +"""Evaluate thermodynamic equilibrium constants. +All functions return ln(K) values. +""" from collections import OrderedDict from jax import numpy as np @@ -14,7 +16,7 @@ def HSO4_CRP94_extra(T=298.15): log10kHSO4 = ( 562.694864456 - 102.5154 * np.log(T) - - 1.117033e-4 * T ** 2 + - 1.117033e-4 * T**2 + 0.2477538 * T - 13273.75 / T ) @@ -28,7 +30,7 @@ def HSO4_CRP94(T=298.15): log10kHSO4 = ( 562.69486 - 102.5154 * np.log(T) - - 1.117033e-4 * T ** 2 + - 1.117033e-4 * T**2 + 0.2477538 * T - 13273.75 / T ) @@ -36,8 +38,8 @@ def HSO4_CRP94(T=298.15): return lnkHSO4 -def trisH_BH64(T=298.15): - """TrisH+ dissociation following BH64 Eq. (3).""" +def trisH_BH61(T=298.15): + """TrisH+ dissociation following BH61 Eq. (3).""" # Matches Clegg's model [2019-07-02] log10ktrisH = -(2981.4 / T - 3.5888 + 0.005571 * T) lnktrisH = log10ktrisH * ln10 @@ -53,10 +55,10 @@ def rhow_K75(T=298.15): return ( 0.99983952 + 16.945176e-3 * tempC - - 7.9870401e-6 * tempC ** 2 - - 46.170461e-9 * tempC ** 3 - + 105.56302e-12 * tempC ** 4 - - 280.54253e-15 * tempC ** 5 + - 7.9870401e-6 * tempC**2 + - 46.170461e-9 * tempC**3 + + 105.56302e-12 * tempC**4 + - 280.54253e-15 * tempC**5 ) / (1 + 16.879850e-3 * tempC) @@ -74,7 +76,7 @@ def H2O_M88(T=298.15): - 3.26224352e4 / T - 1.90877133e2 * np.log(T) - 5.35204850e-1 / (T - 263) - - 2.32009393e-4 * T ** 2 + - 2.32009393e-4 * T**2 + 5.20549183e1 / (680 - T) ) @@ -85,9 +87,9 @@ def H2O_MF(T=298.15): log10kH2O = ( -4.098 - 3.2452e3 / T - + 2.2362e5 / T ** 2 - - 3.984e7 / T ** 3 - + (1.3957e1 - 1.2623e3 / T + 8.5641e5 / T ** 2) * np.log10(rhow_K75(T)) + + 2.2362e5 / T**2 + - 3.984e7 / T**3 + + (1.3957e1 - 1.2623e3 / T + 8.5641e5 / T**2) * np.log10(rhow_K75(T)) ) lnkH2O = log10kH2O * ln10 return lnkH2O @@ -148,6 +150,29 @@ def HCO3_MP98(T=298.15): return _MP98_eq23(T, A=207.6548, B=-11843.79, C=-33.6485) +def _PB82_eq(T, A, B, C, D, E): + """Returns log10(K).""" + return A + B * T + C / T + D * np.log10(T) + E / T**2 + + +def H2CO3_PB82(T=298.15): + """H2CO3 dissociation [PB82].""" + log10_kH2CO3 = _PB82_eq(T, -356.3094, -0.06091964, 21834.37, 126.8339, -1684915) + return ln10 * log10_kH2CO3 + + +def HCO3_PB82(T=298.15): + """HCO3 dissociation [PB82].""" + log10_kHCO3 = _PB82_eq(T, -107.8871, -0.03252849, 5151.79, 38.9256, -563713.9) + return ln10 * log10_kHCO3 + + +def CO2_PB82(T=298.15): + """CO2 solubility (Henry's law constant) [PB82].""" + log10_kCO2 = _PB82_eq(T, 108.3865, 0.01985076, -6919.53, -40.4515, 669365) + return ln10 * log10_kCO2 + + def H3PO4_MP98(T=298.15): """H3PO4 dissociation [MP98 following B51].""" return _MP98_eq23(T, A=115.54, B=-4576.7518, C=-18.453) @@ -170,27 +195,59 @@ def _MP98_eq24(T, A=0, B=0, C=0): def MgF_MP98_MR97(T=298.15): """MgF+ formation [MP98 following MR97].""" - return -_MP98_eq24(T, A=3.504, B=-501.6) * ln10 + # Sign inverted to make CWTD23 solver agree 2023-10-22 + return _MP98_eq24(T, A=3.504, B=-501.6) * ln10 def CaF_MP98_MR97(T=298.15): """CaF+ formation [MP98 following MR97].""" - return -_MP98_eq24(T, A=3.014, B=-501.6) * ln10 + # Sign inverted to make CWTD23 solver agree 2023-10-22 + return _MP98_eq24(T, A=3.014, B=-501.6) * ln10 + + +def MgCO3_PPFD88(T=298.15): + """MgCO3 formation [PPFD88 table 1].""" + log10_kMgCO3 = -32.225 + 1093.486 / T + 12.72433 * np.log10(T) + return log10_kMgCO3 * ln10 + + +def CaCO3_PB82(T=298.15): + """CaCO3 formation [PB82 eq. (53)] between 5 and 80 °C. + PB82 eq. (44): K(CaCO3) = a(CaCO3) / (a(Ca) * a(CO3)). + """ + log10_kCaCO3 = -1228.732 - 0.299444 * T + 35512.75 / T + 485.818 * np.log10(T) + return log10_kCaCO3 * ln10 + + +def CaCO3_PPFD88(T=298.15): + """CaCO3 formation [PPFD88]. Slightly different from PB82.""" + log10_kCaCO3 = -1228.806 - 0.299440 * T + 35512.75 / T + 485.818 * np.log10(T) + return log10_kCaCO3 * ln10 def MgCO3_MP98_MR97(T=298.15): """MgCO3 formation [MP98 following MR97].""" - return -_MP98_eq24(T, A=1.028, C=0.0066154) * ln10 + # Sign inverted to make CWTD23 solver agree 2023-10-22 + return _MP98_eq24(T, A=1.028, C=0.0066154) * ln10 def CaCO3_MP98_MR97(T=298.15): """CaCO3 formation [MP98 following MR97].""" - return -_MP98_eq24(T, A=1.178, C=0.0066154) * ln10 + # Sign inverted to make CWTD23 solver agree 2023-10-22 + return _MP98_eq24(T, A=1.178, C=0.0066154) * ln10 def SrCO3_MP98_MR97(T=298.15): """SrCO3 formation [MP98 following MR97].""" - return -_MP98_eq24(T, A=1.028, C=0.0066154) * ln10 + # Sign inverted to make CWTD23 solver agree 2023-10-22 + return _MP98_eq24(T, A=1.028, C=0.0066154) * ln10 + + +def SrCO3_CWTF23(T=298.15): + """SrCO3 formation [CWTF23].""" + # Copies CaCO3 of MP98/MR97 + # Sign inverted to make CWTD23 solver agree 2023-10-22 + return _MP98_eq24(T, A=1.178, C=0.0066154) * ln10 def MgH2PO4_MP98_MR97(T=298.15): @@ -283,19 +340,6 @@ def pK_CaPO4(T=298.15): return 7.1 -all_log_ks = { - "BOH3": BOH3_M79, - "H2CO3": H2CO3_MP98, - "H2O": H2O_M88, - "HCO3": HCO3_MP98, - "HF": HF_MP98, - "HSO4": HSO4_CRP94, - # "MgOH": lambda T=298.15: np.log(10.0 ** -pK_MgOH(T)), - "MgOH": MgOH_MP98, - "trisH": trisH_BH64, -} - - def assemble(temperature=298.15, exclude_equilibria=None, totals=None): """Evaluate all thermodynamic equilibrium constants.""" kt_constants = OrderedDict() @@ -338,6 +382,8 @@ def assemble(temperature=298.15, exclude_equilibria=None, totals=None): kt_constants["CaPO4"] = np.exp(CaPO4_MP98_MR97(T=temperature)) if "Sr" in totals and "CO2" in totals: kt_constants["SrCO3"] = np.exp(SrCO3_MP98_MR97(T=temperature)) + if "tris" in totals: + kt_constants["trisH"] = np.exp(trisH_BH61(T=temperature)) if exclude_equilibria is not None: for eq in exclude_equilibria: if eq in kt_constants: diff --git a/pytzer/equilibrate/__init__.py b/pytzer/equilibrate/__init__.py index 4ba52c2b..b4cafb26 100644 --- a/pytzer/equilibrate/__init__.py +++ b/pytzer/equilibrate/__init__.py @@ -1,5 +1,5 @@ # Pytzer: Pitzer model for chemical activities in aqueous solutions. -# Copyright (C) 2019--2021 Matthew P. Humphreys (GNU GPLv3) +# Copyright (C) 2019--2023 Matthew P. Humphreys (GNU GPLv3) """Solve for equilibrium.""" from collections import OrderedDict @@ -43,8 +43,8 @@ def solve( temperature=298.15, verbose=False, ): - """Solve for thermodynamic equilibrium to return solute molalities and stoichiometric - equilibrium constants. + """Solve for thermodynamic equilibrium to return solute molalities and + stoichiometric equilibrium constants. """ # Make first estimates of all stoichiometric dissociation constants ks_constants_pz = dissociation.assemble( diff --git a/pytzer/equilibrate/components.py b/pytzer/equilibrate/components.py index 8986ae39..a614523a 100644 --- a/pytzer/equilibrate/components.py +++ b/pytzer/equilibrate/components.py @@ -1,5 +1,5 @@ # Pytzer: Pitzer model for chemical activities in aqueous solutions. -# Copyright (C) 2019--2021 Matthew P. Humphreys (GNU GPLv3) +# Copyright (C) 2019--2023 Matthew P. Humphreys (GNU GPLv3) """Calculate molality of each solution component.""" from collections import OrderedDict @@ -42,7 +42,7 @@ def get_CO3(h, totals, ks_constants): t["CO2"] * k["H2CO3"] * k["HCO3"] - / (h ** 2 + k["H2CO3"] * h + k["H2CO3"] * k["HCO3"]) + / (h**2 + k["H2CO3"] * h + k["H2CO3"] * k["HCO3"]) ) @@ -53,7 +53,7 @@ def get_HCO3(h, co3, ks_constants): def get_CO2(h, co3, ks_constants): k = ks_constants - return co3 * h ** 2 / (k["H2CO3"] * k["HCO3"]) + return co3 * h**2 / (k["H2CO3"] * k["HCO3"]) def get_PO4(h, totals, ks_constants): @@ -64,8 +64,8 @@ def get_PO4(h, totals, ks_constants): * k["H2PO4"] * k["HPO4"] / ( - h ** 3 - + k["H3PO4"] * h ** 2 + h**3 + + k["H3PO4"] * h**2 + k["H3PO4"] * k["H2PO4"] * h + k["H3PO4"] * k["H2PO4"] * k["HPO4"] ) @@ -81,12 +81,12 @@ def get_HPO4(h, po4, ks_constants): @get_wrap def get_H2PO4(h, po4, ks_constants): k = ks_constants - return po4 * h ** 2 / (k["H2PO4"] * k["HPO4"]) + return po4 * h**2 / (k["H2PO4"] * k["HPO4"]) def get_H3PO4(h, po4, ks_constants): k = ks_constants - return po4 * h ** 3 / (k["H3PO4"] * k["H2PO4"] * k["HPO4"]) + return po4 * h**3 / (k["H3PO4"] * k["H2PO4"] * k["HPO4"]) def get_SO4(h, totals, ks_constants): @@ -149,6 +149,16 @@ def get_BOH3(h, totals, ks_constants): return h * t["BOH3"] / (h + k["BOH3"]) +def get_tris(h, totals, ks_constants): + t, k = totals, ks_constants + return k["trisH"] * t["tris"] / (h + k["trisH"]) + + +def get_trisH(h, totals, ks_constants): + t, k = totals, ks_constants + return h * t["tris"] / (h + k["trisH"]) + + def get_Ca(h, f, co3, po4, totals, ks_constants): H2PO4 = get_H2PO4(h, po4, ks_constants) HPO4 = get_HPO4(h, po4, ks_constants) @@ -206,7 +216,7 @@ def get_Mg(h, f, co3, po4, totals, ks_constants): t, k = totals, ks_constants denom = 1.0 if "MgOH" in k: - denom = denom + k["MgOH"] * OH + denom = denom + OH / k["MgOH"] if "MgF" in k: denom = denom + k["MgF"] * f if "MgCO3" in k: @@ -224,7 +234,7 @@ def get_MgOH(h, f, co3, po4, totals, ks_constants): Mg = get_Mg(h, f, co3, po4, totals, ks_constants) OH = get_OH(h, ks_constants) k = ks_constants - return k["MgOH"] * Mg * OH + return Mg * OH / k["MgOH"] def get_MgF(h, f, co3, po4, totals, ks_constants): @@ -315,6 +325,9 @@ def find_solutes(totals, ks_constants, ptargets=None): if "NO2" in totals and "HNO2" in ks_constants: solutes.append("HNO2") solutes.append("NO2") + if "tris" in totals and "trisH" in ks_constants: + solutes.append("tris") + solutes.append("trisH") if "F" in targets and "F" in totals: if "Ca" in totals and "CaF" in ks_constants: solutes.append("CaF") @@ -371,7 +384,7 @@ def find_solutes(totals, ks_constants, ptargets=None): @jax.jit def get_solutes(totals, ks_constants, ptargets): - targets = OrderedDict((k, 10.0 ** -v) for k, v in ptargets.items()) + targets = OrderedDict((k, 10.0**-v) for k, v in ptargets.items()) solutes = OrderedDict() totals = totals.copy() solutes.update(totals) @@ -417,6 +430,9 @@ def get_solutes(totals, ks_constants, ptargets): if "NO2" in totals and "HNO2" in ks_constants: solutes["HNO2"] = get_HNO2(h, totals, ks_constants) solutes["NO2"] = get_NO2(h, totals, ks_constants) + if "tris" in totals and "trisH" in ks_constants: + solutes["tris"] = get_tris(h, totals, ks_constants) + solutes["trisH"] = get_trisH(h, totals, ks_constants) if "F" in targets and "F" in totals: if "Ca" in totals and "CaF" in ks_constants: solutes["CaF"] = get_CaF(h, f, co3, po4, totals, ks_constants) diff --git a/pytzer/equilibrate/stoichiometric.py b/pytzer/equilibrate/stoichiometric.py index f48f43e3..651b58be 100644 --- a/pytzer/equilibrate/stoichiometric.py +++ b/pytzer/equilibrate/stoichiometric.py @@ -1,5 +1,5 @@ # Pytzer: Pitzer model for chemical activities in aqueous solutions. -# Copyright (C) 2019--2021 Matthew P. Humphreys (GNU GPLv3) +# Copyright (C) 2019--2023 Matthew P. Humphreys (GNU GPLv3) """Solve for stoichiometric equilibrium.""" from collections import OrderedDict @@ -92,6 +92,7 @@ def add_if_in(key): + add_if_in("NH3") + add_if_in("H3SiO4") - add_if_in("HNO2") + + add_if_in("tris") ) @@ -117,6 +118,7 @@ def add_if_in(key): - add_if_in("SO4") * 2 + add_if_in("NH3") - add_if_in("NO2") + + add_if_in("tris") ) diff --git a/pytzer/equilibrate/thermodynamic.py b/pytzer/equilibrate/thermodynamic.py index 62ebcd9d..4b838058 100644 --- a/pytzer/equilibrate/thermodynamic.py +++ b/pytzer/equilibrate/thermodynamic.py @@ -1,5 +1,5 @@ # Pytzer: Pitzer model for chemical activities in aqueous solutions. -# Copyright (C) 2019--2021 Matthew P. Humphreys (GNU GPLv3) +# Copyright (C) 2019--2023 Matthew P. Humphreys (GNU GPLv3) """Solve for thermodynamic equilibrium.""" import copy @@ -59,7 +59,7 @@ def Gibbs_HF(log_kt_HF, log_ks_HF, log_acfs, log_aH2O): def Gibbs_MgOH(log_kt_MgOH, log_ks_MgOH, log_acfs, log_aH2O): """Evaluate the Gibbs energy for the magnesium-MgOH+ equilibrium.""" return ( - log_acfs["Mg"] + log_acfs["OH"] - log_acfs["MgOH"] - log_ks_MgOH + log_kt_MgOH + log_acfs["Mg"] + log_acfs["OH"] - log_acfs["MgOH"] + log_ks_MgOH - log_kt_MgOH ) diff --git a/pytzer/io.py b/pytzer/get.py similarity index 95% rename from pytzer/io.py rename to pytzer/get.py index 68773ed5..b3f80907 100644 --- a/pytzer/io.py +++ b/pytzer/get.py @@ -1,5 +1,5 @@ # Pytzer: Pitzer model for chemical activities in aqueous solutions. -# Copyright (C) 2019--2021 Matthew P. Humphreys (GNU GPLv3) +# Copyright (C) 2019--2023 Matthew P. Humphreys (GNU GPLv3) """Import solution composition data, and export the results.""" from collections import OrderedDict @@ -41,7 +41,7 @@ def solve_df( # Solve for thermodynamic equilibrium for i, row in df.iterrows(): # Get thermodynamic solver inputs - totals = OrderedDict(row[total_cols]) + totals = OrderedDict(row[list(total_cols.keys())]) if "temperature" in row: temperature = row.temperature else: diff --git a/pytzer/libraries/Clegg22.py b/pytzer/libraries/Clegg22.py new file mode 100644 index 00000000..799f7320 --- /dev/null +++ b/pytzer/libraries/Clegg22.py @@ -0,0 +1,112 @@ +# Pytzer: Pitzer model for chemical activities in aqueous solutions. +# Copyright (C) 2019--2023 Matthew P. Humphreys (GNU GPLv3) +from . import ParameterLibrary +from .. import debyehueckel, dissociation as k, parameters as prm, unsymmetrical + +# First section is a direct copy of the Humphreys22 library +# --------------------------------------------------------- + +# Following Supp. Info. part 6 +Clegg22 = ParameterLibrary(name="Clegg22") +Clegg22.assign_func_J(unsymmetrical.P75_eq47) + +# Table S6 (Aphi and equilibria) +Clegg22.update_Aphi(debyehueckel.Aosm_M88) +Clegg22.update_equilibrium("H2O", k.H2O_MF) +Clegg22.update_equilibrium("HSO4", k.HSO4_CRP94) +Clegg22.update_equilibrium("MgOH", k.MgOH_CW91_ln) + +# Tables S7-S11 (beta and C coefficients) +Clegg22.update_ca("Ca", "Cl", prm.bC_Ca_Cl_GM89) +Clegg22.update_ca("Ca", "HSO4", prm.bC_Ca_HSO4_WM13) +Clegg22.update_ca("Ca", "OH", prm.bC_Ca_OH_HMW84) +Clegg22.update_ca("Ca", "SO4", prm.bC_Ca_SO4_WM13) +Clegg22.update_ca("H", "Cl", prm.bC_H_Cl_CMR93) +Clegg22.update_ca("H", "HSO4", prm.bC_H_HSO4_CRP94) +Clegg22.update_ca("H", "SO4", prm.bC_H_SO4_CRP94) +Clegg22.update_ca("K", "Cl", prm.bC_K_Cl_GM89) +Clegg22.update_ca("K", "HSO4", prm.bC_K_HSO4_WM13) +Clegg22.update_ca("K", "OH", prm.bC_K_OH_HMW84) +Clegg22.update_ca("K", "SO4", prm.bC_K_SO4_HM86) +Clegg22.update_ca("Mg", "Cl", prm.bC_Mg_Cl_dLP83) +Clegg22.update_ca("Mg", "HSO4", prm.bC_Mg_HSO4_RC99) +Clegg22.update_ca("Mg", "SO4", prm.bC_Mg_SO4_PP86ii) +Clegg22.update_ca("MgOH", "Cl", prm.bC_MgOH_Cl_HMW84) +Clegg22.update_ca("Na", "Cl", prm.bC_Na_Cl_M88) +Clegg22.update_ca("Na", "HSO4", prm.bC_Na_HSO4_HPR93) +Clegg22.update_ca("Na", "OH", prm.bC_Na_OH_HWT22) +Clegg22.update_ca("Na", "SO4", prm.bC_Na_SO4_HM86) + +# Table S12 (cc theta and psi coefficients) +Clegg22.update_cc("Ca", "H", prm.theta_Ca_H_RGO81) +Clegg22.update_cca("Ca", "H", "Cl", prm.psi_Ca_H_Cl_HMW84) +Clegg22.update_cc("Ca", "K", prm.theta_Ca_K_HMW84) +Clegg22.update_cca("Ca", "K", "Cl", prm.psi_Ca_K_Cl_HMW84) +Clegg22.update_cc("Ca", "Mg", prm.theta_Ca_Mg_HMW84) +Clegg22.update_cca("Ca", "Mg", "Cl", prm.psi_Ca_Mg_Cl_HMW84) +Clegg22.update_cca("Ca", "Mg", "SO4", prm.psi_Ca_Mg_SO4_HMW84) +Clegg22.update_cc("Ca", "Na", prm.theta_Ca_Na_HMW84) +Clegg22.update_cca("Ca", "Na", "Cl", prm.psi_Ca_Na_Cl_HMW84) +Clegg22.update_cca("Ca", "Na", "SO4", prm.psi_Ca_Na_SO4_HMW84) +Clegg22.update_cc("H", "K", prm.theta_H_K_HWT22) +Clegg22.update_cca("H", "K", "Cl", prm.psi_H_K_Cl_HMW84) +Clegg22.update_cca("H", "K", "HSO4", prm.psi_H_K_HSO4_HMW84) +Clegg22.update_cca("H", "K", "SO4", prm.psi_H_K_SO4_HMW84) +Clegg22.update_cc("H", "Mg", prm.theta_H_Mg_RGB80) +Clegg22.update_cca("H", "Mg", "Cl", prm.psi_H_Mg_Cl_HMW84) +Clegg22.update_cca("H", "Mg", "HSO4", prm.psi_H_Mg_HSO4_RC99) +Clegg22.update_cca("H", "Mg", "SO4", prm.psi_H_Mg_SO4_RC99) +Clegg22.update_cc("H", "Na", prm.theta_H_Na_HWT22) +Clegg22.update_cca("H", "Na", "Cl", prm.psi_H_Na_Cl_HMW84) +Clegg22.update_cca("H", "Na", "HSO4", prm.psi_H_Na_HSO4_HMW84) +Clegg22.update_cc("K", "Mg", prm.theta_K_Mg_HMW84) +Clegg22.update_cca("K", "Mg", "Cl", prm.psi_K_Mg_Cl_HMW84) +Clegg22.update_cca("K", "Mg", "SO4", prm.psi_K_Mg_SO4_HMW84) +Clegg22.update_cc("K", "Na", prm.theta_K_Na_HMW84) +Clegg22.update_cca("K", "Na", "Cl", prm.psi_K_Na_Cl_HMW84) +Clegg22.update_cca("K", "Na", "SO4", prm.psi_K_Na_SO4_HMW84) +Clegg22.update_cc("Mg", "MgOH", prm.theta_Mg_MgOH_HMW84) +Clegg22.update_cca("Mg", "MgOH", "Cl", prm.psi_Mg_MgOH_Cl_HMW84) +Clegg22.update_cc("Mg", "Na", prm.theta_Mg_Na_HMW84) +Clegg22.update_cca("Mg", "Na", "Cl", prm.psi_Mg_Na_Cl_HMW84) +Clegg22.update_cca("Mg", "Na", "SO4", prm.psi_Mg_Na_SO4_HMW84) + +# Table S13 (aa theta and psi coefficients) +Clegg22.update_aa("Cl", "HSO4", prm.theta_Cl_HSO4_HMW84) +Clegg22.update_caa("Na", "Cl", "HSO4", prm.psi_Na_Cl_HSO4_HMW84) +Clegg22.update_caa("H", "Cl", "HSO4", prm.psi_H_Cl_HSO4_HMW84) +Clegg22.update_aa("Cl", "OH", prm.theta_Cl_OH_HMW84) +Clegg22.update_caa("Ca", "Cl", "OH", prm.psi_Ca_Cl_OH_HMW84) +Clegg22.update_caa("K", "Cl", "OH", prm.psi_K_Cl_OH_HMW84) +Clegg22.update_caa("Na", "Cl", "OH", prm.psi_Na_Cl_OH_HMW84) +Clegg22.update_aa("Cl", "SO4", prm.theta_Cl_SO4_HMW84) +Clegg22.update_caa("Ca", "Cl", "SO4", prm.psi_Ca_Cl_SO4_HMW84) +Clegg22.update_caa("Mg", "Cl", "SO4", prm.psi_Mg_Cl_SO4_HMW84) +Clegg22.update_caa("Na", "Cl", "SO4", prm.psi_Na_Cl_SO4_HMW84) +Clegg22.update_aa("HSO4", "SO4", prm.theta_HSO4_SO4_WM13) +Clegg22.update_caa("K", "HSO4", "SO4", prm.psi_K_HSO4_SO4_HMW84) +Clegg22.update_caa("Mg", "HSO4", "SO4", prm.psi_Mg_HSO4_SO4_RC99) +Clegg22.update_caa("Na", "HSO4", "SO4", prm.psi_Na_HSO4_SO4_HMW84) +Clegg22.update_aa("OH", "SO4", prm.theta_OH_SO4_HMW84) +Clegg22.update_caa("K", "OH", "SO4", prm.psi_K_OH_SO4_HMW84) +Clegg22.update_caa("Na", "OH", "SO4", prm.psi_Na_OH_SO4_HMW84) + +# Below here is new things from the CHW22 Supp. Info. +# --------------------------------------------------- + +# Table S7 (equilibrium constants) +Clegg22.update_equilibrium("trisH", k.trisH_BH61) + +# Tables S8-S12 (betas and Cs) +Clegg22.update_ca("trisH", "Cl", prm.bC_trisH_Cl_CHW22) +Clegg22.update_ca("trisH", "SO4", prm.bC_trisH_SO4_CHW22) + +# Table S15 (lambdas and mu) +Clegg22.update_nc("tris", "Ca", prm.lambd_tris_Ca_CHW22) +Clegg22.update_nc("tris", "K", prm.lambd_tris_K_CHW22) +Clegg22.update_nc("tris", "Mg", prm.lambd_tris_Mg_CHW22) +Clegg22.update_nc("tris", "Na", prm.lambd_tris_Na_CHW22) +Clegg22.update_na("tris", "trisH", prm.lambd_tris_trisH_LTA21) +Clegg22.update_na("tris", "SO4", prm.lambd_tris_SO4_LTA21) +Clegg22.update_nn("tris", "tris", prm.lambd_tris_tris_LTA21) +Clegg22.update_nnn("tris", prm.mu_tris_tris_tris_LTA21) diff --git a/pytzer/libraries/Clegg23.py b/pytzer/libraries/Clegg23.py new file mode 100644 index 00000000..571f6b59 --- /dev/null +++ b/pytzer/libraries/Clegg23.py @@ -0,0 +1,178 @@ +# Pytzer: Pitzer model for chemical activities in aqueous solutions. +# Copyright (C) 2019--2023 Matthew P. Humphreys (GNU GPLv3) +from . import ParameterLibrary +from .. import debyehueckel, dissociation as k, parameters as prm, unsymmetrical + +# Following CWTF23 Supp. Info. part 6 +Clegg23 = ParameterLibrary(name="Clegg23") +Clegg23.assign_func_J(unsymmetrical.P75_eq47) # TODO check this + +# Table S13 (Aphi and equilibria) +Clegg23.update_Aphi(debyehueckel.Aosm_M88) +Clegg23.update_equilibrium("BOH3", k.BOH3_M79) +Clegg23.update_equilibrium("CaCO3", k.CaCO3_MP98_MR97) # CWTD23 cite 84HM + 88PP +Clegg23.update_equilibrium("CaF", k.CaF_MP98_MR97) # CWTF23 cite 82MS +Clegg23.update_equilibrium("HCO3", k.HCO3_MP98) # TODO SOMETHING WEIRD HERE IN CWTF23 +Clegg23.update_equilibrium("H2CO3", k.H2CO3_MP98) # CWTF23 cite 79M +Clegg23.update_equilibrium("HF", k.HF_MP98) # CWTF23 cite DR79a +Clegg23.update_equilibrium("HSO4", k.HSO4_CRP94) # TODO sign differences wth CWTF23? +Clegg23.update_equilibrium("H2O", k.H2O_M79) +Clegg23.update_equilibrium("MgCO3", k.MgCO3_MP98_MR97) # CWTF23 cite 83MT + 88PP +Clegg23.update_equilibrium("MgF", k.MgF_MP98_MR97) # CWTF23 cite 88CB +Clegg23.update_equilibrium("MgOH", k.MgOH_CW91_ln) +Clegg23.update_equilibrium("SrCO3", k.SrCO3_CWTF23) + +# Tables S14-S18 (beta and C coefficients) +Clegg23.update_ca("Ca", "Br", prm.bC_Ca_Br_SP78) +Clegg23.update_ca("Ca", "BOH4", prm.bC_Ca_BOH4_SRM87) +Clegg23.update_ca("Ca", "Cl", prm.bC_Ca_Cl_GM89) # CWTD23 cite M88 but uses GM89 +Clegg23.update_ca( + "Ca", "HCO3", prm.bC_Ca_HCO3_CWTD23 +) # CWTD23 cite HM93 but it's not - it's POS85 with a digit missing +Clegg23.update_ca("Ca", "HSO4", prm.bC_Ca_HSO4_HMW84) +Clegg23.update_ca("Ca", "OH", prm.bC_Ca_OH_HMW84) +Clegg23.update_ca("Ca", "SO4", prm.bC_Ca_SO4_HEW82) +Clegg23.update_ca("CaF", "Cl", prm.bC_CaF_Cl_PM16) +Clegg23.update_ca("H", "Br", prm.bC_H_Br_MP98) +Clegg23.update_ca("H", "Cl", prm.bC_H_Cl_CMR93) +Clegg23.update_ca("H", "HSO4", prm.bC_H_HSO4_CRP94) +Clegg23.update_ca("H", "SO4", prm.bC_H_SO4_CRP94) +Clegg23.update_ca("K", "Br", prm.bC_K_Br_CWTD23) +Clegg23.update_ca("K", "BOH4", prm.bC_K_BOH4_CWTD23) # CWTD23 cite SRRJ87 but it's not +Clegg23.update_ca("K", "Cl", prm.bC_K_Cl_GM89) +Clegg23.update_ca("K", "CO3", prm.bC_K_CO3_CWTD23) # CWTD23 cite SRG87 but it's not +Clegg23.update_ca("K", "F", prm.bC_K_F_CWTD23) # CWTD cite PM73 + SP78 +Clegg23.update_ca("K", "HCO3", prm.bC_K_HCO3_RGW84) +Clegg23.update_ca("K", "HSO4", prm.bC_K_HSO4_WM13) +Clegg23.update_ca("K", "OH", prm.bC_K_OH_MP98) +Clegg23.update_ca("K", "SO4", prm.bC_K_SO4_GM89) +Clegg23.update_ca("Mg", "Br", prm.bC_Mg_Br_SP78) +Clegg23.update_ca("Mg", "BOH4", prm.bC_Mg_BOH4_SRM87) # CWTD23 cite 88SR, numbers agree +Clegg23.update_ca("Mg", "Cl", prm.bC_Mg_Cl_PP87i) +Clegg23.update_ca("Mg", "HCO3", prm.bC_Mg_HCO3_CWTD23) # CWTD23 cite POS85 but it's not +Clegg23.update_ca("Mg", "HSO4", prm.bC_Mg_HSO4_HMW84) +Clegg23.update_ca("Mg", "SO4", prm.bC_Mg_SO4_PP86ii) +Clegg23.update_ca("MgF", "Cl", prm.bC_MgF_Cl_PM16) +Clegg23.update_ca("MgOH", "Cl", prm.bC_MgOH_Cl_HMW84) +Clegg23.update_ca("Na", "Br", prm.bC_Na_Br_CWTD23) # CWTD23 cite 73PM +Clegg23.update_ca("Na", "BOH4", prm.bC_Na_BOH4_CWTD23) # TODO check vs MP98 function +Clegg23.update_ca("Na", "Cl", prm.bC_Na_Cl_M88) +Clegg23.update_ca( + "Na", "CO3", prm.bC_Na_CO3_CWTD23b +) # TODO check code vs table (see functions) +Clegg23.update_ca("Na", "F", prm.bC_Na_F_CWTD23) +Clegg23.update_ca( + "Na", "HCO3", prm.bC_Na_HCO3_CWTD23b +) # TODO check code vs table (see functions) +Clegg23.update_ca("Na", "HSO4", prm.bC_Na_HSO4_CWTD23) +Clegg23.update_ca("Na", "OH", prm.bC_Na_OH_PP87i) +Clegg23.update_ca("Na", "SO4", prm.bC_Na_SO4_M88) +Clegg23.update_ca("Sr", "Br", prm.bC_Sr_Br_SP78) +Clegg23.update_ca("Sr", "BOH4", prm.bC_Ca_BOH4_SRM87) # CWTD23 use Ca function +Clegg23.update_ca("Sr", "Cl", prm.bC_Sr_Cl_CWTD23) +Clegg23.update_ca("Sr", "HCO3", prm.bC_Ca_HCO3_CWTD23) # CWTD23 use Ca function +Clegg23.update_ca("Sr", "HSO4", prm.bC_Ca_HSO4_HMW84) # CWTD23 use Ca function +Clegg23.update_ca("Sr", "OH", prm.bC_Ca_OH_HMW84) # CWTD23 use Ca function +Clegg23.update_ca("Sr", "SO4", prm.bC_Ca_SO4_HEW82) # CWTD23 use Ca function + +# Table S19 (cc theta and psi coefficients) +Clegg23.update_cc("Ca", "H", prm.theta_Ca_H_RGO81) +Clegg23.update_cca("Ca", "H", "Cl", prm.psi_Ca_H_Cl_RGO81) +Clegg23.update_cc("Ca", "K", prm.theta_Ca_K_GM89) +Clegg23.update_cca("Ca", "K", "Cl", prm.psi_Ca_K_Cl_GM89) +Clegg23.update_cc("Ca", "Mg", prm.theta_Ca_Mg_HMW84) # CWTD23 cite HW80 +Clegg23.update_cca("Ca", "Mg", "Cl", prm.psi_Ca_Mg_Cl_HMW84) # CWTD23 cite HW80 +Clegg23.update_cca("Ca", "Mg", "SO4", prm.psi_Ca_Mg_SO4_HMW84) # CWTD23 cite HEW82 +Clegg23.update_cc("Ca", "Na", prm.theta_Ca_Na_M88) +Clegg23.update_cca("Ca", "Na", "Cl", prm.psi_Ca_Na_Cl_M88) +Clegg23.update_cca("Ca", "Na", "SO4", prm.psi_Ca_Na_SO4_HMW84) +Clegg23.update_cc("H", "K", prm.theta_H_K_HWT22) # CWTD23 cite CMR93 +Clegg23.update_cca("H", "K", "Br", prm.psi_H_K_Br_PK74) +Clegg23.update_cca("H", "K", "Cl", prm.psi_H_K_Cl_HMW84) +Clegg23.update_cca("H", "K", "SO4", prm.psi_H_K_SO4_HMW84) +Clegg23.update_cca("H", "K", "HSO4", prm.psi_H_K_HSO4_HMW84) +Clegg23.update_cc("H", "Mg", prm.theta_H_Mg_RGB80) +Clegg23.update_cca("H", "Mg", "Cl", prm.psi_H_Mg_Cl_RGB80) +Clegg23.update_cca("H", "Mg", "HSO4", prm.psi_H_Mg_HSO4_HMW84) # not cited, but in code +Clegg23.update_cc("H", "Na", prm.theta_H_Na_HWT22) +Clegg23.update_cca("H", "Na", "Br", prm.psi_H_Na_Br_PK74) +Clegg23.update_cca("H", "Na", "Cl", prm.psi_H_Na_Cl_PK74) +Clegg23.update_cc("H", "Sr", prm.theta_H_Sr_RGRG86) +Clegg23.update_cca("H", "Sr", "Cl", prm.psi_H_Sr_Cl_RGRG86) +Clegg23.update_cca("K", "Mg", "Cl", prm.psi_K_Mg_Cl_PP87ii) +Clegg23.update_cca("K", "Mg", "SO4", prm.psi_K_Mg_SO4_HMW84) # CWTD23 cite HW80 +Clegg23.update_cca("K", "Mg", "HSO4", prm.psi_K_Mg_HSO4_HMW84) +Clegg23.update_cc("K", "Na", prm.theta_K_Na_GM89) +Clegg23.update_cca("K", "Na", "Br", prm.psi_K_Na_Br_PK74) +Clegg23.update_cca("K", "Na", "Cl", prm.psi_K_Na_Cl_GM89) +Clegg23.update_cca("K", "Na", "SO4", prm.psi_K_Na_SO4_GM89) +Clegg23.update_cc("K", "Sr", prm.theta_Na_Sr_MP98) # CWTD23 use Na-Sr function +Clegg23.update_cca("K", "Sr", "Cl", prm.psi_Na_Sr_Cl_MP98) # CWTD23 use Na-Sr function +Clegg23.update_cca("Mg", "MgOH", "Cl", prm.psi_Mg_MgOH_Cl_HMW84) +Clegg23.update_cc("Mg", "Na", prm.theta_Mg_Na_HMW84) # CWTD23 cite P75 +Clegg23.update_cca("Mg", "Na", "Cl", prm.psi_Mg_Na_Cl_PP87ii) +Clegg23.update_cca("Mg", "Na", "SO4", prm.psi_Mg_Na_SO4_HMW84) # CWTD23 cite HW80 +Clegg23.update_cc("Na", "Sr", prm.theta_Na_Sr_MP98) +Clegg23.update_cca("Na", "Sr", "Cl", prm.psi_Na_Sr_Cl_MP98) + +# Table S20 (aa theta and psi coefficients) +Clegg23.update_aa("BOH4", "Cl", prm.theta_BOH4_Cl_CWTD23) +Clegg23.update_caa("Ca", "BOH4", "Cl", prm.psi_Ca_BOH4_Cl_MP98) # CWTD23 cite 02P +Clegg23.update_caa("Mg", "BOH4", "Cl", prm.psi_Mg_BOH4_Cl_MP98) # CWTD23 cite 02P +Clegg23.update_caa("Na", "BOH4", "Cl", prm.psi_Na_BOH4_Cl_MP98) # CWTD23 cite 02P +Clegg23.update_aa("BOH4", "SO4", prm.theta_BOH4_SO4_FW86) +Clegg23.update_aa("Br", "OH", prm.theta_Br_OH_PK74) +Clegg23.update_caa("K", "Br", "OH", prm.psi_K_Br_OH_PK74) +Clegg23.update_caa("Na", "Br", "OH", prm.psi_Na_Br_OH_PK74) +Clegg23.update_aa("CO3", "Cl", prm.theta_CO3_Cl_PP82) +Clegg23.update_caa("Na", "CO3", "Cl", prm.psi_Na_CO3_Cl_TM82) +Clegg23.update_aa("Cl", "F", prm.theta_Cl_F_MP98) # CWTD23 cite 88CB +Clegg23.update_caa("Na", "Cl", "F", prm.psi_Na_Cl_F_CWTD23) # CWTD23 cite 88CB +Clegg23.update_aa("Cl", "HCO3", prm.theta_Cl_HCO3_PP82) +Clegg23.update_caa("Mg", "Cl", "HCO3", prm.psi_Mg_Cl_HCO3_HMW84) +Clegg23.update_caa("Na", "Cl", "HCO3", prm.psi_Na_Cl_HCO3_PP82) +Clegg23.update_aa("Cl", "HSO4", prm.theta_Cl_HSO4_HMW84) +Clegg23.update_caa("H", "Cl", "HSO4", prm.psi_H_Cl_HSO4_HMW84) +Clegg23.update_caa("Na", "Cl", "HSO4", prm.psi_Na_Cl_HSO4_HMW84) +Clegg23.update_aa("Cl", "OH", prm.theta_Cl_OH_CWTD23) # CWTD23 cite 02P +Clegg23.update_caa("Ca", "Cl", "OH", prm.psi_Ca_Cl_OH_HMW84) +Clegg23.update_caa("K", "Cl", "OH", prm.psi_K_Cl_OH_HMW84) +Clegg23.update_caa("Na", "Cl", "OH", prm.psi_Na_Cl_OH_PK74) +Clegg23.update_aa("Cl", "SO4", prm.theta_Cl_SO4_M88) +Clegg23.update_caa("Ca", "Cl", "SO4", prm.psi_Ca_Cl_SO4_HMW84) # CWTD23 cite 82HE/80HW +Clegg23.update_caa("K", "Cl", "SO4", prm.psi_K_Cl_SO4_GM89) # CWTD23 cite M88 +Clegg23.update_caa("Mg", "Cl", "SO4", prm.psi_Mg_Cl_SO4_HMW84) # CWTD23 cite 82HE/80HW +Clegg23.update_caa("Na", "Cl", "SO4", prm.psi_Na_Cl_SO4_M88) +Clegg23.update_aa("CO3", "SO4", prm.theta_CO3_SO4_HMW84) +Clegg23.update_caa("K", "CO3", "SO4", prm.psi_K_CO3_SO4_HMW84) +Clegg23.update_caa("Na", "CO3", "SO4", prm.psi_Na_CO3_SO4_HMW84) +Clegg23.update_aa("HCO3", "SO4", prm.theta_HCO3_SO4_HMW84) +Clegg23.update_caa("Mg", "HCO3", "SO4", prm.psi_Mg_HCO3_SO4_HMW84) +Clegg23.update_caa("Na", "HCO3", "SO4", prm.psi_Na_HCO3_SO4_HMW84) +Clegg23.update_caa("K", "HSO4", "SO4", prm.psi_K_HSO4_SO4_HMW84) +Clegg23.update_aa("OH", "SO4", prm.theta_OH_SO4_HMW84) +Clegg23.update_caa("K", "OH", "SO4", prm.psi_K_OH_SO4_HMW84) +Clegg23.update_caa("Na", "OH", "SO4", prm.psi_Na_OH_SO4_HMW84) + +# Table S21 (lambda and zeta coefficients) +Clegg23.update_na("BOH3", "Cl", prm.lambd_BOH3_Cl_FW86) +Clegg23.update_nc("BOH3", "K", prm.lambd_BOH3_K_FW86) +Clegg23.update_nc("BOH3", "Na", prm.lambd_BOH3_Na_FW86) +Clegg23.update_nca("BOH3", "Na", "SO4", prm.zeta_BOH3_Na_SO4_FW86) +Clegg23.update_na("BOH3", "SO4", prm.lambd_BOH3_SO4_FW86) +Clegg23.update_nc("CO2", "Ca", prm.lambd_CO2_Ca_HM93) +Clegg23.update_nca("CO2", "Ca", "Cl", prm.zeta_CO2_Ca_Cl_HM93) +Clegg23.update_na("CO2", "Cl", prm.lambd_CO2_Cl_HM93) +Clegg23.update_nca("CO2", "H", "Cl", prm.zeta_CO2_H_Cl_HM93) +Clegg23.update_nc("CO2", "K", prm.lambd_CO2_K_HM93) +Clegg23.update_nca("CO2", "K", "Cl", prm.zeta_CO2_K_Cl_HM93) +Clegg23.update_nca("CO2", "K", "SO4", prm.zeta_CO2_K_SO4_HM93) +Clegg23.update_nc("CO2", "Mg", prm.lambd_CO2_Mg_HM93) +Clegg23.update_nca("CO2", "Mg", "Cl", prm.zeta_CO2_Mg_Cl_HM93) +Clegg23.update_nca("CO2", "Mg", "SO4", prm.zeta_CO2_Mg_SO4_HM93) +Clegg23.update_nc("CO2", "Na", prm.lambd_CO2_Na_HM93) +Clegg23.update_nca("CO2", "Na", "Cl", prm.zeta_CO2_Na_Cl_HM93) +Clegg23.update_nca("CO2", "Na", "SO4", prm.zeta_CO2_Na_SO4_HM93) +Clegg23.update_na("CO2", "SO4", prm.lambd_CO2_SO4_HM93) +Clegg23.update_nc("HF", "Na", prm.lambd_HF_Na_MP98) # CWTD23 cite 88CB +Clegg23.update_nc("MgCO3", "Na", prm.lambd_MgCO3_Na_CWTD23) # CWTD23 cite 83MT diff --git a/pytzer/libraries/Clegg94.py b/pytzer/libraries/Clegg94.py index 4e8aec34..9e017f22 100644 --- a/pytzer/libraries/Clegg94.py +++ b/pytzer/libraries/Clegg94.py @@ -1,5 +1,5 @@ # Pytzer: Pitzer model for chemical activities in aqueous solutions. -# Copyright (C) 2019--2021 Matthew P. Humphreys (GNU GPLv3) +# Copyright (C) 2019--2023 Matthew P. Humphreys (GNU GPLv3) """Clegg et al. (1994). System: H-HSO4-SO4. *Journal of the Chemical Society, Faraday Transactions* 90, 1875--1894. doi:10.1039/FT9949001875 diff --git a/pytzer/libraries/Greenberg89.py b/pytzer/libraries/Greenberg89.py index bb625d49..c6950bbd 100644 --- a/pytzer/libraries/Greenberg89.py +++ b/pytzer/libraries/Greenberg89.py @@ -1,5 +1,5 @@ # Pytzer: Pitzer model for chemical activities in aqueous solutions. -# Copyright (C) 2019--2021 Matthew P. Humphreys (GNU GPLv3) +# Copyright (C) 2019--2023 Matthew P. Humphreys (GNU GPLv3) """Greenberg & Møller (1988). System: Na-K-Ca-Cl-SO4. *Geochimica et Cosmochimica Acta* 53, 2503--2518. doi:10.1016/0016-7037(89)90124-5 diff --git a/pytzer/libraries/Harvie84.py b/pytzer/libraries/Harvie84.py index feda3c76..ab199ca0 100644 --- a/pytzer/libraries/Harvie84.py +++ b/pytzer/libraries/Harvie84.py @@ -1,5 +1,5 @@ # Pytzer: Pitzer model for chemical activities in aqueous solutions. -# Copyright (C) 2019--2021 Matthew P. Humphreys (GNU GPLv3) +# Copyright (C) 2019--2023 Matthew P. Humphreys (GNU GPLv3) from . import ParameterLibrary from .. import debyehueckel, dissociation as k, parameters as prm, unsymmetrical diff --git a/pytzer/libraries/HeMorse93.py b/pytzer/libraries/HeMorse93.py new file mode 100644 index 00000000..4757a537 --- /dev/null +++ b/pytzer/libraries/HeMorse93.py @@ -0,0 +1,285 @@ +# Pytzer: Pitzer model for chemical activities in aqueous solutions. +# Copyright (C) 2019--2023 Matthew P. Humphreys (GNU GPLv3) +"""He & Morse (1993) Geochim. Cosmochim. Acta 57(15), 3533-3554. +https://doi.org/10.1016/0016-7037(93)90137-L +""" + +from . import ParameterLibrary +from .. import debyehueckel, dissociation as k, parameters as prm, unsymmetrical + +HeMorse93 = ParameterLibrary(name="HeMorse93") +HeMorse93.update_Aphi(debyehueckel.Aosm_M88) +HeMorse93.assign_func_J(unsymmetrical.Harvie) +# beta and C +HeMorse93.update_ca("Na", "Cl", prm.bC_Na_Cl_M88) +HeMorse93.update_ca("Na", "SO4", prm.bC_Na_SO4_M88) +HeMorse93.update_ca("Na", "HSO4", prm.bC_Na_HSO4_HMW84) +HeMorse93.update_ca("Na", "OH", prm.bC_Na_OH_PP87i) +HeMorse93.update_ca("Na", "HCO3", prm.bC_Na_HCO3_HM93) +HeMorse93.update_ca("Na", "CO3", prm.bC_Na_CO3_HM93) +HeMorse93.update_ca("K", "Cl", prm.bC_K_Cl_GM89) +HeMorse93.update_ca("K", "SO4", prm.bC_K_SO4_GM89) +HeMorse93.update_ca("K", "HSO4", prm.bC_K_HSO4_HMW84) +HeMorse93.update_ca("K", "OH", prm.bC_K_OH_HMW84) +HeMorse93.update_ca("K", "HCO3", prm.bC_K_HCO3_HM93) +HeMorse93.update_ca("K", "CO3", prm.bC_K_CO3_HM93) +HeMorse93.update_ca("Ca", "Cl", prm.bC_Ca_Cl_GM89) +HeMorse93.update_ca("Ca", "SO4", prm.bC_Ca_SO4_M88) +HeMorse93.update_ca("Ca", "HSO4", prm.bC_Ca_HSO4_HMW84) +HeMorse93.update_ca("Ca", "OH", prm.bC_Ca_OH_HMW84) +HeMorse93.update_ca("Ca", "HCO3", prm.bC_Ca_HCO3_HM93) +HeMorse93.update_ca("Ca", "CO3", prm.bC_Ca_CO3_HM93) +HeMorse93.update_ca("Mg", "Cl", prm.bC_Mg_Cl_SMW90) +HeMorse93.update_ca("Mg", "SO4", prm.bC_Mg_SO4_SMW90) +HeMorse93.update_ca("Mg", "HSO4", prm.bC_Mg_HSO4_HMW84) +HeMorse93.update_ca("Mg", "OH", prm.bC_Mg_OH_HMW84) +HeMorse93.update_ca("Mg", "HCO3", prm.bC_Mg_HCO3_HM93) +HeMorse93.update_ca("Mg", "CO3", prm.bC_Mg_CO3_HM93) +HeMorse93.update_ca("MgOH", "Cl", prm.bC_MgOH_Cl_HMW84) +HeMorse93.update_ca("MgOH", "SO4", prm.bC_MgOH_SO4_HMW84) +HeMorse93.update_ca("MgOH", "HSO4", prm.bC_MgOH_HSO4_HMW84) +HeMorse93.update_ca("MgOH", "OH", prm.bC_MgOH_OH_HMW84) +HeMorse93.update_ca("MgOH", "HCO3", prm.bC_MgOH_HCO3_HMW84) +HeMorse93.update_ca("MgOH", "CO3", prm.bC_MgOH_CO3_HMW84) +HeMorse93.update_ca("H", "Cl", prm.bC_H_Cl_HMW84) +HeMorse93.update_ca("H", "SO4", prm.bC_H_SO4_HM92) +HeMorse93.update_ca("H", "HSO4", prm.bC_H_HSO4_HM92) +HeMorse93.update_ca("H", "OH", prm.bC_H_OH_HMW84) +HeMorse93.update_ca("H", "HCO3", prm.bC_H_HCO3_HMW84) +HeMorse93.update_ca("H", "CO3", prm.bC_H_CO3_HMW84) +# theta and psi +HeMorse93.update_aa("Cl", "SO4", prm.theta_Cl_SO4_M88) +HeMorse93.update_caa("Na", "Cl", "SO4", prm.psi_Na_Cl_SO4_M88) +HeMorse93.update_caa("K", "Cl", "SO4", prm.psi_K_Cl_SO4_GM89) +HeMorse93.update_caa("Ca", "Cl", "SO4", prm.psi_Ca_Cl_SO4_M88) +HeMorse93.update_caa("Mg", "Cl", "SO4", prm.psi_Mg_Cl_SO4_HM93) +HeMorse93.update_caa("MgOH", "Cl", "SO4", prm.psi_MgOH_Cl_SO4_HMW84) +HeMorse93.update_caa("H", "Cl", "SO4", prm.psi_H_Cl_SO4_HMW84) +HeMorse93.update_aa("Cl", "HSO4", prm.theta_Cl_HSO4_HMW84) +HeMorse93.update_caa("Na", "Cl", "HSO4", prm.psi_Na_Cl_HSO4_HMW84) +HeMorse93.update_caa("K", "Cl", "HSO4", prm.psi_K_Cl_HSO4_HMW84) +HeMorse93.update_caa("Ca", "Cl", "HSO4", prm.psi_Ca_Cl_HSO4_HMW84) +HeMorse93.update_caa("Mg", "Cl", "HSO4", prm.psi_Mg_Cl_HSO4_HMW84) +HeMorse93.update_caa("MgOH", "Cl", "HSO4", prm.psi_MgOH_Cl_HSO4_HMW84) +HeMorse93.update_caa("H", "Cl", "HSO4", prm.psi_H_Cl_HSO4_HMW84) +HeMorse93.update_aa("Cl", "OH", prm.theta_Cl_OH_HMW84) +HeMorse93.update_caa("Na", "Cl", "OH", prm.psi_Na_Cl_OH_PP87ii) +HeMorse93.update_caa("K", "Cl", "OH", prm.psi_K_Cl_OH_HMW84) +HeMorse93.update_caa("Ca", "Cl", "OH", prm.psi_Ca_Cl_OH_HMW84) +HeMorse93.update_caa("Mg", "Cl", "OH", prm.psi_Mg_Cl_OH_HMW84) +HeMorse93.update_caa("MgOH", "Cl", "OH", prm.psi_MgOH_Cl_OH_HMW84) +HeMorse93.update_caa("H", "Cl", "OH", prm.psi_H_Cl_OH_HMW84) +HeMorse93.update_aa("Cl", "HCO3", prm.theta_Cl_HCO3_HMW84) +HeMorse93.update_caa("Na", "Cl", "HCO3", prm.psi_Na_Cl_HCO3_HMW84) +HeMorse93.update_caa("K", "Cl", "HCO3", prm.psi_K_Cl_HCO3_HMW84) +HeMorse93.update_caa("Ca", "Cl", "HCO3", prm.psi_Ca_Cl_HCO3_HMW84) +HeMorse93.update_caa("Mg", "Cl", "HCO3", prm.psi_Mg_Cl_HCO3_HMW84) +HeMorse93.update_caa("MgOH", "Cl", "HCO3", prm.psi_MgOH_Cl_HCO3_HMW84) +HeMorse93.update_caa("H", "Cl", "HCO3", prm.psi_H_Cl_HCO3_HMW84) +HeMorse93.update_aa("CO3", "Cl", prm.theta_CO3_Cl_HMW84) +HeMorse93.update_caa("Na", "CO3", "Cl", prm.psi_Na_CO3_Cl_HMW84) +HeMorse93.update_caa("K", "CO3", "Cl", prm.psi_K_CO3_Cl_HMW84) +HeMorse93.update_caa("Ca", "CO3", "Cl", prm.psi_Ca_CO3_Cl_HMW84) +HeMorse93.update_caa("Mg", "CO3", "Cl", prm.psi_Mg_CO3_Cl_HMW84) +HeMorse93.update_caa("MgOH", "CO3", "Cl", prm.psi_MgOH_CO3_Cl_HMW84) +HeMorse93.update_caa("H", "CO3", "Cl", prm.psi_H_CO3_Cl_HMW84) +HeMorse93.update_aa("HSO4", "SO4", prm.theta_HSO4_SO4_HM92) +HeMorse93.update_caa("Na", "HSO4", "SO4", prm.psi_Na_HSO4_SO4_HMW84) +HeMorse93.update_caa("K", "HSO4", "SO4", prm.psi_K_HSO4_SO4_HMW84) +HeMorse93.update_caa("Ca", "HSO4", "SO4", prm.psi_Ca_HSO4_SO4_HMW84) +HeMorse93.update_caa("Mg", "HSO4", "SO4", prm.psi_Mg_HSO4_SO4_HMW84) +HeMorse93.update_caa("MgOH", "HSO4", "SO4", prm.psi_MgOH_HSO4_SO4_HMW84) +HeMorse93.update_caa("H", "HSO4", "SO4", prm.psi_H_HSO4_SO4_HMW84) +HeMorse93.update_aa("OH", "SO4", prm.theta_OH_SO4_HMW84) +HeMorse93.update_caa("Na", "OH", "SO4", prm.psi_Na_OH_SO4_PP87ii) +HeMorse93.update_caa("K", "OH", "SO4", prm.psi_K_OH_SO4_HMW84) +HeMorse93.update_caa("Ca", "OH", "SO4", prm.psi_Ca_OH_SO4_HMW84) +HeMorse93.update_caa("Mg", "OH", "SO4", prm.psi_Mg_OH_SO4_HMW84) +HeMorse93.update_caa("MgOH", "OH", "SO4", prm.psi_MgOH_OH_SO4_HMW84) +HeMorse93.update_caa("H", "OH", "SO4", prm.psi_H_OH_SO4_HMW84) +HeMorse93.update_aa("HCO3", "SO4", prm.theta_HCO3_SO4_HMW84) +HeMorse93.update_caa("Na", "HCO3", "SO4", prm.psi_Na_HCO3_SO4_HMW84) +HeMorse93.update_caa("K", "HCO3", "SO4", prm.psi_K_HCO3_SO4_HMW84) +HeMorse93.update_caa("Ca", "HCO3", "SO4", prm.psi_Ca_HCO3_SO4_HMW84) +HeMorse93.update_caa("Mg", "HCO3", "SO4", prm.psi_Mg_HCO3_SO4_HMW84) +HeMorse93.update_caa("MgOH", "HCO3", "SO4", prm.psi_MgOH_HCO3_SO4_HMW84) +HeMorse93.update_caa("H", "HCO3", "SO4", prm.psi_H_HCO3_SO4_HMW84) +HeMorse93.update_aa("CO3", "SO4", prm.theta_CO3_SO4_HMW84) +HeMorse93.update_caa("Na", "CO3", "SO4", prm.psi_Na_CO3_SO4_HMW84) +HeMorse93.update_caa("K", "CO3", "SO4", prm.psi_K_CO3_SO4_HMW84) +HeMorse93.update_caa("Ca", "CO3", "SO4", prm.psi_Ca_CO3_SO4_HMW84) +HeMorse93.update_caa("Mg", "CO3", "SO4", prm.psi_Mg_CO3_SO4_HMW84) +HeMorse93.update_caa("MgOH", "CO3", "SO4", prm.psi_MgOH_CO3_SO4_HMW84) +HeMorse93.update_caa("H", "CO3", "SO4", prm.psi_H_CO3_SO4_HMW84) +HeMorse93.update_aa("HSO4", "OH", prm.theta_HSO4_OH_HMW84) +HeMorse93.update_caa("Na", "HSO4", "OH", prm.psi_Na_HSO4_OH_HMW84) +HeMorse93.update_caa("K", "HSO4", "OH", prm.psi_K_HSO4_OH_HMW84) +HeMorse93.update_caa("Ca", "HSO4", "OH", prm.psi_Ca_HSO4_OH_HMW84) +HeMorse93.update_caa("Mg", "HSO4", "OH", prm.psi_Mg_HSO4_OH_HMW84) +HeMorse93.update_caa("MgOH", "HSO4", "OH", prm.psi_MgOH_HSO4_OH_HMW84) +HeMorse93.update_caa("H", "HSO4", "OH", prm.psi_H_HSO4_OH_HMW84) +HeMorse93.update_aa("HCO3", "HSO4", prm.theta_HCO3_HSO4_HMW84) +HeMorse93.update_caa("Na", "HCO3", "HSO4", prm.psi_Na_HCO3_HSO4_HMW84) +HeMorse93.update_caa("K", "HCO3", "HSO4", prm.psi_K_HCO3_HSO4_HMW84) +HeMorse93.update_caa("Ca", "HCO3", "HSO4", prm.psi_Ca_HCO3_HSO4_HMW84) +HeMorse93.update_caa("Mg", "HCO3", "HSO4", prm.psi_Mg_HCO3_HSO4_HMW84) +HeMorse93.update_caa("MgOH", "HCO3", "HSO4", prm.psi_MgOH_HCO3_HSO4_HMW84) +HeMorse93.update_caa("H", "HCO3", "HSO4", prm.psi_H_HCO3_HSO4_HMW84) +HeMorse93.update_aa("CO3", "HSO4", prm.theta_CO3_HSO4_HMW84) +HeMorse93.update_caa("Na", "CO3", "HSO4", prm.psi_Na_CO3_HSO4_HMW84) +HeMorse93.update_caa("K", "CO3", "HSO4", prm.psi_K_CO3_HSO4_HMW84) +HeMorse93.update_caa("Ca", "CO3", "HSO4", prm.psi_Ca_CO3_HSO4_HMW84) +HeMorse93.update_caa("Mg", "CO3", "HSO4", prm.psi_Mg_CO3_HSO4_HMW84) +HeMorse93.update_caa("MgOH", "CO3", "HSO4", prm.psi_MgOH_CO3_HSO4_HMW84) +HeMorse93.update_caa("H", "CO3", "HSO4", prm.psi_H_CO3_HSO4_HMW84) +HeMorse93.update_aa("HCO3", "OH", prm.theta_HCO3_OH_HMW84) +HeMorse93.update_caa("Na", "HCO3", "OH", prm.psi_Na_HCO3_OH_HMW84) +HeMorse93.update_caa("K", "HCO3", "OH", prm.psi_K_HCO3_OH_HMW84) +HeMorse93.update_caa("Ca", "HCO3", "OH", prm.psi_Ca_HCO3_OH_HMW84) +HeMorse93.update_caa("Mg", "HCO3", "OH", prm.psi_Mg_HCO3_OH_HMW84) +HeMorse93.update_caa("MgOH", "HCO3", "OH", prm.psi_MgOH_HCO3_OH_HMW84) +HeMorse93.update_caa("H", "HCO3", "OH", prm.psi_H_HCO3_OH_HMW84) +HeMorse93.update_aa("CO3", "OH", prm.theta_CO3_OH_HMW84) +HeMorse93.update_caa("Na", "CO3", "OH", prm.psi_Na_CO3_OH_HMW84) +HeMorse93.update_caa("K", "CO3", "OH", prm.psi_K_CO3_OH_HMW84) +HeMorse93.update_caa("Ca", "CO3", "OH", prm.psi_Ca_CO3_OH_HMW84) +HeMorse93.update_caa("Mg", "CO3", "OH", prm.psi_Mg_CO3_OH_HMW84) +HeMorse93.update_caa("MgOH", "CO3", "OH", prm.psi_MgOH_CO3_OH_HMW84) +HeMorse93.update_caa("H", "CO3", "OH", prm.psi_H_CO3_OH_HMW84) +HeMorse93.update_aa("CO3", "HCO3", prm.theta_CO3_HCO3_HMW84) +HeMorse93.update_caa("Na", "CO3", "HCO3", prm.psi_Na_CO3_HCO3_HMW84) +HeMorse93.update_caa("K", "CO3", "HCO3", prm.psi_K_CO3_HCO3_HMW84) +HeMorse93.update_caa("Ca", "CO3", "HCO3", prm.psi_Ca_CO3_HCO3_HMW84) +HeMorse93.update_caa("Mg", "CO3", "HCO3", prm.psi_Mg_CO3_HCO3_HMW84) +HeMorse93.update_caa("MgOH", "CO3", "HCO3", prm.psi_MgOH_CO3_HCO3_HMW84) +HeMorse93.update_caa("H", "CO3", "HCO3", prm.psi_H_CO3_HCO3_HMW84) +HeMorse93.update_cc("K", "Na", prm.theta_K_Na_GM89) +HeMorse93.update_cca("K", "Na", "Cl", prm.psi_K_Na_Cl_GM89) +HeMorse93.update_cca("K", "Na", "SO4", prm.psi_K_Na_SO4_GM89) +HeMorse93.update_cca("K", "Na", "HSO4", prm.psi_K_Na_HSO4_HMW84) +HeMorse93.update_cca("K", "Na", "OH", prm.psi_K_Na_OH_HMW84) +HeMorse93.update_cca("K", "Na", "HCO3", prm.psi_K_Na_HCO3_HMW84) +HeMorse93.update_cca("K", "Na", "CO3", prm.psi_K_Na_CO3_HMW84) +HeMorse93.update_cc("Ca", "Na", prm.theta_Ca_Na_M88) +HeMorse93.update_cca("Ca", "Na", "Cl", prm.psi_Ca_Na_Cl_M88) +HeMorse93.update_cca("Ca", "Na", "SO4", prm.psi_Ca_Na_SO4_M88) +HeMorse93.update_cca("Ca", "Na", "HSO4", prm.psi_Ca_Na_HSO4_HMW84) +HeMorse93.update_cca("Ca", "Na", "OH", prm.psi_Ca_Na_OH_HMW84) +HeMorse93.update_cca("Ca", "Na", "HCO3", prm.psi_Ca_Na_HCO3_HMW84) +HeMorse93.update_cca("Ca", "Na", "CO3", prm.psi_Ca_Na_CO3_HMW84) +HeMorse93.update_cc("Mg", "Na", prm.theta_Mg_Na_HMW84) +HeMorse93.update_cca("Mg", "Na", "Cl", prm.psi_Mg_Na_Cl_PP87ii) +HeMorse93.update_cca("Mg", "Na", "SO4", prm.psi_Mg_Na_SO4_HMW84) +HeMorse93.update_cca("Mg", "Na", "HSO4", prm.psi_Mg_Na_HSO4_HMW84) +HeMorse93.update_cca("Mg", "Na", "OH", prm.psi_Mg_Na_OH_HMW84) +HeMorse93.update_cca("Mg", "Na", "HCO3", prm.psi_Mg_Na_HCO3_HMW84) +HeMorse93.update_cca("Mg", "Na", "CO3", prm.psi_Mg_Na_CO3_HMW84) +HeMorse93.update_cc("MgOH", "Na", prm.theta_MgOH_Na_HMW84) +HeMorse93.update_cca("MgOH", "Na", "Cl", prm.psi_MgOH_Na_Cl_HMW84) +HeMorse93.update_cca("MgOH", "Na", "SO4", prm.psi_MgOH_Na_SO4_HMW84) +HeMorse93.update_cca("MgOH", "Na", "HSO4", prm.psi_MgOH_Na_HSO4_HMW84) +HeMorse93.update_cca("MgOH", "Na", "OH", prm.psi_MgOH_Na_OH_HMW84) +HeMorse93.update_cca("MgOH", "Na", "HCO3", prm.psi_MgOH_Na_HCO3_HMW84) +HeMorse93.update_cca("MgOH", "Na", "CO3", prm.psi_MgOH_Na_CO3_HMW84) +HeMorse93.update_cc("H", "Na", prm.theta_H_Na_HMW84) +HeMorse93.update_cca("H", "Na", "Cl", prm.psi_H_Na_Cl_HMW84) +HeMorse93.update_cca("H", "Na", "SO4", prm.psi_H_Na_SO4_HMW84) +HeMorse93.update_cca("H", "Na", "HSO4", prm.psi_H_Na_HSO4_HMW84) +HeMorse93.update_cca("H", "Na", "OH", prm.psi_H_Na_OH_HMW84) +HeMorse93.update_cca("H", "Na", "HCO3", prm.psi_H_Na_HCO3_HMW84) +HeMorse93.update_cca("H", "Na", "CO3", prm.psi_H_Na_CO3_HMW84) +HeMorse93.update_cc("Ca", "K", prm.theta_Ca_K_GM89) +HeMorse93.update_cca("Ca", "K", "Cl", prm.psi_Ca_K_Cl_GM89) +HeMorse93.update_cca("Ca", "K", "SO4", prm.psi_Ca_K_SO4_GM89) +HeMorse93.update_cca("Ca", "K", "HSO4", prm.psi_Ca_K_HSO4_HMW84) +HeMorse93.update_cca("Ca", "K", "OH", prm.psi_Ca_K_OH_HMW84) +HeMorse93.update_cca("Ca", "K", "HCO3", prm.psi_Ca_K_HCO3_HMW84) +HeMorse93.update_cca("Ca", "K", "CO3", prm.psi_Ca_K_CO3_HMW84) +HeMorse93.update_cc("K", "Mg", prm.theta_K_Mg_HMW84) +HeMorse93.update_cca("K", "Mg", "Cl", prm.psi_K_Mg_Cl_PP87ii) +HeMorse93.update_cca("K", "Mg", "SO4", prm.psi_K_Mg_SO4_HMW84) +HeMorse93.update_cca("K", "Mg", "HSO4", prm.psi_K_Mg_HSO4_HMW84) +HeMorse93.update_cca("K", "Mg", "OH", prm.psi_K_Mg_OH_HMW84) +HeMorse93.update_cca("K", "Mg", "HCO3", prm.psi_K_Mg_HCO3_HMW84) +HeMorse93.update_cca("K", "Mg", "CO3", prm.psi_K_Mg_CO3_HMW84) +HeMorse93.update_cc("K", "MgOH", prm.theta_K_MgOH_HMW84) +HeMorse93.update_cca("K", "MgOH", "Cl", prm.psi_K_MgOH_Cl_HMW84) +HeMorse93.update_cca("K", "MgOH", "SO4", prm.psi_K_MgOH_SO4_HMW84) +HeMorse93.update_cca("K", "MgOH", "HSO4", prm.psi_K_MgOH_HSO4_HMW84) +HeMorse93.update_cca("K", "MgOH", "OH", prm.psi_K_MgOH_OH_HMW84) +HeMorse93.update_cca("K", "MgOH", "HCO3", prm.psi_K_MgOH_HCO3_HMW84) +HeMorse93.update_cca("K", "MgOH", "CO3", prm.psi_K_MgOH_CO3_HMW84) +HeMorse93.update_cc("H", "K", prm.theta_H_K_HMW84) +HeMorse93.update_cca("H", "K", "Cl", prm.psi_H_K_Cl_HMW84) +HeMorse93.update_cca("H", "K", "SO4", prm.psi_H_K_SO4_HMW84) +HeMorse93.update_cca("H", "K", "HSO4", prm.psi_H_K_HSO4_HMW84) +HeMorse93.update_cca("H", "K", "OH", prm.psi_H_K_OH_HMW84) +HeMorse93.update_cca("H", "K", "HCO3", prm.psi_H_K_HCO3_HMW84) +HeMorse93.update_cca("H", "K", "CO3", prm.psi_H_K_CO3_HMW84) +HeMorse93.update_cc("Ca", "Mg", prm.theta_Ca_Mg_HMW84) +HeMorse93.update_cca("Ca", "Mg", "Cl", prm.psi_Ca_Mg_Cl_HMW84) +HeMorse93.update_cca("Ca", "Mg", "SO4", prm.psi_Ca_Mg_SO4_HMW84) +HeMorse93.update_cca("Ca", "Mg", "HSO4", prm.psi_Ca_Mg_HSO4_HMW84) +HeMorse93.update_cca("Ca", "Mg", "OH", prm.psi_Ca_Mg_OH_HMW84) +HeMorse93.update_cca("Ca", "Mg", "HCO3", prm.psi_Ca_Mg_HCO3_HMW84) +HeMorse93.update_cca("Ca", "Mg", "CO3", prm.psi_Ca_Mg_CO3_HMW84) +HeMorse93.update_cc("Ca", "MgOH", prm.theta_Ca_MgOH_HMW84) +HeMorse93.update_cca("Ca", "MgOH", "Cl", prm.psi_Ca_MgOH_Cl_HMW84) +HeMorse93.update_cca("Ca", "MgOH", "SO4", prm.psi_Ca_MgOH_SO4_HMW84) +HeMorse93.update_cca("Ca", "MgOH", "HSO4", prm.psi_Ca_MgOH_HSO4_HMW84) +HeMorse93.update_cca("Ca", "MgOH", "OH", prm.psi_Ca_MgOH_OH_HMW84) +HeMorse93.update_cca("Ca", "MgOH", "HCO3", prm.psi_Ca_MgOH_HCO3_HMW84) +HeMorse93.update_cca("Ca", "MgOH", "CO3", prm.psi_Ca_MgOH_CO3_HMW84) +HeMorse93.update_cc("Ca", "H", prm.theta_Ca_H_HMW84) +HeMorse93.update_cca("Ca", "H", "Cl", prm.psi_Ca_H_Cl_HMW84) +HeMorse93.update_cca("Ca", "H", "SO4", prm.psi_Ca_H_SO4_HMW84) +HeMorse93.update_cca("Ca", "H", "HSO4", prm.psi_Ca_H_HSO4_HMW84) +HeMorse93.update_cca("Ca", "H", "OH", prm.psi_Ca_H_OH_HMW84) +HeMorse93.update_cca("Ca", "H", "HCO3", prm.psi_Ca_H_HCO3_HMW84) +HeMorse93.update_cca("Ca", "H", "CO3", prm.psi_Ca_H_CO3_HMW84) +HeMorse93.update_cc("Mg", "MgOH", prm.theta_Mg_MgOH_HMW84) +HeMorse93.update_cca("Mg", "MgOH", "Cl", prm.psi_Mg_MgOH_Cl_HMW84) +HeMorse93.update_cca("Mg", "MgOH", "SO4", prm.psi_Mg_MgOH_SO4_HMW84) +HeMorse93.update_cca("Mg", "MgOH", "HSO4", prm.psi_Mg_MgOH_HSO4_HMW84) +HeMorse93.update_cca("Mg", "MgOH", "OH", prm.psi_Mg_MgOH_OH_HMW84) +HeMorse93.update_cca("Mg", "MgOH", "HCO3", prm.psi_Mg_MgOH_HCO3_HMW84) +HeMorse93.update_cca("Mg", "MgOH", "CO3", prm.psi_Mg_MgOH_CO3_HMW84) +HeMorse93.update_cc("H", "Mg", prm.theta_H_Mg_HMW84) +HeMorse93.update_cca("H", "Mg", "Cl", prm.psi_H_Mg_Cl_HMW84) +HeMorse93.update_cca("H", "Mg", "SO4", prm.psi_H_Mg_SO4_HMW84) +HeMorse93.update_cca("H", "Mg", "HSO4", prm.psi_H_Mg_HSO4_HMW84) +HeMorse93.update_cca("H", "Mg", "OH", prm.psi_H_Mg_OH_HMW84) +HeMorse93.update_cca("H", "Mg", "HCO3", prm.psi_H_Mg_HCO3_HMW84) +HeMorse93.update_cca("H", "Mg", "CO3", prm.psi_H_Mg_CO3_HMW84) +HeMorse93.update_cc("H", "MgOH", prm.theta_H_MgOH_HMW84) +HeMorse93.update_cca("H", "MgOH", "Cl", prm.psi_H_MgOH_Cl_HMW84) +HeMorse93.update_cca("H", "MgOH", "SO4", prm.psi_H_MgOH_SO4_HMW84) +HeMorse93.update_cca("H", "MgOH", "HSO4", prm.psi_H_MgOH_HSO4_HMW84) +HeMorse93.update_cca("H", "MgOH", "OH", prm.psi_H_MgOH_OH_HMW84) +HeMorse93.update_cca("H", "MgOH", "HCO3", prm.psi_H_MgOH_HCO3_HMW84) +HeMorse93.update_cca("H", "MgOH", "CO3", prm.psi_H_MgOH_CO3_HMW84) +# lambda +HeMorse93.update_nc("CO2", "H", prm.lambd_CO2_H_HM93) +HeMorse93.update_nc("CO2", "Na", prm.lambd_CO2_Na_HM93) +HeMorse93.update_nc("CO2", "K", prm.lambd_CO2_K_HM93) +HeMorse93.update_nc("CO2", "Ca", prm.lambd_CO2_Ca_HM93) +HeMorse93.update_nc("CO2", "Mg", prm.lambd_CO2_Mg_HM93) +HeMorse93.update_na("CO2", "Cl", prm.lambd_CO2_Cl_HM93) +HeMorse93.update_na("CO2", "SO4", prm.lambd_CO2_SO4_HM93) +HeMorse93.update_na("CO2", "HSO4", prm.lambd_CO2_HSO4_HMW84) +# zeta +HeMorse93.update_nca("CO2", "H", "Cl", prm.zeta_CO2_H_Cl_HM93) +HeMorse93.update_nca("CO2", "Na", "Cl", prm.zeta_CO2_Na_Cl_HM93) +HeMorse93.update_nca("CO2", "K", "Cl", prm.zeta_CO2_K_Cl_HM93) +HeMorse93.update_nca("CO2", "Mg", "Cl", prm.zeta_CO2_Mg_Cl_HM93) +HeMorse93.update_nca("CO2", "Ca", "Cl", prm.zeta_CO2_Ca_Cl_HM93) +HeMorse93.update_nca("CO2", "H", "SO4", prm.zeta_CO2_H_SO4_HM93) +HeMorse93.update_nca("CO2", "Na", "SO4", prm.zeta_CO2_Na_SO4_HM93) +HeMorse93.update_nca("CO2", "K", "SO4", prm.zeta_CO2_K_SO4_HM93) +HeMorse93.update_nca("CO2", "Mg", "SO4", prm.zeta_CO2_Mg_SO4_HM93) +# Equilibria +HeMorse93.update_equilibrium("H2O", k.H2O_MF) +HeMorse93.update_equilibrium("H2CO3", k.H2CO3_PB82) +HeMorse93.update_equilibrium("HCO3", k.HCO3_PB82) +HeMorse93.update_equilibrium("MgCO3", k.MgCO3_PPFD88) +HeMorse93.update_equilibrium("CaCO3", k.CaCO3_PPFD88) diff --git a/pytzer/libraries/Humphreys22.py b/pytzer/libraries/Humphreys22.py new file mode 100644 index 00000000..fda35184 --- /dev/null +++ b/pytzer/libraries/Humphreys22.py @@ -0,0 +1,89 @@ +# Pytzer: Pitzer model for chemical activities in aqueous solutions. +# Copyright (C) 2019--2023 Matthew P. Humphreys (GNU GPLv3) +from . import ParameterLibrary +from .. import debyehueckel, dissociation as k, parameters as prm, unsymmetrical + +# Following Supp. Info. part 6 +Humphreys22 = ParameterLibrary(name="Humphreys22") +Humphreys22.assign_func_J(unsymmetrical.P75_eq47) + +# Table S6 (Aphi and equilibria) +Humphreys22.update_Aphi(debyehueckel.Aosm_M88) +Humphreys22.update_equilibrium("H2O", k.H2O_MF) +Humphreys22.update_equilibrium("HSO4", k.HSO4_CRP94) +Humphreys22.update_equilibrium("MgOH", k.MgOH_CW91_ln) + +# Tables S7-S11 (beta and C coefficients) +Humphreys22.update_ca("Ca", "Cl", prm.bC_Ca_Cl_GM89) +Humphreys22.update_ca("Ca", "HSO4", prm.bC_Ca_HSO4_WM13) +Humphreys22.update_ca("Ca", "OH", prm.bC_Ca_OH_HMW84) +Humphreys22.update_ca("Ca", "SO4", prm.bC_Ca_SO4_WM13) +Humphreys22.update_ca("H", "Cl", prm.bC_H_Cl_CMR93) +Humphreys22.update_ca("H", "HSO4", prm.bC_H_HSO4_CRP94) +Humphreys22.update_ca("H", "SO4", prm.bC_H_SO4_CRP94) +Humphreys22.update_ca("K", "Cl", prm.bC_K_Cl_GM89) +Humphreys22.update_ca("K", "HSO4", prm.bC_K_HSO4_WM13) +Humphreys22.update_ca("K", "OH", prm.bC_K_OH_HMW84) +Humphreys22.update_ca("K", "SO4", prm.bC_K_SO4_HM86) +Humphreys22.update_ca("Mg", "Cl", prm.bC_Mg_Cl_dLP83) +Humphreys22.update_ca("Mg", "HSO4", prm.bC_Mg_HSO4_RC99) +Humphreys22.update_ca("Mg", "SO4", prm.bC_Mg_SO4_PP86ii) +Humphreys22.update_ca("MgOH", "Cl", prm.bC_MgOH_Cl_HMW84) +Humphreys22.update_ca("Na", "Cl", prm.bC_Na_Cl_M88) +Humphreys22.update_ca("Na", "HSO4", prm.bC_Na_HSO4_HPR93) +Humphreys22.update_ca("Na", "OH", prm.bC_Na_OH_HWT22) +Humphreys22.update_ca("Na", "SO4", prm.bC_Na_SO4_HM86) + +# Table S12 (cc theta and psi coefficients) +Humphreys22.update_cc("Ca", "H", prm.theta_Ca_H_RGO81) +Humphreys22.update_cca("Ca", "H", "Cl", prm.psi_Ca_H_Cl_HMW84) +Humphreys22.update_cc("Ca", "K", prm.theta_Ca_K_HMW84) +Humphreys22.update_cca("Ca", "K", "Cl", prm.psi_Ca_K_Cl_HMW84) +Humphreys22.update_cc("Ca", "Mg", prm.theta_Ca_Mg_HMW84) +Humphreys22.update_cca("Ca", "Mg", "Cl", prm.psi_Ca_Mg_Cl_HMW84) +Humphreys22.update_cca("Ca", "Mg", "SO4", prm.psi_Ca_Mg_SO4_HMW84) +Humphreys22.update_cc("Ca", "Na", prm.theta_Ca_Na_HMW84) +Humphreys22.update_cca("Ca", "Na", "Cl", prm.psi_Ca_Na_Cl_HMW84) +Humphreys22.update_cca("Ca", "Na", "SO4", prm.psi_Ca_Na_SO4_HMW84) +Humphreys22.update_cc("H", "K", prm.theta_H_K_HWT22) +Humphreys22.update_cca("H", "K", "Cl", prm.psi_H_K_Cl_HMW84) +Humphreys22.update_cca("H", "K", "HSO4", prm.psi_H_K_HSO4_HMW84) +Humphreys22.update_cca("H", "K", "SO4", prm.psi_H_K_SO4_HMW84) +Humphreys22.update_cc("H", "Mg", prm.theta_H_Mg_RGB80) +Humphreys22.update_cca("H", "Mg", "Cl", prm.psi_H_Mg_Cl_HMW84) +Humphreys22.update_cca("H", "Mg", "HSO4", prm.psi_H_Mg_HSO4_RC99) +Humphreys22.update_cca("H", "Mg", "SO4", prm.psi_H_Mg_SO4_RC99) +Humphreys22.update_cc("H", "Na", prm.theta_H_Na_HWT22) +Humphreys22.update_cca("H", "Na", "Cl", prm.psi_H_Na_Cl_HMW84) +Humphreys22.update_cca("H", "Na", "HSO4", prm.psi_H_Na_HSO4_HMW84) +Humphreys22.update_cc("K", "Mg", prm.theta_K_Mg_HMW84) +Humphreys22.update_cca("K", "Mg", "Cl", prm.psi_K_Mg_Cl_HMW84) +Humphreys22.update_cca("K", "Mg", "SO4", prm.psi_K_Mg_SO4_HMW84) +Humphreys22.update_cc("K", "Na", prm.theta_K_Na_HMW84) +Humphreys22.update_cca("K", "Na", "Cl", prm.psi_K_Na_Cl_HMW84) +Humphreys22.update_cca("K", "Na", "SO4", prm.psi_K_Na_SO4_HMW84) +Humphreys22.update_cc("Mg", "MgOH", prm.theta_Mg_MgOH_HMW84) +Humphreys22.update_cca("Mg", "MgOH", "Cl", prm.psi_Mg_MgOH_Cl_HMW84) +Humphreys22.update_cc("Mg", "Na", prm.theta_Mg_Na_HMW84) +Humphreys22.update_cca("Mg", "Na", "Cl", prm.psi_Mg_Na_Cl_HMW84) +Humphreys22.update_cca("Mg", "Na", "SO4", prm.psi_Mg_Na_SO4_HMW84) + +# Table S13 (aa theta and psi coefficients) +Humphreys22.update_aa("Cl", "HSO4", prm.theta_Cl_HSO4_HMW84) +Humphreys22.update_caa("Na", "Cl", "HSO4", prm.psi_Na_Cl_HSO4_HMW84) +Humphreys22.update_caa("H", "Cl", "HSO4", prm.psi_H_Cl_HSO4_HMW84) +Humphreys22.update_aa("Cl", "OH", prm.theta_Cl_OH_HMW84) +Humphreys22.update_caa("Ca", "Cl", "OH", prm.psi_Ca_Cl_OH_HMW84) +Humphreys22.update_caa("K", "Cl", "OH", prm.psi_K_Cl_OH_HMW84) +Humphreys22.update_caa("Na", "Cl", "OH", prm.psi_Na_Cl_OH_HMW84) +Humphreys22.update_aa("Cl", "SO4", prm.theta_Cl_SO4_HMW84) +Humphreys22.update_caa("Ca", "Cl", "SO4", prm.psi_Ca_Cl_SO4_HMW84) +Humphreys22.update_caa("Mg", "Cl", "SO4", prm.psi_Mg_Cl_SO4_HMW84) +Humphreys22.update_caa("Na", "Cl", "SO4", prm.psi_Na_Cl_SO4_HMW84) +Humphreys22.update_aa("HSO4", "SO4", prm.theta_HSO4_SO4_WM13) +Humphreys22.update_caa("K", "HSO4", "SO4", prm.psi_K_HSO4_SO4_HMW84) +Humphreys22.update_caa("Mg", "HSO4", "SO4", prm.psi_Mg_HSO4_SO4_RC99) +Humphreys22.update_caa("Na", "HSO4", "SO4", prm.psi_Na_HSO4_SO4_HMW84) +Humphreys22.update_aa("OH", "SO4", prm.theta_OH_SO4_HMW84) +Humphreys22.update_caa("K", "OH", "SO4", prm.psi_K_OH_SO4_HMW84) +Humphreys22.update_caa("Na", "OH", "SO4", prm.psi_Na_OH_SO4_HMW84) diff --git a/pytzer/libraries/MarChemSpec.py b/pytzer/libraries/MarChemSpec.py index 768eeef3..628e11e2 100644 --- a/pytzer/libraries/MarChemSpec.py +++ b/pytzer/libraries/MarChemSpec.py @@ -1,5 +1,5 @@ # Pytzer: Pitzer model for chemical activities in aqueous solutions. -# Copyright (C) 2019--2021 Matthew P. Humphreys (GNU GPLv3) +# Copyright (C) 2019--2023 Matthew P. Humphreys (GNU GPLv3) from . import ParameterLibrary from .. import debyehueckel, dissociation as k, parameters as prm, unsymmetrical @@ -129,4 +129,4 @@ MarChemSpec.update_equilibrium("H2O", k.H2O_MF) MarChemSpec.update_equilibrium("HSO4", k.HSO4_CRP94) MarChemSpec.update_equilibrium("MgOH", k.MgOH_CW91) -MarChemSpec.update_equilibrium("trisH", k.trisH_BH64) +MarChemSpec.update_equilibrium("trisH", k.trisH_BH61) diff --git a/pytzer/libraries/MarChemSpec25.py b/pytzer/libraries/MarChemSpec25.py index 0c87c538..b71c83fb 100644 --- a/pytzer/libraries/MarChemSpec25.py +++ b/pytzer/libraries/MarChemSpec25.py @@ -1,5 +1,5 @@ # Pytzer: Pitzer model for chemical activities in aqueous solutions. -# Copyright (C) 2019--2021 Matthew P. Humphreys (GNU GPLv3) +# Copyright (C) 2019--2023 Matthew P. Humphreys (GNU GPLv3) from . import ParameterLibrary from .. import debyehueckel, dissociation as k, parameters as prm, unsymmetrical diff --git a/pytzer/libraries/Millero98.py b/pytzer/libraries/Millero98.py index 39de73f3..3481a662 100644 --- a/pytzer/libraries/Millero98.py +++ b/pytzer/libraries/Millero98.py @@ -1,5 +1,5 @@ # Pytzer: Pitzer model for chemical activities in aqueous solutions. -# Copyright (C) 2019--2021 Matthew P. Humphreys (GNU GPLv3) +# Copyright (C) 2019--2023 Matthew P. Humphreys (GNU GPLv3) from . import ParameterLibrary from .. import debyehueckel, dissociation as k, parameters as prm, unsymmetrical diff --git a/pytzer/libraries/MilleroThurmond83.py b/pytzer/libraries/MilleroThurmond83.py new file mode 100644 index 00000000..3460aee4 --- /dev/null +++ b/pytzer/libraries/MilleroThurmond83.py @@ -0,0 +1,25 @@ +# Pytzer: Pitzer model for chemical activities in aqueous solutions. +# Copyright (C) 2019--2023 Matthew P. Humphreys (GNU GPLv3) +from . import ParameterLibrary +from .. import debyehueckel, dissociation as k, parameters as prm, unsymmetrical + +MilleroThurmond83 = ParameterLibrary(name="MilleroThurmond83") +MilleroThurmond83.update_Aphi(debyehueckel.Aosm_M88) +MilleroThurmond83.assign_func_J(unsymmetrical.Harvie) +# Table III, part 1 +MilleroThurmond83.update_ca("H", "Cl", prm.bC_H_Cl_PM73) +MilleroThurmond83.update_ca("Na", "Cl", prm.bC_Na_Cl_PM73) +MilleroThurmond83.update_ca("Mg", "Cl", prm.bC_Mg_Cl_PM73) +MilleroThurmond83.update_ca("Na", "HCO3", prm.bC_Na_HCO3_PP82) +MilleroThurmond83.update_ca("Na", "CO3", prm.bC_Na_CO3_PP82) +# Table III, part 2 +MilleroThurmond83.update_cc("H", "Na", prm.theta_H_Na_PK74) +MilleroThurmond83.update_cca("H", "Na", "Cl", prm.psi_H_Na_Cl_RGB80) +MilleroThurmond83.update_cc("H", "Mg", prm.theta_H_Mg_RGB80) +MilleroThurmond83.update_cca("H", "Mg", "Cl", prm.psi_H_Na_Cl_PK74) +MilleroThurmond83.update_aa("Cl", "HCO3", prm.theta_HCO3_Cl_PP82) +MilleroThurmond83.update_caa("Na", "Cl", "HCO3", prm.psi_Na_Cl_HCO3_PP82) +MilleroThurmond83.update_aa("Cl", "CO3", prm.theta_CO3_Cl_PP82) +MilleroThurmond83.update_caa("Na", "Cl", "CO3", prm.psi_Na_CO3_Cl_TM82) +MilleroThurmond83.update_cc("Na", "Mg", prm.theta_Mg_Na_HMW84) +MilleroThurmond83.update_cca("Na", "Mg", "Cl", prm.psi_Mg_Na_Cl_HMW84) diff --git a/pytzer/libraries/Moller88.py b/pytzer/libraries/Moller88.py index e47e6e92..79dc7ff2 100644 --- a/pytzer/libraries/Moller88.py +++ b/pytzer/libraries/Moller88.py @@ -1,5 +1,5 @@ # Pytzer: Pitzer model for chemical activities in aqueous solutions. -# Copyright (C) 2019--2021 Matthew P. Humphreys (GNU GPLv3) +# Copyright (C) 2019--2023 Matthew P. Humphreys (GNU GPLv3) """Møller (1988). System: Na-Ca-Cl-SO4. *Geochimica et Cosmochimica Acta* 52, 821--837. doi:10.1016/0016-7037(88)90354-7 diff --git a/pytzer/libraries/MyMarChemSpecCO2.py b/pytzer/libraries/MyMarChemSpecCO2.py new file mode 100644 index 00000000..b9272951 --- /dev/null +++ b/pytzer/libraries/MyMarChemSpecCO2.py @@ -0,0 +1,261 @@ +# Pytzer: Pitzer model for chemical activities in aqueous solutions. +# Copyright (C) 2019--2023 Matthew P. Humphreys (GNU GPLv3) +"""Waters & Millero (2013). +*Marine Chemistry* 149, 8--22. +doi:10.1016/j.marchem.2012.11.003 +according to Clegg et al. (2022) +with CO2-system terms added +""" +from . import ParameterLibrary +from .. import debyehueckel, dissociation as k, parameters as prm, unsymmetrical + +MyMarChemSpecCO2 = ParameterLibrary(name="MyMarChemSpecCO2") +MyMarChemSpecCO2.update_Aphi(debyehueckel.Aosm_M88) +MyMarChemSpecCO2.assign_func_J(unsymmetrical.Harvie) +# Table A1: Na salts +MyMarChemSpecCO2.update_ca("Na", "Cl", prm.bC_Na_Cl_M88) +# MyMarChemSpecCO2.update_ca("Na", "SO4", prm.bC_Na_SO4_HM86) +# MyMarChemSpecCO2.update_ca("Na", "HSO4", prm.bC_Na_HSO4_HPR93) +MyMarChemSpecCO2.update_ca("Na", "OH", prm.bC_Na_OH_PP87i) +# # Table A2: Mg salts +# MyMarChemSpecCO2.update_ca("Mg", "Cl", prm.bC_Mg_Cl_dLP83) +# MyMarChemSpecCO2.update_ca("Mg", "SO4", prm.bC_Mg_SO4_PP86ii) +# MyMarChemSpecCO2.update_ca("Mg", "HSO4", prm.bC_Mg_HSO4_RC99) +# # Table A3: Ca salts +# MyMarChemSpecCO2.update_ca("Ca", "Cl", prm.bC_Ca_Cl_GM89) +# MyMarChemSpecCO2.update_ca("Ca", "SO4", prm.bC_Ca_SO4_WM13) +# MyMarChemSpecCO2.update_ca("Ca", "HSO4", prm.bC_Ca_HSO4_WM13) +# MyMarChemSpecCO2.update_ca("Ca", "OH", prm.bC_Ca_OH_HMW84) +# # Table A4: K salts +# MyMarChemSpecCO2.update_ca("K", "Cl", prm.bC_K_Cl_GM89) +# MyMarChemSpecCO2.update_ca("K", "SO4", prm.bC_K_SO4_HM86) +# MyMarChemSpecCO2.update_ca("K", "HSO4", prm.bC_K_HSO4_WM13) +# MyMarChemSpecCO2.update_ca("K", "OH", prm.bC_K_OH_HMW84) +# Table A5: H+ interactions +MyMarChemSpecCO2.update_ca("H", "Cl", prm.bC_H_Cl_CMR93) +# MyMarChemSpecCO2.update_ca("H", "SO4", prm.bC_H_SO4_CRP94) +# MyMarChemSpecCO2.update_ca("H", "HSO4", prm.bC_H_HSO4_CRP94) +# # Table A6: MgOH+ interactions +# MyMarChemSpecCO2.update_ca("MgOH", "Cl", prm.bC_MgOH_Cl_HMW84) +# Table A7: cation-cation interactions +MyMarChemSpecCO2.update_cc("H", "Na", prm.theta_H_Na_HCW22) # different from WM13 +# MyMarChemSpecCO2.update_cc("H", "Mg", prm.theta_H_Mg_RGB80) +# MyMarChemSpecCO2.update_cc("Ca", "H", prm.theta_Ca_H_RGO81) +# MyMarChemSpecCO2.update_cc("H", "K", prm.theta_H_K_CMR93) +# MyMarChemSpecCO2.update_cc("Mg", "Na", prm.theta_Mg_Na_HMW84) +# MyMarChemSpecCO2.update_cc("Ca", "Na", prm.theta_Ca_Na_HMW84) +# MyMarChemSpecCO2.update_cc("K", "Na", prm.theta_K_Na_HMW84) +# MyMarChemSpecCO2.update_cc("Ca", "Mg", prm.theta_Ca_Mg_HMW84) +# MyMarChemSpecCO2.update_cc("K", "Mg", prm.theta_K_Mg_HMW84) +# MyMarChemSpecCO2.update_cc("Ca", "K", prm.theta_Ca_K_HMW84) +# # Table A7: anion-anion interactions +# MyMarChemSpecCO2.update_aa("Cl", "SO4", prm.theta_Cl_SO4_HMW84) +# MyMarChemSpecCO2.update_aa("Cl", "HSO4", prm.theta_Cl_HSO4_HMW84) +MyMarChemSpecCO2.update_aa("Cl", "OH", prm.theta_Cl_OH_HMW84) +# MyMarChemSpecCO2.update_aa("HSO4", "SO4", prm.theta_HSO4_SO4_WM13) +# MyMarChemSpecCO2.update_aa("OH", "SO4", prm.theta_OH_SO4_HMW84) +# Table A8: c-a-a' triplets +# MyMarChemSpecCO2.update_caa("H", "Cl", "SO4", prm.psi_H_Cl_SO4_WM13) +# MyMarChemSpecCO2.update_caa("Na", "Cl", "SO4", prm.psi_Na_Cl_SO4_HMW84) +# MyMarChemSpecCO2.update_caa("Mg", "Cl", "SO4", prm.psi_Mg_Cl_SO4_HMW84) +# MyMarChemSpecCO2.update_caa("Ca", "Cl", "SO4", prm.psi_Ca_Cl_SO4_HMW84) +# MyMarChemSpecCO2.update_caa("K", "Cl", "SO4", prm.psi_K_Cl_SO4_HMW84) +# MyMarChemSpecCO2.update_caa("H", "Cl", "HSO4", prm.psi_H_Cl_HSO4_HMW84) +# MyMarChemSpecCO2.update_caa("Na", "Cl", "HSO4", prm.psi_Na_Cl_HSO4_HMW84) +# MyMarChemSpecCO2.update_caa("Mg", "Cl", "HSO4", prm.psi_Mg_Cl_HSO4_HMW84) +# MyMarChemSpecCO2.update_caa("Ca", "Cl", "HSO4", prm.psi_Ca_Cl_HSO4_HMW84) +# MyMarChemSpecCO2.update_caa("K", "Cl", "HSO4", prm.psi_K_Cl_HSO4_HMW84) +MyMarChemSpecCO2.update_caa("H", "Cl", "OH", prm.psi_H_Cl_OH_WM13) +MyMarChemSpecCO2.update_caa("Na", "Cl", "OH", prm.psi_Na_Cl_OH_HMW84) +# MyMarChemSpecCO2.update_caa("Mg", "Cl", "OH", prm.psi_Mg_Cl_OH_WM13) +# MyMarChemSpecCO2.update_caa("Ca", "Cl", "OH", prm.psi_Ca_Cl_OH_HMW84) +# MyMarChemSpecCO2.update_caa("K", "Cl", "OH", prm.psi_K_Cl_OH_HMW84) +# MyMarChemSpecCO2.update_caa("H", "HSO4", "SO4", prm.psi_H_HSO4_SO4_HMW84) +# MyMarChemSpecCO2.update_caa("Na", "HSO4", "SO4", prm.psi_Na_HSO4_SO4_HMW84) +# MyMarChemSpecCO2.update_caa("Mg", "HSO4", "SO4", prm.psi_Mg_HSO4_SO4_RC99) +# MyMarChemSpecCO2.update_caa("Ca", "HSO4", "SO4", prm.psi_Ca_HSO4_SO4_WM13) +# MyMarChemSpecCO2.update_caa("K", "HSO4", "SO4", prm.psi_K_HSO4_SO4_HMW84) +# MyMarChemSpecCO2.update_caa("H", "OH", "SO4", prm.psi_H_OH_SO4_WM13) +# MyMarChemSpecCO2.update_caa("Na", "OH", "SO4", prm.psi_Na_OH_SO4_HMW84) +# MyMarChemSpecCO2.update_caa("Mg", "OH", "SO4", prm.psi_Mg_OH_SO4_WM13) +# MyMarChemSpecCO2.update_caa("Ca", "OH", "SO4", prm.psi_Ca_OH_SO4_WM13) +# MyMarChemSpecCO2.update_caa("K", "OH", "SO4", prm.psi_K_OH_SO4_HMW84) +# Table A9: c-c'-a triplets +MyMarChemSpecCO2.update_cca("H", "Na", "Cl", prm.psi_H_Na_Cl_HMW84) +# MyMarChemSpecCO2.update_cca("H", "Na", "SO4", prm.psi_H_Na_SO4_WM13) +# MyMarChemSpecCO2.update_cca("H", "Na", "HSO4", prm.psi_H_Na_HSO4_HMW84) +# MyMarChemSpecCO2.update_cca("H", "Mg", "Cl", prm.psi_H_Mg_Cl_HMW84) +# MyMarChemSpecCO2.update_cca("H", "Mg", "SO4", prm.psi_H_Mg_SO4_RC99) +# MyMarChemSpecCO2.update_cca("H", "Mg", "HSO4", prm.psi_H_Mg_HSO4_RC99) +# MyMarChemSpecCO2.update_cca("Ca", "H", "Cl", prm.psi_Ca_H_Cl_HMW84) +# MyMarChemSpecCO2.update_cca("Ca", "H", "SO4", prm.psi_Ca_H_SO4_WM13) +# MyMarChemSpecCO2.update_cca("Ca", "H", "HSO4", prm.psi_Ca_H_HSO4_WM13) +# MyMarChemSpecCO2.update_cca("H", "K", "Cl", prm.psi_H_K_Cl_HMW84) +# MyMarChemSpecCO2.update_cca("H", "K", "SO4", prm.psi_H_K_SO4_HMW84) +# MyMarChemSpecCO2.update_cca("H", "K", "HSO4", prm.psi_H_K_HSO4_HMW84) +# MyMarChemSpecCO2.update_cca("Mg", "Na", "Cl", prm.psi_Mg_Na_Cl_HMW84) +# MyMarChemSpecCO2.update_cca("Mg", "Na", "SO4", prm.psi_Mg_Na_SO4_HMW84) +# MyMarChemSpecCO2.update_cca("Mg", "Na", "HSO4", prm.psi_Mg_Na_HSO4_WM13) +# MyMarChemSpecCO2.update_cca("Ca", "Na", "Cl", prm.psi_Ca_Na_Cl_HMW84) +# MyMarChemSpecCO2.update_cca("Ca", "Na", "SO4", prm.psi_Ca_Na_SO4_HMW84) +# MyMarChemSpecCO2.update_cca("Ca", "Na", "HSO4", prm.psi_Ca_Na_HSO4_WM13) +# MyMarChemSpecCO2.update_cca("K", "Na", "Cl", prm.psi_K_Na_Cl_HMW84) +# MyMarChemSpecCO2.update_cca("K", "Na", "SO4", prm.psi_K_Na_SO4_HMW84) +# MyMarChemSpecCO2.update_cca("K", "Na", "HSO4", prm.psi_K_Na_HSO4_WM13) +# MyMarChemSpecCO2.update_cca("Ca", "Mg", "Cl", prm.psi_Ca_Mg_Cl_HMW84) +# MyMarChemSpecCO2.update_cca("Ca", "Mg", "SO4", prm.psi_Ca_Mg_SO4_HMW84) +# MyMarChemSpecCO2.update_cca("Ca", "Mg", "HSO4", prm.psi_Ca_Mg_HSO4_WM13) +# MyMarChemSpecCO2.update_cca("K", "Mg", "Cl", prm.psi_K_Mg_Cl_HMW84) +# MyMarChemSpecCO2.update_cca("K", "Mg", "SO4", prm.psi_K_Mg_SO4_HMW84) +# MyMarChemSpecCO2.update_cca("K", "Mg", "HSO4", prm.psi_K_Mg_HSO4_WM13) +# MyMarChemSpecCO2.update_cca("Ca", "K", "Cl", prm.psi_Ca_K_Cl_HMW84) +# MyMarChemSpecCO2.update_cca("Ca", "K", "SO4", prm.psi_Ca_K_SO4_WM13) +# MyMarChemSpecCO2.update_cca("Ca", "K", "HSO4", prm.psi_Ca_K_HSO4_WM13) +# MyMarChemSpecCO2.update_cca("Mg", "MgOH", "Cl", prm.psi_Mg_MgOH_Cl_HMW84) # not in WM13 +# Add equilibria +# MyMarChemSpecCO2.update_equilibrium("HSO4", k.HSO4_CRP94) +# MyMarChemSpecCO2.update_equilibrium("MgOH", k.MgOH_CW91_ln) +MyMarChemSpecCO2.update_equilibrium("H2O", k.H2O_M79) +# # Extras from Clegg22 (all before this point is from Humphreys22) +# MyMarChemSpecCO2.update_equilibrium("trisH", k.trisH_BH61) +# MyMarChemSpecCO2.update_ca("trisH", "Cl", prm.bC_trisH_Cl_CHW22) +# MyMarChemSpecCO2.update_ca("trisH", "SO4", prm.bC_trisH_SO4_CHW22) +# MyMarChemSpecCO2.update_nc("tris", "Ca", prm.lambd_tris_Ca_CHW22) +# MyMarChemSpecCO2.update_nc("tris", "K", prm.lambd_tris_K_CHW22) +# MyMarChemSpecCO2.update_nc("tris", "Mg", prm.lambd_tris_Mg_CHW22) +# MyMarChemSpecCO2.update_nc("tris", "Na", prm.lambd_tris_Na_CHW22) +# MyMarChemSpecCO2.update_nc("tris", "trisH", prm.lambd_tris_trisH_LTA21) +# MyMarChemSpecCO2.update_na("tris", "SO4", prm.lambd_tris_SO4_LTA21) +# MyMarChemSpecCO2.update_nn("tris", "tris", prm.lambd_tris_tris_LTA21) +# MyMarChemSpecCO2.update_nnn("tris", prm.mu_tris_tris_tris_LTA21) + +MyMarChemSpecCO2.update_equilibrium("H2CO3", k.H2CO3_PB82) +MyMarChemSpecCO2.update_equilibrium("HCO3", k.HCO3_PB82) +# still needs CaCO3, MgCO3 formation! + +# Added CO2 system from HM93 +MyMarChemSpecCO2.update_ca("Na", "HCO3", prm.bC_Na_HCO3_HM93) +MyMarChemSpecCO2.update_ca("Na", "CO3", prm.bC_Na_CO3_HM93) +# MyMarChemSpecCO2.update_ca("K", "HCO3", prm.bC_K_HCO3_HM93) +# MyMarChemSpecCO2.update_ca("K", "CO3", prm.bC_K_CO3_HM93) +# MyMarChemSpecCO2.update_ca("Ca", "HCO3", prm.bC_Ca_HCO3_HM93) +# MyMarChemSpecCO2.update_ca("Ca", "CO3", prm.bC_Ca_CO3_HM93) +# MyMarChemSpecCO2.update_ca("Mg", "HCO3", prm.bC_Mg_HCO3_HM93) +# MyMarChemSpecCO2.update_ca("Mg", "CO3", prm.bC_Mg_CO3_HM93) +# MyMarChemSpecCO2.update_ca("MgOH", "HCO3", prm.bC_MgOH_HCO3_HMW84) +# MyMarChemSpecCO2.update_ca("MgOH", "CO3", prm.bC_MgOH_CO3_HMW84) +MyMarChemSpecCO2.update_ca("H", "HCO3", prm.bC_H_HCO3_HMW84) +MyMarChemSpecCO2.update_ca("H", "CO3", prm.bC_H_CO3_HMW84) +# thetas and psis +MyMarChemSpecCO2.update_aa("Cl", "HCO3", prm.theta_Cl_HCO3_HMW84) +MyMarChemSpecCO2.update_caa("Na", "Cl", "HCO3", prm.psi_Na_Cl_HCO3_HMW84) +# MyMarChemSpecCO2.update_caa("K", "Cl", "HCO3", prm.psi_K_Cl_HCO3_HMW84) +# MyMarChemSpecCO2.update_caa("Ca", "Cl", "HCO3", prm.psi_Ca_Cl_HCO3_HMW84) +# MyMarChemSpecCO2.update_caa("Mg", "Cl", "HCO3", prm.psi_Mg_Cl_HCO3_HMW84) +# MyMarChemSpecCO2.update_caa("MgOH", "Cl", "HCO3", prm.psi_MgOH_Cl_HCO3_HMW84) +MyMarChemSpecCO2.update_caa("H", "Cl", "HCO3", prm.psi_H_Cl_HCO3_HMW84) +MyMarChemSpecCO2.update_aa("CO3", "Cl", prm.theta_CO3_Cl_HMW84) +MyMarChemSpecCO2.update_caa("Na", "CO3", "Cl", prm.psi_Na_CO3_Cl_HMW84) +# MyMarChemSpecCO2.update_caa("K", "CO3", "Cl", prm.psi_K_CO3_Cl_HMW84) +# MyMarChemSpecCO2.update_caa("Ca", "CO3", "Cl", prm.psi_Ca_CO3_Cl_HMW84) +# MyMarChemSpecCO2.update_caa("Mg", "CO3", "Cl", prm.psi_Mg_CO3_Cl_HMW84) +# MyMarChemSpecCO2.update_caa("MgOH", "CO3", "Cl", prm.psi_MgOH_CO3_Cl_HMW84) +MyMarChemSpecCO2.update_caa("H", "CO3", "Cl", prm.psi_H_CO3_Cl_HMW84) +# MyMarChemSpecCO2.update_aa("HCO3", "SO4", prm.theta_HCO3_SO4_HMW84) +# MyMarChemSpecCO2.update_caa("Na", "HCO3", "SO4", prm.psi_Na_HCO3_SO4_HMW84) +# MyMarChemSpecCO2.update_caa("K", "HCO3", "SO4", prm.psi_K_HCO3_SO4_HMW84) +# MyMarChemSpecCO2.update_caa("Ca", "HCO3", "SO4", prm.psi_Ca_HCO3_SO4_HMW84) +# MyMarChemSpecCO2.update_caa("Mg", "HCO3", "SO4", prm.psi_Mg_HCO3_SO4_HMW84) +# MyMarChemSpecCO2.update_caa("MgOH", "HCO3", "SO4", prm.psi_MgOH_HCO3_SO4_HMW84) +# MyMarChemSpecCO2.update_caa("H", "HCO3", "SO4", prm.psi_H_HCO3_SO4_HMW84) +# MyMarChemSpecCO2.update_aa("CO3", "SO4", prm.theta_CO3_SO4_HMW84) +# MyMarChemSpecCO2.update_caa("Na", "CO3", "SO4", prm.psi_Na_CO3_SO4_HMW84) +# MyMarChemSpecCO2.update_caa("K", "CO3", "SO4", prm.psi_K_CO3_SO4_HMW84) +# MyMarChemSpecCO2.update_caa("Ca", "CO3", "SO4", prm.psi_Ca_CO3_SO4_HMW84) +# MyMarChemSpecCO2.update_caa("Mg", "CO3", "SO4", prm.psi_Mg_CO3_SO4_HMW84) +# MyMarChemSpecCO2.update_caa("MgOH", "CO3", "SO4", prm.psi_MgOH_CO3_SO4_HMW84) +# MyMarChemSpecCO2.update_caa("H", "CO3", "SO4", prm.psi_H_CO3_SO4_HMW84) +# MyMarChemSpecCO2.update_aa("HCO3", "HSO4", prm.theta_HCO3_HSO4_HMW84) +# MyMarChemSpecCO2.update_caa("Na", "HCO3", "HSO4", prm.psi_Na_HCO3_HSO4_HMW84) +# MyMarChemSpecCO2.update_caa("K", "HCO3", "HSO4", prm.psi_K_HCO3_HSO4_HMW84) +# MyMarChemSpecCO2.update_caa("Ca", "HCO3", "HSO4", prm.psi_Ca_HCO3_HSO4_HMW84) +# MyMarChemSpecCO2.update_caa("Mg", "HCO3", "HSO4", prm.psi_Mg_HCO3_HSO4_HMW84) +# MyMarChemSpecCO2.update_caa("MgOH", "HCO3", "HSO4", prm.psi_MgOH_HCO3_HSO4_HMW84) +# MyMarChemSpecCO2.update_caa("H", "HCO3", "HSO4", prm.psi_H_HCO3_HSO4_HMW84) +# MyMarChemSpecCO2.update_aa("CO3", "HSO4", prm.theta_CO3_HSO4_HMW84) +# MyMarChemSpecCO2.update_caa("Na", "CO3", "HSO4", prm.psi_Na_CO3_HSO4_HMW84) +# MyMarChemSpecCO2.update_caa("K", "CO3", "HSO4", prm.psi_K_CO3_HSO4_HMW84) +# MyMarChemSpecCO2.update_caa("Ca", "CO3", "HSO4", prm.psi_Ca_CO3_HSO4_HMW84) +# MyMarChemSpecCO2.update_caa("Mg", "CO3", "HSO4", prm.psi_Mg_CO3_HSO4_HMW84) +# MyMarChemSpecCO2.update_caa("MgOH", "CO3", "HSO4", prm.psi_MgOH_CO3_HSO4_HMW84) +# MyMarChemSpecCO2.update_caa("H", "CO3", "HSO4", prm.psi_H_CO3_HSO4_HMW84) +MyMarChemSpecCO2.update_aa("HCO3", "OH", prm.theta_HCO3_OH_HMW84) +MyMarChemSpecCO2.update_caa("Na", "HCO3", "OH", prm.psi_Na_HCO3_OH_HMW84) +# MyMarChemSpecCO2.update_caa("K", "HCO3", "OH", prm.psi_K_HCO3_OH_HMW84) +# MyMarChemSpecCO2.update_caa("Ca", "HCO3", "OH", prm.psi_Ca_HCO3_OH_HMW84) +# MyMarChemSpecCO2.update_caa("Mg", "HCO3", "OH", prm.psi_Mg_HCO3_OH_HMW84) +# MyMarChemSpecCO2.update_caa("MgOH", "HCO3", "OH", prm.psi_MgOH_HCO3_OH_HMW84) +MyMarChemSpecCO2.update_caa("H", "HCO3", "OH", prm.psi_H_HCO3_OH_HMW84) +MyMarChemSpecCO2.update_aa("CO3", "OH", prm.theta_CO3_OH_HMW84) +MyMarChemSpecCO2.update_caa("Na", "CO3", "OH", prm.psi_Na_CO3_OH_HMW84) +# MyMarChemSpecCO2.update_caa("K", "CO3", "OH", prm.psi_K_CO3_OH_HMW84) +# MyMarChemSpecCO2.update_caa("Ca", "CO3", "OH", prm.psi_Ca_CO3_OH_HMW84) +# MyMarChemSpecCO2.update_caa("Mg", "CO3", "OH", prm.psi_Mg_CO3_OH_HMW84) +# MyMarChemSpecCO2.update_caa("MgOH", "CO3", "OH", prm.psi_MgOH_CO3_OH_HMW84) +MyMarChemSpecCO2.update_caa("H", "CO3", "OH", prm.psi_H_CO3_OH_HMW84) +MyMarChemSpecCO2.update_aa("CO3", "HCO3", prm.theta_CO3_HCO3_HMW84) +MyMarChemSpecCO2.update_caa("Na", "CO3", "HCO3", prm.psi_Na_CO3_HCO3_HMW84) +# MyMarChemSpecCO2.update_caa("K", "CO3", "HCO3", prm.psi_K_CO3_HCO3_HMW84) +# MyMarChemSpecCO2.update_caa("Ca", "CO3", "HCO3", prm.psi_Ca_CO3_HCO3_HMW84) +# MyMarChemSpecCO2.update_caa("Mg", "CO3", "HCO3", prm.psi_Mg_CO3_HCO3_HMW84) +# MyMarChemSpecCO2.update_caa("MgOH", "CO3", "HCO3", prm.psi_MgOH_CO3_HCO3_HMW84) +MyMarChemSpecCO2.update_caa("H", "CO3", "HCO3", prm.psi_H_CO3_HCO3_HMW84) +# MyMarChemSpecCO2.update_cca("K", "Na", "HCO3", prm.psi_K_Na_HCO3_HMW84) +# MyMarChemSpecCO2.update_cca("K", "Na", "CO3", prm.psi_K_Na_CO3_HMW84) +# MyMarChemSpecCO2.update_cca("Ca", "Na", "HCO3", prm.psi_Ca_Na_HCO3_HMW84) +# MyMarChemSpecCO2.update_cca("Ca", "Na", "CO3", prm.psi_Ca_Na_CO3_HMW84) +# MyMarChemSpecCO2.update_cca("Mg", "Na", "HCO3", prm.psi_Mg_Na_HCO3_HMW84) +# MyMarChemSpecCO2.update_cca("Mg", "Na", "CO3", prm.psi_Mg_Na_CO3_HMW84) +# MyMarChemSpecCO2.update_cca("MgOH", "Na", "HCO3", prm.psi_MgOH_Na_HCO3_HMW84) +# MyMarChemSpecCO2.update_cca("MgOH", "Na", "CO3", prm.psi_MgOH_Na_CO3_HMW84) +MyMarChemSpecCO2.update_cca("H", "Na", "HCO3", prm.psi_H_Na_HCO3_HMW84) +MyMarChemSpecCO2.update_cca("H", "Na", "CO3", prm.psi_H_Na_CO3_HMW84) +# MyMarChemSpecCO2.update_cca("Ca", "K", "HCO3", prm.psi_Ca_K_HCO3_HMW84) +# MyMarChemSpecCO2.update_cca("Ca", "K", "CO3", prm.psi_Ca_K_CO3_HMW84) +# MyMarChemSpecCO2.update_cca("K", "Mg", "HCO3", prm.psi_K_Mg_HCO3_HMW84) +# MyMarChemSpecCO2.update_cca("K", "Mg", "CO3", prm.psi_K_Mg_CO3_HMW84) +# MyMarChemSpecCO2.update_cca("K", "MgOH", "HCO3", prm.psi_K_MgOH_HCO3_HMW84) +# MyMarChemSpecCO2.update_cca("K", "MgOH", "CO3", prm.psi_K_MgOH_CO3_HMW84) +# MyMarChemSpecCO2.update_cca("H", "K", "HCO3", prm.psi_H_K_HCO3_HMW84) +# MyMarChemSpecCO2.update_cca("H", "K", "CO3", prm.psi_H_K_CO3_HMW84) +# MyMarChemSpecCO2.update_cca("Ca", "Mg", "HCO3", prm.psi_Ca_Mg_HCO3_HMW84) +# MyMarChemSpecCO2.update_cca("Ca", "Mg", "CO3", prm.psi_Ca_Mg_CO3_HMW84) +# MyMarChemSpecCO2.update_cca("Ca", "MgOH", "HCO3", prm.psi_Ca_MgOH_HCO3_HMW84) +# MyMarChemSpecCO2.update_cca("Ca", "MgOH", "CO3", prm.psi_Ca_MgOH_CO3_HMW84) +# MyMarChemSpecCO2.update_cca("Ca", "H", "HCO3", prm.psi_Ca_H_HCO3_HMW84) +# MyMarChemSpecCO2.update_cca("Ca", "H", "CO3", prm.psi_Ca_H_CO3_HMW84) +# MyMarChemSpecCO2.update_cca("Mg", "MgOH", "HCO3", prm.psi_Mg_MgOH_HCO3_HMW84) +# MyMarChemSpecCO2.update_cca("Mg", "MgOH", "CO3", prm.psi_Mg_MgOH_CO3_HMW84) +# MyMarChemSpecCO2.update_cca("H", "Mg", "HCO3", prm.psi_H_Mg_HCO3_HMW84) +# MyMarChemSpecCO2.update_cca("H", "Mg", "CO3", prm.psi_H_Mg_CO3_HMW84) +# MyMarChemSpecCO2.update_cca("H", "MgOH", "HCO3", prm.psi_H_MgOH_HCO3_HMW84) +# MyMarChemSpecCO2.update_cca("H", "MgOH", "CO3", prm.psi_H_MgOH_CO3_HMW84) +# lambda +MyMarChemSpecCO2.update_nc("CO2", "H", prm.lambd_CO2_H_HM93) +MyMarChemSpecCO2.update_nc("CO2", "Na", prm.lambd_CO2_Na_HM93) +# MyMarChemSpecCO2.update_nc("CO2", "K", prm.lambd_CO2_K_HM93) +# MyMarChemSpecCO2.update_nc("CO2", "Ca", prm.lambd_CO2_Ca_HM93) +# MyMarChemSpecCO2.update_nc("CO2", "Mg", prm.lambd_CO2_Mg_HM93) +MyMarChemSpecCO2.update_na("CO2", "Cl", prm.lambd_CO2_Cl_HM93) +# MyMarChemSpecCO2.update_na("CO2", "SO4", prm.lambd_CO2_SO4_HM93) +# MyMarChemSpecCO2.update_na("CO2", "HSO4", prm.lambd_CO2_HSO4_HMW84) +# zeta +MyMarChemSpecCO2.update_nca("CO2", "H", "Cl", prm.zeta_CO2_H_Cl_HM93) +MyMarChemSpecCO2.update_nca("CO2", "Na", "Cl", prm.zeta_CO2_Na_Cl_HM93) +# MyMarChemSpecCO2.update_nca("CO2", "K", "Cl", prm.zeta_CO2_K_Cl_HM93) +# MyMarChemSpecCO2.update_nca("CO2", "Mg", "Cl", prm.zeta_CO2_Mg_Cl_HM93) +# MyMarChemSpecCO2.update_nca("CO2", "Ca", "Cl", prm.zeta_CO2_Ca_Cl_HM93) +# MyMarChemSpecCO2.update_nca("CO2", "H", "SO4", prm.zeta_CO2_H_SO4_HM93) +# MyMarChemSpecCO2.update_nca("CO2", "Na", "SO4", prm.zeta_CO2_Na_SO4_HM93) +# MyMarChemSpecCO2.update_nca("CO2", "K", "SO4", prm.zeta_CO2_K_SO4_HM93) +# MyMarChemSpecCO2.update_nca("CO2", "Mg", "SO4", prm.zeta_CO2_Mg_SO4_HM93) diff --git a/pytzer/libraries/ParameterLibrary.py b/pytzer/libraries/ParameterLibrary.py index ddd029a2..7746fd64 100644 --- a/pytzer/libraries/ParameterLibrary.py +++ b/pytzer/libraries/ParameterLibrary.py @@ -1,8 +1,9 @@ # Pytzer: Pitzer model for chemical activities in aqueous solutions. -# Copyright (C) 2019--2021 Matthew P. Humphreys (GNU GPLv3) +# Copyright (C) 2019--2023 Matthew P. Humphreys (GNU GPLv3) from copy import deepcopy from collections import OrderedDict import numpy as np +from scipy.special import comb from .. import debyehueckel as dh, parameters as prm, convert from ..equilibrate import thermodynamic from ..meta import update_func_J @@ -317,3 +318,163 @@ def get_parameters_equilibria( ) log_kt_constants = self.get_equilibria(solutes=solutes, temperature=temperature) return parameters, log_kt_constants + + def get_matrices( + self, + solutes, + temperature=298.15, + pressure=10.1023, + verbose=True, + ): + """Assemble parameter matrices for the matrix model.""" + if verbose: + missing_coeffs = [] + + def report_missing_coeffs(*solutes): + if verbose: + solutes_list = list(solutes) + solutes_list.sort() + if solutes_list not in missing_coeffs: + print( + ( + "{} has no interaction coefficients for " + + "-".join(["{}"] * len(solutes)) + + "; using zero." + ).format(self["name"], *solutes) + ) + missing_coeffs.append(solutes_list) + + cations = [s for s in solutes if s in convert.all_cations] + anions = [s for s in solutes if s in convert.all_anions] + neutrals = [s for s in solutes if s in convert.all_neutrals] + # Set up parameters dict + parameters = {"temperature": temperature, "pressure": pressure} + TP = (temperature, pressure) + if "Aphi" in self: + parameters.update({"Aphi": self["Aphi"](*TP)[0]}) + else: + if verbose: + print( + "{} has no Aphi function; no value returned.".format(self["name"]) + ) + # Preallocate empty matrices + for p in [ + "beta0_ca", + "beta1_ca", + "beta2_ca", + "c0_ca", + "c1_ca", + "theta_xx", + "lambda_nx", + ]: + parameters[p] = np.zeros((len(solutes), len(solutes))) + for p in ["alpha1_ca", "alpha2_ca", "omega_ca"]: + parameters[p] = np.full((len(solutes), len(solutes)), -9.0) + for p in ["psi_cca", "psi_caa"]: + parameters[p] = np.zeros((int(comb(len(cations), 2)), len(anions))) + parameters["zeta_nca"] = np.zeros((len(neutrals), len(cations) * len(anions))) + parameters["mu_nnn"] = np.zeros((len(neutrals), 1)) + # Fill the matrices with coefficients: ca, ii and nx interactions + for x, solute_x in enumerate(solutes): + for y, solute_y in enumerate(solutes): + try: + params_ca = self["ca"][solute_x][solute_y](*TP)[:-1] + ( + parameters["beta0_ca"][x, y], + parameters["beta1_ca"][x, y], + parameters["beta2_ca"][x, y], + parameters["c0_ca"][x, y], + parameters["c1_ca"][x, y], + parameters["alpha1_ca"][x, y], + parameters["alpha2_ca"][x, y], + parameters["omega_ca"][x, y], + ) = ( + parameters["beta0_ca"][y, x], + parameters["beta1_ca"][y, x], + parameters["beta2_ca"][y, x], + parameters["c0_ca"][y, x], + parameters["c1_ca"][y, x], + parameters["alpha1_ca"][y, x], + parameters["alpha2_ca"][y, x], + parameters["omega_ca"][y, x], + ) = params_ca + except KeyError: + if ( + solute_x in convert.all_cations + and solute_y in convert.all_anions + ): + report_missing_coeffs(solute_x, solute_y) + try: + param_theta = self["cc"][solute_x][solute_y](*TP)[0] + parameters["theta_xx"][x, y] = parameters["theta_xx"][ + y, x + ] = param_theta + except KeyError: + if solute_x != solute_y: + if ( + solute_x in convert.all_cations + and solute_y in convert.all_cations + ): + report_missing_coeffs(solute_x, solute_y) + try: + param_theta = self["aa"][solute_x][solute_y](*TP)[0] + parameters["theta_xx"][x, y] = parameters["theta_xx"][ + y, x + ] = param_theta + except KeyError: + if solute_x != solute_y: + if ( + solute_x in convert.all_anions + and solute_y in convert.all_anions + ): + report_missing_coeffs(solute_x, solute_y) + try: + param_lambda = self["nc"][solute_x][solute_y](*TP)[0] + parameters["lambda_nx"][x, y] = parameters["lambda_nx"][ + x, y + ] = param_lambda + except KeyError: + if solute_x in convert.all_neutrals: + report_missing_coeffs(solute_x, solute_y) + try: + param_lambda = self["na"][solute_x][solute_y](*TP)[0] + parameters["lambda_nx"][x, y] = parameters["lambda_nx"][ + x, y + ] = param_lambda + except KeyError: + if solute_x in convert.all_neutrals: + report_missing_coeffs(solute_x, solute_y) + try: + param_lambda = self["nn"][solute_x][solute_y](*TP)[0] + parameters["lambda_nx"][x, y] = parameters["lambda_nx"][ + x, y + ] = param_lambda + except KeyError: + if solute_x in convert.all_neutrals: + report_missing_coeffs(solute_x, solute_y) + # Fill the matrices with coefficients: cca and caa interactions + CC = 0 + for CX, cationx in enumerate(cations): + for xCY, cationy in enumerate(cations[CX + 1 :]): + for A, anion in enumerate(anions): + parameters["psi_cca"][CC, A] = self["cca"][cationx][cationy][anion]( + *TP + )[0] + CC = CC + 1 + AA = 0 + for AX, anionx in enumerate(anions): + for xAY, aniony in enumerate(anions[AX + 1 :]): + for C, cation in enumerate(cations): + parameters["psi_caa"][AA, C] = self["caa"][cation][anionx][aniony]( + *TP + )[0] + AA = AA + 1 + # Fill the matrices with coefficients: nca and nnn interactions + for N, neutral in enumerate(neutrals): + parameters["mu_nnn"][N, 0] = self["nnn"][neutral](*TP)[0] + for C, cation in enumerate(cations): + for A, anion in enumerate(anions): + parameters["zeta_nca"][N, C * len(anions) + A] = self["nca"][ + neutral + ][cation][anion](*TP)[0] + return parameters diff --git a/pytzer/libraries/Seawater.py b/pytzer/libraries/Seawater.py index 8e0b5be2..34beb7c4 100644 --- a/pytzer/libraries/Seawater.py +++ b/pytzer/libraries/Seawater.py @@ -1,5 +1,5 @@ # Pytzer: Pitzer model for chemical activities in aqueous solutions. -# Copyright (C) 2019--2021 Matthew P. Humphreys (GNU GPLv3) +# Copyright (C) 2019--2023 Matthew P. Humphreys (GNU GPLv3) from . import ParameterLibrary from .. import debyehueckel, dissociation as k, parameters as prm, unsymmetrical diff --git a/pytzer/libraries/Waters13.py b/pytzer/libraries/Waters13.py index f9621e3e..9f20c580 100644 --- a/pytzer/libraries/Waters13.py +++ b/pytzer/libraries/Waters13.py @@ -1,5 +1,5 @@ # Pytzer: Pitzer model for chemical activities in aqueous solutions. -# Copyright (C) 2019--2021 Matthew P. Humphreys (GNU GPLv3) +# Copyright (C) 2019--2023 Matthew P. Humphreys (GNU GPLv3) """Waters & Millero (2013). *Marine Chemistry* 149, 8--22. doi:10.1016/j.marchem.2012.11.003 @@ -109,3 +109,7 @@ Waters13.update_cca("Ca", "K", "Cl", prm.psi_Ca_K_Cl_HMW84) Waters13.update_cca("Ca", "K", "SO4", prm.psi_Ca_K_SO4_WM13) # agrees with HMW84 Waters13.update_cca("Ca", "K", "HSO4", prm.psi_Ca_K_HSO4_WM13) # agrees with HMW84 +# Add equilibria +Waters13.update_equilibrium("HSO4", k.HSO4_CRP94) +Waters13.update_equilibrium("MgOH", k.MgOH_CW91_ln) +Waters13.update_equilibrium("H2O", k.H2O_M79) diff --git a/pytzer/libraries/Waters13_Clegg22.py b/pytzer/libraries/Waters13_Clegg22.py new file mode 100644 index 00000000..242bc563 --- /dev/null +++ b/pytzer/libraries/Waters13_Clegg22.py @@ -0,0 +1,129 @@ +# Pytzer: Pitzer model for chemical activities in aqueous solutions. +# Copyright (C) 2019--2023 Matthew P. Humphreys (GNU GPLv3) +"""Waters & Millero (2013). +*Marine Chemistry* 149, 8--22. +doi:10.1016/j.marchem.2012.11.003 +according to Clegg et al. (2022) +""" +from . import ParameterLibrary +from .. import debyehueckel, dissociation as k, parameters as prm, unsymmetrical + +Waters13_Clegg22 = ParameterLibrary(name="Waters13_Clegg22") +Waters13_Clegg22.update_Aphi(debyehueckel.Aosm_M88) +Waters13_Clegg22.assign_func_J(unsymmetrical.Harvie) +# Table A1: Na salts +Waters13_Clegg22.update_ca("Na", "Cl", prm.bC_Na_Cl_M88) +Waters13_Clegg22.update_ca("Na", "SO4", prm.bC_Na_SO4_HM86) +Waters13_Clegg22.update_ca("Na", "HSO4", prm.bC_Na_HSO4_HPR93) +Waters13_Clegg22.update_ca("Na", "OH", prm.bC_Na_OH_PP87i) +# Table A2: Mg salts +Waters13_Clegg22.update_ca("Mg", "Cl", prm.bC_Mg_Cl_dLP83) +Waters13_Clegg22.update_ca("Mg", "SO4", prm.bC_Mg_SO4_PP86ii) +Waters13_Clegg22.update_ca("Mg", "HSO4", prm.bC_Mg_HSO4_RC99) +# Table A3: Ca salts +Waters13_Clegg22.update_ca("Ca", "Cl", prm.bC_Ca_Cl_GM89) +Waters13_Clegg22.update_ca("Ca", "SO4", prm.bC_Ca_SO4_WM13) +Waters13_Clegg22.update_ca("Ca", "HSO4", prm.bC_Ca_HSO4_WM13) +Waters13_Clegg22.update_ca("Ca", "OH", prm.bC_Ca_OH_HMW84) +# Table A4: K salts +Waters13_Clegg22.update_ca("K", "Cl", prm.bC_K_Cl_GM89) +Waters13_Clegg22.update_ca("K", "SO4", prm.bC_K_SO4_HM86) +Waters13_Clegg22.update_ca("K", "HSO4", prm.bC_K_HSO4_WM13) +Waters13_Clegg22.update_ca("K", "OH", prm.bC_K_OH_HMW84) +# Table A5: H+ interactions +Waters13_Clegg22.update_ca("H", "Cl", prm.bC_H_Cl_CMR93) +Waters13_Clegg22.update_ca("H", "SO4", prm.bC_H_SO4_CRP94) +Waters13_Clegg22.update_ca("H", "HSO4", prm.bC_H_HSO4_CRP94) +# Table A6: MgOH+ interactions +Waters13_Clegg22.update_ca("MgOH", "Cl", prm.bC_MgOH_Cl_HMW84) +# Table A7: cation-cation interactions +Waters13_Clegg22.update_cc("H", "Na", prm.theta_H_Na_HCW22) # different from WM13 +Waters13_Clegg22.update_cc("H", "Mg", prm.theta_H_Mg_RGB80) +Waters13_Clegg22.update_cc("Ca", "H", prm.theta_Ca_H_RGO81) +Waters13_Clegg22.update_cc("H", "K", prm.theta_H_K_CMR93) +Waters13_Clegg22.update_cc("Mg", "Na", prm.theta_Mg_Na_HMW84) +Waters13_Clegg22.update_cc("Ca", "Na", prm.theta_Ca_Na_HMW84) +Waters13_Clegg22.update_cc("K", "Na", prm.theta_K_Na_HMW84) +Waters13_Clegg22.update_cc("Ca", "Mg", prm.theta_Ca_Mg_HMW84) +Waters13_Clegg22.update_cc("K", "Mg", prm.theta_K_Mg_HMW84) +Waters13_Clegg22.update_cc("Ca", "K", prm.theta_Ca_K_HMW84) +# Table A7: anion-anion interactions +Waters13_Clegg22.update_aa("Cl", "SO4", prm.theta_Cl_SO4_HMW84) +Waters13_Clegg22.update_aa("Cl", "HSO4", prm.theta_Cl_HSO4_HMW84) +Waters13_Clegg22.update_aa("Cl", "OH", prm.theta_Cl_OH_HMW84) +Waters13_Clegg22.update_aa("HSO4", "SO4", prm.theta_HSO4_SO4_WM13) +Waters13_Clegg22.update_aa("OH", "SO4", prm.theta_OH_SO4_HMW84) +# Table A8: c-a-a' triplets +Waters13_Clegg22.update_caa("H", "Cl", "SO4", prm.psi_H_Cl_SO4_WM13) +Waters13_Clegg22.update_caa("Na", "Cl", "SO4", prm.psi_Na_Cl_SO4_HMW84) +Waters13_Clegg22.update_caa("Mg", "Cl", "SO4", prm.psi_Mg_Cl_SO4_HMW84) +Waters13_Clegg22.update_caa("Ca", "Cl", "SO4", prm.psi_Ca_Cl_SO4_HMW84) +Waters13_Clegg22.update_caa("K", "Cl", "SO4", prm.psi_K_Cl_SO4_HMW84) +Waters13_Clegg22.update_caa("H", "Cl", "HSO4", prm.psi_H_Cl_HSO4_HMW84) +Waters13_Clegg22.update_caa("Na", "Cl", "HSO4", prm.psi_Na_Cl_HSO4_HMW84) +Waters13_Clegg22.update_caa("Mg", "Cl", "HSO4", prm.psi_Mg_Cl_HSO4_HMW84) +Waters13_Clegg22.update_caa("Ca", "Cl", "HSO4", prm.psi_Ca_Cl_HSO4_HMW84) +Waters13_Clegg22.update_caa("K", "Cl", "HSO4", prm.psi_K_Cl_HSO4_HMW84) +Waters13_Clegg22.update_caa("H", "Cl", "OH", prm.psi_H_Cl_OH_WM13) +Waters13_Clegg22.update_caa("Na", "Cl", "OH", prm.psi_Na_Cl_OH_HMW84) +Waters13_Clegg22.update_caa("Mg", "Cl", "OH", prm.psi_Mg_Cl_OH_WM13) +Waters13_Clegg22.update_caa("Ca", "Cl", "OH", prm.psi_Ca_Cl_OH_HMW84) +Waters13_Clegg22.update_caa("K", "Cl", "OH", prm.psi_K_Cl_OH_HMW84) +Waters13_Clegg22.update_caa("H", "HSO4", "SO4", prm.psi_H_HSO4_SO4_HMW84) +Waters13_Clegg22.update_caa("Na", "HSO4", "SO4", prm.psi_Na_HSO4_SO4_HMW84) +Waters13_Clegg22.update_caa("Mg", "HSO4", "SO4", prm.psi_Mg_HSO4_SO4_RC99) +Waters13_Clegg22.update_caa("Ca", "HSO4", "SO4", prm.psi_Ca_HSO4_SO4_WM13) +Waters13_Clegg22.update_caa("K", "HSO4", "SO4", prm.psi_K_HSO4_SO4_HMW84) +Waters13_Clegg22.update_caa("H", "OH", "SO4", prm.psi_H_OH_SO4_WM13) +Waters13_Clegg22.update_caa("Na", "OH", "SO4", prm.psi_Na_OH_SO4_HMW84) +Waters13_Clegg22.update_caa("Mg", "OH", "SO4", prm.psi_Mg_OH_SO4_WM13) +Waters13_Clegg22.update_caa("Ca", "OH", "SO4", prm.psi_Ca_OH_SO4_WM13) +Waters13_Clegg22.update_caa("K", "OH", "SO4", prm.psi_K_OH_SO4_HMW84) +# Table A9: c-c'-a triplets +Waters13_Clegg22.update_cca("H", "Na", "Cl", prm.psi_H_Na_Cl_HMW84) +Waters13_Clegg22.update_cca("H", "Na", "SO4", prm.psi_H_Na_SO4_WM13) +Waters13_Clegg22.update_cca("H", "Na", "HSO4", prm.psi_H_Na_HSO4_HMW84) +Waters13_Clegg22.update_cca("H", "Mg", "Cl", prm.psi_H_Mg_Cl_HMW84) +Waters13_Clegg22.update_cca("H", "Mg", "SO4", prm.psi_H_Mg_SO4_RC99) +Waters13_Clegg22.update_cca("H", "Mg", "HSO4", prm.psi_H_Mg_HSO4_RC99) +Waters13_Clegg22.update_cca("Ca", "H", "Cl", prm.psi_Ca_H_Cl_HMW84) +Waters13_Clegg22.update_cca("Ca", "H", "SO4", prm.psi_Ca_H_SO4_WM13) +Waters13_Clegg22.update_cca("Ca", "H", "HSO4", prm.psi_Ca_H_HSO4_WM13) +Waters13_Clegg22.update_cca("H", "K", "Cl", prm.psi_H_K_Cl_HMW84) +Waters13_Clegg22.update_cca("H", "K", "SO4", prm.psi_H_K_SO4_HMW84) +Waters13_Clegg22.update_cca("H", "K", "HSO4", prm.psi_H_K_HSO4_HMW84) +Waters13_Clegg22.update_cca("Mg", "Na", "Cl", prm.psi_Mg_Na_Cl_HMW84) +Waters13_Clegg22.update_cca("Mg", "Na", "SO4", prm.psi_Mg_Na_SO4_HMW84) +Waters13_Clegg22.update_cca("Mg", "Na", "HSO4", prm.psi_Mg_Na_HSO4_WM13) +Waters13_Clegg22.update_cca("Ca", "Na", "Cl", prm.psi_Ca_Na_Cl_HMW84) +Waters13_Clegg22.update_cca("Ca", "Na", "SO4", prm.psi_Ca_Na_SO4_HMW84) +Waters13_Clegg22.update_cca("Ca", "Na", "HSO4", prm.psi_Ca_Na_HSO4_WM13) +Waters13_Clegg22.update_cca("K", "Na", "Cl", prm.psi_K_Na_Cl_HMW84) +Waters13_Clegg22.update_cca("K", "Na", "SO4", prm.psi_K_Na_SO4_HMW84) +Waters13_Clegg22.update_cca("K", "Na", "HSO4", prm.psi_K_Na_HSO4_WM13) +Waters13_Clegg22.update_cca("Ca", "Mg", "Cl", prm.psi_Ca_Mg_Cl_HMW84) +Waters13_Clegg22.update_cca("Ca", "Mg", "SO4", prm.psi_Ca_Mg_SO4_HMW84) +Waters13_Clegg22.update_cca("Ca", "Mg", "HSO4", prm.psi_Ca_Mg_HSO4_WM13) +Waters13_Clegg22.update_cca("K", "Mg", "Cl", prm.psi_K_Mg_Cl_HMW84) +Waters13_Clegg22.update_cca("K", "Mg", "SO4", prm.psi_K_Mg_SO4_HMW84) +Waters13_Clegg22.update_cca("K", "Mg", "HSO4", prm.psi_K_Mg_HSO4_WM13) +Waters13_Clegg22.update_cca("Ca", "K", "Cl", prm.psi_Ca_K_Cl_HMW84) +Waters13_Clegg22.update_cca("Ca", "K", "SO4", prm.psi_Ca_K_SO4_WM13) +Waters13_Clegg22.update_cca("Ca", "K", "HSO4", prm.psi_Ca_K_HSO4_WM13) +Waters13_Clegg22.update_cca("Mg", "MgOH", "Cl", prm.psi_Mg_MgOH_Cl_HMW84) # not in WM13 +# Add equilibria +Waters13_Clegg22.update_equilibrium("HSO4", k.HSO4_CRP94) +Waters13_Clegg22.update_equilibrium("MgOH", k.MgOH_CW91_ln) +Waters13_Clegg22.update_equilibrium("H2O", k.H2O_M79) +# Extras from Clegg22 (all before this point is from Humphreys22) +Waters13_Clegg22.update_equilibrium("trisH", k.trisH_BH61) +Waters13_Clegg22.update_ca("trisH", "Cl", prm.bC_trisH_Cl_CHW22) +Waters13_Clegg22.update_ca("trisH", "SO4", prm.bC_trisH_SO4_CHW22) +Waters13_Clegg22.update_nc("tris", "Ca", prm.lambd_tris_Ca_CHW22) +Waters13_Clegg22.update_nc("tris", "K", prm.lambd_tris_K_CHW22) +Waters13_Clegg22.update_nc("tris", "Mg", prm.lambd_tris_Mg_CHW22) +Waters13_Clegg22.update_nc("tris", "Na", prm.lambd_tris_Na_CHW22) +Waters13_Clegg22.update_nc("tris", "trisH", prm.lambd_tris_trisH_LTA21) +Waters13_Clegg22.update_na("tris", "SO4", prm.lambd_tris_SO4_LTA21) +Waters13_Clegg22.update_nn("tris", "tris", prm.lambd_tris_tris_LTA21) +Waters13_Clegg22.update_nnn("tris", prm.mu_tris_tris_tris_LTA21) diff --git a/pytzer/libraries/Waters13_Humphreys22.py b/pytzer/libraries/Waters13_Humphreys22.py new file mode 100644 index 00000000..db67b2d7 --- /dev/null +++ b/pytzer/libraries/Waters13_Humphreys22.py @@ -0,0 +1,119 @@ +# Pytzer: Pitzer model for chemical activities in aqueous solutions. +# Copyright (C) 2019--2023 Matthew P. Humphreys (GNU GPLv3) +"""Waters & Millero (2013). +*Marine Chemistry* 149, 8--22. +doi:10.1016/j.marchem.2012.11.003 +according to Humphreys et al. (2022) +""" +from . import ParameterLibrary +from .. import debyehueckel, dissociation as k, parameters as prm, unsymmetrical + +Waters13_Humphreys22 = ParameterLibrary(name="Waters13_Humphreys22") +Waters13_Humphreys22.update_Aphi(debyehueckel.Aosm_M88) +Waters13_Humphreys22.assign_func_J(unsymmetrical.Harvie) +# Table A1: Na salts +Waters13_Humphreys22.update_ca("Na", "Cl", prm.bC_Na_Cl_M88) +Waters13_Humphreys22.update_ca("Na", "SO4", prm.bC_Na_SO4_HM86) +Waters13_Humphreys22.update_ca("Na", "HSO4", prm.bC_Na_HSO4_HPR93) +Waters13_Humphreys22.update_ca("Na", "OH", prm.bC_Na_OH_PP87i) +# Table A2: Mg salts +Waters13_Humphreys22.update_ca("Mg", "Cl", prm.bC_Mg_Cl_dLP83) +Waters13_Humphreys22.update_ca("Mg", "SO4", prm.bC_Mg_SO4_PP86ii) +Waters13_Humphreys22.update_ca("Mg", "HSO4", prm.bC_Mg_HSO4_RC99) +# Table A3: Ca salts +Waters13_Humphreys22.update_ca("Ca", "Cl", prm.bC_Ca_Cl_GM89) +Waters13_Humphreys22.update_ca("Ca", "SO4", prm.bC_Ca_SO4_WM13) +Waters13_Humphreys22.update_ca("Ca", "HSO4", prm.bC_Ca_HSO4_WM13) +Waters13_Humphreys22.update_ca("Ca", "OH", prm.bC_Ca_OH_HMW84) +# Table A4: K salts +Waters13_Humphreys22.update_ca("K", "Cl", prm.bC_K_Cl_GM89) +Waters13_Humphreys22.update_ca("K", "SO4", prm.bC_K_SO4_HM86) +Waters13_Humphreys22.update_ca("K", "HSO4", prm.bC_K_HSO4_WM13) +Waters13_Humphreys22.update_ca("K", "OH", prm.bC_K_OH_HMW84) +# Table A5: H+ interactions +Waters13_Humphreys22.update_ca("H", "Cl", prm.bC_H_Cl_CMR93) +Waters13_Humphreys22.update_ca("H", "SO4", prm.bC_H_SO4_CRP94) +Waters13_Humphreys22.update_ca("H", "HSO4", prm.bC_H_HSO4_CRP94) +# Table A6: MgOH+ interactions +Waters13_Humphreys22.update_ca("MgOH", "Cl", prm.bC_MgOH_Cl_HMW84) +# Table A7: cation-cation interactions +Waters13_Humphreys22.update_cc("H", "Na", prm.theta_H_Na_HCW22) # different from WM13 +Waters13_Humphreys22.update_cc("H", "Mg", prm.theta_H_Mg_RGB80) +Waters13_Humphreys22.update_cc("Ca", "H", prm.theta_Ca_H_RGO81) +Waters13_Humphreys22.update_cc("H", "K", prm.theta_H_K_CMR93) +Waters13_Humphreys22.update_cc("Mg", "Na", prm.theta_Mg_Na_HMW84) +Waters13_Humphreys22.update_cc("Ca", "Na", prm.theta_Ca_Na_HMW84) +Waters13_Humphreys22.update_cc("K", "Na", prm.theta_K_Na_HMW84) +Waters13_Humphreys22.update_cc("Ca", "Mg", prm.theta_Ca_Mg_HMW84) +Waters13_Humphreys22.update_cc("K", "Mg", prm.theta_K_Mg_HMW84) +Waters13_Humphreys22.update_cc("Ca", "K", prm.theta_Ca_K_HMW84) +# Table A7: anion-anion interactions +Waters13_Humphreys22.update_aa("Cl", "SO4", prm.theta_Cl_SO4_HMW84) +Waters13_Humphreys22.update_aa("Cl", "HSO4", prm.theta_Cl_HSO4_HMW84) +Waters13_Humphreys22.update_aa("Cl", "OH", prm.theta_Cl_OH_HMW84) +Waters13_Humphreys22.update_aa("HSO4", "SO4", prm.theta_HSO4_SO4_WM13) +Waters13_Humphreys22.update_aa("OH", "SO4", prm.theta_OH_SO4_HMW84) +# Table A8: c-a-a' triplets +Waters13_Humphreys22.update_caa("H", "Cl", "SO4", prm.psi_H_Cl_SO4_WM13) +Waters13_Humphreys22.update_caa("Na", "Cl", "SO4", prm.psi_Na_Cl_SO4_HMW84) +Waters13_Humphreys22.update_caa("Mg", "Cl", "SO4", prm.psi_Mg_Cl_SO4_HMW84) +Waters13_Humphreys22.update_caa("Ca", "Cl", "SO4", prm.psi_Ca_Cl_SO4_HMW84) +Waters13_Humphreys22.update_caa("K", "Cl", "SO4", prm.psi_K_Cl_SO4_HMW84) +Waters13_Humphreys22.update_caa("H", "Cl", "HSO4", prm.psi_H_Cl_HSO4_HMW84) +Waters13_Humphreys22.update_caa("Na", "Cl", "HSO4", prm.psi_Na_Cl_HSO4_HMW84) +Waters13_Humphreys22.update_caa("Mg", "Cl", "HSO4", prm.psi_Mg_Cl_HSO4_HMW84) +Waters13_Humphreys22.update_caa("Ca", "Cl", "HSO4", prm.psi_Ca_Cl_HSO4_HMW84) +Waters13_Humphreys22.update_caa("K", "Cl", "HSO4", prm.psi_K_Cl_HSO4_HMW84) +Waters13_Humphreys22.update_caa("H", "Cl", "OH", prm.psi_H_Cl_OH_WM13) +Waters13_Humphreys22.update_caa("Na", "Cl", "OH", prm.psi_Na_Cl_OH_HMW84) +Waters13_Humphreys22.update_caa("Mg", "Cl", "OH", prm.psi_Mg_Cl_OH_WM13) +Waters13_Humphreys22.update_caa("Ca", "Cl", "OH", prm.psi_Ca_Cl_OH_HMW84) +Waters13_Humphreys22.update_caa("K", "Cl", "OH", prm.psi_K_Cl_OH_HMW84) +Waters13_Humphreys22.update_caa("H", "HSO4", "SO4", prm.psi_H_HSO4_SO4_HMW84) +Waters13_Humphreys22.update_caa("Na", "HSO4", "SO4", prm.psi_Na_HSO4_SO4_HMW84) +Waters13_Humphreys22.update_caa("Mg", "HSO4", "SO4", prm.psi_Mg_HSO4_SO4_RC99) +Waters13_Humphreys22.update_caa("Ca", "HSO4", "SO4", prm.psi_Ca_HSO4_SO4_WM13) +Waters13_Humphreys22.update_caa("K", "HSO4", "SO4", prm.psi_K_HSO4_SO4_HMW84) +Waters13_Humphreys22.update_caa("H", "OH", "SO4", prm.psi_H_OH_SO4_WM13) +Waters13_Humphreys22.update_caa("Na", "OH", "SO4", prm.psi_Na_OH_SO4_HMW84) +Waters13_Humphreys22.update_caa("Mg", "OH", "SO4", prm.psi_Mg_OH_SO4_WM13) +Waters13_Humphreys22.update_caa("Ca", "OH", "SO4", prm.psi_Ca_OH_SO4_WM13) +Waters13_Humphreys22.update_caa("K", "OH", "SO4", prm.psi_K_OH_SO4_HMW84) +# Table A9: c-c'-a triplets +Waters13_Humphreys22.update_cca("H", "Na", "Cl", prm.psi_H_Na_Cl_HMW84) +Waters13_Humphreys22.update_cca("H", "Na", "SO4", prm.psi_H_Na_SO4_WM13) +Waters13_Humphreys22.update_cca("H", "Na", "HSO4", prm.psi_H_Na_HSO4_HMW84) +Waters13_Humphreys22.update_cca("H", "Mg", "Cl", prm.psi_H_Mg_Cl_HMW84) +Waters13_Humphreys22.update_cca("H", "Mg", "SO4", prm.psi_H_Mg_SO4_RC99) +Waters13_Humphreys22.update_cca("H", "Mg", "HSO4", prm.psi_H_Mg_HSO4_RC99) +Waters13_Humphreys22.update_cca("Ca", "H", "Cl", prm.psi_Ca_H_Cl_HMW84) +Waters13_Humphreys22.update_cca("Ca", "H", "SO4", prm.psi_Ca_H_SO4_WM13) +Waters13_Humphreys22.update_cca("Ca", "H", "HSO4", prm.psi_Ca_H_HSO4_WM13) +Waters13_Humphreys22.update_cca("H", "K", "Cl", prm.psi_H_K_Cl_HMW84) +Waters13_Humphreys22.update_cca("H", "K", "SO4", prm.psi_H_K_SO4_HMW84) +Waters13_Humphreys22.update_cca("H", "K", "HSO4", prm.psi_H_K_HSO4_HMW84) +Waters13_Humphreys22.update_cca("Mg", "Na", "Cl", prm.psi_Mg_Na_Cl_HMW84) +Waters13_Humphreys22.update_cca("Mg", "Na", "SO4", prm.psi_Mg_Na_SO4_HMW84) +Waters13_Humphreys22.update_cca("Mg", "Na", "HSO4", prm.psi_Mg_Na_HSO4_WM13) +Waters13_Humphreys22.update_cca("Ca", "Na", "Cl", prm.psi_Ca_Na_Cl_HMW84) +Waters13_Humphreys22.update_cca("Ca", "Na", "SO4", prm.psi_Ca_Na_SO4_HMW84) +Waters13_Humphreys22.update_cca("Ca", "Na", "HSO4", prm.psi_Ca_Na_HSO4_WM13) +Waters13_Humphreys22.update_cca("K", "Na", "Cl", prm.psi_K_Na_Cl_HMW84) +Waters13_Humphreys22.update_cca("K", "Na", "SO4", prm.psi_K_Na_SO4_HMW84) +Waters13_Humphreys22.update_cca("K", "Na", "HSO4", prm.psi_K_Na_HSO4_WM13) +Waters13_Humphreys22.update_cca("Ca", "Mg", "Cl", prm.psi_Ca_Mg_Cl_HMW84) +Waters13_Humphreys22.update_cca("Ca", "Mg", "SO4", prm.psi_Ca_Mg_SO4_HMW84) +Waters13_Humphreys22.update_cca("Ca", "Mg", "HSO4", prm.psi_Ca_Mg_HSO4_WM13) +Waters13_Humphreys22.update_cca("K", "Mg", "Cl", prm.psi_K_Mg_Cl_HMW84) +Waters13_Humphreys22.update_cca("K", "Mg", "SO4", prm.psi_K_Mg_SO4_HMW84) +Waters13_Humphreys22.update_cca("K", "Mg", "HSO4", prm.psi_K_Mg_HSO4_WM13) +Waters13_Humphreys22.update_cca("Ca", "K", "Cl", prm.psi_Ca_K_Cl_HMW84) +Waters13_Humphreys22.update_cca("Ca", "K", "SO4", prm.psi_Ca_K_SO4_WM13) +Waters13_Humphreys22.update_cca("Ca", "K", "HSO4", prm.psi_Ca_K_HSO4_WM13) +Waters13_Humphreys22.update_cca( + "Mg", "MgOH", "Cl", prm.psi_Mg_MgOH_Cl_HMW84 +) # not in WM13 +# Add equilibria +Waters13_Humphreys22.update_equilibrium("HSO4", k.HSO4_CRP94) +Waters13_Humphreys22.update_equilibrium("MgOH", k.MgOH_CW91_ln) +Waters13_Humphreys22.update_equilibrium("H2O", k.H2O_M79) diff --git a/pytzer/libraries/Waters13_MarChemSpec25.py b/pytzer/libraries/Waters13_MarChemSpec25.py index f3d25f40..14c4ddfc 100644 --- a/pytzer/libraries/Waters13_MarChemSpec25.py +++ b/pytzer/libraries/Waters13_MarChemSpec25.py @@ -1,5 +1,5 @@ # Pytzer: Pitzer model for chemical activities in aqueous solutions. -# Copyright (C) 2019--2021 Matthew P. Humphreys (GNU GPLv3) +# Copyright (C) 2019--2023 Matthew P. Humphreys (GNU GPLv3) from . import ParameterLibrary from .. import debyehueckel, dissociation as k, parameters as prm, unsymmetrical diff --git a/pytzer/libraries/__init__.py b/pytzer/libraries/__init__.py index 0266aa6b..27072143 100644 --- a/pytzer/libraries/__init__.py +++ b/pytzer/libraries/__init__.py @@ -1,27 +1,41 @@ # Pytzer: Pitzer model for chemical activities in aqueous solutions. -# Copyright (C) 2019--2021 Matthew P. Humphreys (GNU GPLv3) +# Copyright (C) 2019--2023 Matthew P. Humphreys (GNU GPLv3) """Assemble parameter libraries.""" from .ParameterLibrary import ParameterLibrary +from .Clegg22 import Clegg22 +from .Clegg23 import Clegg23 from .Clegg94 import Clegg94 from .Greenberg89 import Greenberg89 from .Harvie84 import Harvie84 +from .HeMorse93 import HeMorse93 +from .Humphreys22 import Humphreys22 from .MarChemSpec import MarChemSpec from .MarChemSpec25 import MarChemSpec25 from .Millero98 import Millero98 from .Moller88 import Moller88 +from .MyMarChemSpecCO2 import MyMarChemSpecCO2 from .Seawater import Seawater from .Waters13 import Waters13 +from .Waters13_Humphreys22 import Waters13_Humphreys22 +from .Waters13_Clegg22 import Waters13_Clegg22 from .Waters13_MarChemSpec25 import Waters13_MarChemSpec25 # Aliases for convenience +CHW22 = Clegg22 +CWTD23 = Clegg23 CRP94 = Clegg94 GM89 = Greenberg89 HMW84 = Harvie84 +HM93 = HeMorse93 +HWT22 = Humphreys22 +myMCS = MyMarChemSpecCO2 MCS = MarChemSpec MCS25 = MarChemSpec25 MP98 = MIAMI = Millero98 M88 = Moller88 WM13 = Waters13 +WM13_C22 = Waters13_Clegg22 +WM13_H22 = Waters13_Humphreys22 WM13_MCS25 = Waters13_MarChemSpec25 # solutes_MarChemSpec = np.array( diff --git a/pytzer/matrix.py b/pytzer/matrix.py new file mode 100644 index 00000000..ce4c9031 --- /dev/null +++ b/pytzer/matrix.py @@ -0,0 +1,182 @@ +import jax +from jax import numpy as np +from . import convert, model + + +def ionic_strength(molalities, charges): + """Calculate the ionic strength. + + Parameters + ---------- + molalities : array_like + Molality of each solute in mol/kg. + charges : array_like + Charge on each solute. + + Returns + ------- + float + Ionic strength of the solution in mol/kg. + """ + return molalities @ np.transpose(charges**2) / 2 + + +def ionic_z(molalities, charges): + """Calculate the Z function. + + Parameters + ---------- + molalities : array_like + Molality of each solute in mol/kg. + charges : array_like + Charge on each solute. + + Returns + ------- + float + Z function of the solution in mol/kg. + """ + return molalities @ np.transpose(np.abs(charges)) + + +def sum_B_CT(I, Z, beta0, beta1, beta2, alpha1, alpha2, c0, c1, omega): + """Calculate the sum of the B and CT functions following CRP94 equations (AI7) and + (AI10) respectively. + + Parameters + ---------- + I : float + Ionic strength of the solution in mol/kg. + Z : float + Z function of the solution in mol/kg. + beta0 : array_like + Beta-0 Pitzer model coefficients. + beta1 : array_like + Beta-1 Pitzer model coefficients. + beta2 : array_like + Beta-2 Pitzer model coefficients. + alpha1 : array_like + Alpha-1 Pitzer model coefficients. + alpha2 : array_like + Alpha-2 Pitzer model cofficients. + c0 : array_like + C-0 Pitzer model coefficients. + c1 : array_like + C-1 Pitzer model coefficients. + omega : array_like + Omega Pitzer model coefficients. + + Returns + ------- + array_like + Sum of the B and CT functions. + """ + return ( + beta0 + + beta1 * model.g(alpha1 * np.sqrt(I)) + + beta2 * model.g(alpha2 * np.sqrt(I)) + + (c0 + 4 * c1 * model.h(omega * np.sqrt(I))) * Z / 2 + ) + + +def xij(Aphi, I, charges): + """xij function for unsymmetrical mixing.""" + return (np.transpose(charges) @ charges) * 6 * Aphi * np.sqrt(I) + + +def xi(Aphi, I, charges): + """xi function for unsymmetrical mixing.""" + return charges**2 * 6 * Aphi * np.sqrt(I) + + +def xj(Aphi, I, zs): + """xj function for unsymmetrical mixing.""" + return np.transpose(zs**2) * 6 * Aphi * np.sqrt(I) + + +def etheta(Aphi, I, charges): + """E-theta function for unsymmetrical mixing.""" + x01 = xij(Aphi, I, charges) + x00 = xi(Aphi, I, charges) + x11 = xj(Aphi, I, charges) + func_J = jax.vmap(jax.vmap(model.func_J)) + return ( + (np.transpose(charges) @ charges) + * (func_J(x01) - (func_J(x00) + func_J(x11)) / 2) + / (4 * I) + ) + + +@jax.jit +def Gibbs_nRT( + solutes, + n_cats_triu, + n_anis_triu, + Aphi=None, + beta0_ca=None, + beta1_ca=None, + beta2_ca=None, + alpha1_ca=None, + alpha2_ca=None, + c0_ca=None, + c1_ca=None, + omega_ca=None, + theta_xx=None, + psi_cca=None, + psi_caa=None, + lambda_nx=None, + zeta_nca=None, + mu_nnn=None, + **parameters_extra +): + """Excess Gibbs energy of a solution.""" + # Get the molalities of cations, anions and neutrals in separate arrays + molalities = np.array([[m for m in solutes.values()]]) + m_cats = np.array([[m for s, m in solutes.items() if s in convert.all_cations]]) + m_anis = np.array([[m for s, m in solutes.items() if s in convert.all_anions]]) + m_neus = np.array([[m for s, m in solutes.items() if s in convert.all_neutrals]]) + # Get the charges of cations and anions in separate arrays + s2c = convert.solute_to_charge + charges = np.array([[s2c[s] for s in solutes]]) + z_cats = np.array([[s2c[s] for s in solutes if s in convert.all_cations]]) + z_anis = np.array([[s2c[s] for s in solutes if s in convert.all_anions]]) + I = ionic_strength(molalities, charges) + # if I == 0: + # Gibbs_nRT = ( + # molalities @ lambda_nx @ np.transpose(molalities) + # + m_neus @ zeta_nca @ np.transpose(m_cats_anis) + # + m_neus**3 @ mu_nnn + # ) + # else: + # # Get the products of cation and anion molalities + m_cats_anis = np.array([(np.transpose(m_cats) @ m_anis).ravel()]) + Z = ionic_z(molalities, charges) + m_cats_cats = np.array([(np.transpose(m_cats) @ m_cats)[n_cats_triu]]) + m_anis_anis = np.array([(np.transpose(m_anis) @ m_anis)[n_anis_triu]]) + Gibbs_nRT = model.Gibbs_DH(Aphi, I) + molalities @ ( + sum_B_CT( + I, + Z, + beta0_ca, + beta1_ca, + beta2_ca, + alpha1_ca, + alpha2_ca, + c0_ca, + c1_ca, + omega_ca, + ) + + theta_xx + + lambda_nx + ) @ np.transpose(molalities) + +m_cats @ etheta(Aphi, I, z_cats) @ np.transpose(m_cats) + +m_anis @ etheta(Aphi, I, z_anis) @ np.transpose(m_anis) + if psi_cca.size > 0: + Gibbs_nRT = Gibbs_nRT + m_cats_cats @ psi_cca @ np.transpose(m_anis) + if psi_caa.size > 0: + Gibbs_nRT = Gibbs_nRT + m_anis_anis @ psi_caa @ np.transpose(m_cats) + if zeta_nca.size > 0: + Gibbs_nRT = Gibbs_nRT + m_neus @ zeta_nca @ np.transpose(m_cats_anis) + if mu_nnn.size > 0: + Gibbs_nRT = Gibbs_nRT + m_neus**3 @ mu_nnn + return Gibbs_nRT[0][0] diff --git a/pytzer/meta.py b/pytzer/meta.py index dc8d6a01..f0ca589b 100644 --- a/pytzer/meta.py +++ b/pytzer/meta.py @@ -1,9 +1,9 @@ # Pytzer: Pitzer model for chemical activities in aqueous solutions. -# Copyright (C) 2019--2021 Matthew P. Humphreys (GNU GPLv3) -"""Define package metadata.""" +# Copyright (C) 2019--2023 Matthew P. Humphreys (GNU GPLv3) +"""Pytzer package metadata.""" import importlib -version = "0.5.2" +version = "0.5.3" author = "Matthew P. Humphreys and Abigail J. Schiller" @@ -18,7 +18,7 @@ def update_func_J(pytzer, func_J): def hello(): print( - """ + r""" ____ __ / __ \ __ __ / /_ ____ ___ _____ / /_/ // / / // __//_ / / _ \ / ___/ @@ -26,7 +26,7 @@ def hello(): / / \__, / \__/ /___/\___//_/ \/ /____/ - M.P. Humphreys & A.J. Schiller (2021) + M.P. Humphreys & A.J. Schiller (2023) v{version} | doi:{doi} """.format( version=version, doi="10.5281/zenodo.2637914" diff --git a/pytzer/model.py b/pytzer/model.py index 4b58e456..c9ea6f28 100644 --- a/pytzer/model.py +++ b/pytzer/model.py @@ -1,5 +1,5 @@ # Pytzer: Pitzer model for chemical activities in aqueous solutions. -# Copyright (C) 2019--2021 Matthew P. Humphreys (GNU GPLv3) +# Copyright (C) 2019--2023 Matthew P. Humphreys (GNU GPLv3) """Calculate solution properties using the Pitzer model.""" import itertools, jax from collections import OrderedDict @@ -10,20 +10,31 @@ def Gibbs_DH(Aphi, I): - """The Debye-Hueckel component of the excess Gibbs energy, - following CRP94 Eq. (AI1). + """The Debye-Hueckel component of the excess Gibbs energy following CRP94 eq. (AI1). + + Parameters + ---------- + Aphi : float + Debye-Hueckel limiting slope for the osmotic coefficient. + I : float + Ionic strength of the solution in mol/kg. + + Returns + ------- + float + Debye-Hueckel component of the excess Gibbs energy. """ return -4 * Aphi * I * np.log(1 + b * np.sqrt(I)) / b def g(x): """g function, following CRP94 Eq. (AI13).""" - return 2 * (1 - (1 + x) * np.exp(-x)) / x ** 2 + return 2 * (1 - (1 + x) * np.exp(-x)) / x**2 def h(x): """h function, following CRP94 Eq. (AI15).""" - return (6 - (6 + x * (6 + 3 * x + x ** 2)) * np.exp(-x)) / x ** 4 + return (6 - (6 + x * (6 + 3 * x + x**2)) * np.exp(-x)) / x**4 def B(sqrt_I, b0, b1, b2, alph1, alph2): @@ -51,7 +62,7 @@ def etheta(Aphi, I, z0, z1, func_J=unsymmetrical.Harvie): def ionic_strength(molalities, charges): """Ionic strength.""" - return 0.5 * np.sum(molalities * charges ** 2) + return 0.5 * np.sum(molalities * charges**2) def ionic_z(molalities, charges): @@ -62,6 +73,22 @@ def ionic_z(molalities, charges): func_J = unsymmetrical.Harvie +@jax.jit +def Gibbs_nRT_fori(solutes, params): + # Evaluate terms dependent on overall ionic strength + I = ( + np.sum( + np.array([m * convert.solute_to_charge[s] ** 2 for s, m in solutes.items()]) + ) + / 2 + ) + Z = np.sum( + np.abs(np.array([m * convert.solute_to_charge[s] for s, m in solutes.items()])) + ) + sqrt_I = np.sqrt(I) + Gibbs = Gibbs_DH(params["Aphi"], I) + + @jax.jit def Gibbs_nRT( solutes, diff --git a/pytzer/parameters.py b/pytzer/parameters/__init__.py similarity index 94% rename from pytzer/parameters.py rename to pytzer/parameters/__init__.py index b4726acc..bf7c8134 100644 --- a/pytzer/parameters.py +++ b/pytzer/parameters/__init__.py @@ -1,9 +1,58 @@ # Pytzer: Pitzer model for chemical activities in aqueous solutions. -# Copyright (C) 2019--2021 Matthew P. Humphreys (GNU GPLv3) +# Copyright (C) 2019--2023 Matthew P. Humphreys (GNU GPLv3) """Evaluate Pitzer model interaction parameters.""" from jax import numpy as np -from .constants import Tzero -from .convert import solute_to_charge as i2c +from ..constants import Tzero +from ..convert import solute_to_charge as i2c +from .heMorse1993 import ( + bC_Ca_CO3_HM93, + bC_Ca_HCO3_HM93, + bC_K_CO3_HM93, + bC_K_HCO3_HM93, + bC_Mg_CO3_HM93, + bC_Mg_HCO3_HM93, + bC_Na_CO3_HM93, + bC_Na_HCO3_HM93, + psi_Mg_Cl_SO4_HM93, + lambd_CO2_Ca_HM93, + lambd_CO2_Cl_HM93, + lambd_CO2_H_HM93, + lambd_CO2_K_HM93, + lambd_CO2_Mg_HM93, + lambd_CO2_Na_HM93, + lambd_CO2_SO4_HM93, + zeta_CO2_Ca_Cl_HM93, + zeta_CO2_H_Cl_HM93, + zeta_CO2_H_SO4_HM93, + zeta_CO2_K_Cl_HM93, + zeta_CO2_K_SO4_HM93, + zeta_CO2_Mg_Cl_HM93, + zeta_CO2_Mg_SO4_HM93, + zeta_CO2_Na_Cl_HM93, + zeta_CO2_Na_SO4_HM93, +) +from .holmesMesmer1992 import bC_H_HSO4_HM92, bC_H_SO4_HM92, theta_HSO4_SO4_HM92 +from .pabalanPitzer1987 import ( + theta_K_Na_PP87ii, + theta_Mg_Na_PP87ii, + theta_K_Mg_PP87ii, + theta_Cl_SO4_PP87ii, + theta_Cl_OH_PP87ii, + theta_OH_SO4_PP87ii, + psi_K_Na_Cl_PP87ii, + psi_Mg_Na_Cl_PP87ii, + psi_K_Mg_Cl_PP87ii, + psi_Na_Cl_SO4_PP87ii, + psi_K_Cl_SO4_PP87ii, + psi_Mg_Cl_SO4_PP87ii, + psi_Na_Cl_OH_PP87ii, + psi_Na_OH_SO4_PP87ii, +) +from .spencer1990 import ( + bC_Mg_Cl_SMW90, + bC_Mg_SO4_SMW90, + psi_Mg_Cl_SO4_SMW90, +) # Tolerances for np.isclose() assessment of temperature/pressure validity temperature_tol = dict(atol=1e-8, rtol=0) # K @@ -3905,6 +3954,7 @@ def bC_La_Cl_SP78(T, P): # bC_Znjj_SO4_SP78: no corresponding PM73 function # bC_Cdjj_SO4_SP78: no corresponding PM73 function + # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Roy et al. (1980) ~~~~~ def theta_H_Mg_RGB80(T, P): """c-c': hydrogen magnesium [RGB80].""" @@ -4058,10 +4108,10 @@ def psi_Na_CO3_Cl_TM82(T, P): def bC_Mg_Cl_dLP83(T, P): """c-a: magnesium chloride [dLP83].""" # dLP83 Eq. (11) - b0 = 5.93915e-7 * T ** 2 - 9.31654e-4 * T + 0.576066 - b1 = 2.60169e-5 * T ** 2 - 1.09438e-2 * T + 2.60135 + b0 = 5.93915e-7 * T**2 - 9.31654e-4 * T + 0.576066 + b1 = 2.60169e-5 * T**2 - 1.09438e-2 * T + 2.60135 b2 = 0 - Cphi = 3.01823e-7 * T ** 2 - 2.89125e-4 * T + 6.57867e-2 + Cphi = 3.01823e-7 * T**2 - 2.89125e-4 * T + 6.57867e-2 C0 = Cphi / (2 * np.sqrt(np.abs(i2c["Mg"] * i2c["Cl"]))) C1 = 0 alph1 = 2 @@ -4080,7 +4130,7 @@ def HM83_eq25(T, a): + a[1] * (1 / T - 1 / TR) + a[2] * np.log(T / TR) + a[3] * (T - TR) - + a[4] * (T ** 2 - TR ** 2) + + a[4] * (T**2 - TR**2) + a[5] * np.log(T - 260) ) @@ -4979,7 +5029,7 @@ def theta_Cl_HCO3_HMW84(T, P): def psi_Na_Cl_HCO3_HMW84(T, P): """c-a-a': sodium chloride bicarbonate [HMW84].""" - psi = -0.15 + psi = -0.015 valid = np.isclose(T, 298.15, **temperature_tol) return psi, valid @@ -6626,12 +6676,12 @@ def PP86ii_eq28(T, q): """PP86ii equation 28.""" Tr = PP86ii_Tr return ( - (T ** 2 - Tr ** 2) * q[0] / 2 - + (T ** 3 - Tr ** 3) * q[1] / 3 - + (T ** 4 - Tr ** 4) * q[2] / 4 - + (T ** 5 - Tr ** 5) * q[3] / 5 - + Tr ** 2 * q[4] - ) / T ** 2 + (T**2 - Tr**2) * q[0] / 2 + + (T**3 - Tr**3) * q[1] / 3 + + (T**4 - Tr**4) * q[2] / 4 + + (T**5 - Tr**5) * q[3] / 5 + + Tr**2 * q[4] + ) / T**2 def PP86ii_eq29(T, q): @@ -6649,11 +6699,11 @@ def PP86ii_eq29(T, q): # Original fourth line was: # + q[3] * (T**4/20 + Tr**5/(5*T) - Tr**4/4) return ( - q[0] * (T / 2 + Tr ** 2 / (2 * T) - Tr) - + q[1] * (T ** 2 / 6 + Tr ** 3 / (3 * T) - Tr ** 2 / 2) - + q[2] * (T ** 3 / 12 + Tr ** 4 / (4 * T) - Tr ** 3 / 3) - + q[3] * (t ** 5 + 4 - 5 * t) * Tr ** 5 / (20 * T) - + q[4] * (Tr - Tr ** 2 / T) + q[0] * (T / 2 + Tr**2 / (2 * T) - Tr) + + q[1] * (T**2 / 6 + Tr**3 / (3 * T) - Tr**2 / 2) + + q[2] * (T**3 / 12 + Tr**4 / (4 * T) - Tr**3 / 3) + + q[3] * (t**5 + 4 - 5 * t) * Tr**5 / (20 * T) + + q[4] * (Tr - Tr**2 / T) + q[5] ) @@ -6718,12 +6768,12 @@ def HM86_eq8(T, a): # Typo in a[5] term in HM86 has been corrected here return ( a[0] - + a[1] * (TR - TR ** 2 / T) - + a[2] * (T ** 2 + 2 * TR ** 3 / T - 3 * TR ** 2) - + a[3] * (T + TR ** 2 / T - 2 * TR) + + a[1] * (TR - TR**2 / T) + + a[2] * (T**2 + 2 * TR**3 / T - 3 * TR**2) + + a[3] * (T + TR**2 / T - 2 * TR) + a[4] * (np.log(T / TR) + TR / T - 1) - + a[5] * (1 / (T - 263) + (263 * T - TR ** 2) / (T * (TR - 263) ** 2)) - + a[6] * (1 / (680 - T) + (TR ** 2 - 680 * T) / (T * (680 - TR) ** 2)) + + a[5] * (1 / (T - 263) + (263 * T - TR**2) / (T * (TR - 263) ** 2)) + + a[6] * (1 / (680 - T) + (TR**2 - 680 * T) / (T * (680 - TR) ** 2)) ) @@ -6843,7 +6893,7 @@ def theta_H_Sr_RGRG86(T, P): def psi_H_Sr_Cl_RGRG86(T, P): """c-c'-a: hydrogen strontium chloride [RGRG86].""" - psi = 0.0054 + (T - 298.15) * 0.00021 + psi = 0.0054 - (T - 298.15) * 0.00021 valid = (T >= 278.15) & (T <= 318.15) return psi, valid @@ -6863,8 +6913,8 @@ def PP87i_eqNaOH(T, P, a): + a[4] * np.log(T) + a[5] * T + a[6] * T * P - + a[7] * T ** 2 - + a[8] * T ** 2 * P + + a[7] * T**2 + + a[8] * T**2 * P + a[9] / (T - 227) + a[10] / (647 - T) + a[11] * P / (647 - T) @@ -6941,125 +6991,12 @@ def bC_Na_OH_PP87i(T, P): def bC_Mg_Cl_PP87i(T, P): """c-a: magnesium chloride [PP87i].""" b0, b1, b2, _, C1, alph1, alph2, omega, _ = bC_Mg_Cl_dLP83(T, P) - Cphi = 2.41831e-7 * T ** 2 - 2.49949e-4 * T + 5.95320e-2 + Cphi = 2.41831e-7 * T**2 - 2.49949e-4 * T + 5.95320e-2 C0 = Cphi / (2 * np.sqrt(np.abs(i2c["Mg"] * i2c["Cl"]))) valid = (T >= 298.15) & (T <= 473.15) return b0, b1, b2, C0, C1, alph1, alph2, omega, valid -# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Pabalan and Pitzer (1987ii) ~~~~~ -def theta_K_Na_PP87ii(T, P): - """c-c': potassium sodium [PP87ii].""" - theta = -0.012 - # Validity range declared by MP98 for theta(Na, Mg) from this study - valid = (T >= 298.15) & (T <= 523.25) - return theta, valid - - -def theta_Mg_Na_PP87ii(T, P): - """c-c': magnesium sodium [PP87ii].""" - theta = 0.07 - # Validity range declared by MP98 for theta(Na, Mg) from this study - valid = (T >= 298.15) & (T <= 523.25) - return theta, valid - - -def theta_K_Mg_PP87ii(T, P): - """c-c': potassium magnesium [PP87ii].""" - theta = 0 - # Validity range declared by MP98 for theta(Na, Mg) from this study - valid = (T >= 298.15) & (T <= 523.25) - return theta, valid - - -def theta_Cl_SO4_PP87ii(T, P): - """a-a': chloride sulfate [PP87ii].""" - theta = 0.030 - # Validity range declared by MP98 for theta(Na, Mg) from this study - valid = (T >= 298.15) & (T <= 523.25) - return theta, valid - - -def theta_Cl_OH_PP87ii(T, P): - """a-a': chloride hydroxide [PP87ii].""" - theta = -0.050 - # Validity range declared by MP98 for theta(Na, Mg) from this study - valid = (T >= 298.15) & (T <= 523.25) - return theta, valid - - -def theta_OH_SO4_PP87ii(T, P): - """a-a': hydroxide sulfate [PP87ii].""" - theta = -0.013 - # Validity range declared by MP98 for theta(Na, Mg) from this study - valid = (T >= 298.15) & (T <= 523.25) - return theta, valid - - -def psi_K_Na_Cl_PP87ii(T, P): - """c-c'-a: potassium sodium chloride [PP87ii].""" - psi = -6.81e-3 + 1.68e-5 * T - # Validity range declared by MP98 for theta(Na, Mg) from this study - valid = (T >= 298.15) & (T <= 523.25) - return psi, valid - - -def psi_Mg_Na_Cl_PP87ii(T, P): - """c-c'-a: magnesium sodium chloride [PP87ii].""" - psi = 1.99e-2 - 9.51 / T - # Validity range declared by MP98 for theta(Na, Mg) from this study - valid = (T >= 298.15) & (T <= 523.25) - return psi, valid - - -def psi_K_Mg_Cl_PP87ii(T, P): - """c-c'-a: potassium magnesium chloride [PP87ii].""" - psi = 2.586e-2 - 14.27 / T - # Validity range declared by MP98 for theta(Na, Mg) from this study - valid = (T >= 298.15) & (T <= 523.25) - return psi, valid - - -def psi_Na_Cl_SO4_PP87ii(T, P): - """c-a-a': sodium chloride sulfate [PP87ii].""" - psi = 0 - # Validity range declared by MP98 for theta(Na, Mg) from this study - valid = (T >= 298.15) & (T <= 523.25) - return psi, valid - - -def psi_K_Cl_SO4_PP87ii(T, P): - """c-a-a': potassium chloride sulfate [PP87ii].""" - psi = -5e-3 - # Validity range declared by MP98 for theta(Na, Mg) from this study - valid = (T >= 298.15) & (T <= 523.25) - return psi, valid - - -def psi_Mg_Cl_SO4_PP87ii(T, P): - """c-a-a': magnesium chloride sulfate [PP87ii].""" - psi = -1.174e-1 + 32.63 / T - # Validity range declared by MP98 for theta(Na, Mg) from this study - valid = (T >= 298.15) & (T <= 523.25) - return psi, valid - - -def psi_Na_Cl_OH_PP87ii(T, P): - """c-a-a': sodium chloride hydroxide [PP87ii].""" - psi = 2.73e-2 - 9.93 / T - # Validity range declared by MP98 for theta(Na, Mg) from this study - valid = (T >= 298.15) & (T <= 523.25) - return psi, valid - - -def psi_Na_OH_SO4_PP87ii(T, P): - """c-a-a': sodium hydroxide sulfate [PP87ii].""" - psi = 3.02e-2 - 11.69 / T - # Validity range declared by MP98 for theta(Na, Mg) from this study - valid = (T >= 298.15) & (T <= 523.25) - return psi, valid - - # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Simonson, Roy & Gibbons (1987) ~~~~~ def bC_K_CO3_SRG87(T, P): """c-a: potassium carbonate [SRG87].""" @@ -7228,7 +7165,7 @@ def bC_Na_BOH4_SRRJ87(T, P): T, [ 14.98, - -15.7, + -15.7, # TODO check this term 0, ], ) @@ -7410,7 +7347,7 @@ def M88_eq13(T, a): + a[2] / T + a[3] * np.log(T) + a[4] / (T - 263) - + a[5] * T ** 2 + + a[5] * T**2 + a[6] / (680 - T) + a[7] / (T - 227) ) @@ -7655,7 +7592,7 @@ def psi_Na_Cl_SO4_M88(T, P): # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Clegg & Brimblecombe (1989) ~~~~~ def lambd_NH3_NH3_CB89(T, P): """n-n: ammonia ammonia [CB89].""" - lambd = 0.033161 - 21.12816 / T + 4665.1461 / T ** 2 + lambd = 0.033161 - 21.12816 / T + 4665.1461 / T**2 valid = (T >= 273.15) & (T <= 313.15) return lambd, valid @@ -8324,28 +8261,28 @@ def A92ii_eq36(T, P, a): # a[5] and a[6] multipliers are corrected for typos in A92ii return ( a[0] - + a[1] * 10 ** -3 * T - + a[2] * 4e-6 * T ** 2 + + a[1] * 10**-3 * T + + a[2] * 4e-6 * T**2 + a[3] * 1 / (T - 200) + a[4] * 1 / T + a[5] * 100 / (T - 200) ** 2 - + a[6] * 200 / T ** 2 - + a[7] * 8e-9 * T ** 3 + + a[6] * 200 / T**2 + + a[7] * 8e-9 * T**3 + a[8] * 1 / (650 - T) ** 0.5 - + a[9] * 10 ** -5 * P + + a[9] * 10**-5 * P + a[10] * 2e-4 * P / (T - 225) + a[11] * 100 * P / (650 - T) ** 3 + a[12] * 2e-8 * P * T + a[13] * 2e-4 * P / (650 - T) - + a[14] * 10 ** -7 * P ** 2 - + a[15] * 2e-6 * P ** 2 / (T - 225) - + a[16] * P ** 2 / (650 - T) ** 3 - + a[17] * 2e-10 * P ** 2 * T - + a[18] * 4e-13 * P ** 2 * T ** 2 + + a[14] * 10**-7 * P**2 + + a[15] * 2e-6 * P**2 / (T - 225) + + a[16] * P**2 / (650 - T) ** 3 + + a[17] * 2e-10 * P**2 * T + + a[18] * 4e-13 * P**2 * T**2 + a[19] * 0.04 * P / (T - 225) ** 2 - + a[20] * 4e-11 * P * T ** 2 - + a[21] * 2e-8 * P ** 3 / (T - 225) - + a[22] * 0.01 * P ** 3 / (650 - T) ** 3 + + a[20] * 4e-11 * P * T**2 + + a[21] * 2e-8 * P**3 / (T - 225) + + a[22] * 0.01 * P**3 / (650 - T) ** 3 + a[23] * 200 / (650 - T) ** 3 ) @@ -8570,275 +8507,6 @@ def psi_H_Na_Cl_CMR93(T, P): return psi, valid -# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ He & Morse (1993) ~~~~~ -# Note that HM93 also contains beta/C equations for Na, K, Mg and Ca -# interactions with HCO3 and CO3 (not yet coded here) -def HM93_eq(T, A, B, C, D, E): - """HM93 parameter equation from p. 3548.""" - return A + B * T + C * T ** 2 + D / T + E * np.log(T) - - -def lambd_CO2_H_HM93(T, P): - """n-c: carbon-dioxide hydrogen [HM93].""" - lambd = 0 - valid = (T >= 273.15) & (T <= 363.15) - return lambd, valid - - -def lambd_CO2_Na_HM93(T, P): - """n-c: carbon-dioxide sodium [HM93].""" - lambd = HM93_eq( - T, - -5496.38465, - -3.326566, - 0.0017532, - 109399.341, - 1047.021567, - ) - valid = (T >= 273.15) & (T <= 363.15) - return lambd, valid - - -def lambd_CO2_K_HM93(T, P): - """n-c: carbon-dioxide potassium [HM93].""" - lambd = HM93_eq( - T, - 2856.528099, - 1.7670079, - -0.0009487, - -55954.1929, - -546.074467, - ) - valid = (T >= 273.15) & (T <= 363.15) - return lambd, valid - - -def lambd_CO2_Ca_HM93(T, P): - """n-c: carbon-dioxide calcium [HM93].""" - lambd = HM93_eq( - T, - -12774.6472, - -8.101555, - 0.00442472, - 245541.5435, - 2452.509720, - ) - valid = (T >= 273.15) & (T <= 363.15) - return lambd, valid - - -def lambd_CO2_Mg_HM93(T, P): - """n-c: carbon-dioxide magnesium [HM93].""" - lambd = HM93_eq( - T, - -479.362533, - -0.541843, - 0.00038812, - 3589.474052, - 104.3452732, - ) - valid = (T >= 273.15) & (T <= 363.15) - return lambd, valid - - -def lambd_CO2_Cl_HM93(T, P): - """n-a: carbon-dioxide chloride [HM93].""" - lambd = HM93_eq(T, 1659.944942, 0.9964326, -0.00052122, -33159.6177, -315.827883) - valid = (T >= 273.15) & (T <= 363.15) - return lambd, valid - - -def lambd_CO2_SO4_HM93(T, P): - """n-a: carbon-dioxide sulfate [HM93].""" - lambd = HM93_eq( - T, - 2274.656591, - 1.8270948, - -0.00114272, - -33927.7625, - -457.015738, - ) - valid = (T >= 273.15) & (T <= 363.15) - return lambd, valid - - -def zeta_CO2_H_Cl_HM93(T, P): - """n-c-a: carbon-dioxide hydrogen chloride [HM93].""" - zeta = HM93_eq(T, -804.121738, -0.470474, 0.000240526, 16334.38917, 152.3838752) - valid = (T >= 273.15) & (T <= 363.15) - return zeta, valid - - -def zeta_CO2_Na_Cl_HM93(T, P): - """n-c-a: carbon-dioxide sodium chloride [HM93].""" - zeta = HM93_eq(T, -379.459185, -0.258005, 0.000147823, 6879.030871, 73.74511574) - valid = (T >= 273.15) & (T <= 363.15) - return zeta, valid - - -def zeta_CO2_K_Cl_HM93(T, P): - """n-c-a: carbon-dioxide potassium chloride [HM93].""" - zeta = HM93_eq(T, -379.686097, -0.257891, 0.000147333, 6853.264129, 73.79977116) - valid = (T >= 273.15) & (T <= 363.15) - return zeta, valid - - -def zeta_CO2_Ca_Cl_HM93(T, P): - """n-c-a: carbon-dioxide calcium chloride [HM93].""" - zeta = HM93_eq(T, -166.065290, -0.018002, -2.47349e-5, 5256.844332, 27.377452415) - valid = (T >= 273.15) & (T <= 363.15) - return zeta, valid - - -def zeta_CO2_Mg_Cl_HM93(T, P): - """n-c-a: carbon-dioxide magnesium chloride [HM93].""" - zeta = HM93_eq(T, -1342.60256, -0.772286, 0.000391603, 27726.80974, 253.62319406) - valid = (T >= 273.15) & (T <= 363.15) - return zeta, valid - - -def zeta_CO2_H_SO4_HM93(T, P): - """n-c-a: carbon-dioxide hydrogen sulfate [HM93].""" - zeta = 0 - valid = (T >= 273.15) & (T <= 363.15) - return zeta, valid - - -def zeta_CO2_Na_SO4_HM93(T, P): - """n-c-a: carbon-dioxide sodium sulfate [HM93].""" - zeta = HM93_eq(T, 67030.02482, 37.930519, -0.01894730, -1399082.37, -12630.27457) - valid = (T >= 273.15) & (T <= 363.15) - return zeta, valid - - -def zeta_CO2_K_SO4_HM93(T, P): - """n-c-a: carbon-dioxide potassium sulfate [HM93].""" - zeta = HM93_eq(T, -2907.03326, -2.860763, 0.001951086, 30756.86749, 611.37560512) - valid = (T >= 273.15) & (T <= 363.15) - return zeta, valid - - -def zeta_CO2_Mg_SO4_HM93(T, P): - """n-c-a: carbon-dioxide magnesium sulfate [HM93].""" - zeta = HM93_eq(T, -7374.24392, -4.608331, 0.002489207, 143162.6076, 1412.302898) - valid = (T >= 273.15) & (T <= 363.15) - return zeta, valid - - -def bC_Na_HCO3_HM93(T, P): - """c-a: sodium bicarbonate [HM93].""" - b0 = HM93_eq(T, -37.2624193, -0.01445932, 0, 682.885977, 6.8995857) - b1 = HM93_eq(T, -61.4635193, -0.02446734, 0, 1129.389146, 11.4108589) - b2 = 0 - C0 = 0 - C1 = 0 - alph1 = 2 - alph2 = -9 - omega = -9 - valid = (T >= 273.15) & (T <= 363.15) - return b0, b1, b2, C0, C1, alph1, alph2, omega, valid - - -def bC_K_HCO3_HM93(T, P): - """c-a: potassium bicarbonate [HM93].""" - b0 = HM93_eq(T, -0.3088232, 0.001, 0, -0.00069869, -4.701488e-6) - b1 = HM93_eq(T, -0.2802, 0.00109999, 0, 0.000936932, 6.15660566e-6) - b2 = 0 - C0 = 0 - C1 = 0 - alph1 = 2 - alph2 = -9 - omega = -9 - valid = (T >= 273.15) & (T <= 363.15) - return b0, b1, b2, C0, C1, alph1, alph2, omega, valid - - -def bC_Mg_HCO3_HM93(T, P): - """c-a: magnesium bicarbonate [HM93].""" - b0 = HM93_eq(T, 13697.10, 8.250840, -0.00434, -273406.1716, -2607.115202) - b1 = HM93_eq(T, -157839.8351, -92.7779354, 0.0477642, 3203209.6948, 29927.151503) - b2 = 0 - C0 = 0 - C1 = 0 - alph1 = 2 - alph2 = -9 - omega = -9 - valid = (T >= 273.15) & (T <= 363.15) - return b0, b1, b2, C0, C1, alph1, alph2, omega, valid - - -def bC_Ca_HCO3_HM93(T, P): - """c-a: calcium bicarbonate [HM93].""" - b0 = HM93_eq(T, 29576.53405, 18.447305, -0.009989, -576520.5185, -5661.1237) - b1 = HM93_eq(T, -1028.8510522, -0.3725876718, 8.9691e-5, 26492.240303, 183.13155672) - b2 = 0 - C0 = 0 - C1 = 0 - alph1 = 2 - alph2 = -9 - omega = -9 - valid = (T >= 273.15) & (T <= 363.15) - return b0, b1, b2, C0, C1, alph1, alph2, omega, valid - - -def bC_Na_CO3_HM93(T, P): - """c-a: sodium carbonate [HM93].""" - b0 = HM93_eq(T, -60.5387702, -0.023301655, 0, 1108.3760518, 11.19855531) - b1 = HM93_eq(T, -237.5156616, -0.09989121, 0, 4412.511973, 44.5820703) - b2 = 0 - Cphi = 0.0052 - C0 = Cphi / (2 * np.sqrt(np.abs(i2c["Na"] * i2c["CO3"]))) - C1 = 0 - alph1 = 2 - alph2 = -9 - omega = -9 - valid = (T >= 273.15) & (T <= 363.15) - return b0, b1, b2, C0, C1, alph1, alph2, omega, valid - - -def bC_K_CO3_HM93(T, P): - """c-a: potassium carbonate [HM93].""" - b0 = HM93_eq(T, -0.1991649, 0.00110, 0, 1.8063362e-5, 0) - b1 = HM93_eq(T, 0.1330579, 0.00436, 0, 0.0011899, 0) - b2 = 0 - Cphi = 0.0005 - C0 = Cphi / (2 * np.sqrt(np.abs(i2c["K"] * i2c["CO3"]))) - C1 = 0 - alph1 = 2 - alph2 = -9 - omega = -9 - valid = (T >= 273.15) & (T <= 363.15) - return b0, b1, b2, C0, C1, alph1, alph2, omega, valid - - -def bC_Mg_CO3_HM93(T, P): - """c-a: magnesium carbonate [HM93].""" - b0 = 0 - b1 = 0 - b2 = 0 - C0 = 0 - C1 = 0 - alph1 = -9 - alph2 = -9 - omega = -9 - valid = (T >= 273.15) & (T <= 363.15) - return b0, b1, b2, C0, C1, alph1, alph2, omega, valid - - -def bC_Ca_CO3_HM93(T, P): - """c-a: calcium carbonate [HM93].""" - b0 = 0 - b1 = 0 - b2 = 0 - C0 = 0 - C1 = 0 - alph1 = -9 - alph2 = -9 - omega = -9 - valid = (T >= 273.15) & (T <= 363.15) - return b0, b1, b2, C0, C1, alph1, alph2, omega, valid - - # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Hovey et al. (1993) ~~~~~ def HPR93_eq36(T, a): """HPR93 equation 36.""" @@ -8916,38 +8584,38 @@ def bC_H_HSO4_CRP94(T, P): b0 = CRP94_eq24( T, [ - 0.227784933, - -3.78667718, - -0.124645729, - -0.00235747806, + 0.227_784_933, + -3.786_677_18, + -0.124_645_729, + -0.002_357_478_06, ], ) b1 = CRP94_eq24( T, [ - 0.372293409, + 0.372_293_409, 1.50, - 0.207494846, - 0.00448526492, + 0.207_494_846, + 0.004_485_264_92, ], ) b2 = 0 C0 = CRP94_eq24( T, [ - -0.00280032520, - 0.216200279, - 0.0101500824, - 0.000208682230, + -0.002_800_325_20, + 0.216_200_279, + 0.010_150_082_4, + 0.000_208_682_230, ], ) C1 = CRP94_eq24( T, [ -0.025, - 18.1728946, - 0.382383535, - 0.0025, + 18.172_894_6, + 0.382_383_535, + 0.002_5, ], ) alph1 = 2 @@ -9064,8 +8732,8 @@ def MP98_eq15(T, q): BLR = q[2] * 1e-4 return ( BR - + (BJ * (Tr ** 3 / 3) - Tr ** 2 * BLR) * (1 / T - 1 / Tr) - + (BJ / 6) * (T ** 2 - Tr ** 2) + + (BJ * (Tr**3 / 3) - Tr**2 * BLR) * (1 / T - 1 / Tr) + + (BJ / 6) * (T**2 - Tr**2) ) @@ -9128,7 +8796,7 @@ def bC_Na_Br_MP98(T, P): T, [ 0.00116, - 0.058 * 2 ** 1.5, + 0.058 * 2**1.5, -0.93, ], # more accurate following PM16 model ) @@ -9190,7 +8858,7 @@ def bC_K_Br_MP98(T, P): b1 = MP98_eq15( T, [ - 0.2122, + 0.2122, # 0.2212 in CWTD23 -0.762, 1.74, ], @@ -10879,7 +10547,7 @@ def ZD17_eq8(T, P, b): + b[3] / (T - 215) + b[4] * 1e4 / (T - 215) ** 3 + b[5] * 1e2 / (T - 215) ** 2 - + b[6] * 2e2 / T ** 2 + + b[6] * 2e2 / T**2 + b[7] * (T / 500) ** 3 + b[8] / (650 - T) ** 0.5 + b[9] * 1e-5 * P @@ -10887,15 +10555,15 @@ def ZD17_eq8(T, P, b): + b[11] * 1e2 * P / (650 - T) ** 3 + b[12] * 1e-5 * P * T / 500 + b[13] * 2e-4 * P / (650 - T) - + b[14] * 1e-7 * P ** 2 - + b[15] * 2e-6 * P ** 2 / (T - 225) - + b[16] * P ** 2 / (650 - T) ** 3 - + b[17] * 1e-7 * P ** 2 * T / 500 - + b[18] * 1e-7 * P ** 2 * (T / 500) ** 2 + + b[14] * 1e-7 * P**2 + + b[15] * 2e-6 * P**2 / (T - 225) + + b[16] * P**2 / (650 - T) ** 3 + + b[17] * 1e-7 * P**2 * T / 500 + + b[18] * 1e-7 * P**2 * (T / 500) ** 2 + b[19] * 4e-2 * P / (T - 225) ** 2 + b[20] * 1e-5 * P * (T / 500) ** 2 - + b[21] * 2e-8 * P ** 3 / (T - 225) - + b[22] * 1e-2 * P ** 3 / (650 - T) ** 3 + + b[21] * 2e-8 * P**3 / (T - 225) + + b[22] * 1e-2 * P**3 / (650 - T) ** 3 + b[23] * 2e2 / (650 - T) ** 3 ) @@ -11083,9 +10751,9 @@ def mu_tris_tris_tris_MarChemSpec25(T, P): return mu, valid -# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Clegg et al. (2021) ~~~~~ -def bC_trisH_Cl_CHW21(T, P): - """c-a: trisH+ chloride [CHW21].""" +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Clegg et al. (2022) ~~~~~ +def bC_trisH_Cl_CHW22(T, P): + """c-a: trisH+ chloride [CHW22].""" b0 = 0.03468 b1 = 0.12802 b2 = 0 @@ -11098,8 +10766,8 @@ def bC_trisH_Cl_CHW21(T, P): return b0, b1, b2, C0, C1, alph1, alph2, omega, valid -def bC_trisH_SO4_CHW21(T, P): - """c-a: trisH+ sulfate [CHW21].""" +def bC_trisH_SO4_CHW22(T, P): + """c-a: trisH+ sulfate [CHW22].""" b0 = 9.52294e-2 b1 = 0.585908 b2 = 0 @@ -11112,29 +10780,29 @@ def bC_trisH_SO4_CHW21(T, P): return b0, b1, b2, C0, C1, alph1, alph2, omega, valid -def lambd_tris_Ca_CHW21(T, P): - """n-c: tris calcium [CHW21].""" +def lambd_tris_Ca_CHW22(T, P): + """n-c: tris calcium [CHW22].""" lambd = -0.2686 valid = np.isclose(T, 298.15, **temperature_tol) return lambd, valid -def lambd_tris_K_CHW21(T, P): - """n-c: tris potassium [CHW21].""" +def lambd_tris_K_CHW22(T, P): + """n-c: tris potassium [CHW22].""" lambd = 0.03394 valid = np.isclose(T, 298.15, **temperature_tol) return lambd, valid -def lambd_tris_Mg_CHW21(T, P): - """n-c: tris magnesium [CHW21].""" +def lambd_tris_Mg_CHW22(T, P): + """n-c: tris magnesium [CHW22].""" lambd = -0.1176 valid = np.isclose(T, 298.15, **temperature_tol) return lambd, valid -def lambd_tris_Na_CHW21(T, P): - """n-c: tris sodium [CHW21].""" +def lambd_tris_Na_CHW22(T, P): + """n-c: tris sodium [CHW22].""" lambd = 0.02632 valid = np.isclose(T, 298.15, **temperature_tol) return lambd, valid @@ -12132,3 +11800,525 @@ def psi_K_Mg_Cl_A15(T, P): psi = -0.022 - 14.27 * (1 / T - 1 / 298.15) valid = (273.15 <= T) & (T <= 473.15) return psi, valid + + +def theta_H_Na_HCW22(T, P): + """c-c': hydrogen sodium [HCW22].""" + theta = 0.0306 - 0.000418 * (T - 298.15) + valid = (T >= 278.15) & (T <= 318.15) + return theta, valid + + +def HWT22_eqS5_7(T, q): + return ( + q[0] + + q[1] / T + + q[2] * np.log(T) + + q[3] * T + + q[4] * T**2 + + q[5] / (T - 227) + + q[6] / (647 - T) + ) + + +def bC_Na_OH_HWT22(T, P): + """c-a: sodium hydroxide [HWT22].""" + # This is PP87i but with P set to 1 bar and then the coefficients rounded off + b0 = HWT22_eqS5_7( + T, + [ + 2.76821967e2, + -7.37517417e3, + -4.93599700e1, + 1.09458239e-1, + -4.02243907e-5, + 1.19311220e1, + 2.47767456, + ], + ) + b1 = HWT22_eqS5_7( + T, + [ + 4.62869770e2, + -1.02941810e4, + -8.59605810e1, + 2.39059690e-1, + -1.0795894e-4, + 0, + 0, + ], + ) + b2 = 0 + Cphi = HWT22_eqS5_7( + T, + [ + -1.66864917e1, + 4.53597896e2, + 2.96807720, + -6.51722200e-3, + 2.37747753e-6, + -6.89238990e-1, + -8.1156286e-2, + ], + ) + C0 = Cphi / (2 * np.sqrt(np.abs(i2c["Na"] * i2c["OH"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = np.isclose(P, 1, **pressure_tol) + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def theta_H_K_HWT22(T, P): + """c-c': hydrogen potassium [HWT22].""" + # assuming CMR93's lowercase t means temperature minus 298.15 K + theta = 0.005 - 0.0002275 * (T - 298.15) + valid = (T >= 273.15) & (T <= 328.15) + return theta, valid + + +def theta_H_Na_HWT22(T, P): + """c-c': hydrogen sodium [HWT22].""" + theta = 0.0306 - 4.18e-4 * (T - 298.15) + valid = (T >= 273.15) & (T <= 328.15) + return theta, valid + + +# Extras from CWTD23 + + +def bC_Ca_SO4_HEW82(T, P): + """c-a: calcium sulfate [HEW82].""" + # Values taken from CWTD23 (SI6) + b0 = 0.2 # HW80 is cited for beta0 only + b1 = 3.1973 + 0.0546 * (T - 298.15) + b2 = -54.24 - 0.516 * (T - 298.15) + C0 = 0 + C1 = 0 + alph1 = 1.4 + alph2 = 12.0 + omega = -9 + valid = np.isclose(P, 1, **pressure_tol) # unknown validity + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_CaF_Cl_PM16(T, P): + """c-a: calcium-fluoride chloride [PM16].""" + # Values taken from CWTD23 (SI6) + b0 = 0.14047 + b1 = 0.3022 + b2 = 0 + C0 = 0 + C1 = 0 + alph1 = 2.0 + alph2 = -9 + omega = -9 + valid = np.isclose(T, 298.15, **temperature_tol) # unknown validity + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_K_Br_CWTD23(T, P): + """c-a: potassium bromide [CWTD23].""" + b0 = MP98_eq15( + T, + [ + 0.0569, + -1.43, + 7.39, + ], + ) + # b1 = MP98_eq15( + # T, + # [ + # 0.2212, # 0.2122 in MP98 (my function, at least) + # -0.762, + # 1.74, + # ], + # ) + # TODO not sure why above is incorrect, equation below is from CWTD23 code + Tr = 298.15 + b1 = ( + 0.2212 + + (0.762e-5 * Tr**3 / 3 - 17.4e-4 * Tr**2) * (1 / T - 1 / Tr) + + (0.762e-5 / 6) * (T**2 - Tr**2) + ) + b2 = 0 + Cphi = MP98_eq15( + T, + [ + -0.0018, + 0.216, + -0.7004, + ], + ) + C0 = Cphi / (2 * np.sqrt(np.abs(i2c["K"] * i2c["Br"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = np.isclose(T, 298.15, **temperature_tol) # unknown validity + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_K_CO3_CWTD23(T, P): + """c-a: potassium carbonate [CWTD23].""" + b0 = 0.1288 + 1.1e-3 * (T - 298.15) - 5.1e-6 * (T - 298.15) ** 2 + b1 = 1.433 + 4.36e-3 * (T - 298.15) + 2.07e-5 * (T - 298.15) ** 2 + b2 = 0 + # CWTD23 declare Cphi = 0.0005, like MP98, but I can't find that anywhere in SRG87 + Cphi = 0.0005 + C0 = Cphi / (2 * np.sqrt(np.abs(i2c["K"] * i2c["CO3"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = np.isclose(T, 298.15, **temperature_tol) # unknown validity + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_K_F_CWTD23(T, P): + """c-a: potassium fluoride [CWTD23].""" + Tr = 298.15 + b0 = ( + 0.08089 + + (-1.39e-5 * Tr**3 / 3 - 2.14e-4 * Tr**2) * (1 / T - 1 / Tr) + - (1.39e-5 / 6) * (T**2 - Tr**2) + ) + b1 = 0.2021 - 5.44e-4 * Tr**2 * (1 / T - 1 / Tr) + b2 = 0 + C0 = 0.5 * (0.00093 + 0.595e-4 * Tr**2 * (1 / T - 1 / Tr)) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = np.isclose(T, 298.15, **temperature_tol) # unknown validity + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_K_HCO3_RGW84(T, P): + """c-a: potassium carbonate [RGW84].""" + # Values from CWTD23 SI6 + Tr = 298.15 + b0 = -0.0107 + 1.0e-3 * (T - Tr) + b1 = 0.0478 + 1.1e-3 * (T - Tr) + b2 = 0 + C0 = 0 + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = np.isclose(T, 298.15, **temperature_tol) # unknown validity + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_MgF_Cl_PM16(T, P): + """c-a: magnesium-fluoride chloride [PM16].""" + # Values taken from CWTD23 (SI6) + b0 = 0.2871 + b1 = 0.4538 + b2 = 0 + Cphi = -0.037 + C0 = Cphi / (2 * np.sqrt(np.abs(i2c["MgF"] * i2c["Cl"]))) + C1 = 0 + alph1 = 2.0 + alph2 = -9 + omega = -9 + valid = np.isclose(T, 298.15, **temperature_tol) # unknown validity + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Na_CO3_CWTD23a(T, P): + """c-a: sodium carbonate [CWTD23].""" + # Like MP98 but with corrections for errors there (see CWTD23's SI6) + # This version follows the SI6 table but it's different from the SI7 code + b0 = 0.0362 + 1.437193e-2 * (T - 298.15) - 2.11e-5 * (T - 298.15) ** 2 + b1 = 1.51 + 0.0521392 * (T - 298.15) - 8.4e-5 * (T - 298.15) ** 2 + b2 = 0 + Cphi = 0.0052 + C0 = Cphi / (2 * np.sqrt(np.abs(i2c["Na"] * i2c["CO3"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = np.isclose(T, 298.15, **temperature_tol) # unknown validity + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Na_CO3_CWTD23b(T, P): + """c-a: sodium carbonate [CWTD23].""" + # Like MP98 but with corrections for errors there (see CWTD23's SI6) + # This version follows the SI7 code but it's different from the SI6 table + Tr = 298.15 + b0 = ( + 0.0362 + + (T - Tr) * (1.79e-3 - Tr * (-4.22e-5)) + + 0.5 * (-4.22e-5) * (T**2 - Tr**2) + ) + b1 = ( + 1.51 + + (T - Tr) * (2.05e-3 - Tr * (-16.8e-5)) + + 0.5 * (-16.8e-5) * (T**2 - Tr**2) + ) + b2 = 0 + Cphi = 0.0052 + C0 = Cphi / (2 * np.sqrt(np.abs(i2c["Na"] * i2c["CO3"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = np.isclose(T, 298.15, **temperature_tol) # unknown validity + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Na_HCO3_CWTD23a(T, P): + """c-a: sodium bicarbonate [CWTD23].""" + # Like MP98 but with corrections for errors there (see CWTD23's SI6) + # This version follows the SI6 table but it's different from the SI7 code + b0 = 0.028 + 0.0087519 * (T - 298.15) - 1.3e-5 * (T - 298.15) ** 2 + b1 = 0.044 + 0.01392045 * (T - 298.15) - 2.15e-5 * (T - 298.15) ** 2 + b2 = 0 + C0 = 0 + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = np.isclose(T, 298.15, **temperature_tol) # unknown validity + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Na_HCO3_CWTD23b(T, P): + """c-a: sodium bicarbonate [CWTD23].""" + # Like MP98 but with corrections for errors there (see CWTD23's SI6) + # This version follows the SI7 code but it's different from the SI6 table + Tr = 298.15 + b0 = ( + 0.028 + + (T - Tr) * (0.001 - Tr * (-2.6e-5)) + + 0.5 * (-2.6e-5) * (T**2 - Tr**2) + ) + b1 = ( + 0.044 + + (T - Tr) * (0.0011 - Tr * (-4.3e-5)) + + 0.5 * (-4.3e-5) * (T**2 - Tr**2) + ) + b2 = 0 + C0 = 0 + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = np.isclose(T, 298.15, **temperature_tol) # unknown validity + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Na_F_CWTD23(T, P): + """c-a: sodium fluoride [CWTD23].""" + Tr = 298.15 + b0 = ( + 0.0215 + + (-2.37e-5 * Tr**3 / 3 - 5.361e-4 * Tr**2) * (1 / T - 1 / Tr) + + (-2.37e-5 / 6) * (T**2 - Tr**2) + ) + b1 = 0.2107 + (-8.7e-4 * Tr**2) * (1 / T - 1 / Tr) + b2 = 0 + C0 = 0 + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = np.isclose(T, 298.15, **temperature_tol) # unknown validity + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Na_HSO4_CWTD23(T, P): + """c-a: sodium bisulfate [CWTD23].""" + b0 = 0.02634 + 0.001324 * (T - 298.15) - 1.852e-5 * (T - 298.15) ** 2 + b1 = 0.9159 - 0.007161 * (T - 298.15) + b2 = 0 + C0 = 0 + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = np.isclose(T, 298.15, **temperature_tol) # unknown validity + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Sr_Cl_CWTD23(T, P): + """c-a: strontium chloride [CWTD23].""" + Tr = 298.15 + b0 = ( + 0.28575 + + (-0.18367e-5 * Tr**3 / 3 - 9.56e-4 * 0.75 * Tr**2) * (1 / T - 1 / Tr) + + (-0.18367e-5 / 6) * (T**2 - Tr**2) + ) + b1 = 1.66725 - 0.00379 * 0.75 * Tr**2 * (1 / T - 1 / Tr) + b2 = 0 + Cphi = -0.0013 + C0 = Cphi / (2 * np.sqrt(np.abs(i2c["Sr"] * i2c["Cl"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = np.isclose(T, 298.15, **temperature_tol) # unknown validity + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def theta_BOH4_Cl_CWTD23(T, P): + """a-a': borate chloride [CWTD23].""" + # Like the MP98 function but with one fewer digit on the -0.4233e-4 term + # CWTD23 cite 02P for this + theta = -0.0323 + (T - 298.15) * -0.4233e-4 + (T - 298.15) ** 2 * -21.926e-6 + valid = (T >= 273.15) & (T <= 318.15) + return theta, valid + + +def psi_Na_Cl_F_CWTD23(T, P): + """c-a-a': sodium chloride fluoride [CWTD23].""" + # From 88CB (not checked). Similar to MP98 but with an extra 3 at the end + psi = 0.00233 + valid = np.isclose(T, 298.15, **temperature_tol) + return psi, valid + + +def theta_Cl_OH_CWTD23(T, P): + """a-a': chloride hydroxide [CWTD23].""" + # 02P cited + theta = -0.05 + 0.0003125 * (T - 298.15) - 0.000008362 * (T - 298.15) ** 2 + valid = np.isclose(T, 298.15, **temperature_tol) # unknown + return theta, valid + + +def lambd_MgCO3_Na_CWTD23(T, P): + """n-c: magnesium-carbonate sodium [CWTD23].""" + # CWTD23 cite 83MT + lambd = 0.0745 + valid = np.isclose(T, 298.15, **temperature_tol) + return lambd, valid + + +def bC_Mg_HCO3_CWTD23(T, P): + """c-a: magnesium bicarbonate [CWTD23].""" + # Like POS85 but skipping the final digit (without rounding) + b0 = 0.03 + b1 = 0.8 + b2 = 0 + C0 = 0 + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = np.isclose(T, 298.15, **temperature_tol) + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Ca_HCO3_CWTD23(T, P): + """c-a: calcium bicarbonate [CWTD23].""" + # Like POS85 but skipping the final digit (without rounding) + b0 = 0.2 + b1 = 0.3 + b2 = 0 + C0 = 0 + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = np.isclose(T, 298.15, **temperature_tol) + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Na_Br_CWTD23(T, P): + """c-a: sodium bromide [CWTD23].""" + b0 = MP98_eq15( + T, + [ + 0.0973, + -1.3, + 7.692, + ], + ) + b1 = MP98_eq15( + T, + [ + 0.2791, + -1.06, + 10.79, + ], + ) + b2 = 0 + Cphi = MP98_eq15( + T, + [ + 0.00116, + 0.116, + -0.93, + ], + ) + C0 = Cphi / (2 * np.sqrt(np.abs(i2c["Na"] * i2c["Br"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = (T >= 273.15) & (T <= 323.15) + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Na_BOH4_CWTD23(T, P): + """c-a: sodium borate [CWTD23].""" + # Like SRRJ87 but with different C0, not sure why, TODO need to figure this out + b0 = SRRJ87_eq7( + T, + [ + -0.0510, + 5.264, + 0, + ], + ) + b1 = SRRJ87_eq7( + T, + [ + 0.0961, + -10.68, + 0, + ], + ) + b2 = 0 + Cphi = 14.98e-3 - 1.57e-3 * (T - 298.15) + C0 = Cphi / (2 * np.sqrt(np.abs(i2c["Na"] * i2c["BOH4"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = (T >= 278.15) & (T <= 328.15) + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_K_BOH4_CWTD23(T, P): + """c-a: potassium borate [CWTD23].""" + # TODO not sure why C0 doesn't match the paper + b0 = SRRJ87_eq7( + T, + [ + 0.1469, + 2.881, + 0, + ], + ) + b1 = SRRJ87_eq7( + T, + [ + -0.0989, + -6.876, + 0, + ], + ) + b2 = 0 + Cphi = -0.05643 - 9.56e-4 * (T - 298.15) + C0 = Cphi / (2 * np.sqrt(np.abs(i2c["K"] * i2c["BOH4"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = (T >= 278.15) & (T <= 328.15) + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid diff --git a/pytzer/parameters/heMorse1993.py b/pytzer/parameters/heMorse1993.py new file mode 100644 index 00000000..053a8b08 --- /dev/null +++ b/pytzer/parameters/heMorse1993.py @@ -0,0 +1,285 @@ +# Pytzer: Pitzer model for chemical activities in aqueous solutions. +# Copyright (C) 2019--2023 Matthew P. Humphreys (GNU GPLv3) +"""HM93: He & Morse (1993) Geochim. Cosmochim. Acta 57(15), 3533-3554. +https://doi.org/10.1016/0016-7037(93)90137-L +""" + +from jax import numpy as np +from ..convert import solute_to_charge as i2c +from .spencer1990 import psi_Mg_Cl_SO4_SMW90 +from .pabalanPitzer1987 import psi_Mg_Cl_SO4_PP87ii + + +def HM93_eq(T, A, B, C, D, E): + """HM93 parameter equation from p. 3548.""" + return A + B * T + C * T**2 + D / T + E * np.log(T) + + +def bC_Na_HCO3_HM93(T, P): + """c-a: sodium bicarbonate [HM93].""" + b0 = HM93_eq(T, -37.2624193, -0.01445932, 0, 682.885977, 6.8995857) + b1 = HM93_eq(T, -61.4635193, -0.02446734, 0, 1129.389146, 11.4108589) + b2 = 0 + C0 = 0 + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = (T >= 273.15) & (T <= 363.15) + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_K_HCO3_HM93(T, P): + """c-a: potassium bicarbonate [HM93].""" + b0 = HM93_eq(T, -0.3088232, 0.001, 0, -0.00069869, -4.701488e-6) + b1 = HM93_eq(T, -0.2802, 0.00109999, 0, 0.000936932, 6.15660566e-6) + b2 = 0 + C0 = 0 + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = (T >= 273.15) & (T <= 363.15) + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Mg_HCO3_HM93(T, P): + """c-a: magnesium bicarbonate [HM93].""" + b0 = HM93_eq(T, 13697.10, 8.250840, -0.00434, -273406.1716, -2607.115202) + b1 = HM93_eq(T, -157839.8351, -92.7779354, 0.0477642, 3203209.6948, 29927.151503) + b2 = 0 + C0 = 0 + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = (T >= 273.15) & (T <= 363.15) + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Ca_HCO3_HM93(T, P): + """c-a: calcium bicarbonate [HM93].""" + b0 = HM93_eq(T, 29576.53405, 18.447305, -0.009989, -576520.5185, -5661.1237) + b1 = HM93_eq(T, -1028.8510522, -0.3725876718, 8.9691e-5, 26492.240303, 183.13155672) + b2 = 0 + C0 = 0 + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = (T >= 273.15) & (T <= 363.15) + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Na_CO3_HM93(T, P): + """c-a: sodium carbonate [HM93].""" + b0 = HM93_eq(T, -60.5387702, -0.023301655, 0, 1108.3760518, 11.19855531) + b1 = HM93_eq(T, -237.5156616, -0.09989121, 0, 4412.511973, 44.5820703) + b2 = 0 + Cphi = 0.0052 + C0 = Cphi / (2 * np.sqrt(np.abs(i2c["Na"] * i2c["CO3"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = (T >= 273.15) & (T <= 363.15) + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_K_CO3_HM93(T, P): + """c-a: potassium carbonate [HM93].""" + b0 = HM93_eq(T, -0.1991649, 0.00110, 0, 1.8063362e-5, 0) + b1 = HM93_eq(T, 0.1330579, 0.00436, 0, 0.0011899, 0) + b2 = 0 + Cphi = 0.0005 + C0 = Cphi / (2 * np.sqrt(np.abs(i2c["K"] * i2c["CO3"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = (T >= 273.15) & (T <= 363.15) + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Mg_CO3_HM93(T, P): + """c-a: magnesium carbonate [HM93].""" + b0 = 0 + b1 = 0 + b2 = 0 + C0 = 0 + C1 = 0 + alph1 = -9 + alph2 = -9 + omega = -9 + valid = (T >= 273.15) & (T <= 363.15) + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Ca_CO3_HM93(T, P): + """c-a: calcium carbonate [HM93].""" + b0 = 0 + b1 = 0 + b2 = 0 + C0 = 0 + C1 = 0 + alph1 = -9 + alph2 = -9 + omega = -9 + valid = (T >= 273.15) & (T <= 363.15) + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def psi_Mg_Cl_SO4_HM93(T, P): + """c-a-a': magnesium chloride sulfate [HM93].""" + psi = np.where( + T < 298.15, psi_Mg_Cl_SO4_SMW90(T, P)[0], psi_Mg_Cl_SO4_PP87ii(T, P)[0] + ) + valid = (T > 273.15 - 54) & (T < 523.25) + return psi, valid + + +def lambd_CO2_H_HM93(T, P): + """n-c: carbon-dioxide hydrogen [HM93].""" + lambd = 0 + valid = (T >= 273.15) & (T <= 363.15) + return lambd, valid + + +def lambd_CO2_Na_HM93(T, P): + """n-c: carbon-dioxide sodium [HM93].""" + lambd = HM93_eq( + T, + -5496.38465, + -3.326566, + 0.0017532, + 109399.341, + 1047.021567, + ) + valid = (T >= 273.15) & (T <= 363.15) + return lambd, valid + + +def lambd_CO2_K_HM93(T, P): + """n-c: carbon-dioxide potassium [HM93].""" + lambd = HM93_eq( + T, + 2856.528099, + 1.7670079, + -0.0009487, + -55954.1929, + -546.074467, + ) + valid = (T >= 273.15) & (T <= 363.15) + return lambd, valid + + +def lambd_CO2_Ca_HM93(T, P): + """n-c: carbon-dioxide calcium [HM93].""" + lambd = HM93_eq( + T, + -12774.6472, + -8.101555, + 0.00442472, + 245541.5435, + 2452.509720, + ) + valid = (T >= 273.15) & (T <= 363.15) + return lambd, valid + + +def lambd_CO2_Mg_HM93(T, P): + """n-c: carbon-dioxide magnesium [HM93].""" + lambd = HM93_eq( + T, + -479.362533, + -0.541843, + 0.00038812, + 3589.474052, + 104.3452732, + ) + valid = (T >= 273.15) & (T <= 363.15) + return lambd, valid + + +def lambd_CO2_Cl_HM93(T, P): + """n-a: carbon-dioxide chloride [HM93].""" + lambd = HM93_eq(T, 1659.944942, 0.9964326, -0.00052122, -33159.6177, -315.827883) + valid = (T >= 273.15) & (T <= 363.15) + return lambd, valid + + +def lambd_CO2_SO4_HM93(T, P): + """n-a: carbon-dioxide sulfate [HM93].""" + lambd = HM93_eq( + T, + 2274.656591, + 1.8270948, + -0.00114272, + -33927.7625, + -457.015738, + ) + valid = (T >= 273.15) & (T <= 363.15) + return lambd, valid + + +def zeta_CO2_H_Cl_HM93(T, P): + """n-c-a: carbon-dioxide hydrogen chloride [HM93].""" + zeta = HM93_eq(T, -804.121738, -0.470474, 0.000240526, 16334.38917, 152.3838752) + valid = (T >= 273.15) & (T <= 363.15) + return zeta, valid + + +def zeta_CO2_Na_Cl_HM93(T, P): + """n-c-a: carbon-dioxide sodium chloride [HM93].""" + zeta = HM93_eq(T, -379.459185, -0.258005, 0.000147823, 6879.030871, 73.74511574) + valid = (T >= 273.15) & (T <= 363.15) + return zeta, valid + + +def zeta_CO2_K_Cl_HM93(T, P): + """n-c-a: carbon-dioxide potassium chloride [HM93].""" + zeta = HM93_eq(T, -379.686097, -0.257891, 0.000147333, 6853.264129, 73.79977116) + valid = (T >= 273.15) & (T <= 363.15) + return zeta, valid + + +def zeta_CO2_Ca_Cl_HM93(T, P): + """n-c-a: carbon-dioxide calcium chloride [HM93].""" + zeta = HM93_eq(T, -166.065290, -0.018002, -2.47349e-5, 5256.844332, 27.377452415) + valid = (T >= 273.15) & (T <= 363.15) + return zeta, valid + + +def zeta_CO2_Mg_Cl_HM93(T, P): + """n-c-a: carbon-dioxide magnesium chloride [HM93].""" + zeta = HM93_eq(T, -1342.60256, -0.772286, 0.000391603, 27726.80974, 253.62319406) + valid = (T >= 273.15) & (T <= 363.15) + return zeta, valid + + +def zeta_CO2_H_SO4_HM93(T, P): + """n-c-a: carbon-dioxide hydrogen sulfate [HM93].""" + zeta = 0 + valid = (T >= 273.15) & (T <= 363.15) + return zeta, valid + + +def zeta_CO2_Na_SO4_HM93(T, P): + """n-c-a: carbon-dioxide sodium sulfate [HM93].""" + zeta = HM93_eq(T, 67030.02482, 37.930519, -0.01894730, -1399082.37, -12630.27457) + valid = (T >= 273.15) & (T <= 363.15) + return zeta, valid + + +def zeta_CO2_K_SO4_HM93(T, P): + """n-c-a: carbon-dioxide potassium sulfate [HM93].""" + zeta = HM93_eq(T, -2907.03326, -2.860763, 0.001951086, 30756.86749, 611.37560512) + valid = (T >= 273.15) & (T <= 363.15) + return zeta, valid + + +def zeta_CO2_Mg_SO4_HM93(T, P): + """n-c-a: carbon-dioxide magnesium sulfate [HM93].""" + zeta = HM93_eq(T, -7374.24392, -4.608331, 0.002489207, 143162.6076, 1412.302898) + valid = (T >= 273.15) & (T <= 363.15) + return zeta, valid diff --git a/pytzer/parameters/holmes1987.py b/pytzer/parameters/holmes1987.py new file mode 100644 index 00000000..0e658907 --- /dev/null +++ b/pytzer/parameters/holmes1987.py @@ -0,0 +1,5 @@ +# Pytzer: Pitzer model for chemical activities in aqueous solutions. +# Copyright (C) 2019--2023 Matthew P. Humphreys (GNU GPLv3) +"""HBS87: Holmes et al. (1987) J. Chem. Thermodyn. 19(8), 863-890. +https://doi.org/10.1016/0021-9614(87)90033-4 +""" diff --git a/pytzer/parameters/holmesMesmer1992.py b/pytzer/parameters/holmesMesmer1992.py new file mode 100644 index 00000000..1dbdd558 --- /dev/null +++ b/pytzer/parameters/holmesMesmer1992.py @@ -0,0 +1,89 @@ +# Pytzer: Pitzer model for chemical activities in aqueous solutions. +# Copyright (C) 2019--2023 Matthew P. Humphreys (GNU GPLv3) +"""HM92: Holmes & Mesmer (1992) J. Chem. Thermodyn. 24(3), 317-328. +https://doi.org/10.1016/S0021-9614(05)80072-2 +""" + +from jax import numpy as np +from ..convert import solute_to_charge as i2c + + +def HM92_eq26(T, p): + Tn = T - 298.15 + return p[0] + p[1] * Tn + p[2] * Tn**2 + p[3] * Tn**3 + + +def bC_H_HSO4_HM92(T, P): + """c-a: hydrogen bisulfate [HM92].""" + b0 = HM92_eq26( + T, + [ + 0.2118, + -0.6157e-3, + 0.29193e-5, + -1.4153e-8, + ], + ) + b1 = HM92_eq26( + T, + [ + 0.4177, + 0, + -0.178e-5, + 0, + ], + ) + b2 = 0 + C0 = 0 + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = (T >= 298.15) & (T <= 473.15) + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_H_SO4_HM92(T, P): + """c-a: hydrogen sulfate [HM92].""" + b0 = HM92_eq26( + T, + [ + 0.0819, + -1.214e-3, + 0, + 7.63e-8, + ], + ) + b1 = 0 + b2 = 0 + Cphi = HM92_eq26( + T, + [ + 0.0637, + 0.353e-3, + -1.530e-5, + 5.27e-8, + ], + ) + C0 = Cphi / (2 * np.sqrt(np.abs(i2c["H"] * i2c["SO4"]))) + C1 = 0 + alph1 = -9 + alph2 = -9 + omega = -9 + valid = (T >= 298.15) & (T <= 473.15) + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def theta_HSO4_SO4_HM92(T, P): + """a-a': bisulfate sulfate [HM92].""" + theta = HM92_eq26( + T, + [ + -0.1756, + 3.146e-3, + -2.862e-5, + 6.786e-8, + ], + ) + valid = (T >= 298.15) & (T <= 473.15) + return theta, valid diff --git a/pytzer/parameters/pabalanPitzer1987.py b/pytzer/parameters/pabalanPitzer1987.py new file mode 100644 index 00000000..296418f7 --- /dev/null +++ b/pytzer/parameters/pabalanPitzer1987.py @@ -0,0 +1,117 @@ +# Pytzer: Pitzer model for chemical activities in aqueous solutions. +# Copyright (C) 2019--2023 Matthew P. Humphreys (GNU GPLv3) +"""PP87ii: Pabalan & Pitzer (1987) Geochim. Cosmochim. Acta 51(9), 2429-2443. +https://doi.org/10.1016/0016-7037(87)90295-X +""" + + +def theta_K_Na_PP87ii(T, P): + """c-c': potassium sodium [PP87ii].""" + theta = -0.012 + # Validity range declared by MP98 for theta(Na, Mg) from this study + valid = (T >= 298.15) & (T <= 523.25) + return theta, valid + + +def theta_Mg_Na_PP87ii(T, P): + """c-c': magnesium sodium [PP87ii].""" + theta = 0.07 + # Validity range declared by MP98 for theta(Na, Mg) from this study + valid = (T >= 298.15) & (T <= 523.25) + return theta, valid + + +def theta_K_Mg_PP87ii(T, P): + """c-c': potassium magnesium [PP87ii].""" + theta = 0 + # Validity range declared by MP98 for theta(Na, Mg) from this study + valid = (T >= 298.15) & (T <= 523.25) + return theta, valid + + +def theta_Cl_SO4_PP87ii(T, P): + """a-a': chloride sulfate [PP87ii].""" + theta = 0.030 + # Validity range declared by MP98 for theta(Na, Mg) from this study + valid = (T >= 298.15) & (T <= 523.25) + return theta, valid + + +def theta_Cl_OH_PP87ii(T, P): + """a-a': chloride hydroxide [PP87ii].""" + theta = -0.050 + # Validity range declared by MP98 for theta(Na, Mg) from this study + valid = (T >= 298.15) & (T <= 523.25) + return theta, valid + + +def theta_OH_SO4_PP87ii(T, P): + """a-a': hydroxide sulfate [PP87ii].""" + theta = -0.013 + # Validity range declared by MP98 for theta(Na, Mg) from this study + valid = (T >= 298.15) & (T <= 523.25) + return theta, valid + + +def psi_K_Na_Cl_PP87ii(T, P): + """c-c'-a: potassium sodium chloride [PP87ii].""" + psi = -6.81e-3 + 1.68e-5 * T + # Validity range declared by MP98 for theta(Na, Mg) from this study + valid = (T >= 298.15) & (T <= 523.25) + return psi, valid + + +def psi_Mg_Na_Cl_PP87ii(T, P): + """c-c'-a: magnesium sodium chloride [PP87ii].""" + psi = 1.99e-2 - 9.51 / T + # Validity range declared by MP98 for theta(Na, Mg) from this study + valid = (T >= 298.15) & (T <= 523.25) + return psi, valid + + +def psi_K_Mg_Cl_PP87ii(T, P): + """c-c'-a: potassium magnesium chloride [PP87ii].""" + psi = 2.586e-2 - 14.27 / T + # Validity range declared by MP98 for theta(Na, Mg) from this study + valid = (T >= 298.15) & (T <= 523.25) + return psi, valid + + +def psi_Na_Cl_SO4_PP87ii(T, P): + """c-a-a': sodium chloride sulfate [PP87ii].""" + psi = 0 + # Validity range declared by MP98 for theta(Na, Mg) from this study + valid = (T >= 298.15) & (T <= 523.25) + return psi, valid + + +def psi_K_Cl_SO4_PP87ii(T, P): + """c-a-a': potassium chloride sulfate [PP87ii].""" + psi = -5e-3 + # Validity range declared by MP98 for theta(Na, Mg) from this study + valid = (T >= 298.15) & (T <= 523.25) + return psi, valid + + +def psi_Mg_Cl_SO4_PP87ii(T, P): + """c-a-a': magnesium chloride sulfate [PP87ii].""" + psi = -1.174e-1 + 32.63 / T + # Validity range declared by MP98 for theta(Na, Mg) from this study + valid = (T >= 298.15) & (T <= 523.25) + return psi, valid + + +def psi_Na_Cl_OH_PP87ii(T, P): + """c-a-a': sodium chloride hydroxide [PP87ii].""" + psi = 2.73e-2 - 9.93 / T + # Validity range declared by MP98 for theta(Na, Mg) from this study + valid = (T >= 298.15) & (T <= 523.25) + return psi, valid + + +def psi_Na_OH_SO4_PP87ii(T, P): + """c-a-a': sodium hydroxide sulfate [PP87ii].""" + psi = 3.02e-2 - 11.69 / T + # Validity range declared by MP98 for theta(Na, Mg) from this study + valid = (T >= 298.15) & (T <= 523.25) + return psi, valid diff --git a/pytzer/parameters/spencer1990.py b/pytzer/parameters/spencer1990.py new file mode 100644 index 00000000..3ebbb6b4 --- /dev/null +++ b/pytzer/parameters/spencer1990.py @@ -0,0 +1,123 @@ +# Pytzer: Pitzer model for chemical activities in aqueous solutions. +# Copyright (C) 2019--2023 Matthew P. Humphreys (GNU GPLv3) +"""SMW90: Spencer et al. (1990) Geochim. Cosmochim. Acta 54(3), 575-590. +https://doi.org/10.1016/0016-7037(90)90354-N + +Not all parameters in the paper have yet been added here! +""" + +from jax import numpy as np +from ..convert import solute_to_charge as i2c + + +def SMW90_eq2(T, a): + """a contains the coefficients [a1, a2, a6, a9, a3, a4].""" + return a[0] + a[1] * T + a[2] * T**2 + a[3] * T**3 + a[4] / T + a[5] * np.log(T) + + +def bC_Mg_Cl_SMW90(T, P): + """c-a: magnesium chloride [SMW90].""" + b0 = SMW90_eq2( + T, + [ + 3.13852913e2, + 2.61769099e-1, + -2.46268460e-4, + 1.15764787e-7, + -5.53133381e3, + -6.21616862e1, + ], + ) + b1 = SMW90_eq2( + T, + [ + -3.18432525e4, + -2.86710358e1, + 2.78892838e-2, + -1.3279705e-5, + 5.24032958e5, + 6.40770396e3, + ], + ) + b2 = 0 + Cphi = SMW90_eq2( + T, + [ + 5.9532e-2, + -2.49949e-4, + 2.41831e-7, + 0, + 0, + 0, + 0, + ], + ) + C0 = Cphi / (2 * np.sqrt(np.abs(i2c["Mg"] * i2c["Cl"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = (T > 273.15 - 54) & (T <= 298.15) + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Mg_SO4_SMW90(T, P): + """c-a: magnesium sulfate [SMW90].""" + b0 = SMW90_eq2( + T, + [ + 5.40007849e3, + 4.90576884e0, + -4.80489750e-3, + 2.31126994e-6, + -8.80664146e4, + -1.08839565e3, + ], + ) + b1 = SMW90_eq2( + T, + [ + 2.78730869e0, + 4.30077440e-3, + 0, + 0, + 0, + 0, + ], + ) + b2 = 0 + Cphi = SMW90_eq2( + T, + [ + -5.88623653e2, + -5.05522880e-1, + 4.8277657e-4, + -2.3029838e-7, + 1.02002016e4, + 1.17303808e2, + ], + ) + C0 = Cphi / (2 * np.sqrt(np.abs(i2c["Mg"] * i2c["SO4"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = (T > 273.15 - 54) & (T <= 298.15) + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def psi_Mg_Cl_SO4_SMW90(T, P): + """c-a-a': magnesium chloride sulfate [SMW90].""" + psi = SMW90_eq2( + T, + [ + -1.839158e-1, + 1.429444e-4, + 0, + 0, + 3.263e1, + 0, + ], + ) + valid = (T > 273.15 - 54) & (T <= 298.15) + return psi, valid diff --git a/pytzer/prepare.py b/pytzer/prepare.py index 664ee01d..80bfe3d8 100644 --- a/pytzer/prepare.py +++ b/pytzer/prepare.py @@ -1,5 +1,5 @@ # Pytzer: Pitzer model for chemical activities in aqueous solutions. -# Copyright (C) 2019--2021 Matthew P. Humphreys (GNU GPLv3) +# Copyright (C) 2019--2023 Matthew P. Humphreys (GNU GPLv3) from collections import OrderedDict import numpy as np from . import convert @@ -76,7 +76,9 @@ def salinity_to_molalities_MFWM08(salinity=35): def salinity_to_totals_MFWM08(salinity=35): - """Convert salinity (g/kg-sw) to total molality for standard seawater following MFWM08.""" + """Convert salinity (g/kg-sw) to total molality for standard seawater following + MFWM08. + """ total_molalities = OrderedDict() total_molalities.update( { @@ -135,7 +137,9 @@ def salinity_to_totals_MFWM08(salinity=35): def salinity_to_totals_RRV93(salinity=35): - """Convert salinity (g/kg-sw) to total molality for synthetic seawater following RRV93.""" + """Convert salinity (g/kg-sw) to total molality for synthetic seawater following + RRV93. + """ global salt_to_solutes salt_molalities = OrderedDict() salt_molalities.update( @@ -167,7 +171,9 @@ def salinity_to_totals_RRV93(salinity=35): def salinity_to_totals_GP89(salinity=35): - """Convert salinity (g/kg-sw) to total molality for synthetic seawater following GP89.""" + """Convert salinity (g/kg-sw) to total molality for synthetic seawater following + GP89. + """ global salt_to_solutes gravimetric_salts = ( OrderedDict() @@ -188,7 +194,8 @@ def salinity_to_totals_GP89(salinity=35): ) # Concentrations given in mol/kg solution in the paper volumetric_salts.update({"MgCl2": 0.05327, "CaCl2": 0.01033, "SrCl2": 9e-05}) - # Formula weights are provided in the paper for the gravimetric salts, the rest are taken from PubChem + # Formula weights are provided in the paper for the gravimetric salts, the rest are + # taken from PubChem formula_weights = OrderedDict() formula_weights.update( { @@ -245,7 +252,9 @@ def salinity_to_totals_GP89(salinity=35): def salinity_to_totals_H73(salinity=35): - """Convert salinity (g/kg-sw) to total molality for synthetic seawater following H73.""" + """Convert salinity (g/kg-sw) to total molality for synthetic seawater following + H73. + """ ion_concentrations = OrderedDict( # given in mMol/kg of solution in the paper {"Na": 478, "Mg": 54, "Ca": 10, "Cl": 550, "SO4": 28, "HCO3": 1.3, "CO3": 0.7} ) @@ -297,7 +306,9 @@ def salinity_to_totals_H73(salinity=35): def salinity_to_totals_D90(salinity=35): - """Convert salinity (g/kg-sw) to total molality for synthetic seawater following D90.""" + """Convert salinity (g/kg-sw) to total molality for synthetic seawater following + D90. + """ global salt_to_solutes salt_molalities = OrderedDict() salt_molalities.update( @@ -327,7 +338,9 @@ def salinity_to_totals_D90(salinity=35): def salinity_to_totals_KRCB77(salinity=35): - """Convert salinity (g/kg-sw) to total molality for synthetic seawater following KRCB77.""" + """Convert salinity (g/kg-sw) to total molality for synthetic seawater following + KRCB77. + """ global salt_to_solutes salt_molalities = OrderedDict() salt_molalities.update( @@ -357,7 +370,9 @@ def salinity_to_totals_KRCB77(salinity=35): def salinity_to_totals_DR79(salinity=35): - """Convert salinity (g/kg-sw) to total molality for synthetic seawater following DR79.""" + """Convert salinity (g/kg-sw) to total molality for synthetic seawater following + DR79. + """ total_molalities = OrderedDict() total_molalities.update( diff --git a/pytzer/properties.py b/pytzer/properties.py index ad9fb8f0..23f8db9b 100644 --- a/pytzer/properties.py +++ b/pytzer/properties.py @@ -1,5 +1,5 @@ # Pytzer: Pitzer model for chemical activities in aqueous solutions. -# Copyright (C) 2019--2021 Matthew P. Humphreys (GNU GPLv3) +# Copyright (C) 2019--2023 Matthew P. Humphreys (GNU GPLv3) """Define solute properties.""" from . import convert @@ -188,6 +188,7 @@ "NO3": 62.00490, "OH": 17.00734, "HSO4": 97.07054, + "HS": 33.08, "SO4": 96.06260, "HCO3": 61.01684, "CO3": 60.00890, diff --git a/pytzer/teos10.py b/pytzer/teos10.py index fcd13f19..c3975cdd 100644 --- a/pytzer/teos10.py +++ b/pytzer/teos10.py @@ -1,5 +1,5 @@ # Pytzer: Pitzer model for chemical activities in aqueous solutions. -# Copyright (C) 2019--2021 Matthew P. Humphreys (GNU GPLv3) +# Copyright (C) 2019--2023 Matthew P. Humphreys (GNU GPLv3) """Calculate properties of pure water.""" import jax from jax import numpy as np @@ -65,7 +65,7 @@ def Gibbs(tempK, presPa): for j in range(8): for k in range(7): if (j, k) in Gdict.keys(): - Gsum = Gsum + Gdict[(j, k)] * ctau ** j * cpi ** k + Gsum = Gsum + Gdict[(j, k)] * ctau**j * cpi**k return Gsum @@ -76,6 +76,7 @@ def Gibbs(tempK, presPa): gtp = jax.grad(gt, argnums=1) gpp = jax.grad(gp, argnums=1) + # Define functions for solution properties def rho(tempK, presPa): """Density in kg/m**3.""" diff --git a/pytzer/unsymmetrical.py b/pytzer/unsymmetrical.py index 68608627..10a915df 100644 --- a/pytzer/unsymmetrical.py +++ b/pytzer/unsymmetrical.py @@ -1,5 +1,5 @@ # Pytzer: Pitzer model for chemical activities in aqueous solutions. -# Copyright (C) 2019--2021 Matthew P. Humphreys (GNU GPLv3) +# Copyright (C) 2019--2023 Matthew P. Humphreys (GNU GPLv3) """Unsymmetrical mixing functions.""" import jax from jax import numpy as np @@ -47,7 +47,7 @@ def P75_eq46(x): Jsum = np.zeros_like(x) for k in range(6): Jsum = Jsum + C[k] * x ** -(k + 1) - return -(x ** 2) * np.log(x) * np.exp(-10 * x ** 2) / 6 + 1 / Jsum + return -(x**2) * np.log(x) * np.exp(-10 * x**2) / 6 + 1 / Jsum @jax.jit @@ -124,10 +124,10 @@ def _Harvie_raw(x): x_vec = np.full_like(akI, x) ak = np.where(x_vec < 1, akI, akII) z = np.where( - x < 1, 4 * x ** 0.2 - 2, 40 / 9 * x ** -0.1 - 22 / 9 # Eq. (B-21) # Eq. (B-25) + x < 1, 4 * x**0.2 - 2, 40 / 9 * x**-0.1 - 22 / 9 # Eq. (B-21) # Eq. (B-25) ) dz_dx = np.where( - x < 1, 4 * x ** -0.8 / 5, -4 * x ** -1.1 / 9 # Eq. (B-22) # Eq. (B-26) + x < 1, 4 * x**-0.8 / 5, -4 * x**-1.1 / 9 # Eq. (B-22) # Eq. (B-26) ) b2, b1, b0 = 0.0, 0.0, 0.0 d2, d1, d0 = 0.0, 0.0, 0.0 diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index a2e6403f..00000000 --- a/requirements.txt +++ /dev/null @@ -1,6 +0,0 @@ -numpy >= 1.20 -scipy >= 1.6 -pandas >= 1.3 -jax >= 0.2.12 -jaxlib >= 0.1.64 -pint == 0.17 diff --git a/setup.py b/setup.py deleted file mode 100644 index b162e1cc..00000000 --- a/setup.py +++ /dev/null @@ -1,32 +0,0 @@ -# Pytzer: Pitzer model for chemical activities in aqueous solutions. -# Copyright (C) 2019-2020 Matthew Paul Humphreys (GNU GPLv3) -import setuptools -import pytzer as pz - -with open("README.md", "r") as f: - long_description = f.read() -with open("requirements.txt", "r") as f: - requirements = f.read().splitlines() -setuptools.setup( - name="Pytzer", - version=pz.__version__, - author=pz.__author__, - author_email="m.p.humphreys@icloud.com", - description="Pitzer model for chemical activities in aqueous solutions", - url="https://github.com/mvdh7/pytzer", - packages=setuptools.find_packages(), - install_requires=requirements, - long_description=long_description, - long_description_content_type="text/markdown", - classifiers=[ - "Development Status :: 4 - Beta", - "Programming Language :: Python :: 3.7", - "Programming Language :: Python :: 3.8", - "Programming Language :: Python :: 3.9", - "License :: OSI Approved :: GNU General Public License v3 (GPLv3)", - "Operating System :: OS Independent", - "Natural Language :: English", - "Intended Audience :: Science/Research", - "Topic :: Scientific/Engineering :: Chemistry", - ], -) diff --git a/tests/archive/test_PB82.py b/tests/archive/test_PB82.py new file mode 100644 index 00000000..981e0c41 --- /dev/null +++ b/tests/archive/test_PB82.py @@ -0,0 +1,30 @@ +import numpy as np +from matplotlib import pyplot as plt +import pytzer as pz + +temperature = np.linspace(0, 350, num=1000) +ln_kCO2 = pz.dissociation.CO2_PB82(T=temperature + 273.15) +ln_kH2CO3_PB82 = pz.dissociation.H2CO3_PB82(T=temperature + 273.15) +ln_kHCO3_PB82 = pz.dissociation.HCO3_PB82(T=temperature + 273.15) +ln_kH2CO3_MP98 = pz.dissociation.H2CO3_MP98(T=temperature + 273.15) +ln_kHCO3_MP98 = pz.dissociation.HCO3_MP98(T=temperature + 273.15) +ln10 = np.log(10) + +fig, axs = plt.subplots(nrows=2, ncols=2, dpi=300) +# for ax in axs.ravel(): +# ax.set_xlim([0, 50]) +ax = axs[0, 0] +ax.plot(temperature, ln_kCO2 / ln10) +ax.set_xlabel("Temperature / °C") +ax.set_ylabel("log$_{10}$ $K_\mathrm{H}$") +ax = axs[0, 1] +ax.plot(temperature, ln_kH2CO3_PB82 / ln10) +# ax.plot(temperature, ln_kH2CO3_MP98 / ln10) +ax.set_xlabel("Temperature / °C") +ax.set_ylabel("log$_{10}$ $K_1$") +ax = axs[1, 0] +ax.plot(temperature, ln_kHCO3_PB82 / ln10) +# ax.plot(temperature, ln_kHCO3_MP98 / ln10) +ax.set_xlabel("Temperature / °C") +ax.set_ylabel("log$_{10}$ $K_2$") +plt.tight_layout() diff --git a/tests/test_convert.py b/tests/archive/test_convert.py similarity index 81% rename from tests/test_convert.py rename to tests/archive/test_convert.py index c9289cd4..e93d1110 100644 --- a/tests/test_convert.py +++ b/tests/archive/test_convert.py @@ -21,9 +21,9 @@ # Manual approach - pks_constants mol_kg = unit.mol / unit.kg pks_H2O_molality = 14 -ks_H2O_molality = 10 ** -pks_H2O_molality * mol_kg ** 2 -ks_H2O_content = ks_H2O_molality * mass_H2O ** 2 / mass_total ** 2 -pks_H2O_content = -np.log10(ks_H2O_content / mol_kg ** 2).magnitude +ks_H2O_molality = 10**-pks_H2O_molality * mol_kg**2 +ks_H2O_content = ks_H2O_molality * mass_H2O**2 / mass_total**2 +pks_H2O_content = -np.log10(ks_H2O_content / mol_kg**2).magnitude def test_molinity_conversion(): @@ -37,5 +37,5 @@ def test_pK_conversions(): assert np.isclose(pks_H2O_content, pks_out["H2O"]) -# test_molinity_conversion() -# test_pK_conversions() +test_molinity_conversion() +test_pK_conversions() diff --git a/tests/archive/test_jaxscan.py b/tests/archive/test_jaxscan.py new file mode 100644 index 00000000..fa02121e --- /dev/null +++ b/tests/archive/test_jaxscan.py @@ -0,0 +1,57 @@ +import itertools +from jax import numpy as np, vmap, jit, lax +from time import time + +cats = np.vstack([1.0, 2, 3, 4, 5]) +anis = np.array([[5.0, 2, 6]]) +ca = np.array([[3.0, 1, 4, 7, 5], [3, 2, 6, 8, 4], [1, 4, 3, 6, 8]]) + +m_cats = cats.ravel() +m_anis = anis.ravel() + +go = time() + + +@jit +def test_matmul(): + anisanis = np.array( + [(np.transpose(anis) @ anis)[np.triu_indices(np.size(anis), k=1)]] + ) + # anix = np.triu_indices(np.size(anis), k=1) + # anisanis = anis[0][anix[0]] * anis[0][anix[1]] + catscats = np.array( + [(np.transpose(cats) @ cats)[np.triu_indices(np.size(cats), k=1)]] + ) + return (anis @ ca @ cats)[0][0] + + +test_matmul() +print(time() - go) +go = time() +test_matmul() +print(time() - go) + + +def map_func(i_ca): + ic, ia = i_ca + return m_cats[ic] * m_anis[ia] * ca[ia][ic] + + +go = time() + + +@jit +def test_map(): + r_cats = range(len(m_cats)) + r_anis = range(len(m_anis)) + i_ca = np.array(list(itertools.product(r_cats, r_anis))) + i_cc = np.array(list(itertools.product(r_cats, r_cats))) + i_aa = np.array(list(itertools.product(r_anis, r_anis))) + return np.sum(lax.map(map_func, i_ca)) + + +test_map() +print(time() - go) +go = time() +test_map() +print(time() - go) diff --git a/tests/archive/test_v0_4_3.py b/tests/archive/test_v0_4_3.py new file mode 100644 index 00000000..80b5ffa6 --- /dev/null +++ b/tests/archive/test_v0_4_3.py @@ -0,0 +1,32 @@ +from collections import OrderedDict +import pandas as pd, numpy as np +import pytzer as pz + +v4 = pd.read_csv("tests/data/pytzerQuickStart_py_v0_4_3__GM89.csv") +solutes = [ + k + for k in v4.columns + if k not in ["tempK", "pres", "aw", "osm"] and not k.startswith("g") +] +for s in solutes: + v4["g{}_new".format(s)] = np.nan +plib = pz.libraries.GM89 +plib.set_func_J(pz) + +for i, row in v4.iterrows(): + print(i) + solutes = OrderedDict( + (k, v) + for k, v in row.items() + if k not in ["tempK", "pres", "aw", "osm"] and not k.startswith("g") + ) + params = plib.get_parameters( + solutes, temperature=row.tempK, pressure=row.pres, verbose=False + ) + acfs = pz.activity_coefficients(solutes, **params) + for s in solutes: + v4.loc[i, "g{}_new".format(s)] = acfs[s] +for s in solutes: + gsdiff = "g{}_diff".format(s) + v4[gsdiff] = v4["g{}_new".format(s)] - v4["g{}".format(s)] + v4.loc[v4[gsdiff].abs() < 1e-12, gsdiff] = 0 diff --git a/tests/data/CWTD23 SI Chart 8 part 1.txt b/tests/data/CWTD23 SI Chart 8 part 1.txt new file mode 100644 index 00000000..94fa0e34 --- /dev/null +++ b/tests/data/CWTD23 SI Chart 8 part 1.txt @@ -0,0 +1,82 @@ + b0 b1 b2 C0 C1 alph1 alph2 omega cation anion + 1.75670E-01 2.97786E-01 0.00000E+00 6.84697E-04 0.00000E+00 2.000 0.000 0.000 H Cl +-8.38609E-03 3.14735E-01 0.00000E+00 1.01922E-02 -3.23663E-01 2.000 0.000 2.500 H SO4 + 2.95903E-01 4.00482E-01 0.00000E+00 -5.65787E-03 -4.09364E-01 2.000 0.000 2.500 H HSO4 + 0.00000E+00 0.00000E+00 0.00000E+00 0.00000E+00 0.00000E+00 0.000 0.000 0.000 H OH + 1.96000E-01 3.56400E-01 0.00000E+00 4.13500E-03 0.00000E+00 2.000 0.000 0.000 H Br + 0.00000E+00 0.00000E+00 0.00000E+00 0.00000E+00 0.00000E+00 0.000 0.000 0.000 H HCO3 + 0.00000E+00 0.00000E+00 0.00000E+00 0.00000E+00 0.00000E+00 0.000 0.000 0.000 H CO3 + 0.00000E+00 0.00000E+00 0.00000E+00 0.00000E+00 0.00000E+00 0.000 0.000 0.000 H BOH4 + 0.00000E+00 0.00000E+00 0.00000E+00 0.00000E+00 0.00000E+00 0.000 0.000 0.000 H F + 7.53591E-02 2.77031E-01 0.00000E+00 7.03969E-04 0.00000E+00 2.000 0.000 0.000 Na Cl + 1.86933E-02 1.09940E+00 0.00000E+00 2.22673E-03 0.00000E+00 2.000 0.000 0.000 Na SO4 + 2.63400E-02 9.15900E-01 0.00000E+00 0.00000E+00 0.00000E+00 2.000 0.000 0.000 Na HSO4 + 8.63907E-02 2.53001E-01 0.00000E+00 2.05133E-03 0.00000E+00 2.000 0.000 0.000 Na OH + 9.73000E-02 2.79100E-01 0.00000E+00 5.80000E-04 0.00000E+00 2.000 0.000 0.000 Na Br + 2.80000E-02 4.40000E-02 0.00000E+00 0.00000E+00 0.00000E+00 2.000 0.000 0.000 Na HCO3 + 3.62000E-02 1.51000E+00 0.00000E+00 1.83848E-03 0.00000E+00 2.000 0.000 0.000 Na CO3 +-5.10000E-02 9.61000E-02 0.00000E+00 7.49000E-03 0.00000E+00 2.000 0.000 0.000 Na BOH4 + 2.15000E-02 2.10700E-01 0.00000E+00 0.00000E+00 0.00000E+00 2.000 0.000 0.000 Na F + 3.51088E-01 1.65119E+00 0.00000E+00 2.30053E-03 0.00000E+00 2.000 0.000 0.000 Mg Cl + 2.14990E-01 3.36460E+00 -3.27430E+01 6.99250E-03 0.00000E+00 1.400 12.000 0.000 Mg SO4 + 4.74600E-01 1.72900E+00 0.00000E+00 0.00000E+00 0.00000E+00 2.000 0.000 0.000 Mg HSO4 + 0.00000E+00 0.00000E+00 0.00000E+00 0.00000E+00 0.00000E+00 0.000 0.000 0.000 Mg OH + 4.32675E-01 1.75275E+00 0.00000E+00 1.10437E-03 0.00000E+00 2.000 0.000 0.000 Mg Br + 3.00000E-02 8.00000E-01 0.00000E+00 0.00000E+00 0.00000E+00 2.000 0.000 0.000 Mg HCO3 + 0.00000E+00 0.00000E+00 0.00000E+00 0.00000E+00 0.00000E+00 0.000 0.000 0.000 Mg CO3 +-6.23000E-01 2.51500E-01 -1.15510E+01 0.00000E+00 0.00000E+00 1.400 6.000 0.000 Mg BOH4 + 0.00000E+00 0.00000E+00 0.00000E+00 0.00000E+00 0.00000E+00 0.000 0.000 0.000 Mg F + 3.05320E-01 1.70813E+00 0.00000E+00 8.28085E-04 0.00000E+00 2.000 0.000 0.000 Ca Cl + 2.00000E-01 3.19730E+00 -5.42400E+01 0.00000E+00 0.00000E+00 1.400 12.000 0.000 Ca SO4 + 2.14500E-01 2.53000E+00 0.00000E+00 0.00000E+00 0.00000E+00 2.000 0.000 0.000 Ca HSO4 +-1.74700E-01 -2.30300E-01 -5.72000E+00 0.00000E+00 0.00000E+00 2.000 12.000 0.000 Ca OH + 3.81600E-01 1.61325E+00 0.00000E+00 -9.09375E-04 0.00000E+00 2.000 0.000 0.000 Ca Br + 2.00000E-01 3.00000E-01 0.00000E+00 0.00000E+00 0.00000E+00 2.000 0.000 0.000 Ca HCO3 + 0.00000E+00 0.00000E+00 0.00000E+00 0.00000E+00 0.00000E+00 0.000 0.000 0.000 Ca CO3 +-4.46200E-01 -8.68000E-01 -1.59515E+01 0.00000E+00 0.00000E+00 1.400 6.000 0.000 Ca BOH4 + 0.00000E+00 0.00000E+00 0.00000E+00 0.00000E+00 0.00000E+00 0.000 0.000 0.000 Ca F + 4.80800E-02 2.18025E-01 0.00000E+00 -3.94000E-04 0.00000E+00 2.000 0.000 0.000 K Cl + 5.55358E-02 7.96385E-01 0.00000E+00 -6.64680E-03 0.00000E+00 2.000 0.000 0.000 K SO4 +-3.00000E-04 1.73500E-01 0.00000E+00 0.00000E+00 0.00000E+00 2.000 0.000 0.000 K HSO4 + 1.29800E-01 3.20000E-01 0.00000E+00 2.05000E-03 0.00000E+00 2.000 0.000 0.000 K OH + 5.69000E-02 2.21200E-01 0.00000E+00 -9.00000E-04 0.00000E+00 2.000 0.000 0.000 K Br +-1.07000E-02 4.78000E-02 0.00000E+00 0.00000E+00 0.00000E+00 2.000 0.000 0.000 K HCO3 + 1.28800E-01 1.43300E+00 0.00000E+00 1.76777E-04 0.00000E+00 2.000 0.000 0.000 K CO3 + 1.46900E-01 -9.89000E-02 0.00000E+00 -2.82150E-02 0.00000E+00 2.000 0.000 0.000 K BOH4 + 8.08900E-02 2.02100E-01 0.00000E+00 4.65000E-04 0.00000E+00 2.000 0.000 0.000 K F +-1.00000E-01 1.65800E+00 0.00000E+00 0.00000E+00 0.00000E+00 2.000 0.000 0.000 MgOH Cl + 0.00000E+00 0.00000E+00 0.00000E+00 0.00000E+00 0.00000E+00 0.000 0.000 0.000 MgOH SO4 + 0.00000E+00 0.00000E+00 0.00000E+00 0.00000E+00 0.00000E+00 0.000 0.000 0.000 MgOH HSO4 + 0.00000E+00 0.00000E+00 0.00000E+00 0.00000E+00 0.00000E+00 0.000 0.000 0.000 MgOH OH + 0.00000E+00 0.00000E+00 0.00000E+00 0.00000E+00 0.00000E+00 0.000 0.000 0.000 MgOH Br + 0.00000E+00 0.00000E+00 0.00000E+00 0.00000E+00 0.00000E+00 0.000 0.000 0.000 MgOH HCO3 + 0.00000E+00 0.00000E+00 0.00000E+00 0.00000E+00 0.00000E+00 0.000 0.000 0.000 MgOH CO3 + 0.00000E+00 0.00000E+00 0.00000E+00 0.00000E+00 0.00000E+00 0.000 0.000 0.000 MgOH BOH4 + 0.00000E+00 0.00000E+00 0.00000E+00 0.00000E+00 0.00000E+00 0.000 0.000 0.000 MgOH F + 2.85750E-01 1.66725E+00 0.00000E+00 -4.59619E-04 0.00000E+00 2.000 0.000 0.000 Sr Cl + 2.00000E-01 3.19730E+00 -5.42400E+01 0.00000E+00 0.00000E+00 1.400 12.000 0.000 Sr SO4 + 2.14500E-01 2.53000E+00 0.00000E+00 0.00000E+00 0.00000E+00 2.000 0.000 0.000 Sr HSO4 +-1.74700E-01 -2.30300E-01 -5.72000E+00 0.00000E+00 0.00000E+00 2.000 12.000 0.000 Sr OH + 3.31125E-01 1.71150E+00 0.00000E+00 4.33125E-04 0.00000E+00 2.000 0.000 0.000 Sr Br + 2.00000E-01 3.00000E-01 0.00000E+00 0.00000E+00 0.00000E+00 2.000 0.000 0.000 Sr HCO3 + 0.00000E+00 0.00000E+00 0.00000E+00 0.00000E+00 0.00000E+00 0.000 0.000 0.000 Sr CO3 +-4.46200E-01 -8.68000E-01 -1.59515E+01 0.00000E+00 0.00000E+00 1.400 6.000 0.000 Sr BOH4 + 0.00000E+00 0.00000E+00 0.00000E+00 0.00000E+00 0.00000E+00 0.000 0.000 0.000 Sr F + 2.87100E-01 4.53800E-01 0.00000E+00 -1.85000E-02 0.00000E+00 2.000 0.000 0.000 MgF Cl + 0.00000E+00 0.00000E+00 0.00000E+00 0.00000E+00 0.00000E+00 0.000 0.000 0.000 MgF SO4 + 0.00000E+00 0.00000E+00 0.00000E+00 0.00000E+00 0.00000E+00 0.000 0.000 0.000 MgF HSO4 + 0.00000E+00 0.00000E+00 0.00000E+00 0.00000E+00 0.00000E+00 0.000 0.000 0.000 MgF OH + 0.00000E+00 0.00000E+00 0.00000E+00 0.00000E+00 0.00000E+00 0.000 0.000 0.000 MgF Br + 0.00000E+00 0.00000E+00 0.00000E+00 0.00000E+00 0.00000E+00 0.000 0.000 0.000 MgF HCO3 + 0.00000E+00 0.00000E+00 0.00000E+00 0.00000E+00 0.00000E+00 0.000 0.000 0.000 MgF CO3 + 0.00000E+00 0.00000E+00 0.00000E+00 0.00000E+00 0.00000E+00 0.000 0.000 0.000 MgF BOH4 + 0.00000E+00 0.00000E+00 0.00000E+00 0.00000E+00 0.00000E+00 0.000 0.000 0.000 MgF F + 1.40470E-01 3.02200E-01 0.00000E+00 0.00000E+00 0.00000E+00 2.000 0.000 0.000 CaF Cl + 0.00000E+00 0.00000E+00 0.00000E+00 0.00000E+00 0.00000E+00 0.000 0.000 0.000 CaF SO4 + 0.00000E+00 0.00000E+00 0.00000E+00 0.00000E+00 0.00000E+00 0.000 0.000 0.000 CaF HSO4 + 0.00000E+00 0.00000E+00 0.00000E+00 0.00000E+00 0.00000E+00 0.000 0.000 0.000 CaF OH + 0.00000E+00 0.00000E+00 0.00000E+00 0.00000E+00 0.00000E+00 0.000 0.000 0.000 CaF Br + 0.00000E+00 0.00000E+00 0.00000E+00 0.00000E+00 0.00000E+00 0.000 0.000 0.000 CaF HCO3 + 0.00000E+00 0.00000E+00 0.00000E+00 0.00000E+00 0.00000E+00 0.000 0.000 0.000 CaF CO3 + 0.00000E+00 0.00000E+00 0.00000E+00 0.00000E+00 0.00000E+00 0.000 0.000 0.000 CaF BOH4 + 0.00000E+00 0.00000E+00 0.00000E+00 0.00000E+00 0.00000E+00 0.000 0.000 0.000 CaF F \ No newline at end of file diff --git a/tests/data/CWTD23 SI Chart 8 part 2.csv b/tests/data/CWTD23 SI Chart 8 part 2.csv new file mode 100644 index 00000000..7d7510cc --- /dev/null +++ b/tests/data/CWTD23 SI Chart 8 part 2.csv @@ -0,0 +1,38 @@ +theta_cc,psi_cca,cca_c1,cca_c2,cca_a,theta_aa,psi_caa,caa_a1,caa_a2,caa_c +3.06000E-02,,H,Na,,7.00000E-02,,Cl,SO4, +,-4.00000E-03,H,Na,Cl,,-9.00000E-03,Cl,SO4,Na +,-1.20000E-02,H,Na,Br,,-4.00000E-03,Cl,SO4,Mg +6.20000E-02,,H,Mg,,,-1.80000E-02,Cl,SO4,Ca +,1.00000E-03,H,Mg,Cl,,-1.61523E-03,Cl,SO4,K +,-1.78000E-02,H,Mg,HSO4,-6.00000E-03,,Cl,HSO4, +6.12000E-02,,H,Ca,,,1.30000E-02,Cl,HSO4,H +,8.00000E-04,H,Ca,Cl,,-6.00000E-03,Cl,HSO4,Na +5.00000E-03,,H,K,,-5.00000E-02,,Cl,OH, +,-1.10000E-02,H,K,Cl,,-6.00000E-03,Cl,OH,Na +,1.97000E-01,H,K,SO4,,-2.50000E-02,Cl,OH,Ca +,-2.65000E-02,H,K,HSO4,,-6.00000E-03,Cl,OH,K +,-2.10000E-02,H,K,Br,3.59000E-02,,Cl,HCO3, +5.91000E-02,,H,Sr,,,-1.43000E-02,Cl,HCO3,Na +,5.40000E-03,H,Sr,Cl,,-9.60000E-02,Cl,HCO3,Mg +7.00000E-02,,Na,Mg,,-5.30000E-02,,Cl,CO3, +,-1.19967E-02,Na,Mg,Cl,,1.60000E-02,Cl,CO3,Na +,-1.50000E-02,Na,Mg,SO4,-3.23000E-02,,Cl,BOH4, +5.00000E-02,,Na,Ca,,,-1.32000E-02,Cl,BOH4,Na +,-3.00000E-03,Na,Ca,Cl,,-2.35000E-01,Cl,BOH4,Mg +,-5.50000E-02,Na,Ca,SO4,,-8.00000E-01,Cl,BOH4,Ca +-3.20349E-03,,Na,K,,1.00000E-02,,Cl,F, +,-3.69149E-03,Na,K,Cl,,2.33000E-03,Cl,F,Na +,7.25301E-03,Na,K,SO4,,-6.77000E-02,SO4,HSO4,K +,-2.20000E-03,Na,K,Br,-1.30000E-02,,SO4,OH, +7.00000E-02,,Na,Sr,,,-9.00000E-03,SO4,OH,Na +,-1.50000E-02,Na,Sr,Cl,,-5.00000E-02,SO4,OH,K +7.00000E-03,,Mg,Ca,,1.00000E-02,,SO4,HCO3, +,-1.20000E-02,Mg,Ca,Cl,,-5.00000E-03,SO4,HCO3,Na +,2.40000E-02,Mg,Ca,SO4,,-1.61000E-01,SO4,HCO3,Mg +,-2.20018E-02,Mg,K,Cl,2.00000E-02,,SO4,CO3, +,-4.80000E-02,Mg,K,SO4,,-5.00000E-03,SO4,CO3,Na +,2.80000E-02,Mg,MgOH,Cl,,-9.00000E-03,SO4,CO3,K +1.15600E-01,,Ca,K,,-1.20000E-02,,SO4,BOH4, +,-4.31890E-02,Ca,K,Cl,-6.50000E-02,,OH,Br, +7.00000E-02,,K,Sr,,,-1.80000E-02,OH,Br,Na +,-1.50000E-02,K,Sr,Cl,,-1.40000E-02,OH,Br,K \ No newline at end of file diff --git a/tests/data/CWTD23 SI Chart 8 part 3.txt b/tests/data/CWTD23 SI Chart 8 part 3.txt new file mode 100644 index 00000000..5d6f6a29 --- /dev/null +++ b/tests/data/CWTD23 SI Chart 8 part 3.txt @@ -0,0 +1,13 @@ + lambda_nx n ion +-9.70000E-02 BOH3 Na +-1.40000E-01 BOH3 K + 8.14744E-02 CO2 Na + 1.44733E-01 CO2 Mg + 1.64379E-01 CO2 Ca + 4.49422E-02 CO2 K + 1.10000E-02 HF Na + 7.45000E-02 MgCO3 Na + 9.10000E-02 BOH3 Cl + 1.80000E-02 BOH3 SO4 + 2.04804E-02 CO2 Cl + 1.38973E-01 CO2 SO4 \ No newline at end of file diff --git a/tests/data/CWTD23 SI Chart 8 part 4.txt b/tests/data/CWTD23 SI Chart 8 part 4.txt new file mode 100644 index 00000000..e08f4815 --- /dev/null +++ b/tests/data/CWTD23 SI Chart 8 part 4.txt @@ -0,0 +1,10 @@ + zeta n c a + 4.60000E-02 BOH3 Na SO4 +-4.70519E-03 CO2 H Cl +-5.71530E-04 CO2 Na Cl +-3.74535E-02 CO2 Na SO4 +-9.84695E-03 CO2 Mg Cl +-4.15864E-02 CO2 Mg SO4 +-1.41310E-02 CO2 Ca Cl +-1.20697E-02 CO2 K Cl +-3.57567E-04 CO2 K SO4 \ No newline at end of file diff --git a/tests/data/CWTD23 SI Chart 9 part 1.txt b/tests/data/CWTD23 SI Chart 9 part 1.txt new file mode 100644 index 00000000..27afe1f7 --- /dev/null +++ b/tests/data/CWTD23 SI Chart 9 part 1.txt @@ -0,0 +1,82 @@ + b0 b1 b2 C0 C1 alph1 alph2 omega cation anion + 1.83677E-01 2.89838E-01 0.00000E+00 1.01382E-03 0.00000E+00 2.000 0.000 0.000 H Cl + 1.18617E-02 5.74779E-01 0.00000E+00 9.11500E-03 -9.04955E-01 1.556 0.000 2.500 H SO4 + 3.10426E-01 4.63219E-01 0.00000E+00 -5.27028E-03 -5.07749E-01 2.000 0.000 2.500 H HSO4 + 0.00000E+00 0.00000E+00 0.00000E+00 0.00000E+00 0.00000E+00 0.000 0.000 0.000 H OH + 1.99644E-01 3.44910E-01 0.00000E+00 4.75771E-03 0.00000E+00 2.000 0.000 0.000 H Br + 0.00000E+00 0.00000E+00 0.00000E+00 0.00000E+00 0.00000E+00 0.000 0.000 0.000 H HCO3 + 0.00000E+00 0.00000E+00 0.00000E+00 0.00000E+00 0.00000E+00 0.000 0.000 0.000 H CO3 + 0.00000E+00 0.00000E+00 0.00000E+00 0.00000E+00 0.00000E+00 0.000 0.000 0.000 H BOH4 + 0.00000E+00 0.00000E+00 0.00000E+00 0.00000E+00 0.00000E+00 0.000 0.000 0.000 H F + 5.60482E-02 2.54399E-01 0.00000E+00 2.09594E-03 0.00000E+00 2.000 0.000 0.000 Na Cl +-5.03834E-02 9.48452E-01 0.00000E+00 6.84925E-03 0.00000E+00 2.000 0.000 0.000 Na SO4 +-7.54800E-03 1.05912E+00 0.00000E+00 0.00000E+00 0.00000E+00 2.000 0.000 0.000 Na HSO4 + 7.47613E-02 2.02309E-01 0.00000E+00 3.28482E-03 0.00000E+00 2.000 0.000 0.000 Na OH + 7.80852E-02 2.53747E-01 0.00000E+00 1.69843E-03 0.00000E+00 2.000 0.000 0.000 Na Br + 2.80000E-03 1.34000E-02 0.00000E+00 0.00000E+00 0.00000E+00 2.000 0.000 0.000 Na HCO3 +-8.04000E-03 1.43540E+00 0.00000E+00 1.83848E-03 0.00000E+00 2.000 0.000 0.000 Na CO3 +-1.56280E-01 3.09700E-01 0.00000E+00 2.31900E-02 0.00000E+00 2.000 0.000 0.000 Na BOH4 + 5.03983E-03 1.92049E-01 0.00000E+00 0.00000E+00 0.00000E+00 2.000 0.000 0.000 Na F + 3.62876E-01 1.57019E+00 0.00000E+00 3.08247E-03 0.00000E+00 2.000 0.000 0.000 Mg Cl + 1.94760E-01 3.11357E+00 -2.95146E+01 9.08932E-03 0.00000E+00 1.400 12.000 0.000 Mg SO4 + 4.74600E-01 1.72900E+00 0.00000E+00 0.00000E+00 0.00000E+00 2.000 0.000 0.000 Mg HSO4 + 0.00000E+00 0.00000E+00 0.00000E+00 0.00000E+00 0.00000E+00 0.000 0.000 0.000 Mg OH + 4.33800E-01 1.67550E+00 0.00000E+00 1.10437E-03 0.00000E+00 2.000 0.000 0.000 Mg Br + 3.00000E-02 8.00000E-01 0.00000E+00 0.00000E+00 0.00000E+00 2.000 0.000 0.000 Mg HCO3 + 0.00000E+00 0.00000E+00 0.00000E+00 0.00000E+00 0.00000E+00 0.000 0.000 0.000 Mg CO3 +-7.52920E-01 5.94100E-01 -1.34950E+01 0.00000E+00 0.00000E+00 1.400 6.000 0.000 Mg BOH4 + 0.00000E+00 0.00000E+00 0.00000E+00 0.00000E+00 0.00000E+00 0.000 0.000 0.000 Mg F + 2.84642E-01 1.65005E+00 0.00000E+00 2.64940E-03 0.00000E+00 2.000 0.000 0.000 Ca Cl + 2.00000E-01 2.10530E+00 -4.39200E+01 0.00000E+00 0.00000E+00 1.400 12.000 0.000 Ca SO4 + 2.14500E-01 2.53000E+00 0.00000E+00 0.00000E+00 0.00000E+00 2.000 0.000 0.000 Ca HSO4 +-1.74700E-01 -2.30300E-01 -5.72000E+00 0.00000E+00 0.00000E+00 2.000 12.000 0.000 Ca OH + 3.92055E-01 1.49250E+00 0.00000E+00 -9.09375E-04 0.00000E+00 2.000 0.000 0.000 Ca Br + 2.00000E-01 3.00000E-01 0.00000E+00 0.00000E+00 0.00000E+00 2.000 0.000 0.000 Ca HCO3 + 0.00000E+00 0.00000E+00 0.00000E+00 0.00000E+00 0.00000E+00 0.000 0.000 0.000 Ca CO3 +-5.54060E-01 -5.04000E-01 -1.76663E+01 0.00000E+00 0.00000E+00 1.400 6.000 0.000 Ca BOH4 + 0.00000E+00 0.00000E+00 0.00000E+00 0.00000E+00 0.00000E+00 0.000 0.000 0.000 Ca F + 3.38375E-02 1.82370E-01 0.00000E+00 3.75315E-04 0.00000E+00 2.000 0.000 0.000 K Cl + 1.65833E-02 8.23319E-01 0.00000E+00 -6.64680E-03 0.00000E+00 2.000 0.000 0.000 K SO4 +-1.50000E-03 -2.79000E-02 0.00000E+00 0.00000E+00 0.00000E+00 2.000 0.000 0.000 K HSO4 + 1.06564E-01 2.89146E-01 0.00000E+00 3.12874E-03 0.00000E+00 2.000 0.000 0.000 K OH + 3.80602E-02 1.85495E-01 0.00000E+00 7.71154E-05 0.00000E+00 2.000 0.000 0.000 K Br +-3.07000E-02 2.58000E-02 0.00000E+00 0.00000E+00 0.00000E+00 2.000 0.000 0.000 K HCO3 + 1.04760E-01 1.35408E+00 0.00000E+00 1.76777E-04 0.00000E+00 2.000 0.000 0.000 K CO3 + 8.92800E-02 3.86200E-02 0.00000E+00 -1.86550E-02 0.00000E+00 2.000 0.000 0.000 K BOH4 + 7.33890E-02 1.90438E-01 0.00000E+00 1.10278E-03 0.00000E+00 2.000 0.000 0.000 K F +-1.00000E-01 1.65800E+00 0.00000E+00 0.00000E+00 0.00000E+00 2.000 0.000 0.000 MgOH Cl + 0.00000E+00 0.00000E+00 0.00000E+00 0.00000E+00 0.00000E+00 0.000 0.000 0.000 MgOH SO4 + 0.00000E+00 0.00000E+00 0.00000E+00 0.00000E+00 0.00000E+00 0.000 0.000 0.000 MgOH HSO4 + 0.00000E+00 0.00000E+00 0.00000E+00 0.00000E+00 0.00000E+00 0.000 0.000 0.000 MgOH OH + 0.00000E+00 0.00000E+00 0.00000E+00 0.00000E+00 0.00000E+00 0.000 0.000 0.000 MgOH Br + 0.00000E+00 0.00000E+00 0.00000E+00 0.00000E+00 0.00000E+00 0.000 0.000 0.000 MgOH HCO3 + 0.00000E+00 0.00000E+00 0.00000E+00 0.00000E+00 0.00000E+00 0.000 0.000 0.000 MgOH CO3 + 0.00000E+00 0.00000E+00 0.00000E+00 0.00000E+00 0.00000E+00 0.000 0.000 0.000 MgOH BOH4 + 0.00000E+00 0.00000E+00 0.00000E+00 0.00000E+00 0.00000E+00 0.000 0.000 0.000 MgOH F + 2.69994E-01 1.60631E+00 0.00000E+00 -4.59619E-04 0.00000E+00 2.000 0.000 0.000 Sr Cl + 2.00000E-01 2.10530E+00 -4.39200E+01 0.00000E+00 0.00000E+00 1.400 12.000 0.000 Sr SO4 + 2.14500E-01 2.53000E+00 0.00000E+00 0.00000E+00 0.00000E+00 2.000 0.000 0.000 Sr HSO4 +-1.74700E-01 -2.30300E-01 -5.72000E+00 0.00000E+00 0.00000E+00 2.000 12.000 0.000 Sr OH + 3.37680E-01 1.58085E+00 0.00000E+00 4.33125E-04 0.00000E+00 2.000 0.000 0.000 Sr Br + 2.00000E-01 3.00000E-01 0.00000E+00 0.00000E+00 0.00000E+00 2.000 0.000 0.000 Sr HCO3 + 0.00000E+00 0.00000E+00 0.00000E+00 0.00000E+00 0.00000E+00 0.000 0.000 0.000 Sr CO3 +-5.54060E-01 -5.04000E-01 -1.76663E+01 0.00000E+00 0.00000E+00 1.400 6.000 0.000 Sr BOH4 + 0.00000E+00 0.00000E+00 0.00000E+00 0.00000E+00 0.00000E+00 0.000 0.000 0.000 Sr F + 2.87100E-01 4.53800E-01 0.00000E+00 -1.85000E-02 0.00000E+00 2.000 0.000 0.000 MgF Cl + 0.00000E+00 0.00000E+00 0.00000E+00 0.00000E+00 0.00000E+00 0.000 0.000 0.000 MgF SO4 + 0.00000E+00 0.00000E+00 0.00000E+00 0.00000E+00 0.00000E+00 0.000 0.000 0.000 MgF HSO4 + 0.00000E+00 0.00000E+00 0.00000E+00 0.00000E+00 0.00000E+00 0.000 0.000 0.000 MgF OH + 0.00000E+00 0.00000E+00 0.00000E+00 0.00000E+00 0.00000E+00 0.000 0.000 0.000 MgF Br + 0.00000E+00 0.00000E+00 0.00000E+00 0.00000E+00 0.00000E+00 0.000 0.000 0.000 MgF HCO3 + 0.00000E+00 0.00000E+00 0.00000E+00 0.00000E+00 0.00000E+00 0.000 0.000 0.000 MgF CO3 + 0.00000E+00 0.00000E+00 0.00000E+00 0.00000E+00 0.00000E+00 0.000 0.000 0.000 MgF BOH4 + 0.00000E+00 0.00000E+00 0.00000E+00 0.00000E+00 0.00000E+00 0.000 0.000 0.000 MgF F + 1.40470E-01 3.02200E-01 0.00000E+00 0.00000E+00 0.00000E+00 2.000 0.000 0.000 CaF Cl + 0.00000E+00 0.00000E+00 0.00000E+00 0.00000E+00 0.00000E+00 0.000 0.000 0.000 CaF SO4 + 0.00000E+00 0.00000E+00 0.00000E+00 0.00000E+00 0.00000E+00 0.000 0.000 0.000 CaF HSO4 + 0.00000E+00 0.00000E+00 0.00000E+00 0.00000E+00 0.00000E+00 0.000 0.000 0.000 CaF OH + 0.00000E+00 0.00000E+00 0.00000E+00 0.00000E+00 0.00000E+00 0.000 0.000 0.000 CaF Br + 0.00000E+00 0.00000E+00 0.00000E+00 0.00000E+00 0.00000E+00 0.000 0.000 0.000 CaF HCO3 + 0.00000E+00 0.00000E+00 0.00000E+00 0.00000E+00 0.00000E+00 0.000 0.000 0.000 CaF CO3 + 0.00000E+00 0.00000E+00 0.00000E+00 0.00000E+00 0.00000E+00 0.000 0.000 0.000 CaF BOH4 + 0.00000E+00 0.00000E+00 0.00000E+00 0.00000E+00 0.00000E+00 0.000 0.000 0.000 CaF F \ No newline at end of file diff --git a/tests/data/CWTD23 SI Chart 9 part 2.csv b/tests/data/CWTD23 SI Chart 9 part 2.csv new file mode 100644 index 00000000..5f3fde5b --- /dev/null +++ b/tests/data/CWTD23 SI Chart 9 part 2.csv @@ -0,0 +1,38 @@ +theta_cc,psi_cca,cca_c1,cca_c2,cca_a,theta_aa,psi_caa,caa_a1,caa_a2,caa_c +3.89600E-02,,H,Na,,7.00000E-02,,Cl,SO4, +,-4.00000E-03,H,Na,Cl,,-9.00000E-03,Cl,SO4,Na +,-1.20000E-02,H,Na,Br,,-4.00000E-03,Cl,SO4,Mg +6.20000E-02,,H,Mg,,,-1.80000E-02,Cl,SO4,Ca +,1.00000E-03,H,Mg,Cl,,1.74947E-03,Cl,SO4,K +,-1.78000E-02,H,Mg,HSO4,-6.00000E-03,,Cl,HSO4, +6.12000E-02,,H,Ca,,,1.30000E-02,Cl,HSO4,H +,8.00000E-04,H,Ca,Cl,,-6.00000E-03,Cl,HSO4,Na +9.55000E-03,,H,K,,-5.95948E-02,,Cl,OH, +,-1.10000E-02,H,K,Cl,,-6.00000E-03,Cl,OH,Na +,1.97000E-01,H,K,SO4,,-2.50000E-02,Cl,OH,Ca +,-2.65000E-02,H,K,HSO4,,-6.00000E-03,Cl,OH,K +,-2.10000E-02,H,K,Br,3.59000E-02,,Cl,HCO3, +5.01000E-02,,H,Sr,,,-1.43000E-02,Cl,HCO3,Na +,9.60000E-03,H,Sr,Cl,,-9.60000E-02,Cl,HCO3,Mg +7.00000E-02,,Na,Mg,,-5.30000E-02,,Cl,CO3, +,-1.42902E-02,Na,Mg,Cl,,1.60000E-02,Cl,CO3,Na +,-1.50000E-02,Na,Mg,SO4,-4.02238E-02,,Cl,BOH4, +5.00000E-02,,Na,Ca,,,-1.32000E-02,Cl,BOH4,Na +,-3.00000E-03,Na,Ca,Cl,,-2.35000E-01,Cl,BOH4,Mg +,-5.50000E-02,Na,Ca,SO4,,-8.00000E-01,Cl,BOH4,Ca +1.77971E-04,,Na,K,,1.00000E-02,,Cl,F, +,-4.92195E-03,Na,K,Cl,,2.33000E-03,Cl,F,Na +,5.27146E-03,Na,K,SO4,,-6.77000E-02,SO4,HSO4,K +,-2.20000E-03,Na,K,Br,-1.30000E-02,,SO4,OH, +7.00000E-02,,Na,Sr,,,-9.00000E-03,SO4,OH,Na +,-1.50000E-02,Na,Sr,Cl,,-5.00000E-02,SO4,OH,K +7.00000E-03,,Mg,Ca,,1.00000E-02,,SO4,HCO3, +,-1.20000E-02,Mg,Ca,Cl,,-5.00000E-03,SO4,HCO3,Na +,2.40000E-02,Mg,Ca,SO4,,-1.61000E-01,SO4,HCO3,Mg +,-2.54433E-02,Mg,K,Cl,2.00000E-02,,SO4,CO3, +,-4.80000E-02,Mg,K,SO4,,-5.00000E-03,SO4,CO3,Na +,2.80000E-02,Mg,MgOH,Cl,,-9.00000E-03,SO4,CO3,K +1.15600E-01,,Ca,K,,-1.20000E-02,,SO4,BOH4, +,-4.97190E-02,Ca,K,Cl,-6.50000E-02,,OH,Br, +7.00000E-02,,K,Sr,,,-1.80000E-02,OH,Br,Na +,-1.50000E-02,K,Sr,Cl,,-1.40000E-02,OH,Br,K \ No newline at end of file diff --git a/tests/data/CWTD23 SI Chart 9 part 3.txt b/tests/data/CWTD23 SI Chart 9 part 3.txt new file mode 100644 index 00000000..8b4f1463 --- /dev/null +++ b/tests/data/CWTD23 SI Chart 9 part 3.txt @@ -0,0 +1,13 @@ + lambda_nx n ion +-9.70000E-02 BOH3 Na +-1.40000E-01 BOH3 K + 8.76379E-02 CO2 Na + 1.28444E-01 CO2 Mg + 1.19529E-01 CO2 Ca + 6.25749E-02 CO2 K + 1.10000E-02 HF Na + 7.45000E-02 MgCO3 Na + 9.10000E-02 BOH3 Cl + 1.80000E-02 BOH3 SO4 + 3.23185E-02 CO2 Cl + 3.19271E-01 CO2 SO4 \ No newline at end of file diff --git a/tests/data/CWTD23 SI Chart 9 part 4.txt b/tests/data/CWTD23 SI Chart 9 part 4.txt new file mode 100644 index 00000000..98d36e8b --- /dev/null +++ b/tests/data/CWTD23 SI Chart 9 part 4.txt @@ -0,0 +1,10 @@ + zeta n c a + 4.60000E-02 BOH3 Na SO4 +-9.18227E-03 CO2 H Cl +-5.86999E-03 CO2 Na Cl +-6.74375E-01 CO2 Na SO4 +-1.60427E-03 CO2 Mg Cl +-1.04527E-01 CO2 Mg SO4 +-2.20997E-03 CO2 Ca Cl +-2.40096E-02 CO2 K Cl +-3.07389E-01 CO2 K SO4 \ No newline at end of file diff --git a/tests/data/CWTD23 SI final table.csv b/tests/data/CWTD23 SI final table.csv new file mode 100644 index 00000000..85a66b9e --- /dev/null +++ b/tests/data/CWTD23 SI final table.csv @@ -0,0 +1,5 @@ +temperature,mMgF,yMgF,mCaF,yCaF,mCl,yCl,mSO4,ySO4,mHSO4,yHSO4,mOH,yOH,mBr,yBr,mHCO3,yHCO3,mCO3,yCO3,mBOH4,yBOH4,mF,yF,mBOH3,yBOH3,mCO2,yCO2,mHF,yHF,mMgCO3,yMgCO3,mCaCO3,yCaCO3,aH2O,osm,mH,yH,mNa,yNa,mMg,yMg,mCa,yCa,mK,yK,mMgOH,yMgOH,mSr,ySr,mSrCO3,ySrCO3 +25,2.33170E-05,8.32521E-01,1.68445E-06,6.72832E-01,5.65765E-01,6.92512E-01,2.92643E-02,1.12575E-01,1.71265E-09,8.26416E-01,3.83131E-06,5.74798E-01,8.72800E-04,7.15046E-01,1.78097E-03,5.79074E-01,1.06090E-04,1.00863E-01,1.03961E-04,3.99110E-01,4.57984E-05,5.73959E-01,3.26339E-04,1.00745E+00,9.35624E-06,1.13831E+00,1.74961E-10,1.01075E+00,1.10929E-04,1.07511E+00,3.03943E-05,1.00000E+00,0.98125518,0.90517,6.18895E-09,7.28879E-01,4.86060E-01,6.39507E-01,5.46036E-02,2.03935E-01,1.06247E-02,1.89099E-01,1.05797E-02,5.96067E-01,4.29768E-06,8.78706E-01,9.37380E-05,1.84749E-01,2.61988E-07,1.00000E+00 +25,2.33615E-05,8.32709E-01,1.68932E-06,6.72957E-01,5.65757E-01,6.92689E-01,2.92637E-02,1.12650E-01,1.53859E-07,8.26433E-01,4.26797E-08,5.74732E-01,8.72788E-04,7.15193E-01,1.38320E-03,5.79218E-01,9.18021E-07,1.00857E-01,1.52217E-06,3.98992E-01,4.57325E-05,5.73995E-01,4.28772E-04,1.00764E+00,6.52627E-04,1.13817E+00,1.56868E-08,1.01073E+00,9.63356E-07,1.07495E+00,2.64169E-07,1.00000E+00,0.98126499,0.90538,5.55564E-07,7.28984E-01,4.85053E-01,6.39588E-01,5.47170E-02,2.04227E-01,1.06547E-02,1.89409E-01,1.05796E-02,5.96102E-01,4.80170E-08,8.79082E-01,9.39964E-05,1.84997E-01,2.27623E-09,1.00000E+00 +5,1.99771E-05,8.51870E-01,1.38613E-06,6.88472E-01,5.65765E-01,6.88193E-01,2.92643E-02,1.08477E-01,4.80269E-10,8.57577E-01,1.33085E-06,5.65216E-01,8.72800E-04,7.09227E-01,1.79428E-03,5.71649E-01,1.14093E-04,1.03389E-01,1.18560E-04,3.91178E-01,4.94367E-05,5.73958E-01,3.11740E-04,1.00745E+00,7.18388E-06,1.15797E+00,6.90393E-11,1.01075E+00,9.67552E-05,1.07511E+00,2.54632E-05,1.00000E+00,0.98140082,0.89806,3.18171E-09,7.60537E-01,4.86060E-01,6.30594E-01,5.46242E-02,2.18742E-01,1.06300E-02,1.94793E-01,1.05797E-02,5.92627E-01,1.16515E-06,8.99106E-01,9.37798E-05,1.90917E-01,2.20173E-07,1.00000E+00 +5,2.00182E-05,8.52085E-01,1.39013E-06,6.88617E-01,5.65757E-01,6.88400E-01,2.92638E-02,1.08575E-01,5.65339E-08,8.57573E-01,1.13165E-08,5.65190E-01,8.72788E-04,7.09384E-01,1.38430E-03,5.71830E-01,7.48576E-07,1.03404E-01,1.38751E-06,3.91103E-01,4.93826E-05,5.74028E-01,4.28907E-04,1.00764E+00,6.52116E-04,1.15783E+00,8.11190E-09,1.01073E+00,6.37094E-07,1.07495E+00,1.67771E-07,1.00000E+00,0.98140984,0.89831,3.74141E-07,7.60651E-01,4.85053E-01,6.30706E-01,5.47207E-02,2.19075E-01,1.06551E-02,1.95125E-01,1.05796E-02,5.92686E-01,9.93495E-09,8.99536E-01,9.39973E-05,1.91195E-01,1.45024E-09,1.00000E+00 \ No newline at end of file diff --git a/tests/data/Humphreys22-SI21.xlsx b/tests/data/Humphreys22-SI21.xlsx new file mode 100644 index 00000000..187ce3fc Binary files /dev/null and b/tests/data/Humphreys22-SI21.xlsx differ diff --git a/tests/data/Humphreys22-SI7.xlsx b/tests/data/Humphreys22-SI7.xlsx new file mode 100644 index 00000000..0963fd78 Binary files /dev/null and b/tests/data/Humphreys22-SI7.xlsx differ diff --git a/tests/data/M88 Table 4.csv b/tests/data/M88 Table 4.csv index 1d40a212..e4141ca8 100644 --- a/tests/data/M88 Table 4.csv +++ b/tests/data/M88 Table 4.csv @@ -2,6 +2,6 @@ point,Na,Ca,Cl,SO4,a_H2O 1,6.734,0.02590,6.734,0.0259,0.7413 2,6.930,0.00637,6.664,0.1391,0.7401 3,7.381,0.00121,6.509,0.4374,0.7364 -4,7.382,0.00000,6.590,0.4366,0.7365 +4,7.382,0.00000,6.509,0.4366,0.7365 5,5.976,0.00371,0.000,2.9920,0.9040 6,3.292,0.00794,0.000,1.6540,0.9445 diff --git a/tests/data/pytzerQuickStart_py_v0_4_3.csv b/tests/data/pytzerQuickStart_py_v0_4_3.csv new file mode 100644 index 00000000..91013f28 --- /dev/null +++ b/tests/data/pytzerQuickStart_py_v0_4_3.csv @@ -0,0 +1,28 @@ +tempK,pres,H,Na,Mg,Ca,K,MgOH,trisH,Cl,SO4,HSO4,OH,tris,osm,aw,gH,gNa,gMg,gCa,gK,gMgOH,gtrisH,gCl,gSO4,gHSO4,gOH,gtris +2.731499999999999773e+02,1.013250000000000028e+01,1.000000000000000000e+00,1.500000000000000000e+00,5.000000000000000000e-01,2.000000000000000111e-01,1.199999999999999956e+00,3.499999999999999778e-01,4.500000000000000111e-01,2.250000000000000000e+00,1.500000000000000000e+00,2.500000000000000000e-01,4.000000000000000222e-01,5.999999999999999778e-01,1.270651165535649163e+00,7.917687092281933126e-01,1.986900846348706562e+00,7.596126256208743932e-01,3.921451299821462899e-01,1.736326442962471961e-01,8.365271327656608191e-01,3.188864987613973523e-01,3.089483220459226520e-01,1.239920021462926902e+00,3.305120155151135969e-02,1.424828301056913027e+01,3.109452700972893946e-01,1.000000000000000000e+00 +2.781499999999999773e+02,1.013250000000000028e+01,1.000000000000000000e+00,1.500000000000000000e+00,5.000000000000000000e-01,2.000000000000000111e-01,1.199999999999999956e+00,3.499999999999999778e-01,4.500000000000000111e-01,2.250000000000000000e+00,1.500000000000000000e+00,2.500000000000000000e-01,4.000000000000000222e-01,5.999999999999999778e-01,1.277479955771146258e+00,7.907758124651669274e-01,1.911575656894108022e+00,7.555989031374172882e-01,3.875989455842740461e-01,1.839747409152557300e-01,8.938974743786546329e-01,3.162499744149512848e-01,3.063939656337459905e-01,1.256641199554693111e+00,3.286018609176129951e-02,1.463440320477755385e+01,3.177629818327650235e-01,1.000000000000000000e+00 +2.831499999999999773e+02,1.013250000000000028e+01,1.000000000000000000e+00,1.500000000000000000e+00,5.000000000000000000e-01,2.000000000000000111e-01,1.199999999999999956e+00,3.499999999999999778e-01,4.500000000000000111e-01,2.250000000000000000e+00,1.500000000000000000e+00,2.500000000000000000e-01,4.000000000000000222e-01,5.999999999999999778e-01,1.282751178598207531e+00,7.900102354643958602e-01,1.838689969439061267e+00,7.509202644001256033e-01,3.807159280834045423e-01,1.849904391373967949e-01,9.508530981886873512e-01,3.135802867847282127e-01,3.038074794797451239e-01,1.263968791439409323e+00,3.250006137201097434e-02,1.515130452211254308e+01,3.247630561516453573e-01,1.000000000000000000e+00 +2.881499999999999773e+02,1.013250000000000028e+01,1.000000000000000000e+00,1.500000000000000000e+00,5.000000000000000000e-01,2.000000000000000111e-01,1.199999999999999956e+00,3.499999999999999778e-01,4.500000000000000111e-01,2.250000000000000000e+00,1.500000000000000000e+00,2.500000000000000000e-01,4.000000000000000222e-01,5.999999999999999778e-01,1.286963589581041845e+00,7.893989700524186581e-01,1.768058002083337854e+00,7.455205702833996861e-01,3.718027117627663580e-01,1.821808790829727853e-01,1.007197348046920737e+00,3.108360064229080399e-01,3.011487252951024485e-01,1.265745428341789047e+00,3.198532477330902346e-02,1.580990408755105214e+01,3.312963568243175172e-01,1.000000000000000000e+00 +2.931499999999999773e+02,1.013250000000000028e+01,1.000000000000000000e+00,1.500000000000000000e+00,5.000000000000000000e-01,2.000000000000000111e-01,1.199999999999999956e+00,3.499999999999999778e-01,4.500000000000000111e-01,2.250000000000000000e+00,1.500000000000000000e+00,2.500000000000000000e-01,4.000000000000000222e-01,5.999999999999999778e-01,1.290307235291805910e+00,7.889141083992003978e-01,1.699619608133386528e+00,7.394317797774971890e-01,3.611676629976013353e-01,1.775515420098804087e-01,1.062777359987671089e+00,3.079960063676356885e-01,2.983972345449617536e-01,1.263487894495997521e+00,3.133214260557735248e-02,1.662568018996233477e+01,3.369333633624798652e-01,1.000000000000000000e+00 +2.981499999999999773e+02,1.013250000000000028e+01,1.000000000000000000e+00,1.500000000000000000e+00,5.000000000000000000e-01,2.000000000000000111e-01,1.199999999999999956e+00,3.499999999999999778e-01,4.500000000000000111e-01,2.250000000000000000e+00,1.500000000000000000e+00,2.500000000000000000e-01,4.000000000000000222e-01,5.999999999999999778e-01,1.292888688580800416e+00,7.885399759023913324e-01,1.633359451976793331e+00,7.327250319582517823e-01,3.491117542601997470e-01,1.719813047844447607e-01,1.117465247091178338e+00,3.050477394674859233e-01,2.955408511129798410e-01,1.257994267642398523e+00,3.055762635809584904e-02,1.761886188906396811e+01,3.413889699758317353e-01,1.000000000000000000e+00 +3.031499999999999773e+02,1.013250000000000028e+01,1.000000000000000000e+00,1.500000000000000000e+00,5.000000000000000000e-01,2.000000000000000111e-01,1.199999999999999956e+00,3.499999999999999778e-01,4.500000000000000111e-01,2.250000000000000000e+00,1.500000000000000000e+00,2.500000000000000000e-01,4.000000000000000222e-01,5.999999999999999778e-01,1.294785096546285708e+00,7.882652407335171141e-01,1.569280885423912864e+00,7.254894786443010224e-01,3.359206783341233682e-01,1.659032919818008156e-01,1.171153837744317361e+00,3.019835633475233538e-01,2.925721708007287258e-01,1.249768013709677161e+00,2.967918934862700392e-02,1.881514936376612468e+01,3.444815621088829216e-01,1.000000000000000000e+00 +3.081499999999999773e+02,1.013250000000000028e+01,1.000000000000000000e+00,1.500000000000000000e+00,5.000000000000000000e-01,2.000000000000000111e-01,1.199999999999999956e+00,3.499999999999999778e-01,4.500000000000000111e-01,2.250000000000000000e+00,1.500000000000000000e+00,2.500000000000000000e-01,4.000000000000000222e-01,5.999999999999999778e-01,1.296060939404793722e+00,7.880804615283623082e-01,1.507394283962848913e+00,7.178209781721738292e-01,3.218594689192699754e-01,1.595494662301328859e-01,1.223754990369602780e+00,2.987991107475755359e-01,2.894869624547812270e-01,1.239167946839898171e+00,2.871403706460205416e-02,2.024677580297213453e+01,3.461075496564077758e-01,1.000000000000000000e+00 +3.131499999999999773e+02,1.013250000000000028e+01,1.000000000000000000e+00,1.500000000000000000e+00,5.000000000000000000e-01,2.000000000000000111e-01,1.199999999999999956e+00,3.499999999999999778e-01,4.500000000000000111e-01,2.250000000000000000e+00,1.500000000000000000e+00,2.500000000000000000e-01,4.000000000000000222e-01,5.999999999999999778e-01,1.296774090044934269e+00,7.879771954178967919e-01,1.447710879659009908e+00,7.098155588954849771e-01,3.071693130765590918e-01,1.530525634962173753e-01,1.275198325850684933e+00,2.954923944305531402e-01,2.862833007707838995e-01,1.226472278445068564e+00,2.767877774277826067e-02,2.195392560729232656e+01,3.462238379555496737e-01,1.000000000000000000e+00 +3.181499999999999773e+02,1.013250000000000028e+01,1.000000000000000000e+00,1.500000000000000000e+00,5.000000000000000000e-01,2.000000000000000111e-01,1.199999999999999956e+00,3.499999999999999778e-01,4.500000000000000111e-01,2.250000000000000000e+00,1.500000000000000000e+00,2.500000000000000000e-01,4.000000000000000222e-01,5.999999999999999778e-01,1.296978245072167191e+00,7.879476357180557056e-01,1.390239234437057325e+00,7.015655603202929358e-01,2.920660759722942812e-01,1.464932653080993075e-01,1.325429925010778387e+00,2.920632422265184713e-01,2.829610189445178614e-01,1.211909830761835671e+00,2.658913470466101395e-02,2.398658242816286901e+01,3.448347584261822751e-01,1.000000000000000000e+00 +3.231499999999999773e+02,1.013250000000000028e+01,1.000000000000000000e+00,1.500000000000000000e+00,5.000000000000000000e-01,2.000000000000000111e-01,1.199999999999999956e+00,3.499999999999999778e-01,4.500000000000000111e-01,2.250000000000000000e+00,1.500000000000000000e+00,2.500000000000000000e-01,4.000000000000000222e-01,5.999999999999999778e-01,1.296723983116087942e+00,7.879844505925435172e-01,1.334983191531409430e+00,6.931573995758490980e-01,2.767400982989949298e-01,1.399237506027251332e-01,1.374410919837756095e+00,2.885129050188177668e-01,2.795213288752401715e-01,1.195676780474124401e+00,2.545974379032903134e-02,2.640692012984681369e+01,3.419817378893591497e-01,1.000000000000000000e+00 +2.981499999999999773e+02,1.013250000000000028e+01,0.000000000000000000e+00,1.000000000000000056e-01,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,1.000000000000000056e-01,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,9.325272386354586107e-01,9.966457424922744446e-01,8.002421789748257464e-01,7.776755105901680398e-01,3.705514561052524192e-01,3.685055590352138144e-01,7.668750232203559447e-01,9.018767617098231160e-01,7.383821443108892213e-01,7.776755105901680398e-01,3.142543178366834500e-01,7.843212830163399651e-01,7.691560822325580471e-01,1.000000000000000000e+00 +2.981499999999999773e+02,1.013250000000000028e+01,0.000000000000000000e+00,1.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,1.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,9.363158308002696995e-01,9.668272358831682123e-01,8.617434503250347433e-01,6.571916893751158506e-01,2.418274065576971332e-01,2.206471444431880868e-01,5.935216711036866988e-01,1.049571440136835232e+00,4.788057134200547349e-01,6.571916893751158506e-01,8.438257096136696223e-02,6.555504651286744311e-01,5.973246561507280505e-01,1.000000000000000000e+00 +2.981499999999999773e+02,1.013250000000000028e+01,0.000000000000000000e+00,2.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,2.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,9.838264253427924100e-01,9.315601365353554097e-01,1.139827189233774130e+00,6.684380543027761412e-01,3.067111161227217275e-01,2.524215114102060231e-01,5.521442515943266738e-01,9.594461722228686540e-01,3.968394702878727531e-01,6.684380543027761412e-01,5.057248861488232439e-02,6.223887878073266489e-01,5.540517840184483456e-01,1.000000000000000000e+00 +2.981499999999999773e+02,1.013250000000000028e+01,0.000000000000000000e+00,3.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,3.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,1.044505120847031288e+00,8.932394807625034794e-01,1.579673752064217229e+00,7.135054025991576232e-01,4.486996361187824967e-01,3.353581702696908362e-01,5.356849263733566291e-01,8.070361324248296331e-01,3.532030201969094119e-01,7.135054025991576232e-01,3.703832459157098411e-02,6.003218342557061771e-01,5.369807042428165200e-01,1.000000000000000000e+00 +2.981499999999999773e+02,1.013250000000000028e+01,0.000000000000000000e+00,0.000000000000000000e+00,1.000000000000000056e-01,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,2.000000000000000111e-01,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,8.617902997540748400e-01,9.953532838712774167e-01,6.800514026013662061e-01,6.514783631898126703e-01,2.373632837601243883e-01,2.359663657296998673e-01,6.278308561842269597e-01,7.894969050101438013e-01,5.899317193981068463e-01,7.850596588212667148e-01,1.607382646442801766e-01,1.189039032681080021e+00,6.083285540412896042e-01,1.000000000000000000e+00 +2.981499999999999773e+02,1.013250000000000028e+01,0.000000000000000000e+00,0.000000000000000000e+00,1.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,2.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,1.108784020511432100e+00,9.418358915367924800e-01,7.893824160133536827e-01,5.171146794125383028e-01,1.451244963268614185e-01,1.221681695233233778e-01,3.786125346400965319e-01,5.301674443283694860e-01,2.889660696287453812e-01,1.118729183004812500e+00,7.313170314936970340e-02,1.634464862236418847e+00,2.800816892133365932e-01,1.000000000000000000e+00 +2.981499999999999773e+02,1.013250000000000028e+01,0.000000000000000000e+00,0.000000000000000000e+00,2.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,4.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,1.531301825450311238e+00,8.474542577733499282e-01,1.425851182646996396e+00,5.872507654290760604e-01,2.963411250659474527e-01,1.899084105611521245e-01,3.062602266537939877e-01,3.543159595885431168e-01,2.190849473386949076e-01,1.991362829271862367e+00,8.428613133431360482e-02,3.004364081651869078e+00,1.866468415079050869e-01,1.000000000000000000e+00 +2.981499999999999773e+02,1.013250000000000028e+01,0.000000000000000000e+00,0.000000000000000000e+00,3.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,6.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,2.020531350022046091e+00,7.206520509852143430e-01,2.905661756276947116e+00,7.151814505834948044e-01,8.614249434227910784e-01,3.901997547845781344e-01,2.514856234406388502e-01,2.764841735263518507e-01,1.871666093411497589e-01,3.851685742491151920e+00,1.248252019695434284e-01,1.729928078869860997e+01,1.378367889568912763e-01,1.000000000000000000e+00 +2.981499999999999773e+02,1.013250000000000028e+01,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,1.000000000000000056e-01,0.000000000000000000e+00,0.000000000000000000e+00,1.000000000000000056e-01,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,9.266424530851353758e-01,9.966668744787137157e-01,7.969441238181294018e-01,7.777467093013644694e-01,3.664971982376761250e-01,3.743804464956406175e-01,7.679853227378377056e-01,9.025707184556972518e-01,7.389502987326819206e-01,7.679853227378377056e-01,3.127715548106541621e-01,9.938285248772641411e-01,7.833938899308788839e-01,1.000000000000000000e+00 +2.981499999999999773e+02,1.013250000000000028e+01,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,1.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,1.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,8.988551358284879722e-01,9.681330521877006268e-01,8.192003456367619174e-01,6.561033558730196003e-01,2.157627402710333153e-01,2.505193141322052397e-01,6.046279313626753416e-01,1.058468444766088590e+00,4.828644525262330012e-01,6.046279313626753416e-01,8.291521867991059891e-02,5.388170901761772935e-01,6.836965000448789187e-01,1.000000000000000000e+00 +2.981499999999999773e+02,1.013250000000000028e+01,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,2.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,2.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,9.135091845339095018e-01,9.362923871627033545e-01,1.001798257241684365e+00,6.577492360584993314e-01,2.352172389246501849e-01,2.951158634071363585e-01,5.741262197158149005e-01,9.705046499035268059e-01,4.014134011159205540e-01,5.741262197158149005e-01,4.974411377092958358e-02,3.955808514980437840e-01,7.021742326345865592e-01,1.000000000000000000e+00 +2.981499999999999773e+02,1.013250000000000028e+01,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,3.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,3.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,9.373633822565380358e-01,9.036441748309678168e-01,1.249528549227590046e+00,6.838260559383528836e-01,2.859745979179877384e-01,3.674890460932229708e-01,5.701779766360495216e-01,8.151127285369744735e-01,3.567377790820524530e-01,5.701779766360495216e-01,3.622170039964870553e-02,1.234937793565655584e+00,7.454491834211794954e-01,1.000000000000000000e+00 +2.981499999999999773e+02,1.013250000000000028e+01,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,1.000000000000000056e-01,1.000000000000000000e+00,9.982001217271316840e-01,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00 +2.981499999999999773e+02,1.013250000000000028e+01,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,9.821463000533079413e-01,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00 +2.981499999999999773e+02,1.013250000000000028e+01,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,2.000000000000000000e+00,1.000000000000000000e+00,9.646113547084023132e-01,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00 +2.981499999999999773e+02,1.013250000000000028e+01,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,3.000000000000000000e+00,1.000000000000000000e+00,9.473894730162663036e-01,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00 diff --git a/tests/data/pytzerQuickStart_py_v0_4_3__GM89.csv b/tests/data/pytzerQuickStart_py_v0_4_3__GM89.csv new file mode 100644 index 00000000..5fdc4fdd --- /dev/null +++ b/tests/data/pytzerQuickStart_py_v0_4_3__GM89.csv @@ -0,0 +1,28 @@ +tempK,pres,H,Na,Mg,Ca,K,MgOH,trisH,Cl,SO4,HSO4,OH,tris,osm,aw,gH,gNa,gMg,gCa,gK,gMgOH,gtrisH,gCl,gSO4,gHSO4,gOH,gtris +2.731499999999999773e+02,1.013250000000000028e+01,1.000000000000000000e+00,1.500000000000000000e+00,5.000000000000000000e-01,2.000000000000000111e-01,1.199999999999999956e+00,3.499999999999999778e-01,4.500000000000000111e-01,2.250000000000000000e+00,1.500000000000000000e+00,2.500000000000000000e-01,4.000000000000000222e-01,5.999999999999999778e-01,7.062372422796003857e-01,8.782945950273439717e-01,2.857331378599501925e-01,4.182016043905244507e-01,5.434159945176756344e-03,1.444179920191257238e-01,3.745542479901715627e-01,2.857331378599501925e-01,2.857331378599501925e-01,5.109166954927724102e-01,1.107284846948461063e-02,2.638977225444948393e-01,2.638977225444948393e-01,1.000000000000000000e+00 +2.781499999999999773e+02,1.013250000000000028e+01,1.000000000000000000e+00,1.500000000000000000e+00,5.000000000000000000e-01,2.000000000000000111e-01,1.199999999999999956e+00,3.499999999999999778e-01,4.500000000000000111e-01,2.250000000000000000e+00,1.500000000000000000e+00,2.500000000000000000e-01,4.000000000000000222e-01,5.999999999999999778e-01,7.207169875212338095e-01,8.759608256634302537e-01,2.816004399951441139e-01,4.642778626266697017e-01,5.171356160560190360e-03,1.519660046398969844e-01,3.871910769212975612e-01,2.816004399951441139e-01,2.816004399951441139e-01,5.182210093424902686e-01,1.196306404918001144e-02,2.599372422608295929e-01,2.599372422608295929e-01,1.000000000000000000e+00 +2.831499999999999773e+02,1.013250000000000028e+01,1.000000000000000000e+00,1.500000000000000000e+00,5.000000000000000000e-01,2.000000000000000111e-01,1.199999999999999956e+00,3.499999999999999778e-01,4.500000000000000111e-01,2.250000000000000000e+00,1.500000000000000000e+00,2.500000000000000000e-01,4.000000000000000222e-01,5.999999999999999778e-01,7.269335154126306264e-01,8.749607819499574113e-01,2.773547350542601708e-01,4.923045356081406365e-01,4.909810348243863996e-03,1.516195341367289895e-01,3.984041282880847468e-01,2.773547350542601708e-01,2.773547350542601708e-01,5.214730264428605322e-01,1.233830787010791082e-02,2.558663137424085909e-01,2.558663137424085909e-01,1.000000000000000000e+00 +2.881499999999999773e+02,1.013250000000000028e+01,1.000000000000000000e+00,1.500000000000000000e+00,5.000000000000000000e-01,2.000000000000000111e-01,1.199999999999999956e+00,3.499999999999999778e-01,4.500000000000000111e-01,2.250000000000000000e+00,1.500000000000000000e+00,2.500000000000000000e-01,4.000000000000000222e-01,5.999999999999999778e-01,7.297910255396373724e-01,8.745014815857097279e-01,2.731305249959270487e-01,5.117783485064506532e-01,4.655176849261500986e-03,1.481981047009016395e-01,4.084349117963301246e-01,2.731305249959270487e-01,2.731305249959270487e-01,5.225683215780814184e-01,1.247060470558513864e-02,2.518107835212509693e-01,2.518107835212509693e-01,1.000000000000000000e+00 +2.931499999999999773e+02,1.013250000000000028e+01,1.000000000000000000e+00,1.500000000000000000e+00,5.000000000000000000e-01,2.000000000000000111e-01,1.199999999999999956e+00,3.499999999999999778e-01,4.500000000000000111e-01,2.250000000000000000e+00,1.500000000000000000e+00,2.500000000000000000e-01,4.000000000000000222e-01,5.999999999999999778e-01,7.309143861663111030e-01,8.743209848455324451e-01,2.689534824552924364e-01,5.262479065392274835e-01,4.408548551168494506e-03,1.434336583738412829e-01,4.173879217532588948e-01,2.689534824552924364e-01,2.689534824552924364e-01,5.222203534250097201e-01,1.246069697868473596e-02,2.477950802694408039e-01,2.477950802694408039e-01,1.000000000000000000e+00 +2.981499999999999773e+02,1.013250000000000028e+01,1.000000000000000000e+00,1.500000000000000000e+00,5.000000000000000000e-01,2.000000000000000111e-01,1.199999999999999956e+00,3.499999999999999778e-01,4.500000000000000111e-01,2.250000000000000000e+00,1.500000000000000000e+00,2.500000000000000000e-01,4.000000000000000222e-01,5.999999999999999778e-01,7.309851978666368488e-01,8.743096083752250891e-01,2.648220792261193890e-01,5.373488000574595524e-01,4.169959105136950353e-03,1.380649601532618620e-01,4.253301226297480642e-01,2.648220792261193890e-01,2.648220792261193890e-01,5.207801142795274174e-01,1.235502722556713201e-02,2.438182706967681745e-01,2.438182706967681745e-01,1.000000000000000000e+00 +3.031499999999999773e+02,1.013250000000000028e+01,1.000000000000000000e+00,1.500000000000000000e+00,5.000000000000000000e-01,2.000000000000000111e-01,1.199999999999999956e+00,3.499999999999999778e-01,4.500000000000000111e-01,2.250000000000000000e+00,1.500000000000000000e+00,2.500000000000000000e-01,4.000000000000000222e-01,5.999999999999999778e-01,7.303319295524042243e-01,8.744145668110627767e-01,2.607271848132418635e-01,5.459448808439228973e-01,3.939194259419566586e-03,1.324409527385421725e-01,4.323159085254302259e-01,2.607271848132418635e-01,2.607271848132418635e-01,5.184518658987588013e-01,1.217861247742121900e-02,2.398723251388059363e-01,2.398723251388059363e-01,1.000000000000000000e+00 +3.081499999999999773e+02,1.013250000000000028e+01,1.000000000000000000e+00,1.500000000000000000e+00,5.000000000000000000e-01,2.000000000000000111e-01,1.199999999999999956e+00,3.499999999999999778e-01,4.500000000000000111e-01,2.250000000000000000e+00,1.500000000000000000e+00,2.500000000000000000e-01,4.000000000000000222e-01,5.999999999999999778e-01,7.291276073767847254e-01,8.746080942549333548e-01,2.566580475313561815e-01,5.525391912642051429e-01,3.716020638567173531e-03,1.267370801634971067e-01,4.383950999909317359e-01,2.566580475313561815e-01,2.566580475313561815e-01,5.153690387964847686e-01,1.194673274289369952e-02,2.359476943156209594e-01,2.359476943156209594e-01,1.000000000000000000e+00 +3.131499999999999773e+02,1.013250000000000028e+01,1.000000000000000000e+00,1.500000000000000000e+00,5.000000000000000000e-01,2.000000000000000111e-01,1.199999999999999956e+00,3.499999999999999778e-01,4.500000000000000111e-01,2.250000000000000000e+00,1.500000000000000000e+00,2.500000000000000000e-01,4.000000000000000222e-01,5.999999999999999778e-01,7.274689853988456356e-01,8.748746951047501330e-01,2.526043376943494234e-01,5.574478584110224011e-01,3.500250973684984092e-03,1.210449646286840819e-01,4.436157705260125317e-01,2.526043376943494234e-01,2.526043376943494234e-01,5.116264652774196175e-01,1.166978219025168600e-02,2.320352156847610980e-01,2.320352156847610980e-01,1.000000000000000000e+00 +3.181499999999999773e+02,1.013250000000000028e+01,1.000000000000000000e+00,1.500000000000000000e+00,5.000000000000000000e-01,2.000000000000000111e-01,1.199999999999999956e+00,3.499999999999999778e-01,4.500000000000000111e-01,2.250000000000000000e+00,1.500000000000000000e+00,2.500000000000000000e-01,4.000000000000000222e-01,5.999999999999999778e-01,7.254124430803614576e-01,8.752053690718412104e-01,2.485568487382299463e-01,5.608827653209497166e-01,3.291756595491947702e-03,1.154135581083153700e-01,4.480251962695029344e-01,2.485568487382299463e-01,2.485568487382299463e-01,5.072960144160019169e-01,1.135551232284992725e-02,2.281267683102726762e-01,2.281267683102726762e-01,1.000000000000000000e+00 +3.231499999999999773e+02,1.013250000000000028e+01,1.000000000000000000e+00,1.500000000000000000e+00,5.000000000000000000e-01,2.000000000000000111e-01,1.199999999999999956e+00,3.499999999999999778e-01,4.500000000000000111e-01,2.250000000000000000e+00,1.500000000000000000e+00,2.500000000000000000e-01,4.000000000000000222e-01,5.999999999999999778e-01,7.229918126963166269e-01,8.755947453431948135e-01,2.445076930933001991e-01,5.629944591336792925e-01,3.090462067598785927e-03,1.098694524269453743e-01,4.516700541712272421e-01,2.445076930933001991e-01,2.445076930933001991e-01,5.024349590002848975e-01,1.101015222881662411e-02,2.242154562240317450e-01,2.242154562240317450e-01,1.000000000000000000e+00 +2.981499999999999773e+02,1.013250000000000028e+01,0.000000000000000000e+00,1.000000000000000056e-01,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,1.000000000000000056e-01,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,9.325272386354586107e-01,9.966457424922744446e-01,7.383821443108892213e-01,7.776755105901680398e-01,2.736188927533313997e-01,3.685055590352138144e-01,7.668750232203559447e-01,7.383821443108892213e-01,7.383821443108892213e-01,7.776755105901680398e-01,3.222476300513624214e-01,7.383821443108892213e-01,7.383821443108892213e-01,1.000000000000000000e+00 +2.981499999999999773e+02,1.013250000000000028e+01,0.000000000000000000e+00,1.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,1.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,9.363158308002696995e-01,9.668272358831682123e-01,4.788057134200547349e-01,6.571916893751158506e-01,3.935595532986398831e-02,2.206471444431880868e-01,5.935216711036866988e-01,4.788057134200547349e-01,4.788057134200547349e-01,6.571916893751158506e-01,8.988466430447046573e-02,4.788057134200547349e-01,4.788057134200547349e-01,1.000000000000000000e+00 +2.981499999999999773e+02,1.013250000000000028e+01,0.000000000000000000e+00,2.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,2.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,9.838264253427924100e-01,9.315601365353554097e-01,3.968394702878727531e-01,6.684380543027761412e-01,1.633943597866910347e-02,2.524215114102060231e-01,5.521442515943266738e-01,3.968394702878727531e-01,3.968394702878727531e-01,6.684380543027761412e-01,5.355974830849882795e-02,3.968394702878727531e-01,3.968394702878727531e-01,1.000000000000000000e+00 +2.981499999999999773e+02,1.013250000000000028e+01,0.000000000000000000e+00,3.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,3.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,1.044505120847031288e+00,8.932394807625034794e-01,3.532030201969094119e-01,7.135054025991576232e-01,9.261987939380718349e-03,3.353581702696908362e-01,5.356849263733566291e-01,3.532030201969094119e-01,3.532030201969094119e-01,7.135054025991576232e-01,3.897588590724829216e-02,3.532030201969094119e-01,3.532030201969094119e-01,1.000000000000000000e+00 +2.981499999999999773e+02,1.013250000000000028e+01,0.000000000000000000e+00,0.000000000000000000e+00,1.000000000000000056e-01,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,2.000000000000000111e-01,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,7.412369072270318382e-01,9.960019985083056193e-01,6.006803711520398714e-01,6.542831988602103577e-01,1.594641774420291758e-01,2.533687545489414772e-01,6.395514002826402367e-01,6.006803711520398714e-01,6.006803711520398714e-01,6.319253596019652752e-01,1.481762825090282842e-01,6.319253596019652752e-01,6.319253596019652752e-01,1.000000000000000000e+00 +2.981499999999999773e+02,1.013250000000000028e+01,0.000000000000000000e+00,0.000000000000000000e+00,1.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,2.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,5.594845119885116791e-01,9.702152348991421871e-01,3.254085977982292821e-01,5.185468607581866785e-01,2.202435222843856025e-02,2.002747219982044524e-01,4.455410189942163313e-01,3.254085977982292821e-01,3.254085977982292821e-01,3.852350430356383248e-01,2.079275679833012327e-02,3.852350430356383248e-01,3.852350430356383248e-01,1.000000000000000000e+00 +2.981499999999999773e+02,1.013250000000000028e+01,0.000000000000000000e+00,0.000000000000000000e+00,2.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,4.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,5.131657680956749346e-01,9.460422134075477940e-01,2.521545443385974639e-01,5.622845992224936307e-01,1.054801626828858439e-02,3.700658469850643395e-01,4.203267140040462535e-01,2.521545443385974639e-01,2.521545443385974639e-01,3.204739237629308790e-01,1.143204444477695370e-02,3.204739237629308790e-01,3.204739237629308790e-01,1.000000000000000000e+00 +2.981499999999999773e+02,1.013250000000000028e+01,0.000000000000000000e+00,0.000000000000000000e+00,3.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,6.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,4.893802253047268014e-01,9.237205733870466062e-01,2.132970326019776319e-01,6.645853784323926261e-01,6.711090700556418716e-03,8.508400344372202273e-01,4.258576009673012419e-01,2.132970326019776319e-01,2.132970326019776319e-01,2.862188794299707628e-01,8.633234669510072429e-03,2.862188794299707628e-01,2.862188794299707628e-01,1.000000000000000000e+00 +2.981499999999999773e+02,1.013250000000000028e+01,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,1.000000000000000056e-01,0.000000000000000000e+00,0.000000000000000000e+00,1.000000000000000056e-01,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,9.266424530851353758e-01,9.966668744787137157e-01,7.389502987326819206e-01,7.777467093013644694e-01,2.744680458719048199e-01,3.743804465731373488e-01,7.679853227378377056e-01,7.389502987326819206e-01,7.389502987326819206e-01,7.679853227378377056e-01,3.127715533249892932e-01,7.389502987326819206e-01,7.389502987326819206e-01,1.000000000000000000e+00 +2.981499999999999773e+02,1.013250000000000028e+01,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,1.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,1.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,8.988551358284879722e-01,9.681330521877006268e-01,4.828644525262330012e-01,6.561033558730196003e-01,4.079695832765516117e-02,2.505193193179551248e-01,6.046279313626753416e-01,4.828644525262330012e-01,4.828644525262330012e-01,6.046279313626753416e-01,8.291517929519107155e-02,4.828644525262330012e-01,4.828644525262330012e-01,1.000000000000000000e+00 +2.981499999999999773e+02,1.013250000000000028e+01,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,2.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,2.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,9.135091845339095018e-01,9.362923871627033545e-01,4.014134011159205540e-01,6.577492360584993314e-01,1.725678220067057220e-02,2.951158878427307952e-01,5.741262197158149005e-01,4.014134011159205540e-01,4.014134011159205540e-01,5.741262197158149005e-01,4.974401925720320361e-02,4.014134011159205540e-01,4.014134011159205540e-01,1.000000000000000000e+00 +2.981499999999999773e+02,1.013250000000000028e+01,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,3.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,3.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,9.373633822565380358e-01,9.036441748309678168e-01,3.567377790820524530e-01,6.838260559383528836e-01,9.830738478882217191e-03,3.674891145564385675e-01,5.701779766360495216e-01,3.567377790820524530e-01,3.567377790820524530e-01,5.701779766360495216e-01,3.622154555221047262e-02,3.567377790820524530e-01,3.567377790820524530e-01,1.000000000000000000e+00 +2.981499999999999773e+02,1.013250000000000028e+01,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,1.000000000000000056e-01,1.000000000000000000e+00,9.982001217271316840e-01,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00 +2.981499999999999773e+02,1.013250000000000028e+01,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,9.821463000533079413e-01,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00 +2.981499999999999773e+02,1.013250000000000028e+01,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,2.000000000000000000e+00,1.000000000000000000e+00,9.646113547084023132e-01,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00 +2.981499999999999773e+02,1.013250000000000028e+01,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,3.000000000000000000e+00,1.000000000000000000e+00,9.473894730162663036e-01,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00 diff --git a/tests/test_CRP94.py b/tests/test_CRP94.py index f5847508..fe5ed58f 100644 --- a/tests/test_CRP94.py +++ b/tests/test_CRP94.py @@ -1,4 +1,4 @@ -import pandas as pd +import pandas as pd, numpy as np import pytzer as pz # Update unsymmetrical mixing function @@ -16,9 +16,42 @@ # Close but not exact --- not sure why. Excluding OH makes things much worse. +def test_CRP94_table7(): + """Does Pytzer reproduce the interaction parameters at 298.15 K from Table 7?""" + tp = 298.15, 10.10325 + # H-HSO4 interaction + b0, b1, _, C0, C1, alph1, _, omega, _ = pz.parameters.bC_H_HSO4_CRP94(*tp) + assert np.round(b0, decimals=9) == 0.295_903_322 + assert np.round(b1, decimals=9) == 0.400_482_398 + assert np.round(C0, decimals=10) == -0.005_657_866_5 # should be -0.005_657_866_56 + assert np.round(C1, decimals=8) == -0.409_364_25 # should be -0.409_364_246 + assert alph1 == 2 + assert omega == 2.5 + # H-SO4 interaction + b0, b1, _, C0, C1, alph1, _, omega, _ = pz.parameters.bC_H_SO4_CRP94(*tp) + assert np.round(b0, decimals=11) == -0.008_386_089_24 + assert np.round(b1, decimals=9) == 0.314_734_575 + assert np.round(C0, decimals=10) == 0.010_192_247_4 + assert np.round(C1, decimals=8) == -0.323_662_60 # should be -0.323_662_605 + assert alph1 == 2 + assert omega == 2.5 + k_HSO4 = np.exp(pz.equilibrate.dissociation.HSO4_CRP94(tp[0]).item()) + assert np.round(k_HSO4, decimals=4) == 0.0105 + + def test_CRP94_table8(): - """Are Pytzer's values close to CRP94 Table 8?""" + """Are Pytzer's HSO4-SO4 speciation values close to CRP94 Table 8?""" assert (crp94.alpha_diff.abs() < 4e-5).all() +def test_CRP94_Aphi(): + """Does Pytzer reproduce the Aphi test values from CRP94 Appendix II?""" + Aphi_25 = np.round(pz.debyehueckel.Aosm_CRP94(298.15, 10.10325)[0], decimals=9) + assert Aphi_25 == 0.391_475_238 + Aphi_00 = np.round(pz.debyehueckel.Aosm_CRP94(273.15, 10.10325)[0], decimals=9) + assert Aphi_00 == 0.376_421_452 + + +# test_CRP94_table7() # test_CRP94_table8() +# test_CRP94_Aphi() diff --git a/tests/test_CWTD23_params.py b/tests/test_CWTD23_params.py new file mode 100644 index 00000000..9be352e9 --- /dev/null +++ b/tests/test_CWTD23_params.py @@ -0,0 +1,416 @@ +import pytzer as pz +import pandas as pd + +prmlib = pz.libraries.Clegg23 + +# Get sets of all ions / neutrals +cations = {k for k in prmlib["ca"].keys()} +anions = [] +for c in cations: + for a in prmlib["ca"][c].keys(): + anions.append(a) +anions = set(anions) +neutrals = [] +for nx in ["nc", "na", "nca"]: + for n in prmlib[nx].keys(): + neutrals.append(n) +neutrals = set(neutrals) + +# Chart 8 all at 25 °C +chart8_1 = pd.read_fwf("tests/data/CWTD23 SI Chart 8 part 1.txt") +chart8_2 = pd.read_csv("tests/data/CWTD23 SI Chart 8 part 2.csv") +chart8_3 = pd.read_fwf("tests/data/CWTD23 SI Chart 8 part 3.txt") +chart8_4 = pd.read_fwf("tests/data/CWTD23 SI Chart 8 part 4.txt") + +# Chart 9 all at 5 °C +chart9_1 = pd.read_fwf("tests/data/CWTD23 SI Chart 9 part 1.txt") +chart9_2 = pd.read_csv("tests/data/CWTD23 SI Chart 9 part 2.csv") +chart9_3 = pd.read_fwf("tests/data/CWTD23 SI Chart 9 part 3.txt") +chart9_4 = pd.read_fwf("tests/data/CWTD23 SI Chart 9 part 4.txt") + + +def test_ca(): + """Do all betas and Cs agree? The charts include all possible combinations.""" + print("Checking Chart 8 (betas and Cs at 25 °C)...") + for i, row in chart8_1.iterrows(): + p = {} + try: + ( + p["b0"], + p["b1"], + p["b2"], + p["C0"], + p["C1"], + p["alph1"], + p["alph2"], + p["omega"], + _, + ) = prmlib["ca"][row.cation][row.anion]( + 298.15, 10 + ) # Based on NaOH, appears that CWTD23 have evaluated at 1 bar + if p["alph1"] == -9: + p["alph1"] = 0 + if p["alph2"] == -9: + p["alph2"] = 0 + if p["omega"] == -9: + p["omega"] = 0 + except KeyError: + ( + p["b0"], + p["b1"], + p["b2"], + p["C0"], + p["C1"], + p["alph1"], + p["alph2"], + p["omega"], + ) = (0, 0, 0, 0, 0, 0, 0, 0) + for k in p.keys(): + assert "{:11.5e}".format(p[k]) == "{:11.5e}".format( + row[k] + ), "{} {} {} {:11.5e} {:11.5e}".format( + row.cation, row.anion, k, p[k], row[k] + ) + print("Chart 8 checked!") + + print("Checking Chart 9 (betas and Cs at 5 °C)...") + for i, row in chart9_1.iterrows(): + p = {} + try: + ( + p["b0"], + p["b1"], + p["b2"], + p["C0"], + p["C1"], + p["alph1"], + p["alph2"], + p["omega"], + _, + ) = prmlib["ca"][row.cation][row.anion]( + 278.15, 10 + ) # Based on NaOH, appears that CWTD23 have evaluated at 1 bar + if p["alph1"] == -9: + p["alph1"] = 0 + if p["alph2"] == -9: + p["alph2"] = 0 + if p["omega"] == -9: + p["omega"] = 0 + except KeyError: + ( + p["b0"], + p["b1"], + p["b2"], + p["C0"], + p["C1"], + p["alph1"], + p["alph2"], + p["omega"], + ) = (0, 0, 0, 0, 0, 0, 0, 0) + for k in p.keys(): + if row.cation == "H" and row.anion == "SO4" and k == "alph1": + # Doesn't work to full precision for some reason + assert "{:9.3e}".format(p[k]) == "{:9.3e}".format( + row[k] + ), "{} {} {} {:11.5e} {:11.5e}".format( + row.cation, row.anion, k, p[k], row[k] + ) + elif row.cation == "Mg" and row.anion == "Cl" and k == "C0": + # Very minor rounding error + assert "{:10.4e}".format(p[k]) == "{:10.4e}".format( + row[k] + ), "{} {} {} {:11.5e} {:11.5e}".format( + row.cation, row.anion, k, p[k], row[k] + ) + else: + assert "{:11.5e}".format(p[k]) == "{:11.5e}".format( + row[k] + ), "{} {} {} {:11.5e} {:11.5e}".format( + row.cation, row.anion, k, p[k], row[k] + ) + print("Chart 9 checked!") + # TODO There are quite a few issues with SRRJ87, check equations + + +def test_theta(): + """Do all thetas agree, including ones not on the charts (should all be zero)?""" + # At 25 °C + for c1 in cations: + for c2 in cations: + if c1 != c2: + try: + theta = "{:11.5e}".format(prmlib["cc"][c1][c2](298.15, 10)[0]) + except KeyError: + theta = "0.00000e+00" + L = ~chart8_2.theta_cc.isnull() & ( + ((chart8_2.cca_c1 == c1) & (chart8_2.cca_c2 == c2)) + | ((chart8_2.cca_c1 == c2) & (chart8_2.cca_c2 == c1)) + ) + if sum(L) == 1: + theta_chart = "{:11.5e}".format(chart8_2.theta_cc[L].values[0]) + else: + assert sum(L) == 0 + theta_chart = "0.00000e+00" + assert theta.upper() == theta_chart.upper(), "theta {} {} {} {}".format( + c1, c2, theta, theta_chart + ) + for a1 in anions: + for a2 in anions: + if a1 != a2: + try: + theta = "{:11.5e}".format(prmlib["aa"][a1][a2](298.15, 10)[0]) + except KeyError: + theta = "0.00000e+00" + L = ~chart8_2.theta_aa.isnull() & ( + ((chart8_2.caa_a1 == a1) & (chart8_2.caa_a2 == a2)) + | ((chart8_2.caa_a1 == a2) & (chart8_2.caa_a2 == a1)) + ) + if sum(L) == 1: + theta_chart = "{:11.5e}".format(chart8_2.theta_aa[L].values[0]) + else: + assert sum(L) == 0 + theta_chart = "0.00000e+00" + assert theta.upper() == theta_chart.upper(), "theta {} {} {} {}".format( + a1, a2, theta, theta_chart + ) + # At 5 °C + for c1 in cations: + for c2 in cations: + if c1 != c2: + try: + theta = "{:11.5e}".format(prmlib["cc"][c1][c2](278.15, 10)[0]) + except KeyError: + theta = "0.00000e+00" + L = ~chart9_2.theta_cc.isnull() & ( + ((chart9_2.cca_c1 == c1) & (chart9_2.cca_c2 == c2)) + | ((chart9_2.cca_c1 == c2) & (chart9_2.cca_c2 == c1)) + ) + if sum(L) == 1: + theta_chart = "{:11.5e}".format(chart9_2.theta_cc[L].values[0]) + else: + assert sum(L) == 0 + theta_chart = "0.00000e+00" + assert theta.upper() == theta_chart.upper(), "theta {} {} {} {}".format( + c1, c2, theta, theta_chart + ) + for a1 in anions: + for a2 in anions: + if a1 != a2: + try: + theta = "{:11.5e}".format(prmlib["aa"][a1][a2](278.15, 10)[0]) + except KeyError: + theta = "0.00000e+00" + L = ~chart9_2.theta_aa.isnull() & ( + ((chart9_2.caa_a1 == a1) & (chart9_2.caa_a2 == a2)) + | ((chart9_2.caa_a1 == a2) & (chart9_2.caa_a2 == a1)) + ) + if sum(L) == 1: + theta_chart = "{:11.5e}".format(chart9_2.theta_aa[L].values[0]) + else: + assert sum(L) == 0 + theta_chart = "0.00000e+00" + assert theta.upper() == theta_chart.upper(), "theta {} {} {} {}".format( + a1, a2, theta, theta_chart + ) + + +def test_psi(): + """Do all thetas agree, including ones not on the charts (should all be zero)?""" + # At 25 °C + for c1 in cations: + for c2 in cations: + if c1 != c2: + for a in anions: + try: + psi = "{:11.5e}".format(prmlib["cca"][c1][c2][a](298.15, 10)[0]) + except KeyError: + psi = "0.00000e+00" + L = ( + ~chart8_2.psi_cca.isnull() + & ( + ((chart8_2.cca_c1 == c1) & (chart8_2.cca_c2 == c2)) + | ((chart8_2.cca_c1 == c2) & (chart8_2.cca_c2 == c1)) + ) + & (chart8_2.cca_a == a) + ) + if sum(L) == 1: + psi_chart = "{:11.5e}".format(chart8_2.psi_cca[L].values[0]) + else: + assert sum(L) == 0 + psi_chart = "0.00000e+00" + assert ( + psi.upper() == psi_chart.upper() + ), "psi {} {} {} {} {}".format(c1, c2, a, psi, psi_chart) + for a1 in anions: + for a2 in anions: + if a1 != a2: + for c in cations: + try: + psi = "{:11.5e}".format(prmlib["caa"][c][a1][a2](298.15, 10)[0]) + except KeyError: + psi = "0.00000e+00" + L = ( + ~chart8_2.psi_caa.isnull() + & ( + ((chart8_2.caa_a1 == a1) & (chart8_2.caa_a2 == a2)) + | ((chart8_2.caa_a1 == a2) & (chart8_2.caa_a2 == a1)) + ) + & (chart8_2.caa_c == c) + ) + if sum(L) == 1: + psi_chart = "{:11.5e}".format(chart8_2.psi_caa[L].values[0]) + else: + assert sum(L) == 0 + psi_chart = "0.00000e+00" + assert ( + psi.upper() == psi_chart.upper() + ), "psi {} {} {} {} {}".format(c, a1, a2, psi, psi_chart) + # At 5 °C + for c1 in cations: + for c2 in cations: + if c1 != c2: + for a in anions: + try: + psi = "{:11.5e}".format(prmlib["cca"][c1][c2][a](278.15, 10)[0]) + except KeyError: + psi = "0.00000e+00" + L = ( + ~chart9_2.psi_cca.isnull() + & ( + ((chart9_2.cca_c1 == c1) & (chart9_2.cca_c2 == c2)) + | ((chart9_2.cca_c1 == c2) & (chart9_2.cca_c2 == c1)) + ) + & (chart9_2.cca_a == a) + ) + if sum(L) == 1: + psi_chart = "{:11.5e}".format(chart9_2.psi_cca[L].values[0]) + else: + assert sum(L) == 0 + psi_chart = "0.00000e+00" + assert ( + psi.upper() == psi_chart.upper() + ), "psi {} {} {} {} {}".format(c1, c2, a, psi, psi_chart) + for a1 in anions: + for a2 in anions: + if a1 != a2: + for c in cations: + try: + psi = "{:11.5e}".format(prmlib["caa"][c][a1][a2](278.15, 10)[0]) + except KeyError: + psi = "0.00000e+00" + L = ( + ~chart9_2.psi_caa.isnull() + & ( + ((chart9_2.caa_a1 == a1) & (chart9_2.caa_a2 == a2)) + | ((chart9_2.caa_a1 == a2) & (chart9_2.caa_a2 == a1)) + ) + & (chart9_2.caa_c == c) + ) + if sum(L) == 1: + psi_chart = "{:11.5e}".format(chart9_2.psi_caa[L].values[0]) + else: + assert sum(L) == 0 + psi_chart = "0.00000e+00" + assert ( + psi.upper() == psi_chart.upper() + ), "psi {} {} {} {} {}".format(c, a1, a2, psi, psi_chart) + + +def test_lambda_zeta(): + """Do all lambdas and zetas agree, including ones not on the charts (should all be + zero)? + """ + # At 25 °C + for n in neutrals: + for c in cations: + try: + lambd = "{:11.5e}".format(prmlib["nc"][n][c](298.15, 10)[0]) + except KeyError: + lambd = "0.00000e+00" + L = (chart8_3.n == n) & (chart8_3.ion == c) + if sum(L) == 1: + lambd_chart = "{:11.5e}".format(chart8_3.lambda_nx[L].values[0]) + else: + assert sum(L) == 0 + lambd_chart = "0.00000e+00" + assert lambd.upper() == lambd_chart.upper(), "lambda {} {} {} {}".format( + n, c, lambd, lambd_chart + ) + for a in anions: + try: + lambd = "{:11.5e}".format(prmlib["na"][n][a](298.15, 10)[0]) + except KeyError: + lambd = "0.00000e+00" + L = (chart8_3.n == n) & (chart8_3.ion == a) + if sum(L) == 1: + lambd_chart = "{:11.5e}".format(chart8_3.lambda_nx[L].values[0]) + else: + assert sum(L) == 0 + lambd_chart = "0.00000e+00" + assert lambd.upper() == lambd_chart.upper(), "lambda {} {} {} {}".format( + n, a, lambd, lambd_chart + ) + for c in cations: + try: + zeta = "{:11.5e}".format(prmlib["nca"][n][c][a](298.15, 10)[0]) + except KeyError: + zeta = "0.00000e+00" + L = (chart8_4.n == n) & (chart8_4.c == c) & (chart8_4.a == a) + if sum(L) == 1: + zeta_chart = "{:11.5e}".format(chart8_4.zeta[L].values[0]) + else: + assert sum(L) == 0 + zeta_chart = "0.00000e+00" + assert zeta.upper() == zeta_chart.upper(), "zeta {} {} {} {} {}".format( + n, c, a, zeta, zeta_chart + ) + # At 5 °C + for n in neutrals: + for c in cations: + try: + lambd = "{:11.5e}".format(prmlib["nc"][n][c](278.15, 10)[0]) + except KeyError: + lambd = "0.00000e+00" + L = (chart9_3.n == n) & (chart9_3.ion == c) + if sum(L) == 1: + lambd_chart = "{:11.5e}".format(chart9_3.lambda_nx[L].values[0]) + else: + assert sum(L) == 0 + lambd_chart = "0.00000e+00" + assert lambd.upper() == lambd_chart.upper(), "lambda {} {} {} {}".format( + n, c, lambd, lambd_chart + ) + for a in anions: + try: + lambd = "{:11.5e}".format(prmlib["na"][n][a](278.15, 10)[0]) + except KeyError: + lambd = "0.00000e+00" + L = (chart9_3.n == n) & (chart9_3.ion == a) + if sum(L) == 1: + lambd_chart = "{:11.5e}".format(chart9_3.lambda_nx[L].values[0]) + else: + assert sum(L) == 0 + lambd_chart = "0.00000e+00" + assert lambd.upper() == lambd_chart.upper(), "lambda {} {} {} {}".format( + n, a, lambd, lambd_chart + ) + for c in cations: + try: + zeta = "{:11.5e}".format(prmlib["nca"][n][c][a](278.15, 10)[0]) + except KeyError: + zeta = "0.00000e+00" + L = (chart9_4.n == n) & (chart9_4.c == c) & (chart9_4.a == a) + if sum(L) == 1: + zeta_chart = "{:11.5e}".format(chart9_4.zeta[L].values[0]) + else: + assert sum(L) == 0 + zeta_chart = "0.00000e+00" + assert zeta.upper() == zeta_chart.upper(), "zeta {} {} {} {} {}".format( + n, c, a, zeta, zeta_chart + ) + + +# test_ca() +# test_theta() +# test_psi() +# test_lambda_zeta() diff --git a/tests/test_CWTD23_solver.py b/tests/test_CWTD23_solver.py new file mode 100644 index 00000000..08333f83 --- /dev/null +++ b/tests/test_CWTD23_solver.py @@ -0,0 +1,95 @@ +"""Testing against CWTD23 SI#9 check values.""" +import pandas as pd +import pytzer as pz +import numpy as np + +# Select parameter library +prmlib = pz.libraries.Clegg23 +pz = prmlib.set_func_J(pz) + +# Solve and compare without equilibrating +data = pd.read_csv("tests/data/CWTD23 SI final table.csv") +data["aH2O_pz"] = np.nan +data["osm_pz"] = np.nan +data_diff = data[["temperature"]].copy() +for c in data.columns: + if c.startswith("m"): + data["y" + c[1:] + "_pz"] = np.nan + data_diff["y" + c[1:]] = np.nan +data_diff.drop(columns="temperature", inplace=True) +for i, row in data.iterrows(): + solutes = pz.odict((s[1:], v) for s, v in row.items() if s.startswith("m")) + params = prmlib.get_parameters( + solutes=solutes, temperature=273.15 + row.temperature, verbose=False + ) + aH2O = pz.activity_water(solutes, **params) + data.loc[i, "aH2O_pz"] = aH2O + osm = pz.osmotic_coefficient(solutes, **params) + data.loc[i, "osm_pz"] = osm + acfs = pz.activity_coefficients(solutes, **params) + for s, v in acfs.items(): + data.loc[i, "y" + s + "_pz"] = v + data_diff.loc[i, "y" + s] = 100 * (v - row["y" + s]) / row["y" + s] +dcols = list(data.columns) +dcols.sort() +data = data[dcols] + +# Now with the equilibrium solver +data_eq = data.copy() +for c in data_eq.columns: + if c.startswith("m"): + data_eq[c + "_eq"] = np.nan +for i, row in data_eq.iterrows(): + totals = pz.odict( + ( + ("BOH3", row.mBOH3 + row.mBOH4), + ("Br", row.mBr), + ("Ca", row.mCa + row.mCaCO3 + row.mCaF), + ("Cl", row.mCl), + ("CO2", row.mCO2 + row.mCO3 + row.mHCO3 + row.mCaCO3 + row.mMgCO3), + ("F", row.mCaF + row.mF + row.mHF + row.mMgF), + ("SO4", row.mHSO4 + row.mSO4), + ("K", row.mK), + ("Mg", row.mMg + row.mMgCO3 + row.mMgF + row.mMgOH), + ("Na", row.mNa), + ("Sr", row.mSr + row.mSrCO3), + ) + ) + solutes_eq, pks_constants = pz.solve( + totals, + library=prmlib, + temperature=273.15 + row.temperature, + ) + for c in data_eq.columns: + if c.endswith("_eq"): + data_eq.loc[i, c] = solutes_eq[c[1:-3]] +data_eq["pH"] = -np.log10(data_eq["mH"]) +data_eq["pH_eq"] = -np.log10(data_eq["mH_eq"]) + + +def compeq(solute): + if solute == "pH": + return data_eq[[solute, solute + "_eq"]] + else: + return data_eq[["m" + solute, "m" + solute + "_eq"]] + + +def test_without_equilibrium(): + # Activity coefficients are all within 0.001% (i.e., 1e-3%) of CWTD23 values + assert (data_diff.abs() < 1e-3).all().all() + # Water activity within 1e-6 (absolute) of CWTD23 values + assert ((data.aH2O_pz - data.aH2O).abs() < 1e-6).all() + # Osmotic coefficient within 1e-5 (absolute) of CWTD23 values + assert ((data.osm_pz - data.osm).abs() < 1e-5).all() + + +def test_with_equilibrium(): + for s in solutes: + # Molalities all within 0.1% of CWTD23 values + assert ( + 100 * compeq(s).diff(axis=1)["m" + s + "_eq"].abs() / data_eq["m" + s] + ).max() < 0.1 + + +# test_without_equilibrium() +# test_with_equilibrium() diff --git a/tests/test_HWT22_params.py b/tests/test_HWT22_params.py new file mode 100644 index 00000000..eaea8a2c --- /dev/null +++ b/tests/test_HWT22_params.py @@ -0,0 +1,181 @@ +import pandas as pd, numpy as np +import pytzer as pz + +# Select parameter library +prmlib = pz.libraries.Humphreys22 + + +def compare_ca(sheet_name, tempK): + # Import coefficient values from paper + ca = pd.read_excel("tests/data/Humphreys22-SI7.xlsx", sheet_name=sheet_name) + for v in ["alpha1", "alpha2", "omega"]: + ca[v] = ca[v].fillna(-9) + ca = ca.fillna(0) + # Get coefficient values from parameter library + ca_pz = ca.copy() + ca_test = ca.copy() + for i, row in ca.iterrows(): + try: + res = prmlib["ca"][row.cation][row.anion](T=tempK, P=1)[:-1] + except KeyError: + print(row.cation, row.anion, "not found in prmlib") + res = 0, 0, 0, 0, 0, -9, -9, -9 + beta0, beta1, beta2, C0, C1, alpha1, alpha2, omega = res + # Rounding + beta0 = np.round(beta0, decimals=5) + beta1 = np.round(beta1, decimals=5) + beta2 = np.round(beta2, decimals=3) + C0 = np.round(C0, decimals=7) + C1 = np.round(C1, decimals=5) + alpha1 = np.round(alpha1, decimals=5) + # Fill parameter library values + ca_pz.loc[i, "beta0"] = beta0 + ca_pz.loc[i, "beta1"] = beta1 + ca_pz.loc[i, "beta2"] = beta2 + ca_pz.loc[i, "C0"] = C0 + ca_pz.loc[i, "C1"] = C1 + ca_pz.loc[i, "alpha1"] = alpha1 + ca_pz.loc[i, "alpha2"] = alpha2 + ca_pz.loc[i, "omega"] = omega + # Compute differences + ca_test.loc[i, "beta0"] = np.round(beta0 - row.beta0, decimals=5) + ca_test.loc[i, "beta1"] = np.round(beta1 - row.beta1, decimals=5) + ca_test.loc[i, "beta2"] = np.round(beta2 - row.beta2, decimals=3) + ca_test.loc[i, "C0"] = np.round(C0 - row.C0, decimals=7) + ca_test.loc[i, "C1"] = np.round(C1 - row.C1, decimals=5) + ca_test.loc[i, "alpha1"] = np.round(alpha1 - row.alpha1, decimals=5) + ca_test.loc[i, "alpha2"] = alpha2 - row.alpha2 + ca_test.loc[i, "omega"] = omega - row.omega + return ca, ca_pz, ca_test + + +def compare_cc(sheet_name, tempK): + cc = pd.read_excel("tests/data/Humphreys22-SI7.xlsx", sheet_name=sheet_name) + cc = cc.fillna(0) + cc_pz = cc.copy() + cc_test = cc.copy() + for i, row in cc.iterrows(): + try: + theta = prmlib["cc"][row.cation1][row.cation2](T=tempK, P=1)[0] + except KeyError: + print(row.cation1, row.cation2, "not found in prmlib") + theta = 0 + psi_Cl = prmlib["cca"][row.cation1][row.cation2]["Cl"](T=tempK, P=1)[0] + try: + psi_HSO4 = prmlib["cca"][row.cation1][row.cation2]["HSO4"](T=tempK, P=1)[0] + except KeyError: + print(row.cation1, row.cation2, "HSO4", "not found in prmlib") + psi_HSO4 = 0 + try: + psi_SO4 = prmlib["cca"][row.cation1][row.cation2]["SO4"](T=tempK, P=1)[0] + except KeyError: + print(row.cation1, row.cation2, "SO4", "not found in prmlib") + psi_SO4 = 0 + cc_pz.loc[i, "theta"] = np.round(theta, decimals=4) + cc_pz.loc[i, "Cl"] = np.round(psi_Cl, decimals=4) + cc_pz.loc[i, "HSO4"] = np.round(psi_HSO4, decimals=5) + cc_pz.loc[i, "SO4"] = np.round(psi_SO4, decimals=5) + cc_test.loc[i, "theta"] = np.round(theta - row.theta, decimals=4) + cc_test.loc[i, "Cl"] = np.round(psi_Cl - row.Cl, decimals=4) + cc_test.loc[i, "HSO4"] = np.round(psi_HSO4 - row.HSO4, decimals=5) + cc_test.loc[i, "SO4"] = np.round(psi_SO4 - row.SO4, decimals=5) + return cc, cc_pz, cc_test + + +def compare_aa(): + aa = pd.read_excel("tests/data/Humphreys22-SI7.xlsx", sheet_name="aa") + aa = aa.fillna(0) + aa_pz = aa.copy() + aa_test = aa.copy() + for i, row in aa.iterrows(): + try: + theta = prmlib["aa"][row.anion1][row.anion2](T=298.15, P=1)[0] + except KeyError: + print(row.anion1, row.anion2, "not found in prmlib") + theta = 0 + psi = {} + for c in ["Ca", "H", "K", "Mg", "Na"]: + try: + psi[c] = prmlib["caa"][c][row.anion1][row.anion2](T=298.15, P=1)[0] + except KeyError: + print(c, row.anion1, row.anion2, "not found in prmlib") + psi[c] = 0 + aa_pz.loc[i, "theta"] = np.round(theta, decimals=3) + aa_test.loc[i, "theta"] = np.round(theta - row.theta, decimals=3) + for c, ps in psi.items(): + aa_pz.loc[i, c] = np.round(ps, decimals=6) + aa_test.loc[i, c] = np.round(ps - row[c], decimals=6) + + return aa, aa_pz, aa_test + + +# Run comparisons +ca5, ca5_pz, ca5_test = compare_ca("ca5", 278.15) +ca25, ca25_pz, ca25_test = compare_ca("ca25", 298.15) +cc5, cc5_pz, cc5_test = compare_cc("cc5", 278.15) +cc25, cc25_pz, cc25_test = compare_cc("cc25", 298.15) +aa, aa_pz, aa_test = compare_aa() +# Define columns to check are zero +ca_cols = ["beta0", "beta1", "beta2", "C0", "C1", "alpha1", "alpha2", "omega"] +cc_cols = ["theta", "Cl", "HSO4", "SO4"] +aa_cols = ["theta", "Ca", "H", "K", "Mg", "Na"] + +# Eliminate differences that have been identified and understood +# -------------------------------------------------------------- +# +# It looks like the C0 value for Na-Cl at 25 °C in HWT22 Table S17 is actually a Cphi +# value - if you divide it by 2, then it agrees with Pytzer. Testing of the data in +# HWT22 Table S21 suggests that this is a fault only in Table S17 and thus that the +# HWT22 model code does correctly convert it to C0. +l = (ca25.cation == "Na") & (ca25.anion == "Cl") +ca25.loc[l, "C0"] /= 2 +ca25_test.loc[l, "C0"] = np.round(ca25_pz.loc[l, "C0"] - ca25.loc[l, "C0"], decimals=6) +# +# The final digit of the C0 value for H-SO4 at 25 °C in HWT22 Table S17 is one away from +# the Pytzer value - we assume this is a rounding error. +l = (ca25.cation == "H") & (ca25.anion == "SO4") +ca25.loc[l, "C0"] -= 1e-7 +ca25_test.loc[l, "C0"] = ca25_pz.loc[l, "C0"] - ca25.loc[l, "C0"] +# +# The psi value for Ca-Mg-SO4 is in the wrong place in HWT22 Table S19 - it is in the +# spot for the Ca-H-SO4 value, which should be zero. +l0 = (cc25.cation1 == "Ca") & (cc25.cation2 == "H") +l1 = (cc25.cation1 == "Ca") & (cc25.cation2 == "Mg") +cc25.loc[l1, "SO4"] = cc25.loc[l0, "SO4"].values +cc25.loc[l0, "SO4"] = 0 +cc25_test.loc[l0, "SO4"] = cc25_pz.loc[l0, "SO4"] - cc25.loc[l0, "SO4"] +cc25_test.loc[l1, "SO4"] = cc25_pz.loc[l1, "SO4"] - cc25.loc[l1, "SO4"] + + +def test_ca5(): + """Does Pytzer reproduce the same betas and Cs as HWT22 at 5 °C?""" + assert (ca5_test[ca_cols] == 0).all().all() + + +def test_ca25(): + """Does Pytzer reproduce the same betas and Cs as HWT22 at 25 °C?""" + assert (ca25_test[ca_cols] == 0).all().all() + + +def test_cc5(): + """Does Pytzer reproduce the same cc thetas and cca psis as HWT22 at 5 °C?""" + assert (cc5_test[cc_cols] == 0).all().all() + + +def test_cc25(): + """Does Pytzer reproduce the same cc thetas and cca psis as HWT22 at 25 °C?""" + assert (cc25_test[cc_cols] == 0).all().all() + + +def test_aa(): + """Does Pytzer reproduce the same aa thetas and caa psis as HWT22? These are all + independent of temperature. + """ + assert (aa_test[aa_cols] == 0).all().all() + + +# test_ca5() +# test_ca25() +# test_cc5() +# test_cc25() +# test_aa() diff --git a/tests/test_HWT22_solver.py b/tests/test_HWT22_solver.py new file mode 100644 index 00000000..5c74719d --- /dev/null +++ b/tests/test_HWT22_solver.py @@ -0,0 +1,206 @@ +from collections import OrderedDict +import pandas as pd, numpy as np +import pytzer as pz + +# Select parameter library +prmlib = pz.libraries.Humphreys22 +pz = prmlib.set_func_J(pz) + +# Import data and run comparison, first without the solver (just using concentrations +# from in the table) +data = pd.read_excel("tests/data/Humphreys22-SI21.xlsx") +data["lnkHSO4_calc"] = prmlib["equilibria"]["HSO4"]( + data.temperature.to_numpy() + 273.15 +) +data["lnkHSO4_td"] = np.nan +data["lnkHSO4_diff"] = np.nan +data["lnkH2O_calc"] = prmlib["equilibria"]["H2O"](data.temperature.to_numpy() + 273.15) +data["lnkH2O_td"] = np.nan +data["lnkH2O_diff"] = np.nan +data["lnkMgOH_calc"] = prmlib["equilibria"]["MgOH"]( + data.temperature.to_numpy() + 273.15 +) +data["lnkMgOH_td"] = np.nan +data["lnkMgOH_diff"] = np.nan +data_ns_pz = data.copy() +data_ns_test = data.copy() +data_eq_pz = data.copy() +data_eq_test = data.copy() +data_eq_pct = data.copy() +for i, row in data.iterrows(): + solutes = OrderedDict((s[1:], v) for s, v in row.items() if s.startswith("m")) + params = prmlib.get_parameters( + solutes=solutes, temperature=273.15 + row.temperature, verbose=False + ) + aH2O = pz.activity_water(solutes, **params) + data_ns_pz.loc[i, "aH2O"] = aH2O + data_ns_test.loc[i, "aH2O"] = np.round(aH2O - row.aH2O, decimals=5) + phi = pz.osmotic_coefficient(solutes, **params) + data_ns_pz.loc[i, "phi"] = phi + data_ns_test.loc[i, "phi"] = np.round(phi - row.phi, decimals=5) + acfs = pz.activity_coefficients(solutes, **params) + for s, v in acfs.items(): + data_ns_pz.loc[i, "g" + s] = v + data_ns_test.loc[i, "g" + s] = np.round(v - row["g" + s], decimals=5) + +# Now do it again but with the equilibrium solver too +# Number 1 +totals = OrderedDict( + ( + ("Na", 0.4861818), + ("Mg", 0.05474020), + ("Ca", 0.01075004), + ("K", 0.01058004), + ("Cl", 0.5692021), + ("SO4", 0.02927011), + ) +) +solutes_eq, pks_constants = pz.solve( + totals, + library=prmlib, + temperature=278.15, +) +for s, v in solutes_eq.items(): + data_eq_pz.loc[0, "m" + s] = v + if s in ["OH", "HSO4", "MgOH", "H"]: + d = 12 + else: + d = 5 + data_eq_test.loc[0, "m" + s] = np.round(v - data.loc[0, "m" + s], decimals=d) + data_eq_pct.loc[0, "m" + s] = 100 * v / data.loc[0, "m" + s] +# Number 2 +solutes_eq, pks_constants = pz.solve( + totals, + library=prmlib, + temperature=298.15, +) +for s, v in solutes_eq.items(): + data_eq_pz.loc[1, "m" + s] = v + if s in ["OH", "HSO4", "MgOH", "H"]: + d = 12 + else: + d = 5 + data_eq_test.loc[1, "m" + s] = np.round(v - data.loc[1, "m" + s], decimals=d) + data_eq_pct.loc[1, "m" + s] = 100 * v / data.loc[1, "m" + s] +# Number 3 +totals = OrderedDict( + ( + ("Na", 0.4861818 - 0.04), + ("Mg", 0.05474020), + ("Ca", 0.01075004), + ("K", 0.01058004), + ("Cl", 0.5692021), + ("SO4", 0.02927011), + ) +) +solutes_eq, pks_constants = pz.solve( + totals, + library=prmlib, + temperature=278.15, +) +for s, v in solutes_eq.items(): + data_eq_pz.loc[2, "m" + s] = v + if s in ["HSO4", "H"]: + d = 8 + elif s in ["OH", "MgOH"]: + d = 18 + else: + d = 5 + data_eq_test.loc[2, "m" + s] = np.round(v - data.loc[2, "m" + s], decimals=d) + data_eq_pct.loc[2, "m" + s] = 100 * v / data.loc[2, "m" + s] +# Number 4 +solutes_eq, pks_constants = pz.solve( + totals, + library=prmlib, + temperature=298.15, +) +for s, v in solutes_eq.items(): + data_eq_pz.loc[3, "m" + s] = v + if s in ["HSO4", "H"]: + d = 8 + elif s in ["OH", "MgOH"]: + d = 18 + else: + d = 5 + data_eq_test.loc[3, "m" + s] = np.round(v - data.loc[3, "m" + s], decimals=d) + data_eq_pct.loc[3, "m" + s] = 100 * v / data.loc[3, "m" + s] + +# Calculate activities and coefficients for equilibrated Pytzer data +for i, row in data_eq_pz.iterrows(): + solutes = OrderedDict((s[1:], v) for s, v in row.items() if s.startswith("m")) + params = prmlib.get_parameters( + solutes=solutes, temperature=273.15 + row.temperature, verbose=False + ) + aH2O = pz.activity_water(solutes, **params) + data_eq_test.loc[i, "aH2O"] = np.round(aH2O - row.aH2O, decimals=5) + data_eq_pz.loc[i, "aH2O"] = aH2O + phi = pz.osmotic_coefficient(solutes, **params) + data_eq_test.loc[i, "phi"] = np.round(phi - row.phi, decimals=5) + data_eq_pz.loc[i, "phi"] = phi + acfs = pz.activity_coefficients(solutes, **params) + for s, v in acfs.items(): + data_eq_test.loc[i, "g" + s] = np.round(v - row["g" + s], decimals=5) + data_eq_pz.loc[i, "g" + s] = v + +# Calculate thermodynamic Ks from HWT22 data with top-down approach (_td) +for df in [data, data_eq_pz]: + df["lnkHSO4_td"] = np.log(df.mSO4 * df.gSO4 * df.mH * df.gH / (df.mHSO4 * df.gHSO4)) + df["lnkHSO4_diff"] = np.round(df.lnkHSO4_td - df.lnkHSO4_calc, decimals=8) + df["lnkH2O_td"] = np.log(df.mH * df.gH * df.mOH * df.gOH / df.aH2O) + df["lnkH2O_diff"] = np.round(df.lnkH2O_td - df.lnkH2O_calc, decimals=8) + df["lnkMgOH_td"] = np.log(df.mMg * df.gMg * df.mOH * df.gOH / (df.mMgOH * df.gMgOH)) + df["lnkMgOH_diff"] = np.round(df.lnkMgOH_td - df.lnkMgOH_calc, decimals=8) + +# Eliminate differences that have been identified and understood +# -------------------------------------------------------------- +# +# The final digit of the gMgOH value at point 3 in HWT22 Table S21 is one away from +# the Pytzer value - so we assume this is a rounding error. +l = data.number == 3 +data.loc[l, "gMgOH"] -= 1e-5 +data_ns_test.loc[l, "gMgOH"] = np.round( + data_ns_pz.loc[l, "gMgOH"] - data.loc[l, "gMgOH"], decimals=5 +) + +# Identify columns to test +test_cols_ns = [ + c + for c in data.columns + if c not in ["number", "temperature"] + and not c.startswith("m") + and not c.startswith("lnk") +] +test_cols_eq = [c for c in data.columns if c.startswith("m")] + + +def test_data_ns(): + """If we use the HWT22 concentrations and don't solve for speciation, do the Pytzer + calculations of activity coefficients, osmotic coefficient and water activity agree + with HWT22? + """ + assert (data_ns_test[test_cols_ns] == 0).all().all() + + +def test_data_eq(): + """If we solve for equilibrium, are the Pytzer-calculated concentrations within 1.5% + of the HWT22 values? + """ + assert ( + ((data_eq_pct[test_cols_eq] > 98.5) & (data_eq_pct[test_cols_eq] < 101.5)) + .all() + .all() + ) + + +def test_thermodynamic_Ks(): + """After solving for equilibrium with Pytzer, do the concentrations and activity + coefficients agree with the target thermodynamic K values? + """ + assert (data_eq_pz.lnkHSO4_diff == 0).all() + assert (data_eq_pz.lnkH2O_diff == 0).all() + assert (data_eq_pz.lnkMgOH_diff == 0).all() + + +# test_data_ns() +# test_data_eq() +# test_thermodynamic_Ks() diff --git a/tests/test_M88.py b/tests/test_M88.py index b510e283..574c8906 100644 --- a/tests/test_M88.py +++ b/tests/test_M88.py @@ -11,7 +11,7 @@ def get_activity_water(data_row): dr = pz.odict(data_row[m_cols]) - return np.round(pz.activity_water(dr, **params).item(), decimals=4) + return pz.activity_water(dr, **params).item() data["a_H2O_pytzer"] = data.apply(get_activity_water, axis=1) @@ -19,14 +19,11 @@ def get_activity_water(data_row): def test_M88_activity_water(): """Can we reproduce the values from M88 Table 4? - - We presume that their Point 4 contains some typo, hence worse agreement. + Note that we have corrected a presumed typo in row 4 (6.590 => 6.509 for Cl, + based on an analysis of charge balance). """ for i, row in data.iterrows(): - if row.name == 4: - assert np.isclose(row["a_H2O"], row["a_H2O_pytzer"], rtol=0, atol=0.01) - else: - assert np.isclose(row["a_H2O"], row["a_H2O_pytzer"], rtol=0, atol=0.0001) + assert np.isclose(row["a_H2O"], row["a_H2O_pytzer"], rtol=0, atol=0.0001) # test_M88_activity_water() diff --git a/tests/test_pKs.py b/tests/test_pKs.py new file mode 100644 index 00000000..2491070e --- /dev/null +++ b/tests/test_pKs.py @@ -0,0 +1,25 @@ +import numpy as np +import pytzer as pz + +prmlib = pz.libraries.Clegg23 +totals = pz.prepare.salinity_to_totals_MFWM08(35) +solutes_per_kgH2O, pks_per_kgH2O = pz.solve(totals, temperature=298.15, library=prmlib) +totals_g_per_kgH2O = np.sum( + [pz.properties.ion_to_mass[k] * v for k, v in totals.items()] +) +kgH2O_per_kg = 1000 / (1000 + totals_g_per_kgH2O) + +solutes = {k: v * kgH2O_per_kg for k, v in solutes_per_kgH2O.items()} + +# K1 = [HCO3][H]/[CO2] +pk1_per_kgH2O = pks_per_kgH2O["H2CO3"] +pk1_per_kg = pk1_per_kgH2O - np.log10(kgH2O_per_kg) +pk1_PyCO2SYS = 5.957401472372938 +# AWESOME + + +def test_pK1_PyCO2SYS(): + assert np.abs(pk1_per_kg - pk1_PyCO2SYS) < 0.02 + + +# test_pK1_PyCO2SYS() diff --git a/tests/test_stoichiometric.py b/tests/test_stoichiometric.py index d0f3f4ae..75b868a3 100644 --- a/tests/test_stoichiometric.py +++ b/tests/test_stoichiometric.py @@ -10,7 +10,7 @@ def test_pure_water(): """Can we solve pure water?""" totals = pz.odict() - ks_constants = {"H2O": 10 ** -14} + ks_constants = {"H2O": 10**-14} ptargets = eq.stoichiometric.solve(totals, ks_constants) solutes = eq.components.get_solutes(totals, ks_constants, ptargets) assert len(ptargets) == 1 @@ -22,7 +22,7 @@ def test_pure_water(): def test_NaCl(): """Can we solve NaCl?""" totals = pz.odict(Na=1.5, Cl=1.5) - ks_constants = {"H2O": 10 ** -14} + ks_constants = {"H2O": 10**-14} ptargets = eq.stoichiometric.solve(totals, ks_constants) solutes = eq.components.get_solutes(totals, ks_constants, ptargets) assert len(ptargets) == 1 @@ -36,7 +36,7 @@ def test_NaCl(): def test_NaCl_HCl(): """Can we solve NaCl + HCl?""" totals = pz.odict(Na=1.5, Cl=3.5) - ks_constants = {"H2O": 10 ** -14} + ks_constants = {"H2O": 10**-14} ptargets = eq.stoichiometric.solve(totals, ks_constants) solutes = eq.components.get_solutes(totals, ks_constants, ptargets) assert len(ptargets) == 1 @@ -52,7 +52,7 @@ def test_NaCl_HCl(): def test_NaCl_SO4_only(): """Can we solve NaCl + SO4 without the HSO4 equilibrium?""" totals = pz.odict(Na=1.5, Cl=1.5, SO4=1.0) - ks_constants = {"H2O": 10 ** -14} + ks_constants = {"H2O": 10**-14} ptargets = eq.stoichiometric.solve(totals, ks_constants) solutes = eq.components.get_solutes(totals, ks_constants, ptargets) assert len(ptargets) == 1 @@ -71,7 +71,7 @@ def test_NaCl_SO4_only(): def test_NaCl_H2SO4(): """Can we solve NaCl + SO4 with the HSO4 equilibrium?""" totals = pz.odict(Na=1.5, Cl=1.5, SO4=1.0) - ks_constants = {"H2O": 10 ** -14, "HSO4": 10 ** -1} + ks_constants = {"H2O": 10**-14, "HSO4": 10**-1} ptargets = eq.stoichiometric.solve(totals, ks_constants) solutes = eq.components.get_solutes(totals, ks_constants, ptargets) assert len(ptargets) == 1 @@ -94,9 +94,9 @@ def test_NaCl_H2CO3(): """Can we solve NaCl + CO2 with the H2CO3 equilibria?""" totals = pz.odict(Na=1.5, Cl=1.5, CO2=0.1) ks_constants = { - "H2O": 10 ** -14, - "H2CO3": 10 ** -5, - "HCO3": 10 ** -9, + "H2O": 10**-14, + "H2CO3": 10**-5, + "HCO3": 10**-9, } ptargets = eq.stoichiometric.solve(totals, ks_constants) solutes = eq.components.get_solutes(totals, ks_constants, ptargets) @@ -125,9 +125,9 @@ def test_CaCl_H2CO3(): """Can we solve CaCl + CO2 with the H2CO3 equilibria but no CaCO3?""" totals = pz.odict(Ca=0.75, Cl=1.5, CO2=0.1) ks_constants = { - "H2O": 10 ** -14, - "H2CO3": 10 ** -5, - "HCO3": 10 ** -9, + "H2O": 10**-14, + "H2CO3": 10**-5, + "HCO3": 10**-9, } ptargets = eq.stoichiometric.solve(totals, ks_constants) solutes = eq.components.get_solutes(totals, ks_constants, ptargets) @@ -156,10 +156,10 @@ def test_CaCl_H2CO3_CaCO3(): """Can we solve CaCl + CO2 with the H2CO3 and CaCO3 equilibria?""" totals = pz.odict(Ca=0.75, Cl=1.5, CO2=0.1) ks_constants = { - "H2O": 10 ** -14, - "H2CO3": 10 ** -5, - "HCO3": 10 ** -9, - "CaCO3": 10 ** -4, + "H2O": 10**-14, + "H2CO3": 10**-5, + "HCO3": 10**-9, + "CaCO3": 10**-4, } ptargets = eq.stoichiometric.solve(totals, ks_constants) solutes = eq.components.get_solutes(totals, ks_constants, ptargets) @@ -195,16 +195,16 @@ def test_all_ptargets(): """Can we solve with all ptargets active?""" totals = pz.odict(Ca=2.0, Cl=4.0, CO2=0.1, PO4=0.5, F=1.0) ks_constants = { - "H2O": 10 ** -14, - "H2CO3": 10 ** -5, - "HCO3": 10 ** -9, - "HF": 10 ** -2, - "H3PO4": 10 ** -11, - "H2PO4": 10 ** -6, - "HPO4": 10 ** -3, - "CaCO3": 10 ** -4, - "CaF": 10 ** 1, - "CaH2PO4": 10 ** -7, + "H2O": 10**-14, + "H2CO3": 10**-5, + "HCO3": 10**-9, + "HF": 10**-2, + "H3PO4": 10**-11, + "H2PO4": 10**-6, + "HPO4": 10**-3, + "CaCO3": 10**-4, + "CaF": 10**1, + "CaH2PO4": 10**-7, } ptargets = eq.stoichiometric.solve(totals, ks_constants) solutes = eq.components.get_solutes(totals, ks_constants, ptargets) @@ -234,7 +234,7 @@ def test_get_constants_zero(): """ # Solve without DIC and HF totals = pz.odict(Na=1.5, Cl=3.5) - ks_constants = {"H2O": 10 ** -14} + ks_constants = {"H2O": 10**-14} ptargets = eq.stoichiometric.solve(totals, ks_constants) solutes = eq.components.get_solutes(totals, ks_constants, ptargets) # Get DIC and HF equilibria