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 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)); }