public void TestPPMConversion(double massToConvert, double currentMz, double expectedPPM) { var convertedPPM = PeptideMassCalculator.MassToPPM(massToConvert, currentMz); var reconvertedMass = PeptideMassCalculator.PPMToMass(convertedPPM, currentMz); Console.WriteLine("DelM of {0} Da converts to {1:F5} ppm at {2:F5} m/z ", massToConvert, convertedPPM, currentMz); Assert.AreEqual(expectedPPM, convertedPPM, 0.0001, "PPM Conversion error"); Assert.AreEqual(massToConvert, reconvertedMass, 1E-05, "Da to PPM to Da round trip error"); }
// ReSharper restore StringLiteralTypo public void TestComputeEmpiricalFormulaMassMethod1(string strEmpiricalFormula, double expectedMass) { var empiricalFormula = PeptideMassCalculator.GetEmpiricalFormulaComponents(strEmpiricalFormula); var computedMass = PeptideMassCalculator.ComputeMonoisotopicMass(empiricalFormula); var computedMassAlt = PeptideMassCalculator.ComputeMonoisotopicMass(empiricalFormula.ElementCounts, out _); Console.WriteLine("{0,-30} is {1:F5}; expected {2:F5}", strEmpiricalFormula, computedMass, expectedMass); Assert.AreEqual(computedMass, computedMassAlt, 1E-05, "The two overloads for ComputeMonoisotopicMass reported conflicting mass values"); Assert.AreEqual(expectedMass, computedMass, 0.0001, "Unexpected mass for the empirical formula"); }
public void TestGetAminoAcidMass(char aminoAcidSymbol, double expectedMass) { var computedMass = mPeptideMassCalculator.GetAminoAcidMass(aminoAcidSymbol); var empiricalFormula = new EmpiricalFormula(); empiricalFormula.AddElements(mPeptideMassCalculator.GetAminoAcidEmpiricalFormula(aminoAcidSymbol)); var computedMassAlt = PeptideMassCalculator.ComputeMonoisotopicMass(empiricalFormula); Assert.AreEqual(expectedMass, computedMass, 0.0001, "Amino acid does not match the expected value"); Assert.AreEqual(computedMass, computedMassAlt, 1E-05, "GetAminoAcidMass and ComputeMonoisotopicMass do not agree on the mass for the amino acid"); }
private static void TestMSGFPlusParamFileParsing(string msgfPlusParamFilePath) { var modFileProcessor = new MSGFPlusParamFileModExtractor("MSGF+"); modFileProcessor.ErrorEvent += ErrorEventHandler; modFileProcessor.WarningEvent += WarningEventHandler; var peptideMassCalculator = new PeptideMassCalculator(); MSGFPlusSynFileReader.UpdateMassCalculatorMasses(msgfPlusParamFilePath, modFileProcessor, peptideMassCalculator, out _); var modifiedResidues = new List <PeptideMassCalculator.PeptideSequenceModInfo>(); var monoMass = peptideMassCalculator.ComputeSequenceMass("PEPTIDE", modifiedResidues); Console.WriteLine("Mono mass of PEPTIDE: " + monoMass.ToString("0.0000")); var modifiedResidue = new PeptideMassCalculator.PeptideSequenceModInfo { ResidueLocInPeptide = 4, ModificationMass = 79.966 }; modifiedResidues.Add(modifiedResidue); var monoMassModified = peptideMassCalculator.ComputeSequenceMass("PEPTIDE", modifiedResidues); Console.WriteLine("Mono mass of PEPT*IDE: " + monoMassModified.ToString("0.0000")); const double MONO_MASS_EXPECTED = 799.359926865; const double MODIFIED_MONO_MASS_EXPECTED = 879.325926865; if (Math.Abs(monoMass - MONO_MASS_EXPECTED) > 1E-07) { PRISM.ConsoleMsgUtils.ShowWarning("Computed mass of {0:F6} does not match the expected mass, {1:F6}", monoMass, MONO_MASS_EXPECTED); } if (Math.Abs(monoMassModified - MODIFIED_MONO_MASS_EXPECTED) > 1E-07) { PRISM.ConsoleMsgUtils.ShowWarning("Modified computed mass of {0:F6} does not match the expected mass, {1:F6}", monoMassModified, MODIFIED_MONO_MASS_EXPECTED); } }
private static string GetCorrectedMassErrorPPM(PSM psm, out int intIsotopeError) { const double MASS_C13 = 1.00335483; double dblMassErrorPPM = 0; intIsotopeError = 0; if (double.TryParse(psm.MassErrorDa, out var dblDelM)) { // Examine dblDelM to determine which isotope was chosen if (dblDelM >= -0.5) { // This is the typical case while (dblDelM > 0.5) { dblDelM -= MASS_C13; intIsotopeError += 1; } } else { // This happens less often; but we'll still account for it // In this case, intCorrectionCount will be negative while (dblDelM < -0.5) { dblDelM += MASS_C13; intIsotopeError -= 1; } } dblMassErrorPPM = PeptideMassCalculator.MassToPPM(dblDelM, psm.PrecursorNeutralMass); } return(dblMassErrorPPM.ToString("0.0000")); }
/// <summary> /// Constructor /// </summary> /// <remarks> /// The base class constructor calls InitializeLocalVariables, /// which calls both the base class's Clear method and this class's Clear method /// </remarks> /// <param name="peptideMods"></param> /// <param name="peptideSeqMassCalculator"></param> public MODaResults(PeptideModificationContainer peptideMods, PeptideMassCalculator peptideSeqMassCalculator) : base(peptideMods, peptideSeqMassCalculator) { }
public void Init() { mPeptideMassCalculator = new PeptideMassCalculator(); }
/// <summary> /// Configure and run the AScore algorithm /// </summary> /// <param name="ascoreOptions"></param> /// <returns></returns> public int RunAScore(AScoreOptions ascoreOptions) { var paramManager = new ParameterFileManager(ascoreOptions.AScoreParamFile); RegisterEvents(paramManager); Console.WriteLine(); if (paramManager.DynamicMods.Count > 0 || paramManager.StaticMods.Count > 0) { OnStatusEvent("Loaded modifications from: " + ascoreOptions.AScoreParamFile); foreach (var mod in paramManager.StaticMods) { OnStatusEvent(Utilities.GetModDescription("Static, ", mod)); } foreach (var mod in paramManager.DynamicMods) { OnStatusEvent(Utilities.GetModDescription("Dynamic, ", mod)); } foreach (var mod in paramManager.TerminiMods) { OnStatusEvent(Utilities.GetModDescription("Terminus, ", mod)); } Console.WriteLine(); } PsmResultsManager psmResultsManager; switch (ascoreOptions.SearchType) { case AScoreOptions.SearchMode.XTandem: OnStatusEvent("Caching data in " + PathUtils.CompactPathString(ascoreOptions.DbSearchResultsFile, 80)); psmResultsManager = new XTandemFHT(ascoreOptions.DbSearchResultsFile); break; case AScoreOptions.SearchMode.Sequest: OnStatusEvent("Caching data in " + PathUtils.CompactPathString(ascoreOptions.DbSearchResultsFile, 80)); psmResultsManager = new SequestFHT(ascoreOptions.DbSearchResultsFile); break; case AScoreOptions.SearchMode.Inspect: OnStatusEvent("Caching data in " + PathUtils.CompactPathString(ascoreOptions.DbSearchResultsFile, 80)); psmResultsManager = new InspectFHT(ascoreOptions.DbSearchResultsFile); break; case AScoreOptions.SearchMode.Msgfdb: case AScoreOptions.SearchMode.Msgfplus: OnStatusEvent("Caching data in " + PathUtils.CompactPathString(ascoreOptions.DbSearchResultsFile, 80)); if (ascoreOptions.SearchResultsType == AScoreOptions.DbSearchResultsType.Mzid) { if (ascoreOptions.CreateUpdatedDbSearchResultsFile) { psmResultsManager = new MsgfMzidFull(ascoreOptions.DbSearchResultsFile); } else { psmResultsManager = new MsgfMzid(ascoreOptions.DbSearchResultsFile); } } else { psmResultsManager = new MsgfdbFHT(ascoreOptions.DbSearchResultsFile); } break; default: OnErrorEvent(string.Format( "Incorrect search type: {0} , supported values are {1}", ascoreOptions.SearchType, string.Join(", ", Enum.GetNames(typeof(AScoreOptions.SearchMode))) )); return(-13); } var peptideMassCalculator = new PeptideMassCalculator(); var spectraManager = new SpectraManagerCache(peptideMassCalculator); RegisterEvents(spectraManager); OnStatusEvent("Output directory: " + ascoreOptions.OutputDirectoryInfo.FullName); var ascoreEngine = new AScoreAlgorithm(); RegisterEvents(ascoreEngine); // Initialize the options FilterOnMSGFScore = ascoreOptions.FilterOnMSGFScore; // Run the algorithm if (ascoreOptions.MultiJobMode) { RunAScoreWithMappingFile(ascoreOptions, spectraManager, psmResultsManager, paramManager); } else { spectraManager.OpenFile(ascoreOptions.MassSpecFile, ascoreOptions.ModSummaryFile); RunAScoreOnSingleFile(ascoreOptions, spectraManager, psmResultsManager, paramManager); } OnStatusEvent("AScore Complete"); if (ascoreOptions.CreateUpdatedDbSearchResultsFile) { if (ascoreOptions.SearchResultsType == AScoreOptions.DbSearchResultsType.Fht) { CreateUpdatedFirstHitsFile(ascoreOptions); } else if (psmResultsManager is MsgfMzidFull mzidFull) { mzidFull.WriteToMzidFile(ascoreOptions.UpdatedDbSearchResultsFileName); OnStatusEvent("Results merged; new file: " + PathUtils.CompactPathString(ascoreOptions.UpdatedDbSearchResultsFileName, 80)); } } return(0); }
/// <summary> /// Runs the all the tools necessary to perform an ascore run /// </summary> /// <param name="jobToDatasetNameMap">Keys are job numbers (stored as strings); values are Dataset Names or the path to the _dta.txt file</param> /// <param name="spectraManager">Manager for reading _dta.txt or .mzML files; must have already been initialized by the calling class</param> /// <param name="psmResultsManager"></param> /// <param name="ascoreParams"></param> /// <param name="ascoreOptions"></param> /// <param name="spectraFileOpened">Set to true if processing a single dataset, and spectraManager.OpenFile() has already been called</param> private void RunAScoreOnPreparedData( IReadOnlyDictionary <string, DatasetFileInfo> jobToDatasetNameMap, SpectraManagerCache spectraManager, PsmResultsManager psmResultsManager, ParameterFileManager ascoreParams, AScoreOptions ascoreOptions, bool spectraFileOpened) { var totalRows = psmResultsManager.GetRowLength(); var dctPeptidesProcessed = new Dictionary <string, int>(); if (jobToDatasetNameMap == null || jobToDatasetNameMap.Count == 0) { const string errorMessage = "Error in AlgorithmRun: jobToDatasetNameMap cannot be null or empty"; OnErrorEvent(errorMessage); throw new ArgumentException(errorMessage); } ISpectraManager spectraFile = null; string spectraManagerCurrentJob = null; // Force open after first read from fht var modSummaryManager = new ModSummaryFileManager(); RegisterEvents(modSummaryManager); var peptideMassCalculator = new PeptideMassCalculator(); if (FilterOnMSGFScore) { OnStatusEvent("Filtering using MSGF_SpecProb <= " + ascoreParams.MSGFPreFilter.ToString("0.0E+00")); } Console.WriteLine(); var statsByType = new int[4]; var ascoreAlgorithm = new AScoreAlgorithm(); RegisterEvents(ascoreAlgorithm); while (psmResultsManager.CurrentRowNum < totalRows) { // Console.Clear(); if (psmResultsManager.CurrentRowNum % 100 == 0) { Console.Write("\rPercent Completion " + Math.Round((double)psmResultsManager.CurrentRowNum / totalRows * 100) + "%"); } int scanNumber; int scanCount; int chargeState; string peptideSeq; double msgfScore; if (FilterOnMSGFScore) { psmResultsManager.GetNextRow(out scanNumber, out scanCount, out chargeState, out peptideSeq, out msgfScore, ref ascoreParams); } else { psmResultsManager.GetNextRow(out scanNumber, out scanCount, out chargeState, out peptideSeq, ref ascoreParams); msgfScore = 1; } switch (ascoreParams.FragmentType) { case FragmentType.CID: statsByType[(int)FragmentType.CID]++; break; case FragmentType.ETD: statsByType[(int)FragmentType.ETD]++; break; case FragmentType.HCD: statsByType[(int)FragmentType.HCD]++; break; default: statsByType[(int)FragmentType.Unspecified]++; break; } if (string.IsNullOrEmpty(spectraManagerCurrentJob) || !string.Equals(spectraManagerCurrentJob, psmResultsManager.JobNum)) { // New dataset // Get the correct spectrum file for the match if (!jobToDatasetNameMap.TryGetValue(psmResultsManager.JobNum, out var datasetInfo)) { var errorMessage = "Input file refers to job " + psmResultsManager.JobNum + " but jobToDatasetNameMap does not contain that job; unable to continue"; OnWarningEvent(errorMessage); if (!psmResultsManager.JobColumnDefined) { OnWarningEvent( "If the input file includes results from multiple jobs, the first column must be job number with Job as the column heading"); } throw new Exception(errorMessage); } var datasetName = GetDatasetName(datasetInfo.SpectrumFilePath); OnStatusEvent("Dataset name: " + datasetName); if (!spectraFileOpened) { // This method was called from RunAScoreWithMappingFile // Open the spectrum file for this dataset spectraFile = spectraManager.GetSpectraManagerForFile( psmResultsManager.PSMResultsFilePath, datasetName, datasetInfo.ModSummaryFilePath); } else { spectraFile = spectraManager.GetCurrentSpectrumManager(); } spectraManagerCurrentJob = string.Copy(psmResultsManager.JobNum); Console.Write("\r"); if (string.IsNullOrWhiteSpace(datasetInfo.ModSummaryFilePath) && !string.IsNullOrWhiteSpace(ascoreOptions.ModSummaryFile)) { datasetInfo.ModSummaryFilePath = ascoreOptions.ModSummaryFile; } if (psmResultsManager is MsgfMzid mzid) { mzid.SetModifications(ascoreParams); } else if (psmResultsManager is MsgfMzidFull mzidFull) { mzidFull.SetModifications(ascoreParams); } else { if (string.IsNullOrEmpty(datasetInfo.ModSummaryFilePath)) { modSummaryManager.ReadModSummary(spectraFile.DatasetName, psmResultsManager.PSMResultsFilePath, ascoreParams); } else { var modSummaryFile = new FileInfo(datasetInfo.ModSummaryFilePath); modSummaryManager.ReadModSummary(modSummaryFile, ascoreParams); } } Console.WriteLine(); Console.Write("\rPercent Completion " + Math.Round((double)psmResultsManager.CurrentRowNum / totalRows * 100) + "%"); } // perform work on the match var peptideParts = peptideSeq.Split('.'); string sequenceWithoutSuffixOrPrefix; string front; string back; if (peptideParts.Length >= 3) { front = peptideParts[0]; sequenceWithoutSuffixOrPrefix = peptideParts[1]; back = peptideParts[2]; } else { front = "?"; sequenceWithoutSuffixOrPrefix = string.Copy(peptideSeq); back = "?"; } var sequenceClean = GetCleanSequence(sequenceWithoutSuffixOrPrefix, ref ascoreParams); var skipPSM = FilterOnMSGFScore && msgfScore > ascoreParams.MSGFPreFilter; var scanChargePeptide = scanNumber + "_" + chargeState + "_" + sequenceWithoutSuffixOrPrefix; if (dctPeptidesProcessed.ContainsKey(scanChargePeptide)) { // We have already processed this PSM skipPSM = true; } else { dctPeptidesProcessed.Add(scanChargePeptide, 0); } if (skipPSM) { psmResultsManager.IncrementRow(); continue; } //Get experimental spectra if (spectraFile == null) { const string errorMessage = "spectraFile is uninitialized in RunAScoreOnPreparedData; this indicates a programming bug"; OnErrorEvent(errorMessage); throw new Exception(errorMessage); } var expSpec = spectraFile.GetExperimentalSpectra(scanNumber, scanCount, chargeState); if (expSpec == null) { OnWarningEvent("Scan " + scanNumber + " not found in spectra file for peptide " + peptideSeq); psmResultsManager.IncrementRow(); continue; } // Assume monoisotopic for both hi res and low res spectra MolecularWeights.MassType = MassType.Monoisotopic; // Compute precursor m/z value var precursorMZ = peptideMassCalculator.ConvoluteMass(expSpec.PrecursorMass, 1, chargeState); // Set the m/z range var mzMax = maxRange; var mzMin = precursorMZ * lowRangeMultiplier; if (ascoreParams.FragmentType != FragmentType.CID) { mzMax = maxRange; mzMin = minRange; } //Generate all combination mixtures var modMixture = new Combinatorics.ModMixtureCombo(ascoreParams.DynamicMods, sequenceClean); var myPositionsList = GetMyPositionList(sequenceClean, modMixture); //If I have more than 1 modifiable site proceed to calculation if (myPositionsList.Count > 1) { ascoreAlgorithm.ComputeAScore(psmResultsManager, ascoreParams, scanNumber, chargeState, peptideSeq, front, back, sequenceClean, expSpec, mzMax, mzMin, myPositionsList); } else if (myPositionsList.Count == 1) { // Either one or no modifiable sites var uniqueID = myPositionsList[0].Max(); if (uniqueID == 0) { psmResultsManager.WriteToTable(peptideSeq, scanNumber, 0, myPositionsList[0], MOD_INFO_NO_MODIFIED_RESIDUES); } else { psmResultsManager.WriteToTable(peptideSeq, scanNumber, 0, myPositionsList[0], LookupModInfoByID(uniqueID, ascoreParams.DynamicMods)); } } else { // No modifiable sites psmResultsManager.WriteToTable(peptideSeq, scanNumber, 0, new int[0], MOD_INFO_NO_MODIFIED_RESIDUES); } psmResultsManager.IncrementRow(); } Console.WriteLine(); OnStatusEvent(string.Format("Writing {0:N0} rows to {1}", psmResultsManager.ResultsCount, PathUtils.CompactPathString(ascoreOptions.AScoreResultsFilePath, 80))); psmResultsManager.WriteToFile(ascoreOptions.AScoreResultsFilePath); Console.WriteLine(); if (statsByType.Sum() == 0) { OnWarningEvent("Input file appeared empty"); } else { OnStatusEvent("Stats by fragmentation ion type:"); ReportStatsForFragType(" CID", statsByType, FragmentType.CID); ReportStatsForFragType(" ETD", statsByType, FragmentType.ETD); ReportStatsForFragType(" HCD", statsByType, FragmentType.HCD); } Console.WriteLine(); }
private static void TestPHRPReader(string synOrFhtFile, bool blnSkipDuplicates) { var inputFile = new FileInfo(synOrFhtFile); Console.WriteLine("Instantiating reader"); var startupOptions = new StartupOptions { LoadModsAndSeqInfo = true, LoadMSGFResults = true, LoadScanStatsData = false, MaxProteinsPerPSM = 100 }; var phrpReader = new ReaderFactory(inputFile.FullName, PeptideHitResultTypes.Unknown, startupOptions) { EchoMessagesToConsole = false, SkipDuplicatePSMs = blnSkipDuplicates }; // Check for any load errors if (phrpReader.ErrorMessages.Count > 0) { Console.WriteLine("Error(s) instantiating the reader:"); foreach (var errorMessage in phrpReader.ErrorMessages) { Console.WriteLine(" " + errorMessage); } } phrpReader.ErrorEvent += ErrorEventHandler; phrpReader.StatusEvent += MessageEventHandler; phrpReader.WarningEvent += WarningEventHandler; const bool fastReadEnabled = true; phrpReader.FastReadMode = fastReadEnabled; var massCalculator = new PeptideMassCalculator(); if (!phrpReader.CanRead) { Console.WriteLine("Aborting since PHRPReader is not ready: " + phrpReader.ErrorMessage); return; } var lstValues = new List <string>(); var intPSMsRead = 0; var intModifiedPSMsRead = 0; // ReSharper disable once CollectionNeverQueried.Local var dctCachedValues = new Dictionary <int, PSM>(); Console.WriteLine("Reading data"); while (phrpReader.MoveNext()) { var psm = phrpReader.CurrentPSM; intPSMsRead += 1; lstValues.Clear(); phrpReader.FinalizeCurrentPSM(); PeptideCleavageStateCalculator.SplitPrefixAndSuffixFromSequence(psm.Peptide, out _, out _, out _); var strMassErrorPPM = GetCorrectedMassErrorPPM(psm, out _); lstValues.Add(phrpReader.DatasetName + "_dta.txt"); // #SpecFile lstValues.Add("index=" + intPSMsRead); // SpecID lstValues.Add(psm.ScanNumber.ToString()); // ScanNum lstValues.Add(psm.CollisionMode); // FragMethod lstValues.Add(massCalculator.ConvoluteMass(psm.PrecursorNeutralMass, 0, psm.Charge).ToString(CultureInfo.InvariantCulture)); // Precursor m/z lstValues.Add(strMassErrorPPM); // PrecursorError(ppm) lstValues.Add(psm.Charge.ToString()); // Charge lstValues.Add(psm.NumTrypticTermini.ToString()); // Tryptic state (0, 1, or 2) lstValues.Add(CleanupPeptide(psm.PeptideWithNumericMods)); // Peptide if (psm.SeqID <= 0) { lstValues.Add("**" + psm.SeqID + "**"); // SeqID is undefined } else { lstValues.Add(psm.SeqID.ToString()); // SeqID } lstValues.Add(psm.ProteinFirst); if (psm.ProteinDetails.Count > 0) { var firstProteinDetail = psm.ProteinDetails.First(); if (!string.Equals(psm.ProteinFirst, firstProteinDetail.Key)) { lstValues.Add(firstProteinDetail.Key); } else { lstValues.Add("<Match>"); } lstValues.Add(firstProteinDetail.Value.ResidueStart.ToString()); lstValues.Add(firstProteinDetail.Value.ResidueEnd.ToString()); } var strXCorr = GetScore(psm, SequestSynFileReader.GetColumnNameByID(SequestSynopsisFileColumns.XCorr), "0"); lstValues.Add(strXCorr); lstValues.Add(GetScore(psm, SequestSynFileReader.GetColumnNameByID(SequestSynopsisFileColumns.Sp), "0")); lstValues.Add(psm.MSGFSpecEValue); lstValues.Add(GetScore(psm, SequestSynFileReader.GetColumnNameByID(SequestSynopsisFileColumns.DeltaCn2), "0")); lstValues.Add(GetScore(psm, MSGFPlusSynFileReader.GetMSGFDBColumnNameByID(MSGFDBSynFileColumns.PValue), "0")); lstValues.Add(GetScore(psm, MSGFPlusSynFileReader.GetColumnNameByID(MSGFPlusSynFileColumns.EValue), "0")); lstValues.Add(GetScore(psm, MSGFPlusSynFileReader.GetColumnNameByID(MSGFPlusSynFileColumns.RankSpecEValue), "0")); lstValues.Add(GetScore(psm, MSGFPlusSynFileReader.GetMSGFDBColumnNameByID(MSGFDBSynFileColumns.FDR), "1")); lstValues.Add(GetScore(psm, MSGFPlusSynFileReader.GetColumnNameByID(MSGFPlusSynFileColumns.QValue), "0")); lstValues.Add(GetScore(psm, MSGFPlusSynFileReader.GetColumnNameByID(MSGFPlusSynFileColumns.PepQValue), "0")); if (psm.PeptideCleanSequence == "QQIEESTSDYDKEK") { Console.WriteLine(psm.Peptide + " in scan " + psm.ScanNumber); var parentIonMZ = massCalculator.ConvoluteMass(psm.PrecursorNeutralMass, 0, psm.Charge); Console.WriteLine("ParentIonMZ = " + parentIonMZ); Console.WriteLine("PeptideWithNumericMods = " + psm.PeptideWithNumericMods); } if (psm.ModifiedResidues.Count > 0) { intModifiedPSMsRead += 1; if (intModifiedPSMsRead % 500 == 0) { Console.WriteLine("PeptideWithNumericMods = " + psm.PeptideWithNumericMods); foreach (var modifiedResidue in psm.ModifiedResidues) { Console.WriteLine(" " + modifiedResidue.Residue + modifiedResidue.EndResidueLocInPeptide + ": " + modifiedResidue.ModDefinition.ModificationMassAsText); } } var dblPeptideMassRecomputed = massCalculator.ComputeSequenceMassNumericMods(psm.PeptideWithNumericMods); if (Math.Abs(psm.PeptideMonoisotopicMass - dblPeptideMassRecomputed) > 0.1) { Console.WriteLine(" Peptide mass disagreement: " + (psm.PeptideMonoisotopicMass - dblPeptideMassRecomputed).ToString("0.0000000")); } } var strFlattened = FlattenList(lstValues); if (intPSMsRead % 10000 == 0) { Console.WriteLine(strFlattened); } dctCachedValues.Add(intPSMsRead, psm); } }