eqtk.volumetric_titration

eqtk.volumetric_titration(c0, c0_titrant, vol_titrant, N=None, K=None, A=None, G=None, names=None, units=None, G_units=None, solvent_density=None, T=293.15, return_log=False, logK=None, normal_A=True, tol=1e-07, tol_zero=1e-07, max_iters=1000, delta_bar=1000.0, eta=0.125, min_delta=1e-12, max_trials=100, perturb_scale=100.0)
Solve for equilibrium concentrations of all species in a dilute

solution as titrant is added.

c0array_like or Series, shape (n_compounds, )

An array containing the total “initial” concentration of all possible compounds in solution before any titrant is added. If c0 is inputted as a Pandas Series, the indices contain the name of the chemical species and each value is the “initial concentration.” If c0 is passed as a dict, the dict must be convertible to a Pandas Series as pd.Series(c0).

c0_titrantarray_like or Series, shape (n_compounds, )

An array containing the total “initial” concentration of all possible compounds in the titrant. The titrant is itself is also in equilibrium, but c0 need not contain that actual equilibrium concentrations in the titrant; simply the “initial” concentrations of all species in the titrant such that the equilibrium may be calculated. If c0 is inputted as a Pandas Series, the indices contain the name of the chemical species and each value is the “initial concentration.”

vol_titrantarray_like, shape (n_titration_points, )

Each entry is the volume of titrant added, as a fraction of the initial volume of the solution before addition of solution. Note that this is the volume of added titrant, not the total volume of the mixed solution.

Narray_like or DataFrame, default None

Stoichiometic matrix. N[r, j] = the stoichiometric coefficient of compound j in chemical reaction r. All rows of N must be linearly independent. If entered as a DataFrame, the name of chemical species j is N.columns[j]. Optionally, column ‘equilibrium constant’ contains the equilibrium constants for each reaction in units commensurate with those of c0. If N is given, A and G cannot be given.

Karray_like, shape (n_reactions,), default None

K[r] is the equilibrium constant for chemical reaction r in units commensurate with those of c0. If N is given as a DataFrame with an ‘equilibrium constant’ column, K should not be supplied. If K`is given, `A and G cannot be given.

logKarray_like, shape (n_reactions,), default None

logK[r] is the natural logarithm of the equilibrium constant for chemical reaction r. If logK is specified, the concentrations must all be dimensionless (units=None). If N is given as a DataFrame with a ‘log equilibrium constant’ column, logK should not be supplied. If K is given, A, G, and K cannot be given.

Aarray_like or DataFrame, n_compounds columns

Conservation matrix. If c is the output, then A @ c0 = A @ c. All entries must be nonnegative and the rows of A must be linearly independent. If entered as a DataFrame, the name of chemical species j is A.columns[j]. If A is given, G must be given, and N and K cannot be given.

Garray_like, shape (n_compounds, ), default None

G[j] is the free energy of chemical species j in units specified by G_units. If G is given, A must be given, and N and K cannot be given.

unitsstring or None, default None

The units of the concentrations inputted as c0. The output is also in these units. Allowable values are {None, ‘mole fraction’, ‘molar’, ‘M’, ‘millimolar’, ‘mM’, ‘micromolar’, ‘uM’, ‘µM’, ‘nanomolar’, ‘nM’, ‘picomolar’, ‘pM’}. If None, concentrations are considered to be dimensionless. The equilibrium constants given by K must have corresponding units.

G_unitsstring, default None

Units in which free energy is given. If None or ‘kT’, the free energies are specified in units of of the thermal energy kT. Allowable values are {None, ‘kT’, kcal/mol’, ‘J’, ‘J/mol’, ‘kJ/mol’, ‘pN-nm’}.

nameslist or tuple of str, default None, optional

The names of the chemical species. Names are inferred if N or A is given as a DataFrame, in which case names is unnecessary.

solvent_densityfloat, default None

