/**Convert a binned workspace to point data
 *
 * @param workspace :: The input workspace
 * @return the converted workspace containing point data
 */
MatrixWorkspace_sptr
SplineInterpolation::convertBinnedData(MatrixWorkspace_sptr workspace) const {
  if (workspace->isHistogramData()) {
    const size_t histNo = workspace->getNumberHistograms();
    const size_t size = workspace->y(0).size();

    // make a new workspace for the point data
    MatrixWorkspace_sptr pointWorkspace =
        WorkspaceFactory::Instance().create(workspace, histNo, size, size);

    // loop over each histogram
    for (size_t i = 0; i < histNo; ++i) {
      const auto &xValues = workspace->x(i);
      pointWorkspace->setSharedY(i, workspace->sharedY(i));

      auto &newXValues = pointWorkspace->mutableX(i);

      // set x values to be average of bin bounds
      for (size_t j = 0; j < size; ++j) {
        newXValues[j] = (xValues[j] + xValues[j + 1]) / 2;
      }
    }

    return pointWorkspace;
  }

  return workspace;
}
void SumEventsByLogValue::createBinnedOutput(
    const Kernel::TimeSeriesProperty<T> *log) {
  // If only the number of bins was given, add the min & max values of the log
  if (m_binningParams.size() == 1) {
    m_binningParams.insert(m_binningParams.begin(), log->minValue());
    m_binningParams.push_back(
        log->maxValue() *
        1.000001); // Make it a tiny bit larger to cover full range
  }

  // XValues will be resized in createAxisFromRebinParams()
  std::vector<double> XValues;
  const int XLength =
      VectorHelper::createAxisFromRebinParams(m_binningParams, XValues);
  assert((int)XValues.size() == XLength);

  // Create the output workspace - the factory will give back a Workspace2D
  MatrixWorkspace_sptr outputWorkspace = WorkspaceFactory::Instance().create(
      "Workspace2D", 1, XLength, XLength - 1);
  // Copy the bin boundaries into the output workspace
  outputWorkspace->mutableX(0) = XValues;
  outputWorkspace->getAxis(0)->title() = m_logName;
  outputWorkspace->setYUnit("Counts");

  auto &Y = outputWorkspace->mutableY(0);
  const int numSpec = static_cast<int>(m_inputWorkspace->getNumberHistograms());
  Progress prog(this, 0.0, 1.0, numSpec);
  PARALLEL_FOR_IF(Kernel::threadSafe(*m_inputWorkspace))
  for (int spec = 0; spec < numSpec; ++spec) {
    PARALLEL_START_INTERUPT_REGION
    const IEventList &eventList = m_inputWorkspace->getSpectrum(spec);
    const auto pulseTimes = eventList.getPulseTimes();
    for (auto pulseTime : pulseTimes) {
      // Find the value of the log at the time of this event
      const double logValue = log->getSingleValue(pulseTime);
      if (logValue >= XValues.front() && logValue < XValues.back()) {
        PARALLEL_ATOMIC
        ++Y[VectorHelper::getBinIndex(XValues, logValue)];
      }
    }

    prog.report();
    PARALLEL_END_INTERUPT_REGION
  }
  PARALLEL_CHECK_INTERUPT_REGION

  // The errors are the sqrt of the counts so long as we don't deal with
  // weighted events.
  std::transform(Y.cbegin(), Y.cend(), outputWorkspace->mutableE(0).begin(),
                 (double (*)(double))std::sqrt);

  setProperty("OutputWorkspace", outputWorkspace);
}
/** Convert a workspace to Q
 *
 * @param inputWS : The input workspace (in wavelength) to convert to Q
 * @return : output workspace in Q
 */
MatrixWorkspace_sptr
ReflectometryReductionOne2::convertToQ(MatrixWorkspace_sptr inputWS) {
  bool const moreThanOneDetector = inputWS->getDetector(0)->nDets() > 1;
  bool const shouldCorrectAngle =
      !(*getProperty("ThetaIn")).isDefault() && !summingInQ();
  if (shouldCorrectAngle && moreThanOneDetector) {
    if (inputWS->getNumberHistograms() > 1) {
      throw std::invalid_argument(
          "Expected a single group in "
          "ProcessingInstructions to be able to "
          "perform angle correction, found " +
          std::to_string(inputWS->getNumberHistograms()));
    }
    MatrixWorkspace_sptr IvsQ = inputWS->clone();
    auto &XOut0 = IvsQ->mutableX(0);
    const auto &XIn0 = inputWS->x(0);
    double const theta = getProperty("ThetaIn");
    double const factor = 4.0 * M_PI * sin(theta * M_PI / 180.0);
    std::transform(XIn0.rbegin(), XIn0.rend(), XOut0.begin(),
                   [factor](double x) { return factor / x; });
    auto &Y0 = IvsQ->mutableY(0);
    auto &E0 = IvsQ->mutableE(0);
    std::reverse(Y0.begin(), Y0.end());
    std::reverse(E0.begin(), E0.end());
    IvsQ->getAxis(0)->unit() =
        UnitFactory::Instance().create("MomentumTransfer");
    return IvsQ;
  } else {
    auto convertUnits = this->createChildAlgorithm("ConvertUnits");
    convertUnits->initialize();
    convertUnits->setProperty("InputWorkspace", inputWS);
    convertUnits->setProperty("Target", "MomentumTransfer");
    convertUnits->setProperty("AlignBins", false);
    convertUnits->execute();
    MatrixWorkspace_sptr IvsQ = convertUnits->getProperty("OutputWorkspace");
    return IvsQ;
  }
}
Example #4
0
/**
 * Read histogram data
 * @param histogramEntries map of the file entries that have histogram
 * @param nxFile Reads data from inside first first top entry
 * @return Names of workspaces to include in output group
 */
