Skip to content
Snippets Groups Projects
CompareWorkspaces.cpp 51.1 KiB
Newer Older
  // Check that the number of separate logs is the same
  if (ws1logs.size() != ws2logs.size()) {
    g_log.debug() << "WS1 number of logs: " << ws1logs.size() << "\n";
    g_log.debug() << "WS2 number of logs: " << ws2logs.size() << "\n";
    recordMismatch("Different numbers of logs");
    // Sort logs by name before one-by-one comparison
    auto compareNames = [](Kernel::Property *p1, Kernel::Property *p2) {
      return p1->name() < p2->name();
    };
    std::sort(ws1logs.begin(), ws1logs.end(), compareNames);
    std::sort(ws2logs.begin(), ws2logs.end(), compareNames);
    for (size_t i = 0; i < ws1logs.size(); ++i) {
      if (*(ws1logs[i]) != *(ws2logs[i])) {
        if (g_log.is(Logger::Priority::PRIO_DEBUG)) {
          g_log.debug("WS1 log entry mismatch: " + ws1logs[i]->name());
          g_log.debug("WS2 log entry mismatch: " + ws2logs[i]->name());
        recordMismatch("Log mismatch");
        return false;
  return true;
}

//------------------------------------------------------------------------------------------------
/** Compare 2 different events list with detailed information output (Linear)
 * It assumes that the number of events between these 2 are identical
 * el1 :: event list 1
 * el2 :: event list 2
 * tolfTOF :: tolerance of Time-of-flight (in micro-second)
 * tolWeight :: tolerance of weight for weighted neutron events
 * tolPulse :: tolerance of pulse time (in nanosecond)
 * NOTE: there is no need to compare the event type as it has been done by
 * printdetails :: option for comparing. -1: simple, 0: full but no print, 1:
 * @return :: int.  -1: different number of events;  N > 0 : some
 *            events are not same
 */
int CompareWorkspaces::compareEventsListInDetails(
    const EventList &el1, const EventList &el2, double tolTof, double tolWeight,
    int64_t tolPulse, bool printdetails, size_t &numdiffpulse,
    size_t &numdifftof, size_t &numdiffboth, size_t &numdiffweight) const {
  // Check
  if (el1.getNumberEvents() != el2.getNumberEvents())
    throw std::runtime_error(
        "compareEventsListInDetails only work on 2 event lists with same "
        "number of events.");

  switch (el1.getEventType()) {
  case EventType::TOF:
    return compareEventLists<Types::Event::TofEvent>(
        g_log, el1, el2, tolTof, tolWeight, tolPulse, printdetails,
        numdiffpulse, numdifftof, numdiffboth, numdiffweight);
  case EventType::WEIGHTED:
    return compareEventLists<DataObjects::WeightedEvent>(
        g_log, el1, el2, tolTof, tolWeight, tolPulse, printdetails,
        numdiffpulse, numdifftof, numdiffboth, numdiffweight);
  case EventType::WEIGHTED_NOTIME:
    return compareEventLists<DataObjects::WeightedEventNoTime>(
        g_log, el1, el2, tolTof, tolWeight, tolPulse, printdetails,
        numdiffpulse, numdifftof, numdiffboth, numdiffweight);
  default:
    throw std::runtime_error("Cannot compare event lists: unknown event type.");
//------------------------------------------------------------------------------------------------
Samuel Jackson's avatar
Samuel Jackson committed
void CompareWorkspaces::doPeaksComparison(PeaksWorkspace_sptr tws1,
                                          PeaksWorkspace_sptr tws2) {
  // Check some table-based stuff
  if (tws1->getNumberPeaks() != tws2->getNumberPeaks()) {
    recordMismatch("Mismatched number of rows.");
    return;
  }
  if (tws1->columnCount() != tws2->columnCount()) {
    recordMismatch("Mismatched number of columns.");
    return;
  }

  // sort the workspaces before comparing
  {
    auto sortPeaks = createChildAlgorithm("SortPeaksWorkspace");
    sortPeaks->setProperty("InputWorkspace", tws1);
    sortPeaks->setProperty("ColumnNameToSortBy", "DSpacing");
    sortPeaks->setProperty("SortAscending", true);
    sortPeaks->executeAsChildAlg();
    IPeaksWorkspace_sptr tmp1 = sortPeaks->getProperty("OutputWorkspace");
    tws1 = std::dynamic_pointer_cast<PeaksWorkspace>(tmp1);

    sortPeaks = createChildAlgorithm("SortPeaksWorkspace");
    sortPeaks->setProperty("InputWorkspace", tws2);
    sortPeaks->setProperty("ColumnNameToSortBy", "DSpacing");
    sortPeaks->setProperty("SortAscending", true);
    sortPeaks->executeAsChildAlg();
    IPeaksWorkspace_sptr tmp2 = sortPeaks->getProperty("OutputWorkspace");
    tws2 = std::dynamic_pointer_cast<PeaksWorkspace>(tmp2);
  }

  const double tolerance = getProperty("Tolerance");
  for (int i = 0; i < tws1->getNumberPeaks(); i++) {
    const Peak &peak1 = tws1->getPeak(i);
    const Peak &peak2 = tws2->getPeak(i);
    for (size_t j = 0; j < tws1->columnCount(); j++) {
      std::shared_ptr<const API::Column> col = tws1->getColumn(j);
      std::string name = col->name();
      double s1 = 0.0;
      double s2 = 0.0;
      if (name == "RunNumber") {
        s1 = double(peak1.getRunNumber());
        s2 = double(peak2.getRunNumber());
      } else if (name == "DetID") {
        s1 = double(peak1.getDetectorID());
        s2 = double(peak2.getDetectorID());
      } else if (name == "h") {
        s1 = peak1.getH();
        s2 = peak2.getH();
      } else if (name == "k") {
        s1 = peak1.getK();
        s2 = peak2.getK();
      } else if (name == "l") {
        s1 = peak1.getL();
        s2 = peak2.getL();
      } else if (name == "Wavelength") {
        s1 = peak1.getWavelength();
        s2 = peak2.getWavelength();
      } else if (name == "Energy") {
        s1 = peak1.getInitialEnergy();
        s2 = peak2.getInitialEnergy();
      } else if (name == "TOF") {
        s1 = peak1.getTOF();
        s2 = peak2.getTOF();
      } else if (name == "DSpacing") {
        s1 = peak1.getDSpacing();
        s2 = peak2.getDSpacing();
      } else if (name == "Intens") {
        s1 = peak1.getIntensity();
        s2 = peak2.getIntensity();
      } else if (name == "SigInt") {
        s1 = peak1.getSigmaIntensity();
        s2 = peak2.getSigmaIntensity();
      } else if (name == "BinCount") {
        s1 = peak1.getBinCount();
        s2 = peak2.getBinCount();
      } else if (name == "Row") {
        s1 = peak1.getRow();
        s2 = peak2.getRow();
      } else if (name == "Col") {
        s1 = peak1.getCol();
        s2 = peak2.getCol();
      }
      if (std::fabs(s1 - s2) > tolerance) {
        g_log.debug(name);
        g_log.debug() << "s1 = " << s1 << "\n"
                      << "s2 = " << s2 << "\n"
                      << "std::fabs(s1 - s2) = " << std::fabs(s1 - s2) << "\n"
                      << "tolerance = " << tolerance << "\n";
        g_log.debug() << "Data mismatch at cell (row#,col#): (" << i << "," << j
                      << ")\n";
        recordMismatch("Data mismatch");
//------------------------------------------------------------------------------------------------
void CompareWorkspaces::doLeanElasticPeaksComparison(
    LeanElasticPeaksWorkspace_sptr tws1, LeanElasticPeaksWorkspace_sptr tws2) {
  // Check some table-based stuff
  if (tws1->getNumberPeaks() != tws2->getNumberPeaks()) {
    recordMismatch("Mismatched number of rows.");
    return;
  }
  if (tws1->columnCount() != tws2->columnCount()) {
    recordMismatch("Mismatched number of columns.");
    return;
  }

  // sort the workspaces before comparing
  auto sortPeaks = createChildAlgorithm("SortPeaksWorkspace");
  sortPeaks->setProperty("InputWorkspace", tws1);
  sortPeaks->setProperty("ColumnNameToSortBy", "DSpacing");
  sortPeaks->setProperty("SortAscending", true);
  sortPeaks->executeAsChildAlg();
  IPeaksWorkspace_sptr ipws1 = sortPeaks->getProperty("OutputWorkspace");

  sortPeaks = createChildAlgorithm("SortPeaksWorkspace");
  sortPeaks->setProperty("InputWorkspace", tws2);
  sortPeaks->setProperty("ColumnNameToSortBy", "DSpacing");
  sortPeaks->setProperty("SortAscending", true);
  sortPeaks->executeAsChildAlg();
  IPeaksWorkspace_sptr ipws2 = sortPeaks->getProperty("OutputWorkspace");

  const double tolerance = getProperty("Tolerance");
  for (int i = 0; i < ipws1->getNumberPeaks(); i++) {
    for (size_t j = 0; j < ipws1->columnCount(); j++) {
      std::shared_ptr<const API::Column> col = ipws1->getColumn(j);
      std::string name = col->name();
      double s1 = 0.0;
      double s2 = 0.0;
      if (name == "RunNumber") {
        s1 = double(ipws1->getPeak(i).getRunNumber());
        s2 = double(ipws2->getPeak(i).getRunNumber());
      } else if (name == "h") {
        s1 = ipws1->getPeak(i).getH();
        s2 = ipws2->getPeak(i).getH();
      } else if (name == "k") {
        s1 = ipws1->getPeak(i).getK();
        s2 = ipws2->getPeak(i).getK();
      } else if (name == "l") {
        s1 = ipws1->getPeak(i).getL();
        s2 = ipws2->getPeak(i).getL();
      } else if (name == "Wavelength") {
        s1 = ipws1->getPeak(i).getWavelength();
        s2 = ipws2->getPeak(i).getWavelength();
      } else if (name == "DSpacing") {
        s1 = ipws1->getPeak(i).getDSpacing();
        s2 = ipws2->getPeak(i).getDSpacing();
      } else if (name == "Intens") {
        s1 = ipws1->getPeak(i).getIntensity();
        s2 = ipws2->getPeak(i).getIntensity();
      } else if (name == "SigInt") {
        s1 = ipws1->getPeak(i).getSigmaIntensity();
        s2 = ipws2->getPeak(i).getSigmaIntensity();
      } else if (name == "BinCount") {
        s1 = ipws1->getPeak(i).getBinCount();
        s2 = ipws2->getPeak(i).getBinCount();
      } else if (name == "QLab") {
        V3D q1 = ipws1->getPeak(i).getQLabFrame();
        V3D q2 = ipws2->getPeak(i).getQLabFrame();
        // using s1 here as the diff
        for (int i = 0; i < 3; ++i) {
          s1 += (q1[i] - q2[i]) * (q1[i] - q2[i]);
        }
        s1 = std::sqrt(s1);
      } else if (name == "QSample") {
        V3D q1 = ipws1->getPeak(i).getQSampleFrame();
        V3D q2 = ipws2->getPeak(i).getQSampleFrame();
        // using s1 here as the diff
        for (int i = 0; i < 3; ++i) {
          s1 += (q1[i] - q2[i]) * (q1[i] - q2[i]);
        }
      }
      if (std::fabs(s1 - s2) > tolerance) {
        g_log.debug() << "Data mismatch at cell (row#,col#): (" << i << "," << j
                      << ")\n";
        recordMismatch("Data mismatch");
        return;
      }
    }
  }
}

//------------------------------------------------------------------------------------------------
void CompareWorkspaces::doTableComparison(
    const API::ITableWorkspace_const_sptr &tws1,
    const API::ITableWorkspace_const_sptr &tws2) {
  // First the easy things
  const auto numCols = tws1->columnCount();
  if (numCols != tws2->columnCount()) {
    g_log.debug() << "Number of columns mismatch (" << numCols << " vs "
                  << tws2->columnCount() << ")\n";
    recordMismatch("Number of columns mismatch");
    return;
  }
  const auto numRows = tws1->rowCount();
  if (numRows != tws2->rowCount()) {
    g_log.debug() << "Number of rows mismatch (" << numRows << " vs "
                  << tws2->rowCount() << ")\n";
    recordMismatch("Number of rows mismatch");
    return;
  }

  for (size_t i = 0; i < numCols; ++i) {
    auto c1 = tws1->getColumn(i);
    auto c2 = tws2->getColumn(i);

    if (c1->name() != c2->name()) {
      g_log.debug() << "Column name mismatch at column " << i << " ("
                    << c1->name() << " vs " << c2->name() << ")\n";
      recordMismatch("Column name mismatch");
      return;
    }
    if (c1->type() != c2->type()) {
      g_log.debug() << "Column type mismatch at column " << i << " ("
                    << c1->type() << " vs " << c2->type() << ")\n";
      recordMismatch("Column type mismatch");
      return;
    }
  }

  const bool checkAllData = getProperty("CheckAllData");
  const bool relErr = getProperty("ToleranceRelErr");
  const double tolerance = getProperty("Tolerance");
  bool mismatch = false;
  for (size_t i = 0; i < numCols; ++i) {
    const auto c1 = tws1->getColumn(i);
    const auto c2 = tws2->getColumn(i);
      if (!c1->equalsRelErr(*c2, tolerance)) {
        mismatch = true;
      if (!c1->equals(*c2, tolerance)) {
        mismatch = true;
      }
    }
    if (mismatch) {
      g_log.debug() << "Table data mismatch at column " << i << "\n";
      recordMismatch("Table data mismatch");
      mismatch = false;
      if (!checkAllData) {
//------------------------------------------------------------------------------------------------
void CompareWorkspaces::doMDComparison(const Workspace_sptr &w1,
                                       const Workspace_sptr &w2) {
  IMDWorkspace_sptr mdws1, mdws2;
  mdws1 = std::dynamic_pointer_cast<IMDWorkspace>(w1);
  mdws2 = std::dynamic_pointer_cast<IMDWorkspace>(w2);

  IAlgorithm_sptr alg = this->createChildAlgorithm("CompareMDWorkspaces");
  alg->setProperty<IMDWorkspace_sptr>("Workspace1", mdws1);
  alg->setProperty<IMDWorkspace_sptr>("Workspace2", mdws2);
  const double tolerance = getProperty("Tolerance");
  alg->setProperty("Tolerance", tolerance);
  alg->executeAsChildAlg();
  bool doesMatch = alg->getProperty("Equals");
  std::string algResult = alg->getProperty("Result");
  if (!doesMatch) {
//------------------------------------------------------------------------------------------------
/**
 * Records a mismatch that has occurred in the output workspace and sets the
 * Result to indicate that the input workspaces did not match.
 *
 * @param msg Mismatch message to be logged in output workspace
 * @param ws1 Name of first workspace being compared
 * @param ws2 Name of second workspace being compared
void CompareWorkspaces::recordMismatch(const std::string &msg, std::string ws1,
                                       std::string ws2) {
  // Workspace names default to the workspaces currently being compared
  if (ws1.empty()) {
    Workspace_const_sptr w1 = getProperty("Workspace1");
  }
  if (ws2.empty()) {
    Workspace_const_sptr w2 = getProperty("Workspace2");
  }

  // Add new row and flag this comparison as a mismatch
  TableRow row = m_messages->appendRow();
//------------------------------------------------------------------------------------------------
/** Function which calculates relative error between two values and analyses if
this error is within the limits
* requested. When the absolute value of the difference is smaller then the value
of the error requested,
* absolute error is used instead of relative error.

@param x1       -- first value to check difference
@param x2       -- second value to check difference
@param errorVal -- the value of the error, to check against. Should  be large
then 0

@returns true if error or false if the value is within the limits requested
*/
bool CompareWorkspaces::relErr(double x1, double x2, double errorVal) const {
  double num = std::fabs(x1 - x2);
  // how to treat x1<0 and x2 > 0 ?  probably this way
  double den = 0.5 * (std::fabs(x1) + std::fabs(x2));
  if (den < errorVal)
    return (num > errorVal);

  return (num / den > errorVal);
}

Parallel::ExecutionMode CompareWorkspaces::getParallelExecutionMode(
    const std::map<std::string, Parallel::StorageMode> &storageModes) const {
  using namespace Parallel;
  if (storageModes.at("Workspace1") == StorageMode::Cloned) {
    if (storageModes.at("Workspace2") == StorageMode::Cloned)
      return getCorrespondingExecutionMode(StorageMode::Cloned);
    if (storageModes.at("Workspace2") == StorageMode::MasterOnly)
      return getCorrespondingExecutionMode(StorageMode::MasterOnly);
  }
  if (storageModes.at("Workspace1") == StorageMode::MasterOnly) {
    if (storageModes.at("Workspace2") != StorageMode::Distributed)
      return getCorrespondingExecutionMode(StorageMode::MasterOnly);
  }
  return ExecutionMode::Invalid;
}

void CompareWorkspaces::execMasterOnly() {
  if (communicator().rank() == 0)
    exec();
  else
    setProperty("Result", true);
}

} // namespace Algorithms
} // namespace Mantid