135 throw std::invalid_argument(
"For now, we expect the input MDEventWorkspace "
136 "to have 3 dimensions only.");
143 if (peakWS != inPeakWS)
144 peakWS = inPeakWS->clone();
149 g_log.
warning() <<
" Warning" << CoordinatesToUse <<
'\n';
150 if (CoordinatesToUse ==
Kernel::QLab && CoordinatesToUseStr !=
"Q (lab frame)")
151 g_log.
warning() <<
"Warning: used Q (lab frame) coordinates for MD "
152 "workspace, not CoordinatesToUse from input \n";
153 else if (CoordinatesToUse ==
Kernel::QSample && CoordinatesToUseStr !=
"Q (sample frame)")
154 g_log.
warning() <<
"Warning: used Q (sample frame) coordinates for MD "
155 "workspace, not CoordinatesToUse from input \n";
156 else if (CoordinatesToUse ==
Kernel::HKL && CoordinatesToUseStr !=
"HKL")
157 g_log.
warning() <<
"Warning: used HKL coordinates for MD workspace, not "
158 "CoordinatesToUse from input \n";
163 double BackgroundOuterRadius =
getProperty(
"BackgroundOuterRadius");
165 double BackgroundInnerRadius =
getProperty(
"BackgroundInnerRadius");
166 if (BackgroundInnerRadius < PeakRadius)
167 BackgroundInnerRadius = PeakRadius;
169 double cylinderLength =
getProperty(
"CylinderLength");
173 bool adaptiveQRadius =
getProperty(
"AdaptiveQRadius");
174 std::vector<double> PeakRadiusVector(peakWS->getNumberPeaks(), PeakRadius);
175 std::vector<double> BackgroundInnerRadiusVector(peakWS->getNumberPeaks(), BackgroundInnerRadius);
176 std::vector<double> BackgroundOuterRadiusVector(peakWS->getNumberPeaks(), BackgroundOuterRadius);
179 size_t histogramNumber = peakWS->getNumberPeaks();
181 wsProfile2D = std::dynamic_pointer_cast<Workspace2D>(wsProfile);
182 AnalysisDataService::Instance().addOrReplace(
"ProfilesData", wsProfile2D);
184 wsFit2D = std::dynamic_pointer_cast<Workspace2D>(wsFit);
185 AnalysisDataService::Instance().addOrReplace(
"ProfilesFit", wsFit2D);
187 wsDiff2D = std::dynamic_pointer_cast<Workspace2D>(wsDiff);
188 AnalysisDataService::Instance().addOrReplace(
"ProfilesFitDiff", wsDiff2D);
189 auto newAxis1 = std::make_unique<TextAxis>(peakWS->getNumberPeaks());
190 auto newAxis2 = std::make_unique<TextAxis>(peakWS->getNumberPeaks());
191 auto newAxis3 = std::make_unique<TextAxis>(peakWS->getNumberPeaks());
192 auto newAxis1Raw = newAxis1.get();
193 auto newAxis2Raw = newAxis2.get();
194 auto newAxis3Raw = newAxis3.get();
195 wsProfile2D->replaceAxis(1, std::move(newAxis1));
196 wsFit2D->replaceAxis(1, std::move(newAxis2));
197 wsDiff2D->replaceAxis(1, std::move(newAxis3));
198 for (
int i = 0; i < peakWS->getNumberPeaks(); ++i) {
200 IPeak &p = peakWS->getPeak(i);
201 std::ostringstream label;
204 newAxis1Raw->setLabel(i, label.str());
205 newAxis2Raw->setLabel(i, label.str());
206 newAxis3Raw->setLabel(i, label.str());
209 double percentBackground =
getProperty(
"PercentBackground");
211 size_t peakMax = numSteps;
214 peakMin =
static_cast<size_t>(
static_cast<double>(numSteps) * percentBackground / 100.);
215 peakMax = numSteps - peakMin - 1;
216 size_t numPeakCh = peakMax - peakMin + 1;
217 size_t numBkgCh = numSteps - numPeakCh;
218 ratio =
static_cast<double>(numPeakCh) /
static_cast<double>(numBkgCh);
221 bool replaceIntensity =
getProperty(
"ReplaceIntensity");
222 bool integrateEdge =
getProperty(
"IntegrateIfOnEdge");
224 std::string profileFunction =
getProperty(
"ProfileFunction");
225 std::string integrationOption =
getProperty(
"IntegrationOption");
227 if (cylinderBool && profileFunction !=
"NoFit") {
228 std::string outFile =
getProperty(
"InputWorkspace");
229 outFile.append(profileFunction);
230 outFile.append(
".dat");
231 std::string save_path = ConfigService::Instance().getString(
"defaultsave.directory");
232 outFile = save_path + outFile;
233 out.open(outFile.c_str(), std::ofstream::out);
245 for (
int i = 0; i < peakWS->getNumberPeaks(); ++i) {
247 IPeak &p = peakWS->getPeak(i);
259 inst = peakWS->getInstrument();
261 if (BackgroundOuterRadius > PeakRadius) {
263 g_log.
warning() <<
"Warning: sphere/cylinder for integration is off "
264 "edge of detector for peak "
271 g_log.
warning() <<
"Warning: sphere/cylinder for integration is off "
272 "edge of detector for peak "
280 bool dimensionsUsed[nd];
282 for (
size_t d = 0;
d < nd; ++
d) {
283 dimensionsUsed[
d] =
true;
284 center[
d] =
static_cast<coord_t>(pos[
d]);
290 double background_total = 0.0;
294 if (adaptiveQRadius) {
296 for (
size_t d = 0;
d < nd;
d++) {
297 lenQpeak += center[
d] * center[
d];
299 lenQpeak = std::sqrt(lenQpeak);
301 PeakRadiusVector[i] = lenQpeak * PeakRadius;
302 BackgroundInnerRadiusVector[i] = lenQpeak * BackgroundInnerRadius;
303 BackgroundOuterRadiusVector[i] = lenQpeak * BackgroundOuterRadius;
306 if (
auto *shapeablePeak =
dynamic_cast<Peak *
>(&p)) {
309 new PeakShapeSpherical(PeakRadiusVector[i], BackgroundInnerRadiusVector[i], BackgroundOuterRadiusVector[i],
311 shapeablePeak->setPeakShape(sphereShape);
320 if (BackgroundOuterRadius > PeakRadius) {
323 sphere,
static_cast<coord_t>(lenQpeak * BackgroundOuterRadius * lenQpeak * BackgroundOuterRadius), bgSignal,
331 if (BackgroundInnerRadius != PeakRadius) {
333 sphere,
static_cast<coord_t>(lenQpeak * BackgroundInnerRadius * lenQpeak * BackgroundInnerRadius),
334 interiorSignal, interiorErrorSquared);
337 interiorSignal = signal;
338 interiorErrorSquared = errorSquared;
342 bgSignal -= interiorSignal;
345 bgErrorSquared -= interiorErrorSquared;
348 const double radiusRatio = (PeakRadius / BackgroundOuterRadius);
349 const double peakVolume = radiusRatio * radiusRatio * radiusRatio;
352 const double interiorRatio = (BackgroundInnerRadius / BackgroundOuterRadius);
355 const double bgVolume = 1.0 - interiorRatio * interiorRatio * interiorRatio;
359 const double scaleFactor = peakVolume / bgVolume;
360 bgSignal *= scaleFactor;
361 bgErrorSquared *= scaleFactor * scaleFactor;
367 Counts signal_fit(numSteps);
371 signal, errorSquared, signal_fit.mutableRawData());
373 Points points(signal_fit.size(), LinearGenerator(0, 1));
374 wsProfile2D->setHistogram(i, points, signal_fit);
377 if (BackgroundOuterRadius > PeakRadius) {
382 static_cast<coord_t>(cylinderLength), bgSignal, bgErrorSquared,
383 signal_fit.mutableRawData());
385 wsProfile2D->setHistogram(i, points, signal_fit);
392 if (BackgroundInnerRadius != PeakRadius) {
394 static_cast<coord_t>(cylinderLength), interiorSignal, interiorErrorSquared,
395 signal_fit.mutableRawData());
398 interiorSignal = signal;
399 interiorErrorSquared = errorSquared;
403 bgSignal -= interiorSignal;
406 bgErrorSquared -= interiorErrorSquared;
408 const double radiusRatio = (PeakRadius / BackgroundOuterRadius);
409 const double peakVolume = radiusRatio * radiusRatio * cylinderLength;
412 const double interiorRatio = (BackgroundInnerRadius / BackgroundOuterRadius);
415 const double bgVolume = 1.0 - interiorRatio * interiorRatio * cylinderLength;
419 const double scaleFactor = peakVolume / bgVolume;
420 bgSignal *= scaleFactor;
421 bgErrorSquared *= scaleFactor * scaleFactor;
423 wsProfile2D->setHistogram(i, points, signal_fit);
426 if (profileFunction ==
"NoFit") {
427 auto &
y = wsProfile2D->y(i);
429 signal =
y.sum(peakMin, peakMax);
431 background_total +=
y.sum(0, peakMin);
432 background_total +=
y.sum(peakMax);
433 errorSquared = std::abs(signal);
436 findpeaks->setProperty(
"InputWorkspace", wsProfile2D);
437 findpeaks->setProperty<
int>(
"FWHM", 7);
438 findpeaks->setProperty<
int>(
"Tolerance", 4);
440 findpeaks->setProperty(
"WorkspaceIndex",
static_cast<int>(i));
443 findpeaks->setProperty<std::string>(
"PeakFunction", profileFunction);
445 findpeaks->setProperty<std::string>(
"BackgroundType",
"Quadratic");
446 findpeaks->setProperty<
bool>(
"HighBackground",
true);
447 findpeaks->setProperty<
bool>(
"RawPeakParameters",
true);
448 std::vector<double> peakPosToFit;
449 peakPosToFit.emplace_back(
static_cast<double>(numSteps) / 2.0);
450 findpeaks->setProperty(
"PeakPositions", peakPosToFit);
451 findpeaks->setProperty<
int>(
"MinGuessedPeakWidth", 4);
452 findpeaks->setProperty<
int>(
"MaxGuessedPeakWidth", 4);
454 findpeaks->executeAsChildAlg();
456 g_log.
error(
"Can't execute FindPeaks algorithm");
461 if (paramws->rowCount() < 1)
463 std::ostringstream fun_str;
464 fun_str <<
"name=" << profileFunction;
466 size_t numcols = paramws->columnCount();
467 std::vector<std::string> paramsName = paramws->getColumnNames();
468 std::vector<double> paramsValue;
472 for (
size_t j = 1; j < numcols; ++j) {
475 if (j == numcols - 4)
476 fun_str <<
";name=Quadratic";
480 if (j > 0 && j < numcols - 1)
481 fun_str <<
"," << paramsName[j] <<
"=" << parvalue;
482 paramsValue.emplace_back(parvalue);
485 for (
size_t j = 0; j < numcols; ++j)
486 out << std::setw(20) << paramsName[j] <<
" ";
489 out << std::setw(20) << i;
490 for (
size_t j = 0; j < numcols - 1; ++j)
491 out << std::setw(20) << std::fixed << std::setprecision(10) << paramsValue[j] <<
" ";
496 IFunction_sptr ifun = FunctionFactory::Instance().createInitialized(fun_str.str());
497 std::shared_ptr<const CompositeFunction> fun = std::dynamic_pointer_cast<const CompositeFunction>(ifun);
498 const auto &
x = wsProfile2D->x(i);
499 wsFit2D->setSharedX(i, wsProfile2D->sharedX(i));
500 wsDiff2D->setSharedX(i, wsProfile2D->sharedX(i));
504 fun->function(domain, yy);
507 wsFit2D->mutableY(i) = funcValues;
508 wsDiff2D->setSharedY(i, wsProfile2D->sharedY(i));
509 wsDiff2D->mutableY(i) -= wsFit2D->y(i);
513 if (integrationOption ==
"Sum") {
515 for (
size_t j = peakMin; j <= peakMax; j++)
516 if (std::isfinite(yy[j]))
519 gsl_integration_workspace *w = gsl_integration_workspace_alloc(1000);
527 gsl_integration_qags(&F,
x[peakMin],
x[peakMax], 0, 1e-7, 1000, w, &signal, &
error);
529 gsl_integration_workspace_free(w);
531 errorSquared = std::fabs(signal);
533 for (
size_t j = 0; j < numSteps; j++) {
535 paramsValue[numcols - 3] *
x[j] *
x[j] + paramsValue[numcols - 4] *
x[j] + paramsValue[numcols - 5];
536 if (j < peakMin || j > peakMax)
537 background_total = background_total + background;
542 if (signal != 0. || replaceIntensity) {
543 p.
setIntensity(signal - ratio * background_total - bgSignal);
544 p.
setSigmaIntensity(sqrt(errorSquared + ratio * ratio * std::fabs(background_total) + bgErrorSquared));
547 g_log.
information() <<
"Peak " << i <<
" at " << pos <<
": signal " << signal <<
" (sig^2 " << errorSquared
548 <<
"), with background " << bgSignal + ratio * background_total <<
" (sig^2 "
549 << bgErrorSquared + ratio * ratio * std::fabs(background_total) <<
") subtracted.\n";
553 peakWS->mutableRun().addProperty(
"PeaksIntegrated", 1,
true);
555 peakWS->mutableRun().addProperty(
"PeakRadius", PeakRadiusVector,
true);
556 peakWS->mutableRun().addProperty(
"BackgroundInnerRadius", BackgroundInnerRadiusVector,
true);
557 peakWS->mutableRun().addProperty(
"BackgroundOuterRadius", BackgroundOuterRadiusVector,
true);
560 const std::string outfile =
getProperty(
"ProfilesFile");
561 if (outfile.length() > 0) {
566 g_log.
error(
"Can't locate SaveIsawPeaks algorithm");
569 alg->setProperty(
"InputWorkspace", peakWS);
570 alg->setProperty(
"ProfileWorkspace", wsProfile2D);
571 alg->setPropertyValue(
"Filename", outfile);