public void TestPWiz(
            string fileOrDirectoryName,
            bool isDirectory,
            int expectedSpectraInFile,
            int expectedSpectraLoaded,
            int expectedTotalDataPoints,
            double expectedMedianTIC,
            double expectedMedianBPI)
        {
            try
            {
                if (!InstrumentDataUtilities.FindInstrumentData(fileOrDirectoryName, isDirectory, out var instrumentDataFileOrDirectory))
                {
                    Assert.Fail("File or directory not found");
                    return;
                }

                using (var reader = new MSDataFileReader(instrumentDataFileOrDirectory.FullName))
                {
                    Console.WriteLine("Chromatogram count: " + reader.ChromatogramCount);
                    Console.WriteLine();

                    var ticIntensities = new Dictionary <int, float>();

                    for (var chromatogramIndex = 0; chromatogramIndex < reader.ChromatogramCount; chromatogramIndex++)
                    {
                        // Note that even for a small .Wiff file (1.5 MB), obtaining the Chromatogram list will take some time (20 to 60 seconds)
                        // The chromatogram at index 0 should be the TIC
                        // The chromatogram at index >=1 will be each SRM

                        reader.GetChromatogram(chromatogramIndex, out var chromatogramID, out var timeArray, out var intensityArray);

                        // Determine the chromatogram type

                        if (chromatogramID == null)
                        {
                            chromatogramID = string.Empty;
                        }

                        var cvParams = reader.GetChromatogramCVParams(chromatogramIndex);

                        if (MSDataFileReader.TryGetCVParamDouble(cvParams, pwiz.CLI.cv.CVID.MS_TIC_chromatogram, out _))
                        {
                            // This chromatogram is the TIC
                            Console.WriteLine("TIC has id {0} and {1} data points", chromatogramID, timeArray.Length);

                            for (var i = 0; i < intensityArray.Length; i++)
                            {
                                ticIntensities.Add(i, intensityArray[i]);
                            }
                        }

                        if (MSDataFileReader.TryGetCVParamDouble(cvParams, pwiz.CLI.cv.CVID.MS_selected_reaction_monitoring_chromatogram, out _))
                        {
                            // This chromatogram is an SRM scan
                            Console.WriteLine("SRM scan has id {0} and {1} data points", chromatogramID, timeArray.Length);
                        }
                    }

                    Console.WriteLine("Spectrum count: " + reader.SpectrumCount);

                    var    spectraLoaded    = 0;
                    long   totalPointsRead  = 0;
                    double ticSumAllSpectra = 0;
                    double bpiSumAllSpectra = 0;

                    var spectrumIndex = 0;
                    while (spectrumIndex < reader.SpectrumCount)
                    {
                        var spectrum = reader.GetSpectrum(spectrumIndex, getBinaryData: true);
                        spectraLoaded += 1;

                        Console.WriteLine();
                        Console.WriteLine("ScanIndex {0}, NativeId {1}, Elution Time {2:F2} minutes, MS Level {3}",
                                          spectrumIndex, spectrum.NativeId, spectrum.RetentionTime, spectrum.Level);

                        // Use the following to get the MZs and Intensities
                        var mzList      = spectrum.Mzs.ToList();
                        var intensities = spectrum.Intensities.ToList();

                        if (mzList.Count > 0)
                        {
                            Console.WriteLine("  Data count: " + mzList.Count);

                            totalPointsRead += mzList.Count;

                            double tic = 0;
                            double bpi = 0;
                            for (var index = 0; index <= mzList.Count - 1; index++)
                            {
                                tic += intensities[index];
                                if (intensities[index] > bpi)
                                {
                                    bpi = intensities[index];
                                }
                            }

                            ticSumAllSpectra += tic;
                            bpiSumAllSpectra += bpi;

                            if (!ticIntensities.TryGetValue(spectrumIndex, out var ticFromChromatogram))
                            {
                                ticFromChromatogram = -1;
                            }

                            var spectrumInfo = reader.GetSpectrumObject(spectrumIndex);

                            if (MSDataFileReader.TryGetCVParamDouble(spectrumInfo.cvParams, pwiz.CLI.cv.CVID.MS_total_ion_current,
                                                                     out var ticFromSpectrumObject))
                            {
                                if (ticFromChromatogram < 0)
                                {
                                    // ticIntensities did not have an entry for spectrumIndex
                                    // This could be the case on a Waters Synapt instrument, where ticIntensities has one TIC per frame,
                                    // while pWiz.GetSpectrum() returns individual mass spectra, of which there could be hundreds of spectra per frame
                                    Console.WriteLine("  TIC from actual data is {0:E2} vs. {1:E2} from the spectrum object",
                                                      tic, ticFromSpectrumObject);
                                }
                                else
                                {
                                    // Note: the TIC value from the CvParams has been seen to be drastically off from the manually computed value
                                    Console.WriteLine(
                                        "  TIC from actual data is {0:E2} vs. {1:E2} from the chromatogram and {2:E2} from the spectrum object",
                                        tic, ticFromChromatogram, ticFromSpectrumObject);
                                }
                            }

                            if (MSDataFileReader.TryGetCVParamDouble(spectrumInfo.cvParams, pwiz.CLI.cv.CVID.MS_base_peak_intensity,
                                                                     out var bpiFromSpectrumObject))
                            {
                                if (MSDataFileReader.TryGetCVParamDouble(spectrumInfo.cvParams, pwiz.CLI.cv.CVID.MS_base_peak_m_z,
                                                                         out var bpiMzFromSpectrumObject))
                                {
                                    // Note: the BPI intensity from the CvParams has been seen to be drastically off from the manually computed value
                                    Console.WriteLine("  BPI from spectrum object is {0:E2} at {1:F3} m/z",
                                                      bpiFromSpectrumObject, bpiMzFromSpectrumObject);
                                }
                            }
                        }

                        if (spectrumIndex < 25)
                        {
                            spectrumIndex += 1;
                        }
                        else if (spectrumIndex < 1250)
                        {
                            spectrumIndex += 50;
                        }
                        else
                        {
                            spectrumIndex += 500;
                        }
                    }

                    if (spectraLoaded > 0)
                    {
                        var medianTIC = ticSumAllSpectra / spectraLoaded;
                        var medianBPI = bpiSumAllSpectra / spectraLoaded;

                        Console.WriteLine();
                        Console.WriteLine("Read {0:N0} data points from {1} spectra in {2}",
                                          totalPointsRead, spectraLoaded, Path.GetFileName(fileOrDirectoryName));

                        Console.WriteLine("Median TIC: {0:E4}", medianTIC);
                        Console.WriteLine("Median BPI: {0:E4}", medianBPI);

                        Assert.AreEqual(expectedSpectraInFile, reader.SpectrumCount, "Total spectrum count mismatch");

                        Assert.AreEqual(expectedSpectraLoaded, spectraLoaded, "Spectra loaded mismatch");

                        Assert.AreEqual(expectedTotalDataPoints, totalPointsRead, "Spectra loaded mismatch");
                        var ticComparisonTolerance = expectedMedianTIC * 0.01;
                        var bpiComparisonTolerance = expectedMedianBPI * 0.01;

                        Assert.AreEqual(expectedMedianTIC, medianTIC, ticComparisonTolerance, "Median TIC mismatch");
                        Assert.AreEqual(expectedMedianBPI, medianBPI, bpiComparisonTolerance, "Median BPI mismatch");
                    }
                }
            }
            catch (Exception ex)
            {
                ConsoleMsgUtils.ShowError("Error using ProteoWizard reader", ex);
            }
        }
        public void StoreChromatogramInfo(DatasetFileInfo datasetFileInfo, out bool ticStored, out bool srmDataCached, out double runtimeMinutes)
        {
            var ticScanTimes   = new List <float>();
            var ticScanNumbers = new List <int>();

            // This dictionary tracks the m/z and intensity values for parent (Q1) ions of each scan
            // Key is ScanNumber; Value is a dictionary holding m/z and intensity values for that scan
            var dct2DDataParent = new Dictionary <int, Dictionary <double, double> >();

            // This dictionary tracks the m/z and intensity values for product (Q3) ions of each scan
            var dct2DDataProduct = new Dictionary <int, Dictionary <double, double> >();

            // This dictionary tracks the scan times for each scan number tracked by dct2DDataParent and/or dct2DDataProduct
            var dct2DDataScanTimes = new Dictionary <int, float>();

            // Note that even for a small .Wiff file (1.5 MB), obtaining the first chromatogram will take some time (20 to 60 seconds)
            // The chromatogram at index 0 should be the TIC
            // The chromatogram at index >=1 will be each SRM

            runtimeMinutes = 0;
            ticStored      = false;
            srmDataCached  = false;

            for (var chromatogramIndex = 0; chromatogramIndex <= mPWiz.ChromatogramCount - 1; chromatogramIndex++)
            {
                try
                {
                    if (chromatogramIndex == 0)
                    {
                        OnStatusEvent("Obtaining chromatograms (this could take as long as 60 seconds)");
                    }

                    mPWiz.GetChromatogram(chromatogramIndex, out var chromatogramID, out var scanTimes, out var intensities);

                    if (chromatogramID == null)
                    {
                        chromatogramID = string.Empty;
                    }

                    var cvParams = mPWiz.GetChromatogramCVParams(chromatogramIndex);

                    if (MSDataFileReader.TryGetCVParam(cvParams, pwiz.CLI.cv.CVID.MS_TIC_chromatogram, out _))
                    {
                        // This chromatogram is the TIC

                        var storeInTICAndBPIPlot = (mSaveTICAndBPI && mPWiz.SpectrumCount == 0);

                        ProcessTIC(scanTimes, intensities, ticScanTimes, ticScanNumbers, ref runtimeMinutes, storeInTICAndBPIPlot);

                        ticStored = storeInTICAndBPIPlot;

                        // This is FrameCount for Bruker timsTOF datasets
                        datasetFileInfo.ScanCount = scanTimes.Length;
                    }

                    if (MSDataFileReader.TryGetCVParam(cvParams, pwiz.CLI.cv.CVID.MS_selected_reaction_monitoring_chromatogram, out _))
                    {
                        // This chromatogram is an SRM scan

                        ProcessSRM(chromatogramID, scanTimes, intensities, ticScanTimes, ticScanNumbers, ref runtimeMinutes, dct2DDataParent,
                                   dct2DDataProduct, dct2DDataScanTimes);

                        srmDataCached = true;
                    }
                }
                catch (AccessViolationException)
                {
                    // Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
                    if (!mWarnedAccessViolationException)
                    {
                        OnWarningEvent("Error loading chromatogram data with ProteoWizard: Attempted to read or write protected memory. " +
                                       "The instrument data file is likely corrupt.");
                        mWarnedAccessViolationException = true;
                    }
                    mDatasetStatsSummarizer.CreateEmptyScanStatsFiles = false;
                }
                catch (Exception ex)
                {
                    OnErrorEvent("Error processing chromatogram " + chromatogramIndex + " with ProteoWizard: " + ex.Message, ex);
                }
            }

            if (!mSaveLCMS2DPlots)
            {
                return;
            }

            if (dct2DDataParent.Count <= 0 && dct2DDataProduct.Count <= 0)
            {
                return;
            }

            // Now that all of the chromatograms have been processed, transfer data from dct2DDataParent and dct2DDataProduct into mLCMS2DPlot
            mLCMS2DPlot.Options.MS1PlotTitle = "Q1 m/z";
            mLCMS2DPlot.Options.MS2PlotTitle = "Q3 m/z";

            Store2DPlotData(dct2DDataScanTimes, dct2DDataParent, dct2DDataProduct);
        }