예제 #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);
  }
예제 #2
0
  void MultiplyMD::execEventScalar(typename MDEventWorkspace<MDE, nd>::sptr ws)
  {
    // Get the scalar multiplying
    float scalar = float(m_rhs_scalar->dataY(0)[0]);
    float scalarError = float(m_rhs_scalar->dataE(0)[0]);
    float scalarRelativeErrorSquared = (scalarError * scalarError) / (scalar * scalar);

    // Get all the MDBoxes contained
    MDBoxBase<MDE,nd> * parentBox = ws->getBox();
    std::vector<API::IMDNode *> boxes;
    parentBox->getBoxes(boxes, 1000, true);

    bool fileBackedTarget(false);
    Kernel::DiskBuffer *dbuff(NULL);
    if(ws->isFileBacked())
    {
        fileBackedTarget = true;
        dbuff = ws->getBoxController()->getFileIO();
    }
 

    for (size_t i=0; i<boxes.size(); i++)
    {
      MDBox<MDE,nd> * box = dynamic_cast<MDBox<MDE,nd> *>(boxes[i]);
      if (box)
      {
        typename std::vector<MDE> & events = box->getEvents();
        size_t ic(events.size());
        typename std::vector<MDE>::iterator it = events.begin();
        typename std::vector<MDE>::iterator it_end = events.end();
        for (; it != it_end; it++)
        {
          // Multiply weight by a scalar, propagating error
          float oldSignal = it->getSignal();
          float signal = oldSignal * scalar;
          float errorSquared = signal * signal * (it->getErrorSquared() / (oldSignal * oldSignal) + scalarRelativeErrorSquared);
          it->setSignal(signal);
          it->setErrorSquared(errorSquared);
        }
        box->releaseEvents();
        if(fileBackedTarget && ic>0)
        {
            Kernel::ISaveable *const pSaver(box->getISaveable());
            dbuff->toWrite(pSaver);
        }

      }
    }
    // Recalculate the totals
    ws->refreshCache();
    // Mark file-backed workspace as dirty
    ws->setFileNeedsUpdating(true);
  }
