Mantid
Loading...
Searching...
No Matches
SANSCollimationLengthEstimator.cpp
Go to the documentation of this file.
1// Mantid Repository : https://github.com/mantidproject/mantid
2//
3// Copyright © 2018 ISIS Rutherford Appleton Laboratory UKRI,
4// NScD Oak Ridge National Laboratory, European Spallation Source,
5// Institut Laue - Langevin & CSNS, Institute of High Energy Physics, CAS
6// SPDX - License - Identifier: GPL - 3.0 +
9#include "MantidAPI/Run.h"
11#include "MantidKernel/Logger.h"
14#include "MantidKernel/V3D.h"
15#include "boost/lexical_cast.hpp"
16
17namespace {
18Mantid::Kernel::Logger g_log("SANSCollimationLengthEstimator");
19
25bool checkForDouble(const std::string &val) {
26 auto isDouble = false;
27 try {
28 boost::lexical_cast<double>(val);
29 isDouble = true;
30 } catch (boost::bad_lexical_cast const &) {
31 }
32 return isDouble;
33}
34} // namespace
35
36namespace Mantid::Algorithms {
37
38using namespace Kernel;
39using namespace API;
40
47 // If the instrument does not have a correction specified then set the length
48 // to 4
49 const double defaultLColim = 4.0;
50 auto collimationLengthID = "collimation-length-correction";
51
52 if (!workspace->getInstrument()->hasParameter(collimationLengthID)) {
53 g_log.error("Error in SANSCollimtionLengthEstimator: The instrument "
54 "parameter file does not contain a collimation length "
55 "correction,"
56 "a default of 4 is provided. Please update the instrument "
57 "parameter file.");
58 return defaultLColim;
59 }
60
61 // Get the L1 length
62 const V3D samplePos = workspace->getInstrument()->getSample()->getPos();
63 const V3D sourcePos = workspace->getInstrument()->getSource()->getPos();
64 const V3D SSD = samplePos - sourcePos;
65 const double L1 = SSD.norm();
66
67 auto collimationLengthCorrection = workspace->getInstrument()->getNumberParameter(collimationLengthID);
68
69 if (workspace->getInstrument()->hasParameter("special-default-collimation-length-method")) {
70 auto specialCollimationMethod =
71 workspace->getInstrument()->getStringParameter("special-default-collimation-length-method");
72 if (specialCollimationMethod[0] == "guide") {
73 try {
74 return getCollimationLengthWithGuides(workspace, L1, collimationLengthCorrection[0]);
75 } catch (std::invalid_argument &ex) {
76 g_log.notice() << ex.what();
77 g_log.notice() << "SANSCollimationLengthEstimator: Not using any guides";
78 return L1 - collimationLengthCorrection[0];
79 }
80 } else {
81 throw std::invalid_argument("Error in SANSCollimationLengthEstimator: "
82 "Unknown special collimation method.");
83 }
84 }
85 return L1 - collimationLengthCorrection[0];
86}
87
100 const double L1,
101 const double collimationLengthCorrection) const {
102 auto lCollim = L1 - collimationLengthCorrection;
103
104 // Make sure we have guide cutoffs
105 if (!inOutWS->getInstrument()->hasParameter("guide-cutoff")) {
106 throw std::invalid_argument("TOFSANSResolutionByPixel: Could not get a "
107 "GuideCutoff from the instrument");
108 }
109
110 // Make sure we have a defined number of guidess
111 if (!inOutWS->getInstrument()->hasParameter("number-of-guides")) {
112 throw std::invalid_argument("TOFSANSResolutionByPixel: Could not get the number of guides.");
113 }
114
115 // Make sure we have a guide increment specified
116 if (!inOutWS->getInstrument()->hasParameter("guide-collimation-length-increment")) {
117 throw std::invalid_argument("TOFSANSResolutionByPixel: Could not find a guide increment.");
118 }
119
120 auto numberOfGuides = static_cast<unsigned int>(inOutWS->getInstrument()->getNumberParameter("number-of-guides")[0]);
121 auto guideIncrement = inOutWS->getInstrument()->getNumberParameter("guide-collimation-length-increment")[0];
122
123 // Make sure that all guides are there. They are labelled as Guide1, Guide2,
124 // Guide3, ...
125 // The entry is a numeric TimeSeriesProperty or a numeric entry, if something
126 // else then default
127 std::vector<double> guideValues;
128 for (unsigned int i = 1; i <= numberOfGuides; i++) {
129 auto guideName = "Guide" + std::to_string(i);
130 if (inOutWS->run().hasProperty(guideName)) {
131 auto guideValue = getGuideValue(inOutWS->run().getProperty(guideName));
132 guideValues.emplace_back(guideValue);
133 } else {
134 throw std::invalid_argument("TOFSANSResolutionByPixel: Mismatch between "
135 "specified number of Guides and actual "
136 "Guides.");
137 }
138 }
139
140 auto guideCutoff = inOutWS->getInstrument()->getNumberParameter("guide-cutoff")[0];
141 // Go through the guides and check in an alternate manner if the guide is
142 // smaller
143 // or larger than the cut off value. We start at the last guide and check that
144 // it is
145 // larger than the cutoff, the next one has to be smaller and so on. For
146 // example in pseudocode
147 // If Guide5 > 130: LCollim+=2.0 else break;
148 // If Guide4 < 130: LCollim+=2.0 else break;
149 // If Guide3 > 130: LCollim+=2.0 else break;
150 // ...
151 unsigned int largerSmallerCounter = 0;
152 for (auto it = guideValues.rbegin(); it != guideValues.rend(); ++it) {
153 bool guideIsLarger = largerSmallerCounter % 2 == 0;
154 if (guideIsLarger && (*it > guideCutoff)) {
155 lCollim += guideIncrement;
156 } else if (!guideIsLarger && (*it < guideCutoff)) {
157 lCollim += guideIncrement;
158 } else {
159 break;
160 }
161 largerSmallerCounter++;
162 }
163 return lCollim;
164}
165
172 if (auto timeSeriesProperty = dynamic_cast<TimeSeriesProperty<double> *>(prop)) {
173 return timeSeriesProperty->firstValue();
174 } else if (auto doubleProperty = dynamic_cast<PropertyWithValue<double> *>(prop)) {
175 auto val = doubleProperty->value();
176 if (checkForDouble(val)) {
177 g_log.warning("SANSCollimationLengthEstimator: The Guide was not "
178 "recoginized as a TimeSeriesProperty, but rather as a "
179 "Numeric.");
180 return boost::lexical_cast<double, std::string>(val);
181 }
182 }
183 throw std::invalid_argument("TOFSANSResolutionByPixel: Unknown type for "
184 "Guides. Currently only Numeric and TimeSeries "
185 "are supported.");
186}
187} // namespace Mantid::Algorithms
IPeaksWorkspace_sptr workspace
Definition: IndexPeaks.cpp:114
double getGuideValue(Mantid::Kernel::Property *prop) const
Extracts the value of the guide.
double getCollimationLengthWithGuides(const Mantid::API::MatrixWorkspace_sptr &inOutWS, const double L1, const double collimationLengthCorrection) const
This extraction strategy gets applied when guides are used to calculate the collimation length.
double provideCollimationLength(const Mantid::API::MatrixWorkspace_sptr &workspace)
Provide the collimation length which is associated with the instrument.
The Logger class is in charge of the publishing messages from the framework through various channels.
Definition: Logger.h:52
void notice(const std::string &msg)
Logs at notice level.
Definition: Logger.cpp:95
void error(const std::string &msg)
Logs at error level.
Definition: Logger.cpp:77
void warning(const std::string &msg)
Logs at warning level.
Definition: Logger.cpp:86
The concrete, templated class for properties.
Base class for properties.
Definition: Property.h:94
A specialised Property class for holding a series of time-value pairs.
Class for 3D vectors.
Definition: V3D.h:34
double norm() const noexcept
Definition: V3D.h:263
Kernel::Logger g_log("ExperimentInfo")
static logger object
std::shared_ptr< MatrixWorkspace > MatrixWorkspace_sptr
shared pointer to the matrix workspace base class
std::string to_string(const wide_integer< Bits, Signed > &n)