clophfit.prenspire.thermo ========================= .. py:module:: clophfit.prenspire.thermo .. autoapi-nested-parse:: Joint van't Hoff fit of an EnSpire titration across temperatures. Instead of fitting pKa at each temperature independently, fit every well of every temperature as one model tied by the van't Hoff relation:: pKa(T) = dH / (2.303 R T) - dS / (2.303 R) (T in kelvin) The plateaus ``S0, S1`` stay free per (band, temperature) - brightness is not comparable across temperatures - while the two thermodynamic parameters are shared by all bands and all temperatures. Both reported pKa values therefore come from one fit over all the data, and ``dH`` of chromophore deprotonation falls out as a fitted quantity, not a two-point difference. ``pKa(T) = A + B (1/T - m)`` with the inverse-temperature axis centred on its mean ``m`` decorrelates the fitted pair; the reported constants are ``dH = 2.303 R B`` and ``dS = -2.303 R (A - B m)``. Hill slope is fixed to 1 (Henderson-Hasselbalch); see :func:`clophfit.prenspire.bands.band_rho` for the readout gate. Classes ------- .. autoapisummary:: clophfit.prenspire.thermo.VanthoffFit clophfit.prenspire.thermo.VanthoffModel Functions --------- .. autoapisummary:: clophfit.prenspire.thermo.titrant_kind clophfit.prenspire.thermo.fit_vanthoff_model clophfit.prenspire.thermo.vanthoff_titration Module Contents --------------- .. py:function:: titrant_kind(note) Decide per sample whether its titrant axis is pH or chloride. The titrant is the column that varies within a sample: a pH titration steps the pH and leaves the chloride alone, a chloride titration the other way round. Deciding once for the whole note would fit a chloride sample against its constant pH column and report a meaningless K. :param note: Normalised note with ``Well``, ``pH``, ``Cl``, ``Name`` and ``Temp``. :type note: pd.DataFrame :returns: Sample name to True when the sample is a pH titration. :rtype: dict[str, bool] .. py:class:: VanthoffFit Bases: :py:obj:`NamedTuple` The joint fit of one sample: pKa per temperature plus the pair behind it. .. py:attribute:: ok :type: bool Whether the fit converged. .. py:attribute:: k_by_temp :type: dict[str, tuple[float, float]] Temperature label to (pKa, standard error). .. py:attribute:: b :type: float Centred coefficients, pKa = A + B (1/T - m). .. py:attribute:: ds :type: float Enthalpy (J/mol) and entropy (J/mol/K) of deprotonation. .. py:attribute:: n :type: int Wells fitted. .. py:attribute:: plateaus :type: dict[tuple[str, str], tuple[float, float]] Fitted (S0, S1) per (band, temperature), for plotting. .. py:attribute:: m :type: float Inverse temperatures [1/K] and their centring mean. .. py:class:: VanthoffModel Bases: :py:obj:`NamedTuple` Everything needed to redraw one sample's joint fit. .. py:attribute:: is_ph :type: bool :value: True Whether the sample was fitted as a pH (else ligand) titration. .. py:function:: fit_vanthoff_model(data, *, is_ph = True) Fit (band, temp) curves jointly; pKa(T) = A + B (1/T - m). :param data: Band name and temperature label to its (x, y) curve, y already normalised and scaled by the caller. :type data: dict[tuple[str, str], tuple[ArrayF, ArrayF]] :param is_ph: pH titration (fit pKa(T) against a Henderson-Hasselbalch fraction) or ligand titration (fit pKd(T) against a Langmuir fraction and report Kd on the x scale). :type is_ph: bool :returns: The joint fit; ``ok=False`` when it did not converge or fewer than two temperatures were given. :rtype: VanthoffFit .. py:function:: vanthoff_titration(ef, note, *, buffer = True, is_ph = None, wanted = DIRECT_BANDS, min_rho = 0.8) Joint van't Hoff fit per sample of the note; one row per (sample, temp). :param ef: The parsed EnSpire export. :type ef: EnspireFile :param note: Normalised note with ``Well``, ``pH``, ``Cl``, ``Name`` and ``Temp``. :type note: pd.DataFrame :param buffer: Subtract the buffer wells of the same plate column. :type buffer: bool :param is_ph: Force the titrant column for every sample. ``None`` decides per sample with :func:`titrant_kind`, which is what a note mixing a pH and a chloride titration needs. :type is_ph: bool | None :param wanted: Band names entering the joint fit; default the two direct readouts. :type wanted: Sequence[str] :param min_rho: Monotonicity gate below which a band is dropped, as in the band path. :type min_rho: float :returns: One row per (sample, temperature): ``K``, ``se``, plus per-sample ``A``, ``B``, ``dH_J_mol``, ``dS_J_molK``, ``n``; and per sample the fitted pieces needed to redraw the joint model. :rtype: tuple[pd.DataFrame, dict[str, VanthoffModel]] .. rubric:: Notes pH titrations: pKa is the fitted midpoint (linear in 1/T). Ligand titrations (``is_ph=False``): pKd = -log10 Kd is what is linear in 1/T, so the model carries pKd(T) internally and the table reports Kd on its native mM scale (errors propagated log -> linear). The enthalpy is that of deprotonation / ligand dissociation respectively.