private static int?CalcProductCharge(double productMassH, double productMz, double tolerance, bool isCustomIon, int maxCharge, MassShiftType massShiftType, out int massShift, out int nearestCharge) { return(CalcCharge(productMassH, productMz, tolerance, isCustomIon, Transition.MIN_PRODUCT_CHARGE, Math.Min(maxCharge, Transition.MAX_PRODUCT_CHARGE), Transition.MassShifts, massShiftType, out massShift, out nearestCharge)); }
/// <summary> /// Calculates the matching charge within a tolerance for a mass, assuming (de)protonation. /// </summary> /// <param name="mass">The mass to calculate charge for (actually massH if !IsCustomIon)</param> /// <param name="mz">The desired m/z value the charge should produce</param> /// <param name="tolerance">How far off the actual m/z is allowed to be</param> /// <param name="isCustomIon">Is this a custom ion formula?</param> /// <param name="minCharge">Minimum charge to consider</param> /// <param name="maxCharge">Maximum charge to consider</param> /// <param name="massShifts">Possible mass shifts that may have been applied to decoys</param> /// <param name="massShiftType"></param> /// <param name="massShift">Mass shift required to to achieve this charge state or zero</param> /// <param name="nearestCharge">closest matching charge, useful when return value is null</param> /// <returns>A matching charge or null, in which case the closest non-matching charge can be found in the nearestCharge value.</returns> public static Adduct CalcCharge(TypedMass mass, double mz, double tolerance, bool isCustomIon, int minCharge, int maxCharge, ICollection <int> massShifts, MassShiftType massShiftType, out int massShift, out int nearestCharge) { Assume.IsTrue(minCharge <= maxCharge); massShift = 0; nearestCharge = 0; double nearestDelta = double.MaxValue; for (int i = minCharge; i <= maxCharge; i++) { if (i != 0) // Avoid z=0 if we're entertaining negative charge states { double calculatedMz = isCustomIon ? Adduct.FromChargeProtonated(i).MzFromNeutralMass(mass) : SequenceMassCalc.GetMZ(mass, i); double delta = mz - calculatedMz; double deltaAbs = Math.Abs(delta); int potentialShift = (int)Math.Round(deltaAbs); double fractionalDelta = deltaAbs - potentialShift; if (MatchMz(fractionalDelta, tolerance) && MatchMassShift(potentialShift, massShifts, massShiftType)) { massShift = potentialShift; if (delta < 0) { massShift = -massShift; } var result = i; nearestCharge = i; return(Adduct.FromCharge(result, isCustomIon ? Adduct.ADDUCT_TYPE.non_proteomic : Adduct.ADDUCT_TYPE.proteomic)); } if (deltaAbs < nearestDelta) { nearestDelta = deltaAbs; nearestCharge = i; } // If the charge is positive and the calculated m/z is smaller than the desired m/z // increasing the charge further cannot possibly produce a match if (massShiftType == MassShiftType.none && minCharge > 0 && delta > 0) { break; } } } Debug.Assert(nearestCharge != 0); // Could only happen if min > max return(Adduct.EMPTY); }
/// <summary> /// Calculates the matching charge within a tolerance for a mass. /// </summary> /// <param name="massH">The mass to calculate charge for</param> /// <param name="mz">The desired m/z value the charge should produce</param> /// <param name="tolerance">How far off the actual m/z is allowed to be</param> /// <param name="isCustomIon">Is this a custom ion formula?</param> /// <param name="minCharge">Minimum charge to consider</param> /// <param name="maxCharge">Maximum charge to consider</param> /// <param name="massShifts">Possible mass shifts that may have been applied to decoys</param> /// <param name="massShiftType"></param> /// <param name="massShift">Mass shift required to to achieve this charge state or zero</param> /// <param name="nearestCharge">closest matching charge, useful when return value is null</param> /// <returns>A matching charge or null, in which case the closest non-matching charge can be found in the nearestCharge value.</returns> public static int?CalcCharge(double massH, double mz, double tolerance, bool isCustomIon, int minCharge, int maxCharge, ICollection <int> massShifts, MassShiftType massShiftType, out int massShift, out int nearestCharge) { Assume.IsTrue(minCharge <= maxCharge); massShift = 0; nearestCharge = 0; double nearestDelta = double.MaxValue; for (int i = minCharge; i <= maxCharge; i++) { if (i != 0) // Avoid z=0 if we're entertaining negative charge states { double delta = mz - (isCustomIon ? BioMassCalc.CalculateIonMz(massH, i) : SequenceMassCalc.GetMZ(massH, i)); double deltaAbs = Math.Abs(delta); int potentialShift = (int)Math.Round(deltaAbs); double fractionalDelta = deltaAbs - potentialShift; if (MatchMz(fractionalDelta, tolerance) && MatchMassShift(potentialShift, massShifts, massShiftType)) { massShift = potentialShift; if (delta < 0) { massShift = -massShift; } int?result = i; nearestCharge = i; return(result); } if (deltaAbs < nearestDelta) { nearestDelta = deltaAbs; nearestCharge = i; } } } Debug.Assert(nearestCharge != 0); // Could only happen if min > max return(null); }
/// <summary> /// Calculates the matching charge within a tolerance for a mass. /// </summary> /// <param name="massH">The mass to calculate charge for</param> /// <param name="mz">The desired m/z value the charge should produce</param> /// <param name="tolerance">How far off the actual m/z is allowed to be</param> /// <param name="isCustomIon">Is this a custom ion formula?</param> /// <param name="minCharge">Minimum charge to consider</param> /// <param name="maxCharge">Maximum charge to consider</param> /// <param name="massShifts">Possible mass shifts that may have been applied to decoys</param> /// <param name="massShiftType"></param> /// <param name="massShift">Mass shift required to to achieve this charge state or zero</param> /// <param name="nearestCharge">closest matching charge, useful when return value is null</param> /// <returns>A matching charge or null, in which case the closest non-matching charge can be found in the nearestCharge value.</returns> public static int? CalcCharge(double massH, double mz, double tolerance, bool isCustomIon, int minCharge, int maxCharge, ICollection<int> massShifts, MassShiftType massShiftType, out int massShift, out int nearestCharge) { Assume.IsTrue(minCharge <= maxCharge); massShift = 0; nearestCharge = 0; double nearestDelta = double.MaxValue; for (int i = minCharge; i <= maxCharge; i++) { if (i != 0) // Avoid z=0 if we're entertaining negative charge states { double delta = mz - ( isCustomIon ? BioMassCalc.CalculateIonMz(massH, i) : SequenceMassCalc.GetMZ(massH, i) ); double deltaAbs = Math.Abs(delta); int potentialShift = (int) Math.Round(deltaAbs); double fractionalDelta = deltaAbs - potentialShift; if (MatchMz(fractionalDelta, tolerance) && MatchMassShift(potentialShift, massShifts, massShiftType)) { massShift = potentialShift; if (delta < 0) massShift = -massShift; int? result = i; nearestCharge = i; return result; } if (deltaAbs < nearestDelta) { nearestDelta = deltaAbs; nearestCharge = i; } } } Debug.Assert(nearestCharge != 0); // Could only happen if min > max return null; }
private static bool MatchMassShift(int potentialShift, ICollection<int> massShifts, MassShiftType massShiftType) { return (massShiftType != MassShiftType.shift_only && potentialShift == 0) || (massShiftType != MassShiftType.none && massShifts.Contains(potentialShift)); }
private static int? CalcProductCharge(double productMassH, double productMz, double tolerance, bool isCustomIon, int maxCharge, MassShiftType massShiftType, out int massShift, out int nearestCharge) { return CalcCharge(productMassH, productMz, tolerance, isCustomIon, Transition.MIN_PRODUCT_CHARGE, Math.Min(maxCharge, Transition.MAX_PRODUCT_CHARGE), Transition.MassShifts, massShiftType, out massShift, out nearestCharge); }
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; }
private static bool MatchMassShift(int potentialShift, ICollection <int> massShifts, MassShiftType massShiftType) { return((massShiftType != MassShiftType.shift_only && potentialShift == 0) || (massShiftType != MassShiftType.none && massShifts.Contains(potentialShift))); }
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, 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 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); }