/*
    Execute the transformtion. Generates an output IMDEventWorkspace.
    @return the constructed IMDEventWorkspace following the transformation.
    @param ws: Input MatrixWorkspace const shared pointer
    */
    IMDEventWorkspace_sptr ReflectometryTransformQxQz::execute(MatrixWorkspace_const_sptr inputWs) const
    {
      const size_t nbinsx = 10;
      const size_t nbinsz = 10;

      auto ws = boost::make_shared<MDEventWorkspace<MDLeanEvent<2>,2> >();
      MDHistoDimension_sptr qxDim = MDHistoDimension_sptr(new MDHistoDimension("Qx","qx","(Ang^-1)", static_cast<Mantid::coord_t>(m_qxMin), static_cast<Mantid::coord_t>(m_qxMax), nbinsx)); 
      MDHistoDimension_sptr qzDim = MDHistoDimension_sptr(new MDHistoDimension("Qz","qz","(Ang^-1)", static_cast<Mantid::coord_t>(m_qzMin), static_cast<Mantid::coord_t>(m_qzMax), nbinsz)); 

      ws->addDimension(qxDim);
      ws->addDimension(qzDim);

      // Set some reasonable values for the box controller
      BoxController_sptr bc = ws->getBoxController();
      bc->setSplitInto(2);
      bc->setSplitThreshold(10);

      // Initialize the workspace.
      ws->initialize();

      // Start with a MDGridBox.
      ws->splitBox();

      auto spectraAxis = inputWs->getAxis(1);
      for(size_t index = 0; index < inputWs->getNumberHistograms(); ++index)
      {
        auto counts = inputWs->readY(index);
        auto wavelengths = inputWs->readX(index);
        auto errors = inputWs->readE(index);
        const size_t nInputBins =  wavelengths.size() -1;
        const double theta_final = spectraAxis->getValue(index);
        m_QxCalculation.setThetaFinal(theta_final);
        m_QzCalculation.setThetaFinal(theta_final);
        //Loop over all bins in spectra 
        for(size_t binIndex = 0; binIndex < nInputBins; ++binIndex)
        {
          const double& wavelength = 0.5*(wavelengths[binIndex] + wavelengths[binIndex+1]);
          double _qx = m_QxCalculation.execute(wavelength);
          double _qz = m_QzCalculation.execute(wavelength);
          double centers[2] = {_qx, _qz};

          ws->addEvent(MDLeanEvent<2>(float(counts[binIndex]), float(errors[binIndex]*errors[binIndex]), centers));
        }
        ws->splitAllIfNeeded(NULL);
      }
      return ws;
    }
Ejemplo n.º 2
0
  void CloneMDWorkspace::doClone(const typename MDEventWorkspace<MDE, nd>::sptr ws)
  {
    std::string outWSName = getPropertyValue("OutputWorkspace");
    Progress prog(this, 0.0, 10.0, 100);
    BoxController_sptr bc = ws->getBoxController();

    if (!bc) throw std::runtime_error("Error with InputWorkspace: no BoxController!");
    if (bc->isFileBacked())
    {
      // Generate a new filename to copy to
      prog.report("Copying File");
      std::string originalFile = bc->getFilename();
      std::string outFilename = getPropertyValue("Filename");
      if (outFilename.empty())
      {
        // Auto-generated name
        Poco::Path path = Poco::Path(originalFile).absolute();
        std::string newName = path.getBaseName() + "_clone." + path.getExtension();
        path.setFileName(newName);
        outFilename = path.toString();
      }

      // Perform the copying
      g_log.notice() << "Cloned workspace file being copied to: " << outFilename << std::endl;
      Poco::File(originalFile).copyTo(outFilename);
      g_log.information() << "File copied successfully." << std::endl;

      // Now load it back
      IAlgorithm_sptr alg = createSubAlgorithm("LoadMD", 0.5, 1.0, false);
      alg->setPropertyValue("Filename", outFilename);
      alg->setPropertyValue("FileBackEnd", "1");
      alg->setPropertyValue("Memory", "0"); //TODO: How much memory?
      alg->setPropertyValue("OutputWorkspace", outWSName);
      alg->executeAsSubAlg();

      // Set the output workspace to this
      IMDEventWorkspace_sptr outWS = alg->getProperty("OutputWorkspace");
      this->setProperty("OutputWorkspace", outWS);
    }
    else
    {
      // Perform the clone in memory.
      boost::shared_ptr<MDEventWorkspace<MDE,nd> > outWS(new MDEventWorkspace<MDE,nd>(*ws));
      this->setProperty("OutputWorkspace", boost::dynamic_pointer_cast<IMDEventWorkspace>(outWS) );
    }
  }
/** Set the settings in the given box controller
 * This should only be called immediately after creating the workspace
 *
 * @param bc :: box controller to modify
 * @param instrument :: instrument to read parameters from.
 */
void BoxControllerSettingsAlgorithm::setBoxController(
    BoxController_sptr bc, Mantid::Geometry::Instrument_const_sptr instrument) {
  size_t nd = bc->getNDims();

  takeDefaultsFromInstrument(instrument, nd);

  setBoxController(bc);
}
Ejemplo n.º 4
0
/**
 * Creates an MD workspace
 * @param a : pointer to the first dimension of the MDWorkspace
  *@param b : pointer to the second dimension of the MDWorkspace
 * @param boxController : controls how the MDWorkspace will be split
 */
