-
Notifications
You must be signed in to change notification settings - Fork 122
/
SpecularReflectionPositionCorrect.cpp
231 lines (198 loc) · 8.56 KB
/
SpecularReflectionPositionCorrect.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
#include "MantidAlgorithms/SpecularReflectionPositionCorrect.h"
#include "MantidAPI/MatrixWorkspace.h"
#include "MantidGeometry/Instrument/DetectorGroup.h"
#include "MantidGeometry/Instrument/ReferenceFrame.h"
#include "MantidKernel/BoundedValidator.h"
#include "MantidKernel/CompositeValidator.h"
#include "MantidKernel/MandatoryValidator.h"
using namespace Mantid::API;
using namespace Mantid::Geometry;
using namespace Mantid::Kernel;
namespace Mantid {
namespace Algorithms {
namespace {
const std::string multiDetectorAnalysis = "MultiDetectorAnalysis";
const std::string lineDetectorAnalysis = "LineDetectorAnalysis";
const std::string pointDetectorAnalysis = "PointDetectorAnalysis";
/**
* Get the root component, that is not the instrument itself.
* @param currentComponent : Some component in the tree
* @return : Parent component.
*/
IComponent_const_sptr
getParentComponent(IComponent_const_sptr ¤tComponent) {
if (IComponent_const_sptr parent = currentComponent->getParent()) {
if (!dynamic_cast<Instrument *>(const_cast<IComponent *>(parent.get()))) {
currentComponent = parent;
}
}
return currentComponent;
}
/**
* Determine if there is a common parent component.
* @param detectors : Detectors to evaluate.
* @return True only if all detectors have the same immediate parent.
*/
bool hasCommonParent(const std::vector<IDetector_const_sptr> &detectors) {
auto firstParent = detectors[0]->getParent();
if (!firstParent)
return false;
for (size_t i = 1; i < detectors.size(); ++i) {
auto parent = detectors[i]->getParent();
if (!parent)
return false;
if (firstParent->getComponentID() != parent->getComponentID())
return false;
}
return true;
}
}
// Register the algorithm into the AlgorithmFactory
DECLARE_ALGORITHM(SpecularReflectionPositionCorrect)
//----------------------------------------------------------------------------------------------
/// Algorithm's name for identification. @see Algorithm::name
const std::string SpecularReflectionPositionCorrect::name() const {
return "SpecularReflectionPositionCorrect";
}
/// Algorithm's version for identification. @see Algorithm::version
int SpecularReflectionPositionCorrect::version() const { return 1; }
/// Algorithm's category for identification. @see Algorithm::category
const std::string SpecularReflectionPositionCorrect::category() const {
return "Reflectometry";
}
//----------------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------------
/** Initialize the algorithm's properties.
*/
void SpecularReflectionPositionCorrect::init() {
auto thetaValidator = boost::make_shared<CompositeValidator>();
thetaValidator->add(boost::make_shared<MandatoryValidator<double>>());
thetaValidator->add(
boost::make_shared<BoundedValidator<double>>(0, 90, true));
declareProperty(make_unique<WorkspaceProperty<MatrixWorkspace>>(
"InputWorkspace", "", Direction::Input),
"An input workspace to correct.");
declareProperty(
make_unique<PropertyWithValue<double>>("TwoThetaIn", Mantid::EMPTY_DBL(),
thetaValidator, Direction::Input),
"Input two theta angle in degrees.");
this->initCommonProperties();
declareProperty(make_unique<WorkspaceProperty<MatrixWorkspace>>(
"OutputWorkspace", "", Direction::Output),
"An output workspace.");
}
//----------------------------------------------------------------------------------------------
/** Execute the algorithm.
*/
void SpecularReflectionPositionCorrect::exec() {
MatrixWorkspace_sptr inWS = this->getProperty("InputWorkspace");
const std::string analysisMode = this->getProperty("AnalysisMode");
auto cloneWS = this->createChildAlgorithm("CloneWorkspace");
cloneWS->initialize();
cloneWS->setProperty("InputWorkspace", inWS);
cloneWS->execute();
Workspace_sptr tmp = cloneWS->getProperty("OutputWorkspace");
MatrixWorkspace_sptr outWS =
boost::dynamic_pointer_cast<MatrixWorkspace>(tmp);
const double twoThetaIn = this->getProperty("TwoThetaIn");
auto instrument = outWS->getInstrument();
IComponent_const_sptr detector =
this->getDetectorComponent(outWS, analysisMode == pointDetectorAnalysis);
IComponent_const_sptr sample = this->getSurfaceSampleComponent(instrument);
correctPosition(outWS, twoThetaIn, sample, detector);
setProperty("OutputWorkspace", outWS);
}
/**
* Execute the MoveInstrumentComponent on all (named) subcomponents
* @param toCorrect : Workspace to correct
* @param detector : Detector or DetectorGroup
* @param sample : Sample Component
* @param upOffset : Up offset to apply
* @param acrossOffset : Across offset to apply
* @param detectorPosition: Actual detector or detector group position.
*/
void SpecularReflectionPositionCorrect::moveDetectors(
API::MatrixWorkspace_sptr toCorrect, IComponent_const_sptr detector,
IComponent_const_sptr sample, const double &upOffset,
const double &acrossOffset, const V3D &detectorPosition) {
auto instrument = toCorrect->getInstrument();
const V3D samplePosition = sample->getPos();
auto referenceFrame = instrument->getReferenceFrame();
if (auto groupDetector = boost::dynamic_pointer_cast<const DetectorGroup>(
detector)) // Do we have a group of detectors
{
const std::vector<IDetector_const_sptr> detectors =
groupDetector->getDetectors();
const bool commonParent = hasCommonParent(detectors);
if (commonParent) {
/*
* Same parent component. So lets move that.
*/
moveDetectors(toCorrect, detectors[0], sample, upOffset, acrossOffset,
detectorPosition); // Recursive call
} else {
/*
* We have to move individual components.
*/
for (const auto &detector : detectors) {
moveDetectors(toCorrect, detector, sample, upOffset, acrossOffset,
detectorPosition); // Recursive call
}
}
} else {
auto moveComponentAlg =
this->createChildAlgorithm("MoveInstrumentComponent");
moveComponentAlg->initialize();
moveComponentAlg->setProperty("Workspace", toCorrect);
IComponent_const_sptr root = getParentComponent(detector);
const std::string componentName = root->getName();
moveComponentAlg->setProperty("ComponentName", componentName);
moveComponentAlg->setProperty("RelativePosition", false);
// Movements
moveComponentAlg->setProperty(
referenceFrame->pointingAlongBeamAxis(),
detectorPosition.scalar_prod(referenceFrame->vecPointingAlongBeam()));
moveComponentAlg->setProperty(referenceFrame->pointingHorizontalAxis(),
acrossOffset);
const double detectorVerticalPosition =
detectorPosition.scalar_prod(referenceFrame->vecPointingUp());
const double rootVerticalPosition =
root->getPos().scalar_prod(referenceFrame->vecPointingUp());
const double dm = rootVerticalPosition - detectorVerticalPosition;
moveComponentAlg->setProperty(
referenceFrame->pointingUpAxis(),
samplePosition.scalar_prod(referenceFrame->vecPointingUp()) + upOffset +
dm);
// Execute the movement.
moveComponentAlg->execute();
}
}
/**
* Correct the position of the detectors based on the input theta value.
* @param toCorrect : Workspace to correct detector posisitions on.
* @param twoThetaInDeg : 2* Theta in degrees to use in correction calculations.
* @param sample : Pointer to the sample
* @param detector : Pointer to a given detector
*/
void SpecularReflectionPositionCorrect::correctPosition(
API::MatrixWorkspace_sptr toCorrect, const double &twoThetaInDeg,
IComponent_const_sptr sample, IComponent_const_sptr detector) {
auto instrument = toCorrect->getInstrument();
const V3D detectorPosition = detector->getPos();
const V3D samplePosition = sample->getPos();
const V3D sampleToDetector = detectorPosition - samplePosition;
auto referenceFrame = instrument->getReferenceFrame();
const double twoThetaInRad = twoThetaInDeg * (M_PI / 180.0);
double acrossOffset = 0;
double beamOffset = sampleToDetector.scalar_prod(
referenceFrame
->vecPointingAlongBeam()); // We just recalculate beam offset.
double upOffset =
(beamOffset *
std::tan(0.5 * twoThetaInRad)); // We only correct vertical position
// Apply the movements.
moveDetectors(toCorrect, detector, sample, upOffset, acrossOffset,
detector->getPos());
}
} // namespace Algorithms
} // namespace Mantid