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).");
106 "Maximum Q in S(Q) to calculate in Fourier transform. "
107 "(optional, defaults to 40 on backward transform.)");
110 std::vector<std::string> pdfTypes;
111 pdfTypes.emplace_back(BIG_G_OF_R);
112 pdfTypes.emplace_back(LITTLE_G_OF_R);
113 pdfTypes.emplace_back(RDF_OF_R);
114 pdfTypes.emplace_back(G_K_OF_R);
115 declareProperty(
"PDFType", BIG_G_OF_R, std::make_shared<StringListValidator>(pdfTypes),
116 "Type of output PDF including G(r)");
119 "Step size of r of G(r) to calculate. Default = "
120 ":math:`\\frac{\\pi}{Q_{max}}`.");
124 "Maximum r for G(r) to calculate. (optional, defaults to 20 "
125 "on forward transform.)");
127 string recipGroup(
"Reciprocal Space");
133 string realGroup(
"Real Space");
236 std::vector<double> &DFOfQ,
const std::vector<double> &DQ) {
239 string inputSOQType =
getProperty(
"InputSofQType");
241 soqType = inputSOQType;
242 g_log.
warning() <<
"InputSofQType has been deprecated and replaced by SofQType\n";
244 if (soqType == S_OF_Q) {
247 std::for_each(FOfQ.begin(), FOfQ.end(), [](
double &F) { F--; });
248 soqType = S_OF_Q_MINUS_ONE;
250 if (soqType == Q_S_OF_Q_MINUS_ONE) {
253 for (
size_t i = 0; i < DFOfQ.size(); ++i) {
254 DFOfQ[i] = (Q[i] / DQ[i] + FOfQ[i] / DFOfQ[i]) * (FOfQ[i] / Q[i]);
257 std::transform(FOfQ.begin(), FOfQ.end(), FOfQ.begin(), Q.begin(), std::divides<double>());
258 soqType = S_OF_Q_MINUS_ONE;
260 if (soqType != S_OF_Q_MINUS_ONE) {
262 std::stringstream msg;
263 msg <<
"Do not understand SofQType = " << soqType;
264 throw std::runtime_error(msg.str());
270 std::vector<double> &DFOfR,
const std::vector<double> &DR,
271 const std::string &PDFType,
const double &rho0,
272 const double &cohScatLen) {
273 if (PDFType == LITTLE_G_OF_R) {
274 for (
size_t i = 0; i < FOfR.size(); ++i) {
276 FOfR[i] = FOfR[i] - 1.0;
278 }
else if (PDFType == BIG_G_OF_R) {
279 const double factor = 4. * M_PI * rho0;
280 for (
size_t i = 0; i < FOfR.size(); ++i) {
282 DFOfR[i] = (R[i] / DR[i] + FOfR[i] / DFOfR[i]) * (FOfR[i] / R[i]);
284 FOfR[i] = FOfR[i] / (factor * R[i]);
286 }
else if (PDFType == RDF_OF_R) {
287 const double factor = 4. * M_PI * rho0;
288 for (
size_t i = 0; i < FOfR.size(); ++i) {
290 DFOfR[i] = (2.0 * R[i] / DR[i] + FOfR[i] / DFOfR[i]) * (FOfR[i] / R[i]);
292 FOfR[i] = FOfR[i] / (factor * R[i] * R[i]) - 1.0;
294 }
else if (PDFType == G_K_OF_R) {
295 const double factor = 0.01 * pow(cohScatLen, 2);
297 for (
size_t i = 0; i < FOfR.size(); ++i) {
299 DFOfR[i] = DFOfR[i] / factor;
301 FOfR[i] = FOfR[i] / factor;
331 const HistogramData::HistogramX &R,
332 HistogramData::HistogramE &DFOfR,
const std::string &PDFType,
333 const double &rho0,
const double &cohScatLen) {
335 if (PDFType == LITTLE_G_OF_R) {
336 for (
size_t i = 0; i < FOfR.size(); ++i) {
338 FOfR[i] = FOfR[i] + 1.0;
340 }
else if (PDFType == BIG_G_OF_R) {
341 const double factor = 4. * M_PI * rho0;
342 for (
size_t i = 0; i < FOfR.size(); ++i) {
344 DFOfR[i] = DFOfR[i] * R[i];
346 FOfR[i] = FOfR[i] * factor * R[i];
348 }
else if (PDFType == RDF_OF_R) {
349 const double factor = 4. * M_PI * rho0;
350 for (
size_t i = 0; i < FOfR.size(); ++i) {
352 DFOfR[i] = DFOfR[i] * R[i];
354 FOfR[i] = (FOfR[i] + 1.0) * factor * R[i] * R[i];
356 }
else if (PDFType == G_K_OF_R) {
357 const double factor = 0.01 * pow(cohScatLen, 2);
359 for (
size_t i = 0; i < FOfR.size(); ++i) {
361 DFOfR[i] = DFOfR[i] * factor;
363 FOfR[i] = FOfR[i] * factor;
374 auto inputX = inputWS->x(0).rawData();
375 std::vector<double> inputDX(inputX.size(), 0.0);
376 if (inputWS->sharedDx(0))
377 inputDX = inputWS->dx(0).rawData();
378 auto inputY = inputWS->y(0).rawData();
379 auto inputDY = inputWS->e(0).rawData();
382 if (inputX.size() == inputY.size()) {
383 inputX = BinEdges(Points(inputWS->x(0))).rawData();
388 const std::string inputXunit = inputWS->getAxis(0)->unit()->unitID();
389 if (inputXunit ==
"MomentumTransfer") {
391 }
else if (inputXunit ==
"dSpacing") {
393 const double PI_2(2. * M_PI);
394 std::for_each(inputX.begin(), inputX.end(), [&PI_2](
double &Q) { Q /= PI_2; });
395 std::transform(inputDX.begin(), inputDX.end(), inputX.begin(), inputDX.begin(), std::divides<double>());
397 std::reverse(inputX.begin(), inputX.end());
398 std::reverse(inputDX.begin(), inputDX.end());
399 std::reverse(inputY.begin(), inputY.end());
400 std::reverse(inputDY.begin(), inputDY.end());
401 }
else if (inputXunit ==
"AtomicDistance") {
404 g_log.
debug() <<
"Input unit is " << inputXunit <<
"\n";
407 if (!inputWS->isHistogramData()) {
408 g_log.
warning() <<
"This algorithm has not been tested on density data "
409 "(only on histograms)\n";
425 const std::string PDFType =
getProperty(
"PDFType");
431 if (PDFType ==
"G_k(r)" && cohScatLen == 0.0) {
432 std::stringstream msg;
433 msg <<
"Coherent Scattering Length is zero. Please check a sample material has been specified";
434 throw std::runtime_error(msg.str());
438 if (direction == FORWARD) {
440 }
else if (direction == BACKWARD) {
444 double inMin, inMax, outDelta, outMin, outMax;
453 if (direction == BACKWARD) {
470 g_log.
notice() <<
"Adjusting to data: input min = " << inputX[Xmin_index] <<
" input max = " << inputX[Xmax_index]
474 outDelta = M_PI / inputX[Xmax_index];
475 auto sizer =
static_cast<size_t>((outMax - outMin) / outDelta);
482 outputWS->copyExperimentInfoFrom(inputWS.get());
483 if (direction == FORWARD) {
484 outputWS->getAxis(0)->unit() = UnitFactory::Instance().create(
"AtomicDistance");
485 outputWS->setYUnitLabel(
"PDF");
486 outputWS->mutableRun().addProperty(
"Qmin", inputX[Xmin_index],
"Angstroms^-1",
true);
487 outputWS->mutableRun().addProperty(
"Qmax", inputX[Xmax_index],
"Angstroms^-1",
true);
488 }
else if (direction == BACKWARD) {
489 outputWS->getAxis(0)->unit() = UnitFactory::Instance().create(
"MomentumTransfer");
490 outputWS->setYUnitLabel(
"Spectrum Density");
491 outputWS->mutableRun().addProperty(
"Rmin", inputX[Xmin_index],
"Angstroms",
true);
492 outputWS->mutableRun().addProperty(
"Rmax", inputX[Xmax_index],
"Angstroms",
true);
494 outputWS->setDistribution(
true);
495 BinEdges edges(sizer + 1, LinearGenerator(outMin + outDelta / 2, outDelta));
496 outputWS->setBinEdges(0, edges);
497 auto &outputX = outputWS->mutableX(0);
498 g_log.
information() <<
"Using output min = " << outputX.front() <<
" and output max = " << outputX.back() <<
"\n";
500 auto &outputY = outputWS->mutableY(0);
501 auto &outputE = outputWS->mutableE(0);
507 double corr = 0.5 / M_PI / M_PI / rho0;
508 if (direction == BACKWARD) {
509 corr = 4.0 * M_PI * rho0;
511 const double inXMax = inputX[Xmax_index];
512 for (
size_t outXIndex = 0; outXIndex < sizer; outXIndex++) {
513 const double outX = 0.5 * (outputX[outXIndex] + outputX[outXIndex + 1]);
514 const double outXFac = corr / (outX * outX * outX);
517 double errorSquared = 0;
518 auto pdfIntegral = [outX](
const double x) ->
double {
return sin(
x * outX) -
x * outX * cos(
x * outX); };
519 double inX2 = inputX[Xmin_index];
520 double integralX2 = pdfIntegral(inX2);
522 for (
size_t inXIndex = Xmin_index; inXIndex < Xmax_index; inXIndex++) {
523 const double inX1 = inX2;
524 inX2 = inputX[inXIndex + 1];
525 const double integralX1 = integralX2;
526 integralX2 = pdfIntegral(inX2);
527 double defIntegral = integralX2 - integralX1;
530 auto inXCen = 0.5 * (inX1 + inX2);
531 if (filter &&
fabs(inXCen) > 1e-8) {
532 const double lorchKernel = inXCen * M_PI / inXMax;
533 defIntegral *= sin(lorchKernel) / lorchKernel;
535 fs += defIntegral * inputY[inXIndex];
537 const double error = defIntegral * inputDY[inXIndex];
542 outputY[outXIndex] = fs * outXFac;
543 outputE[outXIndex] = sqrt(errorSquared) * outXFac;
546 if (direction == FORWARD) {
548 }
else if (direction == BACKWARD) {