/// <summary> /// Fills this instance data members with the information read from <paramref name="inputMsExperiment"/>. /// </summary> /// <param name="inputMsExperiment">instance, the data source</param> /// <param name="wiffsample"> Wiff Sample</param> protected override void Initialize(MSExperiment inputMsExperiment, WiffSample wiffsample) { Cursor.Current = Cursors.WaitCursor; try { // set the status information AppContext.StatusInfo = "Getting wiff-data"; // (1) Get Maldi Parameters string strMaldiParams = wiffsample.MaldiParametersString; // (2) get the number of mass MRM transitions this.massRanges = inputMsExperiment.Details.MassRangeInfo.Length; // (3) select 1. MRM trace XYData tic = inputMsExperiment.GetTotalIonChromatogram(); // (4) Dimension the data arrray, the number "data points" this.numDataPoint = tic.NumDataPoints; // (5) Set up arrays for info this.rawData = new float[this.massRanges, this.numDataPoint]; this.timeData = new float[this.numDataPoint]; this.dwellTime = new double[this.massRanges]; this.massRangeName = new string[this.massRanges]; this.massRangeMax = new double[this.massRanges]; this.massRangeMin = new double[this.massRanges]; this.meanValues = new float[this.massRanges]; this.medianValues = new float[this.massRanges]; // helper for mean and median var valuesForMedian = new List <float>(); // (6) loop through the mass ranges for (int actMassRange = 0; actMassRange < this.massRanges; actMassRange++) { // get mass range object this.massRangeName[actMassRange] = inputMsExperiment.Details.MassRangeInfo[actMassRange].Name; this.dwellTime[actMassRange] = inputMsExperiment.Details.MassRangeInfo[actMassRange].DwellTime; // loop through the spectrum this.massRangeMax[actMassRange] = double.MinValue; this.massRangeMin[actMassRange] = double.MaxValue; double meanSum = 0.0; valuesForMedian.Clear(); // Extract xic Full Scan var option = new ExtractedIonChromatogramSettings(actMassRange); ExtractedIonChromatogram xic = inputMsExperiment.GetExtractedIonChromatogram(option); // JP 23/11 I think there might be a better way to do this. for (int actDataPoint = 0; actDataPoint < this.numDataPoint; actDataPoint++) { // get the actual value double anaXValue = xic.GetActualXValues()[actDataPoint]; double anaYValue = xic.GetActualYValues()[actDataPoint]; if (anaYValue < this.massRangeMin[actMassRange]) { this.massRangeMin[actMassRange] = anaYValue; } if (anaYValue > this.massRangeMax[actMassRange]) { this.massRangeMax[actMassRange] = anaYValue; } // now get the actual data this.rawData[actMassRange, actDataPoint] = (float)anaYValue; this.timeData[actDataPoint] = (float)anaXValue * 60; // mean and median calculation...sum up the value to calculate the mean meanSum += anaYValue; // fill an extra array to calculate the median valuesForMedian.Add((float)anaYValue); } // calculate the mean this.meanValues[actMassRange] = (float)(meanSum / this.numDataPoint); // calculate the median valuesForMedian.Sort(); this.medianValues[actMassRange] = ((valuesForMedian.Count % 2) == 0) ? (valuesForMedian[(valuesForMedian.Count / 2) - 1] + valuesForMedian[valuesForMedian.Count / 2]) / 2.0f : valuesForMedian[valuesForMedian.Count / 2]; } // (7) time per point in sec this.timeinXDirection = (float)((tic.GetActualXValues()[this.numDataPoint - 1] - tic.GetActualXValues()[1]) * 60 / (this.numDataPoint - 2)); // (8) Calculate distInXDirection: fetch the x1, x2, y1, y2, width and height from the WiffSample instance this experiment belongs to. double x1 = wiffsample.P1.X; double y2 = 82 - wiffsample.P1.Y; double x2 = wiffsample.P2.X; double width = wiffsample.Width; // (9) fetch the position data from the WiffSample instance this experiment belongs to. uint[,] posData = wiffsample.PositionData; long posDataLength = wiffsample.PositionDataLength; // try and find the first and last valid indices in the posData, where valid means a nonzero time value... long firstNonZeroTimeInPos = -1; for (long t = 0; t < posDataLength - 1; t++) { if (posData[t, 0] > 0) { firstNonZeroTimeInPos = t + 1; break; // ok, we're done... } } long lastNonZeroTimeInPos = -1; for (long t = posDataLength - 1; t >= 0; t++) { if (posData[t, 0] > 0) { lastNonZeroTimeInPos = t - 1; break; // ok, we're done... } } // (10) Make sure we have found valid values, bail out if not if (firstNonZeroTimeInPos < 0 || lastNonZeroTimeInPos < 0) { // haven't found a valid posData triplet. All time values are zero or less...bail out return; } // (11) Calculate distInYDirection this.distInYDirection = 0; for (long t = firstNonZeroTimeInPos; t < lastNonZeroTimeInPos; t++) { if ((posData[t, 1] > ((x2 + x1) * 500)) & Equals(this.distInYDirection, 0.0)) { this.distInYDirection = posData[t, 2]; } if ((posData[t, 1] < ((x2 + x1) * 500)) & (this.distInYDirection > 0)) { this.distInYDirection = (float)Math.Round((decimal)(posData[t, 2] - this.distInYDirection) / 500, (int)(1 - Math.Log10((posData[t, 2] - this.distInYDirection) / 500))) / 2; break; } } // (12) Calculate speed in x direction this.speedinXDirection = (float)Math.Round((posData[firstNonZeroTimeInPos + 2, 1] - posData[firstNonZeroTimeInPos + 1, 1]) / (decimal)(posData[firstNonZeroTimeInPos + 2, 0] - posData[firstNonZeroTimeInPos + 1, 0]) * 2, 0) / 2; // (13) distInXDirection this.distInXDirection = (float)(int)(this.speedinXDirection * this.timeinXDirection * 1000) / 1000; // (14) number of points in x this.numPointsOnXAxis = (int)(width / this.speedinXDirection / this.timeinXDirection); // (15) number of points in y // y2 from the wiff file is not the actual y2 from the stage - replace with value from path file... // JP added "82 -" so what we convert wiff format to analyse co-ordinate system var y1 = 82 - (double)Math.Round((decimal)posData[lastNonZeroTimeInPos, 2] / 1000, 2); // ...and this has an effect of the numPointsOnYAxis this.numPointsOnYAxis = (int)Math.Round((decimal)((y2 - y1) / this.distInYDirection) + 1); // (16) Calc Lines Breaks double syncTime1 = (float)posData[firstNonZeroTimeInPos, 0] / 1000; double syncTime2 = (float)posData[lastNonZeroTimeInPos, 0] / 1000; if (this.numPointsOnYAxis % 2 == 0) { // even number of scanlines this.lineBreak = ((syncTime2 - syncTime1) - ((x2 - ((float)posData[firstNonZeroTimeInPos, 1] / 1000)) / this.speedinXDirection) - (((this.numPointsOnYAxis - 2) * (x2 - x1)) / this.speedinXDirection) - ((x2 - ((float)posData[lastNonZeroTimeInPos, 1] / 1000)) / this.speedinXDirection)) / (this.numPointsOnYAxis - 1); } else { // odd number of scanlines this.lineBreak = ((syncTime2 - syncTime1) - ((x2 - ((float)posData[firstNonZeroTimeInPos, 1] / 1000)) / this.speedinXDirection) - (((this.numPointsOnYAxis - 2) * (x2 - x1)) / this.speedinXDirection) - ((((float)posData[lastNonZeroTimeInPos, 1] / 1000) - x1) / this.speedinXDirection)) / (this.numPointsOnYAxis - 1); } // (17) time offset this.timeOffset = ((float)posData[firstNonZeroTimeInPos, 0] / 1000) - ((((float)posData[firstNonZeroTimeInPos, 1] / 1000) - x1) / this.speedinXDirection); double dwellTimeSum = 0; AppContext.StatusInfo = string.Empty; // (18) Format Data for (int actMassRange = 0; actMassRange < this.massRanges; actMassRange++) { // format the data into a rectangular, 2 dimensional array of floats that will represent the image data var imageData = new float[this.numPointsOnXAxis][]; for (int i = 0; i < imageData.Length; i++) { imageData[i] = new float[this.numPointsOnYAxis]; } dwellTimeSum -= this.dwellTime[actMassRange] / 1000 / 2; double optTimeOffset = this.timeOffset; double optLineBreak = this.lineBreak; if (AppContext.UseApproximation) { // Perform the optimization... this.HeuristicOptimization(imageData, actMassRange, x2 - x1, dwellTimeSum, ref optLineBreak, ref optTimeOffset); } this.FormatImageSharp(imageData, actMassRange, x2 - x1, dwellTimeSum, optLineBreak, optTimeOffset); dwellTimeSum -= this.dwellTime[actMassRange] / 1000 / 2; // create the appropriate dataset and add it to the WiffFileContent object... string imgName = wiffsample.Name + " : " + this.massRangeName[actMassRange]; Document doc = wiffsample.WiffFileContent.Document; // create the meta information data structure and populate with relevant information... var metaData = new ImageMetaData(); try { const float Epsilon = (float)1E-10; metaData.Add("Sample Name", typeof(string), wiffsample.Name, false); metaData.Add("Mass Range", typeof(string), this.massRangeName[actMassRange], false); metaData.Add("X1 (mm)", typeof(string), (Math.Abs(x1 - (int)x1) < Epsilon) ? x1.ToString("0.0") : x1.ToString(CultureInfo.InvariantCulture), false); metaData.Add("Y1 (mm)", typeof(string), (Math.Abs(y1 - (int)y1) < Epsilon) ? y1.ToString("0.0") : y1.ToString(CultureInfo.InvariantCulture), false); metaData.Add("X2 (mm)", typeof(string), (Math.Abs(x2 - (int)x2) < Epsilon) ? x2.ToString("0.0") : x2.ToString(CultureInfo.InvariantCulture), false); metaData.Add("Y2 (mm)", typeof(string), (Math.Abs(y2 - (int)y2) < Epsilon) ? y2.ToString("0.0") : y2.ToString(CultureInfo.InvariantCulture), false); metaData.Add("Data Points in X", typeof(string), this.numPointsOnXAxis.ToString(CultureInfo.InvariantCulture), false); metaData.Add("Data Points in Y", typeof(string), this.numPointsOnYAxis.ToString(CultureInfo.InvariantCulture), false); metaData.Add("Point Width (mm)", typeof(string), Math.Round(this.distInXDirection, 2).ToString(CultureInfo.InvariantCulture), false); metaData.Add("Point Height (mm)", typeof(string), Math.Round(this.distInYDirection, 2).ToString(CultureInfo.InvariantCulture), false); // Add Maldi Parameters string[] splitstring = strMaldiParams.Split(SepMaldiParams, StringSplitOptions.None); metaData.Add("Laser Frequency (Hz)", typeof(string), splitstring[1], false); metaData.Add("Laser Power (%)", typeof(string), splitstring[2], false); metaData.Add("Ablation Mode", typeof(string), splitstring[3], false); metaData.Add("Skimmer Voltage (V)", typeof(string), splitstring[4], false); metaData.Add("Source Gas", typeof(string), splitstring[5], false); metaData.Add("Raster Speed (mm/s)", typeof(string), splitstring[6], false); metaData.Add("Line Direction", typeof(string), splitstring[7], false); metaData.Add("Rastor Pitch ", typeof(string), splitstring[8], false); } catch (Exception e) { Util.ReportException(e); } // (19) Create new ImageData and add WiffContent to Wiffsample wiffsample.WiffFileContent.Add(new ImageData( doc, imageData, imgName, metaData, (float)this.massRangeMin[actMassRange], (float)this.massRangeMax[actMassRange], this.meanValues[actMassRange], this.medianValues[actMassRange], (float)this.distInXDirection, (float)this.distInYDirection, null, Core.ExperimentType.MRM)); } } finally { Cursor.Current = Cursors.Default; } }
/// <summary> /// Fills this instance data members with the information read from <paramref name="wiffFile"/>. /// </summary> /// <param name="wiffFile">A <see cref="FMANWiffFileClass"/> instance. The data source.</param> protected override void Initialize(FMANWiffFileClass wiffFile) { // get experiment object and the experiment parameters ITripleQuadMALDI experimentParams = (ITripleQuadMALDI)wiffFile.GetExperimentObject(WiffPeriod.Sample.Index, WiffPeriod.Index, Index); Experiment experiment = (Experiment)wiffFile.GetExperimentObject(WiffPeriod.Sample.Index, WiffPeriod.Index, Index); MassRange massRange = (MassRange)experiment.GetMassRange(0); minMass = massRange.QstartMass; // anaSpec.GetStartMass(); maxMass = massRange.QstopMass; // anaSpec.GetStopMass(); massStepSize = massRange.QstepMass; //anaSpec.StepSize; // get the number of MS data points massSpecDataPoints = (int)((maxMass - minMass) / massStepSize + 1); // select 1. data points FMANChromData chrom = new FMANChromData(); chrom.WiffFileName = wiffFile.GetWiffFileName(); chrom.SetToTIC(WiffPeriod.Sample.Index, WiffPeriod.Index, Index); // dimension the data arrray nrDataPoints = chrom.GetNumberOfDataPoints(); rawData = new float[nrDataPoints]; timeData = new float[nrDataPoints]; //loop through the mass ranges massRangeName = "TIC " + minMass.ToString() + " - " + maxMass.ToString(); double xValue = chrom.GetDataPointXValue(1); double yValue = chrom.GetDataPointYValue(1); massRangeMax = double.MinValue; massRangeMin = double.MaxValue; timeOffset = xValue * 1000; // helper for mean and median double meanSum = 0; List <float> valuesForMedian = new List <float>(); // read the data... for (int actDataPoint = 1; actDataPoint <= nrDataPoints; actDataPoint++) { // get the actual value... xValue = chrom.GetDataPointXValue(actDataPoint); yValue = chrom.GetDataPointYValue(actDataPoint); // and copy it to our local data structur rawData[actDataPoint - 1] = (float)yValue; timeData[actDataPoint - 1] = (float)xValue * 60; // keep track of the extrema if (yValue < massRangeMin) { massRangeMin = yValue; } if (yValue > massRangeMax) { massRangeMax = yValue; } // mean and median calculation... // sum up the value to calculate the mean meanSum += yValue; // fill an extra array to calculate the median valuesForMedian.Add((float)yValue); } // calculate the mean meanValue = (float)(meanSum / nrDataPoints); // calculate the median valuesForMedian.Sort(); medianValue = ((valuesForMedian.Count % 2) == 0) ? (float)(valuesForMedian[(valuesForMedian.Count / 2) - 1] + valuesForMedian[valuesForMedian.Count / 2]) / 2.0f : valuesForMedian[valuesForMedian.Count / 2]; #if (false) // analyze the timing values in timeData List <float> timeSpans = new List <float>(); for (int i = 1; i < timeData.Length; i++) { timeSpans.Add(timeData[i] - timeData[i - 1]); } float tMean = 0; float tMedian = 0; timeSpans.Sort(); foreach (float ts in timeSpans) { tMean += ts; } tMean = tMean / timeSpans.Count; tMedian = ((timeSpans.Count % 2) == 0) ? (float)(timeSpans[(timeSpans.Count / 2) - 1] + timeSpans[timeSpans.Count / 2]) / 2.0f : timeSpans[timeSpans.Count / 2]; #endif // fetch the x1, x2, y1, y2, width and height from the WiffSample instance this experiment belongs to. double x1 = WiffPeriod.Sample.P1.X; double y1 = WiffPeriod.Sample.P1.Y; double x2 = WiffPeriod.Sample.P2.X; double y2 = WiffPeriod.Sample.P2.Y; double width = WiffPeriod.Sample.Width; double height = WiffPeriod.Sample.Height; //get MALDI parmas and assign variables string strMALDIParams = experimentParams.TripleQuadMALDIParameters; // x speed in mm/s xSpeed = float.Parse(strMALDIParams.Split(sepMALDIParams, System.StringSplitOptions.None)[6]); //line distance in mm yDist = float.Parse(strMALDIParams.Split(sepMALDIParams, System.StringSplitOptions.None)[8]) / 1000; //time per point in s xTime = (float)((chrom.GetDataPointXValue(nrDataPoints) - chrom.GetDataPointXValue(2)) * 60 / (nrDataPoints - 2)); xDist = (float)(int)(xSpeed * xTime * 1000) / 1000; //number of poins in x xPoints = (int)((width) / xSpeed / xTime); // fetch the position data from the WiffSample instance this experiment belongs to. uint[,] posData = WiffPeriod.Sample.PositionData; long posDataLength = WiffPeriod.Sample.PositionDataLength; // try and find the first and last valid indices in the posData, where valid means a nonzero time value... long firstNonZeroTimeInPos = -1; for (long t = 0; t < posDataLength - 1; t++) { if (posData[t, 0] > 0) { firstNonZeroTimeInPos = t; // ok, we're done... break; } } long lastNonZeroTimeInPos = -1; for (long t = posDataLength - 1; t >= 0; t++) { if (posData[t, 0] > 0) { lastNonZeroTimeInPos = t; // ok, we're done... break; } } if (firstNonZeroTimeInPos < 0 || lastNonZeroTimeInPos < 0) { // haven't found a valid posData triplet. All time values are zero or less... // bail out return; } // y2 from the wiff file is not the actual y2 from the stage - replace with value from path file... y2 = (double)Math.Round((decimal)posData[lastNonZeroTimeInPos, 2] / 1000, 2); // ...and this has an effect of the ypoints yPoints = (int)Math.Round((decimal)((y2 - y1) / yDist)) + 1; double timeSpanPos = posData[lastNonZeroTimeInPos, 0] / 1000.0 - posData[firstNonZeroTimeInPos, 0] / 1000.0; if (yPoints % 2 == 0) { // even number of scanlines lineBreak = (timeSpanPos - (x2 - (float)posData[firstNonZeroTimeInPos, 1] / 1000) / xSpeed - (yPoints - 2) * (width) / xSpeed - (x2 - (float)posData[lastNonZeroTimeInPos, 1] / 1000) / xSpeed) / (yPoints - 1); } else { // odd number of scanlines lineBreak = (timeSpanPos - (x2 - (float)posData[firstNonZeroTimeInPos, 1] / 1000) / xSpeed - (yPoints - 2) * (width) / xSpeed - ((float)posData[lastNonZeroTimeInPos, 1] / 1000 - x1) / xSpeed) / (yPoints - 1); } lineBreak = lineBreak / xTime; timeOffset = (float)posData[firstNonZeroTimeInPos, 0] / 1000 - (((float)posData[firstNonZeroTimeInPos, 1] / 1000 - x1) / xSpeed); lineOffset = (5 - (timeData[5] - timeOffset) / xTime) + 1; /////////////////////////////////////////////////////////////////////////////////////////////////////// // TIC throughout the total massrange... /////////////////////////////////////////////////////////////////////////////////////////////////////// // format the data into a rectangular, 2 dimensional array of floats that will represent the image data // AppContext.ProgressStart("formating image data..."); // prepare the data structure float[][] dataTIC; try { dataTIC = new float[xPoints][]; for (int i = 0; i < dataTIC.Length; i++) { dataTIC[i] = new float[yPoints]; } // copy the data from wiff file datastream to the rectangular array. Take account of the line offset and // the line break timings. for (int y = 0; y < yPoints; y++) { int currentPoint; // currentLine is the offset to the start of the current line in the linear datastream (rawData) int currentLine = (int)Math.Floor(Math.Abs(lineOffset + ((x2 - x1) / xSpeed / xTime + lineBreak) * y)); for (int x = 0; x < xPoints; x++) { if (y % 2 == 0) { // even y: scan direction: --> currentPoint = (int)(currentLine + x); } else { // odd y: scan direction: <-- currentPoint = (int)(currentLine + xPoints - 1 - x); } if (currentPoint < nrDataPoints) { dataTIC[x][y] = rawData[currentPoint]; } else { dataTIC[x][y] = 0; } } AppContext.ProgressSetValue(100.0 * y / yPoints); } } finally { AppContext.ProgressClear(); } // create the appropriate dataset and add it to the WiffFileContent object... string imgName = WiffPeriod.Sample.Name + " : " + massRangeName; Document doc = WiffPeriod.Sample.WiffFileContent.Document; //create the meta information data structure and populate with relevant information... ImageMetaData metaData = new ImageMetaData(); try { metaData.Add("Sample Name", typeof(string), WiffPeriod.Sample.Name, false); metaData.Add("Mass Range", typeof(string), massRangeName, false); string[] splitted = strMALDIParams.Split(sepMALDIParams, System.StringSplitOptions.None); metaData.Add("Laser Frequency (Hz)", typeof(string), splitted[1], false); metaData.Add("Laser Power (%)", typeof(string), splitted[2], false); metaData.Add("Ablation Mode", typeof(string), splitted[3], false); metaData.Add("Skimmer Voltage (V)", typeof(string), splitted[4], false); metaData.Add("Source Gas", typeof(string), splitted[5], false); metaData.Add("Raster Speed (mm/s)", typeof(string), splitted[6], false); metaData.Add("Raster Pitch", typeof(string), splitted[8], false); } catch (Exception e) { Util.ReportException(e); } ImageData imageTIC = new ImageData(doc, dataTIC, imgName, metaData, (float)massRangeMin, (float)massRangeMax, (float)meanValue, (float)medianValue, (float)xDist, (float)yDist, (float)minMass, (float)maxMass); /////////////////////////////////////////////////////////////////////////////////////////////////////// // Q1 spectrum scan... FMANSpecData spec = new FMANSpecData(); spec.WiffFileName = wiffFile.GetWiffFileName(); // prepare the data structure List <float[][]> dataList; List <ImageData> imageDataList; AppContext.ProgressStart("formating spectrum data..."); try { dataList = new List <float[][]>(); for (int i = 0; i < massSpecDataPoints; i++) { float[][] data = new float[xPoints][]; for (int j = 0; j < xPoints; j++) { data[j] = new float[yPoints]; } dataList.Add(data); } for (int y = 0; y < yPoints; y++) { int currentPoint; // currentLine is the offset to the start of the current line in the linear datastream (rawData) int currentLine = (int)Math.Floor(Math.Abs(lineOffset + ((x2 - x1) / xSpeed / xTime + lineBreak) * y)); for (int x = 0; x < xPoints; x++) { if (y % 2 == 0) { // even y: scan direction: --> currentPoint = (int)(currentLine + x); } else { // odd y: scan direction: <-- currentPoint = (int)(currentLine + xPoints - 1 - x); } if (currentPoint >= nrDataPoints) { continue; } float currentTime = (float)chrom.GetXValueInSec(currentPoint + 1); spec.SetSpectrum(WiffPeriod.Sample.Index, WiffPeriod.Index, Index, currentTime, currentTime); int specDataPoints = spec.GetNumberOfDataPoints(); for (int k = 1; k <= specDataPoints; k++) { int specIndex = (int)((spec.GetDataPointXValue(k) - minMass) / massStepSize + 0.4); dataList[specIndex][x][y] = (float)spec.GetDataPointYValue(k); } } AppContext.ProgressSetValue(100.0 * y / yPoints); } // create the list of imageData objects passed to the imageSpectrumData object on it's creation later on... imageDataList = new List <ImageData>(); for (int k = 0; k < massSpecDataPoints; k++) { float[][] specData = dataList[k]; float mass = (float)(minMass + (massStepSize * k)); imgName = WiffPeriod.Sample.Name + " : " + mass.ToString(); // TODO -- rethink if one should really calculate the mean, median, min, max etc. if the images aren't used for imaging but for export... float minInt = float.MaxValue; float maxInt = float.MinValue; float mean = 0; float median = 0; // helper for mean and median meanSum = 0; valuesForMedian.Clear(); { for (int x = 0; x < xPoints; x++) { for (int y = 0; y < yPoints; y++) { float value = specData[x][y]; // keep track of the extrema if (value < minInt) { minInt = value; } if (value > maxInt) { maxInt = value; } // mean and median calculation... // sum up the value to calculate the mean meanSum += value; // fill an extra array to calculate the median valuesForMedian.Add(value); } } } // calculate the mean mean = (float)(meanSum / (xPoints * yPoints)); // calculate the median valuesForMedian.Sort(); median = ((valuesForMedian.Count % 2) == 0) ? (float)(valuesForMedian[(valuesForMedian.Count / 2) - 1] + valuesForMedian[valuesForMedian.Count / 2]) / 2.0f : valuesForMedian[valuesForMedian.Count / 2]; // ok, now create the imageData and add to list... ImageData imageData = new ImageData(doc, specData, imgName, new ImageMetaData(), minInt, maxInt, mean, median, (float)xDist, (float)yDist, (float)0.0f, (float)mass); imageDataList.Add(imageData); } } finally { AppContext.ProgressClear(); } // now everything should be set to create the ImageSpectrumData object... imgName = WiffPeriod.Sample.Name + " SPECT " + minMass.ToString() + " - " + maxMass.ToString(); ImageSpectrumData imageSpectrum = new ImageSpectrumData(doc, imgName, new ImageMetaData(), imageDataList, (float)minMass, (float)maxMass, (float)massStepSize); imageSpectrum.ImageTIC = imageTIC; WiffPeriod.Sample.WiffFileContent.Add(imageSpectrum); #if (false) // TODO -- find out what to do with the 'globalMassMax' value float anaTime = (float)chrom.GetXValueInSec(nrDataPoints - 1); chrom.SetToBPC(WiffPeriod.Sample.Index, WiffPeriod.Index, Index, 0, anaTime, minMass, maxMass, 2 * massStepSize); double tempMass; chrom.GetYValueRange(out tempMass, out globalMassMax); chrom.SetToTIC(WiffPeriod.Sample.Index, WiffPeriod.Index, Index); #endif chrom.WiffFileName = ""; chrom = null; spec.WiffFileName = ""; spec = null; }
/// <summary> /// Reads the Data file /// </summary> /// <param name="analysefilecontent">analyse file content Object</param> /// <param name="filepath">Path of file </param> /// <param name="analysefileheaderobject">Header Object</param> protected override void Initialise(AnalyseFileContent analysefilecontent, string filepath, AnalyseFileHeaderObject analysefileheaderobject) { this.filePath = filepath; this.analyseFileHeaderObject = analysefileheaderobject; // 1) Make sure the path file exists if (!File.Exists(this.filePath)) { string header = "Missing File"; string error = string.Format("{0} is missing", this.filePath); MessageBox.Show(error, header); return; } // 2) ReadCalibrationFile (Calc MinMass, MaxMass, StepSize and MassSpecDataPoints) this.ReadCalibrationFile(); // 3) Set Binsize this.binsize = 1; var fileinfo = new FileInfo(this.filePath); long imgFileSize = fileinfo.Length; string appPath = Application.StartupPath; appPath += "\\ApplicationSettings.xml"; var filesizelimit = this.GetPathFileSizeLimit(appPath); var minMassDp = 0; var maxMassDp = (int)(this.massspecdatapoints - 1); // We only want to do binning for files bigger than 100MB filesize > pathfilesize if (imgFileSize != filesizelimit) { // Open up BinNumberWindow var binNumberWindow = new BinNumberWindow(this.analyseFileHeaderObject.NumberOfXPoints, this.analyseFileHeaderObject.NumberOfYPoints, this.MassCal); if (binNumberWindow.ShowDialog() == true) { this.binsize = binNumberWindow.BinSize; minMassDp = binNumberWindow.MinMassDP; maxMassDp = binNumberWindow.MaxMassDP; } } this.massstepsize = 1; // 4) Fill out meta rawdata var metaData = new ImageMetaData(); try { metaData.Add("Sample Name", typeof(string), this.analyseFileHeaderObject.Name, false); metaData.Add("Mass Range", typeof(string), this.massRangeName, false); metaData.Add("Mass Step Size", typeof(string), 1, false); metaData.Add("X1 (mm)", typeof(string), (Math.Abs(this.analyseFileHeaderObject.X1 - (int)this.analyseFileHeaderObject.X1) < Epsilon) ? this.analyseFileHeaderObject.X1.ToString("0.0") : this.analyseFileHeaderObject.X1.ToString(CultureInfo.InvariantCulture), false); metaData.Add("Y1 (mm)", typeof(string), (Math.Abs(this.analyseFileHeaderObject.Y1 - (int)this.analyseFileHeaderObject.Y1) < Epsilon) ? this.analyseFileHeaderObject.Y1.ToString("0.0") : this.analyseFileHeaderObject.Y1.ToString(CultureInfo.InvariantCulture), false); metaData.Add("X2 (mm)", typeof(string), (Math.Abs(this.analyseFileHeaderObject.X2 - (int)this.analyseFileHeaderObject.X2) < Epsilon) ? this.analyseFileHeaderObject.X2.ToString("0.0") : this.analyseFileHeaderObject.X2.ToString(CultureInfo.InvariantCulture), false); metaData.Add("Y2 (mm)", typeof(string), (Math.Abs(this.analyseFileHeaderObject.Y2 - (int)this.analyseFileHeaderObject.Y2) < Epsilon) ? this.analyseFileHeaderObject.Y2.ToString("0.0") : this.analyseFileHeaderObject.Y2.ToString(CultureInfo.InvariantCulture), false); metaData.Add("Data Points in X", typeof(string), this.analyseFileHeaderObject.NumberOfXPoints.ToString(CultureInfo.InvariantCulture), false); metaData.Add("Data Points in Y", typeof(string), this.analyseFileHeaderObject.NumberOfYPoints.ToString(CultureInfo.InvariantCulture), false); metaData.Add("Point Width (mm)", typeof(string), Math.Round(this.analyseFileHeaderObject.Dx, 2).ToString(CultureInfo.InvariantCulture), false); metaData.Add("Point Height (mm)", typeof(string), Math.Round(this.analyseFileHeaderObject.Dy, 2).ToString(CultureInfo.InvariantCulture), false); metaData.Add("Bin Size", typeof(string), this.binsize.ToString(CultureInfo.InvariantCulture), false); } catch (Exception e) { Util.ReportException(e); } // 5) Declare Median List var valuesForMedian = new List <float>(); this.minIntensityValue = 0; this.maxIntensityValue = 0; var minIntList = new float[maxMassDp - minMassDp + 1]; var maxIntList = new float[maxMassDp - minMassDp + 1]; // 6) Declare and Initialise the dataTic var dataTic = new float[analysefileheaderobject.NumberOfXPoints][]; for (int i = 0; i < dataTic.Length; i++) { dataTic[i] = new float[analysefileheaderobject.NumberOfYPoints]; } // 7) Declare mass spectrum datat list this.massspecdatalist = new List <float[][]>(); // 8) Declare and Initialise the dataList var data = new float[analysefileheaderobject.NumberOfXPoints][]; for (int pointOnXAxis = 0; pointOnXAxis < analysefileheaderobject.NumberOfXPoints; pointOnXAxis++) { data[pointOnXAxis] = new float[analysefileheaderobject.NumberOfYPoints]; } this.massspecdatalist.Add(data); // 9) Declare and populate the image data list - Fill it with some default data - this will be over written later Cursor.Current = Cursors.WaitCursor; AppContext.ProgressStart("Generating Empty Imagelist..."); var imageDataList = new List <ImageData>(); try { for (int massSpecDataPt = 0; massSpecDataPt < ((maxMassDp - minMassDp + 1) / this.binsize); massSpecDataPt++) { var specData = new float[analysefileheaderobject.NumberOfXPoints][]; for (int i = 0; i < specData.Length; i++) { specData[i] = new float[analysefileheaderobject.NumberOfYPoints]; } // ok, now create the imageData and add to list... var imageData = new ImageData( analysefilecontent.Document, specData, this.analyseFileHeaderObject.Name, metaData, 0, 10000, 1000, 1000, this.analyseFileHeaderObject.Dx, this.analyseFileHeaderObject.Dy, this.masscal, this.analyseFileHeaderObject.ExperimentType); // Add the imageData to the list imageDataList.Add(imageData); AppContext.ProgressSetValue(100.0 * massSpecDataPt / ((maxMassDp - minMassDp + 1) / this.binsize)); } } catch (Exception e) { Util.ReportException(e); } finally { AppContext.ProgressClear(); Cursor.Current = Cursors.Default; } // 10) Read binary file Cursor.Current = Cursors.WaitCursor; AppContext.ProgressStart("Populating ImageList..."); using (var imgReader = new BinaryReader(File.Open(this.filePath, FileMode.Open))) { int xp = analysefileheaderobject.NumberOfXPoints; int yp = analysefileheaderobject.NumberOfYPoints; int dp = (maxMassDp - minMassDp + 1) / this.binsize; int dd = this.binsize; int dl = minMassDp; int xf = analysefileheaderobject.NumberOfXPoints; int df = this.masscal.Length; int ps = this.analyseFileHeaderObject.DataByteSize; int y; var meanSumList = new double[dp]; for (int i = 0; i < dp; i++) { minIntList[i] = float.MaxValue; maxIntList[i] = float.MinValue; meanSumList[i] = 0.0; } for (y = 0; y < yp; y++) { // for the progress bar AppContext.ProgressSetValue(y * 100 / yp); // refresh counter here; for (int x = 0; x < xp; x++) { long fp = ((((y * xf) + x) * df) + dl) * ps; imgReader.BaseStream.Position = fp; for (int d = 0; d < dp; d++) { float average = 0; for (int di = 0; di < dd; di++) { float intensity; switch (this.analyseFileHeaderObject.DataType) { case 4: intensity = imgReader.ReadInt16(); break; case 8: case 16: intensity = imgReader.ReadInt32(); break; case 64: intensity = imgReader.ReadInt64(); break; default: intensity = imgReader.ReadInt32(); break; } average += intensity; } average = average / dd; imageDataList[d].Data[x][y] = average; dataTic[x][y] += average; if (average < minIntList[d]) { minIntList[d] = average; } if (average > maxIntList[d]) { maxIntList[d] = average; } // mean and median calculation... sum up the value to calculate the mean meanSumList[d] += average; } } } // and cleanup imgReader.Close(); } AppContext.ProgressClear(); Cursor.Current = Cursors.Default; // 11) create new masscal array var newmasscal = new float[(maxMassDp - minMassDp + 1) / this.binsize]; for (int i = 0; i < ((maxMassDp - minMassDp + 1) / this.binsize); i++) { newmasscal[i] = this.masscal[minMassDp + (i * this.binsize)]; } this.masscal = newmasscal; // 12) Mean/Median for Tic double meanSum = 0.0; int numDataPoint = dataTic.Length; for (int y = 0; y < analysefileheaderobject.NumberOfYPoints; y++) { for (int x = 0; x < analysefileheaderobject.NumberOfXPoints; x++) { float intensity = dataTic[x][y]; meanSum += intensity; valuesForMedian.Add(intensity); if (intensity < this.minIntensityValue) { this.minIntensityValue = intensity; } if (intensity > this.maxIntensityValue) { this.maxIntensityValue = intensity; } } } if (numDataPoint != 0) { this.meanValue = (float)(meanSum / numDataPoint); } valuesForMedian.Sort(); this.medianValue = ((valuesForMedian.Count % 2) == 0) ? (valuesForMedian[(valuesForMedian.Count / 2) - 1] + valuesForMedian[valuesForMedian.Count / 2]) / 2.0f : valuesForMedian[valuesForMedian.Count / 2]; // 13) Fill out imageTic var imageTic = new ImageData( analysefilecontent.Document, dataTic, this.analyseFileHeaderObject.Name, metaData, this.minIntensityValue, this.maxIntensityValue, this.meanValue, this.medianValue, this.analyseFileHeaderObject.Dx, this.analyseFileHeaderObject.Dy, this.masscal, this.analyseFileHeaderObject.ExperimentType); // 14) Fill out ImageSpectrumData and add to analysefilecontent analysefilecontent.Add( new ImageSpectrumData( analysefilecontent.Document, this.analyseFileHeaderObject.Name, metaData, this.masscal, imageDataList, this.analyseFileHeaderObject.ExperimentType) { ImageTic = imageTic }); }
/// <summary> /// Fills this instance data members with the information read from <paramref name="inputMsExperiment"/> /// </summary> /// <param name="inputMsExperiment">Mass Spec Experiment</param> /// <param name="wiffsample">Wiff Sample</param> protected override void Initialize(MSExperiment inputMsExperiment, WiffSample wiffsample) { Cursor.Current = Cursors.WaitCursor; try { // (1) Get Maldi Parameters string strMaldiParams = wiffsample.MaldiParametersString; this.msexperiment = inputMsExperiment; // (2) Get the number of mass transitions - For MS experiments by default we will look at the first scan ([0]) MassRange massRange = this.msexperiment.Details.MassRangeInfo[0]; var fullScanMassRange = massRange as FullScanMassRange; if (fullScanMassRange != null) { this.minMass = fullScanMassRange.StartMass; this.maxMass = fullScanMassRange.EndMass; this.massStepSize = fullScanMassRange.StepSize; } this.massSpecDataPoints = (int)(((this.maxMass - this.minMass) / this.massStepSize) + 1); // (3) Populate masscal this.masscal = new float[this.massSpecDataPoints]; for (int i = 0; i < this.massSpecDataPoints; i++) { this.masscal[i] = (float)(this.minMass + (i * this.massStepSize)); } // (4) Select 1 trace XYData tic = this.msexperiment.GetTotalIonChromatogram(); // (5) Dimension the data array, the number "data points" this.numDataPoints = tic.NumDataPoints; this.rawData = new float[this.numDataPoints]; this.timeData = new float[this.numDataPoints]; // (6) mass range info this.massRangeName = "TIC " + this.msexperiment.Details.MassRangeInfo[0].Name; double actualXValue = tic.GetActualXValues()[0]; this.massRangeMax = double.MinValue; this.massRangeMin = double.MaxValue; this.timeOffset = actualXValue * 1000; // helper for mean and median double meanSum = 0; var valuesForMedian = new List <float>(); // (7) read the data... for (int actDataPoint = 0; actDataPoint < this.numDataPoints; actDataPoint++) { // get the actual value... actualXValue = tic.GetActualXValues()[actDataPoint]; double actualYValue = tic.GetActualYValues()[actDataPoint]; // and copy it to our local data structure this.rawData[actDataPoint] = (float)actualYValue; this.timeData[actDataPoint] = (float)actualXValue * 60; // keep track of the extrema if (actualYValue < this.massRangeMin) { this.massRangeMin = actualYValue; } if (actualYValue > this.massRangeMax) { this.massRangeMax = actualYValue; } // mean and median calculation... sum up the value to calculate the mean meanSum += actualYValue; // fill an extra array to calculate the median valuesForMedian.Add((float)actualYValue); } // (8) Calculate the mean this.meanValue = (float)(meanSum / this.numDataPoints); // (9) Calculate the median valuesForMedian.Sort(); this.medianValue = ((valuesForMedian.Count % 2) == 0) ? (valuesForMedian[(valuesForMedian.Count / 2) - 1] + valuesForMedian[valuesForMedian.Count / 2]) / 2.0f : valuesForMedian[valuesForMedian.Count / 2]; // (10) fetch the x1, x2, y1, y2, width and height from the WiffSample instance this experiment belongs to. this.x1 = wiffsample.P1.X; this.y2 = 82 - wiffsample.P1.Y; this.x2 = wiffsample.P2.X; this.width = wiffsample.Width; // (11) time per point in s this.timeinXDirection = (float)((tic.GetActualXValues()[this.numDataPoints - 1] - tic.GetActualXValues()[1]) * 60 / (this.numDataPoints - 2)); // (12) fetch the position data from the WiffSample instance this experiment belongs to. uint[,] posData = wiffsample.PositionData; long posDataLength = wiffsample.PositionDataLength; // try and find the first and last valid indices in the posData, where valid means a nonzero time value... long firstNonZeroTimeInPos = -1; for (long t = 0; t < posDataLength - 1; t++) { if (posData[t, 0] > 0) { firstNonZeroTimeInPos = t; break; } } long lastNonZeroTimeInPos = -1; for (long t = posDataLength - 1; t >= 0; t++) { if (posData[t, 0] > 0) { lastNonZeroTimeInPos = t; break; } } if (firstNonZeroTimeInPos < 0 || lastNonZeroTimeInPos < 0) { // haven't found a valid posData triplet. All time values are zero or less... bail out (Put in an Error Message here?) return; } // (13) Distance in Y direction this.distInYDirection = 0; for (long t = firstNonZeroTimeInPos; t < lastNonZeroTimeInPos; t++) { if ((posData[t, 1] > ((this.x2 + this.x1) * 500)) & Equals(this.distInYDirection, 0.0)) { this.distInYDirection = posData[t, 2]; } if ((posData[t, 1] < ((this.x2 + this.x1) * 500)) & (this.distInYDirection > 0)) { this.distInYDirection = (float)Math.Round((decimal)(posData[t, 2] - this.distInYDirection) / 500, (int)(1 - Math.Log10((posData[t, 2] - this.distInYDirection) / 500))) / 2; break; } } // (14) calculate speed in x direction this.speedinXDirection = (float)Math.Round(((posData[firstNonZeroTimeInPos + 2, 1] - posData[firstNonZeroTimeInPos + 1, 1]) / (decimal)(posData[firstNonZeroTimeInPos + 2, 0] - posData[firstNonZeroTimeInPos + 1, 0]) * 2), 0) / 2; // (15) distInXDirection this.distInXDirection = (float)(int)(this.speedinXDirection * this.timeinXDirection * 1000) / 1000; // (16) number of points in x this.numPointsOnXAxis = (int)(this.width / this.speedinXDirection / this.timeinXDirection); // (17) number of points in y // y1 from the wiff file is not the actual y1 from the stage - replace with value from path file... this.y1 = 82 - (double)Math.Round(((decimal)posData[lastNonZeroTimeInPos, 2] / 1000), 2); // ...and this has an effect of the ypoints this.numPointsOnYAxis = (int)Math.Round((decimal)((this.y2 - this.y1) / this.distInYDirection) + 1); // (18) calculate the line breaks var timeSpanPos = (posData[lastNonZeroTimeInPos, 0] / 1000.0) - (posData[firstNonZeroTimeInPos, 0] / 1000.0); if (this.numPointsOnYAxis % 2 == 0) { // even number of scanlines this.lineBreak = (timeSpanPos - ((this.x2 - ((float)posData[firstNonZeroTimeInPos, 1] / 1000)) / this.speedinXDirection) - (((this.numPointsOnYAxis - 2) * this.width) / this.speedinXDirection) - ((this.x2 - ((float)posData[lastNonZeroTimeInPos, 1] / 1000)) / this.speedinXDirection)) / (this.numPointsOnYAxis - 1); } else { // odd number of scanlines this.lineBreak = (timeSpanPos - ((this.x2 - ((float)posData[firstNonZeroTimeInPos, 1] / 1000)) / this.speedinXDirection) - (((this.numPointsOnYAxis - 2) * this.width) / this.speedinXDirection) - ((((float)posData[lastNonZeroTimeInPos, 1] / 1000) - this.x1) / this.speedinXDirection)) / (this.numPointsOnYAxis - 1); } this.lineBreak = this.lineBreak / this.timeinXDirection; this.timeOffset = ((float)posData[firstNonZeroTimeInPos, 0] / 1000) - ((((float)posData[firstNonZeroTimeInPos, 1] / 1000) - this.x1) / this.speedinXDirection); this.lineOffset = (5 - ((this.timeData[5] - this.timeOffset) / this.timeinXDirection)) + 1; // TIC throughout the total massrange... // format the data into a rectangular, 2 dimensional array of floats that will represent the image data AppContext.ProgressStart("formatting image data..."); // (19) copy the data from wiff file datastream to the rectangular array. Take account of the line offset and the line break timings float[][] dataTic; try { dataTic = new float[this.numPointsOnXAxis][]; this.sampleDataPos = new int[this.numPointsOnXAxis][]; for (int i = 0; i < dataTic.Length; i++) { dataTic[i] = new float[this.numPointsOnYAxis]; this.sampleDataPos[i] = new int[this.numPointsOnYAxis]; } for (int pointOnYAxis = 0; pointOnYAxis < this.numPointsOnYAxis; pointOnYAxis++) { // currentLine is the offset to the start of the current line in the linear datastream (rawData) var currentLine = (int)Math.Floor(Math.Abs(this.lineOffset + (((((this.x2 - this.x1) / this.speedinXDirection) / this.timeinXDirection) + this.lineBreak) * pointOnYAxis))); for (int pointOnXAxis = 0; pointOnXAxis < this.numPointsOnXAxis; pointOnXAxis++) { int currentPoint; if (pointOnYAxis % 2 == 0) { // even y: scan direction: --> currentPoint = currentLine + pointOnXAxis; } else { // odd y: scan direction: <-- currentPoint = currentLine + this.numPointsOnXAxis - 1 - pointOnXAxis; } if (currentPoint < this.numDataPoints) { dataTic[pointOnXAxis][this.numPointsOnYAxis - 1 - pointOnYAxis] = this.rawData[currentPoint]; // Add in a new array to save these dataPos. We can use them to get the scan number // Scan number is the current point this.sampleDataPos[pointOnXAxis][this.numPointsOnYAxis - 1 - pointOnYAxis] = currentPoint; } else { dataTic[pointOnXAxis][this.numPointsOnYAxis - 1 - pointOnYAxis] = 0; this.sampleDataPos[pointOnXAxis][this.numPointsOnYAxis - 1 - pointOnYAxis] = 0; } } AppContext.ProgressSetValue((100.0 * pointOnYAxis) / this.numPointsOnYAxis); } } finally { AppContext.ProgressClear(); } // (20) create the appropriate dataset and add it to the WiffFileContent object... string imgName = wiffsample.Name + " : " + this.massRangeName; Document doc = wiffsample.WiffFileContent.Document; // (21) Calculate Bin Points // Set a default bin size of 1 - Important it is set to 1 and not zero this.binsize = 1; this.GetBinSize(wiffsample.ScanFileSize, this.numPointsOnXAxis, this.numPointsOnYAxis); // By default we set this to massSpecDataPoints this.binnedmassSpecDataPoints = this.massSpecDataPoints; if (this.binsize > 1) { this.binnedmassSpecDataPoints = this.massSpecDataPoints / this.binsize; } // create the meta information data structure and populate with relevant information... var metaData = new ImageMetaData(); try { const float Epsilon = (float)1E-10; metaData.Add("Sample Name", typeof(string), wiffsample.Name, false); metaData.Add("Mass Range", typeof(string), this.massRangeName, false); metaData.Add("Mass Step Size", typeof(string), this.massStepSize, false); metaData.Add("X1 (mm)", typeof(string), (Math.Abs(this.x1 - (int)this.x1) < Epsilon) ? this.x1.ToString("0.0") : this.x1.ToString(CultureInfo.InvariantCulture), false); metaData.Add("Y1 (mm)", typeof(string), (Math.Abs(this.y1 - (int)this.y1) < Epsilon) ? this.y1.ToString("0.0") : this.y1.ToString(CultureInfo.InvariantCulture), false); metaData.Add("X2 (mm)", typeof(string), (Math.Abs(this.x2 - (int)this.x2) < Epsilon) ? this.x2.ToString("0.0") : this.x2.ToString(CultureInfo.InvariantCulture), false); metaData.Add("Y2 (mm)", typeof(string), (Math.Abs(this.y2 - (int)this.y2) < Epsilon) ? this.y2.ToString("0.0") : this.y2.ToString(CultureInfo.InvariantCulture), false); metaData.Add("Data Points in X", typeof(string), this.numPointsOnXAxis.ToString(CultureInfo.InvariantCulture), false); metaData.Add("Data Points in Y", typeof(string), this.numPointsOnYAxis.ToString(CultureInfo.InvariantCulture), false); metaData.Add("Point Width (mm)", typeof(string), Math.Round(this.distInXDirection, 2).ToString(CultureInfo.InvariantCulture), false); metaData.Add("Point Height (mm)", typeof(string), Math.Round(this.distInYDirection, 2).ToString(CultureInfo.InvariantCulture), false); metaData.Add("Bin Size", typeof(string), this.binsize.ToString(CultureInfo.InvariantCulture), false); // Add Maldi Parameters string[] splitstring = strMaldiParams.Split(SepMaldiParams, StringSplitOptions.None); metaData.Add("Laser Frequency (Hz)", typeof(string), splitstring[1], false); metaData.Add("Laser Power (%)", typeof(string), splitstring[2], false); metaData.Add("Ablation Mode", typeof(string), splitstring[3], false); metaData.Add("Skimmer Voltage (V)", typeof(string), splitstring[4], false); metaData.Add("Source Gas", typeof(string), splitstring[5], false); metaData.Add("Raster Speed (mm/s)", typeof(string), splitstring[6], false); metaData.Add("Line Direction", typeof(string), splitstring[7], false); metaData.Add("Rastor Pitch ", typeof(string), splitstring[8], false); } catch (Exception e) { Util.ReportException(e); } // (22) Create the ImageData var imageTic = new ImageData( doc, dataTic, imgName, metaData, (float)this.massRangeMin, (float)this.massRangeMax, this.meanValue, this.medianValue, (float)this.distInXDirection, (float)this.distInYDirection, this.masscal, Core.ExperimentType.MS); // (23) Collate the Spectrum Data List <ImageData> imageDataList = null; try { // (24) Create a list of array's to hold the mass spec images (in effect a 3x3 array or a list of 2x2 array) this.dataList = new List <float[][]>(); for (int numMassSpecDataPts = 0; numMassSpecDataPts < this.binnedmassSpecDataPoints; numMassSpecDataPts++) { var data = new float[this.numPointsOnXAxis][]; for (int pointOnXAxis = 0; pointOnXAxis < this.numPointsOnXAxis; pointOnXAxis++) { data[pointOnXAxis] = new float[this.numPointsOnYAxis]; } this.dataList.Add(data); } // (25) Populate dataList. We can populate this by Scan (PopulateListByScan()) Or MassSpec (PopulateListByMass()) // For now we will use by Scan as it is more effcient this.PopulateListByScan(); // (26) Create the list of imageData objects passed to the imageSpectrumData object on it's creation later on... imageDataList = new List <ImageData>(); for (int massSpecDataPt = 0; massSpecDataPt < this.binnedmassSpecDataPoints; massSpecDataPt++) { float[][] specData = this.dataList[massSpecDataPt]; imgName = wiffsample.Name + " : " + this.massRangeName; // TODO -- rethink if one should really calculate the mean, median, min, max etc. if the images aren't used for imaging but for export... float minInt = float.MaxValue; float maxInt = float.MinValue; // helper for mean and median meanSum = 0; valuesForMedian.Clear(); { for (int x = 0; x < this.numPointsOnXAxis; x++) { for (int y = 0; y < this.numPointsOnYAxis; y++) { float value = specData[x][y]; // keep track of the extrema if (value < minInt) { minInt = value; } if (value > maxInt) { maxInt = value; } // mean and median calculation... // sum up the value to calculate the mean meanSum += value; // fill an extra array to calculate the median valuesForMedian.Add(value); } } } // calculate the mean var mean = (float)(meanSum / (this.numPointsOnXAxis * this.numPointsOnYAxis)); // calculate the median valuesForMedian.Sort(); float median = ((valuesForMedian.Count % 2) == 0) ? (valuesForMedian[(valuesForMedian.Count / 2) - 1] + valuesForMedian[valuesForMedian.Count / 2]) / 2.0f : valuesForMedian[valuesForMedian.Count / 2]; // ok, now create the imageData and add to list... var imageData = new ImageData( doc, specData, imgName, metaData, minInt, maxInt, mean, median, (float)this.distInXDirection, (float)this.distInYDirection, this.masscal, Core.ExperimentType.MS); imageDataList.Add(imageData); } } catch (Exception e) { Util.ReportException(e); } // (27) Now everything should be set to create the ImageSpectrumData object... imgName = wiffsample.Name + " SPECT " + this.massRangeMin.ToString(CultureInfo.InvariantCulture) + " - " + this.massRangeMax.ToString(CultureInfo.InvariantCulture); var imageSpectrum = new ImageSpectrumData( doc, imgName, metaData, this.masscal, imageDataList, Core.ExperimentType.MS) { ImageTic = imageTic }; wiffsample.WiffFileContent.Add(imageSpectrum); } finally { Cursor.Current = Cursors.Default; } }
/// <summary> /// Reads the image file for an MRM experiment /// </summary> /// <param name="analysefilecontent">analyse file content Object</param> /// <param name="filepath">Path of file </param> /// <param name="analysefileheaderobject">Header Object</param> protected override void Initialise(AnalyseFileContent analysefilecontent, string filepath, AnalyseFileHeaderObject analysefileheaderobject) { this.filePath = filepath; this.analyseFileHeaderObject = analysefileheaderobject; // 1) Make sure the path file exists if (!File.Exists(this.filePath)) { MessageBox.Show(this.filePath + " is missing", "Missing File"); return; } // 1) Use BinaryReader this.ReadImgFile(); // 2) Convert data[]to ImageData[][] & (3) And calc Mean and Median and minIntensityValue, maxIntensityValue var imageData = new float[this.analyseFileHeaderObject.NumberOfXPoints][]; double meanSum = 0.0; var valuesForMedian = new List <float>(); this.minIntensityValue = 0; this.maxIntensityValue = 0; int numDataPoint = this.data.Length; for (int i = 0; i < imageData.Length; i++) { imageData[i] = new float[this.analyseFileHeaderObject.NumberOfYPoints]; } // TODO JP If data[i + j] is out of scope, exit loops and continue - remaining array points will be null try { for (int j = 0; j < this.analyseFileHeaderObject.NumberOfYPoints; j++) { for (int i = 0; i < this.analyseFileHeaderObject.NumberOfXPoints; i++) { int index; if (j == 0) { index = i; } else { index = i + this.analyseFileHeaderObject.NumberOfXPoints + ((j - 1) * this.analyseFileHeaderObject.NumberOfXPoints); } float intensity = this.data[index]; imageData[i][j] = intensity; meanSum += intensity; valuesForMedian.Add(intensity); if (intensity < this.minIntensityValue) { this.minIntensityValue = intensity; } if (intensity > this.maxIntensityValue) { this.maxIntensityValue = intensity; } } } } catch (Exception e) { Util.ReportException(e); } // 4) Calculate Mean And Median if (numDataPoint != 0) { this.meanValue = (float)(meanSum / numDataPoint); } valuesForMedian.Sort(); this.medianValue = ((valuesForMedian.Count % 2) == 0) ? (valuesForMedian[(valuesForMedian.Count / 2) - 1] + valuesForMedian[valuesForMedian.Count / 2]) / 2.0f : valuesForMedian[valuesForMedian.Count / 2]; // 5) Fill out meta data var metaData = new ImageMetaData(); try { const float Epsilon = (float)1E-10; metaData.Add("Sample Name", typeof(string), this.analyseFileHeaderObject.Name, false); metaData.Add("X1 (mm)", typeof(string), (Math.Abs(this.analyseFileHeaderObject.X1 - (int)this.analyseFileHeaderObject.X1) < Epsilon) ? this.analyseFileHeaderObject.X1.ToString("0.0") : this.analyseFileHeaderObject.X1.ToString(CultureInfo.InvariantCulture), false); metaData.Add("Y1 (mm)", typeof(string), (Math.Abs(this.analyseFileHeaderObject.Y1 - (int)this.analyseFileHeaderObject.Y1) < Epsilon) ? this.analyseFileHeaderObject.Y1.ToString("0.0") : this.analyseFileHeaderObject.Y1.ToString(CultureInfo.InvariantCulture), false); metaData.Add("X2 (mm)", typeof(string), (Math.Abs(this.analyseFileHeaderObject.X2 - (int)this.analyseFileHeaderObject.X2) < Epsilon) ? this.analyseFileHeaderObject.X2.ToString("0.0") : this.analyseFileHeaderObject.X2.ToString(CultureInfo.InvariantCulture), false); metaData.Add("Y2 (mm)", typeof(string), (Math.Abs(this.analyseFileHeaderObject.Y2 - (int)this.analyseFileHeaderObject.Y2) < Epsilon) ? this.analyseFileHeaderObject.Y2.ToString("0.0") : this.analyseFileHeaderObject.Y2.ToString(CultureInfo.InvariantCulture), false); metaData.Add("Data Points in X", typeof(string), this.analyseFileHeaderObject.NumberOfXPoints.ToString(CultureInfo.InvariantCulture), false); metaData.Add("Data Points in Y", typeof(string), this.analyseFileHeaderObject.NumberOfYPoints.ToString(CultureInfo.InvariantCulture), false); metaData.Add("Point Width (mm)", typeof(string), Math.Round(this.analyseFileHeaderObject.Dx, 2).ToString(CultureInfo.InvariantCulture), false); metaData.Add("Point Height (mm)", typeof(string), Math.Round(this.analyseFileHeaderObject.Dy, 2).ToString(CultureInfo.InvariantCulture), false); } catch (Exception e) { Util.ReportException(e); } // 6) Fill out imageData analysefilecontent.Add(new ImageData( analysefilecontent.Document, imageData, this.analyseFileHeaderObject.Name, metaData, this.minIntensityValue, this.maxIntensityValue, this.meanValue, this.medianValue, this.analyseFileHeaderObject.Dx, this.analyseFileHeaderObject.Dy, null, this.analyseFileHeaderObject.ExperimentType)); }
/// <summary> /// Fills this instance data members with the information read from <paramref name="wiffFile"/>. /// </summary> /// <param name="wiffFile">A <see cref="FMANWiffFileClass"/> instance. The data source.</param> protected override void Initialize(FMANWiffFileClass wiffFile) { // set the status information AppContext.StatusInfo = "Getting wiff-data"; // get the experiment parameters and the experiment object ITripleQuadMALDI experimentParams = (ITripleQuadMALDI)wiffFile.GetExperimentObject(WiffPeriod.Sample.Index, WiffPeriod.Index, Index); Experiment experiment = (Experiment)wiffFile.GetExperimentObject(WiffPeriod.Sample.Index, WiffPeriod.Index, Index); // get the number of mass MRM transitions massRanges = experiment.MassRangesCount; // select 1. MRM trace FMANChromData anaChrom = new FMANChromData(); anaChrom.WiffFileName = wiffFile.GetWiffFileName(); anaChrom.SetToXICZeroWidth(WiffPeriod.Sample.Index, WiffPeriod.Index, Index, 0); // dimension the data arrray, the number "data points" nrDataPoints = anaChrom.GetNumberOfDataPoints(); rawData = new float[massRanges, nrDataPoints]; timeData = new float[nrDataPoints]; dwellTime = new double[massRanges]; massRangeName = new string[massRanges]; massRangeMax = new double[massRanges]; massRangeMin = new double[massRanges]; meanValues = new float[massRanges]; medianValues = new float[massRanges]; // helper for mean and median double meanSum = 0; List <float> valuesForMedian = new List <float>(); // loop through the mass ranges double[] startMass = new double[massRanges]; double[] stopMass = new double[massRanges]; double[] stepMass = new double[massRanges]; for (int actMassRange = 0; actMassRange < massRanges; actMassRange++) { // get mass range object MassRange anaMassRange = (MassRange)experiment.GetMassRange(actMassRange); startMass[actMassRange] = anaMassRange.QstartMass; stopMass[actMassRange] = anaMassRange.QstopMass; stepMass[actMassRange] = anaMassRange.QstepMass; massRangeName[actMassRange] = Math.Round(startMass[actMassRange], 2).ToString() + " > " + Math.Round(stepMass[actMassRange], 2).ToString(); dwellTime[actMassRange] = anaMassRange.DwellTime; // select MRM trace anaChrom.SetToXICZeroWidth(WiffPeriod.Sample.Index, WiffPeriod.Index, Index, (short)actMassRange); // loop throug the spectrum massRangeMax[actMassRange] = double.MinValue; massRangeMin[actMassRange] = double.MaxValue; meanSum = 0.0; valuesForMedian.Clear(); for (int actDataPoint = 1; actDataPoint <= nrDataPoints; actDataPoint++) { // get the actual value double anaXValue = anaChrom.GetDataPointXValue(actDataPoint); double anaYValue = anaChrom.GetDataPointYValue(actDataPoint); if (anaYValue < massRangeMin[actMassRange]) { massRangeMin[actMassRange] = anaYValue; } if (anaYValue > massRangeMax[actMassRange]) { massRangeMax[actMassRange] = anaYValue; } // now get the actual data rawData[actMassRange, actDataPoint - 1] = (float)anaYValue; timeData[actDataPoint - 1] = (float)anaXValue * 60; // mean and median calculation... // sum up the value to calculate the mean meanSum += anaYValue; // fill an extra array to calculate the median valuesForMedian.Add((float)anaYValue); } // calculate the mean meanValues[actMassRange] = (float)(meanSum / nrDataPoints); // calculate the median valuesForMedian.Sort(); medianValues[actMassRange] = ((valuesForMedian.Count % 2) == 0) ? (float)(valuesForMedian[(valuesForMedian.Count / 2) - 1] + valuesForMedian[valuesForMedian.Count / 2]) / 2.0f : valuesForMedian[valuesForMedian.Count / 2]; } // get MALDI parmas and assign variables string strMALDIParams = experimentParams.TripleQuadMALDIParameters; // x speed in mm/s xSpeed = float.Parse(strMALDIParams.Split(sepMALDIParams, System.StringSplitOptions.None)[6]); //line distance in mm yDist = float.Parse(strMALDIParams.Split(sepMALDIParams, System.StringSplitOptions.None)[8]) / 1000; //time per point in s xTime = (float)((anaChrom.GetDataPointXValue(nrDataPoints) - anaChrom.GetDataPointXValue(2)) * 60 / (nrDataPoints - 2)); xDist = (float)(int)(xSpeed * xTime * 1000) / 1000; anaChrom.SetToTIC(WiffPeriod.Sample.Index, WiffPeriod.Index, Index); // fetch the x1, x2, y1, y2, width and height from the WiffSample instance this experiment belongs to. double x1 = WiffPeriod.Sample.P1.X; double y1 = WiffPeriod.Sample.P1.Y; double x2 = WiffPeriod.Sample.P2.X; double y2 = WiffPeriod.Sample.P2.Y; double width = WiffPeriod.Sample.Width; double height = WiffPeriod.Sample.Height; //number of poins in x xPoints = (int)((width) / xSpeed / xTime); //number of points in y yPoints = (int)((height) / yDist + 0.5) + 1; // lineOffset = 1; // fetch the position data from the WiffSample instance this experiment belongs to. uint[,] posData = WiffPeriod.Sample.PositionData; long posDataLength = WiffPeriod.Sample.PositionDataLength; // try and find the first and last valid indices in the posData, where valid means a nonzero time value... long firstNonZeroTimeInPos = -1; for (long t = 0; t < posDataLength - 1; t++) { if (posData[t, 0] > 0) { firstNonZeroTimeInPos = t + 1; // ok, we're done... break; } } long lastNonZeroTimeInPos = -1; for (long t = posDataLength - 1; t >= 0; t++) { if (posData[t, 0] > 0) { lastNonZeroTimeInPos = t - 1; // ok, we're done... break; } } if (firstNonZeroTimeInPos < 0 || lastNonZeroTimeInPos < 0) { // haven't found a valid posData triplet. All time values are zero or less... // bail out return; } // y2 from the wiff file is not the actual y2 from the stage - replace with value from path file... y2 = (double)Math.Round((decimal)posData[lastNonZeroTimeInPos, 2] / 1000, 2); // ...and this has an effect of the ypoints yPoints = (int)Math.Round((decimal)((y2 - y1) / yDist)) + 1; #if (false) // experimental method to format the ms-data to the x,y suitable for an image representation // fet two time stamps from the start and end of chrom file double tFirstMSDataPoint = anaChrom.GetDataPointXValue(10) * 60 * 1000; double tLastMSDataPoint = anaChrom.GetDataPointXValue(nrDataPoints - 10) * 60 * 1000; int positionMarker = 1; // get the corresponding position from the path file for (int i = 0; posData[i, 0] < tFirstMSDataPoint; i++) { positionMarker = i; } double xFirstMSDataPoint = ((tFirstMSDataPoint - posData[positionMarker, 0]) / (posData[positionMarker + 1, 0] - posData[positionMarker, 0]) * (int)(posData[positionMarker + 1, 1] - posData[positionMarker, 1]) + posData[positionMarker, 1]) / 1000; double yFirstMSDataPoint = (double)Math.Round((decimal)posData[positionMarker, 2] / 1000, 2); for (int i = 0; posData[i, 0] < tLastMSDataPoint; i++) { positionMarker = i; } double xLastMSDataPoint = ((tLastMSDataPoint - posData[positionMarker, 0]) / (posData[positionMarker + 1, 0] - posData[positionMarker, 0]) * (int)(posData[positionMarker + 1, 1] - posData[positionMarker, 1]) + posData[positionMarker, 1]) / 1000; double yLastMSDataPoint = (double)Math.Round((decimal)posData[positionMarker, 2] / 1000, 2); lineOffset = 10 - (xFirstMSDataPoint - x1) / xDist; if (yPoints % 2 == 0) { // even number of scanlines lineBreak = (((nrDataPoints - 10 - 10) - (x2 - (float)xFirstMSDataPoint) / xDist - (yPoints - 2) * (x2 - x1) / xDist - (x2 - (float)xLastMSDataPoint) / xDist)) / (yPoints - 1); } else { // odd number of scanlines lineBreak = (((nrDataPoints - 10 - 10) - (x2 - (float)xFirstMSDataPoint) / xDist - (yPoints - 2) * (x2 - x1) / xDist - ((float)xLastMSDataPoint - x1) / xDist)) / (yPoints - 1); } //timeOffset = (float)posData[5, 0] / 1000 - (((float)posData[5, 1] / 1000 - x1) / xSpeed); for (int actMassRange = 0; actMassRange < massRanges; actMassRange++) { /////////////////////////////////////////////////////////////////////////////////////////////////////// // format the data into a rectangular, 2 dimensional array of floats that will represent the image data // // prepare the data structure float[][] imageData = new float[xPoints][]; for (int i = 0; i < imageData.Length; i++) { imageData[i] = new float[yPoints]; } // copy the data from wiff file datastream to the rectangular array. Take account of the line offset and // the line break timings. for (int y = 0; y < yPoints; y++) { int currentPoint; // currentLine is the offset to the start of the current line in the linear datastream (rawData) int currentLine = (int)Math.Floor(lineOffset + ((x2 - x1) / xDist + lineBreak) * y); for (int x = 0; x < xPoints; x++) { if (y % 2 == 0) { // even y: scan direction: --> currentPoint = (int)(currentLine + x); } else { // odd y: scan direction: <-- currentPoint = (int)(currentLine + xPoints - 1 - x); } if (currentPoint < nrDataPoints) { imageData[x][y] = rawData[actMassRange, currentPoint]; } else { imageData[x][y] = 0; } } } lineOffset += ((double)dwellTime[actMassRange] + 5) / 1000 * xSpeed / xDist; #endif double timeSpanPos = posData[lastNonZeroTimeInPos, 0] / 1000.0 - posData[firstNonZeroTimeInPos, 0] / 1000.0; double syncTime1 = (float)posData[firstNonZeroTimeInPos, 0] / 1000; double syncTime2 = (float)posData[lastNonZeroTimeInPos, 0] / 1000; if (yPoints % 2 == 0) { // even number of scanlines lineBreak = ((syncTime2 - syncTime1) - (x2 - (float)posData[firstNonZeroTimeInPos, 1] / 1000) / xSpeed - (yPoints - 2) * (x2 - x1) / xSpeed - (x2 - (float)posData[lastNonZeroTimeInPos, 1] / 1000) / xSpeed) / (yPoints - 1); //timeOffset = (float)posData[posDataLength - 1, 0] / 1000 + (((float)posData[posDataLength - 1, 1] / 1000 - x1) / xSpeed) - (float)timeData[nrDataPoints - 1] + (float)timeData[0] - 2*xTime; //testing new method } else { // odd number of scanlines lineBreak = ((syncTime2 - syncTime1) - (x2 - (float)posData[firstNonZeroTimeInPos, 1] / 1000) / xSpeed - (yPoints - 2) * (x2 - x1) / xSpeed - ((float)posData[lastNonZeroTimeInPos, 1] / 1000 - x1) / xSpeed) / (yPoints - 1); //timeOffset = (float)posData[posDataLength - 1, 0] / 1000 + ((x2 - (float)posData[posDataLength - 1, 1] / 1000) / xSpeed) - (float)timeData[nrDataPoints - 1] + (float)timeData[0] - xTime;//testing new method } // MSt lineBreak = lineBreak / xTime; timeOffset = (float)posData[firstNonZeroTimeInPos, 0] / 1000 - (((float)posData[firstNonZeroTimeInPos, 1] / 1000 - x1) / xSpeed); // original method of calculation //MSt lineOffset = (timeData[0]-timeOffset) * xSpeed / xDist + .5; double dwellTimeSum = 0; // reset the status information AppContext.StatusInfo = ""; for (int actMassRange = 0; actMassRange < massRanges; actMassRange++) { /////////////////////////////////////////////////////////////////////////////////////////////////////// // format the data into a rectangular, 2 dimensional array of floats that will represent the image data // // prepare the data structure float[][] imageData = new float[xPoints][]; for (int i = 0; i < imageData.Length; i++) { imageData[i] = new float[yPoints]; } dwellTimeSum -= (dwellTime[actMassRange] / 1000 / 2); double optTimeOffset = timeOffset; double optLineBreak = lineBreak; if (AppContext.UseApproximation) { // Perform the optimization... HeuristicOptimization(imageData, actMassRange, (x2 - x1), dwellTimeSum, ref optLineBreak, ref optTimeOffset); } FormatImageFuzzy(imageData, actMassRange, (x2 - x1), dwellTimeSum, optLineBreak, optTimeOffset); dwellTimeSum -= (dwellTime[actMassRange] / 1000 / 2); // create the appropriate dataset and add it to the WiffFileContent object... string imgName = WiffPeriod.Sample.Name + " : " + massRangeName[actMassRange]; Document doc = WiffPeriod.Sample.WiffFileContent.Document; //create the meta information data structure and populate with relevant information... ImageMetaData metaData = new ImageMetaData(); try { metaData.Add("Sample Name", typeof(string), WiffPeriod.Sample.Name, false); metaData.Add("Mass Range", typeof(string), massRangeName[actMassRange], false); metaData.Add("X1 (mm)", typeof(string), x1.ToString(), false); metaData.Add("X2 (mm)", typeof(string), x2.ToString(), false); metaData.Add("Y1 (mm)", typeof(string), y1.ToString(), false); metaData.Add("Y2 (mm)", typeof(string), y2.ToString(), false); metaData.Add("Data Points in X", typeof(string), xPoints.ToString(), false); metaData.Add("Data Points in Y", typeof(string), yPoints.ToString(), false); metaData.Add("Point Width (mm)", typeof(string), xDist.ToString(), false); metaData.Add("Point Height (mm)", typeof(string), yDist.ToString(), false); string[] splitted = strMALDIParams.Split(sepMALDIParams, System.StringSplitOptions.None); metaData.Add("Laser Frequency (Hz)", typeof(string), splitted[1], false); metaData.Add("Laser Power (%)", typeof(string), splitted[2], false); metaData.Add("Ablation Mode", typeof(string), splitted[3], false); metaData.Add("Skimmer Voltage (V)", typeof(string), splitted[4], false); metaData.Add("Source Gas", typeof(string), splitted[5], false); metaData.Add("Raster Speed (mm/s)", typeof(string), splitted[6], false); metaData.Add("Line Distance (µm)", typeof(string), splitted[8], false); } catch (Exception e) { Util.ReportException(e); } WiffPeriod.Sample.WiffFileContent.Add(new ImageData(doc, imageData, imgName, metaData, (float)massRangeMin[actMassRange], (float)massRangeMax[actMassRange], (float)meanValues[actMassRange], (float)medianValues[actMassRange], (float)xDist, (float)yDist, (float)startMass[actMassRange], (float)stepMass[actMassRange])); } anaChrom.WiffFileName = ""; anaChrom = null; }