Source code for matchms.filtering.filter_utils.derive_precursor_mz_and_parent_mass
import logging
from typing import Optional, Tuple
from matchms.constants import PROTON_MASS
from matchms.filtering.filter_utils.interpret_unknown_adduct import \
get_multiplier_and_mass_from_adduct
from matchms.filtering.filter_utils.load_known_adducts import \
load_known_adducts
from matchms.filtering.metadata_processing.clean_adduct import _clean_adduct
from matchms.typing import SpectrumType
logger = logging.getLogger("matchms")
[docs]def derive_parent_mass_from_precursor_mz(spectrum: SpectrumType, estimate_from_adduct: bool) -> Optional[float]:
"""Use the precursor mz, charge and adduct information to compute the mass of the case compound.
Args:
spectrum (SpectrumType): Spectrum with metadata.
estimate_from_adduct (bool): Whether to include adduct parsing or not.
Returns:
float: Parent compound neutral mass.
"""
if spectrum is None:
return None
precursor_mz = spectrum.get("precursor_mz", None)
if precursor_mz is None:
logger.warning("Missing precursor m/z to derive parent mass.")
return None
charge = _get_charge(spectrum)
if estimate_from_adduct:
multiplier, correction_mass = _get_multiplier_and_correction_mass_from_adduct(
spectrum.get("adduct"))
if correction_mass is not None and multiplier is not None:
parent_mass = (precursor_mz - correction_mass) / multiplier
return parent_mass
if _is_valid_charge(charge):
# Assume adduct of shape [M+xH] or [M-xH]
protons_mass = PROTON_MASS * charge
precursor_mass = precursor_mz * abs(charge)
parent_mass = precursor_mass - protons_mass
return parent_mass
return None
[docs]def derive_precursor_mz_from_parent_mass(spectrum: SpectrumType, estimate_from_adduct: bool = True) -> Optional[float]:
"""Derives the precursor_mz from the parent mass and adduct or charge"""
if spectrum is None:
return None
parent_mass = spectrum.get("parent_mass")
if parent_mass is None:
logger.warning("Missing parent mass to derive precursor mz.")
return None
if estimate_from_adduct:
multiplier, correction_mass = _get_multiplier_and_correction_mass_from_adduct(
spectrum.get("adduct"))
if correction_mass is not None and multiplier is not None:
precursor_mz = parent_mass * multiplier + correction_mass
return precursor_mz
charge = _get_charge(spectrum)
if _is_valid_charge(charge):
# Assume adduct of shape [M+xH] or [M-xH]
protons_mass = PROTON_MASS * charge
precursor_mass = parent_mass + protons_mass
precursor_mz = precursor_mass / abs(charge)
return precursor_mz
logger.error("Precursor mz could not be derived from parent mass, since charge and adduct were missing")
return None
def _get_multiplier_and_correction_mass_from_adduct(adduct: str) -> Tuple[int, float]:
"""Get the charge multiplier and correction mass for the specifiec adduct.
Args:
adduct (str): Adduct in string description, e.g. [M+Na]+
Returns:
Tuple[int, float]: Charge multiplier and correction mass needed to calculate the precursor mz from this adduct.
"""
adduct = _clean_adduct(adduct)
known_adducts = load_known_adducts()
if adduct in list(known_adducts["adduct"]):
multiplier = known_adducts.loc[known_adducts["adduct"] == adduct, "mass_multiplier"].values[0]
correction_mass = known_adducts.loc[known_adducts["adduct"] == adduct, "correction_mass"].values[0]
else:
multiplier, correction_mass = get_multiplier_and_mass_from_adduct(adduct)
return multiplier, correction_mass
def _is_valid_charge(charge: int) -> bool:
"""Check whether a charge specifier is valid.
Args:
charge (int): Charge number.
Returns:
bool: Validity state.
"""
return (charge is not None) and (charge != 0)
def _get_charge(spectrum: SpectrumType):
"""Get charge from `Spectrum()` object.
In case no valid charge is found, guess +1 or -1 based on ionmode.
Else return 0.
"""
charge = spectrum.get("charge")
if _is_valid_charge(charge):
return charge
if spectrum.get('ionmode') == "positive":
logger.info(
"Missing charge entry, but positive ionmode detected. "
"Consider prior run of `correct_charge()` filter.")
return 1
if spectrum.get('ionmode') == "negative":
logger.info(
"Missing charge entry, but negative ionmode detected. "
"Consider prior run of `correct_charge()` filter.")
return -1
logger.warning(
"Missing charge and ionmode entries. "
"Consider prior run of `derive_ionmode()` and `correct_charge()` filters.")
return 0