Пример #1
0
/**
 * Return a pair of (minimum Q, maximum Q) for given
 * direct geometry workspace.
 * @param ws a workspace
 * @param minE minimum energy transfer in ws
 * @param maxE maximum energy transfer in ws
 * @return a pair containing global minimun and maximum Q
 */
std::pair<double, double>
SofQCommon::qBinHintsDirect(const API::MatrixWorkspace &ws, const double minE,
                            const double maxE) const {
  using namespace Mantid::PhysicalConstants;
  auto minTwoTheta = std::numeric_limits<double>::max();
  auto maxTwoTheta = std::numeric_limits<double>::lowest();
  const auto &spectrumInfo = ws.spectrumInfo();
  for (size_t i = 0; i < spectrumInfo.size(); ++i) {
    if (spectrumInfo.isMasked(i) || spectrumInfo.isMonitor(i)) {
      continue;
    }
    const auto twoTheta = spectrumInfo.twoTheta(i);
    if (twoTheta < minTwoTheta) {
      minTwoTheta = twoTheta;
    }
    if (twoTheta > maxTwoTheta) {
      maxTwoTheta = twoTheta;
    }
  }
  if (minTwoTheta == std::numeric_limits<double>::max()) {
    throw std::runtime_error("Could not determine Q binning: workspace does "
                             "not contain usable spectra.");
  }
  std::array<double, 4> q;
  q[0] = directQ(minE, minTwoTheta);
  q[1] = directQ(minE, maxTwoTheta);
  q[2] = directQ(maxE, minTwoTheta);
  q[3] = directQ(maxE, maxTwoTheta);
  const auto minmaxQ = std::minmax_element(q.cbegin(), q.cend());
  return std::make_pair(*minmaxQ.first, *minmaxQ.second);
}
Пример #2
0
/**
 * Sum counts from the input workspace in lambda along lines of constant Q by
 * projecting to "virtual lambda" at a reference angle.
 *
 * @param detectorWS [in] :: the input workspace in wavelength
 * @param indices [in] :: an index set defining the foreground histograms
 * @return :: the single histogram output workspace in wavelength
 */
API::MatrixWorkspace_sptr
ReflectometrySumInQ::sumInQ(const API::MatrixWorkspace &detectorWS,
                            const Indexing::SpectrumIndexSet &indices) {

  const auto spectrumInfo = detectorWS.spectrumInfo();
  const auto refAngles = referenceAngles(spectrumInfo);
  // Construct the output workspace in virtual lambda
  API::MatrixWorkspace_sptr IvsLam =
      constructIvsLamWS(detectorWS, indices, refAngles);
  auto &outputE = IvsLam->dataE(0);
  // Loop through each spectrum in the detector group
  for (auto spIdx : indices) {
    if (spectrumInfo.isMasked(spIdx) || spectrumInfo.isMonitor(spIdx)) {
      continue;
    }
    // Get the size of this detector in twoTheta
    const auto twoThetaRange = twoThetaWidth(spIdx, spectrumInfo);
    // Check X length is Y length + 1
    const auto inputBinEdges = detectorWS.binEdges(spIdx);
    const auto inputCounts = detectorWS.counts(spIdx);
    const auto inputStdDevs = detectorWS.countStandardDeviations(spIdx);
    // Create a vector for the projected errors for this spectrum.
    // (Output Y values can simply be accumulated directly into the output
    // workspace, but for error values we need to create a separate error
    // vector for the projected errors from each input spectrum and then
    // do an overall sum in quadrature.)
    std::vector<double> projectedE(outputE.size(), 0.0);
    // Process each value in the spectrum
    const int ySize = static_cast<int>(inputCounts.size());
    for (int inputIdx = 0; inputIdx < ySize; ++inputIdx) {
      // Do the summation in Q
      processValue(inputIdx, twoThetaRange, refAngles, inputBinEdges,
                   inputCounts, inputStdDevs, *IvsLam, projectedE);
    }
    // Sum errors in quadrature
    const int eSize = static_cast<int>(outputE.size());
    for (int outIdx = 0; outIdx < eSize; ++outIdx) {
      outputE[outIdx] += projectedE[outIdx] * projectedE[outIdx];
    }
  }

  // Take the square root of all the accumulated squared errors for this
  // detector group. Assumes Gaussian errors
  double (*rs)(double) = std::sqrt;
  std::transform(outputE.begin(), outputE.end(), outputE.begin(), rs);

  return IvsLam;
}
Пример #3
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;
}
Пример #4
0
/**
 *  Finds the median of values in single bin histograms rejecting spectra from
 * masked
 *  detectors and the results of divide by zero (infinite and NaN).
 * The median is an average that is less affected by small numbers of very large
 * values.
 * @param input :: A histogram workspace with one entry in each bin
 * @param excludeZeroes :: If true then zeroes will not be included in the
 * median calculation
 * @param indexmap :: indexmap
 * @return The median value of the histograms in the workspace that was passed
 * to it
 * @throw out_of_range if a value is negative
 */
std::vector<double> DetectorDiagnostic::calculateMedian(
    const API::MatrixWorkspace &input, bool excludeZeroes,
    const std::vector<std::vector<size_t>> &indexmap) {
  std::vector<double> medianvec;
  g_log.debug("Calculating the median count rate of the spectra");

  bool checkForMask = false;
  Geometry::Instrument_const_sptr instrument = input.getInstrument();
  if (instrument != nullptr) {
    checkForMask = ((instrument->getSource() != nullptr) &&
                    (instrument->getSample() != nullptr));
  }
  const auto &spectrumInfo = input.spectrumInfo();

  for (const auto &hists : indexmap) {
    std::vector<double> medianInput;
    const int nhists = static_cast<int>(hists.size());
    // The maximum possible length is that of workspace length
    medianInput.reserve(nhists);

    PARALLEL_FOR_IF(Kernel::threadSafe(input))
    for (int i = 0; i < nhists; ++i) { // NOLINT
      PARALLEL_START_INTERUPT_REGION

      if (checkForMask && spectrumInfo.hasDetectors(hists[i])) {
        if (spectrumInfo.isMasked(hists[i]) || spectrumInfo.isMonitor(hists[i]))
          continue;
      }

      const double yValue = input.readY(hists[i])[0];
      if (yValue < 0.0) {
        throw std::out_of_range("Negative number of counts found, could be "
                                "corrupted raw counts or solid angle data");
      }
      if (!std::isfinite(yValue) ||
          (excludeZeroes && yValue < DBL_EPSILON)) // NaNs/Infs
      {
        continue;
      }
      // Now we have a good value
      PARALLEL_CRITICAL(DetectorDiagnostic_median_d) {
        medianInput.push_back(yValue);
      }

      PARALLEL_END_INTERUPT_REGION
    }
    PARALLEL_CHECK_INTERUPT_REGION

    if (medianInput.empty()) {
      g_log.information(
          "some group has no valid histograms. Will use 0 for median.");
      medianInput.push_back(0.);
    }

    Kernel::Statistics stats =
        Kernel::getStatistics(medianInput, StatOptions::Median);
    double median = stats.median;

    if (median < 0 || median > DBL_MAX / 10.0) {
      throw std::out_of_range("The calculated value for the median was either "
                              "negative or unreliably large");
    }
    medianvec.push_back(median);
  }
  return medianvec;
}