34#include <boost/lexical_cast.hpp>
46bool compareMomentum(
const std::array<double, 4> &v1,
const std::array<double, 4> &v2) {
return (v1[3] < v2[3]); }
53static bool abs_compare(
double a,
double b) {
return (std::fabs(a) < std::fabs(b)); }
64 : m_normWS(), m_inputWS(), m_isRLU(false), m_UB(3, 3, true), m_W(3, 3, true), m_transformation(), m_hX(), m_kX(),
65 m_lX(), m_eX(), m_hIdx(-1), m_kIdx(-1), m_lIdx(-1), m_eIdx(-1), m_numExptInfos(0), m_Ei(0.0), m_diffraction(true),
66 m_monochromatic(false), m_accumulate(false), m_dEIntegrated(true), m_samplePos(), m_beamDir(), convention("") {}
79 return "Bins multidimensional data and calculate the normalization on the "
89 "An input MDEventWorkspace. Must be in Q_sample frame.");
93 "An (optional) input MDEventWorkspace for background. Must be in Q_lab frame.");
96 declareProperty(
"RLU",
true,
"Use reciprocal lattice units. If false, use Q_sample");
99 auto mustBe3D = std::make_shared<Kernel::ArrayLengthValidator<double>>(3);
100 std::vector<double> Q0(3, 0.), Q1(3, 0), Q2(3, 0);
106 "The first Q projection axis - Default is (1,0,0)");
111 "The second Q projection axis - Default is (0,1,0)");
116 "The thirdtCalculateCover Q projection axis - Default is (0,0,1)");
121 auto fluxValidator = std::make_shared<CompositeValidator>();
124 auto solidAngleValidator = fluxValidator->
clone();
127 "An input workspace containing integrated vanadium "
128 "(a measure of the solid angle).\n"
129 "Mandatory for diffraction, optional for direct geometry inelastic");
132 "An input workspace containing momentum dependent flux.\n"
133 "Mandatory for diffraction. No effect on direct geometry inelastic");
140 "An (optional) input MDEventWorkspace containing a pre-computed normalization "
141 "for monochromatic single crystal diffraction (e.g. produced by "
142 "ConvertHFIRSCDtoMDE). Must be in Q_sample frame with the same number of "
143 "dimensions as InputWorkspace. Cannot be used together with "
144 "SolidAngleWorkspace/FluxWorkspace or BackgroundWorkspace.");
148 for (std::size_t i = 0; i < 6; i++) {
151 std::string defaultName =
"";
157 auto atMost3 = std::make_shared<ArrayLengthValidator<double>>(0, 3);
158 std::vector<double> temp;
161 "- Leave blank for complete integration\n" +
162 "- One value is interpreted as step\n"
163 "- Two values are interpreted integration interval\n" +
164 "- Three values are interpreted as min, step, max");
171 "If specified the symmetry will be applied, "
172 "can be space group name, point group name, or list "
173 "individual symmetries.");
178 "An (optional) input MDHistoWorkspace used to accumulate data from "
179 "multiple MDEventWorkspaces. If unspecified a blank "
180 "MDHistoWorkspace will be created.");
183 "An (optional) input MDHistoWorkspace used to accumulate normalization "
184 "from multiple MDEventWorkspaces. If unspecified a blank "
185 "MDHistoWorkspace will be created.");
190 "An (optional) input MDHistoWorkspace used to accumulate background from "
191 "multiple background MDEventWorkspaces. If unspecified but "
192 "BackgroundWorkspace is specified, a blank "
193 "MDHistoWorkspace will be created.");
196 "An (optional) input MDHistoWorkspace used to accumulate background normalization "
197 "from multiple background MDEventWorkspaces. If unspecified but "
198 "BackgroundWorkspace is specified, a blank "
199 "MDHistoWorkspace will be created.");
202 setPropertyGroup(
"TemporaryNormalizationWorkspace",
"Temporary workspaces");
203 setPropertyGroup(
"TemporaryBackgroundDataWorkspace",
"Temporary workspaces");
204 setPropertyGroup(
"TemporaryBackgroundNormalizationWorkspace",
"Temporary workspaces");
207 "A name for the normalized output MDHistoWorkspace.");
210 "A name for the output data MDHistoWorkspace.");
212 "A name for the output normalization MDHistoWorkspace.");
215 "A name for the optional output background data MDHistoWorkspace.");
218 "A name for the optional output background normalization MDHistoWorkspace.");
224 std::map<std::string, std::string> errorMessage;
228 if (inputWS->getNumDims() < 3) {
229 errorMessage.emplace(
"InputWorkspace",
"The input workspace must be at least 3D");
231 for (
size_t i = 0; i < 3; i++) {
233 errorMessage.emplace(
"InputWorkspace",
"The input workspace must be in Q_sample");
241 if (bkgdWS->getNumDims() < 3) {
243 errorMessage.emplace(
"BackgroundWorkspace",
"The input background workspace must be at least 3D");
246 for (
size_t i = 0; i < 3; i++) {
248 errorMessage.emplace(
"BackgroundWorkspace",
"The input backgound workspace must be in Q_lab");
253 if (inputWS->getNumDims() > 3) {
254 if (bkgdWS->getNumDims() <= 3) {
255 errorMessage.emplace(
"BackgroundWorkspace",
"The input background workspace must have at 4 dimensions when "
256 "input workspace has more than 4 dimensions (inelastic case).");
257 }
else if (bkgdWS->getDimension(3)->getName() != inputWS->getDimension(3)->getName()) {
258 errorMessage.emplace(
"BackgroundWorkspace",
"The input background workspace 4th dimension must be DeltaE "
259 "for inelastic case.");
266 bool diffraction =
true;
267 if ((inputWS->getNumDims() > 3) && (inputWS->getDimension(3)->getName() ==
"DeltaE")) {
274 bool monochromatic = bool(monoNormWS);
280 errorMessage.emplace(
"MonoSCDNormalizationWorkspace",
"MonoSCDNormalizationWorkspace can only be used for "
281 "diffraction (InputWorkspace must not have a DeltaE "
284 if (solidAngleWS || fluxWS) {
285 errorMessage.emplace(
"MonoSCDNormalizationWorkspace",
"MonoSCDNormalizationWorkspace cannot be used together "
286 "with SolidAngleWorkspace/FluxWorkspace");
289 errorMessage.emplace(
"MonoSCDNormalizationWorkspace",
"MonoSCDNormalizationWorkspace cannot currently be used "
290 "together with BackgroundWorkspace");
292 if (monoNormWS->getNumDims() < 3) {
293 errorMessage.emplace(
"MonoSCDNormalizationWorkspace",
"MonoSCDNormalizationWorkspace must be at least 3D");
295 if (monoNormWS->getNumDims() != inputWS->getNumDims()) {
296 errorMessage.emplace(
"MonoSCDNormalizationWorkspace",
"MonoSCDNormalizationWorkspace must have the same "
297 "number of dimensions as InputWorkspace");
299 for (
size_t i = 0; i < 3; i++) {
301 errorMessage.emplace(
"MonoSCDNormalizationWorkspace",
"MonoSCDNormalizationWorkspace must be in Q_sample");
305 }
else if (diffraction) {
306 if (solidAngleWS ==
nullptr) {
307 errorMessage.emplace(
"SolidAngleWorkspace",
"SolidAngleWorkspace is required for diffraction");
309 if (fluxWS ==
nullptr) {
310 errorMessage.emplace(
"FluxWorkspace",
"FluxWorkspace is required for diffraction");
315 size_t nExperimentInfos = inputWS->getNumExperimentInfo();
316 if (nExperimentInfos == 0) {
317 errorMessage.emplace(
"InputWorkspace",
"There must be at least one experiment info");
319 for (
size_t iExpInfo = 0; iExpInfo < nExperimentInfos; iExpInfo++) {
320 auto ¤tExptInfo = *(inputWS->getExperimentInfo(
static_cast<uint16_t
>(iExpInfo)));
322 if (!currentExptInfo.run().hasProperty(
"wavelength")) {
323 errorMessage.emplace(
"InputWorkspace",
"Missing wavelength log. InputWorkspace does not look like it was "
324 "produced by ConvertHFIRSCDtoMDE, as expected when "
325 "MonoSCDNormalizationWorkspace is provided");
328 if (!currentExptInfo.run().hasProperty(
"MDNorm_low")) {
329 errorMessage.emplace(
"InputWorkspace",
"Missing MDNorm_low log. Please "
330 "use CropWorkspaceForMDNorm "
331 "before converting to MD");
333 if (!currentExptInfo.run().hasProperty(
"MDNorm_high")) {
334 errorMessage.emplace(
"InputWorkspace",
"Missing MDNorm_high log. Please use "
335 "CropWorkspaceForMDNorm before converting to MD");
343 std::vector<double> Q0Basis =
getProperty(
"QDimension0");
344 std::vector<double> Q1Basis =
getProperty(
"QDimension1");
345 std::vector<double> Q2Basis =
getProperty(
"QDimension2");
350 errorMessage.emplace(
"QDimension0",
"The projection dimensions are coplanar or zero");
351 errorMessage.emplace(
"QDimension1",
"The projection dimensions are coplanar or zero");
352 errorMessage.emplace(
"QDimension2",
"The projection dimensions are coplanar or zero");
354 if (!inputWS->getExperimentInfo(0)->sample().hasOrientedLattice()) {
355 errorMessage.emplace(
"InputWorkspace",
"There is no oriented lattice "
356 "associated with the input workspace. "
357 "Use SetUB algorithm");
361 std::vector<std::string> originalDimensionNames;
362 for (
size_t i = 3; i < inputWS->getNumDims(); i++) {
363 originalDimensionNames.emplace_back(inputWS->getDimension(i)->getName());
365 originalDimensionNames.emplace_back(
"QDimension0");
366 originalDimensionNames.emplace_back(
"QDimension1");
367 originalDimensionNames.emplace_back(
"QDimension2");
368 std::vector<std::string> selectedDimensions;
369 for (std::size_t i = 0; i < 6; i++) {
373 std::vector<double> binning =
getProperty(binningName);
374 if (!dimName.empty()) {
375 auto it = std::find(originalDimensionNames.begin(), originalDimensionNames.end(), dimName);
376 if (it == originalDimensionNames.end()) {
377 errorMessage.emplace(propName,
"Name '" + dimName +
378 "' is not one of the "
379 "original workspace names or a directional dimension");
382 auto itSel = std::find(selectedDimensions.begin(), selectedDimensions.end(), dimName);
383 if (itSel == selectedDimensions.end()) {
384 selectedDimensions.emplace_back(dimName);
386 errorMessage.emplace(propName,
"Name '" + dimName +
"' was already selected");
390 if (!binning.empty()) {
391 errorMessage.emplace(binningName,
"There should be no binning if the dimension name is empty");
396 if ((std::find(selectedDimensions.begin(), selectedDimensions.end(),
"QDimension0") == selectedDimensions.end()) ||
397 (std::find(selectedDimensions.begin(), selectedDimensions.end(),
"QDimension1") == selectedDimensions.end()) ||
398 (std::find(selectedDimensions.begin(), selectedDimensions.end(),
"QDimension2") == selectedDimensions.end())) {
399 for (std::size_t i = 0; i < 6; i++) {
401 errorMessage.emplace(propName,
"All of QDimension0, QDimension1, QDimension2 must be present");
405 std::string symOps = this->
getProperty(
"SymmetryOperations");
406 if (!symOps.empty()) {
407 bool isSpaceGroup = Geometry::SpaceGroupFactory::Instance().isSubscribed(symOps);
408 bool isPointGroup = Geometry::PointGroupFactory::Instance().isSubscribed(symOps);
409 if (!isSpaceGroup && !isPointGroup) {
411 Geometry::SymmetryOperationFactory::Instance().createSymOps(symOps);
413 errorMessage.emplace(
"SymmetryOperations",
"The input is not a space group, a point group, "
414 "or a list of symmetry operations");
419 std::shared_ptr<IMDHistoWorkspace> tempNormWS = this->
getProperty(
"TemporaryNormalizationWorkspace");
423 if ((tempNormWS && !tempDataWS) || (!tempNormWS && tempDataWS)) {
424 errorMessage.emplace(
"TemporaryDataWorkspace",
"Must provide either no accumulation workspaces or,"
425 "both TemporaryNormalizationWorkspaces and TemporaryDataWorkspace");
428 if (tempNormWS && tempDataWS) {
429 size_t numNormDims = tempNormWS->getNumDims();
430 size_t numDataDims = tempDataWS->getNumDims();
431 if (numNormDims == numDataDims) {
432 for (
size_t i = 0; i < numNormDims; i++) {
433 const auto dim1 = tempNormWS->getDimension(i);
434 const auto dim2 = tempDataWS->getDimension(i);
435 if ((dim1->getMinimum() != dim2->getMinimum()) || (dim1->getMaximum() != dim2->getMaximum()) ||
436 (dim1->getNBins() != dim2->getNBins()) || (dim1->getName() != dim2->getName())) {
437 errorMessage.emplace(
"TemporaryDataWorkspace",
"Binning for TemporaryNormalizationWorkspaces "
438 "and TemporaryDataWorkspace must be the same.");
443 errorMessage.emplace(
"TemporaryDataWorkspace",
"TemporaryNormalizationWorkspace and TemporaryDataWorkspace "
444 "do not have the same number of dimensions");
453 if (tempBkgdDataWS && (!bkgdWS || !tempDataWS || !tempBkgdNormWS)) {
454 errorMessage.emplace(
"TemporaryBackgroundDataWorkspace",
"TemporaryBackgroundDataWorkspace is specified but at "
455 "least one of these is not.");
456 }
else if (tempBkgdNormWS && (!bkgdWS || !tempNormWS || !tempBkgdDataWS)) {
457 errorMessage.emplace(
"TemporaryBackgroundNormalizationWorkspace",
"TemporaryBackgroundNormalizationWorkspace is "
458 "specified but at least one of these is not.");
459 }
else if (bkgdWS && tempDataWS && !tempBkgdDataWS) {
460 errorMessage.emplace(
"TemporaryDataWorkspace",
461 "With Background is specifed and TemporaryDataWorkspace is specifed, "
462 "TemporaryBackgroundDataWorkspace must be specified.");
463 }
else if (tempBkgdDataWS && tempNormWS) {
465 size_t numBkgdDataDims = tempBkgdDataWS->getNumDims();
466 size_t numBkgdNormDims = tempBkgdNormWS->getNumDims();
467 size_t numDataDims = tempDataWS->getNumDims();
468 if (numBkgdDataDims == numBkgdNormDims && numBkgdDataDims == numDataDims) {
470 for (
size_t idim = 0; idim < numBkgdDataDims; ++idim) {
471 const auto dimB = tempBkgdDataWS->getDimension(idim);
472 const auto dimN = tempBkgdNormWS->getDimension(idim);
473 const auto dimD = tempDataWS->getDimension(idim);
474 if ((dimB->getMinimum() != dimN->getMinimum()) || (dimB->getMinimum() != dimD->getMinimum()) ||
475 (dimB->getMaximum() != dimN->getMaximum()) || (dimB->getMaximum() != dimD->getMaximum()) ||
476 (dimB->getNBins() != dimN->getNBins()) || (dimB->getNBins() != dimD->getNBins()) ||
477 (dimB->getName() != dimN->getName()) || (dimB->getName() != dimD->getName())) {
478 errorMessage.emplace(
"TemporaryBackgroundDataWorkspace",
479 "TemporaryBackgroundDataWorkspace, "
480 "TemporaryBackgroundNormalizationWorkspace and "
481 "TemporaryDataWorkspace "
482 "must have same minimum, maximum, number of bins and name.");
487 errorMessage.emplace(
"TemporaryBackgroundDataWorkspace",
"TemporaryBackgroundDataWorkspace, "
488 "TemporaryBackgroundNormalizationWorkspace and "
489 "TemporaryDataWorkspace must have same dimensions");
500 convention = Kernel::ConfigService::Instance().getString(
"Q.convention");
502 std::string symOps = this->
getProperty(
"SymmetryOperations");
503 std::vector<Geometry::SymmetryOperation> symmetryOps;
504 if (symOps.empty()) {
507 if (Geometry::SpaceGroupFactory::Instance().isSubscribed(symOps)) {
508 auto spaceGroup = Geometry::SpaceGroupFactory::Instance().createSpaceGroup(symOps);
509 auto pointGroup = spaceGroup->getPointGroup();
510 symmetryOps = pointGroup->getSymmetryOperations();
511 }
else if (Geometry::PointGroupFactory::Instance().isSubscribed(symOps)) {
512 auto pointGroup = Geometry::PointGroupFactory::Instance().createPointGroup(symOps);
513 symmetryOps = pointGroup->getSymmetryOperations();
515 symmetryOps = Geometry::SymmetryOperationFactory::Instance().createSymOps(symOps);
518 for (
const auto &so : symmetryOps) {
528 const auto &exptInfoZero = *(
m_inputWS->getExperimentInfo(0));
529 auto source = exptInfoZero.getInstrument()->getSource();
530 auto sample = exptInfoZero.getInstrument()->getSample();
531 if (source ==
nullptr || sample ==
nullptr) {
533 "Instrument not sufficiently defined: failed to get source and/or "
538 if ((
m_inputWS->getNumDims() > 3) && (
m_inputWS->getDimension(3)->getName() ==
"DeltaE")) {
541 if (exptInfoZero.run().hasProperty(
"Ei")) {
543 m_Ei = boost::lexical_cast<double>(eiprop->
value());
545 throw std::invalid_argument(
"Ei stored in the workspace is not positive");
548 throw std::invalid_argument(
"Could not find Ei value in the workspace.");
564 this->
setProperty(
"OutputDataWorkspace", outputDataWS);
574 this->
setProperty(
"OutputBackgroundDataWorkspace", outputBackgroundDataWS);
581 for (uint16_t expInfoIndex = 0; expInfoIndex <
m_numExptInfos; expInfoIndex++) {
584 bool skipNormalization =
false;
589 if (!skipNormalization) {
590 size_t symmOpsIndex = 0;
591 for (
const auto &so : symmetryOps) {
597 g_log.
warning(
"Binning limits are outside the limits of the MDWorkspace. "
598 "Not applying normalization.");
612 const std::string normedBkgdWSName(
"_normedBkgd");
618 minusMD->setProperty(
"LHSWorkspace", out);
619 minusMD->setProperty(
"RHSWorkspace", outbkgd);
620 minusMD->setPropertyValue(
"OutputWorkspace",
getPropertyValue(
"OutputWorkspace"));
622 minusMD->executeAsChildAlg();
623 out = minusMD->getProperty(
"OutputWorkspace");
636 const double &startProgress,
const double &endProgress) {
638 divideMD->setProperty(
"LHSWorkspace", lhs);
640 divideMD->setPropertyValue(
"OutputWorkspace", outputwsname);
655 return std::string(
"Q_sample_x");
657 return std::string(
"Q_sample_y");
659 return std::string(
"Q_sample_z");
661 throw std::invalid_argument(
"Index must be 0, 1, or 2 for QDimensionNameQSample");
670 std::vector<double>::iterator result;
671 result = std::max_element(projection.begin(), projection.end(), abs_compare);
672 std::vector<char> symbol{
'H',
'K',
'L'};
673 char character = symbol[std::distance(projection.begin(), result)];
674 std::stringstream
name;
676 for (
size_t i = 0; i < 3; i++) {
677 if (projection[i] == 0) {
679 }
else if (projection[i] == 1) {
681 }
else if (projection[i] == -1) {
682 name <<
"-" << character;
684 name << std::defaultfloat << std::setprecision(3) << projection[i] << character;
699 std::map<std::string, std::string> parameters;
700 std::stringstream extents;
701 std::stringstream bins;
702 std::vector<std::string> originalDimensionNames;
703 originalDimensionNames.emplace_back(
"QDimension0");
704 originalDimensionNames.emplace_back(
"QDimension1");
705 originalDimensionNames.emplace_back(
"QDimension2");
706 for (
size_t i = 3; i <
m_inputWS->getNumDims(); i++) {
707 originalDimensionNames.emplace_back(
m_inputWS->getDimension(i)->getName());
714 m_UB =
m_inputWS->getExperimentInfo(0)->sample().getOrientedLattice().getUB() * 2 * M_PI;
734 auto &exptInfo0 = *(
m_inputWS->getExperimentInfo(
static_cast<uint16_t
>(0)));
735 auto upperLimitsVector =
738 maxQ = 2. * (*std::max_element(upperLimitsVector.begin(), upperLimitsVector.end()));
741 double maxDE = *std::max_element(upperLimitsVector.begin(), upperLimitsVector.end());
742 auto loweLimitsVector =
744 double minDE = *std::min_element(loweLimitsVector.begin(), loweLimitsVector.end());
745 if (exptInfo0.run().hasProperty(
"Ei")) {
747 Ei = boost::lexical_cast<double>(eiprop->
value());
749 throw std::invalid_argument(
"Ei stored in the workspace is not positive");
752 throw std::invalid_argument(
"Could not find Ei value in the workspace.");
756 double ki = std::sqrt(energyToK * Ei);
757 double kfmin = std::sqrt(energyToK * (Ei - minDE));
758 double kfmax = std::sqrt(energyToK * (Ei - maxDE));
760 maxQ = ki + std::max(kfmin, kfmax);
768 auto dataExtents =
m_inputWS->getMinimumExtents(4);
769 double qx = std::max(std::fabs(dataExtents[0].getMin()), std::fabs(dataExtents[0].getMax()));
770 double qy = std::max(std::fabs(dataExtents[1].getMin()), std::fabs(dataExtents[1].getMax()));
771 double qz = std::max(std::fabs(dataExtents[2].getMin()), std::fabs(dataExtents[2].getMax()));
772 maxQ = std::sqrt(qx * qx + qy * qy + qz * qz);
774 size_t basisVectorIndex = 0;
775 std::vector<coord_t> transformation;
776 for (std::size_t i = 0; i < 6; i++) {
780 std::vector<double> binning =
getProperty(binningName);
781 std::string bv =
"BasisVector";
782 if (!dimName.empty()) {
784 std::stringstream propertyValue;
785 propertyValue << dimName;
787 auto dimIndex = std::distance(originalDimensionNames.begin(),
788 std::find(originalDimensionNames.begin(), originalDimensionNames.end(), dimName));
789 auto dimension =
m_inputWS->getDimension(dimIndex);
790 propertyValue <<
"," << dimension->getMDUnits().getUnitLabel().ascii();
791 for (
size_t j = 0; j < originalDimensionNames.size(); j++) {
792 if (j ==
static_cast<size_t>(dimIndex)) {
793 propertyValue <<
",1";
794 transformation.emplace_back(1.f);
796 propertyValue <<
",0";
797 transformation.emplace_back(0.f);
800 parameters.emplace(property, propertyValue.str());
802 coord_t dimMax = dimension->getMaximum();
803 coord_t dimMin = dimension->getMinimum();
808 dimMax =
static_cast<coord_t>(ol.
a() * maxQ);
810 }
else if (dimIndex == 1) {
811 dimMax =
static_cast<coord_t>(ol.
b() * maxQ);
813 }
else if (dimIndex == 2) {
814 dimMax =
static_cast<coord_t>(ol.
c() * maxQ);
818 if (binning.size() == 0) {
820 extents << dimMin <<
"," << dimMax <<
",";
822 }
else if (binning.size() == 2) {
824 extents << binning[0] <<
"," << binning[1] <<
",";
826 }
else if (binning.size() == 1) {
827 auto step = binning[0];
828 double nsteps = (dimMax - dimMin) / step;
829 if (nsteps + 1 - std::ceil(nsteps) >= 1e-4) {
830 nsteps = std::ceil(nsteps);
832 nsteps = std::floor(nsteps);
834 bins << static_cast<int>(nsteps) <<
",";
835 extents << dimMin <<
"," << dimMin + nsteps * step <<
",";
836 }
else if (binning.size() == 3) {
837 dimMin =
static_cast<coord_t>(binning[0]);
838 auto step = binning[1];
839 dimMax =
static_cast<coord_t>(binning[2]);
840 double nsteps = (dimMax - dimMin) / step;
841 if (nsteps + 1 - std::ceil(nsteps) >= 1e-4) {
842 nsteps = std::ceil(nsteps);
844 nsteps = std::floor(nsteps);
846 bins << static_cast<int>(nsteps) <<
",";
847 extents << dimMin <<
"," << dimMin + nsteps * step <<
",";
852 parameters.emplace(
"OutputExtents", extents.str());
853 parameters.emplace(
"OutputBins", bins.str());
855 transformation,
static_cast<size_t>((transformation.size()) /
m_inputWS->getNumDims()),
m_inputWS->getNumDims());
865 std::shared_ptr<IMDHistoWorkspace>
tmp = this->
getProperty(
"TemporaryNormalizationWorkspace");
866 m_normWS = std::dynamic_pointer_cast<MDHistoWorkspace>(
tmp);
884 std::shared_ptr<IMDHistoWorkspace>
tmp = this->
getProperty(
"TemporaryBackgroundNormalizationWorkspace");
902 const std::string numBinsStr = parameters.at(
"OutputBins");
903 const std::string extentsStr = parameters.at(
"OutputExtents");
908 size_t numDimsTemp = tempDataWS->getNumDims();
909 if ((numBins.size() != numDimsTemp) || (extents.size() != numDimsTemp * 2)) {
910 std::stringstream errorMessage;
911 errorMessage <<
"The number of dimensions in the output and ";
912 errorMessage <<
"TemporaryDataWorkspace are not the same.";
913 throw(std::invalid_argument(errorMessage.str()));
917 for (
size_t i = 0; i < numDimsTemp; i++) {
918 auto ax = tempDataWS->getDimension(i);
919 if (numBins[i] != ax->getNBins()) {
920 std::stringstream errorMessage;
921 errorMessage <<
"The number of bins output and number of bins in ";
922 errorMessage <<
"TemporaryDataWorkspace are not the same along ";
923 errorMessage <<
"dimension " << i;
924 throw(std::invalid_argument(errorMessage.str()));
926 if (std::abs(extents[2 * i] - ax->getMinimum()) > 1.e-5) {
927 std::stringstream errorMessage;
928 errorMessage <<
"The minimum binning value for the output and ";
929 errorMessage <<
"TemporaryDataWorkspace are not the same along ";
930 errorMessage <<
"dimension " << i;
931 throw(std::invalid_argument(errorMessage.str()));
933 if (std::abs(extents[2 * i + 1] - ax->getMaximum()) > 1.e-5) {
934 std::stringstream errorMessage;
935 errorMessage <<
"The maximum binning value for the output and ";
936 errorMessage <<
"TemporaryDataWorkspace are not the same along ";
937 errorMessage <<
"dimension " << i;
938 throw(std::invalid_argument(errorMessage.str()));
943 size_t parametersIndex = 0;
944 std::vector<size_t> dimensionIndex(numDimsTemp + 1, 3);
945 for (
const auto &p : parameters) {
947 auto value = p.second;
950 if (
value.find(
"QDimension0") != std::string::npos) {
951 dimensionIndex[0] = parametersIndex;
952 const std::string dimXName = tempDataWS->getDimension(parametersIndex)->getName();
955 std::stringstream errorMessage;
956 std::stringstream debugMessage;
957 errorMessage <<
"TemporaryDataWorkspace does not have the ";
958 errorMessage <<
"correct name for dimension " << parametersIndex;
960 debugMessage <<
" TemporaryDataWorkspace: " << dimXName;
962 throw(std::invalid_argument(errorMessage.str()));
966 std::stringstream errorMessage;
967 std::stringstream debugMessage;
968 errorMessage <<
"TemporaryDataWorkspace does not have the ";
969 errorMessage <<
"correct name for dimension " << parametersIndex;
971 debugMessage <<
" TemporaryDataWorkspace: " << dimXName;
973 throw(std::invalid_argument(errorMessage.str()));
976 }
else if (
value.find(
"QDimension1") != std::string::npos) {
977 dimensionIndex[1] = parametersIndex;
978 const std::string dimYName = tempDataWS->getDimension(parametersIndex)->getName();
981 std::stringstream errorMessage;
982 std::stringstream debugMessage;
983 errorMessage <<
"TemporaryDataWorkspace does not have the ";
984 errorMessage <<
"correct name for dimension " << parametersIndex;
986 debugMessage <<
" TemporaryDataWorkspace: " << dimYName;
988 throw(std::invalid_argument(errorMessage.str()));
992 std::stringstream errorMessage;
993 std::stringstream debugMessage;
994 errorMessage <<
"TemporaryDataWorkspace does not have the ";
995 errorMessage <<
"correct name for dimension " << parametersIndex;
997 debugMessage <<
" TemporaryDataWorkspace: " << dimYName;
999 throw(std::invalid_argument(errorMessage.str()));
1002 }
else if (
value.find(
"QDimension2") != std::string::npos) {
1003 dimensionIndex[2] = parametersIndex;
1004 const std::string dimZName = tempDataWS->getDimension(parametersIndex)->getName();
1007 std::stringstream errorMessage;
1008 std::stringstream debugMessage;
1009 errorMessage <<
"TemporaryDataWorkspace does not have the ";
1010 errorMessage <<
"correct name for dimension " << parametersIndex;
1012 debugMessage <<
" TemporaryDataWorkspace: " << dimZName;
1014 throw(std::invalid_argument(errorMessage.str()));
1018 std::stringstream errorMessage;
1019 std::stringstream debugMessage;
1020 errorMessage <<
"TemporaryDataWorkspace does not have the ";
1021 errorMessage <<
"correct name for dimension " << parametersIndex;
1023 debugMessage <<
" TemporaryDataWorkspace: " << dimZName;
1025 throw(std::invalid_argument(errorMessage.str()));
1029 }
else if ((key !=
"OutputBins") && (key !=
"OutputExtents")) {
1031 const std::string nameData = tempDataWS->getDimension(parametersIndex)->getName();
1032 if (
value.find(nameData) != 0) {
1034 <<
" from the temporary workspace"
1035 " is not one of the binning dimensions, "
1036 " or dimensions are in the wrong order."
1038 throw(std::invalid_argument(
"Beside the Q dimensions, "
1039 "TemporaryDataWorkspace does not have the "
1040 "same dimension names as OutputWorkspace."));
1045 const auto it = std::find_if(dimensionIndex.cbegin(), dimensionIndex.cend(),
1046 [numDimsTemp](
const auto &idx) { return idx > numDimsTemp; });
1047 if (it != dimensionIndex.cend())
1048 throw(std::invalid_argument(
"Cannot find at least one of QDimension0, "
1049 "QDimension1, or QDimension2"));
1085 std::stringstream &basisVector, std::vector<size_t> &qDimensionIndices) {
1086 if (
value.find(
"QDimension0") != std::string::npos) {
1092 qDimensionIndices.emplace_back(qindex);
1093 projection[0] = Qtransform[0][0];
1094 projection[1] = Qtransform[1][0];
1095 projection[2] = Qtransform[2][0];
1098 }
else if (
value.find(
"QDimension1") != std::string::npos) {
1104 qDimensionIndices.emplace_back(qindex);
1105 projection[0] = Qtransform[0][1];
1106 projection[1] = Qtransform[1][1];
1107 projection[2] = Qtransform[2][1];
1110 }
else if (
value.find(
"QDimension2") != std::string::npos) {
1116 qDimensionIndices.emplace_back(qindex);
1117 projection[0] = Qtransform[0][2];
1118 projection[1] = Qtransform[1][2];
1119 projection[2] = Qtransform[2][2];
1122 }
else if (
value.find(
"DeltaE") != std::string::npos) {
1138 for (
size_t i : qDimensionIndices) {
1139 auto mdHistoDimension = std::const_pointer_cast<Mantid::Geometry::MDHistoDimension>(
1140 std::dynamic_pointer_cast<const Mantid::Geometry::MDHistoDimension>(outputMDHWS->getDimension(i)));
1141 mdHistoDimension->setMDFrame(*hklFrame);
1144 auto ei = outputMDHWS->getExperimentInfo(0);
1145 ei->mutableRun().addProperty(
"W_MATRIX",
m_W.
getVector(),
true);
1163 if (tempBkgdDataWS) {
1168 std::vector<size_t> qDimensionIndices;
1169 uint16_t numexpinfo =
static_cast<uint16_t
>(
m_inputWS->getNumExperimentInfo());
1171 throw std::runtime_error(
"Symmetry operation number m_umSymops is wrong!");
1173 for (uint16_t i_expinfo = 0; i_expinfo < numexpinfo; ++i_expinfo) {
1175 auto rotMatrix =
m_inputWS->getExperimentInfo(i_expinfo)->run().getGoniometerMatrix();
1180 for (
const auto &so : symmetryOps) {
1187 Qtransform = rotMatrix *
m_UB * soMatrix *
m_W;
1189 Qtransform = rotMatrix * soMatrix *
m_W;
1193 double progress_fraction = 1. /
static_cast<double>(symmetryOps.size() * numexpinfo);
1195 createChildAlgorithm(
"BinMD", soIndex * 0.3 * progress_fraction, (soIndex + 1) * 0.3 * progress_fraction);
1197 binMD->setPropertyValue(
"AxisAligned",
"0");
1199 binMD->setProperty(
"TemporaryDataWorkspace", tempBkgdDataWS);
1200 binMD->setPropertyValue(
"NormalizeBasisVectors",
"0");
1203 binMD->setPropertyValue(
"OutputWorkspace",
getPropertyValue(
"OutputBackgroundDataWorkspace"));
1206 for (
const auto &p : parameters) {
1208 auto value = p.second;
1209 std::stringstream basisVector;
1210 std::vector<double> projection(
m_inputWS->getNumDims(), 0.);
1215 if (!basisVector.str().empty()) {
1217 for (
auto proji : projection) {
1218 proji = std::abs(proji) > 1e-10 ? proji : 0.0;
1219 basisVector <<
"," << proji;
1221 value = basisVector.str();
1224 binMD->setPropertyValue(key,
value);
1228 binMD->executeAsChildAlg();
1233 outputWS = binMD->getProperty(
"OutputWorkspace");
1234 tempBkgdDataWS = std::dynamic_pointer_cast<MDHistoWorkspace>(outputWS);
1235 tempBkgdDataWS->clearOriginalWorkspaces();
1236 tempBkgdDataWS->clearTransforms();
1239 auto outputMDHWS = std::dynamic_pointer_cast<MDHistoWorkspace>(outputWS);
1242 setQUnit(qDimensionIndices, outputMDHWS);
1270 return binMDEventWorkspace(monoNormInputWS,
"TemporaryNormalizationWorkspace",
"OutputNormalizationWorkspace",
1271 symmetryOps, parameters);
1290 const std::string &outputWSPropertyName,
1291 const std::vector<Geometry::SymmetryOperation> &symmetryOps,
1292 const std::map<std::string, std::string> ¶meters) {
1301 std::vector<size_t> qDimensionIndices;
1302 for (
const auto &so : symmetryOps) {
1308 Qtransform =
m_UB * soMatrix *
m_W;
1310 Qtransform = soMatrix *
m_W;
1314 double fraction = 1. /
static_cast<double>(symmetryOps.size());
1315 auto binMD =
createChildAlgorithm(
"BinMD", soIndex * 0.3 * fraction, (soIndex + 1) * 0.3 * fraction);
1316 binMD->setPropertyValue(
"AxisAligned",
"0");
1317 binMD->setProperty(
"InputWorkspace", ws);
1318 binMD->setProperty(
"TemporaryDataWorkspace", tempWS);
1319 binMD->setPropertyValue(
"NormalizeBasisVectors",
"0");
1320 binMD->setPropertyValue(
"OutputWorkspace",
getPropertyValue(outputWSPropertyName));
1323 for (
const auto &p : parameters) {
1324 auto value = p.second;
1325 std::stringstream basisVector;
1326 std::vector<double> projection(ws->getNumDims(), 0.);
1331 if (!basisVector.str().empty()) {
1333 for (
auto proji : projection) {
1334 proji = std::abs(proji) > 1e-10 ? proji : 0.0;
1335 basisVector <<
"," << proji;
1337 value = basisVector.str();
1340 binMD->setPropertyValue(p.first,
value);
1344 binMD->executeAsChildAlg();
1345 outputWS = binMD->getProperty(
"OutputWorkspace");
1349 tempWS = std::dynamic_pointer_cast<MDHistoWorkspace>(outputWS);
1350 tempWS->clearOriginalWorkspaces();
1351 tempWS->clearTransforms();
1355 auto outputMDHWS = std::dynamic_pointer_cast<MDHistoWorkspace>(outputWS);
1358 setQUnit(qDimensionIndices, outputMDHWS);
1374 const auto ¤tRun =
m_inputWS->getExperimentInfo(expInfoIndex)->run();
1376 std::vector<coord_t> otherDimValues;
1377 for (
size_t i = 3; i <
m_inputWS->getNumDims(); i++) {
1378 const auto dimension =
m_inputWS->getDimension(i);
1379 auto inputDimMin =
static_cast<float>(dimension->getMinimum());
1380 auto inputDimMax =
static_cast<float>(dimension->getMaximum());
1381 coord_t outputDimMin(0), outputDimMax(0);
1382 bool isIntegrated =
true;
1386 isIntegrated =
false;
1387 outputDimMin =
m_normWS->getDimension(j)->getMinimum();
1388 outputDimMax =
m_normWS->getDimension(j)->getMaximum();
1391 if (dimension->getName() ==
"DeltaE") {
1392 if ((inputDimMax < outputDimMin) || (inputDimMin > outputDimMax)) {
1393 skipNormalization =
true;
1398 otherDimValues.emplace_back(
value);
1399 if (value < inputDimMin || value > inputDimMax) {
1400 skipNormalization =
true;
1402 if ((!isIntegrated) && (value < outputDimMin || value > outputDimMax)) {
1403 skipNormalization =
true;
1407 return otherDimValues;
1416 m_hX.resize(hDim.getNBoundaries());
1417 for (
size_t i = 0; i <
m_hX.size(); ++i) {
1418 m_hX[i] = hDim.getX(i);
1421 m_kX.resize(kDim.getNBoundaries());
1422 for (
size_t i = 0; i <
m_kX.size(); ++i) {
1423 m_kX[i] = kDim.getX(i);
1427 m_lX.resize(lDim.getNBoundaries());
1428 for (
size_t i = 0; i <
m_lX.size(); ++i) {
1429 m_lX[i] = lDim.getX(i);
1435 m_eX.resize(eDim.getNBoundaries());
1436 for (
size_t i = 0; i <
m_eX.size(); ++i) {
1437 double temp =
m_Ei - eDim.getX(i);
1438 temp = std::max(temp, 0.);
1439 m_eX[i] = std::sqrt(energyToK * temp);
1478 std::vector<double> &xValues, std::vector<double> &yValues,
1482 auto intersectionsBegin = intersections.begin();
1484 xValues.resize(intersections.size());
1485 yValues.resize(intersections.size());
1486 auto x = xValues.begin();
1487 for (
auto it = intersectionsBegin; it != intersections.end(); ++it, ++
x) {
1510 std::vector<double> &yValues,
const size_t &vmdDims,
1511 std::vector<coord_t> &pos, std::vector<coord_t> &posNew,
1512 std::vector<std::atomic<signal_t>> &signalArray,
const double &solidBkgd,
1513 std::vector<std::atomic<signal_t>> &bkgdSignalArray) {
1515 auto intersectionsBegin = intersections.begin();
1516 for (
auto it = intersectionsBegin + 1; it != intersections.end(); ++it) {
1518 const auto &curIntSec = *it;
1519 const auto &prevIntSec = *(it - 1);
1527 delta = curIntSec[3] - prevIntSec[3];
1531 delta = (curIntSec[3] * curIntSec[3] - prevIntSec[3] * prevIntSec[3]) / energyToK;
1539 std::transform(curIntSec.data(), curIntSec.data() + vmdDims, prevIntSec.data(), pos.begin(),
1540 [](
const double rhs,
const double lhs) { return static_cast<coord_t>(0.5 * (rhs + lhs)); });
1546 auto k =
static_cast<size_t>(std::distance(intersectionsBegin, it));
1548 signal = (yValues[k] - yValues[k - 1]) * solid;
1550 bkgdSignal = (yValues[k] - yValues[k - 1]) * solidBkgd;
1555 pos[3] =
static_cast<coord_t>(
m_Ei - pos[3] * pos[3] / energyToK);
1558 signal = solid *
delta;
1560 bkgdSignal = solidBkgd *
delta;
1566 size_t linIndex =
m_normWS->getLinearIndexAtCoord(posNew.data());
1567 if (linIndex ==
size_t(-1))
1589 uint16_t expInfoIndex,
size_t soIndex) {
1590 const auto ¤tExptInfo = *(
m_inputWS->getExperimentInfo(expInfoIndex));
1591 std::vector<double> lowValues, highValues;
1592 auto *lowValuesLog =
dynamic_cast<VectorDoubleProperty *
>(currentExptInfo.getLog(
"MDNorm_low"));
1593 lowValues = (*lowValuesLog)();
1594 auto *highValuesLog =
dynamic_cast<VectorDoubleProperty *
>(currentExptInfo.getLog(
"MDNorm_high"));
1595 highValues = (*highValuesLog)();
1602 const double protonCharge = currentExptInfo.run().getProtonCharge();
1604 const double protonChargeBkgd =
1607 const auto &spectrumInfo = currentExptInfo.spectrumInfo();
1610 const auto ndets =
static_cast<int64_t
>(spectrumInfo.size());
1611 bool haveSA =
false;
1613 if (solidAngleWS !=
nullptr) {
1618 (haveSA) ? solidAngleWS->getDetectorIDToWorkspaceIndexMap() :
detid2index_map();
1624 std::vector<std::atomic<signal_t>> signalArray(
m_normWS->getNPoints());
1628 throw std::runtime_error(
"N points are different");
1630 std::vector<std::atomic<signal_t>> bkgdSignalArray(numNPoints);
1632 std::vector<std::array<double, 4>> intersections;
1633 std::vector<double> xValues, yValues;
1634 std::vector<coord_t> pos, posNew;
1638 auto progIndex =
static_cast<double>(soIndex + expInfoIndex *
m_numSymmOps);
1640 std::make_unique<API::Progress>(
this, 0.3 + progStep * progIndex, 0.3 + progStep * (1. + progIndex), ndets);
1644PRAGMA_OMP(parallel
for private(intersections, xValues, yValues, pos, posNew)
if (safe))
1645for (int64_t i = 0; i < ndets; i++) {
1649 if (!spectrumInfo.hasDetectors(i) || spectrumInfo.isMonitor(i) || spectrumInfo.isMasked(i)) {
1653 const auto &detector = spectrumInfo.detector(i);
1655 double phi = detector.getPhi();
1657 const auto detID = detector.getID();
1662 auto index = fluxDetToIdx.find(detID);
1663 if (
index != fluxDetToIdx.end()) {
1664 wsIdx =
index->second;
1674 if (intersections.empty())
1678 double solid = protonCharge;
1680 double bkgdSolid = protonChargeBkgd;
1682 double solid_angle_factor = solidAngleWS->y(solidAngDetToIdx.find(detID)->second)[0];
1684 solid = solid_angle_factor * protonCharge;
1686 bkgdSolid = solid_angle_factor * protonChargeBkgd;
1696 pos.resize(vmdDims + otherValues.size());
1697 std::copy(otherValues.begin(), otherValues.end(), pos.begin() + vmdDims);
1708 std::transform(signalArray.cbegin(), signalArray.cend(),
m_normWS->getSignalArray(),
m_normWS->mutableSignalArray(),
1709 [](
const std::atomic<signal_t> &a,
const signal_t &b) { return a + b; });
1712 std::transform(bkgdSignalArray.cbegin(), bkgdSignalArray.cend(),
m_bkgdNormWS->getSignalArray(),
1714 [](
const std::atomic<signal_t> &a,
const signal_t &b) { return a + b; });
1718 std::copy(signalArray.cbegin(), signalArray.cend(),
m_normWS->mutableSignalArray());
1721 std::copy(bkgdSignalArray.cbegin(), bkgdSignalArray.cend(),
m_bkgdNormWS->mutableSignalArray());
1739 V3D qout(sin(theta) * cos(phi), sin(theta) * sin(phi), cos(theta)), qin(0., 0., 1);
1741 qout = transform * qout;
1742 qin = transform * qin;
1747 double kfmin, kfmax, kimin, kimax;
1754 kimin = std::sqrt(energyToK *
m_Ei);
1756 kfmin = std::sqrt(energyToK * (
m_Ei - highvalue));
1757 kfmax = std::sqrt(energyToK * (
m_Ei - lowvalue));
1760 double hStart = qin.
X() * kimin - qout.X() * kfmin, hEnd = qin.
X() * kimax - qout.X() * kfmax;
1761 double kStart = qin.
Y() * kimin - qout.Y() * kfmin, kEnd = qin.
Y() * kimax - qout.Y() * kfmax;
1762 double lStart = qin.
Z() * kimin - qout.Z() * kfmin, lEnd = qin.
Z() * kimax - qout.Z() * kfmax;
1765 auto hNBins =
m_hX.size();
1766 auto kNBins =
m_kX.size();
1767 auto lNBins =
m_lX.size();
1768 auto eNBins =
m_eX.size();
1769 intersections.clear();
1770 intersections.reserve(hNBins + kNBins + lNBins + eNBins + 2);
1773 if (
fabs(hStart - hEnd) > eps) {
1774 double fmom = (kfmax - kfmin) / (hEnd - hStart);
1775 double fk = (kEnd - kStart) / (hEnd - hStart);
1776 double fl = (lEnd - lStart) / (hEnd - hStart);
1777 for (
size_t i = 0; i < hNBins; i++) {
1778 double hi =
m_hX[i];
1779 if (((hStart - hi) * (hEnd - hi) < 0)) {
1783 double ki = fk * (hi - hStart) + kStart;
1784 double li = fl * (hi - hStart) + lStart;
1785 if ((ki >=
m_kX[0]) && (ki <=
m_kX[kNBins - 1]) && (li >=
m_lX[0]) && (li <=
m_lX[lNBins - 1])) {
1786 double momi = fmom * (hi - hStart) + kfmin;
1787 intersections.push_back({{hi, ki, li, momi}});
1793 if (
fabs(kStart - kEnd) > eps) {
1794 double fmom = (kfmax - kfmin) / (kEnd - kStart);
1795 double fh = (hEnd - hStart) / (kEnd - kStart);
1796 double fl = (lEnd - lStart) / (kEnd - kStart);
1797 for (
size_t i = 0; i < kNBins; i++) {
1798 double ki =
m_kX[i];
1799 if (((kStart - ki) * (kEnd - ki) < 0)) {
1803 double hi = fh * (ki - kStart) + hStart;
1804 double li = fl * (ki - kStart) + lStart;
1805 if ((hi >=
m_hX[0]) && (hi <=
m_hX[hNBins - 1]) && (li >=
m_lX[0]) && (li <=
m_lX[lNBins - 1])) {
1806 double momi = fmom * (ki - kStart) + kfmin;
1807 intersections.push_back({{hi, ki, li, momi}});
1814 if (
fabs(lStart - lEnd) > eps) {
1815 double fmom = (kfmax - kfmin) / (lEnd - lStart);
1816 double fh = (hEnd - hStart) / (lEnd - lStart);
1817 double fk = (kEnd - kStart) / (lEnd - lStart);
1819 for (
size_t i = 0; i < lNBins; i++) {
1820 double li =
m_lX[i];
1821 if (((lStart - li) * (lEnd - li) < 0)) {
1822 double hi = fh * (li - lStart) + hStart;
1823 double ki = fk * (li - lStart) + kStart;
1824 if ((hi >=
m_hX[0]) && (hi <=
m_hX[hNBins - 1]) && (ki >=
m_kX[0]) && (ki <=
m_kX[kNBins - 1])) {
1825 double momi = fmom * (li - lStart) + kfmin;
1826 intersections.push_back({{hi, ki, li, momi}});
1833 for (
size_t i = 0; i < eNBins; i++) {
1834 double kfi =
m_eX[i];
1835 if ((kfi - kfmin) * (kfi - kfmax) <= 0) {
1836 double h = qin.
X() * kimin - qout.X() * kfi;
1837 double k = qin.
Y() * kimin - qout.Y() * kfi;
1838 double l = qin.
Z() * kimin - qout.Z() * kfi;
1839 if ((h >=
m_hX[0]) && (h <=
m_hX[hNBins - 1]) && (k >=
m_kX[0]) && (k <=
m_kX[kNBins - 1]) && (l >=
m_lX[0]) &&
1840 (l <=
m_lX[lNBins - 1])) {
1841 intersections.push_back({{h, k, l, kfi}});
1848 if ((hStart >=
m_hX[0]) && (hStart <=
m_hX[hNBins - 1]) && (kStart >=
m_kX[0]) && (kStart <=
m_kX[kNBins - 1]) &&
1849 (lStart >=
m_lX[0]) && (lStart <=
m_lX[lNBins - 1])) {
1850 intersections.push_back({{hStart, kStart, lStart, kfmin}});
1852 if ((hEnd >=
m_hX[0]) && (hEnd <=
m_hX[hNBins - 1]) && (kEnd >=
m_kX[0]) && (kEnd <=
m_kX[kNBins - 1]) &&
1853 (lEnd >=
m_lX[0]) && (lEnd <=
m_lX[lNBins - 1])) {
1854 intersections.push_back({{hEnd, kEnd, lEnd, kfmax}});
1858 std::stable_sort(intersections.begin(), intersections.end(), compareMomentum);
1870 size_t sp, std::vector<double> &yValues) {
1871 assert(xValues.size() == yValues.size());
1874 const auto &xData = integrFlux.
x(sp);
1875 const double xStart = xData.front();
1876 const double xEnd = xData.back();
1881 const auto &yData = integrFlux.
y(sp);
1882 size_t spSize = yData.size();
1884 const double yMin = 0.0;
1885 const double yMax = yData.back();
1887 size_t nData = xValues.size();
1889 if (xValues[nData - 1] < xStart) {
1890 std::fill(yValues.begin(), yValues.end(), yMin);
1895 if (xValues[0] > xEnd) {
1896 std::fill(yValues.begin(), yValues.end(), yMax);
1902 while (i < nData - 1 && xValues[i] < xStart) {
1907 for (; i < nData; i++) {
1909 if (j >= spSize - 1) {
1912 double xi = xValues[i];
1913 while (j < spSize - 1 && xi > xData[j])
1916 if (xi == xData[j]) {
1917 yValues[i] = yData[j];
1918 }
else if (j == spSize - 1) {
1923 double x0 = xData[j - 1];
1924 double x1 = xData[j];
1925 double y0 = yData[j - 1];
1926 double y1 = yData[j];
1927 yValues[i] = y0 + (y1 - y0) * (xi - x0) / (x1 - x0);
#define DECLARE_ALGORITHM(classname)
const std::vector< double > & rhs
double value
The value of the point.
std::map< DeltaEMode::Type, std::string > index
#define PARALLEL_START_INTERRUPT_REGION
Begins a block to skip processing is the algorithm has been interupted Note the end of the block if n...
#define PARALLEL_END_INTERRUPT_REGION
Ends a block to skip processing is the algorithm has been interupted Note the start of the block if n...
#define PRAGMA_OMP(expression)
#define PARALLEL_CHECK_INTERRUPT_REGION
Adds a check after a Parallel region to see if it was interupted.
void declareProperty(std::unique_ptr< Kernel::Property > p, const std::string &doc="") override
Add a property to the list of managed properties.
std::string getPropertyValue(const std::string &name) const override
Get the value of a property as a string.
TypedValue getProperty(const std::string &name) const override
Get the value of a property.
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.
A validator which provides a TENTATIVE check that a workspace contains common bins in each spectrum.
Kernel::IValidator_sptr clone() const override
Clone the current state.
This class is shared by a few Workspace types and holds information related to a particular experimen...
const Run & run() const
Run details object access.
A validator which checks that a workspace has a valid instrument.
Base MatrixWorkspace Abstract Class.
const HistogramData::HistogramX & x(const size_t index) const
const HistogramData::HistogramY & y(const size_t index) const
const Kernel::Matrix< double > & getGoniometerMatrix() const
Retrieve the first goniometer rotation matrix.
A property class for workspaces.
std::unique_ptr< MDHistoWorkspace > clone() const
Returns a clone of the workspace.
static const std::string HKLName
Input argument type for MDFrameFactory chainable factory.
Class to implement UB matrix.
void setUB(const Kernel::DblMatrix &newUB)
Sets the UB matrix and recalculates lattice parameters.
static const std::string QLabName
static const std::string QSampleName
Crystallographic symmetry operations are composed of a rotational component, which is represented by ...
Kernel::V3D transformHKL(const Kernel::V3D &hkl) const
Transforms an index triplet hkl.
double a(int nd) const
Get lattice parameter a1-a3 as function of index (0-2)
double c() const
Get lattice parameter.
double b() const
Get lattice parameter.
Support for a property that holds an array of values.
Exception for errors associated with the instrument definition.
Records the filename, the description of failure and the line on which it happened.
IPropertyManager * setProperty(const std::string &name, const T &value)
Templated method to set the value of a PropertyWithValue.
void setPropertySettings(const std::string &name, std::unique_ptr< IPropertySettings const > settings)
Add a PropertySettings instance to the chain of settings for a given property.
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 error(const std::string &msg)
Logs at error level.
void warning(const std::string &msg)
Logs at warning level.
T determinant() const
Calculate the determinant.
T Invert()
LU inversion routine.
void multiplyPoint(const std::vector< T > &in, std::vector< T > &out) const
Multiply M*Vec.
std::vector< T > getVector() const
size_t numRows() const
Return the number of rows in the matrix.
void setColumn(const size_t nCol, const std::vector< T > &newCol)
Matrix< T > & Transpose()
Transpose the matrix.
The concrete, templated class for properties.
Base class for properties.
virtual std::string value() const =0
Returns the value of the property as a string.
static const UnitLabel RLU
Reciprocal lattice units.
constexpr double X() const noexcept
Get x.
constexpr double Y() const noexcept
Get y.
constexpr double Z() const noexcept
Get z.
MDNormalization : Bin single crystal diffraction or direct geometry inelastic data and calculate the ...
size_t m_numSymmOps
number of symmetry operations
bool m_monochromatic
Flag indicating a pre-computed MonoSCDNormalizationWorkspace was provided (monochromatic single cryst...
Mantid::Kernel::DblMatrix m_W
W matrix.
void calcSingleDetectorNorm(const std::vector< std::array< double, 4 > > &intersections, const double &solid, std::vector< double > &yValues, const size_t &vmdDims, std::vector< coord_t > &pos, std::vector< coord_t > &posNew, std::vector< std::atomic< signal_t > > &signalArray, const double &solidBkgd, std::vector< std::atomic< signal_t > > &bkgdSignalArray)
Calculate the normalization among intersections on a single detector in 1 specific SpectrumInfo/Exper...
Mantid::Kernel::Matrix< coord_t > m_transformation
matrix for transforming from intersections to positions in the normalization workspace
bool m_dEIntegrated
Flag to indicate that the energy dimension is integrated.
DataObjects::MDHistoWorkspace_sptr binBackgroundWS(const std::vector< Geometry::SymmetryOperation > &symmetryOps)
Bin(MD) input Background workspace.
std::string QDimensionName(std::vector< double > projection)
Get the dimension name when using reciprocal lattice units.
bool m_diffraction
Flag indicating if the input workspace is from diffraction.
void createNormalizationWS(const DataObjects::MDHistoWorkspace &dataWS)
Create & cached the normalization workspace.
void exec() override
Execute the algorithm.
bool m_accumulate
Flag to accumulate normalization.
void calcIntegralsForIntersections(const std::vector< double > &xValues, const API::MatrixWorkspace &integrFlux, size_t sp, std::vector< double > &yValues)
Linearly interpolate between the points in integrFlux at xValues and save the results in yValues.
std::vector< double > m_Q0Basis
The projection vectors.
DataObjects::MDHistoWorkspace_sptr m_normWS
Normalization workspace.
const std::string summary() const override
Algorithm's summary for use in the GUI and help.
std::map< std::string, std::string > getBinParameters()
Calculate binning parameters.
API::IMDWorkspace_sptr divideMD(const API::IMDHistoWorkspace_sptr &lhs, const API::IMDHistoWorkspace_sptr &rhs, const std::string &outputwsname, const double &startProgress, const double &endProgress)
const std::string category() const override
Algorithm's category for identification.
std::vector< double > m_lX
std::vector< double > m_kX
std::vector< coord_t > getValuesFromOtherDimensions(bool &skipNormalization, uint16_t expInfoIndex=0) const
Retrieve logged values from non-HKL dimensions.
void setQUnit(const std::vector< size_t > &qDimensionIndices, const Mantid::DataObjects::MDHistoWorkspace_sptr &outputMDHWS)
Set the output Frame to HKL.
DataObjects::MDHistoWorkspace_sptr m_bkgdNormWS
void calculateIntersections(std::vector< std::array< double, 4 > > &intersections, const double theta, const double phi, const Kernel::DblMatrix &transform, double lowvalue, double highvalue)
Calculate the points of intersection for the given detector with cuboid surrounding the detector posi...
API::IMDEventWorkspace_sptr m_inputWS
Input workspace.
double m_Ei
Cached value of incident energy dor direct geometry.
size_t m_hIdx
index of h,k,l, dE dimensions in the output workspaces
Mantid::Kernel::DblMatrix m_UB
UB matrix.
std::vector< double > m_Q1Basis
void validateBinningForTemporaryDataWorkspace(const std::map< std::string, std::string > &, const Mantid::API::IMDHistoWorkspace_sptr &)
Validates the TemporaryDataWorkspace has the same binning as the input binning parameters.
Mantid::Kernel::DblMatrix buildSymmetryMatrix(const Geometry::SymmetryOperation &so)
build symmetry matrix
Kernel::V3D m_beamDir
Beam direction.
size_t m_numExptInfos
number of experimentInfo objects
void calcDiffractionIntersectionIntegral(std::vector< std::array< double, 4 > > &intersections, std::vector< double > &xValues, std::vector< double > &yValues, const API::MatrixWorkspace &integrFlux, const size_t &wsIdx)
Calculate the diffraction MDE's intersection integral of a certain detector/spectru.
DataObjects::MDHistoWorkspace_sptr binMonoSCDNormalizationWS(const std::vector< Geometry::SymmetryOperation > &symmetryOps)
Bin(MD) MonoSCDNormalizationWorkspace (monochromatic single crystal diffraction)
std::string QDimensionNameQSample(int i)
Get the dimension name when not using reciprocal lattice units.
void cacheDimensionXValues()
Stores the X values from each H,K,L, and optionally DeltaE dimension as member variables.
std::vector< double > m_hX
cached X values along dimensions h,k,l. dE
const std::string name() const override
Algorithms name for identification.
std::vector< double > m_Q2Basis
bool m_isRLU
flag for reciprocal lattice units
DataObjects::MDHistoWorkspace_sptr binInputWS(const std::vector< Geometry::SymmetryOperation > &symmetryOps)
Bin(MD) input MDE workspace.
void calculateNormalization(const std::vector< coord_t > &otherValues, const Geometry::SymmetryOperation &so, uint16_t expInfoIndex, size_t soIndex)
Computed the normalization for the input workspace.
std::string convention
ki-kf for Inelastic convention; kf-ki for Crystallography convention
DataObjects::MDHistoWorkspace_sptr binMDEventWorkspace(const API::IMDEventWorkspace_sptr &ws, const std::string &temporaryWSPropertyName, const std::string &outputWSPropertyName, const std::vector< Geometry::SymmetryOperation > &symmetryOps, const std::map< std::string, std::string > ¶meters)
Bin(MD), per symmetry operation, an MDEventWorkspace using pre-computed bin parameters.
Mantid::Kernel::DblMatrix calQTransform(const Mantid::API::ExperimentInfo ¤tExpInfo, const Geometry::SymmetryOperation &so)
Calculate QTransform = (R * UB * SymmetryOperation * m_W)^-1.
std::map< std::string, std::string > validateInputs() override final
Validate the input workspace.
void determineBasisVector(const size_t &qindex, const std::string &value, const Kernel::DblMatrix &Qtransform, std::vector< double > &projection, std::stringstream &basisVector, std::vector< size_t > &qDimensionIndices)
MDNorm::determineBasisVector.
int version() const override
Algorithm's version for identification.
void init() override
Initialize the algorithm's properties.
API::IMDEventWorkspace_sptr m_backgroundWS
Input background workspace.
std::vector< double > m_eX
void createBackgroundNormalizationWS(const DataObjects::MDHistoWorkspace &dataWS)
Kernel::V3D m_samplePos
Sample position.
std::shared_ptr< IMDEventWorkspace > IMDEventWorkspace_sptr
Shared pointer to Mantid::API::IMDEventWorkspace.
std::shared_ptr< Workspace > Workspace_sptr
shared pointer to Mantid::API::Workspace
std::shared_ptr< const MatrixWorkspace > MatrixWorkspace_const_sptr
shared pointer to the matrix workspace base class (const version)
std::shared_ptr< IMDHistoWorkspace > IMDHistoWorkspace_sptr
shared pointer to Mantid::API::IMDHistoWorkspace
std::shared_ptr< IMDWorkspace > IMDWorkspace_sptr
Shared pointer to the IMDWorkspace base class.
@ NoNormalization
Don't normalize = return raw counts.
std::shared_ptr< MDHistoWorkspace > MDHistoWorkspace_sptr
A shared pointer to a MDHistoWorkspace.
std::unique_ptr< MDFrame > MDFrame_uptr
MDFrameFactory_uptr MANTID_GEOMETRY_DLL makeMDFrameFactoryChain()
Make a complete factory chain.
std::string toString(const T &value)
Convert a number to a string.
template DLLExport std::vector< size_t > splitStringIntoVector< size_t >(std::string listString, const std::string &separator)
template DLLExport std::vector< double > splitStringIntoVector< double >(std::string listString, const std::string &separator)
std::enable_if< std::is_pointer< Arg >::value, bool >::type threadSafe(Arg workspace)
Thread-safety check Checks the workspace to ensure it is suitable for multithreaded access.
MANTID_KERNEL_DLL V3D normalize(V3D v)
Normalizes a V3D.
void AtomicOp(std::atomic< T > &f, T d, BinaryOp op)
Uses std::compare_exchange_weak to update the atomic value f = op(f, d) Used to improve parallel scal...
Mantid::Kernel::Matrix< double > DblMatrix
Kernel::PropertyWithValue< std::vector< double > > VectorDoubleProperty
static constexpr double NeutronMass
Mass of the neutron in kg.
static constexpr double h
Planck constant in J*s.
static constexpr double meV
1 meV in Joules.
float coord_t
Typedef for the data type to use for coordinate axes in MD objects such as MDBox, MDEventWorkspace,...
std::unordered_map< detid_t, size_t > detid2index_map
Map with key = detector ID, value = workspace index.
double signal_t
Typedef for the signal recorded in a MDBox, etc.
@ Input
An input workspace.
@ Output
An output workspace.