Newer
Older
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
//----------------------------------------------------------------------
// Includes
//----------------------------------------------------------------------
#include "MantidAlgorithms/ConvertUnits.h"
#include "MantidAPI/WorkspaceProperty.h"
namespace Mantid
{
namespace Algorithms
{
// Register with the algorithm factory
DECLARE_ALGORITHM(ConvertUnits)
using namespace Kernel;
using namespace API;
// Get a reference to the logger
Logger& ConvertUnits::g_log = Logger::get("ConvertUnits");
/// Default constructor
ConvertUnits::ConvertUnits() : Algorithm()
{
}
/// Destructor
ConvertUnits::~ConvertUnits()
{
}
/// Initialisation method
void ConvertUnits::init()
{
declareProperty(new WorkspaceProperty<Workspace>("InputWorkspace","",Direction::Input));
declareProperty(new WorkspaceProperty<Workspace>("OutputWorkspace","",Direction::Output));
declareProperty("Target","",new MandatoryValidator);
}
/** Executes the algorithm
Russell Taylor
committed
* @throw std::runtime_error If the input workspace has not had its unit set
* @throw NotImplementedError If the input workspace contains point (not histogram) data
* @throw InstrumentDefinitionError If unable to calculate source-sample distance
*/
void ConvertUnits::exec()
{
// Get the workspace
Workspace_sptr inputWS = getProperty("InputWorkspace");
// Check that the workspace is histogram data
if (inputWS->dataX(0).size() == inputWS->dataY(0).size())
{
g_log.error("Conversion of units for point data is not yet implemented");
throw Exception::NotImplementedError("Conversion of units for point data is not yet implemented");
}
Russell Taylor
committed
// Check that the input workspace has had its unit set
if ( ! inputWS->XUnit() )
{
g_log.error("Input workspace has not had its unit set");
throw std::runtime_error("Input workspace has not had its unit set");
}
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
// Calculate the number of spectra in this workspace
const int numberOfSpectra = inputWS->size() / inputWS->blocksize();
Workspace_sptr outputWS = getProperty("OutputWorkspace");
// If input and output workspaces are not the same, create a new workspace for the output
if (outputWS != inputWS )
{
outputWS = WorkspaceFactory::Instance().create(inputWS);
setProperty("OutputWorkspace",outputWS);
}
// Set the final unit that our output workspace will have
outputWS->XUnit() = UnitFactory::Instance().create(getPropertyValue("Target"));
// Check whether the Y data of the input WS is dimensioned and set output WS flag to be same
bool distribution = outputWS->isDistribution(inputWS->isDistribution());
// Get a reference to the instrument contained in the workspace
API::Instrument &instrument = inputWS->getInstrument();
// Get the distance between the source and the sample (assume in metres)
Geometry::ObjComponent &samplePos = *instrument.getSamplePos();
double l1;
try
{
l1 = instrument.getSource()->getDistance(samplePos);
g_log.debug() << "Source-sample distance: " << l1 << std::endl;
}
catch (Exception::NotFoundError e)
{
g_log.error("Unable to calculate source-sample distance");
throw Exception::InstrumentDefinitionError("Unable to calculate source-sample distance", inputWS->getTitle());
}
const int notFailed = -99;
int failedDetectorIndex = notFailed;
// Not doing anything with the Y vector in to/fromTOF yet, so just pass empty vector
std::vector<double> emptyVec;
unsigned int size = inputWS->blocksize();
// Loop over the histograms (detector spectra)
for (int i = 0; i < numberOfSpectra; ++i) {
// Take the bin width dependency out of the Y & E data
if (distribution)
{
for (unsigned int j = 0; j < size; ++j)
{
double width = std::abs( inputWS->dataX(i)[j+1] - inputWS->dataX(i)[j] );
outputWS->dataY(i)[j] = inputWS->dataY(i)[j]*width;
outputWS->dataE(i)[j] = inputWS->dataE(i)[j]*width;
}
}
else
{
// Just copy over
outputWS->dataY(i) = inputWS->dataY(i);
outputWS->dataE(i) = inputWS->dataE(i);
// Will also need to deal with E2
}
// Copy over the X data (no copying will happen if the two workspaces are the same)
outputWS->dataX(i) = inputWS->dataX(i);
// No implementation for any of these in the geometry yet
const double twoTheta = 1.0;
const int emode = 1;
const double efixed = 1.0;
const double delta = 1.0;
try {
// Get the sample-detector distance for this detector (in metres)
const double l2 = instrument.getDetector(i)->getDistance(samplePos);
if (failedDetectorIndex != notFailed)
{
g_log.information() << "Unable to calculate sample-detector[" << failedDetectorIndex << "-" << i-1 << "] distance. Zeroing spectrum." << std::endl;
failedDetectorIndex = notFailed;
}
// Convert the input unit to time-of-flight
inputWS->XUnit()->toTOF(outputWS->dataX(i),emptyVec,l1,l2,twoTheta,emode,efixed,delta);
// Convert from time-of-flight to the desired unit
outputWS->XUnit()->fromTOF(outputWS->dataX(i),emptyVec,l1,l2,twoTheta,emode,efixed,delta);
if (distribution)
{
// There must be good case for having a 'divideByBinWidth'/'normalise' algorithm...
for (unsigned int j = 0; j < size; ++j)
{
double width = std::abs( outputWS->dataX(i)[j+1] - outputWS->dataX(i)[j] );
outputWS->dataY(i)[j] = inputWS->dataY(i)[j]/width;
outputWS->dataE(i)[j] = inputWS->dataE(i)[j]/width;
// Will also need to deal with E2
}
}
} catch (Exception::NotFoundError e) {
// Get to here if exception thrown when calculating distance to detector
// WHAT IF THIS CONVERSION DOESN'T NEED TO KNOW L2?????
if (failedDetectorIndex == notFailed)
{
failedDetectorIndex = i;
}
outputWS->dataX(i).assign(outputWS->dataX(i).size(),0.0);
outputWS->dataY(i).assign(outputWS->dataY(i).size(),0.0);
outputWS->dataE(i).assign(outputWS->dataE(i).size(),0.0);
}
} // loop over spectra
if (failedDetectorIndex != notFailed)
{
g_log.information() << "Unable to calculate sample-detector[" << failedDetectorIndex << "-" << numberOfSpectra-1 << "] distance. Zeroing spectrum." << std::endl;
}
}
} // namespace Algorithm
} // namespace Mantid