/// Get the counting time from a workspace
/// @param inputWS :: workspace to read the counting time from
double
HFIRDarkCurrentSubtraction::getCountingTime(MatrixWorkspace_sptr inputWS) {
    // First, look whether we have the information in the log
    if (inputWS->run().hasProperty("timer")) {
        return inputWS->run().getPropertyValueAsType<double>("timer");
    } else {
        // If we don't have the information in the log, use the default timer
        // spectrum
        MantidVec &timer = inputWS->dataY(DEFAULT_TIMER_ID);
        return timer[0];
    }
}
Beispiel #2
0
double RefReduction::calculateAngleREFL(MatrixWorkspace_sptr workspace)
{
  Mantid::Kernel::Property* prop = workspace->run().getProperty("ths");
  Mantid::Kernel::TimeSeriesProperty<double>* dp = dynamic_cast<Mantid::Kernel::TimeSeriesProperty<double>* >(prop);
  const double ths = dp->getStatistics().mean;

  prop = workspace->run().getProperty("tthd");
  dp = dynamic_cast<Mantid::Kernel::TimeSeriesProperty<double>* >(prop);
  const double tthd = dp->getStatistics().mean;

  double offset = getProperty("AngleOffset");
  if (isEmpty(offset)) offset = 0.0;
  return tthd - ths + offset;
}
/// Get the counting time from a workspace
/// @param inputWS :: workspace to read the counting time from
double HFIRDarkCurrentSubtraction::getCountingTime(MatrixWorkspace_sptr inputWS)
{
  // First, look whether we have the information in the log
  if (inputWS->run().hasProperty("timer"))
  {
    Mantid::Kernel::Property* prop = inputWS->run().getProperty("timer");
    Mantid::Kernel::PropertyWithValue<double>* dp = dynamic_cast<Mantid::Kernel::PropertyWithValue<double>* >(prop);
    return *dp;
  } else {
    // If we don't have the information in the log, use the default timer spectrum
    MantidVec& timer = inputWS->dataY(DEFAULT_TIMER_ID);
    return timer[0];
  }
}
Beispiel #4
0
/** Return the to-be axis of the workspace dependent on the log entry
* @param ws : the input workspace
* @return : the x-axis to use for the output workspace
*/
std::vector<double> ConjoinXRuns::getXAxis(MatrixWorkspace_sptr ws) const {

  std::vector<double> axis;
  axis.reserve(ws->blocksize());
  auto &run = ws->run();
  // try time series first
  TimeSeriesProperty<double> *timeSeriesDouble(nullptr);
  timeSeriesDouble =
      dynamic_cast<TimeSeriesProperty<double> *>(run.getLogData(m_logEntry));
  if (timeSeriesDouble) {
    // try double series
    axis = timeSeriesDouble->filteredValuesAsVector();
  } else {
    // try int series next
    TimeSeriesProperty<int> *timeSeriesInt(nullptr);
    timeSeriesInt =
        dynamic_cast<TimeSeriesProperty<int> *>(run.getLogData(m_logEntry));
    if (timeSeriesInt) {
      std::vector<int> intAxis = timeSeriesInt->filteredValuesAsVector();
      axis = std::vector<double>(intAxis.begin(), intAxis.end());
    } else {
      // then scalar
      axis.push_back(run.getPropertyAsSingleValue(m_logEntry));
    }
  }

  return axis;
}
Beispiel #5
0
double RefReduction::calculateAngleREFM(MatrixWorkspace_sptr workspace)
{
  double dangle = getProperty("DetectorAngle");
  if (isEmpty(dangle))
  {
    Mantid::Kernel::Property* prop = workspace->run().getProperty("DANGLE");
    Mantid::Kernel::TimeSeriesProperty<double>* dp = dynamic_cast<Mantid::Kernel::TimeSeriesProperty<double>* >(prop);
    dangle = dp->getStatistics().mean;
  }

  double dangle0 = getProperty("DetectorAngle0");
  if (isEmpty(dangle0))
  {
    Mantid::Kernel::Property* prop = workspace->run().getProperty("DANGLE0");
    Mantid::Kernel::TimeSeriesProperty<double>* dp = dynamic_cast<Mantid::Kernel::TimeSeriesProperty<double>* >(prop);
    dangle0 = dp->getStatistics().mean;
  }

  Mantid::Kernel::Property* prop = workspace->run().getProperty("SampleDetDis");
  Mantid::Kernel::TimeSeriesProperty<double>* dp = dynamic_cast<Mantid::Kernel::TimeSeriesProperty<double>* >(prop);
  const double det_distance = dp->getStatistics().mean/1000.0;

  double direct_beam_pix = getProperty("DirectPixel");
  if (isEmpty(direct_beam_pix))
  {
    Mantid::Kernel::Property* prop = workspace->run().getProperty("DIRPIX");
    Mantid::Kernel::TimeSeriesProperty<double>* dp = dynamic_cast<Mantid::Kernel::TimeSeriesProperty<double>* >(prop);
    direct_beam_pix = dp->getStatistics().mean;
  }

  double ref_pix = getProperty("ReflectivityPixel");
  if (ref_pix==0 || isEmpty(ref_pix))
  {
    const std::vector<int> peakRange = getProperty("SignalPeakPixelRange");
    if (peakRange.size()<2) {
      g_log.error() << "SignalPeakPixelRange parameter should be a vector of two values" << std::endl;
      throw std::invalid_argument("SignalPeakPixelRange parameter should be a vector of two values");
    }
    ref_pix = (peakRange[0] + peakRange[1])/2.0;
  }

  double theta = (dangle-dangle0)*M_PI/180.0/2.0
      + ((direct_beam_pix-ref_pix)*PIXEL_SIZE)/ (2.0*det_distance);

  return theta*180.0/M_PI;
}
/**
 * Check the inputs for invalid values
 * @returns A map with validation warnings.
 */
std::map<std::string, std::string> ChangeTimeZero::validateInputs() {
  std::map<std::string, std::string> invalidProperties;

  // Check the time offset for either a value or a date time
  double relativeTimeOffset = getProperty("RelativeTimeOffset");
  std::string absoluteTimeOffset = getProperty("AbsoluteTimeOffset");

  auto isRelative = isRelativeTimeShift(relativeTimeOffset);
  auto absoluteTimeInput = absoluteTimeOffset != m_defaultAbsoluteTimeShift;
  auto isAbsolute = isAbsoluteTimeShift(absoluteTimeOffset);

  // If both inputs are being used, then return straight away.
  if (isRelative && absoluteTimeInput) {
    invalidProperties.insert(std::make_pair(
        "RelativeTimeOffset", "You can either sepcify a relative time shift or "
                              "an absolute time shift."));
    invalidProperties.insert(std::make_pair(
        "AbsoluteTimeOffset", "You can either sepcify a relative time shift or "
                              "an absolute time shift."));

    return invalidProperties;
  } else if (!isRelative && !isAbsolute) {
    invalidProperties.insert(std::make_pair(
        "RelativeTimeOffset",
        "TimeOffset must either be a numeric "
        "value or a ISO8601 (YYYY-MM-DDTHH:MM::SS) date-time stamp."));
    invalidProperties.insert(std::make_pair(
        "AbsoluteTimeOffset",
        "TimeOffset must either be a numeric "
        "value or a ISO8601 (YYYY-MM-DDTHH:MM::SS) date-time stamp."));
  }

  // If we are dealing with an absolute time we need to ensure that the
  // proton_charge entry exists
  if (isAbsolute) {
    MatrixWorkspace_sptr ws = getProperty("InputWorkspace");
    auto run = ws->run();
    try {
      run.getTimeSeriesProperty<double>("proton_charge");
    } catch (...) {
      invalidProperties.insert(
          std::make_pair("InputWorkspace",
                         "A TimeOffset with an absolute time, requires the "
                         "input workspace to have a proton_charge property in "
                         "its log."));
    }
  }

  return invalidProperties;
}
/**
 * Execute the algorithm.
 */
