Beispiel #1
0
/// Constructor
/// @param M :: A matrix to copy.
GSLMatrix::GSLMatrix(const Kernel::Matrix<double> &M) {
  m_matrix = gsl_matrix_alloc(M.numRows(), M.numCols());
  for (size_t i = 0; i < size1(); ++i)
    for (size_t j = 0; j < size2(); ++j) {
      set(i, j, M[i][j]);
    }
}
Beispiel #2
0
std::vector<Kernel::V3D> PeakShapeEllipsoid::getDirectionInSpecificFrame(
    Kernel::Matrix<double> &invertedGoniometerMatrix) const {
  std::vector<Kernel::V3D> directionsInFrame;

  if ((invertedGoniometerMatrix.numCols() != m_directions.size()) ||
      (invertedGoniometerMatrix.numRows() != m_directions.size())) {
    throw std::invalid_argument("The inverted goniometer matrix is not "
                                "compatible with the direction vector");
  }

  for (const auto &direction : m_directions) {
    directionsInFrame.push_back(invertedGoniometerMatrix * direction);
  }

  return directionsInFrame;
}
Beispiel #3
0
/**
 * Checks the normalization workspace against the indices of the original
 * dimensions.
 * If not found, the corresponding dimension is integrated
 * @param otherDimValues Values from non-HKL dimensions
 * @param skipNormalization [InOut] Sets the flag true if normalization values
 * are outside of original inputs
 * @return Affine trasform matrix
 */
Kernel::Matrix<coord_t> MDNormDirectSC::findIntergratedDimensions(
    const std::vector<coord_t> &otherDimValues, bool &skipNormalization) {
  // Get indices of the original dimensions in the output workspace,
  // and if not found, the corresponding dimension is integrated
  Kernel::Matrix<coord_t> affineMat =
      m_normWS->getTransformFromOriginal(0)->makeAffineMatrix();

  const size_t nrm1 = affineMat.numRows() - 1;
  const size_t ncm1 = affineMat.numCols() - 1;
  for (size_t row = 0; row < nrm1; row++) // affine matrix, ignore last row
  {
    const auto dimen = m_normWS->getDimension(row);
    const auto dimMin(dimen->getMinimum()), dimMax(dimen->getMaximum());
    if (affineMat[row][0] == 1.) {
      m_hIntegrated = false;
      m_hIdx = row;
      m_hmin = std::max(m_hmin, dimMin);
      m_hmax = std::min(m_hmax, dimMax);
      if (m_hmin > dimMax || m_hmax < dimMin) {
        skipNormalization = true;
      }
    }
    if (affineMat[row][1] == 1.) {
      m_kIntegrated = false;
      m_kIdx = row;
      m_kmin = std::max(m_kmin, dimMin);
      m_kmax = std::min(m_kmax, dimMax);
      if (m_kmin > dimMax || m_kmax < dimMin) {
        skipNormalization = true;
      }
    }
    if (affineMat[row][2] == 1.) {
      m_lIntegrated = false;
      m_lIdx = row;
      m_lmin = std::max(m_lmin, dimMin);
      m_lmax = std::min(m_lmax, dimMax);
      if (m_lmin > dimMax || m_lmax < dimMin) {
        skipNormalization = true;
      }
    }

    if (affineMat[row][3] == 1.) {
      m_dEIntegrated = false;
      m_eIdx = row;
      m_dEmin = std::max(m_dEmin, dimMin);
      m_dEmax = std::min(m_dEmax, dimMax);
      if (m_dEmin > dimMax || m_dEmax < dimMin) {
        skipNormalization = true;
      }
    }
    for (size_t col = 4; col < ncm1; col++) // affine matrix, ignore last column
    {
      if (affineMat[row][col] == 1.) {
        double val = otherDimValues.at(col - 3);
        if (val > dimMax || val < dimMin) {
          skipNormalization = true;
        }
      }
    }
  }

  return affineMat;
}
Beispiel #4
0
/// Constructor
/// @param M :: A matrix to copy.
GSLMatrix::GSLMatrix(const Kernel::Matrix<double> &M)
    : m_data(M.getVector()),
      m_view(gsl_matrix_view_array(m_data.data(), M.numRows(), M.numCols())) {}
/**
 * This function will create the skew matrix and basis for a non-orthogonal
 * representation.
 *
 * @param ol : The oriented lattice containing B matrix and crystal basis
 *vectors
 * @param w : The tranform requested when MDworkspace was created
 * @param aff : The affine matrix taking care of coordinate transformations
 */
