Mantid
Loading...
Searching...
No Matches
SCDPanelErrors.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 +
12#include "MantidAPI/Sample.h"
13#include "MantidBeamline/ComponentType.h"
24#include "MantidKernel/Unit.h"
25#include <algorithm>
26#include <boost/math/special_functions/round.hpp>
27#include <cmath>
28#include <fstream>
29#include <sstream>
30#include <utility>
31
32namespace Mantid::Crystal {
33
34using namespace CurveFitting;
35
36using namespace Kernel;
37
38using namespace API;
39
40namespace {
42Logger g_log("SCDPanelErrors");
43} // namespace
44
45DECLARE_FUNCTION(SCDPanelErrors)
46
48
50SCDPanelErrors::SCDPanelErrors() : m_setupFinished(false) {
51 declareParameter("XShift", 0.0, "Shift factor in X");
52 declareParameter("YShift", 0.0, "Shift factor in Y");
53 declareParameter("ZShift", 0.0, "Shift factor in Z");
54 declareParameter("XRotate", 0.0, "Rotate angle in X");
55 declareParameter("YRotate", 0.0, "Rotate angle in Y");
56 declareParameter("ZRotate", 0.0, "Rotate angle in Z");
57 declareParameter("ScaleWidth", 1.0, "Scale width of detector");
58 declareParameter("ScaleHeight", 1.0, "Scale height of detector");
59 declareParameter("T0Shift", 0.0, "Shift for TOF");
60 declareAttribute("FileName", Attribute("", true));
61 declareAttribute("Workspace", Attribute(""));
62 declareAttribute("Bank", Attribute(""));
63}
78void SCDPanelErrors::moveDetector(double x, double y, double z, double rotx, double roty, double rotz, double scalex,
79 double scaley, std::string detname, const Workspace_sptr &inputW) const {
80 if (detname.compare("none") == 0.0)
81 return;
82 // CORELLI has sixteenpack under bank
84 Kernel::DynamicPointerCastHelper::dynamicPointerCastWithCheck<DataObjects::PeaksWorkspace, API::Workspace>(
85 inputW);
86 if (inputP->getInstrumentName().compare("CORELLI") == 0.0 && detname != "moderator")
87 detname.append("/sixteenpack");
88
89 if (x != 0.0 || y != 0.0 || z != 0.0) {
90 auto alg1 = Mantid::API::AlgorithmFactory::Instance().create("MoveInstrumentComponent", -1);
91 alg1->initialize();
92 alg1->setChild(true);
93 alg1->setLogging(false);
94 alg1->setProperty<Workspace_sptr>("Workspace", inputW);
95 alg1->setPropertyValue("ComponentName", detname);
96 // Move in m
97 alg1->setProperty("X", x);
98 alg1->setProperty("Y", y);
99 alg1->setProperty("Z", z);
100 alg1->setPropertyValue("RelativePosition", "1");
101 alg1->execute();
102 }
103
104 if (rotx != 0.0) {
105 auto algx = Mantid::API::AlgorithmFactory::Instance().create("RotateInstrumentComponent", -1);
106 algx->initialize();
107 algx->setChild(true);
108 algx->setLogging(false);
109 algx->setProperty<Workspace_sptr>("Workspace", inputW);
110 algx->setPropertyValue("ComponentName", detname);
111 algx->setProperty("X", 1.0);
112 algx->setProperty("Y", 0.0);
113 algx->setProperty("Z", 0.0);
114 algx->setProperty("Angle", rotx);
115 algx->setPropertyValue("RelativeRotation", "1");
116 algx->execute();
117 }
118
119 if (roty != 0.0) {
120 auto algy = Mantid::API::AlgorithmFactory::Instance().create("RotateInstrumentComponent", -1);
121 algy->initialize();
122 algy->setChild(true);
123 algy->setLogging(false);
124 algy->setProperty<Workspace_sptr>("Workspace", inputW);
125 algy->setPropertyValue("ComponentName", detname);
126 algy->setProperty("X", 0.0);
127 algy->setProperty("Y", 1.0);
128 algy->setProperty("Z", 0.0);
129 algy->setProperty("Angle", roty);
130 algy->setPropertyValue("RelativeRotation", "1");
131 algy->execute();
132 }
133
134 if (rotz != 0.0) {
135 auto algz = Mantid::API::AlgorithmFactory::Instance().create("RotateInstrumentComponent", -1);
136 algz->initialize();
137 algz->setChild(true);
138 algz->setLogging(false);
139 algz->setProperty<Workspace_sptr>("Workspace", inputW);
140 algz->setPropertyValue("ComponentName", detname);
141 algz->setProperty("X", 0.0);
142 algz->setProperty("Y", 0.0);
143 algz->setProperty("Z", 1.0);
144 algz->setProperty("Angle", rotz);
145 algz->setPropertyValue("RelativeRotation", "1");
146 algz->execute();
147 }
148 if (scalex != 1.0 || scaley != 1.0) {
149 auto &componentInfo = inputP->mutableComponentInfo();
150 // A path (as for CORELLI) or an unknown name finds no bank to scale
151 size_t bankIndex = Geometry::ComponentInfo::invalidIndex;
152 try {
153 bankIndex = componentInfo.indexOfAny(detname);
154 } catch (const std::invalid_argument &) {
155 // No component of this name, so nothing to scale
156 }
157 if (bankIndex != Geometry::ComponentInfo::invalidIndex &&
158 componentInfo.componentType(bankIndex) == Beamline::ComponentType::Rectangular) {
159 Geometry::ParameterMap &pmap = inputP->instrumentParameters();
160 auto oldscalex = pmap.getDouble(detname, "scalex");
161 auto oldscaley = pmap.getDouble(detname, "scaley");
162 double relscalex = scalex;
163 double relscaley = scaley;
164 if (!oldscalex.empty())
165 relscalex /= oldscalex[0];
166 if (!oldscaley.empty())
167 relscaley /= oldscaley[0];
168 componentInfo.addDouble(bankIndex, "scalex", scalex);
169 componentInfo.addDouble(bankIndex, "scaley", scaley);
170 applyRectangularDetectorScaleToComponentInfo(componentInfo, bankIndex, relscalex, relscaley);
171 }
172 }
173}
174
176void SCDPanelErrors::eval(double xshift, double yshift, double zshift, double xrotate, double yrotate, double zrotate,
177 double scalex, double scaley, double *out, const double *xValues, const size_t nData,
178 double tShift) const {
179 UNUSED_ARG(xValues);
180 if (nData == 0)
181 return;
182
183 setupData();
184
185 std::shared_ptr<API::Workspace> cloned = m_workspace->clone();
186 moveDetector(xshift, yshift, zshift, xrotate, yrotate, zrotate, scalex, scaley, m_bank, cloned);
187
188 auto inputP =
189 Kernel::DynamicPointerCastHelper::dynamicPointerCastWithCheck<DataObjects::PeaksWorkspace, API::Workspace>(
190 std::move(cloned));
191 auto inst = inputP->getInstrument();
192 Geometry::OrientedLattice lattice = inputP->mutableSample().getOrientedLattice();
193 for (int i = 0; i < inputP->getNumberPeaks(); i++) {
194 const DataObjects::Peak &peak = inputP->getPeak(i);
195 V3D hkl = V3D(boost::math::iround(peak.getH()), boost::math::iround(peak.getK()), boost::math::iround(peak.getL()));
196 V3D Q2 = lattice.qFromHKL(hkl);
197 try {
198 if (hkl == V3D(0, 0, 0))
199 throw std::runtime_error("unindexed peak");
200 DataObjects::Peak peak2(inst, peak.getDetectorID(), peak.getWavelength(), hkl, peak.getGoniometerMatrix());
202
203 wl.initialize(peak2.getL1(), 0, {{UnitParams::l2, peak2.getL2()}, {UnitParams::twoTheta, peak2.getScattering()}});
204 peak2.setWavelength(wl.singleFromTOF(peak.getTOF() + tShift));
205 V3D Q3 = peak2.getQSampleFrame();
206 out[i * 3] = Q3[0] - Q2[0];
207 out[i * 3 + 1] = Q3[1] - Q2[1];
208 out[i * 3 + 2] = Q3[2] - Q2[2];
209 } catch (std::runtime_error &) {
210 // set penalty for unindexed peaks greater than tolerance
211 out[i * 3] = 0.15;
212 out[i * 3 + 1] = 0.15;
213 out[i * 3 + 2] = 0.15;
214 }
215 }
216}
217
224void SCDPanelErrors::function1D(double *out, const double *xValues, const size_t nData) const {
225 const double xshift = getParameter("XShift");
226 const double yshift = getParameter("YShift");
227 const double zshift = getParameter("ZShift");
228 const double xrotate = getParameter("XRotate");
229 const double yrotate = getParameter("YRotate");
230 const double zrotate = getParameter("ZRotate");
231 const double scalex = getParameter("ScaleWidth");
232 const double scaley = getParameter("ScaleHeight");
233 const double tShift = getParameter("T0Shift");
234 eval(xshift, yshift, zshift, xrotate, yrotate, zrotate, scalex, scaley, out, xValues, nData, tShift);
235}
236
244void SCDPanelErrors::functionDeriv1D(API::Jacobian *out, const double *xValues, const size_t nData) {
245 FunctionDomain1DView domain(xValues, nData);
246 this->calNumericalDeriv(domain, *out);
247}
248
250void SCDPanelErrors::clear() const { m_setupFinished = false; }
251
256void SCDPanelErrors::setAttribute(const std::string &attName, const IFunction::Attribute &value) {
257 if (attName == "FileName") {
258 std::string fileName = value.asUnquotedString();
259 if (fileName.empty()) {
260 storeAttributeValue("FileName", Attribute("", true));
261 return;
262 }
263 FileValidator fval;
264 std::string error = fval.isValid(fileName);
265 if (error.empty()) {
266 storeAttributeValue(attName, Attribute(fileName, true));
267 storeAttributeValue("Workspace", Attribute(""));
268 } else {
269 // file not found
270 throw Kernel::Exception::FileError(error, fileName);
271 }
272 load(fileName);
273 } else if (attName == "Workspace") {
274 std::string wsName = value.asString();
275 if (!wsName.empty()) {
276 storeAttributeValue(attName, value);
277 storeAttributeValue("FileName", Attribute("", true));
278 loadWorkspace(wsName);
279 }
280 } else {
282 m_setupFinished = false;
283 }
284}
285
290void SCDPanelErrors::load(const std::string &fname) {
291 auto loadAlg = Mantid::API::AlgorithmFactory::Instance().create("Load", -1);
292 loadAlg->initialize();
293 loadAlg->setChild(true);
294 loadAlg->setLogging(false);
295 try {
296 loadAlg->setPropertyValue("Filename", fname);
297 loadAlg->setPropertyValue("OutputWorkspace", "_SCDPanelErrors_fit_data_");
298 loadAlg->execute();
299 } catch (std::runtime_error &) {
300 throw std::runtime_error("Unable to load Nexus file for SCDPanelErrors function.");
301 }
302
303 Workspace_sptr ws = loadAlg->getProperty("OutputWorkspace");
304 API::Workspace_sptr resData = std::dynamic_pointer_cast<Mantid::API::Workspace>(ws);
305 loadWorkspace(resData);
306}
307
312void SCDPanelErrors::loadWorkspace(const std::string &wsName) const {
313 auto ws = AnalysisDataService::Instance().retrieveWS<API::Workspace>(wsName);
314 loadWorkspace(ws);
315}
316
321void SCDPanelErrors::loadWorkspace(std::shared_ptr<API::Workspace> ws) const {
322 m_workspace = std::move(ws);
323 m_setupFinished = false;
324}
325
329void SCDPanelErrors::setupData() const {
330 if (m_setupFinished) {
331 g_log.debug() << "Re-setting isn't required.";
332 return;
333 }
334
335 if (!m_workspace) {
336 std::string wsName = getAttribute("Workspace").asString();
337 if (wsName.empty())
338 throw std::invalid_argument("Data not set for function " + this->name());
339 else
340 loadWorkspace(wsName);
341 }
342
343 m_bank = getAttribute("Bank").asString();
344
345 g_log.debug() << "Setting up " << m_workspace->getName() << " bank " << m_bank << '\n';
346
347 m_setupFinished = true;
348}
349
350} // namespace Mantid::Crystal
std::string name
Definition Run.cpp:60
double value
The value of the point.
Definition FitMW.cpp:51
#define DECLARE_FUNCTION(classname)
Macro for declaring a new type of function to be used with the FunctionFactory.
double error
Mantid::API::IFunction::Attribute Attribute
#define UNUSED_ARG(x)
Function arguments are sometimes unused in certain implmentations but are required for documentation ...
Definition System.h:44
1D domain - a wrapper around an array of doubles.
Attribute is a non-fitting parameter.
Definition IFunction.h:286
void declareAttribute(const std::string &name, const API::IFunction::Attribute &defaultValue)
Declare a single attribute.
virtual void setAttribute(const std::string &name, const Attribute &)
Set a value to attribute attName.
Represents the Jacobian in IFitFunction::functionDeriv.
Definition Jacobian.h:22
void declareParameter(const std::string &name, double initValue=0, const std::string &description="") override
Declare a new parameter.
Base Workspace Abstract Class.
Definition Workspace.h:30
void moveDetector(double x, double y, double z, double rotx, double roty, double rotz, double scalex, double scaley, std::string detname, const API::Workspace_sptr &inputW) const
Move detectors with parameters.
std::string m_bank
Stores bank.
static const int defaultIndexValue
The default value for the workspace index.
std::shared_ptr< API::Workspace > m_workspace
Temporary workspace holder.
void setupData() const
Fill in the workspace and bank names.
void eval(double xshift, double yshift, double zshift, double xrotate, double yrotate, double zrotate, double scalex, double scaley, double *out, const double *xValues, const size_t nData, double tShift) const
Evaluate the function for a list of arguments and given scaling factor.
double getL() const override
Get the L index of the peak.
Definition BasePeak.cpp:100
double getK() const override
Get the K index of the peak.
Definition BasePeak.cpp:97
double getH() const override
Get the H index of the peak.
Definition BasePeak.cpp:94
Mantid::Kernel::Matrix< double > getGoniometerMatrix() const override
Get the goniometer rotation matrix at which this peak was measured.
Definition BasePeak.cpp:210
Structure describing a single-crystal peak.
Definition Peak.h:34
double getL1() const override
Return the L1 flight path length (source to sample), in meters.
Definition Peak.cpp:748
int getDetectorID() const override
Get the ID of the detector at the center of the peak
Definition Peak.cpp:289
double getWavelength() const override
Calculate the neutron wavelength (in angstroms) at the peak (Note for inelastic scattering - it is th...
Definition Peak.cpp:382
double getTOF() const override
Calculate the time of flight (in microseconds) of the neutrons for this peak, using the geometry of t...
Definition Peak.cpp:397
static constexpr size_t invalidIndex
Returned by indexOfOrInvalid() for a component ID that is not part of this instrument.
Class to implement UB matrix.
Kernel::V3D qFromHKL(const Kernel::V3D &hkl) const
Calculate the hkl corresponding to a given Q-vector.
Parameter map iterator typedef.
Records the filename and the description of failure.
Definition Exception.h:98
FileValidator is a validator that checks that a filepath is valid.
void debug(const std::string &msg)
Logs at debug level.
Definition Logger.cpp:145
void initialize(const double &_l1, const int &_emode, const UnitParametersMap &params)
Initialize the unit to perform conversion using singleToTof() and singleFromTof()
Definition Unit.cpp:133
Wavelength in Angstrom.
Definition Unit.h:305
Class for 3D vectors.
Definition V3D.h:35
MANTID_API_DLL void applyRectangularDetectorScaleToComponentInfo(Geometry::ComponentInfo &componentInfo, const size_t componentIndex, const double scaleX, const double scaleY)
Helpers for resizing RectangularDetectors.
std::shared_ptr< Workspace > Workspace_sptr
shared pointer to Mantid::API::Workspace
Kernel::Logger g_log("ExperimentInfo")
static logger object
std::shared_ptr< PeaksWorkspace > PeaksWorkspace_sptr
Typedef for a shared pointer to a peaks workspace.
Generate a tableworkspace to store the calibration results.
adjust instrument component position and orientation
: detector size scale at y-direction