Polarity, adduct, and isotope-model design record¶
Status: implemented in 0.5.0, with future extensions listed below.
Current model¶
spxtacular stores per-peak charge as a magnitude. Positive values are assigned charge states,
-1 means unknown or singleton, and 0 marks a neutral mass after decharge(). Scan polarity and
the mass of the repeated charge carrier are represented separately by IonizationModel.
@dataclass(frozen=True, slots=True)
class IonizationModel:
name: str
polarity: Polarity # tacular.types.Polarity: "positive" | "negative"
carrier_mass: float
carrier: str = "custom"
def ion_mz(self, neutral_mass, charge): ...
def neutral_mass(self, mz, charge): ...
carrier_mass is the signed ion-mass delta per unit charge. The built-in models are:
| Preset | Polarity | Neutral-mass equation |
|---|---|---|
[M+H]+ |
positive | M = mz*z - z*PROTON_MASS |
[M-H]- |
negative | M = mz*z + z*PROTON_MASS |
[M+Na]+ |
positive | M = mz*z - z*SODIUM_CATION_MASS |
[M+NH4]+ |
positive | M = mz*z - z*AMMONIUM_CATION_MASS |
The notation reflects charge magnitude. For example, sodiated charge 2 is displayed as
[M+2Na]2+.
Resolution and provenance¶
Spectrum.deconvolute() accepts a preset name, alias, signed carrier mass, or custom
IonizationModel. An explicit model is authoritative and must agree with known scan polarity.
When no model is passed, a negative scan uses [M-H]- and other scans use [M+H]+.
The output stores a DeconvolutionProvenance record containing the resolved isotope and ionization
models plus every envelope and matching parameter. decharge() reuses that record. In its absence,
it applies the same polarity fallback. Native .npz, namespaced matchms metadata, and spectrl user
parameters preserve the record. Copying, filtering, masking, and updating a spectrum preserve it
unless an operation invalidates deconvolution state.
decon = spec.deconvolute(
isotope_model="lipid",
ionization_model="[M+Na]+",
)
neutral = decon.decharge()
Automatic precursor removal also resolves the isotope and ionization models from explicit arguments, deconvolution provenance, or scan polarity. Mass conversions route through model methods instead of inline proton-only equations.
Isotope models¶
IsotopeModel predicts nominal isotope-envelope abundance from an average elemental composition.
Built-in models cover peptides, glycans, lipids, DNA, and RNA. Callers can supply custom atoms per
Dalton, fixed composition, and isotope abundances. The exact custom model definition is stored in
deconvolution provenance.
The current deconvolution algorithm uses the 13C-12C mass difference (1.00335483507 Da) / charge for nominal isotope spacing. This is separate from the analyte-specific abundance model.
Future scope¶
The following extensions are not implemented:
- Mixed charge carriers such as
[M+2H+Na]3+. The current model repeats one carrier for every unit of charge. - Model-specific exact isotope mass offsets. A future isotope model could propagate probability-weighted exact mass shifts alongside nominal-bin abundance.
- Composition factories such as
for_nucleotides(),for_glycan(), andfor_lipid(). Current callers constructIsotopeModeldirectly or select a broad built-in model. - A chronological processing history. The current focused provenance record covers deconvolution only.
These extensions should preserve the existing charge sentinel meanings and continue routing mass
conversion through IonizationModel methods.