Mantid
Loading...
Searching...
No Matches
LoadILLDiffraction.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
12#include "MantidAPI/Run.h"
24#include "MantidNexus/H5Util.h"
27#include "MantidNexus/NexusFile.h"
28
29#include <H5Cpp.h>
30#include <boost/algorithm/string.hpp>
31#include <boost/math/special_functions/round.hpp>
32#include <filesystem>
33#include <numeric>
34
35namespace Mantid::DataHandling {
36
37using namespace API;
38using namespace Geometry;
39using namespace H5;
40using namespace Kernel;
41using namespace Nexus;
42using Types::Core::DateAndTime;
43
44namespace {
45// This defines the number of physical pixels in D20 (low resolution mode)
46// Then each pixel can be split into 2 (nominal) or 3 (high resolution) by DAQ
47constexpr size_t D20_NUMBER_PIXELS = 1600;
48// This defines the number of dead pixels on each side in low resolution mode
49constexpr size_t D20_NUMBER_DEAD_PIXELS = 32;
50// This defines the number of monitors in the instrument. If there are cases
51// where this is no longer one this decleration should be moved.
52constexpr size_t NUMBER_MONITORS = 1;
53// This is the angular size of a pixel in degrees (in low resolution mode)
54constexpr double D20_PIXEL_SIZE = 0.1;
55// The conversion factor from radian to degree
56constexpr double RAD_TO_DEG = 180. / M_PI;
57// A factor to compute E from lambda: E (mev) = waveToE/lambda(A)
58constexpr double WAVE_TO_E = 81.8;
59} // namespace
60
61// Register the algorithm into the AlgorithmFactory
62DECLARE_NEXUS_FILELOADER_ALGORITHM(LoadILLDiffraction)
63
64
65int LoadILLDiffraction::confidence(Nexus::NexusDescriptor &descriptor) const {
66
67 // fields existent only at the ILL Diffraction
68 // the second one is to recognize D1B, Tx field eliminates SALSA
69 // the third one is to recognize IN5/PANTHER/SHARP scan mode
70 if ((descriptor.isEntry("/entry0/instrument/2theta") && !descriptor.isEntry("/entry0/instrument/Tx")) ||
71 descriptor.isEntry("/entry0/instrument/Canne")) {
72 return 80;
73 } else {
74 return 0;
75 }
76}
77
79const std::string LoadILLDiffraction::name() const { return "LoadILLDiffraction"; }
80
82int LoadILLDiffraction::version() const { return 1; }
83
85const std::string LoadILLDiffraction::category() const { return "DataHandling\\Nexus;ILL\\Diffraction"; }
86
88const std::string LoadILLDiffraction::summary() const { return "Loads ILL diffraction nexus files."; }
89
94 : IFileLoader<Nexus::NexusDescriptor>(), m_instNames({"D20", "D2B", "D1B", "D4C", "IN5", "PANTHER", "SHARP"}) {}
99 declareProperty(std::make_unique<FileProperty>("Filename", "", FileProperty::Load, ".nxs"),
100 "File path of the data file to load");
101 declareProperty(std::make_unique<WorkspaceProperty<MatrixWorkspace>>("OutputWorkspace", "", Direction::Output),
102 "The output workspace.");
103 declareProperty("TwoThetaOffset", 0.0, "2 theta offset for D1B data, in degrees.");
104 declareProperty(std::make_unique<PropertyWithValue<bool>>("AlignTubes", false, Direction::Input),
105 "Apply vertical and horizontal alignment of tubes as defined in IPF");
106 declareProperty("ConvertAxisAndTranspose", false,
107 "Whether to convert the spectrum axis to 2theta and "
108 "transpose (for 1D detector and no-scan configuration)");
109}
110
111std::map<std::string, std::string> LoadILLDiffraction::validateInputs() {
112 std::map<std::string, std::string> issues;
113 return issues;
114}
115
120
121 Progress progress(this, 0, 1, 4);
122
123 m_filename = getPropertyValue("Filename");
124
125 m_scanVar.clear();
126 progress.report("Loading the scanned variables");
127 loadScanVars();
128
129 progress.report("Loading the detector scan data");
130 loadDataScan();
131
132 progress.report("Loading the metadata");
133 loadMetaData();
134
135 progress.report("Setting additional sample logs");
137
138 if (m_instName != "D2B" && m_scanType != DetectorScan && getProperty("ConvertAxisAndTranspose"))
140
141 setProperty("OutputWorkspace", m_outWorkspace);
142}
143
148
149 // open the root entry
150 NXRoot dataRoot(m_filename);
151 NXEntry firstEntry = dataRoot.openFirstEntry();
152 m_instName = firstEntry.getString("instrument/name");
153 m_startTime = DateAndTime(LoadHelper::dateTimeInIsoFormat(firstEntry.getString("start_time")));
154 // Load the data
155 std::string dataName = "data_scan/detector_data/data";
156 g_log.notice() << "Loading data from " + dataName;
157 auto data = firstEntry.openNXDataSet<int>(dataName);
158 data.load();
159
160 // read the scan data
161 auto scan = LoadHelper::getDoubleDataset(firstEntry, "data_scan/scanned_variables");
162 scan.load();
163
164 // read which variables are scanned
165 NXInt scanned = firstEntry.openNXInt("data_scan/scanned_variables/variables_names/scanned");
166 scanned.load();
167
168 // read what is going to be the axis
169 NXInt axis = firstEntry.openNXInt("data_scan/scanned_variables/variables_names/axis");
170 axis.load();
171
172 // read the starting two theta
173 double twoThetaValue = 0;
174 if (m_instName == "D1B") {
175 if (getPointerToProperty("TwoThetaOffset")->isDefault()) {
176 g_log.notice("A 2theta offset angle is necessary for D1B data.");
177 twoThetaValue = 0;
178 } else {
179 twoThetaValue = getProperty("TwoThetaOffset");
180 }
181 } else {
182 std::string twoThetaPath = "instrument/2theta/value";
183 NXFloat twoTheta0 = firstEntry.openNXFloat(twoThetaPath);
184 twoTheta0.load();
185 twoThetaValue = double(twoTheta0[0]);
186 }
187
188 // figure out the dimensions
189 m_sizeDim1 = static_cast<size_t>(data.dim1());
190 m_sizeDim2 = static_cast<size_t>(data.dim2());
192 m_numberScanPoints = static_cast<size_t>(data.dim0());
193 g_log.debug() << "Read " << m_numberDetectorsRead << " detectors and " << m_numberScanPoints << "\n";
194
195 // set which scanned variables are scanned, which should be the axis
196 for (size_t i = 0; i < m_scanVar.size(); ++i) {
197 m_scanVar[i].setAxis(axis[static_cast<int>(i)]);
198 m_scanVar[i].setScanned(scanned[static_cast<int>(i)]);
199 }
200
204
205 if (m_scanType == DetectorScan) {
207 fillMovingInstrumentScan(data, scan);
208 } else {
210 fillStaticInstrumentScan(data, scan, twoThetaValue);
211 }
212
214
215 firstEntry.close();
216 dataRoot.close();
217}
218
223
224 auto &mutableRun = m_outWorkspace->mutableRun();
225 mutableRun.addProperty("Facility", std::string("ILL"));
226
227 // get some information from the NeXus file
228 try {
229 Nexus::File filehandle(m_filename, NXaccess::READ);
230 LoadHelper::addNexusFieldsToWsRun(filehandle, mutableRun);
231 } catch (Nexus::Exception const &e) {
232 g_log.debug() << "Failed to open nexus file \"" << m_filename << "\" in read mode: " << e.what() << "\n";
233 }
234
235 if (mutableRun.hasProperty("run_number"))
236 mutableRun.addProperty("run_list", mutableRun.getPropertyValueAsType<int>("run_number"));
237 else
238 throw std::runtime_error("Failed to find run_number in Run object");
239
240 if (!mutableRun.hasProperty("Detector.calibration_file"))
241 mutableRun.addProperty("Detector.calibration_file", std::string("none"));
242}
243
249 size_t nSpectra = m_numberDetectorsActual + NUMBER_MONITORS;
250 size_t nBins = 1;
251
252 if (m_scanType == DetectorScan) {
254 } else if (m_scanType == OtherScan) {
255 nBins = m_numberScanPoints;
256 }
257
258 m_outWorkspace = WorkspaceFactory::Instance().create("Workspace2D", nSpectra, nBins, nBins);
259
260 // the start time is needed in the workspace when loading the parameter file
261 m_outWorkspace->mutableRun().addProperty("start_time", m_startTime.toISO8601String());
262}
263
270 const size_t nTimeIndexes = m_numberScanPoints;
271 const size_t nBins = 1;
272 const bool isPointData = true;
273
274 const auto instrumentWorkspace = WorkspaceFactory::Instance().create("Workspace2D", 1, 1, 1);
275 auto &run = instrumentWorkspace->mutableRun();
276 // the start time is needed in the workspace when loading the parameter file
277 run.addProperty("start_time", m_startTime.toISO8601String());
278
280 LoadHelper::loadEmptyInstrument(instrumentWorkspace, m_instName);
281 const auto &instrument = instrumentWorkspace->getInstrument();
282 auto &params = instrumentWorkspace->instrumentParameters();
283
284 const auto &referenceComponentPosition = getReferenceComponentPosition(instrumentWorkspace);
285
286 double refR, refTheta, refPhi;
287 referenceComponentPosition.getSpherical(refR, refTheta, refPhi);
288
289 if (m_instName == "D2B") {
290 const bool doAlign = getProperty("AlignTubes");
291 auto &compInfo = instrumentWorkspace->mutableComponentInfo();
292
293 Geometry::IComponent_const_sptr detectors = instrument->getComponentByName("detectors");
294 const auto detCompIndex = compInfo.indexOf(detectors->getComponentID());
295 const auto tubes = compInfo.children(detCompIndex);
296 const size_t nTubes = tubes.size();
297 Geometry::IComponent_const_sptr tube1 = instrument->getComponentByName("tube_1");
298 const auto tube1CompIndex = compInfo.indexOf(tube1->getComponentID());
299 const auto pixels = compInfo.children(tube1CompIndex);
300 const size_t nPixels = pixels.size();
301
302 Geometry::IComponent_const_sptr pixel = instrument->getComponentByName("standard_pixel");
304 pixel->getBoundingBox(bb);
305 m_pixelHeight = bb.yMax() - bb.yMin();
306
307 const auto tubeAnglesStr = params.getString("D2B", "tube_angles");
308 if (!tubeAnglesStr.empty() && doAlign) {
309 std::vector<std::string> tubeAngles;
310 boost::split(tubeAngles, tubeAnglesStr[0], boost::is_any_of(","));
311 const double ref = -refTheta;
312 for (size_t i = 1; i <= nTubes; ++i) {
313 const std::string compName = "tube_" + std::to_string(i);
314 Geometry::IComponent_const_sptr component = instrument->getComponentByName(compName);
315 double r, theta, phi;
316 V3D oldPos = component->getPos();
317 oldPos.getSpherical(r, theta, phi);
318 V3D newPos;
319 const double angle = std::stod(tubeAngles[i - 1]);
320 const double finalAngle = fabs(ref - angle);
321 g_log.debug() << "Rotating " << compName << "to " << finalAngle << "rad\n";
322 newPos.spherical(r, finalAngle, phi);
323 const auto componentIndex = compInfo.indexOf(component->getComponentID());
324 compInfo.setPosition(componentIndex, newPos);
325 }
326 }
327
328 const auto tubeCentersStr = params.getString("D2B", "tube_centers");
329 if (!tubeCentersStr.empty() && doAlign) {
330 std::vector<std::string> tubeCenters;
331 double maxYOffset = 0.;
332 boost::split(tubeCenters, tubeCentersStr[0], boost::is_any_of(","));
333 for (size_t i = 1; i <= nTubes; ++i) {
334 const std::string compName = "tube_" + std::to_string(i);
335 Geometry::IComponent_const_sptr component = instrument->getComponentByName(compName);
336 const double offset = std::stod(tubeCenters[i - 1]) - (double(nPixels) / 2 - 0.5);
337 const double y = -offset * m_pixelHeight;
338 V3D translation(0, y, 0);
339 if (std::fabs(y) > maxYOffset) {
340 maxYOffset = std::fabs(y);
341 }
342 g_log.debug() << "Moving " << compName << " to " << y << "\n";
343 V3D pos = component->getPos() + translation;
344 const auto componentIndex = compInfo.indexOf(component->getComponentID());
345 compInfo.setPosition(componentIndex, pos);
346 }
347 m_maxHeight = double(nPixels + 1) * m_pixelHeight / 2 + maxYOffset;
348 }
349 }
350
351 auto scanningWorkspaceBuilder = DataObjects::ScanningWorkspaceBuilder(instrument, nTimeIndexes, nBins, isPointData);
352
353 std::vector<double> timeDurations = getScannedVaribleByPropertyName(scan, "Time");
354 scanningWorkspaceBuilder.setTimeRanges(m_startTime, timeDurations);
355
356 g_log.debug() << "First time index starts at:" << m_startTime.toISO8601String() << "\n";
357
358 g_log.debug() << "Last time index ends at:"
359 << (m_startTime + std::accumulate(timeDurations.begin(), timeDurations.end(), 0.0)).toISO8601String()
360 << "\n";
361
362 // Angles in the NeXus files are the absolute position for tube 1
363 std::vector<double> tubeAngles = getScannedVaribleByPropertyName(scan, "Position");
364
365 // Convert the tube positions to relative rotations for all detectors
366 calculateRelativeRotations(tubeAngles, referenceComponentPosition);
367
368 auto rotationCentre = V3D(0, 0, 0);
369 auto rotationAxis = V3D(0, 1, 0);
370 scanningWorkspaceBuilder.setRelativeRotationsForScans(std::move(tubeAngles), rotationCentre, rotationAxis);
371
372 m_outWorkspace = scanningWorkspaceBuilder.buildWorkspace();
373}
374
385 if (m_instName == "D2B") {
386 return instrumentWorkspace->getInstrument()->getComponentByName("tube_128")->getPos();
387 }
388
389 const auto &detInfo = instrumentWorkspace->detectorInfo();
390 const auto &indexOfFirstDet = detInfo.indexOf(1);
391 return detInfo.position(indexOfFirstDet);
392}
393
404void LoadILLDiffraction::calculateRelativeRotations(std::vector<double> &tubeRotations, const V3D &firstTubePosition) {
405 // The rotations in the NeXus file are the absolute rotation of the first
406 // tube. Here we get the angle of that tube as defined in the IDF.
407
408 double firstTubeRotationAngle = firstTubePosition.angle(V3D(0, 0, 1)) * RAD_TO_DEG;
409
410 // note that for D20 we have to subtract the offset here
411 // unlike in the static detector case, because in the transform
412 // below, we take (angle - firstTubeRotatingAngle)
413 if (m_instName == "D20") {
414 firstTubeRotationAngle -= m_offsetTheta;
415 } else if (m_instName == "D2B") {
416 firstTubeRotationAngle = -firstTubeRotationAngle;
417 std::transform(tubeRotations.begin(), tubeRotations.end(), tubeRotations.begin(),
418 [&](double angle) { return (-angle); });
419 }
420
421 g_log.debug() << "First tube rotation:" << firstTubeRotationAngle << "\n";
422
423 // Now pass calculate the rotations to apply for each time index.
424 std::transform(tubeRotations.begin(), tubeRotations.end(), tubeRotations.begin(),
425 [&](double angle) { return (angle - firstTubeRotationAngle); });
426
427 g_log.debug() << "Instrument rotations to be applied : " << tubeRotations.front() << " to " << tubeRotations.back()
428 << "\n";
429}
430
438
439 std::vector<double> axis = {0.};
440 std::vector<double> monitor = getMonitor(scan);
441
442 // First load the monitors
443 for (size_t i = 0; i < NUMBER_MONITORS; ++i) {
444 for (size_t j = 0; j < m_numberScanPoints; ++j) {
445 const auto wsIndex = j + i * m_numberScanPoints;
446 m_outWorkspace->mutableY(wsIndex) = monitor[j];
447 m_outWorkspace->mutableE(wsIndex) = sqrt(monitor[j]);
448 m_outWorkspace->mutableX(wsIndex) = axis;
449 }
450 }
451
452 // prepare inputs, dimension orders and list of accepted IDs for exclusion of inactive detectors (D20)
453 std::tuple<int, int, int> dimOrder{2, 1, 0}; // scan - tube - pixel
454 std::set<int> acceptedIDs;
455 if (m_numberDetectorsActual != data.dim1() * data.dim2()) {
456 for (auto index = NUMBER_MONITORS; index < m_numberDetectorsActual + NUMBER_MONITORS; ++index)
457 acceptedIDs.insert(static_cast<detid_t>(index));
458 }
459 std::vector<int> customDetectorIDs;
460 // Assign detector counts
461 LoadHelper::fillMovingWorkspace(m_outWorkspace, data, axis, NUMBER_MONITORS, acceptedIDs, customDetectorIDs,
462 dimOrder);
463}
464
473void LoadILLDiffraction::fillStaticInstrumentScan(const NXInt &data, const NXDouble &scan, const double &twoTheta0) {
474
475 const std::vector<double> axis = getAxis(scan);
476 const std::vector<double> monitor = getMonitor(scan);
477
478 std::size_t startIndex = NUMBER_MONITORS;
479
480 // Assign monitor counts
481 m_outWorkspace->mutableX(0) = axis;
482 m_outWorkspace->mutableY(0) = monitor;
483 std::transform(monitor.begin(), monitor.end(), m_outWorkspace->mutableE(0).begin(), [](double e) { return sqrt(e); });
484
485 // prepare inputs, dimension orders and list of accepted IDs for exclusion of inactive detectors (D20)
486 std::tuple<int, int, int> dimOrder{2, 1, 0}; // scan - tube - pixel
487 std::set<detid_t> acceptedIDs;
488 if (m_numberDetectorsActual != data.dim1() * data.dim2()) {
489 for (std::size_t i = startIndex; i < startIndex + m_numberDetectorsActual; ++i)
490 acceptedIDs.insert(static_cast<detid_t>(i));
491 }
492 // Assign detector counts
493 LoadHelper::fillStaticWorkspace(m_outWorkspace, data, axis, startIndex, true, std::vector<int>(), acceptedIDs,
494 dimOrder);
495
496 // Link the instrument
498 // Move to the starting 2theta
499 moveTwoThetaZero(twoTheta0);
500}
501
506 H5File h5file(m_filename, H5F_ACC_RDONLY, Nexus::H5Util::defaultFileAcc());
507
508 Group entry0 = h5file.openGroup("entry0");
509 Group dataScan = entry0.openGroup("data_scan");
510 Group scanVar = dataScan.openGroup("scanned_variables");
511 Group varNames = scanVar.openGroup("variables_names");
512
513 const auto names = Nexus::H5Util::readStringVector(varNames, "name");
514 const auto properties = Nexus::H5Util::readStringVector(varNames, "property");
515 const auto units = Nexus::H5Util::readStringVector(varNames, "unit");
516
517 for (size_t i = 0; i < names.size(); ++i) {
518 m_scanVar.emplace_back(ScannedVariables(names[i], properties[i], units[i]));
519 }
520
521 varNames.close();
522 scanVar.close();
523 dataScan.close();
524 entry0.close();
525 h5file.close();
526}
527
533 auto absoluteTimes = getAbsoluteTimes(scan);
534 auto &mutableRun = m_outWorkspace->mutableRun();
535 for (size_t i = 0; i < m_scanVar.size(); ++i) {
536 if (!m_scanVar[i].property.starts_with("Monitor")) {
537 const std::string scanVarName = boost::algorithm::to_lower_copy(m_scanVar[i].name);
538 const std::string scanVarProp = boost::algorithm::to_lower_copy(m_scanVar[i].property);
539 const std::string propName = scanVarName + "." + scanVarProp;
540 if (m_scanVar[i].scanned == 1) {
541 mutableRun.addProperty("ScanVar", propName, true);
542 }
543 auto property = std::make_unique<TimeSeriesProperty<double>>(propName);
544 for (size_t j = 0; j < m_numberScanPoints; ++j) {
545 property->addValue(absoluteTimes[j], scan(static_cast<int>(i), static_cast<int>(j)));
546 }
547 mutableRun.addLogData(std::move(property), true);
548 }
549 }
550}
551
563 const std::string &propertyName) const {
564 std::vector<double> scannedVariable;
565
566 for (size_t i = 0; i < m_scanVar.size(); ++i) {
567 if (m_scanVar[i].property == propertyName) {
568 for (size_t j = 0; j < m_numberScanPoints; ++j) {
569 scannedVariable.emplace_back(scan(static_cast<int>(i), static_cast<int>(j)));
570 }
571 break;
572 }
573 }
574
575 if (scannedVariable.empty())
576 throw std::runtime_error("Can not load file because scanned variable with property name " + propertyName +
577 " was not found");
578
579 return scannedVariable;
580}
581
589std::vector<double> LoadILLDiffraction::getMonitor(const NXDouble &scan) const {
590
591 std::vector<double> monitor = {0.};
592 for (size_t i = 0; i < m_scanVar.size(); ++i) {
593 if ((m_scanVar[i].name == "Monitor1") || (m_scanVar[i].name == "Monitor_1") || (m_scanVar[i].name == "monitor1")) {
594 monitor.assign(scan() + m_numberScanPoints * i, scan() + m_numberScanPoints * (i + 1));
595 return monitor;
596 }
597 }
598 throw std::runtime_error("Monitors not found in scanned variables");
599}
600
606std::vector<double> LoadILLDiffraction::getAxis(const NXDouble &scan) const {
607
608 std::vector<double> axis = {0.};
609 if (m_scanType == OtherScan) {
610 for (size_t i = 0; i < m_scanVar.size(); ++i) {
611 if (m_scanVar[i].axis == 1) {
612 axis.assign(scan() + m_numberScanPoints * i, scan() + m_numberScanPoints * (i + 1));
613 break;
614 }
615 }
616 }
617 return axis;
618}
619
625std::vector<double> LoadILLDiffraction::getDurations(const NXDouble &scan) const {
626 std::vector<double> timeDurations;
627 for (size_t i = 0; i < m_scanVar.size(); ++i) {
628 if (m_scanVar[i].property.starts_with("Time")) {
629 timeDurations.assign(scan() + m_numberScanPoints * i, scan() + m_numberScanPoints * (i + 1));
630 break;
631 }
632 }
633 return timeDurations;
634}
635
641std::vector<DateAndTime> LoadILLDiffraction::getAbsoluteTimes(const NXDouble &scan) const {
642 std::vector<DateAndTime> times;
643 std::vector<double> durations = getDurations(scan);
644 DateAndTime time = m_startTime;
645 times.emplace_back(time);
646 size_t timeIndex = 1;
647 while (timeIndex < m_numberScanPoints) {
648 time += durations[timeIndex - 1];
649 times.emplace_back(time);
650 ++timeIndex;
651 }
652 return times;
653}
654
659 ScanType result = NoScan;
660 if (m_instName == "D2B") {
661 result = DetectorScan;
662 } else {
663 if (m_numberScanPoints != 1) {
664 for (const auto &scanVar : m_scanVar) {
665 if (scanVar.scanned == 1) {
666 result = OtherScan;
667 if (scanVar.name == "2theta") {
668 result = DetectorScan;
669 break;
670 }
671 }
672 }
673 }
674 }
675 m_scanType = result;
676}
677
683 if (m_instNames.find(m_instName) == m_instNames.end()) {
684 throw std::runtime_error("Instrument " + m_instName + " not supported.");
685 } else {
687 if (m_instName == "D20") {
688 // Here we have to hardcode the numbers of pixels.
689 // The only way is to read the size of the detectors read from the files
690 // and based on it decide which of the 3 alternative IDFs to load.
691 // Some amount of pixels are dead on at right end, these have to be
692 // subtracted
693 // correspondingly dependent on the resolution mode
694 m_resolutionMode = m_numberDetectorsRead / D20_NUMBER_PIXELS;
695 size_t activePixels = D20_NUMBER_PIXELS - 2 * D20_NUMBER_DEAD_PIXELS;
697
698 if (m_resolutionMode > 3 || m_resolutionMode < 1) {
699 throw std::runtime_error("Unknown resolution mode for instrument " + m_instName);
700 }
701 if (m_resolutionMode == 1) {
702 m_instName += "_lr";
703 } else if (m_resolutionMode == 3) {
704 m_instName += "_hr";
705 }
706 }
707 g_log.debug() << "Instrument name is " << m_instName << " and has " << m_numberDetectorsActual
708 << " actual detectors.\n";
709 }
710}
711
716void LoadILLDiffraction::moveTwoThetaZero(double twoTheta0Read) {
717 Instrument_const_sptr instrument = m_outWorkspace->getInstrument();
718 IComponent_const_sptr component = instrument->getComponentByName("detector");
719 double twoTheta0Actual = twoTheta0Read;
720 if (m_instName == "D20") {
721 twoTheta0Actual += m_offsetTheta;
722 }
723 Quat rotation(twoTheta0Actual, V3D(0, 1, 0));
724 g_log.debug() << "Setting 2theta0 to " << twoTheta0Actual;
725 auto &componentInfo = m_outWorkspace->mutableComponentInfo();
726 const auto componentIndex = componentInfo.indexOf(component->getComponentID());
727 componentInfo.setRotation(componentIndex, rotation);
728}
729
736std::string LoadILLDiffraction::getInstrumentFilePath(const std::string &instName) const {
737
738 std::filesystem::path directory(ConfigService::Instance().getInstrumentDirectory());
739 std::filesystem::path file(instName + "_Definition.xml");
740 std::filesystem::path fullPath = std::filesystem::path(directory) / file;
741 return fullPath.string();
742}
743
748 Run &run = m_outWorkspace->mutableRun();
749 std::string scanTypeStr = "NoScan";
750 if (m_scanType == DetectorScan) {
751 scanTypeStr = "DetectorScan";
752 } else if (m_scanType == OtherScan) {
753 scanTypeStr = "OtherScan";
754 }
755 run.addLogData(new PropertyWithValue<std::string>("ScanType", std::move(scanTypeStr)));
756 run.addLogData(new PropertyWithValue<double>("PixelSize", D20_PIXEL_SIZE / static_cast<double>(m_resolutionMode)));
757 std::string resModeStr = "Nominal";
758 if (m_resolutionMode == 1) {
759 resModeStr = "Low";
760 } else if (m_resolutionMode == 3) {
761 resModeStr = "High";
762 }
763 run.addLogData(new PropertyWithValue<std::string>("ResolutionMode", std::move(resModeStr)));
764 if (m_scanType != NoScan) {
765 run.addLogData(new PropertyWithValue<int>("ScanSteps", static_cast<int>(m_numberScanPoints)));
766 }
767 double eFixed;
768 if (run.hasProperty("wavelength")) {
769 double lambda = run.getLogAsSingleValue("wavelength");
770 eFixed = WAVE_TO_E / (lambda * lambda);
771 } else if (run.hasProperty("Monochromator.ei")) { // D4C, wavelength is not specified and Ei is provided directly
772 eFixed = run.getPropertyValueAsType<double>("Monochromator.ei");
773 } else {
774 throw std::runtime_error("Neither wavelength nor Monochromator.ei are not specified in the loaded file.");
775 }
776 run.addLogData(std::make_unique<Kernel::PropertyWithValue<double>>(PropertyWithValue<double>("Ei", eFixed)), true);
777 run.addLogData(new PropertyWithValue<size_t>("NumberOfDetectors", m_numberDetectorsActual));
778 if (m_pixelHeight != 0.) {
779 run.addLogData(new PropertyWithValue<double>("PixelHeight", m_pixelHeight));
780 }
781 if (m_maxHeight != 0.) {
782 run.addLogData(new PropertyWithValue<double>("MaxHeight", m_maxHeight));
783 }
784}
785
790 m_offsetTheta = static_cast<double>(D20_NUMBER_DEAD_PIXELS) * D20_PIXEL_SIZE -
791 D20_PIXEL_SIZE / (static_cast<double>(m_resolutionMode) * 2);
792}
793
798 auto extractor = createChildAlgorithm("ExtractSpectra");
799 extractor->setProperty("InputWorkspace", m_outWorkspace);
800 extractor->setProperty("StartWorkspaceIndex", 1);
801 extractor->setProperty("OutputWorkspace", "__unused");
802 extractor->execute();
803 API::MatrixWorkspace_sptr det = extractor->getProperty("OutputWorkspace");
804 auto converter = createChildAlgorithm("ConvertSpectrumAxis");
805 converter->setProperty("InputWorkspace", det);
806 converter->setProperty("OutputWorkspace", "__unused");
807 converter->setProperty("Target", "SignedTheta");
808 converter->execute();
809 API::MatrixWorkspace_sptr converted = converter->getProperty("OutputWorkspace");
810 auto transposer = createChildAlgorithm("Transpose");
811 transposer->setProperty("InputWorkspace", converted);
812 transposer->setProperty("OutputWorkspace", "__unused");
813 transposer->execute();
814 API::MatrixWorkspace_sptr transposed = transposer->getProperty("OutputWorkspace");
815 m_outWorkspace = transposed;
816}
817
818} // namespace Mantid::DataHandling
const std::vector< double > * lambda
std::map< DeltaEMode::Type, std::string > index
int64_t nSpectra
#define fabs(x)
Definition Matrix.cpp:22
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.
Kernel::Property * getPointerToProperty(const std::string &name) const override
Get a property by name.
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.
bool isDefault(const std::string &name) const
@ 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
void addLogData(Kernel::Property *p)
Add a log entry.
Definition LogManager.h:127
bool hasProperty(const std::string &name) const
Does the property exist on the object.
HeldType getPropertyValueAsType(const std::string &name) const
Get the value of a property as the given TYPE.
double getLogAsSingleValue(const std::string &name, Kernel::Math::StatisticType statistic=Kernel::Math::Mean) const
Definition LogManager.h:161
Helper class for reporting progress from algorithms.
Definition Progress.h:25
This class stores information regarding an experimental run as a series of log entries.
Definition Run.h:35
A property class for workspaces.
LoadILLDiffraction : Loads ILL diffraction nexus files.
std::vector< ScannedVariables > m_scanVar
holds the scan info
int version() const override
Algorithm's version for identification.
size_t m_sizeDim1
size of dim1, number of tubes (D2B) or the whole detector (D20)
size_t m_sizeDim2
size of dim2, number of pixels (1 for D20!)
size_t m_resolutionMode
resolution mode; 1:low, 2:nominal, 3:high
void moveTwoThetaZero(double)
Rotates the detector to the 2theta0 read from the file.
API::MatrixWorkspace_sptr m_outWorkspace
output workspace
void calculateRelativeRotations(std::vector< double > &instrumentAngles, const Kernel::V3D &firstTubePosition)
Convert from absolute rotation angle, around the sample, of tube 1, to a relative rotation angle arou...
std::map< std::string, std::string > validateInputs() override
Perform validation of ALL the input properties of the algorithm.
std::string m_instName
instrument name to load the IDF
size_t m_numberDetectorsRead
number of cells read from file
Kernel::V3D getReferenceComponentPosition(const API::MatrixWorkspace_sptr &instrumentWorkspace)
Get the position of the component in the workspace which corresponds to the angle stored in the scann...
void fillStaticInstrumentScan(const Nexus::NXInt &, const Nexus::NXDouble &, const double &)
Fills the loaded data to the workspace when the detector is not moving during the run,...
const std::string summary() const override
Algorithm's summary for use in the GUI and help.
std::vector< Types::Core::DateAndTime > getAbsoluteTimes(const Nexus::NXDouble &) const
Returns the vector of absolute times for each scan point.
std::string getInstrumentFilePath(const std::string &) const
Makes up the full path of the relevant IDF dependent on resolution mode.
const std::string category() const override
Algorithm's category for identification.
double m_pixelHeight
height of the pixel in D2B
void fillMovingInstrumentScan(const Nexus::NXInt &, const Nexus::NXDouble &)
Fills the counts for the instrument with moving detectors.
size_t m_numberDetectorsActual
number of cells actually active
ScanType m_scanType
NoScan, DetectorScan or OtherScan.
std::set< std::string > m_instNames
supported instruments
const std::string name() const override
Algorithms name for identification.
std::vector< double > getAxis(const Nexus::NXDouble &) const
Returns the x-axis.
std::vector< double > getScannedVaribleByPropertyName(const Nexus::NXDouble &scan, const std::string &propertyName) const
Gets a scanned variable based on its property type in the scanned_variables block.
void initStaticWorkspace()
Initializes the output workspace based on the resolved instrument, scan points, and scan type.
void initMovingWorkspace(const Nexus::NXDouble &scan)
Use the ScanningWorkspaceBuilder to create a time indexed workspace.
void computeThetaOffset()
Computes the 2theta offset of the decoder for D20.
void loadDataScan()
Loads the scanned detector data.
std::string m_filename
file name to load
void resolveInstrument()
Resolves the instrument based on instrument name and resolution mode.
void init() override
Initialize the algorithm's properties.
size_t m_numberScanPoints
number of scan points
double m_maxHeight
maximum absolute height of the D2B tubes
void setSampleLogs()
Adds some sample logs needed later by reduction.
void fillDataScanMetaData(const Nexus::NXDouble &)
Creates time series sample logs for the scanned variables.
std::vector< double > getMonitor(const Nexus::NXDouble &) const
Returns the monitor spectrum.
std::vector< double > getDurations(const Nexus::NXDouble &) const
Returns the durations in seconds for each scan point.
void exec() override
Executes the algorithm.
Types::Core::DateAndTime m_startTime
start time of acquisition
void convertAxisAndTranspose()
the 2theta offset for D20 to account for dead pixels
void loadScanVars()
Loads the scanned_variables/variables_names block.
void loadMetaData()
Dumps the metadata from the whole file to SampleLogs.
void resolveScanType()
Resolves the scan type.
ScanningWorkspaceBuilder : This is a helper class to make it easy to build a scanning workspace (a wo...
A simple structure that defines an axis-aligned cuboid shaped bounding box for a geometrical object.
Definition BoundingBox.h:33
double yMax() const
Return the maximum value of Y.
Definition BoundingBox.h:83
double yMin() const
Return the minimum value of Y.
Definition BoundingBox.h:81
The class Group represents a set of symmetry operations (or symmetry group).
Definition Group.h:135
IPropertyManager * setProperty(const std::string &name, const T &value)
Templated method to set the value of a PropertyWithValue.
void debug(const std::string &msg)
Logs at debug level.
Definition Logger.cpp:145
void notice(const std::string &msg)
Logs at notice level.
Definition Logger.cpp:126
The concrete, templated class for properties.
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...
Class for 3D vectors.
Definition V3D.h:34
void spherical(const double R, const double theta, const double phi) noexcept
Sets the vector position based on spherical coordinates.
Definition V3D.cpp:56
double angle(const V3D &) const
Angle between this and another vector.
Definition V3D.cpp:162
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.
void close()
Close this class.
NXInt openNXInt(const std::string &name) const
Creates and opens an integer dataset.
NXDataSetTyped< T > openNXDataSet(const std::string &name) const
Templated method for creating datasets.
Templated class implementation of NXDataSet.
void load()
Read all of the datablock in.
dimsize_t dim2() const
Returns the number of elements along the third dimension.
dimsize_t dim1() const
Returns the number of elements along the second dimension.
Implements NXentry Nexus class.
Implements NXroot Nexus class.
NXEntry openFirstEntry()
Open the first NXentry in the file.
std::shared_ptr< MatrixWorkspace > MatrixWorkspace_sptr
shared pointer to the matrix workspace base class
void fillMovingWorkspace(const API::MatrixWorkspace_sptr &, const Mantid::Nexus::NXInt &, const std::vector< double > &xAxis, int64_t initialSpectrum=0, const std::set< detid_t > &acceptedID=std::set< int >(), const std::vector< detid_t > &customID=std::vector< 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.
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::NXDouble getDoubleDataset(const Nexus::NXEntry &, const std::string &)
Fetches NXDouble 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.
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.
MANTID_NEXUS_DLL H5::FileAccPropList defaultFileAcc()
Default file access is H5F_CLOSE_STRONG.
Definition H5Util.cpp:119
MANTID_NEXUS_DLL std::vector< std::string > readStringVector(H5::Group &, const std::string &)
int32_t detid_t
Typedef for a detector ID.
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