Example #1
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;
}