chemistrykit.solutions#

chemistrykit.solutions: solution chemistry.

pH/pOH and weak acid/base equilibria with Henderson-Hasselbalch buffers, Van Slyke buffer capacity, and Bjerrum polyprotic speciation; a full titration-curve solver (strong/weak acid-base) with Gran-plot equivalence-point estimation; solubility equilibria (Ksp, common-ion effect); and Debye-Huckel limiting/extended and Davies activity-coefficient laws. Colligative properties (freezing-point depression, boiling-point elevation, osmotic pressure) live in chemistrykit.thermo instead – see chemistrykit.thermo.freezing_point_depression() and friends.

class chemistrykit.solutions.Buffer(pKa, acid_conc, base_conc)[source]#

Bases: object

An acid/conjugate-base buffer, via the Henderson-Hasselbalch approximation.

Parameters:
  • pKa (float) – \(-\log_{10}(K_a)\) of the weak-acid component.

  • acid_conc (float) – Concentration of the weak-acid form, \([HA]\), in mol/L.

  • base_conc (float) – Concentration of the conjugate-base form, \([A^-]\), in mol/L.

acid_conc: float#
base_conc: float#
classmethod from_target_ph(pKa, target_pH, total_conc)[source]#

Build a Buffer with a target pH from a fixed total buffer concentration.

Inverting the Henderson-Hasselbalch equation for the base/acid ratio \(r=[A^-]/[HA] = 10^{pH-pKa}\) and distributing the fixed total concentration \(C=[HA]+[A^-]\) between the two forms in that ratio.

Parameters:
  • pKa (float) – \(-\log_{10}(K_a)\) of the weak-acid component.

  • target_pH (float) – Desired buffer pH.

  • total_conc (float) – Total buffer concentration, \([HA]+[A^-]\), in mol/L.

Return type:

Buffer

Returns:

Buffer

Examples

Recovering the target pH exactly:

>>> buf = Buffer.from_target_ph(pKa=4.76, target_pH=5.0, total_conc=0.20)
>>> round(buf.pH(), 6)
5.0
>>> round(buf.acid_conc + buf.base_conc, 6)
0.2
pH()[source]#

Return the buffer’s pH via henderson_hasselbalch_ph().

Return type:

float

Returns:

float

pKa: float#
class chemistrykit.solutions.GranPlotResult(Vb, G, slope, intercept, equivalence_volume)[source]#

Bases: object

Container for the output of chemistrykit.solutions.systems.titration.gran_plot().

Parameters:
G: ndarray#

Gran function \((V_a+V_b)\,10^{-\mathrm{pH}}\) at each volume, in mol.

Type:

ndarray

Vb: ndarray#

Titrant volumes used in the fit, in L.

Type:

ndarray

equivalence_volume: float#

Extrapolated x-intercept -intercept/slope – the Gran estimate of the equivalence volume, in L.

Type:

float

intercept: float#

Least-squares intercept of G at Vb = 0, in mol.

Type:

float

slope: float#

Least-squares slope of G against Vb, in mol/L.

Type:

float

class chemistrykit.solutions.StrongAcidStrongBaseTitration(Ca, Va, Cb, Kw=1e-14)[source]#

Bases: Titration

Titrating a strong acid (in the flask) with a strong base (the titrant).

Parameters:
  • Ca (float) – Initial strong-acid concentration, in mol/L.

  • Va (float) – Initial acid volume, in L.

  • Cb (float) – Titrant (strong base) concentration, in mol/L.

  • Kw (float) – Water autoionization constant.

Examples

The equivalence volume (where moles acid = moles base) is exactly Ca*Va/Cb, and the numerically detected steepest-ascent point should match it closely:

>>> import numpy as np
>>> titration = StrongAcidStrongBaseTitration(Ca=0.100, Va=0.050, Cb=0.100)
>>> Vb_equiv_exact = titration.equivalence_volume()
>>> round(Vb_equiv_exact, 4)
0.05
>>> Vb = np.linspace(1e-6, 0.09, 20000)
>>> Vb_equiv_numeric = titration.find_equivalence_point(Vb)
>>> abs(Vb_equiv_numeric - Vb_equiv_exact) < 1e-3
True
equivalence_volume()[source]#

Return the exact (stoichiometric) equivalence volume, Ca*Va/Cb.

Return type:

