private bool MatchNext(RankingState rankingState, double ionMz, MatchedFragmentIon match, bool filter, int end, int start, double startMz, ref RankedMI rankedMI) { // Unless trying to match everything, stop looking outside the instrument range if (!rankingState.matchAll && !HasLosses && ionMz > MaxMz) { return(false); } // Check filter properties, if appropriate if ((rankingState.matchAll || ionMz >= MinMz) && Math.Abs(ionMz - rankedMI.ObservedMz) < Libraries.IonMatchTolerance) { // Make sure each m/z value is only used for the most intense peak // that is within the tolerance range. if (rankingState.IsSeen(ionMz)) { return(true); // Keep looking } rankingState.Seen(ionMz); // If this m/z already matched a different ion, just remember the second ion. if (rankedMI.MatchedIons != null) { // If first type was excluded from causing a ranking, but second does, then make it the first // Otherwise, this can cause very mysterious failures to rank transitions that appear in the // document. if (rankedMI.Rank == 0 && ApplyRanking(rankingState, ionMz, match, filter, start, end, startMz, ref rankedMI)) { rankedMI = rankedMI.ChangeMatchedIons(rankedMI.MatchedIons.Prepend(match)); } else { rankedMI = rankedMI.ChangeMatchedIons(rankedMI.MatchedIons.Append(match)); } if (rankedMI.MatchedIons.Count < MAX_MATCH) { return(true); } rankingState.matched = true; return(false); } double predictedMz = match.PredictedMz; // Avoid using the same predicted m/z on two different peaks if (predictedMz == ionMz || !rankingState.IsSeen(predictedMz)) { rankingState.Seen(predictedMz); ApplyRanking(rankingState, ionMz, match, filter, start, end, startMz, ref rankedMI); rankedMI = rankedMI.ChangeMatchedIons(ImmutableList.Singleton(match)); rankingState.matched = !rankingState.matchAll; return(rankingState.matchAll); } } // Stop looking once the mass has been passed, unless there are losses to consider if (HasLosses) { return(true); } return(ionMz <= rankedMI.ObservedMz); }
private bool ApplyRanking(RankingState rankingState, double ionMz, MatchedFragmentIon match, bool filter, int start, int end, double startMz, ref RankedMI rankedMI) { // Avoid ranking precursor ions without losses, if the precursor isotopes will // not be taken from product ions if (!ExcludePrecursorIsotopes || match.IonType != IonType.precursor || match.Losses != null) { int offset = OrdinalToOffset(match.IonType, match.Ordinal); var type = match.IonType; if (filter) { if (TargetInfoObj.LookupMods == null || !TargetInfoObj.LookupMods.HasCrosslinks) { if (!TransitionSettings.Accept(Sequence, MoleculeMassesObj.precursorMz, type, offset, ionMz, start, end, startMz)) { return(false); } } } if (rankingState.matchAll) { if (MinMz > ionMz || ionMz > MaxMz) { return(false); } if (!RankTypes.Contains(type)) { return(false); } if (RankLimit.HasValue && rankingState.Ranked >= RankLimit) { return(false); } if (type != IonType.precursor) { // CONSIDER(bspratt) we may eventually want adduct-level control for small molecules, not just abs charge if (!RankCharges.Contains(Math.Abs(match.Charge.AdductCharge))) { return(false); } } } rankedMI = rankedMI.ChangeRank(rankingState.RankNext()); return(true); } return(false); }
private MoleculeMasses GetCrosslinkMasses(SrmSettings settings) { var predictDocNode = MakeTransitionGroupWithAllPossibleChildren(settings, TargetInfoObj.TransitionGroupDocNode.LabelType); TransitionGroupDocNode matchDocNode; if (Equals(TargetInfoObj.TransitionGroupDocNode.LabelType, TargetInfoObj.SpectrumLabelType)) { matchDocNode = predictDocNode; } else { matchDocNode = MakeTransitionGroupWithAllPossibleChildren(settings, TargetInfoObj.SpectrumLabelType); } var matchTransitions = matchDocNode.Transitions.ToDictionary(child => child.Key(matchDocNode)); var predictFragments = new List <MatchedFragmentIon>(); var matchFragments = new List <MatchedFragmentIon>(); foreach (var predictedTransition in predictDocNode.Transitions) { var key = predictedTransition.Key(null); TransitionDocNode matchTransition; if (!matchTransitions.TryGetValue(key, out matchTransition)) { continue; } var complexFragmentIonName = predictedTransition.ComplexFragmentIon.GetName(); var ionType = DecideIonType(complexFragmentIonName); string fragmentName = predictedTransition.ComplexFragmentIon.GetFragmentIonName(); var predictedIon = new MatchedFragmentIon(ionType, predictFragments.Count + 1, predictedTransition.Transition.Adduct, fragmentName, predictedTransition.Losses, predictedTransition.Mz) .ChangeComplexFragmentIonName(complexFragmentIonName); predictFragments.Add(predictedIon); matchFragments.Add(predictedIon.ChangePredictedMz(matchTransition.Mz)); } var matchMasses = new IonMasses( SequenceMassCalc.GetMH(matchDocNode.PrecursorMz, matchDocNode.PrecursorAdduct, MassType.MonoisotopicMassH), IonTable <TypedMass> .EMPTY) .ChangeKnownFragments(matchFragments); var predictMasses = new IonMasses( SequenceMassCalc.GetMH(predictDocNode.PrecursorMz, predictDocNode.PrecursorAdduct, MassType.MonoisotopicMassH), IonTable <TypedMass> .EMPTY) .ChangeKnownFragments(predictFragments); return(new MoleculeMasses(predictDocNode.PrecursorMz, matchMasses).ChangePredictIonMasses(predictMasses)); }
private bool MatchNext(RankParams rp, IonType type, int offset, TransitionLosses losses, Adduct adduct, string fragmentName, int len, bool filter, int end, int start, double startMz) { bool isFragment = !Transition.IsPrecursor(type); var ionMass = isFragment ? rp.massesMatch[type, offset] : rp.massPreMatch; if (losses != null) { ionMass -= losses.Mass; } double ionMz = SequenceMassCalc.GetMZ(ionMass, adduct); // Unless trying to match everything, stop looking outside the instrument range if (!rp.matchAll && !rp.HasLosses && ionMz > rp.maxMz) { return(false); } // Check filter properties, if apropriate if ((rp.matchAll || ionMz >= rp.minMz) && Math.Abs(ionMz - ObservedMz) < rp.tolerance) { // Make sure each m/z value is only used for the most intense peak // that is within the tolerance range. if (rp.IsSeen(ionMz)) { return(true); // Keep looking } rp.Seen(ionMz); int ordinal = Transition.OffsetToOrdinal(type, offset, len + 1); // If this m/z aready matched a different ion, just remember the second ion. var predictedMass = isFragment ? rp.massesPredict[type, offset] : rp.massPrePredict; if (losses != null) { predictedMass -= losses.Mass; } double predictedMz = SequenceMassCalc.GetMZ(predictedMass, adduct); if (MatchedIons != null) { // If first type was excluded from causing a ranking, but second does, then make it the first // Otherwise, this can cause very mysterious failures to rank transitions that appear in the // document. var match = new MatchedFragmentIon(type, ordinal, adduct, fragmentName, losses, predictedMz); if (Rank == 0 && ApplyRanking(rp, type, offset, losses, adduct, filter, start, end, startMz, ionMz)) { MatchedIons.Insert(0, match); } else { MatchedIons.Add(match); } if (MatchedIons.Count < RankParams.MAX_MATCH) { return(true); } rp.matched = true; return(false); } // Avoid using the same predicted m/z on two different peaks if (predictedMz == ionMz || !rp.IsSeen(predictedMz)) { rp.Seen(predictedMz); ApplyRanking(rp, type, offset, losses, adduct, filter, start, end, startMz, ionMz); MatchedIons = new List <MatchedFragmentIon> { new MatchedFragmentIon(type, ordinal, adduct, fragmentName, losses, predictedMz) }; rp.matched = !rp.matchAll; return(rp.matchAll); } } // Stop looking once the mass has been passed, unless there are losses to consider if (rp.HasLosses) { return(true); } return(ionMz <= ObservedMz); }