std::vector<std::string> LoadMcStas::readHistogramData(
    const std::map<std::string, std::string> &histogramEntries,
    ::NeXus::File &nxFile) {

  std::string nameAttrValueYLABEL;
  std::vector<std::string> histoWSNames;

  for (const auto &histogramEntry : histogramEntries) {
    const std::string &dataName = histogramEntry.first;
    const std::string &dataType = histogramEntry.second;

    // open second level entry
    nxFile.openGroup(dataName, dataType);

    // grap title to use to e.g. create workspace name
    std::string nameAttrValueTITLE;
    nxFile.getAttr("filename", nameAttrValueTITLE);

    if (nxFile.hasAttr("ylabel")) {
      nxFile.getAttr("ylabel", nameAttrValueYLABEL);
    }

    // Find the axis names
    auto nxdataEntries = nxFile.getEntries();
    std::string axis1Name, axis2Name;
    for (auto &nxdataEntry : nxdataEntries) {
      if (nxdataEntry.second == "NXparameters")
        continue;
      if (nxdataEntry.first == "ncount")
        continue;
      nxFile.openData(nxdataEntry.first);

      if (nxFile.hasAttr("axis")) {
        int axisNo(0);
        nxFile.getAttr("axis", axisNo);
        if (axisNo == 1)
          axis1Name = nxdataEntry.first;
        else if (axisNo == 2)
          axis2Name = nxdataEntry.first;
        else
          throw std::invalid_argument("Unknown axis number");
      }
      nxFile.closeData();
    }

    std::vector<double> axis1Values;
    std::vector<double> axis2Values;
    nxFile.readData<double>(axis1Name, axis1Values);
    if (axis2Name.length() == 0) {
      axis2Name = nameAttrValueYLABEL;
      axis2Values.push_back(0.0);
    } else {
      nxFile.readData<double>(axis2Name, axis2Values);
    }

    const size_t axis1Length = axis1Values.size();
    const size_t axis2Length = axis2Values.size();
    g_log.debug() << "Axis lengths=" << axis1Length << " " << axis2Length
                  << '\n';

    // Require "data" field
    std::vector<double> data;
    nxFile.readData<double>("data", data);

    // Optional errors field
    std::vector<double> errors;
    try {
      nxFile.readData<double>("errors", errors);
    } catch (::NeXus::Exception &) {
      g_log.information() << "Field " << dataName
                          << " contains no error information.\n";
    }

    // close second level entry
    nxFile.closeGroup();

    MatrixWorkspace_sptr ws = WorkspaceFactory::Instance().create(
        "Workspace2D", axis2Length, axis1Length, axis1Length);
    Axis *axis1 = ws->getAxis(0);
    axis1->title() = axis1Name;
    // Set caption
    auto lblUnit = boost::make_shared<Units::Label>();
    lblUnit->setLabel(axis1Name, "");
    axis1->unit() = lblUnit;

    Axis *axis2 = new NumericAxis(axis2Length);
    axis2->title() = axis2Name;
    // Set caption
    lblUnit = boost::make_shared<Units::Label>();
    lblUnit->setLabel(axis2Name, "");
    axis2->unit() = lblUnit;

    ws->setYUnit(axis2Name);
    ws->replaceAxis(1, axis2);

    for (size_t wsIndex = 0; wsIndex < axis2Length; ++wsIndex) {
      auto &dataX = ws->mutableX(wsIndex);
      auto &dataY = ws->mutableY(wsIndex);
      auto &dataE = ws->mutableE(wsIndex);

      for (size_t j = 0; j < axis1Length; ++j) {
        // Data is stored in column-major order so we are translating to
        // row major for Mantid
        const size_t fileDataIndex = j * axis2Length + wsIndex;

        dataX[j] = axis1Values[j];
        dataY[j] = data[fileDataIndex];
        if (!errors.empty())
          dataE[j] = errors[fileDataIndex];
      }
      axis2->setValue(wsIndex, axis2Values[wsIndex]);
    }

    // set the workspace title
    ws->setTitle(nameAttrValueTITLE);

    // use the workspace title to create the workspace name
    std::replace(nameAttrValueTITLE.begin(), nameAttrValueTITLE.end(), ' ',
                 '_');

    // ensure that specified name is given to workspace (eventWS) when added to
    // outputGroup
    const std::string outputWS = getProperty("OutputWorkspace");
    const std::string nameUserSee = nameAttrValueTITLE + "_" + outputWS;
    AnalysisDataService::Instance().addOrReplace(nameUserSee, ws);

    histoWSNames.emplace_back(ws->getName());
  }
  nxFile.closeGroup();
  return histoWSNames;

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

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

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

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

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

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

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

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

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

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

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

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

    // PARALLEL_START_INTERUPT_REGION

    std::size_t wsid = i;

    try {

      double deg2rad = M_PI / 180.;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

  return outputWS;
}