boost::shared_ptr<MDEventWorkspace2Lean>
ReflectometryTransform::createMDWorkspace(
    Mantid::Geometry::IMDDimension_sptr a,
    Mantid::Geometry::IMDDimension_sptr b,
    BoxController_sptr boxController) const {
  auto ws = boost::make_shared<MDEventWorkspace2Lean>();

  ws->addDimension(a);
  ws->addDimension(b);

  BoxController_sptr wsbc = ws->getBoxController(); // Get the box controller
  wsbc->setSplitInto(boxController->getSplitInto(0));
  wsbc->setMaxDepth(boxController->getMaxDepth());
  wsbc->setSplitThreshold(boxController->getSplitThreshold());

  // Initialize the workspace.
  ws->initialize();

  // Start with a MDGridBox.
  ws->splitBox();
  return ws;
}
/** Set the settings in the given box controller
 * This should only be called immediately after creating the workspace
 *
 * @param bc :: box controller to modify
 */
void BoxControllerSettingsAlgorithm::setBoxController(BoxController_sptr bc) {
  size_t nd = bc->getNDims();

  int val;
  val = this->getProperty("SplitThreshold");
  bc->setSplitThreshold(val);
  val = this->getProperty("MaxRecursionDepth");
  bc->setMaxDepth(val);

  // Build MDGridBox
  std::vector<int> splits = getProperty("SplitInto");
  if (splits.size() == 1) {
    bc->setSplitInto(splits[0]);
  } else if (splits.size() == nd) {
    for (size_t d = 0; d < nd; ++d)
      bc->setSplitInto(d, splits[d]);
  } else
    throw std::invalid_argument("SplitInto parameter has " +
                                Strings::toString(splits.size()) +
                                " arguments. It should have either 1, or the "
                                "same as the number of dimensions.");
  bc->resetNumBoxes();
}
/** 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;
}
Ejemplo n.º 7
0
void SliceMD::slice(typename MDEventWorkspace<MDE, nd>::sptr ws) {
  // Create the ouput workspace
  typename MDEventWorkspace<OMDE, ond>::sptr outWS(
      new MDEventWorkspace<OMDE, ond>());
  for (size_t od = 0; od < m_binDimensions.size(); od++) {
    outWS->addDimension(m_binDimensions[od]);
  }
  outWS->setCoordinateSystem(ws->getSpecialCoordinateSystem());
  outWS->initialize();
  // Copy settings from the original box controller
  BoxController_sptr bc = ws->getBoxController();

  // store wrute buffer size for the future
  // uint64_t writeBufSize =
  // bc->getFileIO()getDiskBuffer().getWriteBufferSize();
  // and disable write buffer (if any) for input MD Events for this algorithm
  // purposes;
  // bc->setCacheParameters(1,0);

  BoxController_sptr obc = outWS->getBoxController();
  // Use the "number of bins" as the "split into" parameter
  for (size_t od = 0; od < m_binDimensions.size(); od++)
    obc->setSplitInto(od, m_binDimensions[od]->getNBins());
  obc->setSplitThreshold(bc->getSplitThreshold());

  bool bTakeDepthFromInputWorkspace =
      getProperty("TakeMaxRecursionDepthFromInput");
  int tempDepth = getProperty("MaxRecursionDepth");
  size_t maxDepth =
      bTakeDepthFromInputWorkspace ? bc->getMaxDepth() : size_t(tempDepth);
  obc->setMaxDepth(maxDepth);

  // size_t outputSize = writeBufSize;
  // obc->setCacheParameters(sizeof(OMDE),outputSize);

  obc->resetNumBoxes();
  // Perform the first box splitting
  outWS->splitBox();
  size_t lastNumBoxes = obc->getTotalNumMDBoxes();

  // --- File back end ? ----------------
  std::string filename = getProperty("OutputFilename");
  if (!filename.empty()) {

    // First save to the NXS file
    g_log.notice() << "Running SaveMD to create file back-end" << std::endl;
    IAlgorithm_sptr alg = createChildAlgorithm("SaveMD");
    alg->setPropertyValue("Filename", filename);
    alg->setProperty("InputWorkspace", outWS);
    alg->setProperty("MakeFileBacked", true);
    alg->executeAsChildAlg();

    if (!obc->isFileBacked())
      throw std::runtime_error("SliceMD with file-backed output: Can not set "
                               "up file-backed output workspace ");

    auto IOptr = obc->getFileIO();
    size_t outBufSize = IOptr->getWriteBufferSize();
    // the buffer size for resulting workspace; reasonable size is at least 10
    // data chunk sizes (nice to verify)
    if (outBufSize < 10 * IOptr->getDataChunk()) {
      outBufSize = 10 * IOptr->getDataChunk();
      IOptr->setWriteBufferSize(outBufSize);
    }
  }

  // Function defining which events (in the input dimensions) to place in the
  // output
  MDImplicitFunction *function = this->getImplicitFunctionForChunk(NULL, NULL);

  std::vector<API::IMDNode *> boxes;
  // Leaf-only; no depth limit; with the implicit function passed to it.
  ws->getBox()->getBoxes(boxes, 1000, true, function);
  // Sort boxes by file position IF file backed. This reduces seeking time,
  // hopefully.
  bool fileBackedWS = bc->isFileBacked();
  if (fileBackedWS)
    API::IMDNode::sortObjByID(boxes);

  Progress *prog = new Progress(this, 0.0, 1.0, boxes.size());

  // The root of the output workspace
  MDBoxBase<OMDE, ond> *outRootBox = outWS->getBox();

  // if target workspace has events, we should count them as added
  uint64_t totalAdded = outWS->getNEvents();
  uint64_t numSinceSplit = 0;

  // Go through every box for this chunk.
  // PARALLEL_FOR_IF( !bc->isFileBacked() )
  for (int i = 0; i < int(boxes.size()); i++) {
    MDBox<MDE, nd> *box = dynamic_cast<MDBox<MDE, nd> *>(boxes[i]);
    // Perform the binning in this separate method.
    if (box) {
      // An array to hold the rotated/transformed coordinates
      coord_t outCenter[ond];

      const std::vector<MDE> &events = box->getConstEvents();

      typename std::vector<MDE>::const_iterator it = events.begin();
      typename std::vector<MDE>::const_iterator it_end = events.end();
      for (; it != it_end; it++) {
        // Cache the center of the event (again for speed)
        const coord_t *inCenter = it->getCenter();

        if (function->isPointContained(inCenter)) {
          // Now transform to the output dimensions
          m_transformFromOriginal->apply(inCenter, outCenter);

          // Create the event
          OMDE newEvent(it->getSignal(), it->getErrorSquared(), outCenter);
          // Copy extra data, if any
          copyEvent(*it, newEvent);
          // Add it to the workspace
          outRootBox->addEvent(newEvent);

          numSinceSplit++;
        }
      }
      box->releaseEvents();

      // Ask BC if one needs to split boxes
      if (obc->shouldSplitBoxes(totalAdded, numSinceSplit, lastNumBoxes))
      // if (numSinceSplit > 20000000 || (i == int(boxes.size()-1)))
      {
        // This splits up all the boxes according to split thresholds and sizes.
        Kernel::ThreadScheduler *ts = new ThreadSchedulerFIFO();
        ThreadPool tp(ts);
        outWS->splitAllIfNeeded(ts);
        tp.joinAll();
        // Accumulate stats
        totalAdded += numSinceSplit;
        numSinceSplit = 0;
        lastNumBoxes = obc->getTotalNumMDBoxes();
        // Progress reporting
        if (!fileBackedWS)
          prog->report(i);
      }
      if (fileBackedWS) {
        if (!(i % 10))
          prog->report(i);
      }
    } // is box

  } // for each box in the vector
  prog->report();

  outWS->splitAllIfNeeded(NULL);
  // Refresh all cache.
  outWS->refreshCache();

  g_log.notice() << totalAdded << " " << OMDE::getTypeName()
                 << "'s added to the output workspace." << std::endl;

  if (outWS->isFileBacked()) {
    // Update the file-back-end
    g_log.notice() << "Running SaveMD" << std::endl;
    IAlgorithm_sptr alg = createChildAlgorithm("SaveMD");
    alg->setProperty("UpdateFileBackEnd", true);
    alg->setProperty("InputWorkspace", outWS);
    alg->executeAsChildAlg();
  }
  // return the size of the input workspace write buffer to its initial value
  // bc->setCacheParameters(sizeof(MDE),writeBufSize);
  this->setProperty("OutputWorkspace",
                    boost::dynamic_pointer_cast<IMDEventWorkspace>(outWS));
  delete prog;
}
Ejemplo n.º 8
0
void BinMD::binByIterating(typename MDEventWorkspace<MDE, nd>::sptr ws) {
  BoxController_sptr bc = ws->getBoxController();
  // store exisiting write buffer size for the future
  // uint64_t writeBufSize =bc->getDiskBuffer().getWriteBufferSize();
  // and disable write buffer (if any) for input MD Events for this algorithm
  // purposes;
  // bc->setCacheParameters(1,0);

  // Cache some data to speed up accessing them a bit
  indexMultiplier = new size_t[m_outD];
  for (size_t d = 0; d < m_outD; d++) {
    if (d > 0)
      indexMultiplier[d] = outWS->getIndexMultiplier()[d - 1];
    else
      indexMultiplier[d] = 1;
  }
  signals = outWS->getSignalArray();
  errors = outWS->getErrorSquaredArray();
  numEvents = outWS->getNumEventsArray();

  // Start with signal/error/numEvents at 0.0
  outWS->setTo(0.0, 0.0, 0.0);

  // The dimension (in the output workspace) along which we chunk for parallel
  // processing
  // TODO: Find the smartest dimension to chunk against
  size_t chunkDimension = 0;

  // How many bins (in that dimension) per chunk.
  // Try to split it so each core will get 2 tasks:
  int chunkNumBins = int(m_binDimensions[chunkDimension]->getNBins() /
                         (PARALLEL_GET_MAX_THREADS * 2));
  if (chunkNumBins < 1)
    chunkNumBins = 1;

  // Do we actually do it in parallel?
  bool doParallel = getProperty("Parallel");
  // Not if file-backed!
  if (bc->isFileBacked())
    doParallel = false;
  if (!doParallel)
    chunkNumBins = int(m_binDimensions[chunkDimension]->getNBins());

  // Total number of steps
  size_t progNumSteps = 0;
  if (prog)
    prog->setNotifyStep(0.1);
  if (prog)
    prog->resetNumSteps(100, 0.00, 1.0);

  // Run the chunks in parallel. There is no overlap in the output workspace so
  // it is thread safe to write to it..
  // cppcheck-suppress syntaxError
    PRAGMA_OMP( parallel for schedule(dynamic,1) if (doParallel) )
    for (int chunk = 0;
         chunk < int(m_binDimensions[chunkDimension]->getNBins());
         chunk += chunkNumBins) {
      PARALLEL_START_INTERUPT_REGION
      // Region of interest for this chunk.
      std::vector<size_t> chunkMin(m_outD);
      std::vector<size_t> chunkMax(m_outD);
      for (size_t bd = 0; bd < m_outD; bd++) {
        // Same limits in the other dimensions
        chunkMin[bd] = 0;
        chunkMax[bd] = m_binDimensions[bd]->getNBins();
      }
      // Parcel out a chunk in that single dimension dimension
      chunkMin[chunkDimension] = size_t(chunk);
      if (size_t(chunk + chunkNumBins) >
          m_binDimensions[chunkDimension]->getNBins())
        chunkMax[chunkDimension] = m_binDimensions[chunkDimension]->getNBins();
      else
        chunkMax[chunkDimension] = size_t(chunk + chunkNumBins);

      // Build an implicit function (it needs to be in the space of the
      // MDEventWorkspace)
      MDImplicitFunction *function =
          this->getImplicitFunctionForChunk(chunkMin.data(), chunkMax.data());

      // Use getBoxes() to get an array with a pointer to each box
      std::vector<API::IMDNode *> boxes;
      // Leaf-only; no depth limit; with the implicit function passed to it.
      ws->getBox()->getBoxes(boxes, 1000, true, function);

      // Sort boxes by file position IF file backed. This reduces seeking time,
      // hopefully.
      if (bc->isFileBacked())
        API::IMDNode::sortObjByID(boxes);

      // For progress reporting, the # of boxes
      if (prog) {
        PARALLEL_CRITICAL(BinMD_progress) {
          g_log.debug() << "Chunk " << chunk << ": found " << boxes.size()
                        << " boxes within the implicit function.\n";
          progNumSteps += boxes.size();
          prog->setNumSteps(progNumSteps);
        }
      }

      // Go through every box for this chunk.
      for (auto &boxe : boxes) {
        MDBox<MDE, nd> *box = dynamic_cast<MDBox<MDE, nd> *>(boxe);
        // Perform the binning in this separate method.
        if (box && !box->getIsMasked())
          this->binMDBox(box, chunkMin.data(), chunkMax.data());

        // Progress reporting
        if (prog)
          prog->report();
        // For early cancelling of the loop
        if (this->m_cancel)
          break;
      } // for each box in the vector
      PARALLEL_END_INTERUPT_REGION
    } // for each chunk in parallel
    PARALLEL_CHECK_INTERUPT_REGION

    // Now the implicit function
    if (implicitFunction) {
      if (prog)
        prog->report("Applying implicit function.");
      signal_t nan = std::numeric_limits<signal_t>::quiet_NaN();
      outWS->applyImplicitFunction(implicitFunction, nan, nan);
    }

    // return the size of the input workspace write buffer to its initial value
    // bc->setCacheParameters(sizeof(MDE),writeBufSize);
}
Ejemplo n.º 9
0
  /** Perform the merging, but clone the initial workspace and use the same splitting
   * as its structure is equivalent to the partial box structures. 
   *
   * @param ws :: first MDEventWorkspace in the list to merge to.
   * @param outputFile :: the name of the output file where file-based workspace should be saved
   */
  void MergeMDFiles::doExecByCloning(Mantid::API::IMDEventWorkspace_sptr ws,const std::string &outputFile)
  {
    m_OutIWS = ws;
    m_MDEventType = ws->getEventTypeName();


   // Run the tasks in parallel? TODO: enable
    //bool Parallel = this->getProperty("Parallel");

    // Fix the box controller settings in the output workspace so that it splits normally
    BoxController_sptr bc = ws->getBoxController();
    // set up internal variables characterizing the workspace. 
    m_nDims = static_cast<int>(bc->getNDims());


    // Fix the max depth to something bigger.
    bc->setMaxDepth(20);
    bc->setSplitThreshold(5000);
    auto saver = boost::shared_ptr<API::IBoxControllerIO>(new MDEvents::BoxControllerNeXusIO(bc.get()));
    saver->setDataType(sizeof(coord_t),m_MDEventType);    
    if(m_fileBasedTargetWS)
    {
        bc->setFileBacked(saver,outputFile);
    // Complete the file-back-end creation.
        g_log.notice() << "Setting cache to 400 MB write." << std::endl;
        bc->getFileIO()->setWriteBufferSize(400000000/m_OutIWS->sizeofEvent());
    }

 /*   else
    {
        saver->openFile(outputFile,"w");
    }*/
    // Init box structure used for memory/file space calculations
    m_BoxStruct.initFlatStructure(ws,outputFile);

    // First, load all the box data and experiment info and calculate file positions of the target workspace
    this->loadBoxData();



    size_t numBoxes = m_BoxStruct.getNBoxes();
      // Progress report based on events processed.
    this->prog = new Progress(this, 0.1, 0.9, size_t(numBoxes));
    prog->setNotifyStep(0.1);

    // For tracking progress
    //uint64_t totalEventsInTasks = 0;
   
    // Prepare thread pool
    CPUTimer overallTime;

    ThreadSchedulerFIFO * ts = new ThreadSchedulerFIFO();
    ThreadPool tp(ts);

    Kernel::DiskBuffer *DiskBuf(NULL);
    if(m_fileBasedTargetWS)
    {
        DiskBuf = bc->getFileIO();
    }

    this->totalLoaded = 0;
    std::vector<API::IMDNode *> &boxes = m_BoxStruct.getBoxes();

    for(size_t ib=0;ib<numBoxes;ib++)
    {
      auto box = boxes[ib];
      if(!box->isBox())continue;
      // load all contributed events into current box;
      this->loadEventsFromSubBoxes(boxes[ib]);

      if(DiskBuf)
      {
        if(box->getDataInMemorySize()>0)
        {  // data position has been already precalculated 
            box->getISaveable()->save();
            box->clearDataFromMemory();
            //Kernel::ISaveable *Saver = box->getISaveable();
            //DiskBuf->toWrite(Saver);
        }
      }
      //else
      //{   size_t ID = box->getID();
      //    uint64_t filePosition = targetEventIndexes[2*ID];
      //    box->saveAt(saver.get(), filePosition);
      //}
      //
      //if (!Parallel)
      //{
      //  // Run the task serially only
      //  task->run();
      //  delete task;
      //}
      //else
      //{
      //  // Enqueue to run in parallel (at the joinAll() call below).
      //  ts->push(task);
      //}

      prog->reportIncrement(ib,"Loading and merging box data");
    }
    if(DiskBuf)
    {
      DiskBuf->flushCache();
      bc->getFileIO()->flushData();
    }
    //// Run any final tasks
    //tp.joinAll();
    g_log.information() << overallTime << " to do all the adding." << std::endl;

    // Close any open file handle
    clearEventLoaders();

    // Finish things up
    this->finalizeOutput(outputFile);
  }
