clophfit.prtecan.titration#
Prtecan/prtecan.py.
Classes#
Parameters defining the fitting data with callback support. |
|
Store (robust) linear fit result. |
|
Buffer handling for a titration. |
|
Manage titration results with optional lazy computation. |
|
Build titrations from grouped Tecanfiles and concentrations or pH values. |
|
Group tecan cli options. |
|
A per-well MCMC request, decided by the caller rather than parsed downstream. |
Functions#
|
Whether one label of one well carries no usable titration. |
Module Contents#
- clophfit.prtecan.titration.label_is_uninformative(x, y_masked, y_raw, *, floor, bg_multiplier, turnover_limit, amplitude=None, plate_amplitude=None, plate_amplitude_ratio=_MIN_PLATE_AMPLITUDE_RATIO, ignore_acid_step=False)#
Whether one label of one well carries no usable titration.
Dimness alone does not condemn a channel. Every well here has a dim 400 nm channel by construction, and a 485 nm channel can sit only a few counts above background and still trace a clean titration - L8 H11 runs 5.0 to -1.2 and pins K to 0.193 pH. What makes a dim channel useless is its curve being noise-shaped: a single-pKa titration is monotone, so an interior turnover is evidence there is no titration to fit.
- Parameters:
x (ArrayF) – Titrant axis, matching y_raw.
y_masked (ArrayF) – Signal after outlier masking, used for the brightness test.
y_raw (ArrayF) – Signal before masking, used for the shape test. The mask exists to protect the fit from a bad point, so screening the masked curve would delete the very evidence the screen is looking for: masking L8 E12 removes the spike to 22.8 that proves its channel is noise.
floor (float) – Read-noise scatter for this label, i.e.
bg_noise.bg_multiplier (float) – Multiples of floor the masked mean must reach.
turnover_limit (float | None) – Largest turnover a dim channel may show and still count as informative.
Nonedisables the exemption, which is right for label 1: its curve turns over at the acid end in most wells (65% by more than 0.05 of its range, 40% by more than 0.2), so monotonicity says nothing there. That turnover is real but not a 400 nm feature: both channels lose emission at the last acid addition, by an amount that depends on the mutant (arslanbaeva’sscripts/tecan_acid_turnover.py). It shows at 400 nm because that channel is bright in acid; without the last step only 20% of wells turn over by more than 0.05. At 485 nm the same loss steepens a curve that already falls toward acid, so a real titration stays monotone there (0.9% of wells turn over by more than 0.2).amplitude (float | None) – This label’s own swing, for the plate comparison below.
plate_amplitude (float | None) – Median swing of this label across the plate. When both are given, a label swinging less than plate_amplitude_ratio of it counts as dim however it compares with the read noise - which is what catches a well reading 1.0 count where the plate median is 93.
plate_amplitude_ratio (float) – Fraction of the plate median below which a label is dim.
ignore_acid_step (bool) – Leave the most acidic point out of the shape test (the brightness test still sees every point). For label 1 under
--acid-scale, whose acid turnover is the loss of emission the fit now models.
- Returns:
True when the label carries no usable titration.
- Return type:
bool
- class clophfit.prtecan.titration.TitrationConfig#
Parameters defining the fitting data with callback support.
- acid_scale: bool = False#
Free factor on the most acidic step, shared by both labels, in the global fit.
Both channels lose emission at the last acid addition by a mutant-dependent amount; see
clophfit.fitting.core.ACID_SCALE. Applies to the two-label global fits (lm/huber, fixed or gain-calibrated noise), not to the single-label or ODR ones.
- noise_alpha: tuple[float, ...] = ()#
Proportional noise coefficients per label.
When provided, adds a proportional term to the error estimate so that high-signal wells are appropriately down-weighted: y_err^2 = gain * signal + bg_err^2 + (alpha * signal)^2
Values typically from MCMC multi-noise shared_noise_params.csv. Empty tuple disables the correction (legacy behaviour).
- noise_gain: tuple[float, ...] = ()#
Poisson gain coefficients per label.
Replaces the hardcoded gain=1 in the shot-noise Poisson term: y_err^2 = gain * signal + bg_err^2 + (alpha * signal)^2
Values typically from MCMC multi-noise shared_noise_params.csv. Empty tuple keeps gain=1 (legacy behaviour).
- noise_floor: tuple[float, ...] = ()#
Read-noise floor per label, overriding the measured
bg_noise.bg_noiseis whatever one plate’s three to six buffer wells happened to scatter by, and it is estimated on far fewer degrees of freedom than a value pooled over a campaign. Supplying the floor lets a calibration fitted across plates be used instead.Empty tuple keeps
bg_noise(legacy behaviour).
- noise_floor_ref_gain: tuple[float, ...] = ()#
Reader Gain each
noise_floorwas quoted at, per label.Read noise is amplified along with the signal, so a floor measured at one PMT setting means nothing at another until it is moved there. Given a reference, the floor is scaled by
10 ** ((gain - ref) / 34.1)using the plate’s own Gain metadata, which makes one calibration portable across plates that were read at different settings.0.0disables scaling for that label, which is the right choice where no Gain dependence was measured. Empty tuple disables it for every label.
- mask_outliers: bool = False#
Mask geometric outliers in each well’s curve before fitting. Default is False.
- outlier_threshold: float = 0.2#
Threshold for geometric outlier scoring (0-1). Default is 0.2.
- set_callback(callback)#
Set the callback to be triggered on parameter change.
- Parameters:
callback (collections.abc.Callable[[], None])
- Return type:
None
- class clophfit.prtecan.titration.BufferFit#
Store (robust) linear fit result.
- property empty: bool#
True when all attributes are NaN, emulating DataFrame’s empty behavior.
- Return type:
bool
- class clophfit.prtecan.titration.Buffer#
Buffer handling for a titration.
Manages background correction and fitting for buffer wells.
- property dataframes: dict[str, pandas.DataFrame]#
Buffer dataframes with fit.
- Return type:
dict[str, pandas.DataFrame]
- property dataframes_nrm: dict[str, pandas.DataFrame]#
Buffer normalized dataframes with fit.
- Return type:
dict[str, pandas.DataFrame]
- property wells: list[str]#
List of buffer wells.
- Return type:
list[str]
- property bg: dict[str, clophfit.clophfit_types.ArrayF]#
List of buffer values.
- Return type:
dict[str, clophfit.clophfit_types.ArrayF]
- property bg_err: dict[str, clophfit.clophfit_types.ArrayF]#
List of buffer SEM values.
- Return type:
dict[str, clophfit.clophfit_types.ArrayF]
- property bg_noise: dict[str, float]#
Intrinsic well noise (RMSE/pooled SD) values.
- Return type:
dict[str, float]
- property bg_read_noise: dict[str, float]#
Buffer measurement scatter, with fixed per-well offsets removed.
bg_noisepools the scatter of the buffer wells about the background trend, and on these plates that pooled number is dominated by fixed positional differences between buffer wells rather than by measurement noise – it runs 1.1x to 6.6x this value across the campaign. A positional offset is absorbed by a well’s own plateaus in any per-well fit, so it does not show up as point-to-point residual scatter and does not belong in a noise-model floor. This is the part that does.- Returns:
Per-label RMS interaction of the buffer readings, 0.0 for a label with no buffer wells.
- Return type:
dict[str, float]
- plot(*, nrm=False, title=None)#
Plot buffers of all labelblocksgroups.
- Parameters:
nrm (bool)
title (str | None)
- Return type:
seaborn.FacetGrid
- class clophfit.prtecan.titration.TitrationResults#
Bases:
clophfit.fitting.data_structures.ResidualsMixinManage titration results with optional lazy computation.
Provide either the small
scheme+fit_keysdirectly, or atitrationkeyword to snapshot both from aTitration:TitrationResults(scheme=tit.scheme, fit_keys=tit.fit_keys, results=res) TitrationResults(results=res, titration=tit) # equivalent, more concise
titrationis anInitVar: onlyschemeandfit_keysare copied off it, so the (potentially large) raw plate data is never retained.noise_modelcarries the calibrated per-label noise model when the fit produced one (fgls_fit_plate); it isNonefor plainfit_plate.- residual_table(*, binding_function=None, robust=None, student_t_nu=None, outlier_threshold=3.0)#
Compute the canonical plate-wide residual table.
Delegates to each well’s own
FitResult.residual_table(), so robustness is auto-detected per well from that well’s ownmini(its lmfitMinimizer, ODR output, or PyMC trace). A plate fitted withmethod="mcmc"therefore standardizes each well against its own trace, instead of being forced to Normal standardization.- Parameters:
binding_function (Callable[..., object] | None) – Model evaluated for
yhat; defaults tobinding_1site. Forwarded unchanged to each well.robust (bool | None) – Force the Student-t standardization of
std_res.Noneauto-detects per well from that well’s trace.student_t_nu (float | None) – Student-t degrees of freedom (
Noneuses detected/default).outlier_threshold (float) – Threshold for the
is_residual_outlierflag.
- Returns:
The canonical residual table (see
residuals), built by concatenating each well’s own table. Wells whose fit failed carry no dataset or result and are skipped, so the table may cover fewer wells thanfit_keys.- Return type:
pd.DataFrame
- property dataframe: pandas.DataFrame#
Convert FitResult dictionary to a DataFrame.
- Return type:
pandas.DataFrame
- compute_all()#
Compute results for all keys.
- Return type:
None
- n_sd(par='K', expected_sd=0.15)#
Compute median of K.
- Parameters:
par (str)
expected_sd (float)
- Return type:
float
- static all_computed()#
Check if all keys have been computed.
- Return type:
bool
- export_pngs(folder)#
Export all fit result plots as PNG files.
- Parameters:
folder (str | pathlib.Path)
- Return type:
None
- export_data(folder)#
Export all datasets as CSV files.
- Parameters:
folder (str | pathlib.Path)
- Return type:
None
- plot_k(xlim=None, title='', exclude=None)#
Plot K values as stripplot.
Wells fitted on fewer labels than the rest are marked with a trailing
*, and the title says how many there are. Their K rests on 3 parameters over 7 points rather than 6 over 14 and loses the ratiometric cancellation, so it is systematically less certain than its neighbours - which a bare stripplot would otherwise hide.- Parameters:
xlim (tuple[float, float] | None) – Range.
title (str) – To name the plot.
exclude (Mapping[str, Collection[str]] | None) – Wells to leave off the plot, keyed by the reason (e.g.
"undetermined","non-binding"); the title says how many were left off for each.
- Returns:
The figure.
- Return type:
figure.Figure
- class clophfit.prtecan.titration.Titration#
Bases:
clophfit.prtecan.models.TecanfilesGroupBuild titrations from grouped Tecanfiles and concentrations or pH values.
- Parameters:
tecanfiles (list[Tecanfile]) – List of Tecanfiles.
x (ArrayF) – Concentration or pH values.
is_ph
x_err
- Raises:
ValueError – For unexpected file format, e.g. header names.
- is_ph: bool = False#
Indicate if x values represent pH.
- x_err: clophfit.clophfit_types.ArrayF#
Uncertainties for x values (default is empty array).
- property fit_keys: set[str]#
Set of wells to be fitted.
- Return type:
set[str]
- detect_and_discard_bad_wells(*, outlier_threshold=0.2, bg_multiplier=3.0, max_k_stderr=None, monotone_turnover=_MONOTONE_TURNOVER)#
Detect and discard bad wells from masked per-label signal quality.
By default, each well is converted to a per-label dataset with
_create_ds(), masked withapply_outlier_mask(), and then discarded when the mean masked signal of any label falls below a background-derived floor. The floor usesbg_errwhen available and falls back tobg_noise.The signal test asks two things of a dim label, not one: that it clears the background, and failing that, that its curve still moves further than the read noise and moves monotonically. The second question is what separates a faint titration from a drift - L8 H11 swings six noise widths and pins K to 0.193 pH, while L2 C05 swings 1.7 and puts K at 7.138 +- 254 pH. A fit-quality test still runs alongside, for a well that is bright and uninformative, which no signal test can reach.
The smoothness, roughness and trendline criteria that used to sit here were removed. They were disabled by default, no caller ever passed them, and at plausible thresholds (0.5/0.5/3.0) they discarded 90 of 90 wells on L2 - not a criterion, a bug in waiting.
- Parameters:
outlier_threshold (float | None) – Threshold passed to
apply_outlier_mask()before computing per-label summary statistics. IfNone, no masking is applied.bg_multiplier (float | None) – Discard a well when any masked per-label mean signal is below
bg_multiplier * mean(background_floor). IfNone, this check is disabled.max_k_stderr (float | None) – Discard a well whose fitted K has a standard error above this, or a non-finite one.
Noneuses the titration’s own x span, which is the scale-free form of the rule: a well whose midpoint cannot be located inside the window actually titrated carries no information about K, however bright it is. Passmath.infto disable. pH only: a chloride well whose Kd cannot be located may not bind, and is fitted and reported as such rather than discarded.monotone_turnover (float | None) – Largest turnover a dim label past the first may show and still count as informative.
Nonedisables the exemption, restoring the rule that any dim label fails.
- Returns:
Newly discarded well keys.
- Return type:
list[str]
- clear_all_data_results()#
Clear fit keys, data, results and bg when buffer or scheme properties change.
- Return type:
None
- property params: TitrationConfig#
The datafit parameters.
- Return type:
- property bg: dict[str, clophfit.clophfit_types.ArrayF]#
List of buffer values.
- Return type:
dict[str, clophfit.clophfit_types.ArrayF]
- property bg_err: dict[str, clophfit.clophfit_types.ArrayF]#
List of buffer SEM values.
- Return type:
dict[str, clophfit.clophfit_types.ArrayF]
- property bg_noise: dict[str, float]#
Intrinsic well noise (RMSE/pooled SD) values.
- Return type:
dict[str, float]
- property bg_read_noise: dict[str, float]#
Buffer measurement scatter, with fixed per-well offsets removed.
See
Buffer.bg_read_noise. Reported alongsidebg_noiserather than replacing it:bg_noiseis whaty_errand the classical--plate-noise fixedpath are built on and calibrated against, while this is the candidate for a structured-noise floor.- Returns:
Per-label measurement scatter of the buffer wells.
- Return type:
dict[str, float]
- property sigma_floor: dict[str, float]#
The read-noise floor per label that the error models actually use.
params.noise_floorwhen supplied, otherwise the measuredbg_read_noise. A supplied floor carrying a non-zeroparams.noise_floor_ref_gainis scaled from that reference to this plate’s own reader Gain, so one campaign-wide calibration serves plates read at different settings; a reference of0.0leaves the value alone, which is right for a label whose floor showed no Gain dependence.- Returns:
Per-label floor. Falls back to the measured value for any label the override does not cover.
- Return type:
dict[str, float]
- classmethod fromlistfile(list_file, *, is_ph, base_dir=None)#
Build Titration from a list[.pH|.Cl] file.
- Parameters:
list_file (Path | str) – Path to the list file containing [filenames x x_err].
is_ph (bool) – Whether x values represent pH (True) or concentrations (False).
base_dir (Path | str | None) – Directory holding the Tecan files. Relative filenames in the list file are resolved against it; defaults to the list file’s own directory. Use it when list files and .xls files are kept in separate trees (e.g. data/processed/ and data/raw/).
- Returns:
The constructed Titration object.
- Return type:
- property additions: list[float] | None#
List of initial volume followed by additions.
- Return type:
list[float] | None
- load_additions(additions_file)#
Load additions from file.
Reads a CSV file with a single column ‘add’ containing addition volumes, and updates the Titration’s additions property.
- Parameters:
additions_file (Path) – Path to the additions CSV file.
- Return type:
None
- property data: dict[str, dict[str, clophfit.clophfit_types.ArrayF]]#
Buffer subtracted and corrected for dilution data.
- Return type:
dict[str, dict[str, clophfit.clophfit_types.ArrayF]]
- property scheme: clophfit.prtecan.models.PlateScheme#
Scheme for known samples like {‘buffer’, [‘H12’, ‘H01’], ‘ctrl’…}.
- Return type:
- load_scheme(schemefile)#
Load scheme from file and set buffer wells.
Reads a scheme file to define buffer wells, known samples, and control wells, then updates the Titration’s scheme and buffer wells.
- Parameters:
schemefile (Path) – Path to the scheme CSV file.
- Return type:
None
- create_ds(key, label)#
Create a dataset for the given key.
- Parameters:
key (str)
label (str)
- Return type:
- property excluded_labels: dict[str, set[str]]#
Labels dropped per well, keyed by well.
- Returns:
Well to the set of its excluded labels. Wells with every label excluded are discarded outright instead of appearing here.
- Return type:
dict[str, set[str]]
- exclude_label(key, label)#
Drop one label of one well from the global fit.
The 400 nm channel is dim by construction, so a well can fail a background test on one label while the other is perfectly usable. Discarding the well would throw away a good titration; dropping the label keeps it, at the cost of a less certain K - which is why the results table records how many labels each well was fitted on.
- Parameters:
key (str) – Well identifier.
label (str) – Label to drop for that well. Dropping every label discards the well.
- Return type:
None
- create_global_ds(key)#
Create a global dataset for the given key.
Applies
mask_outlierslikecreate_dataset_dict(). It used not to, and sinceppr tecanbuilds its global datasets here, the flag never reached the global, ODR, MCMC or plate fits - accepted, echoed back in the run configuration, and silently confined to the per-label path. Two builders of the same dataset must not disagree about what a flag means.- Parameters:
key (str) – Well identifier.
- Returns:
The well’s labels, masked and weighted as configured.
- Return type:
- create_dataset_dict(label=None)#
Create a dictionary of datasets for all fit_keys, optionally masking outliers.
- Parameters:
label (str | None) – Specific label to extract. If None, creates global datasets containing all labels. Default is None.
- Returns:
A dictionary mapping well keys to their corresponding Datasets.
- Return type:
dict[str, Dataset]
- fit_plate(datasets=None, method='', *, label=None, **kwargs)#
Run a single-pass fit on an entire plate of datasets.
- Parameters:
datasets (dict[str, Dataset] | None) – Mapping of well keys (e.g. ‘A01’) to Dataset objects. When
None, datasets are built withcreate_dataset_dict(), which also applies outlier masking whenparams.mask_outliersis set.method (str) – The fitting method: ‘lm’ (default), ‘huber’, ‘odr’, or ‘mcmc’. Other methods supported by
clophfit.fitting.core.fit_binding_glob()may also be used.label (str | None) – Build per-label datasets for this label instead of global ones. Only valid when datasets is
None.**kwargs (Any) – Additional keyword arguments passed to the fitting function.
- Returns:
Plate results carrying this titration’s
schemeandfit_keys.- Return type:
- Raises:
ValueError – If both datasets and label are given.
- fgls_fit_plate(datasets=None, *, label=None, sigma_floor=None, first_pass_method='huber', second_pass_method='lm', max_iter=3, tol=0.001)#
Run iterative Feasible Generalized Least Squares (FGLS) on the plate.
Fits every well with first_pass_method using the existing
y_errc, calibrates a per-label noise model from the plate-wide residuals with the floor anchored to sigma_floor, re-applies the calibrated weights and re-fits with second_pass_method, iterating until gain and alpha converge or max_iter is reached.- Parameters:
datasets (dict[str, Dataset] | None) – Mapping of well keys to Dataset objects. When
None, datasets are built withcreate_dataset_dict().label (str | None) – Build per-label datasets for this label instead of global ones. Only valid when datasets is
None.sigma_floor (dict[str, float] | None) – Known read-noise floor per label. Defaults to
sigma_floor.first_pass_method (str) – Method for the first-pass fit.
second_pass_method (str) – Method for subsequent passes.
max_iter (int) – Maximum FGLS iterations.
tol (float) – Relative tolerance for gain/alpha convergence.
- Returns:
Plate results carrying this titration’s
schemeandfit_keys, withnoise_modelset to the converged (or last) calibration.- Return type:
- Raises:
ValueError – If both datasets and label are given.
- plot_temperature(title='')#
Plot temperatures of all labelblocksgroups.
Creates a line plot showing measured temperatures versus concentration/pH values, with statistics overlays.
- Parameters:
title (str) – Additional title text to append to the plot.
- Returns:
The matplotlib Figure object containing the plot.
- Return type:
figure.Figure
- class clophfit.prtecan.titration.TecanConfig#
Group tecan cli options.
- detect_bad: bool = True#
Run bad-well detection before fitting, and act on undetermined K after it.
Before: discard unusable wells (
Titration.detect_and_discard_bad_wells). After: leave wells whose fitted K is undetermined (seemax_k_se) - and, for chloride, wells that do not bind - off the K plot, mark their per-well figure, and list them indiscarded_wells.txt. Theundetermined(andno_binding) columns of eachffit*.csvare written either way.
- ctr_free_k: bool = False#
Give every well its own K in –plate-fit, instead of pooling controls.
Mirrors what the flag already did for
--mcmc multi; without it the two fitters answer different questions from the same command line.
- plate_screen_z: float | None = None#
Drop points whose calibrated |z| exceeds this, then refit, for –plate-fit.
Nonefits once. 3.0 is the value measured to help (sum_log -5.92 against -5.49 unscreened, nine plates of eleven improved); 2.5 turns harmful, so this is not a knob to sweep casually.
- plate_screen_frac: float | None = None#
Also drop 400 nm points deviating fractionally by more than this.
A z-score fails at both ends of a titration: sigma tracks the signal while model error tracks the curve, so a 5% miss at the dim end reads as 3.6 sigma while a 36% miss at the bright end reads as 2.7.
|y - yhat| / yhatseparates reviewer keeps (0.097-0.111) from discards (0.126 up) over three plates. Points the 485 nm channel moves with are spared, since a shared multiplicative shift is what the ratiometric measurement cancels.Noneleaves the z-screen alone.
- plate_noise: str = 'fixed'#
How
--plate-fitweights its points."fixed"usesy_erras built - thebg_noisefloor, plus any--noise-gain/--noise-alphasupplied."calibrated"estimates gain and alpha per label from the fit’s own residuals and refits under them. Calibration describes the residuals better and fits K worse, so it is not the default; seefit_plate_lm. It sets the weights K is fitted with whether or notplate_screen_zis given."gain"and"floor-gain"weight byfloor^2 + gain * yhatwith alpha 0, the gain (and the floor) calibrated from dof-corrected residuals between refits; seecalibrate_plate_lm().
- plate_screen_noise: str = 'calibrated'#
The ruler
--plate-screen-zjudges points on."calibrated"(the default) calibrates gain and alpha from the screening pass’s own residuals so bright and dim points are judged on a comparable scale;"fixed"judges on the weights as built. Independent ofplate_noise: before the two were separate options,plate_noisemeant the fit’s weights without a screen but not after one.
- max_k_se: float = 0.3#
Largest standard error, in pH, at which a fitted pKa counts as determined.
pH is an interval scale, so the cut is absolute; a ratio
sK / KissK / 7here and never fires. 0.30 is three times the 0.10 pH ROPE and four times the 0.074 pH replicate repeatability; on eleven library plates it catches 32 of 875 library wells and none of 123 controls. Chloride ignores it: Kd is a ratio scale, undetermined whensKd > Kd, and a well whose 94% lower bound is above the highest concentration does not bind.
- fit_noise: str = 'fixed'#
How the per-well global lm/huber fit weights its points.
"fixed"usesy_erras built."gain"and"floor-gain"fit every well, pool all wells’ dof-corrected residuals into one gain per label (and with"floor-gain"one floor), and refit until it settles; seecalibrate_single_well().
- class clophfit.prtecan.titration.McmcSpec#
A per-well MCMC request, decided by the caller rather than parsed downstream.
- Parameters:
model (Literal["single", "single-refit", "multi"]) – Which fit to run.
"single"samples each well once;"single-refit"runs the robust screening pass then refits;"multi"fits every well jointly with control K shared across each control group.sampler (SamplerConfig) – NUTS controls forwarded to
pm.sample.structured_noise (bool) – Build the physical
floor + gain * y + (alpha * y) ** 2observation noise instead of scalingy_errby a learnedye_magmultiplier.floor_mode (Literal["centered", "fixed"] | None) – Override the mode for the floor alone;
Nonefollows noise_mode.gain_mode (Literal["centered", "fixed"] | None) – Override the mode for gain alone;
Nonefollows noise_mode.alpha_mode (Literal["centered", "fixed"] | None) – Override the mode for alpha alone;
Nonefollows noise_mode.noise_mode (Literal["centered", "fixed"]) – How a supplied gain/alpha hint is treated when structured_noise is set: centred on (a hint the posterior may leave) or pinned to it. A parameter with no supplied value is always free.
per_well_ye_mags (bool | None) – Whether the ye_mag multiplier is per well rather than per label.
Noneleaves the library to resolve it from the noise family, which couples the two; pass a bool to keep them independent. Only meaningful formodel="multi", since a single-well fit has one well.ye_mag_parameterization (Literal["centered", "hierarchical", "separable", "separable_step"]) – How per-well ye_mags are structured: independent per label (
"centered"), a shared well factor with per-label deviations ("hierarchical"), or a per-label level plus one shared well factor ("separable").robust (RobustConfig) – Likelihood family. The default is a plain Normal; a Student-t with
nu=3is the arm that scored best on this campaign’s plates.ctr_free_k (bool) – Give every well its own K instead of pooling each control group onto a shared one. Only meaningful for
model="multi". Pooling buys no accuracy at the construct level and makes the stated interval too narrow, and the library wells have no group to pool with, so free K is the setting that matches what a plate is fitted for.x_error_model (Literal["deterministic", "per_well"]) – The latent pH axis of
model="multi"."deterministic"is one pipetting walk shared by every well;"per_well"gives each well its own walk, with step SDs split from the measured pH errors into read noise plus accumulated pipetting variance. pH is measured in a few wells and their spread grows along a titration, so an unmeasured well’s pH is uncertain in a way only the per-well axis carries into its K: on eleven plates it took free-K single-well bulk z-SD from ~1.65 to ~0.95 at unchanged accuracy. The default keeps the historical shared axis.x_start_between_sigma (float | None) – For
x_error_model="per_well", the prior SD of each well’s offset at the first step. A per-well offset is degenerate with that well’s K, so this SD passes straight into K’s interval; set it to the measured well-to-well spread at the first step rather than a round number.Nonekeeps the library default.learn_x_start_between (bool) – For
x_error_model="per_well", estimate the between-well spread of the first-step offset instead of pinning it at x_start_between_sigma, which then becomes its prior scale.ctr_sigma_w_prior (float | None) – Prior scale, in pH, of the spread of a control group’s replicates around the group’s own K (
K_sigma_w). Given, each replicate keeps its own K a learned distance from the group’s: the middle ground between one shared K and a free one.None(default) leaves the model as it was.
- noise_ye_mag: bool = False#
Learn a ye_mag multiplier on top of a structured noise model.
A structured model builds sigma from floor, gain and alpha and, by default, has no overall multiplier: the terms themselves carry the level. With this set, sigma is also scaled by a learned ye_mag - per label, or per well when
per_well_ye_magsis set - which lets a calibrated shape keep its shape while the data set the level. Meaningless withoutstructured_noise.
- acid_scale: bool = False#
Per-well factor on the most acidic step, shared by labels (
model="multi"only).