Mantid
Loading...
Searching...
No Matches
LoadILLPolarizedDiffraction.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 +
8
10#include "MantidAPI/Axis.h"
14#include "MantidAPI/Run.h"
24#include "MantidKernel/Unit.h"
27#include "MantidKernel/V3D.h"
31#include "MantidNexus/NexusFile.h"
32
33namespace Mantid::DataHandling {
34
35using namespace API;
36using namespace Geometry;
37using namespace Kernel;
38using namespace Nexus;
39using Types::Core::DateAndTime;
40
41namespace {
42// This defines the number of physical pixels in D7
43constexpr size_t D7_NUMBER_PIXELS = 132;
44// This defines the number of monitors in the instrument.
45constexpr size_t NUMBER_MONITORS = 2;
46// This defines Time Of Flight measurement mode switch value
47constexpr size_t TOF_MODE_ON = 1;
48} // namespace
49
50// Register the algorithm into the AlgorithmFactory
51DECLARE_NEXUS_FILELOADER_ALGORITHM(LoadILLPolarizedDiffraction)
52
53
54int LoadILLPolarizedDiffraction::confidence(Nexus::NexusDescriptor &descriptor) const {
55
56 // fields existent only at the ILL Diffraction
57 if (descriptor.isEntry("/entry0/D7")) {
58 return 80;
59 } else {
60 return 0;
61 }
62}
63
65const std::string LoadILLPolarizedDiffraction::name() const { return "LoadILLPolarizedDiffraction"; }
66
68int LoadILLPolarizedDiffraction::version() const { return 1; }
69
71const std::string LoadILLPolarizedDiffraction::category() const { return "DataHandling\\Nexus;ILL\\Diffraction"; }
72
74const std::string LoadILLPolarizedDiffraction::summary() const {
75 return "Loads ILL D7 instrument polarized diffraction nexus files.";
76}
77
82
87 declareProperty(std::make_unique<FileProperty>("Filename", "", FileProperty::Load, ".nxs"),
88 "File path of the data file to load");
89 declareProperty(std::make_unique<WorkspaceProperty<API::WorkspaceGroup>>("OutputWorkspace", "", Direction::Output),
90 "The output workspace.");
91 const std::vector<std::string> positionCalibrationOptions{"None", "Nexus", "YIGFile"};
92 declareProperty("PositionCalibration", "None", std::make_shared<StringListValidator>(positionCalibrationOptions),
93 "Select the type of pixel position calibration. If None, the pixel "
94 "positions are read from IDF file. If Nexus, the positions are read from "
95 "Nexus file. If YIGFile, then the calibration twotheta data is loaded "
96 "from a user-defined calibration file.");
97
98 declareProperty(std::make_unique<FileProperty>("YIGFilename", "", FileProperty::OptionalLoad, ".xml"),
99 "File path of the YIG calibration data file to load.");
100 setPropertySettings("YIGFilename",
101 std::make_unique<Kernel::EnabledWhenProperty>("PositionCalibration", IS_EQUAL_TO, "YIGFile"));
102 declareProperty("ConvertToScatteringAngle", false, "Convert the bin edges to scattering angle.", Direction::Input);
103 declareProperty("TransposeMonochromatic", false, "Transpose the 2D workspace with monochromatic data",
105 const std::vector<std::string> TOFUnitOptions{"UncalibratedTime", "TimeChannels"};
106 declareProperty("TOFUnits", TOFUnitOptions[0], std::make_shared<StringListValidator>(TOFUnitOptions),
107 "The choice of X-axis units for Time-Of-Flight data.");
108}
109
110std::map<std::string, std::string> LoadILLPolarizedDiffraction::validateInputs() {
111 std::map<std::string, std::string> issues;
112 if (getPropertyValue("PositionCalibration") == "YIGFile" && getPropertyValue("YIGFilename") == "") {
113 issues["PositionCalibration"] = "YIG-based position calibration of detectors requested but "
114 "the file was not provided.";
115 }
116 return issues;
117}
118
123
124 Progress progress(this, 0, 1, 3);
125
126 m_fileName = getPropertyValue("Filename");
127 m_wavelength = 0;
128
129 progress.report("Loading the detector polarization analysis data");
130 loadData();
131
132 progress.report("Loading the metadata");
133 loadMetaData();
134
135 progress.report("Sorting polarisations");
136 auto outputWorkspaceGroup = sortPolarisations();
137
138 setProperty("OutputWorkspace", outputWorkspaceGroup);
139}
140
146
147 // open the root entry
148 NXRoot dataRoot(m_fileName);
149
150 // read each entry
151 for (auto entryNumber = 0; entryNumber < static_cast<int>((dataRoot.groups().size())); entryNumber++) {
152 NXEntry entry = dataRoot.openEntry("entry" + std::to_string(entryNumber));
153 m_instName = entry.getString("D7/name");
154
155 std::string startTime = entry.getString("start_time");
156 startTime = LoadHelper::dateTimeInIsoFormat(startTime);
157
158 // init the workspace with proper number of histograms and number of channels
159 auto workspace = initStaticWorkspace(entry);
160
161 // the start time is needed in the workspace when loading the parameter file
162 workspace->mutableRun().addProperty("start_time", startTime);
163
164 // load the instrument
166
167 // rotate detectors to their position during measurement
168 moveTwoTheta(entry, workspace);
169
170 // prepare axes for data
171 const std::vector<double> axis = prepareAxes(entry);
172
173 // load data from file
174 auto data = LoadHelper::getIntDataset(entry, "data");
175 data.load();
176
178
179 // load and assign monitor data
180 for (auto monitor_no = static_cast<int>(D7_NUMBER_PIXELS);
181 monitor_no < static_cast<int>(D7_NUMBER_PIXELS + NUMBER_MONITORS); ++monitor_no) {
182 auto monitorData = LoadHelper::getIntDataset(
183 entry, "monitor" + std::to_string(monitor_no + 1 - static_cast<int>(D7_NUMBER_PIXELS)));
184 monitorData.load();
185 LoadHelper::fillStaticWorkspace(workspace, monitorData, axis, monitor_no);
186 }
187 // replace errors for bins with zero counts with ones:
189
190 // convert the spectrum axis to scattering angle
191 if (getProperty("ConvertToScatteringAngle")) {
193 }
194 // transpose monochromatic data distribution
195 if (getProperty("TransposeMonochromatic") && m_acquisitionMode != TOF_MODE_ON) {
197 }
198
199 // adds the current entry workspace to the output group
200 m_outputWorkspaceGroup.push_back(std::move(workspace));
201 entry.close();
202 }
203 dataRoot.close();
204}
205
210
211 // Open NeXus file
212 try {
213 Nexus::File nxHandle(m_fileName, NXaccess::READ);
214 for (auto workspaceId = 0; workspaceId < static_cast<int>(m_outputWorkspaceGroup.size()); ++workspaceId) {
216 std::static_pointer_cast<API::MatrixWorkspace>(m_outputWorkspaceGroup[workspaceId]);
217 auto const entryName = std::string("entry" + std::to_string(workspaceId));
218 LoadHelper::addNexusFieldsToWsRun(nxHandle, workspace->mutableRun(), entryName);
219 if (m_wavelength != 0) {
220 workspace->mutableRun().addProperty("monochromator.wavelength", m_wavelength, true);
221 }
222 }
223 } catch (Nexus::Exception const &e) {
224 g_log.debug() << "Failed to open nexus file \"" << m_fileName << "\" in read mode: " << e.what() << "\n";
225 }
226}
227
237 const size_t nSpectra = D7_NUMBER_PIXELS + NUMBER_MONITORS;
238
239 // Set number of channels
240 NXInt acquisitionMode = entry.openNXInt("acquisition_mode");
241 acquisitionMode.load();
242 m_acquisitionMode = acquisitionMode[0];
243 if (m_acquisitionMode == TOF_MODE_ON) {
244 NXFloat timeOfFlightInfo = entry.openNXFloat("D7/Detector/time_of_flight");
245 timeOfFlightInfo.load();
246 m_numberOfChannels = size_t(timeOfFlightInfo[1]);
247 } else {
249 }
250
253
254 // Set x axis units
255 if (m_acquisitionMode == TOF_MODE_ON) {
256 if (getPropertyValue("TOFUnits") == "TimeChannels") {
257 auto lblUnit = std::dynamic_pointer_cast<Kernel::Units::Label>(UnitFactory::Instance().create("Label"));
258 lblUnit->setLabel("Time channel", Units::Symbol::EmptyLabel);
259 workspace->getAxis(0)->unit() = lblUnit;
260 } else {
261 workspace->getAxis(0)->unit() = UnitFactory::Instance().create("TOF");
262 }
263 } else {
264 workspace->getAxis(0)->unit() = UnitFactory::Instance().create("Wavelength");
265 }
266 // Set y axis unit
267 workspace->setYUnit("Counts");
268
269 // check the polarization direction and set the workspace title
270 std::string polDirection = entry.getString("D7/POL/actual_state");
271 std::string flipperState = entry.getString("D7/POL/actual_stateB1B2");
272 workspace->setTitle(polDirection.substr(0, 1) + "_" + flipperState);
273 return workspace;
274}
275
285 const NXEntry &entry, const int bankId) {
286
287 auto const nPixelsPerBank = workspace->getInstrument()->getIntParameter("number_pixels_per_bank")[0];
288 std::vector<double> twoTheta(static_cast<int>(nPixelsPerBank));
289
290 if (getPropertyValue("PositionCalibration") == "Nexus") {
291 NXFloat twoThetaPixels = entry.openNXFloat("D7/Detector/bank" + std::to_string(bankId) + "_offset");
292 twoThetaPixels.load();
293 float *twoThetaDataStart = twoThetaPixels();
294 float *twoThetaDataEnd = twoThetaDataStart + nPixelsPerBank;
295 twoTheta.assign(twoThetaDataStart, twoThetaDataEnd);
296 } else {
297 auto loadIpf = createChildAlgorithm("LoadParameterFile");
298 loadIpf->setPropertyValue("Filename", getPropertyValue("YIGFilename"));
299 loadIpf->setProperty("Workspace", workspace);
300 loadIpf->execute();
301
302 Instrument_const_sptr instrument = workspace->getInstrument();
303 IComponent_const_sptr currentBank = instrument->getComponentByName(std::string("bank" + std::to_string(bankId)));
304
305 m_wavelength = currentBank->getNumberParameter("wavelength")[0];
306
307 for (auto pixel_no = 0; pixel_no < static_cast<int>(nPixelsPerBank); pixel_no++) {
308 twoTheta[pixel_no] = currentBank->getNumberParameter("twoTheta_pixel_" + std::to_string(pixel_no + 1))[0];
309 }
310 }
311 return twoTheta;
312}
313
321 const int bankId) {
322 std::vector<double> bankParameters;
323
324 Instrument_const_sptr instrument = workspace->getInstrument();
325 IComponent_const_sptr currentBank = instrument->getComponentByName(std::string("bank" + std::to_string(bankId)));
326
327 auto slope = currentBank->getNumberParameter("gradient")[0];
328 bankParameters.push_back(slope);
329 auto offset = currentBank->getNumberParameter("offset")[0];
330 bankParameters.push_back(offset);
331
332 return bankParameters;
333}
334
341
342 Instrument_const_sptr instrument = workspace->getInstrument();
343 auto const nBanks = instrument->getIntParameter("number_banks")[0];
344 auto const nPixelsPerBank = instrument->getIntParameter("number_pixels_per_bank")[0];
345
346 auto &componentInfo = workspace->mutableComponentInfo();
347 for (auto bank_no = 0; bank_no < static_cast<int>(nBanks); ++bank_no) {
348 NXFloat twoThetaBank =
349 entry.openNXFloat("D7/2theta/actual_bank" + std::to_string(bank_no + 2)); // detector bank IDs start at 2
350 twoThetaBank.load();
351 if (getPropertyValue("PositionCalibration") == "None") {
352 Quat rotation(-twoThetaBank[0], V3D(0, 1, 0));
353 IComponent_const_sptr currentBank =
354 instrument->getComponentByName(std::string("bank" + std::to_string(bank_no + 2)));
355 const auto componentIndex = componentInfo.indexOf(currentBank->getComponentID());
356 componentInfo.setRotation(componentIndex, rotation);
357 } else {
358 std::vector<double> twoThetaPixels = loadTwoThetaDetectors(workspace, entry, bank_no + 2);
359 std::vector<double> bankParameters{1, 0}; // slope, offset
360 if (getPropertyValue("PositionCalibration") == "YIGFile") {
361 bankParameters = loadBankParameters(workspace, bank_no + 2);
362 }
363 for (auto pixel_no = 0; pixel_no < static_cast<int>(nPixelsPerBank); ++pixel_no) {
364 auto const pixelIndex = bank_no * static_cast<int>(nPixelsPerBank) + pixel_no;
365 auto const pixel = componentInfo.componentID(pixelIndex);
366 V3D position = pixel->getPos();
367 double radius, theta, phi;
368 position.getSpherical(radius, theta, phi);
369 position.spherical(radius, bankParameters[0] * twoThetaBank[0] - bankParameters[1] - twoThetaPixels[pixel_no],
370 phi);
371 componentInfo.setPosition(pixelIndex, position);
372 }
373 }
374 }
375}
376
383std::vector<double> LoadILLPolarizedDiffraction::prepareAxes(const NXEntry &entry) {
384 // check the mode of measurement and prepare axes for data
385 std::vector<double> axes;
386
387 if (m_acquisitionMode == TOF_MODE_ON) {
388 NXFloat timeOfFlightInfo = entry.openNXFloat("D7/Detector/time_of_flight");
389 timeOfFlightInfo.load();
390 auto channelWidth = static_cast<double>(timeOfFlightInfo[0]);
391 m_numberOfChannels = size_t(timeOfFlightInfo[1]);
392 auto tofDelay = timeOfFlightInfo[2];
393 for (auto channel_no = 0; channel_no <= static_cast<int>(m_numberOfChannels); channel_no++) {
394 if (getPropertyValue("TOFUnits") == "UncalibratedTime") {
395 axes.push_back(tofDelay + channel_no * channelWidth);
396 } else {
397 axes.push_back(channel_no);
398 }
399 }
400 } else {
401 double wavelength = 0;
402 if (m_wavelength != 0) {
403 wavelength = m_wavelength;
404 } else {
405 NXFloat wavelengthNexus = entry.openNXFloat("D7/monochromator/wavelength");
406 wavelengthNexus.load();
407 wavelength = wavelengthNexus[0];
408 }
409 axes.push_back(static_cast<double>(wavelength * 0.99));
410 axes.push_back(static_cast<double>(wavelength * 1.01));
411 }
412 return axes;
413}
414
420 auto convertSpectrumAxis = createChildAlgorithm("ConvertSpectrumAxis");
421 convertSpectrumAxis->initialize();
422 convertSpectrumAxis->setProperty("InputWorkspace", workspace);
423 convertSpectrumAxis->setProperty("OutputWorkspace", "__unused_for_child");
424 convertSpectrumAxis->setProperty("Target", "SignedTheta");
425 convertSpectrumAxis->setProperty("EMode", "Direct");
426 convertSpectrumAxis->setProperty("OrderAxis", false);
427 convertSpectrumAxis->execute();
428 workspace = convertSpectrumAxis->getProperty("OutputWorkspace");
429
430 auto changeSign = createChildAlgorithm("ConvertAxisByFormula");
431 changeSign->initialize();
432 changeSign->setProperty("InputWorkspace", workspace);
433 changeSign->setProperty("OutputWorkspace", "__unused_for_child");
434 changeSign->setProperty("Axis", "Y");
435 changeSign->setProperty("Formula", "-y");
436 changeSign->execute();
437 return changeSign->getProperty("OutputWorkspace");
438}
439
446 auto transpose = createChildAlgorithm("Transpose");
447 transpose->initialize();
448 transpose->setProperty("InputWorkspace", workspace);
449 transpose->setProperty("OutputWorkspace", "__unused_for_child");
450 transpose->execute();
451 return transpose->getProperty("OutputWorkspace");
452}
453
459 auto outputGroupSize = static_cast<int>(m_outputWorkspaceGroup.size());
460 API::WorkspaceGroup_sptr sortedGroup = std::make_shared<API::WorkspaceGroup>();
461 if (outputGroupSize < 2) {
462 sortedGroup->addWorkspace(std::move(m_outputWorkspaceGroup[0]));
463 } else {
464 std::vector<int> sortedWorkspaceIds(outputGroupSize);
465 std::map<const std::string, int> polarisationsOrder{{"OFF", 0}, {"ZPO", 1}, {"XPO", 3},
466 {"YPO", 5}, {"XPO-YPO", 7}, {"XPO+YPO", 9}};
467 for (auto workspaceId = 0; workspaceId < outputGroupSize; workspaceId++) {
468 auto ws = m_outputWorkspaceGroup[workspaceId];
469 auto flipperState = ws->mutableRun().getLogData("POL.actual_stateB1B2")->value();
470 std::string polarisation = ws->mutableRun().getLogData("POL.actual_state")->value();
471 int sortedId = 0;
472 if (polarisationsOrder.count(polarisation) > 0) {
473 sortedId = polarisationsOrder[polarisation];
474 if (flipperState == "ON")
475 sortedId--;
476 }
477 sortedWorkspaceIds[workspaceId] = sortedId;
478 }
479 for (auto workspaceId : sortedWorkspaceIds) {
480 sortedGroup->addWorkspace(std::move(m_outputWorkspaceGroup[workspaceId]));
481 }
482 }
483 return sortedGroup;
484}
485
486} // namespace Mantid::DataHandling
double position
Definition GetAllEi.cpp:154
IPeaksWorkspace_sptr workspace
int64_t nSpectra
Mantid::Kernel::Quat(ComponentInfo::* rotation)(const size_t) const
#define DECLARE_NEXUS_FILELOADER_ALGORITHM(classname)
DECLARE_NEXUS_FILELOADER_ALGORITHM should be used in place of the standard DECLARE_ALGORITHM macro wh...
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.
Kernel::Logger & g_log
Definition Algorithm.h:422
void progress(double p, const std::string &msg="", double estimatedTime=0.0, int progressPrecision=0)
Sends ProgressNotification.
@ OptionalLoad
to specify a file to read but the file doesn't have to exist
@ Load
allowed here which will be passed to the algorithm
Defines an interface to an algorithm that loads a file so that it can take part in the automatic sele...
Definition IFileLoader.h:19
Helper class for reporting progress from algorithms.
Definition Progress.h:25
A property class for workspaces.
LoadILLPolarizedDiffraction : Loads ILL polarized diffraction nexus files from instrument D7.
API::WorkspaceGroup_sptr sortPolarisations()
Ensures that the order of flipper state values is 'ON' and then 'OFF' for each polarisation orientati...
API::MatrixWorkspace_sptr transposeMonochromatic(const API::MatrixWorkspace_sptr &)
Transposes given 2D workspace with monochromatic data.
void moveTwoTheta(const Nexus::NXEntry &, const API::MatrixWorkspace_sptr &)
Rotates each pixel to its corresponding 2theta read from the file.
API::MatrixWorkspace_sptr initStaticWorkspace(const Nexus::NXEntry &)
Initializes the output workspace based on the resolved instrument.
void init() override
Initialize the algorithm's properties.
const std::string name() const override
Algorithms name for identification.
std::vector< double > prepareAxes(const Nexus::NXEntry &)
Prepares values for bin edges depending of measurement type.
void loadData()
Loads the polarized detector data, sets up workspaces and labels according to the measurement type an...
std::string m_instName
instrument name to load the IDF
std::vector< double > loadBankParameters(const API::MatrixWorkspace_sptr &, const int)
Loads offsets and slopes for each detector bank from the workspace entry.
void loadMetaData()
Dumps the metadata from the file for each entry separately.
std::vector< API::MatrixWorkspace_sptr > m_outputWorkspaceGroup
vector with output workspaces
std::vector< double > loadTwoThetaDetectors(const API::MatrixWorkspace_sptr &, const Nexus::NXEntry &, const int)
Loads 2theta for each detector pixel from either the nexus file or the Instrument Parameter File.
std::map< std::string, std::string > validateInputs() override
Perform validation of ALL the input properties of the algorithm.
const std::string category() const override
Algorithm's category for identification.
int version() const override
Algorithm's version for identification.
API::MatrixWorkspace_sptr convertSpectrumAxis(API::MatrixWorkspace_sptr)
Converts the spectrum axis to scattering angle.
const std::string summary() const override
Algorithm's summary for use in the GUI and help.
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 > settings)
void debug(const std::string &msg)
Logs at debug level.
Definition Logger.cpp:145
Class for quaternions.
Definition Quat.h:39
static T & Instance()
Return a reference to the Singleton instance, creating it if it does not already exist Creation is do...
static const UnitLabel EmptyLabel
Empty label.
Class for 3D vectors.
Definition V3D.h:34
void getSpherical(double &R, double &theta, double &phi) const noexcept
Return the vector's position in spherical coordinates.
Definition V3D.cpp:116
Class that provides for a standard Nexus exception.
std::string getString(const std::string &name) const
Returns a string.
NXFloat openNXFloat(const std::string &name) const
Creates and opens a float dataset.
std::vector< NXClassInfo > & groups() const
Returns a list of all classes (or groups) in this NXClass.
void close()
Close this class.
NXInt openNXInt(const std::string &name) const
Creates and opens an integer dataset.
Templated class implementation of NXDataSet.
void load()
Read all of the datablock in.
Implements NXentry Nexus class.
Implements NXroot Nexus class.
NXEntry openEntry(const std::string &name)
Opens an entry – a topmost Nexus class.
std::shared_ptr< WorkspaceGroup > WorkspaceGroup_sptr
shared pointer to Mantid::API::WorkspaceGroup
std::shared_ptr< MatrixWorkspace > MatrixWorkspace_sptr
shared pointer to the matrix workspace base class
void addNexusFieldsToWsRun(Nexus::File &filehandle, API::Run &runDetails, const std::string &entryName="", bool useFullAddress=false)
Add properties from a nexus file to the workspace run.
Nexus::NXInt getIntDataset(const Nexus::NXEntry &, const std::string &)
Fetches NXInt data from the requested group name in the entry provided.
void fillStaticWorkspace(const API::MatrixWorkspace_sptr &, const Mantid::Nexus::NXInt &, const std::vector< double > &xAxis, int64_t initialSpectrum=0, bool pointData=false, const std::vector< detid_t > &detectorIDs=std::vector< int >(), const std::set< detid_t > &acceptedID=std::set< int >(), const std::tuple< short, short, short > &axisOrder=std::tuple< short, short, short >(0, 1, 2))
Fills workspace with histogram data from provided data structure.
std::string dateTimeInIsoFormat(const std::string &)
Parses the date as formatted at the ILL: 29-Jun-12 11:27:26 and converts it to the ISO format used in...
void loadEmptyInstrument(const API::MatrixWorkspace_sptr &ws, const std::string &instrumentName, const std::string &instrumentAddress="")
Loads empty instrument of chosen name into a provided workspace.
void replaceZeroErrors(const API::MatrixWorkspace_sptr &, double)
Replaces errors of bins with zero counts with provided value.
std::unique_ptr< T > create(const P &parent, const IndexArg &indexArg, const HistArg &histArg)
This is the create() method that all the other create() methods call.
std::shared_ptr< const IComponent > IComponent_const_sptr
Typdef of a shared pointer to a const IComponent.
Definition IComponent.h:167
std::shared_ptr< const Instrument > Instrument_const_sptr
Shared pointer to an const instrument object.
std::string to_string(const wide_integer< Bits, Signed > &n)
@ Input
An input workspace.
Definition Property.h:53
@ Output
An output workspace.
Definition Property.h:54