float

Returns:

float

pH_at(Vb)[source]#

Return the pH at each titrant volume in Vb.

Parameters:

Vb (ndarray) – Volume(s) of titrant added, in L.

Returns:

ndarray

class chemistrykit.solutions.Titration[source]#

Bases: ABC

Common base for a strong/weak acid-base titration-curve model.

Concrete subclasses implement pH_at(); curve() and find_equivalence_point() are then available on every subclass for free, mirroring how chemistrykit.kinetics.core.base_system.ReactionNetwork.integrate() is shared machinery built once atop each subclass’s rhs.

curve(Vb)[source]#

Compute the full titration curve over a range of titrant volumes.

Parameters:

Vb (array-like of float) – Volumes of titrant added, in L.

Return type:

TitrationResult

Returns:

TitrationResult

find_equivalence_point(Vb)[source]#

Numerically locate the equivalence point as the point of steepest pH ascent.

The equivalence point is where \(d(\text{pH})/dV_b\) is largest in magnitude – the inflection point of the titration curve (Harris, Quantitative Chemical Analysis, 9th ed., Ch. 11). This is a generic numerical detector shared by every Titration subclass; compare its result against a subclass’s closed-form equivalence volume (stoichiometric Ca*Va/Cb) as a correctness check.

Parameters:

Vb (array-like of float) – A sufficiently fine grid of titrant volumes spanning the equivalence point, in L.

Return type:

float

Returns:

float – The titrant volume of steepest ascent.

abstractmethod pH_at(Vb)[source]#

Return the pH at each titrant volume in Vb.

Parameters:

Vb (ndarray) – Volume(s) of titrant added, in L.

Return type:

ndarray

Returns:

ndarray

class chemistrykit.solutions.TitrationResult(Vb, pH)[source]#

Bases: object

Container for the output of a Titration.curve() call.

Parameters:
Vb: ndarray#

Volume(s) of titrant added, in L (or any consistent volume unit).

Type:

ndarray

pH: ndarray#

pH at each volume in Vb.

Type:

ndarray

class chemistrykit.solutions.WeakAcid(Ca, Ka, Kw=1e-14)[source]#

Bases: WeakElectrolyte

A weak monoprotic acid HA in water, solved exactly (see module docstring).

Parameters:
  • Ca (float) – Total (analytical) acid concentration, in mol/L.

  • Ka (float) – Acid dissociation constant.

  • Kw (float) – Water autoionization constant (default: 25 degC).

Examples

0.100 M acetic acid (Ka = 1.8e-5): the exact solution is very close to the textbook approximation \([H^+] \approx \sqrt{K_a C_a}\) here, since \(K_aC_a \gg K_w\):

>>> acid = WeakAcid(Ca=0.100, Ka=1.8e-5)
>>> round(acid.h_concentration(), 6)
0.001333
>>> round(float(np.sqrt(1.8e-5 * 0.100)), 6)
0.001342
>>> round(acid.pH(), 3)
2.875
Ca: float#
Ka: float#
Kw: float = 1e-14#

Water autoionization constant, default 1.0e-14 (25 degC).

Type:

float

property equilibrium_constant: float#

Ka (for a weak acid) or Kb (for a weak base).

Type:

float

h_concentration()[source]#

Return the equilibrium \([H^+]\), in mol/L.

Return type:

float

Returns:

float

pH()[source]#

Return the equilibrium pH.

Return type:

float

Returns:

float

property total_concentration: float#

Total (analytical) concentration of the weak electrolyte, in mol/L.

Type:

float

class chemistrykit.solutions.WeakAcidStrongBaseTitration(Ca, Va, Ka, Cb, Kw=1e-14)[source]#

Bases: Titration

Titrating a weak acid HA (in the flask) with a strong base (the titrant).

Parameters:
  • Ca (float) – Initial weak-acid concentration, in mol/L.

  • Va (float) – Initial acid volume, in L.

  • Ka (float) – Acid dissociation constant of HA.

  • Cb (float) – Titrant (strong base) concentration, in mol/L.

  • Kw (float) – Water autoionization constant.

Examples

At the half-equivalence volume, exactly half the acid has been converted to its conjugate base, so by Henderson-Hasselbalch pH = pKa there:

>>> import numpy as np
>>> titration = WeakAcidStrongBaseTitration(Ca=0.100, Va=0.050, Ka=1.8e-5, Cb=0.100)
>>> Vb_half = titration.equivalence_volume() / 2.0
>>> pKa = float(-np.log10(1.8e-5))
>>> bool(abs(float(titration.pH_at(np.array([Vb_half]))[0]) - pKa) < 1e-3)
True
equivalence_volume()[source]#

Return the exact (stoichiometric) equivalence volume, Ca*Va/Cb.

Return type:

float

Returns:

float

pH_at(Vb)[source]#

Return the pH at each titrant volume in Vb.

Parameters:

Vb (ndarray) – Volume(s) of titrant added, in L.

Returns:

ndarray

class chemistrykit.solutions.WeakBase(Cb, Kb, Kw=1e-14)[source]#

Bases: WeakElectrolyte

A weak base B in water, solved exactly (see module docstring).

Parameters:
  • Cb (float) – Total (analytical) base concentration, in mol/L.

  • Kb (float) – Base dissociation constant.

  • Kw (float) – Water autoionization constant (default: 25 degC).

Examples

0.100 M ammonia (Kb = 1.8e-5), by the acid/base symmetry the same numbers as the WeakAcid example, but for pOH:

>>> base = WeakBase(Cb=0.100, Kb=1.8e-5)
>>> round(base.oh_concentration(), 6)
0.001333
>>> round(base.pH(), 3)
11.125
Cb: float#
Kb: float#
Kw: float = 1e-14#

Water autoionization constant, default 1.0e-14 (25 degC).

Type:

float

property equilibrium_constant: float#

Ka (for a weak acid) or Kb (for a weak base).

Type:

float

oh_concentration()[source]#

Return the equilibrium \([OH^-]\), in mol/L.

Return type:

float

Returns:

float

pH()[source]#

Return the equilibrium pH, via \([H^+] = K_w/[OH^-]\).

Return type:

float

Returns:

float

pOH()[source]#

Return the equilibrium pOH.

Return type:

float

Returns:

float

property total_concentration: float#

Total (analytical) concentration of the weak electrolyte, in mol/L.

Type:

float

class chemistrykit.solutions.WeakBaseStrongAcidTitration(Cb, Vb0, Kb, Ca, Kw=1e-14)[source]#

Bases: Titration

Titrating a weak base B (in the flask) with a strong acid (the titrant).

The mirror image of WeakAcidStrongBaseTitration (swap \([H^+] \leftrightarrow [OH^-]\), \(K_a \leftrightarrow K_b\)).

Parameters:
  • Cb (float) – Initial weak-base concentration, in mol/L.

  • Vb0 (float) – Initial base volume, in L.

  • Kb (float) – Base dissociation constant of B.

  • Ca (float) – Titrant (strong acid) concentration, in mol/L.

  • Kw (float) – Water autoionization constant.

Examples

At the half-equivalence volume, pOH = pKb:

>>> import numpy as np
>>> titration = WeakBaseStrongAcidTitration(Cb=0.100, Vb0=0.050, Kb=1.8e-5, Ca=0.100)
>>> Va_half = titration.equivalence_volume() / 2.0
>>> pKb = float(-np.log10(1.8e-5))
>>> pH_half = float(titration.pH_at(np.array([Va_half]))[0])
>>> pOH_half = 14.0 - pH_half  # Kw = 1e-14 -> pKw = 14
>>> bool(abs(pOH_half - pKb) < 1e-3)
True
equivalence_volume()[source]#

Return the exact (stoichiometric) equivalence volume, Cb*Vb0/Ca.

Return type:

float

Returns:

float

pH_at(Va)[source]#

Return the pH at each titrant volume in Vb.

Parameters:

Vb (ndarray) – Volume(s) of titrant added, in L.

Returns:

ndarray

class chemistrykit.solutions.WeakElectrolyte[source]#

Bases: ABC

Common interface for a single weak acid or weak base dissociation equilibrium.

A concrete subclass represents either a weak acid (in which case _ion_concentration() returns \([H^+]\)) or a weak base (returning \([OH^-]\)) – never both – so percent_dissociation()’s formula \(\alpha = ([\text{ion}] - K_w/[\text{ion}])/C\) applies unchanged to either case (for an acid, \([\text{ion}] - K_w/[\text{ion}] = [H^+] - [OH^-] = [A^-]\), the dissociated fraction’s concentration; for a base, symmetrically, \([OH^-] - [H^+] = [BH^+]\)).