예제 #3
0
void CentroidPeaksMD::integrate(typename MDEventWorkspace<MDE, nd>::sptr ws) {
  if (nd != 3)
    throw std::invalid_argument("For now, we expect the input MDEventWorkspace "
                                "to have 3 dimensions only.");

  /// Peak workspace to centroid
  Mantid::DataObjects::PeaksWorkspace_sptr inPeakWS =
      getProperty("PeaksWorkspace");

  /// Output peaks workspace, create if needed
  Mantid::DataObjects::PeaksWorkspace_sptr peakWS =
      getProperty("OutputWorkspace");
  if (peakWS != inPeakWS)
    peakWS.reset(inPeakWS->clone().release());

  std::string CoordinatesToUseStr = getPropertyValue("CoordinatesToUse");
  int CoordinatesToUse = ws->getSpecialCoordinateSystem();
  if (CoordinatesToUse == 1 && CoordinatesToUseStr != "Q (lab frame)")
    g_log.warning() << "Warning: used Q (lab frame) coordinates for MD "
                       "workspace, not CoordinatesToUse from input "
                    << std::endl;
  else if (CoordinatesToUse == 2 && CoordinatesToUseStr != "Q (sample frame)")
    g_log.warning() << "Warning: used Q (sample frame) coordinates for MD "
                       "workspace, not CoordinatesToUse from input "
                    << std::endl;
  else if (CoordinatesToUse == 3 && CoordinatesToUseStr != "HKL")
    g_log.warning() << "Warning: used HKL coordinates for MD workspace, not "
                       "CoordinatesToUse from input " << std::endl;

  /// Radius to use around peaks
  double PeakRadius = getProperty("PeakRadius");

  // cppcheck-suppress syntaxError
    PRAGMA_OMP(parallel for schedule(dynamic, 10) )
    for (int i = 0; i < int(peakWS->getNumberPeaks()); ++i) {
      // Get a direct ref to that peak.
      IPeak &p = peakWS->getPeak(i);
      double detectorDistance = p.getL2();

      // Get the peak center as a position in the dimensions of the workspace
      V3D pos;
      if (CoordinatesToUse == 1) //"Q (lab frame)"
        pos = p.getQLabFrame();
      else if (CoordinatesToUse == 2) //"Q (sample frame)"
        pos = p.getQSampleFrame();
      else if (CoordinatesToUse == 3) //"HKL"
        pos = p.getHKL();

      // Build the sphere transformation
      bool dimensionsUsed[nd];
      coord_t center[nd];
      for (size_t d = 0; d < nd; ++d) {
        dimensionsUsed[d] = true; // Use all dimensions
        center[d] = static_cast<coord_t>(pos[d]);
      }
      CoordTransformDistance sphere(nd, center, dimensionsUsed);

      // Initialize the centroid to 0.0
      signal_t signal = 0;
      coord_t centroid[nd];
      for (size_t d = 0; d < nd; d++)
        centroid[d] = 0.0;

      // Perform centroid
      ws->getBox()->centroidSphere(
          sphere, static_cast<coord_t>(PeakRadius * PeakRadius), centroid,
          signal);

      // Normalize by signal
      if (signal != 0.0) {
        for (size_t d = 0; d < nd; d++)
          centroid[d] /= static_cast<coord_t>(signal);

        V3D vecCentroid(centroid[0], centroid[1], centroid[2]);

        // Save it back in the peak object, in the dimension specified.
        if (CoordinatesToUse == 1) //"Q (lab frame)"
        {
          p.setQLabFrame(vecCentroid, detectorDistance);
          p.findDetector();
        } else if (CoordinatesToUse == 2) //"Q (sample frame)"
        {
          p.setQSampleFrame(vecCentroid, detectorDistance);
          p.findDetector();
        } else if (CoordinatesToUse == 3) //"HKL"
        {
          p.setHKL(vecCentroid);
        }

        g_log.information() << "Peak " << i << " at " << pos << ": signal "
                            << signal << ", centroid " << vecCentroid << " in "
                            << CoordinatesToUse << std::endl;
      } else {
        g_log.information() << "Peak " << i << " at " << pos
                            << " had no signal, and could not be centroided."
                            << std::endl;
      }
    }

    // Save the output
    setProperty("OutputWorkspace", peakWS);
}
예제 #4
0
파일: SliceMD.cpp 프로젝트: nimgould/mantid
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;
}
예제 #5
0
파일: BinMD.cpp 프로젝트: liyulun/mantid
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);
}
예제 #6
0
void CompareMDWorkspaces::compareMDWorkspaces(
    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>>(inWS2);
    if (!ws1 || !ws2)
        throw std::runtime_error("Incompatible workspace types passed to PlusMD.");

    std::vector<API::IMDNode *> boxes1;
    std::vector<API::IMDNode *> boxes2;

    ws1->getBox()->getBoxes(boxes1, 1000, false);
    ws2->getBox()->getBoxes(boxes2, 1000, false);

    this->compare(boxes1.size(), boxes2.size(),
                  "Workspaces do not have the same number of boxes");

    for (size_t j = 0; j < boxes1.size(); j++) {

        API::IMDNode *box1 = boxes1[j];
        API::IMDNode *box2 = boxes2[j];

        if (m_CompareBoxID)
            this->compare(box1->getID(), box2->getID(), "Boxes have different ID");
        else {
            if (box1->getID() != box2->getID())
                g_log.debug() << " Boxes N: " << j << " have box ID: " << box1->getID()
                              << " and " << box2->getID() << " correspondingly\n";
        }
        this->compare(size_t(box1->getDepth()), size_t(box2->getDepth()),
                      "Boxes are at a different depth");
        this->compare(box1->getNumChildren(), box2->getNumChildren(),
                      "Boxes do not have the same number of children");

        for (size_t i = 0; i < box1->getNumChildren(); i++) {
            if (m_CompareBoxID)
                this->compare(box1->getChild(i)->getID(), box2->getChild(i)->getID(),
                              "Child of boxes do not match IDs");
            else {
                if (box1->getID() != box2->getID())
                    g_log.debug() << " Boxes N: " << j << " children N: " << i
                                  << " have box ID: " << box1->getChild(i)->getID()
                                  << " and " << box2->getChild(i)->getID()
                                  << " correspondingly\n";
            }
        }

        for (size_t d = 0; d < nd; d++) {
            this->compareTol(box1->getExtents(d).getMin(),
                             box2->getExtents(d).getMin(),
                             "Extents of box do not match");
            this->compareTol(box1->getExtents(d).getMax(),
                             box2->getExtents(d).getMax(),
                             "Extents of box do not match");
        }
        this->compareTol(box1->getInverseVolume(), box2->getInverseVolume(),
                         "Box inverse volume does not match");
        this->compareTol(box1->getSignal(), box2->getSignal(),
                         "Box signal does not match");
        this->compareTol(box1->getErrorSquared(), box2->getErrorSquared(),
                         "Box error squared does not match");
        if (m_CheckEvents)
            this->compare(box1->getNPoints(), box2->getNPoints(),
                          "Number of points in box does not match");

        // Are both MDGridBoxes ?
        MDGridBox<MDE, nd> *gridbox1 = dynamic_cast<MDGridBox<MDE, nd> *>(box1);
        MDGridBox<MDE, nd> *gridbox2 = dynamic_cast<MDGridBox<MDE, nd> *>(box2);
        if (gridbox1 && gridbox2) {
            for (size_t d = 0; d < nd; d++)
                this->compareTol(gridbox1->getBoxSize(d), gridbox2->getBoxSize(d),
                                 "Box sizes do not match");
        }

        // Are both MDBoxes (with events)
        MDBox<MDE, nd> *mdbox1 = dynamic_cast<MDBox<MDE, nd> *>(box1);
        MDBox<MDE, nd> *mdbox2 = dynamic_cast<MDBox<MDE, nd> *>(box2);
        if (mdbox1 && mdbox2) {
            if (m_CheckEvents) {
                const std::vector<MDE> &events1 = mdbox1->getConstEvents();
                const std::vector<MDE> &events2 = mdbox2->getConstEvents();
                try {
                    this->compare(events1.size(), events2.size(),
                                  "Box event vectors are not the same length");
                    if (events1.size() == events2.size() && events1.size() > 2) {
                        // Check first and last event
                        for (size_t i = 0; i < events1.size(); i++) {
                            for (size_t d = 0; d < nd; d++) {
                                this->compareTol(events1[i].getCenter(d),
                                                 events2[i].getCenter(d),
                                                 "Event center does not match");
                            }
                            this->compareTol(events1[i].getSignal(), events2[i].getSignal(),
                                             "Event signal does not match");
                            this->compareTol(events1[i].getErrorSquared(),
                                             events2[i].getErrorSquared(),
                                             "Event error does not match");
                        }
                    }
                } catch (CompareFailsException &) {
                    // Boxes must release events if the check fails
                    mdbox1->releaseEvents();
                    mdbox2->releaseEvents();
                    throw;
                }
                mdbox1->releaseEvents();
                mdbox2->releaseEvents();
            } // Don't compare if BoxStructureOnly
        }   // is mdbox1
    }
}
예제 #7
0
  void FindPeaksMD::findPeaks(typename MDEventWorkspace<MDE, nd>::sptr ws)
  {
    if (nd < 3)
      throw std::invalid_argument("Workspace must have at least 3 dimensions.");

    progress(0.01, "Refreshing Centroids");

    // TODO: This might be slow, progress report?
    // Make sure all centroids are fresh
    ws->getBox()->refreshCentroid();

    typedef IMDBox<MDE,nd>* boxPtr;

    if (ws->getNumExperimentInfo() == 0)
      throw std::runtime_error("No instrument was found in the MDEventWorkspace. Cannot find peaks.");

    // TODO: Do we need to pick a different instrument info?
    ExperimentInfo_sptr ei = ws->getExperimentInfo(0);
    // Instrument associated with workspace
    Geometry::Instrument_const_sptr inst = ei->getInstrument();
    // Find the run number
    int runNumber = ei->getRunNumber();

    // Check that the workspace dimensions are in Q-sample-frame or Q-lab-frame.
    eDimensionType dimType;

    std::string dim0 = ws->getDimension(0)->getName();
    if (dim0 == "H")
    {
      dimType = HKL;
      throw std::runtime_error("Cannot find peaks in a workspace that is already in HKL space.");
    }
    else if (dim0 == "Q_lab_x")
    {
      dimType = QLAB;
    }
    else if (dim0 == "Q_sample_x")
      dimType = QSAMPLE;
    else
      throw std::runtime_error("Unexpected dimensions: need either Q_lab_x or Q_sample_x.");

    // Find the goniometer rotation matrix
    Mantid::Kernel::Matrix<double> goniometer(3,3, true); // Default IDENTITY matrix
    try
    {
      goniometer = ei->mutableRun().getGoniometerMatrix();
    }
    catch (std::exception & e)
    {
      g_log.warning() << "Error finding goniometer matrix. It will not be set in the peaks found." << std::endl;
      g_log.warning() << e.what() << std::endl;
    }

    /// Arbitrary scaling factor for density to make more manageable numbers, especially for older file formats.
    signal_t densityScalingFactor = 1e-6;

    // Calculate a threshold below which a box is too diffuse to be considered a peak.
    signal_t thresholdDensity = 0.0;
    thresholdDensity = ws->getBox()->getSignalNormalized() * DensityThresholdFactor * densityScalingFactor;
    g_log.notice() << "Threshold signal density: " << thresholdDensity << std::endl;

    // We will fill this vector with pointers to all the boxes (up to a given depth)
    typename std::vector<boxPtr> boxes;

    // Get all the MDboxes
    progress(0.10, "Getting Boxes");
    ws->getBox()->getBoxes(boxes, 1000, true);



    // TODO: Here keep only the boxes > e.g. 3 * mean.
    typedef std::pair<double, boxPtr> dens_box;

    // Map that will sort the boxes by increasing density. The key = density; value = box *.
    typename std::multimap<double, boxPtr> sortedBoxes;

    progress(0.20, "Sorting Boxes by Density");
    typename std::vector<boxPtr>::iterator it1;
    typename std::vector<boxPtr>::iterator it1_end = boxes.end();
    for (it1 = boxes.begin(); it1 != it1_end; it1++)
    {
      boxPtr box = *it1;
      double density = box->getSignalNormalized() * densityScalingFactor;
      // Skip any boxes with too small a signal density.
      if (density > thresholdDensity)
        sortedBoxes.insert(dens_box(density,box));
    }

    // List of chosen possible peak boxes.
    std::vector<boxPtr> peakBoxes;

    prog = new Progress(this, 0.30, 0.95, MaxPeaks);

    int64_t numBoxesFound = 0;
    // Now we go (backwards) through the map
    // e.g. from highest density down to lowest density.
    typename std::multimap<double, boxPtr>::reverse_iterator it2;
    typename std::multimap<double, boxPtr>::reverse_iterator it2_end = sortedBoxes.rend();
    for (it2 = sortedBoxes.rbegin(); it2 != it2_end; it2++)
    {
      signal_t density = it2->first;
      boxPtr box = it2->second;
#ifndef MDBOX_TRACK_CENTROID
      coord_t boxCenter[nd];
      box->calculateCentroid(boxCenter);
#else
      const coord_t * boxCenter = box->getCentroid();
#endif

      // Compare to all boxes already picked.
      bool badBox = false;
      for (typename std::vector<boxPtr>::iterator it3=peakBoxes.begin(); it3 != peakBoxes.end(); it3++)
      {

#ifndef MDBOX_TRACK_CENTROID
        coord_t otherCenter[nd];
        (*it3)->calculateCentroid(otherCenter);
#else
        const coord_t * otherCenter = (*it3)->getCentroid();
#endif

        // Distance between this box and a box we already put in.
        coord_t distSquared = 0.0;
        for (size_t d=0; d<nd; d++)
        {
          coord_t dist = otherCenter[d] - boxCenter[d];
          distSquared += (dist * dist);
        }

        // Reject this box if it is too close to another previously found box.
        if (distSquared < peakRadiusSquared)
        {
          badBox = true;
          break;
        }
      }

      // The box was not rejected for another reason.
      if (!badBox)
      {
        if (numBoxesFound++ >= MaxPeaks)
        {
          g_log.notice() << "Number of peaks found exceeded the limit of " << MaxPeaks << ". Stopping peak finding." << std::endl;
          break;
        }

        peakBoxes.push_back(box);
        g_log.information() << "Found box at ";
        for (size_t d=0; d<nd; d++)
          g_log.information() << (d>0?",":"") << boxCenter[d];
        g_log.information() << "; Density = " << density << std::endl;
        // Report progres for each box found.
        prog->report("Finding Peaks");
      }
    }

    prog->resetNumSteps(numBoxesFound, 0.95, 1.0);

    // Copy the instrument, sample, run to the peaks workspace.
    peakWS->copyExperimentInfoFrom(ei.get());

    // --- Convert the "boxes" to peaks ----
    for (typename std::vector<boxPtr>::iterator it3=peakBoxes.begin(); it3 != peakBoxes.end(); it3++)
    {
      // The center of the box = Q in the lab frame
      boxPtr box = *it3;
#ifndef MDBOX_TRACK_CENTROID
      coord_t boxCenter[nd];
      box->calculateCentroid(boxCenter);
#else
      const coord_t * boxCenter = box->getCentroid();
#endif

      V3D Q(boxCenter[0], boxCenter[1], boxCenter[2]);

      // Create a peak and add it
      // Empty starting peak.
      Peak p;
      try
      {
        if (dimType == QLAB)
        {
          // Build using the Q-lab-frame constructor
          p = Peak(inst, Q);
          // Save gonio matrix for later
          p.setGoniometerMatrix(goniometer);
        }
        else if (dimType == QSAMPLE)
        {
          // Build using the Q-sample-frame constructor
          p = Peak(inst, Q, goniometer);
        }
      }
      catch (std::exception &e)
      {
        g_log.notice() << "Error creating peak at " << Q << " because of '" << e.what() << "'. Peak will be skipped." << std::endl;
        continue;
      }

      try
      { // Look for a detector
        p.findDetector();
      }
      catch (...)
      { /* Ignore errors in ray-tracer TODO: Handle for WISH data later */ }

      // The "bin count" used will be the box density.
      p.setBinCount( box->getSignalNormalized() * densityScalingFactor);

      // Save the run number found before.
      p.setRunNumber(runNumber);

      peakWS->addPeak(p);

      // Report progres for each box found.
      prog->report("Adding Peaks");

    } // for each box found

  }