void CreateChopperModel::exec() {
  const std::string modelType = getProperty("ModelType");
  if (modelType != "FermiChopperModel") {
    throw std::invalid_argument("Invalid chopper model type.");
  }
  MatrixWorkspace_sptr workspace = getProperty("Workspace");

  API::ChopperModel *chopper = new API::FermiChopperModel;
  chopper->setRun(workspace->run());
  chopper->initialize(getProperty("Parameters"));

  int index = getProperty("ChopperPoint");
  workspace->setChopperModel(chopper, static_cast<size_t>(index));
}
/** Export time stamps looking erroreous
 *  @param dts :: standard delta T in second
 *  @param ws  ::  shared pointer to a matrix workspace, which has the log to
 *study
 *  @param abstimevec :: vector of log time
 *
 *  This algorithm should be reconsidered how to work with it.
 */
void GetTimeSeriesLogInformation::exportErrorLog(MatrixWorkspace_sptr ws,
                                                 vector<DateAndTime> abstimevec,
                                                 double dts) {
  std::string outputdir = getProperty("OutputDirectory");
  if (!outputdir.empty() && outputdir.back() != '/')
    outputdir += "/";

  std::string ofilename = outputdir + "errordeltatime.txt";
  g_log.notice() << ofilename << '\n';
  std::ofstream ofs;
  ofs.open(ofilename.c_str(), std::ios::out);

  size_t numbaddt = 0;
  Kernel::DateAndTime t0(ws->run().getProperty("run_start")->value());

  for (size_t i = 1; i < abstimevec.size(); i++) {
    double tempdts = static_cast<double>(abstimevec[i].totalNanoseconds() -
                                         abstimevec[i - 1].totalNanoseconds()) *
                     1.0E-9;
    double dev = (tempdts - dts) / dts;
    bool baddt = false;
    if (fabs(dev) > 0.5)
      baddt = true;

    if (baddt) {
      numbaddt++;
      double deltapulsetimeSec1 =
          static_cast<double>(abstimevec[i - 1].totalNanoseconds() -
                              t0.totalNanoseconds()) *
          1.0E-9;
      double deltapulsetimeSec2 =
          static_cast<double>(abstimevec[i].totalNanoseconds() -
                              t0.totalNanoseconds()) *
          1.0E-9;
      int index1 = static_cast<int>(deltapulsetimeSec1 * 60);
      int index2 = static_cast<int>(deltapulsetimeSec2 * 60);

      ofs << "Error d(T) = " << tempdts << "   vs   Correct d(T) = " << dts
          << '\n';
      ofs << index1 << "\t\t" << abstimevec[i - 1].totalNanoseconds() << "\t\t"
          << index2 << "\t\t" << abstimevec[i].totalNanoseconds() << '\n';
    }
  }

  ofs.close();
}
Beispiel #9
0
void NormaliseByCurrent::exec()
{
  // Get the input workspace
  MatrixWorkspace_sptr inputWS = getProperty("InputWorkspace");
  MatrixWorkspace_sptr outputWS = getProperty("OutputWorkspace");

  // Get the good proton charge and check it's valid
  double charge(-1.0);
  try
  {
    charge = inputWS->run().getProtonCharge();
  }
  catch(Exception::NotFoundError &)
  {
    g_log.error() << "The proton charge is not set for the run attached to this workspace\n";
    throw;
  }

  if (charge == 0)
  {
    throw std::domain_error("The proton charge is zero");
  }

  g_log.information() << "Normalisation current: " << charge << " uamps" <<  std::endl;

  charge=1.0/charge; // Inverse of the charge to be multiplied by

  // The operator overloads properly take into account of both EventWorkspaces and doing it in place or not.

  if (getPropertyValue("InputWorkspace") != getPropertyValue("OutputWorkspace"))
  {
    outputWS = inputWS*charge;
    setProperty("OutputWorkspace", outputWS);
  }
  else
  {
    inputWS *= charge;
    setProperty("OutputWorkspace", inputWS);
  }

  outputWS->setYUnitLabel("Counts per microAmp.hour");
}
Beispiel #10
0
void ApplyPaalmanPings::run() {
  // Create / Initialize algorithm
  API::BatchAlgorithmRunner::AlgorithmRuntimeProps absCorProps;
  IAlgorithm_sptr applyCorrAlg =
      AlgorithmManager::Instance().create("ApplyPaalmanPingsCorrection");
  applyCorrAlg->initialize();

  // get Sample Workspace
  MatrixWorkspace_sptr sampleWs =
      AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>(
          m_sampleWorkspaceName);
  m_originalSampleUnits = sampleWs->getAxis(0)->unit()->unitID();

  // If not in wavelength then do conversion
  if (m_originalSampleUnits != "Wavelength") {
    g_log.information(
        "Sample workspace not in wavelength, need to convert to continue.");
    absCorProps["SampleWorkspace"] =
        addConvertUnitsStep(sampleWs, "Wavelength");
  } else {
    absCorProps["SampleWorkspace"] = m_sampleWorkspaceName;
  }

  const bool useCan = m_uiForm.ckUseCan->isChecked();
  const bool useCorrections = m_uiForm.ckUseCorrections->isChecked();
  // Get Can and Clone
  MatrixWorkspace_sptr canClone;
  if (useCan) {
    const auto canName =
        m_uiForm.dsContainer->getCurrentDataName().toStdString();
    const auto cloneName = "__algorithm_can";
    IAlgorithm_sptr clone =
        AlgorithmManager::Instance().create("CloneWorkspace");
    clone->initialize();
    clone->setProperty("InputWorkspace", canName);
    clone->setProperty("Outputworkspace", cloneName);
    clone->execute();

    const bool useShift = m_uiForm.ckShiftCan->isChecked();
    if (useShift) {
      IAlgorithm_sptr scaleX = AlgorithmManager::Instance().create("ScaleX");
      scaleX->initialize();
      scaleX->setLogging(false);
      scaleX->setProperty("InputWorkspace", cloneName);
      scaleX->setProperty("OutputWorkspace", cloneName);
      scaleX->setProperty("Factor", m_uiForm.spCanShift->value());
      scaleX->setProperty("Operation", "Add");
      scaleX->execute();
      IAlgorithm_sptr rebin =
          AlgorithmManager::Instance().create("RebinToWorkspace");
      rebin->initialize();
      rebin->setLogging(false);
      rebin->setProperty("WorkspaceToRebin", cloneName);
      rebin->setProperty("WorkspaceToMatch", m_sampleWorkspaceName);
      rebin->setProperty("OutputWorkspace", cloneName);
      rebin->execute();
    }
    canClone =
        AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>(cloneName);
    // Check for same binning across sample and container
    if (!checkWorkspaceBinningMatches(sampleWs, canClone)) {
      const char *text =
          "Binning on sample and container does not match."
          "Would you like to rebin the container to match the sample?";

      int result = QMessageBox::question(NULL, tr("Rebin sample?"), tr(text),
                                         QMessageBox::Yes, QMessageBox::No,
                                         QMessageBox::NoButton);

      if (result == QMessageBox::Yes) {
        addRebinStep(QString::fromStdString(canName),
                     QString::fromStdString(m_sampleWorkspaceName));
      } else {
        m_batchAlgoRunner->clearQueue();
        g_log.error("Cannot apply absorption corrections "
                    "using a sample and "
                    "container with different binning.");
        return;
      }
    }

    // If not in wavelength then do conversion
    std::string originalCanUnits = canClone->getAxis(0)->unit()->unitID();
    if (originalCanUnits != "Wavelength") {
      g_log.information("Container workspace not in wavelength, need to "
                        "convert to continue.");
      absCorProps["CanWorkspace"] = addConvertUnitsStep(canClone, "Wavelength");
    } else {
      absCorProps["CanWorkspace"] = cloneName;
    }

    const bool useCanScale = m_uiForm.ckScaleCan->isChecked();
    if (useCanScale) {
      const double canScaleFactor = m_uiForm.spCanScale->value();
      applyCorrAlg->setProperty("CanScaleFactor", canScaleFactor);
    }
  }

  if (useCorrections) {
    QString correctionsWsName = m_uiForm.dsCorrections->getCurrentDataName();

    WorkspaceGroup_sptr corrections =
        AnalysisDataService::Instance().retrieveWS<WorkspaceGroup>(
            correctionsWsName.toStdString());
    bool interpolateAll = false;
    for (size_t i = 0; i < corrections->size(); i++) {
      MatrixWorkspace_sptr factorWs =
          boost::dynamic_pointer_cast<MatrixWorkspace>(corrections->getItem(i));

      // Check for matching binning
      if (sampleWs && (sampleWs->blocksize() != factorWs->blocksize())) {
        int result;
        if (interpolateAll) {
          result = QMessageBox::Yes;
        } else {
          std::string text = "Number of bins on sample and " +
                             factorWs->name() + " workspace does not match.\n" +
                             "Would you like to interpolate this workspace to "
                             "match the sample?";

          result = QMessageBox::question(
              NULL, tr("Interpolate corrections?"), tr(text.c_str()),
              QMessageBox::YesToAll, QMessageBox::Yes, QMessageBox::No);
        }

        switch (result) {
        case QMessageBox::YesToAll:
          interpolateAll = true;
        // fall through
        case QMessageBox::Yes:
          addInterpolationStep(factorWs, absCorProps["SampleWorkspace"]);
          break;
        default:
          m_batchAlgoRunner->clearQueue();
          g_log.error("ApplyPaalmanPings cannot run with corrections that do "
                      "not match sample binning.");
          return;
        }
      }
    }

    applyCorrAlg->setProperty("CorrectionsWorkspace",
                              correctionsWsName.toStdString());
  }

  // Generate output workspace name
  auto QStrSampleWsName = QString::fromStdString(m_sampleWorkspaceName);
  int nameCutIndex = QStrSampleWsName.lastIndexOf("_");
  if (nameCutIndex == -1)
    nameCutIndex = QStrSampleWsName.length();

  QString correctionType;
  switch (m_uiForm.cbGeometry->currentIndex()) {
  case 0:
    correctionType = "flt";
    break;
  case 1:
    correctionType = "cyl";
    break;
  case 2:
    correctionType = "anl";
    break;
  }
  QString outputWsName = QStrSampleWsName.left(nameCutIndex);

  // Using corrections
  if (m_uiForm.ckUseCorrections->isChecked()) {
    outputWsName += "_" + correctionType + "_Corrected";
  } else {
    outputWsName += "_Subtracted";
  }

  // Using container
  if (m_uiForm.ckUseCan->isChecked()) {
    const auto canName =
        m_uiForm.dsContainer->getCurrentDataName().toStdString();
    MatrixWorkspace_sptr containerWs =
        AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>(canName);
    auto run = containerWs->run();
    if (run.hasProperty("run_number")) {
      outputWsName +=
          "_" + QString::fromStdString(run.getProperty("run_number")->value());
    } else {
      auto canCutIndex = QString::fromStdString(canName).indexOf("_");
      outputWsName += "_" + QString::fromStdString(canName).left(canCutIndex);
    }
  }

  outputWsName += "_red";

  applyCorrAlg->setProperty("OutputWorkspace", outputWsName.toStdString());

  // Add corrections algorithm to queue
  m_batchAlgoRunner->addAlgorithm(applyCorrAlg, absCorProps);

  // Run algorithm queue
  connect(m_batchAlgoRunner, SIGNAL(batchComplete(bool)), this,
          SLOT(absCorComplete(bool)));
  m_batchAlgoRunner->executeBatchAsync();

  // Set the result workspace for Python script export
  m_pythonExportWsName = outputWsName.toStdString();
  // m_containerWorkspaceName = m_uiForm.dsContainer->getCurrentDataName();
  // updateContainer();
}
void ImageROIViewQtWidget::showProjectionImage(
    const Mantid::API::WorkspaceGroup_sptr &wsg, size_t idx) {

  MatrixWorkspace_sptr ws;
  try {
    ws = boost::dynamic_pointer_cast<MatrixWorkspace>(wsg->getItem(idx));
    if (!ws)
      return;
  } catch (std::exception &e) {
    QMessageBox::warning(
        this, "Cannot load image",
        "There was a problem while trying to find the image data: " +
            QString::fromStdString(e.what()));
  }

  const size_t MAXDIM = 2048 * 16;
  size_t width;
  try {
    width = boost::lexical_cast<size_t>(ws->run().getLogData("Axis1")->value());
    // TODO: add a settings option for this (like max mem allocation for
    // images)?
    if (width >= MAXDIM)
      width = MAXDIM;
  } catch (std::exception &e) {
    QMessageBox::critical(this, "Cannot load image",
                          "There was a problem while trying to "
                          "find the width of the image: " +
                              QString::fromStdString(e.what()));
    return;
  }

  size_t height;
  try {
    height =
        boost::lexical_cast<size_t>(ws->run().getLogData("Axis2")->value());
    if (height >= MAXDIM)
      height = MAXDIM;
  } catch (std::exception &e) {
    QMessageBox::critical(this, "Cannot load image",
                          "There was a problem while trying to "
                          "find the height of the image: " +
                              QString::fromStdString(e.what()));
    return;
  }

  // images are loaded as 1 histogram == 1 pixel (1 bin per histogram):
  if (height != ws->getNumberHistograms() || width != ws->blocksize()) {
    QMessageBox::critical(
        this, "Image dimensions do not match in the input image workspace",
        "Could not load the expected "
        "number of rows and columns.");
    return;
  }
  // find min and max to scale pixel values
  double min = std::numeric_limits<double>::max(),
         max = std::numeric_limits<double>::min();
  for (size_t i = 0; i < ws->getNumberHistograms(); ++i) {
    for (size_t j = 0; j < ws->blocksize(); ++j) {
      const double &v = ws->readY(i)[j];
      if (v < min)
        min = v;
      if (v > max)
        max = v;
    }
  }
  if (min >= max) {
    QMessageBox::warning(
        this, "Empty image!",
        "The image could be loaded but it contains "
        "effectively no information, all pixels have the same value.");
    // black picture
    QPixmap pix(static_cast<int>(width), static_cast<int>(height));
    pix.fill(QColor(0, 0, 0));
    m_ui.label_img->setPixmap(pix);
    m_ui.label_img->show();
    m_basePixmap.reset(new QPixmap(pix));
    return;
  }

  // load / transfer image into a QImage
  QImage rawImg(QSize(static_cast<int>(width), static_cast<int>(height)),
                QImage::Format_RGB32);
  const double max_min = max - min;
  const double scaleFactor = 255.0 / max_min;
  for (size_t yi = 0; yi < width; ++yi) {
    for (size_t xi = 0; xi < width; ++xi) {
      const double &v = ws->readY(yi)[xi];
      // color the range min-max in gray scale. To apply different color
      // maps you'd need to use rawImg.setColorTable() or similar.
      const int scaled = static_cast<int>(scaleFactor * (v - min));
      QRgb vRgb = qRgb(scaled, scaled, scaled);
      rawImg.setPixel(static_cast<int>(xi), static_cast<int>(yi), vRgb);
    }
  }

  // paint and show image
  // direct from image
  QPixmap pix = QPixmap::fromImage(rawImg);
  m_ui.label_img->setPixmap(pix);
  m_ui.label_img->show();
  m_basePixmap.reset(new QPixmap(pix));
  // Alternative, drawing with a painter:
  // QPixmap pix(static_cast<int>(width), static_cast<int>(height));
  // QPainter painter;
  // painter.begin(&pix);
  // painter.drawImage(0, 0, rawImg);
  // painter.end();
  // m_ui.label_img->setPixmap(pix);
  // m_ui.label_img->show();
  // m_basePixmap.reset(new QPixmap(pix));
}
/** 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;
}
Beispiel #13
0
/// Do the actual work of modifying the log in the workspace.
void ChangeLogTime::exec()
{
  // check that a log was specified
  string logname = this->getProperty("LogName");
  if (logname.empty()) {
    throw std::runtime_error("Failed to supply a LogName");
  }
  // everything will need an offset
  double offset = this->getProperty("TimeOffset");

  // make sure the log is in the input workspace
  MatrixWorkspace_sptr inputWS = getProperty("InputWorkspace");
  Kernel::TimeSeriesProperty<double> * oldlog = dynamic_cast<Kernel::TimeSeriesProperty<double> *>( inputWS->run().getLogData(logname) );
  if (!oldlog) {
    stringstream msg;
    msg << "InputWorkspace \'" << this->getPropertyValue("InputWorkspace")
        << "\' does not have LogName \'" << logname << "\'";
    throw std::runtime_error(msg.str());
  }

  // Create the new log
  TimeSeriesProperty<double>* newlog = new TimeSeriesProperty<double>(logname);
  newlog->setUnits(oldlog->units());
  int size = oldlog->realSize();
  vector<double> values = oldlog->valuesAsVector();
  vector<DateAndTime> times = oldlog->timesAsVector();
  for (int i = 0; i < size; i++) {
    newlog->addValue(times[i] + offset, values[i]);
  }

  // Just overwrite if the change is in place
  MatrixWorkspace_sptr outputWS = getProperty("OutputWorkspace");
  if (outputWS != inputWS)
  {
    IAlgorithm_sptr duplicate = createChildAlgorithm("CloneWorkspace");
    duplicate->initialize();
    duplicate->setProperty<Workspace_sptr>("InputWorkspace", boost::dynamic_pointer_cast<Workspace>(inputWS));
    duplicate->execute();
    Workspace_sptr temp = duplicate->getProperty("OutputWorkspace");
    outputWS = boost::dynamic_pointer_cast<MatrixWorkspace>(temp);

    setProperty("OutputWorkspace", outputWS);
  }

  outputWS->mutableRun().addProperty(newlog, true);
}
Beispiel #14
0
/** Executes the algorithm. Reading in the file and creating and populating
*  the output workspace
*
*  @throw Exception::FileError If the Nexus file cannot be found/opened
*  @throw std::invalid_argument If the optional properties are set to invalid
*values
*/
void LoadNexusLogs::exec() {
  std::string filename = getPropertyValue("Filename");
  MatrixWorkspace_sptr workspace = getProperty("Workspace");

  // Find the entry name to use (normally "entry" for SNS, "raw_data_1" for
  // ISIS)
  std::string entry_name = LoadTOFRawNexus::getEntryName(filename);

  ::NeXus::File file(filename);
  // Find the root entry
  try {
    file.openGroup(entry_name, "NXentry");
  } catch (::NeXus::Exception &) {
    throw std::invalid_argument("Unknown NeXus file format found in file '" +
                                filename + "'");
  }

  /// Use frequency start for Monitor19 and Special1_19 logs with "No Time" for
  /// SNAP
  try {
    file.openPath("DASlogs");
    try {
      file.openGroup("frequency", "NXlog");
      try {
        file.openData("time");

        //----- Start time is an ISO8601 string date and time. ------
        try {
          file.getAttr("start", freqStart);

        } catch (::NeXus::Exception &) {
          // Some logs have "offset" instead of start
          try {
            file.getAttr("offset", freqStart);
          } catch (::NeXus::Exception &) {
            g_log.warning() << "Log entry has no start time indicated.\n";
            file.closeData();
            throw;
          }
        }
        file.closeData();
      } catch (::NeXus::Exception &) {
        // No time. This is not an SNS SNAP file
      }
      file.closeGroup();
    } catch (::NeXus::Exception &) {
      // No time. This is not an SNS frequency group
    }
    file.closeGroup();
  } catch (::NeXus::Exception &) {
    // No time. This is not an SNS group
  }
  // print out the entry level fields
  std::map<std::string, std::string> entries = file.getEntries();
  std::map<std::string, std::string>::const_iterator iend = entries.end();
  for (std::map<std::string, std::string>::const_iterator it = entries.begin();
       it != iend; ++it) {
    std::string group_name(it->first);
    std::string group_class(it->second);
    if (group_name == "DASlogs" || group_class == "IXrunlog" ||
        group_class == "IXselog" || group_name == "framelog") {
      loadLogs(file, group_name, group_class, workspace);
    }
    if (group_class == "IXperiods") {
      loadNPeriods(file, workspace);
    }
  }

  // If there's measurement information, load that info as logs.
  loadAndApplyMeasurementInfo(&file, *workspace);

  // Freddie Akeroyd 12/10/2011
  // current ISIS implementation contains an additional indirection between
  // collected frames via an
  // "event_frame_number" array in NXevent_data (which eliminates frames with no
  // events).
  // the proton_log is for all frames and so is longer than the event_index
  // array, so we need to
  // filter the proton_charge log based on event_frame_number
  // This difference will be removed in future for compatibility with SNS, but
  // the code below will allow current SANS2D files to load
  if (workspace->mutableRun().hasProperty("proton_log")) {
    std::vector<int> event_frame_number;
    this->getLogger().notice()
        << "Using old ISIS proton_log and event_frame_number indirection..."
        << std::endl;
    try {
      // Find the bank/name corresponding to the first event data entry, i.e.
      // one with type NXevent_data.
      file.openPath("/" + entry_name);
      std::map<std::string, std::string> entries = file.getEntries();
      std::map<std::string, std::string>::const_iterator it = entries.begin();
      std::string eventEntry;
      for (; it != entries.end(); ++it) {
        if (it->second == "NXevent_data") {
          eventEntry = it->first;
          break;
        }
      }
      this->getLogger().debug()
          << "Opening"
          << " /" + entry_name + "/" + eventEntry + "/event_frame_number"
          << " to find the event_frame_number\n";
      file.openPath("/" + entry_name + "/" + eventEntry +
                    "/event_frame_number");
      file.getData(event_frame_number);
    } catch (const ::NeXus::Exception &) {
      this->getLogger().warning() << "Unable to load event_frame_number - "
                                     "filtering events by time will not work "
                                  << std::endl;
    }
    file.openPath("/" + entry_name);
    if (!event_frame_number.empty()) // ISIS indirection - see above comments
    {
      Kernel::TimeSeriesProperty<double> *plog =
          dynamic_cast<Kernel::TimeSeriesProperty<double> *>(
              workspace->mutableRun().getProperty("proton_log"));
      if (!plog)
        throw std::runtime_error(
            "Could not cast (interpret) proton_log as a time "
            "series property. Cannot continue.");
      Kernel::TimeSeriesProperty<double> *pcharge =
          new Kernel::TimeSeriesProperty<double>("proton_charge");
      std::vector<double> pval;
      std::vector<Mantid::Kernel::DateAndTime> ptime;
      pval.reserve(event_frame_number.size());
      ptime.reserve(event_frame_number.size());
      std::vector<Mantid::Kernel::DateAndTime> plogt = plog->timesAsVector();
      std::vector<double> plogv = plog->valuesAsVector();
      for (auto number : event_frame_number) {
        ptime.push_back(plogt[number]);
        pval.push_back(plogv[number]);
      }
      pcharge->create(ptime, pval);
      pcharge->setUnits("uAh");
      workspace->mutableRun().addProperty(pcharge, true);
    }
  }
  try {
    // Read the start and end time strings
    file.openData("start_time");
    Kernel::DateAndTime start(file.getStrData());
    file.closeData();
    file.openData("end_time");
    Kernel::DateAndTime end(file.getStrData());
    file.closeData();
    workspace->mutableRun().setStartAndEndTime(start, end);
  } catch (::NeXus::Exception &) {
  }

  if (!workspace->run().hasProperty("gd_prtn_chrg")) {
    // Try pulling it from the main proton_charge entry first
    try {
      file.openData("proton_charge");
      std::vector<double> values;
      file.getDataCoerce(values);
      std::string units;
      file.getAttr("units", units);
      double charge = values.front();
      if (units.find("picoCoulomb") != std::string::npos) {
        charge *= 1.e-06 / 3600.;
      }
      workspace->mutableRun().setProtonCharge(charge);
    } catch (::NeXus::Exception &) {
      // Try and integrate the proton logs
      try {
        // Use the DAS logs to integrate the proton charge (if any).
        workspace->mutableRun().getProtonCharge();
      } catch (Exception::NotFoundError &) {
        // Ignore not found property error.
      }
    }
  }

  // Close the file
  file.close();
}
Beispiel #15
0
/// Returns the value of a run property from a given workspace
/// @param inputWS :: input workspace
/// @param pname :: name of the property to retrieve
double getRunPropertyDbl(MatrixWorkspace_sptr inputWS, const std::string& pname)
{
  Mantid::Kernel::Property* prop = inputWS->run().getProperty(pname);
  Mantid::Kernel::PropertyWithValue<double>* dp = dynamic_cast<Mantid::Kernel::PropertyWithValue<double>* >(prop);
  return *dp;
}
Beispiel #16
0
    /** Execute the algorithm.
     */
    void DgsReduction::exec()
    {
      // Reduction property manager
      const std::string reductionManagerName = this->getProperty("ReductionProperties");
      if (reductionManagerName.empty())
      {
        g_log.error() << "ERROR: Reduction Property Manager name is empty" << std::endl;
        return;
      }
      this->reductionManager = boost::make_shared<PropertyManager>();
      PropertyManagerDataService::Instance().addOrReplace(reductionManagerName,
          this->reductionManager);

      // Put all properties except input files/workspaces into property manager.
      const std::vector<Property *> props = this->getProperties();
      std::vector<Property *>::const_iterator iter = props.begin();
      for (; iter != props.end(); ++iter)
      {
        if (!boost::contains((*iter)->name(), "Input"))
        {
          this->reductionManager->declareProperty((*iter)->clone());
        }
      }
      // Determine the default facility
      const FacilityInfo defaultFacility = ConfigService::Instance().getFacility();

      // Need to load data to get certain bits of information.
      Workspace_sptr sampleWS = this->loadInputData("Sample");
      MatrixWorkspace_sptr WS = boost::dynamic_pointer_cast<MatrixWorkspace>(sampleWS);
      this->reductionManager->declareProperty(new PropertyWithValue<std::string>(
          "InstrumentName", WS->getInstrument()->getName()));

      // Check the facility for the loaded file and make sure it's the
      // same as the default.
      const InstrumentInfo info = ConfigService::Instance().getInstrument(WS->getInstrument()->getName());
      if (defaultFacility.name() != info.facility().name())
      {
        std::ostringstream mess;
        mess << "Default facility must be set to " << info.facility().name();
        mess << " in order for reduction to work!";
        throw std::runtime_error(mess.str());
      }

      MatrixWorkspace_sptr sampleMonWS = this->getProperty("SampleInputMonitorWorkspace");

      const bool showIntermedWS = this->getProperty("ShowIntermediateWorkspaces");

      // Get output workspace pointer and name
      MatrixWorkspace_sptr outputWS = this->getProperty("OutputWorkspace");
      std::string outputWsName = this->getPropertyValue("OutputWorkspace");
      if (boost::ends_with(outputWsName, "_spe"))
      {
        boost::erase_all(outputWsName, "_spe");
      }

      // Load the hard mask if available
      MatrixWorkspace_sptr hardMaskWS = this->loadHardMask();
      if (hardMaskWS && showIntermedWS)
      {
        std::string hardMaskName = outputWsName + "_hardmask";
        this->declareProperty(new WorkspaceProperty<>("ReductionHardMask",
            hardMaskName, Direction::Output));
        this->setProperty("ReductionHardMask", hardMaskWS);
      }
      // Load the grouping file if available
      MatrixWorkspace_sptr groupingWS = this->loadGroupingFile("");
      if (groupingWS && showIntermedWS)
      {
        std::string groupName = outputWsName + "_grouping";
        this->declareProperty(new WorkspaceProperty<>("ReductionGrouping",
            groupName, Direction::Output));
        this->setProperty("ReductionGrouping", groupingWS);
      }

      // This will be diagnostic mask if DgsDiagnose is run and hard mask if not.
      MatrixWorkspace_sptr maskWS;

      // Process the sample detector vanadium if present
      Workspace_sptr detVanWS = this->loadInputData("DetectorVanadium", false);
      MatrixWorkspace_sptr detVanMonWS = this->getProperty("DetectorVanadiumInputMonitorWorkspace");
      bool isProcessedDetVan = this->getProperty("UseProcessedDetVan");
      // Process a comparison detector vanadium if present
      Workspace_sptr detVan2WS = this->loadInputData("DetectorVanadium2", false);
      MatrixWorkspace_sptr detVan2MonWS = this->getProperty("DetectorVanadium2InputMonitorWorkspace");
      IAlgorithm_sptr detVan;
      Workspace_sptr idetVanWS;
      if (detVanWS && !isProcessedDetVan)
      {
        std::string detVanMaskName = outputWsName + "_diagmask";

        IAlgorithm_sptr diag = this->createChildAlgorithm("DgsDiagnose");
        diag->setProperty("DetVanWorkspace", detVanWS);
        diag->setProperty("DetVanMonitorWorkspace", detVanMonWS);
        diag->setProperty("DetVanCompWorkspace", detVan2WS);
        diag->setProperty("DetVanCompMonitorWorkspace", detVan2MonWS);
        diag->setProperty("SampleWorkspace", sampleWS);
        diag->setProperty("SampleMonitorWorkspace", sampleMonWS);
        diag->setProperty("HardMaskWorkspace", hardMaskWS);
        diag->setProperty("ReductionProperties", reductionManagerName);
        diag->executeAsChildAlg();
        maskWS = diag->getProperty("OutputWorkspace");

        if (showIntermedWS)
        {
          this->declareProperty(new WorkspaceProperty<>("SampleDetVanDiagMask",
              detVanMaskName, Direction::Output));
          this->setProperty("SampleDetVanDiagMask", maskWS);
        }

        detVan = this->createChildAlgorithm("DgsProcessDetectorVanadium");
        detVan->setProperty("InputWorkspace", detVanWS);
        detVan->setProperty("InputMonitorWorkspace", detVanMonWS);
        detVan->setProperty("MaskWorkspace", maskWS);
        std::string idetVanName = outputWsName + "_idetvan";
        detVan->setProperty("ReductionProperties", reductionManagerName);
        detVan->executeAsChildAlg();
        MatrixWorkspace_sptr oWS = detVan->getProperty("OutputWorkspace");
        idetVanWS = boost::dynamic_pointer_cast<Workspace>(oWS);

        if (showIntermedWS)
        {
          this->declareProperty(new WorkspaceProperty<>("IntegratedNormWorkspace",
              idetVanName, Direction::Output));
          this->setProperty("IntegratedNormWorkspace", idetVanWS);
        }
      }
      else
      {
        idetVanWS = detVanWS;
        maskWS = boost::dynamic_pointer_cast<MatrixWorkspace>(idetVanWS);
        detVanWS.reset();
      }

      IAlgorithm_sptr etConv = this->createChildAlgorithm("DgsConvertToEnergyTransfer");
      etConv->setProperty("InputWorkspace", sampleWS);
      etConv->setProperty("InputMonitorWorkspace", sampleMonWS);
      etConv->setProperty("IntegratedDetectorVanadium", idetVanWS);
      const double ei = this->getProperty("IncidentEnergyGuess");
      etConv->setProperty("IncidentEnergyGuess", ei);
      if (!maskWS && hardMaskWS)
      {
        maskWS = hardMaskWS;
      }
      etConv->setProperty("MaskWorkspace", maskWS);
      if (groupingWS)
      {
        etConv->setProperty("GroupingWorkspace", groupingWS);
      }
      etConv->setProperty("ReductionProperties", reductionManagerName);
      std::string tibWsName = this->getPropertyValue("OutputWorkspace") + "_tib";
      etConv->executeAsChildAlg();
      outputWS = etConv->getProperty("OutputWorkspace");
      MatrixWorkspace_sptr tibWS = etConv->getProperty("OutputTibWorkspace");

      if (tibWS && showIntermedWS)
      {
        this->declareProperty(new WorkspaceProperty<>("SampleTibWorkspace",
            tibWsName, Direction::Output));
        this->setProperty("SampleTibWorkspace", tibWS);
      }

      Workspace_sptr absSampleWS = this->loadInputData("AbsUnitsSample", false);

      // Perform absolute normalisation if necessary
      if (absSampleWS)
      {
        std::string absWsName = outputWsName + "_absunits";

        // Collect the other workspaces first.
        MatrixWorkspace_sptr absSampleMonWS = this->getProperty("AbsUnitsSampleInputMonitorWorkspace");
        Workspace_sptr absDetVanWS = this->loadInputData("AbsUnitsDetectorVanadium", false);
        MatrixWorkspace_sptr absDetVanMonWS = this->getProperty("AbsUnitsDetectorVanadiumInputMonitorWorkspace");
        MatrixWorkspace_sptr absGroupingWS = this->loadGroupingFile("AbsUnits");

        // Run the absolute normalisation reduction
        IAlgorithm_sptr absUnitsRed = this->createChildAlgorithm("DgsAbsoluteUnitsReduction");
        absUnitsRed->setProperty("InputWorkspace", absSampleWS);
        absUnitsRed->setProperty("InputMonitorWorkspace", absSampleMonWS);
        absUnitsRed->setProperty("DetectorVanadiumWorkspace", absDetVanWS);
        absUnitsRed->setProperty("DetectorVanadiumMonitorWorkspace",
            absDetVanMonWS);
        absUnitsRed->setProperty("GroupingWorkspace", absGroupingWS);
        absUnitsRed->setProperty("MaskWorkspace", maskWS);
        absUnitsRed->setProperty("ReductionProperties", reductionManagerName);
        absUnitsRed->executeAsChildAlg();
        MatrixWorkspace_sptr absUnitsWS = absUnitsRed->getProperty("OutputWorkspace");
//!!! There is Property outputMaskWorkspace to get masks? It looks like one is using wrong property for masks
        MatrixWorkspace_sptr absMaskWS = absUnitsRed->getProperty("OutputWorkspace");

        IAlgorithm_sptr mask = this->createChildAlgorithm("MaskDetectors");
        mask->setProperty("Workspace", outputWS);
        mask->setProperty("MaskedWorkspace", absMaskWS);
        mask->executeAsChildAlg();
        outputWS = mask->getProperty("Workspace");

        // Do absolute normalisation
        outputWS = divide(outputWS, absUnitsWS);

        if (showIntermedWS)
        {
          this->declareProperty(new WorkspaceProperty<>("AbsUnitsWorkspace",
              absWsName, Direction::Output));
          this->setProperty("AbsUnitsWorkspace", absUnitsWS);
          this->declareProperty(new WorkspaceProperty<>("AbsUnitsDiagMask",
              outputWsName+"_absunits_diagmask", Direction::Output));
          this->setProperty("AbsUnitsDiagMask", absMaskWS);
        }
      }

      // Convert from DeltaE to powder S(Q,W)
      const bool doPowderConvert = this->getProperty("DoPowderDataConversion");
      if (doPowderConvert)
      {
        g_log.notice() << "Converting to powder S(Q,W)" << std::endl;
        // Collect information
        std::string sqwWsName = outputWsName + "_pd_sqw";
        std::vector<double> qBinning = this->getProperty("PowderMomTransferRange");
        const double initialEnergy = boost::lexical_cast<double>(outputWS->run().getProperty("Ei")->value());

        IAlgorithm_sptr sofqw = this->createChildAlgorithm("SofQW3");
        sofqw->setProperty("InputWorkspace", outputWS);
        sofqw->setProperty("QAxisBinning", qBinning);
        sofqw->setProperty("EMode", "Direct");
        sofqw->setProperty("EFixed", initialEnergy);
        sofqw->executeAsChildAlg();
        MatrixWorkspace_sptr sqwWS = sofqw->getProperty("OutputWorkspace");
        this->declareProperty(new WorkspaceProperty<>("PowderSqwWorkspace",
            sqwWsName, Direction::Output));
        this->setProperty("PowderSqwWorkspace", sqwWS);

        const bool saveProcNexus = this->getProperty("SavePowderNexusFile");
        if (saveProcNexus)
        {
          std::string saveProcNexusFilename = this->getProperty("SavePowderNexusFilename");
          if (saveProcNexusFilename.empty())
          {
            saveProcNexusFilename = sqwWsName + ".nxs";
          }
          IAlgorithm_sptr saveNxs = this->createChildAlgorithm("SaveNexus");
          saveNxs->setProperty("InputWorkspace", sqwWS);
          saveNxs->setProperty("Filename", saveProcNexusFilename);
          saveNxs->executeAsChildAlg();
        }
      }

      this->setProperty("OutputWorkspace", outputWS);
    }