Kw: float = 1e-14#

Water autoionization constant, default 1.0e-14 (25 degC).

Type:

float

abstract property equilibrium_constant: float#

Ka (for a weak acid) or Kb (for a weak base).

Type:

float

percent_dissociation()[source]#

Percentage of the weak electrolyte that has dissociated, \(100\alpha\).

Return type:

float

Returns:

float

abstract property total_concentration: float#

Total (analytical) concentration of the weak electrolyte, in mol/L.

Type:

float

chemistrykit.solutions.activity_coefficient_davies(z, I, A=0.509, b=0.3)[source]#

Davies equation: \(\log_{10}\gamma = -A z^2\left(\frac{\sqrt{I}}{1+\sqrt{I}} - bI\right)\).

An empirical extension of the Guntelberg form (activity_coefficient_debye_huckel_extended() with Ba = 1) by a term linear in ionic strength, which makes \(\log\gamma\) pass through a minimum and turn back up at high ionic strength, as measured activity coefficients do; useful up to roughly \(I \approx 0.5\) mol/L with no ion-specific parameter at all. Davies originally used \(b = 0.2\) (C. W. Davies, J. Chem. Soc. 1938, 2093); the now-standard \(b = 0.3\) is from his later monograph (C. W. Davies, Ion Association, Butterworths, 1962).

Parameters:
  • z (float) – Charge number of the ion.

  • I (float) – Ionic strength, in mol/L.

  • A (float) – Debye-Huckel constant for the solvent/temperature.

  • b (float) – Coefficient of the linear correction term.

Return type:

float

Returns:

float – Activity coefficient \(\gamma\).

Examples

With b = 0 it is exactly the Guntelberg (Ba = 1) extended law:

>>> g_davies = activity_coefficient_davies(z=1, I=0.05, b=0.0)
>>> g_ext = activity_coefficient_debye_huckel_extended(z=1, I=0.05, Ba=1.0)
>>> round(g_davies - g_ext, 12)
0.0

The linear term raises \(\gamma\) again at high ionic strength:

>>> activity_coefficient_davies(z=1, I=1.0) > activity_coefficient_davies(z=1, I=0.4)
True
chemistrykit.solutions.activity_coefficient_debye_huckel_extended(z, I, A=0.509, Ba=1.0)[source]#

Extended Debye-Huckel law: \(\log_{10}\gamma = -A z^2 \sqrt{I}/(1+Ba\sqrt{I})\).

Extends the limiting law’s validity to moderate ionic strength (roughly \(I \lesssim 0.1\) mol/L) by accounting for the ion’s finite size via the dimensionless product Ba (the Debye-Huckel parameter B times an effective ion-size parameter a); Ba=1 is a commonly used simplification when a specific ion-size parameter isn’t available (Atkins & de Paula, Physical Chemistry, 11th ed., Ch. 5.9, eq. 5.70) – this is itself still an approximation, one step better than the limiting law, not an exact result.

Parameters:
  • z (float) – Charge number of the ion.

  • I (float) – Ionic strength, in mol/L.

  • A (float) – Debye-Huckel constant for the solvent/temperature.

  • Ba (float) – Dimensionless ion-size product; see above.

Return type:

float

Returns:

float – Activity coefficient \(\gamma\).

Examples

Reduces to the limiting law as \(I \to 0\):

>>> import numpy as np
>>> I = 1e-8
>>> extended = activity_coefficient_debye_huckel_extended(z=1, I=I)
>>> limiting = activity_coefficient_debye_huckel_limiting(z=1, I=I)
>>> bool(np.isclose(extended, limiting, rtol=1e-3))
True

At higher ionic strength, the extended law predicts a less severe deviation from ideality than the (over-extrapolated) limiting law:

>>> extended_at_01 = activity_coefficient_debye_huckel_extended(z=1, I=0.1)
>>> limiting_at_01 = activity_coefficient_debye_huckel_limiting(z=1, I=0.1)
>>> extended_at_01 > limiting_at_01
True
chemistrykit.solutions.activity_coefficient_debye_huckel_limiting(z, I, A=0.509)[source]#

Debye-Huckel limiting law: \(\log_{10}\gamma = -A z^2 \sqrt{I}\).