예제 #8
0
void vtkMDHexFactory::doCreate(
    typename MDEventWorkspace<MDE, nd>::sptr ws) const {
  bool VERBOSE = true;
  CPUTimer tim;
  // Acquire a scoped read-only lock to the workspace (prevent segfault from
  // algos modifying ws)
  ReadLock lock(*ws);

  // First we get all the boxes, up to the given depth; with or wo the slice
  // function
  std::vector<API::IMDNode *> boxes;
  if (this->slice)
    ws->getBox()->getBoxes(boxes, m_maxDepth, true,
                           this->sliceImplicitFunction.get());
  else
    ws->getBox()->getBoxes(boxes, m_maxDepth, true);

  vtkIdType numBoxes = boxes.size();
  vtkIdType imageSizeActual = 0;

  if (VERBOSE)
    std::cout << tim << " to retrieve the " << numBoxes
              << " boxes down to depth " << m_maxDepth << '\n';

  // Create 8 points per box.
  vtkNew<vtkPoints> points;
  vtkFloatArray *pointsArray = vtkFloatArray::FastDownCast(points->GetData());
  float *pointsPtr = pointsArray->WritePointer(0, numBoxes * 8 * 3);

  // One scalar per box
  vtkNew<vtkFloatArray> signals;
  signals->SetName(ScalarName.c_str());
  signals->SetNumberOfComponents(1);
  float *signalsPtr = signals->WritePointer(0, numBoxes);

  // To cache the signal
  std::vector<float> signalCache(numBoxes, 0);

  // True for boxes that we will use
  // We do not use vector<bool> here because of the parallelization below
  // Simultaneous access to different elements of vector<bool> is not safe
  auto useBox = Mantid::Kernel::make_unique<bool[]>(numBoxes);
  memset(useBox.get(), 0, sizeof(bool) * numBoxes);

  // Create the data set (will outlive this object - output of create)
  auto visualDataSet = vtkSmartPointer<vtkUnstructuredGrid>::New();
  this->dataSet = visualDataSet;
  visualDataSet->Allocate(numBoxes);

  vtkNew<vtkIdList> hexPointList;
  hexPointList->SetNumberOfIds(8);
  auto hexPointList_ptr = hexPointList->WritePointer(0, 8);

  NormFuncIMDNodePtr normFunction =
      makeMDEventNormalizationFunction(m_normalizationOption, ws.get());

  // This can be parallelized
  // cppcheck-suppress syntaxError
    PRAGMA_OMP( parallel for schedule (dynamic) )
    for (int ii = 0; ii < int(boxes.size()); ii++) {
      // Get the box here
      size_t i = static_cast<size_t>(ii);
      API::IMDNode *box = boxes[i];
      Mantid::signal_t signal_normalized = (box->*normFunction)();

      if (std::isfinite(signal_normalized)) {
        // Cache the signal and using of it
        signalCache[i] = static_cast<float>(signal_normalized);
        useBox[i] = true;

        // Get the coordinates.
        size_t numVertexes = 0;
        std::unique_ptr<coord_t[]> coords;

        // If slicing down to 3D, specify which dimensions to keep.
        if (this->slice) {
          coords = std::unique_ptr<coord_t[]>(
              box->getVertexesArray(numVertexes, 3, this->sliceMask.get()));
        } else {
          coords =
              std::unique_ptr<coord_t[]>(box->getVertexesArray(numVertexes));
        }
        if (numVertexes == 8) {
          std::copy_n(coords.get(), 24, std::next(pointsPtr, i * 24));
        }
      } else {
        useBox[i] = false;
      }
    } // For each box

    if (VERBOSE)
      std::cout << tim << " to create the necessary points.\n";
    // Add points
    visualDataSet->SetPoints(points.GetPointer());

    for (size_t i = 0; i < boxes.size(); i++) {
      if (useBox[i]) {
        // The bare point ID
        vtkIdType pointId = i * 8;

        // Add signal
        *signalsPtr = signalCache[i];
        std::advance(signalsPtr, 1);

        const std::array<vtkIdType, 8> idList{{0, 1, 3, 2, 4, 5, 7, 6}};

        std::transform(
            idList.begin(), idList.end(), hexPointList_ptr,
            std::bind(std::plus<vtkIdType>(), std::placeholders::_1, pointId));

        // Add cells
        visualDataSet->InsertNextCell(VTK_HEXAHEDRON,
                                      hexPointList.GetPointer());

        imageSizeActual++;
      }
    } // for each box.

    // Shrink to fit
    signals->Resize(imageSizeActual);
    signals->Squeeze();
    visualDataSet->Squeeze();

    // Add scalars
    visualDataSet->GetCellData()->SetScalars(signals.GetPointer());

    // Hedge against empty data sets
    if (visualDataSet->GetNumberOfPoints() <= 0) {
      vtkNullUnstructuredGrid nullGrid;
      visualDataSet = nullGrid.createNullData();
      this->dataSet = visualDataSet;
    }

    if (VERBOSE)
      std::cout << tim << " to create " << imageSizeActual << " hexahedrons.\n";
}
예제 #9
0
파일: PlusMD.cpp 프로젝트: trnielsen/mantid
  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);

  }
