예제 #1
0
/** Validates input properties.
 *  @return A map of input properties as keys and (error) messages as values.
 */
std::map<std::string, std::string> NormaliseToMonitor::validateInputs() {
  std::map<std::string, std::string> issues;
  // Check where the monitor spectrum should come from
  const Property *monSpecProp = getProperty("MonitorSpectrum");
  const Property *monIDProp = getProperty("MonitorID");
  MatrixWorkspace_const_sptr monWS = getProperty("MonitorWorkspace");
  // something has to be set
  if (monSpecProp->isDefault() && !monWS && monIDProp->isDefault()) {
    const std::string mess("Either MonitorSpectrum, MonitorID or "
                           "MonitorWorkspace has to be provided.");
    issues["MonitorSpectrum"] = mess;
    issues["MonitorID"] = mess;
    issues["MonitorWorkspace"] = mess;
  }

  const double intMin = getProperty("IntegrationRangeMin");
  const double intMax = getProperty("IntegrationRangeMax");
  if (!isEmpty(intMin) && !isEmpty(intMax)) {
    if (intMin > intMax) {
      issues["IntegrationRangeMin"] =
          "Range minimum set to a larger value than maximum.";
      issues["IntegrationRangeMax"] =
          "Range maximum set to a smaller value than minimum.";
    }
  }

  if (monWS && monSpecProp->isDefault()) {
    const int monIndex = getProperty("MonitorWorkspaceIndex");
    if (monIndex < 0) {
      issues["MonitorWorkspaceIndex"] = "A workspace index cannot be negative.";
    } else if (monWS->getNumberHistograms() <= static_cast<size_t>(monIndex)) {
      issues["MonitorWorkspaceIndex"] =
          "The MonitorWorkspace must contain the MonitorWorkspaceIndex.";
    }
    MatrixWorkspace_const_sptr inWS = getProperty("InputWorkspace");
    if (monWS->getInstrument()->getName() != inWS->getInstrument()->getName()) {
      issues["MonitorWorkspace"] = "The Input and Monitor workspaces must come "
                                   "from the same instrument.";
    }
    if (monWS->getAxis(0)->unit()->unitID() !=
        inWS->getAxis(0)->unit()->unitID()) {
      issues["MonitorWorkspace"] =
          "The Input and Monitor workspaces must have the same unit";
    }
  }

  return issues;
}
  /**
   * Set default background and rebinning properties for a given instument
   * and analyser
   *
   * @param ws :: Mantid workspace containing the loaded instument
   */
  void ISISCalibration::calSetDefaultResolution(MatrixWorkspace_const_sptr ws)
  {
    auto inst = ws->getInstrument();
    auto analyser = inst->getStringParameter("analyser");

    if(analyser.size() > 0)
    {
      auto comp = inst->getComponentByName(analyser[0]);

      if(!comp)
        return;

      auto params = comp->getNumberParameter("resolution", true);

      //Set the default instrument resolution
      if(params.size() > 0)
      {
        double res = params[0];

        // Set default rebinning bounds
        QPair<double, double> peakRange(-res*10, res*10);
        auto resPeak = m_uiForm.ppResolution->getRangeSelector("ResPeak");
        setRangeSelector(resPeak, m_properties["ResELow"], m_properties["ResEHigh"], peakRange);

        // Set default background bounds
        QPair<double, double> backgroundRange(-res*9, -res*8);
        auto resBackground = m_uiForm.ppResolution->getRangeSelector("ResBackground");
        setRangeSelector(resBackground, m_properties["ResStart"], m_properties["ResEnd"], backgroundRange);
      }
    }
  }
예제 #3
0
void ALCDataLoadingPresenter::updateAvailableInfo() {
  Workspace_sptr loadedWs;
  double firstGoodData = 0, timeZero = 0;

  try //... to load the first run
  {
    IAlgorithm_sptr load = AlgorithmManager::Instance().create("LoadMuonNexus");
    load->setChild(true); // Don't want workspaces in the ADS
    load->setProperty("Filename", m_view->firstRun());
    // We need logs only but we have to use LoadMuonNexus
    // (can't use LoadMuonLogs as not all the logs would be
    // loaded), so we load the minimum amount of data, i.e., one spectrum
    load->setPropertyValue("SpectrumMin", "1");
    load->setPropertyValue("SpectrumMax", "1");
    load->setPropertyValue("OutputWorkspace", "__NotUsed");
    load->execute();

    loadedWs = load->getProperty("OutputWorkspace");
    firstGoodData = load->getProperty("FirstGoodData");
    timeZero = load->getProperty("TimeZero");
  } catch (...) {
    m_view->setAvailableLogs(std::vector<std::string>()); // Empty logs list
    m_view->setAvailablePeriods(
        std::vector<std::string>()); // Empty period list
    m_view->setTimeLimits(0, 0);     // "Empty" time limits
    return;
  }

  // Set logs
  MatrixWorkspace_const_sptr ws = MuonAnalysisHelper::firstPeriod(loadedWs);
  std::vector<std::string> logs;

  const auto &properties = ws->run().getProperties();
  for (auto it = properties.begin(); it != properties.end(); ++it) {
    logs.push_back((*it)->name());
  }
  m_view->setAvailableLogs(logs);

  // Set periods
  size_t numPeriods = MuonAnalysisHelper::numPeriods(loadedWs);
  std::vector<std::string> periods;
  for (size_t i = 0; i < numPeriods; i++) {
    std::stringstream buffer;
    buffer << i + 1;
    periods.push_back(buffer.str());
  }
  m_view->setAvailablePeriods(periods);

  // Set time limits if this is the first data loaded (will both be zero)
  if (auto timeLimits = m_view->timeRange()) {
    if (std::abs(timeLimits->first) < 0.0001 &&
        std::abs(timeLimits->second) < 0.0001) {
      m_view->setTimeLimits(firstGoodData - timeZero, ws->readX(0).back());
    }
  }

  // Update number of detectors for this new first run
  m_numDetectors = ws->getInstrument()->getNumberDetectors();
}
예제 #4
0
/** Initialise a workspace from its parent
 * This sets values such as title, instrument, units, sample, spectramap.
 * This does NOT copy any data.
 *
 * @param parent :: the parent workspace
 * @param child :: the child workspace
 * @param differentSize :: A flag to indicate if the two workspace will be different sizes
 */
