-
Notifications
You must be signed in to change notification settings - Fork 121
/
SaveIsawQvector.cpp
212 lines (183 loc) · 7.35 KB
/
SaveIsawQvector.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
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
129
130
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
211
212
#include "MantidMDAlgorithms/SaveIsawQvector.h"
#include <fstream>
#include "MantidAPI/FileProperty.h"
#include "MantidAPI/InstrumentValidator.h"
#include "MantidAPI/WorkspaceUnitValidator.h"
#include "MantidDataObjects/EventWorkspace.h"
#include "MantidKernel/CompositeValidator.h"
#include "MantidMDAlgorithms/MDTransfFactory.h"
#include "MantidMDAlgorithms/UnitsConversionHelper.h"
using namespace Mantid::API;
using namespace Mantid::Kernel;
using namespace Mantid::DataObjects;
namespace Mantid {
namespace MDAlgorithms {
// Register the algorithm into the AlgorithmFactory
DECLARE_ALGORITHM(SaveIsawQvector)
/// This only works for diffraction.
const std::string ELASTIC("Elastic");
/// Only convert to Q-vector.
const std::string Q3D("Q3D");
/// Q-vector is always three dimensional.
const std::size_t DIMS(3);
/// Constant for the size of the buffer to write to disk.
const std::size_t BUFF_SIZE(DIMS * sizeof(float));
//----------------------------------------------------------------------------------------------
/// Algorithm's name for identification. @see Algorithm::name
const std::string SaveIsawQvector::name() const { return "SaveIsawQvector"; }
/// Algorithm's version for identification. @see Algorithm::version
int SaveIsawQvector::version() const { return 1; }
/// Algorithm's category for identification. @see Algorithm::category
const std::string SaveIsawQvector::category() const {
return "DataHandling\\Isaw";
}
//----------------------------------------------------------------------------------------------
/** Initialize the algorithm's properties.
*/
void SaveIsawQvector::init() {
auto ws_valid = boost::make_shared<CompositeValidator>();
//
ws_valid->add<InstrumentValidator>();
// the validator which checks if the workspace has axis and any units
ws_valid->add<WorkspaceUnitValidator>("TOF");
declareProperty(make_unique<WorkspaceProperty<EventWorkspace>>(
"InputWorkspace", "", Direction::Input, ws_valid),
"An input EventWorkspace with units along X-axis and defined "
"instrument with defined sample");
declareProperty(
make_unique<FileProperty>("Filename", "", FileProperty::OptionalSave,
".bin"),
"Optional path to an hkl file to save. Vectors returned if no file "
"requested.");
declareProperty("RightHanded", true, "Save the Q-vector as k_f - k_i");
declareProperty(
"ISAWcoords", true,
"Save the Q-vector with y gravitationally up and x pointing downstream");
std::vector<double> Qx_save, Qy_save, Qz_save;
declareProperty("Qx_vector", Qx_save,
"The name of the vector in which to store the list of Qx",
Direction::Output);
declareProperty("Qy_vector", Qy_save,
"The name of the vector in which to store the list of Qy",
Direction::Output);
declareProperty("Qz_vector", Qz_save,
"The name of the vector in which to store the list of Qz",
Direction::Output);
}
//----------------------------------------------------------------------------------------------
/** Execute the algorithm.
*/
void SaveIsawQvector::exec() {
// get the input workspace
EventWorkspace_sptr wksp = getProperty("InputWorkspace");
// this only works for unweighted events
if (wksp->getEventType() != API::TOF) {
throw std::runtime_error("SaveIsawQvector only works for raw events");
}
// error out if there are not events
if (wksp->getNumberEvents() <= 0) {
throw std::runtime_error(
"SaveIsawQvector does not work for empty event lists");
}
// open the output file
std::string filename = getPropertyValue("Filename");
std::ofstream handle;
if (!filename.empty()) {
handle.open(filename.c_str(), std::ios::out | std::ios::binary);
if (!handle.is_open())
throw std::runtime_error("Failed to open file for writing");
}
// set up a descripter of where we are going
this->initTargetWSDescr(wksp);
size_t coord_map[DIMS] = {0, 1, 2}; // x->x, y->y, z->z
double coord_signs[DIMS] = {1., 1., 1.}; // signs are unchanged
if (this->getProperty("ISAWcoords")) {
// x -> z
coord_map[0] = 2;
// y -> x
coord_map[1] = 0;
// z -> y
coord_map[2] = 1;
}
if (this->getProperty("RightHanded")) {
for (double &coord_sign : coord_signs)
coord_sign *= -1.; // everything changes sign
}
// units conersion helper
UnitsConversionHelper unitConv;
unitConv.initialize(m_targWSDescr, "Momentum");
// initialize the MD coordinates conversion class
MDTransf_sptr q_converter =
MDTransfFactory::Instance().create(m_targWSDescr.AlgID);
q_converter->initialize(m_targWSDescr);
// set up the progress bar
const size_t numSpectra = wksp->getNumberHistograms();
Progress prog(this, 0.5, 1.0, numSpectra);
// loop through the eventlists
float buffer[DIMS];
std::vector<double> Qx_save, Qy_save, Qz_save;
for (std::size_t i = 0; i < numSpectra; ++i) {
// get a reference to the event list
const EventList &events = wksp->getSpectrum(i);
// check to see if the event list is empty
if (events.empty()) {
prog.report();
continue; // nothing to do
}
// update which pixel is being converted
std::vector<coord_t> locCoord(DIMS, 0.);
unitConv.updateConversion(i);
q_converter->calcYDepCoordinates(locCoord, i);
// loop over the events
double signal(1.); // ignorable garbage
double errorSq(1.); // ignorable garbage
const std::vector<TofEvent> &raw_events = events.getEvents();
for (const auto &raw_event : raw_events) {
double val = unitConv.convertUnits(raw_event.tof());
q_converter->calcMatrixCoord(val, locCoord, signal, errorSq);
for (size_t dim = 0; dim < DIMS; ++dim) {
buffer[dim] =
static_cast<float>(coord_signs[dim] * locCoord[coord_map[dim]]);
}
if (filename.empty()) {
Qx_save.push_back(static_cast<double>(buffer[0]));
Qy_save.push_back(static_cast<double>(buffer[1]));
Qz_save.push_back(static_cast<double>(buffer[2]));
} else
handle.write(reinterpret_cast<char *>(buffer), BUFF_SIZE);
} // end of loop over events in list
prog.report();
} // end of loop over spectra
if (filename.empty()) {
setProperty("Qx_vector", Qx_save);
setProperty("Qy_vector", Qy_save);
setProperty("Qz_vector", Qz_save);
} else
handle.close(); // cleanup
}
/**
* @brief SaveIsawQvector::initTargetWSDescr Initialize the output information
* for the MD conversion framework.
*
* @param wksp The workspace to get information from.
*/
void SaveIsawQvector::initTargetWSDescr(EventWorkspace_sptr wksp) {
m_targWSDescr.setMinMax(std::vector<double>(3, -2000.),
std::vector<double>(3, 2000.));
m_targWSDescr.buildFromMatrixWS(wksp, Q3D, ELASTIC);
m_targWSDescr.setLorentsCorr(false);
// generate the detectors table
Mantid::API::Algorithm_sptr childAlg =
createChildAlgorithm("PreprocessDetectorsToMD", 0., .5);
childAlg->setProperty("InputWorkspace", wksp);
childAlg->executeAsChildAlg();
DataObjects::TableWorkspace_sptr table =
childAlg->getProperty("OutputWorkspace");
if (!table)
throw(std::runtime_error(
"Can not retrieve results of \"PreprocessDetectorsToMD\""));
else
m_targWSDescr.m_PreprDetTable = table;
}
} // namespace MDAlgorithms
} // namespace Mantid