Ejemplo n.º 10
0
void LoadMD::doLoad(typename MDEventWorkspace<MDE, nd>::sptr ws) {
  // Are we using the file back end?
  bool fileBackEnd = getProperty("FileBackEnd");

  if (fileBackEnd && m_BoxStructureAndMethadata)
    throw std::invalid_argument("Combination of BoxStructureOnly or "
                                "MetaDataOnly were set to TRUE with "
                                "fileBackEnd "
                                ": this is not possible.");

  CPUTimer tim;
  auto prog = new Progress(this, 0.0, 1.0, 100);

  prog->report("Opening file.");
  std::string title;
  try {
    m_file->getAttr("title", title);
  } catch (std::exception &) {
    // Leave the title blank if error on loading
  }
  ws->setTitle(title);

  // Load the WorkspaceHistory "process"
  if (this->getProperty("LoadHistory")) {
    ws->history().loadNexus(m_file.get());
  }

  this->loadAffineMatricies(boost::dynamic_pointer_cast<IMDWorkspace>(ws));

  m_file->closeGroup();
  m_file->close();
  // Add each of the dimension
  for (size_t d = 0; d < nd; d++)
    ws->addDimension(m_dims[d]);

  // Coordinate system
  ws->setCoordinateSystem(m_coordSystem);

  // ----------------------------------------- Box Structure
  // ------------------------------
  prog->report("Reading box structure from HDD.");
  MDBoxFlatTree FlatBoxTree;
  int nDims = static_cast<int>(nd); // should be safe
  FlatBoxTree.loadBoxStructure(m_filename, nDims, MDE::getTypeName());

  BoxController_sptr bc = ws->getBoxController();
  bc->fromXMLString(FlatBoxTree.getBCXMLdescr());

  prog->report("Restoring box structure and connectivity");
  std::vector<API::IMDNode *> boxTree;
  FlatBoxTree.restoreBoxTree(boxTree, bc, fileBackEnd,
                             m_BoxStructureAndMethadata);
  size_t numBoxes = boxTree.size();

  // ---------------------------------------- DEAL WITH BOXES
  // ------------------------------------
  if (fileBackEnd) { // TODO:: call to the file format factory
    auto loader = boost::shared_ptr<API::IBoxControllerIO>(
        new DataObjects::BoxControllerNeXusIO(bc.get()));
    loader->setDataType(sizeof(coord_t), MDE::getTypeName());
    bc->setFileBacked(loader, m_filename);
    // boxes have been already made file-backed when restoring the boxTree;
    // How much memory for the cache?
    {
      // TODO: Clean up, only a write buffer now
      double mb = getProperty("Memory");

      // Defaults have changed, default disk buffer size should be 10 data
      // chunks TODO: find optimal, 100 may be better.
      if (mb <= 0)
        mb = double(10 * loader->getDataChunk() * sizeof(MDE)) /
             double(1024 * 1024);

      // Express the cache memory in units of number of events.
      uint64_t cacheMemory =
          static_cast<uint64_t>((mb * 1024. * 1024.) / sizeof(MDE)) + 1;

      // Set these values in the diskMRU
      bc->getFileIO()->setWriteBufferSize(cacheMemory);

      g_log.information() << "Setting a DiskBuffer cache size of " << mb
                          << " MB, or " << cacheMemory << " events.\n";
    }
  } // Not file back end
  else if (!m_BoxStructureAndMethadata) {
    // ---------------------------------------- READ IN THE BOXES
    // ------------------------------------
    // TODO:: call to the file format factory
    auto loader =
        file_holder_type(new DataObjects::BoxControllerNeXusIO(bc.get()));
    loader->setDataType(sizeof(coord_t), MDE::getTypeName());

    loader->openFile(m_filename, "r");

    const std::vector<uint64_t> &BoxEventIndex = FlatBoxTree.getEventIndex();
    prog->setNumSteps(numBoxes);

    for (size_t i = 0; i < numBoxes; i++) {
      prog->report();
      MDBox<MDE, nd> *box = dynamic_cast<MDBox<MDE, nd> *>(boxTree[i]);
      if (!box)
        continue;

      if (BoxEventIndex[2 * i + 1] >
          0) // Load in memory NOT using the file as the back-end,
      {
        boxTree[i]->reserveMemoryForLoad(BoxEventIndex[2 * i + 1]);
        boxTree[i]->loadAndAddFrom(
            loader.get(), BoxEventIndex[2 * i],
            static_cast<size_t>(BoxEventIndex[2 * i + 1]));
      }
    }
    loader->closeFile();
  } else // box structure and metadata only
  {
  }
  g_log.debug() << tim
                << " to create all the boxes and fill them with events.\n";

  // Box of ID 0 is the head box.
  ws->setBox(boxTree[0]);
  // Make sure the max ID is ok for later ID generation
  bc->setMaxId(numBoxes);

  // end-of bMetaDataOnly
  // Refresh cache
  // TODO:if(!fileBackEnd)ws->refreshCache();
  ws->refreshCache();
  g_log.debug() << tim << " to refreshCache(). " << ws->getNPoints()
                << " points after refresh.\n";

  g_log.debug() << tim << " to finish up.\n";
  delete prog;
}
Ejemplo n.º 11
0
void SaveMD::doSaveEvents(typename MDEventWorkspace<MDE, nd>::sptr ws) {
  std::string filename = getPropertyValue("Filename");
  bool update = getProperty("UpdateFileBackEnd");
  bool MakeFileBacked = getProperty("MakeFileBacked");

  bool wsIsFileBacked = ws->isFileBacked();
  if (update && MakeFileBacked)
    throw std::invalid_argument(
        "Please choose either UpdateFileBackEnd or MakeFileBacked, not both.");

  if (MakeFileBacked && wsIsFileBacked)
    throw std::invalid_argument(
        "You picked MakeFileBacked but the workspace is already file-backed!");

  BoxController_sptr bc = ws->getBoxController();

  if (!wsIsFileBacked) { // Erase the file if it exists
    Poco::File oldFile(filename);
    if (oldFile.exists())
      oldFile.remove();
  }

  auto prog = new Progress(this, 0.0, 0.05, 1);
  if (update) // workspace has its own file and ignores any changes to the
              // algorithm parameters
  {
    if (!ws->isFileBacked())
      throw std::runtime_error(" attempt to update non-file backed workspace");
    filename = bc->getFileIO()->getFileName();
  }

  //-----------------------------------------------------------------------------------------------------
  // create or open WS group and put there additional information about WS and
  // its dimensions
  int nDims = static_cast<int>(nd);
  bool data_exist;
  auto file = file_holder_type(MDBoxFlatTree::createOrOpenMDWSgroup(
      filename, nDims, MDE::getTypeName(), false, data_exist));

  // Save each NEW ExperimentInfo to a spot in the file
  MDBoxFlatTree::saveExperimentInfos(file.get(), ws);
  if (!update || !data_exist) {
    MDBoxFlatTree::saveWSGenericInfo(file.get(), ws);
  }
  file->closeGroup();
  file->close();

  MDBoxFlatTree BoxFlatStruct;
  //-----------------------------------------------------------------------------------------------------
  if (update) // the workspace is already file backed;
  {
    // remove all boxes from the DiskBuffer. DB will calculate boxes positions
    // on HDD.
    bc->getFileIO()->flushCache();
    // flatten the box structure; this will remember boxes file positions in the
    // box structure
    BoxFlatStruct.initFlatStructure(ws, filename);
  } else // not file backed;
  {
    // the boxes file positions are unknown and we need to calculate it.
    BoxFlatStruct.initFlatStructure(ws, filename);
    // create saver class
    auto Saver = boost::shared_ptr<API::IBoxControllerIO>(
        new DataObjects::BoxControllerNeXusIO(bc.get()));
    Saver->setDataType(sizeof(coord_t), MDE::getTypeName());
    if (MakeFileBacked) {
      // store saver with box controller
      bc->setFileBacked(Saver, filename);
      // get access to boxes array
      std::vector<API::IMDNode *> &boxes = BoxFlatStruct.getBoxes();
      // calculate the position of the boxes on file, indicating to make them
      // saveable and that the boxes were not saved.
      BoxFlatStruct.setBoxesFilePositions(true);
      prog->resetNumSteps(boxes.size(), 0.06, 0.90);
      for (auto &boxe : boxes) {
        auto saveableTag = boxe->getISaveable();
        if (saveableTag) // only boxes can be saveable
        {
          // do not spend time on empty boxes
          if (boxe->getDataInMemorySize() == 0)
            continue;
          // save boxes directly using the boxes file postion, precalculated in
          // boxFlatStructure.
          saveableTag->save();
          // remove boxes data from memory. This will actually correctly set the
          // tag indicatin that data were not loaded.
          saveableTag->clearDataFromMemory();
          // put boxes into write buffer wich will save them when necessary
          // Saver->toWrite(saveTag);
          prog->report("Saving Box");
        }
      }
      // remove everything from diskBuffer;  (not sure if it really necessary
      // but just in case , should not make any harm)
      Saver->flushCache();
      // drop NeXus on HDD (not sure if it really necessary but just in case )
      Saver->flushData();
    } else // just save data, and finish with it
    {
      Saver->openFile(filename, "w");
      BoxFlatStruct.setBoxesFilePositions(false);
      std::vector<API::IMDNode *> &boxes = BoxFlatStruct.getBoxes();
      std::vector<uint64_t> &eventIndex = BoxFlatStruct.getEventIndex();
      prog->resetNumSteps(boxes.size(), 0.06, 0.90);
      for (size_t i = 0; i < boxes.size(); i++) {
        if (eventIndex[2 * i + 1] == 0)
          continue;
        boxes[i]->saveAt(Saver.get(), eventIndex[2 * i]);
        prog->report("Saving Box");
      }
      Saver->closeFile();
    }
  }

  // -------------- Save Box Structure  -------------------------------------
  // OK, we've filled these big arrays of data representing flat box structrre.
  // Save them.
  progress(0.91, "Writing Box Data");
  prog->resetNumSteps(8, 0.92, 1.00);

  // Save box structure;
  BoxFlatStruct.saveBoxStructure(filename);

  delete prog;

  ws->setFileNeedsUpdating(false);
}
Ejemplo n.º 12
0
/**
 * Create an output event workspace filled with data simulated with the fitting
 * function.
 * @param baseName :: The base name for the workspace
 * @param inputWorkspace :: The input workspace.
 * @param values :: The calculated values
 * @param outputWorkspacePropertyName :: The property name
 */