void vtkDataSetToNonOrthogonalDataSet::createSkewInformation(
    Geometry::OrientedLattice &ol, Kernel::DblMatrix &w,
    Kernel::Matrix<coord_t> &aff) {
  // Get the B matrix
  Kernel::DblMatrix bMat = ol.getB();
  // Apply the W tranform matrix
  bMat *= w;
  // Create G*
  Kernel::DblMatrix gStar = bMat.Tprime() * bMat;
  Geometry::UnitCell uc(ol);
  uc.recalculateFromGstar(gStar);
  m_skewMat = uc.getB();
  // Calculate the column normalisation
  std::vector<double> bNorm;
  for (std::size_t i = 0; i < m_skewMat.numCols(); i++) {
    double sum = 0.0;
    for (std::size_t j = 0; j < m_skewMat.numRows(); j++) {
      sum += m_skewMat[j][i] * m_skewMat[j][i];
    }
    bNorm.push_back(std::sqrt(sum));
  }
  // Apply column normalisation to skew matrix
  Kernel::DblMatrix scaleMat(3, 3, true);
  scaleMat[0][0] /= bNorm[0];
  scaleMat[1][1] /= bNorm[1];
  scaleMat[2][2] /= bNorm[2];
  m_skewMat *= scaleMat;

  // Setup basis normalisation array
  // Intel and MSBuild can't handle this
  // m_basisNorm = {ol.astar(), ol.bstar(), ol.cstar()};
  m_basisNorm.push_back(ol.astar());
  m_basisNorm.push_back(ol.bstar());
  m_basisNorm.push_back(ol.cstar());

  // Expand matrix to 4 dimensions if necessary
  if (4 == m_numDims) {
    m_basisNorm.push_back(1.0);
    Kernel::DblMatrix temp(4, 4, true);
    for (std::size_t i = 0; i < 3; i++) {
      for (std::size_t j = 0; j < 3; j++) {
        temp[i][j] = m_skewMat[i][j];
      }
    }
    m_skewMat = temp;
  }

  // Convert affine matrix to similar type as others
  Kernel::DblMatrix affMat(aff.numRows(), aff.numCols());
  for (std::size_t i = 0; i < aff.numRows(); i++) {
    for (std::size_t j = 0; j < aff.numCols(); j++) {
      affMat[i][j] = aff[i][j];
    }
  }
  // Strip affine matrix down to correct dimensions
  this->stripMatrix(affMat);

  // Perform similarity transform to get coordinate orientation correct
  m_skewMat = affMat.Tprime() * (m_skewMat * affMat);
  m_basisNorm = affMat * m_basisNorm;
  if (4 == m_numDims) {
    this->stripMatrix(m_skewMat);
  }

  this->findSkewBasis(m_basisX, m_basisNorm[0]);
  this->findSkewBasis(m_basisY, m_basisNorm[1]);
  this->findSkewBasis(m_basisZ, m_basisNorm[2]);
}
    /// Run the algorithm
    void PredictFractionalPeaks::exec()
    {
       PeaksWorkspace_sptr Peaks=getProperty("Peaks");

       vector<double> hOffsets = getProperty("HOffset");
       vector<double> kOffsets = getProperty("KOffset");
       vector<double> lOffsets = getProperty("LOffset");
       if ( hOffsets.empty())hOffsets.push_back(0.0);
       if ( kOffsets.empty())kOffsets.push_back(0.0);
       if ( lOffsets.empty())lOffsets.push_back(0.0);

;
       bool includePeaksInRange= getProperty("IncludeAllPeaksInRange");

       if(  Peaks->getNumberPeaks()<=0)
       {
         g_log.error()<<"There are No peaks in the input PeaksWorkspace\n";
         return;
       }

       API::Sample samp= Peaks->sample();

       Geometry::OrientedLattice &ol = samp.getOrientedLattice();

       Geometry::Instrument_const_sptr Instr = Peaks->getInstrument();

       boost::shared_ptr<IPeaksWorkspace> OutPeaks=WorkspaceFactory::Instance().createPeaks();
       OutPeaks->setInstrument(Instr);
      // AnalysisDataService::Instance().addOrReplace(getPropertyValue("FracPeaks"),OutPeaks);

       V3D hkl;
       int peakNum =0;
       int NPeaks = Peaks->getNumberPeaks();
       Kernel::Matrix<double> Gon;
       Gon.identityMatrix();

       double Hmin= getProperty("Hmin");
       double Hmax= getProperty("Hmax");
       double Kmin= getProperty("Kmin");
       double Kmax= getProperty("Kmax");
       double Lmin= getProperty("Lmin");
       double Lmax= getProperty("Lmax");

       int N=NPeaks;
       if( includePeaksInRange)
       {
         N=(int)((Hmax-Hmin+1)*(Kmax-Kmin+1)*(Lmax-Lmin+1)+.5);
         N=max<int>(100,N);
       }
       IPeak& peak0 =Peaks->getPeak(0);
       int RunNumber = peak0.getRunNumber();
       Gon=peak0.getGoniometerMatrix();
       Progress prog(this, 0,  1,N);
       if( includePeaksInRange)
       {


         hkl[0]=Hmin;
         hkl[1]=Kmin;
         hkl[2]=Lmin;
       }else
       {
         hkl[0]=peak0.getH();
         hkl[1]=peak0.getK();
         hkl[2] =peak0.getL();


       }

       Kernel::DblMatrix UB= ol.getUB();
       vector< vector<int> > AlreadyDonePeaks;
       bool done = false;
       int ErrPos = 1;//Used to determine position in code of a throw
       while( !done)
       {
         for( size_t hoffset=0;hoffset<hOffsets.size();hoffset++)
           for(size_t  koffset=0;koffset<kOffsets.size();koffset++)
             for( size_t loffset=0;loffset<lOffsets.size();loffset++)
                try
                {
                  V3D hkl1( hkl );
                  ErrPos = 0;

                  hkl1[0] += hOffsets[hoffset] ;
                  hkl1[1] += kOffsets[koffset] ;
                  hkl1[2] += lOffsets[loffset] ;

                  Kernel::V3D Qs = UB * hkl1 ;
                  Qs*= 2.0;
                  Qs*=M_PI;
                  Qs=Gon*Qs;
                  if( Qs[2] <= 0 )
                    continue;

                  ErrPos=1;
                  boost::shared_ptr<IPeak> peak( Peaks->createPeak( Qs, 1 ));

                  peak->setGoniometerMatrix(Gon);

                  if (Qs[2]>0 && peak->findDetector())
                  {
                    ErrPos=2;
                    vector<int> SavPk;
                    SavPk.push_back(RunNumber);
                    SavPk.push_back((int)floor(1000*hkl1[0]+.5));
                    SavPk.push_back((int)floor(1000*hkl1[1]+.5));
                    SavPk.push_back((int)floor(1000*hkl1[2]+.5));

                  //TODO keep list sorted so searching is faster?
                    vector<vector<int> >::iterator it = find(AlreadyDonePeaks.begin(),AlreadyDonePeaks.end(),SavPk);

                    ErrPos=3;
                    if( it == AlreadyDonePeaks.end())
                      AlreadyDonePeaks.push_back(SavPk);
                    else
                      continue;


                    ErrPos=4;
                    peak->setHKL(hkl1);
                    peak->setRunNumber(RunNumber);
                    OutPeaks->addPeak(*peak);
                  }
                }catch(...)
                {

                  if( ErrPos != 1)// setQLabFrame in createPeak throws exception
                    throw new std::invalid_argument( "Invalid data at this point");
                }
         if( includePeaksInRange)
         {
           hkl[0]++;
           if( hkl[0]>Hmax)
           {
             hkl[0]=Hmin;
             hkl[1]++;
             if( hkl[1]> Kmax)
             {

               hkl[1]=Kmin;
               hkl[2]++;
               if( hkl[2]> Lmax)
                 done = true;
             }
           }
         }else
         {
           peakNum++;
           if( peakNum >= NPeaks)
             done = true;
           else
           {// peak0= Peaks->getPeak(peakNum);
             IPeak& peak1= Peaks->getPeak(peakNum);
           //??? could not assign to peak0 above. Did not work
            // the peak that peak0 was associated with did NOT change
             hkl[0]=peak1.getH();
             hkl[1]=peak1.getK();
             hkl[2] =peak1.getL();
             Gon=peak1.getGoniometerMatrix();
             RunNumber = peak1.getRunNumber();

           }
         }
         prog.report();
       }


     setProperty("FracPeaks",OutPeaks);



    }
