/// <summary>
        /// The find optimum hypothesis.
        /// </summary>
        /// <param name="observations">
        /// The observations.
        /// </param>
        /// <param name="driftTubeLength">
        /// The drift Tube Length.
        /// </param>
        /// <param name="massTarget">
        /// The mass Target.
        /// </param>
        /// <param name="parameters">
        /// The parameters.
        /// </param>
        /// <returns>
        /// The <see cref="AssociationHypothesis"/>.
        /// </returns>
        /// <exception cref="NotImplementedException">
        /// </exception>
        public AssociationHypothesis FindOptimumHypothesis(IEnumerable<ObservedPeak> observations, double driftTubeLength, IImsTarget massTarget, CrossSectionSearchParameters parameters, int numberOfVoltageGroups)
        {
            observations = observations.ToList();

            ObservationTransitionGraph<IonTransition> transitionGraph = new ObservationTransitionGraph<IonTransition>(observations, (a, b) => new IonTransition(a, b));

            // Visualize the graph.
            // transitionGraph.PlotGraph();

            // Find all the possible combinotorial tracks
            // IList<IsomerTrack> candidateTracks = this.FindAllReasonableTracks(transitionGraph, driftTubeLength, massTarget, parameters).ToList();

            // Find the top N tracks using K shorestest path algorithm
            IEnumerable<IEnumerable<IonTransition>> kShorestPaths = transitionGraph.PeakGraph.RankedShortestPathHoffmanPavley(t => 0 - Math.Log(t.TransitionProbability), transitionGraph.SourceVertex, transitionGraph.SinkVertex, this.maxTracks);

            IEnumerable<IsomerTrack> candidateTracks = MinCostFlowIonTracker.ToTracks(kShorestPaths, parameters, numberOfVoltageGroups, parameters.RegressionSelection);

            // filter paths
            TrackFilter filter = new TrackFilter();
            Predicate<IsomerTrack> trackPredicate = track => filter.IsTrackPossible(track, massTarget, parameters);
            List<IsomerTrack> filteredTracks = candidateTracks.ToList().FindAll(trackPredicate);

            // Select the top N tracks to proceed to next step.
            var hypotheses = this.FindAllHypothesis(filteredTracks, observations).ToArray();

            // Find the combination of tracks that produces the highest posterior probablity.
              IOrderedEnumerable<AssociationHypothesis> sortedAssociationHypotheses = hypotheses.OrderByDescending(h => h.ProbabilityOfHypothesisGivenData);

            return sortedAssociationHypotheses.FirstOrDefault();
        }
 public AssociationHypothesis FindOptimumHypothesis(
     IEnumerable<ObservedPeak> observations,
     double driftTubeLength,
     IImsTarget target,
     CrossSectionSearchParameters parameters)
 {
     throw new NotImplementedException();
 }
        public void PlotAssociationHypothesis(AssociationHypothesis hypothesis, string plotLocation, string datasetName, IImsTarget target, IDictionary<string, IList<ObservedPeak>> preFilteredPeaks)
        {
            //int width = 450;
            //int height = 256;

            int width = 675;
            int height = 384;
            PlotModel associationHypothsisPlot = this.AssociationHypothesisPlot(hypothesis, datasetName, target);
            associationHypothsisPlot = this.AnnotateRemovedPeaks(associationHypothsisPlot, preFilteredPeaks);
            this.PlotDiagram(plotLocation, associationHypothsisPlot, width, height);
        }
