diff --git a/Code/Mantid/Framework/SINQ/inc/MantidSINQ/PoldiFitPeaks2D.h b/Code/Mantid/Framework/SINQ/inc/MantidSINQ/PoldiFitPeaks2D.h index 9735c98abde7..973c128b27ba 100644 --- a/Code/Mantid/Framework/SINQ/inc/MantidSINQ/PoldiFitPeaks2D.h +++ b/Code/Mantid/Framework/SINQ/inc/MantidSINQ/PoldiFitPeaks2D.h @@ -109,6 +109,8 @@ class MANTID_SINQ_DLL PoldiFitPeaks2D : public API::Algorithm { const std::string &crystalSystem, const PoldiPeakCollection_sptr &peakCollection); + std::string getUserSpecifiedTies(const API::IFunction_sptr &poldiFn); + PoldiPeakCollection_sptr getPeakCollectionFromFunction(const API::IFunction_sptr &fitFunction); diff --git a/Code/Mantid/Framework/SINQ/src/PoldiFitPeaks2D.cpp b/Code/Mantid/Framework/SINQ/src/PoldiFitPeaks2D.cpp index 38fa55e16789..6ea493548f44 100644 --- a/Code/Mantid/Framework/SINQ/src/PoldiFitPeaks2D.cpp +++ b/Code/Mantid/Framework/SINQ/src/PoldiFitPeaks2D.cpp @@ -616,6 +616,63 @@ std::string PoldiFitPeaks2D::getRefinedStartingCell( return Geometry::unitCellToStr(refinedCell); } +/** + * @brief Returns a string with ties that is passed to Fit + * + * This method uses the GlobalParameters property, which may contain a comma- + * separated list of parameter names that should be the same for all peaks. + * + * Parameters that do not exist are silently ignored, but a warning is written + * to the log so that users have a chance to find typos. + * + * @param poldiFn :: Function with some parameters. + * @return :: String to pass to the Ties-property of Fit. + */ +std::string +PoldiFitPeaks2D::getUserSpecifiedTies(const IFunction_sptr &poldiFn) { + std::string tieParameterList = getProperty("GlobalParameters"); + + if (!tieParameterList.empty()) { + std::vector tieParameters; + + boost::split(tieParameters, tieParameterList, boost::is_any_of(",;")); + + std::vector parameters = poldiFn->getParameterNames(); + + std::vector tieComponents; + for (auto it = tieParameters.begin(); it != tieParameters.end(); ++it) { + if (!(*it).empty()) { + std::vector matchedParameters; + + for (auto parName = parameters.begin(); parName != parameters.end(); + ++parName) { + if (boost::algorithm::ends_with(*parName, *it)) { + matchedParameters.push_back(*parName); + } + } + + if (matchedParameters.size() > 1) { + std::string reference = matchedParameters.front(); + + for (auto par = matchedParameters.begin() + 1; + par != matchedParameters.end(); ++par) { + tieComponents.push_back(*par + "=" + reference); + } + } else { + g_log.warning("Function does not have a parameter called '" + *it + + "', ignoring."); + } + } + } + + if (tieComponents.size() > 0) { + return boost::algorithm::join(tieComponents, ","); + } + } + + return ""; +} + /** * Construct a PoldiPeakCollection from a Poldi2DFunction * @@ -892,6 +949,10 @@ IAlgorithm_sptr PoldiFitPeaks2D::calculateSpectrum( mdFunction->addFunction(getFunctionFromPeakCollection(*pc)); } + std::string ties = getUserSpecifiedTies(mdFunction); + + std::cout << ties << std::endl; + // And finally background terms addBackgroundTerms(mdFunction); @@ -910,6 +971,7 @@ IAlgorithm_sptr PoldiFitPeaks2D::calculateSpectrum( fit->setProperty("MaxIterations", maxIterations); fit->setProperty("Minimizer", "Levenberg-MarquardtMD"); + fit->setProperty("Ties", ties); // Setting the level to Notice to avoid problems with Levenberg-MarquardtMD. int oldLogLevel = g_log.getLevel(); @@ -1100,6 +1162,10 @@ void PoldiFitPeaks2D::init() { "Profile function to use for integrating the peak profiles " "before calculating the spectrum."); + declareProperty("GlobalParameters", "", "Comma-separated list of parameter " + "names that are identical for all " + "peaks."); + declareProperty("PawleyFit", false, "Instead of refining individual peaks, " "refine a unit cell. Peaks must be " @@ -1173,8 +1239,8 @@ void PoldiFitPeaks2D::exec() { std::vector integralPeaks = getCountPeakCollections(fitFunction); - for(size_t i = 0; i < peakCollections.size(); ++i) { - assignMillerIndices(peakCollections[i], integralPeaks[i]); + for (size_t i = 0; i < peakCollections.size(); ++i) { + assignMillerIndices(peakCollections[i], integralPeaks[i]); } // Get the calculated 2D workspace diff --git a/Code/Mantid/Framework/SINQ/test/PoldiFitPeaks2DTest.h b/Code/Mantid/Framework/SINQ/test/PoldiFitPeaks2DTest.h index 4eb4a00e1339..3e9d746d207e 100644 --- a/Code/Mantid/Framework/SINQ/test/PoldiFitPeaks2DTest.h +++ b/Code/Mantid/Framework/SINQ/test/PoldiFitPeaks2DTest.h @@ -225,6 +225,49 @@ class PoldiFitPeaks2DTest : public CxxTest::TestSuite } } + void testGetUserDefinedTies() + { + TestablePoldiFitPeaks2D spectrumCalculator; + spectrumCalculator.initialize(); + spectrumCalculator.setProperty("PeakProfileFunction", "Gaussian"); + + // Create a function with some peaks + PoldiPeakCollection_sptr peaks = PoldiPeakCollectionHelpers::createPoldiPeakCollectionNormalized(); + boost::shared_ptr poldi2DFunction = spectrumCalculator.getFunctionFromPeakCollection(peaks); + + // Make "Height" global, i.e. the same for all peaks + spectrumCalculator.setProperty("GlobalParameters", "Height"); + std::string ties = spectrumCalculator.getUserSpecifiedTies(poldi2DFunction); + TS_ASSERT_EQUALS(ties, "f1.Height=f0.Height,f2.Height=f0.Height,f3.Height=f0.Height"); + + // Height and Sigma + spectrumCalculator.setProperty("GlobalParameters", "Height,Sigma"); + ties = spectrumCalculator.getUserSpecifiedTies(poldi2DFunction); + + TS_ASSERT_EQUALS(ties, "f1.Height=f0.Height,f2.Height=f0.Height,f3.Height=f0.Height," + "f1.Sigma=f0.Sigma,f2.Sigma=f0.Sigma,f3.Sigma=f0.Sigma"); + + // Empty + spectrumCalculator.setProperty("GlobalParameters", ""); + ties = spectrumCalculator.getUserSpecifiedTies(poldi2DFunction); + TS_ASSERT(ties.empty()); + + // Invalid name + spectrumCalculator.setProperty("GlobalParameters", "Invalid"); + ties = spectrumCalculator.getUserSpecifiedTies(poldi2DFunction); + TS_ASSERT(ties.empty()); + + // Valid and invalid + spectrumCalculator.setProperty("GlobalParameters", "Height,Invalid"); + ties = spectrumCalculator.getUserSpecifiedTies(poldi2DFunction); + TS_ASSERT_EQUALS(ties, "f1.Height=f0.Height,f2.Height=f0.Height,f3.Height=f0.Height"); + + // Several empty + spectrumCalculator.setProperty("GlobalParameters", ",,,,"); + ties = spectrumCalculator.getUserSpecifiedTies(poldi2DFunction); + TS_ASSERT(ties.empty()); + } + void testGetPeakCollectionFromFunction() { TestablePoldiFitPeaks2D spectrumCalculator;