Inheritance: MolecularTarget
        /// <summary>
        /// The import drift time library.
        /// </summary>
        /// <param name="inputPath">
        /// The input path.
        /// </param>
        /// <returns>
        /// The <see cref="IList"/>.
        /// </returns>
        public static IList<DriftTimeTarget> ImportDriftTimeLibrary(string inputPath)
        {
            if (!File.Exists(inputPath))
            {
                throw new Exception(string.Format("File: {0} not found", inputPath));
            }

            IList<DriftTimeTarget> targets = new List<DriftTimeTarget>();
            using (StreamReader libraryFile = new StreamReader(inputPath))
            {
                string line;
                int lineNumber = 0;
                while ((line = libraryFile.ReadLine()) != null)
                {
                    lineNumber++;

                    if (!(line.Trim().StartsWith("#") || string.IsNullOrWhiteSpace(line)))
                    {
                        string[] parts = line.Split((char[])null, StringSplitOptions.RemoveEmptyEntries);
                        int size = parts.Count();
                        if (size != 6)
                        {
                            throw new Exception("Cannot parse FitLine: " + line + " into a valid drift time Target");
                        }
                        else
                        {
                            string targetName = parts[0];
                            string targetWithAdduct = parts[1];
                            double driftTime;
                            if (!double.TryParse(parts[4], out driftTime))
                            {
                                throw new FileFormatException("Cannot parse file info: " + parts[4] + " into a valid drift time");
                            }

                            int openIndex = targetWithAdduct.LastIndexOf('[');
                            int formulaLength = openIndex;
                            int closeIndex = targetWithAdduct.LastIndexOf(']');
                            int adductLength = closeIndex - openIndex - 1;
                            string formula = targetWithAdduct.Substring(0, formulaLength);
                            String adduct = targetWithAdduct.Substring(openIndex + 1, adductLength);

                            DriftTimeTarget target = new DriftTimeTarget(targetName, driftTime, formula, IonizationMethodUtilities.ParseIonizationMethod(adduct));
                            targets.Add(target);
                        }
                    }
                }
            }

            return targets;
        }
        public void TestSinglePeptide2()
        {
            string uimfFileLocation = Cheetah;

            LcImsPeptideSearchParameters parameters = new LcImsPeptideSearchParameters
            {
                ChargeStateMax = 5,
                NetTolerance = 0.2,
                IsotopicFitScoreThreshold = 0.15,
                MassToleranceInPpm = 30,
                NumPointForSmoothing = 9
            };

            string peptide = "ATVLNYLPK";
            double net = 0.3612;

            PeptideTarget target = new PeptideTarget(1, peptide, net);
            DriftTimeTarget driftTimeTarget = new DriftTimeTarget("Test Target", 19.62, target, 2);
            target.DriftTimeTargetList.Add(driftTimeTarget);

            LcImsPeptideSearchWorkfow lcImsPeptideSearchWorkfow = new LcImsPeptideSearchWorkfow(uimfFileLocation, parameters);
            ChargeStateCorrelationResult correlationResult = lcImsPeptideSearchWorkfow.RunInformedWorkflow(target);

            using (ImsTargetResultExporter resultsExporter = new ImsTargetResultExporter("outputSingle.csv"))
            {
                if (correlationResult != null) resultsExporter.AppendCorrelationResultToCsv(correlationResult);
            }
        }
 /// <summary>
 /// The equals.
 /// </summary>
 /// <param name="other">
 /// The other.
 /// </param>
 /// <returns>
 /// The <see cref="bool"/>.
 /// </returns>
 public bool Equals(DriftTimeTarget other)
 {
     return base.Equals(other) && Math.Abs(this.NormalizedDriftTimeInMs - other.NormalizedDriftTimeInMs) < 0.00001;
 }
        public void TestMixedSampleLibraryMatching()
        {
            // TODO Import AMT library instead of manually add them
            IList<DriftTimeTarget> imsTargets = new List<DriftTimeTarget>();
            DriftTimeTarget t1 = new DriftTimeTarget("BPS protonated", 23.22, "C12H10O4S", IonizationMethod.Protonated);
            DriftTimeTarget t2 = new DriftTimeTarget("BPS sodiated", 31.8506, "C12H10O4S", IonizationMethod.Sodiumated);
            DriftTimeTarget t3 = new DriftTimeTarget("I made it up", 15, "C14H14O4S", IonizationMethod.Sodiumated);
            DriftTimeTarget t4 = new DriftTimeTarget("I made it up again", 15, "C12H11O4S", IonizationMethod.Sodiumated);

            imsTargets.Add(t3);
            imsTargets.Add(t1);
            imsTargets.Add(t2);
            imsTargets.Add(t4);

            LibraryMatchWorkflow workflow = new LibraryMatchWorkflow(BPSPostive, "output", "result.txt", new LibraryMatchParameters());
            IDictionary<DriftTimeTarget, LibraryMatchResult> results = workflow.RunLibraryMatchWorkflow(imsTargets);
            Assert.AreEqual(results[t1].AnalysisStatus, AnalysisStatus.Positive);
            Assert.AreEqual(results[t2].AnalysisStatus, AnalysisStatus.Positive);
            Assert.AreEqual(results[t3].AnalysisStatus, AnalysisStatus.Negative);
            Assert.AreEqual(results[t4].AnalysisStatus, AnalysisStatus.Negative);
        }
        /// <summary>
        /// The run libray match workflow.
        /// </summary>
        /// <param name="target">
        /// The Target.
        /// </param>
        /// <returns>
        /// The <see cref="LibraryMatchResult"/>.
        /// </returns>
        private LibraryMatchResult RunLibrayMatchWorkflow(DriftTimeTarget target)
        {
            Trace.WriteLine("    Target: " + target.CorrespondingChemical);
            Trace.WriteLine("    Target Info: " + target.TargetDescriptor);

            // Generate Theoretical Isotopic Profile
            List<Peak> theoreticalIsotopicProfilePeakList = null;
            string empiricalFormula = target.CompositionWithAdduct.ToPlainString();
            ITheorFeatureGenerator featureGenerator = new JoshTheorFeatureGenerator();
            IsotopicProfile theoreticalIsotopicProfile = featureGenerator.GenerateTheorProfile(empiricalFormula, 1);
            theoreticalIsotopicProfilePeakList = theoreticalIsotopicProfile.Peaklist.Cast<Peak>().ToList();

            // Voltage grouping
            VoltageSeparatedAccumulatedXiCs accumulatedXiCs = new VoltageSeparatedAccumulatedXiCs(this.uimfReader, target.MassWithAdduct, this.Parameters.InitialSearchMassToleranceInPpm, target.NormalizedDriftTimeInMs, this.Parameters.DriftTimeToleranceInMs, this.Parameters.DriftTubeLengthInCm);

            foreach (VoltageGroup voltageGroup in accumulatedXiCs.Keys)
            {
                // TODO Verify the temperature, pressure and drift tube voltage of the voltage group
                // Because we don't record TVP info in the AMT library. we can't verify it yet, so stick with last voltage group.
                if (IMSUtil.IsLastVoltageGroup(voltageGroup, this.NumberOfFrames))
                {
                    double globalMaxIntensity = IMSUtil.MaxIntensityAfterFrameAccumulation(voltageGroup, this.uimfReader);

                    Trace.WriteLine(string.Format("    Temperature/Pressure/Voltage Adjusted Drift time: {0:F4} ms", IMSUtil.DeNormalizeDriftTime(target.NormalizedDriftTimeInMs, voltageGroup)));

                    // Find peaks using multidimensional peak finder.
                    List<IntensityPoint> intensityPoints = accumulatedXiCs[voltageGroup].IntensityPoints;
                    List<FeatureBlob> featureBlobs = PeakFinding.FindPeakUsingWatershed(intensityPoints, this.smoother, this.Parameters.FeatureFilterLevel);
                    List<StandardImsPeak> standardPeaks = featureBlobs.Select(featureBlob => new StandardImsPeak(featureBlob, this.uimfReader, voltageGroup, target.MassWithAdduct, this.Parameters.InitialSearchMassToleranceInPpm)).ToList();

                    // Score features
                    IDictionary<StandardImsPeak, PeakScores> scoresTable = new Dictionary<StandardImsPeak, PeakScores>();
                    Trace.WriteLine(string.Format("    Voltage Group: {0:F4} V, [{1}-{2}]", voltageGroup.MeanVoltageInVolts, voltageGroup.FirstFrameNumber, voltageGroup.LastFrameNumber));

                    foreach (StandardImsPeak peak in standardPeaks)
                    {
                        PeakScores currentStatistics = FeatureScoreUtilities.ScoreFeature(
                            peak,
                            globalMaxIntensity,
                            this.uimfReader,
                            this.Parameters.InitialSearchMassToleranceInPpm,
                            this.Parameters.DriftTimeToleranceInMs,
                            voltageGroup,
                            this.NumberOfScans,
                            target,
                            IsotopicScoreMethod.Angle,
                            theoreticalIsotopicProfilePeakList);
                        scoresTable.Add(peak, currentStatistics);
                    }

                    // filter out features with Ims scans at 1% left or right.
                    Predicate<StandardImsPeak> scanPredicate = blob => FeatureFilters.FilterExtremeDriftTime(blob, (int)this.NumberOfScans);
                    Predicate<StandardImsPeak> shapeThreshold = blob => FeatureFilters.FilterBadPeakShape(blob, scoresTable[blob].PeakShapeScore, this.Parameters.PeakShapeThreshold);
                    Predicate<StandardImsPeak> isotopeThreshold = blob => FeatureFilters.FilterBadIsotopicProfile(blob, scoresTable[blob].IsotopicScore, this.Parameters.IsotopicThreshold);
                    Predicate<StandardImsPeak> massDistanceThreshold = blob => FeatureFilters.FilterHighMzDistance(blob, target, this.Parameters.MatchingMassToleranceInPpm);

                    // Print out candidate features that pass the intensity threshold.
                    foreach (StandardImsPeak peak in standardPeaks)
                    {
                        DriftTimeFeatureDistance distance = new DriftTimeFeatureDistance(target, peak, voltageGroup);

                        bool badScanRange = scanPredicate(peak);
                        bool badPeakShape = shapeThreshold(peak);
                        bool lowIsotopicAffinity = isotopeThreshold(peak);
                        bool lowMzAffinity = massDistanceThreshold(peak);

                        PeakScores currentStatistics = scoresTable[peak];
                        Trace.WriteLine(string.Empty);
                        Trace.WriteLine(string.Format("        Candidate feature found at drift time {0:F2} ms (scan number {1})",
                            peak.PeakApex.DriftTimeCenterInMs,
                            peak.PeakApex.DriftTimeCenterInScanNumber));
                        Trace.WriteLine(
                            string.Format(
                                "            M/Z: {0:F2} Dalton", peak.PeakApex.MzCenterInDalton));
                        Trace.WriteLine(
                            string.Format(
                                "            Drift time: {0:F2} ms (scan number {1})",
                                peak.PeakApex.DriftTimeCenterInMs,
                                peak.PeakApex.DriftTimeCenterInScanNumber));
                        Trace.WriteLine(
                            string.Format("            MzInDalton difference: {0:F2} ppm", distance.MassDifferenceInPpm));

                        Trace.WriteLine(
                            string.Format("            Drift time difference: {0:F4} ms", distance.DriftTimeDifferenceInMs));

                        Trace.WriteLine(string.Format("            Intensity Score: {0:F4}", currentStatistics.IntensityScore));
                        Trace.WriteLine(string.Format("            Peak Shape Score: {0:F4}", currentStatistics.PeakShapeScore));
                        Trace.WriteLine(string.Format("            Isotopic Score:  {0:F4}", currentStatistics.IsotopicScore));
                        Trace.WriteLine(string.Format("            AveragedPeakIntensities:  {0:F4}", peak.SummedIntensities));

                        string rejectionReason = badScanRange ? "        [Bad scan range] " : "        ";
                        rejectionReason += badPeakShape ? "[Bad Peak Shape] " : string.Empty;
                        rejectionReason += lowMzAffinity ? "[Inaccurate Mass] " : string.Empty;
                        rejectionReason += lowIsotopicAffinity ? "[Different Isotopic Profile] " : string.Empty;

                        if (badScanRange || lowIsotopicAffinity || badPeakShape)
                        {
                            Trace.WriteLine(rejectionReason);
                        }
                        else
                        {
                            Trace.WriteLine("        [Pass]");
                        }
                    }

                    standardPeaks.RemoveAll(scanPredicate);

                    standardPeaks.RemoveAll(massDistanceThreshold);

                    standardPeaks.RemoveAll(shapeThreshold);

                    standardPeaks.RemoveAll(isotopeThreshold);

                    if (standardPeaks.Count == 0)
                    {
                        Trace.WriteLine(string.Format("    [No Match]"));
                        Trace.WriteLine(string.Empty);
                        return new LibraryMatchResult(null, AnalysisStatus.Negative, null);
                    }

                    StandardImsPeak closestPeak = standardPeaks.First();
                    DriftTimeFeatureDistance shortestDistance = new DriftTimeFeatureDistance(target, standardPeaks.First(), voltageGroup);
                    foreach (var peak in standardPeaks)
                    {
                        DriftTimeFeatureDistance distance = new DriftTimeFeatureDistance(target, peak, voltageGroup);
                        if (distance.CompareTo(shortestDistance) < 0)
                        {
                            closestPeak = peak;
                        }
                    }

                    Trace.WriteLine(string.Format("    [Match]"));
                    Trace.WriteLine(string.Empty);
                    return new LibraryMatchResult(closestPeak, AnalysisStatus.Positive, shortestDistance);
                }
            }

            throw new Exception("No voltage groups in the Dataset match temerature, pressure, or drift tube voltage setting from the library. Matching failed.");
        }
        public static List<PeptideTarget> ImportMassTags(string serverName, string databaseName, double maxMsgfSpecProb = 1e-10, bool isForCalibration = false)
        {
            List<PeptideTarget> targetList = new List<PeptideTarget>();

            // Build connection string
            string connectionString = BuildConnectionString(serverName, databaseName);

            // Using connection
            var dbFactory = DbProviderFactories.GetFactory("System.Data.SqlClient");
            using (var connection = dbFactory.CreateConnection())
            {
                connection.ConnectionString = connectionString;
                connection.Open();

                // Execute query
                string queryString = isForCalibration ? GetQueryForCalibration() : GetQuery();
                using (DbCommand command = connection.CreateCommand())
                {
                    command.CommandText = queryString;
                    command.CommandTimeout = 120;
                    DbDataReader reader = command.ExecuteReader();

                    PeptideTarget currentImsTarget = null;

                    while (reader.Read())
                    {
                        int massTagId = Convert.ToInt32(reader["Mass_Tag_ID"]);
                        string peptide = Convert.ToString(reader["peptide"]);
                        double normalizedElutionTime = Convert.ToDouble(reader["Avg_GANET"]);
                        int modCount = Convert.ToInt16(reader["Mod_Count"]);

                        List<Modification> modificationList = new List<Modification>();

                        if(modCount > 0)
                        {
                            string modificationString = Convert.ToString(reader["Mod_Description"]);
                            string[] splitModString = modificationString.Split(',');
                            foreach (var singleModString in splitModString)
                            {
                                string modificationName = singleModString.Split(':')[0];
                                Modification modification = _dmsModToInformedModMap[modificationName];
                                modificationList.Add(modification);
                            }
                        }

                        bool isSameTarget = IsSameTarget(currentImsTarget, peptide, normalizedElutionTime, modificationList);

                        if(!isSameTarget)
                        {
                            currentImsTarget = new PeptideTarget(massTagId, peptide, normalizedElutionTime, modificationList);
                            targetList.Add(currentImsTarget);
                        }

                        int chargeState = Convert.ToInt16(reader["Conformer_Charge"]);
                        double driftTime = Convert.ToDouble(reader["Drift_Time_Avg"]);

                        DriftTimeTarget driftTimeTarget = new DriftTimeTarget(massTagId.ToString(CultureInfo.InvariantCulture), driftTime, currentImsTarget.EmpiricalFormula, new IonizationAdduct(chargeState));
                        currentImsTarget.DriftTimeTargetList.Add(driftTimeTarget);
                    }
                }
            }

            return targetList;
        }