The density of the solvent in units commensurate with the units keyword argument. Default (None) assumes the solvent is water, and its density is computed at the temperature specified by the T keyword argument.

Tfloat, default = 293.15

Temperature, in Kelvin, of the solution. When N and K are given, T is ignored if solvent_density is given or if units is None. If A and G are given, T is ignored when units and G_units are both None.

return_logbool, default False

If True, return the natural logarithm of the concentrations.

carray or DataFrame, shape c0.shape

Equilibrium concentrations of all species. c[i, j] is the equilibrium concentration of species j for initial concentrations given by c0[i, :] in units given by units. If c0 is inputted as a DataFrame or names is not None, then c is a DataFrame with columns given by names or with the same columns (without ‘equilibrium constant’) as c0. Otherwise, c is returned as a Numpy array with the same shape as c0. If return_log is True, then the return value is the natural logarithm of the dimensionless concentrations.

normal_Abool, default True

If True, perform a transformation on A such that its rows are orthonormal. If False, use inputted A directly as the conservation matrix. This is ignored if A is not specified; the resulting conservation matrix in that case has orthonormal rows by construction.

tolfloat, default 1e-7

Tolerance for convergence. The absolute tolerance for a given initial concentration c0 (a one-dimensional array) for the conservation conditions are tol * np.dot(A, c0) except when an entry in np.dot(A, c0) is zero. If that is the case for entry i, then the absolute tolerance is tol * np.max(A[i] * c0). If all entries in A[i] * c0 are zero, which only happens with c0 = 0, the absolute tolerance is tol_zero.

tol_zerofloat, default 1e-12

Absolute tolerance for convergence when the initial concentrations are all zero. This cannot really be set a priori; it depends on the scale of the dimensionless concentrations. By default, assume an absolute tolerance consistent with tol and millimolar mole fractions.

max_itersint, default 1000

Maximum number of iterations allowed in trust region method.

delta_barfloat, default 1000.0

Maximum step size allowed in the trust region method.

etafloat, default 0.125

Value for eta in the trust region method. eta must satisfy 0 < eta < 0.25.

min_deltafloat, default 1e-12

Minimal allowed radius of the trust region. When the trust region radius gets below min_delta, the trust region iterations stop, and a final set of Newton steps is attempted.

max_trialsint, default 100

In the event that an attempt to solve does not converge, the solver tries again with different initial guesses. This continues until max_trials failures.

perturb_scalefloat, default 100.0

Multiplier on random perturbations to the initial guesses as new ones are generated.

ValueError

If input is in any way invalid

RuntimeError

If the trust region algorithm failed to converge

Uses an elliptical trust region optimization to find the

equilibrium concentrations. See 1 for algorithmic details, as well as definitions of the parameters associated with the trust region algorithm.

In practice, the trust region parameters should not be adjusted

from their default values.

1

Nocedal and Wright, Numerical Optimization, Second Edition, Springer, 2006, Chapter 4.

Compute the pH titration curve of a 1 M solution of weak acid HA with acid dissociation constant 1e-5 M, titrating in 1.0 M NaOH.

>>> rxns = '''
... <=> H+ + OH- ; 1e-14
... HA <=> H+ + A- ; 1e-5'''
>>> N = eqtk.parse_rxns(rxns)
>>> c0 = pd.Series([0, 0, 1, 0], index=['H+', 'OH-', 'HA', 'A-'])
>>> c0_titrant = pd.Series([0, 1, 0, 0],
                           index=['H+', 'OH-', 'HA', 'A-'])
>>> vol_titrant = np.array([0, 1, 2]) # Only few for display
>>> c = eqtk.volumetric_titration(c0, c0_titrant, vol_titrant, N=N,
...     units="M")
>>> c['pH'] = -np.log10(c['H+'])
>>> c[['vol titrant / initial vol', 'pH']]
   vol titrant / initial vol         pH
0                          0   2.500687
1                          1   9.349480
2                          2  13.522879