示例#4
0
 /// <summary>
 /// The add result to scores table.
 /// </summary>
 /// <param name="dataset">
 /// The dataset.
 /// </param>
 /// <param name="chemicalResult">
 /// The chemical result.
 /// </param>
 /// <param name="target">
 /// The target.
 /// </param>
 /// <param name="table">
 /// The table.
 /// </param>
 /// <param name="colDef">
 /// The col def.
 /// </param>
 /// <returns>
 /// The <see cref="int"/>.
 /// </returns>
 public static int AddResultToScoresTable(string dataset, CrossSectionWorkflowResult chemicalResult, IImsTarget target, NumericTable table, IList<string> colDef)
 {
     TableRow dict = new TableRow(dataset + target);
     dict.Name += "(" + chemicalResult.AnalysisStatus + ")";
     dict.Add(colDef[1], chemicalResult.AverageObservedPeakStatistics.IntensityScore);
     dict.Add(colDef[2], chemicalResult.AverageObservedPeakStatistics.IsotopicScore);
     dict.Add(colDef[3], chemicalResult.AverageObservedPeakStatistics.PeakShapeScore);
     dict.Add(colDef[0], chemicalResult.AverageVoltageGroupStability);
     dict.Add(colDef[4], chemicalResult.AssociationHypothesisInfo.ProbabilityOfHypothesisGivenData);
     table.Add(dict);
     return 1;
 }
        /// <summary>
        /// The score feature using isotopic profile.
        /// </summary>
        /// <param name="imsPeak">
        /// The ims Peak.
        /// </param>
        /// <param name="reader">
        /// The reader.
        /// </param>
        /// <param name="target">
        /// The Target.
        /// </param>
        /// <param name="isotopicPeakList">
        /// The isotopic peak list.
        /// </param>
        /// <param name="voltageGroup">
        /// The voltage Group.
        /// </param>
        /// <param name="selectedMethod">
        /// The selected Method.
        /// </param>
        /// <param name="globalMaxIntensities">
        /// </param>
        /// <returns>
        /// The <see cref="double"/>.
        /// </returns>
        /// <exception cref="InvalidOperationException">
        /// </exception>
        public static double IsotopicProfileScore(StandardImsPeak imsPeak, DataReader reader, IImsTarget target, List<Peak> isotopicPeakList, VoltageGroup voltageGroup, IsotopicScoreMethod selectedMethod, double globalMaxIntensities, double totalScans)
        {
            // No need to move on if the isotopic profile is not found
            // if (observedIsotopicProfile == null || observedIsotopicProfile.MonoIsotopicMass < 1)
            // {
            // result.AnalysisStatus = AnalysisStatus.IsotopicProfileNotFound;
            // continue;
            // }

            // Find Isotopic Profile
            // List<Peak> massSpectrumPeaks;
            // IsotopicProfile observedIsotopicProfile = _msFeatureFinder.IterativelyFindMSFeature(massSpectrum, theoreticalIsotopicProfile, out massSpectrumPeaks);
            if (target.CompositionWithoutAdduct == null)
            {
                throw new InvalidOperationException("Cannot score feature using isotopic profile for Ims Target without CompositionWithoutAdduct provided.");
            }

            // Bad Feature, so get out
            if (imsPeak == null)
            {
                return 0;
            }

            // Get the scanWindow size
            int scanNumberMax = imsPeak.PeakApex.DriftTimeFullWidthHalfMaxHigherBondInScanNumber;
            int scanNumberMin = imsPeak.PeakApex.DriftTimeFullWidthHalfMaxLowerBondInScanNumber;
            if ((scanNumberMin < 0) || (scanNumberMax > totalScans - 1))
            {
                return 0;
            }

            // Get the mass error from the observed feature peak from the Target theoretical peak
            double mzOffset = imsPeak.PeakApex.MzCenterInDalton - target.MassWithAdduct;

            List<double> observedIsotopicPeakList = new List<double>();

            int totalIsotopicIndex = isotopicPeakList.Count;
            int[] isotopicIndexMask = new int[totalIsotopicIndex];

            // Find an unsaturated peak in the isotopic profile
            for (int i = 0; i < totalIsotopicIndex; i++)
            {
                // Isotopic centerMz
                double Mz = isotopicPeakList[i].XValue;

                var peakList = reader.GetXic(Mz + mzOffset,
                    imsPeak.PeakApex.MzWindowToleranceInPpm,
                    voltageGroup.FirstFrameNumber,
                    voltageGroup.LastFrameNumber,
                    scanNumberMin,
                    scanNumberMax,
                    DataReader.FrameType.MS1,
                    DataReader.ToleranceType.PPM);

                // Sum the intensities
                double sumIntensities = 0;
                foreach (var point in peakList)
                {
                    sumIntensities += point.Intensity;
                    if (point.IsSaturated)
                    {
                        isotopicIndexMask[i] = 1;
                    }
                }

                sumIntensities /= voltageGroup.FrameAccumulationCount;
                observedIsotopicPeakList.Add(sumIntensities);
            }

            // Return 0 if the intensity sum is really small
            if (observedIsotopicPeakList.Sum() < globalMaxIntensities * 0.0003)
            {
                return 0;
            }

            // If the unsaturated isotopes are below a certain threshold
            if (totalIsotopicIndex - isotopicIndexMask.Sum() <= 1)
            {
                return 0;
            }

            if (selectedMethod == IsotopicScoreMethod.Angle)
            {
                return IsotopicProfileScoreAngle(observedIsotopicPeakList, isotopicPeakList);
            }
            else if (selectedMethod == IsotopicScoreMethod.EuclideanDistance)
            {
                return IsotopicProfileScoreEuclidean(observedIsotopicPeakList, isotopicPeakList);
            }
            else if (selectedMethod == IsotopicScoreMethod.PearsonCorrelation)
            {
                return PearsonCorrelation(observedIsotopicPeakList, isotopicPeakList);
            }
            else if (selectedMethod == IsotopicScoreMethod.Bhattacharyya)
            {
                return BhattacharyyaDistance(observedIsotopicPeakList, isotopicPeakList);
            }
            else if (selectedMethod == IsotopicScoreMethod.EuclideanDistanceAlternative)
            {
                return EuclideanAlternative(observedIsotopicPeakList, isotopicPeakList);
            }
            else
            {
                throw new NotImplementedException();
            }
        }
        /// <summary>
        /// The score feature.
        /// </summary>
        /// <param name="peak">
        /// The peak.
        /// </param>
        /// <param name="globalMaxIntensity">
        /// The global max intensity.
        /// </param>
        /// <param name="uimfReader">
        /// The uimf reader.
        /// </param>
        /// <param name="massToleranceInPpm">
        /// The mass tolerance in ppm.
        /// </param>
        /// <param name="driftTimeToleranceInMs">
        /// The drift time tolerance in ms.
        /// </param>
        /// <param name="voltageGroup">
        /// The voltage group.
        /// </param>
        /// <param name="voltageGroupScans">
        /// The voltage group scans.
        /// </param>
        /// <param name="target">
        /// The target.
        /// </param>
        /// <param name="isotopicScoreMethod">
        /// The isotopic score method.
        /// </param>
        /// <param name="theoreticalIsotopicProfile">
        /// The theoretical isotopic profile.
        /// </param>
        /// <returns>
        /// The <see cref="PeakScores"/>.
        /// </returns>
        public static PeakScores ScoreFeature(this StandardImsPeak peak, double globalMaxIntensity, DataReader uimfReader, double massToleranceInPpm, double driftTimeToleranceInMs, VoltageGroup voltageGroup, int voltageGroupScans, IImsTarget target, IsotopicScoreMethod isotopicScoreMethod, List<Peak> theoreticalIsotopicProfile)
        {
            double intensityScore = IntensityScore(peak, globalMaxIntensity);

            double peakShapeScore = PeakShapeScore(
                peak,
                uimfReader,
                massToleranceInPpm,
                driftTimeToleranceInMs,
                voltageGroup,
                globalMaxIntensity,
                voltageGroupScans);

            double isotopicScore = 0;
            if (target.HasCompositionInfo)
            {
                isotopicScore = IsotopicProfileScore(
                    peak,
                    uimfReader,
                    target,
                    theoreticalIsotopicProfile,
                    voltageGroup,
                    IsotopicScoreMethod.Angle,
                    globalMaxIntensity,
                    voltageGroupScans);
            }

            return new PeakScores(intensityScore, isotopicScore, peakShapeScore);
        }
        /// <summary>
        /// The report feature evaluation.
        /// </summary>
        /// <param name="peak">
        /// The peak.
        /// </param>
        /// <param name="scores">
        /// The scores.
        /// </param>
        /// <param name="verbose">
        /// The verbose.
        /// </param>
        /// <param name="target">
        /// The target.
        /// </param>
        /// <param name="badScanRange">
        /// The bad scan range.
        /// </param>
        /// <param name="lowAbsoluteIntensity">
        /// The low intensity.
        /// </param>
        /// <param name="lowRelativeIntensity"></param>
        /// <param name="badPeakShape">
        /// The bad peak shape.
        /// </param>
        /// <param name="lowIsotopicAffinity">
        /// The low isotopic affinity.
        /// </param>
        /// <returns>
        /// If the feature pass all the filters <see cref="bool"/>.
        /// </returns>
        private static string ReportFeatureEvaluation(StandardImsPeak peak, PeakScores scores, bool verbose, IImsTarget target, bool badScanRange, bool lowAbsoluteIntensity, bool lowRelativeIntensity, bool badPeakShape, bool lowIsotopicAffinity)
        {
            Trace.WriteLine(string.Format("        Candidate feature found at [centerMz = {0:F4}, drift time = {1:F2} ms(#{2})] ", peak.PeakApex.MzCenterInDalton, peak.PeakApex.DriftTimeCenterInMs,     peak.PeakApex.DriftTimeCenterInScanNumber));
            Trace.WriteLine(string.Format("            IntensityScore: {0:F4}", scores.IntensityScore));

            if (!lowAbsoluteIntensity)
            {
                Trace.WriteLine(string.Format("            peakShapeScore: {0:F4}", scores.PeakShapeScore));

                if (target.HasCompositionInfo)
                {
                    Trace.WriteLine(string.Format("            isotopicScore:  {0:F4}", scores.IsotopicScore));
                }
            }

            string rejectionReason = badScanRange ? "[Bad scan range] " :
                lowAbsoluteIntensity ? "[Low Absolute Intensity] " :
                badPeakShape ? "[Bad Peak Shape] " :
                lowIsotopicAffinity ? "[Different Isotopic Profile] " :
                lowRelativeIntensity ? "[Low Relative Intensity] " : string.Empty;

            bool rejected = badScanRange || lowAbsoluteIntensity || lowIsotopicAffinity || badPeakShape || lowRelativeIntensity;

            if (verbose)
            {
                if (rejected)
                {
                    Trace.WriteLine("        " + rejectionReason);
                }
                else
                {
                    Trace.WriteLine("        [PASS]");
                }

                Trace.WriteLine(string.Empty);
            }

            return rejectionReason;
        }
        /// <summary>
        /// The run molecule informed work flow.
        /// </summary>
        /// <param name="target">
        /// The Target.
        /// </param>
        /// <param name="detailedVerbose">
        /// </param>
        /// <returns>
        /// The <see cref="CrossSectionWorkflowResult"/>.
        /// </returns>
        public CrossSectionWorkflowResult RunCrossSectionWorkFlow(IImsTarget target, bool detailedVerbose = true)
        {
            // Reassign trace listener to print to console as well as the target directory.
            using (this.ResetTraceListenerToTarget(target, this.DatasetName))
            {
                try
                {
                    // Get the monoisotopic mass for viper, which is different from anything else.
                    double viperFriendlyMass = target.MassWithAdduct;
                    if (target.ChargeState < 0)
                    {
                        viperFriendlyMass = viperFriendlyMass + new Composition(0, target.ChargeState, 0, 0, 0).Mass;
                    }
                    else
                    {
                        viperFriendlyMass = viperFriendlyMass - new Composition(0, Math.Abs(target.ChargeState), 0, 0, 0).Mass;
                    }

                    // Generate Theoretical Isotopic Profile
                    List<Peak> theoreticalIsotopicProfilePeakList = null;
                    if (target.HasCompositionInfo)
                    {
                        int chargeStateAbs = Math.Abs(target.ChargeState);

                        // Again this isotopic profile generator auto adds hydrogen for you depending on charge states. So here take it out.
                        Composition compensatedComposition = target.CompositionWithAdduct - new Composition(0, chargeStateAbs, 0, 0, 0);
                        string empiricalFormula = compensatedComposition.ToPlainString();

                        IsotopicProfile theoreticalIsotopicProfile = this.theoreticalFeatureGenerator.GenerateTheorProfile(empiricalFormula, chargeStateAbs);

                        theoreticalIsotopicProfilePeakList = theoreticalIsotopicProfile.Peaklist.Cast<Peak>().ToList();
                    }

                    Trace.WriteLine(string.Format("Dataset: {0}", this.uimfReader.UimfFilePath));
                    ReportTargetInfo(target, detailedVerbose);

                    double targetMz = Math.Abs(target.MassWithAdduct / target.ChargeState);

                    // Voltage grouping. Note that we only accumulate frames as needed. Accumulate frames globally is too costly.
                    // Here we accumulate the XICs around target MZ.
                    VoltageSeparatedAccumulatedXiCs accumulatedXiCs = new VoltageSeparatedAccumulatedXiCs(this.uimfReader, targetMz, this.Parameters.MzWindowHalfWidthInPpm, this.Parameters.DriftTubeLengthInCm);

                    // Remove voltage groups that don't have sufficient frame accumulations
                    IEnumerable<VoltageGroup> remainingVGs = accumulatedXiCs.Keys;
                    IEnumerable<VoltageGroup> toBeRemoved = VoltageGroupFilters.RemoveVoltageGroupsWithInsufficentFrames(remainingVGs, this.Parameters.InsufficientFramesFraction);
                    foreach (VoltageGroup voltageGroup in toBeRemoved)
                    {
                        accumulatedXiCs.Remove(voltageGroup);
                    }

                    // Perform feature detection and scoring and the given MzInDalton range on the accumulated XICs to get the base peaks.
                    if (detailedVerbose)
                    {
                        Trace.WriteLine("Feature detection and scoring: ");
                    }

                    IList<VoltageGroup> rejectedVoltageGroups = new List<VoltageGroup>();
                    IList<ObservedPeak> filteredObservations = new List<ObservedPeak>();
                    IList<ObservedPeak> allObservations = new List<ObservedPeak>();
                    IDictionary<string, IList<ObservedPeak>> rejectedObservations = new Dictionary<string, IList<ObservedPeak>>();

                    var numberOfParticipatingVGs = accumulatedXiCs.Keys.Count;

                    // Iterate through the features and perform filtering on isotopic affinity, intensity, drift time and peak shape.
                    foreach (VoltageGroup voltageGroup in accumulatedXiCs.Keys)
                    {
                        double globalMaxIntensity = IMSUtil.MaxIntensityAfterFrameAccumulation(voltageGroup, this.uimfReader);

                        List<StandardImsPeak> standardPeaks = this.FindPeaksBasedOnXIC(voltageGroup, accumulatedXiCs[voltageGroup], target);

                        // Score features
                        IDictionary<StandardImsPeak, PeakScores> scoresTable = new Dictionary<StandardImsPeak, PeakScores>();
                        if (detailedVerbose)
                        {
                            Trace.WriteLine(
                                string.Format(
                                    "    Voltage group: {0:F2} V, Frame {1}-{2}, {3:F2}K, {4:F2}Torr",
                                    voltageGroup.MeanVoltageInVolts,
                                    voltageGroup.FirstFrameNumber,
                                    voltageGroup.LastFrameNumber,
                                    voltageGroup.MeanTemperatureInKelvin,
                                    voltageGroup.MeanPressureInTorr));

                        }

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

                            scoresTable.Add(peak, currentStatistics);
                        }

                        double maxIntensity = standardPeaks.Max(x => x.SummedIntensities);

                        Predicate<StandardImsPeak> relativeIntensityThreshold = imsPeak => FeatureFilters.FilterOnRelativeIntesity(imsPeak, maxIntensity, this.Parameters.RelativeIntensityPercentageThreshold);

                        // filter out non Target peaks and noise.
                        Predicate<StandardImsPeak> absoluteIntensityThreshold = imsPeak => FeatureFilters.FilterOnAbsoluteIntensity(imsPeak, scoresTable[imsPeak].IntensityScore, this.Parameters.AbsoluteIntensityThreshold);

                        // filter out features with Ims scans at 1% left or right.
                        Predicate<StandardImsPeak> scanPredicate = imsPeak => FeatureFilters.FilterExtremeDriftTime(imsPeak, this.NumberOfScans);

                        // filter out features with bad peak shapes.
                        Predicate<StandardImsPeak> shapeThreshold = imsPeak => FeatureFilters.FilterBadPeakShape(imsPeak, scoresTable[imsPeak].PeakShapeScore, this.Parameters.PeakShapeThreshold);

                        // filter out features with distant isotopic profile.
                        Predicate<StandardImsPeak> isotopeThreshold = imsPeak => FeatureFilters.FilterBadIsotopicProfile(imsPeak, scoresTable[imsPeak].IsotopicScore, this.Parameters.IsotopicThreshold);

                        // Print out candidate features and how they were rejected.
                        foreach (StandardImsPeak peak in standardPeaks)
                        {
                            PeakScores currentStatistics = scoresTable[peak];
                            string rejectionReason = ReportFeatureEvaluation(
                                peak,
                                currentStatistics,
                                detailedVerbose,
                                target,
                                scanPredicate(peak),
                                absoluteIntensityThreshold(peak),
                                relativeIntensityThreshold(peak),
                                shapeThreshold(peak),
                                isotopeThreshold(peak));
                            bool pass = string.IsNullOrEmpty(rejectionReason);

                            ObservedPeak analyzedPeak = new ObservedPeak(voltageGroup, peak, currentStatistics);
                            if (pass)
                            {
                                filteredObservations.Add(analyzedPeak);
                            }
                            else
                            {
                                if (rejectedObservations.ContainsKey(rejectionReason))
                                {
                                    rejectedObservations[rejectionReason].Add(analyzedPeak);
                                }

                                else
                                {
                                    rejectedObservations.Add(rejectionReason, new List<ObservedPeak>(){analyzedPeak});
                                }
                            }

                            allObservations.Add(analyzedPeak);
                        }

                        standardPeaks.RemoveAll(scanPredicate);

                        standardPeaks.RemoveAll(absoluteIntensityThreshold);

                        standardPeaks.RemoveAll(relativeIntensityThreshold);

                        standardPeaks.RemoveAll(shapeThreshold);

                        if (target.HasCompositionInfo)
                        {
                            standardPeaks.RemoveAll(isotopeThreshold);
                        }

                        if (standardPeaks.Count == 0)
                        {
                            if (detailedVerbose)
                            {
                                Trace.WriteLine(string.Format("    (All features were rejected in voltage group {0:F4} V)",     voltageGroup.MeanVoltageInVolts));
                                Trace.WriteLine(string.Empty);
                                Trace.WriteLine(string.Empty);
                            }

                            rejectedVoltageGroups.Add(voltageGroup);
                        }

                        // Rate the feature's VoltageGroupScoring score. VoltageGroupScoring score measures how likely the voltage group contains and detected the Target ion.
                        voltageGroup.VoltageGroupScore = VoltageGroupScoring.ComputeVoltageGroupStabilityScore(voltageGroup);
                    }

                    // Remove voltage groups that were rejected
                    foreach (VoltageGroup voltageGroup in rejectedVoltageGroups)
                    {
                        accumulatedXiCs.Remove(voltageGroup);
                    }

                    IEnumerable<ObservedPeak> rejectedPeaks = rejectedObservations.Values.SelectMany(x => x);

                    // Report analysis as negative
                    if (accumulatedXiCs.Keys.Count == 0)
                    {
                        CrossSectionWorkflowResult informedResult = CrossSectionWorkflowResult.CreateNegativeResult(rejectedPeaks, rejectedVoltageGroups, target, this.DatasetPath, this.OutputPath, this.SampleCollectionDate);
                        ReportAnslysisResultAndMetrics(informedResult, detailedVerbose);
                        return informedResult;
                    }
                    else
                    {
                    // Perform the data association algorithm.
                    IIonTracker tracker = new CombinatorialIonTracker(3000);

                    // Because for somereason we are not keeping track of drift tube length in UIMF...so we kind of have to go ask the instrument operator..
                    double driftTubeLength = this.Parameters.DriftTubeLengthInCm;
                    AssociationHypothesis optimalAssociationHypothesis = tracker.FindOptimumHypothesis(filteredObservations, driftTubeLength, target, this.Parameters, numberOfParticipatingVGs);

                    if (optimalAssociationHypothesis == null)
                    {
                        CrossSectionWorkflowResult negResult = CrossSectionWorkflowResult.CreateNegativeResult(rejectedPeaks, rejectedVoltageGroups, target, this.DatasetPath, this.OutputPath, this.SampleCollectionDate);
                        ReportAnslysisResultAndMetrics(negResult, detailedVerbose);
                        return negResult;
                    }

                    if (detailedVerbose)
                    {
                        Console.WriteLine("Writes QC plot of fitline to " + this.OutputPath);
                        Trace.WriteLine(string.Empty);
                    }

                    string extension = (this.Parameters.GraphicsExtension.StartsWith(".")) ?
                        this.Parameters.GraphicsExtension : "." + this.Parameters.GraphicsExtension;
                    string outputPath = string.Format("{0}target_{1}_in_{2}_QA{3}", this.OutputPath, target.TargetDescriptor, this.DatasetName, extension);
                    ImsInformedPlotter plotter = new ImsInformedPlotter();
                    plotter.PlotAssociationHypothesis(optimalAssociationHypothesis, outputPath, this.DatasetName, target, rejectedObservations);

                    // Printout results
                    if (detailedVerbose)
                    {
                        Trace.WriteLine("Target Data Association");
                        int count = 0;
                        foreach (IsomerTrack track in optimalAssociationHypothesis.Tracks)
                        {
                            Trace.WriteLine(string.Format(" T{0}:   ", count));
                            foreach (ObservedPeak peak in track.ObservedPeaks)
                            {
                                Trace.WriteLine(string.Format("       [td: {0:F4}ms, V: {1:F4}V, T: {2:F4}K, P: {3:F4}Torr]",
                                    peak.Peak.PeakApex.DriftTimeCenterInMs,
                                    peak.VoltageGroup.MeanVoltageInVolts,
                                    peak.VoltageGroup.MeanTemperatureInKelvin,
                                    peak.VoltageGroup.MeanPressureInTorr));
                            }
                            count++;
                            Trace.WriteLine("");
                        }

                        Trace.WriteLine("");
                    }

                    // Remove outliers with high influence.
                    // FitLine.RemoveOutliersAboveThreshold(3, minFitPoints);

                    // Remove outliers until min fit point is reached or good R2 is achieved.
                    // while (TrackFilter.IsLowR2(FitLine.RSquared) && FitLine.FitPointCollection.Count > minFitPoints)
                    // {
                    //     FitLine.RemoveOutlierWithHighestCookDistance(minFitPoints);
                    // }

                    // Remove the voltage considered outliers
                    // foreach (VoltageGroup voltageGroup in accumulatedXiCs.Keys.Where(p => FitLine.OutlierCollection.Contains(p.FitPoint)).ToList())
                    // {
                    //     accumulatedXiCs.Remove(voltageGroup);
                    // }

                    CrossSectionWorkflowResult informedResult = CrossSectionWorkflowResult.CreateResultFromAssociationHypothesis(
                        this.Parameters,
                        optimalAssociationHypothesis,
                        target,
                        accumulatedXiCs.Keys,
                        allObservations,
                        this.DatasetPath,
                        this.OutputPath,
                        this.SampleCollectionDate,
                        viperFriendlyMass
                        );
                        ReportAnslysisResultAndMetrics(informedResult, detailedVerbose);

                        Trace.Listeners.Clear();
                    return informedResult;
                    }
                }
                catch (Exception e)
                {
                    // Print result
                    Trace.WriteLine(e.Message);
                    Trace.WriteLine(e.StackTrace);
                    Trace.Listeners.Clear();
                    Trace.Close();
                        Trace.Listeners.Clear();

                    // create the error result
                    return CrossSectionWorkflowResult.CreateErrorResult(target, this.DatasetName, this.DatasetPath, this.OutputPath, this.SampleCollectionDate);
                }
            }
        }
 /// <summary>
 /// The create error result.
 /// </summary>
 /// <param name="target">
 /// The target.
 /// </param>
 /// <param name="datasetName">
 /// The dataset name.
 /// </param>
 /// <param name="datasetPath"></param>
 /// <returns>
 /// The <see cref="CrossSectionWorkflowResult"/>.
 /// </returns>
 public static CrossSectionWorkflowResult CreateErrorResult(IImsTarget target, string datasetName, string datasetPath, string analysisPath, string SampleCollectionTime)
 {
     // No hypothesis can be made.
     return new CrossSectionWorkflowResult(
         datasetPath,
         target,
         AnalysisStatus.UknownError,
         null,
         null,
         null,
         0,
         analysisPath,
         SampleCollectionTime
         );
 }
        internal static CrossSectionWorkflowResult CreateResultFromAssociationHypothesis(CrossSectionSearchParameters parameters, AssociationHypothesis optimalHypothesis, IImsTarget target, IEnumerable<VoltageGroup> allVoltageGroups, IEnumerable<ObservedPeak> allPeaks, string datasetPath, string analysisPath, string  sampleCollectionDate, double viperCompatibleMass = 0)
        {
            // Initialize the result struct.
            AssociationHypothesisInfo associationHypothesisInfo = new AssociationHypothesisInfo(optimalHypothesis.ProbabilityOfDataGivenHypothesis, optimalHypothesis.ProbabilityOfHypothesisGivenData);

            double averageVoltageGroupScore = VoltageGroupScoring.ComputeAverageVoltageGroupStabilityScore(allVoltageGroups);
            IEnumerable<PeakScores> allFeatureStatistics = allPeaks.Select(x => x.Statistics);
            PeakScores averageObservedPeakStatistics = FeatureScoreUtilities.AverageFeatureStatistics(allFeatureStatistics);

            IEnumerable<IsomerTrack> tracks = optimalHypothesis.Tracks.ToList();

            // Find the conformer with the closest m/z
            IsomerTrack trackWithBestMz = tracks.OrderBy(x => Math.Abs(Metrics.DaltonToPpm(x.AverageMzInDalton - target.MassWithAdduct, target.MassWithAdduct))).First();
            double bestMzInPpm = Metrics.DaltonToPpm(trackWithBestMz.AverageMzInDalton - target.MassWithAdduct, target.MassWithAdduct);
            IList<IdentifiedIsomerInfo> isomersInfo = tracks.Select(x => x.ExportIdentifiedIsomerInfo(viperCompatibleMass, allVoltageGroups.Count() - parameters.MaxOutliers, parameters.MinR2,  target, bestMzInPpm)).ToList();

            AnalysisStatus finalStatus = TrackToHypothesisConclusionLogic(isomersInfo.Select(info => info.AnalysisStatus));

            CrossSectionWorkflowResult informedResult = new CrossSectionWorkflowResult(
            datasetPath,
            target,
            finalStatus,
            associationHypothesisInfo,
            isomersInfo,
            averageObservedPeakStatistics,
            averageVoltageGroupScore,
            analysisPath,
            sampleCollectionDate
            );

            return informedResult;
        }
        /// <summary>
        /// The compute mobility info.
        /// </summary>
        /// <param name="target">
        /// The inferred target.
        /// </param>
        /// <returns>
        /// The <see cref="double"/>.
        /// </returns>
        private MobilityInfo ComputeMobilityInfo(IImsTarget target)
        {
            // Convert the track into a Continuous XY data points.
            this.mobilityInfo.Mobility = this.driftTubeLengthInMeters * this.driftTubeLengthInMeters * 1000 / (this.FitLine.Slope);
            this.mobilityInfo.RSquared = this.FitLine.RSquared;
            this.mobilityInfo.T0 = this.FitLine.Intercept;

            Composition bufferGas = new Composition(0, 0, 2, 0, 0);
            double reducedMass = MoleculeUtil.ComputeReducedMass(target.MassWithAdduct, bufferGas);
            double meanTemperatureInKelvin = this.GetGlobalMeanTemperature();
            this.mobilityInfo.CollisionCrossSectionArea = MoleculeUtil.ComputeCrossSectionalArea(
                meanTemperatureInKelvin,
                this.mobilityInfo.Mobility,
                target.ChargeState,
                reducedMass);

            return this.mobilityInfo;
        }
 /// <summary>
 /// The equals.
 /// </summary>
 /// <param name="other">
 /// The other.
 /// </param>
 /// <returns>
 /// The <see cref="bool"/>.
 /// </returns>
 public override bool Equals(IImsTarget other)
 {
     if (ReferenceEquals(null, other)) return false;
     if (ReferenceEquals(this, other)) return true;
     if (other.TargetType != TargetType.MoleculeWithKnownDriftTime) return false;
     return this.Equals(other as DriftTimeTarget);
 }
        /// <summary>
        /// The export identified isomer info.
        /// </summary>
        /// <param name="viperCompatibleMass">
        /// The viper compatible mass.
        /// </param>
        /// <param name="minFitPoints">
        /// The min fit points.
        /// </param>
        /// <param name="minR2">
        /// The min r 2.
        /// </param>
        /// <param name="target"></param>
        /// <returns>
        /// The <see cref="IdentifiedIsomerInfo"/>.
        /// </returns>
        public IdentifiedIsomerInfo ExportIdentifiedIsomerInfo(double viperCompatibleMass, int minFitPoints, double minR2, IImsTarget target, double bestMzInPpm)
        {
            double averageVoltageGroupStabilityScore = VoltageGroupScoring.ComputeAverageVoltageGroupStabilityScore(this.definedVoltageGroups);

            IList<ArrivalTimeSnapShot> snapshots = new List<ArrivalTimeSnapShot>();
            foreach (var observation in this.observedPeaks)
            {
                snapshots.Add(this.ExtractArrivalTimeSnapShot(observation));
            }

            IdentifiedIsomerInfo info = new IdentifiedIsomerInfo(
                this.observedPeaks.Count,
                this.AverageMzInDalton,
                this.mobilityInfo.RSquared,
                this.mobilityInfo.Mobility,
                this.mobilityInfo.CollisionCrossSectionArea,
                averageVoltageGroupStabilityScore,
                snapshots,
                viperCompatibleMass,
                this.ConcludeStatus(minFitPoints, minR2),
                this.TrackStatistics,
                target,
                this.mobilityInfo.T0,
                bestMzInPpm
                );
            return info;
        }
        /// <summary>
        /// The report target info.
        /// </summary>
        /// <param name="target">
        /// The target.
        /// </param>
        /// <param name="verbose">
        /// The verbose.
        /// </param>
        private static void ReportTargetInfo(IImsTarget target, bool verbose)
        {
            Trace.WriteLine(string.Empty);

            if (verbose)
            {
                Trace.WriteLine("Target chemical: " + target.CorrespondingChemical);
                Trace.WriteLine("Target description: " + target.TargetDescriptor);
                if (target.HasCompositionInfo)
                {
                    Trace.WriteLine("Target Empirical Formula: " + target.EmpiricalFormula);
                }

                Trace.WriteLine("Targeting centerMz: " + target.MassWithAdduct);
                Trace.WriteLine(string.Empty);
            }
            else
            {
                Trace.WriteLine("Target: " + target.TargetDescriptor);
            }
        }
        /// <summary>
        /// The association hypothesis plot.
        /// </summary>
        /// <param name="hypothesis">
        /// The hypothesis.
        /// </param>
        /// <param name="datasetName">
        /// The dataset name.
        /// </param>
        /// <param name="targetDescriptor">
        /// The target descriptor.
        /// </param>
        /// <returns>
        /// The <see cref="PlotModel"/>.
        /// </returns>
        private PlotModel AssociationHypothesisPlot(AssociationHypothesis hypothesis, string datasetName, IImsTarget target, bool plotXAxisFromZero = false)
        {
            PlotModel model = new PlotModel();

            model.LegendBorderThickness = 0;
            model.LegendOrientation = LegendOrientation.Vertical;
            model.LegendPlacement = LegendPlacement.Inside;
            model.LegendPosition = LegendPosition.LeftTop;

            model.TitlePadding = 0;
            model.Title = "Optimal Association Hypothesis Plot";
            model.Subtitle = string.Format("Target: {0}, dataset: {1}", target.TargetDescriptor, datasetName) ;

            model.Axes.Add(
                new LinearAxis
                    {
                        Title = "IMS arrival time (milliseconds)",
                        MajorGridlineStyle = LineStyle.Solid,
                        Position = AxisPosition.Left,
                    });

            model.Axes.Add(
                new LinearAxis
                    {
                        Title = "P/(T*V) with P and T nondimensionalized (1/V)",
                        Position = AxisPosition.Bottom,
                        MajorGridlineStyle = LineStyle.Solid,
                    });

            // Add all the points
            IEnumerable<ObservedPeak> onTrackPeaks = hypothesis.OnTrackObservations;
            IEnumerable<ObservedPeak> offTrackPeaks = hypothesis.AllObservations.Where(x => !hypothesis.IsOnTrack(x));

            Func<ObservedPeak, ScatterPoint> fitPointMap = obj =>
            {
                ObservedPeak observation = obj;
                ContinuousXYPoint xyPoint = observation.ToContinuousXyPoint(false, 0);
                double size = MapToPointSize(observation);
                ScatterPoint sp = new ScatterPoint(xyPoint.X, xyPoint.Y, size);
                return sp;
            };

            var ontrackSeries= new ScatterSeries
            {
                Title = "[Peaks On Tracks]",
                MarkerFill = OxyColors.BlueViolet,
                MarkerType = MarkerType.Circle
            };

            var offtrackSeries= new ScatterSeries
            {
                Title = "[Peaks Off Tracks]",
                MarkerFill = OxyColors.Red,
                MarkerType = MarkerType.Circle
            };

            ontrackSeries.Points.AddRange(onTrackPeaks.Select(x => fitPointMap(x)));

            offtrackSeries.Points.AddRange(offTrackPeaks.Select(x => fitPointMap(x)));

            model.Series.Add(ontrackSeries);

            model.Series.Add(offtrackSeries);

            var allTracks = hypothesis.Tracks;

            // Add the tracks as linear axes
            int count = 1;
            foreach (var track in allTracks)
            {
                FitLine fitline = track.FitLine;
                LineAnnotation annotation = new LineAnnotation();
                annotation.Slope = fitline.Slope;
                annotation.Intercept = fitline.Intercept;
                annotation.TextPadding = 3;
                annotation.TextMargin = 2;
                annotation.Text = string.Format("Conformer {0} - mz: {1:F2}; ccs: {2:F2}, Isotopic Score: {3:F3}; Track Probability: {4:F2}; R2: {5:F5};",
                    count, track.AverageMzInDalton, track.GetMobilityInfoForTarget(target).CollisionCrossSectionArea, track.TrackStatistics.IsotopicScore, track.TrackProbability, track.FitLine.RSquared);
                count++;
                model.Annotations.Add(annotation);
                //Func<object, DataPoint> lineMap = obj =>
                //{
                //    ObservedPeak observation = (ObservedPeak)obj;
                //    ContinuousXYPoint xyPoint = observation.ToContinuousXyPoint();
                //    double x = xyPoint.X;
                //    double y = fitline.ModelPredictX2Y(x);
                //    DataPoint sp = new DataPoint(x, y);
                //    return sp;
                //};

                //model.Series.Add(new LineSeries()
                //{
                //    Mapping = lineMap,
                //    ItemsSource = track.ObservedPeaks,
                //    Color = OxyColors.Purple
                //});
            }

            return model;
        }
        /// <summary>
        /// The reset trace listener to target.
        /// </summary>
        /// <param name="target">
        /// The target.
        /// </param>
        /// <returns>
        /// The <see cref="FileStream"/>.
        /// </returns>
        private FileStream ResetTraceListenerToTarget(IImsTarget target, string datasetName)
        {
            Trace.Listeners.Clear();
            string targetResultFileName = Path.Combine(this.OutputPath, "target_" + target.TargetDescriptor + "_in_" + datasetName + ".txt");
            FileStream resultFile = new FileStream(targetResultFileName, FileMode.Create, FileAccess.Write, FileShare.None);
            ConsoleTraceListener consoleTraceListener = new ConsoleTraceListener(false);
            consoleTraceListener.TraceOutputOptions = TraceOptions.DateTime;
            TextWriterTraceListener targetResultTraceListener = new TextWriterTraceListener(resultFile)
            {
                TraceOutputOptions = TraceOptions.ThreadId | TraceOptions.DateTime
            };

            Trace.Listeners.Add(consoleTraceListener);
            Trace.Listeners.Add(targetResultTraceListener);
            Trace.AutoFlush = true;
            return resultFile;
        }
        /// <summary>
        /// The find peaks based on xic.
        /// </summary>
        /// <param name="group">
        /// The group.
        /// </param>
        /// <param name="chromatogram">
        /// The chromatogram.
        /// </param>
        /// <param name="target">
        /// The target.
        /// </param>
        /// <returns>
        /// The <see cref="IList"/>.
        /// </returns>
        /// <exception cref="NotImplementedException">
        /// </exception>
        private List<StandardImsPeak> FindPeaksBasedOnXIC(VoltageGroup voltageGroup, ExtractedIonChromatogram chromatogram, IImsTarget target)
        {
            if (this.Parameters.PeakDetectorSelection == PeakDetectorEnum.WaterShed)
            {
                // Find peaks using multidimensional peak finder.
                List<IntensityPoint> intensityPoints = chromatogram.IntensityPoints;
                List<FeatureBlob> featureBlobs = PeakFinding.FindPeakUsingWatershed(intensityPoints, this.smoother, this.Parameters.FeatureFilterLevel);

                // Recapture the 2D peak using the 1D feature blob from multidimensional peak finder.
                return featureBlobs.Select(featureBlob => new StandardImsPeak(featureBlob, this.uimfReader, voltageGroup, target.MassWithAdduct, this.Parameters.MzWindowHalfWidthInPpm)).ToList();
            }
            else if (this.Parameters.PeakDetectorSelection == PeakDetectorEnum.MASICPeakFinder)
            {
                // Find peaks using MASIC peak finder
                List<IntensityPoint> intensityPoints = chromatogram.IntensityPoints;
                IList<clsPeak> masicPeaks = PeakFinding.FindPeakUsingMasic(intensityPoints, this.NumberOfScans);

                // Recapture the 2D peak using the 1D feature blob from multidimensional peak finder.
                return masicPeaks.Select(peak => new StandardImsPeak(peak)).ToList();
            }
            else
            {
                throw new NotImplementedException(string.Format("{0} not supported", this.Parameters.PeakDetectorSelection));
            }
        }
 /// <summary>
 /// Gets the mobility info for inferedTarget
 /// </summary>
 /// <param name="inferedTarget">
 /// The inferedTarget.
 /// </param>
 public MobilityInfo GetMobilityInfoForTarget(IImsTarget inferedTarget)
 {
     return this.ComputeMobilityInfo(inferedTarget);
 }
 public bool Equals(IImsTarget other)
 {
     if (ReferenceEquals(null, other)) return false;
     if (ReferenceEquals(this, other)) return true;
     if (other.TargetType != TargetType.Peptide) return false;
     return this.Equals(other as PeptideTarget);
 }
 /// <summary>
 /// The equals.
 /// </summary>
 /// <param name="other">
 /// The other.
 /// </param>
 /// <returns>
 /// The <see cref="bool"/>.
 /// </returns>
 public virtual bool Equals(IImsTarget other)
 {
     if (ReferenceEquals(null, other)) return false;
     if (ReferenceEquals(this, other)) return true;
     if (other.TargetType != TargetType.Molecule) return false;
     return this.Equals(other as MolecularTarget);
 }
 /// <summary>
 /// The initiate from workflow result.
 /// </summary>
 /// <param name="result">
 /// The result.
 /// </param>
 private void InitiateFromWorkflowResult(CrossSectionWorkflowResult result)
 {
     this.Target = result.Target;
     this.AnalysisStatus = result.AnalysisStatus;
     this.FusionNumber = 1;
     this.DetectedIsomers = result.IdentifiedIsomers;
 }
 /// <summary>
 /// Initializes a new instance of the <see cref="CrossSectionWorkflowResult"/> class. 
 /// Multiple isomer result constructor
 /// </summary>
 /// <param name="datasetName">
 /// The dataset name.
 /// </param>
 /// <param name="target">
 /// The target.
 /// </param>
 /// <param name="analysisStatus">
 /// The analysis status.
 /// </param>
 /// <param name="associationHypothesisInfo">
 /// The analysis scores holder.
 /// </param>
 /// <param name="isomerResults">
 /// The isomer results.
 /// </param>
 /// <param name="averageObservedPeakStatistics"></param>
 /// <param name="averageVoltageGroupStability"></param>
 /// <param name="datasetPath"></param>
 /// <param name="analysisDirectory"></param>
 /// <param name="dateTime"></param>
 public CrossSectionWorkflowResult(
     string datasetPath,
     IImsTarget target, 
     AnalysisStatus analysisStatus, 
     AssociationHypothesisInfo associationHypothesisInfo, 
     IList<IdentifiedIsomerInfo> isomerResults, 
     PeakScores averageObservedPeakStatistics, 
     double averageVoltageGroupStability, 
     string analysisDirectory, 
     string dateTime)
 {
     this.Target = target;
     this.AnalysisStatus = analysisStatus;
     this.AssociationHypothesisInfo = associationHypothesisInfo;
     this.isomerResults = isomerResults;
     this.AverageObservedPeakStatistics = averageObservedPeakStatistics;
     this.AverageVoltageGroupStability = averageVoltageGroupStability;
     this.AnalysisDirectory = analysisDirectory;
     this.DateTime = dateTime;
     this.DatasetPath = datasetPath;
     this.DatasetName = Path.GetFileNameWithoutExtension(datasetPath);
     this.DateTime = dateTime;
 }
 /// <summary>
 /// The more likely than targeted.
 /// </summary>
 /// <param name="a">
 /// The a.
 /// </param>
 /// <param name="b">
 /// The b.
 /// </param>
 /// <param name="likelihoodFunc">
 /// The likelihood func.
 /// </param>
 /// <param name="target">
 /// The target.
 /// </param>
 /// <returns>
 /// The <see cref="bool"/>.
 /// </returns>
 /// <exception cref="NotImplementedException">
 /// </exception>
 public static bool MoreLikelyThanTargeted(ObservedPeak a, ObservedPeak b, LikelihoodFunc likelihoodFunc, IImsTarget target)
 {
     throw new NotImplementedException();
 }
        /// <summary>
        /// The create negative result.
        /// </summary>
        /// <param name="rejectedPeaks">
        /// The rejected peaks.
        /// </param>
        /// <param name="rejectedVoltageGroups">
        /// The rejected voltage groups.
        /// </param>
        /// <param name="datasetName">
        /// The dataset name.
        /// </param>
        /// <param name="target">
        /// The target.
        /// </param>
        /// <returns>
        /// The <see cref="CrossSectionWorkflowResult"/>.
        /// </returns>
        internal static CrossSectionWorkflowResult CreateNegativeResult(IEnumerable<ObservedPeak> rejectedPeaks, IEnumerable<VoltageGroup> rejectedVoltageGroups, IImsTarget target, string datasetPath, string analysisPath, string sampleCollectionTime)
        {
            // No valid feature peaks were identified. No hypothesis.
            double voltageGroupScore = VoltageGroupScoring.ComputeAverageVoltageGroupStabilityScore(rejectedVoltageGroups);

            // quantize the VG score from VGs in the removal list.
            IEnumerable<PeakScores> featureStats = rejectedPeaks.Select(x => x.Statistics);
            PeakScores averagePeakScores = FeatureScoreUtilities.AverageFeatureStatistics(featureStats);
            CrossSectionWorkflowResult informedResult = new CrossSectionWorkflowResult(
                datasetPath,
                target,
                AnalysisStatus.Negative,
                null,
                averagePeakScores,
                voltageGroupScore,
                analysisPath,
                sampleCollectionTime);

            return informedResult;
        }
        private async Task<string> InsertChemical(SQLiteCommand cmd, IImsTarget target)
        {
            // Query if chemical is already added.
            string chemicalName = target.CorrespondingChemical;

            cmd.CommandText = string.Format("SELECT count(*) FROM chemicals WHERE name='{0}'", chemicalName); 
            int count = Convert.ToInt32(cmd.ExecuteScalar());
            if(count == 0)
            {
                // Insert chemical info to chemicals table
                cmd.CommandText = "INSERT INTO chemicals (name, empirical_formula, chemical_class) VALUES      (@name, @empirical_formula, @chemical_class)";

                
                cmd.Parameters.AddWithValue("@name", chemicalName);
                cmd.Parameters.AddWithValue("@empirical_formula", target.EmpiricalFormula);
                cmd.Parameters.AddWithValue("@chemical_class", "");
                await Task.Run(() => cmd.ExecuteNonQuery());

                return chemicalName;
            }

            return "";
        }
 /// Initializes a new instance of the <see cref="CrossSectionWorkflowResult"/> class. 
 /// Constructor for no isomer result. 
 public CrossSectionWorkflowResult(
     string datasetPath,
     IImsTarget target,
     AnalysisStatus analysisStatus,
     AssociationHypothesisInfo associationHypothesisInfo, 
     PeakScores averageObservedPeakStatistics, 
     double averageVoltageGroupStability, 
     string analysisDirectory, string dateTime)
     : this(datasetPath,
     target,
     analysisStatus,
     associationHypothesisInfo,
     new List<IdentifiedIsomerInfo>(), 
     averageObservedPeakStatistics, 
     averageVoltageGroupStability, 
     analysisDirectory, 
     dateTime)
 {
 }
 private async Task<long> InsertTarget(SQLiteCommand cmd, IImsTarget target)
 {
     cmd.CommandText = string.Format("SELECT count(*) FROM targets WHERE target_description ='{0}' AND target_chemical = '{1}'", target.TargetDescriptor, target.CorrespondingChemical);
     int count = Convert.ToInt32(cmd.ExecuteScalar());
     if(count == 0)
     {
         // Insert target info to chemicals table
         cmd.CommandText = "INSERT INTO targets (target_chemical, target_type, adduct, target_description, monoisotopic_mass, composition_with_adduct, mass_with_adduct,     charge_state) VALUES      (@target_chemical, @target_type, @adduct, @target_description, @monoisotopic_mass, @composition_with_adduct, @mass_with_adduct,   @charge_state)";
         cmd.Parameters.AddWithValue("@target_chemical", target.CorrespondingChemical);
         cmd.Parameters.AddWithValue("@target_type", target.TargetType);
         cmd.Parameters.AddWithValue("@adduct", target.Adduct);
         cmd.Parameters.AddWithValue("@target_description", target.TargetDescriptor);
         cmd.Parameters.AddWithValue("@monoisotopic_mass", target.MonoisotopicMass);
         cmd.Parameters.AddWithValue("@composition_with_adduct", target.CompositionWithAdduct);
         cmd.Parameters.AddWithValue("@mass_with_adduct", target.MassWithAdduct);
         cmd.Parameters.AddWithValue("@charge_state", target.ChargeState);
         await Task.Run(() => cmd.ExecuteNonQuery());
         return await this.LastID(cmd);
     }
     else
     {
         cmd.CommandText = string.Format("SELECT rowid FROM targets WHERE target_description ='{0}'", target.TargetDescriptor);
         int id =  Convert.ToInt32(cmd.ExecuteScalar());
         return id;
     }
 }
        /// <summary>
        /// The is track possible.
        /// </summary>
        /// <param name="track">
        /// The track.
        /// </param>
        /// <param name="target"></param>
        /// <param name="crossSectionSearchParameters"></param>
        /// <returns>
        /// The <see cref="bool"/>.
        /// </returns>
        public bool IsTrackPossible(IsomerTrack track, IImsTarget target, CrossSectionSearchParameters crossSectionSearchParameters)
        {
            int minFitPoints = track.TotalNumberOfVoltageGroups - crossSectionSearchParameters.MaxOutliers;
            if (this.FilterLowFitPointNumber(track.RealPeakCount, minFitPoints))
            {
                return false;
            }

            MobilityInfo trackMobilityInfo = track.GetMobilityInfoForTarget(target);
            if (!this.IsConsistentWithIonDynamics(trackMobilityInfo))
            {
                return false;
            }

            if (this.IsLowR2(trackMobilityInfo.RSquared, crossSectionSearchParameters.MinR2))
            {
                return false;
            }

            return true;
        }
 /// <summary>
 /// Initializes a new instance of the <see cref="IdentifiedIsomerInfo"/> class.
 /// </summary>
 /// <param name="numberOfFeaturePointsUsed">
 /// The number of feature points used.
 /// </param>
 /// <param name="mzInDalton"></param>
 /// <param name="rSquared">
 /// The r squred.
 /// </param>
 /// <param name="mobility">
 /// The mobility.
 /// </param>
 /// <param name="crossSectionalArea">
 /// The cross sectional area.
 /// </param>
 /// <param name="averageVoltageGroupStabilityScore">
 /// The average voltage group stability score.
 /// </param>
 /// <param name="arrivalTimeSnapShots">
 /// The arrival time snap shots.
 /// </param>
 /// <param name="viperCompatibleMass">
 /// The viper Compatible Mass.
 /// </param>
 /// <param name="analysisStatus"></param>
 /// <param name="peakScores"></param>
 /// <param name="target"></param>
 public IdentifiedIsomerInfo(
     int numberOfFeaturePointsUsed,
     double mzInDalton,
     double rSquared, 
     double mobility, 
     double crossSectionalArea, 
     double averageVoltageGroupStabilityScore, 
     IEnumerable<ArrivalTimeSnapShot> arrivalTimeSnapShots, 
     double viperCompatibleMass, 
     AnalysisStatus analysisStatus, 
     PeakScores peakScores,
     IImsTarget target,
     double t0,
     double bestMzInPpm)
 {
     this.NumberOfFeaturePointsUsed = numberOfFeaturePointsUsed;
     this.RSquared = rSquared;
     this.Mobility = mobility;
     this.CrossSectionalArea = crossSectionalArea;
     this.AverageVoltageGroupStabilityScore = averageVoltageGroupStabilityScore;
     this.ArrivalTimeSnapShots = arrivalTimeSnapShots;
     this.ViperCompatibleMass = viperCompatibleMass;
     this.AnalysisStatus = analysisStatus;
     this.PeakScores = peakScores;
     this.T0 = t0;
     this.MzInDalton = mzInDalton;
     this.MzInPpm = Metrics.DaltonToPpm(mzInDalton - target.MassWithAdduct, target.MassWithAdduct);
     this.RelativeMzInPpm = Math.Abs(MzInPpm - bestMzInPpm);
 }