/*
 *  Sum up all the unmasked detector pixels.
 *
 * @param rebinnedWS: workspace where all the wavelength bins have been grouped together
 * @param sum: sum of all the unmasked detector pixels (counts)
 * @param error: error on sum (counts)
 * @param nPixels: number of unmasked detector pixels that contributed to sum
 */
void CalculateEfficiency::sumUnmaskedDetectors(MatrixWorkspace_sptr rebinnedWS,
    double& sum, double& error, int& nPixels)
{
    // Number of spectra
    const int numberOfSpectra = static_cast<int>(rebinnedWS->getNumberHistograms());
    sum = 0.0;
    error = 0.0;
    nPixels = 0;

    for (int i = 0; i < numberOfSpectra; i++)
    {
      progress(0.2+0.2*i/numberOfSpectra, "Computing sensitivity");
      // Get the detector object for this spectrum
      IDetector_const_sptr det = rebinnedWS->getDetector(i);
      // If this detector is masked, skip to the next one
      if ( det->isMasked() ) continue;
      // If this detector is a monitor, skip to the next one
      if ( det->isMonitor() ) continue;

      // Retrieve the spectrum into a vector
      const MantidVec& YValues = rebinnedWS->readY(i);
      const MantidVec& YErrors = rebinnedWS->readE(i);

      sum += YValues[0];
      error += YErrors[0]*YErrors[0];
      nPixels++;
    }

    error = std::sqrt(error);
}
/** Returns the detectors of interest, specified via processing instructions.
* Note that this returns the names of the parent detectors of the first and
* last spectrum indices in the processing instructions. It is assumed that all
* the interim detectors have the same parent.
*
* @param instructions :: processing instructions defining detectors of interest
* @param inputWS :: the input workspace
* @return :: the names of the detectors of interest
*/
std::vector<std::string> ReflectometryReductionOneAuto2::getDetectorNames(
    const std::string &instructions, MatrixWorkspace_sptr inputWS) {

  std::vector<std::string> wsIndices;
  boost::split(wsIndices, instructions, boost::is_any_of(":,-+"));
  // vector of comopnents
  std::vector<std::string> detectors;

  try {
    for (const auto &wsIndex : wsIndices) {

      size_t index = boost::lexical_cast<size_t>(wsIndex);

      auto detector = inputWS->getDetector(index);
      auto parent = detector->getParent();

      if (parent) {
        auto parentType = parent->type();
        auto detectorName = (parentType == "Instrument") ? detector->getName()
                                                         : parent->getName();
        detectors.push_back(detectorName);
      }
    }
  } catch (boost::bad_lexical_cast &) {
    throw std::runtime_error("Invalid processing instructions: " +
                             instructions);
  }

  return detectors;
}
 /** Execute the algorithm.
  */
 void WeightedMeanOfWorkspace::exec()
 {
   MatrixWorkspace_sptr inputWS = this->getProperty("InputWorkspace");
   // Check if it is an event workspace
   EventWorkspace_const_sptr eventW = boost::dynamic_pointer_cast<const EventWorkspace>(inputWS);
   if (eventW != NULL)
   {
     throw std::runtime_error("WeightedMeanOfWorkspace cannot handle EventWorkspaces!");
   }
   // Create the output workspace
   MatrixWorkspace_sptr singleValued = WorkspaceFactory::Instance().create("WorkspaceSingleValue", 1, 1, 1);
   // Calculate weighted mean
   std::size_t numHists = inputWS->getNumberHistograms();
   double averageValue = 0.0;
   double weightSum = 0.0;
   for (std::size_t i = 0; i < numHists; ++i)
   {
     try
     {
       IDetector_const_sptr det = inputWS->getDetector(i);
       if( det->isMonitor() || det->isMasked() )
       {
         continue;
       }
     }
     catch (...)
     {
       // Swallow these if no instrument is found
       ;
     }
     MantidVec y = inputWS->dataY(i);
     MantidVec e = inputWS->dataE(i);
     double weight = 0.0;
     for (std::size_t j = 0; j < y.size(); ++j)
     {
       if (!boost::math::isnan(y[j]) && !boost::math::isinf(y[j]) &&
           !boost::math::isnan(e[j]) && !boost::math::isinf(e[j]))
       {
         weight = 1.0 / (e[j] * e[j]);
         averageValue += (y[j] * weight);
         weightSum += weight;
       }
     }
   }
   singleValued->dataX(0)[0] = 0.0;
   singleValued->dataY(0)[0] = averageValue / weightSum;
   singleValued->dataE(0)[0] = std::sqrt(weightSum);
   this->setProperty("OutputWorkspace", singleValued);
 }
/**
 * Get the detector component. Use the name provided as a property as the basis
 *for the lookup as a priority.
 *
 * Throws if the name is invalid.
 * @param workspace : Workspace from instrument with detectors
 * @param isPointDetector : True if this is a point detector. Used to guess a
 *name.
 * @return The component : The component object found.
 */
