Coefficient libraries
The casual user has no need to explicitly call this module.
.cflibs
provides specific combinations of coefficients that have been used in published Pitzer models, to use with Pytzer.
To use a Pitzer model we need to define a set of coefficients that quantify the interactions between different combinations of ions. We do this by creating a coefficient library, which contains functions that evaluate the coefficients for every possible interaction. The functions themselves are defined separately.
A number of pre-defined coefficient libraries are included in pytzer.cflibs. To use these, all you need to do is assign the variable cflib
appropriately:
>>> import pytzer as pz
>>> cflib = pz.cflibs.M88 # Use M88 coefficients
This cflib
can then be passed into all of the Pitzer model functions.
Pre-defined coefficient libraries
Several ready-to-use coefficient libraries are available in this module. To decode their sources, see the literature references table.
cflib name | System | Source |
CRP94 | $\ce{H^+}$, $\ce{HSO4^-}$, $\ce{SO4^2-}$ | CRP94 |
GM89 | $\ce{Ca^2+}$, $\ce{Cl^-}$, $\ce{K^+}$, $\ce{Na^+}$, $\ce{SO4^2-}$ | GM89 |
M88 | $\ce{Ca^2+}$, $\ce{Cl^-}$, $\ce{Na^+}$, $\ce{SO4^2-}$ | M88 |
WM13 | $\ce{Ca^2+}$, $\ce{Cl-}$, $\ce{H+}$, $\ce{HSO4-}$, $\ce{K+}$, $\ce{Mg^2+}$, $\ce{MgOH+}$, $\ce{Na+}$, $\ce{OH-}$, $\ce{SO4^2-}$ | WM13 |
cflib methods
A few handy methods are provided as part of the CoefficientLibrary class. Brief summaries are provided below, and here is a usage example of all of them together:
import pytzer as pz
import numpy as np
from copy import deepcopy
# Copy a pre-defined cflib
cflib = deepcopy(pz.cflibs.M88)
# Get ions within it
cflib.get_contents()
# Add a new ion into the mix
cflib.ions = np.append(cflib.ions, 'K')
# Add zero-functions for all interactions with the new ion
cflib.add_zeros(cflib.ions)
# Update cflib name to show we've changed it
cflib.name = 'M88-modified'
# Print out the coefficients evaluated at 298.15 K
cflib.print_coefficients(298.15, 'coeff_file.txt')
The methods are as follows:
.add_zeros
- add entries for missing interactions
CoefficientLibrary.add_zeros(ions)
adds zero-functions for all missing interactions, given a list of ions.
.get_contents
- create lists of ions and sources
CoefficientLibrary.get_contents()
scans through all functions within the CoefficientLibrary, and puts lists of all ions and of all sources in its ions and srcs fields.
The list of ions is determined from the dict keys, while sources are determined from the function names.
.print_coefficients
- print out model coefficients
CoefficientLibrary.print_coefficients(T,filename)
evaluates all coefficients in a cflib at a single input temperature and pressure, and prints the results to a text file (filename
).
How a CoefficientLibrary works
To modify an existing CoefficientLibrary, or create a new one, it is first necessary to understand how they are used within Pytzer, as follows. A basic understanding of the workings of the Pitzer model is assumed.
A CoefficientLibrary or cflib is an object of the class CoefficientLibrary
. From the initalisation function we can see that it contains the following fields:
class CoefficientLibrary:
# Initialise
def __init__(self):
self.name = ''
self.dh = {} # Aosm
self.bC = {} # c-a
self.theta = {} # c-c' and a-a'
self.jfunc = [] # unsymmetrical mixing
self.psi = {} # c-c'-a and c-a-a'
self.lambd = {} # n-c and n-a
self.zeta = {} # n-c-a
self.mu = {} # n-n-n
self.ions = []
self.srcs = []
Each field is then filled with functions from modules debyehueckel, coefficients or jfuncs that define the Pitzer model interaction coefficients, as follows. (Descriptions of the required contents of the functions themselves are in the separate coefficients documentation.)
Debye-Hückel limiting slope
The function for the Debye-Hückel limiting slope (i.e. Aϕ) is stored as CoefficientLibrary.dh['Aosm']
.
Cation-anion interactions
Functions to evaluate the $\beta$ and $C$ coefficients for interactions between cations and anions are contained within the cflib.bC
dict. The function for each specific interaction gets its own field within the dict. The fields are named as <cation>-<anion>
, with the ionic names matching those described for an input file - see the page on naming conventions for a full description. Some examples:
cflib.bC['Na-Cl'] = <Na-Cl interaction coefficients function>
cflib.bC['Mg-Cl'] = <Mg-Cl interaction coefficients function>
cflib.bC['K-SO4'] = <K-SO4 interaction coefficients function>
Cation-cation and anion-anion interactions
Functions that evaluate the $\theta$ coefficients for interactions between ion pairs with a common charge sign are contained within the cflib.theta
dict. The function for each specific interaction gets its own field within the dict. The fields are named as <cation0>-<cation1>
, with the cations in alphabetical order, and with the ionic names matching those described for an input file. Some examples:
cflib.theta['Ca-Mg'] = <Ca-Mg interaction coefficients function>
cflib.theta['Mg-Na'] = <Mg-Na interaction coefficients function>
cflib.theta['Cl-SO4'] = <Cl-SO4 interaction coefficients function>
Triplet interactions
Functions that evaluate the $\psi$ coefficients for interactions between ion pairs with a common charge sign and a third ion of opposite sign are contained within the cflib.psi
dict. The function for each specific triplet interaction gets its own field within the dict. The fields are named as <ion0>-<ion1>-<ion2>
, with the order of the ions obeying the following rules, given here in order of precedence:
-
Cations before anions;
-
In alphabetical order.
The ionic names should match those described for an input file.
Some examples:
cflib.psi['Ca-Mg-Cl'] = <Ca-Mg-Cl interaction coefficients function>
cflib.psi['Mg-Na-SO4'] = <Mg-Na-SO4 interaction coefficients function>
cflib.psi['Na-Cl-SO4'] = <Na-Cl-SO4 interaction coefficients function>
Neutral interactions
Functions that evaluate the $\lambda$, $\zeta$ and $\mu$ coefficients for the interactions between a neutral solute and an ion or other neutral ($\lambda$), the three-way between a neutral, cation and anion ($\zeta$) and the three-way between three neutrals of the same kind ($\mu$) are contained within cflib.lambd
, cflib.eta
and cflib.mu
respectively.
The field names obey the rules, in order of precedence:
-
Neutrals first, then cations, then anions;
-
In alphabetical order.
Assigning functions is exactly the same as described for the other interaction types.
Unsymmetrical mixing terms
A function to evaluate the J and J' equations are contained in cflib.jfunc
. Unlike the other fields within the cflib, only one function is provided, so this field directly contains the relevant function, rather than storing it in a dict.
Different options for the functions needed here can be found in pytzer.jfuncs.
Modify an existing cflib
The functions within an existing cflib can easily be switched by reassignment. For example, if you wanted to use the Møller (1988) model, but replace only the Na-Cl interaction equations with the model of Archer (1992), you could write:
import pytzer as pz
# Get Møller (1988) cflib
cflib = pz.cflibs.M88
# Update Na-Cl interaction function to Archer (1992)
cflib.bC['Na-Cl'] = pz.coefficients.bC_Na_Cl_A92ii
Note that the statement to get the cflib (cflib = pz.cflibs.M88
) only references, not copies, from pytzer.cflibs. To copy, and make changes without modifying the original, use:
import pytzer as pz
from copy import deepcopy
# Get Møller (1988) cflib
cflib = deepcopy(pz.cflibs.M88)
cflib.name = 'M88-modified' # so we know it's been changed
# Update Na-Cl interaction function to Archer (1992)
cflib.bC['Na-Cl'] = pz.coefficients.bC_Na_Cl_A92ii
Build your own
You can also construct your own cflib from scratch. In the example below, we initialise a cflib
using the pytzer.cflibs.CoefficientLibrary
class. We add functions from pytzer.coefficients
for the system Na-Ca-Cl using functions from Møller (1988). Finally, we use the method add_zeros
to fill out any interactions that we have neglected to provide functions for with zeros.
import pytzer as pz
import numpy as np
# Initialise
mycflib = pz.cflibs.CoefficientLibrary()
# Debye-Hueckel limiting slope
mycflib.dh['Aosm'] = coefficients.Aosm_M88
# Cation-anion interactions (betas and Cs)
mycflib.bC['Ca-Cl' ] = coefficients.bC_Ca_Cl_M88
mycflib.bC['Na-Cl' ] = coefficients.bC_Na_Cl_M88
# Cation-cation and anion-anion interactions (theta)
# c-c'
mycflib.theta['Ca-Na' ] = coefficients.theta_Ca_Na_M88
# Unsymmetrical mixing functions
mycflib.jfunc = jfuncs.Harvie
# Triplet interactions (psi)
# c-c'-a
mycflib.psi['Ca-Na-Cl' ] = coefficients.psi_Ca_Na_Cl_M88
# Fill missing functions with zeros (none in this instance)
mycflib.add_zeros(np.array(['Na','Ca','Cl']))
To explicitly assign zeros to any interaction (i.e. the interaction is ignored by the model), you can use the appropriate zero-functions from pytzer.coefficients:
mycflib.bC['Ba-SO4'] = coefficients.bC_zero # ignore Ba-SO4 interactions
mycflib.bC['H-Na'] = coefficients.theta_zero # ignore H-Na interactions
mycflib.psi['H-Mg-OH'] = coefficients.psi_zero # ignore H-Mg-OH interactions
Print out coefficients
You can use the function CoefficientLibrary.print_coefficients to create a file containing every coefficient, evaluated at a single input temperature and pressure of your choice. For example:
mycflib.print_coefficients(298.15,'mycoefficients.txt')
would evaluate every coefficient at 298.15 K and print the results to the file mycoefficients.txt.