Closed bas-rustenburg closed 6 years ago
I'm working on implementing some other basic models (because it will be useful later in the complex model).
I was thinking about the titrant to buffer titrations. I think in our discussion we talked about a delta H of dilution, but I'm curious whether it is just an enthalpy, or actually the effect of a free energy that we are observing, so there would be a temperature dependence.
Something in the form of:
I suppose can directly subtract the suggested heats in our model that includes dilution. Can we model the single heats of dilution like this?
q_n[n] = (DeltaH_dil * V0 * (Ln[n] - d * Ln[n - 1])) * 1000 + DeltaH_0
And for the total model, something like this?
b = q_blank
t = q_titrant_dilution
d = q_titrand_dilution
x = q_titrant_titrand
and q_bind = q_x - q_t - q_d + q_b
The measured heat should reflect the change in the enthalpy of the system, not the change in free energy.
The dilution heats model will depend on what model we assume the injection follows:
Which model are we using for the titrant-titrand mixing right now?
I generally find it helpful to construct something like a "heat function" or "enthalpy function" that quantifies the total heat content as a function of thermodynamic parameters, in this case composition and volume: Q(x,V). Depending on the mixing model, we can differentiate and integrate, or subtract, the heat function to model the injection process and the heat released.
For a very simple dilution model, we might have
Q(x,V) = DeltaH0 * x * V
but we may need to get more sophisticated and have something that allows us to describe why the dilution heats are not uniform across all injections, such as
Q(x,V) = DeltaH0 * x * V + chi * x * (1-x) * V
Thanks John! That cleared up things.
Added 3 more models.
Two models for titrant into buffer titrations. A simple one and a model based on this paper: Calibration in isothermal titration calorimetry: heat and cell volume from heat of dilution of NaCl(aq),
though I think there might still be a bug or two, looking at some trial experiment that I did.
And one model for buffer into titrand titrations.
Cool!
Are you able to jointly analyze buffer-buffer, titrant-buffer, buffer-titrand, and titrant-titrand together at this stage?
Not yet. Step 1 was to figure out how to model each of them independently. Now that I've got that figured out, hopefully it won't prove too difficult to combine them.
I've begun implementing the multiexperiment model. Not functional yet. Also still a number of bugs in parts of the code. Making progress though.
Still got some bugs...
Order of magnitude mismatch between old and new models deltaH titrand and titrant.
This looks better, not there just yet. H_mech looks off.
Mechanical heat of mixing should always be exothermic, but there could be an experiment dependent heat effect that is due to mismatch between syringe and cell temperatures. This effect causes the heat of water water titrations to depend on temperature in some cases, I think.
Can you show the fits to the injection heats?
@jchodera, you mean these figures:
Plots aren't perfect yet.
Will post the distributions in a second. They look a little funky now that I've split things up, might be an indicator of some errors in the model..
Here are the distributions.
Cool!
By "fits to the data" I mean the model derived predictions of the integrated heats and the observed integrated heats.
Posterior predictive distribution of the injection heats, versus the observed heats (black line)
Very cool!
In a separate plot, can you also plot the family of models sampled from the posterior superimposed over the observed integrated heats, like this? I still find this very helpful.
For example, see In[13]
here:
http://nbviewer.ipython.org/github/choderalab/assaytools/blob/master/examples/fluorescence-binding-assay/Src-bosutinib%20with%20absorbance%20measurements%20in%20ScreenStar%20plate.ipynb
Seems to be a problem with titrant_into_buffer_predictive
...
Traces added. Looks a little hairy.
Whoa, looks like something is majorly wrong. Why would they be so bumpy?
I think that the trace got scrambled somehow.. now to find a way to unscramble it. Here is an unscrambled buffer buffer one, but this is manually recalculating the heats for every parameter in the trace. Looks much better
Still a little confused. Can you draw solid (non-dashed) lines?
They're all essentially flat lines, since all heats should be the same according to the current model. (neglecting the smaller initial heat here, still thinking of a solution for that.)
This is only the buffer buffer model, getting the trace for the other models and putting the parameters in the right order is a harder problem that I am tackling right now.
Here is the trace of the heats (e.g. the deterministic variable determined by the model).
I'm getting a little confused... I thought that this would just give me the model, with the value of the parameters filled in as that point in the trace of those parameters.. yet, the buffer buffer looks different from the picture I showed before, where I just threw the trace values of H_mech into the model and recalculated...
This looks like there is still a bug in either your plotting or your deterministics.
Let's resume debugging tomorrow.
Bug was in the plotting, I think I've got it:
Now I can move on to fixing the models...
Bug was in the plotting, I think I've got it:
Plots look much more reasonable now, thanks!
It does look like you might either not have enough burn-in steps or you are plotting all models, including the very early ones before the sampler has settled into the populated region of parameter space. Perhaps you could increase the number of burn-in iterations, or discard the first half of the data?
Plotting the experimental data as white circles connected by white lines isn't working, though. Can you go back to black or red circles, with no lines connecting them? The model should still be thin lines (dotted? blue? transparent?).
Also, if you can manage to plot the cumulative heat vs titrant concentration in the cell for the titrant-into-buffer, I think that would go along way toward establishing what complexity of model we need for the dilution heats. If it is pretty linear, we can probably use a simple model.
Yeah, this was just a short run. Not a lot of burn in. On Mar 28, 2015 4:06 PM, "John Chodera" notifications@github.com wrote:
Bug was in the plotting, I think I've got it:
Plots look much more reasonable now, thanks!
It does look like you might either not have enough burn-in steps or you are plotting all models, including the very early ones before the sampler has settled into the populated region of parameter space. Perhaps you could increase the number of burn-in iterations, or discard the first half of the data?
— Reply to this email directly or view it on GitHub https://github.com/choderalab/bayesian-itc/pull/57#issuecomment-87294205 .
Using a model that follows this equation for the cumulative heat: (plus the mechanical heat)
Interesting!
Any chance you can export the data pairs of ([X]_n, Q_n) to a text file for us to play with to see what works?
Here is the raw text. I can also email if that is more convenient.
stated_concentration cumulative_observed_heats model_concentrations model_cumulative_heats
2.029768194369673193e-06 -8.013264912622650726e-01 2.026287756756328881e-06 -3.909351073552982836e+00
3.223730114383260468e-05 -6.260916570597019337e+00 3.218202393741813300e-05 -3.459717945343822265e+00
6.200126601478397664e-05 -4.487019767046151131e+00 6.189495262446116750e-05 -3.434407410412215533e+00
9.132817617064910396e-05 -3.545048132875482150e+00 9.117157601286548249e-05 -2.991748860775755414e+00
1.202244493324809650e-04 -2.947011418838135555e+00 1.200183008192363981e-04 -2.973310475109562034e+00
1.486964089833757040e-04 -2.491901888383623920e+00 1.484414396838120613e-04 -2.537423149926453014e+00
1.767502857522647731e-04 -2.214510986798849945e+00 1.764472125518825750e-04 -2.525656546292495364e+00
2.043922187773864157e-04 -1.967691702135538900e+00 2.040417480349237915e-04 -2.096343021332084611e+00
2.316282570497387523e-04 -1.737558880542648954e+00 2.312310847517465100e-04 -2.091053675263612632e+00
2.584643607368026499e-04 -1.587787365490973102e+00 2.580211726499498262e-04 -1.668122283220037749e+00
2.849064024868286143e-04 -1.432699317604888112e+00 2.844178743079713695e-04 -1.669121342595316193e+00
Units are molar and microcalories respectively for [X] and Q.
Hm. Is cumulative_observed_heats
really the cumulative observed heat? It doesn't seem to be monotonic.
Might have saved the wrong array! Checking... On Mar 30, 2015 10:05 PM, "John Chodera" notifications@github.com wrote:
Hm. Is cumulative_observed_heats really the cumulative observed heat? It doesn't seem to be monotonic. [image: stated_concentration vs observed_cumulative_heats] https://cloud.githubusercontent.com/assets/3656088/6911005/ee619732-d728-11e4-8d2f-5b90b759c81b.png
— Reply to this email directly or view it on GitHub https://github.com/choderalab/bayesian-itc/pull/57#issuecomment-87899006 .
Yeah, my bad.. this should be correct.
stated_concentration cumulative_observed_heats model_concentrations model_cumulative_heats
2.029768194369673193e-06 -8.013264912622650726e-01 2.012237405903344579e-06 -3.949380125291007460e+00
3.223730114383260468e-05 -7.062243061859284410e+00 3.195887264709809775e-05 -7.443596481892620353e+00
6.200126601478397664e-05 -1.154926282890543554e+01 6.146577083747025176e-05 -1.091219097295017626e+01
9.132817617064910396e-05 -1.509431096178091813e+01 9.053938908555023190e-05 -1.393268206117227237e+01
1.202244493324809650e-04 -1.804132238061905369e+01 1.191860896835442624e-04 -1.693450796058824182e+01
1.486964089833757040e-04 -2.053322426900267672e+01 1.474121414996201306e-04 -1.949508496778808819e+01
1.767502857522647731e-04 -2.274773525580152622e+01 1.752237213497476881e-04 -2.204375063130386536e+01
2.043922187773864157e-04 -2.471542695793706557e+01 2.026269153493943931e-04 -2.415782206080246652e+01
2.316282570497387523e-04 -2.645298583847971585e+01 2.296277202453750484e-04 -2.626653907474391048e+01
2.584643607368026499e-04 -2.804077320397068718e+01 2.562320447281419352e-04 -2.794712248817040035e+01
2.849064024868286143e-04 -2.947347252157557662e+01 2.824457107248068443e-04 -2.962871723927549894e+01
Awesome, thanks!
Not sure if your implementation of the model above is correct. In the plot you give, the largest heat effect is for the first (tiny) injection. Perhaps you are computing the mole fraction x incorrectly? The mole fraction of titrant should be really tiny for the first injection.
A simple model where I use $Q = DeltaH0 * x + \chi * x * (1-x)$ seems to work decently well: Here, I used ~55M for the concentration of water, and computed the mole fraction of titrant in the cell $x = [X]_n / (55 + [X]_n)$, where [X]_n is the molar concentration of titrant in the cell after injection $n$.
I'm still not sure this is the best form---I think we actually want to adopt a reasonable form for the partial molar enthalpy $L(\phi)$ and then work out how this causes heat to be released on dilution.
Not sure if your implementation of the model above is correct.
I will doublecheck. It's quite possible that I made a mistake somewhere.
Glad to see that the model fits reasonably well.
Glad to see that the model fits reasonably well.
It may fit the injection heats $q_n$ less well. And it definitely needs the linear $x*DeltaH0$ term---doesn't seem to do well without it.
Copy pasting the model:
# Xn[n] is the ligand concentration in sample cell after n+1 injections
Xn = numpy.zeros([N])
# X_frac is the mole fraction of X * (1 - mole fraction of x) in the sample cell
X_frac = numpy.zeros([N])
kt = 1/beta
buffer_mass = 18.01528 # g / mol
buffer_density = 999.97 # g / liter
buffer_concentration = buffer_density / buffer_mass # mol /liter
# Equation 8 of Tellinghuisen Calibration in isothermal titration calorimetry:
# heat and cell volume from heat of dilution of NaCl(aq).
# http://dx.doi.org/10.1016/j.ab.2006.10.015
vcum = 0.0 # cumulative injected volume (liter)
for n in range(N):
# Instantaneous injection model (perfusion)
# dilution factor for this injection (dimensionless)
vcum += DeltaVn[n]
vfactor = vcum / V0 # relative volume factor
# total concentration of ligand in sample cell after n injections (converted from mM to M)
Xn[n] = 1.e-3 * Xs * (1 - numpy.exp(-vfactor))
X_frac[n] = x_times_onemx(mole_fraction(Xn[n], buffer_concentration)) # (x * (1-x))
# Compute expected injection heats.
# q_n_model[n] is the expected heat from injection n
q_n = numpy.zeros([N])
# Instantaneous injection model (perfusion)
# first injection
# From units of cal/mole to ucal
# page 149 of Atkins physical chemistry, 8th edition, eq. 5.30 H^E = n* chi *RT * x_a * x_b
q_n[0] = 1.e9 * V0 * (buffer_concentration + Xn[0]) * chi * kt * (X_frac[0]) + H_0
for n in range(1, N):
# subsequent injections
# From units of cal/mole to ucal
q_n[n] = 1.e9 * V0 * (buffer_concentration + Xn[n]) * chi * kt * (X_frac[n]) + (2 * H_0) - q_n[n-1]
return q_n
Convenience functions used:
def mole_fraction(*concentrations, **options):
"""Returns the molefraction of a component.
concentrations - positional arguments are concentrations for solution components
options supported:
index - zero-based index of component for which to calculate molefraction, 0 if not given
volumes - if given, list of volumes per component, otherwise, same volume is assumed for each component
Needs to be of the same length as components!
"""
for key in options:
if key not in ['index', 'volumes']:
raise NameError('Unexpected keyword argument: %s' % key)
if 'volumes' in options:
volumes = options['volumes']
assert(len(concentrations) == len(volumes))
moles = numpy.array(concentrations) * numpy.array(volumes)
else:
moles = concentrations
if 'index' in options:
index = options['index']
else:
index = 0
return moles[index] / sum(moles)
def x_times_onemx(x):
"""
x - number
Returns x * (1 - x)
"""
return x * (1 - x)
I actually don't have the H_0 * x term you used. Will try and add that, though I was curious about the physical interpretation.
Looks good!