14#include "MantidHistogramData/Histogram.h"
15#include "MantidHistogramData/LinearGenerator.h"
29using namespace HistogramData;
36using namespace DataObjects;
40const string BIG_G_OF_R(
"G(r)");
42const string LITTLE_G_OF_R(
"g(r)");
44const string RDF_OF_R(
"RDF(r)");
47const string S_OF_Q(
"S(Q)");
49const string S_OF_Q_MINUS_ONE(
"S(Q)-1");
51const string Q_S_OF_Q_MINUS_ONE(
"Q[S(Q)-1]");
53constexpr double TWO_OVER_PI(2. / M_PI);
65 auto uv = std::make_shared<API::WorkspaceUnitValidator>(
"MomentumTransfer");
68 S_OF_Q +
", " + S_OF_Q_MINUS_ONE +
", or " + Q_S_OF_Q_MINUS_ONE);
70 "Result paired-distribution function");
73 std::vector<std::string> inputTypes;
74 inputTypes.emplace_back(S_OF_Q);
75 inputTypes.emplace_back(S_OF_Q_MINUS_ONE);
76 inputTypes.emplace_back(Q_S_OF_Q_MINUS_ONE);
77 declareProperty(
"InputSofQType", S_OF_Q, std::make_shared<StringListValidator>(inputTypes),
78 "To identify whether input function");
80 auto mustBePositive = std::make_shared<BoundedValidator<double>>();
81 mustBePositive->setLower(0.0);
84 "Minimum Q in S(Q) to calculate in Fourier transform (optional).");
86 "Maximum Q in S(Q) to calculate in Fourier transform. (optional)");
87 declareProperty(
"Filter",
false,
"Set to apply Lorch function filter to the input");
90 std::vector<std::string> outputTypes;
91 outputTypes.emplace_back(BIG_G_OF_R);
92 outputTypes.emplace_back(LITTLE_G_OF_R);
93 outputTypes.emplace_back(RDF_OF_R);
94 declareProperty(
"PDFType", BIG_G_OF_R, std::make_shared<StringListValidator>(outputTypes),
95 "Type of output PDF including G(r)");
98 "Step size of r of G(r) to calculate. Default = "
99 ":math:`\\frac{\\pi}{Q_{max}}`.");
100 declareProperty(
"Rmax", 20., mustBePositive,
"Maximum r for G(r) to calculate.");
102 "Average number density used for g(r) and RDF(r) conversions (optional)");
104 string recipGroup(
"Reciprocal Space");
110 string realGroup(
"Real Space");
118 std::map<string, string> result;
124 result[
"Qmax"] =
"Must be greater than Qmin";
132 if (inputWS->getNumberHistograms() != 1) {
133 result[
"InputWorkspace"] =
"Input workspace must have only one spectrum";
145 }
else if (qmin < Q.front()) {
146 g_log.
information(
"Specified Qmin < range of data. Adjusting to data range.");
151 auto q_iter = std::upper_bound(Q.begin(), Q.end(), qmin);
152 size_t qmin_index = std::distance(Q.begin(), q_iter);
157 q_iter = std::find_if(std::next(FofQ.begin(), qmin_index), FofQ.end(),
static_cast<bool (*)(
double)
>(std::isnormal));
158 size_t first_normal_index = std::distance(FofQ.begin(), q_iter);
159 if (first_normal_index > qmin_index) {
160 g_log.
information(
"Specified Qmin where data is nan/inf. Adjusting to data range.");
161 qmin_index = first_normal_index;
173 }
else if (qmax > Q.back()) {
174 g_log.
information() <<
"Specified Qmax > range of data. Adjusting to data range.\n";
179 auto q_iter = std::lower_bound(Q.begin(), Q.end(), qmax);
180 size_t qmax_index = std::distance(Q.begin(), q_iter);
183 auto q_back_iter = std::find_if(FofQ.rbegin(), FofQ.rend(),
static_cast<bool (*)(
double)
>(std::isnormal));
184 size_t first_normal_index = FofQ.size() - std::distance(FofQ.rbegin(), q_back_iter) - 1;
185 if (first_normal_index < qmax_index) {
186 g_log.
information(
"Specified Qmax where data is nan/inf. Adjusting to data range.");
187 qmax_index = first_normal_index;
202 if (!
isEmpty(materialDensity) && materialDensity > 0)
203 rho0 = materialDensity;
217 auto inputQ = inputWS->x(0).rawData();
218 HistogramData::HistogramDx inputDQ(inputQ.size(), 0.0);
219 if (inputWS->sharedDx(0))
220 inputDQ = inputWS->dx(0);
221 auto inputFOfQ = inputWS->y(0).rawData();
222 auto inputDfOfQ = inputWS->e(0).rawData();
225 const std::string inputXunit = inputWS->getAxis(0)->unit()->unitID();
226 if (inputXunit ==
"MomentumTransfer") {
228 }
else if (inputXunit ==
"dSpacing") {
230 const double PI_2(2. * M_PI);
231 std::for_each(inputQ.begin(), inputQ.end(), [&PI_2](
double &Q) { Q /= PI_2; });
232 std::transform(inputDQ.begin(), inputDQ.end(), inputQ.begin(), inputDQ.begin(), std::divides<double>());
234 std::reverse(inputQ.begin(), inputQ.end());
235 std::reverse(inputDQ.begin(), inputDQ.end());
236 std::reverse(inputFOfQ.begin(), inputFOfQ.end());
237 std::reverse(inputDfOfQ.begin(), inputDfOfQ.end());
239 std::stringstream msg;
240 msg <<
"Input data x-axis with unit \"" << inputXunit
241 << R
"(" is not supported (use "MomentumTransfer" or "dSpacing"))";
242 throw std::invalid_argument(msg.str());
244 g_log.
debug() <<
"Input unit is " << inputXunit <<
"\n";
247 if (!inputWS->isHistogramData()) {
248 g_log.
warning() <<
"This algorithm has not been tested on density data "
249 "(only on histograms)\n";
267 if (soqType == S_OF_Q) {
270 std::for_each(inputFOfQ.begin(), inputFOfQ.end(), [](
double &F) { F--; });
271 soqType = S_OF_Q_MINUS_ONE;
273 if (soqType == S_OF_Q_MINUS_ONE) {
276 for (
size_t i = 0; i < inputDfOfQ.size(); ++i) {
277 inputDfOfQ[i] = inputQ[i] * inputDfOfQ[i] + inputFOfQ[i] * inputDQ[i];
280 std::transform(inputFOfQ.begin(), inputFOfQ.end(), inputQ.begin(), inputFOfQ.begin(), std::multiplies<double>());
281 soqType = Q_S_OF_Q_MINUS_ONE;
283 if (soqType != Q_S_OF_Q_MINUS_ONE) {
285 std::stringstream msg;
286 msg <<
"Do not understand InputSofQType = " << soqType;
287 throw std::runtime_error(msg.str());
293 g_log.
notice() <<
"Adjusting to data: Qmin = " << inputQ[qmin_index] <<
" Qmax = " << inputQ[qmax_index] <<
"\n";
299 rdelta = M_PI / inputQ[qmax_index];
300 auto sizer =
static_cast<size_t>(rmax / rdelta);
307 outputWS->setYUnitLabel(
"PDF");
309 outputWS->mutableRun().addProperty(
"Qmin", inputQ[qmin_index],
"Angstroms^-1",
true);
310 outputWS->mutableRun().addProperty(
"Qmax", inputQ[qmax_index],
"Angstroms^-1",
true);
312 BinEdges edges(sizer + 1, LinearGenerator(rdelta, rdelta));
313 outputWS->setBinEdges(0, edges);
315 auto &outputR = outputWS->mutableX(0);
316 g_log.
information() <<
"Using rmin = " << outputR.front() <<
"Angstroms and rmax = " << outputR.back()
319 auto &outputY = outputWS->mutableY(0);
320 auto &outputE = outputWS->mutableE(0);
323 for (
size_t r_index = 0; r_index < sizer; r_index++) {
324 const double r = outputR[r_index];
327 for (
size_t q_index = qmin_index; q_index < qmax_index; q_index++) {
328 const double q = inputQ[q_index];
329 const double deltaq = inputQ[q_index] - inputQ[q_index - 1];
330 double sinus = sin(q * r) * deltaq;
333 if (filter && q != 0) {
334 const double lorchKernel = q * M_PI / inputQ[qmax_index];
335 sinus *= sin(lorchKernel) / lorchKernel;
337 fs += sinus * inputFOfQ[q_index];
338 error += (sinus * inputDfOfQ[q_index]) * (sinus * inputDfOfQ[q_index]);
345 outputY[r_index] = fs * TWO_OVER_PI;
346 outputE[r_index] = sqrt(
error) * TWO_OVER_PI;
353 if (pdfType == LITTLE_G_OF_R || pdfType == RDF_OF_R)
356 if (pdfType == BIG_G_OF_R) {
358 }
else if (pdfType == LITTLE_G_OF_R) {
359 const double factor = 1. / (4. * M_PI * rho0);
360 for (
size_t i = 0; i < outputY.size(); ++i) {
362 outputE[i] = outputE[i] / outputR[i];
364 outputY[i] = 1. + factor * outputY[i] / outputR[i];
366 }
else if (pdfType == RDF_OF_R) {
367 const double factor = 4. * M_PI * rho0;
368 for (
size_t i = 0; i < outputY.size(); ++i) {
370 outputE[i] = outputE[i] * outputR[i];
372 outputY[i] = outputR[i] * outputY[i] + factor * outputR[i] * outputR[i];
376 std::stringstream msg;
377 msg <<
"Do not understand PDFType = " << pdfType;
378 throw std::runtime_error(msg.str());
#define DECLARE_ALGORITHM(classname)
void declareProperty(std::unique_ptr< Kernel::Property > p, const std::string &doc="") override
Add a property to the list of managed properties.
TypedValue getProperty(const std::string &name) const override
Get the value of a property.
static bool isEmpty(const NumT toCheck)
checks that the value was not set by users, uses the value in empty double/int.
A property class for workspaces.
IPropertyManager * setProperty(const std::string &name, const T &value)
Templated method to set the value of a PropertyWithValue.
void setPropertyGroup(const std::string &name, const std::string &group)
Set the group for a given property.
void debug(const std::string &msg)
Logs at debug level.
void notice(const std::string &msg)
Logs at notice level.
void warning(const std::string &msg)
Logs at warning level.
void information(const std::string &msg)
Logs at information level.
A material is defined as being composed of a given element, defined as a PhysicalConstants::NeutronAt...
double numberDensity() const
Get the number density.
static T & Instance()
Return a reference to the Singleton instance, creating it if it does not already exist Creation is do...
std::shared_ptr< const MatrixWorkspace > MatrixWorkspace_const_sptr
shared pointer to the matrix workspace base class (const version)
std::shared_ptr< MatrixWorkspace > MatrixWorkspace_sptr
shared pointer to the matrix workspace base class
constexpr double EMPTY_DBL() noexcept
Returns what we consider an "empty" double within a property.
@ Input
An input workspace.
@ Output
An output workspace.