Newer
Older
//---------------------------------------------------
// Includes
//---------------------------------------------------
#include "MantidDataHandling/LoadQKK.h"
#include "MantidAPI/FileProperty.h"
#include "MantidAPI/RegisterFileLoader.h"
#include "MantidAPI/WorkspaceValidators.h"
#include "MantidKernel/UnitFactory.h"
#include "MantidGeometry/Instrument.h"
#include "MantidGeometry/Instrument/RectangularDetector.h"
#include "MantidGeometry/Objects/ShapeFactory.h"
#include "MantidNexus/NexusClasses.h"
#include <boost/math/special_functions/fpclassify.hpp>
#include <Poco/File.h>
#include <fstream>
using namespace Mantid::DataHandling;
using namespace Mantid::API;
using namespace Mantid::Kernel;
namespace Mantid {
namespace DataHandling {
// Register the algorithm into the AlgorithmFactory
DECLARE_NEXUS_FILELOADER_ALGORITHM(LoadQKK)
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
/**
* Return the confidence with with this algorithm can load the file
* @param descriptor A descriptor for the file
* @returns An integer specifying the confidence level. 0 indicates it will not
* be used
*/
int LoadQKK::confidence(Kernel::NexusDescriptor &descriptor) const {
const auto &firstEntryName = descriptor.firstEntryNameType().first;
if (descriptor.pathExists("/" + firstEntryName + "/data/hmm_xy"))
return 80;
else
return 0;
}
/**
* Initialise the algorithm. Declare properties which can be set before
* execution (input) or
* read from after the execution (output).
*/
void LoadQKK::init() {
// Specify file extensions which can be associated with a QKK file.
std::vector<std::string> exts;
exts.push_back(".nx.hdf");
// Declare the Filename algorithm property. Mandatory. Sets the path to the
// file to load.
declareProperty(
new API::FileProperty("Filename", "", API::FileProperty::Load, exts),
"The input filename of the stored data");
// Declare the OutputWorkspace property. This sets the name of the workspace
// to be filled with the data
// from the file.
declareProperty(new API::WorkspaceProperty<>("OutputWorkspace", "",
Kernel::Direction::Output));
}
/**
* Execute the algorithm.
*/
void LoadQKK::exec() {
using namespace Mantid::API;
// Get the name of the file.
std::string filename = getPropertyValue("Filename");
// Open the root.
NeXus::NXRoot root(filename);
// Open the first NXentry found in the file.
NeXus::NXEntry entry = root.openFirstEntry();
// Open NXdata group with name "data"
NeXus::NXData data = entry.openNXData("data");
// Read in wavelength value
double wavelength = static_cast<double>(data.getFloat("wavelength"));
// open the data set with the counts. It is identified by the signal=1
// attribute
NeXus::NXInt hmm = data.openIntData();
// Read the data into memory
hmm.load();
// Get the wavelength spread
double wavelength_spread = static_cast<double>(
entry.getFloat("instrument/velocity_selector/wavelength_spread"));
double wavelength0 = wavelength - wavelength_spread / 2;
double wavelength1 = wavelength + wavelength_spread / 2;
// hmm is a 3d array with axes: sample_x, y_pixel_offset, x_pixel_offset
size_t ny = hmm.dim1(); // second dimension
size_t nx = hmm.dim2(); // third dimension
size_t nHist = ny * nx; // number of spectra in the dataset
if (nHist == 0) {
throw std::runtime_error("Error in data dimensions: " +
boost::lexical_cast<std::string>(ny) + " X " +
boost::lexical_cast<std::string>(nx));
}
// Set the workspace structure. The workspace will contain nHist spectra each
// having a single wavelength bin.
const size_t xWidth = 2; // number of wavelength bin boundaries
const size_t yWidth = 1; // number of bins
// Create a workspace with nHist spectra and a single y bin.
MatrixWorkspace_sptr outputWorkspace =
boost::dynamic_pointer_cast<MatrixWorkspace>(
WorkspaceFactory::Instance().create("Workspace2D", nHist, xWidth,
yWidth));
// Set the units of the x axis as Wavelength
outputWorkspace->getAxis(0)->unit() =
UnitFactory::Instance().create("Wavelength");
// Set the units of the data as Counts
outputWorkspace->setYUnitLabel("Counts");
// Put the data into outputWorkspace
size_t count = 0;
for (size_t i = 0; i < ny; ++i)
for (size_t j = 0; j < nx; ++j) {
// Move data across
double c = hmm(0, int(i), int(j));
outputWorkspace->dataX(count)[0] = wavelength0;
outputWorkspace->dataX(count)[1] = wavelength1;
outputWorkspace->dataY(count)[0] = c;
outputWorkspace->dataE(count)[0] = sqrt(c);
++count;
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
// Build instrument geometry
// Create a new instrument and set its name
std::string instrumentname = "QUOKKA";
Geometry::Instrument_sptr instrument(
new Geometry::Instrument(instrumentname));
outputWorkspace->setInstrument(instrument);
// Add dummy source and samplepos to instrument
// Create an instrument component wich will represent the sample position.
Geometry::ObjComponent *samplepos =
new Geometry::ObjComponent("Sample", instrument.get());
instrument->add(samplepos);
instrument->markAsSamplePos(samplepos);
// Put the sample in the centre of the coordinate system
samplepos->setPos(0.0, 0.0, 0.0);
// Create a component to represent the source
Geometry::ObjComponent *source =
new Geometry::ObjComponent("Source", instrument.get());
instrument->add(source);
instrument->markAsSource(source);
// Read in the L1 value and place the source at (0,0,-L1)
double l1 = static_cast<double>(entry.getFloat("instrument/parameters/L1"));
source->setPos(0.0, 0.0, -1.0 * l1);
// Create a component for the detector.
// We assumed that these are the dimensions of the detector, and height is in
// y direction and width is in x direction
double height =
static_cast<double>(entry.getFloat("instrument/detector/active_height"));
double width =
static_cast<double>(entry.getFloat("instrument/detector/active_width"));
// Convert them to metres
height /= 1000;
width /= 1000;
// We assumed that individual pixels have the same size and shape of a cuboid
// with dimensions:
double pixel_height = height / static_cast<double>(ny);
double pixel_width = width / static_cast<double>(nx);
// Create size strings for shape creation
std::string pixel_height_str =
boost::lexical_cast<std::string>(pixel_height / 2);
std::string pixel_width_str =
boost::lexical_cast<std::string>(pixel_width / 2);
// Set the depth of a pixel to a very small number
std::string pixel_depth_str = "0.00001";
// Create a RectangularDetector which represents a rectangular array of pixels
Geometry::RectangularDetector *bank =
new Geometry::RectangularDetector("bank", instrument.get());
// Define shape of a pixel as an XML string. See
// http://www.mantidproject.org/HowToDefineGeometricShape for details
// on shapes in Mantid.
std::string detXML =
"<cuboid id=\"pixel\">"
"<left-front-bottom-point x= \"" +
pixel_width_str + "\" y=\"-" + pixel_height_str +
"\" z=\"0\" />"
"<left-front-top-point x= \"" +
pixel_width_str + "\" y=\"-" + pixel_height_str + "\" z=\"" +
pixel_depth_str + "\" />"
"<left-back-bottom-point x=\"-" +
pixel_width_str + "\" y=\"-" + pixel_height_str +
"\" z=\"0\" />"
"<right-front-bottom-point x= \"" +
pixel_width_str + "\" y= \"" + pixel_height_str + "\" z=\"0\" />"
"</cuboid>";
// Create a shape object which will be shared by all pixels.
Geometry::Object_sptr shape = Geometry::ShapeFactory().createShape(detXML);
// Initialise the detector specifying the sizes.
bank->initialize(shape, int(nx), 0, pixel_width, int(ny), 0, pixel_height, 1,
true, int(nx));
for (int i = 0; i < static_cast<int>(ny); ++i)
for (int j = 0; j < static_cast<int>(nx); ++j) {
instrument->markAsDetector(bank->getAtXY(j, i).get());
// Position the detector so the z axis goes through its centre
bank->setPos(-width / 2, -height / 2, 0);
// Set the workspace title
outputWorkspace->setTitle(entry.getString("experiment/title"));
// Attach the created workspace to the OutputWorkspace property. The workspace
// will also be saved in AnalysisDataService
// and can be retrieved by its name.
setProperty("OutputWorkspace", outputWorkspace);
}
} // namespace
} // namespace