예제 #10
0
  void vtkSplatterPlotFactory::doCreate(typename MDEventWorkspace<MDE, nd>::sptr ws) const
  {
    bool VERBOSE = true;
    CPUTimer tim;
    // Acquire a scoped read-only lock to the workspace (prevent segfault
    // from algos modifying ws)
    ReadLock lock(*ws);

    // Find out how many events to plot, and the percentage of the largest
    // boxes to use.
    size_t totalPoints = ws->getNPoints();
    size_t numPoints = m_numPoints;

    if (numPoints > totalPoints)
    {
      numPoints = totalPoints;
    }

    double percent_to_use = m_percentToUse;
    // Fail safe limits on fraction of boxes to use
    if (percent_to_use <= 0)
    {
      percent_to_use = 5;
    }

    if (percent_to_use > 100)
    {
      percent_to_use = 100;
    }

    // First we get all the boxes, up to the given depth; with or wo the
    // slice function
    std::vector<API::IMDNode *> boxes;
    if (this->slice)
    {
      ws->getBox()->getBoxes(boxes, 1000, true, this->sliceImplicitFunction);
    }
    else
    {
      ws->getBox()->getBoxes(boxes, 1000, true);
    }

    if (VERBOSE)
    {
      std::cout << tim << " to retrieve the "<< boxes.size() << " boxes down."<< std::endl;
    }

    std::string new_name = ws->getName();
    if (new_name != m_wsName || m_buildSortedList)
    {
      m_wsName = new_name;
      m_buildSortedList = false;
      m_sortedBoxes.clear();
      // get list of boxes with signal > 0 and sort
      // the list in order of decreasing signal
      for (size_t i = 0; i < boxes.size(); i++)
      {
        MDBox<MDE,nd> * box = dynamic_cast<MDBox<MDE,nd> *>(boxes[i]);
        if (box)
        {
          size_t newPoints = box->getNPoints();
          if (newPoints > 0)
          {
            m_sortedBoxes.push_back(box);
          }
        }
      }

      if (VERBOSE)
      {
        std::cout << "START SORTING" << std::endl;
      }
      std::sort(m_sortedBoxes.begin(), m_sortedBoxes.end(),
                CompareNormalizedSignal);
      if (VERBOSE)
      {
        std::cout << "DONE SORTING" << std::endl;
      }
    }
    size_t num_boxes_to_use = static_cast<size_t>(percent_to_use * static_cast<double>(m_sortedBoxes.size()) / 100.0);
    if (num_boxes_to_use >= m_sortedBoxes.size())
    {
      num_boxes_to_use = m_sortedBoxes.size()-1;
    }

    // restrict the number of points to the
    // number of points in boxes being used
    size_t total_points_available = 0;
    for (size_t i = 0; i < num_boxes_to_use; i++)
    {
      size_t newPoints = m_sortedBoxes[i]->getNPoints();
      total_points_available += newPoints;
    }

    if (numPoints > total_points_available)
    {
      numPoints = total_points_available;
    }

    size_t points_per_box = 0;
    // calculate the average number of points to use per box
    if (num_boxes_to_use > 0)
    {
      points_per_box = numPoints / num_boxes_to_use;
    }

    if (points_per_box < 1)
    {
      points_per_box = 1;
    }

    if (VERBOSE)
    {
      std::cout << "numPoints                 = " << numPoints << std::endl;
      std::cout << "num boxes in all          = " << boxes.size() << std::endl;
      std::cout << "num boxes above zero      = " << m_sortedBoxes.size() << std::endl;
      std::cout << "num boxes to use          = " << num_boxes_to_use << std::endl;
      std::cout << "total_points_available    = " << total_points_available << std::endl;
      std::cout << "points needed per box     = " << points_per_box << std::endl;
    }

    // First save the events and signals that we actually use.
    // For each box, get up to the average number of points
    // we want from each box, limited by the number of points
    // in the box.  NOTE: since boxes have different numbers
    // of events, we will not get all the events requested.
    // Also, if we are using a smaller number of points, we
    // won't get points from some of the boxes with lower signal.

    std::vector<float>            saved_signals;
    std::vector<const coord_t*>   saved_centers;
    std::vector<size_t>           saved_n_points_in_cell;
    saved_signals.reserve(numPoints);
    saved_centers.reserve(numPoints);
    saved_n_points_in_cell.reserve(numPoints);
  
    size_t pointIndex = 0;
    size_t box_index  = 0;
    bool   done       = false;
    while (box_index < num_boxes_to_use && !done)
    {
      MDBox<MDE,nd> *box = dynamic_cast<MDBox<MDE,nd> *>(m_sortedBoxes[box_index]);
      box_index++;
      if (NULL == box)
      {
        continue;
      }
      float signal_normalized = static_cast<float>(box->getSignalNormalized());
      size_t newPoints = box->getNPoints();
      size_t num_from_this_box = points_per_box;
      if (num_from_this_box > newPoints)
      {
        num_from_this_box = newPoints;
      }
      const std::vector<MDE> & events = box->getConstEvents();
      size_t startPointIndex = pointIndex;
      size_t event_index = 0;
      while (event_index < num_from_this_box && !done)
      {
        const MDE & ev = events[event_index];
        event_index++;
        const coord_t * center = ev.getCenter();
        // Save location
        saved_centers.push_back(center);
        pointIndex++;
        if (pointIndex >= numPoints)
        {
          done = true;
        }
      }
      box->releaseEvents();
      // Save signal
      saved_signals.push_back(signal_normalized);
      // Save cell size
      saved_n_points_in_cell.push_back(pointIndex-startPointIndex);
    } 

    numPoints = saved_centers.size();
    size_t numCells = saved_signals.size();

    if (VERBOSE)
    {
      std::cout << "Recorded data for all points" << std::endl;
      std::cout << "numPoints = " << numPoints << std::endl;
      std::cout << "numCells  = " << numCells << std::endl;
    }

    // Create the point list, one position for each point actually used
    vtkPoints *points = vtkPoints::New();
    points->Allocate(numPoints);
    points->SetNumberOfPoints(numPoints);

    // The list of IDs of points used, one ID per point, since points
    // are not reused to form polygon facets, etc.
    vtkIdType *ids = new vtkIdType[numPoints];

    // Only one scalar for each cell, NOT one per point
    vtkFloatArray *signal = vtkFloatArray::New();
    signal->Allocate(numCells);
    signal->SetName(m_scalarName.c_str());

    // Create the data set.  Need space for each cell, not for each point
    vtkUnstructuredGrid *visualDataSet = vtkUnstructuredGrid::New();
    this->dataSet = visualDataSet;
    visualDataSet->Allocate(numCells);
    // Now copy the saved point, cell and signal info into vtk data structures
    pointIndex = 0;
    for (size_t cell_i = 0; cell_i < numCells; cell_i++)
    {
      size_t startPointIndex = pointIndex;
      for (size_t point_i = 0; point_i < saved_n_points_in_cell[cell_i]; point_i++)
      {
        points->SetPoint(pointIndex, saved_centers[pointIndex]);
        ids[pointIndex] = pointIndex;
        pointIndex++;
      }
      signal->InsertNextTuple1(saved_signals[cell_i]);
      visualDataSet->InsertNextCell(VTK_POLY_VERTEX, saved_n_points_in_cell[cell_i], ids+startPointIndex);
    }

    if (VERBOSE)
    {
      std::cout << tim << " to create " << pointIndex << " points." << std::endl;
    }

    // Shrink to fit
    //points->Squeeze();
    signal->Squeeze();
    visualDataSet->Squeeze();

    // Add points and scalars
    visualDataSet->SetPoints(points);
    visualDataSet->GetCellData()->SetScalars(signal);

    delete [] ids;
  }
