void TOFSANSResolutionByPixel::exec()
{
  MatrixWorkspace_sptr inOutWS = getProperty("InputWorkspace");
  double deltaR = getProperty("DeltaR");
  double R1 = getProperty("SourceApertureRadius");
  double R2 = getProperty("SampleApertureRadius");
  // Convert to meters
  deltaR /= 1000.0;
  R1 /= 1000.0;
  R2 /= 1000.0;
  const double sigmaModeratorMicroSec = getProperty("SigmaModerator");

  const V3D samplePos = inOutWS->getInstrument()->getSample()->getPos();
  const V3D sourcePos = inOutWS->getInstrument()->getSource()->getPos();
  const V3D SSD = samplePos - sourcePos;
  const double L1 = SSD.norm();

  const int numberOfSpectra = static_cast<int>(inOutWS->getNumberHistograms());
  Progress progress(this,0.0,1.0,numberOfSpectra);

  //PARALLEL_FOR1(inOutWS)
  for (int i = 0; i < numberOfSpectra; i++)
  {
    //PARALLEL_START_INTERUPT_REGION
    IDetector_const_sptr det;
    try {
      det = inOutWS->getDetector(i);
    } catch (Exception::NotFoundError&) {
      g_log.information() << "Spectrum index " << i << " has no detector assigned to it - discarding" << std::endl;
      // Catch if no detector. Next line tests whether this happened - test placed
      // outside here because Mac Intel compiler doesn't like 'continue' in a catch
      // in an openmp block.
    }
    // If no detector found or if it's masked or a monitor, skip onto the next spectrum
    if ( !det || det->isMonitor() || det->isMasked() ) continue;

    // Get the flight path from the sample to the detector pixel
    const V3D scatteredFlightPathV3D = det->getPos() - samplePos; 

    const double L2 = scatteredFlightPathV3D.norm();
    const double Lsum = L1+L2;

    // calculate part that is wavelenght independent
    const double dTheta2 = (4.0 * M_PI * M_PI / 12.0) * 
      ( 3.0*R1*R1/(L1*L1) + 3.0*R2*R2*Lsum*Lsum/(L1*L1*L2*L2) + (deltaR*deltaR)/(L2*L2) );

    // Multiplicative factor to go from lambda to Q
    // Don't get fooled by the function name...
    const double theta = inOutWS->detectorTwoTheta(det);
    const double factor = 4.0 * M_PI * sin( theta/2.0 );

    const MantidVec& xIn = inOutWS->readX(i);
    MantidVec& yIn = inOutWS->dataY(i);
    const size_t xLength = xIn.size();

    for ( size_t j = 0; j < xLength-1; j++)
    {
      // Calculate q. Alternatively q could be calculated using ConvertUnit
      const double wl = (xIn[j+1]+xIn[j])/2.0;
      const double q = factor/wl;

      // calculate wavelenght resolution from moderator and histogram time bin width and
      // convert to from unit of micro-seconds to Aangstrom
      const double sigmaLambda = sigmaModeratorMicroSec*3.9560/(1000.0*Lsum);

      // calculate sigmaQ for a given lambda and pixel
      const double sigmaOverLambdaTimesQ = q*sigmaLambda/wl;
      const double sigmaQ = std::sqrt(dTheta2/(wl*wl)+sigmaOverLambdaTimesQ*sigmaOverLambdaTimesQ);

      // update inout workspace with this sigmaQ
      yIn[j] = sigmaQ;
    }

    progress.report("Computing Q resolution");
    //PARALLEL_END_INTERUPT_REGION
  }

}
void TOFSANSResolutionByPixel::exec() {
  MatrixWorkspace_sptr inOutWS = getProperty("Workspace");
  double deltaR = getProperty("DeltaR");
  double R1 = getProperty("SourceApertureRadius");
  double R2 = getProperty("SampleApertureRadius");
  // Convert to meters
  deltaR /= 1000.0;
  R1 /= 1000.0;
  R2 /= 1000.0;

  const MatrixWorkspace_sptr sigmaModeratorVSwavelength =
      getProperty("SigmaModerator");

  // create interpolation table from sigmaModeratorVSwavelength
  Kernel::Interpolation lookUpTable;

  const MantidVec xInterpolate = sigmaModeratorVSwavelength->readX(0);
  const MantidVec yInterpolate = sigmaModeratorVSwavelength->readY(0);

  // prefer the input to be a pointworkspace and create interpolation function
  if (sigmaModeratorVSwavelength->isHistogramData()) {
    g_log.notice() << "mid-points of SigmaModerator histogram bins will be "
                      "used for interpolation.";

    for (size_t i = 0; i < xInterpolate.size() - 1; ++i) {
      const double midpoint = xInterpolate[i + 1] - xInterpolate[i];
      lookUpTable.addPoint(midpoint, yInterpolate[i]);
    }
  } else {
    for (size_t i = 0; i < xInterpolate.size(); ++i) {
      lookUpTable.addPoint(xInterpolate[i], yInterpolate[i]);
    }
  }

  const V3D samplePos = inOutWS->getInstrument()->getSample()->getPos();
  const V3D sourcePos = inOutWS->getInstrument()->getSource()->getPos();
  const V3D SSD = samplePos - sourcePos;
  const double L1 = SSD.norm();

  const int numberOfSpectra = static_cast<int>(inOutWS->getNumberHistograms());
  Progress progress(this, 0.0, 1.0, numberOfSpectra);

  for (int i = 0; i < numberOfSpectra; i++) {
    IDetector_const_sptr det;
    try {
      det = inOutWS->getDetector(i);
    } catch (Exception::NotFoundError &) {
      g_log.information() << "Spectrum index " << i
                          << " has no detector assigned to it - discarding"
                          << std::endl;
    }
    // If no detector found or if it's masked or a monitor, skip onto the next
    // spectrum
    if (!det || det->isMonitor() || det->isMasked())
      continue;

    // Get the flight path from the sample to the detector pixel
    const V3D scatteredFlightPathV3D = det->getPos() - samplePos;

    const double L2 = scatteredFlightPathV3D.norm();
    const double Lsum = L1 + L2;

    // calculate part that is wavelenght independent
    const double dTheta2 = (4.0 * M_PI * M_PI / 12.0) *
                           (3.0 * R1 * R1 / (L1 * L1) +
                            3.0 * R2 * R2 * Lsum * Lsum / (L1 * L1 * L2 * L2) +
                            (deltaR * deltaR) / (L2 * L2));

    // Multiplicative factor to go from lambda to Q
    // Don't get fooled by the function name...
    const double theta = inOutWS->detectorTwoTheta(det);
    const double factor = 4.0 * M_PI * sin(theta / 2.0);

    const MantidVec &xIn = inOutWS->readX(i);
    MantidVec &yIn = inOutWS->dataY(i);
    const size_t xLength = xIn.size();

    // for each wavelenght bin of each pixel calculate a q-resolution
    for (size_t j = 0; j < xLength - 1; j++) {
      // use the midpoint of each bin
      const double wl = (xIn[j + 1] + xIn[j]) / 2.0;
      // Calculate q. Alternatively q could be calculated using ConvertUnit
      const double q = factor / wl;

      // wavelenght spread from bin assumed to be
      const double sigmaSpreadFromBin = xIn[j + 1] - xIn[j];

      // wavelenght spread from moderatorm, converted from microseconds to
      // wavelengths
      const double sigmaModerator =
          lookUpTable.value(wl) * 3.9560 / (1000.0 * Lsum);

      // calculate wavelenght resolution from moderator and histogram time bin
      const double sigmaLambda =
          std::sqrt(sigmaSpreadFromBin * sigmaSpreadFromBin / 12.0 +
                    sigmaModerator * sigmaModerator);

      // calculate sigmaQ for a given lambda and pixel
      const double sigmaOverLambdaTimesQ = q * sigmaLambda / wl;
      const double sigmaQ = std::sqrt(
          dTheta2 / (wl * wl) + sigmaOverLambdaTimesQ * sigmaOverLambdaTimesQ);

      // update inout workspace with this sigmaQ
      yIn[j] = sigmaQ;
    }

    progress.report("Computing Q resolution");
  }
}
void TOFSANSResolutionByPixel::exec() {
  MatrixWorkspace_sptr inWS = getProperty("InputWorkspace");
  double deltaR = getProperty("DeltaR");
  double R1 = getProperty("SourceApertureRadius");
  double R2 = getProperty("SampleApertureRadius");
  const bool doGravity = getProperty("AccountForGravity");

  // Check the input
  checkInput(inWS);

  // Setup outputworkspace
  auto outWS = setupOutputWorkspace(inWS);

  // Convert to meters
  deltaR /= 1000.0;
  R1 /= 1000.0;
  R2 /= 1000.0;

  // The moderator workspace needs to match the data workspace
  // in terms of wavelength binning
  const MatrixWorkspace_sptr sigmaModeratorVSwavelength =
      getModeratorWorkspace(inWS);

  // create interpolation table from sigmaModeratorVSwavelength
  Kernel::Interpolation lookUpTable;

  const MantidVec xInterpolate = sigmaModeratorVSwavelength->readX(0);
  const MantidVec yInterpolate = sigmaModeratorVSwavelength->readY(0);

  // prefer the input to be a pointworkspace and create interpolation function
  if (sigmaModeratorVSwavelength->isHistogramData()) {
    g_log.notice() << "mid-points of SigmaModerator histogram bins will be "
                      "used for interpolation.";

    for (size_t i = 0; i < xInterpolate.size() - 1; ++i) {
      const double midpoint = (xInterpolate[i + 1] + xInterpolate[i]) / 2.0;
      lookUpTable.addPoint(midpoint, yInterpolate[i]);
    }
  } else {
    for (size_t i = 0; i < xInterpolate.size(); ++i) {
      lookUpTable.addPoint(xInterpolate[i], yInterpolate[i]);
    }
  }

  // Calculate the L1 distance
  const V3D samplePos = inWS->getInstrument()->getSample()->getPos();
  const V3D sourcePos = inWS->getInstrument()->getSource()->getPos();
  const V3D SSD = samplePos - sourcePos;
  const double L1 = SSD.norm();

  // Get the collimation length
  double LCollim = getProperty("CollimationLength");

  if (LCollim == 0.0) {
    auto collimationLengthEstimator = SANSCollimationLengthEstimator();
    LCollim = collimationLengthEstimator.provideCollimationLength(inWS);
    g_log.information() << "No collimation length was specified. A default "
                           "collimation length was estimated to be " << LCollim
                        << std::endl;
  } else {
    g_log.information() << "The collimation length is  " << LCollim
                        << std::endl;
  }

  const int numberOfSpectra = static_cast<int>(inWS->getNumberHistograms());
  Progress progress(this, 0.0, 1.0, numberOfSpectra);

  for (int i = 0; i < numberOfSpectra; i++) {
    IDetector_const_sptr det;
    try {
      det = inWS->getDetector(i);
    } catch (Exception::NotFoundError &) {
      g_log.information() << "Spectrum index " << i
                          << " has no detector assigned to it - discarding"
                          << std::endl;
    }
    // If no detector found or if it's masked or a monitor, skip onto the next
    // spectrum
    if (!det || det->isMonitor() || det->isMasked())
      continue;

    // Get the flight path from the sample to the detector pixel
    const V3D samplePos = inWS->getInstrument()->getSample()->getPos();
    const V3D scatteredFlightPathV3D = det->getPos() - samplePos;
    const double L2 = scatteredFlightPathV3D.norm();

    TOFSANSResolutionByPixelCalculator calculator;
    const double waveLengthIndependentFactor =
        calculator.getWavelengthIndependentFactor(R1, R2, deltaR, LCollim, L2);

    // Multiplicative factor to go from lambda to Q
    // Don't get fooled by the function name...
    const double theta = inWS->detectorTwoTheta(det);
    double sinTheta = sin(theta / 2.0);
    double factor = 4.0 * M_PI * sinTheta;

    const MantidVec &xIn = inWS->readX(i);
    const size_t xLength = xIn.size();

    // Gravity correction
    boost::shared_ptr<GravitySANSHelper> grav;
    if (doGravity) {
      grav = boost::make_shared<GravitySANSHelper>(inWS, det,
                                                   getProperty("ExtraLength"));
    }

    // Get handles on the outputWorkspace
    MantidVec &yOut = outWS->dataY(i);
    // for each wavelenght bin of each pixel calculate a q-resolution
    for (size_t j = 0; j < xLength - 1; j++) {
      // use the midpoint of each bin
      const double wl = (xIn[j + 1] + xIn[j]) / 2.0;
      // Calculate q. Alternatively q could be calculated using ConvertUnit
      // If we include a gravity correction we need to adjust sinTheta
      // for each wavelength (in Angstrom)
      if (doGravity) {
        double sinThetaGrav = grav->calcSinTheta(wl);
        factor = 4.0 * M_PI * sinThetaGrav;
      }
      const double q = factor / wl;

      // wavelenght spread from bin assumed to be
      const double sigmaSpreadFromBin = xIn[j + 1] - xIn[j];

      // Get the uncertainty in Q
      auto sigmaQ = calculator.getSigmaQValue(lookUpTable.value(wl),
                                              waveLengthIndependentFactor, q,
                                              wl, sigmaSpreadFromBin, L1, L2);

      // Insert the Q value and the Q resolution into the outputworkspace
      yOut[j] = sigmaQ;
    }
    progress.report("Computing Q resolution");
  }

  // Set the y axis label
  outWS->setYUnitLabel("QResolution");

  setProperty("OutputWorkspace", outWS);
}