/** * Splits the top level box at level 0 into a defined number of subboxes for the * the first level. * @param bc A pointer to the box controller. */ void ConvertToMD::setupTopLevelSplitting(Mantid::API::BoxController_sptr bc) { const size_t topLevelSplitSetting = 50; const size_t dimCutoff = 4; // Set the Top level splitting for (size_t dim = 0; dim < bc->getNDims(); dim++) { if (dim < dimCutoff) { bc->setSplitTopInto(dim, topLevelSplitSetting); } else { bc->setSplitTopInto(dim, bc->getSplitInto(dim)); } } }
void ConvToMDEventsWS::runConversion(API::Progress *pProgress) { // Get the box controller Mantid::API::BoxController_sptr bc = m_OutWSWrapper->pWorkspace()->getBoxController(); size_t lastNumBoxes = bc->getTotalNumMDBoxes(); size_t nEventsInWS = m_OutWSWrapper->pWorkspace()->getNPoints(); // Is the access to input events thread-safe? // bool MultiThreadedAdding = m_EventWS->threadSafe(); // preprocessed detectors insure that each detector has its own spectra size_t nValidSpectra = m_NSpectra; //--->>> Thread control stuff Kernel::ThreadSchedulerFIFO *ts(NULL); int nThreads(m_NumThreads); if (nThreads < 0) nThreads = 0; // negative m_NumThreads correspond to all cores used, 0 no // threads and positive number -- nThreads requested; bool runMultithreaded = false; if (m_NumThreads != 0) { runMultithreaded = true; // Create the thread pool that will run all of these. It will be deleted by // the threadpool ts = new Kernel::ThreadSchedulerFIFO(); // it will initiate thread pool with number threads or machine's cores (0 in // tp constructor) pProgress->resetNumSteps(nValidSpectra, 0, 1); } Kernel::ThreadPool tp(ts, nThreads, new API::Progress(*pProgress)); //<<<-- Thread control stuff // if any property dimension is outside of the data range requested, the job // is done; if (!m_QConverter->calcGenericVariables(m_Coord, m_NDims)) return; size_t eventsAdded = 0; for (size_t wi = 0; wi < nValidSpectra; wi++) { size_t nConverted = this->conversionChunk(wi); eventsAdded += nConverted; nEventsInWS += nConverted; // 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 if (bc->shouldSplitBoxes(nEventsInWS, eventsAdded, lastNumBoxes)) { if (runMultithreaded) { // Do all the adding tasks tp.joinAll(); // Now do all the splitting tasks m_OutWSWrapper->pWorkspace()->splitAllIfNeeded(ts); if (ts->size() > 0) tp.joinAll(); } else { m_OutWSWrapper->pWorkspace()->splitAllIfNeeded( NULL); // it is done this way as it is possible trying to do single // threaded split more efficiently } // Count the new # of boxes. lastNumBoxes = m_OutWSWrapper->pWorkspace() ->getBoxController() ->getTotalNumMDBoxes(); eventsAdded = 0; pProgress->report(wi); } } // Do a final splitting of everything if (runMultithreaded) { tp.joinAll(); m_OutWSWrapper->pWorkspace()->splitAllIfNeeded(ts); tp.joinAll(); } else { m_OutWSWrapper->pWorkspace()->splitAllIfNeeded(NULL); } // Recount totals at the end. m_OutWSWrapper->pWorkspace()->refreshCache(); // m_OutWSWrapper->refreshCentroid(); pProgress->report(); /// Set the special coordinate system flag on the output workspace. m_OutWSWrapper->pWorkspace()->setCoordinateSystem(m_coordinateSystem); }
/** Execute the algorithm. */ void TransformMD::exec() { Mantid::API::IMDWorkspace_sptr inWS; Mantid::API::IMDWorkspace_sptr outWS; inWS = getProperty("InputWorkspace"); outWS = getProperty("OutputWorkspace"); std::string outName = getPropertyValue("OutputWorkspace"); if (boost::dynamic_pointer_cast<MatrixWorkspace>(inWS)) throw std::runtime_error("TransformMD can only transform a " "MDHistoWorkspace or a MDEventWorkspace."); if (outWS != inWS) { // NOT in-place. So first we clone inWS into outWS IAlgorithm_sptr clone = this->createChildAlgorithm("CloneMDWorkspace", 0.0, 0.5, true); clone->setProperty("InputWorkspace", inWS); clone->executeAsChildAlg(); outWS = clone->getProperty("OutputWorkspace"); } if (!outWS) throw std::runtime_error("Invalid output workspace."); size_t nd = outWS->getNumDims(); m_scaling = getProperty("Scaling"); m_offset = getProperty("Offset"); // Replicate single values if (m_scaling.size() == 1) m_scaling = std::vector<double>(nd, m_scaling[0]); if (m_offset.size() == 1) m_offset = std::vector<double>(nd, m_offset[0]); // Check the size if (m_scaling.size() != nd) throw std::invalid_argument("Scaling argument must be either length 1 or " "match the number of dimensions."); if (m_offset.size() != nd) throw std::invalid_argument("Offset argument must be either length 1 or " "match the number of dimensions."); // Transform the dimensions outWS->transformDimensions(m_scaling, m_offset); MDHistoWorkspace_sptr histo = boost::dynamic_pointer_cast<MDHistoWorkspace>(outWS); IMDEventWorkspace_sptr event = boost::dynamic_pointer_cast<IMDEventWorkspace>(outWS); if (histo) { // Recalculate all the values since the dimensions changed. histo->cacheValues(); // Expect first 3 dimensions to be -1 for changing conventions for (int i = 0; i < static_cast<int>(m_scaling.size()); i++) if (m_scaling[i] < 0) { std::vector<int> axes(m_scaling.size()); // vector with ints. std::iota(std::begin(axes), std::end(axes), 0); // Fill with 0, 1, ... axes[0] = i; axes[i] = 0; if (i > 0) histo = transposeMD(histo, axes); signal_t *signals = histo->getSignalArray(); signal_t *errorsSq = histo->getErrorSquaredArray(); signal_t *numEvents = histo->getNumEventsArray(); // Find the extents size_t nPoints = static_cast<size_t>(histo->getDimension(0)->getNBins()); size_t mPoints = 1; for (size_t k = 1; k < histo->getNumDims(); k++) { mPoints *= static_cast<size_t>(histo->getDimension(k)->getNBins()); } // other dimensions for (size_t j = 0; j < mPoints; j++) { this->reverse(signals + j * nPoints, nPoints); this->reverse(errorsSq + j * nPoints, nPoints); this->reverse(numEvents + j * nPoints, nPoints); } histo = transposeMD(histo, axes); } // Pass on the display normalization from the input workspace histo->setDisplayNormalization(inWS->displayNormalizationHisto()); this->setProperty("OutputWorkspace", histo); } else if (event) { // Call the method for this type of MDEventWorkspace. CALL_MDEVENT_FUNCTION(this->doTransform, outWS); Progress *prog2 = nullptr; ThreadScheduler *ts = new ThreadSchedulerFIFO(); ThreadPool tp(ts, 0, prog2); event->splitAllIfNeeded(ts); // prog2->resetNumSteps( ts->size(), 0.4, 0.6); tp.joinAll(); event->refreshCache(); // Set the special coordinate system. IMDEventWorkspace_sptr inEvent = boost::dynamic_pointer_cast<IMDEventWorkspace>(inWS); event->setCoordinateSystem(inEvent->getSpecialCoordinateSystem()); if (m_scaling[0] < 0) { // Only need these 2 algorithms for transforming with negative number std::vector<double> extents; std::vector<std::string> names, units; for (size_t d = 0; d < nd; d++) { Geometry::IMDDimension_const_sptr dim = event->getDimension(d); // Find the extents extents.push_back(dim->getMinimum()); extents.push_back(dim->getMaximum()); names.push_back(std::string(dim->getName())); units.push_back(dim->getUnits()); } Algorithm_sptr create_alg = createChildAlgorithm("CreateMDWorkspace"); create_alg->setProperty("Dimensions", static_cast<int>(nd)); create_alg->setProperty("EventType", event->getEventTypeName()); create_alg->setProperty("Extents", extents); create_alg->setProperty("Names", names); create_alg->setProperty("Units", units); create_alg->setPropertyValue("OutputWorkspace", "__none"); create_alg->executeAsChildAlg(); Workspace_sptr none = create_alg->getProperty("OutputWorkspace"); AnalysisDataService::Instance().addOrReplace(outName, event); AnalysisDataService::Instance().addOrReplace("__none", none); Mantid::API::BoxController_sptr boxController = event->getBoxController(); std::vector<int> splits; for (size_t d = 0; d < nd; d++) { splits.push_back(static_cast<int>(boxController->getSplitInto(d))); } Algorithm_sptr merge_alg = createChildAlgorithm("MergeMD"); merge_alg->setPropertyValue("InputWorkspaces", outName + ",__none"); merge_alg->setProperty("SplitInto", splits); merge_alg->setProperty( "SplitThreshold", static_cast<int>(boxController->getSplitThreshold())); merge_alg->setProperty("MaxRecursionDepth", 13); merge_alg->executeAsChildAlg(); event = merge_alg->getProperty("OutputWorkspace"); AnalysisDataService::Instance().remove("__none"); } this->setProperty("OutputWorkspace", event); } }
/** run conversion as multithread job*/ void ConvToMDHistoWS::runConversion(API::Progress *pProgress) { // counder for the number of events size_t nAddedEvents(0); // Mantid::API::BoxController_sptr bc = m_OutWSWrapper->pWorkspace()->getBoxController(); size_t lastNumBoxes = bc->getTotalNumMDBoxes(); size_t nEventsInWS = m_OutWSWrapper->pWorkspace()->getNPoints(); // const size_t specSize = m_InWS2D->blocksize(); // preprocessed detectors associate each spectra with a detector (position) size_t nValidSpectra = m_NSpectra; // if any property dimension is outside of the data range requested, the job // is done; if (!m_QConverter->calcGenericVariables(m_Coord, m_NDims)) return; //--->>> Thread control stuff Kernel::ThreadSchedulerFIFO *ts(nullptr); int nThreads(m_NumThreads); if (nThreads < 0) nThreads = 0; // negative m_NumThreads correspond to all cores used, 0 no // threads and positive number -- nThreads requested; bool runMultithreaded = false; if (m_NumThreads != 0) { runMultithreaded = true; // Create the thread pool that will run all of these. It will be deleted by // the threadpool ts = new Kernel::ThreadSchedulerFIFO(); // it will initiate thread pool with number threads or machine's cores (0 in // tp constructor) pProgress->resetNumSteps(nValidSpectra, 0, 1); } Kernel::ThreadPool tp(ts, nThreads, new API::Progress(*pProgress)); //<<<-- Thread control stuff if (runMultithreaded) nThreads = static_cast<int>(tp.getNumPhysicalCores()); else nThreads = 1; // estimate the size of data conversion a single thread should perform // TO DO: this piece of code should be carefully rethinked size_t eventsChunkNum = bc->getSignificantEventsNumber(); this->estimateThreadWork(nThreads, specSize, eventsChunkNum); // External loop over the spectra: for (size_t i = 0; i < nValidSpectra; i += m_spectraChunk) { size_t nThreadEv = this->conversionChunk(i); nAddedEvents += nThreadEv; nEventsInWS += nThreadEv; if (bc->shouldSplitBoxes(nEventsInWS, nAddedEvents, lastNumBoxes)) { if (runMultithreaded) { // Do all the adding tasks tp.joinAll(); // Now do all the splitting tasks m_OutWSWrapper->pWorkspace()->splitAllIfNeeded(ts); if (ts->size() > 0) tp.joinAll(); } else { m_OutWSWrapper->pWorkspace()->splitAllIfNeeded( nullptr); // it is done this way as it is possible trying to do // single // threaded split more efficiently } // Count the new # of boxes. lastNumBoxes = bc->getTotalNumMDBoxes(); nAddedEvents = 0; pProgress->report(i, "Adding Events"); } // TODO:: // if (m_OutWSWrapper->ifNeedsSplitting()) //{ // // Do all the adding tasks // //tp.joinAll(); // // Now do all the splitting tasks // //m_OutWSWrapper->pWorkspace()->splitAllIfNeeded(ts); // m_OutWSWrapper->splitList(ts); // //if (ts->size() > 0) tp.joinAll(); // // Count the new # of boxes. // lastNumBoxes = // m_OutWSWrapper->pWorkspace()->getBoxController()->getTotalNumMDBoxes(); //} // pProgress->report(i); } // end detectors loop; // Do a final splitting of everything if (runMultithreaded) { tp.joinAll(); m_OutWSWrapper->pWorkspace()->splitAllIfNeeded(ts); tp.joinAll(); } else { m_OutWSWrapper->pWorkspace()->splitAllIfNeeded(nullptr); } m_OutWSWrapper->pWorkspace()->refreshCache(); // m_OutWSWrapper->refreshCentroid(); pProgress->report(); /// Set the special coordinate system flag on the output workspace. m_OutWSWrapper->pWorkspace()->setCoordinateSystem(m_coordinateSystem); }