void WorkspaceFactoryImpl::initializeFromParent(const MatrixWorkspace_const_sptr parent,
  const MatrixWorkspace_sptr child, const bool differentSize) const
{
  child->setTitle(parent->getTitle());
  child->setComment(parent->getComment());
  child->setInstrument(parent->getInstrument());  // This call also copies the SHARED POINTER to the parameter map
  // This call will (should) perform a COPY of the parameter map.
  child->instrumentParameters();
  child->m_sample = parent->m_sample;
  child->m_run = parent->m_run;
  child->setYUnit(parent->m_YUnit);
  child->setYUnitLabel(parent->m_YUnitLabel);
  child->isDistribution(parent->isDistribution());

  // Only copy the axes over if new sizes are not given
  if ( !differentSize )
  {
    // Only copy mask map if same size for now. Later will need to check continued validity.
    child->m_masks = parent->m_masks;
  }

  // Same number of histograms = copy over the spectra data
  if (parent->getNumberHistograms() == child->getNumberHistograms())
  {
    for (size_t wi=0; wi<parent->getNumberHistograms(); wi++)
    {
      ISpectrum * childSpec = child->getSpectrum(wi);
      const ISpectrum * parentSpec = parent->getSpectrum(wi);
      // Copy spectrum number and detector IDs
      childSpec->copyInfoFrom(*parentSpec);
    }
  }

  // deal with axis
  for (size_t i = 0; i < parent->m_axes.size(); ++i)
  {
    const size_t newAxisLength = child->getAxis(i)->length();
    const size_t oldAxisLength = parent->getAxis(i)->length();

    if ( !differentSize || newAxisLength == oldAxisLength )
    {
      // Need to delete the existing axis created in init above
      delete child->m_axes[i];
      // Now set to a copy of the parent workspace's axis
      child->m_axes[i] = parent->m_axes[i]->clone(child.get());
    }
    else
    {
      if (! parent->getAxis(i)->isSpectra()) // WHY???
      {
        delete child->m_axes[i];
        // Call the 'different length' clone variant
        child->m_axes[i] = parent->m_axes[i]->clone(newAxisLength,child.get());
      }
    }
  }

  return;
}
예제 #5
0
// read the monitors list from the workspace and try to do it once for any
// particular ws;
bool MonIDPropChanger::monitorIdReader(
    MatrixWorkspace_const_sptr inputWS) const {
  // no workspace
  if (!inputWS)
    return false;

  // no instrument
  Geometry::Instrument_const_sptr pInstr = inputWS->getInstrument();
  if (!pInstr)
    return false;

  // are these monitors really there?
  std::vector<detid_t> monitorIDList = pInstr->getMonitors();
  {
    const auto &specInfo = inputWS->spectrumInfo();
    std::set<detid_t> idsInWorkspace;
    size_t i = 0;
    // Loop over spectra, but finish early if we find everything
    while (i < specInfo.size() &&
           idsInWorkspace.size() < monitorIDList.size()) {
      if (specInfo.isMonitor(i))
        idsInWorkspace.insert(specInfo.detector(i).getID());
      ++i;
    }
    monitorIDList =
        std::vector<detid_t>(idsInWorkspace.begin(), idsInWorkspace.end());
  }

  if (monitorIDList.empty()) {
    if (iExistingAllowedValues.empty()) {
      return false;
    } else {
      iExistingAllowedValues.clear();
      return true;
    }
  }

  // are known values the same as the values we have just identified?
  if (iExistingAllowedValues.size() != monitorIDList.size()) {
    iExistingAllowedValues.clear();
    iExistingAllowedValues.assign(monitorIDList.begin(), monitorIDList.end());
    return true;
  }
  // the monitor list has the same size as before. Is it equivalent to the
  // existing one?
  bool values_redefined = false;
  for (size_t i = 0; i < monitorIDList.size(); i++) {
    if (iExistingAllowedValues[i] != monitorIDList[i]) {
      values_redefined = true;
      iExistingAllowedValues[i] = monitorIDList[i];
    }
  }
  return values_redefined;
}
예제 #6
0
double
ConvertSpectrumAxis::getEfixed(const Mantid::Geometry::IDetector &detector,
                               MatrixWorkspace_const_sptr inputWS,
                               int emode) const {
  double efixed(0);
  double efixedProp = getProperty("Efixed");
  if (efixedProp != EMPTY_DBL()) {
    efixed = efixedProp;
    g_log.debug() << "Detector: " << detector.getID() << " Efixed: " << efixed
                  << "\n";
  } else {
    if (emode == 1) {
      if (inputWS->run().hasProperty("Ei")) {
        Kernel::Property *p = inputWS->run().getProperty("Ei");
        Kernel::PropertyWithValue<double> *doublep =
            dynamic_cast<Kernel::PropertyWithValue<double> *>(p);
        if (doublep) {
          efixed = (*doublep)();
        } else {
          efixed = 0.0;
          g_log.warning() << "Efixed could not be found for detector "
                          << detector.getID() << ", set to 0.0\n";
        }
      } else {
        efixed = 0.0;
        g_log.warning() << "Efixed could not be found for detector "
                        << detector.getID() << ", set to 0.0\n";
      }
    } else if (emode == 2) {
      std::vector<double> efixedVec = detector.getNumberParameter("Efixed");
      if (efixedVec.empty()) {
        int detid = detector.getID();
        IDetector_const_sptr detectorSingle =
            inputWS->getInstrument()->getDetector(detid);
        efixedVec = detectorSingle->getNumberParameter("Efixed");
      }
      if (!efixedVec.empty()) {
        efixed = efixedVec.at(0);
        g_log.debug() << "Detector: " << detector.getID()
                      << " EFixed: " << efixed << "\n";
      } else {
        efixed = 0.0;
        g_log.warning() << "Efixed could not be found for detector "
                        << detector.getID() << ", set to 0.0\n";
      }
    }
  }
  return efixed;
}
예제 #7
0
파일: MergeRuns.cpp 프로젝트: mducle/mantid
/**
Test a workspace for compatibility with others on the basis of the arguments
provided.
@param ws : Workspace to test
@param xUnitID : Unit id for the x axis
@param YUnit : Y Unit
@param dist : flag indicating that the workspace should be a distribution
@param instrument : name of the instrument
@throws an invalid argument if a full match is not acheived.
*/
void MergeRuns::testCompatibility(MatrixWorkspace_const_sptr ws,
                                  const std::string &xUnitID,
                                  const std::string &YUnit, const bool dist,
                                  const std::string instrument) const {
    std::string errors;
    if (ws->getAxis(0)->unit()->unitID() != xUnitID)
        errors += "different X units; ";
    if (ws->YUnit() != YUnit)
        errors += "different Y units; ";
    if (ws->isDistribution() != dist)
        errors += "not all distribution or all histogram type; ";
    if (ws->getInstrument()->getName() != instrument)
        errors += "different instrument names; ";
    if (errors.length() > 0) {
        g_log.error("Input workspaces are not compatible: " + errors);
        throw std::invalid_argument("Input workspaces are not compatible: " +
                                    errors);
    }
}
예제 #8
0
double ConvertSpectrumAxis2::getEfixed(IDetector_const_sptr detector,
                                       MatrixWorkspace_const_sptr inputWS,
                                       int emode) const {
  double efixed(0);
  double efixedProp = getProperty("Efixed");
  if (efixedProp != EMPTY_DBL()) {
    efixed = efixedProp;
    g_log.debug() << "Detector: " << detector->getID() << " Efixed: " << efixed
                  << "\n";
  } else {
    if (emode == 1) {
      if (inputWS->run().hasProperty("Ei")) {
        efixed = inputWS->run().getLogAsSingleValue("Ei");
      } else {
        throw std::invalid_argument("Could not retrieve Efixed from the "
                                    "workspace. Please provide a value.");
      }
    } else if (emode == 2) {
      std::vector<double> efixedVec = detector->getNumberParameter("Efixed");
      if (efixedVec.empty()) {
        int detid = detector->getID();
        IDetector_const_sptr detectorSingle =
            inputWS->getInstrument()->getDetector(detid);
        efixedVec = detectorSingle->getNumberParameter("Efixed");
      }
      if (!efixedVec.empty()) {
        efixed = efixedVec.at(0);
        g_log.debug() << "Detector: " << detector->getID()
                      << " EFixed: " << efixed << "\n";
      } else {
        g_log.warning() << "Efixed could not be found for detector "
                        << detector->getID() << ", please provide a value\n";
        throw std::invalid_argument("Could not retrieve Efixed from the "
                                    "detector. Please provide a value.");
      }
    }
  }
  return efixed;
}
예제 #9
0
  /** Executes the algorithm
   *
   *  @throw Exception::FileError If the grouping file cannot be opened or read successfully
   *  @throw runtime_error If unable to run one of the Child Algorithms successfully
   */
  void ReadGroupsFromFile::exec()
  {
    MatrixWorkspace_const_sptr ws = getProperty("InstrumentWorkspace");

    // Get the instrument.
    Instrument_const_sptr inst = ws->getInstrument();

    // Create a copy (without the data) of the workspace - it will contain the
    Workspace2D_sptr localWorkspace =
        boost::dynamic_pointer_cast<Workspace2D>(WorkspaceFactory::Instance().create(ws, ws->getNumberHistograms(), 2, 1));
    if (!localWorkspace)
      throw std::runtime_error("Failed when creating a Workspace2D from the input!");

    const std::string groupfile=getProperty("GroupingFilename");

    if ( ! groupfile.empty() )
    {
      std::string filename(groupfile);
      std::transform(filename.begin(), filename.end(), filename.begin(), tolower);
      if ( filename.find(".xml") != std::string::npos )
      {
        readXMLGroupingFile(groupfile);
      }
      else
      {
        readGroupingFile(groupfile);
      }
    }

    // Get the instrument.
    const int64_t nHist=localWorkspace->getNumberHistograms();

    // Determine whether the user wants to see unselected detectors or not
    const std::string su=getProperty("ShowUnselected");
    bool showunselected=(!su.compare("True"));
    bool success=false;

    for (int64_t i=0;i<nHist;i++)
    {
      ISpectrum * spec = localWorkspace->getSpectrum(i);
      const std::set<detid_t> & dets = spec->getDetectorIDs();
      if (dets.empty()) // Nothing
      {
        spec->dataY()[0]=0.0;
        continue;
      }
      // Find the first detector ID in the list
      calmap::const_iterator it=calibration.find(*dets.begin());
      if (it==calibration.end()) //Could not find the detector
      {
        spec->dataY()[0]=0.0;
        continue;
      }
      if (showunselected)
      {
        if (((*it).second).second==0)
          spec->dataY()[0]=0.0;
        else
          spec->dataY()[0]=static_cast<double>(((*it).second).first);
      }
      else
        spec->dataY()[0]=static_cast<double>(((*it).second).first);
      if (!success) success=true; //At least one detector is found in the cal file

    }
    progress(1);

    calibration.clear();
    if (!success) //Do some cleanup
    {
      localWorkspace.reset();
      throw std::runtime_error("Fail to found a detector in "+groupfile+" existing in instrument "+inst->getName());
    }
    setProperty("OutputWorkspace",localWorkspace);
    return;
  }
