/** Set the settings in the given box controller * This should only be called immediately after creating the workspace * * @param bc :: box controller to modify */ void BoxControllerSettingsAlgorithm::setBoxController(BoxController_sptr bc) { size_t nd = bc->getNDims(); int val; val = this->getProperty("SplitThreshold"); bc->setSplitThreshold(val); val = this->getProperty("MaxRecursionDepth"); bc->setMaxDepth(val); // Build MDGridBox std::vector<int> splits = getProperty("SplitInto"); if (splits.size() == 1) { bc->setSplitInto(splits[0]); } else if (splits.size() == nd) { for (size_t d = 0; d < nd; ++d) bc->setSplitInto(d, splits[d]); } else throw std::invalid_argument("SplitInto parameter has " + Strings::toString(splits.size()) + " arguments. It should have either 1, or the " "same as the number of dimensions."); bc->resetNumBoxes(); }
/* Execute the transformtion. Generates an output IMDEventWorkspace. @return the constructed IMDEventWorkspace following the transformation. @param ws: Input MatrixWorkspace const shared pointer */ IMDEventWorkspace_sptr ReflectometryTransformQxQz::execute(MatrixWorkspace_const_sptr inputWs) const { const size_t nbinsx = 10; const size_t nbinsz = 10; auto ws = boost::make_shared<MDEventWorkspace<MDLeanEvent<2>,2> >(); MDHistoDimension_sptr qxDim = MDHistoDimension_sptr(new MDHistoDimension("Qx","qx","(Ang^-1)", static_cast<Mantid::coord_t>(m_qxMin), static_cast<Mantid::coord_t>(m_qxMax), nbinsx)); MDHistoDimension_sptr qzDim = MDHistoDimension_sptr(new MDHistoDimension("Qz","qz","(Ang^-1)", static_cast<Mantid::coord_t>(m_qzMin), static_cast<Mantid::coord_t>(m_qzMax), nbinsz)); ws->addDimension(qxDim); ws->addDimension(qzDim); // Set some reasonable values for the box controller BoxController_sptr bc = ws->getBoxController(); bc->setSplitInto(2); bc->setSplitThreshold(10); // Initialize the workspace. ws->initialize(); // Start with a MDGridBox. ws->splitBox(); auto spectraAxis = inputWs->getAxis(1); for(size_t index = 0; index < inputWs->getNumberHistograms(); ++index) { auto counts = inputWs->readY(index); auto wavelengths = inputWs->readX(index); auto errors = inputWs->readE(index); const size_t nInputBins = wavelengths.size() -1; const double theta_final = spectraAxis->getValue(index); m_QxCalculation.setThetaFinal(theta_final); m_QzCalculation.setThetaFinal(theta_final); //Loop over all bins in spectra for(size_t binIndex = 0; binIndex < nInputBins; ++binIndex) { const double& wavelength = 0.5*(wavelengths[binIndex] + wavelengths[binIndex+1]); double _qx = m_QxCalculation.execute(wavelength); double _qz = m_QzCalculation.execute(wavelength); double centers[2] = {_qx, _qz}; ws->addEvent(MDLeanEvent<2>(float(counts[binIndex]), float(errors[binIndex]*errors[binIndex]), centers)); } ws->splitAllIfNeeded(NULL); } return ws; }
/** * Creates an MD workspace * @param a : pointer to the first dimension of the MDWorkspace *@param b : pointer to the second dimension of the MDWorkspace * @param boxController : controls how the MDWorkspace will be split */ boost::shared_ptr<MDEventWorkspace2Lean> ReflectometryTransform::createMDWorkspace( Mantid::Geometry::IMDDimension_sptr a, Mantid::Geometry::IMDDimension_sptr b, BoxController_sptr boxController) const { auto ws = boost::make_shared<MDEventWorkspace2Lean>(); ws->addDimension(a); ws->addDimension(b); BoxController_sptr wsbc = ws->getBoxController(); // Get the box controller wsbc->setSplitInto(boxController->getSplitInto(0)); wsbc->setMaxDepth(boxController->getMaxDepth()); wsbc->setSplitThreshold(boxController->getSplitThreshold()); // Initialize the workspace. ws->initialize(); // Start with a MDGridBox. ws->splitBox(); return ws; }
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; }
/** * Create an output event workspace filled with data simulated with the fitting * function. * @param baseName :: The base name for the workspace * @param inputWorkspace :: The input workspace. * @param values :: The calculated values * @param outputWorkspacePropertyName :: The property name */ boost::shared_ptr<API::Workspace> FitMD::createEventOutputWorkspace( const std::string &baseName, const API::IMDEventWorkspace &inputWorkspace, const API::FunctionValues &values, const std::string &outputWorkspacePropertyName) { auto outputWS = MDEventFactory::CreateMDWorkspace(inputWorkspace.getNumDims(), "MDEvent"); // Add events // TODO: Generalize to ND (the current framework is a bit limiting) auto mdWS = boost::dynamic_pointer_cast< DataObjects::MDEventWorkspace<DataObjects::MDEvent<4>, 4>>(outputWS); if (!mdWS) { return boost::shared_ptr<API::Workspace>(); } // Bins extents and meta data for (size_t i = 0; i < 4; ++i) { boost::shared_ptr<const Geometry::IMDDimension> inputDim = inputWorkspace.getDimension(i); Geometry::MDHistoDimensionBuilder builder; builder.setName(inputDim->getName()); builder.setId(inputDim->getDimensionId()); builder.setUnits(inputDim->getUnits()); builder.setNumBins(inputDim->getNBins()); builder.setMin(inputDim->getMinimum()); builder.setMax(inputDim->getMaximum()); builder.setFrameName(inputDim->getMDFrame().name()); outputWS->addDimension(builder.create()); } // Run information outputWS->copyExperimentInfos(inputWorkspace); // Coordinates outputWS->setCoordinateSystem(inputWorkspace.getSpecialCoordinateSystem()); // Set sensible defaults for splitting behaviour BoxController_sptr bc = outputWS->getBoxController(); bc->setSplitInto(3); bc->setSplitThreshold(3000); outputWS->initialize(); outputWS->splitBox(); auto inputIter = inputWorkspace.createIterator(); size_t resultValueIndex(0); const float errorSq = 0.0; do { const size_t numEvents = inputIter->getNumEvents(); const float signal = static_cast<float>(values.getCalculated(resultValueIndex)); for (size_t i = 0; i < numEvents; ++i) { coord_t centers[4] = { inputIter->getInnerPosition(i, 0), inputIter->getInnerPosition(i, 1), inputIter->getInnerPosition(i, 2), inputIter->getInnerPosition(i, 3)}; mdWS->addEvent(MDEvent<4>(signal, errorSq, inputIter->getInnerRunIndex(i), inputIter->getInnerDetectorID(i), centers)); } ++resultValueIndex; } while (inputIter->next()); delete inputIter; // This splits up all the boxes according to split thresholds and sizes. auto threadScheduler = new Kernel::ThreadSchedulerFIFO(); Kernel::ThreadPool threadPool(threadScheduler); outputWS->splitAllIfNeeded(threadScheduler); threadPool.joinAll(); outputWS->refreshCache(); // Store it if (!outputWorkspacePropertyName.empty()) { declareProperty( new API::WorkspaceProperty<API::IMDEventWorkspace>( outputWorkspacePropertyName, "", Direction::Output), "Name of the output Workspace holding resulting simulated spectrum"); m_manager->setPropertyValue(outputWorkspacePropertyName, baseName + "Workspace"); m_manager->setProperty(outputWorkspacePropertyName, outputWS); } return outputWS; }