public string GenerateFilterReportString(ParameterOptimizationResult selectedResult)
        {
            if (selectedResult == null) return string.Empty;

            StringBuilder sb = new StringBuilder();
            sb.Append("Labeled fit <= " + selectedResult.FitScoreLabelled.ToString("0.####"));
            sb.Append(Environment.NewLine);
            sb.Append("IScore <= " + selectedResult.Iscore.ToString("0.####"));
            sb.Append(Environment.NewLine);
            sb.Append("SumOfRatios >= " + selectedResult.SumOfRatios.ToString("0.#"));
            sb.Append(Environment.NewLine);
            sb.Append("ContigScore >= " + selectedResult.ContigScore.ToString("0"));
            sb.Append(Environment.NewLine);
            sb.Append("PercentIncorp >= " + selectedResult.PercentIncorp.ToString("0.####"));
            sb.Append(Environment.NewLine);
            sb.Append("PercentPeptide >= " + selectedResult.PercentPeptidePopulation.ToString("0.##"));
            sb.Append(Environment.NewLine);
            sb.Append("Num unlabeled results at this filter= " + selectedResult.NumUnlabelledPassingFilter);
            sb.Append(Environment.NewLine);
            sb.Append("Num labeled results at this filter= " + selectedResult.NumLabeledPassingFilter);
            sb.Append(Environment.NewLine);
            sb.Append("False positive rate = " + selectedResult.FalsePositiveRate.ToString("0.###"));

            return sb.ToString();
        }
        public List<ParameterOptimizationResult> DoCalculationsOnAllFilterCombinations(string outputFileName = null)
        {
            bool isHeaderWritten = false;

            if (!string.IsNullOrEmpty(outputFileName) && File.Exists(outputFileName)) File.Delete(outputFileName);

            var parameterOptimizationResults = new List<ParameterOptimizationResult>();
            int numCombinations = GetNumCombinations();

            IqLogger.Log.Info("Filter optimizer - num combinations to analyze = "+ numCombinations);
            StringBuilder sb = new StringBuilder();

            int comboCounter = 0;

            for (double fitScoreLabelled = LabelFitLower; fitScoreLabelled < LabelFitUpper; fitScoreLabelled = fitScoreLabelled + LabelFitStep)
            {
                sb.Clear();

                var levelOneC13Filter = (from n in LabeledResults
                                         where n.FitScoreLabeledProfile <= fitScoreLabelled
                                         select n).ToList();

                var levelOneC12Filter = (from n in UnlabeledResults
                                         where n.FitScoreLabeledProfile <= fitScoreLabelled
                                         select n).ToList();

                IqLogger.Log.Info("Current filter combo: " + comboCounter +" out of " + numCombinations);

                for (double area = SumOfRatiosLower; area < SumOfRatiosUpper; area = area + SumOfRatiosStep)
                {
                    var levelTwoC13Filter = (from n in levelOneC13Filter
                                             where n.AreaUnderRatioCurveRevised >= area
                                             select n).ToList();

                    var levelTwoC12Filter = (from n in levelOneC12Filter
                                             where n.AreaUnderRatioCurveRevised >= area
                                             select n).ToList();

                    for (double iscore = IscoreLower; iscore < IscoreUpper; iscore = iscore + IscoreStep)
                    {

                        var levelThreeC13Filter = (from n in levelTwoC13Filter
                                                 where n.IScore <= iscore
                                                 select n).ToList();

                        var levelThreeC12Filter = (from n in levelTwoC12Filter
                                                 where n.IScore <= iscore
                                                 select n).ToList();

                        for (int contigScore = ContigScoreLower; contigScore <= ContigScoreUpper; contigScore = contigScore + ContigScoreStep)
                        {
                            for (double percentIncorp = PercentIncorpLower; percentIncorp < PercentIncorpUpper; percentIncorp = percentIncorp + PercentIncorpStep)
                            {
                                for (double peptidePop = PercentPeptidePopulationLower; peptidePop < PercentPeptidePopulationUpper; peptidePop = peptidePop + PercentPeptidePopulationStep)
                                {
                                    var c13filteredResults = (from n in levelThreeC13Filter
                                                              where n.ContiguousnessScore >= contigScore
                                                             && n.PercentCarbonsLabelled >= percentIncorp
                                                             && n.PercentPeptideLabelled >= peptidePop
                                                              select n).ToList();

                                    var c12filteredResults = (from n in levelThreeC12Filter
                                                              where n.ContiguousnessScore >= contigScore
                                                             && n.PercentCarbonsLabelled >= percentIncorp
                                                             && n.PercentPeptideLabelled >= peptidePop
                                                              select n).ToList();

                                    ParameterOptimizationResult optimizationResult = new ParameterOptimizationResult();
                                    optimizationResult.FitScoreLabelled = fitScoreLabelled;
                                    optimizationResult.SumOfRatios = area;
                                    optimizationResult.Iscore = iscore;
                                    optimizationResult.ContigScore = contigScore;
                                    optimizationResult.PercentIncorp = percentIncorp;
                                    optimizationResult.PercentPeptidePopulation = peptidePop;

                                    optimizationResult.NumLabeledPassingFilter = c13filteredResults.Count;
                                    optimizationResult.NumUnlabelledPassingFilter = c12filteredResults.Count;

                                    sb.Append(optimizationResult.ToStringWithDetails());
                                    sb.Append(Environment.NewLine);

                                    parameterOptimizationResults.Add(optimizationResult);

                                    comboCounter++;

                                }
                            }

                        }
                    }
                }

                if (!string.IsNullOrEmpty(outputFileName))
                {
                    using (var sw = new StreamWriter(new FileStream(outputFileName, FileMode.Append, FileAccess.Write, FileShare.Read)))
                    {
                        sw.AutoFlush = true;

                        if (!isHeaderWritten)
                        {
                            sw.WriteLine("LabeledFit\tSumOfRatios\tIscore\tContigScore\tPercentIncorp\tPercentPeptideLabeled\tUnlabeledCount\tLabeledCount\tFalsePositiveRate");
                        }
                        sw.Write(sb.ToString());

                    }
                }

            }

            return parameterOptimizationResults;
        }