예제 #10
0
    /**
     * Execute the algorithm
     */
    void ExtractMask::exec()
    {
      MatrixWorkspace_const_sptr inputWS = getProperty("InputWorkspace");
      Geometry::Instrument_const_sptr instr = inputWS->getInstrument();

      // convert input to a mask workspace
      DataObjects::MaskWorkspace_const_sptr inputMaskWS
          = boost::dynamic_pointer_cast<const DataObjects::MaskWorkspace>(inputWS);
      bool inputWSIsSpecial = bool(inputMaskWS);
      if (inputWSIsSpecial)
      {
        g_log.notice() << "Input workspace is a MaskWorkspace.\n";
      }

      DataObjects::MaskWorkspace_sptr maskWS;
      // List masked of detector IDs
      std::vector<detid_t> detectorList;

      if (instr)
      {
        const int nHist = static_cast<int>(inputWS->getNumberHistograms());

        // Create a new workspace for the results, copy from the input to ensure that we copy over the instrument and current masking
        maskWS = DataObjects::MaskWorkspace_sptr(new DataObjects::MaskWorkspace(inputWS));
        maskWS->setTitle(inputWS->getTitle());

        Progress prog(this,0.0,1.0,nHist);

        MantidVecPtr xValues;
        xValues.access() = MantidVec(1, 0.0);

        PARALLEL_FOR2(inputWS, maskWS)
        for( int i = 0; i < nHist; ++i )
        {
          PARALLEL_START_INTERUPT_REGION

          bool inputIsMasked(false);
          IDetector_const_sptr inputDet;
          try
          {
            inputDet = inputWS->getDetector(i);
            if (inputWSIsSpecial) {
              inputIsMasked = inputMaskWS->isMaskedIndex(i);
            }
            // special workspaces can mysteriously have the mask bit set
            // but only check if we haven't already decided to mask the spectrum
            if( !inputIsMasked && inputDet->isMasked() )
            {
              inputIsMasked = true;
            }

            if (inputIsMasked)
            {
              detid_t id = inputDet->getID();
              PARALLEL_CRITICAL(name)
              {
                detectorList.push_back(id);
              }
            }
          }
          catch(Kernel::Exception::NotFoundError &)
          {
            inputIsMasked = false;
          }

          maskWS->setMaskedIndex(i, inputIsMasked);

          prog.report();

          PARALLEL_END_INTERUPT_REGION
        }
        PARALLEL_CHECK_INTERUPT_REGION

        // Clear all the "masked" bits on the output masked workspace
        Geometry::ParameterMap & pmap = maskWS->instrumentParameters();
        pmap.clearParametersByName("masked");
      }
      else // no instrument
      {
        // TODO should fill this in
        throw std::runtime_error("No instrument");
예제 #11
0
/** Executes the algorithm
 *
 *  @throw Exception::FileError If the grouping file cannot be opened or read successfully
 *  @throw runtime_error If unable to run one of the Child Algorithms successfully
 */
void CreateDummyCalFile::exec()
{
    // Get the input workspace
    MatrixWorkspace_const_sptr inputW = getProperty("InputWorkspace");
    if (!inputW)
        throw std::invalid_argument("No InputWorkspace");

    //Get some stuff from the input workspace
    Instrument_const_sptr inst = inputW->getInstrument();
    std::string instname = inst->getName();

    // Check that the instrument is in store
    // Get only the first 3 letters
    std::string instshort=instname;
    std::transform(instshort.begin(),instshort.end(),instshort.begin(),toupper);
    instshort=instshort+"_Definition.xml";
    // Determine the search directory for XML instrument definition files (IDFs)
    std::string directoryName = Kernel::ConfigService::Instance().getInstrumentDirectory();

    // Set up the DOM parser and parse xml file
    DOMParser pParser;
    Document* pDoc;
    try
    {
        pDoc = pParser.parse(directoryName+instshort);
    }
    catch(...)
    {
        g_log.error("Unable to parse file " + m_filename);
        throw Kernel::Exception::FileError("Unable to parse File:" , m_filename);
    }
    // Get pointer to root element
    Element* pRootElem = pDoc->documentElement();
    if ( !pRootElem->hasChildNodes() )
    {
        g_log.error("XML file: " + m_filename + "contains no root element.");
        throw Kernel::Exception::InstrumentDefinitionError("No root element in XML instrument file", m_filename);
    }

    // Handle used in the singleton constructor for instrument file should append the value
    // of the last-modified tag inside the file to determine if it is already in memory so that
    // changes to the instrument file will cause file to be reloaded.
    auto temp = instshort + pRootElem->getAttribute("last-modified");// Generate the mangled name by hand (old-style)

    // If instrument not in store, insult the user
    if (!API::InstrumentDataService::Instance().doesExist(temp))
    {
        Mantid::Geometry::IDFObject idf(directoryName+instshort);
        temp = idf.getMangledName(); // new style.
        if (!API::InstrumentDataService::Instance().doesExist(temp))
        {
            g_log.error("Instrument "+instshort+" is not present in data store.");
            throw std::runtime_error("Instrument "+instshort+" is not present in data store.");
        }
    }

    // Get the names of groups
    groups=instname;

    // Split the names of the group and insert in a vector, throw if group empty
    std::vector<std::string> vgroups;
    boost::split( vgroups, instname, boost::algorithm::detail::is_any_ofF<char>(",/*"));
    if (vgroups.empty())
    {
        g_log.error("Could not determine group names. Group names should be separated by / or ,");
        throw std::runtime_error("Could not determine group names. Group names should be separated by / or ,");
    }

    // Assign incremental number to each group
    std::map<std::string,int> group_map;
    int index=0;
    for (std::vector<std::string>::const_iterator it=vgroups.begin(); it!=vgroups.end(); ++it)
        group_map[(*it)]=++index;

    // Not needed anymore
    vgroups.clear();

    // Find Detectors that belong to groups
    typedef boost::shared_ptr<const Geometry::ICompAssembly> sptr_ICompAss;
    typedef boost::shared_ptr<const Geometry::IComponent> sptr_IComp;
    typedef boost::shared_ptr<const Geometry::IDetector> sptr_IDet;
    std::queue< std::pair<sptr_ICompAss,int> > assemblies;
    sptr_ICompAss current=boost::dynamic_pointer_cast<const Geometry::ICompAssembly>(inst);
    sptr_IDet currentDet;
    sptr_IComp currentIComp;
    sptr_ICompAss currentchild;

    int top_group, child_group;

    if (current.get())
    {
        top_group=group_map[current->getName()]; // Return 0 if not in map
        assemblies.push(std::make_pair(current,top_group));
    }

    std::string filename=getProperty("CalFilename");

    // Plan to overwrite file, so do not check if it exists
    bool overwrite=false;

    int number=0;
    Progress prog(this,0.0,0.8,assemblies.size());
    while(!assemblies.empty()) //Travel the tree from the instrument point
    {
        current=assemblies.front().first;
        top_group=assemblies.front().second;
        assemblies.pop();
        int nchilds=current->nelements();
        if (nchilds!=0)
        {
            for (int i=0; i<nchilds; ++i)
            {
                currentIComp=(*(current.get()))[i]; // Get child
                currentDet=boost::dynamic_pointer_cast<const Geometry::IDetector>(currentIComp);
                if (currentDet.get())// Is detector
                {
                    if (overwrite) // Map will contains udet as the key
                        instrcalib[currentDet->getID()]=std::make_pair(number++,top_group);
                    else          // Map will contains the entry number as the key
                        instrcalib[number++]=std::make_pair(currentDet->getID(),top_group);
                }
                else // Is an assembly, push in the queue
                {
                    currentchild=boost::dynamic_pointer_cast<const Geometry::ICompAssembly>(currentIComp);
                    if (currentchild.get())
                    {
                        child_group=group_map[currentchild->getName()];
                        if (child_group==0)
                            child_group=top_group;
                        assemblies.push(std::make_pair(currentchild,child_group));
                    }
                }
            }
        }
        prog.report();
    }
    // Write the results in a file
    saveGroupingFile(filename,overwrite);
    progress(0.2);
    return;
}
예제 #12
0
/** Constructor with workspace argument
  *
  * This constructor directly takes a matrix workspace and extracts instrument
  *and run information.
  *
  * @param matrixWorkspace :: Workspace with a valid POLDI instrument and run
  *information
  */
PoldiInstrumentAdapter::PoldiInstrumentAdapter(
    const MatrixWorkspace_const_sptr &matrixWorkspace) {
  initializeFromInstrumentAndRun(matrixWorkspace->getInstrument(),
                                 matrixWorkspace->run());
}
예제 #13
0
void SANSDirectBeamScaling::exec()
{
  MatrixWorkspace_const_sptr inputWS = getProperty("InputWorkspace");
  const double beamRadius = getProperty("BeamRadius");
  const double attTrans = getProperty("AttenuatorTransmission");
  const double attTransErr = getProperty("AttenuatorTransmissionError");

  // Extract the required spectra into separate workspaces
  std::vector<detid_t> udet;
  std::vector<size_t> index;
  udet.push_back(getProperty("BeamMonitor"));
  // Convert UDETs to workspace indices
  inputWS->getIndicesFromDetectorIDs(udet,index);
  if (index.size() < 1)
  {
    g_log.debug() << "inputWS->getIndicesFromDetectorIDs() returned empty\n";
    throw std::invalid_argument("Could not find the incident beam monitor spectra\n");
  }

  const int64_t numHists = inputWS->getNumberHistograms();
  Progress progress(this,0.0,1.0,numHists);

  // Number of X bins
  const int64_t xLength = inputWS->readY(0).size();

  // Monitor counts
  double monitor = 0.0;
  const MantidVec& MonIn = inputWS->readY(index[0]);
  for (int64_t j = 0; j < xLength; j++)
    monitor += MonIn[j];

  const V3D sourcePos = inputWS->getInstrument()->getSource()->getPos();
  double counts = 0.0;
  double error = 0.0;
  int nPixels = 0;

  // Sample-detector distance for the contributing pixels
  double sdd = 0.0;

  for (int64_t i = 0; i < int64_t(numHists); ++i)
  {
    IDetector_const_sptr det;
    try {
      det = inputWS->getDetector(i);
    } catch (Exception::NotFoundError&) {
      g_log.warning() << "Spectrum index " << i << " has no detector assigned to it - discarding" << std::endl;
      continue;
    }

    // Skip if we have a monitor or if the detector is masked.
    if ( det->isMonitor() || det->isMasked() ) continue;

    const MantidVec& YIn = inputWS->readY(i);
    const MantidVec& EIn = inputWS->readE(i);

    // Sum up all the counts
    V3D pos = det->getPos() - V3D(sourcePos.X(), sourcePos.Y(), 0.0);
    const double pixelDistance = pos.Z();
    pos.setZ(0.0);
    if (pos.norm() <= beamRadius) {
      // Correct data for all X bins
      for (int64_t j = 0; j < xLength; j++)
      {
        counts += YIn[j];
        error += EIn[j]*EIn[j];
      }
      nPixels += 1;
      sdd += pixelDistance;
    }
    progress.report("Absolute Scaling");
  }
  // Get the average SDD for the counted pixels, and transform to mm.
  sdd = sdd/nPixels*1000.0;
  error = std::sqrt(error);

  // Transform from m to mm
  double sourceAperture = getProperty("SourceApertureRadius");
  sourceAperture *= 1000.0;
  // Transform from m to mm
  double sampleAperture = getProperty("SampleApertureRadius");
  sampleAperture *= 1000.0;
  //TODO: replace this by some meaningful value
  const double KCG2FluxPerMon_SUGAR = 1.0;

  // Solid angle correction scale in 1/(cm^2)/steradian
  double solidAngleCorrScale = sdd/(M_PI*sourceAperture*sampleAperture);
  solidAngleCorrScale = solidAngleCorrScale*solidAngleCorrScale*100.0;

  // Scaling factor in n/(monitor count)/(cm^2)/steradian
  double scale = counts/monitor*solidAngleCorrScale/KCG2FluxPerMon_SUGAR;
  double scaleErr = std::abs(error/monitor)*solidAngleCorrScale/KCG2FluxPerMon_SUGAR;

  scaleErr = std::abs(scale/attTrans)*sqrt( (scaleErr/scale)*(scaleErr/scale) +(attTransErr/attTrans)*(attTransErr/attTrans) );
  scale /= attTrans;

  std::vector<double> output;
  output.push_back(scale);
  output.push_back(scaleErr);
  setProperty("ScaleFactor", output);
}
예제 #14
0
    void FindDetectorsInShape::exec()
    {
      // Get the input workspace
      const MatrixWorkspace_const_sptr WS = getProperty("Workspace");

      bool includeMonitors = getProperty("IncludeMonitors");

      std::string shapeXML = getProperty("ShapeXML");

      //convert into a Geometry object
      Geometry::ShapeFactory sFactory;
      boost::shared_ptr<Geometry::Object> shape_sptr = sFactory.createShape(shapeXML);

      //get the instrument out of the workspace
      Instrument_const_sptr instrument_sptr = WS->getInstrument();

      //To get all the detector ID's
      detid2det_map allDetectors;
      instrument_sptr->getDetectors(allDetectors);

      std::vector<int> foundDets;

      //progress
      detid2det_map::size_type objCmptCount = allDetectors.size();
      int iprogress_step = static_cast<int>(objCmptCount / 100);
      if (iprogress_step == 0) iprogress_step = 1;
      int iprogress=0;


      //Now go through all
      detid2det_map::iterator it;
      detid2det_map::const_iterator it_end = allDetectors.end();
      for (it = allDetectors.begin(); it != it_end; it++)
      {
        Geometry::IDetector_const_sptr det = it->second;

        //attempt to dynamic cast up to an IDetector
        boost::shared_ptr<const Geometry::IDetector> detector_sptr =
            boost::dynamic_pointer_cast<const Geometry::IDetector>(it->second);

        if (detector_sptr)
        {
          if ((includeMonitors) || (!detector_sptr->isMonitor()))
          {
            //check if the centre of this item is within the user defined shape
            if (shape_sptr->isValid(detector_sptr->getPos()))
            {
              //shape encloses this objectComponent
              g_log.debug()<<"Detector contained in shape " << detector_sptr->getID() << std::endl;
              foundDets.push_back(detector_sptr->getID());
            }
          }
        }

        iprogress++;
        if (iprogress % iprogress_step == 0)
        {
          progress(static_cast<double>(iprogress)/static_cast<double>(objCmptCount));
          interruption_point();
        }
      }
      setProperty("DetectorList",foundDets);
    }
예제 #15
0
파일: Qxy.cpp 프로젝트: trnielsen/mantid
void Qxy::exec()
{
  MatrixWorkspace_const_sptr inputWorkspace = getProperty("InputWorkspace");
  MatrixWorkspace_const_sptr waveAdj = getProperty("WavelengthAdj");
  MatrixWorkspace_const_sptr pixelAdj = getProperty("PixelAdj");
  const bool doGravity = getProperty("AccountForGravity");
  const bool doSolidAngle = getProperty("SolidAngleWeighting");

  //throws if we don't have common binning or another incompatibility
  Qhelper helper;
  helper.examineInput(inputWorkspace, waveAdj, pixelAdj);
  g_log.debug() << "All input workspaces were found to be valid\n";

  // Create the output Qx-Qy grid
  MatrixWorkspace_sptr outputWorkspace = this->setUpOutputWorkspace(inputWorkspace);

  // Will also need an identically-sized workspace to hold the solid angle/time bin masked weight
  MatrixWorkspace_sptr weights = WorkspaceFactory::Instance().create(outputWorkspace);
  // Copy the X values from the output workspace to the solidAngles one
  cow_ptr<MantidVec> axis;
  axis.access() = outputWorkspace->readX(0);
  for ( size_t i = 0; i < weights->getNumberHistograms(); ++i ) weights->setX(i,axis);
  
  const size_t numSpec = inputWorkspace->getNumberHistograms();
  const size_t numBins = inputWorkspace->blocksize();
  
  // the samplePos is often not (0, 0, 0) because the instruments components are moved to account for the beam centre
  const V3D samplePos = inputWorkspace->getInstrument()->getSample()->getPos();
  
  // Set the progress bar (1 update for every one percent increase in progress)
  Progress prog(this, 0.05, 1.0, numSpec);

//  PARALLEL_FOR2(inputWorkspace,outputWorkspace)
  for (int64_t i = 0; i < int64_t(numSpec); ++i)
  {
//    PARALLEL_START_INTERUPT_REGION
    // Get the pixel relating to this spectrum
    IDetector_const_sptr det;
    try {
      det = inputWorkspace->getDetector(i);
    } catch (Exception::NotFoundError&) {
      g_log.warning() << "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 bins that are included inside the RadiusCut/WaveCutcut off, those to calculate for
    const size_t wavStart = helper.waveLengthCutOff(inputWorkspace, getProperty("RadiusCut"), getProperty("WaveCut"), i);
    if (wavStart >=  inputWorkspace->readY(i).size())
    {
      // all the spectra in this detector are out of range
      continue;
    }


    V3D detPos = det->getPos()-samplePos;
      
    // these will be re-calculated if gravity is on but without gravity there is no need
    double phi = atan2(detPos.Y(),detPos.X());
    double a = cos(phi);
    double b = sin(phi);
    double sinTheta = sin( inputWorkspace->detectorTwoTheta(det)/2.0 );

    // Get references to the data for this spectrum
    const MantidVec& X = inputWorkspace->readX(i);
    const MantidVec& Y = inputWorkspace->readY(i);
    const MantidVec& E = inputWorkspace->readE(i);
 
    const MantidVec& axis = outputWorkspace->readX(0);

    // the solid angle of the detector as seen by the sample is used for normalisation later on
    double angle = det->solidAngle(samplePos);

    // some bins are masked completely or partially, the following vector will contain the fractions
    MantidVec maskFractions;
    if ( inputWorkspace->hasMaskedBins(i) )
    {
      // go through the set and convert it to a vector
      const MatrixWorkspace::MaskList& mask = inputWorkspace->maskedBins(i);
      maskFractions.resize(numBins, 1.0);
      MatrixWorkspace::MaskList::const_iterator it, itEnd(mask.end());
      for (it = mask.begin(); it != itEnd; ++it)
      {
        // The weight for this masked bin is 1 minus the degree to which this bin is masked
        maskFractions[it->first] -= it->second;
      }
    }
    double maskFraction(1);
    
    // this object is not used if gravity correction is off, but it is only constructed once per spectrum
    GravitySANSHelper grav;
    if (doGravity)
    {
      grav = GravitySANSHelper(inputWorkspace, det);
    }

    
    for (int j = static_cast<int>(numBins)-1; j >= static_cast<int>(wavStart); --j)
    {
      if( j < 0 ) break; // Be careful with counting down. Need a better fix but this will work for now
      const double binWidth = X[j+1]-X[j];
      // Calculate the wavelength at the mid-point of this bin
      const double wavLength = X[j]+(binWidth)/2.0;
      
      if (doGravity)
      {
        // SANS instruments must have their y-axis pointing up, show the detector position as where the neutron would be without gravity
        sinTheta = grav.calcComponents(wavLength, a, b);
      }

      // Calculate |Q| for this bin
      const double Q = 4.0*M_PI*sinTheta/wavLength;

      // Now get the x & y components of Q.
      const double Qx = a*Q;
      // Test whether they're in range, if not go to next spectrum.
      if ( Qx < axis.front() || Qx >= axis.back() ) break;
      const double Qy = b*Q;
      if ( Qy < axis.front() || Qy >= axis.back() ) break;
      // Find the indices pointing to the place in the 2D array where this bin's contents should go
      const MantidVec::difference_type xIndex = std::upper_bound(axis.begin(),axis.end(),Qx) - axis.begin() - 1;
      const int yIndex = static_cast<int>(
        std::upper_bound(axis.begin(),axis.end(),Qy) - axis.begin() - 1);
//      PARALLEL_CRITICAL(qxy)    /* Write to shared memory - must protect */
      {
        // the data will be copied to this bin in the output array
        double & outputBinY = outputWorkspace->dataY(yIndex)[xIndex];
        double & outputBinE = outputWorkspace->dataE(yIndex)[xIndex];

        if ( boost::math::isnan(outputBinY))
        {
          outputBinY = outputBinE = 0;
        }
        // Add the contents of the current bin to the 2D array.
        outputBinY += Y[j];
        // add the errors in quadranture
        outputBinE = std::sqrt( (outputBinE*outputBinE) + (E[j]*E[j]) );
        
        // account for masked bins
        if ( ! maskFractions.empty() )
        {
          maskFraction = maskFractions[j];
        }
        // add the total weight for this bin in the weights workspace, 
        // in an equivalent bin to where the data was stored

        // first take into account the product of contributions to the weight which have
        // no errors
        double weight = 0.0;
        if(doSolidAngle)
          weight = maskFraction*angle; 
        else
          weight = maskFraction;
        
        // then the product of contributions which have errors, i.e. optional 
        // pixelAdj and waveAdj contributions

        if (pixelAdj && waveAdj)
        {
          weights->dataY(yIndex)[xIndex] += weight*pixelAdj->readY(i)[0]*waveAdj->readY(0)[j];
          const double pixelYSq = pixelAdj->readY(i)[0]*pixelAdj->readY(i)[0];
          const double pixelESq = pixelAdj->readE(i)[0]*pixelAdj->readE(i)[0]; 
          const double waveYSq = waveAdj->readY(0)[j]*waveAdj->readY(0)[j];
          const double waveESq = waveAdj->readE(0)[j]*waveAdj->readE(0)[j];
          // add product of errors from pixelAdj and waveAdj (note no error on weight is assumed)   
          weights->dataE(yIndex)[xIndex] += weight*weight*(waveESq*pixelYSq + pixelESq*waveYSq);
        }
        else if (pixelAdj)
        {
          weights->dataY(yIndex)[xIndex] += weight*pixelAdj->readY(i)[0];
          const double pixelE = weight*pixelAdj->readE(i)[0]; 
          // add error from pixelAdj
          weights->dataE(yIndex)[xIndex] += pixelE*pixelE;
        }
        else if(waveAdj)
        {
          weights->dataY(yIndex)[xIndex] += weight*waveAdj->readY(0)[j];
          const double waveE = weight*waveAdj->readE(0)[j]; 
          // add error from waveAdj
          weights->dataE(yIndex)[xIndex] += waveE*waveE;
        }
        else
          weights->dataY(yIndex)[xIndex] += weight;
        

      }
    } // loop over single spectrum
    
    prog.report("Calculating Q");

//    PARALLEL_END_INTERUPT_REGION
  } // loop over all spectra
//  PARALLEL_CHECK_INTERUPT_REGION

  // take sqrt of error weight values
  // left to be executed here for computational efficiency
  size_t numHist = weights->getNumberHistograms();
  for (size_t i = 0; i < numHist; i++)
  {
    for (size_t j = 0; j < weights->dataE(i).size(); j++)
    {
      weights->dataE(i)[j] = sqrt(weights->dataE(i)[j]);
    } 
  }

  bool doOutputParts = getProperty("OutputParts");
  if (doOutputParts)
  {
    // copy outputworkspace before it gets further modified
    MatrixWorkspace_sptr ws_sumOfCounts = WorkspaceFactory::Instance().create(outputWorkspace);
    for (size_t i = 0; i < ws_sumOfCounts->getNumberHistograms(); i++)
    {
      ws_sumOfCounts->dataX(i) = outputWorkspace->dataX(i);
      ws_sumOfCounts->dataY(i) = outputWorkspace->dataY(i);
      ws_sumOfCounts->dataE(i) = outputWorkspace->dataE(i);
    }  

    helper.outputParts(this, ws_sumOfCounts, weights);
  }

  // Divide the output data by the solid angles
  outputWorkspace /= weights;
  outputWorkspace->isDistribution(true);

  
  // Count of the number of empty cells
  MatrixWorkspace::const_iterator wsIt(*outputWorkspace);
  int emptyBins = 0;
  for (;wsIt != wsIt.end(); ++wsIt)
  {
      if (wsIt->Y() < 1.0e-12) ++emptyBins;
  }
  // Log the number of empty bins
  g_log.notice() << "There are a total of " << emptyBins << " (" 
                 << (100*emptyBins)/(outputWorkspace->size()) << "%) empty Q bins.\n"; 
}
예제 #16
0
void EQSANSMonitorTOF::exec()
{
  MatrixWorkspace_const_sptr inputWS = getProperty("InputWorkspace");

  // Now create the output workspace
  MatrixWorkspace_sptr outputWS = getProperty("OutputWorkspace");
  if ( outputWS != inputWS )
  {
    outputWS = WorkspaceFactory::Instance().create(inputWS);
    setProperty("OutputWorkspace",outputWS);
  }

  // Get the nominal sample-to-detector distance (in mm)
  // const double MD = MONITORPOS/1000.0;

  // Get the monitor
  const std::vector<detid_t> monitor_list = inputWS->getInstrument()->getMonitors();
  if (monitor_list.size() != 1) {
    g_log.error() << "EQSANS workspace does not have exactly ones monitor! This should not happen" << std::endl;
  }
  IDetector_const_sptr mon;
  try {
    mon = inputWS->getInstrument()->getDetector(monitor_list[0]);
  } catch (Exception::NotFoundError&) {
    g_log.error() << "Spectrum index " << monitor_list[0] << " has no detector assigned to it - discarding" << std::endl;
    return;
  }

  // Get the source to monitor distance in mm
  double source_z = inputWS->getInstrument()->getSource()->getPos().Z();
  double monitor_z = mon->getPos().Z();
  double source_to_monitor = (monitor_z - source_z)*1000.0;

  // Calculate the frame width
  double frequency = dynamic_cast<TimeSeriesProperty<double>*>(inputWS->run().getLogData("frequency"))->getStatistics().mean;
  double tof_frame_width = 1.0e6/frequency;

  // Determine whether we need frame skipping or not by checking the chopper speed
  bool frame_skipping = false;
  const double chopper_speed = dynamic_cast<TimeSeriesProperty<double>*>(inputWS->run().getLogData("Speed1"))->getStatistics().mean;
  if (std::fabs(chopper_speed-frequency/2.0)<1.0) frame_skipping = true;

  // Get TOF offset
  // this is the call to the chopper code to say where
  // the start of the data frame is relative to the native facility frame
  double frame_tof0 = getTofOffset(inputWS, frame_skipping, source_to_monitor);

  // Calculate the frame width
  // none of this changes in response to just looking at the monitor
  double tmp_frame_width = frame_skipping ? tof_frame_width * 2.0 : tof_frame_width;
  double frame_offset=0.0;
  if (frame_tof0 >= tmp_frame_width) frame_offset = tmp_frame_width * ( (int)( frame_tof0/tmp_frame_width ) );

  // Find the new binning first
  const MantidVec XIn = inputWS->readX(0); // Copy here to avoid holding on to reference for too long (problem with managed workspaces)

  // Since we are swapping the low-TOF and high-TOF regions around the cutoff value,
  // there is the potential for having an overlap between the two regions. We exclude
  // the region beyond a single frame by considering only the first 1/60 sec of the
  // TOF histogram. (Bins 1 to 1666, as opposed to 1 to 2000)
  const int nTOF = static_cast<int>(XIn.size());

  // Loop through each bin to find the cutoff where the TOF distribution wraps around
  int cutoff = 0;
  double threshold = frame_tof0-frame_offset;
  int tof_bin_range = 0;
  double frame = 1000000.0/frequency;
  for (int i=0; i<nTOF; i++)
  {
      if (XIn[i] < threshold) cutoff = i;
      if (XIn[i] < frame) tof_bin_range = i;
  }
  g_log.information() << "Cutoff=" << cutoff << "; Threshold=" << threshold << std::endl;
  g_log.information() << "Low TOFs: old = [" << (cutoff+1) << ", " << (tof_bin_range-2) << "]  ->  new = [0, " << (tof_bin_range-3-cutoff) << "]" << std::endl;
  g_log.information() << "High bin boundary of the Low TOFs: old = " << tof_bin_range-1 << "; new = " << (tof_bin_range-2-cutoff) << std::endl;
  g_log.information() << "High TOFs: old = [0, " << (cutoff-1) << "]  ->  new = [" << (tof_bin_range-1-cutoff) << ", " << (tof_bin_range-2) << "]" << std::endl;
  g_log.information() << "Overlap: new = [" << (tof_bin_range-1) << ", " << (nTOF-2) << "]" << std::endl;

  // Keep a copy of the input data since we may end up overwriting it
  // if the input workspace is equal to the output workspace.
  // This is necessary since we are shuffling around the TOF bins.
  MantidVec YCopy = MantidVec(inputWS->readY(0));
  MantidVec& YIn = YCopy;
  MantidVec ECopy = MantidVec(inputWS->readE(0));
  MantidVec& EIn = ECopy;

  MantidVec& XOut = outputWS->dataX(0);
  MantidVec& YOut = outputWS->dataY(0);
  MantidVec& EOut = outputWS->dataE(0);

  // Here we modify the TOF according to the offset we calculated.
  // Since this correction will change the order of the TOF bins,
  // we do it in sequence so that we obtain a valid distribution
  // as our result (with increasing TOF values).

  // Move up the low TOFs
  for (int i=0; i<cutoff; i++)
  {
    XOut[i+tof_bin_range-1-cutoff] = XIn[i] + frame_offset + tmp_frame_width;
    YOut[i+tof_bin_range-1-cutoff] = YIn[i];
    EOut[i+tof_bin_range-1-cutoff] = EIn[i];
  }

  // Get rid of extra bins
  for (int i=tof_bin_range-1; i<nTOF-1; i++)
  {
    XOut[i] = XOut[i-1]+10.0;
    YOut[i] = 0.0;
    EOut[i] = 0.0;
  }
  XOut[nTOF-1] = XOut[nTOF-2]+10.0;

  // Move down the high TOFs
  for (int i=cutoff+1; i<tof_bin_range-1; i++)
  {
    XOut[i-cutoff-1] = XIn[i] + frame_offset;
    YOut[i-cutoff-1] = YIn[i];
    EOut[i-cutoff-1] = EIn[i];
  }
  // Don't forget the low boundary
  XOut[tof_bin_range-2-cutoff] = XIn[tof_bin_range] + frame_offset;

  // Zero out the cutoff bin, which no longer makes sense because
  // len(x) = len(y)+1
  YOut[tof_bin_range-2-cutoff] = 0.0;
  EOut[tof_bin_range-2-cutoff] = 0.0;

  setProperty("OutputWorkspace",outputWS);
}
예제 #17
0
void SofQWCentre::exec() {
  using namespace Geometry;

  MatrixWorkspace_const_sptr inputWorkspace = getProperty("InputWorkspace");

  // Do the full check for common binning
  if (!WorkspaceHelpers::commonBoundaries(*inputWorkspace)) {
    g_log.error(
        "The input workspace must have common binning across all spectra");
    throw std::invalid_argument(
        "The input workspace must have common binning across all spectra");
  }

  std::vector<double> verticalAxis;
  MatrixWorkspace_sptr outputWorkspace = setUpOutputWorkspace(
      inputWorkspace, getProperty("QAxisBinning"), verticalAxis);
  setProperty("OutputWorkspace", outputWorkspace);

  // Holds the spectrum-detector mapping
  std::vector<specnum_t> specNumberMapping;
  std::vector<detid_t> detIDMapping;

  m_EmodeProperties.initCachedValues(*inputWorkspace, this);
  int emode = m_EmodeProperties.m_emode;

  // Get a pointer to the instrument contained in the workspace
  Instrument_const_sptr instrument = inputWorkspace->getInstrument();

  // Get the distance between the source and the sample (assume in metres)
  IComponent_const_sptr source = instrument->getSource();
  IComponent_const_sptr sample = instrument->getSample();
  V3D beamDir = sample->getPos() - source->getPos();
  beamDir.normalize();

  try {
    double l1 = source->getDistance(*sample);
    g_log.debug() << "Source-sample distance: " << l1 << '\n';
  } catch (Exception::NotFoundError &) {
    g_log.error("Unable to calculate source-sample distance");
    throw Exception::InstrumentDefinitionError(
        "Unable to calculate source-sample distance",
        inputWorkspace->getTitle());
  }

  // Conversion constant for E->k. k(A^-1) = sqrt(energyToK*E(meV))
  const double energyToK = 8.0 * M_PI * M_PI * PhysicalConstants::NeutronMass *
                           PhysicalConstants::meV * 1e-20 /
                           (PhysicalConstants::h * PhysicalConstants::h);

  // Loop over input workspace bins, reassigning data to correct bin in output
  // qw workspace
  const size_t numHists = inputWorkspace->getNumberHistograms();
  const size_t numBins = inputWorkspace->blocksize();
  Progress prog(this, 0.0, 1.0, numHists);
  for (int64_t i = 0; i < int64_t(numHists); ++i) {
    try {
      // Now get the detector object for this histogram
      IDetector_const_sptr spectrumDet = inputWorkspace->getDetector(i);
      if (spectrumDet->isMonitor())
        continue;

      const double efixed = m_EmodeProperties.getEFixed(*spectrumDet);

      // For inelastic scattering the simple relationship q=4*pi*sinTheta/lambda
      // does not hold. In order to
      // be completely general we must calculate the momentum transfer by
      // calculating the incident and final
      // wave vectors and then use |q| = sqrt[(ki - kf)*(ki - kf)]
      DetectorGroup_const_sptr detGroup =
          boost::dynamic_pointer_cast<const DetectorGroup>(spectrumDet);
      std::vector<IDetector_const_sptr> detectors;
      if (detGroup) {
        detectors = detGroup->getDetectors();
      } else {
        detectors.push_back(spectrumDet);
      }

      const size_t numDets = detectors.size();
      // cache to reduce number of static casts
      const double numDets_d = static_cast<double>(numDets);
      const auto &Y = inputWorkspace->y(i);
      const auto &E = inputWorkspace->e(i);
      const auto &X = inputWorkspace->x(i);

      // Loop over the detectors and for each bin calculate Q
      for (size_t idet = 0; idet < numDets; ++idet) {
        IDetector_const_sptr det = detectors[idet];
        // Calculate kf vector direction and then Q for each energy bin
        V3D scatterDir = (det->getPos() - sample->getPos());
        scatterDir.normalize();
        for (size_t j = 0; j < numBins; ++j) {
          const double deltaE = 0.5 * (X[j] + X[j + 1]);
          // Compute ki and kf wave vectors and therefore q = ki - kf
          double ei(0.0), ef(0.0);
          if (emode == 1) {
            ei = efixed;
            ef = efixed - deltaE;
            if (ef < 0) {
              std::string mess =
                  "Energy transfer requested in Direct mode exceeds incident "
                  "energy.\n Found for det ID: " +
                  std::to_string(idet) + " bin No " + std::to_string(j) +
                  " with Ei=" + boost::lexical_cast<std::string>(efixed) +
                  " and energy transfer: " +
                  boost::lexical_cast<std::string>(deltaE);
              throw std::runtime_error(mess);
            }
          } else {
            ei = efixed + deltaE;
            ef = efixed;
            if (ef < 0) {
              std::string mess =
                  "Incident energy of a neutron is negative. Are you trying to "
                  "process Direct data in Indirect mode?\n Found for det ID: " +
                  std::to_string(idet) + " bin No " + std::to_string(j) +
                  " with efied=" + boost::lexical_cast<std::string>(efixed) +
                  " and energy transfer: " +
                  boost::lexical_cast<std::string>(deltaE);
              throw std::runtime_error(mess);
            }
          }

          if (ei < 0)
            throw std::runtime_error(
                "Negative incident energy. Check binning.");

          const V3D ki = beamDir * sqrt(energyToK * ei);
          const V3D kf = scatterDir * (sqrt(energyToK * (ef)));
          const double q = (ki - kf).norm();

          // Test whether it's in range of the Q axis
          if (q < verticalAxis.front() || q > verticalAxis.back())
            continue;
          // Find which q bin this point lies in
          const MantidVec::difference_type qIndex =
              std::upper_bound(verticalAxis.begin(), verticalAxis.end(), q) -
              verticalAxis.begin() - 1;

          // Add this spectra-detector pair to the mapping
          specNumberMapping.push_back(
              outputWorkspace->getSpectrum(qIndex).getSpectrumNo());
          detIDMapping.push_back(det->getID());

          // And add the data and it's error to that bin, taking into account
          // the number of detectors contributing to this bin
          outputWorkspace->mutableY(qIndex)[j] += Y[j] / numDets_d;
          // Standard error on the average
          outputWorkspace->mutableE(qIndex)[j] =
              sqrt((pow(outputWorkspace->e(qIndex)[j], 2) + pow(E[j], 2)) /
                   numDets_d);
        }
      }

    } catch (Exception::NotFoundError &) {
      // Get to here if exception thrown when calculating distance to detector
      // Presumably, if we get to here the spectrum will be all zeroes anyway
      // (from conversion to E)
      continue;
    }
    prog.report();
  }

  // If the input workspace was a distribution, need to divide by q bin width
  if (inputWorkspace->isDistribution())
    this->makeDistribution(outputWorkspace, verticalAxis);

  // Set the output spectrum-detector mapping
  SpectrumDetectorMapping outputDetectorMap(specNumberMapping, detIDMapping);
  outputWorkspace->updateSpectraUsing(outputDetectorMap);

  // Replace any NaNs in outputWorkspace with zeroes
  if (this->getProperty("ReplaceNaNs")) {
    auto replaceNans = this->createChildAlgorithm("ReplaceSpecialValues");
    replaceNans->setChild(true);
    replaceNans->initialize();
    replaceNans->setProperty("InputWorkspace", outputWorkspace);
    replaceNans->setProperty("OutputWorkspace", outputWorkspace);
    replaceNans->setProperty("NaNValue", 0.0);
    replaceNans->setProperty("InfinityValue", 0.0);
    replaceNans->setProperty("BigNumberThreshold", DBL_MAX);
    replaceNans->execute();
  }
}