Beispiel #7
0
  /* Execute the algorithm.   */
void ConvertToQ3DdE::exec(){
    Timer tim, timtotal;
    CPUTimer cputim, cputimtotal;

     // -------- Input workspace 
    MatrixWorkspace_sptr inMatrixWS = getProperty("InputWorkspace");
    Workspace2D_sptr inWS2D         = boost::dynamic_pointer_cast<Workspace2D>(inMatrixWS);


    // get the energy axis
    NumericAxis *pEnAxis = dynamic_cast<NumericAxis *>(inWS2D->getAxis(0));
    if(!pEnAxis){
       convert_log.error()<<"Can not get proper energy axis from processed workspace\n";
       throw(std::invalid_argument("Input workspace is not propwer converted to energy workspace"));
    }
    size_t lastInd = inWS2D->getAxis(0)->length()-1;
    double E_max = inWS2D->getAxis(0)->operator()(lastInd);
    double E_min = inWS2D->getAxis(0)->operator()(0);

    //double E_min = inWS2D->readX(0).front();
    //double E_max = inWS2D->readX(0).back();
    if(E_min>=E_max){
        convert_log.error()<<" expecting to process energy form "<<E_min<<" to "<<E_max<<" but Emin>=Emax\n";
        throw(std::invalid_argument(" Emin>=Emax"));
    }
    //*** Input energy
    // get and check input energy 
    double Ei = getProperty("EnergyInput");
    // check if workspace knows better 
    if(inWS2D->run().hasProperty("Ei")){
        double Ei_t = boost::lexical_cast<double>(inWS2D->run().getProperty("Ei")->value());
        if(std::fabs(Ei-Ei_t)>double(FLT_EPSILON)){
            g_log.information()<<" energy: "<<Ei<<" obtained from the algorithm parameters has been replaced by the energy:"<<Ei_t<<", obtained from the workspace\n";
            Ei=Ei_t;
            setProperty("EnergyInput", Ei);
        }

    }
    if (E_max >Ei){
        convert_log.error()<<"Maximal elergy transferred to sample eq "<<E_max<<" and exceeds the input energy "<<Ei<<std::endl;
        throw(std::invalid_argument("Maximal transferred energy exceeds input energy"));
    }

    // the wawe vector of input neutrons;
    double ki=sqrt(Ei/PhysicalConstants::E_mev_toNeutronWavenumberSq);
    std::vector<double> QEmin = getProperty("MinQdE_values");
    std::vector<double> QEmax = getProperty("MaxQdE_values");
    
    // Try to get the output workspace
    IMDEventWorkspace_sptr i_out = getProperty("OutputWorkspace");
    boost::shared_ptr<MDEvents::MDEventWorkspace<MDE,4> > ws  = boost::dynamic_pointer_cast<MDEvents::MDEventWorkspace<MDE,4> >( i_out );

    std::string dimensionNames[4] = {"Q_x", "Q_y", "Q_z","DeltaE"};
    if (ws){
       //check existing worspace limits and agree these with new limits if they were specified;
       if(QEmin.empty())QEmin.assign(4, FLT_MAX);
       if(QEmax.empty())QEmax.assign(4,-FLT_MAX);
       for(int i=0;i<4;i++){
           // Check that existing workspace dimensions make sense with the desired one (using the name)
            if (ws->getDimension(i)->getName() != dimensionNames[i]){
               convert_log.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.\n";
               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.");
            }
            // coordinate existing and nwe 
            double ws_min = ws->getDimension(i)->getMinimum();
            double ws_max = ws->getDimension(i)->getMaximum();
            if(ws_min>QEmin[i])QEmin[i]=ws_min;
            if(ws_max<QEmax[i])QEmax[i]=ws_max;
       }
       // verify that final limits are correct
       check_max_morethen_min(QEmin,QEmax);
    }else{
        if(QEmin.empty()||QEmax.empty()){
            convert_log.error()<<" min and max Q-dE values can not be empty when creating new workspace";
            throw(std::invalid_argument(" min-max property is empty"));
        }
        if(QEmin.size()!=4||QEmax.size()!=4){
            convert_log.error()<<" min and max Q-dE values have to had 4 elements each";
            throw(std::invalid_argument(" min-max is not 4Dimensional"));
        }
        check_max_morethen_min(QEmin,QEmax);
        std::string dimensionUnits[4] = {"Amgstroms^-1", "Amgstroms^-1", "Amgstroms^-1","meV"};
        ws = create_empty4DEventWS(dimensionNames,dimensionUnits,QEmin,QEmax);
    }
    ws->splitBox();
    //BoxController_sptr bc = ws->getBoxController();
   // if (!bc)
   //   throw std::runtime_error("Output MDEventWorkspace does not have a BoxController!");

    // copy experiment info into 
    ExperimentInfo_sptr ExperimentInfo(inWS2D->cloneExperimentInfo());
    uint16_t runIndex = ws->addExperimentInfo(ExperimentInfo);

 

    // Initalize the matrix to 3x3 identity
    Kernel::Matrix<double> mat = Kernel::Matrix<double>(3,3, true);
    // Set the matrix based on UB etc.
    Kernel::Matrix<double> ub = inWS2D->sample().getOrientedLattice().getUB();
    Kernel::Matrix<double> gon =inWS2D->run().getGoniometer().getR();
    // As per Busing and Levy 1967, HKL = Goniometer * UB * q_lab_frame
    mat = gon * ub;
    std::vector<double> rotMat = mat.get_vector();

    const size_t numSpec  = inWS2D->getNumberHistograms();
    const size_t specSize = inWS2D->blocksize();    

    // Initialise the progress reporting object
    Progress progress(this,0.0,1.0,numSpec);
   // Try to check if one should use preprocessed detector positions or try to calculate the new one
    bool reuse_preprocecced_detectors = getProperty("UsePreprocessedDetectors");
    if(!(reuse_preprocecced_detectors&&det_loc.is_defined()))process_detectors_positions(inWS2D);
 

    // allocate the events buffer;
   //   std::vector<MDE> out_events;
   //   out_events.reserve(specSize);
    // To track when to split up boxes
  //   size_t eventsAdded = 0;
  //   size_t lastNumBoxes = ws->getBoxController()->getTotalNumMDBoxes();

//    // Create the thread pool that will run all of these.
//    ThreadScheduler * ts = new ThreadSchedulerLargestCost();
//    ThreadPool tp(ts);
//      boost::function<void ()> func;
//        func = boost::bind(&ConvertToQ3DdE::convertEventList<TofEvent>, &*this, static_cast<int>(wi));
//
      size_t n_added_events(0);
      size_t SPLIT_LEVEL(1000);
     // PARALLEL_FOR1(inWS2D)
      for (int64_t i = 0; i < int64_t(numSpec); ++i)
      {
   //     PARALLEL_START_INTERUPT_REGION
        const MantidVec& E_transfer = inWS2D->readX(i);
        const MantidVec& Signal     = inWS2D->readY(i);
        const MantidVec& Error      = inWS2D->readE(i);
        int32_t det_id              = det_loc.det_id[i];
    
        coord_t QE[4];
        for (size_t j = 0; j < specSize; ++j)
        {
            // drop emtpy events 
            if(Signal[j]<FLT_EPSILON)continue;

            double E_tr = 0.5*(E_transfer[j]+E_transfer[j+1]);
            if(E_tr<E_min||E_tr>=E_max)continue;

            double k_tr = sqrt((Ei-E_tr)/PhysicalConstants::E_mev_toNeutronWavenumberSq);
   
            double  ex = det_loc.det_dir[i].X();
            double  ey = det_loc.det_dir[i].Y();
            double  ez = det_loc.det_dir[i].Z();
            double  qx  =  -ex*k_tr;                
            double  qy  =  -ey*k_tr;
            double  qz  = ki - ez*k_tr;

            QE[0]  = (coord_t)(rotMat[0]*qx+rotMat[3]*qy+rotMat[6]*qz);  if(QE[0]<QEmin[0]||QE[0]>=QEmax[0])continue;
            QE[1]  = (coord_t)(rotMat[1]*qx+rotMat[4]*qy+rotMat[7]*qz);  if(QE[1]<QEmin[1]||QE[1]>=QEmax[1])continue;
            QE[2]  = (coord_t)(rotMat[2]*qx+rotMat[5]*qy+rotMat[8]*qz);  if(QE[2]<QEmin[2]||QE[2]>=QEmax[2])continue;
            QE[3]  = (coord_t)E_tr;
            float ErrSq = float(Error[j]*Error[j]);
            ws->addEvent(MDE(float(Signal[j]),ErrSq,runIndex,det_id,QE));
            n_added_events++;
        }
  
      // This splits up all the boxes according to split thresholds and sizes.
        //Kernel::ThreadScheduler * ts = new ThreadSchedulerFIFO();
        //ThreadPool tp(NULL);
        if(n_added_events>SPLIT_LEVEL){
            ws->splitAllIfNeeded(NULL);
            n_added_events=0;
        }
        //tp.joinAll();
        progress.report(i);  
   //       PARALLEL_END_INTERUPT_REGION
      }
 //    PARALLEL_CHECK_INTERUPT_REGION
        if(n_added_events>0){
            ws->splitAllIfNeeded(NULL);
            n_added_events=0;
        }
        ws->refreshCache();
        progress.report();      


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

//
//
//    // ------------------- Cache values that are common for all ---------------------------
//    // Extract some parameters global to the instrument
//    in_ws->getInstrument()->getInstrumentParameters(l1,beamline,beamline_norm, samplePos);
//    beamline_norm = beamline.norm();
//    beamDir = beamline / beamline.norm();
//
//    //To get all the detector ID's
//    in_ws->getInstrument()->getDetectors(allDetectors);
//
//    size_t totalCost = in_ws->getNumberEvents();
//    prog = new Progress(this, 0, 1.0, totalCost);
////    if (DODEBUG) prog = new ProgressText(0, 1.0, totalCost, true);
////    if (DODEBUG) prog->setNotifyStep(1);
//
//    // Create the thread pool that will run all of these.
//    ThreadScheduler * ts = new ThreadSchedulerLargestCost();
//    ThreadPool tp(ts);
//
//    if (DODEBUG) std::cout << cputim << ": initial setup. There are " << lastNumBoxes << " MDBoxes.\n";
//
//    for (size_t wi=0; wi < in_ws->getNumberHistograms(); wi++)
//    {
//      // Equivalent of: this->convertEventList(wi);
//      EventList & el = in_ws->getEventList(wi);
//
//      // We want to bind to the right templated function, so we have to know the type of TofEvent contained in the EventList.
//      boost::function<void ()> func;
//      switch (el.getEventType())
//      {
//      case TOF:
//        func = boost::bind(&ConvertToQ3DdE::convertEventList<TofEvent>, &*this, static_cast<int>(wi));
//        break;
//      case WEIGHTED:
//        func = boost::bind(&ConvertToQ3DdE::convertEventList<WeightedEvent>, &*this, static_cast<int>(wi));
//        break;
//      case WEIGHTED_NOTIME:
//        func = boost::bind(&ConvertToQ3DdE::convertEventList<WeightedEventNoTime>, &*this, static_cast<int>(wi));
//        break;
//      default:
//        throw std::runtime_error("EventList had an unexpected data type!");
//      }
//
//      // Give this task to the scheduler
//      double cost = double(el.getNumberEvents());
//      ts->push( new FunctionTask( func, cost) );
//
//      // Keep a running total of how many events we've added
//      eventsAdded += el.getNumberEvents();
//      if (bc->shouldSplitBoxes(eventsAdded, lastNumBoxes))
//      {
//        if (DODEBUG) std::cout << cputim << ": Added tasks worth " << eventsAdded << " events.\n";
//        // Do all the adding tasks
//        tp.joinAll();
//        if (DODEBUG) std::cout << 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) std::cout << cputim << ": Performing the splitting. There are now " << lastNumBoxes << " boxes.\n";
//        eventsAdded = 0;
//      }
//    }
//
//    if (DODEBUG) std::cout << cputim << ": We've added tasks worth " << eventsAdded << " events.\n";
//
//    tp.joinAll();
//    if (DODEBUG) std::cout << cputim << ": Performing the FINAL addition of these events.\n";
//
//    // Do a final splitting of everything
//    ws->splitAllIfNeeded(ts);
//    tp.joinAll();
//    if (DODEBUG) std::cout << 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) std::cout << cputim << ": Performing the refreshCache().\n";
//
//    //TODO: Centroid in parallel, maybe?
//    ws->getBox()->refreshCentroid(NULL);
//    if (DODEBUG) std::cout << cputim << ": Performing the refreshCentroid().\n";
//
//
//    if (DODEBUG)
//    {
//      std::cout << "Workspace has " << ws->getNPoints() << " events. This took " << cputimtotal << " in total.\n";
//      std::vector<std::string> stats = ws->getBoxControllerStats();
//      for (size_t i=0; i<stats.size(); ++i)
//        std::cout << stats[i] << "\n";
//      std::cout << std::endl;
//    }
//
//
  }