Mantid
Loading...
Searching...
No Matches
PawleyFit.cpp
Go to the documentation of this file.
1// Mantid Repository : https://github.com/mantidproject/mantid
2//
3// Copyright © 2018 ISIS Rutherford Appleton Laboratory UKRI,
4// NScD Oak Ridge National Laboratory, European Spallation Source,
5// Institut Laue - Langevin & CSNS, Institute of High Energy Physics, CAS
6// SPDX - License - Identifier: GPL - 3.0 +
8
9#include "MantidAPI/Axis.h"
13#include "MantidAPI/TableRow.h"
16
22
23#include <boost/algorithm/string/classification.hpp>
24#include <boost/algorithm/string/split.hpp>
25#include <boost/algorithm/string/trim.hpp>
26
27#include <algorithm>
28
30
31using namespace API;
32using namespace Kernel;
33using namespace Geometry;
34
35DECLARE_ALGORITHM(PawleyFit)
36
37
38PawleyFit::PawleyFit() : Algorithm(), m_dUnit() {}
39
41const std::string PawleyFit::summary() const {
42 return "This algorithm performs a Pawley-fit on the supplied workspace.";
43}
44
46double PawleyFit::getTransformedCenter(double d, const Unit_sptr &unit) const {
47 if (std::dynamic_pointer_cast<Units::Empty>(unit) || std::dynamic_pointer_cast<Units::dSpacing>(unit)) {
48 return d;
49 }
50
52}
53
76void PawleyFit::addHKLsToFunction(Functions::PawleyFunction_sptr &pawleyFn, const ITableWorkspace_sptr &tableWs,
77 const Unit_sptr &unit, double startX, double endX) const {
78 if (!tableWs || !pawleyFn) {
79 throw std::invalid_argument("Can only process non-null function & table.");
80 }
81
82 pawleyFn->clearPeaks();
83
84 try {
86
87 Column_const_sptr hklColumn = tableWs->getColumn("HKL");
88 Column_const_sptr dColumn = tableWs->getColumn("d");
89 Column_const_sptr intensityColumn = tableWs->getColumn("Intensity");
90 Column_const_sptr fwhmColumn = tableWs->getColumn("FWHM (rel.)");
91
92 for (size_t i = 0; i < tableWs->rowCount(); ++i) {
93 try {
94 V3D hkl = extractor(hklColumn, i);
95
96 double d = (*dColumn)[i];
97 double center = getTransformedCenter(d, unit);
98 double fwhm = (*fwhmColumn)[i] * center;
99 double height = (*intensityColumn)[i];
100
101 if (center > startX && center < endX) {
102 pawleyFn->addPeak(hkl, fwhm, height);
103 }
104 } catch (const std::bad_alloc &) {
105 // do nothing.
106 }
107 }
108 } catch (const std::runtime_error &) {
109 // Column does not exist
110 throw std::runtime_error("Can not process table, the following columns are "
111 "required: HKL, d, Intensity, FWHM (rel.)");
112 }
113}
114
117ITableWorkspace_sptr PawleyFit::getLatticeFromFunction(const Functions::PawleyFunction_sptr &pawleyFn) const {
118 if (!pawleyFn) {
119 throw std::invalid_argument("Cannot extract lattice parameters from null function.");
120 }
121
122 ITableWorkspace_sptr latticeParameterTable = WorkspaceFactory::Instance().createTable();
123
124 latticeParameterTable->addColumn("str", "Parameter");
125 latticeParameterTable->addColumn("double", "Value");
126 latticeParameterTable->addColumn("double", "Error");
127
128 Functions::PawleyParameterFunction_sptr parameters = pawleyFn->getPawleyParameterFunction();
129
130 for (size_t i = 0; i < parameters->nParams(); ++i) {
131 TableRow newRow = latticeParameterTable->appendRow();
132 newRow << parameters->parameterName(i) << parameters->getParameter(i) << parameters->getError(i);
133 }
134
135 return latticeParameterTable;
136}
137
139ITableWorkspace_sptr PawleyFit::getPeakParametersFromFunction(const Functions::PawleyFunction_sptr &pawleyFn) const {
140 if (!pawleyFn) {
141 throw std::invalid_argument("Cannot extract peak parameters from null function.");
142 }
143
144 ITableWorkspace_sptr peakParameterTable = WorkspaceFactory::Instance().createTable();
145
146 peakParameterTable->addColumn("int", "Peak");
147 peakParameterTable->addColumn("V3D", "HKL");
148 peakParameterTable->addColumn("str", "Parameter");
149 peakParameterTable->addColumn("double", "Value");
150 peakParameterTable->addColumn("double", "Error");
151
152 for (size_t i = 0; i < pawleyFn->getPeakCount(); ++i) {
153
154 IPeakFunction_sptr currentPeak = pawleyFn->getPeakFunction(i);
155
156 auto peakNumber = static_cast<int>(i + 1);
157 V3D peakHKL = pawleyFn->getPeakHKL(i);
158
159 for (size_t j = 0; j < currentPeak->nParams(); ++j) {
160 TableRow newRow = peakParameterTable->appendRow();
161 newRow << peakNumber << peakHKL << currentPeak->parameterName(j) << currentPeak->getParameter(j)
162 << currentPeak->getError(j);
163 }
164 }
165
166 return peakParameterTable;
167}
168
171IFunction_sptr PawleyFit::getCompositeFunction(const Functions::PawleyFunction_sptr &pawleyFn) const {
172 CompositeFunction_sptr composite = std::make_shared<CompositeFunction>();
173 composite->addFunction(pawleyFn);
174
175 bool enableChebyshev = getProperty("EnableChebyshevBackground");
176 if (enableChebyshev) {
177 int degree = getProperty("ChebyshevBackgroundDegree");
178 IFunction_sptr chebyshev = FunctionFactory::Instance().createFunction("Chebyshev");
179 chebyshev->setAttributeValue("n", degree);
180
181 composite->addFunction(chebyshev);
182 }
183
184 return composite;
185}
186
188void PawleyFit::init() {
189 declareProperty(std::make_unique<WorkspaceProperty<MatrixWorkspace>>("InputWorkspace", "", Direction::Input),
190 "Input workspace that contains the spectrum on which to "
191 "perform the Pawley fit.");
192
193 declareProperty("WorkspaceIndex", 0, "Spectrum on which the fit should be performed.");
194
195 declareProperty("StartX", 0.0, "Lower border of fitted data range.");
196 declareProperty("EndX", 0.0, "Upper border of fitted data range.");
197
198 std::vector<std::string> latticeSystems{"Cubic", "Tetragonal", "Hexagonal", "Rhombohedral",
199 "Orthorhombic", "Monoclinic", "Triclinic"};
200
201 auto latticeSystemValidator = std::make_shared<StringListValidator>(latticeSystems);
202
203 declareProperty("LatticeSystem", latticeSystems.back(), latticeSystemValidator,
204 "Lattice system to use for refinement.");
205
206 declareProperty("InitialCell", "1.0 1.0 1.0 90.0 90.0 90.0",
207 "Specification of initial unit cell, given as 'a, b, c, "
208 "alpha, beta, gamma'.");
209
210 declareProperty(std::make_unique<WorkspaceProperty<ITableWorkspace>>("PeakTable", "", Direction::Input),
211 "Table with peak information. Can be used instead of "
212 "supplying a list of indices for better starting parameters.");
213
214 declareProperty("RefineZeroShift", false,
215 "If checked, a zero-shift with the "
216 "same unit as the spectrum is "
217 "refined.");
218
219 auto peakFunctionValidator =
220 std::make_shared<StringListValidator>(FunctionFactory::Instance().getFunctionNames<IPeakFunction>());
221
222 declareProperty("PeakProfileFunction", "Gaussian", peakFunctionValidator,
223 "Profile function that is used for each peak.");
224
225 declareProperty("EnableChebyshevBackground", false,
226 "If checked, a Chebyshev "
227 "polynomial will be added "
228 "to model the background.");
229
230 declareProperty("ChebyshevBackgroundDegree", 0, "Degree of the Chebyshev polynomial, if used as background.");
231
232 declareProperty("CalculationOnly", false,
233 "If enabled, no fit is performed, "
234 "the function is only evaluated "
235 "and output is generated.");
236
237 declareProperty(std::make_unique<WorkspaceProperty<MatrixWorkspace>>("OutputWorkspace", "", Direction::Output),
238 "Workspace that contains measured spectrum, calculated "
239 "spectrum and difference curve.");
240
241 declareProperty(std::make_unique<WorkspaceProperty<ITableWorkspace>>("RefinedCellTable", "", Direction::Output),
242 "TableWorkspace with refined lattice parameters, including errors.");
243
245 std::make_unique<WorkspaceProperty<ITableWorkspace>>("RefinedPeakParameterTable", "", Direction::Output),
246 "TableWorkspace with refined peak parameters, including errors.");
247
248 declareProperty("ReducedChiSquare", 0.0,
249 "Outputs the reduced chi square "
250 "value as a measure for the quality "
251 "of the fit.",
253
254 m_dUnit = UnitFactory::Instance().create("dSpacing");
255}
256
258void PawleyFit::exec() {
259 // Setup PawleyFunction with cell from input parameters
260 Functions::PawleyFunction_sptr pawleyFn = std::dynamic_pointer_cast<Functions::PawleyFunction>(
261 FunctionFactory::Instance().createFunction("PawleyFunction"));
262 g_log.information() << "Setting up Pawley function...\n";
263
264 std::string profileFunction = getProperty("PeakProfileFunction");
265 pawleyFn->setProfileFunction(profileFunction);
266 g_log.information() << " Selected profile function: " << profileFunction << '\n';
267
268 std::string latticeSystem = getProperty("LatticeSystem");
269 pawleyFn->setLatticeSystem(latticeSystem);
270 g_log.information() << " Selected crystal system: " << latticeSystem << '\n';
271
272 pawleyFn->setUnitCell(getProperty("InitialCell"));
273 Functions::PawleyParameterFunction_sptr pawleyParameterFunction = pawleyFn->getPawleyParameterFunction();
274 g_log.information() << " Initial unit cell: " << unitCellToStr(pawleyParameterFunction->getUnitCellFromParameters())
275 << '\n';
276
277 // Get the input workspace with the data
278 MatrixWorkspace_const_sptr ws = getProperty("InputWorkspace");
279 int wsIndex = getProperty("WorkspaceIndex");
280
281 // Get x-range start and end values, depending on user input
282 const auto &xData = ws->x(static_cast<size_t>(wsIndex));
283 double startX = xData.front();
284 double endX = xData.back();
285
286 Property *startXProperty = getPointerToProperty("StartX");
287 if (!startXProperty->isDefault()) {
288 double startXInput = getProperty("StartX");
289 startX = std::max(startX, startXInput);
290 }
291
292 Property *endXProperty = getPointerToProperty("EndX");
293 if (!endXProperty->isDefault()) {
294 double endXInput = getProperty("EndX");
295 endX = std::min(endX, endXInput);
296 }
297
298 g_log.information() << " Refined range: " << startX << " - " << endX << '\n';
299
300 // Get HKLs from TableWorkspace
301 ITableWorkspace_sptr peakTable = getProperty("PeakTable");
302 Axis *xAxis = ws->getAxis(0);
303 Unit_sptr xUnit = xAxis->unit();
304 addHKLsToFunction(pawleyFn, peakTable, xUnit, startX, endX);
305
306 g_log.information() << " Peaks in PawleyFunction: " << pawleyFn->getPeakCount() << '\n';
307
308 // Determine if zero-shift should be refined
309 bool refineZeroShift = getProperty("RefineZeroShift");
310 if (!refineZeroShift) {
311 pawleyFn->fix(pawleyFn->parameterIndex("f0.ZeroShift"));
312 } else {
313 g_log.information() << " Refining ZeroShift.\n";
314 }
315
316 pawleyFn->setMatrixWorkspace(ws, static_cast<size_t>(wsIndex), startX, endX);
317
318 g_log.information() << "Setting up Fit...\n";
319
320 // Generate Fit-algorithm with required properties.
321 Algorithm_sptr fit = createChildAlgorithm("Fit", -1, -1, true);
322 fit->setProperty("Function", getCompositeFunction(pawleyFn));
323 fit->setProperty("InputWorkspace", std::const_pointer_cast<MatrixWorkspace>(ws));
324 fit->setProperty("StartX", startX);
325 fit->setProperty("EndX", endX);
326 fit->setProperty("WorkspaceIndex", wsIndex);
327
328 bool calculationOnly = getProperty("CalculationOnly");
329 if (calculationOnly) {
330 fit->setProperty("MaxIterations", 0);
331 }
332
333 fit->setProperty("CreateOutput", true);
334
335 fit->execute();
336 double chiSquare = fit->getProperty("OutputChi2overDoF");
337
338 g_log.information() << "Fit finished, reduced ChiSquare = " << chiSquare << '\n';
339
340 g_log.information() << "Generating output...\n";
341
342 // Create output
343 MatrixWorkspace_sptr output = fit->getProperty("OutputWorkspace");
344 setProperty("OutputWorkspace", output);
345 setProperty("RefinedCellTable", getLatticeFromFunction(pawleyFn));
346 setProperty("RefinedPeakParameterTable", getPeakParametersFromFunction(pawleyFn));
347
348 setProperty("ReducedChiSquare", chiSquare);
349}
350
352V3D V3DFromHKLColumnExtractor::operator()(const Column_const_sptr &hklColumn, size_t i) const {
353 if (hklColumn->type() == "V3D") {
354 return getHKLFromV3DColumn(hklColumn, i);
355 }
356
357 return getHKLFromStringColumn(hklColumn, i);
358}
359
361V3D V3DFromHKLColumnExtractor::getHKLFromV3DColumn(const Column_const_sptr &hklColumn, size_t i) const {
362 return hklColumn->cell<V3D>(i);
363}
364
366V3D V3DFromHKLColumnExtractor::getHKLFromStringColumn(const Column_const_sptr &hklColumn, size_t i) const {
367
368 return getHKLFromString(hklColumn->cell<std::string>(i));
369}
370
372V3D V3DFromHKLColumnExtractor::getHKLFromString(const std::string &hklString) const {
373 auto delimiters = boost::is_any_of(" ,[];");
374
375 std::string workingCopy = boost::trim_copy_if(hklString, delimiters);
376 std::vector<std::string> indicesStr;
377 boost::split(indicesStr, workingCopy, delimiters);
378
379 if (indicesStr.size() != 3) {
380 throw std::invalid_argument("Input string cannot be parsed as HKL.");
381 }
382
383 V3D hkl;
384 hkl.setX(boost::lexical_cast<double>(indicesStr[0]));
385 hkl.setY(boost::lexical_cast<double>(indicesStr[1]));
386 hkl.setZ(boost::lexical_cast<double>(indicesStr[2]));
387
388 return hkl;
389}
390
391} // namespace Mantid::CurveFitting::Algorithms
#define DECLARE_ALGORITHM(classname)
Definition: Algorithm.h:576
double height
Definition: GetAllEi.cpp:155
Base class from which all concrete algorithm classes should be derived.
Definition: Algorithm.h:85
void declareProperty(std::unique_ptr< Kernel::Property > p, const std::string &doc="") override
Add a property to the list of managed properties.
Definition: Algorithm.cpp:1913
Kernel::Property * getPointerToProperty(const std::string &name) const override
Get a property by name.
Definition: Algorithm.cpp:2033
TypedValue getProperty(const std::string &name) const override
Get the value of a property.
Definition: Algorithm.cpp:2076
virtual std::shared_ptr< Algorithm > createChildAlgorithm(const std::string &name, const double startProgress=-1., const double endProgress=-1., const bool enableLogging=true, const int &version=-1)
Create a Child Algorithm.
Definition: Algorithm.cpp:842
Kernel::Logger & g_log
Definition: Algorithm.h:451
Class to represent the axis of a workspace.
Definition: Axis.h:30
const std::shared_ptr< Kernel::Unit > & unit() const
The unit for this axis.
Definition: Axis.cpp:28
TableRow represents a row in a TableWorkspace.
Definition: TableRow.h:39
A property class for workspaces.
This algorithm uses the Pawley-method to refine lattice parameters using a powder diffractogram and a...
Definition: PawleyFit.h:49
API::ITableWorkspace_sptr getLatticeFromFunction(const Functions::PawleyFunction_sptr &pawleyFn) const
Creates a table containing the cell parameters stored in the supplied function.
Definition: PawleyFit.cpp:117
API::IFunction_sptr getCompositeFunction(const Functions::PawleyFunction_sptr &pawleyFn) const
Returns a composite function consisting of the Pawley function and Chebyshev background if enabled in...
Definition: PawleyFit.cpp:171
void addHKLsToFunction(Functions::PawleyFunction_sptr &pawleyFn, const API::ITableWorkspace_sptr &tableWs, const Kernel::Unit_sptr &unit, double startX, double endX) const
Add HKLs from a TableWorkspace to the PawleyFunction.
Definition: PawleyFit.cpp:76
double getTransformedCenter(double d, const Kernel::Unit_sptr &unit) const
Transforms the specified value from d-spacing to the supplied unit.
Definition: PawleyFit.cpp:46
API::ITableWorkspace_sptr getPeakParametersFromFunction(const Functions::PawleyFunction_sptr &pawleyFn) const
Extracts all profile parameters from the supplied function.
Definition: PawleyFit.cpp:139
IPropertyManager * setProperty(const std::string &name, const T &value)
Templated method to set the value of a PropertyWithValue.
void information(const std::string &msg)
Logs at information level.
Definition: Logger.cpp:105
Base class for properties.
Definition: Property.h:94
virtual bool isDefault() const =0
Overriden function that returns if property has the same value that it was initialised with,...
static T & Instance()
Return a reference to the Singleton instance, creating it if it does not already exist Creation is do...
static double run(const std::string &src, const std::string &dest, const double srcValue, const double l1, const double l2, const double theta, const DeltaEMode::Type emode, const double efixed)
Convert a single value between the given units (as strings)
Class for 3D vectors.
Definition: V3D.h:34
void setZ(const double zz) noexcept
Set is z position.
Definition: V3D.h:230
void setX(const double xx) noexcept
Set is x position.
Definition: V3D.h:218
void setY(const double yy) noexcept
Set is y position.
Definition: V3D.h:224
std::shared_ptr< IPeakFunction > IPeakFunction_sptr
std::shared_ptr< ITableWorkspace > ITableWorkspace_sptr
shared pointer to Mantid::API::ITableWorkspace
std::shared_ptr< const MatrixWorkspace > MatrixWorkspace_const_sptr
shared pointer to the matrix workspace base class (const version)
std::shared_ptr< IFunction > IFunction_sptr
shared pointer to the function base class
Definition: IFunction.h:732
std::shared_ptr< const Column > Column_const_sptr
Definition: Column.h:229
std::shared_ptr< Algorithm > Algorithm_sptr
Typedef for a shared pointer to an Algorithm.
Definition: Algorithm.h:61
std::shared_ptr< MatrixWorkspace > MatrixWorkspace_sptr
shared pointer to the matrix workspace base class
std::shared_ptr< CompositeFunction > CompositeFunction_sptr
shared pointer to the composite function base class
std::shared_ptr< PawleyFunction > PawleyFunction_sptr
std::shared_ptr< PawleyParameterFunction > PawleyParameterFunction_sptr
MANTID_GEOMETRY_DLL std::string unitCellToStr(const UnitCell &unitCell)
Definition: UnitCell.cpp:886
std::shared_ptr< Unit > Unit_sptr
Shared pointer to the Unit base class.
Definition: Unit.h:229
Small helper class to extract HKLs as V3D from table columns.
Definition: PawleyFit.h:27
Kernel::V3D getHKLFromV3DColumn(const API::Column_const_sptr &hklColumn, size_t i) const
Returns the i-th cell of a V3D column.
Definition: PawleyFit.cpp:361
Kernel::V3D getHKLFromString(const std::string &hklString) const
Try to extract a V3D from the given string with different separators.
Definition: PawleyFit.cpp:372
Kernel::V3D getHKLFromStringColumn(const API::Column_const_sptr &hklColumn, size_t i) const
Pass the cell value as string to getHKLFromString.
Definition: PawleyFit.cpp:366
@ Input
An input workspace.
Definition: Property.h:53
@ Output
An output workspace.
Definition: Property.h:54