/**
 * This extraction strategy gets applied when guides are used to calculate the
 * collimation length. The instrument
 * parameter file contains the information about the number of guides to use.
 * The guide data itself is fetched
 * from the sample logs.
 * @param inOutWS: a matrix workspace
 * @param L1: the distance between sample and source
 * @param collimationLengthCorrection: The correction to get the collimation
 * length
 */
double SANSCollimationLengthEstimator::getCollimationLengthWithGuides(
    MatrixWorkspace_sptr inOutWS, const double L1,
    const double collimationLengthCorrection) const {
  auto lCollim = L1 - collimationLengthCorrection;

  // Make sure we have guide cutoffs
  if (!inOutWS->getInstrument()->hasParameter("guide-cutoff")) {
    throw std::invalid_argument("TOFSANSResolutionByPixel: Could not get a "
                                "GuideCutoff from the instrument");
  }

  // Make sure we have a defined number of guidess
  if (!inOutWS->getInstrument()->hasParameter("number-of-guides")) {
    throw std::invalid_argument(
        "TOFSANSResolutionByPixel: Could not get the number of guides.");
  }

  // Make sure we have a guide increment specified
  if (!inOutWS->getInstrument()->hasParameter(
          "guide-collimation-length-increment")) {
    throw std::invalid_argument(
        "TOFSANSResolutionByPixel: Could not find a guide increment.");
  }

  auto numberOfGuides = static_cast<unsigned int>(
      inOutWS->getInstrument()->getNumberParameter("number-of-guides")[0]);
  auto guideIncrement = inOutWS->getInstrument()->getNumberParameter(
      "guide-collimation-length-increment")[0];

  // Make sure that all guides are there. They are labelled as Guide1, Guide2,
  // Guide3, ...
  // The entry is a numeric TimeSeriesProperty or a numeric entry, if something
  // else then default
  std::vector<double> guideValues;
  for (unsigned int i = 1; i <= numberOfGuides; i++) {
    auto guideName = "Guide" + boost::lexical_cast<std::string>(i);
    if (inOutWS->run().hasProperty(guideName)) {
      auto guideValue = getGuideValue(inOutWS->run().getProperty(guideName));
      guideValues.push_back(guideValue);
    } else {
      throw std::invalid_argument("TOFSANSResolutionByPixel: Mismatch between "
                                  "specified number of Guides and actual "
                                  "Guides.");
    }
  }

  auto guideCutoff =
      inOutWS->getInstrument()->getNumberParameter("guide-cutoff")[0];
  // Go through the guides and check in an alternate manner if the guide is
  // smaller
  // or larger than the cut off value. We start at the last guide and check that
  // it is
  // larger than the cutoff, the next one has to be smaller and so on. For
  // example in pseudocode
  // If Guide5 > 130: LCollim+=2.0 else break;
  // If Guide4 < 130: LCollim+=2.0 else break;
  // If Guide3 > 130: LCollim+=2.0 else break;
  // ...
  unsigned int largerSmallerCounter = 0;
  for (auto it = guideValues.rbegin(); it != guideValues.rend(); ++it) {
    bool guideIsLarger = largerSmallerCounter % 2 == 0;
    if (guideIsLarger && (*it > guideCutoff)) {
      lCollim += guideIncrement;
    } else if (!guideIsLarger && (*it < guideCutoff)) {
      lCollim += guideIncrement;
    } else {
      break;
    }
    largerSmallerCounter++;
  }
  return lCollim;
}
void SANSSensitivityCorrection::exec() {
  // Output log
  m_output_message = "";

  Progress progress(this, 0.0, 1.0, 10);

  // Reduction property manager
  const std::string reductionManagerName = getProperty("ReductionProperties");
  boost::shared_ptr<PropertyManager> reductionManager;
  if (PropertyManagerDataService::Instance().doesExist(reductionManagerName)) {
    reductionManager =
        PropertyManagerDataService::Instance().retrieve(reductionManagerName);
  } else {
    reductionManager = boost::make_shared<PropertyManager>();
    PropertyManagerDataService::Instance().addOrReplace(reductionManagerName,
                                                        reductionManager);
  }

  if (!reductionManager->existsProperty("SensitivityAlgorithm")) {
    auto algProp = make_unique<AlgorithmProperty>("SensitivityAlgorithm");
    algProp->setValue(toString());
    reductionManager->declareProperty(std::move(algProp));
  }

  progress.report("Loading sensitivity file");
  const std::string fileName = getPropertyValue("Filename");

  // Look for an entry for the dark current in the reduction table
  Poco::Path path(fileName);
  const std::string entryName = "Sensitivity" + path.getBaseName();
  MatrixWorkspace_sptr floodWS;
  std::string floodWSName = "__sensitivity_" + path.getBaseName();

  if (reductionManager->existsProperty(entryName)) {
    std::string wsName = reductionManager->getPropertyValue(entryName);
    floodWS = boost::dynamic_pointer_cast<MatrixWorkspace>(
        AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>(wsName));
    m_output_message += "   |Using " + wsName + "\n";
    g_log.debug()
        << "SANSSensitivityCorrection :: Using sensitivity workspace: "
        << wsName << "\n";
  } else {
    // Load the flood field if we don't have it already
    // First, try to determine whether we need to load data or a sensitivity
    // workspace...
    if (!floodWS && fileCheck(fileName)) {
      g_log.debug() << "SANSSensitivityCorrection :: Loading sensitivity file: "
                    << fileName << "\n";
      IAlgorithm_sptr loadAlg = createChildAlgorithm("Load", 0.1, 0.3);
      loadAlg->setProperty("Filename", fileName);
      loadAlg->executeAsChildAlg();
      Workspace_sptr floodWS_ws = loadAlg->getProperty("OutputWorkspace");
      floodWS = boost::dynamic_pointer_cast<MatrixWorkspace>(floodWS_ws);

      // Check that it's really a sensitivity file
      if (!floodWS->run().hasProperty("is_sensitivity")) {
        // Reset pointer
        floodWS.reset();
        g_log.error() << "A processed Mantid workspace was loaded but it "
                         "wasn't a sensitivity file!\n";
      }
    }

    // ... if we don't, just load the data and process it
    if (!floodWS) {
      // Read in default beam center
      double center_x = getProperty("BeamCenterX");
      double center_y = getProperty("BeamCenterY");
      if (isEmpty(center_x) || isEmpty(center_y)) {
        if (reductionManager->existsProperty("LatestBeamCenterX") &&
            reductionManager->existsProperty("LatestBeamCenterY")) {
          center_x = reductionManager->getProperty("LatestBeamCenterX");
          center_y = reductionManager->getProperty("LatestBeamCenterY");
          m_output_message +=
              "   |Setting beam center to [" +
              Poco::NumberFormatter::format(center_x, 1) + ", " +
              Poco::NumberFormatter::format(center_y, 1) + "]\n";
        } else
          m_output_message += "   |No beam center provided: skipping!\n";
      }

      const std::string rawFloodWSName = "__flood_data_" + path.getBaseName();
      MatrixWorkspace_sptr rawFloodWS;
      if (!reductionManager->existsProperty("LoadAlgorithm")) {
        IAlgorithm_sptr loadAlg = createChildAlgorithm("Load", 0.1, 0.3);
        loadAlg->setProperty("Filename", fileName);
        if (!isEmpty(center_x) && loadAlg->existsProperty("BeamCenterX"))
          loadAlg->setProperty("BeamCenterX", center_x);
        if (!isEmpty(center_y) && loadAlg->existsProperty("BeamCenterY"))
          loadAlg->setProperty("BeamCenterY", center_y);
        loadAlg->setPropertyValue("OutputWorkspace", rawFloodWSName);
        loadAlg->executeAsChildAlg();
        Workspace_sptr tmpWS = loadAlg->getProperty("OutputWorkspace");
        rawFloodWS = boost::dynamic_pointer_cast<MatrixWorkspace>(tmpWS);
        m_output_message += "   | Loaded " + fileName + " (Load algorithm)\n";
      } else {
        // Get load algorithm as a string so that we can create a completely
        // new proxy and ensure that we don't overwrite existing properties
        IAlgorithm_sptr loadAlg0 =
            reductionManager->getProperty("LoadAlgorithm");
        const std::string loadString = loadAlg0->toString();
        IAlgorithm_sptr loadAlg = Algorithm::fromString(loadString);
        loadAlg->setChild(true);
        loadAlg->setProperty("Filename", fileName);
        loadAlg->setPropertyValue("OutputWorkspace", rawFloodWSName);
        if (!isEmpty(center_x) && loadAlg->existsProperty("BeamCenterX"))
          loadAlg->setProperty("BeamCenterX", center_x);
        if (!isEmpty(center_y) && loadAlg->existsProperty("BeamCenterY"))
          loadAlg->setProperty("BeamCenterY", center_y);
        loadAlg->execute();
        rawFloodWS = loadAlg->getProperty("OutputWorkspace");
        m_output_message += "   |Loaded " + fileName + "\n";
        if (loadAlg->existsProperty("OutputMessage")) {
          std::string msg = loadAlg->getPropertyValue("OutputMessage");
          m_output_message +=
              "   |" + Poco::replace(msg, "\n", "\n   |") + "\n";
        }
      }

      // Check whether we just loaded a flood field data set, or the actual
      // sensitivity
      if (!rawFloodWS->run().hasProperty("is_sensitivity")) {
        const std::string darkCurrentFile = getPropertyValue("DarkCurrentFile");

        // Look for a dark current subtraction algorithm
        std::string dark_result;
        if (reductionManager->existsProperty("DarkCurrentAlgorithm")) {
          IAlgorithm_sptr darkAlg =
              reductionManager->getProperty("DarkCurrentAlgorithm");
          darkAlg->setChild(true);
          darkAlg->setProperty("InputWorkspace", rawFloodWS);
          darkAlg->setProperty("OutputWorkspace", rawFloodWS);

          // Execute as-is if we use the sample dark current, otherwise check
          // whether a dark current file was provided.
          // Otherwise do nothing
          if (getProperty("UseSampleDC")) {
            darkAlg->execute();
            if (darkAlg->existsProperty("OutputMessage"))
              dark_result = darkAlg->getPropertyValue("OutputMessage");
          } else if (!darkCurrentFile.empty()) {
            darkAlg->setProperty("Filename", darkCurrentFile);
            darkAlg->setProperty("PersistentCorrection", false);
            darkAlg->execute();
            if (darkAlg->existsProperty("OutputMessage"))
              dark_result = darkAlg->getPropertyValue("OutputMessage");
            else
              dark_result = "   Dark current subtracted\n";
          }
        } else if (!darkCurrentFile.empty()) {
          // We need to subtract the dark current for the flood field but no
          // dark
          // current subtraction was set for the sample! Use the default dark
          // current algorithm if we can find it.
          if (reductionManager->existsProperty("DefaultDarkCurrentAlgorithm")) {
            IAlgorithm_sptr darkAlg =
                reductionManager->getProperty("DefaultDarkCurrentAlgorithm");
            darkAlg->setChild(true);
            darkAlg->setProperty("InputWorkspace", rawFloodWS);
            darkAlg->setProperty("OutputWorkspace", rawFloodWS);
            darkAlg->setProperty("Filename", darkCurrentFile);
            darkAlg->setProperty("PersistentCorrection", false);
            darkAlg->execute();
            if (darkAlg->existsProperty("OutputMessage"))
              dark_result = darkAlg->getPropertyValue("OutputMessage");
          } else {
            // We are running out of options
            g_log.error() << "No dark current algorithm provided to load ["
                          << getPropertyValue("DarkCurrentFile")
                          << "]: skipped!\n";
            dark_result = "   No dark current algorithm provided: skipped\n";
          }
        }
        m_output_message +=
            "   |" + Poco::replace(dark_result, "\n", "\n   |") + "\n";

        // Look for solid angle correction algorithm
        if (reductionManager->existsProperty("SANSSolidAngleCorrection")) {
          IAlgorithm_sptr solidAlg =
              reductionManager->getProperty("SANSSolidAngleCorrection");
          solidAlg->setChild(true);
          solidAlg->setProperty("InputWorkspace", rawFloodWS);
          solidAlg->setProperty("OutputWorkspace", rawFloodWS);
          solidAlg->execute();
          std::string msg = "Solid angle correction applied\n";
          if (solidAlg->existsProperty("OutputMessage"))
            msg = solidAlg->getPropertyValue("OutputMessage");
          m_output_message +=
              "   |" + Poco::replace(msg, "\n", "\n   |") + "\n";
        }

        // Apply transmission correction as needed
        double floodTransmissionValue = getProperty("FloodTransmissionValue");
        double floodTransmissionError = getProperty("FloodTransmissionError");

        if (!isEmpty(floodTransmissionValue)) {
          g_log.debug() << "SANSSensitivityCorrection :: Applying transmission "
                           "to flood field\n";
          IAlgorithm_sptr transAlg =
              createChildAlgorithm("ApplyTransmissionCorrection");
          transAlg->setProperty("InputWorkspace", rawFloodWS);
          transAlg->setProperty("OutputWorkspace", rawFloodWS);
          transAlg->setProperty("TransmissionValue", floodTransmissionValue);
          transAlg->setProperty("TransmissionError", floodTransmissionError);
          transAlg->setProperty("ThetaDependent", true);
          transAlg->execute();
          rawFloodWS = transAlg->getProperty("OutputWorkspace");
          m_output_message += "   |Applied transmission to flood field\n";
        }

        // Calculate detector sensitivity
        IAlgorithm_sptr effAlg = createChildAlgorithm("CalculateEfficiency");
        effAlg->setProperty("InputWorkspace", rawFloodWS);

        const double minEff = getProperty("MinEfficiency");
        const double maxEff = getProperty("MaxEfficiency");
        const std::string maskFullComponent =
            getPropertyValue("MaskedFullComponent");
        const std::string maskEdges = getPropertyValue("MaskedEdges");
        const std::string maskComponent = getPropertyValue("MaskedComponent");

        effAlg->setProperty("MinEfficiency", minEff);
        effAlg->setProperty("MaxEfficiency", maxEff);
        effAlg->setProperty("MaskedFullComponent", maskFullComponent);
        effAlg->setProperty("MaskedEdges", maskEdges);
        effAlg->setProperty("MaskedComponent", maskComponent);
        effAlg->execute();
        floodWS = effAlg->getProperty("OutputWorkspace");
      } else {
        floodWS = rawFloodWS;
      }
      // Patch as needed
      if (reductionManager->existsProperty("SensitivityPatchAlgorithm")) {
        IAlgorithm_sptr patchAlg =
            reductionManager->getProperty("SensitivityPatchAlgorithm");
        patchAlg->setChild(true);
        patchAlg->setProperty("Workspace", floodWS);
        patchAlg->execute();
        m_output_message += "   |Sensitivity patch applied\n";
      }

      floodWS->mutableRun().addProperty("is_sensitivity", 1, "", true);
    }
    std::string floodWSOutputName =
        getPropertyValue("OutputSensitivityWorkspace");
    if (floodWSOutputName.empty()) {
      setPropertyValue("OutputSensitivityWorkspace", floodWSName);
      AnalysisDataService::Instance().addOrReplace(floodWSName, floodWS);
      reductionManager->declareProperty(
          Kernel::make_unique<WorkspaceProperty<>>(entryName, floodWSName,
                                                   Direction::InOut));
      reductionManager->setPropertyValue(entryName, floodWSName);
      reductionManager->setProperty(entryName, floodWS);
    }
    setProperty("OutputSensitivityWorkspace", floodWS);
  }

  progress.report(3, "Loaded flood field");

  // Check whether we need to apply the correction to a workspace
  MatrixWorkspace_sptr inputWS = getProperty("InputWorkspace");
  if (inputWS) {
    // Divide sample data by detector efficiency
    IAlgorithm_sptr divideAlg = createChildAlgorithm("Divide", 0.6, 0.7);
    divideAlg->setProperty("LHSWorkspace", inputWS);
    divideAlg->setProperty("RHSWorkspace", floodWS);
    divideAlg->executeAsChildAlg();
    MatrixWorkspace_sptr outputWS = divideAlg->getProperty("OutputWorkspace");

    // Copy over the efficiency's masked pixels to the reduced workspace
    IAlgorithm_sptr maskAlg = createChildAlgorithm("MaskDetectors", 0.75, 0.85);
    maskAlg->setProperty("Workspace", outputWS);
    maskAlg->setProperty("MaskedWorkspace", floodWS);
    maskAlg->executeAsChildAlg();

    setProperty("OutputWorkspace", outputWS);
  }
  setProperty("OutputMessage",
              "Sensitivity correction computed\n" + m_output_message);

  progress.report("Performed sensitivity correction");
}