diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 41c2abb3..9d203f93 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -24,7 +24,7 @@ jobs: with: fetch-depth: 0 - - uses: actions/setup-python@v4 + - uses: actions/setup-python@v5 with: python-version: "3.10" @@ -38,5 +38,5 @@ jobs: tox -e clean,build - name: Upload to PyPi - uses: pypa/gh-action-pypi-publish@v1.8.10 + uses: pypa/gh-action-pypi-publish@v1.8.11 diff --git a/.github/workflows/testing.yaml b/.github/workflows/testing.yaml index fc685e83..231596dd 100644 --- a/.github/workflows/testing.yaml +++ b/.github/workflows/testing.yaml @@ -26,7 +26,7 @@ jobs: with: fetch-depth: 0 - name: Set up Python - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: 3.11 cache: pip @@ -40,7 +40,7 @@ jobs: strategy: max-parallel: 6 matrix: - python-version: ["3.9", "3.10", "3.11"] + python-version: ["3.9", "3.10", "3.11", "3.12"] platform: - ubuntu-latest - macos-latest @@ -49,7 +49,7 @@ jobs: steps: - uses: actions/checkout@v4 - name: Setup Python - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: ${{ matrix.python }}${{ matrix.dev }} - name: Install test requirements @@ -59,7 +59,7 @@ jobs: - name: Run tests run: | pytest --cov=src/pyEQL --cov-report=xml - - uses: codecov/codecov-action@v3 + - uses: codecov/codecov-action@v4 with: token: ${{ secrets.CODECOV_TOKEN }} file: ./coverage.xml @@ -69,7 +69,7 @@ jobs: steps: - uses: actions/checkout@v4 - name: Setup Python - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: 3.9 - name: Install tox diff --git a/.github/workflows/upgrade_dependencies.yml b/.github/workflows/upgrade_dependencies.yml index 71e6b6aa..21804931 100644 --- a/.github/workflows/upgrade_dependencies.yml +++ b/.github/workflows/upgrade_dependencies.yml @@ -16,12 +16,12 @@ jobs: matrix: os: ['ubuntu-latest', 'macos-latest', 'windows-latest'] package: ["."] - python-version: ["3.9", "3.10", "3.11"] + python-version: ["3.9", "3.10", "3.11", "3.12"] steps: - uses: actions/checkout@v4 with: fetch-depth: 0 - - uses: actions/setup-python@v4 + - uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} cache: 'pip' diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index a9fa0dab..26930a6b 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,4 +1,4 @@ -exclude: '^docs/conf.py' +exclude: "^docs/conf.py" default_stages: [commit] @@ -12,10 +12,10 @@ ci: repos: - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.0.292 + rev: v0.1.13 hooks: - id: ruff - args: [--fix, --ignore, "D,E501"] + args: [--fix, --ignore, "D,E501", "--show-fixes"] - repo: https://github.com/psf/black rev: 23.9.1 @@ -39,3 +39,8 @@ repos: - id: end-of-file-fixer - id: mixed-line-ending - id: trailing-whitespace + + - repo: https://github.com/pre-commit/mirrors-prettier + rev: v4.0.0-alpha.8 + hooks: + - id: prettier diff --git a/AUTHORS.md b/AUTHORS.md index d215a129..7de455bd 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -5,7 +5,9 @@ developed and maintained by the Kingsbury Lab at Princeton University. Other contributors, listed alphabetically, are: -* @DhruvDuseja +* Kirill Pushkarev (@kirill-push) +* Dhruv Duseja (@DhruvDuseja) +* Andrew Rosen (@arosen93) * Hernan Grecco (@hgrecco) (If you think that your name belongs here, please let the maintainer know) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2c7ae2a6..69072c9c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,99 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## Unreleased + +### Fixed + +- `Solution.__add_`: Bugfix in the addition operation `+` that could cause problems with + child classes (i.e., classes that inherit from `Solution`) to work improperly + +### Changed + +- Removed deprecated `pkg_resources` import in favor of `importlib.resources` + +## [0.11.1] - 2023-12-23 + +### Added + +- Add tests for `gibbs_mix` and `entropy_mix` functions. Format docstrings in Google style. + +### Fixed + +- `Solution.from_preset`: Fixed a packaging error that made this method fail with a `FileNotFoundError`. + +### Removed + +- `functions.py` is no longer imported into the root namespace. You'll now need to say `from pyEQL.functions import gibbs_mix` + instead of `from pyEQL import gibbs_mix` + +## [0.11.0] - 2023-11-20 + +### Changed + +- `PhreeqcEOS`: performance improvements for the `phreeqc` engine. The `EOS` instance now retains + the `phreeqpython` solution object in between calls, only re-initializing it if the composition + of the `Solution` has changed since the previous call. + +### Fixed + +- `equilibrate`: Fixed several bugs affecting `NativeEOS` and `PhreeqcEOS` in which calling `equilibrate()` + would mess up the charge balance. This was especially an issue if `balance_charge` was set to something + other than `pH`. + +### Removed + +- `equilibrium.equilibrate_phreeqc()` has been removed to reduce redundant code. All its + was absorbed into `NativeEOS` and `PhreeqcEOS` + +## [0.10.1] - 2023-11-12 + +### Added + +- utility function `create_water_substance` with caching to speed up access to IAPWS instances + +### Changed + +- `Solution.get_diffusion_coefficient`: the default diffusion coefficient (returned when D for a solute is not found in + the database) is now adjusted for temperature and ionic strength. +- `Solution.water_substance` - use the IAPWS97 model instead of IAPWS95 whenever possible, for a substantial speedup. + +## [0.10.0] - 2023-11-12 + +### Added + +- `Solution`: Revamped docstrings for `conductivity`, `get_transport_number`, `get_molar_conductivity`, and + `get_diffusion_coefficient`. +- `Solution`: new method `get_diffusion_coefficient` for dedicated retrieval of diffusion coefficients. This method + implements an improved algorithm for temperature adjustment and a new algorithm for adjusting infinite dilution D values + for ionic strengthe effects. The algorithm is identical to that implemented in PHREEQC >= 3.4. +- Database: empirical parameters for temperature and ionic strength adjustment of diffusion coefficients for 15 solutes +- Added tests for temperature and ionic strength adjustment and conductivity +- Docs: new tutorial notebooks +- Docs: remove duplicate contributing pages (Closes [#68](https://github.com/KingsburyLab/pyEQL/issues/68)) +- `Solution`: new method `to_file()` for more convenient saving Solution object to json or yaml files. (@kirill-push) +- `Solution`: new method `from_file()` for more convenient loading Solution object from json or yaml files. (@kirill-push) +- `Solution`: new classmethod `from_preset()` to `replace pyEQL.functions.autogenerate()` and instantiate a solution from a preset composition. (@kirill-push) + +### Changed + +- `Solution`: method af adjusting diffusion coefficients for temperature was updated (same as used in PHREEQC >= 3.4) +- `Solution.conductvity`: improved equation (same as used in PHREEQC >= 3.4) which is more accurate at higher concentrations + +### Fixed + +- Database errors with `Cs[+1]` diffusion coefficient and `KBr` Pitzer parameters +- Restored filter that suppresses duplicate log messages + +### Deprecated + +- `replace pyEQL.functions.autogenerate()` is now deprecated. Use `from_preset` instead. + +### Removed + +- The `activity_correction` kwarg in `get_transport_number` has been removed, because this now occurs by default and is + handled in `get_diffusion_coefficient`. + ## [0.9.2] - 2023-11-07 ### Fixed @@ -122,7 +215,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed - - `pyEQL.unit` was renamed to `pyEQL.ureg` (short for `UnitRegistry`) for consistency with the `pint` documentation and tutorials. ## [v0.6.0] - 2023-08-15 @@ -142,7 +234,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Add `pymatgen`, `monty`, and `maggma` as dependencies - Add `pre-commit` configuration - Add pull request template, new GitHub actions, and `tox -e autodocs` environment to serve and update docs in real time -- Add pre-commit configuration and lint with `ruff` using rulesets mostly borrowed from `pymatgen` +- Add pre-commit configuration and lint with `ruff` using rulesets mostly borrowed from `pymatgen` - Add more comprehensive platform testing via `tox` ### Changed @@ -172,9 +264,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [0.5.2] - 2020-04-21 - - Fix breaking bug introduced by upstream pint change to avogadro_number - - Format project with black - - Misc. linting and docstring changes +- Fix breaking bug introduced by upstream pint change to avogadro_number +- Format project with black +- Misc. linting and docstring changes ## [0.5.0] 2018-09-19 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md deleted file mode 100644 index 5d041412..00000000 --- a/CONTRIBUTING.md +++ /dev/null @@ -1,371 +0,0 @@ -```{todo} THIS IS SUPPOSED TO BE AN EXAMPLE. MODIFY IT ACCORDING TO YOUR NEEDS! - - The document assumes you are using a source repository service that promotes a - contribution model similar to [GitHub's fork and pull request workflow]. - While this is true for the majority of services (like GitHub, GitLab, - BitBucket), it might not be the case for private repositories (e.g., when - using Gerrit). - - Also notice that the code examples might refer to GitHub URLs or the text - might use GitHub specific terminology (e.g., *Pull Request* instead of *Merge - Request*). - - Please make sure to check the document having these assumptions in mind - and update things accordingly. -``` - -```{todo} Provide the correct links/replacements at the bottom of the document. -``` - -```{todo} You might want to have a look on [PyScaffold's contributor's guide], - - especially if your project is open source. The text should be very similar to - this template, but there are a few extra contents that you might decide to - also include, like mentioning labels of your issue tracker or automated - releases. -``` - -# Contributing - -Welcome to `pyEQL` contributor's guide. - -This document focuses on getting any potential contributor familiarized with -the development processes, but [other kinds of contributions] are also appreciated. - -If you are new to using [git] or have never collaborated in a project previously, -please have a look at [contribution-guide.org]. Other resources are also -listed in the excellent [guide created by FreeCodeCamp] [^contrib1]. - -Please notice, all users and contributors are expected to be **open, -considerate, reasonable, and respectful**. When in doubt, -[Python Software Foundation's Code of Conduct] is a good reference in terms of -behavior guidelines. - -## Issue Reports - -If you experience bugs or general issues with `pyEQL`, please have a look -on the [issue tracker]. -If you don't see anything useful there, please feel free to fire an issue report. - -:::{tip} -Please don't forget to include the closed issues in your search. -Sometimes a solution was already reported, and the problem is considered -**solved**. -::: - -New issue reports should include information about your programming environment -(e.g., operating system, Python version) and steps to reproduce the problem. -Please try also to simplify the reproduction steps to a very minimal example -that still illustrates the problem you are facing. By removing other factors, -you help us to identify the root cause of the issue. - -## Documentation Improvements - -You can help improve `pyEQL` docs by making them more readable and coherent, or -by adding missing information and correcting mistakes. - -`pyEQL` documentation uses [Sphinx] as its main documentation compiler. -This means that the docs are kept in the same repository as the project code, and -that any documentation update is done in the same way was a code contribution. - -```{todo} Don't forget to mention which markup language you are using. - - e.g., [reStructuredText] or [CommonMark] with [MyST] extensions. -``` - -```{todo} If your project is hosted on GitHub, you can also mention the following tip: - - :::{tip} - Please notice that the [GitHub web interface] provides a quick way of - propose changes in `pyEQL`'s files. While this mechanism can - be tricky for normal code contributions, it works perfectly fine for - contributing to the docs, and can be quite handy. - - If you are interested in trying this method out, please navigate to - the `docs` folder in the source [repository], find which file you - would like to propose changes and click in the little pencil icon at the - top, to open [GitHub's code editor]. Once you finish editing the file, - please write a message in the form at the bottom of the page describing - which changes have you made and what are the motivations behind them and - submit your proposal. - ::: -``` - -When working on documentation changes in your local machine, you can -compile them using [tox] : - -``` -tox -e docs -``` - -and use Python's built-in web server for a preview in your web browser -(`http://localhost:8000`): - -``` -python3 -m http.server --directory 'docs/_build/html' -``` - -## Code Contributions - -```{todo} Please include a reference or explanation about the internals of the project. - - An architecture description, design principles or at least a summary of the - main concepts will make it easy for potential contributors to get started - quickly. -``` - -### Submit an issue - -Before you work on any non-trivial code contribution it's best to first create -a report in the [issue tracker] to start a discussion on the subject. -This often provides additional considerations and avoids unnecessary work. - -### Create an environment - -Before you start coding, we recommend creating an isolated [virtual environment] -to avoid any problems with your installed Python packages. -This can easily be done via either [virtualenv]: - -``` -virtualenv -source /bin/activate -``` - -or [Miniconda]: - -``` -conda create -n pyEQL python=3 six virtualenv pytest pytest-cov -conda activate pyEQL -``` - -### Clone the repository - -1. Create an user account on GitHub if you do not already have one. - -2. Fork the project [repository]: click on the *Fork* button near the top of the - page. This creates a copy of the code under your account on GitHub. - -3. Clone this copy to your local disk: - - ``` - git clone git@github.com:YourLogin/pyEQL.git - cd pyEQL - ``` - -4. You should run: - - ``` - pip install -U pip setuptools -e . - ``` - - to be able to import the package under development in the Python REPL. - - ```{todo} if you are not using pre-commit, please remove the following item: - ``` - -5. Install [pre-commit]: - - ``` - pip install pre-commit - pre-commit install - ``` - - `pyEQL` comes with a lot of hooks configured to automatically help the - developer to check the code being written. - -### Implement your changes - -1. Create a branch to hold your changes: - - ``` - git checkout -b my-feature - ``` - - and start making changes. Never work on the main branch! - -2. Start your work on this branch. Don't forget to add [docstrings] to new - functions, modules and classes, especially if they are part of public APIs. - -3. Add yourself to the list of contributors in `AUTHORS.rst`. - -4. When you’re done editing, do: - - ``` - git add - git commit - ``` - - to record your changes in [git]. - - ```{todo} if you are not using pre-commit, please remove the following item: - ``` - - Please make sure to see the validation messages from [pre-commit] and fix - any eventual issues. - This should automatically use [flake8]/[black] to check/fix the code style - in a way that is compatible with the project. - - :::{important} - Don't forget to add unit tests and documentation in case your - contribution adds an additional feature and is not just a bugfix. - - Moreover, writing a [descriptive commit message] is highly recommended. - In case of doubt, you can check the commit history with: - - ``` - git log --graph --decorate --pretty=oneline --abbrev-commit --all - ``` - - to look for recurring communication patterns. - ::: - -5. Please check that your changes don't break any unit tests with: - - ``` - tox - ``` - - (after having installed [tox] with `pip install tox` or `pipx`). - - You can also use [tox] to run several other pre-configured tasks in the - repository. Try `tox -av` to see a list of the available checks. - -### Submit your contribution - -1. If everything works fine, push your local branch to the remote server with: - - ``` - git push -u origin my-feature - ``` - -2. Go to the web page of your fork and click "Create pull request" - to send your changes for review. - - ```{todo} if you are using GitHub, you can uncomment the following paragraph - - Find more detailed information in [creating a PR]. You might also want to open - the PR as a draft first and mark it as ready for review after the feedbacks - from the continuous integration (CI) system or any required fixes. - - ``` - -### Troubleshooting - -The following tips can be used when facing problems to build or test the -package: - -1. Make sure to fetch all the tags from the upstream [repository]. - The command `git describe --abbrev=0 --tags` should return the version you - are expecting. If you are trying to run CI scripts in a fork repository, - make sure to push all the tags. - You can also try to remove all the egg files or the complete egg folder, i.e., - `.eggs`, as well as the `*.egg-info` folders in the `src` folder or - potentially in the root of your project. - -2. Sometimes [tox] misses out when new dependencies are added, especially to - `setup.cfg` and `docs/requirements.txt`. If you find any problems with - missing dependencies when running a command with [tox], try to recreate the - `tox` environment using the `-r` flag. For example, instead of: - - ``` - tox -e docs - ``` - - Try running: - - ``` - tox -r -e docs - ``` - -3. Make sure to have a reliable [tox] installation that uses the correct - Python version (e.g., 3.7+). When in doubt you can run: - - ``` - tox --version - # OR - which tox - ``` - - If you have trouble and are seeing weird errors upon running [tox], you can - also try to create a dedicated [virtual environment] with a [tox] binary - freshly installed. For example: - - ``` - virtualenv .venv - source .venv/bin/activate - .venv/bin/pip install tox - .venv/bin/tox -e all - ``` - -4. [Pytest can drop you] in an interactive session in the case an error occurs. - In order to do that you need to pass a `--pdb` option (for example by - running `tox -- -k --pdb`). - You can also setup breakpoints manually instead of using the `--pdb` option. - -## Maintainer tasks - -### Releases - -```{todo} This section assumes you are using PyPI to publicly release your package. - - If instead you are using a different/private package index, please update - the instructions accordingly. -``` - -If you are part of the group of maintainers and have correct user permissions -on [PyPI], the following steps can be used to release a new version for -`pyEQL`: - -1. Make sure all unit tests are successful. -2. Tag the current commit on the main branch with a release tag, e.g., `v1.2.3`. -3. Push the new tag to the upstream [repository], - e.g., `git push upstream v1.2.3` -4. Clean up the `dist` and `build` folders with `tox -e clean` - (or `rm -rf dist build`) - to avoid confusion with old builds and Sphinx docs. -5. Run `tox -e build` and check that the files in `dist` have - the correct version (no `.dirty` or [git] hash) according to the [git] tag. - Also check the sizes of the distributions, if they are too big (e.g., > - 500KB), unwanted clutter may have been accidentally included. -6. Run `tox -e publish -- --repository pypi` and check that everything was - uploaded to [PyPI] correctly. - -[^contrib1]: Even though, these resources focus on open source projects and - communities, the general ideas behind collaborating with other developers - to collectively create software are general and can be applied to all sorts - of environments, including private companies and proprietary code bases. - - -[black]: https://pypi.org/project/black/ -[commonmark]: https://commonmark.org/ -[contribution-guide.org]: http://www.contribution-guide.org/ -[creating a pr]: https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/creating-a-pull-request -[descriptive commit message]: https://chris.beams.io/posts/git-commit -[docstrings]: https://www.sphinx-doc.org/en/master/usage/extensions/napoleon.html -[first-contributions tutorial]: https://github.com/firstcontributions/first-contributions -[flake8]: https://flake8.pycqa.org/en/stable/ -[git]: https://git-scm.com -[github web interface]: https://docs.github.com/en/github/managing-files-in-a-repository/managing-files-on-github/editing-files-in-your-repository -[github's code editor]: https://docs.github.com/en/github/managing-files-in-a-repository/managing-files-on-github/editing-files-in-your-repository -[github's fork and pull request workflow]: https://guides.github.com/activities/forking/ -[guide created by freecodecamp]: https://github.com/freecodecamp/how-to-contribute-to-open-source -[miniconda]: https://docs.conda.io/en/latest/miniconda.html -[myst]: https://myst-parser.readthedocs.io/en/latest/syntax/syntax.html -[other kinds of contributions]: https://opensource.guide/how-to-contribute -[pre-commit]: https://pre-commit.com/ -[pypi]: https://pypi.org/ -[pyscaffold's contributor's guide]: https://pyscaffold.org/en/stable/contributing.html -[pytest can drop you]: https://docs.pytest.org/en/stable/usage.html#dropping-to-pdb-python-debugger-at-the-start-of-a-test -[python software foundation's code of conduct]: https://www.python.org/psf/conduct/ -[restructuredtext]: https://www.sphinx-doc.org/en/master/usage/restructuredtext/ -[sphinx]: https://www.sphinx-doc.org/en/master/ -[tox]: https://tox.readthedocs.io/en/stable/ -[virtual environment]: https://realpython.com/python-virtual-environments-a-primer/ -[virtualenv]: https://virtualenv.pypa.io/en/stable/ - - -```{todo} Please review and change the following definitions: -``` - -[repository]: https://github.com//pyEQL -[issue tracker]: https://github.com//pyEQL/issues diff --git a/MANIFEST.in b/MANIFEST.in index 2f6f4194..1fb89d73 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,5 +1,6 @@ include README COPYING CHANGELOG LICENSE README.md README.rst README.txt CHANGES pyeql-logo.png pyeql-logo.svg recursive-include src/pyEQL/database/ * +recursive-include src/pyEQL/presets/ * recursive-include docs/ * include src/pyEQL/pint_custom_units.txt prune docs/build diff --git a/README.md b/README.md index 5d0c0750..46b08d3d 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ [![Read the Docs](https://img.shields.io/readthedocs/pyeql)](https://pyeql.readthedocs.io/en/latest/) [![testing](https://github.com/KingsburyLab/pyeql/workflows/testing/badge.svg)](https://github.com/KingsburyLab/pyeql/actions?query=workflow%3Atesting) [![codecov](https://codecov.io/gh/KingsburyLab/pyeql/branch/main/graph/badge.svg?token=I7RP0QML6S)](https://codecov.io/gh/KingsburyLab/pyeql) -![Supported python versions](https://img.shields.io/badge/python-3.9%20%7C%203.10%20%7C%203.11-blue) +![Supported python versions](https://img.shields.io/badge/python-3.9%20%7C%203.10%20%7C%203.11%20%7C%203.12-blue) [![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.8332915.svg)](https://doi.org/10.5281/zenodo.8332915) [![PyPI version](https://badge.fury.io/py/pyEQL.svg)](https://badge.fury.io/py/pyEQL) diff --git a/docs/contributing.md b/docs/contributing.md index 6f91f298..2739e6b0 100644 --- a/docs/contributing.md +++ b/docs/contributing.md @@ -8,10 +8,66 @@ You can help the project simply by using pyEQL and comparing the output to exper If you encounter any bugs, packaging issues, feature requests, comments, or questions, please report them using the [issue tracker](https://github.com/KingsburyLab/pyEQL/issues) on [github](https://github.com/KingsburyLab/pyeql). +:::{tip} Please don't forget to include the closed issues in your search. Sometimes a solution was already reported, and the problem is considered solved. ::: + +New issue reports should include information about your programming environment (e.g., operating system, Python version) and steps to reproduce the problem. Please try also to simplify the reproduction steps to a very minimal example that still illustrates the problem you are facing. By removing other factors, you help us to identify the root cause of the issue. + +## Documentation Improvements + +You can help improve `pyEQL` docs by making them more readable and coherent, or +by adding missing information and correcting mistakes. + +`pyEQL` documentation uses [Sphinx] as its main documentation compiler. +This means that the docs are kept in the same repository as the project code, and +that any documentation update is done in the same way was a code contribution. + +```{todo} Don't forget to mention which markup language you are using. + + e.g., [reStructuredText] or [CommonMark] with [MyST] extensions. +``` + +```{todo} If your project is hosted on GitHub, you can also mention the following tip: + + :::{tip} + Please notice that the [GitHub web interface] provides a quick way of + propose changes in `pyEQL`'s files. While this mechanism can + be tricky for normal code contributions, it works perfectly fine for + contributing to the docs, and can be quite handy. + + If you are interested in trying this method out, please navigate to + the `docs` folder in the source [repository], find which file you + would like to propose changes and click in the little pencil icon at the + top, to open [GitHub's code editor]. Once you finish editing the file, + please write a message in the form at the bottom of the page describing + which changes have you made and what are the motivations behind them and + submit your proposal. + ::: +``` + +When working on documentation changes in your local machine, you can +compile them using [tox] : + +``` +tox -e docs +``` + +and use Python's built-in web server for a preview in your web browser +(`http://localhost:8000`): + +``` +python3 -m http.server --directory 'docs/_build/html' +``` + ## Contributing Code To contribute bug fixes, documentation enhancements, or new code, please fork pyEQL and send us a pull request. It's not as hard as it sounds! Beginning with version 0.6.0, we follow the [GitHub flow](https://docs.github.com/en/get-started/quickstart/github-flow) workflow model. +The [Scientific Python Guide](https://learn.scientific-python.org/development/guides/) is also an excellent technical reference for new and longtime developers. + +### Submit an issue + +Before you work on any non-trivial code contribution it's best to first create +a report in the [issue tracker](https://github.com/KingsburyLab/pyEQL/issues) to start a discussion on the subject. This often provides additional considerations and avoids unnecessary work. ### Hacking pyEQL, step by step diff --git a/docs/creating.md b/docs/creating.md index be75ab74..6d2f8392 100644 --- a/docs/creating.md +++ b/docs/creating.md @@ -44,11 +44,11 @@ Finally, you can manually create a solution with any list of solutes, temperatur ## Using a preset -Alternatively, you can use the `pyEQL.functions.autogenerate()` function to easily create common solutions like seawater: +Alternatively, you can use the `Solution.from_preset()` classmethod to easily create common solutions like seawater: ``` ->>> from pyEQL.functions import autogenerate ->>> s2 = autogenerate('seawater') +>>> from pyEQL import Solution +>>> s2 = Solution.from_preset('seawater') ``` diff --git a/docs/examples.md b/docs/examples.md deleted file mode 100644 index dddc27c7..00000000 --- a/docs/examples.md +++ /dev/null @@ -1,7 +0,0 @@ -# Examples - -## Demonstration notebook - -```{toctree} -../examples/pyEQL_demo_1 -``` diff --git a/examples/pyEQL_demo_1.ipynb b/docs/examples/.ipynb_checkpoints/pyEQL_demo_1-checkpoint.ipynb similarity index 100% rename from examples/pyEQL_demo_1.ipynb rename to docs/examples/.ipynb_checkpoints/pyEQL_demo_1-checkpoint.ipynb diff --git a/examples/pyeql_demo.ipynb b/docs/examples/.ipynb_checkpoints/pyeql_demo-checkpoint.ipynb similarity index 98% rename from examples/pyeql_demo.ipynb rename to docs/examples/.ipynb_checkpoints/pyeql_demo-checkpoint.ipynb index bbc63e3e..8318aa97 100644 --- a/examples/pyeql_demo.ipynb +++ b/docs/examples/.ipynb_checkpoints/pyeql_demo-checkpoint.ipynb @@ -12,31 +12,35 @@ "tags": [] }, "source": [ - "# `pyEQL` Demonstration\n", + "# `pyEQL` Overview\n", "\n", "![pyeql-logo.png](attachment:b51ca3f4-e8bd-4b0a-a599-5f6724ad8fe5.png)\n", "\n", - "`pyEQL` is an open-source `python` library for solution chemistry calculations and ion properties\n", + "`pyEQL` is an open-source `python` library for solution chemistry calculations and ion properties developed by the [Kingsbury Lab](https://www.kingsburylab.org/) at Princeton University.\n", "\n", - "[Documentation](https://pyeql.readthedocs.io/en/latest/)\n", - "\n", - "[GitHub](https://github.com/rkingsbury/pyEQL)" + "[Documentation](https://pyeql.readthedocs.io/en/latest/) | [How to Install](https://pyeql.readthedocs.io/en/latest/installation.html) | [GitHub](https://github.com/rkingsbury/pyEQL) " ] }, { "cell_type": "markdown", "id": "90c14b65-36f0-4bb2-a3bf-f8e725cc897e", - "metadata": {}, + "metadata": { + "tags": [] + }, "source": [ - "## Installation" + "## Installation\n", + "\n", + "Uncomment and run the code cell below, if you do not already have `pyEQL`" ] }, { - "cell_type": "markdown", - "id": "e6f7ffd5-4178-4968-95bb-80c4fd1ec5ff", + "cell_type": "code", + "execution_count": 2, + "id": "abb1f51c-38fc-4543-8b59-057b8c591ba9", "metadata": {}, + "outputs": [], "source": [ - "`>>> pip install pyEQL`" + "# pip install pyEQL" ] }, { @@ -833,7 +837,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.10.12" + "version": "3.10.6" } }, "nbformat": 4, diff --git a/docs/examples/.ipynb_checkpoints/pyeql_tutorial_database-checkpoint.ipynb b/docs/examples/.ipynb_checkpoints/pyeql_tutorial_database-checkpoint.ipynb new file mode 100644 index 00000000..3be8afbe --- /dev/null +++ b/docs/examples/.ipynb_checkpoints/pyeql_tutorial_database-checkpoint.ipynb @@ -0,0 +1,1278 @@ +{ + "cells": [ + { + "attachments": { + "b51ca3f4-e8bd-4b0a-a599-5f6724ad8fe5.png": { + "image/png": "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" + } + }, + "cell_type": "markdown", + "id": "305d1216-9791-43dd-8d7f-ec90aa72a307", + "metadata": { + "tags": [] + }, + "source": [ + "# `pyEQL` Tutorial: Searching the Property Database\n", + "\n", + "![pyeql-logo.png](attachment:b51ca3f4-e8bd-4b0a-a599-5f6724ad8fe5.png)\n", + "\n", + "`pyEQL` is an open-source `python` library for solution chemistry calculations and ion properties developed by the [Kingsbury Lab](https://www.kingsburylab.org/) at Princeton University.\n", + "\n", + "[Documentation](https://pyeql.readthedocs.io/en/latest/) | [How to Install](https://pyeql.readthedocs.io/en/latest/installation.html) | [GitHub](https://github.com/rkingsbury/pyEQL) " + ] + }, + { + "cell_type": "markdown", + "id": "90c14b65-36f0-4bb2-a3bf-f8e725cc897e", + "metadata": { + "tags": [] + }, + "source": [ + "## Installation\n", + "\n", + "Uncomment and run the code cell below, if you do not already have `pyEQL`" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "abb1f51c-38fc-4543-8b59-057b8c591ba9", + "metadata": {}, + "outputs": [], + "source": [ + "# pip install pyEQL" + ] + }, + { + "cell_type": "markdown", + "id": "1b8efc81-17bb-46dc-8a22-63e71ae458b7", + "metadata": {}, + "source": [ + "## First, import the property database\n", + "\n", + "`pyEQL`'s built-in property database contains physichochemical, transport, and model parameters for hundreds of solutes. This information is used behind the scenes when you interact with a `Solution` object, but it can also be accessed directly." + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "55f1aea5-a5b8-49b8-a8e8-20856c4be6e7", + "metadata": { + "scrolled": true + }, + "outputs": [], + "source": [ + "from pyEQL import IonDB" + ] + }, + { + "cell_type": "markdown", + "id": "23b21981-7568-4e29-a93c-4017a32629b4", + "metadata": {}, + "source": [ + "## How to Search the Database" + ] + }, + { + "cell_type": "markdown", + "id": "084e5aa5-041b-4135-a083-76a4d8e555d7", + "metadata": {}, + "source": [ + "### Query an example document\n", + "\n", + "You can think of the database like `list` of `dict` that contain structure data. More specifically, the database is a list of [`Solute` objects](https://pyeql.readthedocs.io/en/latest/database.html#the-solute-class) that have been serialized to dictionaries. We refer to each of these `dict` as **\"documents\"** (consistent with MongoDB terminology) or \"records\"\n", + "\n", + "To see what one document looks like, use `query_one()`, which retrieves a single record from the database. The record is a `dict`." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "91459416-322a-49c5-a9ee-bf74c160a7e2", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'_id': ObjectId('654e5f131ed012c187817e6a'),\n", + " 'formula': 'Ac[+3]',\n", + " 'charge': 3,\n", + " 'molecular_weight': '227.0 g/mol',\n", + " 'elements': ['Ac'],\n", + " 'chemsys': 'Ac',\n", + " 'pmg_ion': {'Ac': 1,\n", + " 'charge': 3,\n", + " '@module': 'pymatgen.core.ion',\n", + " '@class': 'Ion',\n", + " '@version': None},\n", + " 'formula_html': 'Ac+3',\n", + " 'formula_latex': 'Ac$^{+3}$',\n", + " 'formula_hill': 'Ac',\n", + " 'formula_pretty': 'Ac^+3',\n", + " 'oxi_state_guesses': {'Ac': 3},\n", + " 'n_atoms': 1,\n", + " 'n_elements': 1,\n", + " 'size': {'radius_ionic': {'value': '1.26 Å',\n", + " 'reference': 'pymatgen',\n", + " 'data_type': 'experimental'},\n", + " 'radius_hydrated': None,\n", + " 'radius_vdw': {'value': '2.47 Å',\n", + " 'reference': 'pymatgen',\n", + " 'data_type': 'experimental'},\n", + " 'molar_volume': None,\n", + " 'radius_ionic_marcus': {'value': '1.18 ± 0.02 Å',\n", + " 'reference': 'Marcus2015',\n", + " 'data_type': 'experimental'}},\n", + " 'thermo': {'ΔG_hydration': {'value': '-3086.0 ± 10 kJ/mol',\n", + " 'reference': '10.1021/acs.jpca.9b05140',\n", + " 'data_type': 'experimental'},\n", + " 'ΔG_formation': None},\n", + " 'transport': {'diffusion_coefficient': None},\n", + " 'model_parameters': {'activity_pitzer': {'Beta0': None,\n", + " 'Beta1': None,\n", + " 'Beta2': None,\n", + " 'Cphi': None,\n", + " 'Max_C': None},\n", + " 'molar_volume_pitzer': {'Beta0': None,\n", + " 'Beta1': None,\n", + " 'Beta2': None,\n", + " 'Cphi': None,\n", + " 'V_o': None,\n", + " 'Max_C': None},\n", + " 'viscosity_jones_dole': {'B': None}}}" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "IonDB.query_one()" + ] + }, + { + "cell_type": "markdown", + "id": "db042f2d-2926-40bb-b84c-9fc5174618d0", + "metadata": {}, + "source": [ + "### Query a specific document\n", + "\n", + "The `IonDB` is a [`maggma.Store`](https://materialsproject.github.io/maggma/getting_started/stores/) that can be queried using a MongoDB-like syntax. The basic syntax is\n", + "\n", + "```\n", + "IonDB.query_one({field: value})\n", + "```\n", + "\n", + "where `field` is a top-level key in the `Solute` `dict`, such as `formula`, `charge`, or `elements`. See [this page](https://riptutorial.com/mongodb/example/26813/pymongo-queries) and the `maggma` documentation (link WIP) for more detailed examples." + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "5e0b4774-5274-4df1-8a91-7a9d43f675bd", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'_id': ObjectId('654e5f131ed012c187817f46'),\n", + " 'formula': 'Na[+1]',\n", + " 'charge': 1,\n", + " 'molecular_weight': '22.98976928 g/mol',\n", + " 'elements': ['Na'],\n", + " 'chemsys': 'Na',\n", + " 'pmg_ion': {'Na': 1,\n", + " 'charge': 1,\n", + " '@module': 'pymatgen.core.ion',\n", + " '@class': 'Ion',\n", + " '@version': None},\n", + " 'formula_html': 'Na+1',\n", + " 'formula_latex': 'Na$^{+1}$',\n", + " 'formula_hill': 'Na',\n", + " 'formula_pretty': 'Na^+1',\n", + " 'oxi_state_guesses': {'Na': 1},\n", + " 'n_atoms': 1,\n", + " 'n_elements': 1,\n", + " 'size': {'radius_ionic': {'value': '1.16 Å',\n", + " 'reference': 'pymatgen',\n", + " 'data_type': 'experimental'},\n", + " 'radius_hydrated': {'value': '3.58 Å',\n", + " 'reference': 'Nightingale1959',\n", + " 'data_type': 'experimental'},\n", + " 'radius_vdw': {'value': '2.27 Å',\n", + " 'reference': 'pymatgen',\n", + " 'data_type': 'experimental'},\n", + " 'molar_volume': {'value': '-5.0 cm**3/mol',\n", + " 'reference': 'Calculation of the Partial Molal Volume of Organic Compounds and Polymers. Progress in Colloid & Polymer Science (94), 20-39.',\n", + " 'data_type': 'experimental'},\n", + " 'radius_ionic_marcus': {'value': '1.02 ± 0.02 Å',\n", + " 'reference': 'Marcus2015',\n", + " 'data_type': 'experimental'}},\n", + " 'thermo': {'ΔG_hydration': {'value': '-427.0 ± 6 kJ/mol',\n", + " 'reference': 'Marcus2015',\n", + " 'data_type': 'experimental'},\n", + " 'ΔG_formation': None},\n", + " 'transport': {'diffusion_coefficient': {'value': '1.334e-05 cm**2/s',\n", + " 'reference': 'CRC',\n", + " 'data_type': 'experimental'}},\n", + " 'model_parameters': {'activity_pitzer': {'Beta0': None,\n", + " 'Beta1': None,\n", + " 'Beta2': None,\n", + " 'Cphi': None,\n", + " 'Max_C': None},\n", + " 'molar_volume_pitzer': {'Beta0': None,\n", + " 'Beta1': None,\n", + " 'Beta2': None,\n", + " 'Cphi': None,\n", + " 'V_o': None,\n", + " 'Max_C': None},\n", + " 'viscosity_jones_dole': {'B': {'value': '0.085 dm**3/mol',\n", + " 'reference': 'https://doi.org/10.1021/cr00040a004',\n", + " 'data_type': 'fitted'}},\n", + " 'dielectric_zuber': {'value': '3.62 dimensionless',\n", + " 'reference': 'https://doi.org/10.1016/j.fluid.2014.05.037',\n", + " 'data_type': 'fitted'}}}" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# a document with the formula \"Na[+1]\"\n", + "IonDB.query_one({\"formula\":'Na[+1]'})" + ] + }, + { + "cell_type": "markdown", + "id": "381b0bae-436b-44b2-b651-bf8766ee053f", + "metadata": {}, + "source": [ + "### Only return a subset of the document\n", + "\n", + "If you don't need to see the entire document, you can restrict the data returned by the query (in MongoDB, this is called \"projection\"). To use this feature, pass a second argument that is a `list` containing _only the fields that you want returned_. Note that there is a unique identified (field name `_id`) that is always returned." + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "1063fa68-50e3-441c-89f9-32a52314d6a7", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'formula': 'Na[+1]',\n", + " 'charge': 1,\n", + " 'molecular_weight': '22.98976928 g/mol',\n", + " '_id': ObjectId('654e5f131ed012c187817f46')}" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# a document with the formula \"Na[+1]\", where we only want the formula, charge, and molecular_weight\n", + "IonDB.query_one({\"formula\":'Na[+1]'}, [\"formula\",\"charge\",\"molecular_weight\"])" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "2829357c-45f7-487f-b89c-978bf28bf126", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'formula': 'Ag(CN)2[-1]',\n", + " 'charge': -1,\n", + " 'molecular_weight': '159.903 g/mol',\n", + " '_id': ObjectId('654e5f131ed012c187817e6b')}" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# a document with the charge -1, where we only want the formula, charge, and molecular_weight\n", + "IonDB.query_one({\"charge\":-1}, [\"formula\",\"charge\",\"molecular_weight\"])" + ] + }, + { + "cell_type": "markdown", + "id": "d7ffc305-5e92-41fe-96fc-8507ee9be76a", + "metadata": {}, + "source": [ + "**NOTE**: Be mindful of data types when querying. `charge` is an `int`. If we tried to query `charge` as if it were a `str`, we would get no results:" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "0e697fdb-5667-4280-9f09-f45c9a5c0ec2", + "metadata": {}, + "outputs": [], + "source": [ + "# a document with the charge -1, where we only want the formula, charge, and molecular_weight\n", + "IonDB.query_one({\"charge\":\"-1\"}, [\"formula\",\"charge\",\"molecular_weight\"])" + ] + }, + { + "cell_type": "markdown", + "id": "ce6abcd9-5739-44a6-8993-a6ca1d6f0c47", + "metadata": {}, + "source": [ + "### Query nested fields\n", + "\n", + "If you want to query a field that is not a top-level key (such as transport / diffusion_coefficient), you can place a `.` between the field names at each level, e.g." + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "068c1ad7-bb98-4c38-af9f-0fa73b9b4551", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'formula': 'Na2CO3(aq)',\n", + " 'size': {'radius_vdw': {'value': '2.27 Å'}},\n", + " '_id': ObjectId('654e5f131ed012c187817f31')}" + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "IonDB.query_one({\"size.radius_vdw.value\": \"2.27 Å\"}, [\"formula\", \"size.radius_vdw.value\"])" + ] + }, + { + "cell_type": "markdown", + "id": "ef08b109-26f3-40ba-9bc6-6345c1a60e4d", + "metadata": { + "tags": [] + }, + "source": [ + "**Note** that in the `Solute` documents, **most quantitative data are stored as `str` so that there is no ambiguity about their units**. In the example above, the value of the van der Waals radius is `\"2.27 Å\"` (a `str`, including a unit), NOT `2.27` (a `float`).\n", + "\n", + "You can easily extract the value by turning the `str` into a `Quantity` (see [Converting Units](https://pyeql.readthedocs.io/en/latest/units.html)), or by using `python` string operations to split the value and the units, e.g." + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "id": "d3be0fcb-7704-457f-8726-ec140ab5cf01", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2.27\n" + ] + } + ], + "source": [ + "# string operations\n", + "print(float(\"2.27 Å\".split(\" \")[0]))" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "id": "fd89fe2b-0697-4f17-98d4-50634660c112", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2.27\n" + ] + } + ], + "source": [ + "# pint Quantity\n", + "from pyEQL import ureg\n", + "print(ureg.Quantity(\"2.27 Å\").magnitude)" + ] + }, + { + "cell_type": "markdown", + "id": "261da6c7-1033-432c-b2d2-334661cec4f1", + "metadata": {}, + "source": [ + "### Query multiple documents\n", + "\n", + "`query_one` only returns a single document (a single `dict`). You can instead use `query` with exactly the same syntax to return a [generator](https://realpython.com/introduction-to-python-generators/) of all documents that match your query." + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "id": "d7c3936a-ed30-4865-acb6-81e2a6d415c8", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 11, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# all documents with a charge of +2, returning only the formulas\n", + "IonDB.query({\"charge\":2}, [\"formula\",\"molecular_weight\"])" + ] + }, + { + "cell_type": "markdown", + "id": "86ff455f-5e3c-40fa-83a2-eadb74595a56", + "metadata": {}, + "source": [ + "A generator is not very useful unless we turn it into a `list`. You can do this with `list()` or with a [list comprehension](https://www.w3schools.com/python/python_lists_comprehension.asp)" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "id": "82e73a80-9987-4866-bf24-55628a7eb2cc", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[{'formula': 'Ag[+2]',\n", + " 'molecular_weight': '107.8682 g/mol',\n", + " '_id': ObjectId('654e5f131ed012c187817e6e')},\n", + " {'formula': 'Au[+2]',\n", + " 'molecular_weight': '196.966569 g/mol',\n", + " '_id': ObjectId('654e5f131ed012c187817e76')},\n", + " {'formula': 'Ba[+2]',\n", + " 'molecular_weight': '137.327 g/mol',\n", + " '_id': ObjectId('654e5f131ed012c187817e83')},\n", + " {'formula': 'Be[+2]',\n", + " 'molecular_weight': '9.012182 g/mol',\n", + " '_id': ObjectId('654e5f131ed012c187817e85')},\n", + " {'formula': 'Ca[+2]',\n", + " 'molecular_weight': '40.078 g/mol',\n", + " '_id': ObjectId('654e5f131ed012c187817e96')},\n", + " {'formula': 'Cd[+2]',\n", + " 'molecular_weight': '112.411 g/mol',\n", + " '_id': ObjectId('654e5f131ed012c187817e9b')},\n", + " {'formula': 'Co[+2]',\n", + " 'molecular_weight': '58.933195 g/mol',\n", + " '_id': ObjectId('654e5f131ed012c187817ea9')},\n", + " {'formula': 'Cr[+2]',\n", + " 'molecular_weight': '51.9961 g/mol',\n", + " '_id': ObjectId('654e5f131ed012c187817eae')},\n", + " {'formula': 'Cu[+2]',\n", + " 'molecular_weight': '63.546 g/mol',\n", + " '_id': ObjectId('654e5f131ed012c187817ebe')},\n", + " {'formula': 'Dy[+2]',\n", + " 'molecular_weight': '162.5 g/mol',\n", + " '_id': ObjectId('654e5f131ed012c187817ec0')},\n", + " {'formula': 'Eu[+2]',\n", + " 'molecular_weight': '151.964 g/mol',\n", + " '_id': ObjectId('654e5f131ed012c187817ec5')},\n", + " {'formula': 'Fe[+2]',\n", + " 'molecular_weight': '55.845 g/mol',\n", + " '_id': ObjectId('654e5f131ed012c187817ecc')},\n", + " {'formula': 'Ge[+2]',\n", + " 'molecular_weight': '72.64 g/mol',\n", + " '_id': ObjectId('654e5f131ed012c187817ed1')},\n", + " {'formula': 'Hg[+2]',\n", + " 'molecular_weight': '200.59 g/mol',\n", + " '_id': ObjectId('654e5f131ed012c187817ef1')},\n", + " {'formula': 'In[+2]',\n", + " 'molecular_weight': '114.818 g/mol',\n", + " '_id': ObjectId('654e5f131ed012c187817ef7')},\n", + " {'formula': 'Mg[+2]',\n", + " 'molecular_weight': '24.305 g/mol',\n", + " '_id': ObjectId('654e5f131ed012c187817f26')},\n", + " {'formula': 'Mn[+2]',\n", + " 'molecular_weight': '54.938045 g/mol',\n", + " '_id': ObjectId('654e5f131ed012c187817f2a')},\n", + " {'formula': 'Nd[+2]',\n", + " 'molecular_weight': '144.242 g/mol',\n", + " '_id': ObjectId('654e5f131ed012c187817f4a')},\n", + " {'formula': 'Ni[+2]',\n", + " 'molecular_weight': '58.6934 g/mol',\n", + " '_id': ObjectId('654e5f141ed012c187817f4f')},\n", + " {'formula': 'Pb[+2]',\n", + " 'molecular_weight': '207.2 g/mol',\n", + " '_id': ObjectId('654e5f141ed012c187817f62')},\n", + " {'formula': 'Pd[+2]',\n", + " 'molecular_weight': '106.42 g/mol',\n", + " '_id': ObjectId('654e5f141ed012c187817f63')},\n", + " {'formula': 'Po[+2]',\n", + " 'molecular_weight': '210.0 g/mol',\n", + " '_id': ObjectId('654e5f141ed012c187817f65')},\n", + " {'formula': 'Pr[+2]',\n", + " 'molecular_weight': '140.90765 g/mol',\n", + " '_id': ObjectId('654e5f141ed012c187817f67')},\n", + " {'formula': 'Pt[+2]',\n", + " 'molecular_weight': '195.084 g/mol',\n", + " '_id': ObjectId('654e5f141ed012c187817f69')},\n", + " {'formula': 'Ra[+2]',\n", + " 'molecular_weight': '226.0 g/mol',\n", + " '_id': ObjectId('654e5f141ed012c187817f6b')},\n", + " {'formula': 'Ru[+2]',\n", + " 'molecular_weight': '101.07 g/mol',\n", + " '_id': ObjectId('654e5f141ed012c187817f7b')},\n", + " {'formula': 'Sc[+2]',\n", + " 'molecular_weight': '44.955912 g/mol',\n", + " '_id': ObjectId('654e5f141ed012c187817f87')},\n", + " {'formula': 'Sm[+2]',\n", + " 'molecular_weight': '150.36 g/mol',\n", + " '_id': ObjectId('654e5f141ed012c187817f8e')},\n", + " {'formula': 'Sn[+2]',\n", + " 'molecular_weight': '118.71 g/mol',\n", + " '_id': ObjectId('654e5f141ed012c187817f90')},\n", + " {'formula': 'Sr[+2]',\n", + " 'molecular_weight': '87.62 g/mol',\n", + " '_id': ObjectId('654e5f141ed012c187817f97')},\n", + " {'formula': 'Tc[+2]',\n", + " 'molecular_weight': '98.0 g/mol',\n", + " '_id': ObjectId('654e5f141ed012c187817f9b')},\n", + " {'formula': 'Ti[+2]',\n", + " 'molecular_weight': '47.867 g/mol',\n", + " '_id': ObjectId('654e5f141ed012c187817f9f')},\n", + " {'formula': 'Tm[+2]',\n", + " 'molecular_weight': '168.93421 g/mol',\n", + " '_id': ObjectId('654e5f141ed012c187817fa7')},\n", + " {'formula': 'UO2[+2]',\n", + " 'molecular_weight': '270.02771 g/mol',\n", + " '_id': ObjectId('654e5f141ed012c187817fad')},\n", + " {'formula': 'V[+2]',\n", + " 'molecular_weight': '50.9415 g/mol',\n", + " '_id': ObjectId('654e5f141ed012c187817fb2')},\n", + " {'formula': 'Yb[+2]',\n", + " 'molecular_weight': '173.04 g/mol',\n", + " '_id': ObjectId('654e5f141ed012c187817fba')},\n", + " {'formula': 'Zn[+2]',\n", + " 'molecular_weight': '65.409 g/mol',\n", + " '_id': ObjectId('654e5f141ed012c187817fc2')}]" + ] + }, + "execution_count": 12, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# using list()\n", + "list(IonDB.query({\"charge\":2}, [\"formula\",\"molecular_weight\"]))" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "id": "c6dd37ed-9d07-47b3-be85-aecaade0b880", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[{'formula': 'Ag[+2]',\n", + " 'molecular_weight': '107.8682 g/mol',\n", + " '_id': ObjectId('654e5f131ed012c187817e6e')},\n", + " {'formula': 'Au[+2]',\n", + " 'molecular_weight': '196.966569 g/mol',\n", + " '_id': ObjectId('654e5f131ed012c187817e76')},\n", + " {'formula': 'Ba[+2]',\n", + " 'molecular_weight': '137.327 g/mol',\n", + " '_id': ObjectId('654e5f131ed012c187817e83')},\n", + " {'formula': 'Be[+2]',\n", + " 'molecular_weight': '9.012182 g/mol',\n", + " '_id': ObjectId('654e5f131ed012c187817e85')},\n", + " {'formula': 'Ca[+2]',\n", + " 'molecular_weight': '40.078 g/mol',\n", + " '_id': ObjectId('654e5f131ed012c187817e96')},\n", + " {'formula': 'Cd[+2]',\n", + " 'molecular_weight': '112.411 g/mol',\n", + " '_id': ObjectId('654e5f131ed012c187817e9b')},\n", + " {'formula': 'Co[+2]',\n", + " 'molecular_weight': '58.933195 g/mol',\n", + " '_id': ObjectId('654e5f131ed012c187817ea9')},\n", + " {'formula': 'Cr[+2]',\n", + " 'molecular_weight': '51.9961 g/mol',\n", + " '_id': ObjectId('654e5f131ed012c187817eae')},\n", + " {'formula': 'Cu[+2]',\n", + " 'molecular_weight': '63.546 g/mol',\n", + " '_id': ObjectId('654e5f131ed012c187817ebe')},\n", + " {'formula': 'Dy[+2]',\n", + " 'molecular_weight': '162.5 g/mol',\n", + " '_id': ObjectId('654e5f131ed012c187817ec0')},\n", + " {'formula': 'Eu[+2]',\n", + " 'molecular_weight': '151.964 g/mol',\n", + " '_id': ObjectId('654e5f131ed012c187817ec5')},\n", + " {'formula': 'Fe[+2]',\n", + " 'molecular_weight': '55.845 g/mol',\n", + " '_id': ObjectId('654e5f131ed012c187817ecc')},\n", + " {'formula': 'Ge[+2]',\n", + " 'molecular_weight': '72.64 g/mol',\n", + " '_id': ObjectId('654e5f131ed012c187817ed1')},\n", + " {'formula': 'Hg[+2]',\n", + " 'molecular_weight': '200.59 g/mol',\n", + " '_id': ObjectId('654e5f131ed012c187817ef1')},\n", + " {'formula': 'In[+2]',\n", + " 'molecular_weight': '114.818 g/mol',\n", + " '_id': ObjectId('654e5f131ed012c187817ef7')},\n", + " {'formula': 'Mg[+2]',\n", + " 'molecular_weight': '24.305 g/mol',\n", + " '_id': ObjectId('654e5f131ed012c187817f26')},\n", + " {'formula': 'Mn[+2]',\n", + " 'molecular_weight': '54.938045 g/mol',\n", + " '_id': ObjectId('654e5f131ed012c187817f2a')},\n", + " {'formula': 'Nd[+2]',\n", + " 'molecular_weight': '144.242 g/mol',\n", + " '_id': ObjectId('654e5f131ed012c187817f4a')},\n", + " {'formula': 'Ni[+2]',\n", + " 'molecular_weight': '58.6934 g/mol',\n", + " '_id': ObjectId('654e5f141ed012c187817f4f')},\n", + " {'formula': 'Pb[+2]',\n", + " 'molecular_weight': '207.2 g/mol',\n", + " '_id': ObjectId('654e5f141ed012c187817f62')},\n", + " {'formula': 'Pd[+2]',\n", + " 'molecular_weight': '106.42 g/mol',\n", + " '_id': ObjectId('654e5f141ed012c187817f63')},\n", + " {'formula': 'Po[+2]',\n", + " 'molecular_weight': '210.0 g/mol',\n", + " '_id': ObjectId('654e5f141ed012c187817f65')},\n", + " {'formula': 'Pr[+2]',\n", + " 'molecular_weight': '140.90765 g/mol',\n", + " '_id': ObjectId('654e5f141ed012c187817f67')},\n", + " {'formula': 'Pt[+2]',\n", + " 'molecular_weight': '195.084 g/mol',\n", + " '_id': ObjectId('654e5f141ed012c187817f69')},\n", + " {'formula': 'Ra[+2]',\n", + " 'molecular_weight': '226.0 g/mol',\n", + " '_id': ObjectId('654e5f141ed012c187817f6b')},\n", + " {'formula': 'Ru[+2]',\n", + " 'molecular_weight': '101.07 g/mol',\n", + " '_id': ObjectId('654e5f141ed012c187817f7b')},\n", + " {'formula': 'Sc[+2]',\n", + " 'molecular_weight': '44.955912 g/mol',\n", + " '_id': ObjectId('654e5f141ed012c187817f87')},\n", + " {'formula': 'Sm[+2]',\n", + " 'molecular_weight': '150.36 g/mol',\n", + " '_id': ObjectId('654e5f141ed012c187817f8e')},\n", + " {'formula': 'Sn[+2]',\n", + " 'molecular_weight': '118.71 g/mol',\n", + " '_id': ObjectId('654e5f141ed012c187817f90')},\n", + " {'formula': 'Sr[+2]',\n", + " 'molecular_weight': '87.62 g/mol',\n", + " '_id': ObjectId('654e5f141ed012c187817f97')},\n", + " {'formula': 'Tc[+2]',\n", + " 'molecular_weight': '98.0 g/mol',\n", + " '_id': ObjectId('654e5f141ed012c187817f9b')},\n", + " {'formula': 'Ti[+2]',\n", + " 'molecular_weight': '47.867 g/mol',\n", + " '_id': ObjectId('654e5f141ed012c187817f9f')},\n", + " {'formula': 'Tm[+2]',\n", + " 'molecular_weight': '168.93421 g/mol',\n", + " '_id': ObjectId('654e5f141ed012c187817fa7')},\n", + " {'formula': 'UO2[+2]',\n", + " 'molecular_weight': '270.02771 g/mol',\n", + " '_id': ObjectId('654e5f141ed012c187817fad')},\n", + " {'formula': 'V[+2]',\n", + " 'molecular_weight': '50.9415 g/mol',\n", + " '_id': ObjectId('654e5f141ed012c187817fb2')},\n", + " {'formula': 'Yb[+2]',\n", + " 'molecular_weight': '173.04 g/mol',\n", + " '_id': ObjectId('654e5f141ed012c187817fba')},\n", + " {'formula': 'Zn[+2]',\n", + " 'molecular_weight': '65.409 g/mol',\n", + " '_id': ObjectId('654e5f141ed012c187817fc2')}]" + ] + }, + "execution_count": 13, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# using a comprehension\n", + "[doc for doc in IonDB.query({\"charge\":2}, [\"formula\",\"molecular_weight\"])]" + ] + }, + { + "cell_type": "markdown", + "id": "94600f07-a63e-4004-8107-a1a91103d494", + "metadata": {}, + "source": [ + "## Counting Documents\n", + "\n", + "You can use `count()` to see how many documents the database contains" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "id": "bf68990f-bade-425f-8fa5-d6f67c9a15ea", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "346" + ] + }, + "execution_count": 14, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "IonDB.count()" + ] + }, + { + "cell_type": "markdown", + "id": "7272f19b-5871-44f0-a4b6-da817115ceab", + "metadata": {}, + "source": [ + "Count works with queries, too." + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "id": "43a45291-e0bb-4d9d-8b8b-b20f3e49773a", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "7" + ] + }, + "execution_count": 15, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# number of documents with a charge of -3\n", + "IonDB.count({\"charge\": -3})" + ] + }, + { + "cell_type": "markdown", + "id": "b1dd7b65-f54d-4998-aad1-ad73d6c7fe7d", + "metadata": {}, + "source": [ + "## More Advanced Query Syntax" + ] + }, + { + "cell_type": "markdown", + "id": "22a1209c-35ed-4096-8e53-d016b4187a41", + "metadata": {}, + "source": [ + "### Match multiple items with `$in`\n", + "\n", + "If you want to query documents that match _any one of a set of values_, use `$in` with a `list` of possible values. Note that the `$in` operator and your `list` constitute their own dictionary, e.g. `{\"$in\":}`. This entire dictionary is the \"value\" of your query for the associated field. For example:" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "id": "8bed2683-ca20-4b8e-9bde-c4c86fb0e511", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "5" + ] + }, + "execution_count": 16, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# all alkali cations\n", + "IonDB.count({\"formula\":\n", + " {\"$in\": [\"Li[+1]\", \"Na[+1]\", \"K[+1]\", \"Rb[+1]\", \"Cs[+1]\"]}\n", + " }\n", + " )" + ] + }, + { + "cell_type": "markdown", + "id": "ff2b2305-1d45-45cd-aa53-31eccffb8afa", + "metadata": {}, + "source": [ + "### Greater than or less than - `$gt` / `$gte` / `$lt` / `$lte`\n", + "\n", + "In a similar manner, you can query fields whose values are greater than / less than or equal to some value" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "id": "7f7e52c5-6963-4848-99cb-32018adfb12c", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "76" + ] + }, + "execution_count": 17, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# all solutes with a charge less than 0\n", + "IonDB.count({\"charge\":\n", + " {\"$lt\": 0}\n", + " }\n", + " )" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "id": "747d56b6-859f-4a15-9fa5-ef63229a7436", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "108" + ] + }, + "execution_count": 18, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# all solutes with a charge greater than or equal to 1\n", + "IonDB.count({\"charge\":\n", + " {\"$gte\": 1}\n", + " }\n", + " )" + ] + }, + { + "cell_type": "markdown", + "id": "4ad07153-ead4-4a95-a83a-7055089cbd84", + "metadata": {}, + "source": [ + "## Unique Values\n", + "\n", + "It's often useful to understand how many unique values of a field there are. To do so, use `distinct()` with any field name" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "id": "7587a871-ed15-4ab4-b2a7-77018e67a1c1", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "['U(ClO5)2(aq)',\n", + " 'LiClO4(aq)',\n", + " 'Sb(OH)6[-1]',\n", + " 'Ba[+2]',\n", + " 'RbNO3(aq)',\n", + " 'KBrO3(aq)',\n", + " 'H3O[+1]',\n", + " 'CsNO2(aq)',\n", + " 'Re[+1]',\n", + " 'KHC2O.1H2O(aq)',\n", + " 'Ni[+3]',\n", + " 'H8S(NO2)2(aq)',\n", + " 'Sm[+2]',\n", + " 'B(OH)4[-1]',\n", + " 'CoI2(aq)',\n", + " 'ZnBr2(aq)',\n", + " 'Sn[+2]',\n", + " 'USO6(aq)',\n", + " 'Ir[+3]',\n", + " 'Ag(CN)2[-1]',\n", + " 'KNO3(aq)',\n", + " 'Ga[+3]',\n", + " 'Zn(NO3)2(aq)',\n", + " 'NaHC3.2H2O(aq)',\n", + " 'Ni(NO3)2(aq)',\n", + " 'S[-2]',\n", + " 'HS[-1]',\n", + " 'Eu[+2]',\n", + " 'ZnSO4(aq)',\n", + " 'BeSO4(aq)',\n", + " 'MnO4[-1]',\n", + " 'K2CO3(aq)',\n", + " 'Pa[+3]',\n", + " 'SrI2(aq)',\n", + " 'FeCl2(aq)',\n", + " 'Eu(NO3)3(aq)',\n", + " 'NaClO4(aq)',\n", + " 'Zn[+2]',\n", + " 'SeO4[-1]',\n", + " 'NaCrO4(aq)',\n", + " 'CsOH(aq)',\n", + " 'Na3PO4(aq)',\n", + " 'KCSN(aq)',\n", + " 'HSO4[-1]',\n", + " 'Mn[+3]',\n", + " 'H4NClO4(aq)',\n", + " 'NiSO4(aq)',\n", + " 'IO4[-1]',\n", + " 'Sr(ClO4)2(aq)',\n", + " 'SeO4[-2]',\n", + " 'Ag[+1]',\n", + " 'LiI(aq)',\n", + " 'SiF6[-2]',\n", + " 'HF2[-1]',\n", + " 'CoBr2(aq)',\n", + " 'Pr[+3]',\n", + " 'BaBr2(aq)',\n", + " 'ClO2[-1]',\n", + " 'MgBr2(aq)',\n", + " 'Ho[+3]',\n", + " 'Be[+2]',\n", + " 'H2O(aq)',\n", + " 'Po[+2]',\n", + " 'P2O7[-4]',\n", + " 'RbCl(aq)',\n", + " 'K[+1]',\n", + " 'ClO4[-1]',\n", + " 'Mg(ClO4)2(aq)',\n", + " 'NdCl3(aq)',\n", + " 'Au[+1]',\n", + " 'Rb2SO4(aq)',\n", + " 'Na2PHO4(aq)',\n", + " 'Th[+4]',\n", + " 'Fe[+3]',\n", + " 'Ra[+2]',\n", + " 'Tl(NO3)3(aq)',\n", + " 'Rb[+1]',\n", + " 'KF(aq)',\n", + " 'Gd[+3]',\n", + " 'NiCl2(aq)',\n", + " 'Rh[+3]',\n", + " 'Ag[+3]',\n", + " 'Cd(ClO4)2(aq)',\n", + " 'FeCl3(aq)',\n", + " 'NO3[-1]',\n", + " 'MoO4[-2]',\n", + " 'Tl[+3]',\n", + " 'CuSO4(aq)',\n", + " 'Tm[+3]',\n", + " 'OH[-1]',\n", + " 'Zn(ClO4)2(aq)',\n", + " 'Th(NO3)4(aq)',\n", + " 'HNO3(aq)',\n", + " 'AgNO3(aq)',\n", + " 'Cr(NO3)3(aq)',\n", + " 'Tl(NO2)3(aq)',\n", + " 'CaI2(aq)',\n", + " 'Pt[+2]',\n", + " 'U(NO4)2(aq)',\n", + " 'LiNO2(aq)',\n", + " 'Na2CO3(aq)',\n", + " 'Np[+4]',\n", + " 'LiNO3(aq)',\n", + " 'VO2[+1]',\n", + " 'KCrO4(aq)',\n", + " 'PO4[-3]',\n", + " 'Ca(NO3)2(aq)',\n", + " 'Li[+1]',\n", + " 'SrCl2(aq)',\n", + " 'KPO3.1H2O(aq)',\n", + " 'CH3COO[-1]',\n", + " 'PrCl3(aq)',\n", + " 'In[+3]',\n", + " 'ZnI2(aq)',\n", + " 'SmCl3(aq)',\n", + " 'KI(aq)',\n", + " 'K3Fe(CN)6(aq)',\n", + " 'CdSO4(aq)',\n", + " 'GdCl3(aq)',\n", + " 'Os[+3]',\n", + " 'LiHC2O.1H2O(aq)',\n", + " 'Sr(NO3)2(aq)',\n", + " 'H2SO4(aq)',\n", + " 'Hg[+2]',\n", + " 'NaNO2(aq)',\n", + " 'Cd[+2]',\n", + " 'H5N2[+1]',\n", + " 'Mg(NO3)2(aq)',\n", + " 'KClO3(aq)',\n", + " 'P(OH)2[-1]',\n", + " 'Sn[+4]',\n", + " 'Tm[+2]',\n", + " 'U(ClO)2(aq)',\n", + " 'HCO2[-1]',\n", + " 'BO2[-1]',\n", + " 'KBr(aq)',\n", + " 'K2SO4(aq)',\n", + " 'SeO3[-1]',\n", + " 'Ta[+3]',\n", + " 'YNO3(aq)',\n", + " 'Cu[+1]',\n", + " 'Er[+3]',\n", + " 'Al[+3]',\n", + " 'HSO3[-1]',\n", + " 'Tl[+1]',\n", + " 'BrO3[-1]',\n", + " 'Li2SO4(aq)',\n", + " 'Co[+2]',\n", + " 'ZnCl2(aq)',\n", + " 'HO2[-1]',\n", + " 'I[-1]',\n", + " 'Au[+3]',\n", + " 'CSN[-1]',\n", + " 'NaHCO2(aq)',\n", + " 'Ca[+2]',\n", + " 'P(HO2)2[-1]',\n", + " 'Ba(NO3)2(aq)',\n", + " 'Dy[+2]',\n", + " 'Cs2SO4(aq)',\n", + " 'F[-1]',\n", + " 'Pb[+2]',\n", + " 'EuCl3(aq)',\n", + " 'Ca(ClO4)2(aq)',\n", + " 'Al2(SO4)3(aq)',\n", + " 'PH9(NO2)2(aq)',\n", + " 'RbBr(aq)',\n", + " 'CuCl2(aq)',\n", + " 'Co(H3N)6[-3]',\n", + " 'Pb(NO3)2(aq)',\n", + " 'CSeN[-1]',\n", + " 'Ce[+3]',\n", + " 'RbOH(aq)',\n", + " 'P3O10[-5]',\n", + " 'NaOH(aq)',\n", + " 'Sm[+3]',\n", + " 'Yb[+3]',\n", + " 'C2N3[-1]',\n", + " 'BaC4O.3H2O(aq)',\n", + " 'Fe(CN)6[-3]',\n", + " 'RbNO2(aq)',\n", + " 'Re[+3]',\n", + " 'LaCl3(aq)',\n", + " 'CrO4[-2]',\n", + " 'H[+1]',\n", + " 'K3PO4(aq)',\n", + " 'Ce[+4]',\n", + " 'Cu[+2]',\n", + " 'H2CO3(aq)',\n", + " 'BaCl2(aq)',\n", + " 'NaBrO3(aq)',\n", + " 'Zr[+4]',\n", + " 'CsI(aq)',\n", + " 'CoCl2(aq)',\n", + " 'Ac[+3]',\n", + " 'Ti[+2]',\n", + " 'Nd(NO3)3(aq)',\n", + " 'NaBr(aq)',\n", + " 'La(NO3)3(aq)',\n", + " 'MgC4O.3H2O(aq)',\n", + " 'PO3[-1]',\n", + " 'CrCl3(aq)',\n", + " 'U[+3]',\n", + " 'HCl(aq)',\n", + " 'Tc[+2]',\n", + " 'Au(CN)4[-1]',\n", + " 'HOsO5[-1]',\n", + " 'WO4[-1]',\n", + " 'PHO4[-2]',\n", + " 'ClO3[-1]',\n", + " 'K4Fe(CN)6(aq)',\n", + " 'Br[-0.33333333]',\n", + " 'Sr[+2]',\n", + " 'Cr[+3]',\n", + " 'UO2[+2]',\n", + " 'Ni[+2]',\n", + " 'Tl(ClO4)3(aq)',\n", + " 'Pu[+4]',\n", + " 'NaHC2O.1H2O(aq)',\n", + " 'MgI2(aq)',\n", + " 'TlH(C3O)2.4H2O(aq)',\n", + " 'Co(CN)6[-3]',\n", + " 'K2PHO4(aq)',\n", + " 'Mn[+2]',\n", + " 'NaNO3(aq)',\n", + " 'ScCl3(aq)',\n", + " 'CeCl3(aq)',\n", + " 'MnSO4(aq)',\n", + " 'Ru[+3]',\n", + " 'CsNO3(aq)',\n", + " 'HCO3[-1]',\n", + " 'H4NCl(aq)',\n", + " 'Ag[+2]',\n", + " 'Nb[+3]',\n", + " 'CNO[-1]',\n", + " 'H4IN(aq)',\n", + " 'In[+1]',\n", + " 'Ge[+2]',\n", + " 'HI(aq)',\n", + " 'ReO4[-1]',\n", + " 'MgCl2(aq)',\n", + " 'CsF(aq)',\n", + " 'N[-0.33333333]',\n", + " 'HClO4(aq)',\n", + " 'CsCl(aq)',\n", + " 'KHCO3(aq)',\n", + " 'La[+3]',\n", + " 'Ba(ClO4)2(aq)',\n", + " 'Bi[+3]',\n", + " 'CaBr2(aq)',\n", + " 'Yb[+2]',\n", + " 'CaCl2(aq)',\n", + " 'UO2[+1]',\n", + " 'Mo[+3]',\n", + " 'KClO4(aq)',\n", + " 'KOH(aq)',\n", + " 'LiBr(aq)',\n", + " 'SO3[-1]',\n", + " 'NaPO3.1H2O(aq)',\n", + " 'AsO4[-3]',\n", + " 'Br[-1]',\n", + " 'Dy[+3]',\n", + " 'IO3[-1]',\n", + " 'Sc[+3]',\n", + " 'H2SNO3[-1]',\n", + " 'Np[+3]',\n", + " 'Fe(CN)6[-4]',\n", + " 'RbHC2O.1H2O(aq)',\n", + " 'Nd[+2]',\n", + " 'Pr[+2]',\n", + " 'HBr(aq)',\n", + " 'MgSO4(aq)',\n", + " 'PO3F[-2]',\n", + " 'RbI(aq)',\n", + " 'Cu[+3]',\n", + " 'Pm[+3]',\n", + " 'H4BrN(aq)',\n", + " 'MnCl2(aq)',\n", + " 'CsHC2O.1H2O(aq)',\n", + " 'Y[+3]',\n", + " 'Hf[+4]',\n", + " 'Na[+1]',\n", + " 'H5C6O7[-3]',\n", + " 'Co(NO3)2(aq)',\n", + " 'NaCSN(aq)',\n", + " 'NaHCO3(aq)',\n", + " 'CsBr(aq)',\n", + " 'W[+3]',\n", + " 'NO2[-1]',\n", + " 'V[+2]',\n", + " 'SO4[-1]',\n", + " 'B(OH)3(aq)',\n", + " 'KCl(aq)',\n", + " 'Cl[-1]',\n", + " 'SrBr2(aq)',\n", + " 'PF6[-1]',\n", + " 'YCl3(aq)',\n", + " 'Pb(ClO4)2(aq)',\n", + " 'Co[+3]',\n", + " 'S2O3[-2]',\n", + " 'H4N2O3(aq)',\n", + " 'Cr[+2]',\n", + " 'NaF(aq)',\n", + " 'H4N[+1]',\n", + " 'Au(CN)2[-1]',\n", + " 'SO4[-2]',\n", + " 'Tc[+3]',\n", + " 'NaCl(aq)',\n", + " 'Eu[+3]',\n", + " 'Ru[+2]',\n", + " 'V[+3]',\n", + " 'Cu(NO3)2(aq)',\n", + " 'Fe[+2]',\n", + " 'Nd[+3]',\n", + " 'SO3[-2]',\n", + " 'BF4[-1]',\n", + " 'Sb(HO2)2[-1]',\n", + " 'B(H5C6)4[-1]',\n", + " 'Mg[+2]',\n", + " 'Cd(NO2)2(aq)',\n", + " 'SO2[-1]',\n", + " 'NaI(aq)',\n", + " 'Ti[+3]',\n", + " 'Cs[+1]',\n", + " 'HSeO3[-1]',\n", + " 'LiOH(aq)',\n", + " 'LiCl(aq)',\n", + " 'RbF(aq)',\n", + " 'WO4[-2]',\n", + " 'Pd[+2]',\n", + " 'Tb[+3]',\n", + " 'In[+2]',\n", + " 'Re[-1]',\n", + " 'Na2S2O3(aq)',\n", + " 'KNO2(aq)',\n", + " 'TcO4[-1]',\n", + " 'U[+4]',\n", + " 'BaI2(aq)',\n", + " 'CO3[-2]',\n", + " 'H4SNO4(aq)',\n", + " 'CN[-1]',\n", + " 'Sc[+2]',\n", + " 'Cd(NO3)2(aq)',\n", + " 'Na2SO4(aq)',\n", + " 'IrO4[-1]',\n", + " 'Lu[+3]',\n", + " 'Au[+2]']" + ] + }, + "execution_count": 19, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# list of all unique `formula`\n", + "IonDB.distinct('formula')" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python (conda: skagit2)", + "language": "python", + "name": "skagit2" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.6" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/docs/examples/.ipynb_checkpoints/pyeql_tutorial_osmotic_pressure-checkpoint.ipynb b/docs/examples/.ipynb_checkpoints/pyeql_tutorial_osmotic_pressure-checkpoint.ipynb new file mode 100644 index 00000000..d807ad04 --- /dev/null +++ b/docs/examples/.ipynb_checkpoints/pyeql_tutorial_osmotic_pressure-checkpoint.ipynb @@ -0,0 +1,451 @@ +{ + "cells": [ + { + "attachments": { + "b51ca3f4-e8bd-4b0a-a599-5f6724ad8fe5.png": { + "image/png": "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" + } + }, + "cell_type": "markdown", + "id": "305d1216-9791-43dd-8d7f-ec90aa72a307", + "metadata": { + "tags": [] + }, + "source": [ + "# `pyEQL` Tutorial: Calculating Osmotic Pressure\n", + "\n", + "![pyeql-logo.png](attachment:b51ca3f4-e8bd-4b0a-a599-5f6724ad8fe5.png)\n", + "\n", + "`pyEQL` is an open-source `python` library for solution chemistry calculations and ion properties developed by the [Kingsbury Lab](https://www.kingsburylab.org/) at Princeton University.\n", + "\n", + "[Documentation](https://pyeql.readthedocs.io/en/latest/) | [How to Install](https://pyeql.readthedocs.io/en/latest/installation.html) | [GitHub](https://github.com/rkingsbury/pyEQL) " + ] + }, + { + "cell_type": "markdown", + "id": "90c14b65-36f0-4bb2-a3bf-f8e725cc897e", + "metadata": { + "tags": [] + }, + "source": [ + "## Installation\n", + "\n", + "Uncomment and run the code cell below, if you do not already have `pyEQL`" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "abb1f51c-38fc-4543-8b59-057b8c591ba9", + "metadata": {}, + "outputs": [], + "source": [ + "# pip install pyEQL" + ] + }, + { + "cell_type": "markdown", + "id": "1b8efc81-17bb-46dc-8a22-63e71ae458b7", + "metadata": {}, + "source": [ + "## First, create a `Solution`\n", + "\n", + "`pyEQL`'s built-in property database contains Pitzer model parameters for many simple (binary) electrolytes. If such parameters are available, `pyEQL` will use them by default." + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "55f1aea5-a5b8-49b8-a8e8-20856c4be6e7", + "metadata": { + "scrolled": true + }, + "outputs": [], + "source": [ + "from pyEQL import Solution\n", + "# 2 mol/L NaCl\n", + "s1 = Solution({\"Na+\": \"2 mol/L\", \"Cl-\": \"2 mol/L\"})" + ] + }, + { + "cell_type": "markdown", + "id": "23b21981-7568-4e29-a93c-4017a32629b4", + "metadata": {}, + "source": [ + "## Get the osmotic pressure\n", + "\n", + "Note that the osmotic pressure (and most `Solution` properties) are returned as `pint` `Quantity` objects (see [Converting Units](https://pyeql.readthedocs.io/en/latest/units.html))." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "5c037d7c-0a16-4d0a-b2e7-ad2d43a4d3bb", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "10224795.514383134 Pa" + ], + "text/latex": [ + "$10224795.514383134\\ \\mathrm{Pa}$" + ], + "text/plain": [ + "10224795.514383134 " + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "s1.osmotic_pressure" + ] + }, + { + "cell_type": "markdown", + "id": "2b7800c8-e23a-4d6b-9d36-77ac51226fb4", + "metadata": {}, + "source": [ + "If you want the osmotic pressure in different units, or you only want the magnitude, use `to()` and `magnitude`, respectively" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "55f0b945-fe6f-464e-a855-30ec0e5292c5", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "102.24795514383135 bar" + ], + "text/latex": [ + "$102.24795514383135\\ \\mathrm{bar}$" + ], + "text/plain": [ + "102.24795514383135 " + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "s1.osmotic_pressure.to('bar')" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "51adb7d2-40f0-4072-adce-9ca2d980e5ef", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "102.24795514383135" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "s1.osmotic_pressure.to('bar').magnitude" + ] + }, + { + "cell_type": "markdown", + "id": "6b754001-1ee7-4348-882a-6e6f6e046b93", + "metadata": {}, + "source": [ + "## Use a `for` loop for multiple calculations\n", + "\n", + "You can rapidly get estimates for multiple concentrations (or temperatures, or solutes) by using a `for` loop. Notice how in the example below, we use [f-strings](https://realpython.com/python-f-strings/) to insert the desired concentration (from the `for` loop) into the argument passed to `Solution` and to print the results." + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "53ab967d-1cac-4e3a-9a4d-11f9b28f5bd2", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "At C=0.1 M, the osmotic pressure is 4.63 bar.\n", + "At C=0.5 M, the osmotic pressure is 23.07 bar.\n", + "At C=1.0 M, the osmotic pressure is 47.40 bar.\n", + "At C=2.0 M, the osmotic pressure is 102.25 bar.\n", + "At C=4.0 M, the osmotic pressure is 246.95 bar.\n" + ] + } + ], + "source": [ + "for conc in [0.1, 0.5, 1, 2, 4]:\n", + " s1 = Solution({\"Na+\": f\"{conc} mol/L\", \"Cl-\": f\"{conc} mol/L\"})\n", + " print(f\"At C={conc:.1f} M, the osmotic pressure is {s1.osmotic_pressure.to('bar'):.2f}.\")" + ] + }, + { + "cell_type": "markdown", + "id": "ba4ff669-b6c0-4592-b9be-1b088b548cfc", + "metadata": {}, + "source": [ + "## Compare different modeling engines\n", + "\n", + "`pyEQL` contains several different [modeling engines](https://pyeql.readthedocs.io/en/latest/engines.html) that can calculate activity coefficients or osmotic pressures. At present, there are three options:\n", + "\n", + "1. The `native` or built-in engine, which includes an implementation of the Piter model (Default).\n", + "2. the `phreeqc` engine, which utilizes the USGS PHREEQC model with the `phreeqc.dat` database.\n", + "3. An ideal solution model (`ideal`) which does not account for solution non-ideality.\n", + "\n", + "You select a modeling engine using the `engine` keyword argument when you create a `Solution`. Let's compare the preditions from the three models." + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "6962da9e-f510-483f-8ab6-df29a054441a", + "metadata": {}, + "outputs": [], + "source": [ + "s_ideal = Solution({\"Na+\": \"2 mol/L\", \"Cl-\": \"2 mol/L\"}, engine='ideal')\n", + "s_phreeqc = Solution({\"Na+\": \"2 mol/L\", \"Cl-\": \"2 mol/L\"}, engine='phreeqc')\n", + "s_native = Solution({\"Na+\": \"2 mol/L\", \"Cl-\": \"2 mol/L\"}, engine='native')" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "2a627a29-e7b4-458e-86bb-e23b71ae8f65", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "WARNING 2023-11-10 11:48:57,162 solution.py get_water_activity 1934 Pitzer parameters not found. Water activity set equal to mole fraction\n" + ] + }, + { + "data": { + "text/html": [ + "95.73878424096024 bar" + ], + "text/latex": [ + "$95.73878424096024\\ \\mathrm{bar}$" + ], + "text/plain": [ + "95.73878424096024 " + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "s_ideal.osmotic_pressure.to('bar')" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "id": "29ef5458-fc42-44de-a3b5-05e80987f9e8", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "95.73878424096024 bar" + ], + "text/latex": [ + "$95.73878424096024\\ \\mathrm{bar}$" + ], + "text/plain": [ + "95.73878424096024 " + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "s_phreeqc.osmotic_pressure.to('bar')" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "id": "5807fbde-dddd-4883-8bf0-1014ce08833b", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "102.24795514383135 bar" + ], + "text/latex": [ + "$102.24795514383135\\ \\mathrm{bar}$" + ], + "text/plain": [ + "102.24795514383135 " + ] + }, + "execution_count": 10, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "s_native.osmotic_pressure.to('bar')" + ] + }, + { + "cell_type": "markdown", + "id": "c49fb2e3-71a3-49ff-9f17-35e64f6f6d54", + "metadata": {}, + "source": [ + "## Plot the comparison vs. experiment\n", + "\n", + "We can make a plot showing how the 3 models compare by combining the two previous steps (using a `for` loop plus changing the `engine` keyword argument. Note that this example makes use of `matplotlib` for plotting." + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "id": "d38dd675-0767-4eea-ab11-d85c4613e59e", + "metadata": {}, + "outputs": [], + "source": [ + "# create empty lists to hold the results\n", + "pi_ideal = []\n", + "pi_phreeqc = []\n", + "pi_native = []\n", + "\n", + "concentrations = [0.1, 0.2, 0.3, 0.4, 0.5, 1, 1.4, 2, 2.5, 3, 3.5, 4]\n", + "\n", + "for conc in concentrations:\n", + " s_ideal = Solution({\"Na+\": f\"{conc} mol/kg\", \"Cl-\": f\"{conc} mol/kg\"}, engine='ideal')\n", + " s_phreeqc = Solution({\"Na+\": f\"{conc} mol/kg\", \"Cl-\": f\"{conc} mol/kg\"}, engine='phreeqc')\n", + " s_native = Solution({\"Na+\": f\"{conc} mol/kg\", \"Cl-\": f\"{conc} mol/kg\"}, engine='native')\n", + " \n", + " # store the osmotic pressures in the respective lists\n", + " # note that we have to just store the .magnitude because matplotlib can't plot Quantity\n", + " pi_ideal.append(s_ideal.osmotic_pressure.to('bar').magnitude)\n", + " pi_phreeqc.append(s_phreeqc.osmotic_pressure.to('bar').magnitude)\n", + " pi_native.append(s_native.osmotic_pressure.to('bar').magnitude)" + ] + }, + { + "cell_type": "markdown", + "id": "a651b33f-5572-40a2-8587-bd7af7a71170", + "metadata": {}, + "source": [ + "We will include experimental data from the [IDST](https://idst.inl.gov/) as a benchmark. The IDST gives us water activity, which we convert into osmotic pressure according to\n", + "\n", + "$$\n", + "\\Pi = -\\frac{RT}{V_{w}} \\ln a_{w}\n", + "$$\n", + "\n", + "Where $\\Pi$ is the osmotic pressure, $V_{w}$ is the partial molar volume of water (18.2 cm**3/mol), and $a_{w}$ is the water\n", + " activity." + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "id": "008d1e80-536b-4346-9527-462deacd6b70", + "metadata": {}, + "outputs": [], + "source": [ + "import math\n", + "# water activity at [0.1, 0.2, 0.3, 0.4, 0.5, 1, 1.5, 2, 2.5, 3, 3.5, 4] mol/kg\n", + "water_activity_idst = [0.99664, 0.993353, 0.99008, 0.986804, 0.98352, 0.966828, 0.953166, 0.93191, 0.913072, 0.89347, 0.872859, 0.85133]\n", + "\n", + "# calculate osmotic pressure as -RT/Vw ln(a_w). Factor 10 converts to bar.\n", + "pi_idst = [-8.314*298.15/18.2 * math.log(a) * 10 for a in water_activity_idst]" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "id": "1082bad0-c9e1-4e16-941d-fd908ea402fe", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "Text(0.5, 0.98, 'pyEQL prediction of NaCl osmotic pressure')" + ] + }, + "execution_count": 13, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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a7szZ86IZ555Rpibm4u2bduK5557Tv3EeiGECAsLE66urur39z6UTwgh/Pz81A/mGzp0aLUHT1Y5ePCgePzxx4Wpqamws7MTs2fPFjdu3Kgxto8++kgYGRlpfYBhRUWF+tiysjIxe/Zs0blzZyGXy4W3t7dITExUt616uOn+/fuFu7u7aNOmjfD09BQnTpzQ+Mzdu3eLgQMHCrlcLjp16iTGjh2r3ldWVibeeustYWtrK8zMzISHh4c4cOCAev/69euFpaWl2Lt3r3jkkUeEubm5UCgU4sKFC+qf470/lwMHDojc3FwBQGzZskUMGTJEyOVysX79enH58mUxceJEYWtrK9q0aSP69esnNm/erD7flClTqn1ebm6uOtfCwkJ12++++044OTkJmUwmunfvLpYuXaqRd/fu3cX7778v/P39hYWFhbC3txdr166tsV+EEGL79u2ic+fOGtuqclm4cKHo3bu3xr4+ffqIkJAQdZxVysvLhVwuF/v376/1fEQtCUd2iFoICwsLWFhYYNeuXSgvL9faRqVSwc/PD1evXkVcXByio6Nx6tQpPP/88w0+7/fffw87OzssXrwYeXl5yMvLAwCcPHkSo0aNwrPPPou0tDRs3boVhw4dwqxZs2r8rE2bNsHHxwf9+/evts/ExATm5uYAgPnz52PHjh3YuHEjkpOT0atXLygUCly9elXjmP/85z9YtmwZ/vjjDxgbG2PatGnqfVFRURg3bhyeeuoppKSkICYmBh4eHur9s2bNQkJCArZs2YK0tDQ899xzGDVqFHJyctRtSktLsXTpUnz99deIj4/H2bNn8fbbbwMA3n77bUyYMAGjRo1S/1y8vLzUxwYHB2POnDnIysqCQqFAWVkZ3N3dERUVhePHj2P69Ol46aWXkJiYCAD49NNP4enpiYCAAPXn2dvbV/s5JSUlYcKECZg4cSLS09OxaNEihISEYMOGDRrtli1bhoEDByIlJQWvv/46AgMDkZ2dXWPfHDx4EO7u7lr3PfPMMygsLMShQ4cAAIcOHUJhYSHGjBlTra1MJoObmxsOHjxY47mIWhxdV1tE9I/vvvtOdOjQQZiamgovLy+xYMECcezYMfX+X375RUilUnH27Fn1toyMDAFAPTJS35EdIW6PFCxfvlyjzSuvvCKmT5+use3gwYPCyMhI3Lx5U2v8bdq0EW+88UatOd64cUOYmJiITZs2qbdVVFQIW1tbsWTJEiGE5shOlaioKAFAfW5PT08xefJkrec4c+aMkEql4vz58xrbR44cKRYsWCCEuD2yA0D89ddf6v2RkZHC2tpa/X7KlCnCz89P4zOqRkNWrFhRa55CCDF69Gjx1ltvqd9r64t7R3ZeeOEF4evrq9Fm3rx5wsnJSf2+e/fu4sUXX1S/V6lUokuXLmL16tU1xuLn5yemTZumNZeUlBQRFBQk/P39hRBC+Pv7izfffFOkpKRUG9kRQohx48aJqVOn3jd/opaCIztELcizzz6LCxcuYPfu3Rg1ahRiY2MxYMAA9f/qs7KyYG9vrzEi4OTkhPbt2yMrK6tRYzl27Bg2bNigHnGysLCAQqGASqVCbm6u1mOEEPf93JMnT6KyshLe3t7qbSYmJvDw8KiWg4uLi/rvXbt2BQAUFBQAAFJTUzFy5Eit50hPT4dSqUSfPn004o+Li8PJkyfV7czMzNCzZ0+Nc1R9/v0MHDhQ471SqUR4eDicnZ3RsWNHWFhYYN++fTh79mydPq9KVlaWxs8GALy9vZGTkwOlUqnedvfPRiKRwMbGptbYb968CVNT0xr3T5s2Ddu3b0d+fj62b9+uMYp2rzZt2qC0tLQu6RC1CMa6DoCINJmamsLX1xe+vr4ICQnBq6++irCwMEydOrVBn2dkZFStCKnLhNobN25gxowZeOONN6rt69atm9Zj+vTpgxMnTjQoTm1MTEzUf6+awKtSqQDc/sKtyY0bNyCVSpGUlASpVKqxz8LCQuvnV52jLgUbAPWv5Kp8/PHH+PTTT7FixQo4OzvD3NwcQUFBqKioqNPn1Ze22Kt+NtpYWVmhsLCwxv3Ozs545JFHMGnSJPTt2xf9+vVDamqq1rZXr17VKBKJWjqO7BC1cE5OTur7mvTt2xfnzp3DuXPn1PszMzNx7do1ODk5aT2+c+fO6nk4wO0RiOPHj2u0kclkGqMGADBgwABkZmaiV69e1V4ymUzruV544QXs378fKSkp1fZVVlaipKQEPXv2hEwm01hOX1lZiaNHj9aYgzYuLi6IiYnRuq9///5QKpUoKCioFruNjU2dz6Ht51KTw4cPw8/PDy+++CJcXV3x8MMP488//6z35/Xt27farQYOHz6MPn36VCvc6qN///7IzMystc20adMQGxtb66gOABw/flzrvCyilorFDlELceXKFYwYMQLffPMN0tLSkJubi+3bt2PJkiXw8/MDAPj4+MDZ2RmTJ09GcnIyEhMT8fLLL2Po0KHVfq1SZcSIEYiKikJUVBROnDiBwMDAajewc3BwQHx8PM6fP4/Lly8DAP7973/jyJEjmDVrFlJTU5GTk4Mffvih1gnKQUFB8Pb2xsiRIxEZGYljx47h1KlT2LZtGwYPHoycnByYm5sjMDAQ8+bNw969e5GZmYmAgACUlpZqXRZdk7CwMHz77bcICwtDVlYW0tPT8dFHHwG4PcI0efJkvPzyy/j++++Rm5uLxMREREREICoqqs7ncHBwQFpaGrKzs3H58uVaR8R69+6N6OhoHDlyBFlZWZgxYwYuXrxY7fN+//13nD59GpcvX9Y6EvPWW28hJiYG4eHh+PPPP7Fx40asWrVKPXG6oRQKBTIyMmod3QkICMClS5fw6quv1tjm9OnTOH/+PHx8fB4oHqJmpeM5Q0R0R1lZmQgODhYDBgwQlpaWwszMTDg6OoqFCxeK0tJSdbv6Lj2vqKgQgYGBomPHjqJLly4iIiKi2gTlhIQE4eLiIuRyucbS88TEROHr6yssLCyEubm5cHFxEe+///5984iIiBDOzs7C1NRUdOzYUXh7e4sNGzaIyspKIYQQN2/eFLNnzxZWVla1Lj2/ezm2tsmyO3bsEG5ubkImkwkrKysxfvx4jbxDQ0OFg4ODMDExEV27dhXjxo0TaWlpQoh/lp7fbefOnRr5FxQUqPPHPUvPU1JSNI69cuWK8PPzExYWFqJLly5i4cKF4uWXX9aY4JydnS0GDx4s2rRpU6el5yYmJqJbt27i448/1jiXtgnlrq6uIiwsrIZeuc3Dw0OsWbNG/b6mXKpo+5l/8MEHQqFQ1HoeopZGIkQdf0FNRER6LSoqCvPmzcPx48dhZFT/gf2Kigr07t0bmzdvrjaJmqgl4wRlIqJWYvTo0cjJycH58+e13uPnfs6ePYt33nmHhQ7pHY7sEBERkUHjBGUiIiIyaCx2iIiIyKCx2CEiIiKDxmKHiIiIDBqLHSIiIjJoLHaIiIjIoLHYISIiIoPGYoeIiIgMGosdIiIiMmj/D9tzj3YXXYFmAAAAAElFTkSuQmCC\n", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# plot the results!\n", + "from matplotlib import pyplot as plt\n", + "\n", + "fig, ax = plt.subplots()\n", + "ax.plot(concentrations, pi_ideal, label=\"engine='ideal'\", ls='--', color='gray')\n", + "ax.plot(concentrations, pi_phreeqc, label=\"engine='phreeqc'\", ls=':', color='green')\n", + "ax.plot(concentrations, pi_native, label=\"engine='native'\", ls='-', color='navy')\n", + "ax.plot(concentrations, pi_idst, label=\"experiment\", ls='', color='red', marker=\"x\")\n", + "ax.legend()\n", + "ax.set_xlabel('Solute Concentration (M)')\n", + "ax.set_ylabel('Osmotic Pressure (bar)')\n", + "fig.suptitle('pyEQL prediction of NaCl osmotic pressure')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "cd14cb5f-f9a4-4006-ae26-2ef827d2412d", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python (conda: skagit2)", + "language": "python", + "name": "skagit2" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.6" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/docs/examples/.ipynb_checkpoints/speedup-checkpoint.ipynb b/docs/examples/.ipynb_checkpoints/speedup-checkpoint.ipynb new file mode 100644 index 00000000..2deed0b2 --- /dev/null +++ b/docs/examples/.ipynb_checkpoints/speedup-checkpoint.ipynb @@ -0,0 +1,336 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "id": "c45d3fd6-8af1-4df7-ac05-2805da805893", + "metadata": {}, + "outputs": [], + "source": [ + "from pyEQL import Solution" + ] + }, + { + "cell_type": "markdown", + "id": "a376cef5-2e52-4aa7-a365-57337b20171b", + "metadata": {}, + "source": [ + "### Before optimization" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "bdf1fb10-a567-499d-a0c2-2e3ea4e7fdab", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "298 ms ± 4.11 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)\n" + ] + } + ], + "source": [ + "%%timeit\n", + "s = Solution({\"Na+\": \"2 mol/L\", \"Cl-\": \"2 mol/L\"})" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "b6ce2ea9-8a86-4140-bd82-35f72f06fbbc", + "metadata": {}, + "outputs": [], + "source": [ + "s = Solution({\"Na+\": \"2 mol/L\", \"Cl-\": \"2 mol/L\"})" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "3d391433-2a16-4470-8c40-2b43cda68b35", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "27.1 ms ± 277 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)\n" + ] + } + ], + "source": [ + "%%timeit\n", + "s.get_activity_coefficient('Na+')" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "7ef3de2d-15cc-4f3e-8753-1b9de8238aa0", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "WARNING 2023-11-04 17:15:55,353 solution.py viscosity_kinematic 599 Viscosity coefficients for NaCl not found. Viscosity will be approximate.\n", + "WARNING 2023-11-04 17:15:55,408 solution.py viscosity_kinematic 599 Viscosity coefficients for NaCl not found. Viscosity will be approximate.\n", + "WARNING 2023-11-04 17:15:55,460 solution.py viscosity_kinematic 599 Viscosity coefficients for NaCl not found. Viscosity will be approximate.\n", + "WARNING 2023-11-04 17:15:55,489 engines.py get_activity_coefficient 314 Ionic strength too high to estimate activity for species H[+1]. Specify parameters for Pitzer model. Returning unit activity coefficient\n", + "WARNING 2023-11-04 17:15:55,507 solution.py viscosity_kinematic 599 Viscosity coefficients for NaCl not found. Viscosity will be approximate.\n", + "WARNING 2023-11-04 17:15:55,535 engines.py get_activity_coefficient 314 Ionic strength too high to estimate activity for species OH[-1]. Specify parameters for Pitzer model. Returning unit activity coefficient\n", + "WARNING 2023-11-04 17:15:55,644 engines.py get_activity_coefficient 314 Ionic strength too high to estimate activity for species H[+1]. Specify parameters for Pitzer model. Returning unit activity coefficient\n", + "WARNING 2023-11-04 17:15:55,678 engines.py get_activity_coefficient 314 Ionic strength too high to estimate activity for species OH[-1]. Specify parameters for Pitzer model. Returning unit activity coefficient\n", + "WARNING 2023-11-04 17:15:55,788 engines.py get_activity_coefficient 314 Ionic strength too high to estimate activity for species H[+1]. Specify parameters for Pitzer model. Returning unit activity coefficient\n", + "WARNING 2023-11-04 17:15:55,822 engines.py get_activity_coefficient 314 Ionic strength too high to estimate activity for species OH[-1]. Specify parameters for Pitzer model. Returning unit activity coefficient\n", + "WARNING 2023-11-04 17:15:55,932 engines.py get_activity_coefficient 314 Ionic strength too high to estimate activity for species H[+1]. Specify parameters for Pitzer model. Returning unit activity coefficient\n", + "WARNING 2023-11-04 17:15:55,964 engines.py get_activity_coefficient 314 Ionic strength too high to estimate activity for species OH[-1]. Specify parameters for Pitzer model. Returning unit activity coefficient\n", + "WARNING 2023-11-04 17:15:56,071 engines.py get_activity_coefficient 314 Ionic strength too high to estimate activity for species H[+1]. Specify parameters for Pitzer model. Returning unit activity coefficient\n", + "WARNING 2023-11-04 17:15:56,104 engines.py get_activity_coefficient 314 Ionic strength too high to estimate activity for species OH[-1]. Specify parameters for Pitzer model. Returning unit activity coefficient\n", + "WARNING 2023-11-04 17:15:56,211 engines.py get_activity_coefficient 314 Ionic strength too high to estimate activity for species H[+1]. Specify parameters for Pitzer model. Returning unit activity coefficient\n", + "WARNING 2023-11-04 17:15:56,242 engines.py get_activity_coefficient 314 Ionic strength too high to estimate activity for species OH[-1]. Specify parameters for Pitzer model. Returning unit activity coefficient\n", + "WARNING 2023-11-04 17:15:56,348 engines.py get_activity_coefficient 314 Ionic strength too high to estimate activity for species H[+1]. Specify parameters for Pitzer model. Returning unit activity coefficient\n", + "WARNING 2023-11-04 17:15:56,384 engines.py get_activity_coefficient 314 Ionic strength too high to estimate activity for species OH[-1]. Specify parameters for Pitzer model. Returning unit activity coefficient\n", + "WARNING 2023-11-04 17:15:56,495 engines.py get_activity_coefficient 314 Ionic strength too high to estimate activity for species H[+1]. Specify parameters for Pitzer model. Returning unit activity coefficient\n", + "WARNING 2023-11-04 17:15:56,528 engines.py get_activity_coefficient 314 Ionic strength too high to estimate activity for species OH[-1]. Specify parameters for Pitzer model. Returning unit activity coefficient\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "142 ms ± 1.96 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)\n" + ] + } + ], + "source": [ + "%%timeit\n", + "s.conductivity" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "b30d7f1c-9630-4e21-b275-cb3befc2433f", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "5.27 ms ± 153 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)\n" + ] + } + ], + "source": [ + "%%timeit\n", + "s.ionic_strength" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "id": "40a55c8b-947d-4806-8094-2188f244816a", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2.43 ms ± 18.5 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)\n" + ] + } + ], + "source": [ + "%%timeit\n", + "s.get_transport_number('Na+')" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "314d44f5-88c1-44a8-b0e2-3e072e3ad8ab", + "metadata": {}, + "outputs": [ + { + "ename": "SyntaxError", + "evalue": "'break' outside loop (668683560.py, line 1)", + "output_type": "error", + "traceback": [ + "\u001b[0;36m Cell \u001b[0;32mIn [8], line 1\u001b[0;36m\u001b[0m\n\u001b[0;31m break\u001b[0m\n\u001b[0m ^\u001b[0m\n\u001b[0;31mSyntaxError\u001b[0m\u001b[0;31m:\u001b[0m 'break' outside loop\n" + ] + } + ], + "source": [ + "break" + ] + }, + { + "cell_type": "markdown", + "id": "e8ae1012-8728-448a-bebe-03752f97a578", + "metadata": {}, + "source": [ + "### After optimization" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "2f1739e4-da68-484f-b691-9be13a00bc94", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "85 ms ± 1.46 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)\n" + ] + } + ], + "source": [ + "%%timeit\n", + "s = Solution({\"Na+\": \"2 mol/L\", \"Cl-\": \"2 mol/L\"})" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "cc95a42c-1151-4756-9289-6aee0717fe81", + "metadata": {}, + "outputs": [], + "source": [ + "s = Solution({\"Na+\": \"2 mol/L\", \"Cl-\": \"2 mol/L\"})" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "3940edb9-94d6-45bd-a6db-c535d4968045", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "14 ms ± 239 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)\n" + ] + } + ], + "source": [ + "%%timeit\n", + "s.get_activity_coefficient('Na+')" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "185d5272-84a1-4944-bb39-948cc970989d", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "WARNING 2023-11-04 17:30:41,861 engines.py get_activity_coefficient 314 Ionic strength too high to estimate activity for species H[+1]. Specify parameters for Pitzer model. Returning unit activity coefficient\n", + "WARNING 2023-11-04 17:30:41,874 engines.py get_activity_coefficient 314 Ionic strength too high to estimate activity for species OH[-1]. Specify parameters for Pitzer model. Returning unit activity coefficient\n", + "WARNING 2023-11-04 17:30:41,912 engines.py get_activity_coefficient 314 Ionic strength too high to estimate activity for species H[+1]. Specify parameters for Pitzer model. Returning unit activity coefficient\n", + "WARNING 2023-11-04 17:30:41,917 engines.py get_activity_coefficient 314 Ionic strength too high to estimate activity for species OH[-1]. Specify parameters for Pitzer model. Returning unit activity coefficient\n", + "WARNING 2023-11-04 17:30:41,953 engines.py get_activity_coefficient 314 Ionic strength too high to estimate activity for species H[+1]. Specify parameters for Pitzer model. Returning unit activity coefficient\n", + "WARNING 2023-11-04 17:30:41,958 engines.py get_activity_coefficient 314 Ionic strength too high to estimate activity for species OH[-1]. Specify parameters for Pitzer model. Returning unit activity coefficient\n", + "WARNING 2023-11-04 17:30:41,995 engines.py get_activity_coefficient 314 Ionic strength too high to estimate activity for species H[+1]. Specify parameters for Pitzer model. Returning unit activity coefficient\n", + "WARNING 2023-11-04 17:30:42,000 engines.py get_activity_coefficient 314 Ionic strength too high to estimate activity for species OH[-1]. Specify parameters for Pitzer model. Returning unit activity coefficient\n", + "WARNING 2023-11-04 17:30:42,036 engines.py get_activity_coefficient 314 Ionic strength too high to estimate activity for species H[+1]. Specify parameters for Pitzer model. Returning unit activity coefficient\n", + "WARNING 2023-11-04 17:30:42,042 engines.py get_activity_coefficient 314 Ionic strength too high to estimate activity for species OH[-1]. Specify parameters for Pitzer model. Returning unit activity coefficient\n", + "WARNING 2023-11-04 17:30:42,078 engines.py get_activity_coefficient 314 Ionic strength too high to estimate activity for species H[+1]. Specify parameters for Pitzer model. Returning unit activity coefficient\n", + "WARNING 2023-11-04 17:30:42,084 engines.py get_activity_coefficient 314 Ionic strength too high to estimate activity for species OH[-1]. Specify parameters for Pitzer model. Returning unit activity coefficient\n", + "WARNING 2023-11-04 17:30:42,119 engines.py get_activity_coefficient 314 Ionic strength too high to estimate activity for species H[+1]. Specify parameters for Pitzer model. Returning unit activity coefficient\n", + "WARNING 2023-11-04 17:30:42,124 engines.py get_activity_coefficient 314 Ionic strength too high to estimate activity for species OH[-1]. Specify parameters for Pitzer model. Returning unit activity coefficient\n", + "WARNING 2023-11-04 17:30:42,160 engines.py get_activity_coefficient 314 Ionic strength too high to estimate activity for species H[+1]. Specify parameters for Pitzer model. Returning unit activity coefficient\n", + "WARNING 2023-11-04 17:30:42,166 engines.py get_activity_coefficient 314 Ionic strength too high to estimate activity for species OH[-1]. Specify parameters for Pitzer model. Returning unit activity coefficient\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "41.6 ms ± 639 µs per loop (mean ± std. dev. of 7 runs, 1 loop each)\n" + ] + } + ], + "source": [ + "%%timeit\n", + "s.conductivity" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "c3cd2d5b-f3a1-4909-aa18-caeebc60ae4e", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "527 µs ± 7.91 µs per loop (mean ± std. dev. of 7 runs, 1,000 loops each)\n" + ] + } + ], + "source": [ + "%%timeit\n", + "s.ionic_strength" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "366a8d79-d08b-48cc-ae9f-6e3dd1e25b3a", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "549 µs ± 11 µs per loop (mean ± std. dev. of 7 runs, 1,000 loops each)\n" + ] + } + ], + "source": [ + "%%timeit\n", + "s.get_transport_number('Na+')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c0d007b0-ec00-4c06-bee4-40d04e6cebf2", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.6" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/docs/examples/pyEQL_demo_1.ipynb b/docs/examples/pyEQL_demo_1.ipynb new file mode 100644 index 00000000..aefac42e --- /dev/null +++ b/docs/examples/pyEQL_demo_1.ipynb @@ -0,0 +1,525 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# pyEQL Demo" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Inspiration: `numpy` arrays\n", + "\n", + "`numpy` defines an *interface* for creating and manipulating numerical arrays. Because this interface is well-defined and predictable, many other numerical codes can build on `numpy`." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array([[ 1, 2, 3, 4, 5],\n", + " [ 6, 7, 8, 9, 10]])" + ] + }, + "execution_count": 1, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "import numpy as np\n", + "\n", + "array = np.array([[1,2,3,4,5], [6,7,8,9,10]])\n", + "array" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "(2, 5)" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "array.shape" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "9" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "array.argmax()" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "10" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "array.size" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### pyEQL aims to create a well-defined interface for electrolyte solutions\n", + "\n", + "Available methods include:\n", + "- `get_activity_coefficient`\n", + "- `get_amount` (for concentrations in any units)\n", + "- `get_pressure`\n", + "- `get_temperature`\n", + "- `get_volume`\n", + "- `get_dielectric_constant`\n", + "\n", + "and many more" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "
\n", + "\n", + "

\n", + "NOTICE

\n", + "

\n", + "The example below is using a *development* version of `pyEQL`. There are some subtle differences compared to the released version. Specifically:\n", + "\n", + "- The stable version does not support the `engine` keyword argument\n", + "- The stable version requires solutes to be input as list of lists rather than a dictionary\n", + "- The stable version uses `get_xxx` methods (e.g. `get_pressure()`) to access pressure, temperature, and volume instead of python properties.\n", + "\n", + "If you want to try this example, clone and install the `develop` branch from GitHub.\n", + "

\n", + "
" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "metadata": {}, + "outputs": [], + "source": [ + "from pyEQL import Solution\n", + "\n", + "s1 = Solution({\"Na+\": \"0.1 mol/L\",\n", + " \"Cl-\": \"0.1 mol/L\"\n", + " })" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "1 atm" + ], + "text/latex": [ + "$1\\ \\mathrm{atm}$" + ], + "text/plain": [ + "1 " + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "s1.pressure" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "298.15 K" + ], + "text/latex": [ + "$298.15\\ \\mathrm{K}$" + ], + "text/plain": [ + "298.15 " + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "s1.temperature" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "1 l" + ], + "text/latex": [ + "$1\\ \\mathrm{l}$" + ], + "text/plain": [ + "1 " + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "s1.volume" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "0.9322989671350115" + ], + "text/latex": [ + "$0.9322989671350115\\$" + ], + "text/plain": [ + "0.9322989671350115 " + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "s1.get_osmotic_coefficient()" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "0.0780726282259545" + ], + "text/latex": [ + "$0.0780726282259545\\$" + ], + "text/plain": [ + "0.0780726282259545 " + ] + }, + "execution_count": 10, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "s1.get_activity('Na+')" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "0.10046862144792715 mol/kg" + ], + "text/latex": [ + "$0.10046862144792715\\ \\frac{\\mathrm{mol}}{\\mathrm{kg}}$" + ], + "text/plain": [ + "0.10046862144792715 " + ] + }, + "execution_count": 11, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "s1.get_amount('Na+', \"mol/kg\")" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "0.1 mol/l" + ], + "text/latex": [ + "$0.1\\ \\frac{\\mathrm{mol}}{\\mathrm{l}}$" + ], + "text/plain": [ + "0.1 " + ] + }, + "execution_count": 12, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "s1.get_amount('Na+', \"mol/L\")" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "0.22962675104721783" + ], + "text/latex": [ + "$0.22962675104721783\\$" + ], + "text/plain": [ + "0.22962675104721783 " + ] + }, + "execution_count": 13, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "s1.get_amount('Na+', \"%\") #weight percent" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "0.0018034419870333782" + ], + "text/latex": [ + "$0.0018034419870333782\\$" + ], + "text/plain": [ + "0.0018034419870333782 " + ] + }, + "execution_count": 14, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "s1.get_amount('Na+', \"fraction\") # mole fraction" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### with pyEQL's modular \"engine\" system, switching activity models / equation of state models is easy\n", + "\n", + "Currently there are 2 options: `\"native\"` and `\"ideal\"`.\n", + "\n", + "The `\"native\"` model is built on the Pitzer model and has been the default in pyEQL for a long time. The `\"ideal\"` model represents ideal solution behavior.\n", + "\n", + "**Regardless of what model you choose, all the properties and method calls work exactly the same way**" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "0.7784212946835681" + ], + "text/latex": [ + "$0.7784212946835681\\$" + ], + "text/plain": [ + "0.7784212946835681 " + ] + }, + "execution_count": 18, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# native engine\n", + "s1 = Solution({\"Na+\": \"0.1 mol/L\", \"Cl-\": \"0.1 mol/L\"}, engine=\"native\")\n", + "s1.get_activity_coefficient('Na+', scale=\"molar\")" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "0.7784212946835681" + ], + "text/latex": [ + "$0.7784212946835681\\$" + ], + "text/plain": [ + "0.7784212946835681 " + ] + }, + "execution_count": 19, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# ideal engine\n", + "s1 = Solution([[\"Na+\", \"0.1 mol/L\"], [\"Cl-\", \"0.1 mol/L\"]], engine=\"native\")\n", + "s1.get_activity_coefficient('Na+', scale=\"molar\")" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "1.0" + ], + "text/latex": [ + "$1.0\\$" + ], + "text/plain": [ + "1.0 " + ] + }, + "execution_count": 17, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "from pyEQL import Solution\n", + "\n", + "s1 = Solution({\"Na+\": \"0.1 mol/L\", \"Cl-\": \"0.1 mol/L\"}, engine=\"ideal\")\n", + "s1.get_activity_coefficient('Na+', scale=\"molar\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Future `engine` options could include\n", + "\n", + "- PHREEQC / phreeqpython\n", + "- WaterTAP\n", + "- pyeqion2\n", + "- OLI Cloud API?" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3.9.7 ('md')", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.9.7" + }, + "orig_nbformat": 4, + "vscode": { + "interpreter": { + "hash": "20cd9c7c08a0db6a75cb79507bbd68d727d0a89c194dd19a90b8f7137b80c950" + } + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/docs/pyeql_demo.ipynb b/docs/examples/pyeql_demo.ipynb similarity index 98% rename from docs/pyeql_demo.ipynb rename to docs/examples/pyeql_demo.ipynb index bbc63e3e..8318aa97 100644 --- a/docs/pyeql_demo.ipynb +++ b/docs/examples/pyeql_demo.ipynb @@ -12,31 +12,35 @@ "tags": [] }, "source": [ - "# `pyEQL` Demonstration\n", + "# `pyEQL` Overview\n", "\n", "![pyeql-logo.png](attachment:b51ca3f4-e8bd-4b0a-a599-5f6724ad8fe5.png)\n", "\n", - "`pyEQL` is an open-source `python` library for solution chemistry calculations and ion properties\n", + "`pyEQL` is an open-source `python` library for solution chemistry calculations and ion properties developed by the [Kingsbury Lab](https://www.kingsburylab.org/) at Princeton University.\n", "\n", - "[Documentation](https://pyeql.readthedocs.io/en/latest/)\n", - "\n", - "[GitHub](https://github.com/rkingsbury/pyEQL)" + "[Documentation](https://pyeql.readthedocs.io/en/latest/) | [How to Install](https://pyeql.readthedocs.io/en/latest/installation.html) | [GitHub](https://github.com/rkingsbury/pyEQL) " ] }, { "cell_type": "markdown", "id": "90c14b65-36f0-4bb2-a3bf-f8e725cc897e", - "metadata": {}, + "metadata": { + "tags": [] + }, "source": [ - "## Installation" + "## Installation\n", + "\n", + "Uncomment and run the code cell below, if you do not already have `pyEQL`" ] }, { - "cell_type": "markdown", - "id": "e6f7ffd5-4178-4968-95bb-80c4fd1ec5ff", + "cell_type": "code", + "execution_count": 2, + "id": "abb1f51c-38fc-4543-8b59-057b8c591ba9", "metadata": {}, + "outputs": [], "source": [ - "`>>> pip install pyEQL`" + "# pip install pyEQL" ] }, { @@ -833,7 +837,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.10.12" + "version": "3.10.6" } }, "nbformat": 4, diff --git a/docs/examples/pyeql_tutorial_database.ipynb b/docs/examples/pyeql_tutorial_database.ipynb new file mode 100644 index 00000000..3be8afbe --- /dev/null +++ b/docs/examples/pyeql_tutorial_database.ipynb @@ -0,0 +1,1278 @@ +{ + "cells": [ + { + "attachments": { + "b51ca3f4-e8bd-4b0a-a599-5f6724ad8fe5.png": { + "image/png": "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" + } + }, + "cell_type": "markdown", + "id": "305d1216-9791-43dd-8d7f-ec90aa72a307", + "metadata": { + "tags": [] + }, + "source": [ + "# `pyEQL` Tutorial: Searching the Property Database\n", + "\n", + "![pyeql-logo.png](attachment:b51ca3f4-e8bd-4b0a-a599-5f6724ad8fe5.png)\n", + "\n", + "`pyEQL` is an open-source `python` library for solution chemistry calculations and ion properties developed by the [Kingsbury Lab](https://www.kingsburylab.org/) at Princeton University.\n", + "\n", + "[Documentation](https://pyeql.readthedocs.io/en/latest/) | [How to Install](https://pyeql.readthedocs.io/en/latest/installation.html) | [GitHub](https://github.com/rkingsbury/pyEQL) " + ] + }, + { + "cell_type": "markdown", + "id": "90c14b65-36f0-4bb2-a3bf-f8e725cc897e", + "metadata": { + "tags": [] + }, + "source": [ + "## Installation\n", + "\n", + "Uncomment and run the code cell below, if you do not already have `pyEQL`" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "abb1f51c-38fc-4543-8b59-057b8c591ba9", + "metadata": {}, + "outputs": [], + "source": [ + "# pip install pyEQL" + ] + }, + { + "cell_type": "markdown", + "id": "1b8efc81-17bb-46dc-8a22-63e71ae458b7", + "metadata": {}, + "source": [ + "## First, import the property database\n", + "\n", + "`pyEQL`'s built-in property database contains physichochemical, transport, and model parameters for hundreds of solutes. This information is used behind the scenes when you interact with a `Solution` object, but it can also be accessed directly." + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "55f1aea5-a5b8-49b8-a8e8-20856c4be6e7", + "metadata": { + "scrolled": true + }, + "outputs": [], + "source": [ + "from pyEQL import IonDB" + ] + }, + { + "cell_type": "markdown", + "id": "23b21981-7568-4e29-a93c-4017a32629b4", + "metadata": {}, + "source": [ + "## How to Search the Database" + ] + }, + { + "cell_type": "markdown", + "id": "084e5aa5-041b-4135-a083-76a4d8e555d7", + "metadata": {}, + "source": [ + "### Query an example document\n", + "\n", + "You can think of the database like `list` of `dict` that contain structure data. More specifically, the database is a list of [`Solute` objects](https://pyeql.readthedocs.io/en/latest/database.html#the-solute-class) that have been serialized to dictionaries. We refer to each of these `dict` as **\"documents\"** (consistent with MongoDB terminology) or \"records\"\n", + "\n", + "To see what one document looks like, use `query_one()`, which retrieves a single record from the database. The record is a `dict`." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "91459416-322a-49c5-a9ee-bf74c160a7e2", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'_id': ObjectId('654e5f131ed012c187817e6a'),\n", + " 'formula': 'Ac[+3]',\n", + " 'charge': 3,\n", + " 'molecular_weight': '227.0 g/mol',\n", + " 'elements': ['Ac'],\n", + " 'chemsys': 'Ac',\n", + " 'pmg_ion': {'Ac': 1,\n", + " 'charge': 3,\n", + " '@module': 'pymatgen.core.ion',\n", + " '@class': 'Ion',\n", + " '@version': None},\n", + " 'formula_html': 'Ac+3',\n", + " 'formula_latex': 'Ac$^{+3}$',\n", + " 'formula_hill': 'Ac',\n", + " 'formula_pretty': 'Ac^+3',\n", + " 'oxi_state_guesses': {'Ac': 3},\n", + " 'n_atoms': 1,\n", + " 'n_elements': 1,\n", + " 'size': {'radius_ionic': {'value': '1.26 Å',\n", + " 'reference': 'pymatgen',\n", + " 'data_type': 'experimental'},\n", + " 'radius_hydrated': None,\n", + " 'radius_vdw': {'value': '2.47 Å',\n", + " 'reference': 'pymatgen',\n", + " 'data_type': 'experimental'},\n", + " 'molar_volume': None,\n", + " 'radius_ionic_marcus': {'value': '1.18 ± 0.02 Å',\n", + " 'reference': 'Marcus2015',\n", + " 'data_type': 'experimental'}},\n", + " 'thermo': {'ΔG_hydration': {'value': '-3086.0 ± 10 kJ/mol',\n", + " 'reference': '10.1021/acs.jpca.9b05140',\n", + " 'data_type': 'experimental'},\n", + " 'ΔG_formation': None},\n", + " 'transport': {'diffusion_coefficient': None},\n", + " 'model_parameters': {'activity_pitzer': {'Beta0': None,\n", + " 'Beta1': None,\n", + " 'Beta2': None,\n", + " 'Cphi': None,\n", + " 'Max_C': None},\n", + " 'molar_volume_pitzer': {'Beta0': None,\n", + " 'Beta1': None,\n", + " 'Beta2': None,\n", + " 'Cphi': None,\n", + " 'V_o': None,\n", + " 'Max_C': None},\n", + " 'viscosity_jones_dole': {'B': None}}}" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "IonDB.query_one()" + ] + }, + { + "cell_type": "markdown", + "id": "db042f2d-2926-40bb-b84c-9fc5174618d0", + "metadata": {}, + "source": [ + "### Query a specific document\n", + "\n", + "The `IonDB` is a [`maggma.Store`](https://materialsproject.github.io/maggma/getting_started/stores/) that can be queried using a MongoDB-like syntax. The basic syntax is\n", + "\n", + "```\n", + "IonDB.query_one({field: value})\n", + "```\n", + "\n", + "where `field` is a top-level key in the `Solute` `dict`, such as `formula`, `charge`, or `elements`. See [this page](https://riptutorial.com/mongodb/example/26813/pymongo-queries) and the `maggma` documentation (link WIP) for more detailed examples." + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "5e0b4774-5274-4df1-8a91-7a9d43f675bd", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'_id': ObjectId('654e5f131ed012c187817f46'),\n", + " 'formula': 'Na[+1]',\n", + " 'charge': 1,\n", + " 'molecular_weight': '22.98976928 g/mol',\n", + " 'elements': ['Na'],\n", + " 'chemsys': 'Na',\n", + " 'pmg_ion': {'Na': 1,\n", + " 'charge': 1,\n", + " '@module': 'pymatgen.core.ion',\n", + " '@class': 'Ion',\n", + " '@version': None},\n", + " 'formula_html': 'Na+1',\n", + " 'formula_latex': 'Na$^{+1}$',\n", + " 'formula_hill': 'Na',\n", + " 'formula_pretty': 'Na^+1',\n", + " 'oxi_state_guesses': {'Na': 1},\n", + " 'n_atoms': 1,\n", + " 'n_elements': 1,\n", + " 'size': {'radius_ionic': {'value': '1.16 Å',\n", + " 'reference': 'pymatgen',\n", + " 'data_type': 'experimental'},\n", + " 'radius_hydrated': {'value': '3.58 Å',\n", + " 'reference': 'Nightingale1959',\n", + " 'data_type': 'experimental'},\n", + " 'radius_vdw': {'value': '2.27 Å',\n", + " 'reference': 'pymatgen',\n", + " 'data_type': 'experimental'},\n", + " 'molar_volume': {'value': '-5.0 cm**3/mol',\n", + " 'reference': 'Calculation of the Partial Molal Volume of Organic Compounds and Polymers. Progress in Colloid & Polymer Science (94), 20-39.',\n", + " 'data_type': 'experimental'},\n", + " 'radius_ionic_marcus': {'value': '1.02 ± 0.02 Å',\n", + " 'reference': 'Marcus2015',\n", + " 'data_type': 'experimental'}},\n", + " 'thermo': {'ΔG_hydration': {'value': '-427.0 ± 6 kJ/mol',\n", + " 'reference': 'Marcus2015',\n", + " 'data_type': 'experimental'},\n", + " 'ΔG_formation': None},\n", + " 'transport': {'diffusion_coefficient': {'value': '1.334e-05 cm**2/s',\n", + " 'reference': 'CRC',\n", + " 'data_type': 'experimental'}},\n", + " 'model_parameters': {'activity_pitzer': {'Beta0': None,\n", + " 'Beta1': None,\n", + " 'Beta2': None,\n", + " 'Cphi': None,\n", + " 'Max_C': None},\n", + " 'molar_volume_pitzer': {'Beta0': None,\n", + " 'Beta1': None,\n", + " 'Beta2': None,\n", + " 'Cphi': None,\n", + " 'V_o': None,\n", + " 'Max_C': None},\n", + " 'viscosity_jones_dole': {'B': {'value': '0.085 dm**3/mol',\n", + " 'reference': 'https://doi.org/10.1021/cr00040a004',\n", + " 'data_type': 'fitted'}},\n", + " 'dielectric_zuber': {'value': '3.62 dimensionless',\n", + " 'reference': 'https://doi.org/10.1016/j.fluid.2014.05.037',\n", + " 'data_type': 'fitted'}}}" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# a document with the formula \"Na[+1]\"\n", + "IonDB.query_one({\"formula\":'Na[+1]'})" + ] + }, + { + "cell_type": "markdown", + "id": "381b0bae-436b-44b2-b651-bf8766ee053f", + "metadata": {}, + "source": [ + "### Only return a subset of the document\n", + "\n", + "If you don't need to see the entire document, you can restrict the data returned by the query (in MongoDB, this is called \"projection\"). To use this feature, pass a second argument that is a `list` containing _only the fields that you want returned_. Note that there is a unique identified (field name `_id`) that is always returned." + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "1063fa68-50e3-441c-89f9-32a52314d6a7", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'formula': 'Na[+1]',\n", + " 'charge': 1,\n", + " 'molecular_weight': '22.98976928 g/mol',\n", + " '_id': ObjectId('654e5f131ed012c187817f46')}" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# a document with the formula \"Na[+1]\", where we only want the formula, charge, and molecular_weight\n", + "IonDB.query_one({\"formula\":'Na[+1]'}, [\"formula\",\"charge\",\"molecular_weight\"])" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "2829357c-45f7-487f-b89c-978bf28bf126", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'formula': 'Ag(CN)2[-1]',\n", + " 'charge': -1,\n", + " 'molecular_weight': '159.903 g/mol',\n", + " '_id': ObjectId('654e5f131ed012c187817e6b')}" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# a document with the charge -1, where we only want the formula, charge, and molecular_weight\n", + "IonDB.query_one({\"charge\":-1}, [\"formula\",\"charge\",\"molecular_weight\"])" + ] + }, + { + "cell_type": "markdown", + "id": "d7ffc305-5e92-41fe-96fc-8507ee9be76a", + "metadata": {}, + "source": [ + "**NOTE**: Be mindful of data types when querying. `charge` is an `int`. If we tried to query `charge` as if it were a `str`, we would get no results:" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "0e697fdb-5667-4280-9f09-f45c9a5c0ec2", + "metadata": {}, + "outputs": [], + "source": [ + "# a document with the charge -1, where we only want the formula, charge, and molecular_weight\n", + "IonDB.query_one({\"charge\":\"-1\"}, [\"formula\",\"charge\",\"molecular_weight\"])" + ] + }, + { + "cell_type": "markdown", + "id": "ce6abcd9-5739-44a6-8993-a6ca1d6f0c47", + "metadata": {}, + "source": [ + "### Query nested fields\n", + "\n", + "If you want to query a field that is not a top-level key (such as transport / diffusion_coefficient), you can place a `.` between the field names at each level, e.g." + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "068c1ad7-bb98-4c38-af9f-0fa73b9b4551", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'formula': 'Na2CO3(aq)',\n", + " 'size': {'radius_vdw': {'value': '2.27 Å'}},\n", + " '_id': ObjectId('654e5f131ed012c187817f31')}" + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "IonDB.query_one({\"size.radius_vdw.value\": \"2.27 Å\"}, [\"formula\", \"size.radius_vdw.value\"])" + ] + }, + { + "cell_type": "markdown", + "id": "ef08b109-26f3-40ba-9bc6-6345c1a60e4d", + "metadata": { + "tags": [] + }, + "source": [ + "**Note** that in the `Solute` documents, **most quantitative data are stored as `str` so that there is no ambiguity about their units**. In the example above, the value of the van der Waals radius is `\"2.27 Å\"` (a `str`, including a unit), NOT `2.27` (a `float`).\n", + "\n", + "You can easily extract the value by turning the `str` into a `Quantity` (see [Converting Units](https://pyeql.readthedocs.io/en/latest/units.html)), or by using `python` string operations to split the value and the units, e.g." + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "id": "d3be0fcb-7704-457f-8726-ec140ab5cf01", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2.27\n" + ] + } + ], + "source": [ + "# string operations\n", + "print(float(\"2.27 Å\".split(\" \")[0]))" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "id": "fd89fe2b-0697-4f17-98d4-50634660c112", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2.27\n" + ] + } + ], + "source": [ + "# pint Quantity\n", + "from pyEQL import ureg\n", + "print(ureg.Quantity(\"2.27 Å\").magnitude)" + ] + }, + { + "cell_type": "markdown", + "id": "261da6c7-1033-432c-b2d2-334661cec4f1", + "metadata": {}, + "source": [ + "### Query multiple documents\n", + "\n", + "`query_one` only returns a single document (a single `dict`). You can instead use `query` with exactly the same syntax to return a [generator](https://realpython.com/introduction-to-python-generators/) of all documents that match your query." + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "id": "d7c3936a-ed30-4865-acb6-81e2a6d415c8", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 11, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# all documents with a charge of +2, returning only the formulas\n", + "IonDB.query({\"charge\":2}, [\"formula\",\"molecular_weight\"])" + ] + }, + { + "cell_type": "markdown", + "id": "86ff455f-5e3c-40fa-83a2-eadb74595a56", + "metadata": {}, + "source": [ + "A generator is not very useful unless we turn it into a `list`. You can do this with `list()` or with a [list comprehension](https://www.w3schools.com/python/python_lists_comprehension.asp)" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "id": "82e73a80-9987-4866-bf24-55628a7eb2cc", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[{'formula': 'Ag[+2]',\n", + " 'molecular_weight': '107.8682 g/mol',\n", + " '_id': ObjectId('654e5f131ed012c187817e6e')},\n", + " {'formula': 'Au[+2]',\n", + " 'molecular_weight': '196.966569 g/mol',\n", + " '_id': ObjectId('654e5f131ed012c187817e76')},\n", + " {'formula': 'Ba[+2]',\n", + " 'molecular_weight': '137.327 g/mol',\n", + " '_id': ObjectId('654e5f131ed012c187817e83')},\n", + " {'formula': 'Be[+2]',\n", + " 'molecular_weight': '9.012182 g/mol',\n", + " '_id': ObjectId('654e5f131ed012c187817e85')},\n", + " {'formula': 'Ca[+2]',\n", + " 'molecular_weight': '40.078 g/mol',\n", + " '_id': ObjectId('654e5f131ed012c187817e96')},\n", + " {'formula': 'Cd[+2]',\n", + " 'molecular_weight': '112.411 g/mol',\n", + " '_id': ObjectId('654e5f131ed012c187817e9b')},\n", + " {'formula': 'Co[+2]',\n", + " 'molecular_weight': '58.933195 g/mol',\n", + " '_id': ObjectId('654e5f131ed012c187817ea9')},\n", + " {'formula': 'Cr[+2]',\n", + " 'molecular_weight': '51.9961 g/mol',\n", + " '_id': ObjectId('654e5f131ed012c187817eae')},\n", + " {'formula': 'Cu[+2]',\n", + " 'molecular_weight': '63.546 g/mol',\n", + " '_id': ObjectId('654e5f131ed012c187817ebe')},\n", + " {'formula': 'Dy[+2]',\n", + " 'molecular_weight': '162.5 g/mol',\n", + " '_id': ObjectId('654e5f131ed012c187817ec0')},\n", + " {'formula': 'Eu[+2]',\n", + " 'molecular_weight': '151.964 g/mol',\n", + " '_id': ObjectId('654e5f131ed012c187817ec5')},\n", + " {'formula': 'Fe[+2]',\n", + " 'molecular_weight': '55.845 g/mol',\n", + " '_id': ObjectId('654e5f131ed012c187817ecc')},\n", + " {'formula': 'Ge[+2]',\n", + " 'molecular_weight': '72.64 g/mol',\n", + " '_id': ObjectId('654e5f131ed012c187817ed1')},\n", + " {'formula': 'Hg[+2]',\n", + " 'molecular_weight': '200.59 g/mol',\n", + " '_id': ObjectId('654e5f131ed012c187817ef1')},\n", + " {'formula': 'In[+2]',\n", + " 'molecular_weight': '114.818 g/mol',\n", + " '_id': ObjectId('654e5f131ed012c187817ef7')},\n", + " {'formula': 'Mg[+2]',\n", + " 'molecular_weight': '24.305 g/mol',\n", + " '_id': ObjectId('654e5f131ed012c187817f26')},\n", + " {'formula': 'Mn[+2]',\n", + " 'molecular_weight': '54.938045 g/mol',\n", + " '_id': ObjectId('654e5f131ed012c187817f2a')},\n", + " {'formula': 'Nd[+2]',\n", + " 'molecular_weight': '144.242 g/mol',\n", + " '_id': ObjectId('654e5f131ed012c187817f4a')},\n", + " {'formula': 'Ni[+2]',\n", + " 'molecular_weight': '58.6934 g/mol',\n", + " '_id': ObjectId('654e5f141ed012c187817f4f')},\n", + " {'formula': 'Pb[+2]',\n", + " 'molecular_weight': '207.2 g/mol',\n", + " '_id': ObjectId('654e5f141ed012c187817f62')},\n", + " {'formula': 'Pd[+2]',\n", + " 'molecular_weight': '106.42 g/mol',\n", + " '_id': ObjectId('654e5f141ed012c187817f63')},\n", + " {'formula': 'Po[+2]',\n", + " 'molecular_weight': '210.0 g/mol',\n", + " '_id': ObjectId('654e5f141ed012c187817f65')},\n", + " {'formula': 'Pr[+2]',\n", + " 'molecular_weight': '140.90765 g/mol',\n", + " '_id': ObjectId('654e5f141ed012c187817f67')},\n", + " {'formula': 'Pt[+2]',\n", + " 'molecular_weight': '195.084 g/mol',\n", + " '_id': ObjectId('654e5f141ed012c187817f69')},\n", + " {'formula': 'Ra[+2]',\n", + " 'molecular_weight': '226.0 g/mol',\n", + " '_id': ObjectId('654e5f141ed012c187817f6b')},\n", + " {'formula': 'Ru[+2]',\n", + " 'molecular_weight': '101.07 g/mol',\n", + " '_id': ObjectId('654e5f141ed012c187817f7b')},\n", + " {'formula': 'Sc[+2]',\n", + " 'molecular_weight': '44.955912 g/mol',\n", + " '_id': ObjectId('654e5f141ed012c187817f87')},\n", + " {'formula': 'Sm[+2]',\n", + " 'molecular_weight': '150.36 g/mol',\n", + " '_id': ObjectId('654e5f141ed012c187817f8e')},\n", + " {'formula': 'Sn[+2]',\n", + " 'molecular_weight': '118.71 g/mol',\n", + " '_id': ObjectId('654e5f141ed012c187817f90')},\n", + " {'formula': 'Sr[+2]',\n", + " 'molecular_weight': '87.62 g/mol',\n", + " '_id': ObjectId('654e5f141ed012c187817f97')},\n", + " {'formula': 'Tc[+2]',\n", + " 'molecular_weight': '98.0 g/mol',\n", + " '_id': ObjectId('654e5f141ed012c187817f9b')},\n", + " {'formula': 'Ti[+2]',\n", + " 'molecular_weight': '47.867 g/mol',\n", + " '_id': ObjectId('654e5f141ed012c187817f9f')},\n", + " {'formula': 'Tm[+2]',\n", + " 'molecular_weight': '168.93421 g/mol',\n", + " '_id': ObjectId('654e5f141ed012c187817fa7')},\n", + " {'formula': 'UO2[+2]',\n", + " 'molecular_weight': '270.02771 g/mol',\n", + " '_id': ObjectId('654e5f141ed012c187817fad')},\n", + " {'formula': 'V[+2]',\n", + " 'molecular_weight': '50.9415 g/mol',\n", + " '_id': ObjectId('654e5f141ed012c187817fb2')},\n", + " {'formula': 'Yb[+2]',\n", + " 'molecular_weight': '173.04 g/mol',\n", + " '_id': ObjectId('654e5f141ed012c187817fba')},\n", + " {'formula': 'Zn[+2]',\n", + " 'molecular_weight': '65.409 g/mol',\n", + " '_id': ObjectId('654e5f141ed012c187817fc2')}]" + ] + }, + "execution_count": 12, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# using list()\n", + "list(IonDB.query({\"charge\":2}, [\"formula\",\"molecular_weight\"]))" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "id": "c6dd37ed-9d07-47b3-be85-aecaade0b880", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[{'formula': 'Ag[+2]',\n", + " 'molecular_weight': '107.8682 g/mol',\n", + " '_id': ObjectId('654e5f131ed012c187817e6e')},\n", + " {'formula': 'Au[+2]',\n", + " 'molecular_weight': '196.966569 g/mol',\n", + " '_id': ObjectId('654e5f131ed012c187817e76')},\n", + " {'formula': 'Ba[+2]',\n", + " 'molecular_weight': '137.327 g/mol',\n", + " '_id': ObjectId('654e5f131ed012c187817e83')},\n", + " {'formula': 'Be[+2]',\n", + " 'molecular_weight': '9.012182 g/mol',\n", + " '_id': ObjectId('654e5f131ed012c187817e85')},\n", + " {'formula': 'Ca[+2]',\n", + " 'molecular_weight': '40.078 g/mol',\n", + " '_id': ObjectId('654e5f131ed012c187817e96')},\n", + " {'formula': 'Cd[+2]',\n", + " 'molecular_weight': '112.411 g/mol',\n", + " '_id': ObjectId('654e5f131ed012c187817e9b')},\n", + " {'formula': 'Co[+2]',\n", + " 'molecular_weight': '58.933195 g/mol',\n", + " '_id': ObjectId('654e5f131ed012c187817ea9')},\n", + " {'formula': 'Cr[+2]',\n", + " 'molecular_weight': '51.9961 g/mol',\n", + " '_id': ObjectId('654e5f131ed012c187817eae')},\n", + " {'formula': 'Cu[+2]',\n", + " 'molecular_weight': '63.546 g/mol',\n", + " '_id': ObjectId('654e5f131ed012c187817ebe')},\n", + " {'formula': 'Dy[+2]',\n", + " 'molecular_weight': '162.5 g/mol',\n", + " '_id': ObjectId('654e5f131ed012c187817ec0')},\n", + " {'formula': 'Eu[+2]',\n", + " 'molecular_weight': '151.964 g/mol',\n", + " '_id': ObjectId('654e5f131ed012c187817ec5')},\n", + " {'formula': 'Fe[+2]',\n", + " 'molecular_weight': '55.845 g/mol',\n", + " '_id': ObjectId('654e5f131ed012c187817ecc')},\n", + " {'formula': 'Ge[+2]',\n", + " 'molecular_weight': '72.64 g/mol',\n", + " '_id': ObjectId('654e5f131ed012c187817ed1')},\n", + " {'formula': 'Hg[+2]',\n", + " 'molecular_weight': '200.59 g/mol',\n", + " '_id': ObjectId('654e5f131ed012c187817ef1')},\n", + " {'formula': 'In[+2]',\n", + " 'molecular_weight': '114.818 g/mol',\n", + " '_id': ObjectId('654e5f131ed012c187817ef7')},\n", + " {'formula': 'Mg[+2]',\n", + " 'molecular_weight': '24.305 g/mol',\n", + " '_id': ObjectId('654e5f131ed012c187817f26')},\n", + " {'formula': 'Mn[+2]',\n", + " 'molecular_weight': '54.938045 g/mol',\n", + " '_id': ObjectId('654e5f131ed012c187817f2a')},\n", + " {'formula': 'Nd[+2]',\n", + " 'molecular_weight': '144.242 g/mol',\n", + " '_id': ObjectId('654e5f131ed012c187817f4a')},\n", + " {'formula': 'Ni[+2]',\n", + " 'molecular_weight': '58.6934 g/mol',\n", + " '_id': ObjectId('654e5f141ed012c187817f4f')},\n", + " {'formula': 'Pb[+2]',\n", + " 'molecular_weight': '207.2 g/mol',\n", + " '_id': ObjectId('654e5f141ed012c187817f62')},\n", + " {'formula': 'Pd[+2]',\n", + " 'molecular_weight': '106.42 g/mol',\n", + " '_id': ObjectId('654e5f141ed012c187817f63')},\n", + " {'formula': 'Po[+2]',\n", + " 'molecular_weight': '210.0 g/mol',\n", + " '_id': ObjectId('654e5f141ed012c187817f65')},\n", + " {'formula': 'Pr[+2]',\n", + " 'molecular_weight': '140.90765 g/mol',\n", + " '_id': ObjectId('654e5f141ed012c187817f67')},\n", + " {'formula': 'Pt[+2]',\n", + " 'molecular_weight': '195.084 g/mol',\n", + " '_id': ObjectId('654e5f141ed012c187817f69')},\n", + " {'formula': 'Ra[+2]',\n", + " 'molecular_weight': '226.0 g/mol',\n", + " '_id': ObjectId('654e5f141ed012c187817f6b')},\n", + " {'formula': 'Ru[+2]',\n", + " 'molecular_weight': '101.07 g/mol',\n", + " '_id': ObjectId('654e5f141ed012c187817f7b')},\n", + " {'formula': 'Sc[+2]',\n", + " 'molecular_weight': '44.955912 g/mol',\n", + " '_id': ObjectId('654e5f141ed012c187817f87')},\n", + " {'formula': 'Sm[+2]',\n", + " 'molecular_weight': '150.36 g/mol',\n", + " '_id': ObjectId('654e5f141ed012c187817f8e')},\n", + " {'formula': 'Sn[+2]',\n", + " 'molecular_weight': '118.71 g/mol',\n", + " '_id': ObjectId('654e5f141ed012c187817f90')},\n", + " {'formula': 'Sr[+2]',\n", + " 'molecular_weight': '87.62 g/mol',\n", + " '_id': ObjectId('654e5f141ed012c187817f97')},\n", + " {'formula': 'Tc[+2]',\n", + " 'molecular_weight': '98.0 g/mol',\n", + " '_id': ObjectId('654e5f141ed012c187817f9b')},\n", + " {'formula': 'Ti[+2]',\n", + " 'molecular_weight': '47.867 g/mol',\n", + " '_id': ObjectId('654e5f141ed012c187817f9f')},\n", + " {'formula': 'Tm[+2]',\n", + " 'molecular_weight': '168.93421 g/mol',\n", + " '_id': ObjectId('654e5f141ed012c187817fa7')},\n", + " {'formula': 'UO2[+2]',\n", + " 'molecular_weight': '270.02771 g/mol',\n", + " '_id': ObjectId('654e5f141ed012c187817fad')},\n", + " {'formula': 'V[+2]',\n", + " 'molecular_weight': '50.9415 g/mol',\n", + " '_id': ObjectId('654e5f141ed012c187817fb2')},\n", + " {'formula': 'Yb[+2]',\n", + " 'molecular_weight': '173.04 g/mol',\n", + " '_id': ObjectId('654e5f141ed012c187817fba')},\n", + " {'formula': 'Zn[+2]',\n", + " 'molecular_weight': '65.409 g/mol',\n", + " '_id': ObjectId('654e5f141ed012c187817fc2')}]" + ] + }, + "execution_count": 13, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# using a comprehension\n", + "[doc for doc in IonDB.query({\"charge\":2}, [\"formula\",\"molecular_weight\"])]" + ] + }, + { + "cell_type": "markdown", + "id": "94600f07-a63e-4004-8107-a1a91103d494", + "metadata": {}, + "source": [ + "## Counting Documents\n", + "\n", + "You can use `count()` to see how many documents the database contains" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "id": "bf68990f-bade-425f-8fa5-d6f67c9a15ea", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "346" + ] + }, + "execution_count": 14, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "IonDB.count()" + ] + }, + { + "cell_type": "markdown", + "id": "7272f19b-5871-44f0-a4b6-da817115ceab", + "metadata": {}, + "source": [ + "Count works with queries, too." + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "id": "43a45291-e0bb-4d9d-8b8b-b20f3e49773a", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "7" + ] + }, + "execution_count": 15, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# number of documents with a charge of -3\n", + "IonDB.count({\"charge\": -3})" + ] + }, + { + "cell_type": "markdown", + "id": "b1dd7b65-f54d-4998-aad1-ad73d6c7fe7d", + "metadata": {}, + "source": [ + "## More Advanced Query Syntax" + ] + }, + { + "cell_type": "markdown", + "id": "22a1209c-35ed-4096-8e53-d016b4187a41", + "metadata": {}, + "source": [ + "### Match multiple items with `$in`\n", + "\n", + "If you want to query documents that match _any one of a set of values_, use `$in` with a `list` of possible values. Note that the `$in` operator and your `list` constitute their own dictionary, e.g. `{\"$in\":}`. This entire dictionary is the \"value\" of your query for the associated field. For example:" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "id": "8bed2683-ca20-4b8e-9bde-c4c86fb0e511", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "5" + ] + }, + "execution_count": 16, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# all alkali cations\n", + "IonDB.count({\"formula\":\n", + " {\"$in\": [\"Li[+1]\", \"Na[+1]\", \"K[+1]\", \"Rb[+1]\", \"Cs[+1]\"]}\n", + " }\n", + " )" + ] + }, + { + "cell_type": "markdown", + "id": "ff2b2305-1d45-45cd-aa53-31eccffb8afa", + "metadata": {}, + "source": [ + "### Greater than or less than - `$gt` / `$gte` / `$lt` / `$lte`\n", + "\n", + "In a similar manner, you can query fields whose values are greater than / less than or equal to some value" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "id": "7f7e52c5-6963-4848-99cb-32018adfb12c", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "76" + ] + }, + "execution_count": 17, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# all solutes with a charge less than 0\n", + "IonDB.count({\"charge\":\n", + " {\"$lt\": 0}\n", + " }\n", + " )" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "id": "747d56b6-859f-4a15-9fa5-ef63229a7436", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "108" + ] + }, + "execution_count": 18, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# all solutes with a charge greater than or equal to 1\n", + "IonDB.count({\"charge\":\n", + " {\"$gte\": 1}\n", + " }\n", + " )" + ] + }, + { + "cell_type": "markdown", + "id": "4ad07153-ead4-4a95-a83a-7055089cbd84", + "metadata": {}, + "source": [ + "## Unique Values\n", + "\n", + "It's often useful to understand how many unique values of a field there are. To do so, use `distinct()` with any field name" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "id": "7587a871-ed15-4ab4-b2a7-77018e67a1c1", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "['U(ClO5)2(aq)',\n", + " 'LiClO4(aq)',\n", + " 'Sb(OH)6[-1]',\n", + " 'Ba[+2]',\n", + " 'RbNO3(aq)',\n", + " 'KBrO3(aq)',\n", + " 'H3O[+1]',\n", + " 'CsNO2(aq)',\n", + " 'Re[+1]',\n", + " 'KHC2O.1H2O(aq)',\n", + " 'Ni[+3]',\n", + " 'H8S(NO2)2(aq)',\n", + " 'Sm[+2]',\n", + " 'B(OH)4[-1]',\n", + " 'CoI2(aq)',\n", + " 'ZnBr2(aq)',\n", + " 'Sn[+2]',\n", + " 'USO6(aq)',\n", + " 'Ir[+3]',\n", + " 'Ag(CN)2[-1]',\n", + " 'KNO3(aq)',\n", + " 'Ga[+3]',\n", + " 'Zn(NO3)2(aq)',\n", + " 'NaHC3.2H2O(aq)',\n", + " 'Ni(NO3)2(aq)',\n", + " 'S[-2]',\n", + " 'HS[-1]',\n", + " 'Eu[+2]',\n", + " 'ZnSO4(aq)',\n", + " 'BeSO4(aq)',\n", + " 'MnO4[-1]',\n", + " 'K2CO3(aq)',\n", + " 'Pa[+3]',\n", + " 'SrI2(aq)',\n", + " 'FeCl2(aq)',\n", + " 'Eu(NO3)3(aq)',\n", + " 'NaClO4(aq)',\n", + " 'Zn[+2]',\n", + " 'SeO4[-1]',\n", + " 'NaCrO4(aq)',\n", + " 'CsOH(aq)',\n", + " 'Na3PO4(aq)',\n", + " 'KCSN(aq)',\n", + " 'HSO4[-1]',\n", + " 'Mn[+3]',\n", + " 'H4NClO4(aq)',\n", + " 'NiSO4(aq)',\n", + " 'IO4[-1]',\n", + " 'Sr(ClO4)2(aq)',\n", + " 'SeO4[-2]',\n", + " 'Ag[+1]',\n", + " 'LiI(aq)',\n", + " 'SiF6[-2]',\n", + " 'HF2[-1]',\n", + " 'CoBr2(aq)',\n", + " 'Pr[+3]',\n", + " 'BaBr2(aq)',\n", + " 'ClO2[-1]',\n", + " 'MgBr2(aq)',\n", + " 'Ho[+3]',\n", + " 'Be[+2]',\n", + " 'H2O(aq)',\n", + " 'Po[+2]',\n", + " 'P2O7[-4]',\n", + " 'RbCl(aq)',\n", + " 'K[+1]',\n", + " 'ClO4[-1]',\n", + " 'Mg(ClO4)2(aq)',\n", + " 'NdCl3(aq)',\n", + " 'Au[+1]',\n", + " 'Rb2SO4(aq)',\n", + " 'Na2PHO4(aq)',\n", + " 'Th[+4]',\n", + " 'Fe[+3]',\n", + " 'Ra[+2]',\n", + " 'Tl(NO3)3(aq)',\n", + " 'Rb[+1]',\n", + " 'KF(aq)',\n", + " 'Gd[+3]',\n", + " 'NiCl2(aq)',\n", + " 'Rh[+3]',\n", + " 'Ag[+3]',\n", + " 'Cd(ClO4)2(aq)',\n", + " 'FeCl3(aq)',\n", + " 'NO3[-1]',\n", + " 'MoO4[-2]',\n", + " 'Tl[+3]',\n", + " 'CuSO4(aq)',\n", + " 'Tm[+3]',\n", + " 'OH[-1]',\n", + " 'Zn(ClO4)2(aq)',\n", + " 'Th(NO3)4(aq)',\n", + " 'HNO3(aq)',\n", + " 'AgNO3(aq)',\n", + " 'Cr(NO3)3(aq)',\n", + " 'Tl(NO2)3(aq)',\n", + " 'CaI2(aq)',\n", + " 'Pt[+2]',\n", + " 'U(NO4)2(aq)',\n", + " 'LiNO2(aq)',\n", + " 'Na2CO3(aq)',\n", + " 'Np[+4]',\n", + " 'LiNO3(aq)',\n", + " 'VO2[+1]',\n", + " 'KCrO4(aq)',\n", + " 'PO4[-3]',\n", + " 'Ca(NO3)2(aq)',\n", + " 'Li[+1]',\n", + " 'SrCl2(aq)',\n", + " 'KPO3.1H2O(aq)',\n", + " 'CH3COO[-1]',\n", + " 'PrCl3(aq)',\n", + " 'In[+3]',\n", + " 'ZnI2(aq)',\n", + " 'SmCl3(aq)',\n", + " 'KI(aq)',\n", + " 'K3Fe(CN)6(aq)',\n", + " 'CdSO4(aq)',\n", + " 'GdCl3(aq)',\n", + " 'Os[+3]',\n", + " 'LiHC2O.1H2O(aq)',\n", + " 'Sr(NO3)2(aq)',\n", + " 'H2SO4(aq)',\n", + " 'Hg[+2]',\n", + " 'NaNO2(aq)',\n", + " 'Cd[+2]',\n", + " 'H5N2[+1]',\n", + " 'Mg(NO3)2(aq)',\n", + " 'KClO3(aq)',\n", + " 'P(OH)2[-1]',\n", + " 'Sn[+4]',\n", + " 'Tm[+2]',\n", + " 'U(ClO)2(aq)',\n", + " 'HCO2[-1]',\n", + " 'BO2[-1]',\n", + " 'KBr(aq)',\n", + " 'K2SO4(aq)',\n", + " 'SeO3[-1]',\n", + " 'Ta[+3]',\n", + " 'YNO3(aq)',\n", + " 'Cu[+1]',\n", + " 'Er[+3]',\n", + " 'Al[+3]',\n", + " 'HSO3[-1]',\n", + " 'Tl[+1]',\n", + " 'BrO3[-1]',\n", + " 'Li2SO4(aq)',\n", + " 'Co[+2]',\n", + " 'ZnCl2(aq)',\n", + " 'HO2[-1]',\n", + " 'I[-1]',\n", + " 'Au[+3]',\n", + " 'CSN[-1]',\n", + " 'NaHCO2(aq)',\n", + " 'Ca[+2]',\n", + " 'P(HO2)2[-1]',\n", + " 'Ba(NO3)2(aq)',\n", + " 'Dy[+2]',\n", + " 'Cs2SO4(aq)',\n", + " 'F[-1]',\n", + " 'Pb[+2]',\n", + " 'EuCl3(aq)',\n", + " 'Ca(ClO4)2(aq)',\n", + " 'Al2(SO4)3(aq)',\n", + " 'PH9(NO2)2(aq)',\n", + " 'RbBr(aq)',\n", + " 'CuCl2(aq)',\n", + " 'Co(H3N)6[-3]',\n", + " 'Pb(NO3)2(aq)',\n", + " 'CSeN[-1]',\n", + " 'Ce[+3]',\n", + " 'RbOH(aq)',\n", + " 'P3O10[-5]',\n", + " 'NaOH(aq)',\n", + " 'Sm[+3]',\n", + " 'Yb[+3]',\n", + " 'C2N3[-1]',\n", + " 'BaC4O.3H2O(aq)',\n", + " 'Fe(CN)6[-3]',\n", + " 'RbNO2(aq)',\n", + " 'Re[+3]',\n", + " 'LaCl3(aq)',\n", + " 'CrO4[-2]',\n", + " 'H[+1]',\n", + " 'K3PO4(aq)',\n", + " 'Ce[+4]',\n", + " 'Cu[+2]',\n", + " 'H2CO3(aq)',\n", + " 'BaCl2(aq)',\n", + " 'NaBrO3(aq)',\n", + " 'Zr[+4]',\n", + " 'CsI(aq)',\n", + " 'CoCl2(aq)',\n", + " 'Ac[+3]',\n", + " 'Ti[+2]',\n", + " 'Nd(NO3)3(aq)',\n", + " 'NaBr(aq)',\n", + " 'La(NO3)3(aq)',\n", + " 'MgC4O.3H2O(aq)',\n", + " 'PO3[-1]',\n", + " 'CrCl3(aq)',\n", + " 'U[+3]',\n", + " 'HCl(aq)',\n", + " 'Tc[+2]',\n", + " 'Au(CN)4[-1]',\n", + " 'HOsO5[-1]',\n", + " 'WO4[-1]',\n", + " 'PHO4[-2]',\n", + " 'ClO3[-1]',\n", + " 'K4Fe(CN)6(aq)',\n", + " 'Br[-0.33333333]',\n", + " 'Sr[+2]',\n", + " 'Cr[+3]',\n", + " 'UO2[+2]',\n", + " 'Ni[+2]',\n", + " 'Tl(ClO4)3(aq)',\n", + " 'Pu[+4]',\n", + " 'NaHC2O.1H2O(aq)',\n", + " 'MgI2(aq)',\n", + " 'TlH(C3O)2.4H2O(aq)',\n", + " 'Co(CN)6[-3]',\n", + " 'K2PHO4(aq)',\n", + " 'Mn[+2]',\n", + " 'NaNO3(aq)',\n", + " 'ScCl3(aq)',\n", + " 'CeCl3(aq)',\n", + " 'MnSO4(aq)',\n", + " 'Ru[+3]',\n", + " 'CsNO3(aq)',\n", + " 'HCO3[-1]',\n", + " 'H4NCl(aq)',\n", + " 'Ag[+2]',\n", + " 'Nb[+3]',\n", + " 'CNO[-1]',\n", + " 'H4IN(aq)',\n", + " 'In[+1]',\n", + " 'Ge[+2]',\n", + " 'HI(aq)',\n", + " 'ReO4[-1]',\n", + " 'MgCl2(aq)',\n", + " 'CsF(aq)',\n", + " 'N[-0.33333333]',\n", + " 'HClO4(aq)',\n", + " 'CsCl(aq)',\n", + " 'KHCO3(aq)',\n", + " 'La[+3]',\n", + " 'Ba(ClO4)2(aq)',\n", + " 'Bi[+3]',\n", + " 'CaBr2(aq)',\n", + " 'Yb[+2]',\n", + " 'CaCl2(aq)',\n", + " 'UO2[+1]',\n", + " 'Mo[+3]',\n", + " 'KClO4(aq)',\n", + " 'KOH(aq)',\n", + " 'LiBr(aq)',\n", + " 'SO3[-1]',\n", + " 'NaPO3.1H2O(aq)',\n", + " 'AsO4[-3]',\n", + " 'Br[-1]',\n", + " 'Dy[+3]',\n", + " 'IO3[-1]',\n", + " 'Sc[+3]',\n", + " 'H2SNO3[-1]',\n", + " 'Np[+3]',\n", + " 'Fe(CN)6[-4]',\n", + " 'RbHC2O.1H2O(aq)',\n", + " 'Nd[+2]',\n", + " 'Pr[+2]',\n", + " 'HBr(aq)',\n", + " 'MgSO4(aq)',\n", + " 'PO3F[-2]',\n", + " 'RbI(aq)',\n", + " 'Cu[+3]',\n", + " 'Pm[+3]',\n", + " 'H4BrN(aq)',\n", + " 'MnCl2(aq)',\n", + " 'CsHC2O.1H2O(aq)',\n", + " 'Y[+3]',\n", + " 'Hf[+4]',\n", + " 'Na[+1]',\n", + " 'H5C6O7[-3]',\n", + " 'Co(NO3)2(aq)',\n", + " 'NaCSN(aq)',\n", + " 'NaHCO3(aq)',\n", + " 'CsBr(aq)',\n", + " 'W[+3]',\n", + " 'NO2[-1]',\n", + " 'V[+2]',\n", + " 'SO4[-1]',\n", + " 'B(OH)3(aq)',\n", + " 'KCl(aq)',\n", + " 'Cl[-1]',\n", + " 'SrBr2(aq)',\n", + " 'PF6[-1]',\n", + " 'YCl3(aq)',\n", + " 'Pb(ClO4)2(aq)',\n", + " 'Co[+3]',\n", + " 'S2O3[-2]',\n", + " 'H4N2O3(aq)',\n", + " 'Cr[+2]',\n", + " 'NaF(aq)',\n", + " 'H4N[+1]',\n", + " 'Au(CN)2[-1]',\n", + " 'SO4[-2]',\n", + " 'Tc[+3]',\n", + " 'NaCl(aq)',\n", + " 'Eu[+3]',\n", + " 'Ru[+2]',\n", + " 'V[+3]',\n", + " 'Cu(NO3)2(aq)',\n", + " 'Fe[+2]',\n", + " 'Nd[+3]',\n", + " 'SO3[-2]',\n", + " 'BF4[-1]',\n", + " 'Sb(HO2)2[-1]',\n", + " 'B(H5C6)4[-1]',\n", + " 'Mg[+2]',\n", + " 'Cd(NO2)2(aq)',\n", + " 'SO2[-1]',\n", + " 'NaI(aq)',\n", + " 'Ti[+3]',\n", + " 'Cs[+1]',\n", + " 'HSeO3[-1]',\n", + " 'LiOH(aq)',\n", + " 'LiCl(aq)',\n", + " 'RbF(aq)',\n", + " 'WO4[-2]',\n", + " 'Pd[+2]',\n", + " 'Tb[+3]',\n", + " 'In[+2]',\n", + " 'Re[-1]',\n", + " 'Na2S2O3(aq)',\n", + " 'KNO2(aq)',\n", + " 'TcO4[-1]',\n", + " 'U[+4]',\n", + " 'BaI2(aq)',\n", + " 'CO3[-2]',\n", + " 'H4SNO4(aq)',\n", + " 'CN[-1]',\n", + " 'Sc[+2]',\n", + " 'Cd(NO3)2(aq)',\n", + " 'Na2SO4(aq)',\n", + " 'IrO4[-1]',\n", + " 'Lu[+3]',\n", + " 'Au[+2]']" + ] + }, + "execution_count": 19, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# list of all unique `formula`\n", + "IonDB.distinct('formula')" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python (conda: skagit2)", + "language": "python", + "name": "skagit2" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.6" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/docs/examples/pyeql_tutorial_osmotic_pressure.ipynb b/docs/examples/pyeql_tutorial_osmotic_pressure.ipynb new file mode 100644 index 00000000..d807ad04 --- /dev/null +++ b/docs/examples/pyeql_tutorial_osmotic_pressure.ipynb @@ -0,0 +1,451 @@ +{ + "cells": [ + { + "attachments": { + "b51ca3f4-e8bd-4b0a-a599-5f6724ad8fe5.png": { + "image/png": "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" + } + }, + "cell_type": "markdown", + "id": "305d1216-9791-43dd-8d7f-ec90aa72a307", + "metadata": { + "tags": [] + }, + "source": [ + "# `pyEQL` Tutorial: Calculating Osmotic Pressure\n", + "\n", + "![pyeql-logo.png](attachment:b51ca3f4-e8bd-4b0a-a599-5f6724ad8fe5.png)\n", + "\n", + "`pyEQL` is an open-source `python` library for solution chemistry calculations and ion properties developed by the [Kingsbury Lab](https://www.kingsburylab.org/) at Princeton University.\n", + "\n", + "[Documentation](https://pyeql.readthedocs.io/en/latest/) | [How to Install](https://pyeql.readthedocs.io/en/latest/installation.html) | [GitHub](https://github.com/rkingsbury/pyEQL) " + ] + }, + { + "cell_type": "markdown", + "id": "90c14b65-36f0-4bb2-a3bf-f8e725cc897e", + "metadata": { + "tags": [] + }, + "source": [ + "## Installation\n", + "\n", + "Uncomment and run the code cell below, if you do not already have `pyEQL`" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "abb1f51c-38fc-4543-8b59-057b8c591ba9", + "metadata": {}, + "outputs": [], + "source": [ + "# pip install pyEQL" + ] + }, + { + "cell_type": "markdown", + "id": "1b8efc81-17bb-46dc-8a22-63e71ae458b7", + "metadata": {}, + "source": [ + "## First, create a `Solution`\n", + "\n", + "`pyEQL`'s built-in property database contains Pitzer model parameters for many simple (binary) electrolytes. If such parameters are available, `pyEQL` will use them by default." + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "55f1aea5-a5b8-49b8-a8e8-20856c4be6e7", + "metadata": { + "scrolled": true + }, + "outputs": [], + "source": [ + "from pyEQL import Solution\n", + "# 2 mol/L NaCl\n", + "s1 = Solution({\"Na+\": \"2 mol/L\", \"Cl-\": \"2 mol/L\"})" + ] + }, + { + "cell_type": "markdown", + "id": "23b21981-7568-4e29-a93c-4017a32629b4", + "metadata": {}, + "source": [ + "## Get the osmotic pressure\n", + "\n", + "Note that the osmotic pressure (and most `Solution` properties) are returned as `pint` `Quantity` objects (see [Converting Units](https://pyeql.readthedocs.io/en/latest/units.html))." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "5c037d7c-0a16-4d0a-b2e7-ad2d43a4d3bb", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "10224795.514383134 Pa" + ], + "text/latex": [ + "$10224795.514383134\\ \\mathrm{Pa}$" + ], + "text/plain": [ + "10224795.514383134 " + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "s1.osmotic_pressure" + ] + }, + { + "cell_type": "markdown", + "id": "2b7800c8-e23a-4d6b-9d36-77ac51226fb4", + "metadata": {}, + "source": [ + "If you want the osmotic pressure in different units, or you only want the magnitude, use `to()` and `magnitude`, respectively" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "55f0b945-fe6f-464e-a855-30ec0e5292c5", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "102.24795514383135 bar" + ], + "text/latex": [ + "$102.24795514383135\\ \\mathrm{bar}$" + ], + "text/plain": [ + "102.24795514383135 " + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "s1.osmotic_pressure.to('bar')" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "51adb7d2-40f0-4072-adce-9ca2d980e5ef", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "102.24795514383135" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "s1.osmotic_pressure.to('bar').magnitude" + ] + }, + { + "cell_type": "markdown", + "id": "6b754001-1ee7-4348-882a-6e6f6e046b93", + "metadata": {}, + "source": [ + "## Use a `for` loop for multiple calculations\n", + "\n", + "You can rapidly get estimates for multiple concentrations (or temperatures, or solutes) by using a `for` loop. Notice how in the example below, we use [f-strings](https://realpython.com/python-f-strings/) to insert the desired concentration (from the `for` loop) into the argument passed to `Solution` and to print the results." + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "53ab967d-1cac-4e3a-9a4d-11f9b28f5bd2", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "At C=0.1 M, the osmotic pressure is 4.63 bar.\n", + "At C=0.5 M, the osmotic pressure is 23.07 bar.\n", + "At C=1.0 M, the osmotic pressure is 47.40 bar.\n", + "At C=2.0 M, the osmotic pressure is 102.25 bar.\n", + "At C=4.0 M, the osmotic pressure is 246.95 bar.\n" + ] + } + ], + "source": [ + "for conc in [0.1, 0.5, 1, 2, 4]:\n", + " s1 = Solution({\"Na+\": f\"{conc} mol/L\", \"Cl-\": f\"{conc} mol/L\"})\n", + " print(f\"At C={conc:.1f} M, the osmotic pressure is {s1.osmotic_pressure.to('bar'):.2f}.\")" + ] + }, + { + "cell_type": "markdown", + "id": "ba4ff669-b6c0-4592-b9be-1b088b548cfc", + "metadata": {}, + "source": [ + "## Compare different modeling engines\n", + "\n", + "`pyEQL` contains several different [modeling engines](https://pyeql.readthedocs.io/en/latest/engines.html) that can calculate activity coefficients or osmotic pressures. At present, there are three options:\n", + "\n", + "1. The `native` or built-in engine, which includes an implementation of the Piter model (Default).\n", + "2. the `phreeqc` engine, which utilizes the USGS PHREEQC model with the `phreeqc.dat` database.\n", + "3. An ideal solution model (`ideal`) which does not account for solution non-ideality.\n", + "\n", + "You select a modeling engine using the `engine` keyword argument when you create a `Solution`. Let's compare the preditions from the three models." + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "6962da9e-f510-483f-8ab6-df29a054441a", + "metadata": {}, + "outputs": [], + "source": [ + "s_ideal = Solution({\"Na+\": \"2 mol/L\", \"Cl-\": \"2 mol/L\"}, engine='ideal')\n", + "s_phreeqc = Solution({\"Na+\": \"2 mol/L\", \"Cl-\": \"2 mol/L\"}, engine='phreeqc')\n", + "s_native = Solution({\"Na+\": \"2 mol/L\", \"Cl-\": \"2 mol/L\"}, engine='native')" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "2a627a29-e7b4-458e-86bb-e23b71ae8f65", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "WARNING 2023-11-10 11:48:57,162 solution.py get_water_activity 1934 Pitzer parameters not found. Water activity set equal to mole fraction\n" + ] + }, + { + "data": { + "text/html": [ + "95.73878424096024 bar" + ], + "text/latex": [ + "$95.73878424096024\\ \\mathrm{bar}$" + ], + "text/plain": [ + "95.73878424096024 " + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "s_ideal.osmotic_pressure.to('bar')" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "id": "29ef5458-fc42-44de-a3b5-05e80987f9e8", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "95.73878424096024 bar" + ], + "text/latex": [ + "$95.73878424096024\\ \\mathrm{bar}$" + ], + "text/plain": [ + "95.73878424096024 " + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "s_phreeqc.osmotic_pressure.to('bar')" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "id": "5807fbde-dddd-4883-8bf0-1014ce08833b", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "102.24795514383135 bar" + ], + "text/latex": [ + "$102.24795514383135\\ \\mathrm{bar}$" + ], + "text/plain": [ + "102.24795514383135 " + ] + }, + "execution_count": 10, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "s_native.osmotic_pressure.to('bar')" + ] + }, + { + "cell_type": "markdown", + "id": "c49fb2e3-71a3-49ff-9f17-35e64f6f6d54", + "metadata": {}, + "source": [ + "## Plot the comparison vs. experiment\n", + "\n", + "We can make a plot showing how the 3 models compare by combining the two previous steps (using a `for` loop plus changing the `engine` keyword argument. Note that this example makes use of `matplotlib` for plotting." + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "id": "d38dd675-0767-4eea-ab11-d85c4613e59e", + "metadata": {}, + "outputs": [], + "source": [ + "# create empty lists to hold the results\n", + "pi_ideal = []\n", + "pi_phreeqc = []\n", + "pi_native = []\n", + "\n", + "concentrations = [0.1, 0.2, 0.3, 0.4, 0.5, 1, 1.4, 2, 2.5, 3, 3.5, 4]\n", + "\n", + "for conc in concentrations:\n", + " s_ideal = Solution({\"Na+\": f\"{conc} mol/kg\", \"Cl-\": f\"{conc} mol/kg\"}, engine='ideal')\n", + " s_phreeqc = Solution({\"Na+\": f\"{conc} mol/kg\", \"Cl-\": f\"{conc} mol/kg\"}, engine='phreeqc')\n", + " s_native = Solution({\"Na+\": f\"{conc} mol/kg\", \"Cl-\": f\"{conc} mol/kg\"}, engine='native')\n", + " \n", + " # store the osmotic pressures in the respective lists\n", + " # note that we have to just store the .magnitude because matplotlib can't plot Quantity\n", + " pi_ideal.append(s_ideal.osmotic_pressure.to('bar').magnitude)\n", + " pi_phreeqc.append(s_phreeqc.osmotic_pressure.to('bar').magnitude)\n", + " pi_native.append(s_native.osmotic_pressure.to('bar').magnitude)" + ] + }, + { + "cell_type": "markdown", + "id": "a651b33f-5572-40a2-8587-bd7af7a71170", + "metadata": {}, + "source": [ + "We will include experimental data from the [IDST](https://idst.inl.gov/) as a benchmark. The IDST gives us water activity, which we convert into osmotic pressure according to\n", + "\n", + "$$\n", + "\\Pi = -\\frac{RT}{V_{w}} \\ln a_{w}\n", + "$$\n", + "\n", + "Where $\\Pi$ is the osmotic pressure, $V_{w}$ is the partial molar volume of water (18.2 cm**3/mol), and $a_{w}$ is the water\n", + " activity." + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "id": "008d1e80-536b-4346-9527-462deacd6b70", + "metadata": {}, + "outputs": [], + "source": [ + "import math\n", + "# water activity at [0.1, 0.2, 0.3, 0.4, 0.5, 1, 1.5, 2, 2.5, 3, 3.5, 4] mol/kg\n", + "water_activity_idst = [0.99664, 0.993353, 0.99008, 0.986804, 0.98352, 0.966828, 0.953166, 0.93191, 0.913072, 0.89347, 0.872859, 0.85133]\n", + "\n", + "# calculate osmotic pressure as -RT/Vw ln(a_w). Factor 10 converts to bar.\n", + "pi_idst = [-8.314*298.15/18.2 * math.log(a) * 10 for a in water_activity_idst]" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "id": "1082bad0-c9e1-4e16-941d-fd908ea402fe", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "Text(0.5, 0.98, 'pyEQL prediction of NaCl osmotic pressure')" + ] + }, + "execution_count": 13, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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a7szZ86IZ555Rpibm4u2bduK5557Tv3EeiGECAsLE66urur39z6UTwgh/Pz81A/mGzp0aLUHT1Y5ePCgePzxx4Wpqamws7MTs2fPFjdu3Kgxto8++kgYGRlpfYBhRUWF+tiysjIxe/Zs0blzZyGXy4W3t7dITExUt616uOn+/fuFu7u7aNOmjfD09BQnTpzQ+Mzdu3eLgQMHCrlcLjp16iTGjh2r3ldWVibeeustYWtrK8zMzISHh4c4cOCAev/69euFpaWl2Lt3r3jkkUeEubm5UCgU4sKFC+qf470/lwMHDojc3FwBQGzZskUMGTJEyOVysX79enH58mUxceJEYWtrK9q0aSP69esnNm/erD7flClTqn1ebm6uOtfCwkJ12++++044OTkJmUwmunfvLpYuXaqRd/fu3cX7778v/P39hYWFhbC3txdr166tsV+EEGL79u2ic+fOGtuqclm4cKHo3bu3xr4+ffqIkJAQdZxVysvLhVwuF/v376/1fEQtCUd2iFoICwsLWFhYYNeuXSgvL9faRqVSwc/PD1evXkVcXByio6Nx6tQpPP/88w0+7/fffw87OzssXrwYeXl5yMvLAwCcPHkSo0aNwrPPPou0tDRs3boVhw4dwqxZs2r8rE2bNsHHxwf9+/evts/ExATm5uYAgPnz52PHjh3YuHEjkpOT0atXLygUCly9elXjmP/85z9YtmwZ/vjjDxgbG2PatGnqfVFRURg3bhyeeuoppKSkICYmBh4eHur9s2bNQkJCArZs2YK0tDQ899xzGDVqFHJyctRtSktLsXTpUnz99deIj4/H2bNn8fbbbwMA3n77bUyYMAGjRo1S/1y8vLzUxwYHB2POnDnIysqCQqFAWVkZ3N3dERUVhePHj2P69Ol46aWXkJiYCAD49NNP4enpiYCAAPXn2dvbV/s5JSUlYcKECZg4cSLS09OxaNEihISEYMOGDRrtli1bhoEDByIlJQWvv/46AgMDkZ2dXWPfHDx4EO7u7lr3PfPMMygsLMShQ4cAAIcOHUJhYSHGjBlTra1MJoObmxsOHjxY47mIWhxdV1tE9I/vvvtOdOjQQZiamgovLy+xYMECcezYMfX+X375RUilUnH27Fn1toyMDAFAPTJS35EdIW6PFCxfvlyjzSuvvCKmT5+use3gwYPCyMhI3Lx5U2v8bdq0EW+88UatOd64cUOYmJiITZs2qbdVVFQIW1tbsWTJEiGE5shOlaioKAFAfW5PT08xefJkrec4c+aMkEql4vz58xrbR44cKRYsWCCEuD2yA0D89ddf6v2RkZHC2tpa/X7KlCnCz89P4zOqRkNWrFhRa55CCDF69Gjx1ltvqd9r64t7R3ZeeOEF4evrq9Fm3rx5wsnJSf2+e/fu4sUXX1S/V6lUokuXLmL16tU1xuLn5yemTZumNZeUlBQRFBQk/P39hRBC+Pv7izfffFOkpKRUG9kRQohx48aJqVOn3jd/opaCIztELcizzz6LCxcuYPfu3Rg1ahRiY2MxYMAA9f/qs7KyYG9vrzEi4OTkhPbt2yMrK6tRYzl27Bg2bNigHnGysLCAQqGASqVCbm6u1mOEEPf93JMnT6KyshLe3t7qbSYmJvDw8KiWg4uLi/rvXbt2BQAUFBQAAFJTUzFy5Eit50hPT4dSqUSfPn004o+Li8PJkyfV7czMzNCzZ0+Nc1R9/v0MHDhQ471SqUR4eDicnZ3RsWNHWFhYYN++fTh79mydPq9KVlaWxs8GALy9vZGTkwOlUqnedvfPRiKRwMbGptbYb968CVNT0xr3T5s2Ddu3b0d+fj62b9+uMYp2rzZt2qC0tLQu6RC1CMa6DoCINJmamsLX1xe+vr4ICQnBq6++irCwMEydOrVBn2dkZFStCKnLhNobN25gxowZeOONN6rt69atm9Zj+vTpgxMnTjQoTm1MTEzUf6+awKtSqQDc/sKtyY0bNyCVSpGUlASpVKqxz8LCQuvnV52jLgUbAPWv5Kp8/PHH+PTTT7FixQo4OzvD3NwcQUFBqKioqNPn1Ze22Kt+NtpYWVmhsLCwxv3Ozs545JFHMGnSJPTt2xf9+vVDamqq1rZXr17VKBKJWjqO7BC1cE5OTur7mvTt2xfnzp3DuXPn1PszMzNx7do1ODk5aT2+c+fO6nk4wO0RiOPHj2u0kclkGqMGADBgwABkZmaiV69e1V4ymUzruV544QXs378fKSkp1fZVVlaipKQEPXv2hEwm01hOX1lZiaNHj9aYgzYuLi6IiYnRuq9///5QKpUoKCioFruNjU2dz6Ht51KTw4cPw8/PDy+++CJcXV3x8MMP488//6z35/Xt27farQYOHz6MPn36VCvc6qN///7IzMystc20adMQGxtb66gOABw/flzrvCyilorFDlELceXKFYwYMQLffPMN0tLSkJubi+3bt2PJkiXw8/MDAPj4+MDZ2RmTJ09GcnIyEhMT8fLLL2Po0KHVfq1SZcSIEYiKikJUVBROnDiBwMDAajewc3BwQHx8PM6fP4/Lly8DAP7973/jyJEjmDVrFlJTU5GTk4Mffvih1gnKQUFB8Pb2xsiRIxEZGYljx47h1KlT2LZtGwYPHoycnByYm5sjMDAQ8+bNw969e5GZmYmAgACUlpZqXRZdk7CwMHz77bcICwtDVlYW0tPT8dFHHwG4PcI0efJkvPzyy/j++++Rm5uLxMREREREICoqqs7ncHBwQFpaGrKzs3H58uVaR8R69+6N6OhoHDlyBFlZWZgxYwYuXrxY7fN+//13nD59GpcvX9Y6EvPWW28hJiYG4eHh+PPPP7Fx40asWrVKPXG6oRQKBTIyMmod3QkICMClS5fw6quv1tjm9OnTOH/+PHx8fB4oHqJmpeM5Q0R0R1lZmQgODhYDBgwQlpaWwszMTDg6OoqFCxeK0tJSdbv6Lj2vqKgQgYGBomPHjqJLly4iIiKi2gTlhIQE4eLiIuRyucbS88TEROHr6yssLCyEubm5cHFxEe+///5984iIiBDOzs7C1NRUdOzYUXh7e4sNGzaIyspKIYQQN2/eFLNnzxZWVla1Lj2/ezm2tsmyO3bsEG5ubkImkwkrKysxfvx4jbxDQ0OFg4ODMDExEV27dhXjxo0TaWlpQoh/lp7fbefOnRr5FxQUqPPHPUvPU1JSNI69cuWK8PPzExYWFqJLly5i4cKF4uWXX9aY4JydnS0GDx4s2rRpU6el5yYmJqJbt27i448/1jiXtgnlrq6uIiwsrIZeuc3Dw0OsWbNG/b6mXKpo+5l/8MEHQqFQ1HoeopZGIkQdf0FNRER6LSoqCvPmzcPx48dhZFT/gf2Kigr07t0bmzdvrjaJmqgl4wRlIqJWYvTo0cjJycH58+e13uPnfs6ePYt33nmHhQ7pHY7sEBERkUHjBGUiIiIyaCx2iIiIyKCx2CEiIiKDxmKHiIiIDBqLHSIiIjJoLHaIiIjIoLHYISIiIoPGYoeIiIgMGosdIiIiMmj/D9tzj3YXXYFmAAAAAElFTkSuQmCC\n", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# plot the results!\n", + "from matplotlib import pyplot as plt\n", + "\n", + "fig, ax = plt.subplots()\n", + "ax.plot(concentrations, pi_ideal, label=\"engine='ideal'\", ls='--', color='gray')\n", + "ax.plot(concentrations, pi_phreeqc, label=\"engine='phreeqc'\", ls=':', color='green')\n", + "ax.plot(concentrations, pi_native, label=\"engine='native'\", ls='-', color='navy')\n", + "ax.plot(concentrations, pi_idst, label=\"experiment\", ls='', color='red', marker=\"x\")\n", + "ax.legend()\n", + "ax.set_xlabel('Solute Concentration (M)')\n", + "ax.set_ylabel('Osmotic Pressure (bar)')\n", + "fig.suptitle('pyEQL prediction of NaCl osmotic pressure')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "cd14cb5f-f9a4-4006-ae26-2ef827d2412d", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python (conda: skagit2)", + "language": "python", + "name": "skagit2" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.6" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/docs/examples/speedup.ipynb b/docs/examples/speedup.ipynb new file mode 100644 index 00000000..83bea9c0 --- /dev/null +++ b/docs/examples/speedup.ipynb @@ -0,0 +1,404 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "id": "c45d3fd6-8af1-4df7-ac05-2805da805893", + "metadata": {}, + "outputs": [], + "source": [ + "from pyEQL import Solution" + ] + }, + { + "cell_type": "markdown", + "id": "a376cef5-2e52-4aa7-a365-57337b20171b", + "metadata": {}, + "source": [ + "### Before optimization" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "bdf1fb10-a567-499d-a0c2-2e3ea4e7fdab", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "298 ms ± 4.11 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)\n" + ] + } + ], + "source": [ + "%%timeit\n", + "s = Solution({\"Na+\": \"2 mol/L\", \"Cl-\": \"2 mol/L\"})" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "b6ce2ea9-8a86-4140-bd82-35f72f06fbbc", + "metadata": {}, + "outputs": [], + "source": [ + "s = Solution({\"Na+\": \"2 mol/L\", \"Cl-\": \"2 mol/L\"})" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "3d391433-2a16-4470-8c40-2b43cda68b35", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "27.1 ms ± 277 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)\n" + ] + } + ], + "source": [ + "%%timeit\n", + "s.get_activity_coefficient('Na+')" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "7ef3de2d-15cc-4f3e-8753-1b9de8238aa0", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "WARNING 2023-11-04 17:15:55,353 solution.py viscosity_kinematic 599 Viscosity coefficients for NaCl not found. Viscosity will be approximate.\n", + "WARNING 2023-11-04 17:15:55,408 solution.py viscosity_kinematic 599 Viscosity coefficients for NaCl not found. Viscosity will be approximate.\n", + "WARNING 2023-11-04 17:15:55,460 solution.py viscosity_kinematic 599 Viscosity coefficients for NaCl not found. Viscosity will be approximate.\n", + "WARNING 2023-11-04 17:15:55,489 engines.py get_activity_coefficient 314 Ionic strength too high to estimate activity for species H[+1]. Specify parameters for Pitzer model. Returning unit activity coefficient\n", + "WARNING 2023-11-04 17:15:55,507 solution.py viscosity_kinematic 599 Viscosity coefficients for NaCl not found. Viscosity will be approximate.\n", + "WARNING 2023-11-04 17:15:55,535 engines.py get_activity_coefficient 314 Ionic strength too high to estimate activity for species OH[-1]. Specify parameters for Pitzer model. Returning unit activity coefficient\n", + "WARNING 2023-11-04 17:15:55,644 engines.py get_activity_coefficient 314 Ionic strength too high to estimate activity for species H[+1]. Specify parameters for Pitzer model. Returning unit activity coefficient\n", + "WARNING 2023-11-04 17:15:55,678 engines.py get_activity_coefficient 314 Ionic strength too high to estimate activity for species OH[-1]. Specify parameters for Pitzer model. Returning unit activity coefficient\n", + "WARNING 2023-11-04 17:15:55,788 engines.py get_activity_coefficient 314 Ionic strength too high to estimate activity for species H[+1]. Specify parameters for Pitzer model. Returning unit activity coefficient\n", + "WARNING 2023-11-04 17:15:55,822 engines.py get_activity_coefficient 314 Ionic strength too high to estimate activity for species OH[-1]. Specify parameters for Pitzer model. Returning unit activity coefficient\n", + "WARNING 2023-11-04 17:15:55,932 engines.py get_activity_coefficient 314 Ionic strength too high to estimate activity for species H[+1]. Specify parameters for Pitzer model. Returning unit activity coefficient\n", + "WARNING 2023-11-04 17:15:55,964 engines.py get_activity_coefficient 314 Ionic strength too high to estimate activity for species OH[-1]. Specify parameters for Pitzer model. Returning unit activity coefficient\n", + "WARNING 2023-11-04 17:15:56,071 engines.py get_activity_coefficient 314 Ionic strength too high to estimate activity for species H[+1]. Specify parameters for Pitzer model. Returning unit activity coefficient\n", + "WARNING 2023-11-04 17:15:56,104 engines.py get_activity_coefficient 314 Ionic strength too high to estimate activity for species OH[-1]. Specify parameters for Pitzer model. Returning unit activity coefficient\n", + "WARNING 2023-11-04 17:15:56,211 engines.py get_activity_coefficient 314 Ionic strength too high to estimate activity for species H[+1]. Specify parameters for Pitzer model. Returning unit activity coefficient\n", + "WARNING 2023-11-04 17:15:56,242 engines.py get_activity_coefficient 314 Ionic strength too high to estimate activity for species OH[-1]. Specify parameters for Pitzer model. Returning unit activity coefficient\n", + "WARNING 2023-11-04 17:15:56,348 engines.py get_activity_coefficient 314 Ionic strength too high to estimate activity for species H[+1]. Specify parameters for Pitzer model. Returning unit activity coefficient\n", + "WARNING 2023-11-04 17:15:56,384 engines.py get_activity_coefficient 314 Ionic strength too high to estimate activity for species OH[-1]. Specify parameters for Pitzer model. Returning unit activity coefficient\n", + "WARNING 2023-11-04 17:15:56,495 engines.py get_activity_coefficient 314 Ionic strength too high to estimate activity for species H[+1]. Specify parameters for Pitzer model. Returning unit activity coefficient\n", + "WARNING 2023-11-04 17:15:56,528 engines.py get_activity_coefficient 314 Ionic strength too high to estimate activity for species OH[-1]. Specify parameters for Pitzer model. Returning unit activity coefficient\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "142 ms ± 1.96 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)\n" + ] + } + ], + "source": [ + "%%timeit\n", + "s.conductivity" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "b30d7f1c-9630-4e21-b275-cb3befc2433f", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "5.27 ms ± 153 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)\n" + ] + } + ], + "source": [ + "%%timeit\n", + "s.ionic_strength" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "id": "40a55c8b-947d-4806-8094-2188f244816a", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2.43 ms ± 18.5 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)\n" + ] + } + ], + "source": [ + "%%timeit\n", + "s.get_transport_number('Na+')" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "314d44f5-88c1-44a8-b0e2-3e072e3ad8ab", + "metadata": {}, + "outputs": [ + { + "ename": "SyntaxError", + "evalue": "'break' outside loop (668683560.py, line 1)", + "output_type": "error", + "traceback": [ + "\u001b[0;36m Cell \u001b[0;32mIn [8], line 1\u001b[0;36m\u001b[0m\n\u001b[0;31m break\u001b[0m\n\u001b[0m ^\u001b[0m\n\u001b[0;31mSyntaxError\u001b[0m\u001b[0;31m:\u001b[0m 'break' outside loop\n" + ] + } + ], + "source": [ + "break" + ] + }, + { + "cell_type": "markdown", + "id": "e8ae1012-8728-448a-bebe-03752f97a578", + "metadata": {}, + "source": [ + "### After optimization" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "2f1739e4-da68-484f-b691-9be13a00bc94", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "85 ms ± 1.46 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)\n" + ] + } + ], + "source": [ + "%%timeit\n", + "s = Solution({\"Na+\": \"2 mol/L\", \"Cl-\": \"2 mol/L\"})" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "cc95a42c-1151-4756-9289-6aee0717fe81", + "metadata": {}, + "outputs": [], + "source": [ + "s = Solution({\"Na+\": \"2 mol/L\", \"Cl-\": \"2 mol/L\"})" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "3940edb9-94d6-45bd-a6db-c535d4968045", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "14 ms ± 239 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)\n" + ] + } + ], + "source": [ + "%%timeit\n", + "s.get_activity_coefficient('Na+')" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "185d5272-84a1-4944-bb39-948cc970989d", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "WARNING 2023-11-04 17:30:41,861 engines.py get_activity_coefficient 314 Ionic strength too high to estimate activity for species H[+1]. Specify parameters for Pitzer model. Returning unit activity coefficient\n", + "WARNING 2023-11-04 17:30:41,874 engines.py get_activity_coefficient 314 Ionic strength too high to estimate activity for species OH[-1]. Specify parameters for Pitzer model. Returning unit activity coefficient\n", + "WARNING 2023-11-04 17:30:41,912 engines.py get_activity_coefficient 314 Ionic strength too high to estimate activity for species H[+1]. Specify parameters for Pitzer model. Returning unit activity coefficient\n", + "WARNING 2023-11-04 17:30:41,917 engines.py get_activity_coefficient 314 Ionic strength too high to estimate activity for species OH[-1]. Specify parameters for Pitzer model. Returning unit activity coefficient\n", + "WARNING 2023-11-04 17:30:41,953 engines.py get_activity_coefficient 314 Ionic strength too high to estimate activity for species H[+1]. Specify parameters for Pitzer model. Returning unit activity coefficient\n", + "WARNING 2023-11-04 17:30:41,958 engines.py get_activity_coefficient 314 Ionic strength too high to estimate activity for species OH[-1]. Specify parameters for Pitzer model. Returning unit activity coefficient\n", + "WARNING 2023-11-04 17:30:41,995 engines.py get_activity_coefficient 314 Ionic strength too high to estimate activity for species H[+1]. Specify parameters for Pitzer model. Returning unit activity coefficient\n", + "WARNING 2023-11-04 17:30:42,000 engines.py get_activity_coefficient 314 Ionic strength too high to estimate activity for species OH[-1]. Specify parameters for Pitzer model. Returning unit activity coefficient\n", + "WARNING 2023-11-04 17:30:42,036 engines.py get_activity_coefficient 314 Ionic strength too high to estimate activity for species H[+1]. Specify parameters for Pitzer model. Returning unit activity coefficient\n", + "WARNING 2023-11-04 17:30:42,042 engines.py get_activity_coefficient 314 Ionic strength too high to estimate activity for species OH[-1]. Specify parameters for Pitzer model. Returning unit activity coefficient\n", + "WARNING 2023-11-04 17:30:42,078 engines.py get_activity_coefficient 314 Ionic strength too high to estimate activity for species H[+1]. Specify parameters for Pitzer model. Returning unit activity coefficient\n", + "WARNING 2023-11-04 17:30:42,084 engines.py get_activity_coefficient 314 Ionic strength too high to estimate activity for species OH[-1]. Specify parameters for Pitzer model. Returning unit activity coefficient\n", + "WARNING 2023-11-04 17:30:42,119 engines.py get_activity_coefficient 314 Ionic strength too high to estimate activity for species H[+1]. Specify parameters for Pitzer model. Returning unit activity coefficient\n", + "WARNING 2023-11-04 17:30:42,124 engines.py get_activity_coefficient 314 Ionic strength too high to estimate activity for species OH[-1]. Specify parameters for Pitzer model. Returning unit activity coefficient\n", + "WARNING 2023-11-04 17:30:42,160 engines.py get_activity_coefficient 314 Ionic strength too high to estimate activity for species H[+1]. Specify parameters for Pitzer model. Returning unit activity coefficient\n", + "WARNING 2023-11-04 17:30:42,166 engines.py get_activity_coefficient 314 Ionic strength too high to estimate activity for species OH[-1]. Specify parameters for Pitzer model. Returning unit activity coefficient\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "41.6 ms ± 639 µs per loop (mean ± std. dev. of 7 runs, 1 loop each)\n" + ] + } + ], + "source": [ + "%%timeit\n", + "s.conductivity" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "c3cd2d5b-f3a1-4909-aa18-caeebc60ae4e", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "527 µs ± 7.91 µs per loop (mean ± std. dev. of 7 runs, 1,000 loops each)\n" + ] + } + ], + "source": [ + "%%timeit\n", + "s.ionic_strength" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "366a8d79-d08b-48cc-ae9f-6e3dd1e25b3a", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "549 µs ± 11 µs per loop (mean ± std. dev. of 7 runs, 1,000 loops each)\n" + ] + } + ], + "source": [ + "%%timeit\n", + "s.get_transport_number('Na+')" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "c0d007b0-ec00-4c06-bee4-40d04e6cebf2", + "metadata": {}, + "outputs": [], + "source": [ + "from pint import UnitRegistry\n", + "ureg = UnitRegistry()" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "id": "a6a7e789-5882-4756-a9b3-cf1b597be661", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "4.89 µs ± 45.8 ns per loop (mean ± std. dev. of 7 runs, 100,000 loops each)\n" + ] + } + ], + "source": [ + "%%timeit\n", + "ureg.Quantity(1, 'meter')" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "id": "438f9cba-84a6-4639-a715-ccfae50aa621", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "57.2 µs ± 1.07 µs per loop (mean ± std. dev. of 7 runs, 10,000 loops each)\n" + ] + } + ], + "source": [ + "%%timeit\n", + "1*ureg.Quantity('meter')" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "id": "a82b8604-1985-4e4f-b473-6ba9d1d0e0ad", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "69.1 µs ± 389 ns per loop (mean ± std. dev. of 7 runs, 10,000 loops each)\n" + ] + } + ], + "source": [ + "%%timeit\n", + "ureg.Quantity('1 meter')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e07940ec-c3a7-47d8-b49b-b904b07335e8", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.6" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/docs/index.md b/docs/index.md index 58da2ef9..fe68d540 100644 --- a/docs/index.md +++ b/docs/index.md @@ -77,7 +77,8 @@ high level of transparency about data sources and calculation methods. ```{toctree} :maxdepth: 2 quickstart -pyeql_demo +examples/pyeql_demo +tutorials ``` ```{toctree} diff --git a/docs/tutorials.md b/docs/tutorials.md new file mode 100644 index 00000000..bdccf6f6 --- /dev/null +++ b/docs/tutorials.md @@ -0,0 +1,32 @@ +# Tutorials + +Each tutorial below is presented in a Jupyter notebook. You can view the executed notebooks here +in the documentation, view the raw notebooks on GitHub, or interactively run them in your web +browser using Binder by clicking the respective links below. + +## Functionality Overview + +[View Notebook on GitHub](https://github.com/KingsburyLab/pyEQL/tree/main/docs/examples/pyeql_demo.ipynb) | Try Interactive Notebook on Binder [![Binder](https://mybinder.org/badge_logo.svg)](https://mybinder.org/v2/gh/KingsburyLab/pyEQL/main?labpath=docs%2Fexamples%2Fpyeql_demo.ipynb) + +```{toctree} +:maxdepth: 1 +examples/pyeql_demo +``` + +## Calculating Osmotic Pressure + +[View Notebook on GitHub](https://github.com/KingsburyLab/pyEQL/tree/main/docs/examples/pyeql_tutorial_osmotic_pressure.ipynb) | Try Interactive Notebook on Binder [![Binder](https://mybinder.org/badge_logo.svg)](https://mybinder.org/v2/gh/KingsburyLab/pyEQL/main?labpath=docs%2Fexamples%2Fpyeql_tutorial_osmotic_pressure.ipynb) + +```{toctree} +:maxdepth: 2 +examples/pyeql_tutorial_osmotic_pressure +``` + +## Accessing the Property Database + +[View Notebook on GitHub](https://github.com/KingsburyLab/pyEQL/tree/main/docs/examples/pyeql_tutorial_database.ipynb) | Try Interactive Notebook on Binder [![Binder](https://mybinder.org/badge_logo.svg)](https://mybinder.org/v2/gh/KingsburyLab/pyEQL/main?labpath=docs%2Fexamples%2Fpyeql_tutorial_osmotic_pressure.ipynb) + +```{toctree} +:maxdepth: 2 +examples/pyeql_tutorial_database +``` diff --git a/pyproject.toml b/pyproject.toml index 5b44cc80..77012e10 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [build-system] # AVOID CHANGING REQUIRES: IT WILL BE UPDATED BY PYSCAFFOLD! -requires = ["setuptools>=46.1.0", "setuptools_scm[toml]>=5", "wheel"] +requires = ["setuptools>=46.1.0", "setuptools_scm[toml]>=5"] build-backend = "setuptools.build_meta" [tool.setuptools_scm] @@ -11,10 +11,12 @@ version_scheme = "no-guess-dev" line-length = 120 [tool.ruff] -target-version = "py38" +target-version = "py39" line-length = 120 exclude = [".dat"] src = ["src"] + +[tool.ruff.lint] select = [ "B", # flake8-bugbear "C4", # flake8-comprehensions @@ -68,14 +70,26 @@ ignore = [ pydocstyle.convention = "google" isort.split-on-trailing-comma = false -[tool.ruff.per-file-ignores] +[tool.ruff.lint.per-file-ignores] "__init__.py" = ["F401"] "tests/*" = ["D", "E501"] # TODO - remove E501 [tool.pytest.ini_options] -addopts = "--color=yes -p no:warnings --import-mode=importlib --durations=30" +minversion = "6.0" +addopts = [ + "-ra", + "--showlocals", + "--strict-markers", + "--strict-config", + "--color=yes", + "--import-mode=importlib", + "--durations=30" +] +xfail_strict = true +filterwarnings = ["error", "ignore::UserWarning", "ignore::DeprecationWarning"] +log_cli_level = "warning" testpaths = [ - "tests", + "tests", ] [tool.mypy] @@ -83,6 +97,10 @@ ignore_missing_imports = true namespace_packages = true explicit_package_bases = true no_implicit_optional = false +strict = true +hide_error_codes = true +enable_error_code = ["ignore-without-code", "redundant-expr", "truthy-bool"] +warn_unreachable = true [tool.codespell] ignore-words-list = "nd" diff --git a/requirements/macos-latest_py3.10.txt b/requirements/macos-latest_py3.10.txt index bd2316e7..55beda6b 100644 --- a/requirements/macos-latest_py3.10.txt +++ b/requirements/macos-latest_py3.10.txt @@ -8,54 +8,52 @@ aioitertools==0.11.0 # via maggma annotated-types==0.6.0 # via pydantic -anyio==3.7.1 - # via - # fastapi - # starlette -attrs==23.1.0 +anyio==4.2.0 + # via starlette +attrs==23.2.0 # via # jsonschema # referencing -bcrypt==4.0.1 +bcrypt==4.1.2 # via paramiko -blinker==1.6.3 +blinker==1.7.0 # via flask -boto3==1.28.65 +boto3==1.34.35 # via maggma -botocore==1.31.65 +botocore==1.34.35 # via # boto3 # s3transfer -certifi==2023.7.22 +certifi==2024.2.2 # via requests cffi==1.16.0 # via # cryptography # pynacl -charset-normalizer==3.3.0 +charset-normalizer==3.3.2 # via requests click==8.1.7 # via # flask # mongogrant # uvicorn -contourpy==1.1.1 +contourpy==1.2.0 # via matplotlib -cryptography==41.0.4 +cryptography==42.0.2 # via paramiko cycler==0.12.1 # via matplotlib -dnspython==2.4.2 +dnspython==2.5.0 # via # maggma # pymongo -exceptiongroup==1.1.3 +exceptiongroup==1.2.0 # via anyio -fastapi==0.103.2 +fastapi==0.109.2 # via maggma -flask==3.0.0 +flask==3.0.2 # via mongogrant -fonttools==4.43.1 +fonttools==4.48.1 # via matplotlib future==0.18.3 # via uncertainties @@ -63,13 +61,13 @@ h11==0.14.0 # via uvicorn iapws==1.5.3 # via pyEQL (setup.py) -idna==3.4 +idna==3.6 # via # anyio # requests itsdangerous==2.1.2 # via flask -jinja2==3.1.2 +jinja2==3.1.3 # via flask jmespath==1.0.1 # via @@ -77,27 +75,27 @@ jmespath==1.0.1 # botocore joblib==1.3.2 # via pymatgen -jsonschema==4.19.1 +jsonschema==4.21.1 # via maggma -jsonschema-specifications==2023.7.1 +jsonschema-specifications==2023.12.1 # via jsonschema kiwisolver==1.4.5 # via matplotlib latexcodec==2.0.1 # via pybtex -maggma==0.57.4 +maggma==0.62.1 # via pyEQL (setup.py) -markupsafe==2.1.3 +markupsafe==2.1.5 # via # jinja2 # werkzeug -matplotlib==3.8.0 +matplotlib==3.8.2 # via pymatgen mongogrant==0.3.3 # via maggma mongomock==4.1.2 # via maggma -monty==2023.9.25 +monty==2024.2.2 # via # maggma # pyEQL (setup.py) @@ -106,9 +104,9 @@ mpmath==1.3.0 # via sympy msgpack==1.0.7 # via maggma -networkx==3.1 +networkx==3.2.1 # via pymatgen -numpy==1.26.1 +numpy==1.26.4 # via # contourpy # maggma @@ -119,7 +117,7 @@ numpy==1.26.1 # pymatgen # scipy # spglib -orjson==3.9.9 +orjson==3.9.13 # via maggma packaging==23.2 # via @@ -128,38 +126,38 @@ packaging==23.2 # plotly palettable==3.3.3 # via pymatgen -pandas==2.1.1 +pandas==2.2.0 # via pymatgen -paramiko==3.3.1 +paramiko==3.4.0 # via sshtunnel periodictable==1.6.1 # via phreeqpython phreeqpython==1.5.0 # via pyEQL (setup.py) -pillow==10.1.0 +pillow==10.2.0 # via matplotlib -pint==0.22 +pint==0.23 # via pyEQL (setup.py) -plotly==5.17.0 +plotly==5.18.0 # via pymatgen pybtex==0.24.0 # via pymatgen pycparser==2.21 # via cffi -pydantic==2.4.2 +pydantic==2.6.1 # via # fastapi # maggma # pydantic-settings -pydantic-core==2.10.1 +pydantic-core==2.16.2 # via pydantic -pydantic-settings==2.0.3 +pydantic-settings==2.1.0 # via maggma -pydash==7.0.6 +pydash==7.0.7 # via maggma -pymatgen==2023.10.11 +pymatgen==2024.1.27 # via pyEQL (setup.py) -pymongo==4.5.0 +pymongo==4.6.1 # via # maggma # mongogrant @@ -175,15 +173,15 @@ python-dateutil==2.8.2 # maggma # matplotlib # pandas -python-dotenv==1.0.0 +python-dotenv==1.0.1 # via pydantic-settings -pytz==2023.3.post1 +pytz==2024.1 # via pandas pyyaml==6.0.1 # via pybtex -pyzmq==25.1.1 +pyzmq==25.1.2 # via maggma -referencing==0.30.2 +referencing==0.33.0 # via # jsonschema # jsonschema-specifications @@ -191,19 +189,19 @@ requests==2.31.0 # via # mongogrant # pymatgen -rpds-py==0.10.6 +rpds-py==0.17.1 # via # jsonschema # referencing -ruamel-yaml==0.17.35 +ruamel-yaml==0.17.40 # via # maggma # pymatgen ruamel-yaml-clib==0.2.8 # via ruamel-yaml -s3transfer==0.7.0 +s3transfer==0.10.0 # via boto3 -scipy==1.11.3 +scipy==1.12.0 # via # iapws # phreeqpython @@ -218,11 +216,11 @@ six==1.16.0 # python-dateutil sniffio==1.3.0 # via anyio -spglib==2.1.0 +spglib==2.3.0 # via pymatgen sshtunnel==0.4.0 # via maggma -starlette==0.27.0 +starlette==0.36.3 # via fastapi sympy==1.12 # via pymatgen @@ -234,15 +232,16 @@ tqdm==4.66.1 # via # maggma # pymatgen -typing-extensions==4.8.0 +typing-extensions==4.9.0 # via + # anyio # fastapi # pint # pydantic # pydantic-core # pydash # uvicorn -tzdata==2023.3 +tzdata==2023.4 # via pandas uncertainties==3.1.7 # via pymatgen @@ -250,7 +249,7 @@ urllib3==2.0.7 # via # botocore # requests -uvicorn==0.23.2 +uvicorn==0.27.0.post1 # via maggma werkzeug==3.0.1 # via flask diff --git a/requirements/macos-latest_py3.10_extras.txt b/requirements/macos-latest_py3.10_extras.txt index 4cabfab2..43044592 100644 --- a/requirements/macos-latest_py3.10_extras.txt +++ b/requirements/macos-latest_py3.10_extras.txt @@ -6,35 +6,31 @@ # aioitertools==0.11.0 # via maggma -alabaster==0.7.13 +alabaster==0.7.16 # via sphinx annotated-types==0.6.0 # via pydantic -anyio==3.7.1 - # via - # fastapi - # starlette -attrs==23.1.0 +anyio==4.2.0 + # via starlette +attrs==23.2.0 # via # jsonschema # referencing -babel==2.13.0 +babel==2.14.0 # via sphinx -bcrypt==4.0.1 +bcrypt==4.1.2 # via paramiko -black==23.10.0 +black==24.1.1 # via pyEQL (setup.py) -blinker==1.6.3 +blinker==1.7.0 # via flask -boto3==1.28.65 +boto3==1.34.35 # via maggma -botocore==1.31.65 +botocore==1.34.35 # via # boto3 # s3transfer -cachetools==5.3.1 - # via tox -certifi==2023.7.22 +certifi==2024.2.2 # via requests cffi==1.16.0 # via @@ -42,9 +38,7 @@ cffi==1.16.0 # pynacl cfgv==3.4.0 # via pre-commit -chardet==5.2.0 - # via tox -charset-normalizer==3.3.0 +charset-normalizer==3.3.2 # via requests click==8.1.7 # via @@ -52,42 +46,40 @@ click==8.1.7 # flask # mongogrant # uvicorn -colorama==0.4.6 - # via tox -contourpy==1.1.1 +contourpy==1.2.0 # via matplotlib -coverage[toml]==7.3.2 +coverage[toml]==7.4.1 # via # coverage # pytest-cov -cryptography==41.0.4 +cryptography==42.0.2 # via paramiko cycler==0.12.1 # via matplotlib -distlib==0.3.7 +distlib==0.3.8 # via virtualenv -dnspython==2.4.2 +dnspython==2.5.0 # via # maggma # pymongo -docutils==0.18.1 +docutils==0.20.1 # via # myst-parser # sphinx # sphinx-rtd-theme -exceptiongroup==1.1.3 +exceptiongroup==1.2.0 # via # anyio # pytest -fastapi==0.103.2 +fastapi==0.109.2 # via maggma -filelock==3.12.4 +filelock==3.13.1 # via # tox # virtualenv -flask==3.0.0 +flask==3.0.2 # via mongogrant -fonttools==4.43.1 +fonttools==4.48.1 # via matplotlib future==0.18.3 # via uncertainties @@ -95,9 +87,9 @@ h11==0.14.0 # via uvicorn iapws==1.5.3 # via pyEQL (setup.py) -identify==2.5.30 +identify==2.5.33 # via pre-commit -idna==3.4 +idna==3.6 # via # anyio # requests @@ -107,7 +99,7 @@ iniconfig==2.0.0 # via pytest itsdangerous==2.1.2 # via flask -jinja2==3.1.2 +jinja2==3.1.3 # via # flask # myst-parser @@ -118,28 +110,28 @@ jmespath==1.0.1 # botocore joblib==1.3.2 # via pymatgen -jsonschema==4.19.1 +jsonschema==4.21.1 # via maggma -jsonschema-specifications==2023.7.1 +jsonschema-specifications==2023.12.1 # via jsonschema kiwisolver==1.4.5 # via matplotlib latexcodec==2.0.1 # via pybtex -linkify-it-py==2.0.2 +linkify-it-py==2.0.3 # via myst-parser -maggma==0.57.4 +maggma==0.62.1 # via pyEQL (setup.py) markdown-it-py==3.0.0 # via # mdit-py-plugins # myst-parser # rich -markupsafe==2.1.3 +markupsafe==2.1.5 # via # jinja2 # werkzeug -matplotlib==3.8.0 +matplotlib==3.8.2 # via pymatgen mdit-py-plugins==0.4.0 # via myst-parser @@ -149,7 +141,7 @@ mongogrant==0.3.3 # via maggma mongomock==4.1.2 # via maggma -monty==2023.9.25 +monty==2024.2.2 # via # maggma # pyEQL (setup.py) @@ -158,7 +150,7 @@ mpmath==1.3.0 # via sympy msgpack==1.0.7 # via maggma -mypy==1.6.0 +mypy==1.8.0 # via pyEQL (setup.py) mypy-extensions==1.0.0 # via @@ -166,11 +158,11 @@ mypy-extensions==1.0.0 # mypy myst-parser[linkify]==2.0.0 # via pyEQL (setup.py) -networkx==3.1 +networkx==3.2.1 # via pymatgen nodeenv==1.8.0 # via pre-commit -numpy==1.26.1 +numpy==1.26.4 # via # contourpy # maggma @@ -181,7 +173,7 @@ numpy==1.26.1 # pymatgen # scipy # spglib -orjson==3.9.9 +orjson==3.9.13 # via maggma packaging==23.2 # via @@ -189,61 +181,61 @@ packaging==23.2 # matplotlib # mongomock # plotly - # pyproject-api # pytest # sphinx # tox palettable==3.3.3 # via pymatgen -pandas==2.1.1 +pandas==2.2.0 # via pymatgen -paramiko==3.3.1 +paramiko==3.4.0 # via sshtunnel -pathspec==0.11.2 +pathspec==0.12.1 # via black periodictable==1.6.1 # via phreeqpython phreeqpython==1.5.0 # via pyEQL (setup.py) -pillow==10.1.0 +pillow==10.2.0 # via matplotlib -pint==0.22 +pint==0.23 # via pyEQL (setup.py) -platformdirs==3.11.0 +platformdirs==4.2.0 # via # black - # tox # virtualenv -plotly==5.17.0 +plotly==5.18.0 # via pymatgen -pluggy==1.3.0 +pluggy==1.4.0 # via # pytest # tox -pre-commit==3.5.0 +pre-commit==3.6.0 # via pyEQL (setup.py) +py==1.11.0 + # via tox pybtex==0.24.0 # via pymatgen pycparser==2.21 # via cffi -pydantic==2.4.2 +pydantic==2.6.1 # via # fastapi # maggma # pydantic-settings -pydantic-core==2.10.1 +pydantic-core==2.16.2 # via pydantic -pydantic-settings==2.0.3 +pydantic-settings==2.1.0 # via maggma -pydash==7.0.6 +pydash==7.0.7 # via maggma -pygments==2.16.1 +pygments==2.17.2 # via # rich # sphinx -pymatgen==2023.10.11 +pymatgen==2024.1.27 # via pyEQL (setup.py) -pymongo==4.5.0 +pymongo==4.6.1 # via # maggma # mongogrant @@ -253,9 +245,7 @@ pyparsing==3.1.1 # via # matplotlib # periodictable -pyproject-api==1.6.1 - # via tox -pytest==7.4.2 +pytest==8.0.0 # via # pyEQL (setup.py) # pytest-cov @@ -267,18 +257,18 @@ python-dateutil==2.8.2 # maggma # matplotlib # pandas -python-dotenv==1.0.0 +python-dotenv==1.0.1 # via pydantic-settings -pytz==2023.3.post1 +pytz==2024.1 # via pandas pyyaml==6.0.1 # via # myst-parser # pre-commit # pybtex -pyzmq==25.1.1 +pyzmq==25.1.2 # via maggma -referencing==0.30.2 +referencing==0.33.0 # via # jsonschema # jsonschema-specifications @@ -287,23 +277,23 @@ requests==2.31.0 # mongogrant # pymatgen # sphinx -rich==13.6.0 +rich==13.7.0 # via pyEQL (setup.py) -rpds-py==0.10.6 +rpds-py==0.17.1 # via # jsonschema # referencing -ruamel-yaml==0.17.35 +ruamel-yaml==0.17.40 # via # maggma # pymatgen ruamel-yaml-clib==0.2.8 # via ruamel-yaml -ruff==0.1.0 +ruff==0.2.1 # via pyEQL (setup.py) -s3transfer==0.7.0 +s3transfer==0.10.0 # via boto3 -scipy==1.11.3 +scipy==1.12.0 # via # iapws # phreeqpython @@ -316,42 +306,38 @@ six==1.16.0 # latexcodec # pybtex # python-dateutil + # tox sniffio==1.3.0 # via anyio snowballstemmer==2.2.0 # via sphinx -spglib==2.1.0 +spglib==2.3.0 # via pymatgen sphinx==7.2.6 # via # myst-parser # pyEQL (setup.py) # sphinx-rtd-theme - # sphinxcontrib-applehelp - # sphinxcontrib-devhelp - # sphinxcontrib-htmlhelp # sphinxcontrib-jquery - # sphinxcontrib-qthelp - # sphinxcontrib-serializinghtml -sphinx-rtd-theme==1.3.0 +sphinx-rtd-theme==2.0.0 # via pyEQL (setup.py) -sphinxcontrib-applehelp==1.0.7 +sphinxcontrib-applehelp==1.0.8 # via sphinx -sphinxcontrib-devhelp==1.0.5 +sphinxcontrib-devhelp==1.0.6 # via sphinx -sphinxcontrib-htmlhelp==2.0.4 +sphinxcontrib-htmlhelp==2.0.5 # via sphinx sphinxcontrib-jquery==4.1 # via sphinx-rtd-theme sphinxcontrib-jsmath==1.0.1 # via sphinx -sphinxcontrib-qthelp==1.0.6 +sphinxcontrib-qthelp==1.0.7 # via sphinx -sphinxcontrib-serializinghtml==1.1.9 +sphinxcontrib-serializinghtml==1.1.10 # via sphinx sshtunnel==0.4.0 # via maggma -starlette==0.27.0 +starlette==0.36.3 # via fastapi sympy==1.12 # via pymatgen @@ -364,17 +350,17 @@ tomli==2.0.1 # black # coverage # mypy - # pyproject-api # pytest # tox -tox==4.11.3 +tox==3.28.0 # via pyEQL (setup.py) tqdm==4.66.1 # via # maggma # pymatgen -typing-extensions==4.8.0 +typing-extensions==4.9.0 # via + # anyio # black # fastapi # mypy @@ -383,7 +369,7 @@ typing-extensions==4.8.0 # pydantic-core # pydash # uvicorn -tzdata==2023.3 +tzdata==2023.4 # via pandas uc-micro-py==1.0.2 # via linkify-it-py @@ -393,9 +379,9 @@ urllib3==2.0.7 # via # botocore # requests -uvicorn==0.23.2 +uvicorn==0.27.0.post1 # via maggma -virtualenv==20.24.5 +virtualenv==20.25.0 # via # pre-commit # tox diff --git a/requirements/macos-latest_py3.11.txt b/requirements/macos-latest_py3.11.txt index 1a3d6681..ddb2fec2 100644 --- a/requirements/macos-latest_py3.11.txt +++ b/requirements/macos-latest_py3.11.txt @@ -8,52 +8,50 @@ aioitertools==0.11.0 # via maggma annotated-types==0.6.0 # via pydantic -anyio==3.7.1 - # via - # fastapi - # starlette -attrs==23.1.0 +anyio==4.2.0 + # via starlette +attrs==23.2.0 # via # jsonschema # referencing -bcrypt==4.0.1 +bcrypt==4.1.2 # via paramiko -blinker==1.6.3 +blinker==1.7.0 # via flask -boto3==1.28.65 +boto3==1.34.35 # via maggma -botocore==1.31.65 +botocore==1.34.35 # via # boto3 # s3transfer -certifi==2023.7.22 +certifi==2024.2.2 # via requests cffi==1.16.0 # via # cryptography # pynacl -charset-normalizer==3.3.0 +charset-normalizer==3.3.2 # via requests click==8.1.7 # via # flask # mongogrant # uvicorn -contourpy==1.1.1 +contourpy==1.2.0 # via matplotlib -cryptography==41.0.4 +cryptography==42.0.2 # via paramiko cycler==0.12.1 # via matplotlib -dnspython==2.4.2 +dnspython==2.5.0 # via # maggma # pymongo -fastapi==0.103.2 +fastapi==0.109.2 # via maggma -flask==3.0.0 +flask==3.0.2 # via mongogrant -fonttools==4.43.1 +fonttools==4.48.1 # via matplotlib future==0.18.3 # via uncertainties @@ -61,13 +59,13 @@ h11==0.14.0 # via uvicorn iapws==1.5.3 # via pyEQL (setup.py) -idna==3.4 +idna==3.6 # via # anyio # requests itsdangerous==2.1.2 # via flask -jinja2==3.1.2 +jinja2==3.1.3 # via flask jmespath==1.0.1 # via @@ -75,27 +73,27 @@ jmespath==1.0.1 # botocore joblib==1.3.2 # via pymatgen -jsonschema==4.19.1 +jsonschema==4.21.1 # via maggma -jsonschema-specifications==2023.7.1 +jsonschema-specifications==2023.12.1 # via jsonschema kiwisolver==1.4.5 # via matplotlib latexcodec==2.0.1 # via pybtex -maggma==0.57.4 +maggma==0.62.1 # via pyEQL (setup.py) -markupsafe==2.1.3 +markupsafe==2.1.5 # via # jinja2 # werkzeug -matplotlib==3.8.0 +matplotlib==3.8.2 # via pymatgen mongogrant==0.3.3 # via maggma mongomock==4.1.2 # via maggma -monty==2023.9.25 +monty==2024.2.2 # via # maggma # pyEQL (setup.py) @@ -104,9 +102,9 @@ mpmath==1.3.0 # via sympy msgpack==1.0.7 # via maggma -networkx==3.1 +networkx==3.2.1 # via pymatgen -numpy==1.26.1 +numpy==1.26.4 # via # contourpy # maggma @@ -117,7 +115,7 @@ numpy==1.26.1 # pymatgen # scipy # spglib -orjson==3.9.9 +orjson==3.9.13 # via maggma packaging==23.2 # via @@ -126,38 +124,38 @@ packaging==23.2 # plotly palettable==3.3.3 # via pymatgen -pandas==2.1.1 +pandas==2.2.0 # via pymatgen -paramiko==3.3.1 +paramiko==3.4.0 # via sshtunnel periodictable==1.6.1 # via phreeqpython phreeqpython==1.5.0 # via pyEQL (setup.py) -pillow==10.1.0 +pillow==10.2.0 # via matplotlib -pint==0.22 +pint==0.23 # via pyEQL (setup.py) -plotly==5.17.0 +plotly==5.18.0 # via pymatgen pybtex==0.24.0 # via pymatgen pycparser==2.21 # via cffi -pydantic==2.4.2 +pydantic==2.6.1 # via # fastapi # maggma # pydantic-settings -pydantic-core==2.10.1 +pydantic-core==2.16.2 # via pydantic -pydantic-settings==2.0.3 +pydantic-settings==2.1.0 # via maggma -pydash==7.0.6 +pydash==7.0.7 # via maggma -pymatgen==2023.10.11 +pymatgen==2024.1.27 # via pyEQL (setup.py) -pymongo==4.5.0 +pymongo==4.6.1 # via # maggma # mongogrant @@ -173,15 +171,15 @@ python-dateutil==2.8.2 # maggma # matplotlib # pandas -python-dotenv==1.0.0 +python-dotenv==1.0.1 # via pydantic-settings -pytz==2023.3.post1 +pytz==2024.1 # via pandas pyyaml==6.0.1 # via pybtex -pyzmq==25.1.1 +pyzmq==25.1.2 # via maggma -referencing==0.30.2 +referencing==0.33.0 # via # jsonschema # jsonschema-specifications @@ -189,19 +187,19 @@ requests==2.31.0 # via # mongogrant # pymatgen -rpds-py==0.10.6 +rpds-py==0.17.1 # via # jsonschema # referencing -ruamel-yaml==0.17.35 +ruamel-yaml==0.17.40 # via # maggma # pymatgen ruamel-yaml-clib==0.2.8 # via ruamel-yaml -s3transfer==0.7.0 +s3transfer==0.10.0 # via boto3 -scipy==1.11.3 +scipy==1.12.0 # via # iapws # phreeqpython @@ -216,11 +214,11 @@ six==1.16.0 # python-dateutil sniffio==1.3.0 # via anyio -spglib==2.1.0 +spglib==2.3.0 # via pymatgen sshtunnel==0.4.0 # via maggma -starlette==0.27.0 +starlette==0.36.3 # via fastapi sympy==1.12 # via pymatgen @@ -232,14 +230,14 @@ tqdm==4.66.1 # via # maggma # pymatgen -typing-extensions==4.8.0 +typing-extensions==4.9.0 # via # fastapi # pint # pydantic # pydantic-core # pydash -tzdata==2023.3 +tzdata==2023.4 # via pandas uncertainties==3.1.7 # via pymatgen @@ -247,7 +245,7 @@ urllib3==2.0.7 # via # botocore # requests -uvicorn==0.23.2 +uvicorn==0.27.0.post1 # via maggma werkzeug==3.0.1 # via flask diff --git a/requirements/macos-latest_py3.11_extras.txt b/requirements/macos-latest_py3.11_extras.txt index 822bfd7e..09744ee1 100644 --- a/requirements/macos-latest_py3.11_extras.txt +++ b/requirements/macos-latest_py3.11_extras.txt @@ -6,35 +6,31 @@ # aioitertools==0.11.0 # via maggma -alabaster==0.7.13 +alabaster==0.7.16 # via sphinx annotated-types==0.6.0 # via pydantic -anyio==3.7.1 - # via - # fastapi - # starlette -attrs==23.1.0 +anyio==4.2.0 + # via starlette +attrs==23.2.0 # via # jsonschema # referencing -babel==2.13.0 +babel==2.14.0 # via sphinx -bcrypt==4.0.1 +bcrypt==4.1.2 # via paramiko -black==23.10.0 +black==24.1.1 # via pyEQL (setup.py) -blinker==1.6.3 +blinker==1.7.0 # via flask -boto3==1.28.65 +boto3==1.34.35 # via maggma -botocore==1.31.65 +botocore==1.34.35 # via # boto3 # s3transfer -cachetools==5.3.1 - # via tox -certifi==2023.7.22 +certifi==2024.2.2 # via requests cffi==1.16.0 # via @@ -42,9 +38,7 @@ cffi==1.16.0 # pynacl cfgv==3.4.0 # via pre-commit -chardet==5.2.0 - # via tox -charset-normalizer==3.3.0 +charset-normalizer==3.3.2 # via requests click==8.1.7 # via @@ -52,38 +46,36 @@ click==8.1.7 # flask # mongogrant # uvicorn -colorama==0.4.6 - # via tox -contourpy==1.1.1 +contourpy==1.2.0 # via matplotlib -coverage[toml]==7.3.2 +coverage[toml]==7.4.1 # via # coverage # pytest-cov -cryptography==41.0.4 +cryptography==42.0.2 # via paramiko cycler==0.12.1 # via matplotlib -distlib==0.3.7 +distlib==0.3.8 # via virtualenv -dnspython==2.4.2 +dnspython==2.5.0 # via # maggma # pymongo -docutils==0.18.1 +docutils==0.20.1 # via # myst-parser # sphinx # sphinx-rtd-theme -fastapi==0.103.2 +fastapi==0.109.2 # via maggma -filelock==3.12.4 +filelock==3.13.1 # via # tox # virtualenv -flask==3.0.0 +flask==3.0.2 # via mongogrant -fonttools==4.43.1 +fonttools==4.48.1 # via matplotlib future==0.18.3 # via uncertainties @@ -91,9 +83,9 @@ h11==0.14.0 # via uvicorn iapws==1.5.3 # via pyEQL (setup.py) -identify==2.5.30 +identify==2.5.33 # via pre-commit -idna==3.4 +idna==3.6 # via # anyio # requests @@ -103,7 +95,7 @@ iniconfig==2.0.0 # via pytest itsdangerous==2.1.2 # via flask -jinja2==3.1.2 +jinja2==3.1.3 # via # flask # myst-parser @@ -114,28 +106,28 @@ jmespath==1.0.1 # botocore joblib==1.3.2 # via pymatgen -jsonschema==4.19.1 +jsonschema==4.21.1 # via maggma -jsonschema-specifications==2023.7.1 +jsonschema-specifications==2023.12.1 # via jsonschema kiwisolver==1.4.5 # via matplotlib latexcodec==2.0.1 # via pybtex -linkify-it-py==2.0.2 +linkify-it-py==2.0.3 # via myst-parser -maggma==0.57.4 +maggma==0.62.1 # via pyEQL (setup.py) markdown-it-py==3.0.0 # via # mdit-py-plugins # myst-parser # rich -markupsafe==2.1.3 +markupsafe==2.1.5 # via # jinja2 # werkzeug -matplotlib==3.8.0 +matplotlib==3.8.2 # via pymatgen mdit-py-plugins==0.4.0 # via myst-parser @@ -145,7 +137,7 @@ mongogrant==0.3.3 # via maggma mongomock==4.1.2 # via maggma -monty==2023.9.25 +monty==2024.2.2 # via # maggma # pyEQL (setup.py) @@ -154,7 +146,7 @@ mpmath==1.3.0 # via sympy msgpack==1.0.7 # via maggma -mypy==1.6.0 +mypy==1.8.0 # via pyEQL (setup.py) mypy-extensions==1.0.0 # via @@ -162,11 +154,11 @@ mypy-extensions==1.0.0 # mypy myst-parser[linkify]==2.0.0 # via pyEQL (setup.py) -networkx==3.1 +networkx==3.2.1 # via pymatgen nodeenv==1.8.0 # via pre-commit -numpy==1.26.1 +numpy==1.26.4 # via # contourpy # maggma @@ -177,7 +169,7 @@ numpy==1.26.1 # pymatgen # scipy # spglib -orjson==3.9.9 +orjson==3.9.13 # via maggma packaging==23.2 # via @@ -185,61 +177,61 @@ packaging==23.2 # matplotlib # mongomock # plotly - # pyproject-api # pytest # sphinx # tox palettable==3.3.3 # via pymatgen -pandas==2.1.1 +pandas==2.2.0 # via pymatgen -paramiko==3.3.1 +paramiko==3.4.0 # via sshtunnel -pathspec==0.11.2 +pathspec==0.12.1 # via black periodictable==1.6.1 # via phreeqpython phreeqpython==1.5.0 # via pyEQL (setup.py) -pillow==10.1.0 +pillow==10.2.0 # via matplotlib -pint==0.22 +pint==0.23 # via pyEQL (setup.py) -platformdirs==3.11.0 +platformdirs==4.2.0 # via # black - # tox # virtualenv -plotly==5.17.0 +plotly==5.18.0 # via pymatgen -pluggy==1.3.0 +pluggy==1.4.0 # via # pytest # tox -pre-commit==3.5.0 +pre-commit==3.6.0 # via pyEQL (setup.py) +py==1.11.0 + # via tox pybtex==0.24.0 # via pymatgen pycparser==2.21 # via cffi -pydantic==2.4.2 +pydantic==2.6.1 # via # fastapi # maggma # pydantic-settings -pydantic-core==2.10.1 +pydantic-core==2.16.2 # via pydantic -pydantic-settings==2.0.3 +pydantic-settings==2.1.0 # via maggma -pydash==7.0.6 +pydash==7.0.7 # via maggma -pygments==2.16.1 +pygments==2.17.2 # via # rich # sphinx -pymatgen==2023.10.11 +pymatgen==2024.1.27 # via pyEQL (setup.py) -pymongo==4.5.0 +pymongo==4.6.1 # via # maggma # mongogrant @@ -249,9 +241,7 @@ pyparsing==3.1.1 # via # matplotlib # periodictable -pyproject-api==1.6.1 - # via tox -pytest==7.4.2 +pytest==8.0.0 # via # pyEQL (setup.py) # pytest-cov @@ -263,18 +253,18 @@ python-dateutil==2.8.2 # maggma # matplotlib # pandas -python-dotenv==1.0.0 +python-dotenv==1.0.1 # via pydantic-settings -pytz==2023.3.post1 +pytz==2024.1 # via pandas pyyaml==6.0.1 # via # myst-parser # pre-commit # pybtex -pyzmq==25.1.1 +pyzmq==25.1.2 # via maggma -referencing==0.30.2 +referencing==0.33.0 # via # jsonschema # jsonschema-specifications @@ -283,23 +273,23 @@ requests==2.31.0 # mongogrant # pymatgen # sphinx -rich==13.6.0 +rich==13.7.0 # via pyEQL (setup.py) -rpds-py==0.10.6 +rpds-py==0.17.1 # via # jsonschema # referencing -ruamel-yaml==0.17.35 +ruamel-yaml==0.17.40 # via # maggma # pymatgen ruamel-yaml-clib==0.2.8 # via ruamel-yaml -ruff==0.1.0 +ruff==0.2.1 # via pyEQL (setup.py) -s3transfer==0.7.0 +s3transfer==0.10.0 # via boto3 -scipy==1.11.3 +scipy==1.12.0 # via # iapws # phreeqpython @@ -312,42 +302,38 @@ six==1.16.0 # latexcodec # pybtex # python-dateutil + # tox sniffio==1.3.0 # via anyio snowballstemmer==2.2.0 # via sphinx -spglib==2.1.0 +spglib==2.3.0 # via pymatgen sphinx==7.2.6 # via # myst-parser # pyEQL (setup.py) # sphinx-rtd-theme - # sphinxcontrib-applehelp - # sphinxcontrib-devhelp - # sphinxcontrib-htmlhelp # sphinxcontrib-jquery - # sphinxcontrib-qthelp - # sphinxcontrib-serializinghtml -sphinx-rtd-theme==1.3.0 +sphinx-rtd-theme==2.0.0 # via pyEQL (setup.py) -sphinxcontrib-applehelp==1.0.7 +sphinxcontrib-applehelp==1.0.8 # via sphinx -sphinxcontrib-devhelp==1.0.5 +sphinxcontrib-devhelp==1.0.6 # via sphinx -sphinxcontrib-htmlhelp==2.0.4 +sphinxcontrib-htmlhelp==2.0.5 # via sphinx sphinxcontrib-jquery==4.1 # via sphinx-rtd-theme sphinxcontrib-jsmath==1.0.1 # via sphinx -sphinxcontrib-qthelp==1.0.6 +sphinxcontrib-qthelp==1.0.7 # via sphinx -sphinxcontrib-serializinghtml==1.1.9 +sphinxcontrib-serializinghtml==1.1.10 # via sphinx sshtunnel==0.4.0 # via maggma -starlette==0.27.0 +starlette==0.36.3 # via fastapi sympy==1.12 # via pymatgen @@ -355,13 +341,13 @@ tabulate==0.9.0 # via pymatgen tenacity==8.2.3 # via plotly -tox==4.11.3 +tox==3.28.0 # via pyEQL (setup.py) tqdm==4.66.1 # via # maggma # pymatgen -typing-extensions==4.8.0 +typing-extensions==4.9.0 # via # fastapi # mypy @@ -369,7 +355,7 @@ typing-extensions==4.8.0 # pydantic # pydantic-core # pydash -tzdata==2023.3 +tzdata==2023.4 # via pandas uc-micro-py==1.0.2 # via linkify-it-py @@ -379,9 +365,9 @@ urllib3==2.0.7 # via # botocore # requests -uvicorn==0.23.2 +uvicorn==0.27.0.post1 # via maggma -virtualenv==20.24.5 +virtualenv==20.25.0 # via # pre-commit # tox diff --git a/requirements/macos-latest_py3.12.txt b/requirements/macos-latest_py3.12.txt new file mode 100644 index 00000000..f322fd63 --- /dev/null +++ b/requirements/macos-latest_py3.12.txt @@ -0,0 +1,254 @@ +# +# This file is autogenerated by pip-compile with Python 3.12 +# by the following command: +# +# pip-compile --output-file=requirements/macos-latest_py3.12.txt +# +aioitertools==0.11.0 + # via maggma +annotated-types==0.6.0 + # via pydantic +anyio==4.2.0 + # via starlette +attrs==23.2.0 + # via + # jsonschema + # referencing +bcrypt==4.1.2 + # via paramiko +blinker==1.7.0 + # via flask +boto3==1.34.35 + # via maggma +botocore==1.34.35 + # via + # boto3 + # s3transfer +certifi==2024.2.2 + # via requests +cffi==1.16.0 + # via + # cryptography + # pynacl +charset-normalizer==3.3.2 + # via requests +click==8.1.7 + # via + # flask + # mongogrant + # uvicorn +contourpy==1.2.0 + # via matplotlib +cryptography==42.0.2 + # via paramiko +cycler==0.12.1 + # via matplotlib +dnspython==2.5.0 + # via + # maggma + # pymongo +fastapi==0.109.2 + # via maggma +flask==3.0.2 + # via mongogrant +fonttools==4.48.1 + # via matplotlib +future==0.18.3 + # via uncertainties +h11==0.14.0 + # via uvicorn +iapws==1.5.3 + # via pyEQL (setup.py) +idna==3.6 + # via + # anyio + # requests +itsdangerous==2.1.2 + # via flask +jinja2==3.1.3 + # via flask +jmespath==1.0.1 + # via + # boto3 + # botocore +joblib==1.3.2 + # via pymatgen +jsonschema==4.21.1 + # via maggma +jsonschema-specifications==2023.12.1 + # via jsonschema +kiwisolver==1.4.5 + # via matplotlib +latexcodec==2.0.1 + # via pybtex +maggma==0.62.1 + # via pyEQL (setup.py) +markupsafe==2.1.5 + # via + # jinja2 + # werkzeug +matplotlib==3.8.2 + # via pymatgen +mongogrant==0.3.3 + # via maggma +mongomock==4.1.2 + # via maggma +monty==2024.2.2 + # via + # maggma + # pyEQL (setup.py) + # pymatgen +mpmath==1.3.0 + # via sympy +msgpack==1.0.7 + # via maggma +networkx==3.2.1 + # via pymatgen +numpy==1.26.4 + # via + # contourpy + # maggma + # matplotlib + # pandas + # periodictable + # pyEQL (setup.py) + # pymatgen + # scipy + # spglib +orjson==3.9.13 + # via maggma +packaging==23.2 + # via + # matplotlib + # mongomock + # plotly +palettable==3.3.3 + # via pymatgen +pandas==2.2.0 + # via pymatgen +paramiko==3.4.0 + # via sshtunnel +periodictable==1.6.1 + # via phreeqpython +phreeqpython==1.5.0 + # via pyEQL (setup.py) +pillow==10.2.0 + # via matplotlib +pint==0.23 + # via pyEQL (setup.py) +plotly==5.18.0 + # via pymatgen +pybtex==0.24.0 + # via pymatgen +pycparser==2.21 + # via cffi +pydantic==2.6.1 + # via + # fastapi + # maggma + # pydantic-settings +pydantic-core==2.16.2 + # via pydantic +pydantic-settings==2.1.0 + # via maggma +pydash==7.0.7 + # via maggma +pymatgen==2024.1.27 + # via pyEQL (setup.py) +pymongo==4.6.1 + # via + # maggma + # mongogrant +pynacl==1.5.0 + # via paramiko +pyparsing==3.1.1 + # via + # matplotlib + # periodictable +python-dateutil==2.8.2 + # via + # botocore + # maggma + # matplotlib + # pandas +python-dotenv==1.0.1 + # via pydantic-settings +pytz==2024.1 + # via pandas +pyyaml==6.0.1 + # via pybtex +pyzmq==25.1.2 + # via maggma +referencing==0.33.0 + # via + # jsonschema + # jsonschema-specifications +requests==2.31.0 + # via + # mongogrant + # pymatgen +rpds-py==0.17.1 + # via + # jsonschema + # referencing +ruamel-yaml==0.17.40 + # via + # maggma + # pymatgen +ruamel-yaml-clib==0.2.8 + # via ruamel-yaml +s3transfer==0.10.0 + # via boto3 +scipy==1.12.0 + # via + # iapws + # phreeqpython + # pyEQL (setup.py) + # pymatgen +sentinels==1.0.0 + # via mongomock +six==1.16.0 + # via + # latexcodec + # pybtex + # python-dateutil +sniffio==1.3.0 + # via anyio +spglib==2.3.0 + # via pymatgen +sshtunnel==0.4.0 + # via maggma +starlette==0.36.3 + # via fastapi +sympy==1.12 + # via pymatgen +tabulate==0.9.0 + # via pymatgen +tenacity==8.2.3 + # via plotly +tqdm==4.66.1 + # via + # maggma + # pymatgen +typing-extensions==4.9.0 + # via + # fastapi + # pint + # pydantic + # pydantic-core + # pydash +tzdata==2023.4 + # via pandas +uncertainties==3.1.7 + # via pymatgen +urllib3==2.0.7 + # via + # botocore + # requests +uvicorn==0.27.0.post1 + # via maggma +werkzeug==3.0.1 + # via flask + +# The following packages are considered to be unsafe in a requirements file: +# setuptools diff --git a/requirements/macos-latest_py3.12_extras.txt b/requirements/macos-latest_py3.12_extras.txt new file mode 100644 index 00000000..fd47efa9 --- /dev/null +++ b/requirements/macos-latest_py3.12_extras.txt @@ -0,0 +1,378 @@ +# +# This file is autogenerated by pip-compile with Python 3.12 +# by the following command: +# +# pip-compile --all-extras --output-file=requirements/macos-latest_py3.12_extras.txt +# +aioitertools==0.11.0 + # via maggma +alabaster==0.7.16 + # via sphinx +annotated-types==0.6.0 + # via pydantic +anyio==4.2.0 + # via starlette +attrs==23.2.0 + # via + # jsonschema + # referencing +babel==2.14.0 + # via sphinx +bcrypt==4.1.2 + # via paramiko +black==24.1.1 + # via pyEQL (setup.py) +blinker==1.7.0 + # via flask +boto3==1.34.35 + # via maggma +botocore==1.34.35 + # via + # boto3 + # s3transfer +certifi==2024.2.2 + # via requests +cffi==1.16.0 + # via + # cryptography + # pynacl +cfgv==3.4.0 + # via pre-commit +charset-normalizer==3.3.2 + # via requests +click==8.1.7 + # via + # black + # flask + # mongogrant + # uvicorn +contourpy==1.2.0 + # via matplotlib +coverage[toml]==7.4.1 + # via + # coverage + # pytest-cov +cryptography==42.0.2 + # via paramiko +cycler==0.12.1 + # via matplotlib +distlib==0.3.8 + # via virtualenv +dnspython==2.5.0 + # via + # maggma + # pymongo +docutils==0.20.1 + # via + # myst-parser + # sphinx + # sphinx-rtd-theme +fastapi==0.109.2 + # via maggma +filelock==3.13.1 + # via + # tox + # virtualenv +flask==3.0.2 + # via mongogrant +fonttools==4.48.1 + # via matplotlib +future==0.18.3 + # via uncertainties +h11==0.14.0 + # via uvicorn +iapws==1.5.3 + # via pyEQL (setup.py) +identify==2.5.33 + # via pre-commit +idna==3.6 + # via + # anyio + # requests +imagesize==1.4.1 + # via sphinx +iniconfig==2.0.0 + # via pytest +itsdangerous==2.1.2 + # via flask +jinja2==3.1.3 + # via + # flask + # myst-parser + # sphinx +jmespath==1.0.1 + # via + # boto3 + # botocore +joblib==1.3.2 + # via pymatgen +jsonschema==4.21.1 + # via maggma +jsonschema-specifications==2023.12.1 + # via jsonschema +kiwisolver==1.4.5 + # via matplotlib +latexcodec==2.0.1 + # via pybtex +linkify-it-py==2.0.3 + # via myst-parser +maggma==0.62.1 + # via pyEQL (setup.py) +markdown-it-py==3.0.0 + # via + # mdit-py-plugins + # myst-parser + # rich +markupsafe==2.1.5 + # via + # jinja2 + # werkzeug +matplotlib==3.8.2 + # via pymatgen +mdit-py-plugins==0.4.0 + # via myst-parser +mdurl==0.1.2 + # via markdown-it-py +mongogrant==0.3.3 + # via maggma +mongomock==4.1.2 + # via maggma +monty==2024.2.2 + # via + # maggma + # pyEQL (setup.py) + # pymatgen +mpmath==1.3.0 + # via sympy +msgpack==1.0.7 + # via maggma +mypy==1.8.0 + # via pyEQL (setup.py) +mypy-extensions==1.0.0 + # via + # black + # mypy +myst-parser[linkify]==2.0.0 + # via pyEQL (setup.py) +networkx==3.2.1 + # via pymatgen +nodeenv==1.8.0 + # via pre-commit +numpy==1.26.4 + # via + # contourpy + # maggma + # matplotlib + # pandas + # periodictable + # pyEQL (setup.py) + # pymatgen + # scipy + # spglib +orjson==3.9.13 + # via maggma +packaging==23.2 + # via + # black + # matplotlib + # mongomock + # plotly + # pytest + # sphinx + # tox +palettable==3.3.3 + # via pymatgen +pandas==2.2.0 + # via pymatgen +paramiko==3.4.0 + # via sshtunnel +pathspec==0.12.1 + # via black +periodictable==1.6.1 + # via phreeqpython +phreeqpython==1.5.0 + # via pyEQL (setup.py) +pillow==10.2.0 + # via matplotlib +pint==0.23 + # via pyEQL (setup.py) +platformdirs==4.2.0 + # via + # black + # virtualenv +plotly==5.18.0 + # via pymatgen +pluggy==1.4.0 + # via + # pytest + # tox +pre-commit==3.6.0 + # via pyEQL (setup.py) +py==1.11.0 + # via tox +pybtex==0.24.0 + # via pymatgen +pycparser==2.21 + # via cffi +pydantic==2.6.1 + # via + # fastapi + # maggma + # pydantic-settings +pydantic-core==2.16.2 + # via pydantic +pydantic-settings==2.1.0 + # via maggma +pydash==7.0.7 + # via maggma +pygments==2.17.2 + # via + # rich + # sphinx +pymatgen==2024.1.27 + # via pyEQL (setup.py) +pymongo==4.6.1 + # via + # maggma + # mongogrant +pynacl==1.5.0 + # via paramiko +pyparsing==3.1.1 + # via + # matplotlib + # periodictable +pytest==8.0.0 + # via + # pyEQL (setup.py) + # pytest-cov +pytest-cov==4.1.0 + # via pyEQL (setup.py) +python-dateutil==2.8.2 + # via + # botocore + # maggma + # matplotlib + # pandas +python-dotenv==1.0.1 + # via pydantic-settings +pytz==2024.1 + # via pandas +pyyaml==6.0.1 + # via + # myst-parser + # pre-commit + # pybtex +pyzmq==25.1.2 + # via maggma +referencing==0.33.0 + # via + # jsonschema + # jsonschema-specifications +requests==2.31.0 + # via + # mongogrant + # pymatgen + # sphinx +rich==13.7.0 + # via pyEQL (setup.py) +rpds-py==0.17.1 + # via + # jsonschema + # referencing +ruamel-yaml==0.17.40 + # via + # maggma + # pymatgen +ruamel-yaml-clib==0.2.8 + # via ruamel-yaml +ruff==0.2.1 + # via pyEQL (setup.py) +s3transfer==0.10.0 + # via boto3 +scipy==1.12.0 + # via + # iapws + # phreeqpython + # pyEQL (setup.py) + # pymatgen +sentinels==1.0.0 + # via mongomock +six==1.16.0 + # via + # latexcodec + # pybtex + # python-dateutil + # tox +sniffio==1.3.0 + # via anyio +snowballstemmer==2.2.0 + # via sphinx +spglib==2.3.0 + # via pymatgen +sphinx==7.2.6 + # via + # myst-parser + # pyEQL (setup.py) + # sphinx-rtd-theme + # sphinxcontrib-jquery +sphinx-rtd-theme==2.0.0 + # via pyEQL (setup.py) +sphinxcontrib-applehelp==1.0.8 + # via sphinx +sphinxcontrib-devhelp==1.0.6 + # via sphinx +sphinxcontrib-htmlhelp==2.0.5 + # via sphinx +sphinxcontrib-jquery==4.1 + # via sphinx-rtd-theme +sphinxcontrib-jsmath==1.0.1 + # via sphinx +sphinxcontrib-qthelp==1.0.7 + # via sphinx +sphinxcontrib-serializinghtml==1.1.10 + # via sphinx +sshtunnel==0.4.0 + # via maggma +starlette==0.36.3 + # via fastapi +sympy==1.12 + # via pymatgen +tabulate==0.9.0 + # via pymatgen +tenacity==8.2.3 + # via plotly +tox==3.28.0 + # via pyEQL (setup.py) +tqdm==4.66.1 + # via + # maggma + # pymatgen +typing-extensions==4.9.0 + # via + # fastapi + # mypy + # pint + # pydantic + # pydantic-core + # pydash +tzdata==2023.4 + # via pandas +uc-micro-py==1.0.2 + # via linkify-it-py +uncertainties==3.1.7 + # via pymatgen +urllib3==2.0.7 + # via + # botocore + # requests +uvicorn==0.27.0.post1 + # via maggma +virtualenv==20.25.0 + # via + # pre-commit + # tox +werkzeug==3.0.1 + # via flask + +# The following packages are considered to be unsafe in a requirements file: +# setuptools diff --git a/requirements/macos-latest_py3.9.txt b/requirements/macos-latest_py3.9.txt index a8f6cda7..8497980b 100644 --- a/requirements/macos-latest_py3.9.txt +++ b/requirements/macos-latest_py3.9.txt @@ -8,54 +8,52 @@ aioitertools==0.11.0 # via maggma annotated-types==0.6.0 # via pydantic -anyio==3.7.1 - # via - # fastapi - # starlette -attrs==23.1.0 +anyio==4.2.0 + # via starlette +attrs==23.2.0 # via # jsonschema # referencing -bcrypt==4.0.1 +bcrypt==4.1.2 # via paramiko -blinker==1.6.3 +blinker==1.7.0 # via flask -boto3==1.28.65 +boto3==1.34.35 # via maggma -botocore==1.31.65 +botocore==1.34.35 # via # boto3 # s3transfer -certifi==2023.7.22 +certifi==2024.2.2 # via requests cffi==1.16.0 # via # cryptography # pynacl -charset-normalizer==3.3.0 +charset-normalizer==3.3.2 # via requests click==8.1.7 # via # flask # mongogrant # uvicorn -contourpy==1.1.1 +contourpy==1.2.0 # via matplotlib -cryptography==41.0.4 +cryptography==42.0.2 # via paramiko cycler==0.12.1 # via matplotlib -dnspython==2.4.2 +dnspython==2.5.0 # via # maggma # pymongo -exceptiongroup==1.1.3 +exceptiongroup==1.2.0 # via anyio -fastapi==0.103.2 +fastapi==0.109.2 # via maggma -flask==3.0.0 +flask==3.0.2 # via mongogrant -fonttools==4.43.1 +fonttools==4.48.1 # via matplotlib future==0.18.3 # via uncertainties @@ -63,17 +61,17 @@ h11==0.14.0 # via uvicorn iapws==1.5.3 # via pyEQL (setup.py) -idna==3.4 +idna==3.6 # via # anyio # requests -importlib-metadata==6.8.0 +importlib-metadata==7.0.1 # via flask -importlib-resources==6.1.0 +importlib-resources==6.1.1 # via matplotlib itsdangerous==2.1.2 # via flask -jinja2==3.1.2 +jinja2==3.1.3 # via flask jmespath==1.0.1 # via @@ -81,27 +79,27 @@ jmespath==1.0.1 # botocore joblib==1.3.2 # via pymatgen -jsonschema==4.19.1 +jsonschema==4.21.1 # via maggma -jsonschema-specifications==2023.7.1 +jsonschema-specifications==2023.12.1 # via jsonschema kiwisolver==1.4.5 # via matplotlib latexcodec==2.0.1 # via pybtex -maggma==0.57.4 +maggma==0.62.1 # via pyEQL (setup.py) -markupsafe==2.1.3 +markupsafe==2.1.5 # via # jinja2 # werkzeug -matplotlib==3.8.0 +matplotlib==3.8.2 # via pymatgen mongogrant==0.3.3 # via maggma mongomock==4.1.2 # via maggma -monty==2023.9.25 +monty==2024.2.2 # via # maggma # pyEQL (setup.py) @@ -110,9 +108,9 @@ mpmath==1.3.0 # via sympy msgpack==1.0.7 # via maggma -networkx==3.1 +networkx==3.2.1 # via pymatgen -numpy==1.26.1 +numpy==1.26.4 # via # contourpy # maggma @@ -123,7 +121,7 @@ numpy==1.26.1 # pymatgen # scipy # spglib -orjson==3.9.9 +orjson==3.9.13 # via maggma packaging==23.2 # via @@ -132,38 +130,38 @@ packaging==23.2 # plotly palettable==3.3.3 # via pymatgen -pandas==2.1.1 +pandas==2.2.0 # via pymatgen -paramiko==3.3.1 +paramiko==3.4.0 # via sshtunnel periodictable==1.6.1 # via phreeqpython phreeqpython==1.5.0 # via pyEQL (setup.py) -pillow==10.1.0 +pillow==10.2.0 # via matplotlib -pint==0.22 +pint==0.23 # via pyEQL (setup.py) -plotly==5.17.0 +plotly==5.18.0 # via pymatgen pybtex==0.24.0 # via pymatgen pycparser==2.21 # via cffi -pydantic==2.4.2 +pydantic==2.6.1 # via # fastapi # maggma # pydantic-settings -pydantic-core==2.10.1 +pydantic-core==2.16.2 # via pydantic -pydantic-settings==2.0.3 +pydantic-settings==2.1.0 # via maggma -pydash==7.0.6 +pydash==7.0.7 # via maggma -pymatgen==2023.10.11 +pymatgen==2024.1.27 # via pyEQL (setup.py) -pymongo==4.5.0 +pymongo==4.6.1 # via # maggma # mongogrant @@ -179,15 +177,15 @@ python-dateutil==2.8.2 # maggma # matplotlib # pandas -python-dotenv==1.0.0 +python-dotenv==1.0.1 # via pydantic-settings -pytz==2023.3.post1 +pytz==2024.1 # via pandas pyyaml==6.0.1 # via pybtex -pyzmq==25.1.1 +pyzmq==25.1.2 # via maggma -referencing==0.30.2 +referencing==0.33.0 # via # jsonschema # jsonschema-specifications @@ -195,19 +193,19 @@ requests==2.31.0 # via # mongogrant # pymatgen -rpds-py==0.10.6 +rpds-py==0.17.1 # via # jsonschema # referencing -ruamel-yaml==0.17.35 +ruamel-yaml==0.17.40 # via # maggma # pymatgen ruamel-yaml-clib==0.2.8 # via ruamel-yaml -s3transfer==0.7.0 +s3transfer==0.10.0 # via boto3 -scipy==1.11.3 +scipy==1.12.0 # via # iapws # phreeqpython @@ -222,11 +220,11 @@ six==1.16.0 # python-dateutil sniffio==1.3.0 # via anyio -spglib==2.1.0 +spglib==2.3.0 # via pymatgen sshtunnel==0.4.0 # via maggma -starlette==0.27.0 +starlette==0.36.3 # via fastapi sympy==1.12 # via pymatgen @@ -238,9 +236,10 @@ tqdm==4.66.1 # via # maggma # pymatgen -typing-extensions==4.8.0 +typing-extensions==4.9.0 # via # aioitertools + # anyio # fastapi # pint # pydantic @@ -248,7 +247,7 @@ typing-extensions==4.8.0 # pydash # starlette # uvicorn -tzdata==2023.3 +tzdata==2023.4 # via pandas uncertainties==3.1.7 # via pymatgen @@ -256,7 +255,7 @@ urllib3==1.26.18 # via # botocore # requests -uvicorn==0.23.2 +uvicorn==0.27.0.post1 # via maggma werkzeug==3.0.1 # via flask diff --git a/requirements/macos-latest_py3.9_extras.txt b/requirements/macos-latest_py3.9_extras.txt index c3ddcebf..f19eaff2 100644 --- a/requirements/macos-latest_py3.9_extras.txt +++ b/requirements/macos-latest_py3.9_extras.txt @@ -6,35 +6,31 @@ # aioitertools==0.11.0 # via maggma -alabaster==0.7.13 +alabaster==0.7.16 # via sphinx annotated-types==0.6.0 # via pydantic -anyio==3.7.1 - # via - # fastapi - # starlette -attrs==23.1.0 +anyio==4.2.0 + # via starlette +attrs==23.2.0 # via # jsonschema # referencing -babel==2.13.0 +babel==2.14.0 # via sphinx -bcrypt==4.0.1 +bcrypt==4.1.2 # via paramiko -black==23.10.0 +black==24.1.1 # via pyEQL (setup.py) -blinker==1.6.3 +blinker==1.7.0 # via flask -boto3==1.28.65 +boto3==1.34.35 # via maggma -botocore==1.31.65 +botocore==1.34.35 # via # boto3 # s3transfer -cachetools==5.3.1 - # via tox -certifi==2023.7.22 +certifi==2024.2.2 # via requests cffi==1.16.0 # via @@ -42,9 +38,7 @@ cffi==1.16.0 # pynacl cfgv==3.4.0 # via pre-commit -chardet==5.2.0 - # via tox -charset-normalizer==3.3.0 +charset-normalizer==3.3.2 # via requests click==8.1.7 # via @@ -52,42 +46,40 @@ click==8.1.7 # flask # mongogrant # uvicorn -colorama==0.4.6 - # via tox -contourpy==1.1.1 +contourpy==1.2.0 # via matplotlib -coverage[toml]==7.3.2 +coverage[toml]==7.4.1 # via # coverage # pytest-cov -cryptography==41.0.4 +cryptography==42.0.2 # via paramiko cycler==0.12.1 # via matplotlib -distlib==0.3.7 +distlib==0.3.8 # via virtualenv -dnspython==2.4.2 +dnspython==2.5.0 # via # maggma # pymongo -docutils==0.18.1 +docutils==0.20.1 # via # myst-parser # sphinx # sphinx-rtd-theme -exceptiongroup==1.1.3 +exceptiongroup==1.2.0 # via # anyio # pytest -fastapi==0.103.2 +fastapi==0.109.2 # via maggma -filelock==3.12.4 +filelock==3.13.1 # via # tox # virtualenv -flask==3.0.0 +flask==3.0.2 # via mongogrant -fonttools==4.43.1 +fonttools==4.48.1 # via matplotlib future==0.18.3 # via uncertainties @@ -95,25 +87,25 @@ h11==0.14.0 # via uvicorn iapws==1.5.3 # via pyEQL (setup.py) -identify==2.5.30 +identify==2.5.33 # via pre-commit -idna==3.4 +idna==3.6 # via # anyio # requests imagesize==1.4.1 # via sphinx -importlib-metadata==6.8.0 +importlib-metadata==7.0.1 # via # flask # sphinx -importlib-resources==6.1.0 +importlib-resources==6.1.1 # via matplotlib iniconfig==2.0.0 # via pytest itsdangerous==2.1.2 # via flask -jinja2==3.1.2 +jinja2==3.1.3 # via # flask # myst-parser @@ -124,28 +116,28 @@ jmespath==1.0.1 # botocore joblib==1.3.2 # via pymatgen -jsonschema==4.19.1 +jsonschema==4.21.1 # via maggma -jsonschema-specifications==2023.7.1 +jsonschema-specifications==2023.12.1 # via jsonschema kiwisolver==1.4.5 # via matplotlib latexcodec==2.0.1 # via pybtex -linkify-it-py==2.0.2 +linkify-it-py==2.0.3 # via myst-parser -maggma==0.57.4 +maggma==0.62.1 # via pyEQL (setup.py) markdown-it-py==3.0.0 # via # mdit-py-plugins # myst-parser # rich -markupsafe==2.1.3 +markupsafe==2.1.5 # via # jinja2 # werkzeug -matplotlib==3.8.0 +matplotlib==3.8.2 # via pymatgen mdit-py-plugins==0.4.0 # via myst-parser @@ -155,7 +147,7 @@ mongogrant==0.3.3 # via maggma mongomock==4.1.2 # via maggma -monty==2023.9.25 +monty==2024.2.2 # via # maggma # pyEQL (setup.py) @@ -164,7 +156,7 @@ mpmath==1.3.0 # via sympy msgpack==1.0.7 # via maggma -mypy==1.6.0 +mypy==1.8.0 # via pyEQL (setup.py) mypy-extensions==1.0.0 # via @@ -172,11 +164,11 @@ mypy-extensions==1.0.0 # mypy myst-parser[linkify]==2.0.0 # via pyEQL (setup.py) -networkx==3.1 +networkx==3.2.1 # via pymatgen nodeenv==1.8.0 # via pre-commit -numpy==1.26.1 +numpy==1.26.4 # via # contourpy # maggma @@ -187,7 +179,7 @@ numpy==1.26.1 # pymatgen # scipy # spglib -orjson==3.9.9 +orjson==3.9.13 # via maggma packaging==23.2 # via @@ -195,61 +187,61 @@ packaging==23.2 # matplotlib # mongomock # plotly - # pyproject-api # pytest # sphinx # tox palettable==3.3.3 # via pymatgen -pandas==2.1.1 +pandas==2.2.0 # via pymatgen -paramiko==3.3.1 +paramiko==3.4.0 # via sshtunnel -pathspec==0.11.2 +pathspec==0.12.1 # via black periodictable==1.6.1 # via phreeqpython phreeqpython==1.5.0 # via pyEQL (setup.py) -pillow==10.1.0 +pillow==10.2.0 # via matplotlib -pint==0.22 +pint==0.23 # via pyEQL (setup.py) -platformdirs==3.11.0 +platformdirs==4.2.0 # via # black - # tox # virtualenv -plotly==5.17.0 +plotly==5.18.0 # via pymatgen -pluggy==1.3.0 +pluggy==1.4.0 # via # pytest # tox -pre-commit==3.5.0 +pre-commit==3.6.0 # via pyEQL (setup.py) +py==1.11.0 + # via tox pybtex==0.24.0 # via pymatgen pycparser==2.21 # via cffi -pydantic==2.4.2 +pydantic==2.6.1 # via # fastapi # maggma # pydantic-settings -pydantic-core==2.10.1 +pydantic-core==2.16.2 # via pydantic -pydantic-settings==2.0.3 +pydantic-settings==2.1.0 # via maggma -pydash==7.0.6 +pydash==7.0.7 # via maggma -pygments==2.16.1 +pygments==2.17.2 # via # rich # sphinx -pymatgen==2023.10.11 +pymatgen==2024.1.27 # via pyEQL (setup.py) -pymongo==4.5.0 +pymongo==4.6.1 # via # maggma # mongogrant @@ -259,9 +251,7 @@ pyparsing==3.1.1 # via # matplotlib # periodictable -pyproject-api==1.6.1 - # via tox -pytest==7.4.2 +pytest==8.0.0 # via # pyEQL (setup.py) # pytest-cov @@ -273,18 +263,18 @@ python-dateutil==2.8.2 # maggma # matplotlib # pandas -python-dotenv==1.0.0 +python-dotenv==1.0.1 # via pydantic-settings -pytz==2023.3.post1 +pytz==2024.1 # via pandas pyyaml==6.0.1 # via # myst-parser # pre-commit # pybtex -pyzmq==25.1.1 +pyzmq==25.1.2 # via maggma -referencing==0.30.2 +referencing==0.33.0 # via # jsonschema # jsonschema-specifications @@ -293,23 +283,23 @@ requests==2.31.0 # mongogrant # pymatgen # sphinx -rich==13.6.0 +rich==13.7.0 # via pyEQL (setup.py) -rpds-py==0.10.6 +rpds-py==0.17.1 # via # jsonschema # referencing -ruamel-yaml==0.17.35 +ruamel-yaml==0.17.40 # via # maggma # pymatgen ruamel-yaml-clib==0.2.8 # via ruamel-yaml -ruff==0.1.0 +ruff==0.2.1 # via pyEQL (setup.py) -s3transfer==0.7.0 +s3transfer==0.10.0 # via boto3 -scipy==1.11.3 +scipy==1.12.0 # via # iapws # phreeqpython @@ -322,42 +312,38 @@ six==1.16.0 # latexcodec # pybtex # python-dateutil + # tox sniffio==1.3.0 # via anyio snowballstemmer==2.2.0 # via sphinx -spglib==2.1.0 +spglib==2.3.0 # via pymatgen sphinx==7.2.6 # via # myst-parser # pyEQL (setup.py) # sphinx-rtd-theme - # sphinxcontrib-applehelp - # sphinxcontrib-devhelp - # sphinxcontrib-htmlhelp # sphinxcontrib-jquery - # sphinxcontrib-qthelp - # sphinxcontrib-serializinghtml -sphinx-rtd-theme==1.3.0 +sphinx-rtd-theme==2.0.0 # via pyEQL (setup.py) -sphinxcontrib-applehelp==1.0.7 +sphinxcontrib-applehelp==1.0.8 # via sphinx -sphinxcontrib-devhelp==1.0.5 +sphinxcontrib-devhelp==1.0.6 # via sphinx -sphinxcontrib-htmlhelp==2.0.4 +sphinxcontrib-htmlhelp==2.0.5 # via sphinx sphinxcontrib-jquery==4.1 # via sphinx-rtd-theme sphinxcontrib-jsmath==1.0.1 # via sphinx -sphinxcontrib-qthelp==1.0.6 +sphinxcontrib-qthelp==1.0.7 # via sphinx -sphinxcontrib-serializinghtml==1.1.9 +sphinxcontrib-serializinghtml==1.1.10 # via sphinx sshtunnel==0.4.0 # via maggma -starlette==0.27.0 +starlette==0.36.3 # via fastapi sympy==1.12 # via pymatgen @@ -370,18 +356,18 @@ tomli==2.0.1 # black # coverage # mypy - # pyproject-api # pytest # tox -tox==4.11.3 +tox==3.28.0 # via pyEQL (setup.py) tqdm==4.66.1 # via # maggma # pymatgen -typing-extensions==4.8.0 +typing-extensions==4.9.0 # via # aioitertools + # anyio # black # fastapi # mypy @@ -391,7 +377,7 @@ typing-extensions==4.8.0 # pydash # starlette # uvicorn -tzdata==2023.3 +tzdata==2023.4 # via pandas uc-micro-py==1.0.2 # via linkify-it-py @@ -401,9 +387,9 @@ urllib3==1.26.18 # via # botocore # requests -uvicorn==0.23.2 +uvicorn==0.27.0.post1 # via maggma -virtualenv==20.24.5 +virtualenv==20.25.0 # via # pre-commit # tox diff --git a/requirements/ubuntu-latest_py3.10.txt b/requirements/ubuntu-latest_py3.10.txt index 33e21a32..8ffe26ca 100644 --- a/requirements/ubuntu-latest_py3.10.txt +++ b/requirements/ubuntu-latest_py3.10.txt @@ -8,54 +8,52 @@ aioitertools==0.11.0 # via maggma annotated-types==0.6.0 # via pydantic -anyio==3.7.1 - # via - # fastapi - # starlette -attrs==23.1.0 +anyio==4.2.0 + # via starlette +attrs==23.2.0 # via # jsonschema # referencing -bcrypt==4.0.1 +bcrypt==4.1.2 # via paramiko -blinker==1.6.3 +blinker==1.7.0 # via flask -boto3==1.28.65 +boto3==1.34.35 # via maggma -botocore==1.31.65 +botocore==1.34.35 # via # boto3 # s3transfer -certifi==2023.7.22 +certifi==2024.2.2 # via requests cffi==1.16.0 # via # cryptography # pynacl -charset-normalizer==3.3.0 +charset-normalizer==3.3.2 # via requests click==8.1.7 # via # flask # mongogrant # uvicorn -contourpy==1.1.1 +contourpy==1.2.0 # via matplotlib -cryptography==41.0.4 +cryptography==42.0.2 # via paramiko cycler==0.12.1 # via matplotlib -dnspython==2.4.2 +dnspython==2.5.0 # via # maggma # pymongo -exceptiongroup==1.1.3 +exceptiongroup==1.2.0 # via anyio -fastapi==0.103.2 +fastapi==0.109.2 # via maggma -flask==3.0.0 +flask==3.0.2 # via mongogrant -fonttools==4.43.1 +fonttools==4.48.1 # via matplotlib future==0.18.3 # via uncertainties @@ -63,13 +61,13 @@ h11==0.14.0 # via uvicorn iapws==1.5.3 # via pyEQL (setup.py) -idna==3.4 +idna==3.6 # via # anyio # requests itsdangerous==2.1.2 # via flask -jinja2==3.1.2 +jinja2==3.1.3 # via flask jmespath==1.0.1 # via @@ -77,27 +75,27 @@ jmespath==1.0.1 # botocore joblib==1.3.2 # via pymatgen -jsonschema==4.19.1 +jsonschema==4.21.1 # via maggma -jsonschema-specifications==2023.7.1 +jsonschema-specifications==2023.12.1 # via jsonschema kiwisolver==1.4.5 # via matplotlib latexcodec==2.0.1 # via pybtex -maggma==0.57.4 +maggma==0.62.1 # via pyEQL (setup.py) -markupsafe==2.1.3 +markupsafe==2.1.5 # via # jinja2 # werkzeug -matplotlib==3.8.0 +matplotlib==3.8.2 # via pymatgen mongogrant==0.3.3 # via maggma mongomock==4.1.2 # via maggma -monty==2023.9.25 +monty==2024.2.2 # via # maggma # pyEQL (setup.py) @@ -106,9 +104,9 @@ mpmath==1.3.0 # via sympy msgpack==1.0.7 # via maggma -networkx==3.1 +networkx==3.2.1 # via pymatgen -numpy==1.26.1 +numpy==1.26.4 # via # contourpy # maggma @@ -119,7 +117,7 @@ numpy==1.26.1 # pymatgen # scipy # spglib -orjson==3.9.9 +orjson==3.9.13 # via maggma packaging==23.2 # via @@ -128,38 +126,38 @@ packaging==23.2 # plotly palettable==3.3.3 # via pymatgen -pandas==2.1.1 +pandas==2.2.0 # via pymatgen -paramiko==3.3.1 +paramiko==3.4.0 # via sshtunnel periodictable==1.6.1 # via phreeqpython phreeqpython==1.5.0 # via pyEQL (setup.py) -pillow==10.1.0 +pillow==10.2.0 # via matplotlib -pint==0.22 +pint==0.23 # via pyEQL (setup.py) -plotly==5.17.0 +plotly==5.18.0 # via pymatgen pybtex==0.24.0 # via pymatgen pycparser==2.21 # via cffi -pydantic==2.4.2 +pydantic==2.6.1 # via # fastapi # maggma # pydantic-settings -pydantic-core==2.10.1 +pydantic-core==2.16.2 # via pydantic -pydantic-settings==2.0.3 +pydantic-settings==2.1.0 # via maggma -pydash==7.0.6 +pydash==7.0.7 # via maggma -pymatgen==2023.10.11 +pymatgen==2024.1.27 # via pyEQL (setup.py) -pymongo==4.5.0 +pymongo==4.6.1 # via # maggma # mongogrant @@ -175,15 +173,15 @@ python-dateutil==2.8.2 # maggma # matplotlib # pandas -python-dotenv==1.0.0 +python-dotenv==1.0.1 # via pydantic-settings -pytz==2023.3.post1 +pytz==2024.1 # via pandas pyyaml==6.0.1 # via pybtex -pyzmq==25.1.1 +pyzmq==25.1.2 # via maggma -referencing==0.30.2 +referencing==0.33.0 # via # jsonschema # jsonschema-specifications @@ -191,19 +189,19 @@ requests==2.31.0 # via # mongogrant # pymatgen -rpds-py==0.10.6 +rpds-py==0.17.1 # via # jsonschema # referencing -ruamel-yaml==0.17.35 +ruamel-yaml==0.17.40 # via # maggma # pymatgen ruamel-yaml-clib==0.2.8 # via ruamel-yaml -s3transfer==0.7.0 +s3transfer==0.10.0 # via boto3 -scipy==1.11.3 +scipy==1.12.0 # via # iapws # phreeqpython @@ -218,11 +216,11 @@ six==1.16.0 # python-dateutil sniffio==1.3.0 # via anyio -spglib==2.1.0 +spglib==2.3.0 # via pymatgen sshtunnel==0.4.0 # via maggma -starlette==0.27.0 +starlette==0.36.3 # via fastapi sympy==1.12 # via pymatgen @@ -234,15 +232,16 @@ tqdm==4.66.1 # via # maggma # pymatgen -typing-extensions==4.8.0 +typing-extensions==4.9.0 # via + # anyio # fastapi # pint # pydantic # pydantic-core # pydash # uvicorn -tzdata==2023.3 +tzdata==2023.4 # via pandas uncertainties==3.1.7 # via pymatgen @@ -250,7 +249,7 @@ urllib3==2.0.7 # via # botocore # requests -uvicorn==0.23.2 +uvicorn==0.27.0.post1 # via maggma werkzeug==3.0.1 # via flask diff --git a/requirements/ubuntu-latest_py3.10_extras.txt b/requirements/ubuntu-latest_py3.10_extras.txt index c66eb9dd..078d8fdf 100644 --- a/requirements/ubuntu-latest_py3.10_extras.txt +++ b/requirements/ubuntu-latest_py3.10_extras.txt @@ -6,35 +6,31 @@ # aioitertools==0.11.0 # via maggma -alabaster==0.7.13 +alabaster==0.7.16 # via sphinx annotated-types==0.6.0 # via pydantic -anyio==3.7.1 - # via - # fastapi - # starlette -attrs==23.1.0 +anyio==4.2.0 + # via starlette +attrs==23.2.0 # via # jsonschema # referencing -babel==2.13.0 +babel==2.14.0 # via sphinx -bcrypt==4.0.1 +bcrypt==4.1.2 # via paramiko -black==23.10.0 +black==24.1.1 # via pyEQL (setup.py) -blinker==1.6.3 +blinker==1.7.0 # via flask -boto3==1.28.65 +boto3==1.34.35 # via maggma -botocore==1.31.65 +botocore==1.34.35 # via # boto3 # s3transfer -cachetools==5.3.1 - # via tox -certifi==2023.7.22 +certifi==2024.2.2 # via requests cffi==1.16.0 # via @@ -42,9 +38,7 @@ cffi==1.16.0 # pynacl cfgv==3.4.0 # via pre-commit -chardet==5.2.0 - # via tox -charset-normalizer==3.3.0 +charset-normalizer==3.3.2 # via requests click==8.1.7 # via @@ -52,42 +46,40 @@ click==8.1.7 # flask # mongogrant # uvicorn -colorama==0.4.6 - # via tox -contourpy==1.1.1 +contourpy==1.2.0 # via matplotlib -coverage[toml]==7.3.2 +coverage[toml]==7.4.1 # via # coverage # pytest-cov -cryptography==41.0.4 +cryptography==42.0.2 # via paramiko cycler==0.12.1 # via matplotlib -distlib==0.3.7 +distlib==0.3.8 # via virtualenv -dnspython==2.4.2 +dnspython==2.5.0 # via # maggma # pymongo -docutils==0.18.1 +docutils==0.20.1 # via # myst-parser # sphinx # sphinx-rtd-theme -exceptiongroup==1.1.3 +exceptiongroup==1.2.0 # via # anyio # pytest -fastapi==0.103.2 +fastapi==0.109.2 # via maggma -filelock==3.12.4 +filelock==3.13.1 # via # tox # virtualenv -flask==3.0.0 +flask==3.0.2 # via mongogrant -fonttools==4.43.1 +fonttools==4.48.1 # via matplotlib future==0.18.3 # via uncertainties @@ -95,9 +87,9 @@ h11==0.14.0 # via uvicorn iapws==1.5.3 # via pyEQL (setup.py) -identify==2.5.30 +identify==2.5.33 # via pre-commit -idna==3.4 +idna==3.6 # via # anyio # requests @@ -107,7 +99,7 @@ iniconfig==2.0.0 # via pytest itsdangerous==2.1.2 # via flask -jinja2==3.1.2 +jinja2==3.1.3 # via # flask # myst-parser @@ -118,28 +110,28 @@ jmespath==1.0.1 # botocore joblib==1.3.2 # via pymatgen -jsonschema==4.19.1 +jsonschema==4.21.1 # via maggma -jsonschema-specifications==2023.7.1 +jsonschema-specifications==2023.12.1 # via jsonschema kiwisolver==1.4.5 # via matplotlib latexcodec==2.0.1 # via pybtex -linkify-it-py==2.0.2 +linkify-it-py==2.0.3 # via myst-parser -maggma==0.57.4 +maggma==0.62.1 # via pyEQL (setup.py) markdown-it-py==3.0.0 # via # mdit-py-plugins # myst-parser # rich -markupsafe==2.1.3 +markupsafe==2.1.5 # via # jinja2 # werkzeug -matplotlib==3.8.0 +matplotlib==3.8.2 # via pymatgen mdit-py-plugins==0.4.0 # via myst-parser @@ -149,7 +141,7 @@ mongogrant==0.3.3 # via maggma mongomock==4.1.2 # via maggma -monty==2023.9.25 +monty==2024.2.2 # via # maggma # pyEQL (setup.py) @@ -158,7 +150,7 @@ mpmath==1.3.0 # via sympy msgpack==1.0.7 # via maggma -mypy==1.6.0 +mypy==1.8.0 # via pyEQL (setup.py) mypy-extensions==1.0.0 # via @@ -166,11 +158,11 @@ mypy-extensions==1.0.0 # mypy myst-parser[linkify]==2.0.0 # via pyEQL (setup.py) -networkx==3.1 +networkx==3.2.1 # via pymatgen nodeenv==1.8.0 # via pre-commit -numpy==1.26.1 +numpy==1.26.4 # via # contourpy # maggma @@ -181,7 +173,7 @@ numpy==1.26.1 # pymatgen # scipy # spglib -orjson==3.9.9 +orjson==3.9.13 # via maggma packaging==23.2 # via @@ -189,61 +181,61 @@ packaging==23.2 # matplotlib # mongomock # plotly - # pyproject-api # pytest # sphinx # tox palettable==3.3.3 # via pymatgen -pandas==2.1.1 +pandas==2.2.0 # via pymatgen -paramiko==3.3.1 +paramiko==3.4.0 # via sshtunnel -pathspec==0.11.2 +pathspec==0.12.1 # via black periodictable==1.6.1 # via phreeqpython phreeqpython==1.5.0 # via pyEQL (setup.py) -pillow==10.1.0 +pillow==10.2.0 # via matplotlib -pint==0.22 +pint==0.23 # via pyEQL (setup.py) -platformdirs==3.11.0 +platformdirs==4.2.0 # via # black - # tox # virtualenv -plotly==5.17.0 +plotly==5.18.0 # via pymatgen -pluggy==1.3.0 +pluggy==1.4.0 # via # pytest # tox -pre-commit==3.5.0 +pre-commit==3.6.0 # via pyEQL (setup.py) +py==1.11.0 + # via tox pybtex==0.24.0 # via pymatgen pycparser==2.21 # via cffi -pydantic==2.4.2 +pydantic==2.6.1 # via # fastapi # maggma # pydantic-settings -pydantic-core==2.10.1 +pydantic-core==2.16.2 # via pydantic -pydantic-settings==2.0.3 +pydantic-settings==2.1.0 # via maggma -pydash==7.0.6 +pydash==7.0.7 # via maggma -pygments==2.16.1 +pygments==2.17.2 # via # rich # sphinx -pymatgen==2023.10.11 +pymatgen==2024.1.27 # via pyEQL (setup.py) -pymongo==4.5.0 +pymongo==4.6.1 # via # maggma # mongogrant @@ -253,9 +245,7 @@ pyparsing==3.1.1 # via # matplotlib # periodictable -pyproject-api==1.6.1 - # via tox -pytest==7.4.2 +pytest==8.0.0 # via # pyEQL (setup.py) # pytest-cov @@ -267,18 +257,18 @@ python-dateutil==2.8.2 # maggma # matplotlib # pandas -python-dotenv==1.0.0 +python-dotenv==1.0.1 # via pydantic-settings -pytz==2023.3.post1 +pytz==2024.1 # via pandas pyyaml==6.0.1 # via # myst-parser # pre-commit # pybtex -pyzmq==25.1.1 +pyzmq==25.1.2 # via maggma -referencing==0.30.2 +referencing==0.33.0 # via # jsonschema # jsonschema-specifications @@ -287,23 +277,23 @@ requests==2.31.0 # mongogrant # pymatgen # sphinx -rich==13.6.0 +rich==13.7.0 # via pyEQL (setup.py) -rpds-py==0.10.6 +rpds-py==0.17.1 # via # jsonschema # referencing -ruamel-yaml==0.17.35 +ruamel-yaml==0.17.40 # via # maggma # pymatgen ruamel-yaml-clib==0.2.8 # via ruamel-yaml -ruff==0.1.0 +ruff==0.2.1 # via pyEQL (setup.py) -s3transfer==0.7.0 +s3transfer==0.10.0 # via boto3 -scipy==1.11.3 +scipy==1.12.0 # via # iapws # phreeqpython @@ -316,42 +306,38 @@ six==1.16.0 # latexcodec # pybtex # python-dateutil + # tox sniffio==1.3.0 # via anyio snowballstemmer==2.2.0 # via sphinx -spglib==2.1.0 +spglib==2.3.0 # via pymatgen sphinx==7.2.6 # via # myst-parser # pyEQL (setup.py) # sphinx-rtd-theme - # sphinxcontrib-applehelp - # sphinxcontrib-devhelp - # sphinxcontrib-htmlhelp # sphinxcontrib-jquery - # sphinxcontrib-qthelp - # sphinxcontrib-serializinghtml -sphinx-rtd-theme==1.3.0 +sphinx-rtd-theme==2.0.0 # via pyEQL (setup.py) -sphinxcontrib-applehelp==1.0.7 +sphinxcontrib-applehelp==1.0.8 # via sphinx -sphinxcontrib-devhelp==1.0.5 +sphinxcontrib-devhelp==1.0.6 # via sphinx -sphinxcontrib-htmlhelp==2.0.4 +sphinxcontrib-htmlhelp==2.0.5 # via sphinx sphinxcontrib-jquery==4.1 # via sphinx-rtd-theme sphinxcontrib-jsmath==1.0.1 # via sphinx -sphinxcontrib-qthelp==1.0.6 +sphinxcontrib-qthelp==1.0.7 # via sphinx -sphinxcontrib-serializinghtml==1.1.9 +sphinxcontrib-serializinghtml==1.1.10 # via sphinx sshtunnel==0.4.0 # via maggma -starlette==0.27.0 +starlette==0.36.3 # via fastapi sympy==1.12 # via pymatgen @@ -364,17 +350,17 @@ tomli==2.0.1 # black # coverage # mypy - # pyproject-api # pytest # tox -tox==4.11.3 +tox==3.28.0 # via pyEQL (setup.py) tqdm==4.66.1 # via # maggma # pymatgen -typing-extensions==4.8.0 +typing-extensions==4.9.0 # via + # anyio # black # fastapi # mypy @@ -383,7 +369,7 @@ typing-extensions==4.8.0 # pydantic-core # pydash # uvicorn -tzdata==2023.3 +tzdata==2023.4 # via pandas uc-micro-py==1.0.2 # via linkify-it-py @@ -393,9 +379,9 @@ urllib3==2.0.7 # via # botocore # requests -uvicorn==0.23.2 +uvicorn==0.27.0.post1 # via maggma -virtualenv==20.24.5 +virtualenv==20.25.0 # via # pre-commit # tox diff --git a/requirements/ubuntu-latest_py3.11.txt b/requirements/ubuntu-latest_py3.11.txt index b43a9820..2b22e83e 100644 --- a/requirements/ubuntu-latest_py3.11.txt +++ b/requirements/ubuntu-latest_py3.11.txt @@ -8,52 +8,50 @@ aioitertools==0.11.0 # via maggma annotated-types==0.6.0 # via pydantic -anyio==3.7.1 - # via - # fastapi - # starlette -attrs==23.1.0 +anyio==4.2.0 + # via starlette +attrs==23.2.0 # via # jsonschema # referencing -bcrypt==4.0.1 +bcrypt==4.1.2 # via paramiko -blinker==1.6.3 +blinker==1.7.0 # via flask -boto3==1.28.65 +boto3==1.34.35 # via maggma -botocore==1.31.65 +botocore==1.34.35 # via # boto3 # s3transfer -certifi==2023.7.22 +certifi==2024.2.2 # via requests cffi==1.16.0 # via # cryptography # pynacl -charset-normalizer==3.3.0 +charset-normalizer==3.3.2 # via requests click==8.1.7 # via # flask # mongogrant # uvicorn -contourpy==1.1.1 +contourpy==1.2.0 # via matplotlib -cryptography==41.0.4 +cryptography==42.0.2 # via paramiko cycler==0.12.1 # via matplotlib -dnspython==2.4.2 +dnspython==2.5.0 # via # maggma # pymongo -fastapi==0.103.2 +fastapi==0.109.2 # via maggma -flask==3.0.0 +flask==3.0.2 # via mongogrant -fonttools==4.43.1 +fonttools==4.48.1 # via matplotlib future==0.18.3 # via uncertainties @@ -61,13 +59,13 @@ h11==0.14.0 # via uvicorn iapws==1.5.3 # via pyEQL (setup.py) -idna==3.4 +idna==3.6 # via # anyio # requests itsdangerous==2.1.2 # via flask -jinja2==3.1.2 +jinja2==3.1.3 # via flask jmespath==1.0.1 # via @@ -75,27 +73,27 @@ jmespath==1.0.1 # botocore joblib==1.3.2 # via pymatgen -jsonschema==4.19.1 +jsonschema==4.21.1 # via maggma -jsonschema-specifications==2023.7.1 +jsonschema-specifications==2023.12.1 # via jsonschema kiwisolver==1.4.5 # via matplotlib latexcodec==2.0.1 # via pybtex -maggma==0.57.4 +maggma==0.62.1 # via pyEQL (setup.py) -markupsafe==2.1.3 +markupsafe==2.1.5 # via # jinja2 # werkzeug -matplotlib==3.8.0 +matplotlib==3.8.2 # via pymatgen mongogrant==0.3.3 # via maggma mongomock==4.1.2 # via maggma -monty==2023.9.25 +monty==2024.2.2 # via # maggma # pyEQL (setup.py) @@ -104,9 +102,9 @@ mpmath==1.3.0 # via sympy msgpack==1.0.7 # via maggma -networkx==3.1 +networkx==3.2.1 # via pymatgen -numpy==1.26.1 +numpy==1.26.4 # via # contourpy # maggma @@ -117,7 +115,7 @@ numpy==1.26.1 # pymatgen # scipy # spglib -orjson==3.9.9 +orjson==3.9.13 # via maggma packaging==23.2 # via @@ -126,38 +124,38 @@ packaging==23.2 # plotly palettable==3.3.3 # via pymatgen -pandas==2.1.1 +pandas==2.2.0 # via pymatgen -paramiko==3.3.1 +paramiko==3.4.0 # via sshtunnel periodictable==1.6.1 # via phreeqpython phreeqpython==1.5.0 # via pyEQL (setup.py) -pillow==10.1.0 +pillow==10.2.0 # via matplotlib -pint==0.22 +pint==0.23 # via pyEQL (setup.py) -plotly==5.17.0 +plotly==5.18.0 # via pymatgen pybtex==0.24.0 # via pymatgen pycparser==2.21 # via cffi -pydantic==2.4.2 +pydantic==2.6.1 # via # fastapi # maggma # pydantic-settings -pydantic-core==2.10.1 +pydantic-core==2.16.2 # via pydantic -pydantic-settings==2.0.3 +pydantic-settings==2.1.0 # via maggma -pydash==7.0.6 +pydash==7.0.7 # via maggma -pymatgen==2023.10.11 +pymatgen==2024.1.27 # via pyEQL (setup.py) -pymongo==4.5.0 +pymongo==4.6.1 # via # maggma # mongogrant @@ -173,15 +171,15 @@ python-dateutil==2.8.2 # maggma # matplotlib # pandas -python-dotenv==1.0.0 +python-dotenv==1.0.1 # via pydantic-settings -pytz==2023.3.post1 +pytz==2024.1 # via pandas pyyaml==6.0.1 # via pybtex -pyzmq==25.1.1 +pyzmq==25.1.2 # via maggma -referencing==0.30.2 +referencing==0.33.0 # via # jsonschema # jsonschema-specifications @@ -189,19 +187,19 @@ requests==2.31.0 # via # mongogrant # pymatgen -rpds-py==0.10.6 +rpds-py==0.17.1 # via # jsonschema # referencing -ruamel-yaml==0.17.35 +ruamel-yaml==0.17.40 # via # maggma # pymatgen ruamel-yaml-clib==0.2.8 # via ruamel-yaml -s3transfer==0.7.0 +s3transfer==0.10.0 # via boto3 -scipy==1.11.3 +scipy==1.12.0 # via # iapws # phreeqpython @@ -216,11 +214,11 @@ six==1.16.0 # python-dateutil sniffio==1.3.0 # via anyio -spglib==2.1.0 +spglib==2.3.0 # via pymatgen sshtunnel==0.4.0 # via maggma -starlette==0.27.0 +starlette==0.36.3 # via fastapi sympy==1.12 # via pymatgen @@ -232,14 +230,14 @@ tqdm==4.66.1 # via # maggma # pymatgen -typing-extensions==4.8.0 +typing-extensions==4.9.0 # via # fastapi # pint # pydantic # pydantic-core # pydash -tzdata==2023.3 +tzdata==2023.4 # via pandas uncertainties==3.1.7 # via pymatgen @@ -247,7 +245,7 @@ urllib3==2.0.7 # via # botocore # requests -uvicorn==0.23.2 +uvicorn==0.27.0.post1 # via maggma werkzeug==3.0.1 # via flask diff --git a/requirements/ubuntu-latest_py3.11_extras.txt b/requirements/ubuntu-latest_py3.11_extras.txt index 585aec6b..5b30dab3 100644 --- a/requirements/ubuntu-latest_py3.11_extras.txt +++ b/requirements/ubuntu-latest_py3.11_extras.txt @@ -6,35 +6,31 @@ # aioitertools==0.11.0 # via maggma -alabaster==0.7.13 +alabaster==0.7.16 # via sphinx annotated-types==0.6.0 # via pydantic -anyio==3.7.1 - # via - # fastapi - # starlette -attrs==23.1.0 +anyio==4.2.0 + # via starlette +attrs==23.2.0 # via # jsonschema # referencing -babel==2.13.0 +babel==2.14.0 # via sphinx -bcrypt==4.0.1 +bcrypt==4.1.2 # via paramiko -black==23.10.0 +black==24.1.1 # via pyEQL (setup.py) -blinker==1.6.3 +blinker==1.7.0 # via flask -boto3==1.28.65 +boto3==1.34.35 # via maggma -botocore==1.31.65 +botocore==1.34.35 # via # boto3 # s3transfer -cachetools==5.3.1 - # via tox -certifi==2023.7.22 +certifi==2024.2.2 # via requests cffi==1.16.0 # via @@ -42,9 +38,7 @@ cffi==1.16.0 # pynacl cfgv==3.4.0 # via pre-commit -chardet==5.2.0 - # via tox -charset-normalizer==3.3.0 +charset-normalizer==3.3.2 # via requests click==8.1.7 # via @@ -52,38 +46,36 @@ click==8.1.7 # flask # mongogrant # uvicorn -colorama==0.4.6 - # via tox -contourpy==1.1.1 +contourpy==1.2.0 # via matplotlib -coverage[toml]==7.3.2 +coverage[toml]==7.4.1 # via # coverage # pytest-cov -cryptography==41.0.4 +cryptography==42.0.2 # via paramiko cycler==0.12.1 # via matplotlib -distlib==0.3.7 +distlib==0.3.8 # via virtualenv -dnspython==2.4.2 +dnspython==2.5.0 # via # maggma # pymongo -docutils==0.18.1 +docutils==0.20.1 # via # myst-parser # sphinx # sphinx-rtd-theme -fastapi==0.103.2 +fastapi==0.109.2 # via maggma -filelock==3.12.4 +filelock==3.13.1 # via # tox # virtualenv -flask==3.0.0 +flask==3.0.2 # via mongogrant -fonttools==4.43.1 +fonttools==4.48.1 # via matplotlib future==0.18.3 # via uncertainties @@ -91,9 +83,9 @@ h11==0.14.0 # via uvicorn iapws==1.5.3 # via pyEQL (setup.py) -identify==2.5.30 +identify==2.5.33 # via pre-commit -idna==3.4 +idna==3.6 # via # anyio # requests @@ -103,7 +95,7 @@ iniconfig==2.0.0 # via pytest itsdangerous==2.1.2 # via flask -jinja2==3.1.2 +jinja2==3.1.3 # via # flask # myst-parser @@ -114,28 +106,28 @@ jmespath==1.0.1 # botocore joblib==1.3.2 # via pymatgen -jsonschema==4.19.1 +jsonschema==4.21.1 # via maggma -jsonschema-specifications==2023.7.1 +jsonschema-specifications==2023.12.1 # via jsonschema kiwisolver==1.4.5 # via matplotlib latexcodec==2.0.1 # via pybtex -linkify-it-py==2.0.2 +linkify-it-py==2.0.3 # via myst-parser -maggma==0.57.4 +maggma==0.62.1 # via pyEQL (setup.py) markdown-it-py==3.0.0 # via # mdit-py-plugins # myst-parser # rich -markupsafe==2.1.3 +markupsafe==2.1.5 # via # jinja2 # werkzeug -matplotlib==3.8.0 +matplotlib==3.8.2 # via pymatgen mdit-py-plugins==0.4.0 # via myst-parser @@ -145,7 +137,7 @@ mongogrant==0.3.3 # via maggma mongomock==4.1.2 # via maggma -monty==2023.9.25 +monty==2024.2.2 # via # maggma # pyEQL (setup.py) @@ -154,7 +146,7 @@ mpmath==1.3.0 # via sympy msgpack==1.0.7 # via maggma -mypy==1.6.0 +mypy==1.8.0 # via pyEQL (setup.py) mypy-extensions==1.0.0 # via @@ -162,11 +154,11 @@ mypy-extensions==1.0.0 # mypy myst-parser[linkify]==2.0.0 # via pyEQL (setup.py) -networkx==3.1 +networkx==3.2.1 # via pymatgen nodeenv==1.8.0 # via pre-commit -numpy==1.26.1 +numpy==1.26.4 # via # contourpy # maggma @@ -177,7 +169,7 @@ numpy==1.26.1 # pymatgen # scipy # spglib -orjson==3.9.9 +orjson==3.9.13 # via maggma packaging==23.2 # via @@ -185,61 +177,61 @@ packaging==23.2 # matplotlib # mongomock # plotly - # pyproject-api # pytest # sphinx # tox palettable==3.3.3 # via pymatgen -pandas==2.1.1 +pandas==2.2.0 # via pymatgen -paramiko==3.3.1 +paramiko==3.4.0 # via sshtunnel -pathspec==0.11.2 +pathspec==0.12.1 # via black periodictable==1.6.1 # via phreeqpython phreeqpython==1.5.0 # via pyEQL (setup.py) -pillow==10.1.0 +pillow==10.2.0 # via matplotlib -pint==0.22 +pint==0.23 # via pyEQL (setup.py) -platformdirs==3.11.0 +platformdirs==4.2.0 # via # black - # tox # virtualenv -plotly==5.17.0 +plotly==5.18.0 # via pymatgen -pluggy==1.3.0 +pluggy==1.4.0 # via # pytest # tox -pre-commit==3.5.0 +pre-commit==3.6.0 # via pyEQL (setup.py) +py==1.11.0 + # via tox pybtex==0.24.0 # via pymatgen pycparser==2.21 # via cffi -pydantic==2.4.2 +pydantic==2.6.1 # via # fastapi # maggma # pydantic-settings -pydantic-core==2.10.1 +pydantic-core==2.16.2 # via pydantic -pydantic-settings==2.0.3 +pydantic-settings==2.1.0 # via maggma -pydash==7.0.6 +pydash==7.0.7 # via maggma -pygments==2.16.1 +pygments==2.17.2 # via # rich # sphinx -pymatgen==2023.10.11 +pymatgen==2024.1.27 # via pyEQL (setup.py) -pymongo==4.5.0 +pymongo==4.6.1 # via # maggma # mongogrant @@ -249,9 +241,7 @@ pyparsing==3.1.1 # via # matplotlib # periodictable -pyproject-api==1.6.1 - # via tox -pytest==7.4.2 +pytest==8.0.0 # via # pyEQL (setup.py) # pytest-cov @@ -263,18 +253,18 @@ python-dateutil==2.8.2 # maggma # matplotlib # pandas -python-dotenv==1.0.0 +python-dotenv==1.0.1 # via pydantic-settings -pytz==2023.3.post1 +pytz==2024.1 # via pandas pyyaml==6.0.1 # via # myst-parser # pre-commit # pybtex -pyzmq==25.1.1 +pyzmq==25.1.2 # via maggma -referencing==0.30.2 +referencing==0.33.0 # via # jsonschema # jsonschema-specifications @@ -283,23 +273,23 @@ requests==2.31.0 # mongogrant # pymatgen # sphinx -rich==13.6.0 +rich==13.7.0 # via pyEQL (setup.py) -rpds-py==0.10.6 +rpds-py==0.17.1 # via # jsonschema # referencing -ruamel-yaml==0.17.35 +ruamel-yaml==0.17.40 # via # maggma # pymatgen ruamel-yaml-clib==0.2.8 # via ruamel-yaml -ruff==0.1.0 +ruff==0.2.1 # via pyEQL (setup.py) -s3transfer==0.7.0 +s3transfer==0.10.0 # via boto3 -scipy==1.11.3 +scipy==1.12.0 # via # iapws # phreeqpython @@ -312,42 +302,38 @@ six==1.16.0 # latexcodec # pybtex # python-dateutil + # tox sniffio==1.3.0 # via anyio snowballstemmer==2.2.0 # via sphinx -spglib==2.1.0 +spglib==2.3.0 # via pymatgen sphinx==7.2.6 # via # myst-parser # pyEQL (setup.py) # sphinx-rtd-theme - # sphinxcontrib-applehelp - # sphinxcontrib-devhelp - # sphinxcontrib-htmlhelp # sphinxcontrib-jquery - # sphinxcontrib-qthelp - # sphinxcontrib-serializinghtml -sphinx-rtd-theme==1.3.0 +sphinx-rtd-theme==2.0.0 # via pyEQL (setup.py) -sphinxcontrib-applehelp==1.0.7 +sphinxcontrib-applehelp==1.0.8 # via sphinx -sphinxcontrib-devhelp==1.0.5 +sphinxcontrib-devhelp==1.0.6 # via sphinx -sphinxcontrib-htmlhelp==2.0.4 +sphinxcontrib-htmlhelp==2.0.5 # via sphinx sphinxcontrib-jquery==4.1 # via sphinx-rtd-theme sphinxcontrib-jsmath==1.0.1 # via sphinx -sphinxcontrib-qthelp==1.0.6 +sphinxcontrib-qthelp==1.0.7 # via sphinx -sphinxcontrib-serializinghtml==1.1.9 +sphinxcontrib-serializinghtml==1.1.10 # via sphinx sshtunnel==0.4.0 # via maggma -starlette==0.27.0 +starlette==0.36.3 # via fastapi sympy==1.12 # via pymatgen @@ -355,13 +341,13 @@ tabulate==0.9.0 # via pymatgen tenacity==8.2.3 # via plotly -tox==4.11.3 +tox==3.28.0 # via pyEQL (setup.py) tqdm==4.66.1 # via # maggma # pymatgen -typing-extensions==4.8.0 +typing-extensions==4.9.0 # via # fastapi # mypy @@ -369,7 +355,7 @@ typing-extensions==4.8.0 # pydantic # pydantic-core # pydash -tzdata==2023.3 +tzdata==2023.4 # via pandas uc-micro-py==1.0.2 # via linkify-it-py @@ -379,9 +365,9 @@ urllib3==2.0.7 # via # botocore # requests -uvicorn==0.23.2 +uvicorn==0.27.0.post1 # via maggma -virtualenv==20.24.5 +virtualenv==20.25.0 # via # pre-commit # tox diff --git a/requirements/ubuntu-latest_py3.12.txt b/requirements/ubuntu-latest_py3.12.txt new file mode 100644 index 00000000..a5936ccf --- /dev/null +++ b/requirements/ubuntu-latest_py3.12.txt @@ -0,0 +1,254 @@ +# +# This file is autogenerated by pip-compile with Python 3.12 +# by the following command: +# +# pip-compile --output-file=requirements/ubuntu-latest_py3.12.txt +# +aioitertools==0.11.0 + # via maggma +annotated-types==0.6.0 + # via pydantic +anyio==4.2.0 + # via starlette +attrs==23.2.0 + # via + # jsonschema + # referencing +bcrypt==4.1.2 + # via paramiko +blinker==1.7.0 + # via flask +boto3==1.34.35 + # via maggma +botocore==1.34.35 + # via + # boto3 + # s3transfer +certifi==2024.2.2 + # via requests +cffi==1.16.0 + # via + # cryptography + # pynacl +charset-normalizer==3.3.2 + # via requests +click==8.1.7 + # via + # flask + # mongogrant + # uvicorn +contourpy==1.2.0 + # via matplotlib +cryptography==42.0.2 + # via paramiko +cycler==0.12.1 + # via matplotlib +dnspython==2.5.0 + # via + # maggma + # pymongo +fastapi==0.109.2 + # via maggma +flask==3.0.2 + # via mongogrant +fonttools==4.48.1 + # via matplotlib +future==0.18.3 + # via uncertainties +h11==0.14.0 + # via uvicorn +iapws==1.5.3 + # via pyEQL (setup.py) +idna==3.6 + # via + # anyio + # requests +itsdangerous==2.1.2 + # via flask +jinja2==3.1.3 + # via flask +jmespath==1.0.1 + # via + # boto3 + # botocore +joblib==1.3.2 + # via pymatgen +jsonschema==4.21.1 + # via maggma +jsonschema-specifications==2023.12.1 + # via jsonschema +kiwisolver==1.4.5 + # via matplotlib +latexcodec==2.0.1 + # via pybtex +maggma==0.62.1 + # via pyEQL (setup.py) +markupsafe==2.1.5 + # via + # jinja2 + # werkzeug +matplotlib==3.8.2 + # via pymatgen +mongogrant==0.3.3 + # via maggma +mongomock==4.1.2 + # via maggma +monty==2024.2.2 + # via + # maggma + # pyEQL (setup.py) + # pymatgen +mpmath==1.3.0 + # via sympy +msgpack==1.0.7 + # via maggma +networkx==3.2.1 + # via pymatgen +numpy==1.26.4 + # via + # contourpy + # maggma + # matplotlib + # pandas + # periodictable + # pyEQL (setup.py) + # pymatgen + # scipy + # spglib +orjson==3.9.13 + # via maggma +packaging==23.2 + # via + # matplotlib + # mongomock + # plotly +palettable==3.3.3 + # via pymatgen +pandas==2.2.0 + # via pymatgen +paramiko==3.4.0 + # via sshtunnel +periodictable==1.6.1 + # via phreeqpython +phreeqpython==1.5.0 + # via pyEQL (setup.py) +pillow==10.2.0 + # via matplotlib +pint==0.23 + # via pyEQL (setup.py) +plotly==5.18.0 + # via pymatgen +pybtex==0.24.0 + # via pymatgen +pycparser==2.21 + # via cffi +pydantic==2.6.1 + # via + # fastapi + # maggma + # pydantic-settings +pydantic-core==2.16.2 + # via pydantic +pydantic-settings==2.1.0 + # via maggma +pydash==7.0.7 + # via maggma +pymatgen==2024.1.27 + # via pyEQL (setup.py) +pymongo==4.6.1 + # via + # maggma + # mongogrant +pynacl==1.5.0 + # via paramiko +pyparsing==3.1.1 + # via + # matplotlib + # periodictable +python-dateutil==2.8.2 + # via + # botocore + # maggma + # matplotlib + # pandas +python-dotenv==1.0.1 + # via pydantic-settings +pytz==2024.1 + # via pandas +pyyaml==6.0.1 + # via pybtex +pyzmq==25.1.2 + # via maggma +referencing==0.33.0 + # via + # jsonschema + # jsonschema-specifications +requests==2.31.0 + # via + # mongogrant + # pymatgen +rpds-py==0.17.1 + # via + # jsonschema + # referencing +ruamel-yaml==0.17.40 + # via + # maggma + # pymatgen +ruamel-yaml-clib==0.2.8 + # via ruamel-yaml +s3transfer==0.10.0 + # via boto3 +scipy==1.12.0 + # via + # iapws + # phreeqpython + # pyEQL (setup.py) + # pymatgen +sentinels==1.0.0 + # via mongomock +six==1.16.0 + # via + # latexcodec + # pybtex + # python-dateutil +sniffio==1.3.0 + # via anyio +spglib==2.3.0 + # via pymatgen +sshtunnel==0.4.0 + # via maggma +starlette==0.36.3 + # via fastapi +sympy==1.12 + # via pymatgen +tabulate==0.9.0 + # via pymatgen +tenacity==8.2.3 + # via plotly +tqdm==4.66.1 + # via + # maggma + # pymatgen +typing-extensions==4.9.0 + # via + # fastapi + # pint + # pydantic + # pydantic-core + # pydash +tzdata==2023.4 + # via pandas +uncertainties==3.1.7 + # via pymatgen +urllib3==2.0.7 + # via + # botocore + # requests +uvicorn==0.27.0.post1 + # via maggma +werkzeug==3.0.1 + # via flask + +# The following packages are considered to be unsafe in a requirements file: +# setuptools diff --git a/requirements/ubuntu-latest_py3.12_extras.txt b/requirements/ubuntu-latest_py3.12_extras.txt new file mode 100644 index 00000000..424c6d54 --- /dev/null +++ b/requirements/ubuntu-latest_py3.12_extras.txt @@ -0,0 +1,378 @@ +# +# This file is autogenerated by pip-compile with Python 3.12 +# by the following command: +# +# pip-compile --all-extras --output-file=requirements/ubuntu-latest_py3.12_extras.txt +# +aioitertools==0.11.0 + # via maggma +alabaster==0.7.16 + # via sphinx +annotated-types==0.6.0 + # via pydantic +anyio==4.2.0 + # via starlette +attrs==23.2.0 + # via + # jsonschema + # referencing +babel==2.14.0 + # via sphinx +bcrypt==4.1.2 + # via paramiko +black==24.1.1 + # via pyEQL (setup.py) +blinker==1.7.0 + # via flask +boto3==1.34.35 + # via maggma +botocore==1.34.35 + # via + # boto3 + # s3transfer +certifi==2024.2.2 + # via requests +cffi==1.16.0 + # via + # cryptography + # pynacl +cfgv==3.4.0 + # via pre-commit +charset-normalizer==3.3.2 + # via requests +click==8.1.7 + # via + # black + # flask + # mongogrant + # uvicorn +contourpy==1.2.0 + # via matplotlib +coverage[toml]==7.4.1 + # via + # coverage + # pytest-cov +cryptography==42.0.2 + # via paramiko +cycler==0.12.1 + # via matplotlib +distlib==0.3.8 + # via virtualenv +dnspython==2.5.0 + # via + # maggma + # pymongo +docutils==0.20.1 + # via + # myst-parser + # sphinx + # sphinx-rtd-theme +fastapi==0.109.2 + # via maggma +filelock==3.13.1 + # via + # tox + # virtualenv +flask==3.0.2 + # via mongogrant +fonttools==4.48.1 + # via matplotlib +future==0.18.3 + # via uncertainties +h11==0.14.0 + # via uvicorn +iapws==1.5.3 + # via pyEQL (setup.py) +identify==2.5.33 + # via pre-commit +idna==3.6 + # via + # anyio + # requests +imagesize==1.4.1 + # via sphinx +iniconfig==2.0.0 + # via pytest +itsdangerous==2.1.2 + # via flask +jinja2==3.1.3 + # via + # flask + # myst-parser + # sphinx +jmespath==1.0.1 + # via + # boto3 + # botocore +joblib==1.3.2 + # via pymatgen +jsonschema==4.21.1 + # via maggma +jsonschema-specifications==2023.12.1 + # via jsonschema +kiwisolver==1.4.5 + # via matplotlib +latexcodec==2.0.1 + # via pybtex +linkify-it-py==2.0.3 + # via myst-parser +maggma==0.62.1 + # via pyEQL (setup.py) +markdown-it-py==3.0.0 + # via + # mdit-py-plugins + # myst-parser + # rich +markupsafe==2.1.5 + # via + # jinja2 + # werkzeug +matplotlib==3.8.2 + # via pymatgen +mdit-py-plugins==0.4.0 + # via myst-parser +mdurl==0.1.2 + # via markdown-it-py +mongogrant==0.3.3 + # via maggma +mongomock==4.1.2 + # via maggma +monty==2024.2.2 + # via + # maggma + # pyEQL (setup.py) + # pymatgen +mpmath==1.3.0 + # via sympy +msgpack==1.0.7 + # via maggma +mypy==1.8.0 + # via pyEQL (setup.py) +mypy-extensions==1.0.0 + # via + # black + # mypy +myst-parser[linkify]==2.0.0 + # via pyEQL (setup.py) +networkx==3.2.1 + # via pymatgen +nodeenv==1.8.0 + # via pre-commit +numpy==1.26.4 + # via + # contourpy + # maggma + # matplotlib + # pandas + # periodictable + # pyEQL (setup.py) + # pymatgen + # scipy + # spglib +orjson==3.9.13 + # via maggma +packaging==23.2 + # via + # black + # matplotlib + # mongomock + # plotly + # pytest + # sphinx + # tox +palettable==3.3.3 + # via pymatgen +pandas==2.2.0 + # via pymatgen +paramiko==3.4.0 + # via sshtunnel +pathspec==0.12.1 + # via black +periodictable==1.6.1 + # via phreeqpython +phreeqpython==1.5.0 + # via pyEQL (setup.py) +pillow==10.2.0 + # via matplotlib +pint==0.23 + # via pyEQL (setup.py) +platformdirs==4.2.0 + # via + # black + # virtualenv +plotly==5.18.0 + # via pymatgen +pluggy==1.4.0 + # via + # pytest + # tox +pre-commit==3.6.0 + # via pyEQL (setup.py) +py==1.11.0 + # via tox +pybtex==0.24.0 + # via pymatgen +pycparser==2.21 + # via cffi +pydantic==2.6.1 + # via + # fastapi + # maggma + # pydantic-settings +pydantic-core==2.16.2 + # via pydantic +pydantic-settings==2.1.0 + # via maggma +pydash==7.0.7 + # via maggma +pygments==2.17.2 + # via + # rich + # sphinx +pymatgen==2024.1.27 + # via pyEQL (setup.py) +pymongo==4.6.1 + # via + # maggma + # mongogrant +pynacl==1.5.0 + # via paramiko +pyparsing==3.1.1 + # via + # matplotlib + # periodictable +pytest==8.0.0 + # via + # pyEQL (setup.py) + # pytest-cov +pytest-cov==4.1.0 + # via pyEQL (setup.py) +python-dateutil==2.8.2 + # via + # botocore + # maggma + # matplotlib + # pandas +python-dotenv==1.0.1 + # via pydantic-settings +pytz==2024.1 + # via pandas +pyyaml==6.0.1 + # via + # myst-parser + # pre-commit + # pybtex +pyzmq==25.1.2 + # via maggma +referencing==0.33.0 + # via + # jsonschema + # jsonschema-specifications +requests==2.31.0 + # via + # mongogrant + # pymatgen + # sphinx +rich==13.7.0 + # via pyEQL (setup.py) +rpds-py==0.17.1 + # via + # jsonschema + # referencing +ruamel-yaml==0.17.40 + # via + # maggma + # pymatgen +ruamel-yaml-clib==0.2.8 + # via ruamel-yaml +ruff==0.2.1 + # via pyEQL (setup.py) +s3transfer==0.10.0 + # via boto3 +scipy==1.12.0 + # via + # iapws + # phreeqpython + # pyEQL (setup.py) + # pymatgen +sentinels==1.0.0 + # via mongomock +six==1.16.0 + # via + # latexcodec + # pybtex + # python-dateutil + # tox +sniffio==1.3.0 + # via anyio +snowballstemmer==2.2.0 + # via sphinx +spglib==2.3.0 + # via pymatgen +sphinx==7.2.6 + # via + # myst-parser + # pyEQL (setup.py) + # sphinx-rtd-theme + # sphinxcontrib-jquery +sphinx-rtd-theme==2.0.0 + # via pyEQL (setup.py) +sphinxcontrib-applehelp==1.0.8 + # via sphinx +sphinxcontrib-devhelp==1.0.6 + # via sphinx +sphinxcontrib-htmlhelp==2.0.5 + # via sphinx +sphinxcontrib-jquery==4.1 + # via sphinx-rtd-theme +sphinxcontrib-jsmath==1.0.1 + # via sphinx +sphinxcontrib-qthelp==1.0.7 + # via sphinx +sphinxcontrib-serializinghtml==1.1.10 + # via sphinx +sshtunnel==0.4.0 + # via maggma +starlette==0.36.3 + # via fastapi +sympy==1.12 + # via pymatgen +tabulate==0.9.0 + # via pymatgen +tenacity==8.2.3 + # via plotly +tox==3.28.0 + # via pyEQL (setup.py) +tqdm==4.66.1 + # via + # maggma + # pymatgen +typing-extensions==4.9.0 + # via + # fastapi + # mypy + # pint + # pydantic + # pydantic-core + # pydash +tzdata==2023.4 + # via pandas +uc-micro-py==1.0.2 + # via linkify-it-py +uncertainties==3.1.7 + # via pymatgen +urllib3==2.0.7 + # via + # botocore + # requests +uvicorn==0.27.0.post1 + # via maggma +virtualenv==20.25.0 + # via + # pre-commit + # tox +werkzeug==3.0.1 + # via flask + +# The following packages are considered to be unsafe in a requirements file: +# setuptools diff --git a/requirements/ubuntu-latest_py3.9.txt b/requirements/ubuntu-latest_py3.9.txt index 296e28d5..84a02481 100644 --- a/requirements/ubuntu-latest_py3.9.txt +++ b/requirements/ubuntu-latest_py3.9.txt @@ -8,54 +8,52 @@ aioitertools==0.11.0 # via maggma annotated-types==0.6.0 # via pydantic -anyio==3.7.1 - # via - # fastapi - # starlette -attrs==23.1.0 +anyio==4.2.0 + # via starlette +attrs==23.2.0 # via # jsonschema # referencing -bcrypt==4.0.1 +bcrypt==4.1.2 # via paramiko -blinker==1.6.3 +blinker==1.7.0 # via flask -boto3==1.28.65 +boto3==1.34.35 # via maggma -botocore==1.31.65 +botocore==1.34.35 # via # boto3 # s3transfer -certifi==2023.7.22 +certifi==2024.2.2 # via requests cffi==1.16.0 # via # cryptography # pynacl -charset-normalizer==3.3.0 +charset-normalizer==3.3.2 # via requests click==8.1.7 # via # flask # mongogrant # uvicorn -contourpy==1.1.1 +contourpy==1.2.0 # via matplotlib -cryptography==41.0.4 +cryptography==42.0.2 # via paramiko cycler==0.12.1 # via matplotlib -dnspython==2.4.2 +dnspython==2.5.0 # via # maggma # pymongo -exceptiongroup==1.1.3 +exceptiongroup==1.2.0 # via anyio -fastapi==0.103.2 +fastapi==0.109.2 # via maggma -flask==3.0.0 +flask==3.0.2 # via mongogrant -fonttools==4.43.1 +fonttools==4.48.1 # via matplotlib future==0.18.3 # via uncertainties @@ -63,17 +61,17 @@ h11==0.14.0 # via uvicorn iapws==1.5.3 # via pyEQL (setup.py) -idna==3.4 +idna==3.6 # via # anyio # requests -importlib-metadata==6.8.0 +importlib-metadata==7.0.1 # via flask -importlib-resources==6.1.0 +importlib-resources==6.1.1 # via matplotlib itsdangerous==2.1.2 # via flask -jinja2==3.1.2 +jinja2==3.1.3 # via flask jmespath==1.0.1 # via @@ -81,27 +79,27 @@ jmespath==1.0.1 # botocore joblib==1.3.2 # via pymatgen -jsonschema==4.19.1 +jsonschema==4.21.1 # via maggma -jsonschema-specifications==2023.7.1 +jsonschema-specifications==2023.12.1 # via jsonschema kiwisolver==1.4.5 # via matplotlib latexcodec==2.0.1 # via pybtex -maggma==0.57.4 +maggma==0.62.1 # via pyEQL (setup.py) -markupsafe==2.1.3 +markupsafe==2.1.5 # via # jinja2 # werkzeug -matplotlib==3.8.0 +matplotlib==3.8.2 # via pymatgen mongogrant==0.3.3 # via maggma mongomock==4.1.2 # via maggma -monty==2023.9.25 +monty==2024.2.2 # via # maggma # pyEQL (setup.py) @@ -110,9 +108,9 @@ mpmath==1.3.0 # via sympy msgpack==1.0.7 # via maggma -networkx==3.1 +networkx==3.2.1 # via pymatgen -numpy==1.26.1 +numpy==1.26.4 # via # contourpy # maggma @@ -123,7 +121,7 @@ numpy==1.26.1 # pymatgen # scipy # spglib -orjson==3.9.9 +orjson==3.9.13 # via maggma packaging==23.2 # via @@ -132,38 +130,38 @@ packaging==23.2 # plotly palettable==3.3.3 # via pymatgen -pandas==2.1.1 +pandas==2.2.0 # via pymatgen -paramiko==3.3.1 +paramiko==3.4.0 # via sshtunnel periodictable==1.6.1 # via phreeqpython phreeqpython==1.5.0 # via pyEQL (setup.py) -pillow==10.1.0 +pillow==10.2.0 # via matplotlib -pint==0.22 +pint==0.23 # via pyEQL (setup.py) -plotly==5.17.0 +plotly==5.18.0 # via pymatgen pybtex==0.24.0 # via pymatgen pycparser==2.21 # via cffi -pydantic==2.4.2 +pydantic==2.6.1 # via # fastapi # maggma # pydantic-settings -pydantic-core==2.10.1 +pydantic-core==2.16.2 # via pydantic -pydantic-settings==2.0.3 +pydantic-settings==2.1.0 # via maggma -pydash==7.0.6 +pydash==7.0.7 # via maggma -pymatgen==2023.10.11 +pymatgen==2024.1.27 # via pyEQL (setup.py) -pymongo==4.5.0 +pymongo==4.6.1 # via # maggma # mongogrant @@ -179,15 +177,15 @@ python-dateutil==2.8.2 # maggma # matplotlib # pandas -python-dotenv==1.0.0 +python-dotenv==1.0.1 # via pydantic-settings -pytz==2023.3.post1 +pytz==2024.1 # via pandas pyyaml==6.0.1 # via pybtex -pyzmq==25.1.1 +pyzmq==25.1.2 # via maggma -referencing==0.30.2 +referencing==0.33.0 # via # jsonschema # jsonschema-specifications @@ -195,19 +193,19 @@ requests==2.31.0 # via # mongogrant # pymatgen -rpds-py==0.10.6 +rpds-py==0.17.1 # via # jsonschema # referencing -ruamel-yaml==0.17.35 +ruamel-yaml==0.17.40 # via # maggma # pymatgen ruamel-yaml-clib==0.2.8 # via ruamel-yaml -s3transfer==0.7.0 +s3transfer==0.10.0 # via boto3 -scipy==1.11.3 +scipy==1.12.0 # via # iapws # phreeqpython @@ -222,11 +220,11 @@ six==1.16.0 # python-dateutil sniffio==1.3.0 # via anyio -spglib==2.1.0 +spglib==2.3.0 # via pymatgen sshtunnel==0.4.0 # via maggma -starlette==0.27.0 +starlette==0.36.3 # via fastapi sympy==1.12 # via pymatgen @@ -238,9 +236,10 @@ tqdm==4.66.1 # via # maggma # pymatgen -typing-extensions==4.8.0 +typing-extensions==4.9.0 # via # aioitertools + # anyio # fastapi # pint # pydantic @@ -248,7 +247,7 @@ typing-extensions==4.8.0 # pydash # starlette # uvicorn -tzdata==2023.3 +tzdata==2023.4 # via pandas uncertainties==3.1.7 # via pymatgen @@ -256,7 +255,7 @@ urllib3==1.26.18 # via # botocore # requests -uvicorn==0.23.2 +uvicorn==0.27.0.post1 # via maggma werkzeug==3.0.1 # via flask diff --git a/requirements/ubuntu-latest_py3.9_extras.txt b/requirements/ubuntu-latest_py3.9_extras.txt index b6f922c5..bc09b9bb 100644 --- a/requirements/ubuntu-latest_py3.9_extras.txt +++ b/requirements/ubuntu-latest_py3.9_extras.txt @@ -6,35 +6,31 @@ # aioitertools==0.11.0 # via maggma -alabaster==0.7.13 +alabaster==0.7.16 # via sphinx annotated-types==0.6.0 # via pydantic -anyio==3.7.1 - # via - # fastapi - # starlette -attrs==23.1.0 +anyio==4.2.0 + # via starlette +attrs==23.2.0 # via # jsonschema # referencing -babel==2.13.0 +babel==2.14.0 # via sphinx -bcrypt==4.0.1 +bcrypt==4.1.2 # via paramiko -black==23.10.0 +black==24.1.1 # via pyEQL (setup.py) -blinker==1.6.3 +blinker==1.7.0 # via flask -boto3==1.28.65 +boto3==1.34.35 # via maggma -botocore==1.31.65 +botocore==1.34.35 # via # boto3 # s3transfer -cachetools==5.3.1 - # via tox -certifi==2023.7.22 +certifi==2024.2.2 # via requests cffi==1.16.0 # via @@ -42,9 +38,7 @@ cffi==1.16.0 # pynacl cfgv==3.4.0 # via pre-commit -chardet==5.2.0 - # via tox -charset-normalizer==3.3.0 +charset-normalizer==3.3.2 # via requests click==8.1.7 # via @@ -52,42 +46,40 @@ click==8.1.7 # flask # mongogrant # uvicorn -colorama==0.4.6 - # via tox -contourpy==1.1.1 +contourpy==1.2.0 # via matplotlib -coverage[toml]==7.3.2 +coverage[toml]==7.4.1 # via # coverage # pytest-cov -cryptography==41.0.4 +cryptography==42.0.2 # via paramiko cycler==0.12.1 # via matplotlib -distlib==0.3.7 +distlib==0.3.8 # via virtualenv -dnspython==2.4.2 +dnspython==2.5.0 # via # maggma # pymongo -docutils==0.18.1 +docutils==0.20.1 # via # myst-parser # sphinx # sphinx-rtd-theme -exceptiongroup==1.1.3 +exceptiongroup==1.2.0 # via # anyio # pytest -fastapi==0.103.2 +fastapi==0.109.2 # via maggma -filelock==3.12.4 +filelock==3.13.1 # via # tox # virtualenv -flask==3.0.0 +flask==3.0.2 # via mongogrant -fonttools==4.43.1 +fonttools==4.48.1 # via matplotlib future==0.18.3 # via uncertainties @@ -95,25 +87,25 @@ h11==0.14.0 # via uvicorn iapws==1.5.3 # via pyEQL (setup.py) -identify==2.5.30 +identify==2.5.33 # via pre-commit -idna==3.4 +idna==3.6 # via # anyio # requests imagesize==1.4.1 # via sphinx -importlib-metadata==6.8.0 +importlib-metadata==7.0.1 # via # flask # sphinx -importlib-resources==6.1.0 +importlib-resources==6.1.1 # via matplotlib iniconfig==2.0.0 # via pytest itsdangerous==2.1.2 # via flask -jinja2==3.1.2 +jinja2==3.1.3 # via # flask # myst-parser @@ -124,28 +116,28 @@ jmespath==1.0.1 # botocore joblib==1.3.2 # via pymatgen -jsonschema==4.19.1 +jsonschema==4.21.1 # via maggma -jsonschema-specifications==2023.7.1 +jsonschema-specifications==2023.12.1 # via jsonschema kiwisolver==1.4.5 # via matplotlib latexcodec==2.0.1 # via pybtex -linkify-it-py==2.0.2 +linkify-it-py==2.0.3 # via myst-parser -maggma==0.57.4 +maggma==0.62.1 # via pyEQL (setup.py) markdown-it-py==3.0.0 # via # mdit-py-plugins # myst-parser # rich -markupsafe==2.1.3 +markupsafe==2.1.5 # via # jinja2 # werkzeug -matplotlib==3.8.0 +matplotlib==3.8.2 # via pymatgen mdit-py-plugins==0.4.0 # via myst-parser @@ -155,7 +147,7 @@ mongogrant==0.3.3 # via maggma mongomock==4.1.2 # via maggma -monty==2023.9.25 +monty==2024.2.2 # via # maggma # pyEQL (setup.py) @@ -164,7 +156,7 @@ mpmath==1.3.0 # via sympy msgpack==1.0.7 # via maggma -mypy==1.6.0 +mypy==1.8.0 # via pyEQL (setup.py) mypy-extensions==1.0.0 # via @@ -172,11 +164,11 @@ mypy-extensions==1.0.0 # mypy myst-parser[linkify]==2.0.0 # via pyEQL (setup.py) -networkx==3.1 +networkx==3.2.1 # via pymatgen nodeenv==1.8.0 # via pre-commit -numpy==1.26.1 +numpy==1.26.4 # via # contourpy # maggma @@ -187,7 +179,7 @@ numpy==1.26.1 # pymatgen # scipy # spglib -orjson==3.9.9 +orjson==3.9.13 # via maggma packaging==23.2 # via @@ -195,61 +187,61 @@ packaging==23.2 # matplotlib # mongomock # plotly - # pyproject-api # pytest # sphinx # tox palettable==3.3.3 # via pymatgen -pandas==2.1.1 +pandas==2.2.0 # via pymatgen -paramiko==3.3.1 +paramiko==3.4.0 # via sshtunnel -pathspec==0.11.2 +pathspec==0.12.1 # via black periodictable==1.6.1 # via phreeqpython phreeqpython==1.5.0 # via pyEQL (setup.py) -pillow==10.1.0 +pillow==10.2.0 # via matplotlib -pint==0.22 +pint==0.23 # via pyEQL (setup.py) -platformdirs==3.11.0 +platformdirs==4.2.0 # via # black - # tox # virtualenv -plotly==5.17.0 +plotly==5.18.0 # via pymatgen -pluggy==1.3.0 +pluggy==1.4.0 # via # pytest # tox -pre-commit==3.5.0 +pre-commit==3.6.0 # via pyEQL (setup.py) +py==1.11.0 + # via tox pybtex==0.24.0 # via pymatgen pycparser==2.21 # via cffi -pydantic==2.4.2 +pydantic==2.6.1 # via # fastapi # maggma # pydantic-settings -pydantic-core==2.10.1 +pydantic-core==2.16.2 # via pydantic -pydantic-settings==2.0.3 +pydantic-settings==2.1.0 # via maggma -pydash==7.0.6 +pydash==7.0.7 # via maggma -pygments==2.16.1 +pygments==2.17.2 # via # rich # sphinx -pymatgen==2023.10.11 +pymatgen==2024.1.27 # via pyEQL (setup.py) -pymongo==4.5.0 +pymongo==4.6.1 # via # maggma # mongogrant @@ -259,9 +251,7 @@ pyparsing==3.1.1 # via # matplotlib # periodictable -pyproject-api==1.6.1 - # via tox -pytest==7.4.2 +pytest==8.0.0 # via # pyEQL (setup.py) # pytest-cov @@ -273,18 +263,18 @@ python-dateutil==2.8.2 # maggma # matplotlib # pandas -python-dotenv==1.0.0 +python-dotenv==1.0.1 # via pydantic-settings -pytz==2023.3.post1 +pytz==2024.1 # via pandas pyyaml==6.0.1 # via # myst-parser # pre-commit # pybtex -pyzmq==25.1.1 +pyzmq==25.1.2 # via maggma -referencing==0.30.2 +referencing==0.33.0 # via # jsonschema # jsonschema-specifications @@ -293,23 +283,23 @@ requests==2.31.0 # mongogrant # pymatgen # sphinx -rich==13.6.0 +rich==13.7.0 # via pyEQL (setup.py) -rpds-py==0.10.6 +rpds-py==0.17.1 # via # jsonschema # referencing -ruamel-yaml==0.17.35 +ruamel-yaml==0.17.40 # via # maggma # pymatgen ruamel-yaml-clib==0.2.8 # via ruamel-yaml -ruff==0.1.0 +ruff==0.2.1 # via pyEQL (setup.py) -s3transfer==0.7.0 +s3transfer==0.10.0 # via boto3 -scipy==1.11.3 +scipy==1.12.0 # via # iapws # phreeqpython @@ -322,42 +312,38 @@ six==1.16.0 # latexcodec # pybtex # python-dateutil + # tox sniffio==1.3.0 # via anyio snowballstemmer==2.2.0 # via sphinx -spglib==2.1.0 +spglib==2.3.0 # via pymatgen sphinx==7.2.6 # via # myst-parser # pyEQL (setup.py) # sphinx-rtd-theme - # sphinxcontrib-applehelp - # sphinxcontrib-devhelp - # sphinxcontrib-htmlhelp # sphinxcontrib-jquery - # sphinxcontrib-qthelp - # sphinxcontrib-serializinghtml -sphinx-rtd-theme==1.3.0 +sphinx-rtd-theme==2.0.0 # via pyEQL (setup.py) -sphinxcontrib-applehelp==1.0.7 +sphinxcontrib-applehelp==1.0.8 # via sphinx -sphinxcontrib-devhelp==1.0.5 +sphinxcontrib-devhelp==1.0.6 # via sphinx -sphinxcontrib-htmlhelp==2.0.4 +sphinxcontrib-htmlhelp==2.0.5 # via sphinx sphinxcontrib-jquery==4.1 # via sphinx-rtd-theme sphinxcontrib-jsmath==1.0.1 # via sphinx -sphinxcontrib-qthelp==1.0.6 +sphinxcontrib-qthelp==1.0.7 # via sphinx -sphinxcontrib-serializinghtml==1.1.9 +sphinxcontrib-serializinghtml==1.1.10 # via sphinx sshtunnel==0.4.0 # via maggma -starlette==0.27.0 +starlette==0.36.3 # via fastapi sympy==1.12 # via pymatgen @@ -370,18 +356,18 @@ tomli==2.0.1 # black # coverage # mypy - # pyproject-api # pytest # tox -tox==4.11.3 +tox==3.28.0 # via pyEQL (setup.py) tqdm==4.66.1 # via # maggma # pymatgen -typing-extensions==4.8.0 +typing-extensions==4.9.0 # via # aioitertools + # anyio # black # fastapi # mypy @@ -391,7 +377,7 @@ typing-extensions==4.8.0 # pydash # starlette # uvicorn -tzdata==2023.3 +tzdata==2023.4 # via pandas uc-micro-py==1.0.2 # via linkify-it-py @@ -401,9 +387,9 @@ urllib3==1.26.18 # via # botocore # requests -uvicorn==0.23.2 +uvicorn==0.27.0.post1 # via maggma -virtualenv==20.24.5 +virtualenv==20.25.0 # via # pre-commit # tox diff --git a/requirements/windows-latest_py3.10.txt b/requirements/windows-latest_py3.10.txt index 3ccdc870..8a0aa14c 100644 --- a/requirements/windows-latest_py3.10.txt +++ b/requirements/windows-latest_py3.10.txt @@ -8,31 +8,29 @@ aioitertools==0.11.0 # via maggma annotated-types==0.6.0 # via pydantic -anyio==3.7.1 - # via - # fastapi - # starlette -attrs==23.1.0 +anyio==4.2.0 + # via starlette +attrs==23.2.0 # via # jsonschema # referencing -bcrypt==4.0.1 +bcrypt==4.1.2 # via paramiko -blinker==1.6.3 +blinker==1.7.0 # via flask -boto3==1.28.65 +boto3==1.34.35 # via maggma -botocore==1.31.65 +botocore==1.34.35 # via # boto3 # s3transfer -certifi==2023.7.22 +certifi==2024.2.2 # via requests cffi==1.16.0 # via # cryptography # pynacl -charset-normalizer==3.3.0 +charset-normalizer==3.3.2 # via requests click==8.1.7 # via @@ -43,23 +41,23 @@ colorama==0.4.6 # via # click # tqdm -contourpy==1.1.1 +contourpy==1.2.0 # via matplotlib -cryptography==41.0.4 +cryptography==42.0.2 # via paramiko cycler==0.12.1 # via matplotlib -dnspython==2.4.2 +dnspython==2.5.0 # via # maggma # pymongo -exceptiongroup==1.1.3 +exceptiongroup==1.2.0 # via anyio -fastapi==0.103.2 +fastapi==0.109.2 # via maggma -flask==3.0.0 +flask==3.0.2 # via mongogrant -fonttools==4.43.1 +fonttools==4.48.1 # via matplotlib future==0.18.3 # via uncertainties @@ -67,13 +65,13 @@ h11==0.14.0 # via uvicorn iapws==1.5.3 # via pyEQL (setup.py) -idna==3.4 +idna==3.6 # via # anyio # requests itsdangerous==2.1.2 # via flask -jinja2==3.1.2 +jinja2==3.1.3 # via flask jmespath==1.0.1 # via @@ -81,27 +79,27 @@ jmespath==1.0.1 # botocore joblib==1.3.2 # via pymatgen -jsonschema==4.19.1 +jsonschema==4.21.1 # via maggma -jsonschema-specifications==2023.7.1 +jsonschema-specifications==2023.12.1 # via jsonschema kiwisolver==1.4.5 # via matplotlib latexcodec==2.0.1 # via pybtex -maggma==0.57.4 +maggma==0.62.1 # via pyEQL (setup.py) -markupsafe==2.1.3 +markupsafe==2.1.5 # via # jinja2 # werkzeug -matplotlib==3.8.0 +matplotlib==3.8.2 # via pymatgen mongogrant==0.3.3 # via maggma mongomock==4.1.2 # via maggma -monty==2023.9.25 +monty==2024.2.2 # via # maggma # pyEQL (setup.py) @@ -110,9 +108,9 @@ mpmath==1.3.0 # via sympy msgpack==1.0.7 # via maggma -networkx==3.1 +networkx==3.2.1 # via pymatgen -numpy==1.26.1 +numpy==1.26.4 # via # contourpy # maggma @@ -123,7 +121,7 @@ numpy==1.26.1 # pymatgen # scipy # spglib -orjson==3.9.9 +orjson==3.9.13 # via maggma packaging==23.2 # via @@ -132,38 +130,38 @@ packaging==23.2 # plotly palettable==3.3.3 # via pymatgen -pandas==2.1.1 +pandas==2.2.0 # via pymatgen -paramiko==3.3.1 +paramiko==3.4.0 # via sshtunnel periodictable==1.6.1 # via phreeqpython phreeqpython==1.5.0 # via pyEQL (setup.py) -pillow==10.1.0 +pillow==10.2.0 # via matplotlib -pint==0.22 +pint==0.23 # via pyEQL (setup.py) -plotly==5.17.0 +plotly==5.18.0 # via pymatgen pybtex==0.24.0 # via pymatgen pycparser==2.21 # via cffi -pydantic==2.4.2 +pydantic==2.6.1 # via # fastapi # maggma # pydantic-settings -pydantic-core==2.10.1 +pydantic-core==2.16.2 # via pydantic -pydantic-settings==2.0.3 +pydantic-settings==2.1.0 # via maggma -pydash==7.0.6 +pydash==7.0.7 # via maggma -pymatgen==2023.10.11 +pymatgen==2024.1.27 # via pyEQL (setup.py) -pymongo==4.5.0 +pymongo==4.6.1 # via # maggma # mongogrant @@ -179,15 +177,15 @@ python-dateutil==2.8.2 # maggma # matplotlib # pandas -python-dotenv==1.0.0 +python-dotenv==1.0.1 # via pydantic-settings -pytz==2023.3.post1 +pytz==2024.1 # via pandas pyyaml==6.0.1 # via pybtex -pyzmq==25.1.1 +pyzmq==25.1.2 # via maggma -referencing==0.30.2 +referencing==0.33.0 # via # jsonschema # jsonschema-specifications @@ -195,19 +193,19 @@ requests==2.31.0 # via # mongogrant # pymatgen -rpds-py==0.10.6 +rpds-py==0.17.1 # via # jsonschema # referencing -ruamel-yaml==0.17.35 +ruamel-yaml==0.17.40 # via # maggma # pymatgen ruamel-yaml-clib==0.2.8 # via ruamel-yaml -s3transfer==0.7.0 +s3transfer==0.10.0 # via boto3 -scipy==1.11.3 +scipy==1.12.0 # via # iapws # phreeqpython @@ -222,11 +220,11 @@ six==1.16.0 # python-dateutil sniffio==1.3.0 # via anyio -spglib==2.1.0 +spglib==2.3.0 # via pymatgen sshtunnel==0.4.0 # via maggma -starlette==0.27.0 +starlette==0.36.3 # via fastapi sympy==1.12 # via pymatgen @@ -238,15 +236,16 @@ tqdm==4.66.1 # via # maggma # pymatgen -typing-extensions==4.8.0 +typing-extensions==4.9.0 # via + # anyio # fastapi # pint # pydantic # pydantic-core # pydash # uvicorn -tzdata==2023.3 +tzdata==2023.4 # via pandas uncertainties==3.1.7 # via pymatgen @@ -254,7 +253,7 @@ urllib3==2.0.7 # via # botocore # requests -uvicorn==0.23.2 +uvicorn==0.27.0.post1 # via maggma werkzeug==3.0.1 # via flask diff --git a/requirements/windows-latest_py3.10_extras.txt b/requirements/windows-latest_py3.10_extras.txt index 676bc839..e67eac44 100644 --- a/requirements/windows-latest_py3.10_extras.txt +++ b/requirements/windows-latest_py3.10_extras.txt @@ -6,35 +6,31 @@ # aioitertools==0.11.0 # via maggma -alabaster==0.7.13 +alabaster==0.7.16 # via sphinx annotated-types==0.6.0 # via pydantic -anyio==3.7.1 - # via - # fastapi - # starlette -attrs==23.1.0 +anyio==4.2.0 + # via starlette +attrs==23.2.0 # via # jsonschema # referencing -babel==2.13.0 +babel==2.14.0 # via sphinx -bcrypt==4.0.1 +bcrypt==4.1.2 # via paramiko -black==23.10.0 +black==24.1.1 # via pyEQL (setup.py) -blinker==1.6.3 +blinker==1.7.0 # via flask -boto3==1.28.65 +boto3==1.34.35 # via maggma -botocore==1.31.65 +botocore==1.34.35 # via # boto3 # s3transfer -cachetools==5.3.1 - # via tox -certifi==2023.7.22 +certifi==2024.2.2 # via requests cffi==1.16.0 # via @@ -42,9 +38,7 @@ cffi==1.16.0 # pynacl cfgv==3.4.0 # via pre-commit -chardet==5.2.0 - # via tox -charset-normalizer==3.3.0 +charset-normalizer==3.3.2 # via requests click==8.1.7 # via @@ -59,40 +53,40 @@ colorama==0.4.6 # sphinx # tox # tqdm -contourpy==1.1.1 +contourpy==1.2.0 # via matplotlib -coverage[toml]==7.3.2 +coverage[toml]==7.4.1 # via # coverage # pytest-cov -cryptography==41.0.4 +cryptography==42.0.2 # via paramiko cycler==0.12.1 # via matplotlib -distlib==0.3.7 +distlib==0.3.8 # via virtualenv -dnspython==2.4.2 +dnspython==2.5.0 # via # maggma # pymongo -docutils==0.18.1 +docutils==0.20.1 # via # myst-parser # sphinx # sphinx-rtd-theme -exceptiongroup==1.1.3 +exceptiongroup==1.2.0 # via # anyio # pytest -fastapi==0.103.2 +fastapi==0.109.2 # via maggma -filelock==3.12.4 +filelock==3.13.1 # via # tox # virtualenv -flask==3.0.0 +flask==3.0.2 # via mongogrant -fonttools==4.43.1 +fonttools==4.48.1 # via matplotlib future==0.18.3 # via uncertainties @@ -100,9 +94,9 @@ h11==0.14.0 # via uvicorn iapws==1.5.3 # via pyEQL (setup.py) -identify==2.5.30 +identify==2.5.33 # via pre-commit -idna==3.4 +idna==3.6 # via # anyio # requests @@ -112,7 +106,7 @@ iniconfig==2.0.0 # via pytest itsdangerous==2.1.2 # via flask -jinja2==3.1.2 +jinja2==3.1.3 # via # flask # myst-parser @@ -123,28 +117,28 @@ jmespath==1.0.1 # botocore joblib==1.3.2 # via pymatgen -jsonschema==4.19.1 +jsonschema==4.21.1 # via maggma -jsonschema-specifications==2023.7.1 +jsonschema-specifications==2023.12.1 # via jsonschema kiwisolver==1.4.5 # via matplotlib latexcodec==2.0.1 # via pybtex -linkify-it-py==2.0.2 +linkify-it-py==2.0.3 # via myst-parser -maggma==0.57.4 +maggma==0.62.1 # via pyEQL (setup.py) markdown-it-py==3.0.0 # via # mdit-py-plugins # myst-parser # rich -markupsafe==2.1.3 +markupsafe==2.1.5 # via # jinja2 # werkzeug -matplotlib==3.8.0 +matplotlib==3.8.2 # via pymatgen mdit-py-plugins==0.4.0 # via myst-parser @@ -154,7 +148,7 @@ mongogrant==0.3.3 # via maggma mongomock==4.1.2 # via maggma -monty==2023.9.25 +monty==2024.2.2 # via # maggma # pyEQL (setup.py) @@ -163,7 +157,7 @@ mpmath==1.3.0 # via sympy msgpack==1.0.7 # via maggma -mypy==1.6.0 +mypy==1.8.0 # via pyEQL (setup.py) mypy-extensions==1.0.0 # via @@ -171,11 +165,11 @@ mypy-extensions==1.0.0 # mypy myst-parser[linkify]==2.0.0 # via pyEQL (setup.py) -networkx==3.1 +networkx==3.2.1 # via pymatgen nodeenv==1.8.0 # via pre-commit -numpy==1.26.1 +numpy==1.26.4 # via # contourpy # maggma @@ -186,7 +180,7 @@ numpy==1.26.1 # pymatgen # scipy # spglib -orjson==3.9.9 +orjson==3.9.13 # via maggma packaging==23.2 # via @@ -194,61 +188,61 @@ packaging==23.2 # matplotlib # mongomock # plotly - # pyproject-api # pytest # sphinx # tox palettable==3.3.3 # via pymatgen -pandas==2.1.1 +pandas==2.2.0 # via pymatgen -paramiko==3.3.1 +paramiko==3.4.0 # via sshtunnel -pathspec==0.11.2 +pathspec==0.12.1 # via black periodictable==1.6.1 # via phreeqpython phreeqpython==1.5.0 # via pyEQL (setup.py) -pillow==10.1.0 +pillow==10.2.0 # via matplotlib -pint==0.22 +pint==0.23 # via pyEQL (setup.py) -platformdirs==3.11.0 +platformdirs==4.2.0 # via # black - # tox # virtualenv -plotly==5.17.0 +plotly==5.18.0 # via pymatgen -pluggy==1.3.0 +pluggy==1.4.0 # via # pytest # tox -pre-commit==3.5.0 +pre-commit==3.6.0 # via pyEQL (setup.py) +py==1.11.0 + # via tox pybtex==0.24.0 # via pymatgen pycparser==2.21 # via cffi -pydantic==2.4.2 +pydantic==2.6.1 # via # fastapi # maggma # pydantic-settings -pydantic-core==2.10.1 +pydantic-core==2.16.2 # via pydantic -pydantic-settings==2.0.3 +pydantic-settings==2.1.0 # via maggma -pydash==7.0.6 +pydash==7.0.7 # via maggma -pygments==2.16.1 +pygments==2.17.2 # via # rich # sphinx -pymatgen==2023.10.11 +pymatgen==2024.1.27 # via pyEQL (setup.py) -pymongo==4.5.0 +pymongo==4.6.1 # via # maggma # mongogrant @@ -258,9 +252,7 @@ pyparsing==3.1.1 # via # matplotlib # periodictable -pyproject-api==1.6.1 - # via tox -pytest==7.4.2 +pytest==8.0.0 # via # pyEQL (setup.py) # pytest-cov @@ -272,18 +264,18 @@ python-dateutil==2.8.2 # maggma # matplotlib # pandas -python-dotenv==1.0.0 +python-dotenv==1.0.1 # via pydantic-settings -pytz==2023.3.post1 +pytz==2024.1 # via pandas pyyaml==6.0.1 # via # myst-parser # pre-commit # pybtex -pyzmq==25.1.1 +pyzmq==25.1.2 # via maggma -referencing==0.30.2 +referencing==0.33.0 # via # jsonschema # jsonschema-specifications @@ -292,23 +284,23 @@ requests==2.31.0 # mongogrant # pymatgen # sphinx -rich==13.6.0 +rich==13.7.0 # via pyEQL (setup.py) -rpds-py==0.10.6 +rpds-py==0.17.1 # via # jsonschema # referencing -ruamel-yaml==0.17.35 +ruamel-yaml==0.17.40 # via # maggma # pymatgen ruamel-yaml-clib==0.2.8 # via ruamel-yaml -ruff==0.1.0 +ruff==0.2.1 # via pyEQL (setup.py) -s3transfer==0.7.0 +s3transfer==0.10.0 # via boto3 -scipy==1.11.3 +scipy==1.12.0 # via # iapws # phreeqpython @@ -321,42 +313,38 @@ six==1.16.0 # latexcodec # pybtex # python-dateutil + # tox sniffio==1.3.0 # via anyio snowballstemmer==2.2.0 # via sphinx -spglib==2.1.0 +spglib==2.3.0 # via pymatgen sphinx==7.2.6 # via # myst-parser # pyEQL (setup.py) # sphinx-rtd-theme - # sphinxcontrib-applehelp - # sphinxcontrib-devhelp - # sphinxcontrib-htmlhelp # sphinxcontrib-jquery - # sphinxcontrib-qthelp - # sphinxcontrib-serializinghtml -sphinx-rtd-theme==1.3.0 +sphinx-rtd-theme==2.0.0 # via pyEQL (setup.py) -sphinxcontrib-applehelp==1.0.7 +sphinxcontrib-applehelp==1.0.8 # via sphinx -sphinxcontrib-devhelp==1.0.5 +sphinxcontrib-devhelp==1.0.6 # via sphinx -sphinxcontrib-htmlhelp==2.0.4 +sphinxcontrib-htmlhelp==2.0.5 # via sphinx sphinxcontrib-jquery==4.1 # via sphinx-rtd-theme sphinxcontrib-jsmath==1.0.1 # via sphinx -sphinxcontrib-qthelp==1.0.6 +sphinxcontrib-qthelp==1.0.7 # via sphinx -sphinxcontrib-serializinghtml==1.1.9 +sphinxcontrib-serializinghtml==1.1.10 # via sphinx sshtunnel==0.4.0 # via maggma -starlette==0.27.0 +starlette==0.36.3 # via fastapi sympy==1.12 # via pymatgen @@ -369,17 +357,17 @@ tomli==2.0.1 # black # coverage # mypy - # pyproject-api # pytest # tox -tox==4.11.3 +tox==3.28.0 # via pyEQL (setup.py) tqdm==4.66.1 # via # maggma # pymatgen -typing-extensions==4.8.0 +typing-extensions==4.9.0 # via + # anyio # black # fastapi # mypy @@ -388,7 +376,7 @@ typing-extensions==4.8.0 # pydantic-core # pydash # uvicorn -tzdata==2023.3 +tzdata==2023.4 # via pandas uc-micro-py==1.0.2 # via linkify-it-py @@ -398,9 +386,9 @@ urllib3==2.0.7 # via # botocore # requests -uvicorn==0.23.2 +uvicorn==0.27.0.post1 # via maggma -virtualenv==20.24.5 +virtualenv==20.25.0 # via # pre-commit # tox diff --git a/requirements/windows-latest_py3.11.txt b/requirements/windows-latest_py3.11.txt index 6fb6831b..8b176f1a 100644 --- a/requirements/windows-latest_py3.11.txt +++ b/requirements/windows-latest_py3.11.txt @@ -8,31 +8,29 @@ aioitertools==0.11.0 # via maggma annotated-types==0.6.0 # via pydantic -anyio==3.7.1 - # via - # fastapi - # starlette -attrs==23.1.0 +anyio==4.2.0 + # via starlette +attrs==23.2.0 # via # jsonschema # referencing -bcrypt==4.0.1 +bcrypt==4.1.2 # via paramiko -blinker==1.6.3 +blinker==1.7.0 # via flask -boto3==1.28.65 +boto3==1.34.35 # via maggma -botocore==1.31.65 +botocore==1.34.35 # via # boto3 # s3transfer -certifi==2023.7.22 +certifi==2024.2.2 # via requests cffi==1.16.0 # via # cryptography # pynacl -charset-normalizer==3.3.0 +charset-normalizer==3.3.2 # via requests click==8.1.7 # via @@ -43,21 +41,21 @@ colorama==0.4.6 # via # click # tqdm -contourpy==1.1.1 +contourpy==1.2.0 # via matplotlib -cryptography==41.0.4 +cryptography==42.0.2 # via paramiko cycler==0.12.1 # via matplotlib -dnspython==2.4.2 +dnspython==2.5.0 # via # maggma # pymongo -fastapi==0.103.2 +fastapi==0.109.2 # via maggma -flask==3.0.0 +flask==3.0.2 # via mongogrant -fonttools==4.43.1 +fonttools==4.48.1 # via matplotlib future==0.18.3 # via uncertainties @@ -65,13 +63,13 @@ h11==0.14.0 # via uvicorn iapws==1.5.3 # via pyEQL (setup.py) -idna==3.4 +idna==3.6 # via # anyio # requests itsdangerous==2.1.2 # via flask -jinja2==3.1.2 +jinja2==3.1.3 # via flask jmespath==1.0.1 # via @@ -79,27 +77,27 @@ jmespath==1.0.1 # botocore joblib==1.3.2 # via pymatgen -jsonschema==4.19.1 +jsonschema==4.21.1 # via maggma -jsonschema-specifications==2023.7.1 +jsonschema-specifications==2023.12.1 # via jsonschema kiwisolver==1.4.5 # via matplotlib latexcodec==2.0.1 # via pybtex -maggma==0.57.4 +maggma==0.62.1 # via pyEQL (setup.py) -markupsafe==2.1.3 +markupsafe==2.1.5 # via # jinja2 # werkzeug -matplotlib==3.8.0 +matplotlib==3.8.2 # via pymatgen mongogrant==0.3.3 # via maggma mongomock==4.1.2 # via maggma -monty==2023.9.25 +monty==2024.2.2 # via # maggma # pyEQL (setup.py) @@ -108,9 +106,9 @@ mpmath==1.3.0 # via sympy msgpack==1.0.7 # via maggma -networkx==3.1 +networkx==3.2.1 # via pymatgen -numpy==1.26.1 +numpy==1.26.4 # via # contourpy # maggma @@ -121,7 +119,7 @@ numpy==1.26.1 # pymatgen # scipy # spglib -orjson==3.9.9 +orjson==3.9.13 # via maggma packaging==23.2 # via @@ -130,38 +128,38 @@ packaging==23.2 # plotly palettable==3.3.3 # via pymatgen -pandas==2.1.1 +pandas==2.2.0 # via pymatgen -paramiko==3.3.1 +paramiko==3.4.0 # via sshtunnel periodictable==1.6.1 # via phreeqpython phreeqpython==1.5.0 # via pyEQL (setup.py) -pillow==10.1.0 +pillow==10.2.0 # via matplotlib -pint==0.22 +pint==0.23 # via pyEQL (setup.py) -plotly==5.17.0 +plotly==5.18.0 # via pymatgen pybtex==0.24.0 # via pymatgen pycparser==2.21 # via cffi -pydantic==2.4.2 +pydantic==2.6.1 # via # fastapi # maggma # pydantic-settings -pydantic-core==2.10.1 +pydantic-core==2.16.2 # via pydantic -pydantic-settings==2.0.3 +pydantic-settings==2.1.0 # via maggma -pydash==7.0.6 +pydash==7.0.7 # via maggma -pymatgen==2023.10.11 +pymatgen==2024.1.27 # via pyEQL (setup.py) -pymongo==4.5.0 +pymongo==4.6.1 # via # maggma # mongogrant @@ -177,15 +175,15 @@ python-dateutil==2.8.2 # maggma # matplotlib # pandas -python-dotenv==1.0.0 +python-dotenv==1.0.1 # via pydantic-settings -pytz==2023.3.post1 +pytz==2024.1 # via pandas pyyaml==6.0.1 # via pybtex -pyzmq==25.1.1 +pyzmq==25.1.2 # via maggma -referencing==0.30.2 +referencing==0.33.0 # via # jsonschema # jsonschema-specifications @@ -193,19 +191,19 @@ requests==2.31.0 # via # mongogrant # pymatgen -rpds-py==0.10.6 +rpds-py==0.17.1 # via # jsonschema # referencing -ruamel-yaml==0.17.35 +ruamel-yaml==0.17.40 # via # maggma # pymatgen ruamel-yaml-clib==0.2.8 # via ruamel-yaml -s3transfer==0.7.0 +s3transfer==0.10.0 # via boto3 -scipy==1.11.3 +scipy==1.12.0 # via # iapws # phreeqpython @@ -220,11 +218,11 @@ six==1.16.0 # python-dateutil sniffio==1.3.0 # via anyio -spglib==2.1.0 +spglib==2.3.0 # via pymatgen sshtunnel==0.4.0 # via maggma -starlette==0.27.0 +starlette==0.36.3 # via fastapi sympy==1.12 # via pymatgen @@ -236,14 +234,14 @@ tqdm==4.66.1 # via # maggma # pymatgen -typing-extensions==4.8.0 +typing-extensions==4.9.0 # via # fastapi # pint # pydantic # pydantic-core # pydash -tzdata==2023.3 +tzdata==2023.4 # via pandas uncertainties==3.1.7 # via pymatgen @@ -251,7 +249,7 @@ urllib3==2.0.7 # via # botocore # requests -uvicorn==0.23.2 +uvicorn==0.27.0.post1 # via maggma werkzeug==3.0.1 # via flask diff --git a/requirements/windows-latest_py3.11_extras.txt b/requirements/windows-latest_py3.11_extras.txt index 09e5dbe3..3402a08b 100644 --- a/requirements/windows-latest_py3.11_extras.txt +++ b/requirements/windows-latest_py3.11_extras.txt @@ -6,35 +6,31 @@ # aioitertools==0.11.0 # via maggma -alabaster==0.7.13 +alabaster==0.7.16 # via sphinx annotated-types==0.6.0 # via pydantic -anyio==3.7.1 - # via - # fastapi - # starlette -attrs==23.1.0 +anyio==4.2.0 + # via starlette +attrs==23.2.0 # via # jsonschema # referencing -babel==2.13.0 +babel==2.14.0 # via sphinx -bcrypt==4.0.1 +bcrypt==4.1.2 # via paramiko -black==23.10.0 +black==24.1.1 # via pyEQL (setup.py) -blinker==1.6.3 +blinker==1.7.0 # via flask -boto3==1.28.65 +boto3==1.34.35 # via maggma -botocore==1.31.65 +botocore==1.34.35 # via # boto3 # s3transfer -cachetools==5.3.1 - # via tox -certifi==2023.7.22 +certifi==2024.2.2 # via requests cffi==1.16.0 # via @@ -42,9 +38,7 @@ cffi==1.16.0 # pynacl cfgv==3.4.0 # via pre-commit -chardet==5.2.0 - # via tox -charset-normalizer==3.3.0 +charset-normalizer==3.3.2 # via requests click==8.1.7 # via @@ -59,36 +53,36 @@ colorama==0.4.6 # sphinx # tox # tqdm -contourpy==1.1.1 +contourpy==1.2.0 # via matplotlib -coverage[toml]==7.3.2 +coverage[toml]==7.4.1 # via # coverage # pytest-cov -cryptography==41.0.4 +cryptography==42.0.2 # via paramiko cycler==0.12.1 # via matplotlib -distlib==0.3.7 +distlib==0.3.8 # via virtualenv -dnspython==2.4.2 +dnspython==2.5.0 # via # maggma # pymongo -docutils==0.18.1 +docutils==0.20.1 # via # myst-parser # sphinx # sphinx-rtd-theme -fastapi==0.103.2 +fastapi==0.109.2 # via maggma -filelock==3.12.4 +filelock==3.13.1 # via # tox # virtualenv -flask==3.0.0 +flask==3.0.2 # via mongogrant -fonttools==4.43.1 +fonttools==4.48.1 # via matplotlib future==0.18.3 # via uncertainties @@ -96,9 +90,9 @@ h11==0.14.0 # via uvicorn iapws==1.5.3 # via pyEQL (setup.py) -identify==2.5.30 +identify==2.5.33 # via pre-commit -idna==3.4 +idna==3.6 # via # anyio # requests @@ -108,7 +102,7 @@ iniconfig==2.0.0 # via pytest itsdangerous==2.1.2 # via flask -jinja2==3.1.2 +jinja2==3.1.3 # via # flask # myst-parser @@ -119,28 +113,28 @@ jmespath==1.0.1 # botocore joblib==1.3.2 # via pymatgen -jsonschema==4.19.1 +jsonschema==4.21.1 # via maggma -jsonschema-specifications==2023.7.1 +jsonschema-specifications==2023.12.1 # via jsonschema kiwisolver==1.4.5 # via matplotlib latexcodec==2.0.1 # via pybtex -linkify-it-py==2.0.2 +linkify-it-py==2.0.3 # via myst-parser -maggma==0.57.4 +maggma==0.62.1 # via pyEQL (setup.py) markdown-it-py==3.0.0 # via # mdit-py-plugins # myst-parser # rich -markupsafe==2.1.3 +markupsafe==2.1.5 # via # jinja2 # werkzeug -matplotlib==3.8.0 +matplotlib==3.8.2 # via pymatgen mdit-py-plugins==0.4.0 # via myst-parser @@ -150,7 +144,7 @@ mongogrant==0.3.3 # via maggma mongomock==4.1.2 # via maggma -monty==2023.9.25 +monty==2024.2.2 # via # maggma # pyEQL (setup.py) @@ -159,7 +153,7 @@ mpmath==1.3.0 # via sympy msgpack==1.0.7 # via maggma -mypy==1.6.0 +mypy==1.8.0 # via pyEQL (setup.py) mypy-extensions==1.0.0 # via @@ -167,11 +161,11 @@ mypy-extensions==1.0.0 # mypy myst-parser[linkify]==2.0.0 # via pyEQL (setup.py) -networkx==3.1 +networkx==3.2.1 # via pymatgen nodeenv==1.8.0 # via pre-commit -numpy==1.26.1 +numpy==1.26.4 # via # contourpy # maggma @@ -182,7 +176,7 @@ numpy==1.26.1 # pymatgen # scipy # spglib -orjson==3.9.9 +orjson==3.9.13 # via maggma packaging==23.2 # via @@ -190,61 +184,61 @@ packaging==23.2 # matplotlib # mongomock # plotly - # pyproject-api # pytest # sphinx # tox palettable==3.3.3 # via pymatgen -pandas==2.1.1 +pandas==2.2.0 # via pymatgen -paramiko==3.3.1 +paramiko==3.4.0 # via sshtunnel -pathspec==0.11.2 +pathspec==0.12.1 # via black periodictable==1.6.1 # via phreeqpython phreeqpython==1.5.0 # via pyEQL (setup.py) -pillow==10.1.0 +pillow==10.2.0 # via matplotlib -pint==0.22 +pint==0.23 # via pyEQL (setup.py) -platformdirs==3.11.0 +platformdirs==4.2.0 # via # black - # tox # virtualenv -plotly==5.17.0 +plotly==5.18.0 # via pymatgen -pluggy==1.3.0 +pluggy==1.4.0 # via # pytest # tox -pre-commit==3.5.0 +pre-commit==3.6.0 # via pyEQL (setup.py) +py==1.11.0 + # via tox pybtex==0.24.0 # via pymatgen pycparser==2.21 # via cffi -pydantic==2.4.2 +pydantic==2.6.1 # via # fastapi # maggma # pydantic-settings -pydantic-core==2.10.1 +pydantic-core==2.16.2 # via pydantic -pydantic-settings==2.0.3 +pydantic-settings==2.1.0 # via maggma -pydash==7.0.6 +pydash==7.0.7 # via maggma -pygments==2.16.1 +pygments==2.17.2 # via # rich # sphinx -pymatgen==2023.10.11 +pymatgen==2024.1.27 # via pyEQL (setup.py) -pymongo==4.5.0 +pymongo==4.6.1 # via # maggma # mongogrant @@ -254,9 +248,7 @@ pyparsing==3.1.1 # via # matplotlib # periodictable -pyproject-api==1.6.1 - # via tox -pytest==7.4.2 +pytest==8.0.0 # via # pyEQL (setup.py) # pytest-cov @@ -268,18 +260,18 @@ python-dateutil==2.8.2 # maggma # matplotlib # pandas -python-dotenv==1.0.0 +python-dotenv==1.0.1 # via pydantic-settings -pytz==2023.3.post1 +pytz==2024.1 # via pandas pyyaml==6.0.1 # via # myst-parser # pre-commit # pybtex -pyzmq==25.1.1 +pyzmq==25.1.2 # via maggma -referencing==0.30.2 +referencing==0.33.0 # via # jsonschema # jsonschema-specifications @@ -288,23 +280,23 @@ requests==2.31.0 # mongogrant # pymatgen # sphinx -rich==13.6.0 +rich==13.7.0 # via pyEQL (setup.py) -rpds-py==0.10.6 +rpds-py==0.17.1 # via # jsonschema # referencing -ruamel-yaml==0.17.35 +ruamel-yaml==0.17.40 # via # maggma # pymatgen ruamel-yaml-clib==0.2.8 # via ruamel-yaml -ruff==0.1.0 +ruff==0.2.1 # via pyEQL (setup.py) -s3transfer==0.7.0 +s3transfer==0.10.0 # via boto3 -scipy==1.11.3 +scipy==1.12.0 # via # iapws # phreeqpython @@ -317,42 +309,38 @@ six==1.16.0 # latexcodec # pybtex # python-dateutil + # tox sniffio==1.3.0 # via anyio snowballstemmer==2.2.0 # via sphinx -spglib==2.1.0 +spglib==2.3.0 # via pymatgen sphinx==7.2.6 # via # myst-parser # pyEQL (setup.py) # sphinx-rtd-theme - # sphinxcontrib-applehelp - # sphinxcontrib-devhelp - # sphinxcontrib-htmlhelp # sphinxcontrib-jquery - # sphinxcontrib-qthelp - # sphinxcontrib-serializinghtml -sphinx-rtd-theme==1.3.0 +sphinx-rtd-theme==2.0.0 # via pyEQL (setup.py) -sphinxcontrib-applehelp==1.0.7 +sphinxcontrib-applehelp==1.0.8 # via sphinx -sphinxcontrib-devhelp==1.0.5 +sphinxcontrib-devhelp==1.0.6 # via sphinx -sphinxcontrib-htmlhelp==2.0.4 +sphinxcontrib-htmlhelp==2.0.5 # via sphinx sphinxcontrib-jquery==4.1 # via sphinx-rtd-theme sphinxcontrib-jsmath==1.0.1 # via sphinx -sphinxcontrib-qthelp==1.0.6 +sphinxcontrib-qthelp==1.0.7 # via sphinx -sphinxcontrib-serializinghtml==1.1.9 +sphinxcontrib-serializinghtml==1.1.10 # via sphinx sshtunnel==0.4.0 # via maggma -starlette==0.27.0 +starlette==0.36.3 # via fastapi sympy==1.12 # via pymatgen @@ -360,13 +348,13 @@ tabulate==0.9.0 # via pymatgen tenacity==8.2.3 # via plotly -tox==4.11.3 +tox==3.28.0 # via pyEQL (setup.py) tqdm==4.66.1 # via # maggma # pymatgen -typing-extensions==4.8.0 +typing-extensions==4.9.0 # via # fastapi # mypy @@ -374,7 +362,7 @@ typing-extensions==4.8.0 # pydantic # pydantic-core # pydash -tzdata==2023.3 +tzdata==2023.4 # via pandas uc-micro-py==1.0.2 # via linkify-it-py @@ -384,9 +372,9 @@ urllib3==2.0.7 # via # botocore # requests -uvicorn==0.23.2 +uvicorn==0.27.0.post1 # via maggma -virtualenv==20.24.5 +virtualenv==20.25.0 # via # pre-commit # tox diff --git a/requirements/windows-latest_py3.12.txt b/requirements/windows-latest_py3.12.txt new file mode 100644 index 00000000..6aec2909 --- /dev/null +++ b/requirements/windows-latest_py3.12.txt @@ -0,0 +1,258 @@ +# +# This file is autogenerated by pip-compile with Python 3.12 +# by the following command: +# +# pip-compile --output-file=requirements/windows-latest_py3.12.txt +# +aioitertools==0.11.0 + # via maggma +annotated-types==0.6.0 + # via pydantic +anyio==4.2.0 + # via starlette +attrs==23.2.0 + # via + # jsonschema + # referencing +bcrypt==4.1.2 + # via paramiko +blinker==1.7.0 + # via flask +boto3==1.34.35 + # via maggma +botocore==1.34.35 + # via + # boto3 + # s3transfer +certifi==2024.2.2 + # via requests +cffi==1.16.0 + # via + # cryptography + # pynacl +charset-normalizer==3.3.2 + # via requests +click==8.1.7 + # via + # flask + # mongogrant + # uvicorn +colorama==0.4.6 + # via + # click + # tqdm +contourpy==1.2.0 + # via matplotlib +cryptography==42.0.2 + # via paramiko +cycler==0.12.1 + # via matplotlib +dnspython==2.5.0 + # via + # maggma + # pymongo +fastapi==0.109.2 + # via maggma +flask==3.0.2 + # via mongogrant +fonttools==4.48.1 + # via matplotlib +future==0.18.3 + # via uncertainties +h11==0.14.0 + # via uvicorn +iapws==1.5.3 + # via pyEQL (setup.py) +idna==3.6 + # via + # anyio + # requests +itsdangerous==2.1.2 + # via flask +jinja2==3.1.3 + # via flask +jmespath==1.0.1 + # via + # boto3 + # botocore +joblib==1.3.2 + # via pymatgen +jsonschema==4.21.1 + # via maggma +jsonschema-specifications==2023.12.1 + # via jsonschema +kiwisolver==1.4.5 + # via matplotlib +latexcodec==2.0.1 + # via pybtex +maggma==0.62.1 + # via pyEQL (setup.py) +markupsafe==2.1.5 + # via + # jinja2 + # werkzeug +matplotlib==3.8.2 + # via pymatgen +mongogrant==0.3.3 + # via maggma +mongomock==4.1.2 + # via maggma +monty==2024.2.2 + # via + # maggma + # pyEQL (setup.py) + # pymatgen +mpmath==1.3.0 + # via sympy +msgpack==1.0.7 + # via maggma +networkx==3.2.1 + # via pymatgen +numpy==1.26.4 + # via + # contourpy + # maggma + # matplotlib + # pandas + # periodictable + # pyEQL (setup.py) + # pymatgen + # scipy + # spglib +orjson==3.9.13 + # via maggma +packaging==23.2 + # via + # matplotlib + # mongomock + # plotly +palettable==3.3.3 + # via pymatgen +pandas==2.2.0 + # via pymatgen +paramiko==3.4.0 + # via sshtunnel +periodictable==1.6.1 + # via phreeqpython +phreeqpython==1.5.0 + # via pyEQL (setup.py) +pillow==10.2.0 + # via matplotlib +pint==0.23 + # via pyEQL (setup.py) +plotly==5.18.0 + # via pymatgen +pybtex==0.24.0 + # via pymatgen +pycparser==2.21 + # via cffi +pydantic==2.6.1 + # via + # fastapi + # maggma + # pydantic-settings +pydantic-core==2.16.2 + # via pydantic +pydantic-settings==2.1.0 + # via maggma +pydash==7.0.7 + # via maggma +pymatgen==2024.1.27 + # via pyEQL (setup.py) +pymongo==4.6.1 + # via + # maggma + # mongogrant +pynacl==1.5.0 + # via paramiko +pyparsing==3.1.1 + # via + # matplotlib + # periodictable +python-dateutil==2.8.2 + # via + # botocore + # maggma + # matplotlib + # pandas +python-dotenv==1.0.1 + # via pydantic-settings +pytz==2024.1 + # via pandas +pyyaml==6.0.1 + # via pybtex +pyzmq==25.1.2 + # via maggma +referencing==0.33.0 + # via + # jsonschema + # jsonschema-specifications +requests==2.31.0 + # via + # mongogrant + # pymatgen +rpds-py==0.17.1 + # via + # jsonschema + # referencing +ruamel-yaml==0.17.40 + # via + # maggma + # pymatgen +ruamel-yaml-clib==0.2.8 + # via ruamel-yaml +s3transfer==0.10.0 + # via boto3 +scipy==1.12.0 + # via + # iapws + # phreeqpython + # pyEQL (setup.py) + # pymatgen +sentinels==1.0.0 + # via mongomock +six==1.16.0 + # via + # latexcodec + # pybtex + # python-dateutil +sniffio==1.3.0 + # via anyio +spglib==2.3.0 + # via pymatgen +sshtunnel==0.4.0 + # via maggma +starlette==0.36.3 + # via fastapi +sympy==1.12 + # via pymatgen +tabulate==0.9.0 + # via pymatgen +tenacity==8.2.3 + # via plotly +tqdm==4.66.1 + # via + # maggma + # pymatgen +typing-extensions==4.9.0 + # via + # fastapi + # pint + # pydantic + # pydantic-core + # pydash +tzdata==2023.4 + # via pandas +uncertainties==3.1.7 + # via pymatgen +urllib3==2.0.7 + # via + # botocore + # requests +uvicorn==0.27.0.post1 + # via maggma +werkzeug==3.0.1 + # via flask + +# The following packages are considered to be unsafe in a requirements file: +# setuptools diff --git a/requirements/windows-latest_py3.12_extras.txt b/requirements/windows-latest_py3.12_extras.txt new file mode 100644 index 00000000..59fa46bc --- /dev/null +++ b/requirements/windows-latest_py3.12_extras.txt @@ -0,0 +1,385 @@ +# +# This file is autogenerated by pip-compile with Python 3.12 +# by the following command: +# +# pip-compile --all-extras --output-file=requirements/windows-latest_py3.12_extras.txt +# +aioitertools==0.11.0 + # via maggma +alabaster==0.7.16 + # via sphinx +annotated-types==0.6.0 + # via pydantic +anyio==4.2.0 + # via starlette +attrs==23.2.0 + # via + # jsonschema + # referencing +babel==2.14.0 + # via sphinx +bcrypt==4.1.2 + # via paramiko +black==24.1.1 + # via pyEQL (setup.py) +blinker==1.7.0 + # via flask +boto3==1.34.35 + # via maggma +botocore==1.34.35 + # via + # boto3 + # s3transfer +certifi==2024.2.2 + # via requests +cffi==1.16.0 + # via + # cryptography + # pynacl +cfgv==3.4.0 + # via pre-commit +charset-normalizer==3.3.2 + # via requests +click==8.1.7 + # via + # black + # flask + # mongogrant + # uvicorn +colorama==0.4.6 + # via + # click + # pytest + # sphinx + # tox + # tqdm +contourpy==1.2.0 + # via matplotlib +coverage[toml]==7.4.1 + # via + # coverage + # pytest-cov +cryptography==42.0.2 + # via paramiko +cycler==0.12.1 + # via matplotlib +distlib==0.3.8 + # via virtualenv +dnspython==2.5.0 + # via + # maggma + # pymongo +docutils==0.20.1 + # via + # myst-parser + # sphinx + # sphinx-rtd-theme +fastapi==0.109.2 + # via maggma +filelock==3.13.1 + # via + # tox + # virtualenv +flask==3.0.2 + # via mongogrant +fonttools==4.48.1 + # via matplotlib +future==0.18.3 + # via uncertainties +h11==0.14.0 + # via uvicorn +iapws==1.5.3 + # via pyEQL (setup.py) +identify==2.5.33 + # via pre-commit +idna==3.6 + # via + # anyio + # requests +imagesize==1.4.1 + # via sphinx +iniconfig==2.0.0 + # via pytest +itsdangerous==2.1.2 + # via flask +jinja2==3.1.3 + # via + # flask + # myst-parser + # sphinx +jmespath==1.0.1 + # via + # boto3 + # botocore +joblib==1.3.2 + # via pymatgen +jsonschema==4.21.1 + # via maggma +jsonschema-specifications==2023.12.1 + # via jsonschema +kiwisolver==1.4.5 + # via matplotlib +latexcodec==2.0.1 + # via pybtex +linkify-it-py==2.0.3 + # via myst-parser +maggma==0.62.1 + # via pyEQL (setup.py) +markdown-it-py==3.0.0 + # via + # mdit-py-plugins + # myst-parser + # rich +markupsafe==2.1.5 + # via + # jinja2 + # werkzeug +matplotlib==3.8.2 + # via pymatgen +mdit-py-plugins==0.4.0 + # via myst-parser +mdurl==0.1.2 + # via markdown-it-py +mongogrant==0.3.3 + # via maggma +mongomock==4.1.2 + # via maggma +monty==2024.2.2 + # via + # maggma + # pyEQL (setup.py) + # pymatgen +mpmath==1.3.0 + # via sympy +msgpack==1.0.7 + # via maggma +mypy==1.8.0 + # via pyEQL (setup.py) +mypy-extensions==1.0.0 + # via + # black + # mypy +myst-parser[linkify]==2.0.0 + # via pyEQL (setup.py) +networkx==3.2.1 + # via pymatgen +nodeenv==1.8.0 + # via pre-commit +numpy==1.26.4 + # via + # contourpy + # maggma + # matplotlib + # pandas + # periodictable + # pyEQL (setup.py) + # pymatgen + # scipy + # spglib +orjson==3.9.13 + # via maggma +packaging==23.2 + # via + # black + # matplotlib + # mongomock + # plotly + # pytest + # sphinx + # tox +palettable==3.3.3 + # via pymatgen +pandas==2.2.0 + # via pymatgen +paramiko==3.4.0 + # via sshtunnel +pathspec==0.12.1 + # via black +periodictable==1.6.1 + # via phreeqpython +phreeqpython==1.5.0 + # via pyEQL (setup.py) +pillow==10.2.0 + # via matplotlib +pint==0.23 + # via pyEQL (setup.py) +platformdirs==4.2.0 + # via + # black + # virtualenv +plotly==5.18.0 + # via pymatgen +pluggy==1.4.0 + # via + # pytest + # tox +pre-commit==3.6.0 + # via pyEQL (setup.py) +py==1.11.0 + # via tox +pybtex==0.24.0 + # via pymatgen +pycparser==2.21 + # via cffi +pydantic==2.6.1 + # via + # fastapi + # maggma + # pydantic-settings +pydantic-core==2.16.2 + # via pydantic +pydantic-settings==2.1.0 + # via maggma +pydash==7.0.7 + # via maggma +pygments==2.17.2 + # via + # rich + # sphinx +pymatgen==2024.1.27 + # via pyEQL (setup.py) +pymongo==4.6.1 + # via + # maggma + # mongogrant +pynacl==1.5.0 + # via paramiko +pyparsing==3.1.1 + # via + # matplotlib + # periodictable +pytest==8.0.0 + # via + # pyEQL (setup.py) + # pytest-cov +pytest-cov==4.1.0 + # via pyEQL (setup.py) +python-dateutil==2.8.2 + # via + # botocore + # maggma + # matplotlib + # pandas +python-dotenv==1.0.1 + # via pydantic-settings +pytz==2024.1 + # via pandas +pyyaml==6.0.1 + # via + # myst-parser + # pre-commit + # pybtex +pyzmq==25.1.2 + # via maggma +referencing==0.33.0 + # via + # jsonschema + # jsonschema-specifications +requests==2.31.0 + # via + # mongogrant + # pymatgen + # sphinx +rich==13.7.0 + # via pyEQL (setup.py) +rpds-py==0.17.1 + # via + # jsonschema + # referencing +ruamel-yaml==0.17.40 + # via + # maggma + # pymatgen +ruamel-yaml-clib==0.2.8 + # via ruamel-yaml +ruff==0.2.1 + # via pyEQL (setup.py) +s3transfer==0.10.0 + # via boto3 +scipy==1.12.0 + # via + # iapws + # phreeqpython + # pyEQL (setup.py) + # pymatgen +sentinels==1.0.0 + # via mongomock +six==1.16.0 + # via + # latexcodec + # pybtex + # python-dateutil + # tox +sniffio==1.3.0 + # via anyio +snowballstemmer==2.2.0 + # via sphinx +spglib==2.3.0 + # via pymatgen +sphinx==7.2.6 + # via + # myst-parser + # pyEQL (setup.py) + # sphinx-rtd-theme + # sphinxcontrib-jquery +sphinx-rtd-theme==2.0.0 + # via pyEQL (setup.py) +sphinxcontrib-applehelp==1.0.8 + # via sphinx +sphinxcontrib-devhelp==1.0.6 + # via sphinx +sphinxcontrib-htmlhelp==2.0.5 + # via sphinx +sphinxcontrib-jquery==4.1 + # via sphinx-rtd-theme +sphinxcontrib-jsmath==1.0.1 + # via sphinx +sphinxcontrib-qthelp==1.0.7 + # via sphinx +sphinxcontrib-serializinghtml==1.1.10 + # via sphinx +sshtunnel==0.4.0 + # via maggma +starlette==0.36.3 + # via fastapi +sympy==1.12 + # via pymatgen +tabulate==0.9.0 + # via pymatgen +tenacity==8.2.3 + # via plotly +tox==3.28.0 + # via pyEQL (setup.py) +tqdm==4.66.1 + # via + # maggma + # pymatgen +typing-extensions==4.9.0 + # via + # fastapi + # mypy + # pint + # pydantic + # pydantic-core + # pydash +tzdata==2023.4 + # via pandas +uc-micro-py==1.0.2 + # via linkify-it-py +uncertainties==3.1.7 + # via pymatgen +urllib3==2.0.7 + # via + # botocore + # requests +uvicorn==0.27.0.post1 + # via maggma +virtualenv==20.25.0 + # via + # pre-commit + # tox +werkzeug==3.0.1 + # via flask + +# The following packages are considered to be unsafe in a requirements file: +# setuptools diff --git a/requirements/windows-latest_py3.9.txt b/requirements/windows-latest_py3.9.txt index 1649f00e..a115f3a5 100644 --- a/requirements/windows-latest_py3.9.txt +++ b/requirements/windows-latest_py3.9.txt @@ -8,31 +8,29 @@ aioitertools==0.11.0 # via maggma annotated-types==0.6.0 # via pydantic -anyio==3.7.1 - # via - # fastapi - # starlette -attrs==23.1.0 +anyio==4.2.0 + # via starlette +attrs==23.2.0 # via # jsonschema # referencing -bcrypt==4.0.1 +bcrypt==4.1.2 # via paramiko -blinker==1.6.3 +blinker==1.7.0 # via flask -boto3==1.28.65 +boto3==1.34.35 # via maggma -botocore==1.31.65 +botocore==1.34.35 # via # boto3 # s3transfer -certifi==2023.7.22 +certifi==2024.2.2 # via requests cffi==1.16.0 # via # cryptography # pynacl -charset-normalizer==3.3.0 +charset-normalizer==3.3.2 # via requests click==8.1.7 # via @@ -43,23 +41,23 @@ colorama==0.4.6 # via # click # tqdm -contourpy==1.1.1 +contourpy==1.2.0 # via matplotlib -cryptography==41.0.4 +cryptography==42.0.2 # via paramiko cycler==0.12.1 # via matplotlib -dnspython==2.4.2 +dnspython==2.5.0 # via # maggma # pymongo -exceptiongroup==1.1.3 +exceptiongroup==1.2.0 # via anyio -fastapi==0.103.2 +fastapi==0.109.2 # via maggma -flask==3.0.0 +flask==3.0.2 # via mongogrant -fonttools==4.43.1 +fonttools==4.48.1 # via matplotlib future==0.18.3 # via uncertainties @@ -67,17 +65,17 @@ h11==0.14.0 # via uvicorn iapws==1.5.3 # via pyEQL (setup.py) -idna==3.4 +idna==3.6 # via # anyio # requests -importlib-metadata==6.8.0 +importlib-metadata==7.0.1 # via flask -importlib-resources==6.1.0 +importlib-resources==6.1.1 # via matplotlib itsdangerous==2.1.2 # via flask -jinja2==3.1.2 +jinja2==3.1.3 # via flask jmespath==1.0.1 # via @@ -85,27 +83,27 @@ jmespath==1.0.1 # botocore joblib==1.3.2 # via pymatgen -jsonschema==4.19.1 +jsonschema==4.21.1 # via maggma -jsonschema-specifications==2023.7.1 +jsonschema-specifications==2023.12.1 # via jsonschema kiwisolver==1.4.5 # via matplotlib latexcodec==2.0.1 # via pybtex -maggma==0.57.4 +maggma==0.62.1 # via pyEQL (setup.py) -markupsafe==2.1.3 +markupsafe==2.1.5 # via # jinja2 # werkzeug -matplotlib==3.8.0 +matplotlib==3.8.2 # via pymatgen mongogrant==0.3.3 # via maggma mongomock==4.1.2 # via maggma -monty==2023.9.25 +monty==2024.2.2 # via # maggma # pyEQL (setup.py) @@ -114,9 +112,9 @@ mpmath==1.3.0 # via sympy msgpack==1.0.7 # via maggma -networkx==3.1 +networkx==3.2.1 # via pymatgen -numpy==1.26.1 +numpy==1.26.4 # via # contourpy # maggma @@ -127,7 +125,7 @@ numpy==1.26.1 # pymatgen # scipy # spglib -orjson==3.9.9 +orjson==3.9.13 # via maggma packaging==23.2 # via @@ -136,38 +134,38 @@ packaging==23.2 # plotly palettable==3.3.3 # via pymatgen -pandas==2.1.1 +pandas==2.2.0 # via pymatgen -paramiko==3.3.1 +paramiko==3.4.0 # via sshtunnel periodictable==1.6.1 # via phreeqpython phreeqpython==1.5.0 # via pyEQL (setup.py) -pillow==10.1.0 +pillow==10.2.0 # via matplotlib -pint==0.22 +pint==0.23 # via pyEQL (setup.py) -plotly==5.17.0 +plotly==5.18.0 # via pymatgen pybtex==0.24.0 # via pymatgen pycparser==2.21 # via cffi -pydantic==2.4.2 +pydantic==2.6.1 # via # fastapi # maggma # pydantic-settings -pydantic-core==2.10.1 +pydantic-core==2.16.2 # via pydantic -pydantic-settings==2.0.3 +pydantic-settings==2.1.0 # via maggma -pydash==7.0.6 +pydash==7.0.7 # via maggma -pymatgen==2023.10.11 +pymatgen==2024.1.27 # via pyEQL (setup.py) -pymongo==4.5.0 +pymongo==4.6.1 # via # maggma # mongogrant @@ -183,15 +181,15 @@ python-dateutil==2.8.2 # maggma # matplotlib # pandas -python-dotenv==1.0.0 +python-dotenv==1.0.1 # via pydantic-settings -pytz==2023.3.post1 +pytz==2024.1 # via pandas pyyaml==6.0.1 # via pybtex -pyzmq==25.1.1 +pyzmq==25.1.2 # via maggma -referencing==0.30.2 +referencing==0.33.0 # via # jsonschema # jsonschema-specifications @@ -199,19 +197,19 @@ requests==2.31.0 # via # mongogrant # pymatgen -rpds-py==0.10.6 +rpds-py==0.17.1 # via # jsonschema # referencing -ruamel-yaml==0.17.35 +ruamel-yaml==0.17.40 # via # maggma # pymatgen ruamel-yaml-clib==0.2.8 # via ruamel-yaml -s3transfer==0.7.0 +s3transfer==0.10.0 # via boto3 -scipy==1.11.3 +scipy==1.12.0 # via # iapws # phreeqpython @@ -226,11 +224,11 @@ six==1.16.0 # python-dateutil sniffio==1.3.0 # via anyio -spglib==2.1.0 +spglib==2.3.0 # via pymatgen sshtunnel==0.4.0 # via maggma -starlette==0.27.0 +starlette==0.36.3 # via fastapi sympy==1.12 # via pymatgen @@ -242,9 +240,10 @@ tqdm==4.66.1 # via # maggma # pymatgen -typing-extensions==4.8.0 +typing-extensions==4.9.0 # via # aioitertools + # anyio # fastapi # pint # pydantic @@ -252,7 +251,7 @@ typing-extensions==4.8.0 # pydash # starlette # uvicorn -tzdata==2023.3 +tzdata==2023.4 # via pandas uncertainties==3.1.7 # via pymatgen @@ -260,7 +259,7 @@ urllib3==1.26.18 # via # botocore # requests -uvicorn==0.23.2 +uvicorn==0.27.0.post1 # via maggma werkzeug==3.0.1 # via flask diff --git a/requirements/windows-latest_py3.9_extras.txt b/requirements/windows-latest_py3.9_extras.txt index b009d675..c3bf287b 100644 --- a/requirements/windows-latest_py3.9_extras.txt +++ b/requirements/windows-latest_py3.9_extras.txt @@ -6,35 +6,31 @@ # aioitertools==0.11.0 # via maggma -alabaster==0.7.13 +alabaster==0.7.16 # via sphinx annotated-types==0.6.0 # via pydantic -anyio==3.7.1 - # via - # fastapi - # starlette -attrs==23.1.0 +anyio==4.2.0 + # via starlette +attrs==23.2.0 # via # jsonschema # referencing -babel==2.13.0 +babel==2.14.0 # via sphinx -bcrypt==4.0.1 +bcrypt==4.1.2 # via paramiko -black==23.10.0 +black==24.1.1 # via pyEQL (setup.py) -blinker==1.6.3 +blinker==1.7.0 # via flask -boto3==1.28.65 +boto3==1.34.35 # via maggma -botocore==1.31.65 +botocore==1.34.35 # via # boto3 # s3transfer -cachetools==5.3.1 - # via tox -certifi==2023.7.22 +certifi==2024.2.2 # via requests cffi==1.16.0 # via @@ -42,9 +38,7 @@ cffi==1.16.0 # pynacl cfgv==3.4.0 # via pre-commit -chardet==5.2.0 - # via tox -charset-normalizer==3.3.0 +charset-normalizer==3.3.2 # via requests click==8.1.7 # via @@ -59,40 +53,40 @@ colorama==0.4.6 # sphinx # tox # tqdm -contourpy==1.1.1 +contourpy==1.2.0 # via matplotlib -coverage[toml]==7.3.2 +coverage[toml]==7.4.1 # via # coverage # pytest-cov -cryptography==41.0.4 +cryptography==42.0.2 # via paramiko cycler==0.12.1 # via matplotlib -distlib==0.3.7 +distlib==0.3.8 # via virtualenv -dnspython==2.4.2 +dnspython==2.5.0 # via # maggma # pymongo -docutils==0.18.1 +docutils==0.20.1 # via # myst-parser # sphinx # sphinx-rtd-theme -exceptiongroup==1.1.3 +exceptiongroup==1.2.0 # via # anyio # pytest -fastapi==0.103.2 +fastapi==0.109.2 # via maggma -filelock==3.12.4 +filelock==3.13.1 # via # tox # virtualenv -flask==3.0.0 +flask==3.0.2 # via mongogrant -fonttools==4.43.1 +fonttools==4.48.1 # via matplotlib future==0.18.3 # via uncertainties @@ -100,25 +94,25 @@ h11==0.14.0 # via uvicorn iapws==1.5.3 # via pyEQL (setup.py) -identify==2.5.30 +identify==2.5.33 # via pre-commit -idna==3.4 +idna==3.6 # via # anyio # requests imagesize==1.4.1 # via sphinx -importlib-metadata==6.8.0 +importlib-metadata==7.0.1 # via # flask # sphinx -importlib-resources==6.1.0 +importlib-resources==6.1.1 # via matplotlib iniconfig==2.0.0 # via pytest itsdangerous==2.1.2 # via flask -jinja2==3.1.2 +jinja2==3.1.3 # via # flask # myst-parser @@ -129,28 +123,28 @@ jmespath==1.0.1 # botocore joblib==1.3.2 # via pymatgen -jsonschema==4.19.1 +jsonschema==4.21.1 # via maggma -jsonschema-specifications==2023.7.1 +jsonschema-specifications==2023.12.1 # via jsonschema kiwisolver==1.4.5 # via matplotlib latexcodec==2.0.1 # via pybtex -linkify-it-py==2.0.2 +linkify-it-py==2.0.3 # via myst-parser -maggma==0.57.4 +maggma==0.62.1 # via pyEQL (setup.py) markdown-it-py==3.0.0 # via # mdit-py-plugins # myst-parser # rich -markupsafe==2.1.3 +markupsafe==2.1.5 # via # jinja2 # werkzeug -matplotlib==3.8.0 +matplotlib==3.8.2 # via pymatgen mdit-py-plugins==0.4.0 # via myst-parser @@ -160,7 +154,7 @@ mongogrant==0.3.3 # via maggma mongomock==4.1.2 # via maggma -monty==2023.9.25 +monty==2024.2.2 # via # maggma # pyEQL (setup.py) @@ -169,7 +163,7 @@ mpmath==1.3.0 # via sympy msgpack==1.0.7 # via maggma -mypy==1.6.0 +mypy==1.8.0 # via pyEQL (setup.py) mypy-extensions==1.0.0 # via @@ -177,11 +171,11 @@ mypy-extensions==1.0.0 # mypy myst-parser[linkify]==2.0.0 # via pyEQL (setup.py) -networkx==3.1 +networkx==3.2.1 # via pymatgen nodeenv==1.8.0 # via pre-commit -numpy==1.26.1 +numpy==1.26.4 # via # contourpy # maggma @@ -192,7 +186,7 @@ numpy==1.26.1 # pymatgen # scipy # spglib -orjson==3.9.9 +orjson==3.9.13 # via maggma packaging==23.2 # via @@ -200,61 +194,61 @@ packaging==23.2 # matplotlib # mongomock # plotly - # pyproject-api # pytest # sphinx # tox palettable==3.3.3 # via pymatgen -pandas==2.1.1 +pandas==2.2.0 # via pymatgen -paramiko==3.3.1 +paramiko==3.4.0 # via sshtunnel -pathspec==0.11.2 +pathspec==0.12.1 # via black periodictable==1.6.1 # via phreeqpython phreeqpython==1.5.0 # via pyEQL (setup.py) -pillow==10.1.0 +pillow==10.2.0 # via matplotlib -pint==0.22 +pint==0.23 # via pyEQL (setup.py) -platformdirs==3.11.0 +platformdirs==4.2.0 # via # black - # tox # virtualenv -plotly==5.17.0 +plotly==5.18.0 # via pymatgen -pluggy==1.3.0 +pluggy==1.4.0 # via # pytest # tox -pre-commit==3.5.0 +pre-commit==3.6.0 # via pyEQL (setup.py) +py==1.11.0 + # via tox pybtex==0.24.0 # via pymatgen pycparser==2.21 # via cffi -pydantic==2.4.2 +pydantic==2.6.1 # via # fastapi # maggma # pydantic-settings -pydantic-core==2.10.1 +pydantic-core==2.16.2 # via pydantic -pydantic-settings==2.0.3 +pydantic-settings==2.1.0 # via maggma -pydash==7.0.6 +pydash==7.0.7 # via maggma -pygments==2.16.1 +pygments==2.17.2 # via # rich # sphinx -pymatgen==2023.10.11 +pymatgen==2024.1.27 # via pyEQL (setup.py) -pymongo==4.5.0 +pymongo==4.6.1 # via # maggma # mongogrant @@ -264,9 +258,7 @@ pyparsing==3.1.1 # via # matplotlib # periodictable -pyproject-api==1.6.1 - # via tox -pytest==7.4.2 +pytest==8.0.0 # via # pyEQL (setup.py) # pytest-cov @@ -278,18 +270,18 @@ python-dateutil==2.8.2 # maggma # matplotlib # pandas -python-dotenv==1.0.0 +python-dotenv==1.0.1 # via pydantic-settings -pytz==2023.3.post1 +pytz==2024.1 # via pandas pyyaml==6.0.1 # via # myst-parser # pre-commit # pybtex -pyzmq==25.1.1 +pyzmq==25.1.2 # via maggma -referencing==0.30.2 +referencing==0.33.0 # via # jsonschema # jsonschema-specifications @@ -298,23 +290,23 @@ requests==2.31.0 # mongogrant # pymatgen # sphinx -rich==13.6.0 +rich==13.7.0 # via pyEQL (setup.py) -rpds-py==0.10.6 +rpds-py==0.17.1 # via # jsonschema # referencing -ruamel-yaml==0.17.35 +ruamel-yaml==0.17.40 # via # maggma # pymatgen ruamel-yaml-clib==0.2.8 # via ruamel-yaml -ruff==0.1.0 +ruff==0.2.1 # via pyEQL (setup.py) -s3transfer==0.7.0 +s3transfer==0.10.0 # via boto3 -scipy==1.11.3 +scipy==1.12.0 # via # iapws # phreeqpython @@ -327,42 +319,38 @@ six==1.16.0 # latexcodec # pybtex # python-dateutil + # tox sniffio==1.3.0 # via anyio snowballstemmer==2.2.0 # via sphinx -spglib==2.1.0 +spglib==2.3.0 # via pymatgen sphinx==7.2.6 # via # myst-parser # pyEQL (setup.py) # sphinx-rtd-theme - # sphinxcontrib-applehelp - # sphinxcontrib-devhelp - # sphinxcontrib-htmlhelp # sphinxcontrib-jquery - # sphinxcontrib-qthelp - # sphinxcontrib-serializinghtml -sphinx-rtd-theme==1.3.0 +sphinx-rtd-theme==2.0.0 # via pyEQL (setup.py) -sphinxcontrib-applehelp==1.0.7 +sphinxcontrib-applehelp==1.0.8 # via sphinx -sphinxcontrib-devhelp==1.0.5 +sphinxcontrib-devhelp==1.0.6 # via sphinx -sphinxcontrib-htmlhelp==2.0.4 +sphinxcontrib-htmlhelp==2.0.5 # via sphinx sphinxcontrib-jquery==4.1 # via sphinx-rtd-theme sphinxcontrib-jsmath==1.0.1 # via sphinx -sphinxcontrib-qthelp==1.0.6 +sphinxcontrib-qthelp==1.0.7 # via sphinx -sphinxcontrib-serializinghtml==1.1.9 +sphinxcontrib-serializinghtml==1.1.10 # via sphinx sshtunnel==0.4.0 # via maggma -starlette==0.27.0 +starlette==0.36.3 # via fastapi sympy==1.12 # via pymatgen @@ -375,18 +363,18 @@ tomli==2.0.1 # black # coverage # mypy - # pyproject-api # pytest # tox -tox==4.11.3 +tox==3.28.0 # via pyEQL (setup.py) tqdm==4.66.1 # via # maggma # pymatgen -typing-extensions==4.8.0 +typing-extensions==4.9.0 # via # aioitertools + # anyio # black # fastapi # mypy @@ -396,7 +384,7 @@ typing-extensions==4.8.0 # pydash # starlette # uvicorn -tzdata==2023.3 +tzdata==2023.4 # via pandas uc-micro-py==1.0.2 # via linkify-it-py @@ -406,9 +394,9 @@ urllib3==1.26.18 # via # botocore # requests -uvicorn==0.23.2 +uvicorn==0.27.0.post1 # via maggma -virtualenv==20.24.5 +virtualenv==20.25.0 # via # pre-commit # tox diff --git a/setup.cfg b/setup.cfg index 479e710d..e0b36c7e 100644 --- a/setup.cfg +++ b/setup.cfg @@ -77,7 +77,7 @@ testing = black mypy ruff - tox + tox<4 docs = sphinx>=3.2.1 sphinx-rtd-theme diff --git a/src/pyEQL/__init__.py b/src/pyEQL/__init__.py index 5099e626..7ac6c8f5 100644 --- a/src/pyEQL/__init__.py +++ b/src/pyEQL/__init__.py @@ -1,7 +1,4 @@ """ -pyEQL -===== - pyEQL is a python package for calculating the properties of aqueous solutions and performing chemical thermodynamics computations. @@ -9,11 +6,10 @@ :license: LGPL, see LICENSE for more details. """ from importlib.metadata import PackageNotFoundError, version # pragma: no cover +from importlib.resources import files -from pint import UnitRegistry -from pathlib import Path from maggma.stores import JSONStore -from pkg_resources import resource_filename +from pint import UnitRegistry try: # Change here if project is renamed and does not equal the package name @@ -34,7 +30,7 @@ # see https://pint.readthedocs.io/en/0.22/user/nonmult.html?highlight=offset#temperature-conversion ureg.autoconvert_offset_to_baseunit = True # append custom unit definitions and contexts -fname = resource_filename("pyEQL", "pint_custom_units.txt") +fname = files("pyEQL") / "pint_custom_units.txt" ureg.load_definitions(fname) # activate the "chemistry" context globally ureg.enable_contexts("chem") @@ -42,13 +38,11 @@ ureg.default_format = "P~" # create a Store for the default database -database_dir = resource_filename("pyEQL", "database") -json = Path(database_dir) / "pyeql_db.json" -IonDB = JSONStore(str(json), key="formula") +json_db_file = files("pyEQL") / "database" / "pyeql_db.json" +IonDB = JSONStore(str(json_db_file), key="formula") # By calling connect on init, we get the expensive JSON reading operation out # of the way. Subsequent calls to connect will bypass this and access the already- # instantiated Store in memory, which should speed up instantiation of Solution objects. IonDB.connect() -from pyEQL.functions import * # noqa: E402, F403 from pyEQL.solution import Solution # noqa: E402 diff --git a/src/pyEQL/activity_correction.py b/src/pyEQL/activity_correction.py index dcd19423..0d0fdec3 100644 --- a/src/pyEQL/activity_correction.py +++ b/src/pyEQL/activity_correction.py @@ -14,116 +14,102 @@ """ import math -from iapws import IAPWS95 +from pint import Quantity -# the pint unit registry from pyEQL import ureg from pyEQL.logging_system import logger +from pyEQL.utils import create_water_substance -def _debye_parameter_B(temperature="25 degC"): +def _debye_parameter_B(temperature: str = "25 degC") -> Quantity: """ Return the constant B used in the extended Debye-Huckel equation. - Parameters - ---------- - temperature : str Quantity, optional - String representing the temperature of the solution. Defaults to '25 degC' if not specified. + Args: + temperature: The temperature of the solution at which to calculate the constant. + Defaults to '25 degC'. - Notes - ----- - The parameter B is equal to: + Returns: + The parameter B for use in extended Debye-Huckel equation (base e). For base 10, + divide the resulting value by 2.303. Note that A is often given in base 10 terms + in older textbooks and reference material (0.3281 at 25 degC). - .. math:: B = ( {8 \\pi N_A e^2 \\over 1000 \\epsilon k T} ) ^ {1 \\over 2} + Notes: + The parameter B is equal to: - References - ---------- - Bockris and Reddy. /Modern Electrochemistry/, vol 1. Plenum/Rosetta, 1977, p.210. + .. math:: B = ( \\frac{{2 N_A \\rho_w e^2}{\\epsilon_o \\epsilon_r k T}) ^ {1 \\over 2} - Examples: - -------- - >>> _debye_parameter_B() #doctest: +ELLIPSIS - 0.3291... + References: + Bockris and Reddy. /Modern Electrochemistry/, vol 1. Plenum/Rosetta, 1977, p.210. + + Archer, Donald G. and Wang, Peiming. "The Dielectric Constant of Water \ + and Debye-Huckel Limiting Law Slopes." /J. Phys. Chem. Ref. Data/ 19(2), 1990. + + https://chem.libretexts.org/Bookshelves/Physical_and_Theoretical_Chemistry_Textbook_Maps/Physical_Chemistry_(LibreTexts)/25%3A_Solutions_II_-_Nonvolatile_Solutes/25.06%3A_The_Debye-Huckel_Theory + https://en.wikipedia.org/wiki/Debye%E2%80%93H%C3%BCckel_equation """ - water_substance = IAPWS95( - T=ureg.Quantity(temperature).magnitude, - P=ureg.Quantity("1 atm").to("MPa").magnitude, + T = ureg.Quantity(temperature) + water_substance = create_water_substance( + T, + ureg.Quantity(1, "atm"), ) param_B = ( - 8 - * math.pi + 2 * ureg.N_A + * ureg.Quantity(water_substance.rho, "g/L") * ureg.elementary_charge**2 - / ( - water_substance.mu - * ureg.Quantity("1 g/L") # in g/L - * ureg.epsilon_0 - * water_substance.epsilon - * ureg.boltzmann_constant - * ureg.Quantity(temperature) - ) + / (ureg.epsilon_0 * water_substance.epsilon * ureg.boltzmann_constant * T) ) ** 0.5 return param_B.to_base_units() -def _debye_parameter_activity(temperature="25 degC"): +def _debye_parameter_activity(temperature: str = "25 degC") -> "Quantity": """ - Return the constant A for use in the Debye-Huckel limiting law (base 10). + Return the constant A for use in the Debye-Huckel limiting law (base e). - Parameters - ---------- - temperature : str Quantity, optional - String representing the temperature of the solution. Defaults to '25 degC' if not specified. + Args: + temperature: The temperature of the solution at which to calculate the constant. + Defaults to '25 degC'. - Returns - ------- - Quantity The parameter A for use in the Debye-Huckel limiting law (base e) + Returns: + The parameter A for use in the Debye-Huckel limiting law (base e). For base 10, + divide the resulting value by 2.303. Note that A is often given in base 10 terms + in older textbooks and reference material (0.509 at 25 degC). - Notes - ----- - The parameter A is equal to: + Notes: + The parameter A is equal to: - .. math:: - A^{\\gamma} = {e^3 ( 2 \\pi N_A {\\rho})^{0.5} \\over (4 \\pi \\epsilon_o \\epsilon_r k T)^{1.5}} + .. math:: + A^{\\gamma} = {e^3 ( 2 \\pi N_A {\\rho})^{0.5} \\over (4 \\pi \\epsilon_o \\epsilon_r k T)^{1.5}} - Note that this equation returns the parameter value that can be used to calculate - the natural logarithm of the activity coefficient. For base 10, divide the - value returned by 2.303. The value is often given in base 10 terms (0.509 at - 25 degC) in older textbooks. + Note that this equation returns the parameter value that can be used to calculate + the natural logarithm of the activity coefficient. For base 10, divide the + value returned by 2.303. - References - ---------- - Archer, Donald G. and Wang, Peiming. "The Dielectric Constant of Water \ - and Debye-Huckel Limiting Law Slopes." /J. Phys. Chem. Ref. Data/ 19(2), 1990. + References: + Archer, Donald G. and Wang, Peiming. "The Dielectric Constant of Water \ + and Debye-Huckel Limiting Law Slopes." /J. Phys. Chem. Ref. Data/ 19(2), 1990. - Examples: - -------- - >>> _debye_parameter_activity() #doctest: +ELLIPSIS - 1.17499... + https://chem.libretexts.org/Bookshelves/Physical_and_Theoretical_Chemistry_Textbook_Maps/Physical_Chemistry_(LibreTexts)/25%3A_Solutions_II_-_Nonvolatile_Solutes/25.06%3A_The_Debye-Huckel_Theory + + https://en.wikipedia.org/wiki/Debye%E2%80%93H%C3%BCckel_equation See Also: :py:func:`_debye_parameter_osmotic` """ - water_substance = IAPWS95( - T=ureg.Quantity(temperature).magnitude, - P=ureg.Quantity("1 atm").to("MPa").magnitude, + T = ureg.Quantity(temperature) + water_substance = create_water_substance( + T, + ureg.Quantity(1, "atm"), ) debyeparam = ( ureg.elementary_charge**3 - * (2 * math.pi * ureg.N_A * water_substance.rho * ureg.Quantity("1 g/L")) ** 0.5 - / ( - 4 - * math.pi - * ureg.epsilon_0 - * water_substance.epsilon - * ureg.boltzmann_constant - * ureg.Quantity(temperature) - ) - ** 1.5 + * (2 * math.pi * ureg.N_A * ureg.Quantity(water_substance.rho, "g/L")) ** 0.5 + / (4 * math.pi * ureg.epsilon_0 * water_substance.epsilon * ureg.boltzmann_constant * T) ** 1.5 ) logger.info(f"Computed Debye-Huckel Limiting Law Constant A^{{\\gamma}} = {debyeparam} at {temperature}") @@ -210,24 +196,21 @@ def _debye_parameter_volume(temperature="25 degC"): _debye_parameter_osmotic """ - water_substance = IAPWS95( - T=ureg.Quantity(temperature).magnitude, - P=ureg.Quantity("1 atm").to("MPa").magnitude, + T = ureg.Quantity(temperature) + water_substance = create_water_substance( + T, + ureg.Quantity(1, "atm"), ) # TODO - add partial derivatives to calculation epsilon = water_substance.epsilon - dedp = ureg.Quantity("-0.01275 1/MPa") + dedp = ureg.Quantity(-0.01275, "1/MPa") result = ( - -2 - * _debye_parameter_osmotic(temperature) - * ureg.R - * ureg.Quantity(temperature) - * (3 / epsilon * dedp - 1 / ureg.Quantity("2.2 GPa")) + -2 * _debye_parameter_osmotic(temperature) * ureg.R * T * (3 / epsilon * dedp - 1 / ureg.Quantity(2.2, "GPa")) ) # result = ureg.Quantity('1.898 cm ** 3 * kg ** 0.5 / mol ** 1.5') - if ureg.Quantity(temperature) != ureg.Quantity("25 degC"): + if T.to("degC").magnitude != 25: logger.warning("Debye-Huckel limiting slope for volume is approximate when T is not equal to 25 degC") logger.info(f"Computed Debye-Huckel Limiting Slope for volume A^V = {result} at {temperature}") @@ -277,7 +260,7 @@ def get_activity_coefficient_debyehuckel(ionic_strength, formal_charge=1, temper log_f = -_debye_parameter_activity(temperature) * formal_charge**2 * ionic_strength**0.5 - return math.exp(log_f) * ureg.Quantity("1 dimensionless") + return math.exp(log_f) * ureg.Quantity(1, "dimensionless") def get_activity_coefficient_guntelberg(ionic_strength, formal_charge=1, temperature="25 degC"): @@ -327,7 +310,7 @@ def get_activity_coefficient_guntelberg(ionic_strength, formal_charge=1, tempera / (1 + ionic_strength.magnitude**0.5) ) - return math.exp(log_f) * ureg.Quantity("1 dimensionless") + return math.exp(log_f) * ureg.Quantity(1, "dimensionless") def get_activity_coefficient_davies(ionic_strength, formal_charge=1, temperature="25 degC"): @@ -377,7 +360,7 @@ def get_activity_coefficient_davies(ionic_strength, formal_charge=1, temperature * (ionic_strength.magnitude**0.5 / (1 + ionic_strength.magnitude**0.5) - 0.2 * ionic_strength.magnitude) ) - return math.exp(log_f) * ureg.Quantity("1 dimensionless") + return math.exp(log_f) * ureg.Quantity(1, "dimensionless") def get_activity_coefficient_pitzer( @@ -482,14 +465,14 @@ def get_activity_coefficient_pitzer( """ # assign proper units to alpha1, alpha2, and b - alpha1 = alpha1 * ureg.Quantity("kg ** 0.5 / mol ** 0.5") - alpha2 = alpha2 * ureg.Quantity("kg ** 0.5 / mol ** 0.5") - b = b * ureg.Quantity("kg ** 0.5 / mol ** 0.5") - C_phi = C_phi * ureg.Quantity("kg ** 2 /mol ** 2") + alpha1 = ureg.Quantity(alpha1, "kg ** 0.5 / mol ** 0.5") + alpha2 = ureg.Quantity(alpha2, "kg ** 0.5 / mol ** 0.5") + b = ureg.Quantity(b, "kg ** 0.5 / mol ** 0.5") + C_phi = ureg.Quantity(C_phi, "kg ** 2 /mol ** 2") # assign units appropriate for the activity parameters - BMX = _pitzer_B_MX(ionic_strength, alpha1, alpha2, beta0, beta1, beta2) * ureg.Quantity("kg/mol") - Bphi = _pitzer_B_phi(ionic_strength, alpha1, alpha2, beta0, beta1, beta2) * ureg.Quantity("kg/mol") + BMX = ureg.Quantity(_pitzer_B_MX(ionic_strength, alpha1, alpha2, beta0, beta1, beta2), "kg/mol") + Bphi = ureg.Quantity(_pitzer_B_phi(ionic_strength, alpha1, alpha2, beta0, beta1, beta2), "kg/mol") loggamma = _pitzer_log_gamma( ionic_strength, @@ -505,7 +488,7 @@ def get_activity_coefficient_pitzer( b, ) - return math.exp(loggamma) * ureg.Quantity("1 dimensionless") + return math.exp(loggamma) * ureg.Quantity(1, "dimensionless") def get_apparent_volume_pitzer( @@ -613,14 +596,14 @@ def get_apparent_volume_pitzer( """ # TODO - find a cleaner way to make sure coefficients are assigned the proper units # if they aren't, the calculation gives very wrong results - alpha1 = alpha1 * ureg.Quantity("kg ** 0.5 / mol ** 0.5") - alpha2 = alpha2 * ureg.Quantity("kg ** 0.5 / mol ** 0.5") - b = b * ureg.Quantity("kg ** 0.5 / mol ** 0.5") - C_phi = C_phi * ureg.Quantity("kg ** 2 /mol ** 2 / dabar") - V_o = V_o * ureg.Quantity("cm ** 3 / mol") + alpha1 = ureg.Quantity(alpha1, "kg ** 0.5 / mol ** 0.5") + alpha2 = ureg.Quantity(alpha2, "kg ** 0.5 / mol ** 0.5") + b = ureg.Quantity(b, "kg ** 0.5 / mol ** 0.5") + C_phi = ureg.Quantity(C_phi, "kg ** 2 /mol ** 2 / dabar") + V_o = ureg.Quantity(V_o, "cm ** 3 / mol") # assign units appropriate for the volume parameter - BMX = _pitzer_B_MX(ionic_strength, alpha1, alpha2, beta0, beta1, beta2) * ureg.Quantity("kg /mol/dabar") + BMX = ureg.Quantity(_pitzer_B_MX(ionic_strength, alpha1, alpha2, beta0, beta1, beta2), "kg /mol/dabar") second_term = ( (nu_cation + nu_anion) @@ -852,7 +835,7 @@ def _pitzer_log_gamma( nu_cation, nu_anion, temperature="25 degC", - b=ureg.Quantity("1.2 kg**0.5/mol**0.5"), + b=ureg.Quantity(1.2, "kg**0.5/mol**0.5"), ): """ Return the natural logarithm of the binary activity coefficient calculated by the Pitzer @@ -1011,11 +994,11 @@ def get_osmotic_coefficient_pitzer( """ # assign proper units to alpha1, alpha2, and b - alpha1 = alpha1 * ureg.Quantity("kg ** 0.5 / mol ** 0.5") - alpha2 = alpha2 * ureg.Quantity("kg ** 0.5 / mol ** 0.5") - b = b * ureg.Quantity("kg ** 0.5 / mol ** 0.5") - C_phi = C_phi * ureg.Quantity("kg ** 2 /mol ** 2") - B_phi = _pitzer_B_phi(ionic_strength, alpha1, alpha2, beta0, beta1, beta2) * ureg.Quantity("kg/mol") + alpha1 = ureg.Quantity(alpha1, "kg ** 0.5 / mol ** 0.5") + alpha2 = ureg.Quantity(alpha2, "kg ** 0.5 / mol ** 0.5") + b = ureg.Quantity(b, "kg ** 0.5 / mol ** 0.5") + C_phi = ureg.Quantity(C_phi, "kg ** 2 /mol ** 2") + B_phi = ureg.Quantity(_pitzer_B_phi(ionic_strength, alpha1, alpha2, beta0, beta1, beta2), "kg/mol") first_term = 1 - _debye_parameter_osmotic(temperature) * abs(z_cation * z_anion) * ionic_strength**0.5 / ( 1 + b * ionic_strength**0.5 diff --git a/src/pyEQL/database/pyeql_db.json b/src/pyEQL/database/pyeql_db.json index d701bf4f..b8ddc27a 100644 --- a/src/pyEQL/database/pyeql_db.json +++ b/src/pyEQL/database/pyeql_db.json @@ -71,6 +71,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -147,6 +152,11 @@ "reference": "https://doi.org/10.1021/cr00040a004", "data_type": "fitted" } + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -263,6 +273,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -350,6 +365,11 @@ "reference": "https://doi.org/10.1021/cr00040a004", "data_type": "fitted" } + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -420,6 +440,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -490,6 +515,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -606,6 +636,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -694,6 +729,11 @@ "data_type": "fitted" } }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null + }, "dielectric_zuber": { "value": "2.87 dimensionless", "reference": "https://doi.org/10.1016/j.fluid.2014.05.037", @@ -776,86 +816,11 @@ }, "viscosity_jones_dole": { "B": null - } - } - }, - { - "formula": "Au(CN)2[-1]", - "charge": -1, - "molecular_weight": "249.00136899999998 g/mol", - "elements": [ - "Au", - "C", - "N" - ], - "chemsys": "Au-C-N", - "pmg_ion": { - "Au": 1, - "C": 2, - "N": 2, - "charge": -1, - "@module": "pymatgen.core.ion", - "@class": "Ion", - "@version": null - }, - "formula_html": "Au(CN)2-1", - "formula_latex": "Au(CN)$_{2}$$^{-1}$", - "formula_hill": "C2 Au N2", - "formula_pretty": "Au(CN)2^-1", - "oxi_state_guesses": { - "Au": -1, - "C": 3, - "N": -3 - }, - "n_atoms": 5, - "n_elements": 3, - "size": { - "radius_ionic": { - "value": "None", - "reference": "pymatgen", - "data_type": "experimental" - }, - "radius_hydrated": null, - "radius_vdw": { - "value": "2.14 Å", - "reference": "pymatgen", - "data_type": "experimental" - }, - "molar_volume": null - }, - "thermo": { - "ΔG_hydration": null, - "ΔG_formation": null - }, - "transport": { - "diffusion_coefficient": { - "value": "1.331e-05 cm**2/s", - "reference": "CRC", - "data_type": "experimental" - } - }, - "model_parameters": { - "activity_pitzer": { - "Beta0": null, - "Beta1": null, - "Beta2": null, - "Cphi": null, - "Max_C": null }, - "molar_volume_pitzer": { - "Beta0": null, - "Beta1": null, - "Beta2": null, - "Cphi": null, - "V_o": null, - "Max_C": null - }, - "viscosity_jones_dole": { - "B": { - "value": "-0.04 dm**3/mol", - "reference": "https://doi.org/10.1021/cr00040a004", - "data_type": "fitted" - } + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -937,10 +902,10 @@ "data_type": "fitted" } }, - "dielectric_zuber": { - "value": "8.48 dimensionless", - "reference": "https://doi.org/10.1016/j.fluid.2014.05.037", - "data_type": "fitted" + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -1017,6 +982,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -1088,6 +1058,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -1158,6 +1133,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -1228,6 +1208,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -1304,6 +1289,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -1380,6 +1370,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -1456,6 +1451,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -1534,6 +1534,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -1612,6 +1617,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -1704,6 +1714,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -1820,6 +1835,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -1909,42 +1929,41 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, { - "formula": "BaC4O.3H2O(aq)", + "formula": "BaCl2(aq)", "charge": 0, - "molecular_weight": "255.41504 g/mol", + "molecular_weight": "208.233 g/mol", "elements": [ "Ba", - "C", - "H", - "O" + "Cl" ], - "chemsys": "Ba-C-H-O", + "chemsys": "Ba-Cl", "pmg_ion": { "Ba": 1, - "C": 4, - "H": 6, - "O": 4, + "Cl": 2, "charge": 0, "@module": "pymatgen.core.ion", "@class": "Ion", "@version": null }, - "formula_html": "BaC4O.3H2O", - "formula_latex": "BaC$_{4}$O$_{.3}$H$_{2}$O", - "formula_hill": "C4 H6 Ba O4", - "formula_pretty": "BaC4O.3H2O", + "formula_html": "BaCl2", + "formula_latex": "BaCl$_{2}$", + "formula_hill": "Ba Cl2", + "formula_pretty": "BaCl2", "oxi_state_guesses": { "Ba": 2, - "C": 0, - "H": 1, - "O": -2 + "Cl": -1 }, - "n_atoms": 15, - "n_elements": 4, + "n_atoms": 3, + "n_elements": 2, "size": { "radius_ionic": { "value": "None", @@ -1969,12 +1988,12 @@ "model_parameters": { "activity_pitzer": { "Beta0": { - "value": "0.2437 dimensionless", + "value": "0.2891 dimensionless", "reference": "10.1021/je2009329", "data_type": "fitted" }, "Beta1": { - "value": "1.093 dimensionless", + "value": "1.217 dimensionless", "reference": "10.1021/je2009329", "data_type": "fitted" }, @@ -1984,56 +2003,91 @@ "data_type": "fitted" }, "Cphi": { - "value": "-0.03794 dimensionless", + "value": "-0.02987 dimensionless", "reference": "10.1021/je2009329", "data_type": "fitted" }, "Max_C": { - "value": "3.5 mol/kg", + "value": "1.8 mol/kg", "reference": "10.1021/je2009329", "data_type": "fitted" } }, "molar_volume_pitzer": { - "Beta0": null, - "Beta1": null, - "Beta2": null, - "Cphi": null, - "V_o": null, - "Max_C": null + "Beta0": { + "value": "-0.0005681 dimensionless", + "reference": "10.1021/je2009329", + "data_type": "fitted" + }, + "Beta1": { + "value": "0.003069 dimensionless", + "reference": "10.1021/je2009329", + "data_type": "fitted" + }, + "Beta2": { + "value": "0.0 dimensionless", + "reference": "10.1021/je2009329", + "data_type": "fitted" + }, + "Cphi": { + "value": "0.0004377 dimensionless", + "reference": "10.1021/je2009329", + "data_type": "fitted" + }, + "V_o": { + "value": "23.1 dimensionless", + "reference": "10.1021/je2009329", + "data_type": "fitted" + }, + "Max_C": { + "value": "1.623 mol/kg", + "reference": "10.1021/je2009329", + "data_type": "fitted" + } }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, { - "formula": "BaCl2(aq)", + "formula": "BaH6(CO)4(aq)", "charge": 0, - "molecular_weight": "208.233 g/mol", + "molecular_weight": "255.41504 g/mol", "elements": [ "Ba", - "Cl" + "C", + "H", + "O" ], - "chemsys": "Ba-Cl", + "chemsys": "Ba-C-H-O", "pmg_ion": { "Ba": 1, - "Cl": 2, + "C": 4, + "H": 6, + "O": 4, "charge": 0, "@module": "pymatgen.core.ion", "@class": "Ion", "@version": null }, - "formula_html": "BaCl2", - "formula_latex": "BaCl$_{2}$", - "formula_hill": "Ba Cl2", - "formula_pretty": "BaCl2", + "formula_html": "BaH6(CO)4", + "formula_latex": "BaH$_{6}$(CO)$_{4}$", + "formula_hill": "C4 H6 Ba O4", + "formula_pretty": "BaH6(CO)4", "oxi_state_guesses": { "Ba": 2, - "Cl": -1 + "C": 0, + "H": 1, + "O": -2 }, - "n_atoms": 3, - "n_elements": 2, + "n_atoms": 15, + "n_elements": 4, "size": { "radius_ionic": { "value": "None", @@ -2058,12 +2112,12 @@ "model_parameters": { "activity_pitzer": { "Beta0": { - "value": "0.2891 dimensionless", + "value": "0.2437 dimensionless", "reference": "10.1021/je2009329", "data_type": "fitted" }, "Beta1": { - "value": "1.217 dimensionless", + "value": "1.093 dimensionless", "reference": "10.1021/je2009329", "data_type": "fitted" }, @@ -2073,50 +2127,31 @@ "data_type": "fitted" }, "Cphi": { - "value": "-0.02987 dimensionless", + "value": "-0.03794 dimensionless", "reference": "10.1021/je2009329", "data_type": "fitted" }, "Max_C": { - "value": "1.8 mol/kg", + "value": "3.5 mol/kg", "reference": "10.1021/je2009329", "data_type": "fitted" } }, "molar_volume_pitzer": { - "Beta0": { - "value": "-0.0005681 dimensionless", - "reference": "10.1021/je2009329", - "data_type": "fitted" - }, - "Beta1": { - "value": "0.003069 dimensionless", - "reference": "10.1021/je2009329", - "data_type": "fitted" - }, - "Beta2": { - "value": "0.0 dimensionless", - "reference": "10.1021/je2009329", - "data_type": "fitted" - }, - "Cphi": { - "value": "0.0004377 dimensionless", - "reference": "10.1021/je2009329", - "data_type": "fitted" - }, - "V_o": { - "value": "23.1 dimensionless", - "reference": "10.1021/je2009329", - "data_type": "fitted" - }, - "Max_C": { - "value": "1.623 mol/kg", - "reference": "10.1021/je2009329", - "data_type": "fitted" - } + "Beta0": null, + "Beta1": null, + "Beta2": null, + "Cphi": null, + "V_o": null, + "Max_C": null }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -2206,6 +2241,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -2294,6 +2334,11 @@ "data_type": "fitted" } }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null + }, "dielectric_zuber": { "value": "0.75 dimensionless", "reference": "https://doi.org/10.1016/j.fluid.2014.05.037", @@ -2390,6 +2435,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -2464,6 +2514,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -2539,6 +2594,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -2629,6 +2689,11 @@ "reference": "https://doi.org/10.1021/cr00040a004", "data_type": "fitted" } + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -2699,6 +2764,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -2791,6 +2861,11 @@ "data_type": "fitted" } }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null + }, "dielectric_zuber": { "value": "7.31 dimensionless", "reference": "https://doi.org/10.1016/j.fluid.2014.05.037", @@ -2868,6 +2943,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -2916,15 +2996,15 @@ "molar_volume": null }, "thermo": { - "ΔG_hydration": null, + "ΔG_hydration": { + "value": "-330.0 ± 6 kJ/mol", + "reference": "Marcus2015", + "data_type": "experimental" + }, "ΔG_formation": null }, "transport": { - "diffusion_coefficient": { - "value": "1.089e-05 cm**2/s", - "reference": "CRC", - "data_type": "experimental" - } + "diffusion_coefficient": null }, "model_parameters": { "activity_pitzer": { @@ -2944,6 +3024,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -2992,15 +3077,15 @@ "molar_volume": null }, "thermo": { - "ΔG_hydration": { - "value": "-330.0 ± 6 kJ/mol", - "reference": "Marcus2015", - "data_type": "experimental" - }, + "ΔG_hydration": null, "ΔG_formation": null }, "transport": { - "diffusion_coefficient": null + "diffusion_coefficient": { + "value": "1.089e-05 cm**2/s", + "reference": "CRC", + "data_type": "experimental" + } }, "model_parameters": { "activity_pitzer": { @@ -3020,6 +3105,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -3028,15 +3118,15 @@ "charge": -1, "molecular_weight": "42.0168 g/mol", "elements": [ + "O", "C", - "N", - "O" + "N" ], "chemsys": "C-N-O", "pmg_ion": { + "O": 1, "C": 1, "N": 1, - "O": 1, "charge": -1, "@module": "pymatgen.core.ion", "@class": "Ion", @@ -3047,9 +3137,9 @@ "formula_hill": "C N O", "formula_pretty": "CNO^-1", "oxi_state_guesses": { + "O": -2, "C": 4, - "N": -3, - "O": -2 + "N": -3 }, "n_atoms": 3, "n_elements": 3, @@ -3061,7 +3151,7 @@ }, "radius_hydrated": null, "radius_vdw": { - "value": "1.7 Å", + "value": "1.52 Å", "reference": "pymatgen", "data_type": "experimental" }, @@ -3096,6 +3186,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -3104,15 +3199,15 @@ "charge": -1, "molecular_weight": "42.0168 g/mol", "elements": [ - "O", "C", - "N" + "N", + "O" ], "chemsys": "C-N-O", "pmg_ion": { - "O": 1, "C": 1, "N": 1, + "O": 1, "charge": -1, "@module": "pymatgen.core.ion", "@class": "Ion", @@ -3123,9 +3218,9 @@ "formula_hill": "C N O", "formula_pretty": "CNO^-1", "oxi_state_guesses": { - "O": -2, "C": 4, - "N": -3 + "N": -3, + "O": -2 }, "n_atoms": 3, "n_elements": 3, @@ -3137,7 +3232,7 @@ }, "radius_hydrated": null, "radius_vdw": { - "value": "1.52 Å", + "value": "1.7 Å", "reference": "pymatgen", "data_type": "experimental" }, @@ -3172,6 +3267,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -3258,6 +3358,97 @@ "reference": "https://doi.org/10.1021/cr00040a004", "data_type": "fitted" } + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null + } + } + }, + { + "formula": "CO32[-1]", + "charge": -1, + "molecular_weight": "523.9915 g/mol", + "elements": [ + "C", + "O" + ], + "chemsys": "C-O", + "pmg_ion": { + "C": 1, + "O": 32, + "charge": -1, + "@module": "pymatgen.core.ion", + "@class": "Ion", + "@version": null + }, + "formula_html": "CO32-1", + "formula_latex": "CO$_{32}$$^{-1}$", + "formula_hill": "C O32", + "formula_pretty": "CO32^-1", + "oxi_state_guesses": { + "C": 4, + "O": -0.15625 + }, + "n_atoms": 33, + "n_elements": 2, + "size": { + "radius_ionic": { + "value": "None", + "reference": "pymatgen", + "data_type": "experimental" + }, + "radius_hydrated": null, + "radius_vdw": { + "value": "1.7 Å", + "reference": "pymatgen", + "data_type": "experimental" + }, + "molar_volume": null + }, + "thermo": { + "ΔG_hydration": null, + "ΔG_formation": null + }, + "transport": { + "diffusion_coefficient": null + }, + "model_parameters": { + "activity_pitzer": { + "Beta0": null, + "Beta1": null, + "Beta2": null, + "Cphi": null, + "Max_C": null + }, + "molar_volume_pitzer": { + "Beta0": null, + "Beta1": null, + "Beta2": null, + "Cphi": null, + "V_o": null, + "Max_C": null + }, + "viscosity_jones_dole": { + "B": null + }, + "diffusion_temp_smolyakov": { + "a1": { + "value": "1.12 dimensionless", + "reference": "https://doi.org/10.1016/j.cemconres.2017.08.030", + "data_type": "fitted" + }, + "a2": { + "value": "2.84 dimensionless", + "reference": "https://doi.org/10.1016/j.cemconres.2017.08.030", + "data_type": "fitted" + }, + "d": { + "value": "0 dimensionless", + "reference": "https://doi.org/10.1016/j.cemconres.2017.08.030", + "data_type": "fitted" + } } } }, @@ -3352,6 +3543,11 @@ "reference": "https://doi.org/10.1021/cr00040a004", "data_type": "fitted" } + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -3441,6 +3637,11 @@ "reference": "https://doi.org/10.1021/cr00040a004", "data_type": "fitted" } + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -3517,6 +3718,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -3609,6 +3815,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -3725,6 +3936,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -3838,6 +4054,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -3951,6 +4172,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -4040,6 +4266,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -4132,6 +4363,11 @@ "data_type": "fitted" } }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null + }, "dielectric_zuber": { "value": "-0.53 dimensionless", "reference": "https://doi.org/10.1016/j.fluid.2014.05.037", @@ -4228,6 +4464,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -4320,6 +4561,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -4436,6 +4682,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -4552,6 +4803,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -4639,6 +4895,11 @@ "reference": "https://doi.org/10.1021/cr00040a004", "data_type": "fitted" } + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -4728,6 +4989,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -4815,6 +5081,11 @@ "reference": "https://doi.org/10.1021/cr00040a004", "data_type": "fitted" } + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -4890,6 +5161,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -4963,6 +5239,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -5044,6 +5325,11 @@ "reference": "https://doi.org/10.1021/cr00040a004", "data_type": "fitted" } + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -5134,6 +5420,11 @@ "reference": "https://doi.org/10.1021/cr00040a004", "data_type": "fitted" } + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -5226,6 +5517,23 @@ "data_type": "fitted" } }, + "diffusion_temp_smolyakov": { + "a1": { + "value": "1.6 dimensionless", + "reference": "https://doi.org/10.1016/j.cemconres.2017.08.030", + "data_type": "fitted" + }, + "a2": { + "value": "6.9 dimensionless", + "reference": "https://doi.org/10.1016/j.cemconres.2017.08.030", + "data_type": "fitted" + }, + "d": { + "value": "194 dimensionless", + "reference": "https://doi.org/10.1016/j.cemconres.2017.08.030", + "data_type": "fitted" + } + }, "dielectric_zuber": { "value": "6.8 dimensionless", "reference": "https://doi.org/10.1016/j.fluid.2014.05.037", @@ -5310,6 +5618,11 @@ "reference": "https://doi.org/10.1021/cr00040a004", "data_type": "fitted" } + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -5386,6 +5699,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -5502,6 +5820,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -5591,6 +5914,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -5704,6 +6032,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -5793,6 +6126,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -5880,6 +6218,11 @@ "reference": "https://doi.org/10.1021/cr00040a004", "data_type": "fitted" } + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -5955,6 +6298,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -6047,6 +6395,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -6136,6 +6489,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -6226,6 +6584,11 @@ "reference": "https://doi.org/10.1021/cr00040a004", "data_type": "fitted" } + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -6301,6 +6664,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -6388,6 +6756,11 @@ "reference": "https://doi.org/10.1021/cr00040a004", "data_type": "fitted" } + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -6504,36 +6877,44 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, { - "formula": "CsBr(aq)", + "formula": "Cs2SO4(aq)", "charge": 0, - "molecular_weight": "212.8094519 g/mol", + "molecular_weight": "361.8735038 g/mol", "elements": [ "Cs", - "Br" + "S", + "O" ], - "chemsys": "Br-Cs", + "chemsys": "Cs-O-S", "pmg_ion": { - "Cs": 1, - "Br": 1, + "Cs": 2, + "S": 1, + "O": 4, "charge": 0, "@module": "pymatgen.core.ion", "@class": "Ion", "@version": null }, - "formula_html": "CsBr", - "formula_latex": "CsBr", - "formula_hill": "Br Cs", - "formula_pretty": "CsBr", + "formula_html": "Cs2SO4", + "formula_latex": "Cs$_{2}$SO$_{4}$", + "formula_hill": "Cs2 O4 S", + "formula_pretty": "Cs2SO4", "oxi_state_guesses": { "Cs": 1, - "Br": -1 + "S": 6, + "O": -2 }, - "n_atoms": 2, - "n_elements": 2, + "n_atoms": 7, + "n_elements": 3, "size": { "radius_ionic": { "value": "None", @@ -6549,7 +6930,11 @@ "molar_volume": null }, "thermo": { - "ΔG_hydration": null, + "ΔG_hydration": { + "value": "-1394.0 ± 10 kJ/mol", + "reference": "10.1021/acs.jpca.9b05140", + "data_type": "experimental" + }, "ΔG_formation": null }, "transport": { @@ -6558,12 +6943,12 @@ "model_parameters": { "activity_pitzer": { "Beta0": { - "value": "0.02187 dimensionless", + "value": "0.1009 dimensionless", "reference": "10.1021/je2009329", "data_type": "fitted" }, "Beta1": { - "value": "0.07237 dimensionless", + "value": "0.9094 dimensionless", "reference": "10.1021/je2009329", "data_type": "fitted" }, @@ -6573,24 +6958,24 @@ "data_type": "fitted" }, "Cphi": { - "value": "0.001244 dimensionless", + "value": "-0.0087 dimensionless", "reference": "10.1021/je2009329", "data_type": "fitted" }, "Max_C": { - "value": "5.0 mol/kg", + "value": "4.0 mol/kg", "reference": "10.1021/je2009329", "data_type": "fitted" } }, "molar_volume_pitzer": { "Beta0": { - "value": "7.096e-05 dimensionless", + "value": "0.0007906 dimensionless", "reference": "10.1021/je2009329", "data_type": "fitted" }, "Beta1": { - "value": "0.0002329 dimensionless", + "value": "0.002396 dimensionless", "reference": "10.1021/je2009329", "data_type": "fitted" }, @@ -6600,50 +6985,55 @@ "data_type": "fitted" }, "Cphi": { - "value": "-5.2e-06 dimensionless", + "value": "-1.989e-05 dimensionless", "reference": "10.1021/je2009329", "data_type": "fitted" }, "V_o": { - "value": "46.0 dimensionless", + "value": "40.0 dimensionless", "reference": "10.1021/je2009329", "data_type": "fitted" }, "Max_C": { - "value": "4.731 mol/kg", + "value": "3.816 mol/kg", "reference": "10.1021/je2009329", "data_type": "fitted" } }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, { - "formula": "CsCl(aq)", + "formula": "CsBr(aq)", "charge": 0, - "molecular_weight": "168.3584519 g/mol", + "molecular_weight": "212.8094519 g/mol", "elements": [ "Cs", - "Cl" + "Br" ], - "chemsys": "Cl-Cs", + "chemsys": "Br-Cs", "pmg_ion": { "Cs": 1, - "Cl": 1, + "Br": 1, "charge": 0, "@module": "pymatgen.core.ion", "@class": "Ion", "@version": null }, - "formula_html": "CsCl", - "formula_latex": "CsCl", - "formula_hill": "Cl Cs", - "formula_pretty": "CsCl", + "formula_html": "CsBr", + "formula_latex": "CsBr", + "formula_hill": "Br Cs", + "formula_pretty": "CsBr", "oxi_state_guesses": { "Cs": 1, - "Cl": -1 + "Br": -1 }, "n_atoms": 2, "n_elements": 2, @@ -6671,12 +7061,12 @@ "model_parameters": { "activity_pitzer": { "Beta0": { - "value": "0.03745 dimensionless", + "value": "0.02187 dimensionless", "reference": "10.1021/je2009329", "data_type": "fitted" }, "Beta1": { - "value": "0.02709 dimensionless", + "value": "0.07237 dimensionless", "reference": "10.1021/je2009329", "data_type": "fitted" }, @@ -6686,24 +7076,24 @@ "data_type": "fitted" }, "Cphi": { - "value": "-0.00103 dimensionless", + "value": "0.001244 dimensionless", "reference": "10.1021/je2009329", "data_type": "fitted" }, "Max_C": { - "value": "11.0 mol/kg", + "value": "5.0 mol/kg", "reference": "10.1021/je2009329", "data_type": "fitted" } }, "molar_volume_pitzer": { "Beta0": { - "value": "8.174e-05 dimensionless", + "value": "7.096e-05 dimensionless", "reference": "10.1021/je2009329", "data_type": "fitted" }, "Beta1": { - "value": "0.0004061 dimensionless", + "value": "0.0002329 dimensionless", "reference": "10.1021/je2009329", "data_type": "fitted" }, @@ -6713,50 +7103,295 @@ "data_type": "fitted" }, "Cphi": { - "value": "-7.6e-06 dimensionless", + "value": "-5.2e-06 dimensionless", "reference": "10.1021/je2009329", "data_type": "fitted" }, "V_o": { - "value": "39.1 dimensionless", + "value": "46.0 dimensionless", "reference": "10.1021/je2009329", "data_type": "fitted" }, "Max_C": { - "value": "10.6 mol/kg", + "value": "4.731 mol/kg", "reference": "10.1021/je2009329", "data_type": "fitted" } }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, { - "formula": "CsF(aq)", + "formula": "CsCl(aq)", "charge": 0, - "molecular_weight": "151.9038551 g/mol", + "molecular_weight": "168.3584519 g/mol", "elements": [ "Cs", - "F" + "Cl" ], - "chemsys": "Cs-F", + "chemsys": "Cl-Cs", "pmg_ion": { "Cs": 1, - "F": 1, + "Cl": 1, "charge": 0, "@module": "pymatgen.core.ion", "@class": "Ion", "@version": null }, - "formula_html": "CsF", - "formula_latex": "CsF", - "formula_hill": "Cs F", - "formula_pretty": "CsF", + "formula_html": "CsCl", + "formula_latex": "CsCl", + "formula_hill": "Cl Cs", + "formula_pretty": "CsCl", "oxi_state_guesses": { "Cs": 1, - "F": -1 + "Cl": -1 + }, + "n_atoms": 2, + "n_elements": 2, + "size": { + "radius_ionic": { + "value": "None", + "reference": "pymatgen", + "data_type": "experimental" + }, + "radius_hydrated": null, + "radius_vdw": { + "value": "3.43 Å", + "reference": "pymatgen", + "data_type": "experimental" + }, + "molar_volume": null + }, + "thermo": { + "ΔG_hydration": null, + "ΔG_formation": null + }, + "transport": { + "diffusion_coefficient": null + }, + "model_parameters": { + "activity_pitzer": { + "Beta0": { + "value": "0.03745 dimensionless", + "reference": "10.1021/je2009329", + "data_type": "fitted" + }, + "Beta1": { + "value": "0.02709 dimensionless", + "reference": "10.1021/je2009329", + "data_type": "fitted" + }, + "Beta2": { + "value": "0.0 dimensionless", + "reference": "10.1021/je2009329", + "data_type": "fitted" + }, + "Cphi": { + "value": "-0.00103 dimensionless", + "reference": "10.1021/je2009329", + "data_type": "fitted" + }, + "Max_C": { + "value": "11.0 mol/kg", + "reference": "10.1021/je2009329", + "data_type": "fitted" + } + }, + "molar_volume_pitzer": { + "Beta0": { + "value": "8.174e-05 dimensionless", + "reference": "10.1021/je2009329", + "data_type": "fitted" + }, + "Beta1": { + "value": "0.0004061 dimensionless", + "reference": "10.1021/je2009329", + "data_type": "fitted" + }, + "Beta2": { + "value": "0.0 dimensionless", + "reference": "10.1021/je2009329", + "data_type": "fitted" + }, + "Cphi": { + "value": "-7.6e-06 dimensionless", + "reference": "10.1021/je2009329", + "data_type": "fitted" + }, + "V_o": { + "value": "39.1 dimensionless", + "reference": "10.1021/je2009329", + "data_type": "fitted" + }, + "Max_C": { + "value": "10.6 mol/kg", + "reference": "10.1021/je2009329", + "data_type": "fitted" + } + }, + "viscosity_jones_dole": { + "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null + } + } + }, + { + "formula": "CsCl(aq)", + "charge": 0, + "molecular_weight": "168.3584519 g/mol", + "elements": [ + "Cs", + "Cl" + ], + "chemsys": "Cl-Cs", + "pmg_ion": { + "Cs": 1, + "Cl": 1, + "charge": 0, + "@module": "pymatgen.core.ion", + "@class": "Ion", + "@version": null + }, + "formula_html": "CsCl", + "formula_latex": "CsCl", + "formula_hill": "Cl Cs", + "formula_pretty": "CsCl", + "oxi_state_guesses": { + "Cs": 1, + "Cl": -1 + }, + "n_atoms": 2, + "n_elements": 2, + "size": { + "radius_ionic": { + "value": "None", + "reference": "pymatgen", + "data_type": "experimental" + }, + "radius_hydrated": null, + "radius_vdw": { + "value": "3.43 Å", + "reference": "pymatgen", + "data_type": "experimental" + }, + "molar_volume": null + }, + "thermo": { + "ΔG_hydration": { + "value": "nan ± 6 kJ/mol", + "reference": "Marcus2015", + "data_type": "experimental" + }, + "ΔG_formation": null + }, + "transport": { + "diffusion_coefficient": null + }, + "model_parameters": { + "activity_pitzer": { + "Beta0": { + "value": "0.03745 dimensionless", + "reference": "10.1021/je2009329", + "data_type": "fitted" + }, + "Beta1": { + "value": "0.02709 dimensionless", + "reference": "10.1021/je2009329", + "data_type": "fitted" + }, + "Beta2": { + "value": "0.0 dimensionless", + "reference": "10.1021/je2009329", + "data_type": "fitted" + }, + "Cphi": { + "value": "-0.00103 dimensionless", + "reference": "10.1021/je2009329", + "data_type": "fitted" + }, + "Max_C": { + "value": "11.0 mol/kg", + "reference": "10.1021/je2009329", + "data_type": "fitted" + } + }, + "molar_volume_pitzer": { + "Beta0": { + "value": "8.174e-05 dimensionless", + "reference": "10.1021/je2009329", + "data_type": "fitted" + }, + "Beta1": { + "value": "0.0004061 dimensionless", + "reference": "10.1021/je2009329", + "data_type": "fitted" + }, + "Beta2": { + "value": "0.0 dimensionless", + "reference": "10.1021/je2009329", + "data_type": "fitted" + }, + "Cphi": { + "value": "-7.6e-06 dimensionless", + "reference": "10.1021/je2009329", + "data_type": "fitted" + }, + "V_o": { + "value": "39.1 dimensionless", + "reference": "10.1021/je2009329", + "data_type": "fitted" + }, + "Max_C": { + "value": "10.6 mol/kg", + "reference": "10.1021/je2009329", + "data_type": "fitted" + } + }, + "viscosity_jones_dole": { + "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null + } + } + }, + { + "formula": "CsF(aq)", + "charge": 0, + "molecular_weight": "151.9038551 g/mol", + "elements": [ + "Cs", + "F" + ], + "chemsys": "Cs-F", + "pmg_ion": { + "Cs": 1, + "F": 1, + "charge": 0, + "@module": "pymatgen.core.ion", + "@class": "Ion", + "@version": null + }, + "formula_html": "CsF", + "formula_latex": "CsF", + "formula_hill": "Cs F", + "formula_pretty": "CsF", + "oxi_state_guesses": { + "Cs": 1, + "F": -1 }, "n_atoms": 2, "n_elements": 2, @@ -6843,11 +7478,116 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null + } + } + }, + { + "formula": "CsH3(CO)2(aq)", + "charge": 0, + "molecular_weight": "191.9494719 g/mol", + "elements": [ + "Cs", + "C", + "H", + "O" + ], + "chemsys": "C-Cs-H-O", + "pmg_ion": { + "Cs": 1, + "C": 2, + "H": 3, + "O": 2, + "charge": 0, + "@module": "pymatgen.core.ion", + "@class": "Ion", + "@version": null + }, + "formula_html": "CsH3(CO)2", + "formula_latex": "CsH$_{3}$(CO)$_{2}$", + "formula_hill": "C2 H3 Cs O2", + "formula_pretty": "CsH3(CO)2", + "oxi_state_guesses": { + "Cs": 1, + "C": 0, + "H": 1, + "O": -2 + }, + "n_atoms": 8, + "n_elements": 4, + "size": { + "radius_ionic": { + "value": "None", + "reference": "pymatgen", + "data_type": "experimental" + }, + "radius_hydrated": null, + "radius_vdw": { + "value": "3.43 Å", + "reference": "pymatgen", + "data_type": "experimental" + }, + "molar_volume": null + }, + "thermo": { + "ΔG_hydration": null, + "ΔG_formation": null + }, + "transport": { + "diffusion_coefficient": null + }, + "model_parameters": { + "activity_pitzer": { + "Beta0": { + "value": "0.1674 dimensionless", + "reference": "10.1021/je2009329", + "data_type": "fitted" + }, + "Beta1": { + "value": "0.3399 dimensionless", + "reference": "10.1021/je2009329", + "data_type": "fitted" + }, + "Beta2": { + "value": "0.0 dimensionless", + "reference": "10.1021/je2009329", + "data_type": "fitted" + }, + "Cphi": { + "value": "-0.00671 dimensionless", + "reference": "10.1021/je2009329", + "data_type": "fitted" + }, + "Max_C": { + "value": "3.5 mol/kg", + "reference": "10.1021/je2009329", + "data_type": "fitted" + } + }, + "molar_volume_pitzer": { + "Beta0": null, + "Beta1": null, + "Beta2": null, + "Cphi": null, + "V_o": null, + "Max_C": null + }, + "viscosity_jones_dole": { + "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, { - "formula": "CsHC2O.1H2O(aq)", + "formula": "CsH3(CO)2(aq)", "charge": 0, "molecular_weight": "191.9494719 g/mol", "elements": [ @@ -6867,10 +7607,10 @@ "@class": "Ion", "@version": null }, - "formula_html": "CsHC2O.1H2O", - "formula_latex": "CsHC$_{2}$O$_{.1}$H$_{2}$O", + "formula_html": "CsH3(CO)2", + "formula_latex": "CsH$_{3}$(CO)$_{2}$", "formula_hill": "C2 H3 Cs O2", - "formula_pretty": "CsHC2O.1H2O", + "formula_pretty": "CsH3(CO)2", "oxi_state_guesses": { "Cs": 1, "C": 0, @@ -6938,6 +7678,16 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null + }, + "dielectric_zuber": { + "value": "8.48 dimensionless", + "reference": "https://doi.org/10.1016/j.fluid.2014.05.037", + "data_type": "fitted" } } }, @@ -7051,6 +7801,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -7143,6 +7898,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -7259,6 +8019,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -7351,6 +8116,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -7439,6 +8209,11 @@ "data_type": "fitted" } }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null + }, "dielectric_zuber": { "value": "2.23 dimensionless", "reference": "https://doi.org/10.1016/j.fluid.2014.05.037", @@ -7559,6 +8334,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -7672,6 +8452,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -7788,6 +8573,136 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null + } + } + }, + { + "formula": "CuSO4(aq)", + "charge": 0, + "molecular_weight": "159.6086 g/mol", + "elements": [ + "Cu", + "S", + "O" + ], + "chemsys": "Cu-O-S", + "pmg_ion": { + "Cu": 1, + "S": 1, + "O": 4, + "charge": 0, + "@module": "pymatgen.core.ion", + "@class": "Ion", + "@version": null + }, + "formula_html": "CuSO4", + "formula_latex": "CuSO$_{4}$", + "formula_hill": "Cu O4 S", + "formula_pretty": "CuSO4", + "oxi_state_guesses": { + "Cu": 2, + "S": 6, + "O": -2 + }, + "n_atoms": 6, + "n_elements": 3, + "size": { + "radius_ionic": { + "value": "None", + "reference": "pymatgen", + "data_type": "experimental" + }, + "radius_hydrated": null, + "radius_vdw": { + "value": "1.96 Å", + "reference": "pymatgen", + "data_type": "experimental" + }, + "molar_volume": null + }, + "thermo": { + "ΔG_hydration": { + "value": "nan ± 6 kJ/mol", + "reference": "Marcus2015", + "data_type": "experimental" + }, + "ΔG_formation": null + }, + "transport": { + "diffusion_coefficient": null + }, + "model_parameters": { + "activity_pitzer": { + "Beta0": { + "value": "0.2281 dimensionless", + "reference": "10.1021/je2009329", + "data_type": "fitted" + }, + "Beta1": { + "value": "2.505 dimensionless", + "reference": "10.1021/je2009329", + "data_type": "fitted" + }, + "Beta2": { + "value": "-50.28 dimensionless", + "reference": "10.1021/je2009329", + "data_type": "fitted" + }, + "Cphi": { + "value": "0.005787 dimensionless", + "reference": "10.1021/je2009329", + "data_type": "fitted" + }, + "Max_C": { + "value": "1.42 mol/kg", + "reference": "10.1021/je2009329", + "data_type": "fitted" + } + }, + "molar_volume_pitzer": { + "Beta0": { + "value": "0.001499 dimensionless", + "reference": "10.1021/je2009329", + "data_type": "fitted" + }, + "Beta1": { + "value": "-0.008124 dimensionless", + "reference": "10.1021/je2009329", + "data_type": "fitted" + }, + "Beta2": { + "value": "0.2203 dimensionless", + "reference": "10.1021/je2009329", + "data_type": "fitted" + }, + "Cphi": { + "value": "-0.0002589 dimensionless", + "reference": "10.1021/je2009329", + "data_type": "fitted" + }, + "V_o": { + "value": "-6.0 dimensionless", + "reference": "10.1021/je2009329", + "data_type": "fitted" + }, + "Max_C": { + "value": "1.418 mol/kg", + "reference": "10.1021/je2009329", + "data_type": "fitted" + } + }, + "viscosity_jones_dole": { + "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -7863,6 +8778,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -7954,6 +8874,11 @@ "reference": "https://doi.org/10.1021/cr00040a004", "data_type": "fitted" } + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -8024,6 +8949,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -8094,6 +9024,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -8177,6 +9112,11 @@ "reference": "https://doi.org/10.1021/cr00040a004", "data_type": "fitted" } + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -8260,113 +9200,11 @@ "reference": "https://doi.org/10.1021/cr00040a004", "data_type": "fitted" } - } - } - }, - { - "formula": "Er[+3]", - "charge": 3, - "molecular_weight": "167.259 g/mol", - "elements": [ - "Er" - ], - "chemsys": "Er", - "pmg_ion": { - "Er": 1, - "charge": 3, - "@module": "pymatgen.core.ion", - "@class": "Ion", - "@version": null - }, - "formula_html": "Er+3", - "formula_latex": "Er$^{+3}$", - "formula_hill": "Er", - "formula_pretty": "Er^+3", - "oxi_state_guesses": { - "Er": 3 - }, - "n_atoms": 1, - "n_elements": 1, - "size": { - "radius_ionic": { - "value": "1.03 Å", - "reference": "pymatgen", - "data_type": "experimental" - }, - "radius_hydrated": null, - "radius_vdw": { - "value": "2.29 Å", - "reference": "pymatgen", - "data_type": "experimental" - }, - "molar_volume": null, - "radius_ionic_marcus": { - "value": "1.04 ± 0.01 Å", - "reference": "10.1021/ic200260r", - "data_type": "experimental" - } - }, - "thermo": { - "ΔG_hydration": { - "value": "-3627.0 ± 10 kJ/mol", - "reference": "10.1021/acs.jpca.9b05140", - "data_type": "experimental" }, - "ΔG_formation": null - }, - "transport": { - "diffusion_coefficient": { - "value": "5.85e-06 cm**2/s", - "reference": "CRC", - "data_type": "experimental" - } - }, - "model_parameters": { - "activity_pitzer": { - "Beta0": null, - "Beta1": null, - "Beta2": null, - "Cphi": null, - "Max_C": null - }, - "molar_volume_pitzer": { - "Beta0": { - "value": "2.655e-05 dimensionless", - "reference": "10.1021/je2009329", - "data_type": "fitted" - }, - "Beta1": { - "value": "0.000352 dimensionless", - "reference": "10.1021/je2009329", - "data_type": "fitted" - }, - "Beta2": { - "value": "0.0 dimensionless", - "reference": "10.1021/je2009329", - "data_type": "fitted" - }, - "Cphi": { - "value": "1.061e-05 dimensionless", - "reference": "10.1021/je2009329", - "data_type": "fitted" - }, - "V_o": { - "value": "33.7 dimensionless", - "reference": "10.1021/je2009329", - "data_type": "fitted" - }, - "Max_C": { - "value": "5.15 mol/kg", - "reference": "10.1021/je2009329", - "data_type": "fitted" - } - }, - "viscosity_jones_dole": { - "B": { - "value": "0.657 dm**3/mol", - "reference": "https://doi.org/10.1021/cr00040a004", - "data_type": "fitted" - } + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -8459,6 +9297,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -8572,6 +9415,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -8642,6 +9490,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -8725,6 +9578,11 @@ "reference": "https://doi.org/10.1021/cr00040a004", "data_type": "fitted" } + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -8817,6 +9675,11 @@ "data_type": "fitted" } }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null + }, "dielectric_zuber": { "value": "5.88 dimensionless", "reference": "https://doi.org/10.1016/j.fluid.2014.05.037", @@ -8910,6 +9773,11 @@ "reference": "https://doi.org/10.1021/cr00040a004", "data_type": "fitted" } + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -9003,6 +9871,11 @@ "reference": "https://doi.org/10.1021/cr00040a004", "data_type": "fitted" } + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -9116,6 +9989,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -9229,6 +10107,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -9320,12 +10203,17 @@ "reference": "https://doi.org/10.1021/cr00040a004", "data_type": "fitted" } + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, { - "formula": "Fe[+2]", - "charge": 2, + "formula": "Fe[+3]", + "charge": 3, "molecular_weight": "55.845 g/mol", "elements": [ "Fe" @@ -9333,28 +10221,28 @@ "chemsys": "Fe", "pmg_ion": { "Fe": 1, - "charge": 2, + "charge": 3, "@module": "pymatgen.core.ion", "@class": "Ion", "@version": null }, - "formula_html": "Fe+2", - "formula_latex": "Fe$^{+2}$", + "formula_html": "Fe+3", + "formula_latex": "Fe$^{+3}$", "formula_hill": "Fe", - "formula_pretty": "Fe^+2", + "formula_pretty": "Fe^+3", "oxi_state_guesses": { - "Fe": 2 + "Fe": 3 }, "n_atoms": 1, "n_elements": 1, "size": { "radius_ionic": { - "value": "0.92 Å", + "value": "0.785 Å", "reference": "pymatgen", "data_type": "experimental" }, "radius_hydrated": { - "value": "4.28 Å", + "value": "4.57 Å", "reference": "Nightingale1959", "data_type": "experimental" }, @@ -9364,19 +10252,19 @@ "data_type": "experimental" }, "molar_volume": { - "value": "-32.3 cm**3/mol", + "value": "-55.1 cm**3/mol", "reference": "Calculation of the Partial Molal Volume of Organic Compounds and Polymers. Progress in Colloid & Polymer Science (94), 20-39.", "data_type": "experimental" }, "radius_ionic_marcus": { - "value": "0.78 ± 0.02 Å", + "value": "0.65 ± 0.02 Å", "reference": "Marcus2015", "data_type": "experimental" } }, "thermo": { "ΔG_hydration": { - "value": "-1561.0 ± 10 kJ/mol", + "value": "-4383.0 ± 10 kJ/mol", "reference": "10.1021/acs.jpca.9b05140", "data_type": "experimental" }, @@ -9384,98 +10272,7 @@ }, "transport": { "diffusion_coefficient": { - "value": "7.19e-06 cm**2/s", - "reference": "CRC", - "data_type": "experimental" - } - }, - "model_parameters": { - "activity_pitzer": { - "Beta0": null, - "Beta1": null, - "Beta2": null, - "Cphi": null, - "Max_C": null - }, - "molar_volume_pitzer": { - "Beta0": null, - "Beta1": null, - "Beta2": null, - "Cphi": null, - "V_o": null, - "Max_C": null - }, - "viscosity_jones_dole": { - "B": { - "value": "0.412 dm**3/mol", - "reference": "https://doi.org/10.1021/cr00040a004", - "data_type": "fitted" - } - } - } - }, - { - "formula": "Fe[+3]", - "charge": 3, - "molecular_weight": "55.845 g/mol", - "elements": [ - "Fe" - ], - "chemsys": "Fe", - "pmg_ion": { - "Fe": 1, - "charge": 3, - "@module": "pymatgen.core.ion", - "@class": "Ion", - "@version": null - }, - "formula_html": "Fe+3", - "formula_latex": "Fe$^{+3}$", - "formula_hill": "Fe", - "formula_pretty": "Fe^+3", - "oxi_state_guesses": { - "Fe": 3 - }, - "n_atoms": 1, - "n_elements": 1, - "size": { - "radius_ionic": { - "value": "0.785 Å", - "reference": "pymatgen", - "data_type": "experimental" - }, - "radius_hydrated": { - "value": "4.57 Å", - "reference": "Nightingale1959", - "data_type": "experimental" - }, - "radius_vdw": { - "value": "2.04 Å", - "reference": "pymatgen", - "data_type": "experimental" - }, - "molar_volume": { - "value": "-55.1 cm**3/mol", - "reference": "Calculation of the Partial Molal Volume of Organic Compounds and Polymers. Progress in Colloid & Polymer Science (94), 20-39.", - "data_type": "experimental" - }, - "radius_ionic_marcus": { - "value": "0.65 ± 0.02 Å", - "reference": "Marcus2015", - "data_type": "experimental" - } - }, - "thermo": { - "ΔG_hydration": { - "value": "-4383.0 ± 10 kJ/mol", - "reference": "10.1021/acs.jpca.9b05140", - "data_type": "experimental" - }, - "ΔG_formation": null - }, - "transport": { - "diffusion_coefficient": { - "value": "6.04e-06 cm**2/s", + "value": "6.04e-06 cm**2/s", "reference": "CRC", "data_type": "experimental" } @@ -9502,6 +10299,11 @@ "reference": "https://doi.org/10.1021/cr00040a004", "data_type": "fitted" } + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -9577,6 +10379,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -9690,6 +10497,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -9773,6 +10585,11 @@ "reference": "https://doi.org/10.1021/cr00040a004", "data_type": "fitted" } + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -9843,270 +10660,376 @@ }, "viscosity_jones_dole": { "B": null - } - } - }, - { - "formula": "H2CO3(aq)", - "charge": 0, - "molecular_weight": "62.02477999999999 g/mol", - "elements": [ - "H", - "C", - "O" - ], - "chemsys": "C-H-O", - "pmg_ion": { - "H": 2, - "C": 1, - "O": 3, - "charge": 0, - "@module": "pymatgen.core.ion", - "@class": "Ion", - "@version": null - }, - "formula_html": "H2CO3", - "formula_latex": "H$_{2}$CO$_{3}$", - "formula_hill": "C H2 O3", - "formula_pretty": "H2CO3", - "oxi_state_guesses": { - "H": 1, - "C": 4, - "O": -2 - }, - "n_atoms": 6, - "n_elements": 3, - "size": { - "radius_ionic": { - "value": "None", - "reference": "pymatgen", - "data_type": "experimental" - }, - "radius_hydrated": null, - "radius_vdw": { - "value": "1.1 Å", - "reference": "pymatgen", - "data_type": "experimental" - }, - "molar_volume": null - }, - "thermo": { - "ΔG_hydration": { - "value": "nan ± 6 kJ/mol", - "reference": "Marcus2015", - "data_type": "experimental" }, - "ΔG_formation": null - }, - "transport": { - "diffusion_coefficient": null - }, - "model_parameters": { - "activity_pitzer": { - "Beta0": null, - "Beta1": null, - "Beta2": null, - "Cphi": null, - "Max_C": null - }, - "molar_volume_pitzer": { - "Beta0": null, - "Beta1": null, - "Beta2": null, - "Cphi": null, - "V_o": null, - "Max_C": null - }, - "viscosity_jones_dole": { - "B": null + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null + } + } + }, + { + "formula": "H2CO3(aq)", + "charge": 0, + "molecular_weight": "62.02477999999999 g/mol", + "elements": [ + "H", + "C", + "O" + ], + "chemsys": "C-H-O", + "pmg_ion": { + "H": 2, + "C": 1, + "O": 3, + "charge": 0, + "@module": "pymatgen.core.ion", + "@class": "Ion", + "@version": null + }, + "formula_html": "H2CO3", + "formula_latex": "H$_{2}$CO$_{3}$", + "formula_hill": "C H2 O3", + "formula_pretty": "H2CO3", + "oxi_state_guesses": { + "H": 1, + "C": 4, + "O": -2 + }, + "n_atoms": 6, + "n_elements": 3, + "size": { + "radius_ionic": { + "value": "None", + "reference": "pymatgen", + "data_type": "experimental" + }, + "radius_hydrated": null, + "radius_vdw": { + "value": "1.1 Å", + "reference": "pymatgen", + "data_type": "experimental" + }, + "molar_volume": null + }, + "thermo": { + "ΔG_hydration": { + "value": "nan ± 6 kJ/mol", + "reference": "Marcus2015", + "data_type": "experimental" + }, + "ΔG_formation": null + }, + "transport": { + "diffusion_coefficient": null + }, + "model_parameters": { + "activity_pitzer": { + "Beta0": null, + "Beta1": null, + "Beta2": null, + "Cphi": null, + "Max_C": null + }, + "molar_volume_pitzer": { + "Beta0": null, + "Beta1": null, + "Beta2": null, + "Cphi": null, + "V_o": null, + "Max_C": null + }, + "viscosity_jones_dole": { + "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null + } + } + }, + { + "formula": "H2O(aq)", + "charge": 0, + "molecular_weight": "18.01528 g/mol", + "elements": [ + "H", + "O" + ], + "chemsys": "H-O", + "pmg_ion": { + "H": 2, + "O": 1, + "charge": 0 + }, + "formula_html": "H2O", + "formula_latex": "H$_{2}$O", + "formula_hill": "H2 O", + "formula_pretty": "H2O", + "oxi_state_guesses": { + "H": 1, + "O": -2 + }, + "n_atoms": 3, + "n_elements": 2, + "size": { + "radius_ionic": null, + "radius_hydrated": null, + "radius_vdw": null, + "molar_volume": null + }, + "thermo": { + "ΔG_hydration": null, + "ΔG_formation": null + }, + "transport": { + "diffusion_coefficient": null + }, + "model_parameters": { + "activity_pitzer": { + "Beta0": null, + "Beta1": null, + "Beta2": null, + "Cphi": null, + "Max_C": null + }, + "molar_volume_pitzer": { + "Beta0": null, + "Beta1": null, + "Beta2": null, + "Cphi": null, + "V_o": null, + "Max_C": null + }, + "viscosity_jones_dole": { + "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null + } + } + }, + { + "formula": "H2SNO3[-1]", + "charge": -1, + "molecular_weight": "96.08578 g/mol", + "elements": [ + "N", + "H", + "S", + "O" + ], + "chemsys": "H-N-O-S", + "pmg_ion": { + "N": 1, + "H": 2, + "S": 1, + "O": 3, + "charge": -1, + "@module": "pymatgen.core.ion", + "@class": "Ion", + "@version": null + }, + "formula_html": "H2SNO3-1", + "formula_latex": "H$_{2}$SNO$_{3}$$^{-1}$", + "formula_hill": "H2 N O3 S", + "formula_pretty": "H2SNO3^-1", + "oxi_state_guesses": { + "N": 5, + "H": 1, + "S": -2, + "O": -2 + }, + "n_atoms": 7, + "n_elements": 4, + "size": { + "radius_ionic": { + "value": "None", + "reference": "pymatgen", + "data_type": "experimental" + }, + "radius_hydrated": null, + "radius_vdw": { + "value": "1.55 Å", + "reference": "pymatgen", + "data_type": "experimental" + }, + "molar_volume": null + }, + "thermo": { + "ΔG_hydration": null, + "ΔG_formation": null + }, + "transport": { + "diffusion_coefficient": { + "value": "1.286e-05 cm**2/s", + "reference": "CRC", + "data_type": "experimental" + } + }, + "model_parameters": { + "activity_pitzer": { + "Beta0": null, + "Beta1": null, + "Beta2": null, + "Cphi": null, + "Max_C": null + }, + "molar_volume_pitzer": { + "Beta0": null, + "Beta1": null, + "Beta2": null, + "Cphi": null, + "V_o": null, + "Max_C": null + }, + "viscosity_jones_dole": { + "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null + } + } + }, + { + "formula": "H2SO4(aq)", + "charge": 0, + "molecular_weight": "98.07848 g/mol", + "elements": [ + "H", + "S", + "O" + ], + "chemsys": "H-O-S", + "pmg_ion": { + "H": 2, + "S": 1, + "O": 4, + "charge": 0, + "@module": "pymatgen.core.ion", + "@class": "Ion", + "@version": null + }, + "formula_html": "H2SO4", + "formula_latex": "H$_{2}$SO$_{4}$", + "formula_hill": "H2 O4 S", + "formula_pretty": "H2SO4", + "oxi_state_guesses": { + "H": 1, + "S": 6, + "O": -2 + }, + "n_atoms": 7, + "n_elements": 3, + "size": { + "radius_ionic": { + "value": "None", + "reference": "pymatgen", + "data_type": "experimental" + }, + "radius_hydrated": null, + "radius_vdw": { + "value": "1.1 Å", + "reference": "pymatgen", + "data_type": "experimental" + }, + "molar_volume": null + }, + "thermo": { + "ΔG_hydration": { + "value": "nan ± 6 kJ/mol", + "reference": "Marcus2015", + "data_type": "experimental" + }, + "ΔG_formation": null + }, + "transport": { + "diffusion_coefficient": null + }, + "model_parameters": { + "activity_pitzer": { + "Beta0": null, + "Beta1": null, + "Beta2": null, + "Cphi": null, + "Max_C": null + }, + "molar_volume_pitzer": { + "Beta0": null, + "Beta1": null, + "Beta2": null, + "Cphi": null, + "V_o": null, + "Max_C": null + }, + "viscosity_jones_dole": { + "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, { - "formula": "H2O(aq)", - "charge": 0, - "molecular_weight": "18.01528 g/mol", + "formula": "H3O[+1]", + "charge": 1, + "molecular_weight": "19.02322 g/mol", "elements": [ "H", "O" ], "chemsys": "H-O", "pmg_ion": { - "H": 2, + "H": 3, "O": 1, - "charge": 0 - }, - "formula_html": "H2O", - "formula_latex": "H$_{2}$O", - "formula_hill": "H2 O", - "formula_pretty": "H2O", - "oxi_state_guesses": - { - "H": 1, - "O": -2 - }, - "n_atoms": 3, - "n_elements": 2, - "size": { - "radius_ionic": null, - "radius_hydrated": null, - "radius_vdw": null, - "molar_volume": null - }, - "thermo": { - "ΔG_hydration": null, - "ΔG_formation": null - }, - "transport": { - "diffusion_coefficient": null - }, - "model_parameters": { - "activity_pitzer": { - "Beta0": null, - "Beta1": null, - "Beta2": null, - "Cphi": null, - "Max_C": null - }, - "molar_volume_pitzer": { - "Beta0": null, - "Beta1": null, - "Beta2": null, - "Cphi": null, - "V_o": null, - "Max_C": null - }, - "viscosity_jones_dole": { - "B": null - } - } - }, - { - "formula": "H2SNO3[-1]", - "charge": -1, - "molecular_weight": "96.08578 g/mol", - "elements": [ - "N", - "H", - "S", - "O" - ], - "chemsys": "H-N-O-S", - "pmg_ion": { - "N": 1, - "H": 2, - "S": 1, - "O": 3, - "charge": -1, + "charge": 1, "@module": "pymatgen.core.ion", "@class": "Ion", "@version": null }, - "formula_html": "H2SNO3-1", - "formula_latex": "H$_{2}$SNO$_{3}$$^{-1}$", - "formula_hill": "H2 N O3 S", - "formula_pretty": "H2SNO3^-1", + "formula_html": "H3O+1", + "formula_latex": "H$_{3}$O$^{+1}$", + "formula_hill": "H3 O", + "formula_pretty": "H3O^+1", "oxi_state_guesses": { - "N": 5, "H": 1, - "S": -2, "O": -2 }, - "n_atoms": 7, - "n_elements": 4, + "n_atoms": 4, + "n_elements": 2, "size": { "radius_ionic": { "value": "None", "reference": "pymatgen", "data_type": "experimental" }, - "radius_hydrated": null, - "radius_vdw": { - "value": "1.55 Å", - "reference": "pymatgen", - "data_type": "experimental" - }, - "molar_volume": null - }, - "thermo": { - "ΔG_hydration": null, - "ΔG_formation": null - }, - "transport": { - "diffusion_coefficient": { - "value": "1.286e-05 cm**2/s", - "reference": "CRC", - "data_type": "experimental" - } - }, - "model_parameters": { - "activity_pitzer": { - "Beta0": null, - "Beta1": null, - "Beta2": null, - "Cphi": null, - "Max_C": null - }, - "molar_volume_pitzer": { - "Beta0": null, - "Beta1": null, - "Beta2": null, - "Cphi": null, - "V_o": null, - "Max_C": null - }, - "viscosity_jones_dole": { - "B": null - } - } - }, - { - "formula": "H2SO4(aq)", - "charge": 0, - "molecular_weight": "98.07848 g/mol", - "elements": [ - "H", - "S", - "O" - ], - "chemsys": "H-O-S", - "pmg_ion": { - "H": 2, - "S": 1, - "O": 4, - "charge": 0, - "@module": "pymatgen.core.ion", - "@class": "Ion", - "@version": null - }, - "formula_html": "H2SO4", - "formula_latex": "H$_{2}$SO$_{4}$", - "formula_hill": "H2 O4 S", - "formula_pretty": "H2SO4", - "oxi_state_guesses": { - "H": 1, - "S": 6, - "O": -2 - }, - "n_atoms": 7, - "n_elements": 3, - "size": { - "radius_ionic": { - "value": "None", - "reference": "pymatgen", + "radius_hydrated": { + "value": "2.82 Å", + "reference": "Nightingale1959", "data_type": "experimental" }, - "radius_hydrated": null, "radius_vdw": { "value": "1.1 Å", "reference": "pymatgen", "data_type": "experimental" }, - "molar_volume": null + "molar_volume": null, + "radius_ionic_marcus": { + "value": "1.3 ± 0.02 Å", + "reference": "Marcus2015", + "data_type": "experimental" + } }, "thermo": { "ΔG_hydration": { - "value": "nan ± 6 kJ/mol", + "value": "-211.0 ± 6 kJ/mol", "reference": "Marcus2015", "data_type": "experimental" }, @@ -10133,6 +11056,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -10188,8 +11116,8 @@ }, "thermo": { "ΔG_hydration": { - "value": "-211.0 ± 6 kJ/mol", - "reference": "Marcus2015", + "value": "-1561.0 ± 10 kJ/mol", + "reference": "10.1021/acs.jpca.9b05140", "data_type": "experimental" }, "ΔG_formation": null @@ -10215,6 +11143,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -10331,6 +11264,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -10447,6 +11385,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -10563,6 +11506,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -10679,6 +11627,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -10798,6 +11751,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -10892,6 +11850,23 @@ "reference": "https://doi.org/10.1021/cr00040a004", "data_type": "fitted" } + }, + "diffusion_temp_smolyakov": { + "a1": { + "value": "0.95 dimensionless", + "reference": "https://doi.org/10.1016/j.cemconres.2017.08.030", + "data_type": "fitted" + }, + "a2": { + "value": "4.53 dimensionless", + "reference": "https://doi.org/10.1016/j.cemconres.2017.08.030", + "data_type": "fitted" + }, + "d": { + "value": "312 dimensionless", + "reference": "https://doi.org/10.1016/j.cemconres.2017.08.030", + "data_type": "fitted" + } } } }, @@ -10991,6 +11966,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -11067,6 +12047,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -11140,6 +12125,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -11235,6 +12225,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -11348,6 +12343,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -11433,6 +12433,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -11522,6 +12527,23 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": { + "value": "1.43 dimensionless", + "reference": "https://doi.org/10.1016/j.cemconres.2017.08.030", + "data_type": "fitted" + }, + "a2": { + "value": "0 dimensionless", + "reference": "https://doi.org/10.1016/j.cemconres.2017.08.030", + "data_type": "fitted" + }, + "d": { + "value": "0 dimensionless", + "reference": "https://doi.org/10.1016/j.cemconres.2017.08.030", + "data_type": "fitted" + } } } }, @@ -11635,6 +12657,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -11751,6 +12778,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -11824,6 +12856,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -11937,6 +12974,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -12057,6 +13099,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -12135,6 +13182,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -12211,6 +13263,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -12287,6 +13344,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -12372,6 +13434,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -12449,6 +13516,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -12525,6 +13597,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -12608,6 +13685,23 @@ "data_type": "fitted" } }, + "diffusion_temp_smolyakov": { + "a1": { + "value": "0.46 dimensionless", + "reference": "https://doi.org/10.1016/j.cemconres.2017.08.030", + "data_type": "fitted" + }, + "a2": { + "value": "0 dimensionless", + "reference": "https://doi.org/10.1016/j.cemconres.2017.08.030", + "data_type": "fitted" + }, + "d": { + "value": "763 dimensionless", + "reference": "https://doi.org/10.1016/j.cemconres.2017.08.030", + "data_type": "fitted" + } + }, "dielectric_zuber": { "value": "9.55 dimensionless", "reference": "https://doi.org/10.1016/j.fluid.2014.05.037", @@ -12687,6 +13781,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -12766,6 +13865,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -12849,6 +13953,11 @@ "reference": "https://doi.org/10.1021/cr00040a004", "data_type": "fitted" } + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -12939,6 +14048,11 @@ "reference": "https://doi.org/10.1021/cr00040a004", "data_type": "fitted" } + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -13016,6 +14130,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -13108,6 +14227,11 @@ "data_type": "fitted" } }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null + }, "dielectric_zuber": { "value": "7.65 dimensionless", "reference": "https://doi.org/10.1016/j.fluid.2014.05.037", @@ -13182,6 +14306,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -13252,6 +14381,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -13327,6 +14461,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -13400,6 +14539,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -13470,6 +14614,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -13586,6 +14735,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -13705,6 +14859,132 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null + } + } + }, + { + "formula": "K2SO4(aq)", + "charge": 0, + "molecular_weight": "174.2592 g/mol", + "elements": [ + "K", + "S", + "O" + ], + "chemsys": "K-O-S", + "pmg_ion": { + "K": 2, + "S": 1, + "O": 4, + "charge": 0, + "@module": "pymatgen.core.ion", + "@class": "Ion", + "@version": null + }, + "formula_html": "K2SO4", + "formula_latex": "K$_{2}$SO$_{4}$", + "formula_hill": "K2 O4 S", + "formula_pretty": "K2SO4", + "oxi_state_guesses": { + "K": 1, + "S": 6, + "O": -2 + }, + "n_atoms": 7, + "n_elements": 3, + "size": { + "radius_ionic": { + "value": "None", + "reference": "pymatgen", + "data_type": "experimental" + }, + "radius_hydrated": null, + "radius_vdw": { + "value": "2.75 Å", + "reference": "pymatgen", + "data_type": "experimental" + }, + "molar_volume": null + }, + "thermo": { + "ΔG_hydration": null, + "ΔG_formation": null + }, + "transport": { + "diffusion_coefficient": null + }, + "model_parameters": { + "activity_pitzer": { + "Beta0": { + "value": "0.07424 dimensionless", + "reference": "10.1021/je2009329", + "data_type": "fitted" + }, + "Beta1": { + "value": "0.5188 dimensionless", + "reference": "10.1021/je2009329", + "data_type": "fitted" + }, + "Beta2": { + "value": "0.0 dimensionless", + "reference": "10.1021/je2009329", + "data_type": "fitted" + }, + "Cphi": { + "value": "-0.01057 dimensionless", + "reference": "10.1021/je2009329", + "data_type": "fitted" + }, + "Max_C": { + "value": "2.0 mol/kg", + "reference": "10.1021/je2009329", + "data_type": "fitted" + } + }, + "molar_volume_pitzer": { + "Beta0": { + "value": "-0.001179 dimensionless", + "reference": "10.1021/je2009329", + "data_type": "fitted" + }, + "Beta1": { + "value": "0.006263 dimensionless", + "reference": "10.1021/je2009329", + "data_type": "fitted" + }, + "Beta2": { + "value": "0.0 dimensionless", + "reference": "10.1021/je2009329", + "data_type": "fitted" + }, + "Cphi": { + "value": "0.001473 dimensionless", + "reference": "10.1021/je2009329", + "data_type": "fitted" + }, + "V_o": { + "value": "32.0 dimensionless", + "reference": "10.1021/je2009329", + "data_type": "fitted" + }, + "Max_C": { + "value": "1.05 mol/kg", + "reference": "10.1021/je2009329", + "data_type": "fitted" + } + }, + "viscosity_jones_dole": { + "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -13821,6 +15101,23 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": { + "value": "3.4 dimensionless", + "reference": "https://doi.org/10.1016/j.cemconres.2017.08.030", + "data_type": "fitted" + }, + "a2": { + "value": "24.6 dimensionless", + "reference": "https://doi.org/10.1016/j.cemconres.2017.08.030", + "data_type": "fitted" + }, + "d": { + "value": "97 dimensionless", + "reference": "https://doi.org/10.1016/j.cemconres.2017.08.030", + "data_type": "fitted" + } } } }, @@ -13916,6 +15213,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -14032,6 +15334,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -14127,95 +15434,11 @@ }, "viscosity_jones_dole": { "B": null - } - } - }, - { - "formula": "KBr(aq)", - "charge": 0, - "molecular_weight": "119.00229999999999 g/mol", - "elements": [ - "K", - "Br" - ], - "chemsys": "Br-K", - "pmg_ion": { - "K": 1, - "Br": 1, - "charge": 0, - "@module": "pymatgen.core.ion", - "@class": "Ion", - "@version": null - }, - "formula_html": "KBr", - "formula_latex": "KBr", - "formula_hill": "Br K", - "formula_pretty": "KBr", - "oxi_state_guesses": { - "K": 1, - "Br": -1 - }, - "n_atoms": 2, - "n_elements": 2, - "size": { - "radius_ionic": { - "value": "None", - "reference": "pymatgen", - "data_type": "experimental" - }, - "radius_hydrated": null, - "radius_vdw": { - "value": "2.75 Å", - "reference": "pymatgen", - "data_type": "experimental" - }, - "molar_volume": null - }, - "thermo": { - "ΔG_hydration": null, - "ΔG_formation": null - }, - "transport": { - "diffusion_coefficient": null - }, - "model_parameters": { - "activity_pitzer": { - "Beta0": { - "value": "0.05517 dimensionless", - "reference": "10.1021/je2009329", - "data_type": "fitted" - }, - "Beta1": { - "value": "0.2361 dimensionless", - "reference": "10.1021/je2009329", - "data_type": "fitted" - }, - "Beta2": { - "value": "0.0 dimensionless", - "reference": "10.1021/je2009329", - "data_type": "fitted" - }, - "Cphi": { - "value": "-0.00148 dimensionless", - "reference": "10.1021/je2009329", - "data_type": "fitted" - }, - "Max_C": { - "value": "5.5 mol/kg", - "reference": "10.1021/je2009329", - "data_type": "fitted" - } }, - "molar_volume_pitzer": { - "Beta0": null, - "Beta1": null, - "Beta2": null, - "Cphi": null, - "V_o": null, - "Max_C": null - }, - "viscosity_jones_dole": { - "B": null + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -14265,11 +15488,7 @@ "ΔG_formation": null }, "transport": { - "diffusion_coefficient": { - "value": "9.05e-06 cm**2/s", - "reference": "CRC", - "data_type": "experimental" - } + "diffusion_coefficient": null }, "model_parameters": { "activity_pitzer": { @@ -14300,15 +15519,44 @@ } }, "molar_volume_pitzer": { - "Beta0": null, - "Beta1": null, - "Beta2": null, - "Cphi": null, - "V_o": null, - "Max_C": null + "Beta0": { + "value": "2.655e-05 dimensionless", + "reference": "10.1021/je2009329", + "data_type": "fitted" + }, + "Beta1": { + "value": "0.000352 dimensionless", + "reference": "10.1021/je2009329", + "data_type": "fitted" + }, + "Beta2": { + "value": "0.0 dimensionless", + "reference": "10.1021/je2009329", + "data_type": "fitted" + }, + "Cphi": { + "value": "1.061e-05 dimensionless", + "reference": "10.1021/je2009329", + "data_type": "fitted" + }, + "V_o": { + "value": "33.7 dimensionless", + "reference": "10.1021/je2009329", + "data_type": "fitted" + }, + "Max_C": { + "value": "5.15 mol/kg", + "reference": "10.1021/je2009329", + "data_type": "fitted" + } }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -14401,6 +15649,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -14520,6 +15773,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -14609,6 +15867,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -14701,6 +15964,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -14797,6 +16065,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -14913,6 +16186,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -15026,11 +16304,16 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, { - "formula": "KHC2O.1H2O(aq)", + "formula": "KH3(CO)2(aq)", "charge": 0, "molecular_weight": "98.14232 g/mol", "elements": [ @@ -15050,10 +16333,10 @@ "@class": "Ion", "@version": null }, - "formula_html": "KHC2O.1H2O", - "formula_latex": "KHC$_{2}$O$_{.1}$H$_{2}$O", + "formula_html": "KH3(CO)2", + "formula_latex": "KH$_{3}$(CO)$_{2}$", "formula_hill": "C2 H3 K O2", - "formula_pretty": "KHC2O.1H2O", + "formula_pretty": "KH3(CO)2", "oxi_state_guesses": { "K": 1, "C": 0, @@ -15145,6 +16428,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -15264,6 +16552,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -15377,6 +16670,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -15493,6 +16791,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -15609,6 +16912,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -15725,11 +17033,16 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, { - "formula": "KPO3.1H2O(aq)", + "formula": "KP(HO2)2(aq)", "charge": 0, "molecular_weight": "136.085542 g/mol", "elements": [ @@ -15749,10 +17062,10 @@ "@class": "Ion", "@version": null }, - "formula_html": "KPO3.1H2O", - "formula_latex": "KPO$_{3.1}$H$_{2}$O", + "formula_html": "KP(HO2)2", + "formula_latex": "KP(HO$_{2}$)$_{2}$", "formula_hill": "H2 K O4 P", - "formula_pretty": "KPO3.1H2O", + "formula_pretty": "KP(HO2)2", "oxi_state_guesses": { "K": 1, "H": 1, @@ -15844,6 +17157,100 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null + } + } + }, + { + "formula": "KSO4[-1]", + "charge": -1, + "molecular_weight": "135.1609 g/mol", + "elements": [ + "K", + "S", + "O" + ], + "chemsys": "K-O-S", + "pmg_ion": { + "K": 1, + "S": 1, + "O": 4, + "charge": -1, + "@module": "pymatgen.core.ion", + "@class": "Ion", + "@version": null + }, + "formula_html": "KSO4-1", + "formula_latex": "KSO$_{4}$$^{-1}$", + "formula_hill": "K O4 S", + "formula_pretty": "KSO4^-1", + "oxi_state_guesses": { + "K": 1, + "S": 6, + "O": -2 + }, + "n_atoms": 6, + "n_elements": 3, + "size": { + "radius_ionic": { + "value": "None", + "reference": "pymatgen", + "data_type": "experimental" + }, + "radius_hydrated": null, + "radius_vdw": { + "value": "2.75 Å", + "reference": "pymatgen", + "data_type": "experimental" + }, + "molar_volume": null + }, + "thermo": { + "ΔG_hydration": null, + "ΔG_formation": null + }, + "transport": { + "diffusion_coefficient": null + }, + "model_parameters": { + "activity_pitzer": { + "Beta0": null, + "Beta1": null, + "Beta2": null, + "Cphi": null, + "Max_C": null + }, + "molar_volume_pitzer": { + "Beta0": null, + "Beta1": null, + "Beta2": null, + "Cphi": null, + "V_o": null, + "Max_C": null + }, + "viscosity_jones_dole": { + "B": null + }, + "diffusion_temp_smolyakov": { + "a1": { + "value": "0 dimensionless", + "reference": "https://doi.org/10.1016/j.cemconres.2017.08.030", + "data_type": "fitted" + }, + "a2": { + "value": "0 dimensionless", + "reference": "https://doi.org/10.1016/j.cemconres.2017.08.030", + "data_type": "fitted" + }, + "d": { + "value": "0 dimensionless", + "reference": "https://doi.org/10.1016/j.cemconres.2017.08.030", + "data_type": "fitted" + } } } }, @@ -15936,6 +17343,23 @@ "data_type": "fitted" } }, + "diffusion_temp_smolyakov": { + "a1": { + "value": "2.5 dimensionless", + "reference": "https://doi.org/10.1016/j.cemconres.2017.08.030", + "data_type": "fitted" + }, + "a2": { + "value": "21 dimensionless", + "reference": "https://doi.org/10.1016/j.cemconres.2017.08.030", + "data_type": "fitted" + }, + "d": { + "value": "395 dimensionless", + "reference": "https://doi.org/10.1016/j.cemconres.2017.08.030", + "data_type": "fitted" + } + }, "dielectric_zuber": { "value": "2.43 dimensionless", "reference": "https://doi.org/10.1016/j.fluid.2014.05.037", @@ -16032,6 +17456,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -16145,6 +17574,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -16232,6 +17666,11 @@ "reference": "https://doi.org/10.1021/cr00040a004", "data_type": "fitted" } + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -16348,6 +17787,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -16461,6 +17905,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -16574,6 +18023,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -16690,11 +18144,16 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, { - "formula": "LiHC2O.1H2O(aq)", + "formula": "LiH3(CO)2(aq)", "charge": 0, "molecular_weight": "65.98501999999999 g/mol", "elements": [ @@ -16714,10 +18173,10 @@ "@class": "Ion", "@version": null }, - "formula_html": "LiHC2O.1H2O", - "formula_latex": "LiHC$_{2}$O$_{.1}$H$_{2}$O", + "formula_html": "LiH3(CO)2", + "formula_latex": "LiH$_{3}$(CO)$_{2}$", "formula_hill": "C2 H3 Li O2", - "formula_pretty": "LiHC2O.1H2O", + "formula_pretty": "LiH3(CO)2", "oxi_state_guesses": { "Li": 1, "C": 0, @@ -16809,6 +18268,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -16922,6 +18386,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -17014,6 +18483,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -17130,6 +18604,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -17246,6 +18725,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -17338,6 +18822,11 @@ "data_type": "fitted" } }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null + }, "dielectric_zuber": { "value": "6.59 dimensionless", "reference": "https://doi.org/10.1016/j.fluid.2014.05.037", @@ -17421,6 +18910,11 @@ "reference": "https://doi.org/10.1021/cr00040a004", "data_type": "fitted" } + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -17537,6 +19031,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -17653,6 +19152,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -17707,131 +19211,12 @@ "model_parameters": { "activity_pitzer": { "Beta0": { - "value": "0.4368 dimensionless", - "reference": "10.1021/je2009329", - "data_type": "fitted" - }, - "Beta1": { - "value": "1.73 dimensionless", - "reference": "10.1021/je2009329", - "data_type": "fitted" - }, - "Beta2": { - "value": "0.0 dimensionless", - "reference": "10.1021/je2009329", - "data_type": "fitted" - }, - "Cphi": { - "value": "0.002432 dimensionless", - "reference": "10.1021/je2009329", - "data_type": "fitted" - }, - "Max_C": { - "value": "5.61 mol/kg", - "reference": "10.1021/je2009329", - "data_type": "fitted" - } - }, - "molar_volume_pitzer": { - "Beta0": { - "value": "0.0003715 dimensionless", - "reference": "10.1021/je2009329", - "data_type": "fitted" - }, - "Beta1": { - "value": "-0.001361 dimensionless", - "reference": "10.1021/je2009329", - "data_type": "fitted" - }, - "Beta2": { - "value": "0.0 dimensionless", - "reference": "10.1021/je2009329", - "data_type": "fitted" - }, - "Cphi": { - "value": "-5.296e-05 dimensionless", - "reference": "10.1021/je2009329", - "data_type": "fitted" - }, - "V_o": { - "value": "28.2 dimensionless", - "reference": "10.1021/je2009329", - "data_type": "fitted" - }, - "Max_C": { - "value": "5.431 mol/kg", - "reference": "10.1021/je2009329", - "data_type": "fitted" - } - }, - "viscosity_jones_dole": { - "B": null - } - } - }, - { - "formula": "MgC4O.3H2O(aq)", - "charge": 0, - "molecular_weight": "142.39304 g/mol", - "elements": [ - "Mg", - "C", - "H", - "O" - ], - "chemsys": "C-H-Mg-O", - "pmg_ion": { - "Mg": 1, - "C": 4, - "H": 6, - "O": 4, - "charge": 0, - "@module": "pymatgen.core.ion", - "@class": "Ion", - "@version": null - }, - "formula_html": "MgC4O.3H2O", - "formula_latex": "MgC$_{4}$O$_{.3}$H$_{2}$O", - "formula_hill": "C4 H6 Mg O4", - "formula_pretty": "MgC4O.3H2O", - "oxi_state_guesses": { - "Mg": 2, - "C": 0, - "H": 1, - "O": -2 - }, - "n_atoms": 15, - "n_elements": 4, - "size": { - "radius_ionic": { - "value": "None", - "reference": "pymatgen", - "data_type": "experimental" - }, - "radius_hydrated": null, - "radius_vdw": { - "value": "1.73 Å", - "reference": "pymatgen", - "data_type": "experimental" - }, - "molar_volume": null - }, - "thermo": { - "ΔG_hydration": null, - "ΔG_formation": null - }, - "transport": { - "diffusion_coefficient": null - }, - "model_parameters": { - "activity_pitzer": { - "Beta0": { - "value": "0.21 dimensionless", + "value": "0.4368 dimensionless", "reference": "10.1021/je2009329", "data_type": "fitted" }, "Beta1": { - "value": "0.9347 dimensionless", + "value": "1.73 dimensionless", "reference": "10.1021/je2009329", "data_type": "fitted" }, @@ -17841,24 +19226,24 @@ "data_type": "fitted" }, "Cphi": { - "value": "-0.01332 dimensionless", + "value": "0.002432 dimensionless", "reference": "10.1021/je2009329", "data_type": "fitted" }, "Max_C": { - "value": "4.0 mol/kg", + "value": "5.61 mol/kg", "reference": "10.1021/je2009329", "data_type": "fitted" } }, "molar_volume_pitzer": { "Beta0": { - "value": "0.0006679 dimensionless", + "value": "0.0003715 dimensionless", "reference": "10.1021/je2009329", "data_type": "fitted" }, "Beta1": { - "value": "-0.0002526 dimensionless", + "value": "-0.001361 dimensionless", "reference": "10.1021/je2009329", "data_type": "fitted" }, @@ -17868,59 +19253,58 @@ "data_type": "fitted" }, "Cphi": { - "value": "0.0001019 dimensionless", + "value": "-5.296e-05 dimensionless", "reference": "10.1021/je2009329", "data_type": "fitted" }, "V_o": { - "value": "60.2 dimensionless", + "value": "28.2 dimensionless", "reference": "10.1021/je2009329", "data_type": "fitted" }, "Max_C": { - "value": "0.573 mol/kg", + "value": "5.431 mol/kg", "reference": "10.1021/je2009329", "data_type": "fitted" } }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, { - "formula": "MgC4O.3H2O(aq)", + "formula": "MgCl2(aq)", "charge": 0, - "molecular_weight": "142.39304 g/mol", + "molecular_weight": "95.21100000000001 g/mol", "elements": [ "Mg", - "C", - "H", - "O" + "Cl" ], - "chemsys": "C-H-Mg-O", + "chemsys": "Cl-Mg", "pmg_ion": { "Mg": 1, - "C": 4, - "H": 6, - "O": 4, + "Cl": 2, "charge": 0, "@module": "pymatgen.core.ion", "@class": "Ion", "@version": null }, - "formula_html": "MgC4O.3H2O", - "formula_latex": "MgC$_{4}$O$_{.3}$H$_{2}$O", - "formula_hill": "C4 H6 Mg O4", - "formula_pretty": "MgC4O.3H2O", + "formula_html": "MgCl2", + "formula_latex": "MgCl$_{2}$", + "formula_hill": "Cl2 Mg", + "formula_pretty": "MgCl2", "oxi_state_guesses": { "Mg": 2, - "C": 0, - "H": 1, - "O": -2 + "Cl": -1 }, - "n_atoms": 15, - "n_elements": 4, + "n_atoms": 3, + "n_elements": 2, "size": { "radius_ionic": { "value": "None", @@ -17936,11 +19320,7 @@ "molar_volume": null }, "thermo": { - "ΔG_hydration": { - "value": "-1394.0 ± 10 kJ/mol", - "reference": "10.1021/acs.jpca.9b05140", - "data_type": "experimental" - }, + "ΔG_hydration": null, "ΔG_formation": null }, "transport": { @@ -17949,12 +19329,12 @@ "model_parameters": { "activity_pitzer": { "Beta0": { - "value": "0.21 dimensionless", + "value": "0.3553 dimensionless", "reference": "10.1021/je2009329", "data_type": "fitted" }, "Beta1": { - "value": "0.9347 dimensionless", + "value": "1.644 dimensionless", "reference": "10.1021/je2009329", "data_type": "fitted" }, @@ -17964,24 +19344,24 @@ "data_type": "fitted" }, "Cphi": { - "value": "-0.01332 dimensionless", + "value": "0.005098 dimensionless", "reference": "10.1021/je2009329", "data_type": "fitted" }, "Max_C": { - "value": "4.0 mol/kg", + "value": "5.925 mol/kg", "reference": "10.1021/je2009329", "data_type": "fitted" } }, "molar_volume_pitzer": { "Beta0": { - "value": "0.0006679 dimensionless", + "value": "0.0001747 dimensionless", "reference": "10.1021/je2009329", "data_type": "fitted" }, "Beta1": { - "value": "-0.0002526 dimensionless", + "value": "-0.0007983 dimensionless", "reference": "10.1021/je2009329", "data_type": "fitted" }, @@ -17991,53 +19371,64 @@ "data_type": "fitted" }, "Cphi": { - "value": "0.0001019 dimensionless", + "value": "-1.76e-05 dimensionless", "reference": "10.1021/je2009329", "data_type": "fitted" }, "V_o": { - "value": "60.2 dimensionless", + "value": "14.4 dimensionless", "reference": "10.1021/je2009329", "data_type": "fitted" }, "Max_C": { - "value": "0.573 mol/kg", + "value": "5.411 mol/kg", "reference": "10.1021/je2009329", "data_type": "fitted" } }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, { - "formula": "MgCl2(aq)", + "formula": "MgH6(CO)4(aq)", "charge": 0, - "molecular_weight": "95.21100000000001 g/mol", + "molecular_weight": "142.39304 g/mol", "elements": [ "Mg", - "Cl" + "C", + "H", + "O" ], - "chemsys": "Cl-Mg", + "chemsys": "C-H-Mg-O", "pmg_ion": { "Mg": 1, - "Cl": 2, + "C": 4, + "H": 6, + "O": 4, "charge": 0, "@module": "pymatgen.core.ion", "@class": "Ion", "@version": null }, - "formula_html": "MgCl2", - "formula_latex": "MgCl$_{2}$", - "formula_hill": "Cl2 Mg", - "formula_pretty": "MgCl2", + "formula_html": "MgH6(CO)4", + "formula_latex": "MgH$_{6}$(CO)$_{4}$", + "formula_hill": "C4 H6 Mg O4", + "formula_pretty": "MgH6(CO)4", "oxi_state_guesses": { "Mg": 2, - "Cl": -1 + "C": 0, + "H": 1, + "O": -2 }, - "n_atoms": 3, - "n_elements": 2, + "n_atoms": 15, + "n_elements": 4, "size": { "radius_ionic": { "value": "None", @@ -18062,12 +19453,12 @@ "model_parameters": { "activity_pitzer": { "Beta0": { - "value": "0.3553 dimensionless", + "value": "0.21 dimensionless", "reference": "10.1021/je2009329", "data_type": "fitted" }, "Beta1": { - "value": "1.644 dimensionless", + "value": "0.9347 dimensionless", "reference": "10.1021/je2009329", "data_type": "fitted" }, @@ -18077,24 +19468,24 @@ "data_type": "fitted" }, "Cphi": { - "value": "0.005098 dimensionless", + "value": "-0.01332 dimensionless", "reference": "10.1021/je2009329", "data_type": "fitted" }, "Max_C": { - "value": "5.925 mol/kg", + "value": "4.0 mol/kg", "reference": "10.1021/je2009329", "data_type": "fitted" } }, "molar_volume_pitzer": { "Beta0": { - "value": "0.0001747 dimensionless", + "value": "0.0006679 dimensionless", "reference": "10.1021/je2009329", "data_type": "fitted" }, "Beta1": { - "value": "-0.0007983 dimensionless", + "value": "-0.0002526 dimensionless", "reference": "10.1021/je2009329", "data_type": "fitted" }, @@ -18104,23 +19495,28 @@ "data_type": "fitted" }, "Cphi": { - "value": "-1.76e-05 dimensionless", + "value": "0.0001019 dimensionless", "reference": "10.1021/je2009329", "data_type": "fitted" }, "V_o": { - "value": "14.4 dimensionless", + "value": "60.2 dimensionless", "reference": "10.1021/je2009329", "data_type": "fitted" }, "Max_C": { - "value": "5.411 mol/kg", + "value": "0.573 mol/kg", "reference": "10.1021/je2009329", "data_type": "fitted" } }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -18234,6 +19630,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -18350,6 +19751,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -18442,6 +19848,11 @@ "data_type": "fitted" } }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null + }, "dielectric_zuber": { "value": "6.69 dimensionless", "reference": "https://doi.org/10.1016/j.fluid.2014.05.037", @@ -18500,103 +19911,321 @@ "model_parameters": { "activity_pitzer": { "Beta0": { - "value": "0.3268 dimensionless", + "value": "0.3268 dimensionless", + "reference": "10.1021/je2009329", + "data_type": "fitted" + }, + "Beta1": { + "value": "1.524 dimensionless", + "reference": "10.1021/je2009329", + "data_type": "fitted" + }, + "Beta2": { + "value": "0.0 dimensionless", + "reference": "10.1021/je2009329", + "data_type": "fitted" + }, + "Cphi": { + "value": "-0.02109 dimensionless", + "reference": "10.1021/je2009329", + "data_type": "fitted" + }, + "Max_C": { + "value": "5.0 mol/kg", + "reference": "10.1021/je2009329", + "data_type": "fitted" + } + }, + "molar_volume_pitzer": { + "Beta0": { + "value": "8.053e-05 dimensionless", + "reference": "10.1021/je2009329", + "data_type": "fitted" + }, + "Beta1": { + "value": "0.0002428 dimensionless", + "reference": "10.1021/je2009329", + "data_type": "fitted" + }, + "Beta2": { + "value": "0.0 dimensionless", + "reference": "10.1021/je2009329", + "data_type": "fitted" + }, + "Cphi": { + "value": "-7.2e-05 dimensionless", + "reference": "10.1021/je2009329", + "data_type": "fitted" + }, + "V_o": { + "value": "17.9 dimensionless", + "reference": "10.1021/je2009329", + "data_type": "fitted" + }, + "Max_C": { + "value": "4.87 mol/kg", + "reference": "10.1021/je2009329", + "data_type": "fitted" + } + }, + "viscosity_jones_dole": { + "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null + } + } + }, + { + "formula": "MnO4[-1]", + "charge": -1, + "molecular_weight": "118.935645 g/mol", + "elements": [ + "Mn", + "O" + ], + "chemsys": "Mn-O", + "pmg_ion": { + "Mn": 1, + "O": 4, + "charge": -1, + "@module": "pymatgen.core.ion", + "@class": "Ion", + "@version": null + }, + "formula_html": "MnO4-1", + "formula_latex": "MnO$_{4}$$^{-1}$", + "formula_hill": "Mn O4", + "formula_pretty": "MnO4^-1", + "oxi_state_guesses": { + "Mn": 7, + "O": -2 + }, + "n_atoms": 5, + "n_elements": 2, + "size": { + "radius_ionic": { + "value": "None", + "reference": "pymatgen", + "data_type": "experimental" + }, + "radius_hydrated": { + "value": "3.45 Å", + "reference": "Nightingale1959", + "data_type": "experimental" + }, + "radius_vdw": { + "value": "2.05 Å", + "reference": "pymatgen", + "data_type": "experimental" + }, + "molar_volume": null, + "radius_ionic_marcus": { + "value": "2.4 ± 0.02 Å", + "reference": "Marcus2015", + "data_type": "experimental" + } + }, + "thermo": { + "ΔG_hydration": { + "value": "-187.0 ± 6 kJ/mol", + "reference": "Marcus2015", + "data_type": "experimental" + }, + "ΔG_formation": null + }, + "transport": { + "diffusion_coefficient": { + "value": "1.632e-05 cm**2/s", + "reference": "CRC", + "data_type": "experimental" + } + }, + "model_parameters": { + "activity_pitzer": { + "Beta0": null, + "Beta1": null, + "Beta2": null, + "Cphi": null, + "Max_C": null + }, + "molar_volume_pitzer": { + "Beta0": null, + "Beta1": null, + "Beta2": null, + "Cphi": null, + "V_o": null, + "Max_C": null + }, + "viscosity_jones_dole": { + "B": { + "value": "-0.057 dm**3/mol", + "reference": "https://doi.org/10.1021/cr00040a004", + "data_type": "fitted" + } + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null + } + } + }, + { + "formula": "MnSO4(aq)", + "charge": 0, + "molecular_weight": "151.000645 g/mol", + "elements": [ + "Mn", + "S", + "O" + ], + "chemsys": "Mn-O-S", + "pmg_ion": { + "Mn": 1, + "S": 1, + "O": 4, + "charge": 0, + "@module": "pymatgen.core.ion", + "@class": "Ion", + "@version": null + }, + "formula_html": "MnSO4", + "formula_latex": "MnSO$_{4}$", + "formula_hill": "Mn O4 S", + "formula_pretty": "MnSO4", + "oxi_state_guesses": { + "Mn": 2, + "S": 6, + "O": -2 + }, + "n_atoms": 6, + "n_elements": 3, + "size": { + "radius_ionic": { + "value": "None", + "reference": "pymatgen", + "data_type": "experimental" + }, + "radius_hydrated": null, + "radius_vdw": { + "value": "2.05 Å", + "reference": "pymatgen", + "data_type": "experimental" + }, + "molar_volume": null + }, + "thermo": { + "ΔG_hydration": null, + "ΔG_formation": null + }, + "transport": { + "diffusion_coefficient": null + }, + "model_parameters": { + "activity_pitzer": { + "Beta0": { + "value": "0.2139 dimensionless", "reference": "10.1021/je2009329", "data_type": "fitted" }, "Beta1": { - "value": "1.524 dimensionless", + "value": "2.875 dimensionless", "reference": "10.1021/je2009329", "data_type": "fitted" }, "Beta2": { - "value": "0.0 dimensionless", + "value": "-52.32 dimensionless", "reference": "10.1021/je2009329", "data_type": "fitted" }, "Cphi": { - "value": "-0.02109 dimensionless", + "value": "0.01497 dimensionless", "reference": "10.1021/je2009329", "data_type": "fitted" }, "Max_C": { - "value": "5.0 mol/kg", + "value": "4.966 mol/kg", "reference": "10.1021/je2009329", "data_type": "fitted" } }, "molar_volume_pitzer": { "Beta0": { - "value": "8.053e-05 dimensionless", + "value": "0.001401 dimensionless", "reference": "10.1021/je2009329", "data_type": "fitted" }, "Beta1": { - "value": "0.0002428 dimensionless", + "value": "0.008694 dimensionless", "reference": "10.1021/je2009329", "data_type": "fitted" }, "Beta2": { - "value": "0.0 dimensionless", + "value": "-0.6453 dimensionless", "reference": "10.1021/je2009329", "data_type": "fitted" }, "Cphi": { - "value": "-7.2e-05 dimensionless", + "value": "-0.0003672 dimensionless", "reference": "10.1021/je2009329", "data_type": "fitted" }, "V_o": { - "value": "17.9 dimensionless", + "value": "-3.7 dimensionless", "reference": "10.1021/je2009329", "data_type": "fitted" }, "Max_C": { - "value": "4.87 mol/kg", + "value": "4.059 mol/kg", "reference": "10.1021/je2009329", "data_type": "fitted" } }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, { - "formula": "MnO4[-1]", - "charge": -1, - "molecular_weight": "118.935645 g/mol", + "formula": "Mn[+2]", + "charge": 2, + "molecular_weight": "54.938045 g/mol", "elements": [ - "Mn", - "O" + "Mn" ], - "chemsys": "Mn-O", + "chemsys": "Mn", "pmg_ion": { "Mn": 1, - "O": 4, - "charge": -1, + "charge": 2, "@module": "pymatgen.core.ion", "@class": "Ion", "@version": null }, - "formula_html": "MnO4-1", - "formula_latex": "MnO$_{4}$$^{-1}$", - "formula_hill": "Mn O4", - "formula_pretty": "MnO4^-1", + "formula_html": "Mn+2", + "formula_latex": "Mn$^{+2}$", + "formula_hill": "Mn", + "formula_pretty": "Mn^+2", "oxi_state_guesses": { - "Mn": 7, - "O": -2 + "Mn": 2 }, - "n_atoms": 5, - "n_elements": 2, + "n_atoms": 1, + "n_elements": 1, "size": { "radius_ionic": { - "value": "None", + "value": "0.97 Å", "reference": "pymatgen", "data_type": "experimental" }, "radius_hydrated": { - "value": "3.45 Å", + "value": "4.38 Å", "reference": "Nightingale1959", "data_type": "experimental" }, @@ -18605,24 +20234,28 @@ "reference": "pymatgen", "data_type": "experimental" }, - "molar_volume": null, + "molar_volume": { + "value": "-25.3 cm**3/mol", + "reference": "Calculation of the Partial Molal Volume of Organic Compounds and Polymers. Progress in Colloid & Polymer Science (94), 20-39.", + "data_type": "experimental" + }, "radius_ionic_marcus": { - "value": "2.4 ± 0.02 Å", + "value": "0.83 ± 0.02 Å", "reference": "Marcus2015", "data_type": "experimental" } }, "thermo": { "ΔG_hydration": { - "value": "-187.0 ± 6 kJ/mol", - "reference": "Marcus2015", + "value": "-1848.0 ± 10 kJ/mol", + "reference": "10.1021/acs.jpca.9b05140", "data_type": "experimental" }, "ΔG_formation": null }, "transport": { "diffusion_coefficient": { - "value": "1.632e-05 cm**2/s", + "value": "7.12e-06 cm**2/s", "reference": "CRC", "data_type": "experimental" } @@ -18645,126 +20278,15 @@ }, "viscosity_jones_dole": { "B": { - "value": "-0.057 dm**3/mol", + "value": "0.388 dm**3/mol", "reference": "https://doi.org/10.1021/cr00040a004", "data_type": "fitted" } - } - } - }, - { - "formula": "MnSO4(aq)", - "charge": 0, - "molecular_weight": "151.000645 g/mol", - "elements": [ - "Mn", - "S", - "O" - ], - "chemsys": "Mn-O-S", - "pmg_ion": { - "Mn": 1, - "S": 1, - "O": 4, - "charge": 0, - "@module": "pymatgen.core.ion", - "@class": "Ion", - "@version": null - }, - "formula_html": "MnSO4", - "formula_latex": "MnSO$_{4}$", - "formula_hill": "Mn O4 S", - "formula_pretty": "MnSO4", - "oxi_state_guesses": { - "Mn": 2, - "S": 6, - "O": -2 - }, - "n_atoms": 6, - "n_elements": 3, - "size": { - "radius_ionic": { - "value": "None", - "reference": "pymatgen", - "data_type": "experimental" - }, - "radius_hydrated": null, - "radius_vdw": { - "value": "2.05 Å", - "reference": "pymatgen", - "data_type": "experimental" - }, - "molar_volume": null - }, - "thermo": { - "ΔG_hydration": null, - "ΔG_formation": null - }, - "transport": { - "diffusion_coefficient": null - }, - "model_parameters": { - "activity_pitzer": { - "Beta0": { - "value": "0.2139 dimensionless", - "reference": "10.1021/je2009329", - "data_type": "fitted" - }, - "Beta1": { - "value": "2.875 dimensionless", - "reference": "10.1021/je2009329", - "data_type": "fitted" - }, - "Beta2": { - "value": "-52.32 dimensionless", - "reference": "10.1021/je2009329", - "data_type": "fitted" - }, - "Cphi": { - "value": "0.01497 dimensionless", - "reference": "10.1021/je2009329", - "data_type": "fitted" - }, - "Max_C": { - "value": "4.966 mol/kg", - "reference": "10.1021/je2009329", - "data_type": "fitted" - } - }, - "molar_volume_pitzer": { - "Beta0": { - "value": "0.001401 dimensionless", - "reference": "10.1021/je2009329", - "data_type": "fitted" - }, - "Beta1": { - "value": "0.008694 dimensionless", - "reference": "10.1021/je2009329", - "data_type": "fitted" - }, - "Beta2": { - "value": "-0.6453 dimensionless", - "reference": "10.1021/je2009329", - "data_type": "fitted" - }, - "Cphi": { - "value": "-0.0003672 dimensionless", - "reference": "10.1021/je2009329", - "data_type": "fitted" - }, - "V_o": { - "value": "-3.7 dimensionless", - "reference": "10.1021/je2009329", - "data_type": "fitted" - }, - "Max_C": { - "value": "4.059 mol/kg", - "reference": "10.1021/je2009329", - "data_type": "fitted" - } }, - "viscosity_jones_dole": { - "B": null + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -18821,7 +20343,7 @@ }, "thermo": { "ΔG_hydration": { - "value": "-1848.0 ± 10 kJ/mol", + "value": "-1489.0 ± 10 kJ/mol", "reference": "10.1021/acs.jpca.9b05140", "data_type": "experimental" }, @@ -18856,6 +20378,11 @@ "reference": "https://doi.org/10.1021/cr00040a004", "data_type": "fitted" } + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -18926,6 +20453,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -19012,6 +20544,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -19082,6 +20619,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -19164,6 +20706,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -19259,6 +20806,23 @@ "data_type": "fitted" } }, + "diffusion_temp_smolyakov": { + "a1": { + "value": "1.85 dimensionless", + "reference": "https://doi.org/10.1016/j.cemconres.2017.08.030", + "data_type": "fitted" + }, + "a2": { + "value": "3.85 dimensionless", + "reference": "https://doi.org/10.1016/j.cemconres.2017.08.030", + "data_type": "fitted" + }, + "d": { + "value": "184 dimensionless", + "reference": "https://doi.org/10.1016/j.cemconres.2017.08.030", + "data_type": "fitted" + } + }, "dielectric_zuber": { "value": "6.75 dimensionless", "reference": "https://doi.org/10.1016/j.fluid.2014.05.037", @@ -19337,6 +20901,11 @@ "reference": "https://doi.org/10.1021/cr00040a004", "data_type": "fitted" } + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -19453,6 +21022,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -19572,6 +21146,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -19629,128 +21208,12 @@ "model_parameters": { "activity_pitzer": { "Beta0": { - "value": "0.06306 dimensionless", - "reference": "10.1021/je2009329", - "data_type": "fitted" - }, - "Beta1": { - "value": "1.254 dimensionless", - "reference": "10.1021/je2009329", - "data_type": "fitted" - }, - "Beta2": { - "value": "0.0 dimensionless", - "reference": "10.1021/je2009329", - "data_type": "fitted" - }, - "Cphi": { - "value": "0.004673 dimensionless", - "reference": "10.1021/je2009329", - "data_type": "fitted" - }, - "Max_C": { - "value": "4.0 mol/kg", - "reference": "10.1021/je2009329", - "data_type": "fitted" - } - }, - "molar_volume_pitzer": { - "Beta0": { - "value": "0.0004842 dimensionless", - "reference": "10.1021/je2009329", - "data_type": "fitted" - }, - "Beta1": { - "value": "-0.002513 dimensionless", - "reference": "10.1021/je2009329", - "data_type": "fitted" - }, - "Beta2": { - "value": "0.0 dimensionless", - "reference": "10.1021/je2009329", - "data_type": "fitted" - }, - "Cphi": { - "value": "-4.894e-05 dimensionless", - "reference": "10.1021/je2009329", - "data_type": "fitted" - }, - "V_o": { - "value": "31.5 dimensionless", - "reference": "10.1021/je2009329", - "data_type": "fitted" - }, - "Max_C": { - "value": "3.877 mol/kg", - "reference": "10.1021/je2009329", - "data_type": "fitted" - } - }, - "viscosity_jones_dole": { - "B": null - } - } - }, - { - "formula": "Na2SO4(aq)", - "charge": 0, - "molecular_weight": "142.04213856 g/mol", - "elements": [ - "Na", - "S", - "O" - ], - "chemsys": "Na-O-S", - "pmg_ion": { - "Na": 2, - "S": 1, - "O": 4, - "charge": 0, - "@module": "pymatgen.core.ion", - "@class": "Ion", - "@version": null - }, - "formula_html": "Na2SO4", - "formula_latex": "Na$_{2}$SO$_{4}$", - "formula_hill": "Na2 O4 S", - "formula_pretty": "Na2SO4", - "oxi_state_guesses": { - "Na": 1, - "S": 6, - "O": -2 - }, - "n_atoms": 7, - "n_elements": 3, - "size": { - "radius_ionic": { - "value": "None", - "reference": "pymatgen", - "data_type": "experimental" - }, - "radius_hydrated": null, - "radius_vdw": { - "value": "2.27 Å", - "reference": "pymatgen", - "data_type": "experimental" - }, - "molar_volume": null - }, - "thermo": { - "ΔG_hydration": null, - "ΔG_formation": null - }, - "transport": { - "diffusion_coefficient": null - }, - "model_parameters": { - "activity_pitzer": { - "Beta0": { - "value": "0.01959 dimensionless", + "value": "0.06306 dimensionless", "reference": "10.1021/je2009329", "data_type": "fitted" }, "Beta1": { - "value": "1.049 dimensionless", + "value": "1.254 dimensionless", "reference": "10.1021/je2009329", "data_type": "fitted" }, @@ -19760,24 +21223,24 @@ "data_type": "fitted" }, "Cphi": { - "value": "0.005416 dimensionless", + "value": "0.004673 dimensionless", "reference": "10.1021/je2009329", "data_type": "fitted" }, "Max_C": { - "value": "5.0 mol/kg", + "value": "4.0 mol/kg", "reference": "10.1021/je2009329", "data_type": "fitted" } }, "molar_volume_pitzer": { "Beta0": { - "value": "0.0004129 dimensionless", + "value": "0.0004842 dimensionless", "reference": "10.1021/je2009329", "data_type": "fitted" }, "Beta1": { - "value": "0.001954 dimensionless", + "value": "-0.002513 dimensionless", "reference": "10.1021/je2009329", "data_type": "fitted" }, @@ -19787,55 +21250,60 @@ "data_type": "fitted" }, "Cphi": { - "value": "-3.7e-05 dimensionless", + "value": "-4.894e-05 dimensionless", "reference": "10.1021/je2009329", "data_type": "fitted" }, "V_o": { - "value": "11.6 dimensionless", + "value": "31.5 dimensionless", "reference": "10.1021/je2009329", "data_type": "fitted" }, "Max_C": { - "value": "4.694 mol/kg", + "value": "3.877 mol/kg", "reference": "10.1021/je2009329", "data_type": "fitted" } }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, { - "formula": "Na3PO4(aq)", + "formula": "Na2SO4(aq)", "charge": 0, - "molecular_weight": "163.94066984 g/mol", + "molecular_weight": "142.04213856 g/mol", "elements": [ "Na", - "P", + "S", "O" ], - "chemsys": "Na-O-P", + "chemsys": "Na-O-S", "pmg_ion": { - "Na": 3, - "P": 1, + "Na": 2, + "S": 1, "O": 4, "charge": 0, "@module": "pymatgen.core.ion", "@class": "Ion", "@version": null }, - "formula_html": "Na3PO4", - "formula_latex": "Na$_{3}$PO$_{4}$", - "formula_hill": "Na3 O4 P", - "formula_pretty": "Na3PO4", + "formula_html": "Na2SO4", + "formula_latex": "Na$_{2}$SO$_{4}$", + "formula_hill": "Na2 O4 S", + "formula_pretty": "Na2SO4", "oxi_state_guesses": { "Na": 1, - "P": 5, + "S": 6, "O": -2 }, - "n_atoms": 8, + "n_atoms": 7, "n_elements": 3, "size": { "radius_ionic": { @@ -19861,12 +21329,12 @@ "model_parameters": { "activity_pitzer": { "Beta0": { - "value": "0.139 dimensionless", + "value": "0.01959 dimensionless", "reference": "10.1021/je2009329", "data_type": "fitted" }, "Beta1": { - "value": "5.419 dimensionless", + "value": "1.049 dimensionless", "reference": "10.1021/je2009329", "data_type": "fitted" }, @@ -19876,24 +21344,24 @@ "data_type": "fitted" }, "Cphi": { - "value": "-0.04454 dimensionless", + "value": "0.005416 dimensionless", "reference": "10.1021/je2009329", "data_type": "fitted" }, "Max_C": { - "value": "0.8 mol/kg", + "value": "5.0 mol/kg", "reference": "10.1021/je2009329", "data_type": "fitted" } }, "molar_volume_pitzer": { "Beta0": { - "value": "-0.002545 dimensionless", + "value": "0.0004129 dimensionless", "reference": "10.1021/je2009329", "data_type": "fitted" }, "Beta1": { - "value": "0.01227 dimensionless", + "value": "0.001954 dimensionless", "reference": "10.1021/je2009329", "data_type": "fitted" }, @@ -19903,23 +21371,28 @@ "data_type": "fitted" }, "Cphi": { - "value": "0.00337 dimensionless", + "value": "-3.7e-05 dimensionless", "reference": "10.1021/je2009329", "data_type": "fitted" }, "V_o": { - "value": "-25.0 dimensionless", + "value": "11.6 dimensionless", "reference": "10.1021/je2009329", "data_type": "fitted" }, "Max_C": { - "value": "0.6657 mol/kg", + "value": "4.694 mol/kg", "reference": "10.1021/je2009329", "data_type": "fitted" } }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -19972,11 +21445,7 @@ "ΔG_formation": null }, "transport": { - "diffusion_coefficient": { - "value": "nan cm**2/s", - "reference": "CRC", - "data_type": "experimental" - } + "diffusion_coefficient": null }, "model_parameters": { "activity_pitzer": { @@ -20040,6 +21509,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -20153,6 +21627,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -20269,6 +21748,100 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null + } + } + }, + { + "formula": "NaCO3[-1]", + "charge": -1, + "molecular_weight": "82.99866928 g/mol", + "elements": [ + "Na", + "C", + "O" + ], + "chemsys": "C-Na-O", + "pmg_ion": { + "Na": 1, + "C": 1, + "O": 3, + "charge": -1, + "@module": "pymatgen.core.ion", + "@class": "Ion", + "@version": null + }, + "formula_html": "NaCO3-1", + "formula_latex": "NaCO$_{3}$$^{-1}$", + "formula_hill": "C Na O3", + "formula_pretty": "NaCO3^-1", + "oxi_state_guesses": { + "Na": 1, + "C": 4, + "O": -2 + }, + "n_atoms": 5, + "n_elements": 3, + "size": { + "radius_ionic": { + "value": "None", + "reference": "pymatgen", + "data_type": "experimental" + }, + "radius_hydrated": null, + "radius_vdw": { + "value": "2.27 Å", + "reference": "pymatgen", + "data_type": "experimental" + }, + "molar_volume": null + }, + "thermo": { + "ΔG_hydration": null, + "ΔG_formation": null + }, + "transport": { + "diffusion_coefficient": null + }, + "model_parameters": { + "activity_pitzer": { + "Beta0": null, + "Beta1": null, + "Beta2": null, + "Cphi": null, + "Max_C": null + }, + "molar_volume_pitzer": { + "Beta0": null, + "Beta1": null, + "Beta2": null, + "Cphi": null, + "V_o": null, + "Max_C": null + }, + "viscosity_jones_dole": { + "B": null + }, + "diffusion_temp_smolyakov": { + "a1": { + "value": "0 dimensionless", + "reference": "https://doi.org/10.1016/j.cemconres.2017.08.030", + "data_type": "fitted" + }, + "a2": { + "value": "0 dimensionless", + "reference": "https://doi.org/10.1016/j.cemconres.2017.08.030", + "data_type": "fitted" + }, + "d": { + "value": "0 dimensionless", + "reference": "https://doi.org/10.1016/j.cemconres.2017.08.030", + "data_type": "fitted" + } } } }, @@ -20388,6 +21961,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -20501,6 +22079,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -20617,6 +22200,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -20674,12 +22262,130 @@ "model_parameters": { "activity_pitzer": { "Beta0": { - "value": "0.06437 dimensionless", + "value": "0.06437 dimensionless", + "reference": "10.1021/je2009329", + "data_type": "fitted" + }, + "Beta1": { + "value": "1.544 dimensionless", + "reference": "10.1021/je2009329", + "data_type": "fitted" + }, + "Beta2": { + "value": "0.0 dimensionless", + "reference": "10.1021/je2009329", + "data_type": "fitted" + }, + "Cphi": { + "value": "0.009028 dimensionless", + "reference": "10.1021/je2009329", + "data_type": "fitted" + }, + "Max_C": { + "value": "4.363 mol/kg", + "reference": "10.1021/je2009329", + "data_type": "fitted" + } + }, + "molar_volume_pitzer": { + "Beta0": { + "value": "0.0005722 dimensionless", + "reference": "10.1021/je2009329", + "data_type": "fitted" + }, + "Beta1": { + "value": "-0.001298 dimensionless", + "reference": "10.1021/je2009329", + "data_type": "fitted" + }, + "Beta2": { + "value": "0.0 dimensionless", + "reference": "10.1021/je2009329", + "data_type": "fitted" + }, + "Cphi": { + "value": "-5.95e-05 dimensionless", + "reference": "10.1021/je2009329", + "data_type": "fitted" + }, + "V_o": { + "value": "17.3 dimensionless", + "reference": "10.1021/je2009329", + "data_type": "fitted" + }, + "Max_C": { + "value": "4.234 mol/kg", + "reference": "10.1021/je2009329", + "data_type": "fitted" + } + }, + "viscosity_jones_dole": { + "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null + } + } + }, + { + "formula": "NaF(aq)", + "charge": 0, + "molecular_weight": "41.98817248 g/mol", + "elements": [ + "Na", + "F" + ], + "chemsys": "F-Na", + "pmg_ion": { + "Na": 1, + "F": 1, + "charge": 0, + "@module": "pymatgen.core.ion", + "@class": "Ion", + "@version": null + }, + "formula_html": "NaF", + "formula_latex": "NaF", + "formula_hill": "F Na", + "formula_pretty": "NaF", + "oxi_state_guesses": { + "Na": 1, + "F": -1 + }, + "n_atoms": 2, + "n_elements": 2, + "size": { + "radius_ionic": { + "value": "None", + "reference": "pymatgen", + "data_type": "experimental" + }, + "radius_hydrated": null, + "radius_vdw": { + "value": "2.27 Å", + "reference": "pymatgen", + "data_type": "experimental" + }, + "molar_volume": null + }, + "thermo": { + "ΔG_hydration": null, + "ΔG_formation": null + }, + "transport": { + "diffusion_coefficient": null + }, + "model_parameters": { + "activity_pitzer": { + "Beta0": { + "value": "0.02109 dimensionless", "reference": "10.1021/je2009329", "data_type": "fitted" }, "Beta1": { - "value": "1.544 dimensionless", + "value": "0.2183 dimensionless", "reference": "10.1021/je2009329", "data_type": "fitted" }, @@ -20689,24 +22395,24 @@ "data_type": "fitted" }, "Cphi": { - "value": "0.009028 dimensionless", + "value": "-0.001 dimensionless", "reference": "10.1021/je2009329", "data_type": "fitted" }, "Max_C": { - "value": "4.363 mol/kg", + "value": "1.0 mol/kg", "reference": "10.1021/je2009329", "data_type": "fitted" } }, "molar_volume_pitzer": { "Beta0": { - "value": "0.0005722 dimensionless", + "value": "0.002113 dimensionless", "reference": "10.1021/je2009329", "data_type": "fitted" }, "Beta1": { - "value": "-0.001298 dimensionless", + "value": "-0.003857 dimensionless", "reference": "10.1021/je2009329", "data_type": "fitted" }, @@ -20716,23 +22422,28 @@ "data_type": "fitted" }, "Cphi": { - "value": "-5.95e-05 dimensionless", + "value": "-0.001535 dimensionless", "reference": "10.1021/je2009329", "data_type": "fitted" }, "V_o": { - "value": "17.3 dimensionless", + "value": "-2.4 dimensionless", "reference": "10.1021/je2009329", "data_type": "fitted" }, "Max_C": { - "value": "4.234 mol/kg", + "value": "0.9923 mol/kg", "reference": "10.1021/je2009329", "data_type": "fitted" } }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -20778,7 +22489,11 @@ "molar_volume": null }, "thermo": { - "ΔG_hydration": null, + "ΔG_hydration": { + "value": "-1576.0 ± 10 kJ/mol", + "reference": "10.1021/acs.jpca.9b05140", + "data_type": "experimental" + }, "ΔG_formation": null }, "transport": { @@ -20846,11 +22561,16 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, { - "formula": "NaHC2O.1H2O(aq)", + "formula": "NaH3(CO)2(aq)", "charge": 0, "molecular_weight": "82.03378928000001 g/mol", "elements": [ @@ -20870,10 +22590,10 @@ "@class": "Ion", "@version": null }, - "formula_html": "NaHC2O.1H2O", - "formula_latex": "NaHC$_{2}$O$_{.1}$H$_{2}$O", + "formula_html": "NaH3(CO)2", + "formula_latex": "NaH$_{3}$(CO)$_{2}$", "formula_hill": "C2 H3 Na O2", - "formula_pretty": "NaHC2O.1H2O", + "formula_pretty": "NaH3(CO)2", "oxi_state_guesses": { "Na": 1, "C": 0, @@ -20965,11 +22685,16 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, { - "formula": "NaHC3.2H2O(aq)", + "formula": "NaH5C3O2(aq)", "charge": 0, "molecular_weight": "96.06036928 g/mol", "elements": [ @@ -20989,10 +22714,10 @@ "@class": "Ion", "@version": null }, - "formula_html": "NaHC3.2H2O", - "formula_latex": "NaHC$_{3.2}$H$_{2}$O", + "formula_html": "NaH5C3O2", + "formula_latex": "NaH$_{5}$C$_{3}$O$_{2}$", "formula_hill": "C3 H5 Na O2", - "formula_pretty": "NaHC3.2H2O", + "formula_pretty": "NaH5C3O2", "oxi_state_guesses": { "Na": 1, "C": -0.6666666666666666, @@ -21060,6 +22785,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -21179,6 +22909,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -21298,6 +23033,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -21411,6 +23151,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -21503,6 +23248,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -21619,6 +23369,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -21675,185 +23430,284 @@ }, "model_parameters": { "activity_pitzer": { - "Beta0": { - "value": "0.09226 dimensionless", - "reference": "10.1021/je2009329", - "data_type": "fitted" - }, - "Beta1": { - "value": "0.2424 dimensionless", - "reference": "10.1021/je2009329", - "data_type": "fitted" - }, - "Beta2": { - "value": "0.0 dimensionless", - "reference": "10.1021/je2009329", - "data_type": "fitted" - }, - "Cphi": { - "value": "0.003343 dimensionless", - "reference": "10.1021/je2009329", - "data_type": "fitted" - }, - "Max_C": { - "value": "11.5 mol/kg", - "reference": "10.1021/je2009329", - "data_type": "fitted" - } + "Beta0": { + "value": "0.09226 dimensionless", + "reference": "10.1021/je2009329", + "data_type": "fitted" + }, + "Beta1": { + "value": "0.2424 dimensionless", + "reference": "10.1021/je2009329", + "data_type": "fitted" + }, + "Beta2": { + "value": "0.0 dimensionless", + "reference": "10.1021/je2009329", + "data_type": "fitted" + }, + "Cphi": { + "value": "0.003343 dimensionless", + "reference": "10.1021/je2009329", + "data_type": "fitted" + }, + "Max_C": { + "value": "11.5 mol/kg", + "reference": "10.1021/je2009329", + "data_type": "fitted" + } + }, + "molar_volume_pitzer": { + "Beta0": { + "value": "0.000218 dimensionless", + "reference": "10.1021/je2009329", + "data_type": "fitted" + }, + "Beta1": { + "value": "0.0005212 dimensionless", + "reference": "10.1021/je2009329", + "data_type": "fitted" + }, + "Beta2": { + "value": "0.0 dimensionless", + "reference": "10.1021/je2009329", + "data_type": "fitted" + }, + "Cphi": { + "value": "-1.07e-05 dimensionless", + "reference": "10.1021/je2009329", + "data_type": "fitted" + }, + "V_o": { + "value": "-5.2 dimensionless", + "reference": "10.1021/je2009329", + "data_type": "fitted" + }, + "Max_C": { + "value": "10.88 mol/kg", + "reference": "10.1021/je2009329", + "data_type": "fitted" + } + }, + "viscosity_jones_dole": { + "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null + } + } + }, + { + "formula": "NaP(HO2)2(aq)", + "charge": 0, + "molecular_weight": "119.97701128 g/mol", + "elements": [ + "Na", + "H", + "P", + "O" + ], + "chemsys": "H-Na-O-P", + "pmg_ion": { + "Na": 1, + "H": 2, + "P": 1, + "O": 4, + "charge": 0, + "@module": "pymatgen.core.ion", + "@class": "Ion", + "@version": null + }, + "formula_html": "NaP(HO2)2", + "formula_latex": "NaP(HO$_{2}$)$_{2}$", + "formula_hill": "H2 Na O4 P", + "formula_pretty": "NaP(HO2)2", + "oxi_state_guesses": { + "Na": 1, + "H": 1, + "P": 5, + "O": -2 + }, + "n_atoms": 8, + "n_elements": 4, + "size": { + "radius_ionic": { + "value": "None", + "reference": "pymatgen", + "data_type": "experimental" + }, + "radius_hydrated": null, + "radius_vdw": { + "value": "2.27 Å", + "reference": "pymatgen", + "data_type": "experimental" + }, + "molar_volume": null + }, + "thermo": { + "ΔG_hydration": null, + "ΔG_formation": null + }, + "transport": { + "diffusion_coefficient": null + }, + "model_parameters": { + "activity_pitzer": { + "Beta0": { + "value": "-0.05135 dimensionless", + "reference": "10.1021/je2009329", + "data_type": "fitted" + }, + "Beta1": { + "value": "0.05496 dimensionless", + "reference": "10.1021/je2009329", + "data_type": "fitted" + }, + "Beta2": { + "value": "0.0 dimensionless", + "reference": "10.1021/je2009329", + "data_type": "fitted" + }, + "Cphi": { + "value": "0.007441 dimensionless", + "reference": "10.1021/je2009329", + "data_type": "fitted" + }, + "Max_C": { + "value": "6.5 mol/kg", + "reference": "10.1021/je2009329", + "data_type": "fitted" + } + }, + "molar_volume_pitzer": { + "Beta0": { + "value": "-8.958e-05 dimensionless", + "reference": "10.1021/je2009329", + "data_type": "fitted" + }, + "Beta1": { + "value": "0.003652 dimensionless", + "reference": "10.1021/je2009329", + "data_type": "fitted" + }, + "Beta2": { + "value": "0.0 dimensionless", + "reference": "10.1021/je2009329", + "data_type": "fitted" + }, + "Cphi": { + "value": "9.716e-05 dimensionless", + "reference": "10.1021/je2009329", + "data_type": "fitted" + }, + "V_o": { + "value": "27.9 dimensionless", + "reference": "10.1021/je2009329", + "data_type": "fitted" + }, + "Max_C": { + "value": "5.557 mol/kg", + "reference": "10.1021/je2009329", + "data_type": "fitted" + } + }, + "viscosity_jones_dole": { + "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null + } + } + }, + { + "formula": "NaSO4[-1]", + "charge": -1, + "molecular_weight": "119.05236928 g/mol", + "elements": [ + "Na", + "S", + "O" + ], + "chemsys": "Na-O-S", + "pmg_ion": { + "Na": 1, + "S": 1, + "O": 4, + "charge": -1, + "@module": "pymatgen.core.ion", + "@class": "Ion", + "@version": null + }, + "formula_html": "NaSO4-1", + "formula_latex": "NaSO$_{4}$$^{-1}$", + "formula_hill": "Na O4 S", + "formula_pretty": "NaSO4^-1", + "oxi_state_guesses": { + "Na": 1, + "S": 6, + "O": -2 + }, + "n_atoms": 6, + "n_elements": 3, + "size": { + "radius_ionic": { + "value": "None", + "reference": "pymatgen", + "data_type": "experimental" + }, + "radius_hydrated": null, + "radius_vdw": { + "value": "2.27 Å", + "reference": "pymatgen", + "data_type": "experimental" + }, + "molar_volume": null + }, + "thermo": { + "ΔG_hydration": null, + "ΔG_formation": null + }, + "transport": { + "diffusion_coefficient": null + }, + "model_parameters": { + "activity_pitzer": { + "Beta0": null, + "Beta1": null, + "Beta2": null, + "Cphi": null, + "Max_C": null }, "molar_volume_pitzer": { - "Beta0": { - "value": "0.000218 dimensionless", - "reference": "10.1021/je2009329", - "data_type": "fitted" - }, - "Beta1": { - "value": "0.0005212 dimensionless", - "reference": "10.1021/je2009329", - "data_type": "fitted" - }, - "Beta2": { - "value": "0.0 dimensionless", - "reference": "10.1021/je2009329", - "data_type": "fitted" - }, - "Cphi": { - "value": "-1.07e-05 dimensionless", - "reference": "10.1021/je2009329", - "data_type": "fitted" - }, - "V_o": { - "value": "-5.2 dimensionless", - "reference": "10.1021/je2009329", - "data_type": "fitted" - }, - "Max_C": { - "value": "10.88 mol/kg", - "reference": "10.1021/je2009329", - "data_type": "fitted" - } + "Beta0": null, + "Beta1": null, + "Beta2": null, + "Cphi": null, + "V_o": null, + "Max_C": null }, "viscosity_jones_dole": { "B": null - } - } - }, - { - "formula": "NaPO3.1H2O(aq)", - "charge": 0, - "molecular_weight": "119.97701128 g/mol", - "elements": [ - "Na", - "H", - "P", - "O" - ], - "chemsys": "H-Na-O-P", - "pmg_ion": { - "Na": 1, - "H": 2, - "P": 1, - "O": 4, - "charge": 0, - "@module": "pymatgen.core.ion", - "@class": "Ion", - "@version": null - }, - "formula_html": "NaPO3.1H2O", - "formula_latex": "NaPO$_{3.1}$H$_{2}$O", - "formula_hill": "H2 Na O4 P", - "formula_pretty": "NaPO3.1H2O", - "oxi_state_guesses": { - "Na": 1, - "H": 1, - "P": 5, - "O": -2 - }, - "n_atoms": 8, - "n_elements": 4, - "size": { - "radius_ionic": { - "value": "None", - "reference": "pymatgen", - "data_type": "experimental" - }, - "radius_hydrated": null, - "radius_vdw": { - "value": "2.27 Å", - "reference": "pymatgen", - "data_type": "experimental" }, - "molar_volume": null - }, - "thermo": { - "ΔG_hydration": null, - "ΔG_formation": null - }, - "transport": { - "diffusion_coefficient": null - }, - "model_parameters": { - "activity_pitzer": { - "Beta0": { - "value": "-0.05135 dimensionless", - "reference": "10.1021/je2009329", + "diffusion_temp_smolyakov": { + "a1": { + "value": "0.57 dimensionless", + "reference": "https://doi.org/10.1016/j.cemconres.2017.08.030", "data_type": "fitted" }, - "Beta1": { - "value": "0.05496 dimensionless", - "reference": "10.1021/je2009329", + "a2": { + "value": "0 dimensionless", + "reference": "https://doi.org/10.1016/j.cemconres.2017.08.030", "data_type": "fitted" }, - "Beta2": { - "value": "0.0 dimensionless", - "reference": "10.1021/je2009329", - "data_type": "fitted" - }, - "Cphi": { - "value": "0.007441 dimensionless", - "reference": "10.1021/je2009329", - "data_type": "fitted" - }, - "Max_C": { - "value": "6.5 mol/kg", - "reference": "10.1021/je2009329", + "d": { + "value": "0 dimensionless", + "reference": "https://doi.org/10.1016/j.cemconres.2017.08.030", "data_type": "fitted" } - }, - "molar_volume_pitzer": { - "Beta0": { - "value": "-8.958e-05 dimensionless", - "reference": "10.1021/je2009329", - "data_type": "fitted" - }, - "Beta1": { - "value": "0.003652 dimensionless", - "reference": "10.1021/je2009329", - "data_type": "fitted" - }, - "Beta2": { - "value": "0.0 dimensionless", - "reference": "10.1021/je2009329", - "data_type": "fitted" - }, - "Cphi": { - "value": "9.716e-05 dimensionless", - "reference": "10.1021/je2009329", - "data_type": "fitted" - }, - "V_o": { - "value": "27.9 dimensionless", - "reference": "10.1021/je2009329", - "data_type": "fitted" - }, - "Max_C": { - "value": "5.557 mol/kg", - "reference": "10.1021/je2009329", - "data_type": "fitted" - } - }, - "viscosity_jones_dole": { - "B": null } } }, @@ -21946,6 +23800,23 @@ "data_type": "fitted" } }, + "diffusion_temp_smolyakov": { + "a1": { + "value": "1.52 dimensionless", + "reference": "https://doi.org/10.1016/j.cemconres.2017.08.030", + "data_type": "fitted" + }, + "a2": { + "value": "3.7 dimensionless", + "reference": "https://doi.org/10.1016/j.cemconres.2017.08.030", + "data_type": "fitted" + }, + "d": { + "value": "122 dimensionless", + "reference": "https://doi.org/10.1016/j.cemconres.2017.08.030", + "data_type": "fitted" + } + }, "dielectric_zuber": { "value": "3.62 dimensionless", "reference": "https://doi.org/10.1016/j.fluid.2014.05.037", @@ -22020,6 +23891,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -22112,6 +23988,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -22225,6 +24106,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -22295,6 +24181,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -22378,6 +24269,11 @@ "reference": "https://doi.org/10.1021/cr00040a004", "data_type": "fitted" } + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -22494,6 +24390,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -22607,6 +24508,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -22723,6 +24629,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -22810,6 +24721,11 @@ "reference": "https://doi.org/10.1021/cr00040a004", "data_type": "fitted" } + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -22880,76 +24796,86 @@ }, "viscosity_jones_dole": { "B": null - } - } - }, - { - "formula": "Np[+3]", - "charge": 3, - "molecular_weight": "237.0 g/mol", - "elements": [ - "Np" - ], - "chemsys": "Np", - "pmg_ion": { - "Np": 1, - "charge": 3, - "@module": "pymatgen.core.ion", - "@class": "Ion", - "@version": null - }, - "formula_html": "Np+3", - "formula_latex": "Np$^{+3}$", - "formula_hill": "Np", - "formula_pretty": "Np^+3", - "oxi_state_guesses": { - "Np": 3 - }, - "n_atoms": 1, - "n_elements": 1, - "size": { - "radius_ionic": { - "value": "1.15 Å", - "reference": "pymatgen", - "data_type": "experimental" - }, - "radius_hydrated": null, - "radius_vdw": { - "value": "2.39 Å", - "reference": "pymatgen", - "data_type": "experimental" - }, - "molar_volume": null - }, - "thermo": { - "ΔG_hydration": { - "value": "-3203.0 ± 10 kJ/mol", - "reference": "10.1021/acs.jpca.9b05140", - "data_type": "experimental" - }, - "ΔG_formation": null - }, - "transport": { - "diffusion_coefficient": null - }, - "model_parameters": { - "activity_pitzer": { - "Beta0": null, - "Beta1": null, - "Beta2": null, - "Cphi": null, - "Max_C": null - }, - "molar_volume_pitzer": { - "Beta0": null, - "Beta1": null, - "Beta2": null, - "Cphi": null, - "V_o": null, - "Max_C": null }, - "viscosity_jones_dole": { - "B": null + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null + } + } + }, + { + "formula": "Np[+3]", + "charge": 3, + "molecular_weight": "237.0 g/mol", + "elements": [ + "Np" + ], + "chemsys": "Np", + "pmg_ion": { + "Np": 1, + "charge": 3, + "@module": "pymatgen.core.ion", + "@class": "Ion", + "@version": null + }, + "formula_html": "Np+3", + "formula_latex": "Np$^{+3}$", + "formula_hill": "Np", + "formula_pretty": "Np^+3", + "oxi_state_guesses": { + "Np": 3 + }, + "n_atoms": 1, + "n_elements": 1, + "size": { + "radius_ionic": { + "value": "1.15 Å", + "reference": "pymatgen", + "data_type": "experimental" + }, + "radius_hydrated": null, + "radius_vdw": { + "value": "2.39 Å", + "reference": "pymatgen", + "data_type": "experimental" + }, + "molar_volume": null + }, + "thermo": { + "ΔG_hydration": { + "value": "-3203.0 ± 10 kJ/mol", + "reference": "10.1021/acs.jpca.9b05140", + "data_type": "experimental" + }, + "ΔG_formation": null + }, + "transport": { + "diffusion_coefficient": null + }, + "model_parameters": { + "activity_pitzer": { + "Beta0": null, + "Beta1": null, + "Beta2": null, + "Cphi": null, + "Max_C": null + }, + "molar_volume_pitzer": { + "Beta0": null, + "Beta1": null, + "Beta2": null, + "Cphi": null, + "V_o": null, + "Max_C": null + }, + "viscosity_jones_dole": { + "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -23025,6 +24951,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -23120,6 +25051,23 @@ "data_type": "fitted" } }, + "diffusion_temp_smolyakov": { + "a1": { + "value": "0.52 dimensionless", + "reference": "https://doi.org/10.1016/j.cemconres.2017.08.030", + "data_type": "fitted" + }, + "a2": { + "value": "0 dimensionless", + "reference": "https://doi.org/10.1016/j.cemconres.2017.08.030", + "data_type": "fitted" + }, + "d": { + "value": "553 dimensionless", + "reference": "https://doi.org/10.1016/j.cemconres.2017.08.030", + "data_type": "fitted" + } + }, "dielectric_zuber": { "value": "13.96 dimensionless", "reference": "https://doi.org/10.1016/j.fluid.2014.05.037", @@ -23194,6 +25142,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -23274,6 +25227,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -23355,6 +25313,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -23431,6 +25394,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -23504,6 +25472,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -23577,6 +25550,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -23650,6 +25628,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -23745,6 +25728,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -23834,6 +25822,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -23910,6 +25903,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -23983,6 +25981,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -24065,88 +26068,11 @@ }, "viscosity_jones_dole": { "B": null - } - } - }, - { - "formula": "PO4[-3]", - "charge": -3, - "molecular_weight": "94.971362 g/mol", - "elements": [ - "P", - "O" - ], - "chemsys": "O-P", - "pmg_ion": { - "P": 1, - "O": 4, - "charge": -3, - "@module": "pymatgen.core.ion", - "@class": "Ion", - "@version": null - }, - "formula_html": "PO4-3", - "formula_latex": "PO$_{4}$$^{-3}$", - "formula_hill": "O4 P", - "formula_pretty": "PO4^-3", - "oxi_state_guesses": { - "P": 5, - "O": -2 - }, - "n_atoms": 5, - "n_elements": 2, - "size": { - "radius_ionic": { - "value": "None", - "reference": "pymatgen", - "data_type": "experimental" - }, - "radius_hydrated": null, - "radius_vdw": { - "value": "1.8 Å", - "reference": "pymatgen", - "data_type": "experimental" - }, - "molar_volume": null, - "radius_ionic_marcus": { - "value": "2.38 ± 0.02 Å", - "reference": "Marcus2015", - "data_type": "experimental" - } - }, - "thermo": { - "ΔG_hydration": { - "value": "nan ± 6 kJ/mol", - "reference": "Marcus2015", - "data_type": "experimental" }, - "ΔG_formation": null - }, - "transport": { - "diffusion_coefficient": { - "value": "8.24e-06 cm**2/s", - "reference": "CRC", - "data_type": "experimental" - } - }, - "model_parameters": { - "activity_pitzer": { - "Beta0": null, - "Beta1": null, - "Beta2": null, - "Cphi": null, - "Max_C": null - }, - "molar_volume_pitzer": { - "Beta0": null, - "Beta1": null, - "Beta2": null, - "Cphi": null, - "V_o": null, - "Max_C": null - }, - "viscosity_jones_dole": { - "B": null + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -24217,6 +26143,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -24309,6 +26240,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -24425,6 +26361,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -24507,6 +26448,11 @@ "reference": "https://doi.org/10.1021/cr00040a004", "data_type": "fitted" } + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -24582,6 +26528,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -24657,6 +26608,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -24727,6 +26683,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -24840,6 +26801,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -24910,6 +26876,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -24993,6 +26964,11 @@ "reference": "https://doi.org/10.1021/cr00040a004", "data_type": "fitted" } + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -25068,81 +27044,11 @@ }, "viscosity_jones_dole": { "B": null - } - } - }, - { - "formula": "Pt[+2]", - "charge": 2, - "molecular_weight": "195.084 g/mol", - "elements": [ - "Pt" - ], - "chemsys": "Pt", - "pmg_ion": { - "Pt": 1, - "charge": 2, - "@module": "pymatgen.core.ion", - "@class": "Ion", - "@version": null - }, - "formula_html": "Pt+2", - "formula_latex": "Pt$^{+2}$", - "formula_hill": "Pt", - "formula_pretty": "Pt^+2", - "oxi_state_guesses": { - "Pt": 2 - }, - "n_atoms": 1, - "n_elements": 1, - "size": { - "radius_ionic": { - "value": "0.94 Å", - "reference": "pymatgen", - "data_type": "experimental" }, - "radius_hydrated": null, - "radius_vdw": { - "value": "2.13 Å", - "reference": "pymatgen", - "data_type": "experimental" - }, - "molar_volume": null, - "radius_ionic_marcus": { - "value": "0.8 ± 0.02 Å", - "reference": "Marcus2015", - "data_type": "experimental" - } - }, - "thermo": { - "ΔG_hydration": { - "value": "-1489.0 ± 10 kJ/mol", - "reference": "10.1021/acs.jpca.9b05140", - "data_type": "experimental" - }, - "ΔG_formation": null - }, - "transport": { - "diffusion_coefficient": null - }, - "model_parameters": { - "activity_pitzer": { - "Beta0": null, - "Beta1": null, - "Beta2": null, - "Cphi": null, - "Max_C": null - }, - "molar_volume_pitzer": { - "Beta0": null, - "Beta1": null, - "Beta2": null, - "Cphi": null, - "V_o": null, - "Max_C": null - }, - "viscosity_jones_dole": { - "B": null + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -25218,6 +27124,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -25301,6 +27212,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -25417,6 +27333,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -25530,6 +27451,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -25643,6 +27569,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -25756,11 +27687,16 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, { - "formula": "RbHC2O.1H2O(aq)", + "formula": "RbH3(CO)2(aq)", "charge": 0, "molecular_weight": "144.51182 g/mol", "elements": [ @@ -25780,10 +27716,10 @@ "@class": "Ion", "@version": null }, - "formula_html": "RbHC2O.1H2O", - "formula_latex": "RbHC$_{2}$O$_{.1}$H$_{2}$O", + "formula_html": "RbH3(CO)2", + "formula_latex": "RbH$_{3}$(CO)$_{2}$", "formula_hill": "C2 H3 O2 Rb", - "formula_pretty": "RbHC2O.1H2O", + "formula_pretty": "RbH3(CO)2", "oxi_state_guesses": { "Rb": 1, "C": 0, @@ -25851,6 +27787,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -25964,6 +27905,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -26056,6 +28002,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -26172,6 +28123,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -26288,6 +28244,136 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null + } + } + }, + { + "formula": "RbOH(aq)", + "charge": 0, + "molecular_weight": "102.47514 g/mol", + "elements": [ + "Rb", + "O", + "H" + ], + "chemsys": "H-O-Rb", + "pmg_ion": { + "Rb": 1, + "O": 1, + "H": 1, + "charge": 0, + "@module": "pymatgen.core.ion", + "@class": "Ion", + "@version": null + }, + "formula_html": "RbOH", + "formula_latex": "RbOH", + "formula_hill": "H O Rb", + "formula_pretty": "RbOH", + "oxi_state_guesses": { + "Rb": 1, + "O": -2, + "H": 1 + }, + "n_atoms": 3, + "n_elements": 3, + "size": { + "radius_ionic": { + "value": "None", + "reference": "pymatgen", + "data_type": "experimental" + }, + "radius_hydrated": null, + "radius_vdw": { + "value": "3.03 Å", + "reference": "pymatgen", + "data_type": "experimental" + }, + "molar_volume": null + }, + "thermo": { + "ΔG_hydration": null, + "ΔG_formation": null + }, + "transport": { + "diffusion_coefficient": { + "value": "9.05e-06 cm**2/s", + "reference": "CRC", + "data_type": "experimental" + } + }, + "model_parameters": { + "activity_pitzer": { + "Beta0": { + "value": "0.1404 dimensionless", + "reference": "10.1021/je2009329", + "data_type": "fitted" + }, + "Beta1": { + "value": "0.2992 dimensionless", + "reference": "10.1021/je2009329", + "data_type": "fitted" + }, + "Beta2": { + "value": "0.0 dimensionless", + "reference": "10.1021/je2009329", + "data_type": "fitted" + }, + "Cphi": { + "value": "0.003028 dimensionless", + "reference": "10.1021/je2009329", + "data_type": "fitted" + }, + "Max_C": { + "value": "6.0 mol/kg", + "reference": "10.1021/je2009329", + "data_type": "fitted" + } + }, + "molar_volume_pitzer": { + "Beta0": { + "value": "0.001028 dimensionless", + "reference": "10.1021/je2009329", + "data_type": "fitted" + }, + "Beta1": { + "value": "-0.008523 dimensionless", + "reference": "10.1021/je2009329", + "data_type": "fitted" + }, + "Beta2": { + "value": "0.0 dimensionless", + "reference": "10.1021/je2009329", + "data_type": "fitted" + }, + "Cphi": { + "value": "-9.437e-05 dimensionless", + "reference": "10.1021/je2009329", + "data_type": "fitted" + }, + "V_o": { + "value": "10.1 dimensionless", + "reference": "10.1021/je2009329", + "data_type": "fitted" + }, + "Max_C": { + "value": "5.981 mol/kg", + "reference": "10.1021/je2009329", + "data_type": "fitted" + } + }, + "viscosity_jones_dole": { + "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -26376,6 +28462,11 @@ "data_type": "fitted" } }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null + }, "dielectric_zuber": { "value": "2.08 dimensionless", "reference": "https://doi.org/10.1016/j.fluid.2014.05.037", @@ -26416,33 +28507,24 @@ "reference": "pymatgen", "data_type": "experimental" }, - "radius_hydrated": { - "value": "3.52 Å", - "reference": "Nightingale1959", - "data_type": "experimental" - }, + "radius_hydrated": null, "radius_vdw": { "value": "2.16 Å", "reference": "pymatgen", "data_type": "experimental" }, - "molar_volume": null, - "radius_ionic_marcus": { - "value": "2.6 ± 0.02 Å", - "reference": "Marcus2015", - "data_type": "experimental" - } + "molar_volume": null }, "thermo": { - "ΔG_hydration": { - "value": "-182.0 ± 6 kJ/mol", - "reference": "Marcus2015", - "data_type": "experimental" - }, + "ΔG_hydration": null, "ΔG_formation": null }, "transport": { - "diffusion_coefficient": null + "diffusion_coefficient": { + "value": "1.462e-05 cm**2/s", + "reference": "CRC", + "data_type": "experimental" + } }, "model_parameters": { "activity_pitzer": { @@ -26461,7 +28543,16 @@ "Max_C": null }, "viscosity_jones_dole": { - "B": null + "B": { + "value": "-0.055 dm**3/mol", + "reference": "https://doi.org/10.1021/cr00040a004", + "data_type": "fitted" + } + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -26498,24 +28589,33 @@ "reference": "pymatgen", "data_type": "experimental" }, - "radius_hydrated": null, + "radius_hydrated": { + "value": "3.52 Å", + "reference": "Nightingale1959", + "data_type": "experimental" + }, "radius_vdw": { "value": "2.16 Å", "reference": "pymatgen", "data_type": "experimental" }, - "molar_volume": null + "molar_volume": null, + "radius_ionic_marcus": { + "value": "2.6 ± 0.02 Å", + "reference": "Marcus2015", + "data_type": "experimental" + } }, "thermo": { - "ΔG_hydration": null, + "ΔG_hydration": { + "value": "-182.0 ± 6 kJ/mol", + "reference": "Marcus2015", + "data_type": "experimental" + }, "ΔG_formation": null }, "transport": { - "diffusion_coefficient": { - "value": "1.462e-05 cm**2/s", - "reference": "CRC", - "data_type": "experimental" - } + "diffusion_coefficient": null }, "model_parameters": { "activity_pitzer": { @@ -26534,11 +28634,12 @@ "Max_C": null }, "viscosity_jones_dole": { - "B": { - "value": "-0.055 dm**3/mol", - "reference": "https://doi.org/10.1021/cr00040a004", - "data_type": "fitted" - } + "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -26609,146 +28710,161 @@ }, "viscosity_jones_dole": { "B": null - } - } - }, - { - "formula": "Re[+3]", - "charge": 3, - "molecular_weight": "186.207 g/mol", - "elements": [ - "Re" - ], - "chemsys": "Re", - "pmg_ion": { - "Re": 1, - "charge": 3, - "@module": "pymatgen.core.ion", - "@class": "Ion", - "@version": null - }, - "formula_html": "Re+3", - "formula_latex": "Re$^{+3}$", - "formula_hill": "Re", - "formula_pretty": "Re^+3", - "oxi_state_guesses": { - "Re": 3 - }, - "n_atoms": 1, - "n_elements": 1, - "size": { - "radius_ionic": { - "value": "None", - "reference": "pymatgen", - "data_type": "experimental" - }, - "radius_hydrated": null, - "radius_vdw": { - "value": "2.16 Å", - "reference": "pymatgen", - "data_type": "experimental" - }, - "molar_volume": null - }, - "thermo": { - "ΔG_hydration": { - "value": "-4298.0 ± 10 kJ/mol", - "reference": "10.1021/acs.jpca.9b05140", - "data_type": "experimental" - }, - "ΔG_formation": null - }, - "transport": { - "diffusion_coefficient": null - }, - "model_parameters": { - "activity_pitzer": { - "Beta0": null, - "Beta1": null, - "Beta2": null, - "Cphi": null, - "Max_C": null - }, - "molar_volume_pitzer": { - "Beta0": null, - "Beta1": null, - "Beta2": null, - "Cphi": null, - "V_o": null, - "Max_C": null }, - "viscosity_jones_dole": { - "B": null - } - } - }, - { - "formula": "Re[-1]", - "charge": -1, - "molecular_weight": "186.207 g/mol", - "elements": [ - "Re" - ], - "chemsys": "Re", - "pmg_ion": { - "Re": 1, - "charge": -1, - "@module": "pymatgen.core.ion", - "@class": "Ion", - "@version": null - }, - "formula_html": "Re-1", - "formula_latex": "Re$^{-1}$", - "formula_hill": "Re", - "formula_pretty": "Re^-1", - "oxi_state_guesses": { - "Re": -1 - }, - "n_atoms": 1, - "n_elements": 1, - "size": { - "radius_ionic": { - "value": "None", - "reference": "pymatgen", - "data_type": "experimental" - }, - "radius_hydrated": null, - "radius_vdw": { - "value": "2.16 Å", - "reference": "pymatgen", - "data_type": "experimental" - }, - "molar_volume": null - }, - "thermo": { - "ΔG_hydration": { - "value": "nan ± 6 kJ/mol", - "reference": "Marcus2015", - "data_type": "experimental" - }, - "ΔG_formation": null - }, - "transport": { - "diffusion_coefficient": null - }, - "model_parameters": { - "activity_pitzer": { - "Beta0": null, - "Beta1": null, - "Beta2": null, - "Cphi": null, - "Max_C": null - }, - "molar_volume_pitzer": { - "Beta0": null, - "Beta1": null, - "Beta2": null, - "Cphi": null, - "V_o": null, - "Max_C": null - }, - "viscosity_jones_dole": { - "B": null + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null + } + } + }, + { + "formula": "Re[+3]", + "charge": 3, + "molecular_weight": "186.207 g/mol", + "elements": [ + "Re" + ], + "chemsys": "Re", + "pmg_ion": { + "Re": 1, + "charge": 3, + "@module": "pymatgen.core.ion", + "@class": "Ion", + "@version": null + }, + "formula_html": "Re+3", + "formula_latex": "Re$^{+3}$", + "formula_hill": "Re", + "formula_pretty": "Re^+3", + "oxi_state_guesses": { + "Re": 3 + }, + "n_atoms": 1, + "n_elements": 1, + "size": { + "radius_ionic": { + "value": "None", + "reference": "pymatgen", + "data_type": "experimental" + }, + "radius_hydrated": null, + "radius_vdw": { + "value": "2.16 Å", + "reference": "pymatgen", + "data_type": "experimental" + }, + "molar_volume": null + }, + "thermo": { + "ΔG_hydration": { + "value": "-4298.0 ± 10 kJ/mol", + "reference": "10.1021/acs.jpca.9b05140", + "data_type": "experimental" + }, + "ΔG_formation": null + }, + "transport": { + "diffusion_coefficient": null + }, + "model_parameters": { + "activity_pitzer": { + "Beta0": null, + "Beta1": null, + "Beta2": null, + "Cphi": null, + "Max_C": null + }, + "molar_volume_pitzer": { + "Beta0": null, + "Beta1": null, + "Beta2": null, + "Cphi": null, + "V_o": null, + "Max_C": null + }, + "viscosity_jones_dole": { + "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null + } + } + }, + { + "formula": "Re[-1]", + "charge": -1, + "molecular_weight": "186.207 g/mol", + "elements": [ + "Re" + ], + "chemsys": "Re", + "pmg_ion": { + "Re": 1, + "charge": -1, + "@module": "pymatgen.core.ion", + "@class": "Ion", + "@version": null + }, + "formula_html": "Re-1", + "formula_latex": "Re$^{-1}$", + "formula_hill": "Re", + "formula_pretty": "Re^-1", + "oxi_state_guesses": { + "Re": -1 + }, + "n_atoms": 1, + "n_elements": 1, + "size": { + "radius_ionic": { + "value": "None", + "reference": "pymatgen", + "data_type": "experimental" + }, + "radius_hydrated": null, + "radius_vdw": { + "value": "2.16 Å", + "reference": "pymatgen", + "data_type": "experimental" + }, + "molar_volume": null + }, + "thermo": { + "ΔG_hydration": { + "value": "nan ± 6 kJ/mol", + "reference": "Marcus2015", + "data_type": "experimental" + }, + "ΔG_formation": null + }, + "transport": { + "diffusion_coefficient": null + }, + "model_parameters": { + "activity_pitzer": { + "Beta0": null, + "Beta1": null, + "Beta2": null, + "Cphi": null, + "Max_C": null + }, + "molar_volume_pitzer": { + "Beta0": null, + "Beta1": null, + "Beta2": null, + "Cphi": null, + "V_o": null, + "Max_C": null + }, + "viscosity_jones_dole": { + "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -26819,6 +28935,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -26889,6 +29010,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -26959,6 +29085,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -27032,6 +29163,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -27105,6 +29241,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -27178,6 +29319,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -27264,6 +29410,97 @@ "reference": "https://doi.org/10.1021/cr00040a004", "data_type": "fitted" } + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null + } + } + }, + { + "formula": "SO42[-1]", + "charge": -1, + "molecular_weight": "704.0398 g/mol", + "elements": [ + "S", + "O" + ], + "chemsys": "O-S", + "pmg_ion": { + "S": 1, + "O": 42, + "charge": -1, + "@module": "pymatgen.core.ion", + "@class": "Ion", + "@version": null + }, + "formula_html": "SO42-1", + "formula_latex": "SO$_{42}$$^{-1}$", + "formula_hill": "O42 S", + "formula_pretty": "SO42^-1", + "oxi_state_guesses": { + "S": 6, + "O": -0.16666666666666666 + }, + "n_atoms": 43, + "n_elements": 2, + "size": { + "radius_ionic": { + "value": "None", + "reference": "pymatgen", + "data_type": "experimental" + }, + "radius_hydrated": null, + "radius_vdw": { + "value": "1.8 Å", + "reference": "pymatgen", + "data_type": "experimental" + }, + "molar_volume": null + }, + "thermo": { + "ΔG_hydration": null, + "ΔG_formation": null + }, + "transport": { + "diffusion_coefficient": null + }, + "model_parameters": { + "activity_pitzer": { + "Beta0": null, + "Beta1": null, + "Beta2": null, + "Cphi": null, + "Max_C": null + }, + "molar_volume_pitzer": { + "Beta0": null, + "Beta1": null, + "Beta2": null, + "Cphi": null, + "V_o": null, + "Max_C": null + }, + "viscosity_jones_dole": { + "B": null + }, + "diffusion_temp_smolyakov": { + "a1": { + "value": "2.08 dimensionless", + "reference": "https://doi.org/10.1016/j.cemconres.2017.08.030", + "data_type": "fitted" + }, + "a2": { + "value": "13.4 dimensionless", + "reference": "https://doi.org/10.1016/j.cemconres.2017.08.030", + "data_type": "fitted" + }, + "d": { + "value": "34 dimensionless", + "reference": "https://doi.org/10.1016/j.cemconres.2017.08.030", + "data_type": "fitted" + } } } }, @@ -27337,6 +29574,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -27432,6 +29674,11 @@ "data_type": "fitted" } }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null + }, "dielectric_zuber": { "value": "-0.66 dimensionless", "reference": "https://doi.org/10.1016/j.fluid.2014.05.037", @@ -27506,76 +29753,11 @@ }, "viscosity_jones_dole": { "B": null - } - } - }, - { - "formula": "S[-2]", - "charge": -2, - "molecular_weight": "32.065 g/mol", - "elements": [ - "S" - ], - "chemsys": "S", - "pmg_ion": { - "S": 1, - "charge": -2, - "@module": "pymatgen.core.ion", - "@class": "Ion", - "@version": null - }, - "formula_html": "S-2", - "formula_latex": "S$^{-2}$", - "formula_hill": "S", - "formula_pretty": "S^-2", - "oxi_state_guesses": { - "S": -2 - }, - "n_atoms": 1, - "n_elements": 1, - "size": { - "radius_ionic": { - "value": "1.7 Å", - "reference": "pymatgen", - "data_type": "experimental" - }, - "radius_hydrated": null, - "radius_vdw": { - "value": "1.8 Å", - "reference": "pymatgen", - "data_type": "experimental" - }, - "molar_volume": null - }, - "thermo": { - "ΔG_hydration": { - "value": "-1576.0 ± 10 kJ/mol", - "reference": "10.1021/acs.jpca.9b05140", - "data_type": "experimental" - }, - "ΔG_formation": null - }, - "transport": { - "diffusion_coefficient": null - }, - "model_parameters": { - "activity_pitzer": { - "Beta0": null, - "Beta1": null, - "Beta2": null, - "Cphi": null, - "Max_C": null - }, - "molar_volume_pitzer": { - "Beta0": null, - "Beta1": null, - "Beta2": null, - "Cphi": null, - "V_o": null, - "Max_C": null - }, - "viscosity_jones_dole": { - "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -27652,6 +29834,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -27728,6 +29915,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -27817,6 +30009,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -27887,6 +30084,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -27966,6 +30168,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -28044,6 +30251,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -28117,6 +30329,101 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null + } + } + }, + { + "formula": "SeO4[-1]", + "charge": -1, + "molecular_weight": "142.95759999999999 g/mol", + "elements": [ + "Se", + "O" + ], + "chemsys": "O-Se", + "pmg_ion": { + "Se": 1, + "O": 4, + "charge": -1, + "@module": "pymatgen.core.ion", + "@class": "Ion", + "@version": null + }, + "formula_html": "SeO4-1", + "formula_latex": "SeO$_{4}$$^{-1}$", + "formula_hill": "O4 Se", + "formula_pretty": "SeO4^-1", + "oxi_state_guesses": { + "Se": 4, + "O": -1.25 + }, + "n_atoms": 5, + "n_elements": 2, + "size": { + "radius_ionic": { + "value": "None", + "reference": "pymatgen", + "data_type": "experimental" + }, + "radius_hydrated": null, + "radius_vdw": { + "value": "1.9 Å", + "reference": "pymatgen", + "data_type": "experimental" + }, + "molar_volume": null + }, + "thermo": { + "ΔG_hydration": null, + "ΔG_formation": null + }, + "transport": { + "diffusion_coefficient": { + "value": "1.008e-05 cm**2/s", + "reference": "CRC", + "data_type": "experimental" + } + }, + "model_parameters": { + "activity_pitzer": { + "Beta0": null, + "Beta1": null, + "Beta2": null, + "Cphi": null, + "Max_C": null + }, + "molar_volume_pitzer": { + "Beta0": null, + "Beta1": null, + "Beta2": null, + "Cphi": null, + "V_o": null, + "Max_C": null + }, + "viscosity_jones_dole": { + "B": null + }, + "diffusion_temp_smolyakov": { + "a1": { + "value": "2.4 dimensionless", + "reference": "https://doi.org/10.1016/j.cemconres.2017.08.030", + "data_type": "fitted" + }, + "a2": { + "value": "13.7 dimensionless", + "reference": "https://doi.org/10.1016/j.cemconres.2017.08.030", + "data_type": "fitted" + }, + "d": { + "value": "111 dimensionless", + "reference": "https://doi.org/10.1016/j.cemconres.2017.08.030", + "data_type": "fitted" + } } } }, @@ -28199,6 +30506,102 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null + } + } + }, + { + "formula": "SeO4[-2]", + "charge": -2, + "molecular_weight": "142.95759999999999 g/mol", + "elements": [ + "Se", + "O" + ], + "chemsys": "O-Se", + "pmg_ion": { + "Se": 1, + "O": 4, + "charge": -2, + "@module": "pymatgen.core.ion", + "@class": "Ion", + "@version": null + }, + "formula_html": "SeO4-2", + "formula_latex": "SeO$_{4}$$^{-2}$", + "formula_hill": "O4 Se", + "formula_pretty": "SeO4^-2", + "oxi_state_guesses": { + "Se": 6, + "O": -2 + }, + "n_atoms": 5, + "n_elements": 2, + "size": { + "radius_ionic": { + "value": "1.84 Å", + "reference": "pymatgen", + "data_type": "experimental" + }, + "radius_hydrated": { + "value": "3.84 Å", + "reference": "Nightingale1959", + "data_type": "experimental" + }, + "radius_vdw": { + "value": "1.9 Å", + "reference": "pymatgen", + "data_type": "experimental" + }, + "molar_volume": null, + "radius_ionic_marcus": { + "value": "2.43 ± 0.02 Å", + "reference": "Marcus2015", + "data_type": "experimental" + } + }, + "thermo": { + "ΔG_hydration": { + "value": "-821.0 ± 6 kJ/mol", + "reference": "Marcus2015", + "data_type": "experimental" + }, + "ΔG_formation": null + }, + "transport": { + "diffusion_coefficient": { + "value": "nan cm**2/s", + "reference": "CRC", + "data_type": "experimental" + } + }, + "model_parameters": { + "activity_pitzer": { + "Beta0": null, + "Beta1": null, + "Beta2": null, + "Cphi": null, + "Max_C": null + }, + "molar_volume_pitzer": { + "Beta0": null, + "Beta1": null, + "Beta2": null, + "Cphi": null, + "V_o": null, + "Max_C": null + }, + "viscosity_jones_dole": { + "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -28277,6 +30680,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -28390,6 +30798,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -28460,6 +30873,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -28543,6 +30961,11 @@ "reference": "https://doi.org/10.1021/cr00040a004", "data_type": "fitted" } + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -28613,81 +31036,91 @@ }, "viscosity_jones_dole": { "B": null - } - } - }, - { - "formula": "Sn[+4]", - "charge": 4, - "molecular_weight": "118.71 g/mol", - "elements": [ - "Sn" - ], - "chemsys": "Sn", - "pmg_ion": { - "Sn": 1, - "charge": 4, - "@module": "pymatgen.core.ion", - "@class": "Ion", - "@version": null - }, - "formula_html": "Sn+4", - "formula_latex": "Sn$^{+4}$", - "formula_hill": "Sn", - "formula_pretty": "Sn^+4", - "oxi_state_guesses": { - "Sn": 4 - }, - "n_atoms": 1, - "n_elements": 1, - "size": { - "radius_ionic": { - "value": "0.83 Å", - "reference": "pymatgen", - "data_type": "experimental" - }, - "radius_hydrated": null, - "radius_vdw": { - "value": "2.17 Å", - "reference": "pymatgen", - "data_type": "experimental" }, - "molar_volume": null, - "radius_ionic_marcus": { - "value": "0.69 ± 0.02 Å", - "reference": "Marcus2015", - "data_type": "experimental" - } - }, - "thermo": { - "ΔG_hydration": { - "value": "-7720.0 ± 6 kJ/mol", - "reference": "Marcus2015", - "data_type": "experimental" - }, - "ΔG_formation": null - }, - "transport": { - "diffusion_coefficient": null - }, - "model_parameters": { - "activity_pitzer": { - "Beta0": null, - "Beta1": null, - "Beta2": null, - "Cphi": null, - "Max_C": null - }, - "molar_volume_pitzer": { - "Beta0": null, - "Beta1": null, - "Beta2": null, - "Cphi": null, - "V_o": null, - "Max_C": null - }, - "viscosity_jones_dole": { - "B": null + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null + } + } + }, + { + "formula": "Sn[+4]", + "charge": 4, + "molecular_weight": "118.71 g/mol", + "elements": [ + "Sn" + ], + "chemsys": "Sn", + "pmg_ion": { + "Sn": 1, + "charge": 4, + "@module": "pymatgen.core.ion", + "@class": "Ion", + "@version": null + }, + "formula_html": "Sn+4", + "formula_latex": "Sn$^{+4}$", + "formula_hill": "Sn", + "formula_pretty": "Sn^+4", + "oxi_state_guesses": { + "Sn": 4 + }, + "n_atoms": 1, + "n_elements": 1, + "size": { + "radius_ionic": { + "value": "0.83 Å", + "reference": "pymatgen", + "data_type": "experimental" + }, + "radius_hydrated": null, + "radius_vdw": { + "value": "2.17 Å", + "reference": "pymatgen", + "data_type": "experimental" + }, + "molar_volume": null, + "radius_ionic_marcus": { + "value": "0.69 ± 0.02 Å", + "reference": "Marcus2015", + "data_type": "experimental" + } + }, + "thermo": { + "ΔG_hydration": { + "value": "-7720.0 ± 6 kJ/mol", + "reference": "Marcus2015", + "data_type": "experimental" + }, + "ΔG_formation": null + }, + "transport": { + "diffusion_coefficient": null + }, + "model_parameters": { + "activity_pitzer": { + "Beta0": null, + "Beta1": null, + "Beta2": null, + "Cphi": null, + "Max_C": null + }, + "molar_volume_pitzer": { + "Beta0": null, + "Beta1": null, + "Beta2": null, + "Cphi": null, + "V_o": null, + "Max_C": null + }, + "viscosity_jones_dole": { + "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -28804,6 +31237,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -28920,6 +31358,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -29033,6 +31476,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -29146,6 +31594,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -29259,6 +31712,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -29346,6 +31804,11 @@ "reference": "https://doi.org/10.1021/cr00040a004", "data_type": "fitted" } + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -29416,6 +31879,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -29490,262 +31958,46 @@ "Max_C": null }, "viscosity_jones_dole": { - "B": { - "value": "0.647 dm**3/mol", - "reference": "https://doi.org/10.1021/cr00040a004", - "data_type": "fitted" - } - } - } - }, - { - "formula": "TcO4[-1]", - "charge": -1, - "molecular_weight": "161.9976 g/mol", - "elements": [ - "Tc", - "O" - ], - "chemsys": "O-Tc", - "pmg_ion": { - "Tc": 1, - "O": 4, - "charge": -1, - "@module": "pymatgen.core.ion", - "@class": "Ion", - "@version": null - }, - "formula_html": "TcO4-1", - "formula_latex": "TcO$_{4}$$^{-1}$", - "formula_hill": "O4 Tc", - "formula_pretty": "TcO4^-1", - "oxi_state_guesses": { - "Tc": 7, - "O": -2 - }, - "n_atoms": 5, - "n_elements": 2, - "size": { - "radius_ionic": { - "value": "None", - "reference": "pymatgen", - "data_type": "experimental" - }, - "radius_hydrated": null, - "radius_vdw": { - "value": "2.16 Å", - "reference": "pymatgen", - "data_type": "experimental" - }, - "molar_volume": null, - "radius_ionic_marcus": { - "value": "2.5 ± 0.02 Å", - "reference": "Marcus2015", - "data_type": "experimental" - } - }, - "thermo": { - "ΔG_hydration": { - "value": "-227.0 ± 6 kJ/mol", - "reference": "Marcus2015", - "data_type": "experimental" - }, - "ΔG_formation": null - }, - "transport": { - "diffusion_coefficient": null - }, - "model_parameters": { - "activity_pitzer": { - "Beta0": null, - "Beta1": null, - "Beta2": null, - "Cphi": null, - "Max_C": null - }, - "molar_volume_pitzer": { - "Beta0": null, - "Beta1": null, - "Beta2": null, - "Cphi": null, - "V_o": null, - "Max_C": null - }, - "viscosity_jones_dole": { - "B": null - } - } - }, - { - "formula": "Tc[+2]", - "charge": 2, - "molecular_weight": "98.0 g/mol", - "elements": [ - "Tc" - ], - "chemsys": "Tc", - "pmg_ion": { - "Tc": 1, - "charge": 2, - "@module": "pymatgen.core.ion", - "@class": "Ion", - "@version": null - }, - "formula_html": "Tc+2", - "formula_latex": "Tc$^{+2}$", - "formula_hill": "Tc", - "formula_pretty": "Tc^+2", - "oxi_state_guesses": { - "Tc": 2 - }, - "n_atoms": 1, - "n_elements": 1, - "size": { - "radius_ionic": { - "value": "None", - "reference": "pymatgen", - "data_type": "experimental" - }, - "radius_hydrated": null, - "radius_vdw": { - "value": "2.16 Å", - "reference": "pymatgen", - "data_type": "experimental" - }, - "molar_volume": null - }, - "thermo": { - "ΔG_hydration": { - "value": "-1776.0 ± 10 kJ/mol", - "reference": "10.1021/acs.jpca.9b05140", - "data_type": "experimental" - }, - "ΔG_formation": null - }, - "transport": { - "diffusion_coefficient": null - }, - "model_parameters": { - "activity_pitzer": { - "Beta0": null, - "Beta1": null, - "Beta2": null, - "Cphi": null, - "Max_C": null - }, - "molar_volume_pitzer": { - "Beta0": null, - "Beta1": null, - "Beta2": null, - "Cphi": null, - "V_o": null, - "Max_C": null - }, - "viscosity_jones_dole": { - "B": null - } - } - }, - { - "formula": "Tc[+3]", - "charge": 3, - "molecular_weight": "98.0 g/mol", - "elements": [ - "Tc" - ], - "chemsys": "Tc", - "pmg_ion": { - "Tc": 1, - "charge": 3, - "@module": "pymatgen.core.ion", - "@class": "Ion", - "@version": null - }, - "formula_html": "Tc+3", - "formula_latex": "Tc$^{+3}$", - "formula_hill": "Tc", - "formula_pretty": "Tc^+3", - "oxi_state_guesses": { - "Tc": 3 - }, - "n_atoms": 1, - "n_elements": 1, - "size": { - "radius_ionic": { - "value": "None", - "reference": "pymatgen", - "data_type": "experimental" - }, - "radius_hydrated": null, - "radius_vdw": { - "value": "2.16 Å", - "reference": "pymatgen", - "data_type": "experimental" - }, - "molar_volume": null - }, - "thermo": { - "ΔG_hydration": { - "value": "-4170.0 ± 10 kJ/mol", - "reference": "10.1021/acs.jpca.9b05140", - "data_type": "experimental" - }, - "ΔG_formation": null - }, - "transport": { - "diffusion_coefficient": null - }, - "model_parameters": { - "activity_pitzer": { - "Beta0": null, - "Beta1": null, - "Beta2": null, - "Cphi": null, - "Max_C": null - }, - "molar_volume_pitzer": { - "Beta0": null, - "Beta1": null, - "Beta2": null, - "Cphi": null, - "V_o": null, - "Max_C": null - }, - "viscosity_jones_dole": { - "B": null + "B": { + "value": "0.647 dm**3/mol", + "reference": "https://doi.org/10.1021/cr00040a004", + "data_type": "fitted" + } + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, { - "formula": "Th(NO3)4(aq)", - "charge": 0, - "molecular_weight": "480.05766 g/mol", + "formula": "TcO4[-1]", + "charge": -1, + "molecular_weight": "161.9976 g/mol", "elements": [ - "Th", - "N", + "Tc", "O" ], - "chemsys": "N-O-Th", + "chemsys": "O-Tc", "pmg_ion": { - "Th": 1, - "N": 4, - "O": 12, - "charge": 0, + "Tc": 1, + "O": 4, + "charge": -1, "@module": "pymatgen.core.ion", "@class": "Ion", "@version": null }, - "formula_html": "Th(NO3)4", - "formula_latex": "Th(NO$_{3}$)$_{4}$", - "formula_hill": "N4 O12 Th", - "formula_pretty": "Th(NO3)4", + "formula_html": "TcO4-1", + "formula_latex": "TcO$_{4}$$^{-1}$", + "formula_hill": "O4 Tc", + "formula_pretty": "TcO4^-1", "oxi_state_guesses": { - "Th": 4, - "N": 5, + "Tc": 7, "O": -2 }, - "n_atoms": 17, - "n_elements": 3, + "n_atoms": 5, + "n_elements": 2, "size": { "radius_ionic": { "value": "None", @@ -29754,14 +32006,98 @@ }, "radius_hydrated": null, "radius_vdw": { - "value": "2.45 Å", + "value": "2.16 Å", + "reference": "pymatgen", + "data_type": "experimental" + }, + "molar_volume": null, + "radius_ionic_marcus": { + "value": "2.5 ± 0.02 Å", + "reference": "Marcus2015", + "data_type": "experimental" + } + }, + "thermo": { + "ΔG_hydration": { + "value": "-227.0 ± 6 kJ/mol", + "reference": "Marcus2015", + "data_type": "experimental" + }, + "ΔG_formation": null + }, + "transport": { + "diffusion_coefficient": null + }, + "model_parameters": { + "activity_pitzer": { + "Beta0": null, + "Beta1": null, + "Beta2": null, + "Cphi": null, + "Max_C": null + }, + "molar_volume_pitzer": { + "Beta0": null, + "Beta1": null, + "Beta2": null, + "Cphi": null, + "V_o": null, + "Max_C": null + }, + "viscosity_jones_dole": { + "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null + } + } + }, + { + "formula": "Tc[+2]", + "charge": 2, + "molecular_weight": "98.0 g/mol", + "elements": [ + "Tc" + ], + "chemsys": "Tc", + "pmg_ion": { + "Tc": 1, + "charge": 2, + "@module": "pymatgen.core.ion", + "@class": "Ion", + "@version": null + }, + "formula_html": "Tc+2", + "formula_latex": "Tc$^{+2}$", + "formula_hill": "Tc", + "formula_pretty": "Tc^+2", + "oxi_state_guesses": { + "Tc": 2 + }, + "n_atoms": 1, + "n_elements": 1, + "size": { + "radius_ionic": { + "value": "None", + "reference": "pymatgen", + "data_type": "experimental" + }, + "radius_hydrated": null, + "radius_vdw": { + "value": "2.16 Å", "reference": "pymatgen", "data_type": "experimental" }, "molar_volume": null }, "thermo": { - "ΔG_hydration": null, + "ΔG_hydration": { + "value": "-1776.0 ± 10 kJ/mol", + "reference": "10.1021/acs.jpca.9b05140", + "data_type": "experimental" + }, "ΔG_formation": null }, "transport": { @@ -29769,31 +32105,11 @@ }, "model_parameters": { "activity_pitzer": { - "Beta0": { - "value": "0.8219 dimensionless", - "reference": "10.1021/je2009329", - "data_type": "fitted" - }, - "Beta1": { - "value": "17.68 dimensionless", - "reference": "10.1021/je2009329", - "data_type": "fitted" - }, - "Beta2": { - "value": "0.0 dimensionless", - "reference": "10.1021/je2009329", - "data_type": "fitted" - }, - "Cphi": { - "value": "-0.1081 dimensionless", - "reference": "10.1021/je2009329", - "data_type": "fitted" - }, - "Max_C": { - "value": "1.4 mol/kg", - "reference": "10.1021/je2009329", - "data_type": "fitted" - } + "Beta0": null, + "Beta1": null, + "Beta2": null, + "Cphi": null, + "Max_C": null }, "molar_volume_pitzer": { "Beta0": null, @@ -29805,6 +32121,86 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null + } + } + }, + { + "formula": "Tc[+3]", + "charge": 3, + "molecular_weight": "98.0 g/mol", + "elements": [ + "Tc" + ], + "chemsys": "Tc", + "pmg_ion": { + "Tc": 1, + "charge": 3, + "@module": "pymatgen.core.ion", + "@class": "Ion", + "@version": null + }, + "formula_html": "Tc+3", + "formula_latex": "Tc$^{+3}$", + "formula_hill": "Tc", + "formula_pretty": "Tc^+3", + "oxi_state_guesses": { + "Tc": 3 + }, + "n_atoms": 1, + "n_elements": 1, + "size": { + "radius_ionic": { + "value": "None", + "reference": "pymatgen", + "data_type": "experimental" + }, + "radius_hydrated": null, + "radius_vdw": { + "value": "2.16 Å", + "reference": "pymatgen", + "data_type": "experimental" + }, + "molar_volume": null + }, + "thermo": { + "ΔG_hydration": { + "value": "-4170.0 ± 10 kJ/mol", + "reference": "10.1021/acs.jpca.9b05140", + "data_type": "experimental" + }, + "ΔG_formation": null + }, + "transport": { + "diffusion_coefficient": null + }, + "model_parameters": { + "activity_pitzer": { + "Beta0": null, + "Beta1": null, + "Beta2": null, + "Cphi": null, + "Max_C": null + }, + "molar_volume_pitzer": { + "Beta0": null, + "Beta1": null, + "Beta2": null, + "Cphi": null, + "V_o": null, + "Max_C": null + }, + "viscosity_jones_dole": { + "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -29853,11 +32249,7 @@ "molar_volume": null }, "thermo": { - "ΔG_hydration": { - "value": "nan ± 6 kJ/mol", - "reference": "Marcus2015", - "data_type": "experimental" - }, + "ΔG_hydration": null, "ΔG_formation": null }, "transport": { @@ -29901,6 +32293,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -29980,6 +32377,11 @@ "reference": "https://doi.org/10.1021/cr00040a004", "data_type": "fitted" } + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -30050,6 +32452,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -30120,6 +32527,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -30212,6 +32624,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -30304,6 +32721,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -30396,11 +32818,16 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, { - "formula": "TlH(C3O)2.4H2O(aq)", + "formula": "TlH9(CO)6(aq)", "charge": 0, "molecular_weight": "381.51536 g/mol", "elements": [ @@ -30420,10 +32847,10 @@ "@class": "Ion", "@version": null }, - "formula_html": "TlH(C3O)2.4H2O", - "formula_latex": "TlH(C$_{3}$O)$_{2.4}$H$_{2}$O", + "formula_html": "TlH9(CO)6", + "formula_latex": "TlH$_{9}$(CO)$_{6}$", "formula_hill": "C6 H9 O6 Tl", - "formula_pretty": "TlH(C3O)2.4H2O", + "formula_pretty": "TlH9(CO)6", "oxi_state_guesses": { "Tl": 1, "C": 0.3333333333333333, @@ -30491,6 +32918,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -30578,6 +33010,11 @@ "reference": "https://doi.org/10.1021/cr00040a004", "data_type": "fitted" } + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -30653,6 +33090,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -30723,6 +33165,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -30810,6 +33257,11 @@ "reference": "https://doi.org/10.1021/cr00040a004", "data_type": "fitted" } + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -30926,6 +33378,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -31018,6 +33475,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -31134,6 +33596,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -31208,6 +33675,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -31281,6 +33753,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -31397,6 +33874,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -31472,6 +33954,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -31547,6 +34034,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -31620,6 +34112,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -31695,6 +34192,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -31770,6 +34272,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -31848,6 +34355,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -31925,6 +34437,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -31995,6 +34512,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -32108,6 +34630,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -32224,6 +34751,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -32298,6 +34830,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -32373,6 +34910,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -32456,6 +34998,11 @@ "reference": "https://doi.org/10.1021/cr00040a004", "data_type": "fitted" } + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -32572,6 +35119,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -32688,6 +35240,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -32801,6 +35358,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -32914,6 +35476,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -33027,6 +35594,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -33143,6 +35715,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -33234,6 +35811,11 @@ "reference": "https://doi.org/10.1021/cr00040a004", "data_type": "fitted" } + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } }, @@ -33309,6 +35891,11 @@ }, "viscosity_jones_dole": { "B": null + }, + "diffusion_temp_smolyakov": { + "a1": null, + "a2": null, + "d": null } } } diff --git a/src/pyEQL/engines.py b/src/pyEQL/engines.py index ba94638e..1ea2c289 100644 --- a/src/pyEQL/engines.py +++ b/src/pyEQL/engines.py @@ -19,11 +19,14 @@ # import the parameters database # the pint unit registry from pyEQL import ureg -from pyEQL.equilibrium import equilibrate_phreeqc from pyEQL.logging_system import logger from pyEQL.salt_ion_match import Salt from pyEQL.utils import standardize_formula +# These are the only elements that are allowed to have parenthetical oxidation states +# PHREEQC will ignore others (e.g., 'Na(1)') +SPECIAL_ELEMENTS = ["S", "C", "N", "Cu", "Fe", "Mn"] + class EOS(ABC): """ @@ -112,18 +115,18 @@ def get_activity_coefficient(self, solution, solute): Return the *molal scale* activity coefficient of solute, given a Solution object. """ - return ureg.Quantity("1 dimensionless") + return ureg.Quantity(1, "dimensionless") def get_osmotic_coefficient(self, solution): """ Return the *molal scale* osmotic coefficient of solute, given a Solution object. """ - return ureg.Quantity("1 dimensionless") + return ureg.Quantity(1, "dimensionless") def get_solute_volume(self, solution): """Return the volume of the solutes.""" - return ureg.Quantity("0 L") + return ureg.Quantity(0, "L") def equilibrate(self, solution): """Adjust the speciation of a Solution object to achieve chemical equilibrium.""" @@ -138,6 +141,102 @@ class NativeEOS(EOS): if sufficient parameters are not available. """ + def __init__( + self, + phreeqc_db: Literal["vitens.dat", "wateq4f_PWN.dat", "pitzer.dat", "llnl.dat", "geothermal.dat"] = "llnl.dat", + ): + """ + Args: + phreeqc_db: Name of the PHREEQC database file to use for solution thermodynamics + and speciation calculations. Generally speaking, `llnl.dat` is recommended + for moderate salinity water and prediction of mineral solubilities, + `wateq4f_PWN.dat` is recommended for low to moderate salinity waters. It is + similar to vitens.dat but has many more species. `pitzer.dat` is recommended + when accurate activity coefficients in solutions above 1 M TDS are desired, but + it has fewer species than the other databases. `llnl.dat` and `geothermal.dat` + may offer improved prediction of LSI but currently these databases are not + usable because they do not allow for conductivity calculations. + """ + self.phreeqc_db = phreeqc_db + # database files in this list are not distributed with phreeqpython + self.db_path = ( + Path(os.path.dirname(__file__)) / "database" if self.phreeqc_db in ["llnl.dat", "geothermal.dat"] else None + ) + # create the PhreeqcPython instance + self.pp = PhreeqPython(database=self.phreeqc_db, database_directory=self.db_path) + # attributes to hold the PhreeqPython solution. + self.ppsol = None + # store the solution composition to see whether we need to re-instantiate the solution + self._stored_comp = None + + def _setup_ppsol(self, solution): + """ + Helper method to set up a PhreeqPython solution for subsequent analysis. + """ + self._stored_comp = solution.components.copy() + solv_mass = solution.solvent_mass.to("kg").magnitude + # inherit bulk solution properties + d = { + "temp": solution.temperature.to("degC").magnitude, + "units": "mol/kgw", # to avoid confusion about volume, use mol/kgw which seems more robust in PHREEQC + "pH": solution.pH, + "pe": solution.pE, + "redox": "pe", # hard-coded to use the pe + # PHREEQC will assume 1 kg if not specified, there is also no direct way to specify volume, so we + # really have to specify the solvent mass in 1 liter of solution + "water": solv_mass, + "density": solution.density.to("g/mL").magnitude, + } + if solution.balance_charge == "pH": + d["pH"] = str(d["pH"]) + " charge" + if solution.balance_charge == "pE": + d["pe"] = str(d["pe"]) + " charge" + + # add the composition to the dict + # also, skip H and O + for el, mol in solution.get_el_amt_dict().items(): + # strip off the oxi state + bare_el = el.split("(")[0] + if bare_el in SPECIAL_ELEMENTS: + # PHREEQC will ignore float-formatted oxi states. Need to make sure we are + # passing, e.g. 'C(4)' and not 'C(4.0)' + key = f'{bare_el}({int(float(el.split("(")[-1].split(")")[0]))})' + elif bare_el in ["H", "O"]: + continue + else: + key = bare_el + + d[key] = str(mol / solv_mass) + + # tell PHREEQC which species to use for charge balance + if ( + solution.balance_charge is not None + and solution.balance_charge in solution.get_components_by_element()[el] + ): + d[key] += " charge" + + # create the PHREEQC solution object + try: + ppsol = self.pp.add_solution(d) + except Exception as e: + print(d) + # catch problems with the input to phreeqc + raise ValueError( + "There is a problem with your input. The error message received from " + f" phreeqpython is:\n\n {e}\n Check your input arguments, especially " + "the composition dictionary, and try again." + ) + + self.ppsol = ppsol + + def _destroy_ppsol(self): + """ + Remove the PhreeqPython solution from memory + """ + if self.ppsol is not None: + self.ppsol.forget() + self.ppsol = None + def get_activity_coefficient(self, solution, solute): """ Whenever the appropriate parameters are available, the Pitzer model [may]_ is used. @@ -170,16 +269,9 @@ def get_activity_coefficient(self, solution, solute): Valid options are "molal", "molar", and "rational" (i.e., mole fraction). By default, the molal scale activity coefficient is returned. - Returns + Returns: The mean ion activity coefficient of the solute in question on the selected scale. - See Also: - get_ionic_strength - get_salt - activity_correction.get_activity_coefficient_debyehuckel - activity_correction.get_activity_coefficient_guntelberg - activity_correction.get_activity_coefficient_davies - activity_correction.get_activity_coefficient_pitzer Notes: For multicomponent mixtures, pyEQL implements the "effective Pitzer model" @@ -190,8 +282,7 @@ def get_activity_coefficient(self, solution, solute): .. math:: m_effective = 2 I \\over (\\nu_{+} z_{+}^2 + \\nu{_}- z_{-} ^2) - References - + References: .. [may] May, P. M., Rowland, D., Hefter, G., & Königsberger, E. (2011). A Generic and Updatable Pitzer Characterization of Aqueous Binary Electrolyte Solutions at 1 bar and 25 °C. *Journal of Chemical & Engineering Data*, 56(12), 5066-5077. doi:10.1021/je2009329 @@ -204,6 +295,14 @@ def get_activity_coefficient(self, solution, solute): .. [mistry] Mistry, K. H.; Hunter, H. a.; Lienhard V, J. H. Effect of composition and nonideal solution behavior on desalination calculations for mixed electrolyte solutions with comparison to seawater. Desalination 2013, 318, 34-47. + + See Also: + get_ionic_strength + get_salt + activity_correction.get_activity_coefficient_debyehuckel + activity_correction.get_activity_coefficient_guntelberg + activity_correction.get_activity_coefficient_davies + activity_correction.get_activity_coefficient_pitzer """ # identify the predominant salt that this ion is a member of salt = None @@ -219,16 +318,14 @@ def get_activity_coefficient(self, solution, solute): # show an error if no salt can be found that contains the solute if salt is None: logger.warning("No salts found that contain solute %s. Returning unit activity coefficient." % solute) - return ureg.Quantity("1 dimensionless") + return ureg.Quantity(1, "dimensionless") # use the Pitzer model for higher ionic strength, if the parameters are available # search for Pitzer parameters param = solution.get_property(salt.formula, "model_parameters.activity_pitzer") if param is not None: - # TODO - consider re-enabling a log message recording what salt(s) are used as basis for activity - # calculation - # if verbose is True: - # print("Calculating activity coefficient based on parent salt %s" % salt.formula) + # TODO - consider re-enabling a log message recording what salt(s) are used as basis for activity calculation + logger.info(f"Calculating activity coefficient based on parent salt {salt.formula}") # determine alpha1 and alpha2 based on the type of salt # see the May reference for the rules used to determine @@ -316,7 +413,7 @@ def get_activity_coefficient(self, solution, solute): % solute ) - molal = ureg.Quantity("1 dimensionless") + molal = ureg.Quantity(1, "dimensionless") return molal @@ -475,7 +572,7 @@ def get_solute_volume(self, solution): """Return the volume of the solutes.""" # identify the predominant salt in the solution salt = solution.get_salt() - solute_vol = ureg.Quantity("0 L") + solute_vol = ureg.Quantity(0, "L") # use the pitzer approach if parameters are available pitzer_calc = False @@ -558,15 +655,59 @@ def get_solute_volume(self, solution): def equilibrate(self, solution): """Adjust the speciation of a Solution object to achieve chemical equilibrium.""" - equilibrate_phreeqc(solution, phreeqc_db="llnl.dat") - - -# These are the only elements that are allowed to have parenthetical oxidation states -# PHREEQC will ignore others (e.g., 'Na(1)') -SPECIAL_ELEMENTS = ["S", "C", "N", "Cu", "Fe", "Mn"] + if self.ppsol is not None: + self.ppsol.forget() + self._setup_ppsol(solution) + # self._stored_comp = solution.components + + # use the output from PHREEQC to update the Solution composition + # the .species_moles attribute should return MOLES (not moles per ___) + for s, mol in self.ppsol.species_moles.items(): + solution.components[s] = mol + + # make sure all species are accounted for + charge_adjust = 0 + assert set(self._stored_comp.keys()) - set(solution.components.keys()) == set() + + # log a message if any components were not touched by PHREEQC + # if that was the case, re-adjust the charge balance to account for those species (since PHREEQC did not) + missing_species = set(self._stored_comp.keys()) - {standardize_formula(s) for s in self.ppsol.species} + if len(missing_species) > 0: + logger.warning( + f"After equilibration, the amounts of species {missing_species} were not modified " + "by PHREEQC. These species are likely absent from its database." + ) + for s in missing_species: + charge_adjust += -1 * solution.get_amount(s, "eq").magnitude + + # re-adjust charge balance + if solution.balance_charge is None: + pass + elif solution.balance_charge == "pH": + solution.components["H+"] += charge_adjust + elif solution.balance_charge == "pE": + raise NotImplementedError + else: + z = solution.get_property(solution.balance_charge, "charge") + solution.add_amount(solution.balance_charge, f"{charge_adjust/z} mol") + + def __deepcopy__(self, memo): + # custom deepcopy required because the PhreeqPython instance used by the Native and Phreeqc engines + # is not pickle-able. + import copy + + cls = self.__class__ + result = cls.__new__(cls) + memo[id(self)] = result + for k, v in self.__dict__.items(): + if k == "pp": + result.pp = PhreeqPython(database=self.phreeqc_db, database_directory=self.db_path) + continue + setattr(result, k, copy.deepcopy(v, memo)) + return result -class PhreeqcEOS(EOS): +class PhreeqcEOS(NativeEOS): """Engine based on the PhreeqC model, as implemented via the phreeqpython package.""" def __init__( @@ -587,88 +728,16 @@ def __init__( may offer improved prediction of LSI but currently these databases are not usable because they do not allow for conductivity calculations. """ - # database files in this list are not distributed with phreeqpython - self.db_path = ( - Path(os.path.dirname(__file__)) / "database" if phreeqc_db in ["llnl.dat", "geothermal.dat"] else None - ) - self.database = phreeqc_db - - # create the PhreeqcPython instance - self.pp = PhreeqPython(database=self.database, database_directory=self.db_path) - - def _setup_ppsol(self, solution): - """ - Helper method to set up a PhreeqPython solution for subsequent analysis - """ - # TODO - copied from equilibrate_phreeqc. Can be streamlined / consolidated into a private method somewhere. - solv_mass = solution.solvent_mass.to("kg").magnitude - # inherit bulk solution properties - d = { - "temp": solution.temperature.to("degC").magnitude, - "units": "mol/kgw", # to avoid confusion about volume, use mol/kgw which seems more robust in PHREEQC - "pH": solution.pH, - "pe": solution.pE, - "redox": "pe", # hard-coded to use the pe - # PHREEQC will assume 1 kg if not specified, there is also no direct way to specify volume, so we - # really have to specify the solvent mass in 1 liter of solution - "water": solv_mass, - "density": solution.density.to("g/mL").magnitude, - } - balance_charge = solution.balance_charge - if balance_charge == "pH": - d["pH"] = str(d["pH"]) + " charge" - if balance_charge == "pE": - d["pe"] = str(d["pe"]) + " charge" - initial_comp = solution.components.copy() - - # add the composition to the dict - # also, skip H and O - for el, mol in solution.get_el_amt_dict().items(): - # strip off the oxi state - bare_el = el.split("(")[0] - if bare_el in SPECIAL_ELEMENTS: - # PHREEQC will ignore float-formatted oxi states. Need to make sure we are - # passing, e.g. 'C(4)' and not 'C(4.0)' - key = f'{bare_el}({int(float(el.split("(")[-1].split(")")[0]))})' - elif bare_el in ["H", "O"]: - continue - else: - key = bare_el - - # tell PHREEQC which species to use for charge balance - if el == balance_charge: - key += " charge" - d[key] = mol / solv_mass - - # create the PHREEQC solution object - try: - ppsol = self.pp.add_solution(d) - except Exception as e: - print(d) - # catch problems with the input to phreeqc - raise ValueError( - "There is a problem with your input. The error message received from " - f" phreeqpython is:\n\n {e}\n Check your input arguments, especially " - "the composition dictionary, and try again." - ) - - # make sure PHREEQC has accounted for all the species that were originally present - assert set(initial_comp.keys()) - set(solution.components.keys()) == set() - - return ppsol - - def _destroy_ppsol(self, ppsol): - """ - Remove the PhreeqPython solution from memory - """ - ppsol.forget() + super().__init__(phreeqc_db=phreeqc_db) def get_activity_coefficient(self, solution, solute): """ Return the *molal scale* activity coefficient of solute, given a Solution object. """ - ppsol = self._setup_ppsol(solution) + if self.ppsol is None or solution.components != self._stored_comp: + self._destroy_ppsol() + self._setup_ppsol(solution) # translate the species into keys that phreeqc will understand k = standardize_formula(solute) @@ -680,10 +749,8 @@ def get_activity_coefficient(self, solution, solute): k = el + chg # calculate the molal scale activity coefficient - act = ppsol.activity(k, "mol") / ppsol.molality(k, "mol") - - # remove the PPSol from the phreeqcpython instance - self._destroy_ppsol(ppsol) + # act = self.ppsol.activity(k, "mol") / self.ppsol.molality(k, "mol") + act = self.ppsol.pp.ip.get_activity(self.ppsol.number, k) / self.ppsol.pp.ip.get_molality(self.ppsol.number, k) return ureg.Quantity(act, "dimensionless") @@ -697,13 +764,9 @@ def get_osmotic_coefficient(self, solution): via phreeqcpython """ # TODO - find a way to access or calculate osmotic coefficient - return ureg.Quantity("1 dimensionless") + return ureg.Quantity(1, "dimensionless") def get_solute_volume(self, solution): """Return the volume of the solutes.""" # TODO - phreeqc seems to have no concept of volume, but it does calculate density - return ureg.Quantity("0 L") - - def equilibrate(self, solution): - """Adjust the speciation of a Solution object to achieve chemical equilibrium.""" - equilibrate_phreeqc(solution, phreeqc_db=self.database) + return ureg.Quantity(0, "L") diff --git a/src/pyEQL/equilibrium.py b/src/pyEQL/equilibrium.py index 4a3d5920..3ff9a9c4 100644 --- a/src/pyEQL/equilibrium.py +++ b/src/pyEQL/equilibrium.py @@ -10,11 +10,6 @@ """ # import libraries for scientific functions import math -import os -from pathlib import Path -from typing import Literal - -from phreeqpython import PhreeqPython # the pint unit registry from pyEQL import ureg @@ -38,99 +33,6 @@ "Bicarbonate": "HCO3-", } -# These are the only elements that are allowed to have parenthetical oxidation states -# PHREEQC will ignore others (e.g., 'Na(1)') -SPECIAL_ELEMENTS = ["S", "C", "N", "Cu", "Fe", "Mn"] - - -def equilibrate_phreeqc( - solution, - phreeqc_db: Literal["vitens.dat", "wateq4f_PWN.dat", "pitzer.dat", "llnl.dat", "geothermal.dat"] = "vitens.dat", -): - """Adjust the speciation of a Solution object to achieve chemical equilibrium. - - Args: - phreeqc_db: Name of the PHREEQC database file to use for solution thermodynamics - and speciation calculations. Generally speaking, `llnl.dat` is recommended - for moderate salinity water and prediction of mineral solubilities, - `wateq4f_PWN.dat` is recommended for low to moderate salinity waters. It is - similar to vitens.dat but has many more species. `pitzer.dat` is recommended - when accurate activity coefficients in solutions above 1 M TDS are desired, but - it has fewer species than the other databases. `llnl.dat` and `geothermal.dat` - may offer improved prediction of LSI. - """ - solv_mass = solution.solvent_mass.to("kg").magnitude - # inherit bulk solution properties - d = { - "temp": solution.temperature.to("degC").magnitude, - "units": "mol/kgw", # to avoid confusion about volume, use mol/kgw which seems more robust in PHREEQC - "pH": solution.pH, - "pe": solution.pE, - "redox": "pe", # hard-coded to use the pe - # PHREEQC will assume 1 kg if not specified, there is also no direct way to specify volume, so we - # really have to specify the solvent mass in 1 liter of solution - "water": solv_mass, - "density": solution.density.to("g/mL").magnitude, - } - balance_charge = solution.balance_charge - if balance_charge == "pH": - d["pH"] = str(d["pH"]) + " charge" - if balance_charge == "pE": - d["pe"] = str(d["pe"]) + " charge" - initial_comp = solution.components.copy() - - # add the composition to the dict - # also, skip H and O - for el, mol in solution.get_el_amt_dict().items(): - # strip off the oxi state - bare_el = el.split("(")[0] - if bare_el in SPECIAL_ELEMENTS: - # PHREEQC will ignore float-formatted oxi states. Need to make sure we are - # passing, e.g. 'C(4)' and not 'C(4.0)' - key = f'{bare_el}({int(float(el.split("(")[-1].split(")")[0]))})' - elif bare_el in ["H", "O"]: - continue - else: - key = bare_el - - # tell PHREEQC which species to use for charge balance - if el == balance_charge: - key += " charge" - d[key] = mol / solv_mass - - # database files in this list are not distributed with phreeqpython - db_path = Path(os.path.dirname(__file__)) / "database" if phreeqc_db in ["llnl.dat", "geothermal.dat"] else None - # create the PhreeqcPython instance - pp = PhreeqPython(database=phreeqc_db, database_directory=db_path) - - # # equalize with atmospheric air (optional) - # if EQUALIZE: - # phases = [("CO2(g)", -3.5), ("O2(g)", -0.67)] - # self.ppsol.equalize([t[0] for t in phases], [t[1] for t in phases]) - - # create the PHREEQC solution object - try: - ppsol = pp.add_solution(d) - except Exception as e: - print(d) - # catch problems with the input to phreeqc - raise ValueError( - "There is a problem with your input. The error message received from " - f" phreeqpython is:\n\n {e}\n Check your input arguments, especially " - "the composition dictionary, and try again." - ) - - # use the output from PHREEQC to update the Solution composition - # the .species attribute should return MOLES (not moles per ___) - for s, mol in ppsol.species.items(): - solution.components[s] = mol - - # make sure PHREEQC has accounted for all the species that were originally present - assert set(initial_comp.keys()) - set(solution.components.keys()) == set() - - # remove the PPSol from the phreeqcpython instance - pp.remove_solutions([0]) - def adjust_temp_pitzer(c1, c2, c3, c4, c5, temp, temp_ref=ureg.Quantity("298.15 K")): """ diff --git a/src/pyEQL/functions.py b/src/pyEQL/functions.py index bde86aeb..f20fbb9f 100644 --- a/src/pyEQL/functions.py +++ b/src/pyEQL/functions.py @@ -10,51 +10,44 @@ from monty.dev import deprecated -import pyEQL -from pyEQL import ureg +from pyEQL import Solution, ureg from pyEQL.logging_system import logger -def gibbs_mix(Solution1, Solution2): +def gibbs_mix(solution1: Solution, solution2: Solution): r""" Return the Gibbs energy change associated with mixing two solutions. - Parameters - ---------- - Solution1, Solution2 : Solution objects - The two solutions to be mixed. + Args: + solution1, solution2: The two solutions to be mixed. - Returns - ------- - Quantity + Returns: The change in Gibbs energy associated with complete mixing of the Solutions, in Joules. - Notes - ----- - The Gibbs energy of mixing is calculated as follows + Notes: + The Gibbs energy of mixing is calculated as follows - .. math:: + .. math:: - \\Delta_{mix} G = \\sum_i (n_c + n_d) R T \\ln a_b - \\sum_i n_c R T \\ln a_c - \\sum_i n_d R T \\ln a_d + \\Delta_{mix} G = \\sum_i (n_c + n_d) R T \\ln a_b - \\sum_i n_c R T \\ln a_c - \\sum_i n_d R T \\ln a_d - Where :math:`n` is the number of moles of substance, :math:`T` is the temperature in kelvin, - and subscripts :math:`b`, :math:`c`, and :math:`d` refer to the concentrated, dilute, and blended - Solutions, respectively. + Where :math:`n` is the number of moles of substance, :math:`T` is the temperature in kelvin, + and subscripts :math:`b`, :math:`c`, and :math:`d` refer to the concentrated, dilute, and blended + Solutions, respectively. - Note that dissociated ions must be counted as separate components, - so a simple salt dissolved in water is a three component solution (cation, - anion, and water). + Note that dissociated ions must be counted as separate components, + so a simple salt dissolved in water is a three component solution (cation, + anion, and water). - References - ---------- - Koga, Yoshikata, 2007. *Solution Thermodynamics and its Application to Aqueous Solutions: - A differential approach.* Elsevier, 2007, pp. 23-37. + References: + Koga, Yoshikata, 2007. *Solution Thermodynamics and its Application to Aqueous Solutions: + A differential approach.* Elsevier, 2007, pp. 23-37. """ - concentrate = Solution1 - dilute = Solution2 - blend = mix(Solution1, Solution2) + concentrate = solution1 + dilute = solution2 + blend = solution1 + solution2 term_list = {concentrate: 0, dilute: 0, blend: 0} # calculate the entropy change and number of moles solute for each solution @@ -68,46 +61,40 @@ def gibbs_mix(Solution1, Solution2): ) -def entropy_mix(Solution1, Solution2): +def entropy_mix(solution1: Solution, solution2: Solution): r""" Return the ideal mixing entropy associated with mixing two solutions. - Parameters - ---------- - Solution1, Solution2 : Solution objects - The two solutions to be mixed. + Parameters: + solution1, solution2: The two solutions to be mixed. - Returns - ------- - Quantity + Returns: The ideal mixing entropy associated with complete mixing of the Solutions, in Joules. - Notes - ----- - The ideal entropy of mixing is calculated as follows + Notes: + The ideal entropy of mixing is calculated as follows - .. math:: + .. math:: - \\Delta_{mix} S = \\sum_i (n_c + n_d) R T \\ln x_b - \\sum_i n_c R T \\ln x_c - \\sum_i n_d R T \\ln x_d + \\Delta_{mix} S = \\sum_i (n_c + n_d) R T \\ln x_b - \\sum_i n_c R T \\ln x_c - \\sum_i n_d R T \\ln x_d - Where :math:`n` is the number of moles of substance, :math:`T` is the temperature in kelvin, - and subscripts :math:`b`, :math:`c`, and :math:`d` refer to the concentrated, dilute, and blended - Solutions, respectively. + Where :math:`n` is the number of moles of substance, :math:`T` is the temperature in kelvin, + and subscripts :math:`b`, :math:`c`, and :math:`d` refer to the concentrated, dilute, and blended + Solutions, respectively. - Note that dissociated ions must be counted as separate components, - so a simple salt dissolved in water is a three component solution (cation, - anion, and water). + Note that dissociated ions must be counted as separate components, + so a simple salt dissolved in water is a three component solution (cation, + anion, and water). - References - ---------- - Koga, Yoshikata, 2007. *Solution Thermodynamics and its Application to Aqueous Solutions: - A differential approach.* Elsevier, 2007, pp. 23-37. + References: + Koga, Yoshikata, 2007. *Solution Thermodynamics and its Application to Aqueous Solutions: + A differential approach.* Elsevier, 2007, pp. 23-37. """ - concentrate = Solution1 - dilute = Solution2 - blend = mix(Solution1, Solution2) + concentrate = solution1 + dilute = solution2 + blend = solution1 + solution2 term_list = {concentrate: 0, dilute: 0, blend: 0} # calculate the entropy change and number of moles solute for each solution @@ -123,67 +110,61 @@ def entropy_mix(Solution1, Solution2): ) -def donnan_eql(solution, fixed_charge): +def donnan_eql(solution: Solution, fixed_charge: str): """ Return a solution object in equilibrium with fixed_charge. - Parameters - ---------- - solution : Solution object - The external solution to be brought into equilibrium with the fixed - charges - fixed_charge : str quantity - String representing the concentration of fixed charges, including sign. - May be specified in mol/L or mol/kg units. e.g. '1 mol/kg' + Parameters: + solution : Solution object + The external solution to be brought into equilibrium with the fixed + charges + fixed_charge : str quantity + String representing the concentration of fixed charges, including sign. + May be specified in mol/L or mol/kg units. e.g. '1 mol/kg' - Returns - ------- - Solution - A solution that has established Donnan equilibrium with the external + Returns: + A Solution that has established Donnan equilibrium with the external (input) Solution - Notes - ----- - The general equation representing the equilibrium between an external - electrolyte solution and an ion-exchange medium containing fixed charges - is + Notes: + The general equation representing the equilibrium between an external + electrolyte solution and an ion-exchange medium containing fixed charges + is - .. math:: + .. math:: - \\frac{a_{-}}{\\bar a_{-}}^{\\frac{1}{z_{-}} \\frac{\\bar a_{+}}{a_{+}}^{\\frac{1}{z_{+}} \ - = exp(\\frac{\\Delta \\pi \\bar V}{{RT z_{+} \\nu_{+}}}) + \\frac{a_{-}}{\\bar a_{-}}^{\\frac{1}{z_{-}} \\frac{\\bar a_{+}}{a_{+}}^{\\frac{1}{z_{+}} \ + = exp(\\frac{\\Delta \\pi \\bar V}{{RT z_{+} \\nu_{+}}}) - Where subscripts :math:`+` and :math:`-` indicate the cation and anion, respectively, - the overbar indicates the membrane phase, - :math:`a` represents activity, :math:`z` represents charge, :math:`\\nu` represents the stoichiometric - coefficient, :math:`V` represents the partial molar volume of the salt, and - :math:`\\Delta \\pi` is the difference in osmotic pressure between the membrane and the - solution phase. + Where subscripts :math:`+` and :math:`-` indicate the cation and anion, respectively, + the overbar indicates the membrane phase, + :math:`a` represents activity, :math:`z` represents charge, :math:`\\nu` represents the stoichiometric + coefficient, :math:`V` represents the partial molar volume of the salt, and + :math:`\\Delta \\pi` is the difference in osmotic pressure between the membrane and the + solution phase. - In addition, electroneutrality must prevail within the membrane phase: + In addition, electroneutrality must prevail within the membrane phase: - .. math:: \\bar C_{+} z_{+} + \\bar X + \\bar C_{-} z_{-} = 0 + .. math:: \\bar C_{+} z_{+} + \\bar X + \\bar C_{-} z_{-} = 0 - Where :math:`C` represents concentration and :math:`X` is the fixed charge concentration - in the membrane or ion exchange phase. + Where :math:`C` represents concentration and :math:`X` is the fixed charge concentration + in the membrane or ion exchange phase. - This function solves these two equations simultaneously to arrive at the - concentrations of the cation and anion in the membrane phase. It returns - a solution equal to the input solution except that the concentrations of - the predominant cation and anion have been adjusted according to this - equilibrium. + This function solves these two equations simultaneously to arrive at the + concentrations of the cation and anion in the membrane phase. It returns + a solution equal to the input solution except that the concentrations of + the predominant cation and anion have been adjusted according to this + equilibrium. - NOTE that this treatment is only capable of equilibrating a single salt. - This salt is identified by the get_salt() method. + NOTE that this treatment is only capable of equilibrating a single salt. + This salt is identified by the get_salt() method. - References - ---------- - Strathmann, Heiner, ed. *Membrane Science and Technology* vol. 9, 2004. Chapter 2, p. 51. + References: + Strathmann, Heiner, ed. *Membrane Science and Technology* vol. 9, 2004. Chapter 2, p. 51. http://dx.doi.org/10.1016/S0927-5193(04)80033-0 See Also: - -------- - get_salt() + get_salt() """ # identify the salt @@ -286,7 +267,7 @@ def donnan_solve(x): @deprecated( message="mix() is deprecated and will be removed in the next release! You can now mix solutions using the addition operator, e.g. s_mix = s1 + s2." ) -def mix(s1, s2): +def mix(s1, s2): # pragma: no cover """ Mix two solutions together. @@ -305,7 +286,12 @@ def mix(s1, s2): return s1 + s2 -def autogenerate(solution: Literal["seawater", "rainwater", "wastewater", "urine", "Ringers lactate", "normal saline"]): +@deprecated( + message="autogenerate() is deprecated and will be removed in the next release! Use Solution.from_preset() instead.)" +) +def autogenerate( + solution: Literal["seawater", "rainwater", "wastewater", "urine", "Ringers lactate", "normal saline"] +): # pragma: no cover """ This method provides a quick way to create Solution objects representing commonly-encountered solutions, such as seawater, rainwater, and wastewater. @@ -429,4 +415,4 @@ def autogenerate(solution: Literal["seawater", "rainwater", "wastewater", "urine logger.error("Invalid solution entered - %s" % solution) return None - return pyEQL.Solution(solutes, temperature=temperature, pressure=pressure, pH=pH) + return Solution(solutes, temperature=temperature, pressure=pressure, pH=pH) diff --git a/src/pyEQL/presets/Ringers lactate.yaml b/src/pyEQL/presets/Ringers lactate.yaml new file mode 100644 index 00000000..cdbd5259 --- /dev/null +++ b/src/pyEQL/presets/Ringers lactate.yaml @@ -0,0 +1,20 @@ +'@module': pyEQL.solution +'@class': Solution +'@version': 0.0.post1.dev699+g0764b1c +solutes: + H2O(aq): 55.2313771443148 mol + Na[+1]: 0.13 mol + Cl[-1]: 0.109 mol + H5(CO)3[-1]: 0.028 mol + K[+1]: 0.004 mol + Ca[+2]: 0.0015 mol + H[+1]: 3.162277660168379e-07 mol + OH[-1]: 3.162277660168379e-08 mol +volume: 1 l +temperature: 298.15 K +pressure: 1 atm +pH: 6.5 +pE: 8.5 +balance_charge: +solvent: H2O(aq) +engine: native diff --git a/src/pyEQL/presets/normal saline.yaml b/src/pyEQL/presets/normal saline.yaml new file mode 100644 index 00000000..31e78bf1 --- /dev/null +++ b/src/pyEQL/presets/normal saline.yaml @@ -0,0 +1,17 @@ +'@module': pyEQL.solution +'@class': Solution +'@version': 0.0.post1.dev699+g0764b1c +solutes: + H2O(aq): 55.19703719794332 mol + Na[+1]: 0.154 mol + Cl[-1]: 0.154 mol + H[+1]: 1e-07 mol + OH[-1]: 1e-07 mol +volume: 1 l +temperature: 298.15 K +pressure: 1 atm +pH: 7.0 +pE: 8.5 +balance_charge: +solvent: H2O(aq) +engine: native diff --git a/src/pyEQL/presets/rainwater.yaml b/src/pyEQL/presets/rainwater.yaml new file mode 100644 index 00000000..83c80351 --- /dev/null +++ b/src/pyEQL/presets/rainwater.yaml @@ -0,0 +1,17 @@ +'@module': pyEQL.solution +'@class': Solution +'@version': 0.0.post1.dev699+g0764b1c +solutes: + H2O(aq): 55.34454944845822 mol + HCO3[-1]: 3.162277660168379e-06 mol + H[+1]: 1e-06 mol + OH[-1]: 1e-08 mol + CO3[-2]: 1e-09 mol +volume: 1 l +temperature: 298.15 K +pressure: 1 atm +pH: 6.0 +pE: 8.5 +balance_charge: +solvent: H2O(aq) +engine: native diff --git a/src/pyEQL/presets/seawater.yaml b/src/pyEQL/presets/seawater.yaml new file mode 100644 index 00000000..09eca400 --- /dev/null +++ b/src/pyEQL/presets/seawater.yaml @@ -0,0 +1,29 @@ +'@module': pyEQL.solution +'@class': Solution +'@version': 0.0.post1.dev699+g0764b1c +solutes: + H2O(aq): 55.34455401423017 mol + Cl[-1]: 0.54425785619973 mol + Na[+1]: 0.4675827371496296 mol + Mg[+2]: 0.05266118052346798 mol + SO4[-2]: 0.02815187344845402 mol + Ca[+2]: 0.010251594148212317 mol + K[+1]: 0.010177468379526855 mol + HCO3[-1]: 0.0017126511769261989 mol + Br[-1]: 0.0008395244921424561 mol + B(OH)3(aq): 0.0003134669156396757 mol + CO3[-2]: 0.00023825904349479544 mol + B(OH)4(aq): 0.0001005389715937341 mol + Sr[+2]: 9.046483353663284e-05 mol + F[-1]: 6.822478260456777e-05 mol + CO2(aq): 9.515218476861173e-06 mol + OH[-1]: 8.207436858780224e-06 mol + H[+1]: 7.943282347242822e-09 mol +volume: 1.0080615264452506 l +temperature: 298.15 K +pressure: 1 atm +pH: 8.103487039827968 +pE: 8.5 +balance_charge: +solvent: H2O(aq) +engine: native diff --git a/src/pyEQL/presets/urine.yaml b/src/pyEQL/presets/urine.yaml new file mode 100644 index 00000000..c9a38b4b --- /dev/null +++ b/src/pyEQL/presets/urine.yaml @@ -0,0 +1,26 @@ +'@module': pyEQL.solution +'@class': Solution +'@version': 0.0.post1.dev699+g0764b1c +solutes: + H2O(aq): 55.135679438263864 mol + H4CN2O(aq): 0.333026615820163 mol + Na[+1]: 0.26098565526795925 mol + Cl[-1]: 0.05359207965475418 mol + K[+1]: 0.038364839391994025 mol + H4N[+1]: 0.027718552470665455 mol + SO4[-2]: 0.018737781405042127 mol + PO4[-3]: 0.012635387918307416 mol + H7C4N3O(aq): 0.008840335409397701 mol + HCO3[-1]: 0.004916675462052772 mol + Mg[+2]: 0.004114379757251594 mol + H4C5N4O3(aq): 0.0017845430730997621 mol + H[+1]: 1e-07 mol + OH[-1]: 1e-07 mol +volume: 1 l +temperature: 298.15 K +pressure: 1 atm +pH: 7.0 +pE: 8.5 +balance_charge: +solvent: H2O(aq) +engine: native diff --git a/src/pyEQL/presets/wastewater.yaml b/src/pyEQL/presets/wastewater.yaml new file mode 100644 index 00000000..1e7ee964 --- /dev/null +++ b/src/pyEQL/presets/wastewater.yaml @@ -0,0 +1,21 @@ +'@module': pyEQL.solution +'@class': Solution +'@version': 0.0.post1.dev699+g0764b1c +solutes: + H2O(aq): 55.342123269143364 mol + CH3COOH(aq): 0.006827420786931851 mol + Cl[-1]: 0.0016641751050686824 mol + H3N(aq): 0.0014268501490265714 mol + K[+1]: 0.0004092249535146029 mol + SO4[-2]: 0.00027065684251727516 mol + PO4[-3]: 8.002412348261364e-05 mol + H[+1]: 1e-07 mol + OH[-1]: 1e-07 mol +volume: 1 l +temperature: 298.15 K +pressure: 1 atm +pH: 7.0 +pE: 8.5 +balance_charge: +solvent: H2O(aq) +engine: native diff --git a/src/pyEQL/solute.py b/src/pyEQL/solute.py index cb1b0f50..6d55e001 100644 --- a/src/pyEQL/solute.py +++ b/src/pyEQL/solute.py @@ -95,6 +95,7 @@ class Solute: "Max_C": None, }, "viscosity_jones_dole": {"B": None}, + "diffusion_temp_smolyakov": {"a1": None, "a2": None, "d": None}, } ) diff --git a/src/pyEQL/solution.py b/src/pyEQL/solution.py index 282b0707..fe4dccbd 100644 --- a/src/pyEQL/solution.py +++ b/src/pyEQL/solution.py @@ -8,28 +8,31 @@ from __future__ import annotations import math +import os import warnings from functools import lru_cache +from importlib.resources import files from pathlib import Path from typing import Any, Literal import numpy as np -from iapws import IAPWS95 from maggma.stores import JSONStore, Store from monty.dev import deprecated from monty.json import MontyDecoder, MSONable +from monty.serialization import dumpfn, loadfn from pint import DimensionalityError, Quantity from pymatgen.core import Element from pymatgen.core.ion import Ion from pyEQL import IonDB, ureg +from pyEQL.activity_correction import _debye_parameter_activity, _debye_parameter_B from pyEQL.engines import EOS, IdealEOS, NativeEOS, PhreeqcEOS # logging system from pyEQL.logging_system import logger from pyEQL.salt_ion_match import Salt from pyEQL.solute import Solute -from pyEQL.utils import FormulaDict, standardize_formula +from pyEQL.utils import FormulaDict, create_water_substance, standardize_formula EQUIV_WT_CACO3 = ureg.Quantity(100.09 / 2, "g/mol") @@ -54,6 +57,7 @@ def __init__( database: str | Path | Store | None = None, ): """ + Instantiate a Solution from a composition. Args: solutes : dict, optional. Keys must be the chemical formula, while values must be @@ -89,7 +93,7 @@ def __init__( 'pH', which will adjust the solution pH to balance charge, 'pE' which will adjust the redox equilibrium to balance charge, or the name of a dissolved species e.g. 'Ca+2' or 'Cl-' that will be added/subtracted to balance charge. If set to None, no charge balancing will be performed either on init - or when equilibrate() is called. + or when equilibrate() is called. Note that in this case, equilibrate() can distort the charge balance! solvent: Formula of the solvent. Solvents other than water are not supported at this time. engine: Electrolyte modeling engine to use. See documentation for details on the available engines. @@ -113,6 +117,8 @@ def __init__( # see https://rednafi.com/python/lru_cache_on_methods/ self.get_property = lru_cache()(self._get_property) self.get_molar_conductivity = lru_cache()(self._get_molar_conductivity) + self.get_mobility = lru_cache()(self._get_mobility) + self.get_diffusion_coefficient = lru_cache()(self._get_diffusion_coefficient) # initialize the volume recalculation flag self.volume_update_required = False @@ -123,7 +129,7 @@ def __init__( self._volume = ureg.Quantity(volume).to("L") else: # volume_set = False - self._volume = ureg.Quantity("1 L") + self._volume = ureg.Quantity(1, "L") # store the initial conditions as private variables in case they are # changed later self._temperature = ureg.Quantity(temperature) @@ -137,10 +143,7 @@ def __init__( self.balance_charge = balance_charge # instantiate a water substance for property retrieval - self.water_substance = IAPWS95( - T=self.temperature.magnitude, - P=self.pressure.to("MPa").magnitude, - ) + self.water_substance = create_water_substance(self.temperature, self.pressure) # create an empty dictionary of components. This dict comprises {formula: moles} # where moles is the number of moles in the solution. @@ -150,7 +153,7 @@ def __init__( if database is None: # load the default database, which is a JSONStore db_store = IonDB - elif isinstance(database, (str, Path)): + elif isinstance(database, str | Path): db_store = JSONStore(str(database), key="formula") logger.info(f"Created maggma JSONStore from .json file {database}") else: @@ -192,8 +195,8 @@ def __init__( # self.add_solvent(self.solvent, kwargs["solvent"][1]) # calculate the moles of solvent (water) on the density and the solution volume - moles = self.volume / ureg.Quantity("55.55 mol/L") - self.components["H2O"] = moles.magnitude + moles = self.volume.magnitude / 55.55 # molarity of pure water + self.components["H2O"] = moles # set the pH with H+ and OH- self.add_solute("H+", str(10 ** (-1 * pH)) + "mol/L") @@ -337,10 +340,7 @@ def temperature(self, temperature: str): self._temperature = ureg.Quantity(temperature) # update the water substance - self.water_substance = IAPWS95( - T=self.temperature.magnitude, - P=self.pressure.to("MPa").magnitude, - ) + self.water_substance = create_water_substance(self.temperature, self.pressure) # recalculate the volume self.volume_update_required = True @@ -348,6 +348,8 @@ def temperature(self, temperature: str): # clear any cached solute properties that may depend on temperature self.get_property.cache_clear() self.get_molar_conductivity.cache_clear() + self.get_mobility.cache_clear() + self.get_diffusion_coefficient.cache_clear() @property def pressure(self) -> Quantity: @@ -365,10 +367,7 @@ def pressure(self, pressure: str): self._pressure = ureg.Quantity(pressure) # update the water substance - self.water_substance = IAPWS95( - T=self.temperature.magnitude, - P=self.pressure.to("MPa").magnitude, - ) + self.water_substance = create_water_substance(self.temperature, self.pressure) # recalculate the volume self.volume_update_required = True @@ -619,75 +618,51 @@ def viscosity_kinematic(self) -> Quantity: # calculate the kinematic viscosity nu = math.log(nu_w * MW_w / MW) + 15 * x_cat**2 + x_cat**3 * G_123 + 3 * x_cat * G_23 * (1 - 0.05 * x_cat) - return ureg.Quantity(math.exp(nu), "m**2 / s") + return ureg.Quantity(np.exp(nu), "m**2 / s") - # TODO - need tests of conductivity - # TODO - update with newer conductivity model used since PHREEQC 3.4+ - # https://www.hydrochemistry.eu/pub/appt_CCR17.pdf @property def conductivity(self) -> Quantity: """ Compute the electrical conductivity of the solution. - Parameters - ---------- - None - Returns: - ------- - Quantity The electrical conductivity of the solution in Siemens / meter. Notes: - ----- - Conductivity is calculated by summing the molar conductivities of the respective - solutes, but they are activity-corrected and adjusted using an empricial exponent. - This approach is used in PHREEQC and Aqion models [aq]_ [hc]_ - - .. math:: + Conductivity is calculated by summing the molar conductivities of the respective + solutes. - EC = {F^2 \\over R T} \\sum_i D_i z_i ^ 2 \\gamma_i ^ {\\alpha} m_i + .. math:: - Where: + EC = {F^2 \\over R T} \\sum_i D_i z_i ^ 2 m_i = \\sum_i \\lambda_i m_i - .. math:: + Where :math:`D_i` is the diffusion coefficient, :math:`m_i` is the molal concentration, + :math:`z_i` is the charge, and the summation extends over all species in the solution. + Alternatively, :math:`\\lambda_i` is the molar conductivity of solute i. - \\alpha = - \\begin{cases} - {\\frac{0.6}{\\sqrt{| z_{i} | }}} & {I < 0.36 | z_{i} | } - {\\frac{\\sqrt{I}}{| z_i |}} & otherwise - \\end{cases} - - Note: PHREEQC uses the molal rather than molar concentration according to - http://wwwbrr.cr.usgs.gov/projects/GWC_coupled/phreeqc/phreeqc3-html/phreeqc3-43.htm + Diffusion coefficients :math:`D_i` (and molar conductivities :math:`\\lambda_i`) are + adjusted for the effects of temperature and ionic strength using the method implemented + in PHREEQC >= 3.4. [aq]_ [hc]_ See `get_diffusion_coefficient for` further details. References: - ---------- - .. [aq] https://www.aqion.de/site/electrical-conductivity - .. [hc] http://www.hydrochemistry.eu/exmpls/sc.html + .. [aq] https://www.aqion.de/site/electrical-conductivity + .. [hc] http://www.hydrochemistry.eu/exmpls/sc.html See Also: - -------- - :py:attr:`ionic_strength` - :py:meth:`get_molar_conductivity()` - :py:meth:`get_activity_coefficient()` - - """ - EC = ureg.Quantity("0 S/m") - IS = self.ionic_strength.magnitude - - for item in self.components: - z = abs(self.get_property(item, "charge")) - # ignore uncharged species - if z != 0: - # determine the value of the exponent alpha - alpha = 0.6 / z**0.5 if 0.36 * z > IS else IS**0.5 / z - - molar_cond = self.get_molar_conductivity(item) - - EC += molar_cond * self.get_activity_coefficient(item) ** alpha * self.get_amount(item, "mol/L") - - return EC.to("S/m") + :py:attr:`get_diffusion_coefficient` + :py:meth:`get_molar_conductivity` + :py:attr:`ionic_strength` + """ + EC = ureg.Quantity( + np.asarray( + [ + self.get_molar_conductivity(i).to("S*L/mol/m").magnitude * self.get_amount(i, "mol/L").magnitude + for i in self.components + ] + ), + "S/m", + ) + return np.sum(EC) @property def ionic_strength(self) -> Quantity: @@ -743,9 +718,9 @@ def charge_balance(self) -> float: on the solution and SHOULD equal zero at all times, but due to numerical errors will usually have a small nonzero value. It is calculated according to: - .. math:: CB = \\sum_i n_i z_i + .. math:: CB = \\sum_i C_i z_i - where :math:`n_i` is the number of moles, and :math:`z_i` is the charge on species i. + where :math:`C_i` is the molar concentration, and :math:`z_i` is the charge on species i. Returns: ------- @@ -786,7 +761,7 @@ def alkalinity(self) -> Quantity: .. [stm] Stumm, Werner and Morgan, James J. Aquatic Chemistry, 3rd ed, pp 165. Wiley Interscience, 1996. """ - alkalinity = ureg.Quantity("0 mol/L") + alkalinity = ureg.Quantity(0, "mol/L") base_cations = { "Li[+1]", @@ -833,7 +808,7 @@ def hardness(self) -> Quantity: The hardness of the solution in mg/L as CaCO3 """ - hardness = ureg.Quantity("0 mol/L") + hardness = ureg.Quantity(0, "mol/L") for item in self.components: z = self.get_property(item, "charge") @@ -850,7 +825,7 @@ def total_dissolved_solids(self) -> Quantity: The TDS is defined as the sum of the concentrations of all aqueous solutes (not including the solvent), except for H[+1] and OH[-1]]. """ - tds = ureg.Quantity("0 mg/L") + tds = ureg.Quantity(0, "mg/L") for s in self.components: # ignore pure water and dissolved gases, but not CO2 if s in ["H2O(aq)", "H[+1]", "OH[-1]"]: @@ -1104,7 +1079,7 @@ def get_components_by_element(self) -> dict[str, list]: Return a list of all species associated with a given element. Elements (keys) are suffixed with their oxidation state in parentheses, e.g., - {"Na(1)":["Na[+1]", "NaOH(aq)"]} + {"Na(1.0)":["Na[+1]", "NaOH(aq)"]} Species associated with each element are sorted in descending order of the amount present (i.e., the first species listed is the most abundant). @@ -1136,7 +1111,7 @@ def get_el_amt_dict(self): Return a dict of Element: amount in mol Elements (keys) are suffixed with their oxidation state in parentheses, - e.g. "Fe(2)", "Cl(-1)". + e.g. "Fe(2.0)", "Cl(-1.0)". """ d = {} for s, mol in self.components.items(): @@ -1167,7 +1142,7 @@ def get_total_amount(self, element: str, units) -> Quantity: Args: element: The symbol of the element of interest. The symbol can optionally be followed by the - oxidation state in parentheses, e.g., "Na(1)", "Fe(2)", or "O(0)". If no oxidation state + oxidation state in parentheses, e.g., "Na(1.0)", "Fe(2.0)", or "O(0.0)". If no oxidation state is given, the total concentration of the element (over all oxidation states) is returned. units : str Units desired for the output. Examples of valid units are @@ -1279,7 +1254,7 @@ def add_solute(self, formula: str, amount: str): # update the volume to account for the space occupied by all the solutes # make sure that there is still solvent present in the first place - if self.solvent_mass <= ureg.Quantity("0 kg"): + if self.solvent_mass <= ureg.Quantity(0, "kg"): logger.error("All solvent has been depleted from the solution") return # set the volume recalculation flag @@ -1383,7 +1358,7 @@ def add_amount(self, solute: str, amount: str): # update the volume to account for the space occupied by all the solutes # make sure that there is still solvent present in the first place - if self.solvent_mass <= ureg.Quantity("0 kg"): + if self.solvent_mass <= ureg.Quantity(0, "kg"): logger.error("All solvent has been depleted from the solution") return @@ -1471,7 +1446,7 @@ def set_amount(self, solute: str, amount: str): # update the volume to account for the space occupied by all the solutes # make sure that there is still solvent present in the first place - if self.solvent_mass <= ureg.Quantity("0 kg"): + if self.solvent_mass <= ureg.Quantity(0, "kg"): logger.error("All solvent has been depleted from the solution") return @@ -1780,14 +1755,14 @@ def get_activity_coefficient( """ # return unit activity coefficient if the concentration of the solute is zero if self.get_amount(solute, "mol").magnitude == 0: - return ureg.Quantity("1 dimensionless") + return ureg.Quantity(1, "dimensionless") try: # get the molal-scale activity coefficient from the EOS engine molal = self.engine.get_activity_coefficient(solution=self, solute=solute) - except ValueError: + except (ValueError, ZeroDivisionError): logger.warning("Calculation unsuccessful. Returning unit activity coefficient.") - return ureg.Quantity("1 dimensionless") + return ureg.Quantity(1, "dimensionless") # if necessary, convert the activity coefficient to another scale, and return the result if scale == "molal": @@ -1795,11 +1770,11 @@ def get_activity_coefficient( if scale == "molar": total_molality = self.get_total_moles_solute() / self.solvent_mass total_molarity = self.get_total_moles_solute() / self.volume - return (molal * self.water_substance.rho * ureg.Quantity("1 g/L") * total_molality / total_molarity).to( + return (molal * ureg.Quantity(self.water_substance.rho, "g/L") * total_molality / total_molarity).to( "dimensionless" ) if scale == "rational": - return molal * (1 + ureg.Quantity("0.018015 kg/mol") * self.get_total_moles_solute() / self.solvent_mass) + return molal * (1 + ureg.Quantity(0.018015, "kg/mol") * self.get_total_moles_solute() / self.solvent_mass) raise ValueError("Invalid scale argument. Pass 'molal', 'molar', or 'rational'.") @@ -1881,7 +1856,7 @@ def get_osmotic_coefficient(self, scale: Literal["molal", "molar", "rational"] = / math.log(self.get_amount(self.solvent, "fraction")) ) if scale == "fugacity": - return math.exp( + return np.exp( -molal_phi * ureg.Quantity(0.018015, "kg/mol") * self.get_total_moles_solute() / self.solvent_mass - math.log(self.get_amount(self.solvent, "fraction")) ) * ureg.Quantity(1, "dimensionless") @@ -1937,7 +1912,7 @@ def get_water_activity(self) -> Quantity: logger.info("Calculated water activity using osmotic coefficient") - return ureg.Quantity(math.exp(-osmotic_coefficient * 0.018015 * concentration_sum), "dimensionless") + return ureg.Quantity(np.exp(-osmotic_coefficient * 0.018015 * concentration_sum), "dimensionless") def get_chemical_potential_energy(self, activity_correction: bool = True) -> Quantity: """ @@ -1980,7 +1955,7 @@ def get_chemical_potential_energy(self, activity_correction: bool = True) -> Qua .. [koga] Koga, Yoshikata, 2007. *Solution Thermodynamics and its Application to Aqueous Solutions: A differential approach.* Elsevier, 2007, pp. 23-37. """ - E = ureg.Quantity("0 J") + E = ureg.Quantity(0, "J") # loop through all the components and add their potential energy for item in self.components: @@ -2023,7 +1998,7 @@ def _get_property(self, solute: str, name: str) -> Any | None: Quantity: The desired parameter or None if not found """ - base_temperature = ureg.Quantity("25 degC") + base_temperature = ureg.Quantity(25, "degC") # base_pressure = ureg.Quantity("1 atm") # query the database using the standardized formula @@ -2060,20 +2035,7 @@ def _get_property(self, solute: str, name: str) -> Any | None: if name == "transport.diffusion_coefficient": data = doc["transport"]["diffusion_coefficient"] if data is not None: - # correct for temperature and viscosity - # .. math:: D_1 \over D_2 = T_1 \over T_2 * \mu_2 \over \mu_1 - # where :math:`\mu` is the dynamic viscosity - # assume that the base viscosity is that of pure water - return ( - ureg.Quantity(data["value"]).to("m**2/s") - * self.temperature.magnitude - / 298.15 - * self.water_substance.mu - / self.viscosity_dynamic.to("Pa*s").magnitude - ) - - # logger.warning("Diffusion coefficient not found for species %s. Assuming zero." % (solute)) - # return ureg.Quantity("0 m**2/s") + return ureg.Quantity(data["value"]).to("m**2/s") # just return the base-value molar volume for now; find a way to adjust for concentration later if name == "size.molar_volume": @@ -2147,21 +2109,18 @@ def _get_property(self, solute: str, name: str) -> Any | None: return ureg.Quantity(val) return None - def get_transport_number(self, solute, activity_correction=False) -> Quantity: + def get_transport_number(self, solute: str) -> Quantity: """Calculate the transport number of the solute in the solution. Args: - solute : String identifying the solute for which the transport number is + solute: Formula of the solute for which the transport number is to be calculated. - activity_correction: If True, the transport number will be corrected for activity following - the same method used for solution conductivity. Defaults to False if omitted. - Returns: - The transport number of `solute` + The transport number of `solute`, as a dimensionless Quantity. Notes: - Transport number is calculated according to : + Transport number is calculated according to : .. math:: @@ -2171,47 +2130,34 @@ def get_transport_number(self, solute, activity_correction=False) -> Quantity: coefficient, and :math:`z_i` is the charge, and the summation extends over all species in the solution. - If `activity_correction` is True, the contribution of each ion to the - transport number is corrected with an activity factor. See the documentation - for Solution.conductivity for an explanation of this correction. + Diffusion coefficients :math:`D_i` are adjusted for the effects of temperature + and ionic strength using the method implemented in PHREEQC >= 3.4. + See `get_diffusion_coefficient for` further details. + References: Geise, G. M.; Cassady, H. J.; Paul, D. R.; Logan, E.; Hickner, M. A. "Specific ion effects on membrane potential and the permselectivity of ion exchange membranes."" *Phys. Chem. Chem. Phys.* 2014, 16, 21673-21681. + See Also: + :py:meth:`get_diffusion_coefficient` + :py:meth:`get_molar_conductivity` """ solute = standardize_formula(solute) denominator = numerator = 0 - IS = self.ionic_strength.magnitude for item, mol in self.components.items(): - z = self.get_property(item, "charge") - # neutral solutes do not contribute to transport number - if z == 0: - continue - # the molar conductivity of each species is F/RT D * z^2, and the F/RT factor # cancels out # using species amounts in mol is equivalent to using concentrations in mol/L # since there is only one solution volume, and it's much faster. term = self.get_molar_conductivity(item).magnitude * mol - if activity_correction is True: - gamma = self.get_activity_coefficient(item).magnitude - - alpha = 0.6 / z**0.5 if 0.36 * z > IS else IS**0.5 / z - - if item == solute: - numerator = term * gamma**alpha + if item == solute: + numerator = term - denominator += term * gamma**alpha - - else: - if item == solute: - numerator = term - - denominator += term + denominator += term return ureg.Quantity(numerator / denominator, "dimensionless") @@ -2232,16 +2178,26 @@ def _get_molar_conductivity(self, solute: str) -> Quantity: .. math:: - \\kappa_i = {z_i^2 D_i F^2 \\over RT} + \\lambda_i = \\frac{F^2}{RT} D_i z_i^2 - Note that the diffusion coefficient is strongly variable with temperature. + Diffusion coefficients :math:`D_i` are adjusted for the effects of temperature + and ionic strength using the method implemented in PHREEQC >= 3.4. See `get_diffusion_coefficient for` further details. References: - .. [smed] Smedley, Stuart. The Interpretation of Ionic Conductivity in Liquids, pp 1-9. Plenum Press, 1980. + 1. .. [smed] Smedley, Stuart. The Interpretation of Ionic Conductivity in Liquids, pp 1-9. Plenum Press, 1980. + + 2. https://www.hydrochemistry.eu/exmpls/sc.html + + 3. Appelo, C.A.J. Solute transport solved with the Nernst-Planck equation for concrete pores with `free' water and a double layer. Cement and Concrete Research 101, 2017. https://dx.doi.org/10.1016/j.cemconres.2017.08.030 + + 4. CRC Handbook of Chemistry and Physics + + See Also: + :py:meth:`get_diffusion_coefficient` """ - D = self.get_property(solute, "transport.diffusion_coefficient") + D = self.get_diffusion_coefficient(solute, default=0) - if D is not None: + if D != 0: molar_cond = ( D * (ureg.e * ureg.N_A) ** 2 * self.get_property(solute, "charge") ** 2 / (ureg.R * self.temperature) ) @@ -2252,7 +2208,106 @@ def _get_molar_conductivity(self, solute: str) -> Quantity: return molar_cond.to("mS / cm / (mol/L)") - def get_mobility(self, solute: str) -> Quantity: + def _get_diffusion_coefficient(self, solute: str, activity_correction: bool = True, default: float = 0) -> Quantity: + """ + Get the **temperature-adjusted** diffusion coefficient of a solute. + + Args: + solute: the solute for which to retrieve the diffusion coefficient. + activity_correction: If True (default), adjusts the diffusion coefficient for the effects of ionic + strength using a model from Ref 2. + default: The diffusion coefficient value to assume if data for the chosen solute are not found in + the database. If None (default), a diffusion coefficient of 0 will be returned. + + Notes: + This method is equivalent to self.get_property(solute, "transport.diffusion_coefficient") + ONLY when the Solution temperature is the same as the reference temperature for the diffusion coefficient + in the database (usually 25 C). + + Otherwise, the reference D value is adjusted based on the Solution temperature and (optionally), ionic strength. + The adjustments are" + + .. math:: + + D_T = D_{298} \\exp(\\frac{d}{T} - \\frac{d}{298}) \\frac{\\nu_{298}}{\\nu_T} + + .. math:: + + D_{\\gamma} = D^0 \\exp(\\frac{-a1 A |z_i| \\sqrt{I}}{1+\\kappa a} + + .. math:: + + \\kappa a = B \\sqrt{I} \\frac{a2}{1+I^{0.75}} + + where a1, a2, and d are parameters from Ref. 2, A and B are the parameters used in the Debye Huckel equation, and + I is the ionic strength. If the model parameters for a particular solute are not available, + default values of d=0, a1=1.6, and a2=4.73 (as recommended in Ref. 2) are used instead. + + References: + 1. https://www.hydrochemistry.eu/exmpls/sc.html + 2. Appelo, C.A.J. Solute transport solved with the Nernst-Planck equation for concrete pores with `free' water and a double layer. Cement and Concrete Research 101, 2017. https://dx.doi.org/10.1016/j.cemconres.2017.08.030 + 3. CRC Handbook of Chemistry and Physics + + See Also: + pyEQL.activity_correction._debye_parameter_B + pyEQL.activity_correction._debye_parameter_activity + + """ + D = self.get_property(solute, "transport.diffusion_coefficient") + rform = standardize_formula(solute) + if D is None or D.magnitude == 0: + logger.info(f"Diffusion coefficient not found for species {rform}. Use default value of {default} m**2/s.") + D = ureg.Quantity(default, "m**2/s") + + # assume reference temperature is 298.15 K (this is the case for all current DB entries) + T_ref = 298.15 + mu_ref = 0.0008900225512925807 # water viscosity from IAPWS97 at 298.15 K + T_sol = self.temperature.to("K").magnitude + mu = self.water_substance.mu + + # skip temperature correction if within 1 degree + if abs(T_sol - T_ref) > 1 or activity_correction is True: + # get the a1, a2, and d parameters required by the PHREEQC model + try: + doc = self.database.query_one({"formula": rform}) + d = doc["model_parameters"]["diffusion_temp_smolyakov"]["d"]["value"] + a1 = doc["model_parameters"]["diffusion_temp_smolyakov"]["a1"]["value"] + a2 = doc["model_parameters"]["diffusion_temp_smolyakov"]["a2"]["value"] + # values will be a str, e.g. "1 dimensionless" + d = float(d.split(" ")[0]) + a1 = float(a1.split(" ")[0]) + a2 = float(a2.split(" ")[0]) + except TypeError: + # this means the database doesn't contain a d value. + # according to Ref 2, the following are recommended default parameters + logger.info( + f"Temperature and ionic strength correction parameters for solute {rform} diffusion " + "coefficient not in database. Using recommended default values of a1=1.6, a2=4.73, and d=0." + ) + d = 0 + a1 = 1.6 + a2 = 4.73 + + # use the PHREEQC model from Ref 2 to correct for temperature + D_final = D * np.exp(d / T_sol - d / T_ref) * mu_ref / mu + + if activity_correction: + A = _debye_parameter_activity(str(self.temperature)).to("kg**0.5/mol**0.5").magnitude / 2.303 + B = _debye_parameter_B(str(self.temperature)).to("1/angstrom * kg**0.5/mol**0.5").magnitude + z = self.get_property(solute, "charge") + IS = self.ionic_strength.magnitude + kappaa = B * IS**0.5 * a2 / (1 + IS**0.75) + # correct for ionic strength + D_final *= np.exp(-a1 * A * abs(z) * IS**0.5 / (1 + kappaa)) + # else: + # # per CRC handbook, D increases by 2-3% per degree above 25 C + # return D * (1 + 0.025 * (T_sol - T_ref)) + else: + D_final = D + + return D_final + + def _get_mobility(self, solute: str) -> Quantity: """ Calculate the ionic mobility of the solute. @@ -2281,7 +2336,7 @@ def get_mobility(self, solute: str) -> Quantity: .. [smed] Smedley, Stuart I. The Interpretation of Ionic Conductivity in Liquids. Plenum Press, 1980. """ - D = self.get_property(solute, "transport.diffusion_coefficient") + D = self.get_diffusion_coefficient(solute) mobility = ureg.N_A * ureg.e * abs(self.get_property(solute, "charge")) * D / (ureg.R * self.temperature) @@ -3224,3 +3279,113 @@ def get_salt_list(self): # pragma: no cover :py:meth:`get_salt_dict` """ return self.get_salt_dict() + + @classmethod + def from_preset( + cls, preset: Literal["seawater", "rainwater", "wastewater", "urine", "normal saline", "Ringers lactate"] + ) -> Solution: + """Instantiate a solution from a preset composition. + + Args: + preset (str): String representing the desired solution. + Valid entries are 'seawater', 'rainwater', 'wastewater', + 'urine', 'normal saline' and 'Ringers lactate'. + + Returns: + A pyEQL Solution object. + + Raises: + FileNotFoundError: If the given preset file doesn't exist on the file system. + + Notes: + The following sections explain the different solution options: + + - 'rainwater' - pure water in equilibrium with atmospheric CO2 at pH 6 + - 'seawater' or 'SW'- Standard Seawater. See Table 4 of the Reference for Composition [1]_ + - 'wastewater' or 'WW' - medium strength domestic wastewater. See Table 3-18 of [2]_ + - 'urine' - typical human urine. See Table 3-15 of [2]_ + - 'normal saline' or 'NS' - normal saline solution used in medicine [3]_ + - 'Ringers lacatate' or 'RL' - Ringer's lactate solution used in medicine [4]_ + + References: + .. [1] Millero, Frank J. "The composition of Standard Seawater and the definition of + the Reference-Composition Salinity Scale." *Deep-sea Research. Part I* 55(1), 2008, 50-72. + + .. [2] Metcalf & Eddy, Inc. et al. *Wastewater Engineering: Treatment and Resource Recovery*, 5th Ed. + McGraw-Hill, 2013. + + .. [3] https://en.wikipedia.org/wiki/Saline_(medicine) + + .. [4] https://en.wikipedia.org/wiki/Ringer%27s_lactate_solution + """ + # preset_dir = files("pyEQL") / "presets" + # Path to the YAML and JSON files corresponding to the preset + yaml_path = files("pyEQL") / "presets" / f"{preset}.yaml" + json_path = files("pyEQL") / "presets" / f"{preset}.json" + + # Check if the file exists + if yaml_path.exists(): + preset_path = yaml_path + elif json_path.exists(): + preset_path = json_path + else: + logger.error("Invalid solution entered - %s" % preset) + raise FileNotFoundError(f"Files '{yaml_path}' and '{json_path} not found!") + + # Create and return a Solution object + return cls().from_file(preset_path) + + def to_file(self, filename: str | Path) -> None: + """Saving to a .yaml or .json file. + + Args: + filename (str | Path): The path to the file to save Solution. + Valid extensions are .json or .yaml. + """ + str_filename = str(filename) + if not ("yaml" in str_filename.lower() or "json" in str_filename.lower()): + logger.error("Invalid file extension entered - %s" % str_filename) + raise ValueError("File extension must be .json or .yaml") + if "yaml" in str_filename.lower(): + solution_dict = self.as_dict() + solution_dict.pop("database") + dumpfn(solution_dict, filename) + else: + dumpfn(self, filename) + + def from_file(self, filename: str | Path) -> Solution: + """Loading from a .yaml or .json file. + + Args: + filename (str | Path): Path to the .json or .yaml file (including extension) to load the Solution from. + Valid extensions are .json or .yaml. + + Returns: + A pyEQL Solution object. + + Raises: + FileNotFoundError: If the given filename doesn't exist on the file system. + """ + if not os.path.exists(filename): + logger.error("Invalid path to file entered - %s" % filename) + raise FileNotFoundError(f"File '{filename}' not found!") + str_filename = str(filename) + if "yaml" in str_filename.lower(): + true_keys = [ + "solutes", + "volume", + "temperature", + "pressure", + "pH", + "pE", + "balance_charge", + "solvent", + "engine", + # "database", + ] + solution_dict = loadfn(filename) + keys_to_delete = [key for key in solution_dict if key not in true_keys] + for key in keys_to_delete: + solution_dict.pop(key) + return Solution(**solution_dict) + return loadfn(filename) diff --git a/src/pyEQL/utils.py b/src/pyEQL/utils.py index 52d70a6e..30792fd0 100644 --- a/src/pyEQL/utils.py +++ b/src/pyEQL/utils.py @@ -9,8 +9,11 @@ from collections import UserDict from functools import lru_cache +from iapws import IAPWS95, IAPWS97 from pymatgen.core.ion import Ion +from pyEQL import ureg + @lru_cache def standardize_formula(formula: str): @@ -56,6 +59,29 @@ def format_solutes_dict(solute_dict: dict, units: str): return {key: f"{value!s} {units}" for key, value in solute_dict.items()} +@lru_cache +@ureg.wraps(ret=None, args=["K", "MPa"], strict=False) +def create_water_substance(temperature: float, pressure: float): + """ + Instantiate a water substance model from IAPWS + + Args: + temperature: the desired temperature in K + pressure: the desired pressure in MPa + + Notes: + The IAPWS97 model is much faster than IAPWS95, but the latter can do temp + below zero. See https://github.com/jjgomera/iapws/issues/14. Hence, + IAPWS97 will be used except when `temperature` is less than 0 degC. + + Returns: + A IAPWS97 or IAPWS95 instance + """ + if temperature >= 273.15: + return IAPWS97(T=temperature, P=pressure) + return IAPWS95(T=temperature, P=pressure) + + class FormulaDict(UserDict): """ Automatically converts keys on get/set using pymatgen.core.Ion.from_formula(key).reduced_formula. diff --git a/tests/test_activity.py b/tests/test_activity.py index 5f91dbbf..a4dc460e 100644 --- a/tests/test_activity.py +++ b/tests/test_activity.py @@ -14,6 +14,7 @@ import numpy as np import pytest +from pyEQL.activity_correction import _debye_parameter_activity, _debye_parameter_B from pyEQL.solution import Solution ## Tests of the pitzer model @@ -52,6 +53,13 @@ def test_units_and_equality(): assert a1 == a2 +def test_debye_params(): + # tests of the various Debye Huckel parameters + # A should be equal to 0.509 at 25 C, for log base 10 + assert np.isclose(_debye_parameter_activity().magnitude / 2.303, 0.509, atol=1e-3) + assert np.isclose(_debye_parameter_B().to("nm**-1 * kg**0.5/mol**0.5").magnitude, 3.29, atol=1e-2) + + def test_activity_crc_HCl(): """ calculate the activity coefficient of HCl at each concentration and compare diff --git a/tests/test_functions.py b/tests/test_functions.py new file mode 100644 index 00000000..6816b212 --- /dev/null +++ b/tests/test_functions.py @@ -0,0 +1,85 @@ +""" +Tests of pyEQL.functions module + +""" +import numpy as np +import pytest + +from pyEQL import Solution +from pyEQL.functions import entropy_mix, gibbs_mix + + +@pytest.fixture() +def s1(): + return Solution(volume="2 L") + + +@pytest.fixture() +def s2(): + return Solution({"Na+": "1 mol/L", "Cl-": "1 mol/L"}, volume="10 L") + + +@pytest.fixture() +def s1_p(): + return Solution(volume="2 L", engine="phreeqc") + + +@pytest.fixture() +def s2_p(): + return Solution({"Na+": "1 mol/L", "Cl-": "1 mol/L"}, volume="10 L", engine="phreeqc") + + +@pytest.fixture() +def s1_i(): + return Solution(volume="2 L", engine="ideal") + + +@pytest.fixture() +def s2_i(): + return Solution({"Na+": "1 mol/L", "Cl-": "1 mol/L"}, volume="10 L", engine="ideal") + + +def test_mixing_functions(s1, s2, s1_p, s2_p, s1_i, s2_i): + # mixing energy and entropy of any solution with itself should be zero + assert np.isclose(gibbs_mix(s1, s1).magnitude, 0) + assert np.isclose(entropy_mix(s2, s2).magnitude, 0) + assert np.isclose(gibbs_mix(s1_p, s1_p).magnitude, 0) + assert np.isclose(entropy_mix(s2_p, s2_p).magnitude, 0) + assert np.isclose(gibbs_mix(s1_i, s1_i).magnitude, 0, atol=1e-6) + assert np.isclose(entropy_mix(s2_i, s2_i).magnitude, 0) + + # TODO - I have not tested how equilibrate() affects the results + for dil, conc in zip([s1, s1_p, s1_i], [s2, s2_p, s2_i]): + # for mixing 1 and 2, we should have + # H20: 55.5 * 2 mol + 55.5 * 10 mol, x1 = 0.9999 x2 = 0.9645, mixture = 0.9703 = approximately -9043 J + s_theoretical = ( + 8.314 + * 298.15 + * ( + (dil + conc).get_amount("H2O", "mol").magnitude + * np.log((dil + conc).get_amount("H2O", "fraction").magnitude) + + (dil + conc).get_amount("Na+", "mol").magnitude + * np.log((dil + conc).get_amount("Na+", "fraction").magnitude) + + (dil + conc).get_amount("Cl-", "mol").magnitude + * np.log((dil + conc).get_amount("Cl-", "fraction").magnitude) + - dil.get_amount("H2O", "mol").magnitude * np.log(dil.get_amount("H2O", "fraction").magnitude) + - conc.get_amount("H2O", "mol").magnitude * np.log(conc.get_amount("H2O", "fraction").magnitude) + - conc.get_amount("Na+", "mol").magnitude * np.log(conc.get_amount("Na+", "fraction").magnitude) + - conc.get_amount("Cl-", "mol").magnitude * np.log(conc.get_amount("Cl-", "fraction").magnitude) + ) + ) + assert np.isclose(entropy_mix(dil, conc).magnitude, s_theoretical, rtol=0.005) + g_theoretical = ( + 8.314 + * 298.15 + * ( + (dil + conc).get_amount("H2O", "mol").magnitude * np.log((dil + conc).get_activity("H2O").magnitude) + + (dil + conc).get_amount("Na+", "mol").magnitude * np.log((dil + conc).get_activity("Na+").magnitude) + + (dil + conc).get_amount("Cl-", "mol").magnitude * np.log((dil + conc).get_activity("Cl-").magnitude) + - dil.get_amount("H2O", "mol").magnitude * np.log(dil.get_activity("H2O").magnitude) + - conc.get_amount("H2O", "mol").magnitude * np.log(conc.get_activity("H2O").magnitude) + - conc.get_amount("Na+", "mol").magnitude * np.log(conc.get_activity("Na+").magnitude) + - conc.get_amount("Cl-", "mol").magnitude * np.log(conc.get_activity("Cl-").magnitude) + ) + ) + assert np.isclose(gibbs_mix(dil, conc).magnitude, g_theoretical, rtol=0.005) diff --git a/tests/test_mixed_electrolyte_activity.py b/tests/test_mixed_electrolyte_activity.py index 5a5d4f7f..6a60852e 100644 --- a/tests/test_mixed_electrolyte_activity.py +++ b/tests/test_mixed_electrolyte_activity.py @@ -54,7 +54,6 @@ def test_activity_Na_XNa_75(self): assert np.isclose(result, expected[item], RTOL) - @pytest.mark.xfail() def test_activity_K_XNa_75(self): # test the activity coefficient of Na+ in mixed NaNO3 and KNO3 when the # mole fraction of Na+ is 0.75 diff --git a/tests/test_osmotic_coeff.py b/tests/test_osmotic_coeff.py index 9c19bcbc..d4d50a01 100644 --- a/tests/test_osmotic_coeff.py +++ b/tests/test_osmotic_coeff.py @@ -11,7 +11,7 @@ import numpy as np -import pyEQL +from pyEQL import Solution def test_osmotic_pressure(): @@ -21,9 +21,9 @@ def test_osmotic_pressure(): # TODO - at present this test is inaccurate because in the complex matrix # of seawater, pyEQL falls back to using an ideal solution model with # unit osmotic coefficient. - empty = pyEQL.Solution() + empty = Solution() assert np.isclose(empty.osmotic_pressure.to("atm").magnitude, 0, atol=1e-5) - sea = pyEQL.autogenerate("seawater") + sea = Solution.from_preset("seawater") assert np.isclose(sea.osmotic_pressure.to("atm").magnitude, 27, rtol=0.15) @@ -35,7 +35,7 @@ class Test_osmotic_pitzer: """ def test_dimensionality(self): - s1 = pyEQL.Solution([["Na+", "0.1 mol/L"], ["Cl-", "0.1 mol/L"]]) + s1 = Solution([["Na+", "0.1 mol/L"], ["Cl-", "0.1 mol/L"]]) assert s1.get_osmotic_coefficient().dimensionality == "" assert s1.get_osmotic_coefficient() >= 0 @@ -59,7 +59,7 @@ def test_osmotic_pitzer_ammoniumnitrate(self): for i, conc in enumerate(conc_list): conc = str(conc) + "mol/kg" - sol = pyEQL.Solution() + sol = Solution() sol.add_solute("NH4+", conc) sol.add_solute("NO3-", conc) result = sol.get_osmotic_coefficient() @@ -87,7 +87,7 @@ def test_osmotic_pitzer_coppersulfate(self): for i, conc in enumerate(conc_list): conc = str(conc) + "mol/kg" - sol = pyEQL.Solution() + sol = Solution() sol.add_solute("Cu+2", conc) sol.add_solute("SO4-2", conc) result = sol.get_osmotic_coefficient() diff --git a/tests/test_phreeqc.py b/tests/test_phreeqc.py index e028a353..bf6942d1 100644 --- a/tests/test_phreeqc.py +++ b/tests/test_phreeqc.py @@ -6,6 +6,8 @@ used by pyEQL's Solution class """ +import logging + import numpy as np import pytest @@ -37,7 +39,9 @@ def s5(): @pytest.fixture() def s5_pH(): # 100 mg/L as CaCO3 ~ 1 mM - return Solution([["Ca+2", "40.078 mg/L"], ["CO3-2", "60.0089 mg/L"]], volume="1 L", balance_charge="pH") + return Solution( + [["Ca+2", "40.078 mg/L"], ["CO3-2", "60.0089 mg/L"]], volume="1 L", balance_charge="pH", engine="phreeqc" + ) @pytest.fixture() @@ -56,6 +60,7 @@ def s6(): ["Br-", "20 mM"], ], # -20 meq/L volume="1 L", + engine="phreeqc", ) @@ -76,6 +81,7 @@ def s6_Ca(): ], # -20 meq/L volume="1 L", balance_charge="Ca+2", + engine="phreeqc", ) @@ -113,34 +119,54 @@ def test_init_engines(): # with pytest.warns(match="Solute Mg+2 not found"): assert s.get_activity_coefficient("Mg+2").magnitude == 1 assert s.get_activity("Mg+2").magnitude == 0 + s.engine._destroy_ppsol() + assert s.engine.ppsol is None -def test_conductivity(s1, s2): +def test_conductivity(s1): # even an empty solution should have some conductivity assert s1.conductivity > 0 - # per CRC handbook "standard Kcl solutions for calibratinG conductiVity cells", 0.1m KCl has a conductivity of 12.824 mS/cm at 25 C + + for conc, cond in zip([0.001, 0.05, 0.1], [123.68, 111.01, 106.69]): + s1 = Solution({"Na+": f"{conc} mol/L", "Cl-": f"{conc} mol/L"}) + assert np.isclose( + s1.conductivity.to("S/m").magnitude, conc * cond / 10, atol=0.5 + ), f"Conductivity test failed for NaCl at {conc} mol/L. Result = {s1.conductivity.to('S/m').magnitude}" + + # higher concentration data points from Appelo, 2017 Figure 4. + s1 = Solution({"Na+": "2 mol/kg", "Cl-": "2 mol/kg"}) + assert np.isclose(s1.conductivity.to("mS/cm").magnitude, 145, atol=10) + + # MgCl2 + for conc, cond in zip([0.001, 0.05, 0.1], [124.15, 114.49, 97.05]): + s1 = Solution({"Mg+2": f"{conc} mol/L", "Cl-": f"{2*conc} mol/L"}) + assert np.isclose( + s1.conductivity.to("S/m").magnitude, 2 * conc * cond / 10, atol=1 + ), f"Conductivity test failed for MgCl2 at {conc} mol/L. Result = {s1.conductivity.to('S/m').magnitude}" + + # per CRC handbook "standard KCl solutions for calibrating conductiVity cells", + # 0.1m KCl has a conductivity of 12.824 mS/cm at 25 C s_kcl = Solution({"K+": "0.1 mol/kg", "Cl-": "0.1 mol/kg"}) assert np.isclose(s_kcl.conductivity.magnitude, 1.2824, atol=0.02) # conductivity is in S/m - # TODO - expected failures due to limited temp adjustment of diffusion coeff - # s_kcl.temperature = '5 degC' - # assert np.isclose(s_kcl.conductivity.magnitude, 0.81837, atol=0.02) + s_kcl.temperature = "5 degC" + assert np.isclose(s_kcl.conductivity.magnitude, 0.81837, atol=0.06) - # s_kcl.temperature = '50 degC' - # assert np.isclose(s_kcl.conductivity.magnitude, 1.91809, atol=0.02) + s_kcl.temperature = "50 degC" + assert np.isclose(s_kcl.conductivity.magnitude, 1.91809, atol=0.18) # TODO - conductivity model not very accurate at high conc. s_kcl = Solution({"K+": "1 mol/kg", "Cl-": "1 mol/kg"}) - assert np.isclose(s_kcl.conductivity.magnitude, 10.862, rtol=0.2) + assert np.isclose(s_kcl.conductivity.magnitude, 10.862, rtol=0.05) -def test_equilibrate(s1, s2, s5_pH): +def test_equilibrate(s1, s2, s5_pH, s6_Ca, caplog): assert "H2(aq)" not in s1.components orig_pH = s1.pH orig_pE = s1.pE s1.equilibrate() assert "H2(aq)" in s1.components - assert np.isclose(s1.charge_balance, 0, atol=1e-7) + assert np.isclose(s1.charge_balance, 0, atol=1e-8) assert np.isclose(s1.pH, orig_pH, atol=0.01) assert np.isclose(s1.pE, orig_pE) @@ -157,9 +183,23 @@ def test_equilibrate(s1, s2, s5_pH): assert np.isclose(s2.get_total_amount("Cl", "mol").magnitude, 8) assert np.isclose(s2.solvent_mass.magnitude, orig_solv_mass) assert np.isclose(s2.density.magnitude, orig_density) - assert np.isclose(s2.charge_balance, 0, atol=1e-7) + # this solution has balance_charge=None, therefore, the charge balance + # may be off after equilibration + assert not np.isclose(s2.charge_balance, 0, atol=1e-8) assert np.isclose(s2.pH, orig_pH, atol=0.01) assert np.isclose(s2.pE, orig_pE) + s2.balance_charge = "pH" + s2.equilibrate() + assert np.isclose(s2.charge_balance, 0, atol=1e-8) + + # test log message if there is a species not present in the phreeqc database + s_zr = Solution({"Zr+4": "0.05 mol/kg", "Na+": "0.05 mol/kg", "Cl-": "0.1 mol/kg"}, engine="phreeqc") + totzr = s_zr.get_total_amount("Zr", "mol") + with caplog.at_level(logging.INFO, "pyEQL.logging_system"): + s_zr.equilibrate() + assert "likely absent from its database" in caplog.text + assert "Zr[+4]" in s_zr.components + assert s_zr.get_total_amount("Zr", "mol") == totzr # this solution is the only one in the test that contains alkalinity # and equilibrating it results in a shift in the pH @@ -184,3 +224,11 @@ def test_equilibrate(s1, s2, s5_pH): assert "HCO3[-1]" in s5_pH.components assert s5_pH.pH > orig_pH assert np.isclose(s5_pH.pE, orig_pE) + + # test equilibrate() with a non-pH balancing species + assert np.isclose(s6_Ca.charge_balance, 0, atol=1e-8) + initial_Ca = s6_Ca.get_total_amount("Ca", "mol").magnitude + assert s6_Ca.balance_charge == "Ca[+2]" + s6_Ca.equilibrate() + assert s6_Ca.get_total_amount("Ca", "mol").magnitude != initial_Ca + assert np.isclose(s6_Ca.charge_balance, 0, atol=1e-8) diff --git a/tests/test_solute_properties.py b/tests/test_solute_properties.py index 29748b66..a767fabe 100644 --- a/tests/test_solute_properties.py +++ b/tests/test_solute_properties.py @@ -14,6 +14,7 @@ """ import numpy as np + from pyEQL import Solution, ureg # relative tolerance between experimental and computed properties for this test file @@ -83,7 +84,7 @@ def test_molar_conductivity_magnesium(self): result = s1.get_molar_conductivity("Mg+2").to("m**2*S/mol").magnitude expected = ureg.Quantity("106e-4 m**2 * S / mol").magnitude - assert np.isclose(result, expected, rtol=RTOL) + assert np.isclose(result, expected, atol=0.005) def test_molar_conductivity_chloride(self): # Cl- - 76.31 x 10 ** -4 m ** 2 S / mol @@ -107,7 +108,7 @@ def test_molar_conductivity_sulfate(self): result = s1.get_molar_conductivity("SO4-2").to("m**2*S/mol").magnitude expected = ureg.Quantity("160.0e-4 m**2 * S / mol").magnitude - assert np.isclose(result, expected, rtol=RTOL) + assert np.isclose(result, expected, atol=0.002) def test_molar_conductivity_hydroxide(self): # OH- - 198 x 10 ** -4 m ** 2 S / mol @@ -129,7 +130,7 @@ def test_molar_conductivity_hydrogen(self): def test_molar_conductivity_neutral(self): s1 = Solution([["FeCl3", "0.001 mol/L"]], temperature="25 degC") result = s1.get_molar_conductivity("FeCl3").to("m**2*S/mol").magnitude - expected = ureg.Quantity("0 m**2 * S / mol").magnitude + expected = ureg.Quantity(0, "m**2 * S / mol").magnitude assert round(abs(result - expected), 5) == 0 @@ -137,7 +138,7 @@ def test_molar_conductivity_neutral(self): def test_molar_conductivity_water(self): s1 = Solution(temperature="25 degC") result = s1.get_molar_conductivity("H2O").to("m**2*S/mol").magnitude - expected = ureg.Quantity("0 m**2 * S / mol").magnitude + expected = ureg.Quantity(0, "m**2 * S / mol").magnitude assert round(abs(result - expected), 5) == 0 diff --git a/tests/test_solution.py b/tests/test_solution.py index 92498de6..dbcea437 100644 --- a/tests/test_solution.py +++ b/tests/test_solution.py @@ -7,9 +7,12 @@ """ import copy +import os +from pathlib import Path import numpy as np import pytest +import yaml from pyEQL import Solution, ureg from pyEQL.engines import IdealEOS, NativeEOS @@ -109,14 +112,54 @@ def test_empty_solution_3(): assert set(s1.components.keys()) == {"H2O(aq)", "OH[-1]", "H[+1]"} -def test_diffusion_transport(s2): - d25 = s2.get_property("Na+", "transport.diffusion_coefficient").magnitude - assert np.isclose(d25, 1.334e-9) - assert np.isclose(s2.get_transport_number("Na+"), 0.396, atol=1e-3) - assert np.isclose(s2.get_transport_number("Cl-"), 0.604, atol=1e-3) +def test_diffusion_transport(s1, s2): + # test ionic strength adjustment + assert s1.get_diffusion_coefficient("H+") > s2.get_diffusion_coefficient("H+") + + # for Na+, d=122, a1=1.52, a2=3.7, A=1.173802/2.303 at 25 DegC, B = 3.2843078+10 + factor = np.exp( + -1.52 + * 1.173802 + / 2.303 + * 1 + * np.sqrt(s2.ionic_strength.magnitude) + / (1 + 3.2843078e10 * np.sqrt(s2.ionic_strength.magnitude) * 3.7 / (1 + s2.ionic_strength.magnitude**0.75)) + ) + assert np.isclose( + factor * s2.get_diffusion_coefficient("Na+").magnitude, + s2.get_diffusion_coefficient("Na+").magnitude, + atol=5e-11, + ) + s_dilute = Solution({"Na+": "1 mmol/L", "Cl-": "1 mmol/L"}) + assert np.isclose( + s_dilute.get_diffusion_coefficient("Na+", activity_correction=False).magnitude, 1.334e-9, atol=1e-12 + ) + assert np.isclose(s_dilute.get_transport_number("Na+"), 0.396, atol=1e-3) + assert np.isclose(s_dilute.get_transport_number("Cl-"), 0.604, atol=1e-3) + + # test setting a default value + assert s2.get_diffusion_coefficient("Cs+").magnitude == 0 + assert s2.get_diffusion_coefficient("Cs+", default=1e-9, activity_correction=False).magnitude == 1e-9 + assert s2.get_diffusion_coefficient("Cs+", default=1e-9, activity_correction=True).magnitude < 1e-9 + d25 = s2.get_diffusion_coefficient("Na+", activity_correction=False).magnitude + nu25 = s2.water_substance.nu s2.temperature = "40 degC" - d40 = s2.get_property("Na+", "transport.diffusion_coefficient").magnitude - assert np.isclose(d40, d25 * 40 / 25) + d40 = s2.get_diffusion_coefficient("Na+", activity_correction=False).magnitude + nu40 = s2.water_substance.nu + assert np.isclose( + d40, + d25 * np.exp(122 / (273.15 + 40) - 122 / 298.15) * (nu25 / nu40), + atol=5e-11, + ) + + # test correction factors for concentration, as per Appelo 2017 Fig 5 + D1 = Solution({"Na+": "1 umol/L", "Cl-": "1 umol/L"}).get_diffusion_coefficient("Na+").magnitude + D2 = Solution({"Na+": "1.7 mol/kg", "Cl-": "1.7 mol/kg"}).get_diffusion_coefficient("Na+").magnitude + assert np.isclose(D2 / D1, 0.54, atol=1e-2) + + D1 = Solution({"K+": "1 umol/L", "Cl-": "1 umol/L"}).get_diffusion_coefficient("K+").magnitude + D2 = Solution({"K+": "0.5 mol/kg", "Cl-": "0.5 mol/kg"}).get_diffusion_coefficient("K+").magnitude + assert np.isclose(D2 / D1, 0.80, atol=1e-2) def test_init_raises(): @@ -414,24 +457,48 @@ def test_tds(s1, s2, s5): def test_conductivity(s1, s2): - # even an empty solution should have some conductivity - assert s1.conductivity > 0 - s_nacl = Solution({"Na+": "2298 mg/L", "Cl-": "3544 ppm"}) - assert np.isclose(s_nacl.conductivity.to("mS/cm").magnitude, 10, atol=1) # conductivity ~ 10 mS/cm - # per CRC handbook "standard Kcl solutions for calibratinG conductiVity cells", 0.1m KCl has a conductivity of 12.824 mS/cm at 25 C + # per CRC handbook - "electrical conductiVity of Water" , conductivity of pure water + # at 25 and 100 C is 0.0550 and 0.765 uS/cm + assert np.isclose(s1.conductivity.to("uS/cm").magnitude, 0.055, atol=1e-3) + + # TODO - seems to be a possible bug related to setting temperature here + # s1.temperature = "100 degC" + # s2 = Solution(temperature='100 degC') + # assert np.isclose(s1.conductivity.to('uS/cm').magnitude, 0.765, atol=1e-3) + + # CRC handbook table - "equivalent conductivity of electrolytes in aqueous solution" + # nacl + for conc, cond in zip([0.001, 0.05, 0.1], [123.68, 111.01, 106.69]): + s1 = Solution({"Na+": f"{conc} mol/L", "Cl-": f"{conc} mol/L"}) + assert np.isclose( + s1.conductivity.to("S/m").magnitude, conc * cond / 10, atol=0.5 + ), f"Conductivity test failed for NaCl at {conc} mol/L. Result = {s1.conductivity.to('S/m').magnitude}" + + # higher concentration data points from Appelo, 2017 Figure 4. + s1 = Solution({"Na+": "2 mol/kg", "Cl-": "2 mol/kg"}) + assert np.isclose(s1.conductivity.to("mS/cm").magnitude, 145, atol=10) + + # MgCl2 + for conc, cond in zip([0.001, 0.05, 0.1], [124.15, 114.49, 97.05]): + s1 = Solution({"Mg+2": f"{conc} mol/L", "Cl-": f"{2*conc} mol/L"}) + assert np.isclose( + s1.conductivity.to("S/m").magnitude, 2 * conc * cond / 10, atol=1 + ), f"Conductivity test failed for MgCl2 at {conc} mol/L. Result = {s1.conductivity.to('S/m').magnitude}" + + # per CRC handbook "standard KCl solutions for calibrating conductivity cells", 0.1m KCl has a conductivity of 12.824 mS/cm at 25 C s_kcl = Solution({"K+": "0.1 mol/kg", "Cl-": "0.1 mol/kg"}) - assert np.isclose(s_kcl.conductivity.magnitude, 1.2824, atol=0.02) # conductivity is in S/m + assert np.isclose(s_kcl.conductivity.magnitude, 1.2824, atol=0.25) # conductivity is in S/m # TODO - expected failures due to limited temp adjustment of diffusion coeff - # s_kcl.temperature = '5 degC' - # assert np.isclose(s_kcl.conductivity.magnitude, 0.81837, atol=0.02) + s_kcl.temperature = "5 degC" + assert np.isclose(s_kcl.conductivity.magnitude, 0.81837, atol=0.2) - # s_kcl.temperature = '50 degC' - # assert np.isclose(s_kcl.conductivity.magnitude, 1.91809, atol=0.02) + s_kcl.temperature = "50 degC" + assert np.isclose(s_kcl.conductivity.magnitude, 1.91809, atol=0.2) # TODO - conductivity model not very accurate at high conc. s_kcl = Solution({"K+": "1 mol/kg", "Cl-": "1 mol/kg"}) - assert np.isclose(s_kcl.conductivity.magnitude, 10.862, rtol=0.2) + assert np.isclose(s_kcl.conductivity.magnitude, 10.862, atol=0.45) def test_arithmetic_and_copy(s2, s6): @@ -450,6 +517,9 @@ def test_arithmetic_and_copy(s2, s6): with pytest.raises(NotImplementedError): s6 - s6_scale + # confirm that a copied solution can be equilibrated + s6_scale.equilibrate() + # TODO - test pH and pE s2.temperature = "35 degC" s2.pressure = "1.1 atm" @@ -576,3 +646,48 @@ def test_serialization(s1, s2, tmpdir): # also should point to different Store instances # TODO currently this test will fail due to a bug in maggma's __eq__ # assert s2_new.database != s2.database + + +def test_from_preset(tmpdir): + from monty.serialization import dumpfn + + preset_name = "seawater" + solution = Solution.from_preset(preset_name) + with open(os.path.join("src/pyEQL/presets", f"{preset_name}.yaml")) as file: + data = yaml.load(file, Loader=yaml.FullLoader) + # test valid preset + assert isinstance(solution, Solution) + assert solution.temperature.to("degC") == ureg.Quantity(data["temperature"]) + assert solution.pressure == ureg.Quantity(data["pressure"]) + assert np.isclose(solution.pH, data["pH"], atol=0.01) + for solute in solution._solutes: + assert solute in data["solutes"] + # test invalid preset + with pytest.raises(FileNotFoundError): + Solution.from_preset("nonexistent_preset") + # test json as preset + tmp_path = Path(tmpdir) + json_preset = tmp_path / "test.json" + dumpfn(solution, json_preset) + solution_json = Solution.from_preset(tmp_path / "test") + assert isinstance(solution_json, Solution) + assert solution_json.temperature.to("degC") == ureg.Quantity(data["temperature"]) + assert solution_json.pressure == ureg.Quantity(data["pressure"]) + assert np.isclose(solution_json.pH, data["pH"], atol=0.01) + + +def test_test_to_from_file(tmpdir, s1): + tmp_path = Path(tmpdir) + for f in ["test.json", "test.yaml"]: + filename = tmp_path / f + s1.to_file(filename) + assert filename.exists() + loaded_s1 = Solution().from_file(filename) + assert loaded_s1 is not None + assert pytest.approx(loaded_s1.volume.to("L").magnitude) == s1.volume.to("L").magnitude + # test invalid extension raises error + filename = tmp_path / "test_solution.txt" + with pytest.raises(ValueError, match=r"File extension must be .json or .yaml"): + s1.to_file(filename) + with pytest.raises(FileNotFoundError, match=r"File .* not found!"): + Solution().from_file(filename) diff --git a/tests/test_utils.py b/tests/test_utils.py index d2cfad37..b6b48802 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -2,9 +2,11 @@ Tests of pyEQL.utils module """ +from iapws import IAPWS95, IAPWS97 from pytest import raises -from pyEQL.utils import FormulaDict, format_solutes_dict, standardize_formula +from pyEQL import ureg +from pyEQL.utils import FormulaDict, create_water_substance, format_solutes_dict, standardize_formula def test_standardize_formula(): @@ -50,3 +52,8 @@ def test_format_solute(): error_msg = "solute_dict must be a dictionary. Refer to the doc for proper formatting." with raises(TypeError, match=error_msg): format_solutes_dict(bad_test, units="mol/kg") + + +def test_create_water_substance(): + assert isinstance(create_water_substance(300, 0.1), IAPWS97) + assert isinstance(create_water_substance(ureg.Quantity(-15, "degC"), 0.1), IAPWS95) diff --git a/tox.ini b/tox.ini index 50306db2..597b3bd3 100644 --- a/tox.ini +++ b/tox.ini @@ -3,8 +3,8 @@ # THIS SCRIPT IS SUPPOSED TO BE AN EXAMPLE. MODIFY IT ACCORDING TO YOUR NEEDS! [tox] -minversion = 3.15 -envlist = {py38,py39,py310,py11}-{linux,windows,macos} +minversion = 4.11 +envlist = {py39,py310,py11,py312}-{linux,windows,macos} [testenv]