public Transition(TransitionGroup group, IonType type, int?offset, int?massIndex, int charge, int?decoyMassShift, CustomIon customIon = null) { _group = group; IonType = type; CleavageOffset = offset ?? 0; MassIndex = massIndex ?? 0; Charge = charge; DecoyMassShift = decoyMassShift; // Small molecule precursor transition should have same custom ion as parent if (IsPrecursor(type) && group.IsCustomIon) { CustomIon = group.CustomIon; } else { CustomIon = customIon; } // Derived values if (!IsCustom(type, group)) { Peptide peptide = group.Peptide; Ordinal = OffsetToOrdinal(type, (int)offset, peptide.Length); AA = (IsNTerminal() ? peptide.Sequence[(int)offset] : peptide.Sequence[(int)offset + 1]); } else { // caller may have passed in offset = group.Peptide.Length - 1, which for custom ions gives -1 CleavageOffset = 0; } Validate(); }
public static int CompareGroups(TransitionGroup group1, TransitionGroup group2) { int chargeDiff = group1.PrecursorCharge - group2.PrecursorCharge; if (chargeDiff != 0) { return(chargeDiff); } return(group1.LabelType.CompareTo(group2.LabelType)); }
public PeptideDocNode PermuteModificationsOnPeptide(SrmDocument document, PeptideGroupDocNode peptideGroupDocNode, PeptideDocNode peptideDocNode, List <IsotopeLabelType> partialLabelTypes) { if (SkipPeptide(peptideDocNode)) { return(peptideDocNode); } var potentiallyModifiedResidues = PotentiallyModifiedResidues(peptideDocNode, IsotopeModification); if (potentiallyModifiedResidues.Count == 0) { return(peptideDocNode); } // Create a document containing only one peptide so that "ChangePeptideMods" does not have to walk // over a long list of peptides to see which modifications are in use. var smallDocument = (SrmDocument)document.ChangeChildren(new DocNode[] { peptideGroupDocNode.ChangeChildren(new DocNode[] { peptideDocNode }) }); var newTypedExplicitModifications = PermuteTypedExplicitModifications(partialLabelTypes, peptideDocNode, potentiallyModifiedResidues); var newExplicitMods = new ExplicitMods(peptideDocNode.Peptide, peptideDocNode.ExplicitMods?.StaticModifications, newTypedExplicitModifications); var identityPath = new IdentityPath(peptideGroupDocNode.PeptideGroup, peptideDocNode.Peptide); smallDocument = smallDocument.ChangePeptideMods(identityPath, newExplicitMods, false, GlobalStaticMods, GlobalIsotopeMods); peptideDocNode = (PeptideDocNode)smallDocument.FindPeptideGroup(peptideGroupDocNode.PeptideGroup).FindNode(peptideDocNode.Peptide); var lightChargeStates = peptideDocNode.TransitionGroups.Where(tg => tg.IsLight).Select(tg => tg.PrecursorCharge).Distinct().ToList(); var chargeStatesByLabel = peptideDocNode.TransitionGroups.ToLookup(tg => tg.LabelType, tg => tg.PrecursorCharge); var transitionGroupsToAdd = new List <TransitionGroupDocNode>(); foreach (var typedExplicitModifications in newExplicitMods.GetHeavyModifications()) { var labelType = typedExplicitModifications.LabelType; foreach (var chargeState in lightChargeStates.Except(chargeStatesByLabel[labelType])) { var tranGroup = new TransitionGroup(peptideDocNode.Peptide, Adduct.FromChargeProtonated(chargeState), labelType); TransitionDocNode[] transitions = peptideDocNode.GetMatchingTransitions(tranGroup, smallDocument.Settings, newExplicitMods); var nodeGroup = new TransitionGroupDocNode(tranGroup, transitions); nodeGroup = nodeGroup.ChangeSettings(smallDocument.Settings, peptideDocNode, newExplicitMods, SrmSettingsDiff.ALL); transitionGroupsToAdd.Add(nodeGroup); } } if (transitionGroupsToAdd.Any()) { var newChildren = peptideDocNode.TransitionGroups.Concat(transitionGroupsToAdd).ToList(); newChildren.Sort(Peptide.CompareGroups); peptideDocNode = (PeptideDocNode)peptideDocNode.ChangeChildren(newChildren.Cast <DocNode>().ToList()); } return(peptideDocNode); }
public bool Equals(TransitionGroup obj) { if (ReferenceEquals(null, obj)) { return(false); } if (ReferenceEquals(this, obj)) { return(true); } bool equal = Equals(obj._peptide, _peptide) && Equals(obj.CustomIon, CustomIon) && obj.PrecursorCharge == PrecursorCharge && obj.LabelType.Equals(LabelType) && obj.DecoyMassShift.Equals(DecoyMassShift); return(equal); // For debugging convenience }
public Transition(TransitionGroup group, IonType type, int?offset, int?massIndex, Adduct adduct, int?decoyMassShift, CustomMolecule customMolecule = null) { _group = group; IonType = type; CleavageOffset = offset ?? 0; MassIndex = massIndex ?? 0; Adduct = adduct; DecoyMassShift = decoyMassShift; // Small molecule precursor transition should have same custom molecule as parent if (IsPrecursor(type) && group.IsCustomIon) { CustomIon = new CustomIon(group.CustomMolecule, adduct); } else if (customMolecule is CustomIon) { // As with reporter ions CustomIon = (CustomIon)customMolecule; Assume.IsTrue(Equals(adduct.AdductCharge, CustomIon.Adduct.AdductCharge)); Adduct = CustomIon.Adduct; // Ion mass is part of formula, so use charge only adduct } else if (customMolecule != null) { CustomIon = new CustomIon(customMolecule, adduct); } // Derived values if (!IsCustom(type, group)) { Peptide peptide = group.Peptide; Ordinal = OffsetToOrdinal(type, (int)offset, peptide.Length); AA = (IsNTerminal() ? peptide.Sequence[(int)offset] : peptide.Sequence[(int)offset + 1]); } else { // caller may have passed in offset = group.Peptide.Length - 1, which for custom ions gives -1 CleavageOffset = 0; } Validate(); }
public PeptideDocNode CreateDocNodeFromSettings(LibKey key, Peptide peptide, SrmSettingsDiff diff, out TransitionGroupDocNode nodeGroupMatched) { if (!key.Target.IsProteomic) { // Scan the spectral lib entry for top N ranked (for now, that's just by intensity with high mz as tie breaker) fragments, // add those as mass-only fragments, or with more detail if peak annotations are present. foreach (var nodePep in peptide.CreateDocNodes(Settings, new MaxModFilter(0))) { SpectrumHeaderInfo libInfo; if (nodePep != null && Settings.PeptideSettings.Libraries.TryGetLibInfo(key, out libInfo)) { var isotopeLabelType = key.Adduct.HasIsotopeLabels ? IsotopeLabelType.heavy : IsotopeLabelType.light; var group = new TransitionGroup(peptide, key.Adduct, isotopeLabelType); nodeGroupMatched = new TransitionGroupDocNode(group, Annotations.EMPTY, Settings, null, libInfo, ExplicitTransitionGroupValues.EMPTY, null, null, false); SpectrumPeaksInfo spectrum; if (Settings.PeptideSettings.Libraries.TryLoadSpectrum(key, out spectrum)) { // Add fragment and precursor transitions as needed var transitionDocNodes = Settings.TransitionSettings.Filter.SmallMoleculeIonTypes.Contains(IonType.precursor) ? nodeGroupMatched.GetPrecursorChoices(Settings, null, true) // Gives list of precursors : new List <DocNode>(); if (Settings.TransitionSettings.Filter.SmallMoleculeIonTypes.Contains(IonType.custom)) { GetSmallMoleculeFragments(key, nodeGroupMatched, spectrum, transitionDocNodes); } nodeGroupMatched = (TransitionGroupDocNode)nodeGroupMatched.ChangeChildren(transitionDocNodes); return((PeptideDocNode)nodePep.ChangeChildren(new List <DocNode>() { nodeGroupMatched })); } } } nodeGroupMatched = null; return(null); } return(CreateDocNodeFromSettings(key.Target, peptide, diff, out nodeGroupMatched)); }
public static Adduct CalcProductCharge(TypedMass productPrecursorMass, int?productZ, Adduct precursorCharge, IList <IonType> acceptedIonTypes, IonTable <TypedMass> productMasses, IList <IList <ExplicitLoss> > potentialLosses, double productMz, double tolerance, MassType massType, MassShiftType massShiftType, out IonType?ionType, out int?ordinal, out TransitionLosses losses, out int massShift) { // Get length of fragment ion mass array int len = productMasses.GetLength(1); // Check all possible ion types and offsets double?minDelta = null; double?minFragmentMass = null, maxFragmentMass = null, maxLoss = null; if (massShiftType == MassShiftType.none) { if (!productZ.HasValue) { minFragmentMass = productMz - tolerance; } else { minFragmentMass = SequenceMassCalc.GetMH(productMz - tolerance, productZ.Value); maxFragmentMass = SequenceMassCalc.GetMH(productMz + tolerance, productZ.Value); } } var bestCharge = Adduct.EMPTY; IonType? bestIonType = null; int? bestOrdinal = null; TransitionLosses bestLosses = null; int bestMassShift = 0; // Check to see if it is the precursor foreach (var lossesTrial in TransitionGroup.CalcTransitionLosses(IonType.precursor, 0, massType, potentialLosses)) { var productMass = productPrecursorMass; if (lossesTrial != null) { productMass -= lossesTrial.Mass; maxLoss = Math.Max(maxLoss ?? 0, lossesTrial.Mass); } int potentialMassShift; int nearestCharge; var charge = CalcProductCharge(productMass, productZ, productMz, tolerance, false, precursorCharge, massShiftType, out potentialMassShift, out nearestCharge); if (Equals(charge, precursorCharge)) { double potentialMz = SequenceMassCalc.GetMZ(productMass, charge) + potentialMassShift; double delta = Math.Abs(productMz - potentialMz); if (CompareIonMatch(delta, lossesTrial, potentialMassShift, minDelta, bestLosses, bestMassShift) < 0) { bestCharge = charge; bestIonType = IonType.precursor; bestOrdinal = len + 1; bestLosses = lossesTrial; bestMassShift = potentialMassShift; minDelta = delta; } } } if (maxLoss.HasValue) { maxFragmentMass += maxLoss.Value; } var categoryLast = -1; foreach (var typeAccepted in GetIonTypes(acceptedIonTypes)) { var type = typeAccepted.IonType; var category = typeAccepted.IonCategory; // Types have priorities. If changing type category, and there is already a // suitable answer stop looking. if (category != categoryLast && minDelta.HasValue && MatchMz(minDelta.Value, tolerance)) { break; } categoryLast = category; // The peptide length is 1 longer than the mass array for (int ord = len; ord > 0; ord--) { int offset = Transition.OrdinalToOffset(type, ord, len + 1); var productMassBase = productMasses[type, offset]; // Until below the maximum fragment mass no possible matches if (maxFragmentMass.HasValue && productMassBase > maxFragmentMass.Value) { continue; } // Once below the minimum fragment mass no more possible matches, so stop if (minFragmentMass.HasValue && productMassBase < minFragmentMass.Value) { break; } foreach (var lossesTrial in TransitionGroup.CalcTransitionLosses(type, offset, massType, potentialLosses)) { // Look for the closest match. var productMass = productMassBase; if (lossesTrial != null) { productMass -= lossesTrial.Mass; } int potentialMassShift; int nearestCharge; var chargeFound = CalcProductCharge(productMass, productZ, productMz, tolerance, false, precursorCharge, massShiftType, out potentialMassShift, out nearestCharge); if (!chargeFound.IsEmpty) { var charge = chargeFound; double potentialMz = SequenceMassCalc.GetMZ(productMass, charge) + potentialMassShift; double delta = Math.Abs(productMz - potentialMz); if (CompareIonMatch(delta, lossesTrial, potentialMassShift, minDelta, bestLosses, bestMassShift) < 0) { bestCharge = charge; bestIonType = type; bestOrdinal = ord; bestLosses = lossesTrial; bestMassShift = potentialMassShift; minDelta = delta; } } } } } ionType = bestIonType; ordinal = bestOrdinal; losses = bestLosses; massShift = bestMassShift; return(bestCharge); }
public Transition(TransitionGroup group, Adduct charge, int?massIndex, CustomMolecule customMolecule, IonType type = IonType.custom) : this(group, type, null, massIndex, charge, null, customMolecule) { }
public Transition(TransitionGroup group, IonType type, int offset, int massIndex, Adduct charge) : this(group, type, offset, massIndex, charge, null) { }
/// <summary> /// Creates a precursor transition /// </summary> /// <param name="group">The <see cref="TransitionGroup"/> which the transition represents</param> /// <param name="massIndex">Isotope mass shift</param> /// <param name="productAdduct">Adduct on the transition</param> /// <param name="customMolecule">Non-null if this is a custom transition</param> public Transition(TransitionGroup group, int massIndex, Adduct productAdduct, CustomMolecule customMolecule = null) : this(group, IonType.precursor, group.Peptide.Length - 1, massIndex, productAdduct, null, customMolecule) { }
public static bool IsCustom(IonType type, TransitionGroup parent) { return(type == IonType.custom || (type == IonType.precursor && parent.IsCustomIon)); }
public static int CalcProductCharge(double productPrecursorMass, int precursorCharge, double[,] productMasses, IList <IList <ExplicitLoss> > potentialLosses, double productMz, double tolerance, MassType massType, MassShiftType massShiftType, out IonType?ionType, out int?ordinal, out TransitionLosses losses, out int massShift) { // Get length of fragment ion mass array int len = productMasses.GetLength(1); // Check all possible ion types and offsets double minDelta = double.MaxValue, minDeltaNs = double.MaxValue; int bestCharge = 0, bestChargeNs = 0; IonType? bestIonType = null, bestIonTypeNs = null; int? bestOrdinal = null, bestOrdinalNs = null; TransitionLosses bestLosses = null, bestLossesNs = null; int bestMassShift = 0; // Check to see if it is the precursor foreach (var lossesTrial in TransitionGroup.CalcTransitionLosses(IonType.precursor, 0, massType, potentialLosses)) { double productMass = productPrecursorMass - (lossesTrial != null ? lossesTrial.Mass : 0); int potentialMassShift; int nearestCharge; int? charge = CalcProductCharge(productMass, productMz, tolerance, false, precursorCharge, massShiftType, out potentialMassShift, out nearestCharge); if (charge.HasValue && charge.Value == precursorCharge) { double potentialMz = SequenceMassCalc.GetMZ(productMass, charge.Value) + potentialMassShift; double delta = Math.Abs(productMz - potentialMz); if (potentialMassShift == 0 && minDeltaNs > delta) { bestChargeNs = charge.Value; bestIonTypeNs = IonType.precursor; bestOrdinalNs = len + 1; bestLossesNs = lossesTrial; minDeltaNs = delta; } else if (potentialMassShift != 0 && minDelta > delta) { bestCharge = charge.Value; bestIonType = IonType.precursor; bestOrdinal = len + 1; bestLosses = lossesTrial; bestMassShift = potentialMassShift; minDelta = delta; } } } foreach (IonType type in Transition.ALL_TYPES) { // Types have priorities. If moving to a lower priority type, and there is already a // suitable answer stop looking. if ((type == Transition.ALL_TYPES[2] || type == Transition.ALL_TYPES[2]) && (MatchMz(minDelta, tolerance) || MatchMz(minDeltaNs, tolerance))) { break; } for (int offset = 0; offset < len; offset++) { foreach (var lossesTrial in TransitionGroup.CalcTransitionLosses(type, offset, massType, potentialLosses)) { // Look for the closest match. double productMass = productMasses[(int)type, offset]; if (lossesTrial != null) { productMass -= lossesTrial.Mass; } int potentialMassShift; int nearestCharge; int?chargeFound = CalcProductCharge(productMass, productMz, tolerance, false, precursorCharge, massShiftType, out potentialMassShift, out nearestCharge); if (chargeFound.HasValue) { int charge = chargeFound.Value; double potentialMz = SequenceMassCalc.GetMZ(productMass, charge) + potentialMassShift; double delta = Math.Abs(productMz - potentialMz); if (potentialMassShift == 0 && minDeltaNs > delta) { bestChargeNs = charge; bestIonTypeNs = type; // The peptide length is 1 longer than the mass array bestOrdinalNs = Transition.OffsetToOrdinal(type, offset, len + 1); bestLossesNs = lossesTrial; minDeltaNs = delta; } else if (potentialMassShift != 0 && minDelta > delta) { bestCharge = charge; bestIonType = type; // The peptide length is 1 longer than the mass array bestOrdinal = Transition.OffsetToOrdinal(type, offset, len + 1); bestLosses = lossesTrial; bestMassShift = potentialMassShift; minDelta = delta; } } } } } // Pefer no-shift to shift, even if the shift value is closer if (MatchMz(minDelta, tolerance) && !MatchMz(minDeltaNs, tolerance)) { ionType = bestIonType; ordinal = bestOrdinal; losses = bestLosses; massShift = bestMassShift; return(bestCharge); } ionType = bestIonTypeNs; ordinal = bestOrdinalNs; losses = bestLossesNs; massShift = 0; return(bestChargeNs); }
public static Adduct CalcProductCharge(TypedMass productPrecursorMass, Adduct precursorCharge, IList <IonType> acceptedIonTypes, IonTable <TypedMass> productMasses, IList <IList <ExplicitLoss> > potentialLosses, double productMz, double tolerance, MassType massType, MassShiftType massShiftType, out IonType?ionType, out int?ordinal, out TransitionLosses losses, out int massShift) { // Get length of fragment ion mass array int len = productMasses.GetLength(1); // Check all possible ion types and offsets double? minDelta = null; var bestCharge = Adduct.EMPTY; IonType? bestIonType = null; int? bestOrdinal = null; TransitionLosses bestLosses = null; int bestMassShift = 0; // Check to see if it is the precursor foreach (var lossesTrial in TransitionGroup.CalcTransitionLosses(IonType.precursor, 0, massType, potentialLosses)) { var productMass = productPrecursorMass - (lossesTrial != null ? lossesTrial.Mass : 0); int potentialMassShift; int nearestCharge; var charge = CalcProductCharge(productMass, productMz, tolerance, false, precursorCharge, massShiftType, out potentialMassShift, out nearestCharge); if (Equals(charge, precursorCharge)) { double potentialMz = SequenceMassCalc.GetMZ(productMass, charge) + potentialMassShift; double delta = Math.Abs(productMz - potentialMz); if (CompareIonMatch(delta, lossesTrial, potentialMassShift, minDelta, bestLosses, bestMassShift) < 0) { bestCharge = charge; bestIonType = IonType.precursor; bestOrdinal = len + 1; bestLosses = lossesTrial; bestMassShift = potentialMassShift; minDelta = delta; } } } var categoryLast = -1; foreach (var typeAccepted in GetIonTypes(acceptedIonTypes)) { var type = typeAccepted.IonType; var category = typeAccepted.IonCategory; // Types have priorities. If changing type category, and there is already a // suitable answer stop looking. if (category != categoryLast && minDelta.HasValue && MatchMz(minDelta.Value, tolerance)) { break; } categoryLast = category; for (int offset = 0; offset < len; offset++) { foreach (var lossesTrial in TransitionGroup.CalcTransitionLosses(type, offset, massType, potentialLosses)) { // Look for the closest match. var productMass = productMasses[type, offset]; if (lossesTrial != null) { productMass -= lossesTrial.Mass; } int potentialMassShift; int nearestCharge; var chargeFound = CalcProductCharge(productMass, productMz, tolerance, false, precursorCharge, massShiftType, out potentialMassShift, out nearestCharge); if (!chargeFound.IsEmpty) { var charge = chargeFound; double potentialMz = SequenceMassCalc.GetMZ(productMass, charge) + potentialMassShift; double delta = Math.Abs(productMz - potentialMz); if (CompareIonMatch(delta, lossesTrial, potentialMassShift, minDelta, bestLosses, bestMassShift) < 0) { bestCharge = charge; bestIonType = type; // The peptide length is 1 longer than the mass array bestOrdinal = Transition.OffsetToOrdinal(type, offset, len + 1); bestLosses = lossesTrial; bestMassShift = potentialMassShift; minDelta = delta; } } } } } ionType = bestIonType; ordinal = bestOrdinal; losses = bestLosses; massShift = bestMassShift; return(bestCharge); }
public IEnumerable <TransitionDocNode> GetTransitions(SrmSettings settings, TransitionGroupDocNode groupDocNode, ExplicitMods mods, double precursorMz, IsotopeDistInfo isotopeDist, SpectrumHeaderInfo libInfo, IDictionary <double, LibraryRankedSpectrumInfo.RankedMI> transitionRanks, bool useFilter) { Assume.IsTrue(ReferenceEquals(groupDocNode.TransitionGroup, this)); // Get necessary mass calculators and masses var calcFilterPre = settings.GetPrecursorCalc(IsotopeLabelType.light, mods); var calcFilter = settings.GetFragmentCalc(IsotopeLabelType.light, mods); var calcPredict = settings.GetFragmentCalc(LabelType, mods); string sequence = Peptide.Sequence; // Save the true precursor m/z for TranstionSettings.Accept() now that all isotope types are // checked. This is more correct than just using the light precursor m/z for precursor window // exclusion. double precursorMzAccept = precursorMz; if (!ReferenceEquals(calcFilter, calcPredict)) { // Get the normal precursor m/z for filtering, so that light and heavy ion picks will match. precursorMz = IsCustomIon ? BioMassCalc.CalculateIonMz(calcFilterPre.GetPrecursorMass(groupDocNode.CustomIon), groupDocNode.TransitionGroup.PrecursorCharge) : SequenceMassCalc.GetMZ(calcFilterPre.GetPrecursorMass(sequence), groupDocNode.TransitionGroup.PrecursorCharge); } if (!IsAvoidMismatchedIsotopeTransitions) { precursorMzAccept = precursorMz; } var tranSettings = settings.TransitionSettings; var filter = tranSettings.Filter; var charges = filter.ProductCharges; var startFinder = filter.FragmentRangeFirst; var endFinder = filter.FragmentRangeLast; double precursorMzWindow = filter.PrecursorMzWindow; var types = filter.IonTypes; MassType massType = tranSettings.Prediction.FragmentMassType; int minMz = tranSettings.Instrument.GetMinMz(precursorMzAccept); int maxMz = tranSettings.Instrument.MaxMz; var pepMods = settings.PeptideSettings.Modifications; var potentialLosses = CalcPotentialLosses(sequence, pepMods, mods, massType); // A start m/z will need to be calculated if the start fragment // finder uses m/z and their are losses to consider. If the filter // is set to only consider fragments with m/z greater than the // precursor, the code below needs to also prevent loss fragments // from being under that m/z. double startMz = 0; // Get library settings var pick = tranSettings.Libraries.Pick; if (!useFilter) { pick = TransitionLibraryPick.all; var listAll = Transition.ALL_CHARGES.ToList(); listAll.AddRange(charges.Where(c => !Transition.ALL_CHARGES.Contains(c))); listAll.Sort(); charges = listAll.ToArray(); types = Transition.ALL_TYPES; } // If there are no libraries or no library information, then // picking cannot use library information else if (!settings.PeptideSettings.Libraries.HasLibraries || libInfo == null) { pick = TransitionLibraryPick.none; } // If filtering without library picking if (potentialLosses != null) { if (pick == TransitionLibraryPick.none) { // Only include loss combinations where all losses are included always potentialLosses = potentialLosses.Where(losses => losses.All(loss => loss.TransitionLoss.Loss.Inclusion == LossInclusion.Always)).ToArray(); } else if (useFilter) { // Exclude all losses which should never be included by default potentialLosses = potentialLosses.Where(losses => losses.All(loss => loss.TransitionLoss.Loss.Inclusion != LossInclusion.Never)).ToArray(); } if (!potentialLosses.Any()) { potentialLosses = null; } } // Return precursor ions if (!useFilter || types.Contains(IonType.precursor)) { bool libraryFilter = (pick == TransitionLibraryPick.all || pick == TransitionLibraryPick.filter); foreach (var nodeTran in GetPrecursorTransitions(settings, mods, calcFilterPre, calcPredict, precursorMz, isotopeDist, potentialLosses, transitionRanks, libraryFilter, useFilter)) { if (minMz <= nodeTran.Mz && nodeTran.Mz <= maxMz) { yield return(nodeTran); } } } // Return special ions from settings, if this is a peptide if (!IsCustomIon) { // This is a peptide, but it may have custom transitions (reporter ions), check those foreach (var measuredIon in tranSettings.Filter.MeasuredIons.Where(m => m.IsCustom)) { if (useFilter && measuredIon.IsOptional) { continue; } var tran = new Transition(this, measuredIon.Charge, null, measuredIon.CustomIon); double mass = settings.GetFragmentMass(IsotopeLabelType.light, null, tran, null); var nodeTran = new TransitionDocNode(tran, null, mass, null, null); if (minMz <= nodeTran.Mz && nodeTran.Mz <= maxMz) { yield return(nodeTran); } } } // For small molecules we can't generate new nodes, so just mz filter those we have foreach (var nodeTran in groupDocNode.Transitions.Where(tran => tran.Transition.IsNonPrecursorNonReporterCustomIon())) { if (minMz <= nodeTran.Mz && nodeTran.Mz <= maxMz) { yield return(nodeTran); } } if (sequence == null) // Completely custom { yield break; } // If picking relies on library information if (useFilter && pick != TransitionLibraryPick.none) { // If it is not yet loaded, or nothing got ranked, return an empty enumeration if (!settings.PeptideSettings.Libraries.IsLoaded || (transitionRanks != null && transitionRanks.Count == 0)) { yield break; } } double[,] massesPredict = calcPredict.GetFragmentIonMasses(sequence); int len = massesPredict.GetLength(1); if (len == 0) { yield break; } double[,] massesFilter = massesPredict; if (!ReferenceEquals(calcFilter, calcPredict)) { // Get the normal m/z values for filtering, so that light and heavy // ion picks will match. massesFilter = calcFilter.GetFragmentIonMasses(sequence); } // Get types other than this to make sure matches are possible for all types var listOtherTypes = new List <Tuple <TransitionGroupDocNode, IFragmentMassCalc> >(); foreach (var labelType in settings.PeptideSettings.Modifications.GetModificationTypes()) { if (Equals(labelType, LabelType)) { continue; } var calc = settings.GetFragmentCalc(labelType, mods); if (calc == null) { continue; } var tranGroupOther = new TransitionGroup(Peptide, PrecursorCharge, labelType, false, DecoyMassShift); var nodeGroupOther = new TransitionGroupDocNode(tranGroupOther, Annotations.EMPTY, settings, mods, libInfo, ExplicitTransitionGroupValues.EMPTY, null, new TransitionDocNode[0], false); listOtherTypes.Add(new Tuple <TransitionGroupDocNode, IFragmentMassCalc>(nodeGroupOther, calc)); } // Loop over potential product ions picking transitions foreach (IonType type in types) { // Precursor type is handled above. if (type == IonType.precursor) { continue; } foreach (int charge in charges) { // Precursor charge can never be lower than product ion charge. if (Math.Abs(PrecursorCharge) < Math.Abs(charge)) { continue; } int start = 0, end = 0; if (pick != TransitionLibraryPick.all) { start = startFinder.FindStartFragment(massesFilter, type, charge, precursorMz, precursorMzWindow, out startMz); end = endFinder.FindEndFragment(type, start, len); if (Transition.IsCTerminal(type)) { Helpers.Swap(ref start, ref end); } } for (int i = 0; i < len; i++) { // Get the predicted m/z that would be used in the transition double massH = massesPredict[(int)type, i]; foreach (var losses in CalcTransitionLosses(type, i, massType, potentialLosses)) { double ionMz = SequenceMassCalc.GetMZ(Transition.CalcMass(massH, losses), charge); // Make sure the fragment m/z value falls within the valid instrument range. // CONSIDER: This means that a heavy transition might excede the instrument // range where a light one is accepted, leading to a disparity // between heavy and light transtions picked. if (minMz > ionMz || ionMz > maxMz) { continue; } TransitionDocNode nodeTranReturn = null; bool accept = true; if (pick == TransitionLibraryPick.all || pick == TransitionLibraryPick.all_plus) { if (!useFilter) { nodeTranReturn = CreateTransitionNode(type, i, charge, massH, losses, transitionRanks); accept = false; } else { if (IsMatched(transitionRanks, ionMz, type, charge, losses)) { nodeTranReturn = CreateTransitionNode(type, i, charge, massH, losses, transitionRanks); accept = false; } // If allowing library or filter, check the filter to decide whether to accept else if (pick == TransitionLibraryPick.all_plus && tranSettings.Accept(sequence, precursorMzAccept, type, i, ionMz, start, end, startMz)) { nodeTranReturn = CreateTransitionNode(type, i, charge, massH, losses, transitionRanks); } } } else if (tranSettings.Accept(sequence, precursorMzAccept, type, i, ionMz, start, end, startMz)) { if (pick == TransitionLibraryPick.none) { nodeTranReturn = CreateTransitionNode(type, i, charge, massH, losses, transitionRanks); } else { if (IsMatched(transitionRanks, ionMz, type, charge, losses)) { nodeTranReturn = CreateTransitionNode(type, i, charge, massH, losses, transitionRanks); } } } if (nodeTranReturn != null) { if (IsAvoidMismatchedIsotopeTransitions && !OtherLabelTypesAllowed(settings, minMz, maxMz, start, end, startMz, accept, groupDocNode, nodeTranReturn, listOtherTypes)) { continue; } Assume.IsTrue(minMz <= nodeTranReturn.Mz && nodeTranReturn.Mz <= maxMz); yield return(nodeTranReturn); } } } } } }
public static TransitionDocNode FromTransitionProto(AnnotationScrubber scrubber, SrmSettings settings, TransitionGroup group, ExplicitMods mods, IsotopeDistInfo isotopeDist, ExplicitTransitionValues pre422ExplicitTransitionValues, SkylineDocumentProto.Types.Transition transitionProto) { var stringPool = scrubber.StringPool; IonType ionType = DataValues.FromIonType(transitionProto.FragmentType); MeasuredIon measuredIon = null; if (transitionProto.MeasuredIonName != null) { measuredIon = settings.TransitionSettings.Filter.MeasuredIons.SingleOrDefault( i => i.Name.Equals(transitionProto.MeasuredIonName.Value)); if (measuredIon == null) { throw new InvalidDataException(string.Format(Resources.TransitionInfo_ReadXmlAttributes_The_reporter_ion__0__was_not_found_in_the_transition_filter_settings_, transitionProto.MeasuredIonName)); } ionType = IonType.custom; } bool isCustom = Transition.IsCustom(ionType, group); bool isPrecursor = Transition.IsPrecursor(ionType); CustomMolecule customIon = null; if (isCustom) { if (measuredIon != null) { customIon = measuredIon.SettingsCustomIon; } else if (isPrecursor) { customIon = group.CustomMolecule; } else { var formula = DataValues.FromOptional(transitionProto.Formula); var moleculeID = MoleculeAccessionNumbers.FromString(DataValues.FromOptional(transitionProto.MoleculeId)); // Tab separated list of InChiKey, CAS etc var monoMassH = DataValues.FromOptional(transitionProto.MonoMassH); var averageMassH = DataValues.FromOptional(transitionProto.AverageMassH); var monoMass = DataValues.FromOptional(transitionProto.MonoMass) ?? monoMassH; var averageMass = DataValues.FromOptional(transitionProto.AverageMass) ?? averageMassH; customIon = new CustomMolecule(formula, new TypedMass(monoMass.Value, monoMassH.HasValue ? MassType.MonoisotopicMassH : MassType.Monoisotopic), new TypedMass(averageMass.Value, averageMassH.HasValue ? MassType.AverageMassH : MassType.Average), DataValues.FromOptional(transitionProto.CustomIonName), moleculeID); } } Transition transition; var adductString = DataValues.FromOptional(transitionProto.Adduct); var adduct = string.IsNullOrEmpty(adductString) ? Adduct.FromChargeProtonated(transitionProto.Charge) : Adduct.FromStringAssumeChargeOnly(adductString); if (isCustom) { transition = new Transition(group, isPrecursor ? group.PrecursorAdduct :adduct, transitionProto.MassIndex, customIon, ionType); } else if (isPrecursor) { transition = new Transition(group, ionType, group.Peptide.Length - 1, transitionProto.MassIndex, group.PrecursorAdduct, DataValues.FromOptional(transitionProto.DecoyMassShift)); } else { int offset = Transition.OrdinalToOffset(ionType, transitionProto.FragmentOrdinal, group.Peptide.Length); transition = new Transition(group, ionType, offset, transitionProto.MassIndex, adduct, DataValues.FromOptional(transitionProto.DecoyMassShift)); } var losses = TransitionLosses.FromLossProtos(settings, transitionProto.Losses); var mass = settings.GetFragmentMass(group, mods, transition, isotopeDist); var isotopeDistInfo = GetIsotopeDistInfo(transition, losses, isotopeDist); if (group.DecoyMassShift.HasValue && transitionProto.DecoyMassShift == null) { throw new InvalidDataException(Resources.SrmDocument_ReadTransitionXml_All_transitions_of_decoy_precursors_must_have_a_decoy_mass_shift); } TransitionLibInfo libInfo = null; if (transitionProto.LibInfo != null) { libInfo = new TransitionLibInfo(transitionProto.LibInfo.Rank, transitionProto.LibInfo.Intensity); } var annotations = scrubber.ScrubAnnotations(Annotations.FromProtoAnnotations(transitionProto.Annotations), AnnotationDef.AnnotationTarget.transition); var results = TransitionChromInfo.FromProtoTransitionResults(scrubber, settings, transitionProto.Results); var explicitTransitionValues = pre422ExplicitTransitionValues ?? ExplicitTransitionValues.Create( DataValues.FromOptional(transitionProto.ExplicitCollisionEnergy), DataValues.FromOptional(transitionProto.ExplicitIonMobilityHighEnergyOffset), DataValues.FromOptional(transitionProto.ExplicitSLens), DataValues.FromOptional(transitionProto.ExplicitConeVoltage), DataValues.FromOptional(transitionProto.ExplicitDeclusteringPotential)); return(new TransitionDocNode(transition, annotations, losses, mass, new TransitionQuantInfo(isotopeDistInfo, libInfo, !transitionProto.NotQuantitative), explicitTransitionValues, results)); }
public Transition(TransitionGroup group, int charge, int?massIndex, CustomIon customIon, IonType type = IonType.custom) : this(group, type, null, massIndex, charge, null, customIon) { }
/// <summary> /// Creates a precursor transition /// </summary> /// <param name="group">The <see cref="TransitionGroup"/> which the transition represents</param> /// <param name="massIndex">Isotope mass shift</param> /// <param name="customIon">Non-null if this is a custom transition</param> public Transition(TransitionGroup group, int massIndex, CustomIon customIon = null) : this(group, IonType.precursor, group.Peptide.Length - 1, massIndex, group.PrecursorCharge, null, customIon) { }