Пример #1
0
/**
 * Project an input pixel onto an arbitrary reference line at a reference angle.
 * The projection is done along lines of constant Q, which emanate from the
 * horizon angle at wavelength = 0. The top-left and bottom-right corners of
 * the pixel are projected, resulting in an output range in "virtual" lambda.
 *
 * For a description of this projection, see:
 *   R. Cubitt, T. Saerbeck, R.A. Campbell, R. Barker, P. Gutfreund
 *   J. Appl. Crystallogr., 48 (6) (2015)
 *
 * @param wavelengthRange [in] :: the bin edges of the input bin
 * @param twoThetaRange [in] :: the 2theta width of the pixel
 * @param refAngles [in] :: the reference angles
 * @return :: the projected wavelength range
 */
ReflectometrySumInQ::MinMax
ReflectometrySumInQ::projectedLambdaRange(const MinMax &wavelengthRange,
                                          const MinMax &twoThetaRange,
                                          const Angles &refAngles) {

  // We cannot project pixels below the horizon angle
  if (twoThetaRange.min <= refAngles.horizon) {
    const auto twoTheta = (twoThetaRange.min + twoThetaRange.max) / 2.;
    throw std::runtime_error(
        "Cannot process twoTheta=" +
        std::to_string(twoTheta * Geometry::rad2deg) +
        " as it is below the horizon angle=" +
        std::to_string(refAngles.horizon * Geometry::rad2deg));
  }

  // Calculate the projected wavelength range
  MinMax range;
  try {
    const double lambdaTop =
        projectToReference(wavelengthRange.max, twoThetaRange.min, refAngles);
    const double lambdaBot =
        projectToReference(wavelengthRange.min, twoThetaRange.max, refAngles);
    range.testAndSet(lambdaBot);
    range.testAndSet(lambdaTop);
  } catch (std::exception &ex) {
    const auto twoTheta = (twoThetaRange.min + twoThetaRange.max) / 2.;
    const auto lambda = (wavelengthRange.min + wavelengthRange.max) / 2.;
    throw std::runtime_error(
        "Failed to project (lambda, twoTheta) = (" + std::to_string(lambda) +
        "," + std::to_string(twoTheta * Geometry::rad2deg) +
        ") onto twoThetaR = " + std::to_string(refAngles.twoTheta) + ": " +
        ex.what());
  }
  return range;
}
Пример #2
0
/**
 * Return the wavelength range of the output histogram.
 * @param detectorWS [in] :: the input workspace
 * @param indices [in] :: the workspace indices of foreground histograms
 * @param refAngles [in] :: the reference angles
 * @return :: the minimum and maximum virtual wavelengths
 */
ReflectometrySumInQ::MinMax ReflectometrySumInQ::findWavelengthMinMax(
    const API::MatrixWorkspace &detectorWS,
    const Indexing::SpectrumIndexSet &indices, const Angles &refAngles) {
  const API::SpectrumInfo &spectrumInfo = detectorWS.spectrumInfo();
  // Get the new max and min X values of the projected (virtual) lambda range
  const bool includePartialBins = getProperty(Prop::PARTIAL_BINS);
  // Find minimum and maximum 2thetas and the corresponding indices.
  // It cannot be assumed that 2theta increases with indices, check for example
  // D17 at ILL
  MinMax inputLambdaRange;
  MinMax inputTwoThetaRange;
  for (const auto i : indices) {
    const auto twoThetas = twoThetaWidth(i, spectrumInfo);
    inputTwoThetaRange.testAndSetMin(includePartialBins ? twoThetas.min
                                                        : twoThetas.max);
    inputTwoThetaRange.testAndSetMax(includePartialBins ? twoThetas.max
                                                        : twoThetas.min);
    const auto &edges = detectorWS.binEdges(i);
    for (size_t xIndex = 0; xIndex < edges.size(); ++xIndex) {
      // It is common for the wavelength to have negative values at ILL.
      const auto x = edges[xIndex + (includePartialBins ? 0 : 1)];
      if (x > 0.) {
        inputLambdaRange.testAndSet(x);
        break;
      }
    }
    if (includePartialBins) {
      inputLambdaRange.testAndSet(edges.back());
    } else {
      inputLambdaRange.testAndSet(edges[edges.size() - 2]);
    }
  }

  MinMax outputLambdaRange;
  outputLambdaRange.min = projectToReference(inputLambdaRange.min,
                                             inputTwoThetaRange.max, refAngles);
  outputLambdaRange.max = projectToReference(inputLambdaRange.max,
                                             inputTwoThetaRange.min, refAngles);
  if (outputLambdaRange.min > outputLambdaRange.max) {
    throw std::runtime_error(
        "Error projecting lambda range to reference line; projected range (" +
        std::to_string(outputLambdaRange.min) + "," +
        std::to_string(outputLambdaRange.max) + ") is negative.");
  }
  return outputLambdaRange;
}