/// Populates a spectrum with peaks of type given by peakShape argument. /// @param spectrum :: A composite function that is a collection of peaks. /// @param peakShape :: A shape of each peak as a name of an IPeakFunction. /// @param centresAndIntensities :: A FunctionValues object containing centres /// and intensities for the peaks. First nPeaks calculated values are the /// centres and the following nPeaks values are the intensities. /// @param xVec :: x-values of a tabulated width function. /// @param yVec :: y-values of a tabulated width function. /// @param fwhmVariation :: A variation in the peak width allowed in a fit. /// @param defaultFWHM :: A default value for the FWHM to use if xVec and yVec /// are empty. /// @param nRequiredPeaks :: A number of peaks required to be created. /// @param fixAllPeaks :: If true fix all peak parameters /// @return :: The number of peaks that will be actually fitted. size_t buildSpectrumFunction(API::CompositeFunction &spectrum, const std::string &peakShape, const API::FunctionValues ¢resAndIntensities, const std::vector<double> &xVec, const std::vector<double> &yVec, double fwhmVariation, double defaultFWHM, size_t nRequiredPeaks, bool fixAllPeaks) { if (xVec.size() != yVec.size()) { throw std::runtime_error("WidthX and WidthY must have the same size."); } auto nPeaks = calculateNPeaks(centresAndIntensities); auto maxNPeaks = calculateMaxNPeaks(nPeaks); if (nRequiredPeaks > maxNPeaks) { maxNPeaks = nRequiredPeaks; } for (size_t i = 0; i < maxNPeaks; ++i) { const bool isGood = i < nPeaks; const auto centre = isGood ? centresAndIntensities.getCalculated(i) : 0.0; const auto intensity = isGood ? centresAndIntensities.getCalculated(i + nPeaks) : 0.0; auto peak = createPeak(peakShape, centre, intensity, xVec, yVec, fwhmVariation, defaultFWHM, isGood, fixAllPeaks); spectrum.addFunction(peak); } return nPeaks; }
/** * 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; }