boost::shared_ptr<const Mantid::Geometry::IComponent>
SpecularReflectionAlgorithm::getDetectorComponent(
    MatrixWorkspace_sptr workspace, const bool isPointDetector) const {
  boost::shared_ptr<const IComponent> searchResult;
  if (!isPropertyDefault("SpectrumNumbersOfDetectors")) {
    const std::vector<int> spectrumNumbers =
        this->getProperty("SpectrumNumbersOfDetectors");
    const bool strictSpectrumChecking =
        this->getProperty("StrictSpectrumChecking");
    checkSpectrumNumbers(spectrumNumbers, strictSpectrumChecking, g_log);
    auto specToWorkspaceIndex = workspace->getSpectrumToWorkspaceIndexMap();
    DetectorGroup_sptr allDetectors = boost::make_shared<DetectorGroup>();
    const auto &spectrumInfo = workspace->spectrumInfo();
    for (auto index : spectrumNumbers) {
      const size_t spectrumNumber{static_cast<size_t>(index)};
      auto it = specToWorkspaceIndex.find(index);
      if (it == specToWorkspaceIndex.end()) {
        std::stringstream message;
        message << "Spectrum number " << spectrumNumber
                << " does not exist in the InputWorkspace";
        throw std::invalid_argument(message.str());
      }
      const size_t workspaceIndex = it->second;
      auto detector = workspace->getDetector(workspaceIndex);
      if (spectrumInfo.isMasked(workspaceIndex))
        g_log.warning() << "Adding a detector (ID:" << detector->getID()
                        << ") that is flagged as masked.\n";
      allDetectors->addDetector(detector);
    }
    searchResult = allDetectors;
  } else {
    Mantid::Geometry::Instrument_const_sptr inst = workspace->getInstrument();
    std::string componentToCorrect =
        isPointDetector ? "point-detector" : "linedetector";

    if (!isPropertyDefault("DetectorComponentName")) {
      componentToCorrect = this->getPropertyValue("DetectorComponentName");
    }
    searchResult = inst->getComponentByName(componentToCorrect);
    if (searchResult == nullptr) {
      throw std::invalid_argument(componentToCorrect +
                                  " does not exist. Check input properties.");
    }
  }

  return searchResult;
}
Example #5
0
//calculate time from sample to detector
double ModeratorTzero::CalculateT2(MatrixWorkspace_sptr inputWS, size_t i)
{
  static const double convFact = 1.0e-6*sqrt(2*PhysicalConstants::meV/PhysicalConstants::NeutronMass);
  double t2(-1.0); // negative initialization signals error
  // Get detector position
  IDetector_const_sptr det;
  try
  {
    det = inputWS->getDetector(i);
  }
  catch (Exception::NotFoundError&)
  {
    return t2;
  }

  if( det->isMonitor() )
  {
    t2 = 0.0; //t2=0.0 since there is no sample to detector path
  }
  else
  {
    IComponent_const_sptr sample = m_instrument->getSample();
    // Get final energy E_f, final velocity v_f
    std::vector< double >  wsProp=det->getNumberParameter("Efixed");
    if ( !wsProp.empty() )
    {
      double E2 = wsProp.at(0); //[E2]=meV
      double v2 = convFact * sqrt(E2); //[v2]=meter/microsec
      try
      {
        double L2 = det->getDistance(*sample);
        t2 = L2 / v2;
      }
      catch (Exception::NotFoundError &)
      {
        g_log.error("Unable to calculate detector-sample distance");
        throw Exception::InstrumentDefinitionError("Unable to calculate detector-sample distance", inputWS->getTitle());
      }
    }
    else
    {
      g_log.debug() <<"Efixed not found for detector "<< i << std::endl;
    }
  }
  return t2;
} // end of CalculateT2(const MatrixWorkspace_sptr inputWS, size_t i)
/** Convert a workspace to Q
 *
 * @param inputWS : The input workspace (in wavelength) to convert to Q
 * @return : output workspace in Q
 */
MatrixWorkspace_sptr
ReflectometryReductionOne2::convertToQ(MatrixWorkspace_sptr inputWS) {
  bool const moreThanOneDetector = inputWS->getDetector(0)->nDets() > 1;
  bool const shouldCorrectAngle =
      !(*getProperty("ThetaIn")).isDefault() && !summingInQ();
  if (shouldCorrectAngle && moreThanOneDetector) {
    if (inputWS->getNumberHistograms() > 1) {
      throw std::invalid_argument(
          "Expected a single group in "
          "ProcessingInstructions to be able to "
          "perform angle correction, found " +
          std::to_string(inputWS->getNumberHistograms()));
    }
    MatrixWorkspace_sptr IvsQ = inputWS->clone();
    auto &XOut0 = IvsQ->mutableX(0);
    const auto &XIn0 = inputWS->x(0);
    double const theta = getProperty("ThetaIn");
    double const factor = 4.0 * M_PI * sin(theta * M_PI / 180.0);
    std::transform(XIn0.rbegin(), XIn0.rend(), XOut0.begin(),
                   [factor](double x) { return factor / x; });
    auto &Y0 = IvsQ->mutableY(0);
    auto &E0 = IvsQ->mutableE(0);
    std::reverse(Y0.begin(), Y0.end());
    std::reverse(E0.begin(), E0.end());
    IvsQ->getAxis(0)->unit() =
        UnitFactory::Instance().create("MomentumTransfer");
    return IvsQ;
  } else {
    auto convertUnits = this->createChildAlgorithm("ConvertUnits");
    convertUnits->initialize();
    convertUnits->setProperty("InputWorkspace", inputWS);
    convertUnits->setProperty("Target", "MomentumTransfer");
    convertUnits->setProperty("AlignBins", false);
    convertUnits->execute();
    MatrixWorkspace_sptr IvsQ = convertUnits->getProperty("OutputWorkspace");
    return IvsQ;
  }
}
Example #7
0
/** Execute the algorithm.
 */
