44 : m_hmin(0.f), m_hmax(0.f), m_kmin(0.f), m_kmax(0.f), m_lmin(0.f), m_lmax(0.f), m_dEmin(0.f), m_dEmax(0.f),
45 m_Ei(0.), m_ki(0.), m_kfmin(0.), m_kfmax(0.), m_hIntegrated(false), m_kIntegrated(false), m_lIntegrated(false),
46 m_dEIntegrated(false), m_hX(), m_kX(), m_lX(), m_eX(), m_hIdx(-1), m_kIdx(-1), m_lIdx(-1), m_eIdx(-1),
47 m_rubw(3, 3), m_normWS() {}
98 std::make_shared<InstrumentValidator>()),
99 "An input workspace.");
101 auto mustBe3D = std::make_shared<ArrayLengthValidator<double>>(3);
102 auto mustBePositive = std::make_shared<BoundedValidator<double>>();
103 mustBePositive->setLower(0.0);
105 std::vector<double> Q1(3, 0.), Q2(3, 0), Q3(3, 0);
110 "Q1 projection direction in the x,y,z format. Q1, Q2, Q3 "
111 "must not be coplanar");
113 "Q2 projection direction in the x,y,z format. Q1, Q2, Q3 "
114 "must not be coplanar");
116 "Q3 projection direction in the x,y,z format. Q1, Q2, Q3 "
117 "must not be coplanar");
120 "Incident energy. If set, will override Ei in the input workspace");
122 std::vector<std::string> options{
"Q1",
"Q2",
"Q3",
"DeltaE"};
124 for (
int i = 1; i <= 4; i++) {
125 std::string dim(
"Dimension");
126 dim += boost::lexical_cast<std::string>(i);
127 declareProperty(dim, options[i - 1], std::make_shared<StringListValidator>(options),
128 "Dimension to bin or integrate");
132 dim +
" step size. If empty the dimension will be "
133 "integrated between minimum and maximum values");
137 "A name for the output data MDHistoWorkspace.");
147 convention = Kernel::ConfigService::Instance().getString(
"Q.convention");
149 const auto &detectorInfo = inputWS->detectorInfo();
150 std::vector<double> tt, phi;
151 for (
size_t i = 0; i < detectorInfo.size(); ++i) {
152 if (!detectorInfo.isMasked(i) && !detectorInfo.isMonitor(i)) {
153 tt.emplace_back(detectorInfo.twoTheta(i,
V3D(0, 0, 0),
V3D(0, 0, 1)));
154 phi.emplace_back(detectorInfo.phi(i));
158 double ttmax = *(std::max_element(tt.begin(), tt.end()));
163 if (inputWS->run().hasProperty(
"Ei")) {
165 m_Ei = boost::lexical_cast<double>(eiprop->
value());
167 throw std::invalid_argument(
"Ei stored in the workspace is not positive");
170 throw std::invalid_argument(
"Could not find Ei in the workspace. Please enter a positive value");
177 double q1min(0.), q1max(0.), q2min(0.), q2max(0.), q3min(0.), q3max(0.);
178 double q1step(0.), q2step(0.), q3step(0.), dEstep(0.);
179 size_t q1NumBins = 1, q2NumBins = 1, q3NumBins = 1, dENumBins = 1;
180 for (
int i = 1; i <= 4; i++) {
181 std::string dim(
"Dimension");
182 dim += boost::lexical_cast<std::string>(i);
184 if (dimensioni ==
"Q1") {
185 affineMat[i - 1][0] = 1.;
191 if (dimensioni ==
"Q2") {
192 affineMat[i - 1][1] = 1.;
198 if (dimensioni ==
"Q3") {
199 affineMat[i - 1][2] = 1.;
205 if (dimensioni ==
"DeltaE") {
206 affineMat[i - 1][3] = 1.;
225 if (dEstep *
static_cast<double>(dENumBins) +
m_dEmin <
m_dEmax) {
235 throw std::invalid_argument(
"Please make sure each dimension is selected only once.");
252 double Qmax = QmaxTemp;
259 if (inputWS->run().getGoniometer().isDefined()) {
260 gon = inputWS->run().getGoniometerMatrix();
265 if (inputWS->sample().hasOrientedLattice()) {
266 UB = inputWS->sample().getOrientedLattice().getUB();
271 std::vector<double> Q1Basis =
getProperty(
"Q1Basis");
272 std::vector<double> Q2Basis =
getProperty(
"Q2Basis");
273 std::vector<double> Q3Basis =
getProperty(
"Q3Basis");
278 m_rubw = gon * UB * W * (2.0 * M_PI);
297 if (q1min >= q1max) {
298 throw std::invalid_argument(
"Q1max has to be greater than Q1min");
303 q1NumBins =
static_cast<size_t>((q1max - q1min) / q1step);
304 if (q1step *
static_cast<double>(q1NumBins) + q1min < q1max) {
306 q1max = q1step *
static_cast<double>(q1NumBins) + q1min;
316 if (q2min >= q2max) {
317 throw std::invalid_argument(
"Q2max has to be greater than Q2min");
322 q2NumBins =
static_cast<size_t>((q2max - q2min) / q2step);
323 if (q2step *
static_cast<double>(q2NumBins) + q2min < q2max) {
325 q2max = q2step *
static_cast<double>(q2NumBins) + q2min;
335 if (q3min >= q3max) {
336 throw std::invalid_argument(
"Q3max has to be greater than Q3min");
341 q3NumBins =
static_cast<size_t>((q3max - q3min) / q3step);
342 if (q3step *
static_cast<double>(q3NumBins) + q3min < q3max) {
344 q3max = q3step *
static_cast<double>(q3NumBins) + q3min;
349 std::vector<Mantid::Geometry::MDHistoDimension_sptr> binDimensions;
356 auto out1 = std::make_shared<MDHistoDimension>(
"Q1",
"Q1", frame1,
static_cast<coord_t>(q1min),
357 static_cast<coord_t>(q1max), q1NumBins);
358 auto out2 = std::make_shared<MDHistoDimension>(
"Q2",
"Q2", frame2,
static_cast<coord_t>(q2min),
359 static_cast<coord_t>(q2max), q2NumBins);
360 auto out3 = std::make_shared<MDHistoDimension>(
"Q3",
"Q3", frame3,
static_cast<coord_t>(q3min),
361 static_cast<coord_t>(q3max), q3NumBins);
362 auto out4 = std::make_shared<MDHistoDimension>(
"DeltaE",
"DeltaE", frame4,
static_cast<coord_t>(
m_dEmin),
365 for (
size_t row = 0; row <= 3; row++) {
366 if (affineMat[row][0] == 1.) {
367 binDimensions.emplace_back(out1);
369 if (affineMat[row][1] == 1.) {
370 binDimensions.emplace_back(out2);
372 if (affineMat[row][2] == 1.) {
373 binDimensions.emplace_back(out3);
375 if (affineMat[row][3] == 1.) {
376 binDimensions.emplace_back(out4);
380 m_normWS = std::make_shared<MDHistoWorkspace>(binDimensions);
386 const auto ndets =
static_cast<int64_t
>(tt.size());
389 for (int64_t i = 0; i < ndets; i++) {
392 if (intersections.empty())
394 auto intersectionsBegin = intersections.begin();
395 for (
auto it = intersectionsBegin + 1; it != intersections.end(); ++it) {
396 const auto &curIntSec = *it;
397 const auto &prevIntSec = *(it - 1);
399 double delta = curIntSec[3] - prevIntSec[3];
403 std::vector<coord_t> pos(4);
404 std::transform(curIntSec.getBareArray(), curIntSec.getBareArray() + 4, prevIntSec.getBareArray(), pos.begin(),
405 [](
const double lhs,
const double rhs) { return static_cast<coord_t>(0.5 * (lhs + rhs)); });
407 pos[3] =
static_cast<coord_t>(
m_Ei - pos[3] * pos[3] / energyToK);
409 std::vector<coord_t> posNew = affineMat * pos;
410 size_t linIndex =
m_normWS->getLinearIndexAtCoord(posNew.data());
411 if (linIndex ==
size_t(-1))
429 V3D qout(sin(theta) * cos(phi), sin(theta) * sin(phi), cos(theta)), qin(0., 0.,
m_ki);
436 double hStart = qin.
X() - qout.X() *
m_kfmin, hEnd = qin.
X() - qout.X() *
m_kfmax;
437 double kStart = qin.
Y() - qout.Y() *
m_kfmin, kEnd = qin.
Y() - qout.Y() *
m_kfmax;
438 double lStart = qin.
Z() - qout.Z() *
m_kfmin, lEnd = qin.
Z() - qout.Z() *
m_kfmax;
440 auto hNBins =
m_hX.size();
441 auto kNBins =
m_kX.size();
442 auto lNBins =
m_lX.size();
443 auto eNBins =
m_eX.size();
444 std::vector<Kernel::VMD> intersections;
445 intersections.reserve(hNBins + kNBins + lNBins + eNBins + 8);
448 if (
fabs(hStart - hEnd) > eps) {
450 double fk = (kEnd - kStart) / (hEnd - hStart);
451 double fl = (lEnd - lStart) / (hEnd - hStart);
453 for (
size_t i = 0; i < hNBins; i++) {
455 if ((hi >=
m_hmin) && (hi <=
m_hmax) && ((hStart - hi) * (hEnd - hi) < 0)) {
459 double ki = fk * (hi - hStart) + kStart;
460 double li = fl * (hi - hStart) + lStart;
462 double momi = fmom * (hi - hStart) +
m_kfmin;
463 intersections.emplace_back(hi, ki, li, momi);
472 double khmin = fk * (
m_hmin - hStart) + kStart;
473 double lhmin = fl * (
m_hmin - hStart) + lStart;
475 intersections.emplace_back(
m_hmin, khmin, lhmin, momhMin);
481 double khmax = fk * (
m_hmax - hStart) + kStart;
482 double lhmax = fl * (
m_hmax - hStart) + lStart;
484 intersections.emplace_back(
m_hmax, khmax, lhmax, momhMax);
490 if (
fabs(kStart - kEnd) > eps) {
492 double fh = (hEnd - hStart) / (kEnd - kStart);
493 double fl = (lEnd - lStart) / (kEnd - kStart);
495 for (
size_t i = 0; i < kNBins; i++) {
497 if ((ki >=
m_kmin) && (ki <=
m_kmax) && ((kStart - ki) * (kEnd - ki) < 0)) {
501 double hi = fh * (ki - kStart) + hStart;
502 double li = fl * (ki - kStart) + lStart;
504 double momi = fmom * (ki - kStart) +
m_kfmin;
505 intersections.emplace_back(hi, ki, li, momi);
513 double hkmin = fh * (
m_kmin - kStart) + hStart;
514 double lkmin = fl * (
m_kmin - kStart) + lStart;
516 intersections.emplace_back(hkmin,
m_kmin, lkmin, momkMin);
522 double hkmax = fh * (
m_kmax - kStart) + hStart;
523 double lkmax = fl * (
m_kmax - kStart) + lStart;
525 intersections.emplace_back(hkmax,
m_kmax, lkmax, momkMax);
531 if (
fabs(lStart - lEnd) > eps) {
533 double fh = (hEnd - hStart) / (lEnd - lStart);
534 double fk = (kEnd - kStart) / (lEnd - lStart);
536 for (
size_t i = 0; i < lNBins; i++) {
538 if ((li >=
m_lmin) && (li <=
m_lmax) && ((lStart - li) * (lEnd - li) < 0)) {
539 double hi = fh * (li - lStart) + hStart;
540 double ki = fk * (li - lStart) + kStart;
542 double momi = fmom * (li - lStart) +
m_kfmin;
543 intersections.emplace_back(hi, ki, li, momi);
551 double hlmin = fh * (
m_lmin - lStart) + hStart;
552 double klmin = fk * (
m_lmin - lStart) + kStart;
554 intersections.emplace_back(hlmin, klmin,
m_lmin, momlMin);
560 double hlmax = fh * (
m_lmax - lStart) + hStart;
561 double klmax = fk * (
m_lmax - lStart) + kStart;
563 intersections.emplace_back(hlmax, klmax,
m_lmax, momlMax);
570 for (
size_t i = 0; i < eNBins; i++) {
571 double kfi =
m_eX[i];
573 double h = qin.
X() - qout.X() * kfi;
574 double k = qin.
Y() - qout.Y() * kfi;
575 double l = qin.
Z() - qout.Z() * kfi;
577 intersections.emplace_back(h, k, l, kfi);
586 intersections.emplace_back(hStart, kStart, lStart,
m_kfmin);
590 intersections.emplace_back(hEnd, kEnd, lEnd,
m_kfmax);
594 using IterType = std::vector<Mantid::Kernel::VMD>::iterator;
595 std::stable_sort<IterType, bool (*)(const Mantid::Kernel::VMD &, const Mantid::Kernel::VMD &)>(
596 intersections.begin(), intersections.end(), compareMomentum);
598 return intersections;