Newer
Older
#include "MantidDataHandling/LoadILLDiffraction.h"
#include "MantidGeometry/Instrument/ComponentHelper.h"
#include "MantidAPI/FileProperty.h"
#include "MantidAPI/MatrixWorkspace.h"
#include "MantidAPI/RegisterFileLoader.h"
#include "MantidAPI/WorkspaceFactory.h"
#include <numeric>
#include <boost/algorithm/string/predicate.hpp>
#include <H5Cpp.h>
#include <nexus/napi.h>
namespace Mantid {
namespace DataHandling {
using namespace API;
using namespace Geometry;
using namespace H5;
using namespace NeXus;
// Register the algorithm into the AlgorithmFactory
DECLARE_NEXUS_FILELOADER_ALGORITHM(LoadILLDiffraction)
/// Returns confidence. @see IFileLoader::confidence
int LoadILLDiffraction::confidence(NexusDescriptor &descriptor) const {
// fields existent only at the ILL Diffraction
if (descriptor.pathExists("/entry0/data_scan")) {
return 80;
} else {
return 0;
}
}
/// Algorithms name for identification. @see Algorithm::name
const std::string LoadILLDiffraction::name() const {
return "LoadILLDiffraction";
}
/// Algorithm's version for identification. @see Algorithm::version
int LoadILLDiffraction::version() const { return 1; }
/// Algorithm's category for identification. @see Algorithm::category
const std::string LoadILLDiffraction::category() const {
return "DataHandling\\Nexus;ILL\\Diffraction";
}
/// Algorithm's summary for use in the GUI and help. @see Algorithm::summary
const std::string LoadILLDiffraction::summary() const {
return "Loads ILL diffraction nexus files.";
/**
* Constructor
*/
LoadILLDiffraction::LoadILLDiffraction()
: IFileLoader<NexusDescriptor>(), m_instNames({"D20"}) {}
/**
* Initialize the algorithm's properties.
*/
void LoadILLDiffraction::init() {
declareProperty(
make_unique<FileProperty>("Filename", "", FileProperty::Load, ".nxs"),
declareProperty(make_unique<WorkspaceProperty<Workspace>>(
"OutputWorkspace", "", Direction::Output),
*/
void LoadILLDiffraction::exec() {
m_fileName = getPropertyValue("Filename");
loadScannedVariables();
progress.report("Loaded the scanned variables");
loadDataScan();
progress.report("Loaded the detector scan data");
setProperty("OutputWorkspace", m_outWorkspace);
}
/**
void LoadILLDiffraction::loadDataScan() {
// open the root entry
NXRoot dataRoot(m_fileName);
NXEntry firstEntry = dataRoot.openFirstEntry();
m_instName = firstEntry.getString("instrument/name");
// read the detector data
NXData dataGroup = firstEntry.openNXData("data_scan/detector_data");
NXUInt data = dataGroup.openUIntData();
// read the scan data
NXData scanGroup = firstEntry.openNXData("data_scan/scanned_variables");
NXDouble scan = scanGroup.openDoubleData();
scan.load();
// read which variables are scanned
NXInt scanned = firstEntry.openNXInt(
"data_scan/scanned_variables/variables_names/scanned");
scanned.load();
// read what is going to be the axis
NXInt axis =
firstEntry.openNXInt("data_scan/scanned_variables/variables_names/axis");
axis.load();
NXFloat twoTheta0 = firstEntry.openNXFloat("instrument/2theta/value");
twoTheta0.load();
m_numberDetectorsRead = static_cast<size_t>(data.dim1());
m_numberScanPoints = static_cast<size_t>(data.dim0());
for (size_t i = 0; i < m_scanVar.size(); ++i) {
int ii = static_cast<int>(i);
m_scanVar[i].setAxis(axis[ii]);
m_scanVar[i].setScanned(scanned[ii]);
}
fillMovingInstrumentScan(data, scan);
fillStaticInstrumentScan(data, scan, twoTheta0);
scanGroup.close();
dataGroup.close();
firstEntry.close();
dataRoot.close();
* Dumps the metadata from the whole file to SampleLogs
*/
void LoadILLDiffraction::loadMetadata() {
m_outWorkspace->mutableRun().addProperty("Facility", std::string("ILL"));
// Open NeXus file
NXhandle nxHandle;
NXstatus nxStat = NXopen(m_fileName.c_str(), NXACC_READ, &nxHandle);
if (nxStat != NX_ERROR) {
m_loadHelper.addNexusFieldsToWsRun(nxHandle, m_outWorkspace->mutableRun());
nxStat = NXclose(&nxHandle);
}
* Fills the loaded data to the workspace when the detector
* is not moving during the run, but can be moved before
* @param data : detector data
* @param scan : scan data
* @param twoTheta0 : starting two theta
*/
void LoadILLDiffraction::fillStaticInstrumentScan(const NXUInt &data,
const NXDouble &scan,
const NXFloat &twoTheta0) {
std::vector<double> axis = getAxis(scan);
std::vector<double> monitor = getMonitor(scan);
// Assign monitor counts
m_outWorkspace->mutableY(0) = monitor;
std::transform(monitor.begin(), monitor.end(),
m_outWorkspace->mutableE(0).begin(), sqrt);
// Assign detector counts
size_t deadOffset = (m_numberDetectorsRead - m_numberDetectorsActual) / 2;
for (size_t i = 1; i <= m_numberDetectorsActual; ++i) {
for (size_t j = 0; j < m_numberScanPoints; ++j) {
unsigned int y =
data(static_cast<int>(j), static_cast<int>(i - 1 + deadOffset));
m_outWorkspace->mutableY(i)[j] = y;
m_outWorkspace->mutableE(i)[j] = sqrt(y);
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
loadStaticInstrument();
// Move to the starting 2theta
moveTwoThetaZero(double(twoTheta0[0]));
}
/**
* Loads the scanned_variables/variables_names block
*/
void LoadILLDiffraction::loadScannedVariables() {
H5File h5file(m_fileName, H5F_ACC_RDONLY);
Group entry0 = h5file.openGroup("entry0");
Group dataScan = entry0.openGroup("data_scan");
Group scanVar = dataScan.openGroup("scanned_variables");
Group varNames = scanVar.openGroup("variables_names");
const auto names = H5Util::readStringVector(varNames, "name");
const auto properties = H5Util::readStringVector(varNames, "property");
const auto units = H5Util::readStringVector(varNames, "unit");
for (size_t i = 0; i < names.size(); ++i) {
m_scanVar.emplace_back(
ScannedVariables(names[i], properties[i], units[i]));
}
varNames.close();
scanVar.close();
dataScan.close();
entry0.close();
h5file.close();
}
/**
* Creates sample logs for the scanned variables
* @param scan : scan data
*/
void LoadILLDiffraction::fillDataScanMetaData(const NXDouble &scan) const {
std::map<std::string, std::string> logs;
for (size_t i = 0; i < m_scanVar.size(); ++i) {
if (m_scanVar[i].axis != 1 &&
!boost::starts_with(m_scanVar[i].name, "Monitor")) {
std::string key = m_scanVar[i].name;
std::string value;
if (m_scanVar[i].scanned == 1) {
// keep the list
for (size_t j = 0; j < m_numberScanPoints; ++j) {
value +=
std::to_string(scan(static_cast<int>(i), static_cast<int>(j))) +
",";
}
value = value.substr(0, value.size() - 1);
} else {
// average
double avg = std::accumulate(scan() + i * m_numberScanPoints,
scan() + (i + 1) * m_numberScanPoints, 0.);
value = std::to_string(avg / m_numberScanPoints);
}
logs[key] = value;
}
}
for(const auto& item : logs) {
m_outWorkspace->mutableRun().addProperty(item.first, item.second);
}
}
/**
* Returns the monitor spectrum
* @param scan : scan data
* @return monitor spectrum
*/
std::vector<double> LoadILLDiffraction::getMonitor(const NXDouble &scan) const {
std::vector<double> monitor = {0.};
for (size_t i = 0; i < m_scanVar.size(); ++i) {
if (m_scanVar[i].name == "Monitor1") {
monitor.assign(scan() + m_numberScanPoints * i,
scan() + m_numberScanPoints * (i + 1));
break;
}
}
return monitor;
}
/**
* Returns the x-axis
* @param scan : scan data
* @return the x-axis
*/
std::vector<double> LoadILLDiffraction::getAxis(const NXDouble &scan) const {
std::vector<double> axis = {0.};
if (m_scanType == OtherScan) {
for (size_t i = 0; i < m_scanVar.size(); ++i) {
if (m_scanVar[i].axis == 1) {
axis.assign(scan() + m_numberScanPoints * i,
scan() + m_numberScanPoints * (i + 1));
break;
}
}
}
return axis;
}
/**
* Resolves the scan type
*/
void LoadILLDiffraction::resolveScanType() {
ScanType result = NoScan;
for (const auto &scanVar : m_scanVar) {
if (scanVar.scanned == 1) {
result = OtherScan;
result = DetectorScan;
break;
}
}
}
m_scanType = result;
/**
* Resolves the instrument based on instrument name and resolution mode
* @throws runtime_error, if the instrument is not supported
void LoadILLDiffraction::resolveInstrument() {
if (m_instNames.find(m_instName) == m_instNames.end()) {
throw std::runtime_error("Instrument " + m_instName + " not supported.");
m_numberDetectorsActual = m_numberDetectorsRead;
if (m_instName == "D20") {
switch (m_numberDetectorsRead) {
case 1600: {
// low resolution mode
m_instName += "_lr";
m_numberDetectorsActual = 1536;
break;
}
case 3200: {
// nominal resolution
m_numberDetectorsActual = 3072;
break;
}
case 4800: {
// high resolution mode
m_instName += "_hr";
m_numberDetectorsActual = 4608;
break;
}
default:
throw std::runtime_error("Unknown resolution mode for instrument " +
}
}
}
}
/**
* Initializes the output workspace based on the resolved instrument, scan
* points, and scan type
*/
void LoadILLDiffraction::initWorkspace() {
size_t nSpectra = m_numberDetectorsActual + 1, nBins = 1;
if (m_scanType == DetectorScan) {
nSpectra *= m_numberScanPoints;
} else if (m_scanType == OtherScan) {
nBins = m_numberScanPoints;
m_outWorkspace = WorkspaceFactory::Instance().create("Workspace2D", nSpectra,
nBins, nBins);
}
/**
* Runs LoadInstrument as child to link the non-moving instrument to workspace
*/
void LoadILLDiffraction::loadStaticInstrument() {
IAlgorithm_sptr loadInst = createChildAlgorithm("LoadInstrument");
loadInst->setPropertyValue("InstrumentName", m_instName);
loadInst->setProperty<MatrixWorkspace_sptr>("Workspace", m_outWorkspace);
loadInst->setProperty("RewriteSpectraMap", OptionalBool(true));
loadInst->execute();
/**
* Rotates the detector to the 2theta0 read from the file
*/
void LoadILLDiffraction::moveTwoThetaZero(double twoTheta0) {
Instrument_const_sptr instrument = m_outWorkspace->getInstrument();
IComponent_const_sptr component = instrument->getComponentByName("detector");
Quat rotation(twoTheta0, V3D(0, 1, 0));
g_log.debug() << "Setting 2theta0 to " << twoTheta0;
m_outWorkspace->mutableDetectorInfo().setRotation(*component, rotation);
} // namespace DataHandling
} // namespace Mantid