void LoadNXSPE::exec() {
  std::string filename = getProperty("Filename");
  // quicly check if it's really nxspe
  try {
    ::NeXus::File file(filename);
    std::string mainEntry = (*(file.getEntries().begin())).first;
    file.openGroup(mainEntry, "NXentry");
    file.openData("definition");
    if (identiferConfidence(file.getStrData()) < 1) {
      throw std::invalid_argument("Not NXSPE");
    }
    file.close();
  } catch (...) {
    throw std::invalid_argument("Not NeXus or not NXSPE");
  }

  // Load the data
  ::NeXus::File file(filename);

  std::string mainEntry = (*(file.getEntries().begin())).first;
  file.openGroup(mainEntry, "NXentry");

  file.openGroup("NXSPE_info", "NXcollection");
  std::map<std::string, std::string> entries = file.getEntries();
  std::vector<double> temporary;
  double fixed_energy, psi = 0.;

  if (!entries.count("fixed_energy")) {
    throw std::invalid_argument("fixed_energy field was not found");
  }
  file.openData("fixed_energy");
  file.getData(temporary);
  fixed_energy = temporary.at(0);
  file.closeData();

  if (entries.count("psi")) {
    file.openData("psi");
    file.getData(temporary);
    psi = temporary.at(0);
    file.closeData();
  }

  int kikfscaling = 0;
  if (entries.count("ki_over_kf_scaling")) {
    file.openData("ki_over_kf_scaling");
    std::vector<int> temporaryint;
    file.getData(temporaryint);
    kikfscaling = temporaryint.at(0);
    file.closeData();
  }

  file.closeGroup(); // NXSPE_Info

  file.openGroup("data", "NXdata");
  entries = file.getEntries();

  if (!entries.count("data")) {
    throw std::invalid_argument("data field was not found");
  }
  file.openData("data");
  ::NeXus::Info info = file.getInfo();
  std::size_t numSpectra = static_cast<std::size_t>(info.dims.at(0));
  std::size_t numBins = static_cast<std::size_t>(info.dims.at(1));
  std::vector<double> data;
  file.getData(data);
  file.closeData();

  if (!entries.count("error")) {
    throw std::invalid_argument("error field was not found");
  }
  file.openData("error");
  std::vector<double> error;
  file.getData(error);
  file.closeData();

  if (!entries.count("energy")) {
    throw std::invalid_argument("energy field was not found");
  }
  file.openData("energy");
  std::vector<double> energies;
  file.getData(energies);
  file.closeData();

  if (!entries.count("azimuthal")) {
    throw std::invalid_argument("azimuthal field was not found");
  }
  file.openData("azimuthal");
  std::vector<double> azimuthal;
  file.getData(azimuthal);
  file.closeData();

  if (!entries.count("azimuthal_width")) {
    throw std::invalid_argument("azimuthal_width field was not found");
  }
  file.openData("azimuthal_width");
  std::vector<double> azimuthal_width;
  file.getData(azimuthal_width);
  file.closeData();

  if (!entries.count("polar")) {
    throw std::invalid_argument("polar field was not found");
  }
  file.openData("polar");
  std::vector<double> polar;
  file.getData(polar);
  file.closeData();

  if (!entries.count("polar_width")) {
    throw std::invalid_argument("polar_width field was not found");
  }
  file.openData("polar_width");
  std::vector<double> polar_width;
  file.getData(polar_width);
  file.closeData();

  // distance might not have been saved in all NXSPE files
  std::vector<double> distance;
  if (entries.count("distance")) {
    file.openData("distance");
    file.getData(distance);
    file.closeData();
  }

  file.closeGroup(); // data group
  file.closeGroup(); // Main entry
  file.close();

  // check if dimensions of the vectors are correct
  if ((error.size() != data.size()) || (azimuthal.size() != numSpectra) ||
      (azimuthal_width.size() != numSpectra) || (polar.size() != numSpectra) ||
      (polar_width.size() != numSpectra) ||
      ((energies.size() != numBins) && (energies.size() != numBins + 1))) {
    throw std::invalid_argument(
        "incompatible sizes of fields in the NXSPE file");
  }

  MatrixWorkspace_sptr outputWS = boost::dynamic_pointer_cast<MatrixWorkspace>(
      WorkspaceFactory::Instance().create("Workspace2D", numSpectra,
                                          energies.size(), numBins));
  // Need to get hold of the parameter map
  outputWS->getAxis(0)->unit() = UnitFactory::Instance().create("DeltaE");
  outputWS->setYUnit("SpectraNumber");

  // add logs
  outputWS->mutableRun().addLogData(
      new PropertyWithValue<double>("Ei", fixed_energy));
  outputWS->mutableRun().addLogData(new PropertyWithValue<double>("psi", psi));
  outputWS->mutableRun().addLogData(new PropertyWithValue<std::string>(
      "ki_over_kf_scaling", kikfscaling == 1 ? "true" : "false"));

  // Set Goniometer
  Geometry::Goniometer gm;
  gm.pushAxis("psi", 0, 1, 0, psi);
  outputWS->mutableRun().setGoniometer(gm, true);

  // generate instrument
  Geometry::Instrument_sptr instrument(new Geometry::Instrument("NXSPE"));
  outputWS->setInstrument(instrument);

  Geometry::ObjComponent *source = new Geometry::ObjComponent("source");
  source->setPos(0.0, 0.0, -10.0);
  instrument->add(source);
  instrument->markAsSource(source);
  Geometry::ObjComponent *sample = new Geometry::ObjComponent("sample");
  instrument->add(sample);
  instrument->markAsSamplePos(sample);

  Geometry::Object_const_sptr cuboid(
      createCuboid(0.1, 0.1, 0.1)); // FIXME: memory hog on rendering. Also,
                                    // make each detector separate size
  for (std::size_t i = 0; i < numSpectra; ++i) {
    double r = 1.0;
    if (!distance.empty()) {
      r = distance.at(i);
    }

    Kernel::V3D pos;
    pos.spherical(r, polar.at(i), azimuthal.at(i));

    Geometry::Detector *det =
        new Geometry::Detector("pixel", static_cast<int>(i + 1), sample);
    det->setPos(pos);
    det->setShape(cuboid);
    instrument->add(det);
    instrument->markAsDetector(det);
  }

  Geometry::ParameterMap &pmap = outputWS->instrumentParameters();
  std::vector<double>::iterator itdata = data.begin(), iterror = error.begin(),
                                itdataend, iterrorend;
  API::Progress prog = API::Progress(this, 0.0, 0.9, numSpectra);
  for (std::size_t i = 0; i < numSpectra; ++i) {
    itdataend = itdata + numBins;
    iterrorend = iterror + numBins;
    outputWS->dataX(i) = energies;
    if ((!boost::math::isfinite(*itdata)) || (*itdata <= -1e10)) // masked bin
    {
      outputWS->dataY(i) = std::vector<double>(numBins, 0);
      outputWS->dataE(i) = std::vector<double>(numBins, 0);
      pmap.addBool(outputWS->getDetector(i)->getComponentID(), "masked", true);
    } else {
      outputWS->dataY(i) = std::vector<double>(itdata, itdataend);
      outputWS->dataE(i) = std::vector<double>(iterror, iterrorend);
    }
    itdata = (itdataend);
    iterror = (iterrorend);
    prog.report();
  }

  setProperty("OutputWorkspace", outputWS);
}
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");
  }
}
/**
 * This function handles the logic for summing RebinnedOutput workspaces.
 * @param outputWorkspace the workspace to hold the summed input
 * @param progress the progress indicator
 * @param numSpectra
 * @param numMasked
 * @param numZeros
 */