Valid only at low ionic strength (roughly \(I \lesssim 0.01\) mol/L), where ion-ion interactions are dominated by long-range electrostatics (Debye & Huckel, 1923; Atkins & de Paula, Physical Chemistry, 11th ed., Ch. 5.9, eq. 5.69).

Parameters:
  • z (float) – Charge number of the ion (its sign does not matter – only \(z^2\) enters).

  • I (float) – Ionic strength, in mol/L.

  • A (float) – Debye-Huckel constant for the solvent/temperature.

Return type:

float

Returns:

float – Activity coefficient \(\gamma\) (dimensionless, \(\leq 1\)).

Examples

At zero ionic strength the activity coefficient is exactly 1 (ideal, infinitely dilute behavior):

>>> round(activity_coefficient_debye_huckel_limiting(z=1, I=0.0), 6)
1.0

A more highly charged ion deviates further from ideality at the same ionic strength:

>>> gamma_1 = activity_coefficient_debye_huckel_limiting(z=1, I=0.01)
>>> gamma_2 = activity_coefficient_debye_huckel_limiting(z=2, I=0.01)
>>> gamma_2 < gamma_1 < 1.0
True
chemistrykit.solutions.buffer_capacity(pH, C, Ka, Kw=1e-14)[source]#

Van Slyke’s buffer value \(\beta = dC_b/d\mathrm{pH}\) of a weak monoprotic acid.

The moles of strong base per litre needed to raise the pH of a solution containing a weak acid/conjugate base pair (total concentration \(C\)) by one unit, from differentiating the charge balance \(C_b = CK_a/(K_a+h) + K_w/h - h\):

\[\beta = \ln 10\left(h + \frac{K_w}{h} + \frac{CK_ah}{(K_a+h)^2}\right)\]

The buffer term peaks at \(pH = pK_a\) with value \(\ln 10\,C/4\) (D. D. Van Slyke, J. Biol. Chem. 52, 525 (1922); Harris, Quantitative Chemical Analysis, 9th ed., Ch. 9-5).

Parameters:
  • pH (float or array-like of float) – pH value(s).

  • C (float) – Total concentration of the buffer pair, \([HA]+[A^-]\), in mol/L.

  • Ka (float) – Acid dissociation constant.

  • Kw (float) – Water autoionization constant.

Returns:

float or ndarray – Buffer capacity, in mol/L per pH unit.

Examples

A 0.10 M acetate buffer at \(pH = pK_a\) (water terms negligible):

>>> import numpy as np
>>> round(float(buffer_capacity(4.76, C=0.10, Ka=10**-4.76)), 4)
0.0576
>>> round(float(np.log(10) * 0.10 / 4), 4)
0.0576
chemistrykit.solutions.gran_plot(Vb, pH, Va)[source]#

Gran’s linearization of a strong-acid/strong-base titration curve.

Before the equivalence point of a strong acid (initial volume \(V_a\)) titrated with a strong base, the charge balance gives, once \([OH^-]\) is negligible,

\[(V_a + V_b)\,10^{-\mathrm{pH}} = C_aV_a - C_bV_b,\]

a straight line in \(V_b\) whose x-intercept is exactly the equivalence volume \(V_e = C_aV_a/C_b\) – so \(V_e\) can be found by extrapolating pre-equivalence data, without having to resolve the steep inflection itself (G. Gran, Analyst 77, 661 (1952); Harris, Quantitative Chemical Analysis, 9th ed., Ch. 11-5). Neither \(C_a\) nor \(C_b\) needs to be known.

Parameters:
  • Vb (array-like of float) – Titrant volumes, in L, all before the equivalence point (conventionally the last 10-90% of the way to it).

  • pH (array-like of float) – Measured pH at each volume in Vb.

  • Va (float) – Initial volume of the acid being titrated, in L.

Return type:

GranPlotResult

Returns:

GranPlotResult

Examples

Recovering the 50.00 mL equivalence volume of 50.00 mL of 0.100 M HCl titrated with 0.100 M NaOH from pre-equivalence points only:

>>> import numpy as np
>>> titration = StrongAcidStrongBaseTitration(Ca=0.100, Va=0.050, Cb=0.100)
>>> Vb = np.linspace(0.030, 0.045, 10)
>>> result = gran_plot(Vb, titration.pH_at(Vb), Va=0.050)
>>> round(result.equivalence_volume * 1000.0, 4)
50.0
>>> round(-result.slope, 6)  # slope is -Cb
0.1
chemistrykit.solutions.h_from_ph(pH)[source]#

