All notable changes to this project will be documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
Solution.get_total_amount
: Bugfix that caused an error when called on certain elements without specifying an oxidation state. For example,get_total_amount('N')
could raise an exception in a solution containingNa
(but noN
) due to a flaw in a logical test.Solution._adjust_charge_balance
: Removed a misleading and redundant log message (#162, @SuixiongTay)
gibbs_mix
: A new keyword argumentactivity_correction
was added togibbs_mix
. It defaults toTrue
(no change from prior behavior), but can be set toFalse
in order to calculate the ideal mixing energy, which is equivalent to only considering entropic effects. (#178, @Jaebeom-P)standardize_formula
: Improve formatting of ammonium sulfate salts. Aqueous ammonium sulfate previously standardized toH8S(NO2)2(aq)
, now it will display as(NH4)2SO4(aq)
.
- BREAKING
entropy_mix
now returns the ideal mixing entropy in units of J/K rather than the mixing energy in J. This was done to improve clarity with respect to the function name. Anactivity_correction
kwarg was added togibbs_mix
so that you can still calculate the ideal mixing energy by setting it toFalse
. (#178, @Jaebeom-P) - Revise documentation of
gibbs_mix
,entropy_mix
, anddonnan_eql
. (#178, @Jaebeom-P) - CI: Improve comprehensiveness of CI dependency testing. (#163, #164, @abhardwaj73)
Solution
: Hotfix to remove a strayassert
statement in_adjust_charge_balance
that would sometimes cause errors inpH
charge balancing.
Solution
: Fix a bug inpH
charge balancing that erroneously prevented charge balancing from occurring in certain cases, and raised an error.
Solution
: Fix a bug in which settingbalance_charge
topH
could result in negative concentration errors when charge balancing or afterequilibrate
was called.Solution
now correctly enforces the ion product of water (Kw=1e-14) whenever adjusting the amounts of H+ or OH- for charge balancing.
Solution._adjust_charge_balance
: Added a privat helper method to consolidate charge balancing code used in__init__
andequilibrate
.
Solution
: Fix a bug in which settingbalance_charge
toauto
when the initial composition was electroneutral would cause errors and/or improper charge balancing afterequilibrate
was called.
equilibrate
: Fixed a bug that could cause anAttributeError
when pH was used for charge balancing.- Database:
size.radius_ionic
was missing units forNi[+2]
andCr[+3]
. Correct units have been added.
Solution
: New automatic charge balancing method will automatically identify the majority (highest concentration) cation or anion as appropriate (depending on the charge balance) for charge balancing. To use this mode, setbalance_charge='auto'
when instantiating aSolution
.
Solution.add_amount
: This method will now add solutes that are absent from the Solution. Previously, calling, e.g.,add_amount('Na+', '1 mol')
on aSolution
that did not contain any sodium would result in an error. A warning is logged if the method has to add a new solute.- Units: use the upstream chemistry context from
pint
instead of the custom one from 2013. pre-commit autoupdate
- Misc. linting and code quality improvements.
- Unit tests: update
tmpdir
totmp_path
text fixture. - CI: Small updates to pre-commit and GitHub actions per scientific python repo review.
standardize_formula
: Fix incorrect display of additional formulas, including methane which was shown as "H4C(aq)", other tri-anions (N3-, P3-), and a variety of haloacetic acids. For example, tricholoracetic acid was previously shown as'C2Cl3O2[-1]'
but will now display as'CCl3COO[-1]'
.
standardize_formula
:pyEQL
can now parse ion formulas that contain unicode superscript or subscript characters, which makes input even more flexible. For example,"PO₄³⁻"
and"Co²⁺"
will now standardize correctly to"PO4[-3]"
and"Co[+2]"
, respectively.
- Housekeeping: move all project configuration to
pyproject.toml
standardize_formula
: Fix incorrect display of ammonium/ammonia. Previously, their formulas were shown as "H4N[+1]" and "H3N(aq)", respectively. They now correctly display as NH4 and NH3. Similar fixes were implemented for HPO4[-2] / H2PO4[-1] / H3PO4, formate (HCOO[-1]), oxalate (C2O4[-2]), thicyanate (SCN[-1]), and triiodide (I3[-1]). Fixes #136 (@xiaoxiaozhu123)
- Added
NPY201
ruleset toruff
configuration to check support fornumpy
2.0
NativeEOS
andPHREEQCEOS
equilibrate
: Fixed a charge balancing bug that cause repeated calls toequlibrate
to severely distort the pH and/or the composition. (#141)[KingsburyLab#141]UnicodeDecodeError
when trying to connect to ion database on non-English platforms (#122)
- Replace
math
withnumpy
functions throughout. This mainly changed calls tolog
andexp
. - Docs: Fix missing close parentheses in docstring (@Andrew S. Rosen)
Solution.__init__
: new keyword argumentlog_level
allows user to control the verbosity of log messages by setting the level (e.g., ERROR, WARNING, etc.) that will be shown in stdout.- Docs: added a note about a workaround for Apple M1/M2 Macs proposed by @xiaoxiaozhu123
Solution.__init__
: The deprecated format for specifying solutes (e.g.,[["Na+", "0.5 mol/L]]
) which previously only generated log warning message, now raises aDeprecationWarning
. Use dict-style input (e.g.,{"Na+":"0.5 mol/L"}
) instead.- New logo! Updated the
pyEQL
logo (for the first time in 9 years!) to address an obsolete font in the .svg and modernize the design.
- BREAKING All methods and functions (with the exception of
Solution.list_XXX
methods) previously marked with deprecation warnings have been removed.
Solution.get_total_amount
: Fixed an issue in whichppm
units would fail.
utils.interpret_units
: New method to "sanitize" environmental engineering units like ppm to strings thatpint
can understand, e.g. ppm -> mg/L. This method is now used inget_amount
andget_total_amount
to ensure consistency in how they process units.
- CI:
pre-commit autoupdate
Solution
: Fixed an issue in which repeated calls toequilibrate
when usingNativeEOS
orPHREEQCEOS
would change the mass of theSolution
slightly. This was attributed to the fact thatpyEQL
andPHREEQC
use slightly different molecular weights for water.Solution
:get_total_amount
and related methods could fail when the oxidation state of an element was unknown (e.g., 'Br') (Issue #116)
NativeEOS
/PhreeqcEOS
: Addedtry
/catch
so thatpyEQL
can still be used on platforms that PHREEQC does not support, such as Apple Silicon. In such cases, functions likeequilibrate
that depend on PHREEQC will raise errors, but everything else can still be used.- CI: Added Apple M1 runner (GitHub:
macos-14
) to the CI tests.
- CI: Addressed several issues in the testing configuration which had resulted in testing fewer operating systems x python version combinations than intended. CI tests now correctly and comprehensively test every supported version of python on every os (macos, windows, ubuntu).
utils.FormulaDict
: implemented__contains__
so thatget()
works correctly in python 3.12+. See python/cpython#105524- Docs: fixed many small problems in documentation causing equations and examples to render incorrectly.
Solution.from_file
: Add missing@classmethod
decorator; update documentation.
equilibrium.alpha()
: Fixed incorrect calculation of acid-base distribution coefficient for multiprotic acids.
Solution.get_total_amount
: Fix bug that would cause the method to fail if units with names not natively understood bypint
(e.g., 'ppm') were passed.
Solute.from_formula
: Fix bug in which an uncaught exception could occur when ifpymatgen
failed to guess the oxidation state of a solute. (Issue #103 - thanks to @xiaoxiaozhu123 for reporting).Solution.get_total_amount
: Fix bug that would cause the method to fail if mass-based units such as mg/L or ppm were requested.
Solution
: new kwargdefault_diffusion_coeff
which allows the user to specify a value to use when a species diffusion coefficient is missing from the database. By default, the value for NaCl salt (1.61e-9 m2/s) is used. This is important for conductivity and transport number calculations, which perform weighted summations of diffusion coefficients over every species in the solution. Previously, species with missing diffusion coefficients would be excluded from such calculations, possibly resulting in inaccuracies, particularly after callingequilibrate()
, which often generates charged complexes such as NaSO4- or MgCl+.
Solution.__add__
: Bugfix in the addition operation+
that could cause problems with child classes (i.e., classes that inherit fromSolution
) to work improperly
- Removed deprecated
pkg_resources
import in favor ofimportlib.resources
- Add tests for
gibbs_mix
andentropy_mix
functions. Format docstrings in Google style.
Solution.from_preset
: Fixed a packaging error that made this method fail with aFileNotFoundError
.
functions.py
is no longer imported into the root namespace. You'll now need to sayfrom pyEQL.functions import gibbs_mix
instead offrom pyEQL import gibbs_mix
PhreeqcEOS
: performance improvements for thephreeqc
engine. TheEOS
instance now retains thephreeqpython
solution object in between calls, only re-initializing it if the composition of theSolution
has changed since the previous call.
equilibrate
: Fixed several bugs affectingNativeEOS
andPhreeqcEOS
in which callingequilibrate()
would mess up the charge balance. This was especially an issue ifbalance_charge
was set to something other thanpH
.
equilibrium.equilibrate_phreeqc()
has been removed to reduce redundant code. All its was absorbed intoNativeEOS
andPhreeqcEOS
- utility function
create_water_substance
with caching to speed up access to IAPWS instances
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.
Solution
: Revamped docstrings forconductivity
,get_transport_number
,get_molar_conductivity
, andget_diffusion_coefficient
.Solution
: new methodget_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)
Solution
: new methodto_file()
for more convenient saving Solution object to json or yaml files. (@kirill-push)Solution
: new methodfrom_file()
for more convenient loading Solution object from json or yaml files. (@kirill-push)Solution
: new classmethodfrom_preset()
toreplace pyEQL.functions.autogenerate()
and instantiate a solution from a preset composition. (@kirill-push)
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
- Database errors with
Cs[+1]
diffusion coefficient andKBr
Pitzer parameters - Restored filter that suppresses duplicate log messages
replace pyEQL.functions.autogenerate()
is now deprecated. Usefrom_preset
instead.
- The
activity_correction
kwarg inget_transport_number
has been removed, because this now occurs by default and is handled inget_diffusion_coefficient
.
- Restored filter that suppresses duplicate log messages
format_solutes_dict()
method added into the utils module to help format solutes dictionaries with a unit. (@DhruvDuseja)
- Native property database is now instantiated on
pyEQL.__init__
to speed subsequent access bySolution
- Numerous performance optimization increased the speed of many
Solution
property and method calls by 3x-10x
Solution.print()
added to take the place of the deprecatedlist_xxx
methods.
- Breaking
pyEQL.unit
deprecation machinery has been removed to quiet the warning messages on import. ThepyEQL
unit registry was renamed topyEQL.ureg
in v0.6.1. - Significant documentation updates.
Solution.components
is now automatically sorted in descending order of amount, for consistency withanions
,cations
, andneutrals
.
Solution.list_solutes()
has been removed. UseSolution.components.keys()
instead.
- Bugfix in
as_dict
to make serialization viadumpfn
possible. Previously,Quantity
were not converted to a serializable form. Now,Quantity
are converted tostr
inas_dict()
.
- python 3.8 is no longer supported
from_dict
modified to avoid call tosuper()
, making for more robust behavior ifSolution
is inherited.
copy()
method was removed for consistency withpython
conventions (it returned a deep rather than a shallow copy). Usecopy.deepcopy(Solution)
instead.
- Bugfix in
as_dict
in which thesolutes
attribute was saved withQuantity
rather thanfloat
- Simplified
Solution.get_conductivity
to avoid errors in selected cases. - Required
pymatgen
version was incorrectly set at2022.8.10
when it should be2023.8.10
- Bug in
get_osmotic_coefficient
that caused aZeroDivisionError
with an empty solution.
- New electrolyte engine
PhreeqcEOS
providesphreeqpython
activities withinpyEQL
Solution
: use total element concentrations when performing salt matching (can be disabled via kwarg)Solution
: add speciation support to the native engine viaphreeqpython
Solution
: add keyword argument to enable automatic charge balancingSalt
: class is now MSONable (i.e., serializable viaas_dict
/from_dict
)Solution
: new propertiesanions
,cations
,neutrals
provide easy access to subsetscomponents
.Solution
: improvements toget_total_amount
.Solution
: new functionget_components_by_element
that lists all species associated with elements in specific oxidation states.Solution
: new propertieselements
andchemical_system
, new functionget_el_amt_dict
to compute the total number of moles of each element present in the Solution.
pH
attribute is now calculated from the H+ concentration rather than its activity. For the old behavior, useSolution.p('H+')
which defaults to applying the activity correction.- Update
test_salt_ion_match
topytest
format and add additional tests - Update
test_bulk_properties
topytest
format
Solution.list_salts()
has been removed. SeeSolution.get_salt_dict()
for equivalent functionalitysalt_ion_match.generate_salt_list
andidentify_salt
have been removed. SeeSolution.get_salt_dict()
andSolution.get_salt()
for equivalent functionality.
- Bug in
get_transport_number
caused by migration to standardized solute formulas - Scaling of salt concentrations in
get_salt_dict
was incorrect in some edge cases - Disable hydrate notation in
standardize_formula
, which caused hydroxides such as 'Ca(OH)3' to be written 'CaO2H.H2O' - Inconsistent formatting of oxidation states in
get_total_amount
andSolute
- Inconsistent return type from
get_property
whenmolar_volume
anddiffusion_coefficient
were missing - Two issues with the formatting of the
H2O(aq)
entry in the database,pyeql_db.json
Solution
now more robustly converts any user-supplied formulas into unique values usingpymatgen.core.ion.Ion.reduced_formula
. This means that the.components
orsolvent
attributes may now differ slightly from whatever is entered during__init__
. For example,Solution(solvent='H2O').solvent
givesH2O(aq)
. This behavior resolved a small bug that could occur when mixing solutions. User supplied formulas passed toget_amount
orSolution.components[xxx]
can still be any valid formula. E.g.,Solution.components["Na+"]
,Solution.components["Na+1"]
, andSolution.components["Na[+]"]
will all return the same thing.
Solution
: enable passing anEOS
instance to theengine
kwarg.Solution
: new propertiestotal_dissolved_solids
and aliasTDS
Solution
: support new units inget_amount
- ppm, ppb, eq/L, etc.Solution
: implemented arithmetic operations+
(for mixing two solutions),*
and\
for scaling their amounts
pyEQL.unit
was renamed topyEQL.ureg
(short forUnitRegistry
) for consistency with thepint
documentation and tutorials.
Solution
: add tests to confirm that solution density changes with temperature and pressureSolution
: add tests forcharge_balance
,alkalinity
,hardness
,osmotic_pressure
,p()
, andconductivity
Solution
:pE
attribute and kwargSolution
: add support for passing solutes as adict
- Implement extensible system for connecting
Solution
to various activity and speciation models. Models can be integrated into pyEQL by implementing anEOS
class. The desired activity model is selected on init. Currently available models arenative
(for pyEQL's implementation of Pitzer, which decays gracefully into Debye-Huckel and other models if parameters are not available) orideal
for a dummy engine that returns unit activity coefficients. Support for additional external engines such asphreeqpython
is planned. - Add
pymatgen
,monty
, andmaggma
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 frompymatgen
- Add more comprehensive platform testing via
tox
- Complete overhaul of the property database. The database is now distributed in a .json file containing serialize
Solute
objects.Solution
can now be connected to this database (by default) or to any othermaggma
Store
containing properly formatted data.database.py
,parameter.py
, and all the.tsv
data files have been removed and replaced withpyeql_db.json
. - Docs: update, change theme, convert to .md format, and adopt Keep a Changelog format
- Replace
water_properties.py
with iapws package - Replace
elements.py`` with
pymatgen.core.periodic_table` Solution.charge_balance
now returns in equivalents instead of Coulombs- Migrate all tests to
pytest
- Update packaging format to use pyscaffold
Solution
: new propertiespressure
,temperature
,volume
,pH
,mass
,density
,viscosity_dynamic
,viscosity_kinematic
,ionic_strength
,conductivity
,debye_length
,bjerrum_length
,alkalinity
,hardness
,dielectric_constant
,osmotic_pressure
,solvent_mass
,charge_balance
have replaced the corresponding get_XXX and set_XXX (for temperature and pressure) methods, which will be removed in a future release.get_viscosity_relative
will be removed entirely.Solute
: methodsget_formal_charge()
,get_name()
, andget_molecular_weight()
have been replaced by direct access to the attributescharge
,formula
, andmw
, respectively.
- disable 'verbose' kwarg in
get_activity
andget_activity_coefficient
- Fixed various documentation rendering issues
- bug in
alkalinity
- Fix breaking bug introduced by upstream pint change to avogadro_number
- Format project with black
- Misc. linting and docstring changes
- Implement the effective Pitzer model for improved activity calculations in multicomponent solutions
- Add support for calculation of activity and osmotic coefficients on different scales
- Add support for calculating % by weight to get_amount()
- Added methods for calculating the osmolarity or osmolality of a Solution
- Add the ability to filter list_concentrations() to show only cations or anions
- Add two medical solutions - normal saline and Ringer's lacate -to the autogenerate method
- Add shorthand abbreviations for 'seawater' and 'wastewater' in the autogenerate method
- Enhance automatic test suite to compare results with experimental data based on relative error
- Add test suites for the effective Pitzer model and a multicomponent salt solution
- DEPRECATED get_mole_fraction. Use get_amount() instead
- Fix bug causing get_activity_coefficient to fail if the solute concentration was zero
- Add ability to calculate dielectric constant based on solution composition for salts
- Add database entries for the viscosity 'B' parameter for 63 more inorganic ions
- Add domestic wastewater and human urine to the autogenerate()method
- Improve entry point for running automated tests (#16, thanks Hernan Grecco)
- Significantly expand documentation of activity correction methods
- Make output of get_osmotic_coefficient more verbose when Pitzer parameters are not found
- Fix bug causing activity corrections for non 1:1 salts to be calculated incorrectly (#15)
- Fix bug causing 'bad operand type' error when calculating osmotic pressure on some systems
- Fix bug causing ValueError exceptions when a solute has zero concentration
- Numerous fixes and corrections in the documentation
- Fix packaging problems preventing installation from PyPi
- Fix character encoding issue in Erying_viscosity database file
- Add method to calculate the total concentration of an element in a solution
- Add method to automatically generate certain solutions (like seawater)
- Add method to calculate the hardness of a solution
- Add method to calculate the alkalinity of a solution
- Add method to calculate the charge balance of a solution
- Add method to calculate the Bjerrum length
- Add database entries for hydrated and ionic radii of 23 commonions
- Add database entries for the 'B' parameter in the Jones-Dole viscosity equation for 20 common ions
- Add test suites for solute property methods, hardness, osmotic coefficient, and Debye length
- Improve logging system to work better when using pyEQL interactively
- Improved README with graphics and rich formatting
- Fix bug related to activity and osmotic coefficients for multivalent salts
- Fix bug related to retrieval of water properties
- Documentation enhancements and fixes
- Fix bug in get_amount() causing no output when mass-based units were specified.
- Add 93 entries to diffusion coefficient database
- Add 93 entries to Pitzer partial molar volume parameters database
- Add 130 entries to Pitzer activity parameters database
- Change extension for database files from .csv to .tsv
- Corrections and additions to the contributing documentation
- Uploaded to the Python Package Index for easier installation
- Add this changelog
- First public release