void SumSpectra::doRebinnedOutput(MatrixWorkspace_sptr outputWorkspace,
                                  Progress &progress, size_t &numSpectra,
                                  size_t &numMasked, size_t &numZeros) {
  // Get a copy of the input workspace
  MatrixWorkspace_sptr temp = getProperty("InputWorkspace");

  // First, we need to clean the input workspace for nan's and inf's in order
  // to treat the data correctly later. This will create a new private
  // workspace that will be retrieved as mutable.
  IAlgorithm_sptr alg = this->createChildAlgorithm("ReplaceSpecialValues");
  alg->setProperty<MatrixWorkspace_sptr>("InputWorkspace", temp);
  std::string outName = "_" + temp->getName() + "_clean";
  alg->setProperty("OutputWorkspace", outName);
  alg->setProperty("NaNValue", 0.0);
  alg->setProperty("NaNError", 0.0);
  alg->setProperty("InfinityValue", 0.0);
  alg->setProperty("InfinityError", 0.0);
  alg->executeAsChildAlg();
  MatrixWorkspace_sptr localworkspace = alg->getProperty("OutputWorkspace");

  // Transform to real workspace types
  RebinnedOutput_sptr inWS =
      boost::dynamic_pointer_cast<RebinnedOutput>(localworkspace);
  RebinnedOutput_sptr outWS =
      boost::dynamic_pointer_cast<RebinnedOutput>(outputWorkspace);

  // Get references to the output workspaces's data vectors
  ISpectrum *outSpec = outputWorkspace->getSpectrum(0);
  MantidVec &YSum = outSpec->dataY();
  MantidVec &YError = outSpec->dataE();
  MantidVec &FracSum = outWS->dataF(0);
  MantidVec Weight;
  std::vector<size_t> nZeros;
  if (m_calculateWeightedSum) {
    Weight.assign(YSum.size(), 0);
    nZeros.assign(YSum.size(), 0);
  }
  numSpectra = 0;
  numMasked = 0;
  numZeros = 0;

  // Loop over spectra
  std::set<int>::iterator it;
  // for (int i = m_minSpec; i <= m_maxSpec; ++i)
  for (it = m_indices.begin(); it != m_indices.end(); ++it) {
    int i = *it;
    // Don't go outside the range.
    if ((i >= m_numberOfSpectra) || (i < 0)) {
      g_log.error() << "Invalid index " << i
                    << " was specified. Sum was aborted.\n";
      break;
    }

    try {
      // Get the detector object for this spectrum
      Geometry::IDetector_const_sptr det = localworkspace->getDetector(i);
      // Skip monitors, if the property is set to do so
      if (!m_keepMonitors && det->isMonitor())
        continue;
      // Skip masked detectors
      if (det->isMasked()) {
        numMasked++;
        continue;
      }
    } catch (...) {
      // if the detector not found just carry on
    }
    numSpectra++;

    // Retrieve the spectrum into a vector
    const MantidVec &YValues = localworkspace->readY(i);
    const MantidVec &YErrors = localworkspace->readE(i);
    const MantidVec &FracArea = inWS->readF(i);

    if (m_calculateWeightedSum) {
      for (int k = 0; k < this->m_yLength; ++k) {
        if (YErrors[k] != 0) {
          double errsq = YErrors[k] * YErrors[k] * FracArea[k] * FracArea[k];
          YError[k] += errsq;
          Weight[k] += 1. / errsq;
          YSum[k] += YValues[k] * FracArea[k] / errsq;
          FracSum[k] += FracArea[k];
        } else {
          nZeros[k]++;
          FracSum[k] += FracArea[k];
        }
      }
    } else {
      for (int k = 0; k < this->m_yLength; ++k) {
        YSum[k] += YValues[k] * FracArea[k];
        YError[k] += YErrors[k] * YErrors[k] * FracArea[k] * FracArea[k];
        FracSum[k] += FracArea[k];
      }
    }

    // Map all the detectors onto the spectrum of the output
    outSpec->addDetectorIDs(localworkspace->getSpectrum(i)->getDetectorIDs());

    progress.report();
  }

  if (m_calculateWeightedSum) {
    numZeros = 0;
    for (size_t i = 0; i < Weight.size(); i++) {
      if (nZeros[i] == 0)
        YSum[i] *= double(numSpectra) / Weight[i];
      else
        numZeros += nZeros[i];
    }
  }

  // Create the correct representation
  outWS->finalize();
}
void CalculateEfficiency::normalizeDetectors(MatrixWorkspace_sptr rebinnedWS,
    MatrixWorkspace_sptr outputWS, double sum, double error, int nPixels,
    double min_eff, double max_eff)
{
    // Number of spectra
    const size_t numberOfSpectra = rebinnedWS->getNumberHistograms();

    // Empty vector to store the pixels that outside the acceptable efficiency range
    std::vector<size_t> dets_to_mask;

    for (size_t i = 0; i < numberOfSpectra; i++)
    {
      const double currProgress = 0.4+0.2*((double)i/(double)numberOfSpectra);
      progress(currProgress, "Computing sensitivity");
      // Get the detector object for this spectrum
      IDetector_const_sptr det = rebinnedWS->getDetector(i);
      // If this detector is masked, skip to the next one
      if ( det->isMasked() ) continue;

      // Retrieve the spectrum into a vector
      const MantidVec& YIn = rebinnedWS->readY(i);
      const MantidVec& EIn = rebinnedWS->readE(i);
      MantidVec& YOut = outputWS->dataY(i);
      MantidVec& EOut = outputWS->dataE(i);
      // If this detector is a monitor, skip to the next one
      if ( det->isMonitor() )
      {
        YOut[0] = 1.0;
        EOut[0] = 0.0;
        continue;
      }

      // Normalize counts to get relative efficiency
      YOut[0] = nPixels/sum * YIn[0];
      const double err_sum = YIn[0]/sum*error;
      EOut[0] = nPixels/std::abs(sum) * std::sqrt(EIn[0]*EIn[0] + err_sum*err_sum);

      // Mask this detector if the signal is outside the acceptable band
      if ( !isEmpty(min_eff) && YOut[0] < min_eff ) dets_to_mask.push_back(i);
      if ( !isEmpty(max_eff) && YOut[0] > max_eff ) dets_to_mask.push_back(i);

    }

    // If we identified pixels to be masked, mask them now
    if ( !dets_to_mask.empty() )
    {
      // Mask detectors that were found to be outside the acceptable efficiency band
      try
      {
        IAlgorithm_sptr mask = createChildAlgorithm("MaskDetectors", 0.8, 0.9);
        // First we mask detectors in the output workspace
        mask->setProperty<MatrixWorkspace_sptr>("Workspace", outputWS);
        mask->setProperty< std::vector<size_t> >("WorkspaceIndexList", dets_to_mask);
        mask->execute();

        mask = createChildAlgorithm("MaskDetectors", 0.9, 1.0);
        // Then we mask the same detectors in the input workspace
        mask->setProperty<MatrixWorkspace_sptr>("Workspace", rebinnedWS);
        mask->setProperty< std::vector<size_t> >("WorkspaceIndexList", dets_to_mask);
        mask->execute();
      } catch (std::invalid_argument& err)
      {
        std::stringstream e;
        e << "Invalid argument to MaskDetectors Child Algorithm: " << err.what();
        g_log.error(e.str());
      } catch (std::runtime_error& err)
      {
        std::stringstream e;
        e << "Unable to successfully run MaskDetectors Child Algorithm: " << err.what();
        g_log.error(e.str());
      }
    }
}
Example #11
0
    /** Executes the algorithm. Reading in the file and creating and populating
     *  the output workspace
     * 
     *  @throw std::runtime_error If the instrument cannot be loaded by the LoadInstrument ChildAlgorithm
     *  @throw InstrumentDefinitionError Thrown if issues with the content of XML instrument file not covered by LoadInstrument
     *  @throw std::invalid_argument If the optional properties are set to invalid values
     */
    void LoadEmptyInstrument::exec()
    {
      // Get other properties
      const double detector_value = getProperty("DetectorValue");
      const double monitor_value = getProperty("MonitorValue");

      // load the instrument into this workspace
      MatrixWorkspace_sptr ws = this->runLoadInstrument();
      Instrument_const_sptr instrument = ws->getInstrument();

      // Get number of detectors stored in instrument
      const size_t number_spectra = instrument->getNumberDetectors();

      // Check that we have some spectra for the workspace
      if( number_spectra == 0){
            g_log.error("Instrument has no detectors, unable to create workspace for it");
            throw Kernel::Exception::InstrumentDefinitionError("No detectors found in instrument");
      }
      
      bool MakeEventWorkspace = getProperty("MakeEventWorkspace");
      
      MatrixWorkspace_sptr outWS;

      if (MakeEventWorkspace)
      {
        //Make a brand new EventWorkspace
        EventWorkspace_sptr localWorkspace = boost::dynamic_pointer_cast<EventWorkspace>(
            API::WorkspaceFactory::Instance().create("EventWorkspace", number_spectra, 2, 1));
        //Copy geometry over.
        API::WorkspaceFactory::Instance().initializeFromParent(ws, localWorkspace, true);

        // Cast to matrix WS
        outWS = boost::dynamic_pointer_cast<MatrixWorkspace>(localWorkspace);
      }
      else
      { 
        // Now create the outputworkspace and copy over the instrument object
        DataObjects::Workspace2D_sptr localWorkspace =
          boost::dynamic_pointer_cast<DataObjects::Workspace2D>(WorkspaceFactory::Instance().create(ws,number_spectra,2,1));

        outWS = boost::dynamic_pointer_cast<MatrixWorkspace>(localWorkspace);
      }

      outWS->rebuildSpectraMapping( true /* include monitors */);


      // ---- Set the values ----------
      if (!MakeEventWorkspace)
      {
        MantidVecPtr x,v,v_monitor;
        x.access().resize(2); x.access()[0]=1.0; x.access()[1]=2.0;
        v.access().resize(1); v.access()[0]=detector_value;
        v_monitor.access().resize(1); v_monitor.access()[0]=monitor_value;

        for (size_t i=0; i < outWS->getNumberHistograms(); i++)
        {
          IDetector_const_sptr det = outWS->getDetector(i);
          if ( det->isMonitor() )
            outWS->setData(i, v_monitor, v_monitor);
          else
            outWS->setData(i, v, v);
        }
      }
      // Save in output
      this->setProperty("OutputWorkspace", outWS);

    }
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
  }

}
Example #13
0
  /**
   * Execute the algorithm.
   */
  void SofQW3::exec()
  {
    MatrixWorkspace_sptr inputWS = getProperty("InputWorkspace");
    // Do the full check for common binning
    if( !WorkspaceHelpers::commonBoundaries(inputWS) )
    {
      throw std::invalid_argument("The input workspace must have common binning across all spectra");
    }

    RebinnedOutput_sptr outputWS = this->setUpOutputWorkspace(inputWS,
                                                 getProperty("QAxisBinning"),
                                                              m_Qout);
    g_log.debug() << "Workspace type: " << outputWS->id() << std::endl;
    setProperty("OutputWorkspace", outputWS);
    const size_t nEnergyBins = inputWS->blocksize();
    const size_t nHistos = inputWS->getNumberHistograms();

    // Progress reports & cancellation
    const size_t nreports(nHistos * nEnergyBins);
    m_progress = boost::shared_ptr<API::Progress>(new API::Progress(this, 0.0,
                                                                    1.0,
                                                                    nreports));

    // Compute input caches
    this->initCachedValues(inputWS);

    std::vector<double> par = inputWS->getInstrument()->getNumberParameter("detector-neighbour-offset");
    if (par.empty())
    {
      // Index theta cache
      this->initThetaCache(inputWS);
    }
    else
    {
      g_log.debug() << "Offset: " << par[0] << std::endl;
      this->m_detNeighbourOffset = static_cast<int>(par[0]);
      this->getValuesAndWidths(inputWS);
    }

    const MantidVec & X = inputWS->readX(0);

    PARALLEL_FOR2(inputWS, outputWS)
    for (int64_t i = 0; i < static_cast<int64_t>(nHistos); ++i) // signed for openmp
    {
      PARALLEL_START_INTERUPT_REGION

      DetConstPtr detector = inputWS->getDetector(i);
      if (detector->isMasked() || detector->isMonitor())
      {
        continue;
      }

      double theta = this->m_theta[i];
      double phi = 0.0;
      double thetaWidth = 0.0;
      double phiWidth = 0.0;
      // Non-PSD mode
      if (par.empty())
      {
        thetaWidth = this->m_thetaWidth;
      }
      // PSD mode
      else
      {
        phi = this->m_phi[i];
        thetaWidth = this->m_thetaWidths[i];
        phiWidth = this->m_phiWidths[i];
      }

      double thetaHalfWidth = 0.5 * thetaWidth;
      double phiHalfWidth = 0.5 * phiWidth;

      const double thetaLower = theta - thetaHalfWidth;
      const double thetaUpper = theta + thetaHalfWidth;

      const double phiLower = phi - phiHalfWidth;
      const double phiUpper = phi + phiHalfWidth;

      const double efixed = this->getEFixed(detector);

      for(size_t j = 0; j < nEnergyBins; ++j)
      {
        m_progress->report("Computing polygon intersections");
        // For each input polygon test where it intersects with
        // the output grid and assign the appropriate weights of Y/E
        const double dE_j = X[j];
        const double dE_jp1 = X[j+1];

        const V2D ll(dE_j, this->calculateQ(efixed, dE_j, thetaLower, phiLower));
        const V2D lr(dE_jp1, this->calculateQ(efixed, dE_jp1, thetaLower, phiLower));
        const V2D ur(dE_jp1, this->calculateQ(efixed, dE_jp1, thetaUpper, phiUpper));
        const V2D ul(dE_j, this->calculateQ(efixed, dE_j, thetaUpper, phiUpper));
        Quadrilateral inputQ = Quadrilateral(ll, lr, ur, ul);

        this->rebinToFractionalOutput(inputQ, inputWS, i, j, outputWS, m_Qout);
      }

      PARALLEL_END_INTERUPT_REGION
    }
    PARALLEL_CHECK_INTERUPT_REGION

    outputWS->finalize();
    this->normaliseOutput(outputWS, inputWS);
  }
