72 auto mustBePositive = std::make_shared<BoundedValidator<double>>();
74 "Input spectrum density or paired-distribution function");
76 "Result paired-distribution function or Input spectrum density");
78 std::vector<std::string> directionOptions;
79 directionOptions.emplace_back(FORWARD);
80 directionOptions.emplace_back(BACKWARD);
81 declareProperty(
"Direction", FORWARD, std::make_shared<StringListValidator>(directionOptions),
82 "The direction of the fourier transform");
84 "Average number density used for g(r) and RDF(r) conversions (optional)");
85 declareProperty(
"Filter",
false,
"Set to apply Lorch function filter to the input");
88 std::vector<std::string> soqTypes;
89 soqTypes.emplace_back(S_OF_Q);
90 soqTypes.emplace_back(S_OF_Q_MINUS_ONE);
91 soqTypes.emplace_back(Q_S_OF_Q_MINUS_ONE);
92 declareProperty(
"InputSofQType", S_OF_Q, std::make_shared<StringListValidator>(soqTypes),
93 "To identify spectral density function (deprecated)");
95 declareProperty(
"SofQType", S_OF_Q, std::make_shared<StringListValidator>(soqTypes),
96 "To identify spectral density function");
97 mustBePositive->setLower(0.0);
100 "Step size of Q of S(Q) to calculate. Default = "
101 ":math:`\\frac{\\pi}{R_{max}}`.");
104 "Minimum Q in S(Q) to calculate in Fourier transform (optional).");
107 "Maximum Q in S(Q) to calculate in Fourier transform. "
108 "(optional, defaults to 40 on backward transform.)");
111 std::vector<std::string> pdfTypes;
112 pdfTypes.emplace_back(BIG_G_OF_R);
113 pdfTypes.emplace_back(LITTLE_G_OF_R);
114 pdfTypes.emplace_back(RDF_OF_R);
115 pdfTypes.emplace_back(G_K_OF_R);
116 declareProperty(
"PDFType", BIG_G_OF_R, std::make_shared<StringListValidator>(pdfTypes),
117 "Type of output PDF including G(r)");
120 "Step size of r of G(r) to calculate. Default = "
121 ":math:`\\frac{\\pi}{Q_{max}}`.");
126 "Maximum r for G(r) to calculate. (optional, defaults to 20 "
127 "on forward transform.)");
129 string recipGroup(
"Reciprocal Space");
135 string realGroup(
"Real Space");
238 std::vector<double> &DFOfQ,
const std::vector<double> &DQ) {
241 string inputSOQType =
getProperty(
"InputSofQType");
243 soqType = inputSOQType;
244 g_log.
warning() <<
"InputSofQType has been deprecated and replaced by SofQType\n";
246 if (soqType == S_OF_Q) {
249 std::for_each(FOfQ.begin(), FOfQ.end(), [](
double &F) { F--; });
250 soqType = S_OF_Q_MINUS_ONE;
252 if (soqType == Q_S_OF_Q_MINUS_ONE) {
255 for (
size_t i = 0; i < DFOfQ.size(); ++i) {
256 DFOfQ[i] = (Q[i] / DQ[i] + FOfQ[i] / DFOfQ[i]) * (FOfQ[i] / Q[i]);
259 std::transform(FOfQ.begin(), FOfQ.end(), FOfQ.begin(), Q.begin(), std::divides<double>());
260 soqType = S_OF_Q_MINUS_ONE;
262 if (soqType != S_OF_Q_MINUS_ONE) {
264 std::stringstream msg;
265 msg <<
"Do not understand SofQType = " << soqType;
266 throw std::runtime_error(msg.str());
272 std::vector<double> &DFOfR,
const std::vector<double> &DR,
273 const std::string &PDFType,
const double &rho0,
274 const double &cohScatLen) {
275 if (PDFType == LITTLE_G_OF_R) {
276 for (
size_t i = 0; i < FOfR.size(); ++i) {
278 FOfR[i] = FOfR[i] - 1.0;
280 }
else if (PDFType == BIG_G_OF_R) {
281 const double factor = 4. * M_PI * rho0;
282 for (
size_t i = 0; i < FOfR.size(); ++i) {
284 DFOfR[i] = (R[i] / DR[i] + FOfR[i] / DFOfR[i]) * (FOfR[i] / R[i]);
286 FOfR[i] = FOfR[i] / (factor * R[i]);
288 }
else if (PDFType == RDF_OF_R) {
289 const double factor = 4. * M_PI * rho0;
290 for (
size_t i = 0; i < FOfR.size(); ++i) {
292 DFOfR[i] = (2.0 * R[i] / DR[i] + FOfR[i] / DFOfR[i]) * (FOfR[i] / R[i]);
294 FOfR[i] = FOfR[i] / (factor * R[i] * R[i]) - 1.0;
296 }
else if (PDFType == G_K_OF_R) {
297 const double factor = 0.01 * pow(cohScatLen, 2);
299 for (
size_t i = 0; i < FOfR.size(); ++i) {
301 DFOfR[i] = DFOfR[i] / factor;
303 FOfR[i] = FOfR[i] / factor;
333 const HistogramData::HistogramX &R,
334 HistogramData::HistogramE &DFOfR,
const std::string &PDFType,
335 const double &rho0,
const double &cohScatLen) {
337 if (PDFType == LITTLE_G_OF_R) {
338 for (
size_t i = 0; i < FOfR.size(); ++i) {
340 FOfR[i] = FOfR[i] + 1.0;
342 }
else if (PDFType == BIG_G_OF_R) {
343 const double factor = 4. * M_PI * rho0;
344 for (
size_t i = 0; i < FOfR.size(); ++i) {
346 DFOfR[i] = DFOfR[i] * R[i];
348 FOfR[i] = FOfR[i] * factor * R[i];
350 }
else if (PDFType == RDF_OF_R) {
351 const double factor = 4. * M_PI * rho0;
352 for (
size_t i = 0; i < FOfR.size(); ++i) {
354 DFOfR[i] = DFOfR[i] * R[i];
356 FOfR[i] = (FOfR[i] + 1.0) * factor * R[i] * R[i];
358 }
else if (PDFType == G_K_OF_R) {
359 const double factor = 0.01 * pow(cohScatLen, 2);
361 for (
size_t i = 0; i < FOfR.size(); ++i) {
363 DFOfR[i] = DFOfR[i] * factor;
365 FOfR[i] = FOfR[i] * factor;
376 auto inputX = inputWS->x(0).rawData();
377 std::vector<double> inputDX(inputX.size(), 0.0);
378 if (inputWS->sharedDx(0))
379 inputDX = inputWS->dx(0).rawData();
380 auto inputY = inputWS->y(0).rawData();
381 auto inputDY = inputWS->e(0).rawData();
384 if (inputX.size() == inputY.size()) {
385 inputX = BinEdges(Points(inputWS->x(0))).rawData();
390 const std::string inputXunit = inputWS->getAxis(0)->unit()->unitID();
391 if (inputXunit ==
"MomentumTransfer") {
393 }
else if (inputXunit ==
"dSpacing") {
395 const double PI_2(2. * M_PI);
396 std::for_each(inputX.begin(), inputX.end(), [&PI_2](
double &Q) { Q /= PI_2; });
397 std::transform(inputDX.begin(), inputDX.end(), inputX.begin(), inputDX.begin(), std::divides<double>());
399 std::reverse(inputX.begin(), inputX.end());
400 std::reverse(inputDX.begin(), inputDX.end());
401 std::reverse(inputY.begin(), inputY.end());
402 std::reverse(inputDY.begin(), inputDY.end());
403 }
else if (inputXunit ==
"AtomicDistance") {
406 g_log.
debug() <<
"Input unit is " << inputXunit <<
"\n";
409 if (!inputWS->isHistogramData()) {
410 g_log.
warning() <<
"This algorithm has not been tested on density data "
411 "(only on histograms)\n";
427 const std::string PDFType =
getProperty(
"PDFType");
433 if (PDFType ==
"G_k(r)" && cohScatLen == 0.0) {
434 std::stringstream msg;
435 msg <<
"Coherent Scattering Length is zero. Please check a sample material has been specified";
436 throw std::runtime_error(msg.str());
440 if (direction == FORWARD) {
442 }
else if (direction == BACKWARD) {
446 double inMin, inMax, outDelta, outMax;
454 if (direction == BACKWARD) {
467 g_log.
notice() <<
"Adjusting to data: input min = " << inputX[Xmin_index] <<
" input max = " << inputX[Xmax_index]
471 outDelta = M_PI / inputX[Xmax_index];
472 auto sizer =
static_cast<size_t>(outMax / outDelta);
479 outputWS->copyExperimentInfoFrom(inputWS.get());
480 if (direction == FORWARD) {
481 outputWS->getAxis(0)->unit() = UnitFactory::Instance().create(
"AtomicDistance");
482 outputWS->setYUnitLabel(
"PDF");
483 outputWS->mutableRun().addProperty(
"Qmin", inputX[Xmin_index],
"Angstroms^-1",
true);
484 outputWS->mutableRun().addProperty(
"Qmax", inputX[Xmax_index],
"Angstroms^-1",
true);
485 }
else if (direction == BACKWARD) {
486 outputWS->getAxis(0)->unit() = UnitFactory::Instance().create(
"MomentumTransfer");
487 outputWS->setYUnitLabel(
"Spectrum Density");
488 outputWS->mutableRun().addProperty(
"Rmin", inputX[Xmin_index],
"Angstroms",
true);
489 outputWS->mutableRun().addProperty(
"Rmax", inputX[Xmax_index],
"Angstroms",
true);
491 outputWS->setDistribution(
true);
492 BinEdges edges(sizer + 1, LinearGenerator(outDelta / 2, outDelta));
493 outputWS->setBinEdges(0, edges);
494 auto &outputX = outputWS->mutableX(0);
495 g_log.
information() <<
"Using output min = " << outputX.front() <<
"and output max = " << outputX.back() <<
"\n";
497 auto &outputY = outputWS->mutableY(0);
498 auto &outputE = outputWS->mutableE(0);
504 double corr = 0.5 / M_PI / M_PI / rho0;
505 if (direction == BACKWARD) {
506 corr = 4.0 * M_PI * rho0;
508 const double inXMax = inputX[Xmax_index];
509 for (
size_t outXIndex = 0; outXIndex < sizer; outXIndex++) {
510 const double outX = 0.5 * (outputX[outXIndex] + outputX[outXIndex + 1]);
511 const double outXFac = corr / (outX * outX * outX);
514 double errorSquared = 0;
515 auto pdfIntegral = [outX](
const double x) ->
double {
return sin(
x * outX) -
x * outX * cos(
x * outX); };
516 double inX2 = inputX[Xmin_index];
517 double integralX2 = pdfIntegral(inX2);
519 for (
size_t inXIndex = Xmin_index; inXIndex < Xmax_index; inXIndex++) {
520 const double inX1 = inX2;
521 inX2 = inputX[inXIndex + 1];
522 const double integralX1 = integralX2;
523 integralX2 = pdfIntegral(inX2);
524 double defIntegral = integralX2 - integralX1;
527 auto inXCen = 0.5 * (inX1 + inX2);
528 if (filter &&
fabs(inXCen) > 1e-8) {
529 const double lorchKernel = inXCen * M_PI / inXMax;
530 defIntegral *= sin(lorchKernel) / lorchKernel;
532 fs += defIntegral * inputY[inXIndex];
534 const double error = defIntegral * inputDY[inXIndex];
539 outputY[outXIndex] = fs * outXFac;
540 outputE[outXIndex] = sqrt(errorSquared) * outXFac;
543 if (direction == FORWARD) {
545 }
else if (direction == BACKWARD) {