예제 #11
0
  void BinToMDHistoWorkspace::do_centerpointBin(typename MDEventWorkspace<MDE, nd>::sptr ws)
  {
    bool DODEBUG = true;

    CPUTimer tim;

    // Number of output binning dimensions found
    size_t outD = binDimensions.size();

    //Since the costs are not known ahead of time, use a simple FIFO buffer.
    ThreadScheduler * ts = new ThreadSchedulerFIFO();

    // Create the threadpool with: all CPUs, a progress reporter
    ThreadPool tp(ts, 0, prog);

    // Big efficiency gain is obtained by grouping a few bins per task.
    size_t binsPerTask = 100;

    // For progress reporting, the approx  # of tasks
    if (prog)
      prog->setNumSteps( int(outWS->getNPoints()/100) );

    // The root-level box.
    IMDBox<MDE,nd> * rootBox = ws->getBox();

    // This is the limit to loop over in each dimension
    size_t * index_max = new size_t[outD];
    for (size_t bd=0; bd<outD; bd++) index_max[bd] = binDimensions[bd]->getNBins();

    // Cache a calculation to convert indices x,y,z,t into a linear index.
    size_t * index_maker = new size_t[outD];
    Utils::NestedForLoop::SetUpIndexMaker(outD, index_maker, index_max);

    int numPoints = int(outWS->getNPoints());

    // Run in OpenMP with dynamic scheduling and a smallish chunk size (binsPerTask)
    // Right now, not parallel for file-backed systems.
    bool fileBacked = (ws->getBoxController()->getFile() != NULL);
    PRAGMA_OMP(parallel for schedule(dynamic, binsPerTask) if (!fileBacked)  )
    for (int i=0; i < numPoints; i++)
    {
      PARALLEL_START_INTERUPT_REGION

      size_t linear_index = size_t(i);
      // nd >= outD in all cases so this is safe.
      size_t index[nd];

      // Get the index at each dimension for this bin.
      Utils::NestedForLoop::GetIndicesFromLinearIndex(outD, linear_index, index_maker, index_max, index);

      // Construct the bin and its coordinates
      MDBin<MDE,nd> bin;
      for (size_t bd=0; bd<outD; bd++)
      {
        // Index in this binning dimension (i_x, i_y, etc.)
        size_t idx = index[bd];
        // Dimension in the MDEventWorkspace
        size_t d = dimensionToBinFrom[bd];
        // Corresponding extents
        bin.m_min[d] = binDimensions[bd]->getX(idx);
        bin.m_max[d] = binDimensions[bd]->getX(idx+1);
      }
      bin.m_index = linear_index;

      bool dimensionsUsed[nd];
      for (size_t d=0; d<nd; d++)
        dimensionsUsed[d] = (d<3);

      // Check if the bin is in the ImplicitFunction (if any)
      bool binContained = true;
      if (implicitFunction)
      {
        binContained = implicitFunction->isPointContained(bin.m_min); //TODO. Correct argument passed to this method?
      }

      if (binContained)
      {
        // Array of bools set to true when a dimension is fully contained (binary splitting only)
        bool fullyContained[nd];
        for (size_t d=0; d<nd; d++)
          fullyContained[d] = false;

        // This will recursively bin into the sub grids
        rootBox->centerpointBin(bin, fullyContained);

        // Save the data into the dense histogram
        outWS->setSignalAt(linear_index, bin.m_signal);
        outWS->setErrorAt(linear_index, bin.m_errorSquared);
      }

      // Report progress but not too often.
      if (((linear_index % 100) == 0) && prog ) prog->report();

      PARALLEL_END_INTERUPT_REGION
    } // (for each linear index)
    PARALLEL_CHECK_INTERUPT_REGION

    if (DODEBUG) std::cout << tim << " to run the openmp loop.\n";

    delete [] index_max;
    delete [] index_maker;
  }