/** Convert a SPICE 2D Det MatrixWorkspace to MDEvents and append to an
 * MDEventWorkspace
 * It is optional to use a virtual instrument or copy from input data workspace
 * @brief ConvertCWSDExpToMomentum::convertSpiceMatrixToMomentumMDEvents
 * @param dataws :: data matrix workspace
 * @param usevirtual :: boolean flag to use virtual instrument
 * @param startdetid :: starting detid for detectors from this workspace mapping
 * to virtual instrument in MDEventWorkspace
 * @param runnumber :: run number for all MDEvents created from this matrix
 * workspace
 */
void ConvertCWSDExpToMomentum::convertSpiceMatrixToMomentumMDEvents(
    MatrixWorkspace_sptr dataws, bool usevirtual, const detid_t &startdetid,
    const int runnumber) {
  // Create transformation matrix from which the transformation is
  Kernel::DblMatrix rotationMatrix;
  setupTransferMatrix(dataws, rotationMatrix);

  g_log.information() << "Before insert new event, output workspace has "
                      << m_outputWS->getNEvents() << "Events.\n";

  // Creates a new instance of the MDEventInserte to output workspace
  MDEventWorkspace<MDEvent<3>, 3>::sptr mdws_mdevt_3 =
      boost::dynamic_pointer_cast<MDEventWorkspace<MDEvent<3>, 3>>(m_outputWS);
  MDEventInserter<MDEventWorkspace<MDEvent<3>, 3>::sptr> inserter(mdws_mdevt_3);

  // Calcualte k_i: it is assumed that all k_i are same for one Pt.
  // number, i.e., one 2D XML file
  Kernel::V3D sourcePos = dataws->getInstrument()->getSource()->getPos();
  Kernel::V3D samplePos = dataws->getInstrument()->getSample()->getPos();
  if (dataws->readX(0).size() != 2)
    throw std::runtime_error(
        "Input matrix workspace has wrong dimension in X-axis.");
  double momentum = 0.5 * (dataws->readX(0)[0] + dataws->readX(0)[1]);
  Kernel::V3D ki = (samplePos - sourcePos) * (momentum / sourcePos.norm());

  g_log.debug() << "Source at " << sourcePos.toString()
                << ", Norm = " << sourcePos.norm()
                << ", momentum = " << momentum << "\n"
                << "k_i = " << ki.toString() << "\n";

  // Go though each spectrum to conver to MDEvent
  size_t numspec = dataws->getNumberHistograms();
  double maxsignal = 0;
  size_t nummdevents = 0;
  for (size_t iws = 0; iws < numspec; ++iws) {
    // Get detector positions and signal
    double signal = dataws->readY(iws)[0];
    // Skip event with 0 signal
    if (signal < 0.001)
      continue;
    double error = dataws->readE(iws)[0];
    Kernel::V3D detpos = dataws->getDetector(iws)->getPos();
    std::vector<Mantid::coord_t> q_sample(3);

    // Calculate Q-sample and new detector ID in virtual instrument.
    Kernel::V3D qlab = convertToQSample(samplePos, ki, detpos, momentum,
                                        q_sample, rotationMatrix);
    detid_t native_detid = dataws->getDetector(iws)->getID();
    detid_t detid = native_detid + startdetid;

    // Insert
    inserter.insertMDEvent(
        static_cast<float>(signal), static_cast<float>(error * error),
        static_cast<uint16_t>(runnumber), detid, q_sample.data());
    updateQRange(q_sample);

    g_log.debug() << "Q-lab = " << qlab.toString() << "\n";
    g_log.debug() << "Insert DetID " << detid << ", signal = " << signal
                  << ", with q_sample = " << q_sample[0] << ", " << q_sample[1]
                  << ", " << q_sample[2] << "\n";

    // Update some statistical inforamtion
    if (signal > maxsignal)
      maxsignal = signal;
    ++nummdevents;
  }

  g_log.information() << "Imported Matrixworkspace: Max. Signal = " << maxsignal
                      << ", Add " << nummdevents << " MDEvents "
                      << "\n";

  // Add experiment info including instrument, goniometer and run number
  ExperimentInfo_sptr expinfo = boost::make_shared<ExperimentInfo>();
  if (usevirtual)
    expinfo->setInstrument(m_virtualInstrument);
  else {
    Geometry::Instrument_const_sptr tmp_inst = dataws->getInstrument();
    expinfo->setInstrument(tmp_inst);
  }
  expinfo->mutableRun().setGoniometer(dataws->run().getGoniometer(), false);
  expinfo->mutableRun().addProperty("run_number", runnumber);
  // Add all the other propertys from original data workspace
  const std::vector<Kernel::Property *> vec_property =
      dataws->run().getProperties();
  for (auto property : vec_property) {
    expinfo->mutableRun().addProperty(property->clone());
  }

  m_outputWS->addExperimentInfo(expinfo);

  return;
}
/** Convert the workspace units using TOF as an intermediate step in the
* conversion
* @param fromUnit :: The unit of the input workspace
* @param inputWS :: The input workspace
* @returns A shared pointer to the output workspace
*/
MatrixWorkspace_sptr ConvertUnitsUsingDetectorTable::convertViaTOF(
    Kernel::Unit_const_sptr fromUnit, API::MatrixWorkspace_const_sptr inputWS) {
  using namespace Geometry;

  // Let's see if we are using a TableWorkspace to override parameters
  TableWorkspace_sptr paramWS = getProperty("DetectorParameters");

  // See if we have supplied a DetectorParameters Workspace
  // TODO: Check if paramWS is NULL and if so throw an exception

  //      const std::string l1ColumnLabel("l1");

  // Let's check all the columns exist and are readable
  try {
    auto spectraColumnTmp = paramWS->getColumn("spectra");
    auto l1ColumnTmp = paramWS->getColumn("l1");
    auto l2ColumnTmp = paramWS->getColumn("l2");
    auto twoThetaColumnTmp = paramWS->getColumn("twotheta");
    auto efixedColumnTmp = paramWS->getColumn("efixed");
    auto emodeColumnTmp = paramWS->getColumn("emode");
  } catch (...) {
    throw Exception::InstrumentDefinitionError(
        "DetectorParameter TableWorkspace is not defined correctly.");
  }

  // Now let's take a reference to the vectors.
  const auto &l1Column = paramWS->getColVector<double>("l1");
  const auto &l2Column = paramWS->getColVector<double>("l2");
  const auto &twoThetaColumn = paramWS->getColVector<double>("twotheta");
  const auto &efixedColumn = paramWS->getColVector<double>("efixed");
  const auto &emodeColumn = paramWS->getColVector<int>("emode");
  const auto &spectraColumn = paramWS->getColVector<int>("spectra");

  Progress prog(this, 0.2, 1.0, m_numberOfSpectra);
  int64_t numberOfSpectra_i =
      static_cast<int64_t>(m_numberOfSpectra); // cast to make openmp happy

  // Get the unit object for each workspace
  Kernel::Unit_const_sptr outputUnit = m_outputUnit;
  std::vector<double> emptyVec;
  int failedDetectorCount = 0;

  // Perform Sanity Validation before creating workspace
  size_t checkIndex = 0;
  int checkSpecNo = inputWS->getDetector(checkIndex)->getID();
  auto checkSpecIter =
      std::find(spectraColumn.begin(), spectraColumn.end(), checkSpecNo);
  if (checkSpecIter != spectraColumn.end()) {
    size_t detectorRow = std::distance(spectraColumn.begin(), checkSpecIter);
    // copy the X values for the check
    auto checkXValues = inputWS->readX(checkIndex);
    // Convert the input unit to time-of-flight
    auto checkFromUnit = std::unique_ptr<Unit>(fromUnit->clone());
    auto checkOutputUnit = std::unique_ptr<Unit>(outputUnit->clone());
    double checkdelta = 0;
    checkFromUnit->toTOF(checkXValues, emptyVec, l1Column[detectorRow],
                         l2Column[detectorRow], twoThetaColumn[detectorRow],
                         emodeColumn[detectorRow], efixedColumn[detectorRow],
                         checkdelta);
    // Convert from time-of-flight to the desired unit
    checkOutputUnit->fromTOF(checkXValues, emptyVec, l1Column[detectorRow],
                             l2Column[detectorRow], twoThetaColumn[detectorRow],
                             emodeColumn[detectorRow],
                             efixedColumn[detectorRow], checkdelta);
  }

  // create the output workspace
  MatrixWorkspace_sptr outputWS = this->setupOutputWorkspace(inputWS);
  EventWorkspace_sptr eventWS =
      boost::dynamic_pointer_cast<EventWorkspace>(outputWS);
  assert(static_cast<bool>(eventWS) == m_inputEvents); // Sanity check

  // TODO: Check why this parallel stuff breaks
  // Loop over the histograms (detector spectra)
  // PARALLEL_FOR_IF(Kernel::threadSafe(*outputWS))
  for (int64_t i = 0; i < numberOfSpectra_i; ++i) {

    // Lets find what row this spectrum Number appears in our detector table.

    // PARALLEL_START_INTERUPT_REGION

    std::size_t wsid = i;

    try {

      double deg2rad = M_PI / 180.;

      auto det = outputWS->getDetector(i);
      int specNo = det->getID();

      // int spectraNumber = static_cast<int>(spectraColumn->toDouble(i));
      // wsid = outputWS->getIndexFromSpectrumNumber(spectraNumber);
      g_log.debug() << "###### Spectra #" << specNo
                    << " ==> Workspace ID:" << wsid << '\n';

      // Now we need to find the row that contains this spectrum
      std::vector<int>::const_iterator specIter;

      specIter = std::find(spectraColumn.begin(), spectraColumn.end(), specNo);
      if (specIter != spectraColumn.end()) {
        const size_t detectorRow =
            std::distance(spectraColumn.begin(), specIter);
        const double l1 = l1Column[detectorRow];
        const double l2 = l2Column[detectorRow];
        const double twoTheta = twoThetaColumn[detectorRow] * deg2rad;
        const double efixed = efixedColumn[detectorRow];
        const int emode = emodeColumn[detectorRow];

        if (g_log.is(Logger::Priority::PRIO_DEBUG)) {
          g_log.debug() << "specNo from detector table = "
                        << spectraColumn[detectorRow] << '\n';

          g_log.debug() << "###### Spectra #" << specNo
                        << " ==> Det Table Row:" << detectorRow << '\n';

          g_log.debug() << "\tL1=" << l1 << ",L2=" << l2 << ",TT=" << twoTheta
                        << ",EF=" << efixed << ",EM=" << emode << '\n';
        }

        // Make local copies of the units. This allows running the loop in
        // parallel
        auto localFromUnit = std::unique_ptr<Unit>(fromUnit->clone());
        auto localOutputUnit = std::unique_ptr<Unit>(outputUnit->clone());
        /// @todo Don't yet consider hold-off (delta)
        const double delta = 0.0;
        std::vector<double> values(outputWS->x(wsid).begin(),
                                   outputWS->x(wsid).end());

        // Convert the input unit to time-of-flight
        localFromUnit->toTOF(values, emptyVec, l1, l2, twoTheta, emode, efixed,
                             delta);
        // Convert from time-of-flight to the desired unit
        localOutputUnit->fromTOF(values, emptyVec, l1, l2, twoTheta, emode,
                                 efixed, delta);

        outputWS->mutableX(wsid) = std::move(values);

        // EventWorkspace part, modifying the EventLists.
        if (m_inputEvents) {
          eventWS->getSpectrum(wsid)
              .convertUnitsViaTof(localFromUnit.get(), localOutputUnit.get());
        }

      } else {
        // Not found
        failedDetectorCount++;
        outputWS->maskWorkspaceIndex(wsid);
      }

    } catch (Exception::NotFoundError &) {
      // Get to here if exception thrown when calculating distance to detector
      failedDetectorCount++;
      // Since you usually (always?) get to here when there's no attached
      // detectors, this call is
      // the same as just zeroing out the data (calling clearData on the
      // spectrum)
      outputWS->maskWorkspaceIndex(i);
    }

    prog.report("Convert to " + m_outputUnit->unitID());
    // PARALLEL_END_INTERUPT_REGION
  } // loop over spectra
  // PARALLEL_CHECK_INTERUPT_REGION

  if (failedDetectorCount != 0) {
    g_log.information() << "Something went wrong for " << failedDetectorCount
                        << " spectra. Masking spectrum.\n";
  }
  if (m_inputEvents)
    eventWS->clearMRU();

  return outputWS;
}
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);
}