Inverse of ph_from_h(): \([H^+] = 10^{-pH}\).

Examples

>>> round(float(h_from_ph(7.0)), 10)
1e-07
chemistrykit.solutions.henderson_hasselbalch_ph(pKa, base_conc, acid_conc)[source]#

The Henderson-Hasselbalch equation: \(pH = pK_a + \log_{10}([A^-]/[HA])\).

A buffer approximation valid when both base_conc and acid_conc are large enough that dissociation/hydrolysis negligibly perturbs their equilibrium ratio (L. J. Henderson, Am. J. Physiol. 21, 173 (1908); K. A. Hasselbalch, Biochem. Z. 78, 112 (1917); see Atkins & de Paula, Physical Chemistry, 11th ed., Ch. 6.7).

Parameters:
  • pKa (float) – \(-\log_{10}(K_a)\) of the weak acid.

  • base_conc (float) – Concentration (or moles) of the conjugate base, \([A^-]\).

  • acid_conc (float) – Concentration (or moles) of the weak acid, \([HA]\).

Return type:

float

Returns:

float

Examples

An equimolar acid/conjugate-base buffer has pH = pKa exactly:

>>> round(henderson_hasselbalch_ph(pKa=4.76, base_conc=0.10, acid_conc=0.10), 6)
4.76
chemistrykit.solutions.ionic_strength(concentrations, charges)[source]#

Ionic strength \(I = \frac{1}{2}\sum_i c_i z_i^2\).

Parameters:
  • concentrations (array-like of float) – Molar concentration of each ion, in mol/L.

  • charges (array-like of float) – Charge number of each ion (signed), same order as concentrations.

Return type:

float

Returns:

float

Examples

A 0.10 M solution of a 1:1 electrolyte (e.g. NaCl) has ionic strength equal to its concentration:

>>> round(ionic_strength([0.10, 0.10], [1, -1]), 6)
0.1

A 0.10 M solution of a 1:2 electrolyte (e.g. CaCl2) has three times the concentration’s worth of ionic strength:

>>> round(ionic_strength([0.10, 0.20], [2, -1]), 6)
0.3
chemistrykit.solutions.ksp_from_molar_solubility(s, cation_coeff, anion_coeff)[source]#

Compute \(K_{sp} = p^pq^q s^{p+q}\) from a measured molar solubility.

Parameters:
  • s (float) – Molar solubility of the salt, in mol/L.

  • cation_coeff (int) – Stoichiometric coefficient of the cation, p (e.g. 1 for AgCl, 1 for CaF2’s Ca2+, 2 for Ag2CrO4’s Ag+).

  • anion_coeff (int) – Stoichiometric coefficient of the anion, q (e.g. 1 for AgCl, 2 for CaF2’s F-, 1 for Ag2CrO4’s CrO4 2-).

Return type:

float

Returns:

float

Examples

AgCl (1:1 salt) with molar solubility 1.3e-5 mol/L:

>>> round(ksp_from_molar_solubility(s=1.3e-5, cation_coeff=1, anion_coeff=1), 12)
1.69e-10

CaF2 (1:2 salt), Ksp = [Ca2+][F-]^2 = s*(2s)^2 = 4s^3:

>>> round(ksp_from_molar_solubility(s=2.1e-4, cation_coeff=1, anion_coeff=2), 12)
3.7e-11
chemistrykit.solutions.molar_solubility_from_ksp(Ksp, cation_coeff, anion_coeff)[source]#

Invert ksp_from_molar_solubility(): \(s = (K_{sp}/(p^pq^q))^{1/(p+q)}\).

Parameters:
  • Ksp (float) – Solubility product.

  • cation_coeff (int) – Stoichiometric coefficient of the cation, p.

  • anion_coeff (int) – Stoichiometric coefficient of the anion, q.

Return type:

float

Returns:

float – Molar solubility, in mol/L.

Examples

Round-trips with ksp_from_molar_solubility():

