An Online Calculator to perform the calculations described in this document
Source Code for the online calculator
# Initialize
import numpy as np
import scipy.constants as const
This section sets up the variables used in the CK Clamp.
# Temperature of the assay
temp37 = 273.15 + 37
# Free Magnesium [M]
# Measured with Magnesium Green at each titration setp
freeMg = [
0.000407972,
0.000395923,
0.000377038,
0.000364626,
0.0003487,
0.00033737,
0.000323291,
0.000309397,
0.000299109,
0.000292253,
0.000281548,
]
phosphate = 0.010
pH = 7.1
Ionic Composition of Assay Buffer
Salt | [M] |
---|---|
K-MES | 0.105 |
KCl | 0.030 |
KH₂PO₄ | 0.010 |
MgCl₂ | 0.005 |
EGTA K₂ | 0.001 |
pH 7.1 at 37°C
Ionic Strength is defined as:
$$ \begin{equation} \frac{1}{2} \sum_{i=1}^n M_i \times z^2_i \end{equation} $$Where $M_i$ is the Molarity of the individual ion
This system is buffered at a specific pH and contains a few weak acids (H₂PO₄, EGTA K₄, K-MES). Therefore, in addition to their concentration, we need to consider the percent ionization of each species.
J. P. Y. Kao, G. Li, and D. A. Auston, “Chapter 5 - Practical Aspects of Measuring Intracellular Calcium Signals with Fluorescent Indicators,” in Methods in Cell Biology, vol. 99, Supplement C vols., M. Whitaker, Ed. Academic Press, 2010, pp. 113–152.
From Figure 7 of the above citation, we know that at pH 7.1, ~99% of the EGTA is H2EGTA2- . Therefore, we will make the approximation that the added ionic strenght comes from K2EGTA
For the following two ions, the pKa were obtained from the online calculator http://www.reachdevices.com/Protein/BiologicalBuffers.html
The pKa of 10 mM H2PO4 is 7. To determine the ion concentrations, we will use the Henderson–Hasselbalch equation:
$$\text{pH} = \text{pKa} + \log\frac{\text{H}\text{PO}_4^{2-}}{\text{H}_2\text{PO}_4^{1-}}$$Doing this, we find that ~45% of the acid is H₂PO₄1- and ~55% is HPO₄2-
The pKa of of 105 mM MES is 6. Again, using the H-H equation, we find that ~92% of the MES is in the ionic (deprotonated) form
Using this information, the basal ionic strength of our buffer is calculated to be 0.168 M
The salts utilized in the CK Clamp have the following stoichiometry and charge
$$\text{PCr}^{-2} \cdot \text{Tris}^{+1}_2$$$$\text{ATP}^{-4} \cdot \text{Tris}^{+1}_2$$The following is an extended table listing the steps in the CK clamp:
Steps for the CK Clamp:
Step | Conc. added [M] |
---|---|
Initial PCr | 0.001 |
+ ATP | 0.005 |
+ PCr 1 | 0.002 |
+ PCr 2 | 0.003 |
+ PCr 3 | 0.003 |
+ PCr 4 | 0.003 |
+ PCr 5 | 0.003 |
+ PCr 6 | 0.003 |
+ PCr 7 | 0.003 |
+ PCr 8 | 0.003 |
+ PCr 9 | 0.003 |
+ PCr 10 | 0.003 |
Below, we generate a list containing the calculated ionic strength at each step.
#
basal_IS = 0.168
# Initial PCr and Tris Concentrations
pcr_0 = 0.001
tris_0 = 2*pcr_0
# Initial PCr and Tris Ionic Strength
pcr_0_is = 0.5*(pcr_0*(-2)**2 + tris_0*(1)**2)
# ATP and Tris
atp_conc = 0.005
tris_atp = atp_conc*2
# ATP Ionic Strength
atp_is = 0.5*(atp_conc*(-4)**2 + tris_atp*(1)**2)
# First PCr Addition
pcr_1 = 0.002
tris_1 = pcr_1*2
# First PCr Addition Ionic Strength
pcr_1_is = 0.5*(pcr_1*(-2)**2 + tris_1*(1)**2)
# Subsequent PCr Addition's Added Concentration
pcr_add = 0.003
tris_add = 2*pcr_add
pcr_is_add = 0.5*(pcr_add*(-2)**2 + tris_add*(1)**2)
# A list to hold the ionic strengths over the CK Clamp
ionicStrengths = []
# Workign Buffer
changing_IS = basal_IS + pcr_0_is
# After ATP Addition
ionicStrengths.append(changing_IS + atp_is)
#After 1st PCr Addition
ionicStrengths.append(ionicStrengths[0] + pcr_1_is)
#After Each Subsequent PCr Addition
for step in np.arange(1, 10):
ionicStrengths.append(ionicStrengths[step] + pcr_is_add)
# Print the Results
print('{0: <8}{1: <16}'.format('Step', 'Ionic Strength (mM)'))
print('{:-^27}'.format(''))
for idx, step in enumerate(ionicStrengths):
print('{0: <8}{1: <12.6}'.format(idx+1, step*1000))
This section lists the necessary equilibrium constants and briefly describes the equations utilized to adjust them. For a more detialed discussion on the theory, please consult the references listed at the bottom of this document.
The Van't Hoff Equation to adjust the temperature of $K_{ref}$
$$ \begin{equation} \ln\left(\frac{K_2}{K_1}\right) = -\frac{\Delta H ^\circ}{R}\left( \frac{1}{T_2} - \frac{1}{T_1} \right) \end{equation} $$$R = 8.3144598 \frac{J}{K mol}$
$K_1 = K_{ref_{I=0}}$
$T_1 = T $ for temperature of $K_1$
$K_2 = K_{ref_{I=0}}$ at new temperature $T_2$
The equation assumes constant enthalpy $(\Delta H)$
To solve for $K_2$ in the Van't Hoff Equation: $$ \begin{equation} K_2 = e^{\left\{-\frac{\Delta H ^\circ}{R}\left( \frac{1}{T_2} - \frac{1}{T_1} \right) + \ln \left(K_1\right)\right\}} \end{equation} $$
The following function vant_hoff
solves this equation. It is through this function that the reference constants (Kref) will be adjusted to the specified Temperature of the assay.
def vant_hoff(temp1, temp2, Kref1, dH):
'''
temp1 = temperature for constant Kref1 (Kelvins)
Kref1 = constant at temp1 and ionic strength 0
[the original constant from which Kref2 will be adjusted]
temp2 = temperature for constant Kref2 (Kelvins)
[the new temperature to which Kref1 is to be adjusted]
dH = ΔH° associated with Kref1 at temp1 and ionic strength 0 (kilojoules)
Returns the modified constant at ionic strength 0, temp2
'''
# note, constants stored in the data table are in kJ; they are converted inline.
return np.e**((-1000*dH/const.R)*(1/temp2 - 1/temp1) + np.log(Kref1))
The following function is designed to solve for Γ as defined as:
$$ \begin{equation} \Gamma = \frac{\prod \gamma_{\text{products}_{I=\text{finite}}}} {\prod \gamma_{\text{reactants}_{I=\text{finite}}}} \end{equation} $$Where γ is derived from the extended Debye–Hückel equation:
$$ \begin{equation} \ln γ = \frac{-A_m \sqrt{I} z^2}{1 + B \sqrt{I}} \end{equation} $$$I= \text{ionic strength} (\frac{mol}{L})$
$B = 1.6 \frac{kg^{1/2}}{mol^{1/2}}$
$z = \text{charge}$
The variable Am
is derived from the following equation (Clark and Glew, 1980):
Γ relates the reference constant (Kref) at a specified (non-zero) ionic strength to the constant at zero ionic strength:
$$ \begin{equation} K_{\text{ref}_{I=O\text{, }T=\text{finite}}} = \Gamma K_{\text{ref}_{I=\text{finite, }T=\text{finite}}} \end{equation} $$It is through this relationship that the reference constants (Kref) will be adjusted to the specified Ionic Strength of the assay.
def solve_gamma(products, reactants, temp, ionic_strength):
'''
products = list of all charged product ions
reactants = list of all charged reactant ions
temp = temperature in Kelvins
ionic_strength = ionic strength in Molarity
Returns the calculated Γ
'''
# Function to solve for Γ
# Debye–Hückel
Am = 3*(-16.39023 + (261.3371/temp) + 3.3689633*np.log(temp) - 1.437167*(temp/100) + 0.111995*(temp/100)**2)
# constant with units of kg**1/2 mol**-1/2
B = 1.6
# reactants = list of the charge carried by each reactant ionic species
reactant_gammas = []
# If there isn't a charged species, pass in None to ensure the returned value divides by 1
if reactants[0] == None:
reactant_gammas = [1]
else:
for react in reactants:
reactant_gammas.append(np.e**((-Am * np.sqrt(ionic_strength) * react**2)/(1 + B*np.sqrt(ionic_strength))))
# products = list of the charge carried by each product ionic species
product_gammas = []
# if there isn't a charged species, pass in None to ensure the returned value divides by 1
if products[0] == None:
product_gammas = [1]
else:
for prod in products:
product_gammas.append(np.e**((-Am * np.sqrt(ionic_strength) * prod**2)/(1 + B*np.sqrt(ionic_strength))))
return np.prod(product_gammas)/np.prod(reactant_gammas)
The Chemical Equations for the hydrolysis of ATP and the Creatine Kinase reaction:
The apparent equilibrium constant (K`) for the above chemical equations is related to the Reference Equilibrium Constant (Kref, which is measured under specific experimental conditions) through the following relationship:
Each expression contained within $\{ \}$ represents one of the ions within the Kref expressed as a function of its its acid dissociation and magnesium binding properties. These are also equilibrium constants and must be adjusted for ionic strenght, pH, free magnesium, and temperature of the system. It is through their adjustment and the above equations that we will determine the apparent Equilbrium Constants (K`) for the Creatine Kinase reaction and hydrolysis of ATP.
Teague, Golding, and Dobson (1996) compiled the following table of reference constants. The values listed are at an ionic strength of 0 and temperature of 25°C. These constants will be used to solve the apparent Equilibrium Constants in the above equations.
Symbol | Python Variable | Reaction | Equilibrium Constant | $K_{\text{ref}}$ | $\Delta H{^\circ} (kJ mol^{-1})$ |
---|---|---|---|---|---|
$$K_{\text{a}_{\text{ATP}}}$$ | Ka_atp | $$\text{HATP}^{3-} \leftrightarrow \text{H}{^+} + \text{ATP}^{4-}$$ | $$\frac{[\text{H}{^+}][\text{ATP}^{4-}]}{[\text{HATP}^{3-}]}$$ | 2.512e-8 | -6.30 |
$$K_{\text{b}_{\text{MgATP}}}$$ | Kb_mg_atp | $$\text{Mg}^{2+} + \text{ATP}^{4-} \leftrightarrow \text{MgATP}^{2-}$$ | $$\frac{[\text{MgATP}^{2-}]}{[\text{Mg}^{2+}][\text{ATP}^{4-}]}$$ | 1.514e6 | 22.90 |
$$K_{\text{b}_{\text{MgHATP}}}$$ | Kb_mg_hatp | $$\text{Mg}^{2+} + \text{HATP}^{3-} \leftrightarrow \text{MgHATP}^{1-}$$ | $$\frac{[\text{MgHATP}^{1-}]}{[\text{Mg}^{2+}][\text{HATP}^{3-}]}$$ | 4.266e3 | 16.90 |
$$K_{\text{a}_{\text{ADP}}}$$ | Ka_adp | $$\text{HADP}^{2-} \leftrightarrow \text{H}{^+} + \text{ADP}^{3-}$$ | $$\frac{[\text{H}{^+}][\text{ADP}^{3-}]}{[\text{HADP}^{2-}]}$$ | 6.607e-8 | -5.60 |
$$K_{\text{b}_{\text{MgADP}}}$$ | Kb_mg_adp | $$\text{Mg}^{2+} + \text{ADP}^{3-} \leftrightarrow \text{MgADP}^{1-}$$ | $$\frac{[\text{MgADP}^{1-}]}{[\text{Mg}^{2+}][\text{ADP}^{3-}]}$$ | 4.466e4 | 19.0 |
$$K_{\text{b}_{\text{MgHADP}}}$$ | Kb_mg_hadp | $$\text{Mg}^{2+} + \text{HADP}^{2-} \leftrightarrow \text{MgHADP}$$ | $$\frac{[\text{MgHADP}]}{[\text{Mg}^{2+}][\text{HADP}^{2-}]}$$ | 3.163e2 | 12.50 |
$$K_{\text{a}_{\text{HPO}{_4}}}$$ | Ka_pho | $$\text{H}{_2}\text{PO}{_4}^{1-} \leftrightarrow \text{H}{^+} + \text{HPO}{_4}^{2-}$$ | $$\frac {[\text{HPO}{_4}^{2-}][\text{H}^{+}]}{[\text{H}{_2}\text{PO}{_4}^{1-}]}$$ | 6.026e-8 | 3.60 |
$$K_{\text{b}_{\text{MgHPO}{_4}}}$$ | Kb_mg_pho | $$\text{Mg}^{2+} + \text{HPO}{_4}^{2-} \leftrightarrow \text{MgHPO}{_4}$$ | $$\frac{[\text{MgHPO}{_4}]}{[\text{Mg}^{2+}][\text{HPO}{_4}^{2-}]}$$ | 5.128e2 | 12.20 |
$$K_{\text{a}_{\text{PCr}}}$$ | Ka_pcr | $$\text{HPCr}^{1-} \leftrightarrow \text{H}{^+} + \text{PCr}^{2-}$$ | $$\frac{[\text{H}{^+}][\text{PCr}^{2-}]}{[\text{HPCr}^{1-}]}$$ | 8.854e-6 | 2.66 |
$$K_{\text{b}_{\text{MgPCr}}}$$ | Kb_mg_pcr | $$\text{Mg}^{2+} + \text{PCr}^{2-} \leftrightarrow \text{MgPCr}$$ | $$\frac{[\text{MgPCr}]}{[\text{Mg}^{2+}][\text{PCr}^{2-}]}$$ | 2.320e2 | 8.19 |
$$K_{\text{ref ATP}}$$ | Kref_ATP | $$\text{ATP}^{4-} + \text{H}_2\text{O} \leftrightarrow \text{ADP}^{3-} + \text{HPO}{_4}^{2-} + \text{H}^+$$ | $$\frac{[\text{ADP}^{3-}][\text{HPO}{_4}^{2-}][\text{H}^+]}{[\text{ATP}^{4-}]}$$ | 2.946e-1 | -20.50 |
$$K_{\text{ref CK}}$$ | Kref_CK | $$\text{PCr}^{2-} + \text{ADP}^{3-} + \text{H}^+ \leftrightarrow \text{ATP}^{4-} + \text{Cr} $$ | $$\frac{[\text{ATP}^{4-}][\text{Cr}]}{[\text{PCr}^{2-}][\text{ADP}^{3-}][\text{H}^+]}$$ | 2.58e8 | -17.55 |
# Defining a class to hold the thermodynamic information
class equilibriumConstant:
def __init__(self, kref, dH, product_charges, reactant_charges, new_name):
self.kref = kref
self.dH = dH
self.prod = product_charges
self.react = reactant_charges
self.name = new_name
# From Acid and Mg-Binding Constants at T=25°C, I=0
# Tuple Positional Key
# [0] Kref
# [1] ΔH° (kJ/mol)
# [2] list of product charges (all positive as they will be squared later)
# [3] list of reactant charges
# [4] dict. string for new_Ks
is0_Ka_atp = equilibriumConstant(2.512e-08, -6.30, [1, 4], [3], 'Ka_atp')
is0_Kb_mg_atp = equilibriumConstant(1.514e+06, 22.90, [2], [4, 2], 'Kb_mg_atp')
is0_Kb_mg_hatp = equilibriumConstant(4.266e+03, 16.90, [1], [2, 3], 'Kb_mg_hatp')
is0_Ka_adp = equilibriumConstant(6.607e-08, -5.60, [1, 3], [2], 'Ka_adp')
is0_Kb_mg_adp = equilibriumConstant(4.466e+04, 19, [1], [2, 3], 'Kb_mg_adp')
is0_Kb_mg_hadp = equilibriumConstant(3.163e+02, 12.50, [None], [2, 2], 'Kb_mg_hadp')
is0_Ka_pho = equilibriumConstant(6.026e-8, 12.2, [2], [None], 'Ka_pho')
is0_Kb_mg_pho = equilibriumConstant(5.128e+02, 8.19, [None], [2, 2], 'Kb_mg_pho')
is0_Ka_pcr = equilibriumConstant(8.854e-06, 2.66, [2], [None], 'Ka_pcr')
is0_Kb_mg_pcr = equilibriumConstant(2.320e+02, 8.19, [None], [2, 2], 'Kb_mg_pcr')
Kref_CK = equilibriumConstant(2.58e8, -17.55, [4], [3, 2, 1], 'Kref_CK')
Kref_ATP = equilibriumConstant(2.946e-1, -20.50, [3, 2, 1], [4] , 'Kref_ATP')
# the temperature of the reference constants
temp25 = 273.15 + 25
In section 1, we detailed the experimental conditions over the Creatine Kinase clamp.
In section 2, the necessary equations and constants were outlined.
In this section, we will combine that information to determine the apparent Creatine Kinase Equilibrium Constant.
Step 1. Use the Van't Hoff equation to adjust $K_{\text{ref}_{I=0, T=25°C}}$ to 37°C.
$$ K_{\text{ref}_{I=0, T=37°C}} = e^{\left\{-\frac{\Delta H ^\circ}{R}\left( \frac{1}{T_2} - \frac{1}{T_1} \right) + \ln \left(K_{\text{ref}_{I=0, T=25°C}}\right)\right\}} $$(See above section Van't Hoff for more details)
# The temperature of the reference constant
temp25 = 273.15 + 25
# The temperature to which we will adjust the constant
temp37 = 273.15 + 37
# We use the function vant_hoff (defined above) to solve the Van't Hoff equation
# and adjust the constant to 37°C
CK_k2 = vant_hoff(temp25, temp37, Kref_CK.kref, Kref_CK.dH)
print('Creatine Kinase Kref\n -Ionic Strength 0\n -Temp. 37°C\n')
print('{:.4e}'.format(CK_k2))
Step. 2. Adjust the $K_{\text{ref}}$ from an Ionic Strength of 0 to the Ionic Strength at each step of the assay
$$ \begin{equation} \frac {K_{\text{ref}_{I=0\text{, }T=\text{37°C}}}}{\Gamma_{I=\text{CK Clamp}}} = K_{\text{ref}_{I=\text{CK Clamp, }T=\text{37°C}}} \end{equation} $$(See above section Debye–Hückel for more details)
# CK Clamp temperature in Kelvin
temp37 = 273.15 + 37
# List to hold the new CK_Kref at each steop of the CK Clamp titration
CK_kref_titration = []
# iterate through each step in the CK clamp and
# adjust the constant to the appropriate ionic strength
for ion_str in ionicStrengths:
# We use our function solve_gamma (based on the extended Debye–Hückel equation, defined above)
# to calculate Γ
gamma = solve_gamma(Kref_CK.prod, Kref_CK.react, temp37, ion_str)
# We divide the temperature-adjusted constant (from step 1) by gamma
# to adjust to the new ionic strength
CK_k3 = CK_k2/gamma
# Append the constant to the end of our holding list
CK_kref_titration.append(CK_k3)
# Print the Results
print('{0: <8}{1: <16}'.format('Step', 'Creatine Kinase Krefs'))
print('{:-^29}'.format(''))
for idx, step in enumerate(CK_kref_titration):
print('{0: <8}{1: <#12.6}'.format(idx+1, step))
The following function accepts 5 arguments:
calc_CK_Keq_steps
performs the same calculations (steps 1 and 2) to each of the equilibrium constants in the chemical equation of the Creatine Kinase reaction. It then uses those values (along with the experimental conditions) to solve the apparent equilibrium constant of CK (K`). This is repeated for each step in the assay and stored in a list.
def calc_CK_Keq_steps(ionicStrengths, tempK, CK_kref_titration, pH, freeMg):
'''
ionicStrengths = list of ionic strength values over titration. (Molarity)
temp = temperature of the assay in Kelvins
pH = the pH of the assay
freeMg = list of free Magnesium concentration over the titration. (Molarity)
Returns a list of the apparent CK Eq. Constants (Keq_CK)
'''
# Convert input variables into necessary units
proton = 10**-pH
temp25 = 273.15 + 25
# List to store CK Equilibrium Constants calculated for each step of the CK-Clamp titration
Keq_CK = []
# Make sure the 2 lists are equal
if len(ionicStrengths) != len(freeMg):
raise ValueError('Size mismatch: the length of ionicStrengths and freeMg are not equal')
# A list of the constants contained in the Creatine Kinase reaction
ck_Ks = [is0_Ka_atp,
is0_Kb_mg_atp,
is0_Kb_mg_hatp,
is0_Ka_adp,
is0_Kb_mg_adp,
is0_Kb_mg_hadp,
is0_Ka_pcr,
is0_Kb_mg_pcr]
# iterate through each ionic strength change in the CK Clamp
for index, ion_str in enumerate(ionicStrengths):
# a dictionary to store the modified equilibrium constants at each step in the titration
new_Kabs = {}
# Free Magnesium at the specific ionic strength
mg = freeMg[index]
# iterate through the acid and Mg-binding Krefs in the CK Eq reaction
for k1 in ck_Ks:
# Use Van't Hoff
# new kref (k2) adjusted from I=0, T=25°C to I=0, T=tempK
k2 = vant_hoff(temp25, tempK, k1.kref, k1.dH)
# Use Debye–Hückel
# new kref (k3) adjusted from I=0,T=25°C to new I, T=tempK
# the k1 object contains the product and reactant charges
k3 = k2/solve_gamma(k1.prod, k1.react, tempK, ion_str)
# Store the new equilibrium constant
new_Kabs[k1.name] = k3
# Modified Equilibrium Constant for the Creatine Kinase Reaction
products = (1 + proton/new_Kabs['Ka_atp'] + new_Kabs['Kb_mg_atp']*mg
+ new_Kabs['Kb_mg_hatp']*proton*mg/new_Kabs['Ka_atp'])
react_adp = (1 + proton/new_Kabs['Ka_adp'] + new_Kabs['Kb_mg_adp']*mg
+ new_Kabs['Kb_mg_hadp']*proton*mg/new_Kabs['Ka_adp'])
react_pcr = (1 + proton/new_Kabs['Ka_pcr'] + new_Kabs['Kb_mg_pcr']*mg)
Kf_CK = CK_kref_titration[index] * proton * products/(react_adp * react_pcr)
# Append the apparent Keq to our holding list
Keq_CK.append(Kf_CK)
return Keq_CK
# CK Clamp temperature in Kelvins
temp37 = 273.15 + 37
Keq_CK = calc_CK_Keq_steps(ionicStrengths, temp37, CK_kref_titration, pH, freeMg)
# Print the Results
print('{0: <8}{1: <16}'.format('Step', 'Creatine Kinase K`'))
print('{:-^26}'.format(''))
for idx, step in enumerate(Keq_CK):
print('{0: <8}{1: <#12.6}'.format(idx+1, step))
This section has the same format as Section 3
Step 1. Use the Van't Hoff equation to adjust $K_{\text{ref}_{I=0, T=25°C}}$ to 37°C.
$$ K_{\text{ref}_{I=0, T=37°C}} = e^{\left\{-\frac{\Delta H ^\circ}{R}\left( \frac{1}{T_2} - \frac{1}{T_1} \right) + \ln \left(K_{\text{ref}_{I=0, T=25°C}}\right)\right\}} $$(See above section Van't Hoff for more details)
# The temperature of the reference constant
temp25 = 273.15 + 25
# The temperature to which we will adjust the constant
temp37 = 273.15 + 37
# We use the function vant_hoff (defined above) to solve the Van't Hoff equation
# and adjust the constant to 37°C
ATP_k2 = vant_hoff(temp25, temp37, Kref_ATP.kref, Kref_ATP.dH)
print('ATP Hydrolysis Kref\n -Ionic Strength 0\n -Temp. 37°C\n')
print('{:.4e}'.format(ATP_k2))
Step. 2. Adjust the $K_{\text{ref}}$ from an Ionic Strength of 0 to the Ionic Strength at each step of the assay
$$ \begin{equation} \frac {K_{\text{ref}_{I=0\text{, }T=\text{37°C}}}}{\Gamma_{I=\text{CK Clamp}}} = K_{\text{ref}_{I=\text{CK Clamp, }T=\text{37°C}}} \end{equation} $$(See above section Debye–Hückel for more details)
# Assay temperature in Kelvin
temp37 = 273.15 + 37
# List to hold the new ATP_Kref at each steop of the assay
ATP_kref_titration = []
# iterate through each step in the assay and
# adjust the constant to the appropriate ionic strength
for ion_str in ionicStrengths:
# We use our function solve_gamma (based on the extended Debye–HüATPel equation, defined above)
# to calculate Γ
gamma = solve_gamma(Kref_ATP.prod, Kref_ATP.react, temp37, ion_str)
# We divide the temperature-adjusted constant (from step 1) by gamma
# to adjust to the new ionic strength
ATP_k3 = ATP_k2/gamma
# Append the constant to the end of our holding list
ATP_kref_titration.append(ATP_k3)
# Print the Results
print('{0: <8}{1: <16}'.format('Step', 'ATP Hydrolysis Krefs'))
print('{:-^28}'.format(''))
for idx, step in enumerate(ATP_kref_titration):
print('{0: <8}{1: <#12.6}'.format(idx+1, step))
The following function accepts 5 arguments:
calc_ATP_Keq_steps
performs the same calculations (steps 1 and 2) to each of the equilibrium constants in the chemical equation of ATP Hydrolysis. It then uses those values (along with the experimental conditions) to solve the apparent equilibrium constant of ATP Hydrolysis (K`). This is repeated for each step in the assay and stored in a list.
def calc_ATP_Keq_steps(ionicStrengths, tempK, ATP_kref_titration, pH, freeMg):
'''
ionicStrengths = list of ionic strength values over titration. Unit = Molarity
temp = temperature of the assay in Kelvin
pH = the pH of the assay
freeMg = list of free Magnesium concentration over the titration. Unit = Molarity.
Returns a list of the apparent ATP Hydrolysis Eq. Constants (Keq_ATP)
'''
# Convert input variables into necessary units
proton = 10**-pH
# Temp. of all reference constants
temp25 = 273.15 + 25
# List to store ATP Equilibrium Constants calculated for each step of the ATP-Clamp titration
Keq_ATP = []
# Make sure the 2 lists are equal
if len(ionicStrengths) != len(freeMg):
raise ValueError('Size mismatch: the length of ionicStrengths and freeMg are not equal')
# A list of the constants contained in the ATP Hydrolysis reaction
atp_Ks = [is0_Ka_atp,
is0_Kb_mg_atp,
is0_Kb_mg_hatp,
is0_Ka_adp,
is0_Kb_mg_adp,
is0_Kb_mg_hadp,
is0_Ka_pho,
is0_Kb_mg_pho]
# iterate through each ionic strength change in the assay
for index, ion_str in enumerate(ionicStrengths):
# a dictionary to store the modified equilibrium constants at each step in the titration
new_Kabs = {}
# Free Magnesium at the specific ionic strength
mg = freeMg[index]
# iterate through the acid and Mg-binding Krefs in the ATP Eq reaction
for k1 in atp_Ks:
# Use Van't Hoff
# new kref (k2) adjusted from I=0, T=25°C to I=0, T=tempK
k2 = vant_hoff(temp25, tempK, k1.kref, k1.dH)
# Use Debye–Hückel
# new kref (k3) adjusted from I=0,T=25°C to new I, T=tempK
# the k1 object contains the product and reactant charges
k3 = k2/solve_gamma(k1.prod, k1.react, tempK, ion_str)
# Store the new equilibrium constant
new_Kabs[k1.name] = k3
# Modified Equilibrium Constant for the ATP Hydrolysis Reaction
react = (1 + proton/new_Kabs['Ka_atp'] + new_Kabs['Kb_mg_atp']*mg
+ new_Kabs['Kb_mg_hatp']*proton*mg/new_Kabs['Ka_atp'])
prod_adp = (1 + proton/new_Kabs['Ka_adp'] + new_Kabs['Kb_mg_adp']*mg
+ new_Kabs['Kb_mg_hadp']*proton*mg/new_Kabs['Ka_adp'])
prod_pho = (1 + proton/new_Kabs['Ka_pho'] + new_Kabs['Kb_mg_pho']*mg)
Kf_ATP = (ATP_kref_titration[index] * prod_adp * prod_pho)/(react * proton)
Keq_ATP.append(Kf_ATP)
return Keq_ATP
# Assay temperature in Kelvin
temp37 = 273.15 + 37
Keq_ATP = calc_ATP_Keq_steps(ionicStrengths, temp37, ATP_kref_titration, pH, freeMg)
# Print the Results
print('{0: <8}{1: <16}'.format('Step', 'ATP Hydrolysis K`'))
print('{:-^25}'.format(''))
for idx, step in enumerate(Keq_ATP):
print('{0: <8}{1: <#12.6}'.format(idx+1, step))
The ultimate goal of this endeavor is to determine the Gibbs energy of ATP hydrolysis ($\Delta G'_{ATP}$) within our Creatine Kinase Clamp.
The following equation relates the apparent Gibbs energy of ATP Hydrolysis ($\Delta G'_{ATP}$) with the apparent standard Gibbs energy of ATP hydrolysis ($\Delta G'{^\circ}_{ATP}$)
$$ \begin{equation} \Delta G'_{ATP} = \Delta G'{^\circ}_{ATP} + \mathbf{R}T \ln \frac {[\text{ADP}][\text{P}_i]}{[\text{ATP}]} \end{equation} $$The apparent standard Gibbs energy under specified conditions of pH, Ionic Strength, Free Magnesium, and Pressure (which we are not considering in our equations):
$$ \Delta G'{^\circ}_\text{ATP} $$Another way to express $\Delta G'{^\circ}_\text{ATP}$: $$ \begin{equation} \Delta G'{^\circ}_\text{ATP} = -\mathbf{R}T \ln K'_{\text{ATP}} \end{equation} $$
Where $K'_{\text{ATP}}$ is the apparent equilbrium constant of ATP hydrolysis. In section 4 we calculated this value at each step in the assay. We will now use those values to calculate $\Delta G'{^\circ}_\text{ATP}$ over the CK clamp.
# Temperature of the assay
t37 = 273.15 + 37
# A list to store the apparent standard Gibbs energy for each step
dG_std_ATP = []
# iterate through each step of the assay
# and calculate the G`° of ATP Hyd.
for keq in Keq_ATP:
# solve the equation and store the value in a temporary variable
dG_std = -const.R * t37 * np.log(keq)
# Store the value on our list
dG_std_ATP.append(dG_std)
# Print the Results
print('{0: <8}{1: <16}'.format('Step', 'ΔG°` of ATP Hydrolysis (kJ/mol)'))
print('{:-^39}'.format(''))
for idx, step in enumerate(dG_std_ATP):
print('{0: <8}{1: <#12.6}'.format(idx+1, step/1000))
In section 3, we adjusted the Creatine Kinase Equilibrium Constants to conditions of our assay. We will now use those values to determine the concentration of ATP and ADP at each step in the assay.
Below, we define 2 functions to solve for the concentrations of each species in the following Equilibrium Reaction:
$$ \begin{equation} K'_{CK} = \frac {[\text{ATP}][\text{Cr}]} {[\text{ADP}][\text{PCr}]} \end{equation} $$Step 1 This solves the concentrations of ATP, ADP, Cr, and PCr after the first step in the titration. Prior to this step, the buffer contains Creatine Kinase, Creatine, and Phosphocreatine. After the ATP is added, the equilibrium produces ADP and PCr at the expense of ATP and Creatine.
The function solves the following equation for x:
$$ \begin{equation} K'_{CK} = \frac {[\text{ATP} - x][\text{Cr} - x]} {[\text{ADP} + x][\text{PCr} + x]} \end{equation} $$Where
This equilibrium can be rearranged to the following quadratic formula.
$$ \begin{equation} \left(K'_{CK} - 1 \right)x^2 + \left(K'_{CK} \times [\text{PCr}] + [\text{ATP}] + [\text{Cr}] \right) x - \left( [\text{ATP}] \times [\text{Cr}] \right) = 0 \end{equation} $$We can use the quadratic equation to solve for x:
$$ x={\frac {-b\pm {\sqrt {b^{2}-4ac\ }}}{2a}} $$Where
# Defining a class to hold the concentration data
class CK_concentration:
def __init__(self, atp, cr, adp, pcr):
self.atp = atp
self.cr = cr
self.adp = adp
self.pcr = pcr
def calc_step_one_conc(Keq_CK, ATP, Cr, PCr):
a = (Keq_CK - 1)
b = (Keq_CK*PCr + ATP + Cr)
c = -ATP*Cr
x = (-1*b + np.sqrt((b**2) - 4*(a*c))) / (2*a)
atp = ATP-x
cr = Cr-x
adp = x
pcr = PCr+x
concentrations = CK_concentration(atp, cr, adp, pcr)
return concentrations
Step 2 This solves the concentrations of ATP, ADP, Cr, and PCr for all steps in the titration except the first (where ATP is added)
The function solves the following equation for x:
$$ \begin{equation} K'_{CK} = \frac {[\text{ATP} + x][\text{Cr} + x]} {[\text{ADP} - x][\text{PCr}_\text{pre} + \left( \text{PCr}_\text{addition} - x \right)]} \end{equation} $$Where
This equilibrium can be rearranged into the following quadratic formula
$$ \left(K'_{CK} - 1 \right)x^2 - \left( K'_{CK} \left([\text{ADP}] - [\text{PCr}_\text{pre}] - [\text{PCr}_\text{addition}]\right) - [\text{ATP}] - [\text{Cr}]\right)x + \left( K'_{CK} \times [\text{ADP}] \times [\text{PCr}_\text{pre}] + K'_{CK} \times [\text{ADP}] \times [\text{PCr}_\text{addition}] - [\text{ATP}] \times [\text{Cr}]\right) = 0 $$Again, we can use the quadratic equation to solve for x:
$$ x={\frac {-b\pm {\sqrt {b^{2}-4ac\ }}}{2a}} $$Where
a = $K'_{CK} - 1$
b = $ -\left( K'_{CK} \left([\text{ADP}] - [\text{PCr}_\text{pre}] - [\text{PCr}_\text{addition}]\right) - [\text{ATP}] -[\text{Cr}]\right)$
def calc_step_conc(Keq_CK, ATP, Cr, ADP, PCr_pre, PCr_add):
a = (Keq_CK - 1)
b = Keq_CK*(ADP - PCr_pre - PCr_add) - ATP - Cr
c = Keq_CK*ADP*PCr_pre + Keq_CK*ADP*PCr_add - ATP*Cr
x = (-1*b - np.sqrt((b**2) - 4*(a*c))) / (2*a)
atp = ATP+x
cr = Cr+x
adp = ADP-x
pcr = PCr_pre + (PCr_add - x)
concentrations = CK_concentration(atp, cr, adp, pcr)
return concentrations
# Calculate the concentrations of ATP, Creatine, ADP, and PCr at each step in the CK Clamp
# Starting Concentrations [M]
ATP = 0.005
Cr = 0.005
PCr = 0.001
# A list to store the concentrations
step_concentrations = []
# Calc. the first step with addition of ATP
# and add it to the list
step_concentrations.append(calc_step_one_conc(Keq_CK[0], ATP, Cr, PCr))
# Calc. second step (addition of 2mM PC)
# and add it to the list
PCr_add = 0.002
step_concentrations.append(calc_step_conc(Keq_CK[1],
step_concentrations[0].atp,
step_concentrations[0].cr,
step_concentrations[0].adp,
step_concentrations[0].pcr,
PCr_add))
# Calc. remaining steps (each with addition of 3mM PCr)
# and add them to the list.
PCr_add = 0.003
index = np.arange(2, len(Keq_CK))
for idx in index:
step_concentrations.append(calc_step_conc(Keq_CK[idx],
step_concentrations[idx-1].atp,
step_concentrations[idx-1].cr,
step_concentrations[idx-1].adp,
step_concentrations[idx-1].pcr,
PCr_add))
# Print the Results
print('{: ^60}'.format('Concentrations over the CK Clamp (mM)'))
print('{0: ^12}{1: ^12.6}{2: ^12.6}{3: ^12.6}{4: ^12.6}'.format('Step', 'ATP', 'ADP', 'PCr', 'Cr'))
print('{:-^60}'.format(''))
for idx, step in enumerate(step_concentrations):
print('{0: ^12}{1: ^12.6}{2: ^12.6}{3: ^12.6}{4: ^12.6}'.format(idx+1,
step.atp*1000,
step.adp*1000,
step.pcr*1000,
step.cr*1000))
Now, we will use the $\Delta G'{^\circ}_{ATP}$ along with the concentrations of ATP, ADP, and Phosphate to calculate the apparent Gibbs Energy of ATP Hydrolysis with the following equation
$$ \begin{equation} \Delta G'_{ATP} = \Delta G'{^\circ}_{ATP} + \mathbf{R}T \ln \frac {[\text{ADP}][\text{P}_i]}{[\text{ATP}]} \end{equation} $$# List to store the ΔG' of ATP Hydrolysis at each step of the titration
dG_ATP = []
temp37 = 273.13 + 37
for index, step in enumerate(step_concentrations):
dG_ATP.append(dG_std_ATP[index] + const.R * temp37 * np.log(step.adp*phosphate/step.atp))
print('{0: <8}{1: <16}'.format('Step', 'ΔG` of ATP Hydrolysis (kJ/mol)'))
print('{:-^38}'.format(''))
for idx, step in enumerate(dG_ATP):
print('{0: <8}{1: <#12.6}'.format(idx+1, step/1000))
print('{0: <8}{1: <16}'.format('Step', 'ΔG` of ATP Hydrolysis (kCal/mol)'))
print('{:-^40}'.format(''))
for idx, step in enumerate(dG_ATP):
print('{0: <8}{1: <#12.6}'.format(idx+1, step/1000*0.239006))
This section's purpose is to highlight the importance of correcting for assay conditions.
# Import necessary libraries
import matplotlib.pyplot as plt
import matplotlib.gridspec as gridspec
%matplotlib inline
# Increase the matplotlib plot size for easier viewing
plt.rcParams['ytick.labelsize'] = 16
plt.rcParams['xtick.labelsize'] = 16
plt.rcParams['axes.titlesize'] = 24
plt.rcParams['legend.fontsize'] = 16
plt.rcParams['axes.labelsize'] = 20
plt.rcParams['figure.figsize'] = (8,6)
plt.rcParams['lines.linewidth'] = 3
plt.rcParams['figure.dpi'] = 120
# Generate lists to store the concentrations of each molecule
ADP = []
ATP = []
# A list of the ratio
ATP_ADP = []
for step in step_concentrations:
ADP.append(step.adp*1000)
ATP.append(step.atp*1000)
ATP_ADP.append(step.atp/step.adp*1000)
In the next cell, we will repeat the calculations performed in section 5.2.1. Instead of using the adjusted K`CK for each step in the assay, we will use a value that is widely used in the literature: 166. This constant is specified at pH 7.0, free Mg2+ 1 mM, Ionic Strength 0.25 M, and temperature of 38°C (Golding, Teague, and Dobson 1995).
# Calculate the concentrations of ATP, Creatine, ADP, and PCr at each step in the CK Clamp
# Use a constant from the literature without adjusting it over the clamp
iKeq_CK = [166]*11
# Starting Concentrations [M]
iATP = 0.005
iCr = 0.005
iPCr = 0.001
# A list to store the concentrations
istep_concentrations = []
# Calc. the first step with addition of ATP
# and add it to the list
istep_concentrations.append(calc_step_one_conc(iKeq_CK[0], iATP, iCr, iPCr))
# Calc. second step (addition of 2mM PC)
# and add it to the list
iPCr_add = 0.002
istep_concentrations.append(calc_step_conc(iKeq_CK[1],
istep_concentrations[0].atp,
istep_concentrations[0].cr,
istep_concentrations[0].adp,
istep_concentrations[0].pcr,
iPCr_add))
# Calc. remaining steps (each with addition of 3mM PCr)
# and add them to the list.
iPCr_add = 0.003
index = np.arange(2, len(iKeq_CK))
for idx in index:
istep_concentrations.append(calc_step_conc(iKeq_CK[idx],
istep_concentrations[idx-1].atp,
istep_concentrations[idx-1].cr,
istep_concentrations[idx-1].adp,
istep_concentrations[idx-1].pcr,
iPCr_add))
# Print the Results
print('{: ^60}'.format('Concentrations over the CK Clamp (mM)'))
print('{0: ^12}{1: ^12.6}{2: ^12.6}{3: ^12.6}{4: ^12.6}'.format('Step', 'ATP', 'ADP', 'PCr', 'Cr'))
print('{:-^60}'.format(''))
for idx, step in enumerate(istep_concentrations):
print('{0: ^12}{1: ^12.6}{2: ^12.6}{3: ^12.6}{4: ^12.6}'.format(idx+1,
step.atp*1000,
step.adp*1000,
step.pcr*1000,
step.cr*1000))
# Generate lists to store the concentrations of each molecule
# Non-adjusted equilibrium values
iADP = []
iATP = []
# A list of the ratio
iATP_ADP = []
for step in istep_concentrations:
iADP.append(step.adp*1000)
iATP.append(step.atp*1000)
iATP_ADP.append(step.atp/step.adp*1000)
Failing to accurately adjust the equilibrium constants can result in significant errors.
# Plot the ATP, ADP, and ATP/ADP ratios for adjusted (solid lines) and unadjusted (dotted lines)
ax1 = plt.subplot2grid((2, 4), (0, 0), colspan=2)
ax2 = plt.subplot2grid((2, 4), (1, 0), colspan=2)
ax3 = plt.subplot2grid((2, 4), (0, 2), colspan=2, rowspan=2)
# Adjusted [ATP]
ax1.plot(np.arange(1,9), ATP[0:8], label='ATP', color='C0')
ax1.scatter(np.arange(1,9), ATP[0:8], color='C0')
# Unadjusted [ATP]
ax1.plot(np.arange(1,9), iATP[0:8], label='iATP', ls='dotted', color='C0')
ax1.scatter(np.arange(1,9), iATP[0:8])
ax1.set_ylabel('[mM]')
ax1.set_xticks(np.arange(1,9))
ax1.set_xticklabels([], fontsize=8)
ax1.legend(loc='center right', )
# Adjusted [ADP]
ax2.plot(np.arange(1,9), ADP[0:8], label='ADP', color='C2')
ax2.scatter(np.arange(1,9), ADP[0:8], color='C2')
# Unadjusted [ADP]
ax2.plot(np.arange(1,9), iADP[0:8], label='iADP', color='C2', ls='dotted')
ax2.scatter(np.arange(1,9), iADP[0:8], color='C2')
ax2.set_ylabel('[mM]')
ax2.legend(loc='center right', )
ax2.set_xticks(np.arange(1,9))
ax2.set_xticklabels(['+ATP', '+PCr', '+PCr', '+PCr', '+PCr', '+PCr', '+PCr', '+PCr'], fontsize=8)
# Adjusted Ratio
ax3.plot(np.arange(1,9), ATP_ADP[0:8], label='ATP/ADP', color='C3')
ax3.scatter(np.arange(1,9), ATP_ADP[0:8], color='C3')
# Unadjusted Ratio
ax3.plot(np.arange(1,9), iATP_ADP[0:8], label='iATP/ADP', color='C3', ls='dotted')
ax3.scatter(np.arange(1,9), iATP_ADP[0:8], color='C3')
ax3.set_xticks(np.arange(1,9))
ax3.set_xticklabels(['+ATP', '+PCr', '+PCr', '+PCr', '+PCr', '+PCr', '+PCr', '+PCr'], fontsize=8)
ax3.legend()
plt.tight_layout()