/// <summary> /// method to tally to detector /// </summary> /// <param name="photon">photon data needed to tally</param> public void Tally(Photon photon) { if (!IsWithinDetectorAperture(photon)) { return; } // WhichBin to match pMCROfRho which matches ROfRho var ir = DetectorBinning.WhichBin(DetectorBinning.GetRho(photon.DP.Position.X, photon.DP.Position.Y), Rho.Count - 1, Rho.Delta, Rho.Start); if (ir != -1) { double weightFactor = _absorbAction( photon.History.SubRegionInfoList.Select(c => c.NumberOfCollisions).ToList(), photon.History.SubRegionInfoList.Select(p => p.PathLength).ToList(), _perturbedOps); Mean[ir] += photon.DP.Weight * weightFactor; if (TallySecondMoment) { SecondMoment[ir] += photon.DP.Weight * weightFactor * photon.DP.Weight * weightFactor; } TallyCount++; } }
/// <summary> /// method to tally reflected photon by determining cumulative MT in each tissue subregion and binning in MT /// </summary> /// <param name="photon">Photon (includes HistoryData)</param> public void Tally(Photon photon) { if (!IsWithinDetectorAperture(photon)) { return; } // calculate the radial and time bin of reflected photon var ir = DetectorBinning.WhichBin(DetectorBinning.GetRho(photon.DP.Position.X, photon.DP.Position.Y), Rho.Count - 1, Rho.Delta, Rho.Start); for (int i = 0; i < NumSubregions; i++) { var timeInSubRegion = DetectorBinning.GetTimeDelay(photon.History.SubRegionInfoList[i].PathLength, _tissue.Regions[i].RegionOP.N); // make sure floating point round in Photon's update to S and subsequently to PathLength in SRIL doesn't get tallied if (timeInSubRegion > 1e-14) { var it = DetectorBinning.WhichBin(timeInSubRegion, Time.Count - 1, Time.Delta, Time.Start); // tally Continuous Absorption Weighting (CAW) var tally = Math.Exp(-_tissue.Regions[i].RegionOP.Mua * photon.History.SubRegionInfoList[i].PathLength); Mean[ir, i, it] += tally; if (TallySecondMoment) { SecondMoment[ir, i, it] += tally * tally; } } } TallyCount++; }
/// <summary> /// method to tally to detector /// </summary> /// <param name="photon">photon data needed to tally</param> public void Tally(Photon photon) { if (!IsWithinDetectorAperture(photon)) { return; } // ray trace exit location and direction to location at ZPlane var positionAtZPlane = LayerTissueRegionToolbox.RayExtendToInfinitePlane( photon.DP.Position, photon.DP.Direction, ZPlane); // WhichBin to match ROfRhoAndTimeDetector var ir = DetectorBinning.WhichBin(DetectorBinning.GetRho(positionAtZPlane.X, positionAtZPlane.Y), Rho.Count - 1, Rho.Delta, Rho.Start); var it = DetectorBinning.WhichBin(photon.DP.TotalTime, Time.Count - 1, Time.Delta, Time.Start); if ((ir != -1) && (it != -1)) { double weightFactor = _absorbAction( photon.History.SubRegionInfoList.Select(c => c.NumberOfCollisions).ToList(), photon.History.SubRegionInfoList.Select(p => p.PathLength).ToList(), _perturbedOps, _referenceOps, _perturbedRegionsIndices); Mean[ir, it] += photon.DP.Weight * weightFactor; if (TallySecondMoment) { SecondMoment[ir, it] += photon.DP.Weight * weightFactor * photon.DP.Weight * weightFactor; } TallyCount++; } }
/// <summary> /// method to tally to detector /// </summary> /// <param name="photon">photon data needed to tally</param> public void Tally(Photon photon) { if (!IsWithinDetectorAperture(photon)) { return; } // WhichBin to match ROfRhoAndTimeDetector var ir = DetectorBinning.WhichBin(DetectorBinning.GetRho(photon.DP.Position.X, photon.DP.Position.Y), Rho.Count - 1, Rho.Delta, Rho.Start); var it = DetectorBinning.WhichBin(photon.DP.TotalTime, Time.Count - 1, Time.Delta, Time.Start); if ((ir != -1) && (it != -1)) { double weightFactor = _absorbAction( photon.History.SubRegionInfoList.Select(c => c.NumberOfCollisions).ToList(), photon.History.SubRegionInfoList.Select(p => p.PathLength).ToList(), _perturbedOps, _referenceOps, _perturbedRegionsIndices); Mean[ir, it] += photon.DP.Weight * weightFactor; if (TallySecondMoment) { SecondMoment[ir, it] += photon.DP.Weight * weightFactor * photon.DP.Weight * weightFactor; } TallyCount++; } }
public void verify_that_GetFinalPositionAndWeight_samples_from_UnifOfRhoAndZ_sampling_correctly() { ITissueInput tissueInput = new SingleInfiniteCylinderTissueInput(); ITissue tissue = tissueInput.CreateTissue(AbsorptionWeightingType.Discrete, PhaseFunctionType.HenyeyGreenstein, 0); tissue.Regions[1] = _xyzLoaderUnif.FluorescentTissueRegion; for (int i = 0; i < 100; i++) { var photon = _fluorEmissionAOfRhoAndZSourceUnif.GetNextPhoton(tissue); // verify that photons start within range of midpoints of voxels in infinite cylinder Assert.IsTrue(photon.DP.Position.X <= 3.5); Assert.AreEqual(photon.DP.Position.Y, 0); Assert.IsTrue((photon.DP.Position.Z >= 0.5) && (photon.DP.Position.Z <= 1.5)); // verify sampling is proceeding in coded sequence // detector center=(0,0,1) radius=4, rho=[0 4] 4 bins, z=[0 2] 2 bins var ir = DetectorBinning.WhichBin(DetectorBinning.GetRho( photon.DP.Position.X, photon.DP.Position.Y), _rhozLoaderUnif.Rho.Count - 1, _rhozLoaderUnif.Rho.Delta, _rhozLoaderUnif.Rho.Start); var iz = DetectorBinning.WhichBin(photon.DP.Position.Z, _rhozLoaderUnif.Z.Count - 1, _rhozLoaderUnif.Z.Delta, _rhozLoaderUnif.Z.Start); var rhozNorm = (_rhozLoaderUnif.Rho.Start + (ir + 0.5) * _rhozLoaderUnif.Rho.Delta) * 2.0 * Math.PI * _rhozLoaderUnif.Rho.Delta * _rhozLoaderUnif.Z.Delta; // verify weight at location is equal to AOfRhoAndZ note: setup with single y bin // expected: Map [ 1 1 1 1; 1 1 1 1] row major // expected: A [ 1 3 5 7; 2 4 6 8] row major Assert.IsTrue(Math.Abs(photon.DP.Weight - _rhozLoaderUnif.AOfRhoAndZ[ir, iz] * rhozNorm) < 1e-6); } }
/// <summary> /// method to tally to detector /// </summary> /// <param name="photon">photon data needed to tally</param> public void Tally(Photon photon) { if (!IsWithinDetectorAperture(photon)) { return; } var ir = DetectorBinning.WhichBin(DetectorBinning.GetRho(photon.DP.Position.X, photon.DP.Position.Y), Rho.Count - 1, Rho.Delta, Rho.Start); var totalTime = photon.DP.TotalTime; for (int iw = 0; iw < Omega.Count; iw++) { double freq = Omega.AsEnumerable().ToArray()[iw]; Mean[ir, iw] += photon.DP.Weight * (Math.Cos(-2 * Math.PI * freq * totalTime) + Complex.ImaginaryOne * Math.Sin(-2 * Math.PI * freq * totalTime)); if (TallySecondMoment) // 2nd moment is E[xx*]=E[xreal^2]+E[ximag^2] { SecondMoment[ir, iw] += photon.DP.Weight * (Math.Cos(-2 * Math.PI * freq * totalTime)) * photon.DP.Weight * (Math.Cos(-2 * Math.PI * freq * totalTime)) + photon.DP.Weight * (Math.Sin(-2 * Math.PI * freq * totalTime)) * photon.DP.Weight * (Math.Sin(-2 * Math.PI * freq * totalTime)); } } TallyCount++; }
/// <summary> /// method to tally given two consecutive photon data points /// </summary> /// <param name="previousDP">previous data point</param> /// <param name="dp">current data point</param> /// <param name="currentRegionIndex">index of region photon current is in</param> public void TallySingle(PhotonDataPoint previousDP, PhotonDataPoint dp, int currentRegionIndex) { var totalTime = dp.TotalTime; var ir = DetectorBinning.WhichBin(DetectorBinning.GetRho(dp.Position.X, dp.Position.Y), Rho.Count - 1, Rho.Delta, Rho.Start); var iz = DetectorBinning.WhichBin(dp.Position.Z, Z.Count - 1, Z.Delta, Z.Start); var weight = _absorptionWeightingMethod(previousDP, dp, currentRegionIndex); // Note: GetVolumeAbsorptionWeightingMethod in Initialize method determines the *absorbed* weight // so for fluence this weight is divided by Mua var regionIndex = currentRegionIndex; if (weight != 0.0) { for (int iw = 0; iw < Omega.Count; iw++) { double freq = Omega.AsEnumerable().ToArray()[iw]; Mean[ir, iz, iw] += (weight / _ops[regionIndex].Mua) * (Math.Cos(-2 * Math.PI * freq * totalTime) + Complex.ImaginaryOne * Math.Sin(-2 * Math.PI * freq * totalTime)); if (TallySecondMoment) { _tallyForOnePhoton[ir, iz, iw] += (weight / _ops[regionIndex].Mua) * (Math.Cos(-2 * Math.PI * freq * totalTime) + Complex.ImaginaryOne * Math.Sin(-2 * Math.PI * freq * totalTime)); } } TallyCount++; } }
/// <summary> /// method to tally to detector /// </summary> /// <param name="photon">photon data needed to tally</param> public void Tally(Photon photon) { var ir = DetectorBinning.WhichBin(DetectorBinning.GetRho(photon.DP.Position.X, photon.DP.Position.Y), Rho.Count - 1, Rho.Delta, Rho.Start); Mean[ir] += photon.DP.Weight; if (TallySecondMoment) { SecondMoment[ir] += photon.DP.Weight * photon.DP.Weight; } TallyCount++; }
/// <summary> /// method to tally to detector /// </summary> /// <param name="photon">photon data needed to tally</param> public void Tally(Photon photon) { // if exiting tissue top surface, Uz < 0 => Acos in [pi/2, pi] var ia = DetectorBinning.WhichBin(Math.Acos(photon.DP.Direction.Uz), Angle.Count - 1, Angle.Delta, Angle.Start); var ir = DetectorBinning.WhichBin(DetectorBinning.GetRho(photon.DP.Position.X, photon.DP.Position.Y), Rho.Count - 1, Rho.Delta, Rho.Start); Mean[ir, ia] += photon.DP.Weight; if (TallySecondMoment) { SecondMoment[ir, ia] += photon.DP.Weight * photon.DP.Weight; } TallyCount++; }
/// <summary> /// method to tally to detector /// </summary> /// <param name="photon">photon data needed to tally</param> public void Tally(Photon photon) { if (!IsWithinDetectorAperture(photon)) { return; } var ir = DetectorBinning.WhichBin(DetectorBinning.GetRho(photon.DP.Position.X, photon.DP.Position.Y), Rho.Count - 1, Rho.Delta, Rho.Start); Mean[ir] += photon.DP.Weight / photon.DP.Direction.Uz; if (TallySecondMoment) { SecondMoment[ir] += (photon.DP.Weight / photon.DP.Direction.Uz) * (photon.DP.Weight / photon.DP.Direction.Uz); } TallyCount++; }
/// <summary> /// method to tally given two consecutive photon data points /// </summary> /// <param name="previousDP">previous data point</param> /// <param name="dp">current data point</param> /// <param name="currentRegionIndex">index of region photon current is in</param> public void TallySingle(PhotonDataPoint previousDP, PhotonDataPoint dp, int currentRegionIndex) { var ir = DetectorBinning.WhichBin(DetectorBinning.GetRho(dp.Position.X, dp.Position.Y), Rho.Count - 1, Rho.Delta, Rho.Start); var iz = DetectorBinning.WhichBin(dp.Position.Z, Z.Count - 1, Z.Delta, Z.Start); var weight = _absorptionWeightingMethod(previousDP, dp, currentRegionIndex); if (weight != 0.0) { Mean[ir, iz] += weight; if (TallySecondMoment) { _tallyForOnePhoton[ir, iz] += weight; } TallyCount++; } }
/// <summary> /// method to tally to detector /// </summary> /// <param name="photon">photon data needed to tally</param> public void Tally(Photon photon) { if (!IsWithinDetectorAperture(photon)) { return; } var ir = DetectorBinning.WhichBin(DetectorBinning.GetRho(photon.DP.Position.X, photon.DP.Position.Y), Rho.Count - 1, Rho.Delta, Rho.Start); var it = DetectorBinning.WhichBin(photon.DP.TotalTime, Time.Count - 1, Time.Delta, Time.Start); Mean[ir, it] += photon.DP.Weight; if (TallySecondMoment) { SecondMoment[ir, it] += photon.DP.Weight * photon.DP.Weight; } TallyCount++; }
/// <summary> /// method to tally to detector /// </summary> /// <param name="photon">photon data needed to tally</param> public void Tally(Photon photon) { if (!IsWithinDetectorAperture(photon)) { return; } var ir = DetectorBinning.WhichBin(DetectorBinning.GetRho(photon.DP.Position.X, photon.DP.Position.Y), Rho.Count - 1, Rho.Delta, Rho.Start); double maxDepth = photon.History.HistoryData.Max(d => d.Position.Z); var id = DetectorBinning.WhichBin(maxDepth, MaxDepth.Count - 1, MaxDepth.Delta, MaxDepth.Start); Mean[ir, id] += photon.DP.Weight; // mean integrated over max depth = R(rho) if (TallySecondMoment) { SecondMoment[ir, id] += photon.DP.Weight * photon.DP.Weight; } TallyCount++; }
/// <summary> /// method to tally to detector /// </summary> /// <param name="photon">photon data needed to tally</param> public void Tally(Photon photon) { var ir = DetectorBinning.WhichBin(DetectorBinning.GetRho(photon.DP.Position.X, photon.DP.Position.Y), Rho.Count - 1, Rho.Delta, Rho.Start); if (ir != -1) { double weightFactor = _absorbAction( photon.History.SubRegionInfoList.Select(c => c.NumberOfCollisions).ToList(), photon.History.SubRegionInfoList.Select(p => p.PathLength).ToList(), _perturbedOps, _referenceOps, _perturbedRegionsIndices); Mean[ir] += photon.DP.Weight * weightFactor; if (TallySecondMoment) { SecondMoment[ir] += photon.DP.Weight * weightFactor * photon.DP.Weight * weightFactor; } TallyCount++; } }
/// <summary> /// method to tally given two consecutive photon data points /// </summary> /// <param name="previousDP">previous data point</param> /// <param name="dp">current data point</param> /// <param name="currentRegionIndex">index of region photon current is in</param> public void TallySingle(PhotonDataPoint previousDP, PhotonDataPoint dp, int currentRegionIndex) { var ir = DetectorBinning.WhichBin(DetectorBinning.GetRho(dp.Position.X, dp.Position.Y), Rho.Count - 1, Rho.Delta, Rho.Start); var iz = DetectorBinning.WhichBin(dp.Position.Z, Z.Count - 1, Z.Delta, Z.Start); var weight = _absorptionWeightingMethod(previousDP, dp, currentRegionIndex); // Note: GetVolumeAbsorptionWeightingMethod in Initialize method determines the *absorbed* weight // so for fluence this weight is divided by Mua var regionIndex = currentRegionIndex; if (weight != 0.0) { Mean[ir, iz] += weight / _ops[regionIndex].Mua; if (TallySecondMoment) { _tallyForOnePhoton[ir, iz] += weight / _ops[regionIndex].Mua; } TallyCount++; } }
/// <summary> /// method to tally given two consecutive photon data points /// </summary> /// <param name="previousDP">previous data point</param> /// <param name="dp">current data point</param> /// <param name="currentRegionIndex">index of region photon current is in</param> public void TallySingle(PhotonDataPoint previousDP, PhotonDataPoint dp, int currentRegionIndex) { var ir = DetectorBinning.WhichBin(DetectorBinning.GetRho(dp.Position.X, dp.Position.Y), Rho.Count - 1, Rho.Delta, Rho.Start); var iz = DetectorBinning.WhichBin(dp.Position.Z, Z.Count - 1, Z.Delta, Z.Start); // using Acos, -1<Uz<1 goes to pi<theta<0, so first bin is most forward directed angle var ia = DetectorBinning.WhichBin(Math.Acos(dp.Direction.Uz), Angle.Count - 1, Angle.Delta, Angle.Start); var weight = _absorptionWeightingMethod(previousDP, dp, currentRegionIndex); var regionIndex = currentRegionIndex; if (weight != 0.0) { Mean[ir, iz, ia] += weight / _ops[regionIndex].Mua; if (TallySecondMoment) { _tallyForOnePhoton[ir, iz, ia] += weight / _ops[regionIndex].Mua; } TallyCount++; } }
/// <summary> /// method to tally to detector /// </summary> /// <param name="photon">photon data needed to tally</param> public void Tally(Photon photon) { if (!IsWithinDetectorAperture(photon)) { return; } // ray trace exit location and direction to location at ZPlane in air var positionAtHeight = LayerTissueRegionToolbox.RayExtendToInfinitePlane( photon.DP.Position, photon.DP.Direction, ZPlane); var ir = DetectorBinning.WhichBin(DetectorBinning.GetRho(positionAtHeight.X, positionAtHeight.Y), Rho.Count - 1, Rho.Delta, Rho.Start); double maxDepth = photon.History.HistoryData.Max(d => d.Position.Z); var id = DetectorBinning.WhichBin(maxDepth, MaxDepth.Count - 1, MaxDepth.Delta, MaxDepth.Start); Mean[ir, id] += photon.DP.Weight; // mean integrated over max depth = R(rho) if (TallySecondMoment) { SecondMoment[ir, id] += photon.DP.Weight * photon.DP.Weight; } TallyCount++; }
/// <summary> /// method to tally to detector /// </summary> /// <param name="photon">photon data needed to tally</param> public void Tally(Photon photon) { if (!IsWithinDetectorAperture(photon)) { return; } // ray trace exit location and direction to location at ZPlane var positionAtZPlane = LayerTissueRegionToolbox.RayExtendToInfinitePlane( photon.DP.Position, photon.DP.Direction, ZPlane); var ir = DetectorBinning.WhichBin( DetectorBinning.GetRho(positionAtZPlane.X, positionAtZPlane.Y), Rho.Count - 1, Rho.Delta, Rho.Start); Mean[ir] += photon.DP.Weight; if (TallySecondMoment) { SecondMoment[ir] += photon.DP.Weight * photon.DP.Weight; } TallyCount++; }
/// <summary> /// method to tally to detector /// </summary> /// <param name="photon">photon data needed to tally</param> public void Tally(Photon photon) { // calculate the radial bin to attribute the deposition var irho = DetectorBinning.WhichBin(DetectorBinning.GetRho(photon.DP.Position.X, photon.DP.Position.Y), Rho.Count - 1, Rho.Delta, Rho.Start); var subregionMT = new double[NumSubregions]; bool talliedMT = false; // go through photon history and claculate momentum transfer // assumes that no MT tallied at pseudo-collisions (reflections and refractions) // this algorithm needs to look ahead to angle of next DP, but needs info from previous to determine whether real or pseudo-collision PhotonDataPoint previousDP = photon.History.HistoryData.First(); PhotonDataPoint currentDP = photon.History.HistoryData.Skip(1).Take(1).First(); foreach (PhotonDataPoint nextDP in photon.History.HistoryData.Skip(2)) { if (previousDP.Weight != currentDP.Weight) // only for true collision points { var csr = _tissue.GetRegionIndex(currentDP.Position); // get current region index // get angle between current and next double cosineBetweenTrajectories = Direction.GetDotProduct(currentDP.Direction, nextDP.Direction); var momentumTransfer = 1 - cosineBetweenTrajectories; subregionMT[csr] += momentumTransfer; talliedMT = true; } previousDP = currentDP; currentDP = nextDP; } // tally total MT double totalMT = subregionMT.Sum(); if (totalMT > 0.0) // only tally if momentum transfer accumulated { var imt = DetectorBinning.WhichBin(totalMT, MTBins.Count - 1, MTBins.Delta, MTBins.Start); Mean[irho, imt] += photon.DP.Weight; if (TallySecondMoment) { SecondMoment[irho, imt] += photon.DP.Weight * photon.DP.Weight; } if (talliedMT) { TallyCount++; } // tally fractional MT in each subregion int ifrac; for (int isr = 0; isr < NumSubregions; isr++) { // add 1 to ifrac to offset bin 0 added for =0 only tallies ifrac = DetectorBinning.WhichBin(subregionMT[isr] / totalMT, FractionalMTBins.Count - 1, FractionalMTBins.Delta, FractionalMTBins.Start) + 1; // put identically 0 fractional MT into separate bin at index 0 if (subregionMT[isr] / totalMT == 0.0) { ifrac = 0; } // put identically 1 fractional MT into separate bin at index Count+1 -1 if (subregionMT[isr] / totalMT == 1.0) { ifrac = FractionalMTBins.Count; } FractionalMT[irho, imt, isr, ifrac] += photon.DP.Weight; } } }
/// <summary> /// method to tally to detector /// </summary> /// <param name="photon">photon data needed to tally</param> public void Tally(Photon photon) { // calculate the radial bin to attribute the deposition var irho = DetectorBinning.WhichBin(DetectorBinning.GetRho(photon.DP.Position.X, photon.DP.Position.Y), Rho.Count - 1, Rho.Delta, Rho.Start); var tissueMT = new double[2]; // 2 is for [static, dynamic] tally separation bool talliedMT = false; double totalMT = 0; var totalMTOfZForOnePhoton = new double[Rho.Count - 1, Z.Count - 1]; var dynamicMTOfZForOnePhoton = new double[Rho.Count - 1, Z.Count - 1]; // go through photon history and claculate momentum transfer // assumes that no MT tallied at pseudo-collisions (reflections and refractions) // this algorithm needs to look ahead to angle of next DP, but needs info from previous to determine whether real or pseudo-collision PhotonDataPoint previousDP = photon.History.HistoryData.First(); PhotonDataPoint currentDP = photon.History.HistoryData.Skip(1).Take(1).First(); foreach (PhotonDataPoint nextDP in photon.History.HistoryData.Skip(2)) { if (previousDP.Weight != currentDP.Weight) // only for true collision points { var csr = _tissue.GetRegionIndex(currentDP.Position); // get current region index // get z bin of current position var iz = DetectorBinning.WhichBin(currentDP.Position.Z, Z.Count - 1, Z.Delta, Z.Start); // get angle between current and next double cosineBetweenTrajectories = Direction.GetDotProduct(currentDP.Direction, nextDP.Direction); var momentumTransfer = 1 - cosineBetweenTrajectories; totalMT += momentumTransfer; TotalMTOfZ[irho, iz] += photon.DP.Weight * momentumTransfer; totalMTOfZForOnePhoton[irho, iz] += photon.DP.Weight * momentumTransfer; if (_rng.NextDouble() < _bloodVolumeFraction[csr]) // hit blood { tissueMT[1] += momentumTransfer; DynamicMTOfZ[irho, iz] += photon.DP.Weight * momentumTransfer; dynamicMTOfZForOnePhoton[irho, iz] += photon.DP.Weight * momentumTransfer; SubregionCollisions[csr, 1] += 1; // add to dynamic collision count } else // index 0 captures static events { tissueMT[0] += momentumTransfer; SubregionCollisions[csr, 0] += 1; // add to static collision count } talliedMT = true; } previousDP = currentDP; currentDP = nextDP; } if (totalMT > 0.0) // only tally if momentum transfer accumulated { var imt = DetectorBinning.WhichBin(totalMT, MTBins.Count - 1, MTBins.Delta, MTBins.Start); Mean[irho, imt] += photon.DP.Weight; if (TallySecondMoment) { SecondMoment[irho, imt] += photon.DP.Weight * photon.DP.Weight; for (int i = 0; i < Rho.Count - 1; i++) { for (int j = 0; j < Z.Count - 1; j++) { TotalMTOfZSecondMoment[i, j] += totalMTOfZForOnePhoton[i, j] * totalMTOfZForOnePhoton[i, j]; DynamicMTOfZSecondMoment[i, j] += dynamicMTOfZForOnePhoton[i, j] * dynamicMTOfZForOnePhoton[i, j]; } } } if (talliedMT) { TallyCount++; } // tally DYNAMIC fractional MT in each subregion int ifrac; for (int isr = 0; isr < NumSubregions; isr++) { // add 1 to ifrac to offset bin 0 added for =0 only tallies ifrac = DetectorBinning.WhichBin(tissueMT[1] / totalMT, FractionalMTBins.Count - 1, FractionalMTBins.Delta, FractionalMTBins.Start) + 1; // put identically 0 fractional MT into separate bin at index 0 if (tissueMT[1] / totalMT == 0.0) { ifrac = 0; } // put identically 1 fractional MT into separate bin at index Count+1 -1 if (tissueMT[1] / totalMT == 1.0) { ifrac = FractionalMTBins.Count; } FractionalMT[irho, imt, ifrac] += photon.DP.Weight; } } }