public void CalculateRank(RankParams rp) { // Rank based on filtered range, if the settings use it in picking bool filter = (rp.pick == TransitionLibraryPick.filter); if (rp.knownFragments != null) { // Small molecule work - we only know about the fragments we're given, we can't predict others foreach (IonType type in rp.types) { if (Transition.IsPrecursor(type)) { if (!MatchNext(rp, type, 0, null, rp.precursorAdduct, null, 0, filter, 0, 0, 0)) { // If matched return. Otherwise look for other ion types. if (rp.matched) { rp.Clean(); return; } } } else { for (var i = 0; i < rp.knownFragments.Count; i++) { var fragment = rp.knownFragments[i]; if (!MatchNext(rp, IonType.custom, i, null, fragment.Adduct, fragment.Name, 0, filter, 0, 0, fragment.Mz)) { // If matched return. Otherwise look for other ion types. if (rp.matched) { rp.Clean(); return; } } } } } return; } // Look for a predicted match within the acceptable tolerance int len = rp.massesMatch.GetLength(1); foreach (IonType type in rp.types) { if (Transition.IsPrecursor(type)) { foreach (var losses in TransitionGroup.CalcTransitionLosses(type, 0, rp.massType, rp.potentialLosses)) { if (!MatchNext(rp, type, len, losses, rp.precursorAdduct, null, len + 1, filter, len, len, 0)) { // If matched return. Otherwise look for other ion types. if (rp.matched) { rp.Clean(); return; } } } continue; } foreach (var adduct in rp.adducts) { // Precursor charge can never be lower than product ion charge. if (Math.Abs(rp.precursorAdduct.AdductCharge) < Math.Abs(adduct.AdductCharge)) { continue; } int start = 0, end = 0; double startMz = 0; if (filter) { start = rp.startFinder.FindStartFragment(rp.massesMatch, type, adduct, rp.precursorMz, rp.filter.PrecursorMzWindow, out startMz); end = rp.endFinder.FindEndFragment(type, start, len); if (Transition.IsCTerminal(type)) { Helpers.Swap(ref start, ref end); } } // These inner loops are performance bottlenecks, and the following // code duplication proved the fastest implementation under a // profiler. Apparently .NET failed to inline an attempt to put // the loop contents in a function. if (Transition.IsCTerminal(type)) { for (int i = len - 1; i >= 0; i--) { foreach (var losses in TransitionGroup.CalcTransitionLosses(type, i, rp.massType, rp.potentialLosses)) { if (!MatchNext(rp, type, i, losses, adduct, null, len, filter, end, start, startMz)) { if (rp.matched) { rp.Clean(); return; } i = -1; // Terminate loop on i break; } } } } else { for (int i = 0; i < len; i++) { foreach (var losses in TransitionGroup.CalcTransitionLosses(type, i, rp.massType, rp.potentialLosses)) { if (!MatchNext(rp, type, i, losses, adduct, null, len, filter, end, start, startMz)) { if (rp.matched) { rp.Clean(); return; } i = len; // Terminate loop on i break; } } } } } } }
private RankedMI CalculateRank(RankingState rankingState, RankedMI rankedMI) { // Rank based on filtered range, if the settings use it in picking bool filter = (Pick == TransitionLibraryPick.filter); var knownFragments = MoleculeMassesObj.MatchIonMasses.KnownFragments; if (knownFragments != null) { // Small molecule work - we only know about the fragments we're given, we can't predict others foreach (IonType type in Types) { if (Transition.IsPrecursor(type)) { var matchedFragmentIon = MakeMatchedFragmentIon(type, 0, PrecursorAdduct, null, out double matchMz); if (!MatchNext(rankingState, matchMz, matchedFragmentIon, filter, 0, 0, 0, ref rankedMI)) { // If matched return. Otherwise look for other ion types. if (rankingState.matched) { rankingState.Clean(); return(rankedMI); } } } else { for (var i = 0; i < knownFragments.Count; i++) { var fragment = knownFragments[i]; double matchMz = MoleculeMassesObj.PredictIonMasses.KnownFragments[i].PredictedMz; if (!MatchNext(rankingState, matchMz, fragment, filter, 0, 0, fragment.PredictedMz, ref rankedMI)) { // If matched return. Otherwise look for other ion types. if (rankingState.matched) { rankingState.Clean(); return(rankedMI); } } } } } return(rankedMI); } // Look for a predicted match within the acceptable tolerance int len = MoleculeMassesObj.MatchIonMasses.FragmentMasses.GetLength(1); foreach (IonType type in Types) { if (Transition.IsPrecursor(type)) { foreach (var losses in TransitionGroup.CalcTransitionLosses(type, 0, MassType, PotentialLosses)) { var matchedFragmentIon = MakeMatchedFragmentIon(type, 0, PrecursorAdduct, losses, out double matchMz); if (!MatchNext(rankingState, matchMz, matchedFragmentIon, filter, len, len, 0, ref rankedMI)) { // If matched return. Otherwise look for other ion types. if (rankingState.matched) { rankingState.Clean(); return(rankedMI); } } } continue; } foreach (var adduct in Adducts) { // Precursor charge can never be lower than product ion charge. if (Math.Abs(PrecursorAdduct.AdductCharge) < Math.Abs(adduct.AdductCharge)) { continue; } int start = 0, end = 0; double startMz = 0; if (filter) { start = TransitionSettings.Filter.FragmentRangeFirst.FindStartFragment( MoleculeMassesObj.MatchIonMasses.FragmentMasses, type, adduct, MoleculeMassesObj.precursorMz, TransitionSettings.Filter.PrecursorMzWindow, out startMz); end = TransitionSettings.Filter.FragmentRangeLast.FindEndFragment(type, start, len); if (Transition.IsCTerminal(type)) { Helpers.Swap(ref start, ref end); } } // These inner loops are performance bottlenecks, and the following // code duplication proved the fastest implementation under a // profiler. Apparently .NET failed to inline an attempt to put // the loop contents in a function. if (Transition.IsCTerminal(type)) { for (int i = len - 1; i >= 0; i--) { foreach (var losses in TransitionGroup.CalcTransitionLosses(type, i, MassType, PotentialLosses)) { var matchedFragmentIon = MakeMatchedFragmentIon(type, i, adduct, losses, out double matchMz); if (!MatchNext(rankingState, matchMz, matchedFragmentIon, filter, end, start, startMz, ref rankedMI)) { if (rankingState.matched) { rankingState.Clean(); return(rankedMI); } i = -1; // Terminate loop on i break; } } } } else { for (int i = 0; i < len; i++) { foreach (var losses in TransitionGroup.CalcTransitionLosses(type, i, MassType, PotentialLosses)) { var matchedFragmentIon = MakeMatchedFragmentIon(type, i, adduct, losses, out double matchMz); if (!MatchNext(rankingState, matchMz, matchedFragmentIon, filter, end, start, startMz, ref rankedMI)) { if (rankingState.matched) { rankingState.Clean(); return(rankedMI); } i = len; // Terminate loop on i break; } } } } } } return(rankedMI); }