예제 #12
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);
    }
  }
예제 #13
0
  void CentroidPeaksMD::integrate(typename MDEventWorkspace<MDE, nd>::sptr ws)
  {
    if (nd != 3)
      throw std::invalid_argument("For now, we expect the input MDEventWorkspace to have 3 dimensions only.");

    /// Peak workspace to centroid
    Mantid::DataObjects::PeaksWorkspace_sptr inPeakWS = getProperty("PeaksWorkspace");

    /// Output peaks workspace, create if needed
    Mantid::DataObjects::PeaksWorkspace_sptr peakWS = getProperty("OutputWorkspace");
    if (peakWS != inPeakWS)
      peakWS = inPeakWS->clone();

    /// Value of the CoordinatesToUse property.
    std::string CoordinatesToUse = getPropertyValue("CoordinatesToUse");

    // TODO: Confirm that the coordinates requested match those in the MDEventWorkspace

    /// Radius to use around peaks
    double PeakRadius = getProperty("PeakRadius");

    PRAGMA_OMP(parallel for schedule(dynamic, 10) )
    for (int i=0; i < int(peakWS->getNumberPeaks()); ++i)
    {
      // Get a direct ref to that peak.
      IPeak & p = peakWS->getPeak(i);
      double detectorDistance = p.getL2();

      // Get the peak center as a position in the dimensions of the workspace
      V3D pos;
      if (CoordinatesToUse == "Q (lab frame)")
        pos = p.getQLabFrame();
      else if (CoordinatesToUse == "Q (sample frame)")
        pos = p.getQSampleFrame();
      else if (CoordinatesToUse == "HKL")
        pos = p.getHKL();

      // Build the sphere transformation
      bool dimensionsUsed[nd];
      coord_t center[nd];
      for (size_t d=0; d<nd; ++d)
      {
        dimensionsUsed[d] = true; // Use all dimensions
        center[d] = pos[d];
      }
      CoordTransformDistance sphere(nd, center, dimensionsUsed);

      // Initialize the centroid to 0.0
      signal_t signal = 0;
      coord_t centroid[nd];
      for (size_t d=0; d<nd; d++)
        centroid[d] = 0.0;

      // Perform centroid
      ws->getBox()->centroidSphere(sphere, PeakRadius*PeakRadius, centroid, signal);

      // Normalize by signal
      if (signal != 0.0)
      {
        for (size_t d=0; d<nd; d++)
          centroid[d] /= signal;

        V3D vecCentroid(centroid[0], centroid[1], centroid[2]);

        // Save it back in the peak object, in the dimension specified.
        if (CoordinatesToUse == "Q (lab frame)")
        {
          p.setQLabFrame( vecCentroid, detectorDistance);
          p.findDetector();
        }
        else if (CoordinatesToUse == "Q (sample frame)")
        {
          p.setQSampleFrame( vecCentroid, detectorDistance);
          p.findDetector();
        }
        else if (CoordinatesToUse == "HKL")
        {
          p.setHKL( vecCentroid );
        }


        g_log.information() << "Peak " << i << " at " << pos << ": signal "
            << signal << ", centroid " << vecCentroid
            << " in " << CoordinatesToUse
            << std::endl;
      }
      else
      {
        g_log.information() << "Peak " << i << " at " << pos << " had no signal, and could not be centroided."
            << std::endl;
      }
    }

    // Save the output
    setProperty("OutputWorkspace", peakWS);

  }