>>> Ksp = ksp_from_molar_solubility(s=1.3e-5, cation_coeff=1, anion_coeff=1)
>>> round(molar_solubility_from_ksp(Ksp, cation_coeff=1, anion_coeff=1), 12)
1.3e-05
chemistrykit.solutions.molar_solubility_with_common_ion(Ksp, cation_coeff, anion_coeff, common_ion_conc, common_ion='cation')[source]#

Molar solubility of \(M_pX_q\) in the presence of an added common ion.

Le Chatelier’s principle predicts that adding a common ion (independently, e.g. from a soluble salt sharing that ion) suppresses the target salt’s solubility relative to molar_solubility_from_ksp() (Atkins & de Paula, Physical Chemistry, 11th ed., Ch. 6.8b). This solves the exact polynomial

\[K_{sp} = (ps + C_0)^p (qs)^q \quad\text{(common cation, added at concentration } C_0\text{)}\]

or the mirror-image equation for a common anion, via chemistrykit.solutions.utils.rootfinding.find_positive_root() (exact for any p, q – not just the textbook 1:1-salt quadratic special case).

Parameters:
  • Ksp (float) – Solubility product of the salt whose solubility is being found.

  • cation_coeff (int) – Stoichiometric coefficient of the cation, p.

  • anion_coeff (int) – Stoichiometric coefficient of the anion, q.

  • common_ion_conc (float) – Concentration of the common ion contributed by an independent (fully dissociated) source, in mol/L.

  • common_ion (str) – Which ion is shared with the independent source.

Return type:

float

Returns:

float – Molar solubility of the salt, in mol/L.

Examples

AgCl (Ksp = 1.8e-10) is much less soluble in 0.10 M NaCl (common Cl- ion) than in pure water:

>>> s_pure = molar_solubility_from_ksp(1.8e-10, cation_coeff=1, anion_coeff=1)
>>> s_common = molar_solubility_with_common_ion(1.8e-10, cation_coeff=1, anion_coeff=1, common_ion_conc=0.10, common_ion="anion")
>>> s_common < s_pure
True
>>> round(s_common, 12)  # dominated by the 0.10 M Cl- already present: s ~= Ksp/0.10
1.8e-09
chemistrykit.solutions.oh_from_poh(pOH)[source]#

Inverse of poh_from_oh(): \([OH^-] = 10^{-pOH}\).

chemistrykit.solutions.ph_from_h(h_conc)[source]#

pH \(= -\log_{10}[H^+]\).

Parameters:

h_conc (float or array-like of float) – Hydrogen ion concentration, in mol/L.

Return type:

float

Returns:

float or ndarray

Examples

>>> round(float(ph_from_h(1.0e-7)), 6)
7.0
chemistrykit.solutions.poh_from_oh(oh_conc)[source]#

pOH \(= -\log_{10}[OH^-]\).

Examples

>>> round(float(poh_from_oh(1.0e-7)), 6)
7.0
chemistrykit.solutions.polyprotic_fractions(pH, Ka)[source]#

Bjerrum’s species-distribution fractions of a polyprotic acid \(H_nA\).

With stepwise dissociation constants \(K_1, \dots, K_n\) and \(h = [H^+]\), the fraction of the total acid present as \(H_{n-j}A^{j-}\) is

\[\alpha_j = \frac{h^{n-j}\prod_{i=1}^{j} K_i}{\sum_{k=0}^{n} h^{n-k}\prod_{i=1}^{k} K_i},\]

which depends only on pH, not on the total concentration (N. Bjerrum, Die Theorie der alkalimetrischen und azidimetrischen Titrierungen, Stuttgart: Enke, 1914; Harris, Quantitative Chemical Analysis, 9th ed., Ch. 11-7).

Parameters:
  • pH (float or array-like of float) – pH value(s).

  • Ka (array-like of float) – Stepwise dissociation constants \(K_1, \dots, K_n\), in order.

Return type:

ndarray

Returns:

ndarray – Shape (n + 1, len(pH)): row j is \(\alpha_j\), the fraction that has lost j protons. The rows sum to 1.

Examples

Carbonic acid (\(pK_1 = 6.35\), \(pK_2 = 10.33\)): at \(pH = pK_1\) the fully protonated form and bicarbonate are (almost exactly) equally abundant:

>>> alpha = polyprotic_fractions(6.35, [10**-6.35, 10**-10.33])
>>> [round(float(a), 3) for a in alpha[:, 0]]
[0.5, 0.5, 0.0]