Beispiel #1
0
  void MinusMD::doMinus(typename MDEventWorkspace<MDE, nd>::sptr ws)
  {
    typename MDEventWorkspace<MDE, nd>::sptr ws1 = ws;
    typename MDEventWorkspace<MDE, nd>::sptr ws2 = boost::dynamic_pointer_cast<MDEventWorkspace<MDE, nd> >(m_operand_event);
    if (!ws1 || !ws2)
      throw std::runtime_error("Incompatible workspace types passed to MinusMD.");

    MDBoxBase<MDE,nd> * box1 = ws1->getBox();
    MDBoxBase<MDE,nd> * box2 = ws2->getBox();

    Progress prog(this, 0.0, 0.4, box2->getBoxController()->getTotalNumMDBoxes());

    // How many events you started with
    size_t initial_numEvents = ws1->getNPoints();

    // Make a leaf-only iterator through all boxes with events in the RHS workspace
    MDBoxIterator<MDE,nd> it2(box2, 1000, true);
    do
    {
      MDBox<MDE,nd> * box = dynamic_cast<MDBox<MDE,nd> *>(it2.getBox());
      if (box)
      {
        // Copy the events from WS2 and add them into WS1
        const std::vector<MDE> & events = box->getConstEvents();

        // Perform a copy while flipping the signal
        std::vector<MDE> eventsCopy;
        eventsCopy.reserve(events.size());
        for (auto it = events.begin(); it != events.end(); it++)
        {
          MDE eventCopy(*it);
          eventCopy.setSignal( -eventCopy.getSignal());
          eventsCopy.push_back(eventCopy);
        }
        // Add events, with bounds checking
        box1->addEvents(eventsCopy);
        box->releaseEvents();
      }
      prog.report("Adding Events");
    } while (it2.next());

    this->progress(0.41, "Splitting Boxes");
    Progress * prog2 = new Progress(this, 0.4, 0.9, 100);
    ThreadScheduler * ts = new ThreadSchedulerFIFO();
    ThreadPool tp(ts, 0, prog2);
    ws1->splitAllIfNeeded(ts);
    prog2->resetNumSteps( ts->size(), 0.4, 0.6);
    tp.joinAll();


    this->progress(0.95, "Refreshing cache");
    ws1->refreshCache();

    // Set a marker that the file-back-end needs updating if the # of events changed.
    if (ws1->getNPoints() != initial_numEvents)
      ws1->setFileNeedsUpdating(true);
  }
/** Execute the algorithm.
 */
