Newer
Older
Russell Taylor
committed
//----------------------------------------------------------------------
// Includes
//----------------------------------------------------------------------
#include "MantidDataHandling/AlignDetectors.h"
Russell Taylor
committed
#include "MantidAPI/WorkspaceValidators.h"
Russell Taylor
committed
#include "MantidAPI/SpectraDetectorMap.h"
Russell Taylor
committed
#include "MantidKernel/UnitFactory.h"
#include "MantidKernel/PhysicalConstants.h"
Gigg, Martyn Anthony
committed
#include "MantidKernel/FileProperty.h"
Russell Taylor
committed
#include <fstream>
namespace Mantid
{
namespace DataHandling
{
// Register the algorithm into the algorithm factory
DECLARE_ALGORITHM(AlignDetectors)
using namespace Kernel;
using namespace API;
/// (Empty) Constructor
AlignDetectors::AlignDetectors()
{}
/// Destructor
AlignDetectors::~AlignDetectors()
{}
void AlignDetectors::init()
{
Russell Taylor
committed
CompositeValidator<> *wsValidator = new CompositeValidator<>;
wsValidator->add(new WorkspaceUnitValidator<>("TOF"));
wsValidator->add(new RawCountValidator<>);
Steve Williams
committed
declareProperty(
new WorkspaceProperty<API::MatrixWorkspace>("InputWorkspace","",Direction::Input,wsValidator),
"A workspace with units of TOF" );
declareProperty(
new WorkspaceProperty<API::MatrixWorkspace>("OutputWorkspace","",Direction::Output),
"The name to use for the output workspace" );
Gigg, Martyn Anthony
committed
declareProperty(new FileProperty("CalibrationFile", "", FileProperty::Load,
std::vector<std::string>(1,"cal")),
"The CalFile containing the position correction factors");
Russell Taylor
committed
}
/** Executes the algorithm
* @throw Exception::FileError If the calibration file cannot be opened and read successfully
* @throw Exception::InstrumentDefinitionError If unable to obtain the source-sample distance
*/
void AlignDetectors::exec()
{
// Get the input workspace
Roman Tolchenov
committed
const MatrixWorkspace_const_sptr inputWS = getProperty("InputWorkspace");
Russell Taylor
committed
// Read in the calibration data
const std::string calFileName = getProperty("CalibrationFile");
std::map<int,double> offsets;
if ( ! this->readCalFile(calFileName, offsets) )
{
throw Exception::FileError("Problem reading file", calFileName);
}
Roman Tolchenov
committed
API::MatrixWorkspace_sptr outputWS = getProperty("OutputWorkspace");
Russell Taylor
committed
// 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->getAxis(0)->unit() = UnitFactory::Instance().create("dSpacing");
// Get a pointer to the instrument contained in the workspace
IInstrument_const_sptr instrument = inputWS->getInstrument();
Russell Taylor
committed
// And one to the SpectraDetectorMap
Russell Taylor
committed
const SpectraDetectorMap& specMap = inputWS->spectraMap();
Russell Taylor
committed
// Get the distance between the source and the sample (assume in metres)
Geometry::IObjComponent_const_sptr sample = instrument->getSample();
Russell Taylor
committed
double l1;
try
{
l1 = instrument->getSource()->getDistance(*sample);
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 double constant = (PhysicalConstants::h * 1e10) / (2.0 * PhysicalConstants::NeutronMass * 1e6);
// Calculate the number of spectra in this workspace
const int numberOfSpectra = inputWS->size() / inputWS->blocksize();
// Initialise the progress reporting object
Sofia Antony
committed
Progress progress(this,0.0,1.0,numberOfSpectra);
Russell Taylor
committed
// Loop over the histograms (detector spectra)
for (int i = 0; i < numberOfSpectra; ++i)
{
try {
// Get the spectrum number for this histogram
const int spec = inputWS->getAxis(1)->spectraNo(i);
// Loop over the detectors that contribute to this spectrum and calculate the average correction
Russell Taylor
committed
const int ndets = specMap.ndet(spec);
const std::vector<int> dets = specMap.getDetectors(spec);
Russell Taylor
committed
double factor = 0.0;
for (int j = 0; j < ndets; ++j)
{
Russell Taylor
committed
Geometry::IDetector_const_sptr det = instrument->getDetector(dets[j]);
Russell Taylor
committed
// Get the sample-detector distance for this detector (in metres)
Russell Taylor
committed
const double l2 = det->getDistance(*sample);
Russell Taylor
committed
// The scattering angle for this detector (in radians).
Russell Taylor
committed
const double twoTheta = inputWS->detectorTwoTheta(det);
Russell Taylor
committed
// Get the correction for this detector
Russell Taylor
committed
const double offset = offsets[dets[j]];
Russell Taylor
committed
const double numerator = constant * (1.0+offset);
const double denom = ((l1+l2)*sin(twoTheta/2.0));
factor += numerator / denom;
}
// Now average the factor
factor = factor / ndets;
// Get a reference to the x data
const MantidVec& xIn = inputWS->dataX(i);
MantidVec& xOut = outputWS->dataX(i);
Russell Taylor
committed
std::transform( xIn.begin(), xIn.end(), xOut.begin(), std::bind2nd(std::multiplies<double>(), factor) );
// Copy the Y&E data
outputWS->dataY(i) = inputWS->dataY(i);
outputWS->dataE(i) = inputWS->dataE(i);
} catch (Exception::NotFoundError e) {
Roman Tolchenov
committed
// Zero the data in this case
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);
Russell Taylor
committed
}
progress.report();
Russell Taylor
committed
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
}
}
/// Reads the calibration file. Returns true for success, false otherwise.
bool AlignDetectors::readCalFile(const std::string& calFileName, std::map<int,double>& offsets)
{
std::ifstream grFile(calFileName.c_str());
if (!grFile)
{
g_log.error() << "Unable to open calibration file " << calFileName << std::endl;
return false;
}
offsets.clear();
std::string str;
while(getline(grFile,str))
{
if (str.empty() || str[0] == '#') continue;
std::istringstream istr(str);
int n,udet;
double offset;
istr >> n >> udet >> offset;
// Check the line wasn't badly formatted - return a failure if it is
if ( ! istr.good() ) return false;
offsets.insert(std::make_pair(udet,offset));
}
return true;
}
} // namespace DataHandling
} // namespace Mantid