boost::shared_ptr<API::Workspace> FitMD::createEventOutputWorkspace(
    const std::string &baseName, const API::IMDEventWorkspace &inputWorkspace,
    const API::FunctionValues &values,
    const std::string &outputWorkspacePropertyName) {
  auto outputWS =
      MDEventFactory::CreateMDWorkspace(inputWorkspace.getNumDims(), "MDEvent");
  // Add events
  // TODO: Generalize to ND (the current framework is a bit limiting)
  auto mdWS = boost::dynamic_pointer_cast<
      DataObjects::MDEventWorkspace<DataObjects::MDEvent<4>, 4>>(outputWS);
  if (!mdWS) {
    return boost::shared_ptr<API::Workspace>();
  }

  // Bins extents and meta data
  for (size_t i = 0; i < 4; ++i) {
    boost::shared_ptr<const Geometry::IMDDimension> inputDim =
        inputWorkspace.getDimension(i);
    Geometry::MDHistoDimensionBuilder builder;
    builder.setName(inputDim->getName());
    builder.setId(inputDim->getDimensionId());
    builder.setUnits(inputDim->getUnits());
    builder.setNumBins(inputDim->getNBins());
    builder.setMin(inputDim->getMinimum());
    builder.setMax(inputDim->getMaximum());
    builder.setFrameName(inputDim->getMDFrame().name());

    outputWS->addDimension(builder.create());
  }

  // Run information
  outputWS->copyExperimentInfos(inputWorkspace);
  // Coordinates
  outputWS->setCoordinateSystem(inputWorkspace.getSpecialCoordinateSystem());
  // Set sensible defaults for splitting behaviour
  BoxController_sptr bc = outputWS->getBoxController();
  bc->setSplitInto(3);
  bc->setSplitThreshold(3000);
  outputWS->initialize();
  outputWS->splitBox();

  auto inputIter = inputWorkspace.createIterator();
  size_t resultValueIndex(0);
  const float errorSq = 0.0;
  do {
    const size_t numEvents = inputIter->getNumEvents();
    const float signal =
        static_cast<float>(values.getCalculated(resultValueIndex));
    for (size_t i = 0; i < numEvents; ++i) {
      coord_t centers[4] = {
          inputIter->getInnerPosition(i, 0), inputIter->getInnerPosition(i, 1),
          inputIter->getInnerPosition(i, 2), inputIter->getInnerPosition(i, 3)};
      mdWS->addEvent(MDEvent<4>(signal, errorSq, inputIter->getInnerRunIndex(i),
                                inputIter->getInnerDetectorID(i), centers));
    }
    ++resultValueIndex;
  } while (inputIter->next());
  delete inputIter;

  // This splits up all the boxes according to split thresholds and sizes.
  auto threadScheduler = new Kernel::ThreadSchedulerFIFO();
  Kernel::ThreadPool threadPool(threadScheduler);
  outputWS->splitAllIfNeeded(threadScheduler);
  threadPool.joinAll();
  outputWS->refreshCache();

  // Store it
  if (!outputWorkspacePropertyName.empty()) {
    declareProperty(
        new API::WorkspaceProperty<API::IMDEventWorkspace>(
            outputWorkspacePropertyName, "", Direction::Output),
        "Name of the output Workspace holding resulting simulated spectrum");
    m_manager->setPropertyValue(outputWorkspacePropertyName,
                                baseName + "Workspace");
    m_manager->setProperty(outputWorkspacePropertyName, outputWS);
  }

  return outputWS;
}
Ejemplo n.º 13
0
  void BinToMDHistoWorkspace::binByIterating(typename MDEventWorkspace<MDE, nd>::sptr ws)
  {
    BoxController_sptr bc = ws->getBoxController();

    // Start with signal at 0.0
    outWS->setTo(0.0, 0.0);

    // Cache some data to speed up accessing them a bit
    indexMultiplier = new size_t[outD];
    for (size_t d=0; d<outD; d++)
    {
      if (d > 0)
        indexMultiplier[d] = outWS->getIndexMultiplier()[d-1];
      else
        indexMultiplier[d] = 1;
    }
    signals = outWS->getSignalArray();
    errors = outWS->getErrorSquaredArray();

    // The dimension (in the output workspace) along which we chunk for parallel processing
    // TODO: Find the smartest dimension to chunk against
    size_t chunkDimension = 0;

    // How many bins (in that dimension) per chunk.
    // Try to split it so each core will get 2 tasks:
    int chunkNumBins =  int(binDimensions[chunkDimension]->getNBins() / (Mantid::Kernel::ThreadPool::getNumPhysicalCores() * 2));
    if (chunkNumBins < 1) chunkNumBins = 1;

    // Do we actually do it in parallel?
    bool doParallel = getProperty("Parallel");
    // Not if file-backed!
    if (bc->isFileBacked()) doParallel = false;
    if (!doParallel)
      chunkNumBins = int(binDimensions[chunkDimension]->getNBins());

    // Total number of steps
    size_t progNumSteps = 0;
    if (prog) prog->setNotifyStep(0.1);
    if (prog) prog->resetNumSteps(100, 0.00, 1.0);

    // Run the chunks in parallel. There is no overlap in the output workspace so it is
    // thread safe to write to it..
    PRAGMA_OMP( parallel for schedule(dynamic,1) if (doParallel) )
    for(int chunk=0; chunk < int(binDimensions[chunkDimension]->getNBins()); chunk += chunkNumBins)
    {
      PARALLEL_START_INTERUPT_REGION
      // Region of interest for this chunk.
      size_t * chunkMin = new size_t[outD];
      size_t * chunkMax = new size_t[outD];
      for (size_t bd=0; bd<outD; bd++)
      {
        // Same limits in the other dimensions
        chunkMin[bd] = 0;
        chunkMax[bd] = binDimensions[bd]->getNBins();
      }
      // Parcel out a chunk in that single dimension dimension
      chunkMin[chunkDimension] = size_t(chunk);
      if (size_t(chunk+chunkNumBins) > binDimensions[chunkDimension]->getNBins())
        chunkMax[chunkDimension] = binDimensions[chunkDimension]->getNBins();
      else
        chunkMax[chunkDimension] = size_t(chunk+chunkNumBins);

      // Build an implicit function (it needs to be in the space of the MDEventWorkspace)
      MDImplicitFunction * function = this->getImplicitFunctionForChunk(chunkMin, chunkMax);

      // Use getBoxes() to get an array with a pointer to each box
      std::vector<IMDBox<MDE,nd>*> boxes;
      // Leaf-only; no depth limit; with the implicit function passed to it.
      ws->getBox()->getBoxes(boxes, 1000, true, function);

      // Sort boxes by file position IF file backed. This reduces seeking time, hopefully.
      if (bc->isFileBacked())
        IMDBox<MDE, nd>::sortBoxesByFilePos(boxes);

      // For progress reporting, the # of boxes
      if (prog)
      {
        PARALLEL_CRITICAL(BinToMDHistoWorkspace_progress)
        {
          std::cout << "Chunk " << chunk << ": found " << boxes.size() << " boxes within the implicit function." << std::endl;
          progNumSteps += boxes.size();
          prog->setNumSteps( progNumSteps );
        }
      }

      // Go through every box for this chunk.
      for (size_t i=0; i<boxes.size(); i++)
      {
        MDBox<MDE,nd> * box = dynamic_cast<MDBox<MDE,nd> *>(boxes[i]);
        // Perform the binning in this separate method.
        if (box)
          this->binMDBox(box, chunkMin, chunkMax);

        // Progress reporting
        if (prog) prog->report();

      }// for each box in the vector
      PARALLEL_END_INTERUPT_REGION
    } // for each chunk in parallel
    PARALLEL_CHECK_INTERUPT_REGION



    // Now the implicit function
    if (implicitFunction)
    {
      prog->report("Applying implicit function.");
      signal_t nan = std::numeric_limits<signal_t>::quiet_NaN();
      outWS->applyImplicitFunction(implicitFunction, nan, nan);
    }
  }