Electrolyte Modeling Engines¶
Overview¶
Every Solution is instantiated with an electrolyte modeling “engine”, which is a
subclass of pyEQL.engine.EOS. The modeling
engine performs three functions:
Calculate species activity and osmotic coefficients via
get_activity_coefficientandget_osmotic_coefficient, respectivelyUpdate the composition of the
Solution(i.e., speciation) viaequilibrateCalculate the volume occupied by the solutes via
get_solute_volume
All other calculations are performed directly by the Solution class and are the
same, regardless of the engine selected
The purpose of this architecture is to allow Solution to provide a consistent interface
for working with electrolyte solutions, but allow the underlying models to be customized
as needed to particular use cases.
pyEQL currently supports three modeling engines: ideal, native, and phreeqc, which
are selected via the engine kwarg to Solution.__init__(). Each engine is briefly described below.
Warning
If you are using a Mac with an Apple M1, M2, etc. chip (i.e., Arm64 architecture), some features of pyEQL will be
unavailable. Specifically, anything which depends on PHREEQC (e.g., the
equilibrate method in the native engine and the entire
phreeqc engine) will not work. This is because phreeqpython is currently
not available for this platform. All other functions of pyEQL should work as expected.
Feel free to post your experiences or proposed solutions at https://github.com/KingsburyLab/pyEQL/issues/109
The 'native' engine (Default)¶
The native engine is the default choice and was the only option available prior to
version 0.6.0.
Activity and osmotic coefficients¶
Activity coefficients are calculated using the “effective Pitzer model” of Mistry et al.
when possible. pyEQL selects parameters by identifying the predominant salt in the
solution (see Salt Matching). The ionic
strength is calculated based on all solutes, but only the predominant salt parameters
are used in the Pitzer calculation.
If the required parameters are not available in the property database, the native engine decays gracefully
through several models more appropriate for dilute solutions, including Davies, Guntelberg,
and Debye-Huckel. See the module reference for
full details.
Solute volumes¶
Solute volumes are also calculated according to the Pitzer model whenever parameters are available. Specifically, the apparent molar volume of the primary salt is calculated via Pitzer. The volumes of all other components (except the solvent, water) are added based on fixed partial molar volumes, if the data are available in the property database. If data are not available, the volume for that solute is not accounted for.
Speciation¶
Speciation calculations are provided by PHREEQC via our natively-developed IPHREEQC wrapper pyEQL.phreeqc.
This wrapper powers the phreeqc2026 engine, described below. In the native engine, in
contrast to the phreeqc2026 engine, we use the llnl.dat PHREEQC database due to its superior accuracy for moderate salinity
water and the large number of species included (see Lu et al.).
See pyEQL.engine.Phreeqc2026EOS.equilibrate() in the module reference
for more details.
Warning
The native engine is an engineering model designed to represent moderate to high salinity brines as accurately as
possible. Because it uses a non-Pitzer PHREEQC database for speciation but uses the Pitzer model (when possible) for
activity coefficients, there may be subtle thermodynamic inconsistencies between the activities and the equilibrium
concentrations returned by equilibrate().
The 'phreeqc2026' engine¶
The phreeqc2026 engine uses pyEQL.phreeqc
for speciation, activity, and volume calculations. The PHREEQC engine
uses the phreeqc.dat (v3.8) PHREEQC database by default, although it is possible to instantiate
the engine with other databases such as llnl.dat, pitzer.dat, vitens.dat, wateq4f_PWN.dat, and geothermal.dat. See
pyEQL.engine.Phreeqc2026EOS.equilibrate() in the module reference
for more details.
Older version provided in pyEQL.equilibrium.equilibrate_phreeqc has been removed and absorbed in NativeEOS, Phreeqc2026EOS, and PhreeqcEOS.
The 'phreeqc' engine¶
The phreeqc engine uses phreeqpython
for speciation, activity, and volume calculations. The PHREEQC engine
uses the phreeqc.dat (v3.7) PHREEQC database by default, although it is possible to instantiate
the engine with other databases such as llnl.dat, pitzer.dat, vitens.dat, wateq4f_PWN.dat, and geothermal.dat. See
pyEQL.engine.PhreeqcEOS.equilibrate() in the module reference
for more details.
Older version provided in pyEQL.equilibrium.equilibrate_phreeqc has been removed and absorbed in NativeEOS, Phreeqc2026EOS, and PhreeqcEOS.
Activity and osmotic coefficients¶
Activity coefficients are calculated by dividing the PHREEQC activity by the molal concentration of the solute.
Due to limitations in the phreeqpython interface, the osmotic coefficient is always
returned as 1 at present.
Warning
The phreeqc engine currently returns an osmotic coefficient of 1 and solute volume of
0 for all solutions. There appear to be limitations in the phreeqpython interface that
make it difficult to access these properties.
Solute volumes¶
Due to limitations in the phreeqpython interface, solute volumes are ignored (as in
the ideal engine). More
research is needed to determine whether this is consistent with intended PHREEQC behavior
(when using the default database) or not.
Warning
The phreeqc engine currently returns an osmotic coefficient of 1 and solute volume of
0 for all solutions. There appear to be limitations in the phreeqpython interface that
make it difficult to access these properties.
Speciation¶
Speciation calculations are provided by PHREEQC via phreeqpython.
The 'ideal' engine¶
The 'ideal' engine applies ideal solution behavior. Activity and osmotic coefficients
are always equal to 1, solute volumes are always equal to zero, and there is no support
for speciation.
Custom engines¶
The modeling engine system is designed to be extensible and customizable. To define a
custom engine, you simply need to inherit from pyEQL.engines.EOS (or a pre-existing
engine class) and then populate the abstract methods get_activity_coefficient),
get_osmotic_coefficient, get_solute_volume, and equilibrate.
Equations that implement commonly used models or the above properties (such as the Debye-Huckel
and Pitzer activity models, among others) are available in pyEQL.activity_correction and
pyEQL.equilibrium, respectively. The idea is that end users can “compose” custom
engine classes by mixing and matching the desired functions from these modules, adding
custom logic as necessary.