public DatabaseSearcherThreadLocalStorage(bool minimize_memory_usage, int psms_length) { this.num_target_peptides = 0; this.num_decoy_peptides = 0; this.proteins = 0; if (!minimize_memory_usage) this.peptides_observed = new Dictionary<FastSubstring, bool>(new LeucineSequenceEqualityComparer()); else this.peptides_observed = null; digested_peptides_buf = new FastListOfBoxes<Peptide>(1000); modified_peptides_buf = new FastListOfBoxes<Peptide>(1000); fixed_modifications_buf = new Dictionary<int, List<Modification>>(1000); possible_modifications_buf = new Dictionary<int, List<Modification>>(1000); mass_spectra_indices_buf = new List<int>(1000); product_masses_buf = new double[1000]; fast_q_sorter = new FastQSorter(); psm = new PeptideSpectrumMatch(); psms = new PeptideSpectrumMatch[psms_length]; }
// This method is called, via PeptideSpectrumMatch.ScoreMatch, in a // tight loop in DatabaseSearcher.DoSearch. Originally, (i) a // List<Double> containing the product masses was newly allocated and // returned each time this method was called, and then (ii) // PeptideSpectrumMatch.ScoreMatch converted this List<Double> to an // array of doubles. Thus, a lot of garbage was generated and needed to // be collected. // // In the current version of this function, we instead take a // preallocated array, product_masses_buf, by reference, and we fill in // the beginning of this array with the calculated product masses. If // product_masses_buf to small to store the calculated product masses, // we resize it so it is big enough. If product_masses_buf is bigger // than necessary, we only fill in the beginning of it and leave the // rest of the entries unchanged (in case the extra capacity is needed // on subsequent calls). We return the total number of entries in the // product_masses_buf that are actually used. // // It is important to emphasize that, in general, // product_masses_buf.Length != the number of calculated product // masses. That is, the number of elements in the array does not equal // the number of elements that are filled in with meaningful info. // // Note also that the fast_q_sorter object's internal state will be // modified by this method. public int CalculateProductMasses(ProductType[] productTypes, ref double[] product_masses_buf, FastQSorter fast_q_sorter) { // If product_masses isn't big enough to store all the product // masses we might want to store, resize it. int max_products = 2 * (Length - 1); if(product_masses_buf.Length < max_products) { System.Array.Resize<double>(ref product_masses_buf, max_products); } // Calculate the product masses and store them in the prefix of // product_masses_buf. int i = 0; for(int r = 1; r < Length; r++) { for(int p = 0; p < productTypes.Length; p++) { if(!(productTypes[p] == ProductType.c && r < Length && this[r] == 'P') && !(productTypes[p] == ProductType.zdot && Length - r < Length && this[Length - r] == 'P')) { double product_mass = CalculateProductMass(productTypes[p], r); product_masses_buf[i] = product_mass; ++i; } } } int total_products = i; // Sort the product masses. Only the filled-in prefix of // product_masses_buf is sorted. fast_q_sorter.Sort(product_masses_buf, 0, total_products); // Return the number of products, i.e., the size of the filled-in // prefix of product_masses_buf. return total_products; }
// Calculates the score for this match. Both product_masses_buf and // fast_q_sorter are modified by this method; see Init's documentation // for details. private void ScoreMatch(MassTolerance productMassTolerance, ref double[] product_masses_buf, FastQSorter fast_q_sorter) { // Calculate the theoretical product masses and store them in // product_masses_buf, which is aliased under the more informative // name theoretical_product_masses for the code below. TotalProducts = Peptide.CalculateProductMasses(PRODUCT_TYPES[Spectrum.FragmentationMethod], ref product_masses_buf, fast_q_sorter); double[] theoretical_product_masses = product_masses_buf; // speed optimizations int num_theoretical_products = TotalProducts; double[] experimental_masses = Spectrum.Masses; double[] experimental_intensities = Spectrum.Intensities; int num_experimental_peaks = experimental_masses.Length; double product_mass_tolerance_value = productMassTolerance.Value; MassToleranceUnits product_mass_tolerance_units = productMassTolerance.Units; MatchingProducts = 0; int t = 0; int e = 0; while(t < num_theoretical_products && e < num_experimental_peaks) { double mass_difference = experimental_masses[e] - theoretical_product_masses[t]; if(product_mass_tolerance_units == MassToleranceUnits.ppm) { mass_difference = mass_difference / theoretical_product_masses[t] * 1e6; } if(Math.Abs(mass_difference) <= product_mass_tolerance_value) { MatchingProducts++; t++; } else if(mass_difference < 0) { e++; } else if(mass_difference > 0) { t++; } } MatchingProductsFraction = (double)MatchingProducts / TotalProducts; MatchingIntensity = 0.0; int e2 = 0; int t2 = 0; while(e2 < num_experimental_peaks && t2 < num_theoretical_products) { double mass_difference = experimental_masses[e2] - theoretical_product_masses[t2]; if(product_mass_tolerance_units == MassToleranceUnits.ppm) { mass_difference = mass_difference / theoretical_product_masses[t2] * 1e6; } if(Math.Abs(mass_difference) <= product_mass_tolerance_value) { MatchingIntensity += experimental_intensities[e2]; e2++; } else if(mass_difference < 0) { e2++; } else if(mass_difference > 0) { t2++; } } MatchingIntensityFraction = MatchingIntensity / Spectrum.TotalIntensity; MorpheusScore = MatchingProducts + MatchingIntensityFraction; }
// This Init method needs to be called before this object can be used. // For more info, see how we use these objects in DatabaseSearcher. // // We copy the peptide parameter deeply (because these sometimes come // from reusable buffers) but not the spectrum parameter (because these // are not reused). // // The array product_masses_buf is used for temporary internal storage // and may be resized. It needs to be local to the current thread; no // locking is performed. Its contents are not of interest to the // caller. // // The fast_q_sorter object also need to be local to the current // thread, as its internal state will be modified. public void Init(TandemMassSpectrum spectrum, Peptide peptide, MassTolerance productMassTolerance, ref double[] product_masses_buf, FastQSorter fast_q_sorter) { Spectrum = spectrum; if(Peptide == null) Peptide = new Peptide(); Peptide.CopyFrom(peptide); PrecursorMassErrorDa = spectrum.PrecursorMass - (precursorMassType == MassType.Average ? peptide.AverageMass : peptide.MonoisotopicMass); PrecursorMassErrorPpm = PrecursorMassErrorDa / (precursorMassType == MassType.Average ? peptide.AverageMass : peptide.MonoisotopicMass) * 1e6; ScoreMatch(productMassTolerance, ref product_masses_buf, fast_q_sorter); }