void ConvertToDiffractionMDWorkspace::exec() {
  Timer tim, timtotal;
  CPUTimer cputim, cputimtotal;

  // ---------------------- Extract properties
  // --------------------------------------
  ClearInputWorkspace = getProperty("ClearInputWorkspace");
  Append = getProperty("Append");
  std::string OutputDimensions = getPropertyValue("OutputDimensions");
  LorentzCorrection = getProperty("LorentzCorrection");
  OneEventPerBin = getProperty("OneEventPerBin");

  // -------- Input workspace -> convert to Event
  // ------------------------------------
  m_inWS = getProperty("InputWorkspace");
  Workspace2D_sptr m_InWS2D = boost::dynamic_pointer_cast<Workspace2D>(m_inWS);
  if (LorentzCorrection) {
    API::Run &run = m_inWS->mutableRun();
    if (run.hasProperty("LorentzCorrection")) {
      Kernel::Property *prop = run.getProperty("LorentzCorrection");
      bool lorentzDone = boost::lexical_cast<bool, std::string>(prop->value());
      if (lorentzDone) {
        LorentzCorrection = false;
        g_log.warning() << "Lorentz Correction was already done for this "
                           "workspace.  LorentzCorrection was changed to false."
                        << std::endl;
      }
    }
  }

  m_inEventWS = boost::dynamic_pointer_cast<EventWorkspace>(m_inWS);

  // check the input units
  if (m_inWS->getAxis(0)->unit()->unitID() != "TOF")
    throw std::invalid_argument(
        "Input event workspace's X axis must be in TOF units.");

  // Try to get the output workspace
  IMDEventWorkspace_sptr i_out = getProperty("OutputWorkspace");
  ws = boost::dynamic_pointer_cast<
      DataObjects::MDEventWorkspace<DataObjects::MDLeanEvent<3>, 3>>(i_out);

  // Initalize the matrix to 3x3 identity
  mat = Kernel::Matrix<double>(3, 3, true);

  // ----------------- Handle the type of output
  // -------------------------------------

  std::string dimensionNames[3] = {"Q_lab_x", "Q_lab_y", "Q_lab_z"};
  Mantid::Kernel::SpecialCoordinateSystem coordinateSystem =
      Mantid::Kernel::QLab;

  // Setup the MDFrame
  auto frameFactory = makeMDFrameFactoryChain();
  Mantid::Geometry::MDFrame_uptr frame;

  if (OutputDimensions == "Q (sample frame)") {
    // Set the matrix based on goniometer angles
    mat = m_inWS->mutableRun().getGoniometerMatrix();
    // But we need to invert it, since we want to get the Q in the sample frame.
    mat.Invert();
    // Names
    dimensionNames[0] = "Q_sample_x";
    dimensionNames[1] = "Q_sample_y";
    dimensionNames[2] = "Q_sample_z";
    coordinateSystem = Mantid::Kernel::QSample;
    // Frame
    MDFrameArgument frameArgQSample(QSample::QSampleName, "");
    frame = frameFactory->create(frameArgQSample);

  } else if (OutputDimensions == "HKL") {
    // Set the matrix based on UB etc.
    Kernel::Matrix<double> ub =
        m_inWS->mutableSample().getOrientedLattice().getUB();
    Kernel::Matrix<double> gon = m_inWS->mutableRun().getGoniometerMatrix();
    // As per Busing and Levy 1967, q_lab_frame = 2pi * Goniometer * UB * HKL
    // Therefore, HKL = (2*pi * Goniometer * UB)^-1 * q_lab_frame
    mat = gon * ub;
    mat.Invert();
    // Divide by 2 PI to account for our new convention, |Q| = 2pi / wl
    // (December 2011, JZ)
    mat /= (2 * M_PI);
    dimensionNames[0] = "H";
    dimensionNames[1] = "K";
    dimensionNames[2] = "L";
    coordinateSystem = Mantid::Kernel::HKL;
    MDFrameArgument frameArgQLab(HKL::HKLName, Units::Symbol::RLU.ascii());
    frame = frameFactory->create(frameArgQLab);
  } else {
    MDFrameArgument frameArgQLab(QLab::QLabName, "");
    frame = frameFactory->create(frameArgQLab);
  }
  // Q in the lab frame is the default, so nothing special to do.

  if (ws && Append) {
    // Check that existing workspace dimensions make sense with the desired one
    // (using the name)
    if (ws->getDimension(0)->getName() != dimensionNames[0])
      throw std::runtime_error("The existing MDEventWorkspace " +
                               ws->getName() +
                               " has different dimensions than were requested! "
                               "Either give a different name for the output, "
                               "or change the OutputDimensions parameter.");
  }

  // ------------------- Create the output workspace if needed
  // ------------------------
  if (!ws || !Append) {
    // Create an output workspace with 3 dimensions.
    size_t nd = 3;
    i_out = DataObjects::MDEventFactory::CreateMDWorkspace(nd, "MDLeanEvent");
    ws = boost::dynamic_pointer_cast<DataObjects::MDEventWorkspace3Lean>(i_out);

    // ---------------- Get the extents -------------
    std::vector<double> extents = getProperty("Extents");
    // Replicate a single min,max into several
    if (extents.size() == 2) {
      for (size_t d = 1; d < nd; d++) {
        extents.push_back(extents[0]);
        extents.push_back(extents[1]);
      }
    }
    if (extents.size() != nd * 2)
      throw std::invalid_argument(
          "You must specify either 2 or 6 extents (min,max).");

    // Give all the dimensions
    for (size_t d = 0; d < nd; d++) {
      MDHistoDimension *dim =
          new MDHistoDimension(dimensionNames[d], dimensionNames[d], *frame,
                               static_cast<coord_t>(extents[d * 2]),
                               static_cast<coord_t>(extents[d * 2 + 1]), 10);
      ws->addDimension(MDHistoDimension_sptr(dim));
    }
    ws->initialize();

    // Build up the box controller, using the properties in
    // BoxControllerSettingsAlgorithm
    BoxController_sptr bc = ws->getBoxController();
    this->setBoxController(bc, m_inWS->getInstrument());
    // We always want the box to be split (it will reject bad ones)
    ws->splitBox();

    // Perform minimum recursion depth splitting
    int minDepth = this->getProperty("MinRecursionDepth");
    int maxDepth = this->getProperty("MaxRecursionDepth");
    if (minDepth > maxDepth)
      throw std::invalid_argument(
          "MinRecursionDepth must be <= MaxRecursionDepth ");
    ws->setMinRecursionDepth(size_t(minDepth));
  }

  ws->splitBox();

  if (!ws)
    throw std::runtime_error("Error creating a 3D MDEventWorkspace!");

  BoxController_sptr bc = ws->getBoxController();
  if (!bc)
    throw std::runtime_error(
        "Output MDEventWorkspace does not have a BoxController!");

  // Cache the extents for speed.
  m_extentsMin = new coord_t[3];
  m_extentsMax = new coord_t[3];
  for (size_t d = 0; d < 3; d++) {
    m_extentsMin[d] = ws->getDimension(d)->getMinimum();
    m_extentsMax[d] = ws->getDimension(d)->getMaximum();
  }

  // Copy ExperimentInfo (instrument, run, sample) to the output WS
  ExperimentInfo_sptr ei(m_inWS->cloneExperimentInfo());
  uint16_t runIndex = ws->addExperimentInfo(ei);
  UNUSED_ARG(runIndex);

  // ------------------- Cache values that are common for all
  // ---------------------------
  // Extract some parameters global to the instrument
  m_inWS->getInstrument()->getInstrumentParameters(l1, beamline, beamline_norm,
                                                   samplePos);
  beamline_norm = beamline.norm();
  beamDir = beamline / beamline.norm();

  // To get all the detector ID's
  m_inWS->getInstrument()->getDetectors(allDetectors);

  // Estimate the number of events in the final workspace
  size_t totalEvents = m_inWS->size();
  if (m_inEventWS && !OneEventPerBin)
    totalEvents = m_inEventWS->getNumberEvents();
  prog = boost::make_shared<Progress>(this, 0, 1.0, totalEvents);

  // Is the addition of events thread-safe?
  bool MultiThreadedAdding = m_inWS->threadSafe();

  // Create the thread pool that will run all of these.
  ThreadScheduler *ts = new ThreadSchedulerFIFO();
  ThreadPool tp(ts, 0);

  // To track when to split up boxes
  this->failedDetectorLookupCount = 0;
  size_t eventsAdded = 0;
  size_t approxEventsInOutput = 0;
  size_t lastNumBoxes = ws->getBoxController()->getTotalNumMDBoxes();
  if (DODEBUG)
    g_log.information() << cputim << ": initial setup. There are "
                        << lastNumBoxes << " MDBoxes.\n";

  for (size_t wi = 0; wi < m_inWS->getNumberHistograms(); wi++) {
    // Get an idea of how many events we'll be adding
    size_t eventsAdding = m_inWS->blocksize();
    if (m_inEventWS && !OneEventPerBin)
      eventsAdding = m_inEventWS->getEventList(wi).getNumberEvents();

    if (MultiThreadedAdding) {
      // Equivalent to calling "this->convertSpectrum(wi)"
      boost::function<void()> func =
          boost::bind(&ConvertToDiffractionMDWorkspace::convertSpectrum, &*this,
                      static_cast<int>(wi));
      // Give this task to the scheduler
      double cost = static_cast<double>(eventsAdding);
      ts->push(new FunctionTask(func, cost));
    } else {
      // Not thread-safe. Just add right now
      this->convertSpectrum(static_cast<int>(wi));
    }

    // Keep a running total of how many events we've added
    eventsAdded += eventsAdding;
    approxEventsInOutput += eventsAdding;

    if (bc->shouldSplitBoxes(approxEventsInOutput, eventsAdded, lastNumBoxes)) {
      if (DODEBUG)
        g_log.information() << cputim << ": Added tasks worth " << eventsAdded
                            << " events. WorkspaceIndex " << wi << std::endl;
      // Do all the adding tasks
      tp.joinAll();
      if (DODEBUG)
        g_log.information() << cputim
                            << ": Performing the addition of these events.\n";

      // Now do all the splitting tasks
      ws->splitAllIfNeeded(ts);
      if (ts->size() > 0)
        prog->doReport("Splitting Boxes");
      tp.joinAll();

      // Count the new # of boxes.
      lastNumBoxes = ws->getBoxController()->getTotalNumMDBoxes();
      if (DODEBUG)
        g_log.information() << cputim
                            << ": Performing the splitting. There are now "
                            << lastNumBoxes << " boxes.\n";
      eventsAdded = 0;
    }
  }

  if (this->failedDetectorLookupCount > 0) {
    if (this->failedDetectorLookupCount == 1)
      g_log.warning() << "Unable to find a detector for "
                      << this->failedDetectorLookupCount
                      << " spectrum. It has been skipped." << std::endl;
    else
      g_log.warning() << "Unable to find detectors for "
                      << this->failedDetectorLookupCount
                      << " spectra. They have been skipped." << std::endl;
  }

  if (DODEBUG)
    g_log.information() << cputim << ": We've added tasks worth " << eventsAdded
                        << " events.\n";

  tp.joinAll();
  if (DODEBUG)
    g_log.information() << cputim
                        << ": Performing the FINAL addition of these events.\n";

  // Do a final splitting of everything
  ws->splitAllIfNeeded(ts);
  tp.joinAll();
  if (DODEBUG)
    g_log.information()
        << cputim << ": Performing the FINAL splitting of boxes. There are now "
        << ws->getBoxController()->getTotalNumMDBoxes() << " boxes\n";

  // Recount totals at the end.
  cputim.reset();
  ws->refreshCache();
  if (DODEBUG)
    g_log.information() << cputim << ": Performing the refreshCache().\n";

  // TODO: Centroid in parallel, maybe?
  // ws->getBox()->refreshCentroid(NULL);
  // if (DODEBUG) g_log.information() << cputim << ": Performing the
  // refreshCentroid().\n";

  if (DODEBUG) {
    g_log.information() << "Workspace has " << ws->getNPoints()
                        << " events. This took " << cputimtotal
                        << " in total.\n";
    std::vector<std::string> stats = ws->getBoxControllerStats();
    for (auto &stat : stats)
      g_log.information() << stat << "\n";
    g_log.information() << std::endl;
  }

  // Set the special coordinate system.
  ws->setCoordinateSystem(coordinateSystem);

  // Save the output
  setProperty("OutputWorkspace",
              boost::dynamic_pointer_cast<IMDEventWorkspace>(ws));

  // Clean up
  delete[] m_extentsMin;
  delete[] m_extentsMax;
}
Beispiel #3
0
  void PlusMD::doPlus(typename MDEventWorkspace<MDE, nd>::sptr ws)
  {
    typename MDEventWorkspace<MDE, nd>::sptr ws1 = ws;
    typename MDEventWorkspace<MDE, nd>::sptr ws2 = boost::dynamic_pointer_cast<MDEventWorkspace<MDE, nd> >(m_operand_event);
    if (!ws1 || !ws2)
      throw std::runtime_error("Incompatible workspace types passed to PlusMD.");

    MDBoxBase<MDE,nd> * box1 = ws1->getBox();
    MDBoxBase<MDE,nd> * box2 = ws2->getBox();

    Progress prog(this, 0.0, 0.4, box2->getBoxController()->getTotalNumMDBoxes());

    // How many events you started with
    size_t initial_numEvents = ws1->getNPoints();

    // Make a leaf-only iterator through all boxes with events in the RHS workspace
    MDBoxIterator<MDE,nd> it2(box2, 1000, true);
    do
    {
      MDBox<MDE,nd> * box = dynamic_cast<MDBox<MDE,nd> *>(it2.getBox());
      if (box)
      {
        // Copy the events from WS2 and add them into WS1
        const std::vector<MDE> & events = box->getConstEvents();
        // Add events, with bounds checking
        box1->addEvents(events);
        box->releaseEvents();
      }
      prog.report("Adding Events");
    } while (it2.next());

    this->progress(0.41, "Splitting Boxes");
    Progress * prog2 = new Progress(this, 0.4, 0.9, 100);
    ThreadScheduler * ts = new ThreadSchedulerFIFO();
    ThreadPool tp(ts, 0, prog2);
    ws1->splitAllIfNeeded(ts);
    prog2->resetNumSteps( ts->size(), 0.4, 0.6);
    tp.joinAll();

//    // Now we need to save all the data that was not saved before.
//    if (ws1->isFileBacked())
//    {
//      // Flush anything else in the to-write buffer
//      BoxController_sptr bc = ws1->getBoxController();
//
//      prog.resetNumSteps(bc->getTotalNumMDBoxes(), 0.6, 1.0);
//      MDBoxIterator<MDE,nd> it1(box1, 1000, true);
//      while (true)
//      {
//        MDBox<MDE,nd> * box = dynamic_cast<MDBox<MDE,nd> *>(it1.getBox());
//        if (box)
//        {
//          // Something was maybe added to this box
//          if (box->getEventVectorSize() > 0)
//          {
//            // By getting the events, this will merge the newly added and the cached events.
//            box->getEvents();
//            // The MRU to-write cache will optimize writes by reducing seek times
//            box->releaseEvents();
//          }
//        }
//        prog.report("Saving");
//        if (!it1.next()) break;
//      }
//      //bc->getDiskBuffer().flushCache();
//      // Flush the data writes to disk.
//      box1->flushData();
//    }

    this->progress(0.95, "Refreshing cache");
    ws1->refreshCache();

    // Set a marker that the file-back-end needs updating if the # of events changed.
    if (ws1->getNPoints() != initial_numEvents)
      ws1->setFileNeedsUpdating(true);

  }