Newer
Older
Janik Zikovsky
committed
/*WIKI*
Loads a Dspacemap file (POWGEN binary, VULCAN binary or ascii format) into an OffsetsWorkspace.
The resulting workspace can then be used with, e.g. [[AlignDetectors]] to perform calibration.
*WIKI*/
#include "MantidAPI/FileProperty.h"
#include "MantidAPI/SpectraDetectorMap.h"
#include "MantidAPI/WorkspaceValidators.h"
#include "MantidDataHandling/LoadCalFile.h"
#include "MantidDataHandling/LoadDspacemap.h"
#include "MantidDataObjects/EventWorkspace.h"
#include "MantidDataObjects/GroupingWorkspace.h"
#include "MantidDataObjects/OffsetsWorkspace.h"
Gigg, Martyn Anthony
committed
#include "MantidKernel/V3D.h"
#include "MantidKernel/BinaryFile.h"
#include "MantidKernel/PhysicalConstants.h"
#include "MantidKernel/System.h"
#include "MantidKernel/UnitFactory.h"

Zhou, Wenduo
committed
#include "MantidGeometry/IDetector.h"
#include "MantidKernel/ListValidator.h"
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
using namespace Mantid::Kernel;
using namespace Mantid::API;
using namespace Mantid::Geometry;
using namespace Mantid::DataObjects;
namespace Mantid
{
namespace DataHandling
{
// Register the algorithm into the AlgorithmFactory
DECLARE_ALGORITHM(LoadDspacemap)
//----------------------------------------------------------------------------------------------
/** Constructor
*/
LoadDspacemap::LoadDspacemap()
{
}
//----------------------------------------------------------------------------------------------
/** Destructor
*/
LoadDspacemap::~LoadDspacemap()
{
}
//----------------------------------------------------------------------------------------------
/// Sets documentation strings for this algorithm
void LoadDspacemap::initDocs()
{
this->setWikiSummary("Loads a Dspacemap file (POWGEN binary, VULCAN binary or ascii format) into an OffsetsWorkspace.");
this->setOptionalMessage("Loads a Dspacemap file (POWGEN binary, VULCAN binary or ascii format) into an OffsetsWorkspace.");
}
//----------------------------------------------------------------------------------------------
/** Initialize the algorithm's properties.
*/
void LoadDspacemap::init()
{
// 3 properties for getting the right instrument
LoadCalFile::getInstrument3WaysInit(this);
std::vector< std::string > exts;
exts.push_back(".dat");
exts.push_back(".bin");
Janik Zikovsky
committed
declareProperty(new FileProperty("Filename", "", FileProperty::Load, exts),
"The DspacemapFile containing the d-space mapping.");
std::vector<std::string> propOptions;
propOptions.push_back("POWGEN");
propOptions.push_back("VULCAN-ASCII");
propOptions.push_back("VULCAN-Binary");
declareProperty("FileType", "POWGEN", boost::make_shared<StringListValidator>(propOptions),
"The type of file being read.");
declareProperty(new WorkspaceProperty<OffsetsWorkspace>("OutputWorkspace","",Direction::Output),
"An output OffsetsWorkspace.");
}
//----------------------------------------------------------------------------------------------
/** Execute the algorithm.
*/
void LoadDspacemap::exec()
{
// Get the instrument
Russell Taylor
committed
Instrument_const_sptr inst = LoadCalFile::getInstrument3Ways(this);
// Read in the calibration data
Janik Zikovsky
committed
const std::string DFileName = getProperty("Filename");
// Create the blank output
OffsetsWorkspace_sptr offsetsWS(new OffsetsWorkspace(inst));
setProperty("OutputWorkspace", offsetsWS);
std::string type = this->getPropertyValue("FileType");
if (type == "POWGEN")
{
// generate map of the tof->d conversion factors
CalculateOffsetsFromDSpacemapFile(DFileName, offsetsWS);
}
else
{
// Map of udet:funny vulcan correction factor.
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
if (type == "VULCAN-ASCII")
{
readVulcanAsciiFile(DFileName, vulcan);
}
else if (type == "VULCAN-Binary")
{
readVulcanBinaryFile(DFileName, vulcan);
}
else
throw std::invalid_argument("Unexpected FileType property value received.");
// Now that we have loaded the vulcan file (either type), convert it out.
this->CalculateOffsetsFromVulcanFactors(vulcan, offsetsWS);
}
}
//-----------------------------------------------------------------------
/**
* Make a map of the conversion factors between tof and D-spacing
* for all pixel IDs in a workspace.
*
* @param DFileName :: name of dspacemap file
* @param offsetsWS :: OffsetsWorkspace to be filled.
*/
void LoadDspacemap::CalculateOffsetsFromDSpacemapFile(const std::string DFileName,
Mantid::DataObjects::OffsetsWorkspace_sptr offsetsWS)
{
// Get a pointer to the instrument contained in the workspace
Russell Taylor
committed
Instrument_const_sptr instrument = offsetsWS->getInstrument();
double l1;
Gigg, Martyn Anthony
committed
Kernel::V3D beamline,samplePos;
double beamline_norm;
instrument->getInstrumentParameters(l1,beamline,beamline_norm, samplePos);
//To get all the detector ID's
instrument->getDetectors(allDetectors);
//Read in the POWGEN-style Dspace mapping file
const char * filename = DFileName.c_str();
std::ifstream fin(filename, std::ios_base::in|std::ios_base::binary);
std::vector<double> dspace;
double read;
while (!fin.eof( ))
{
fin.read( reinterpret_cast<char*>( &read ), sizeof read );
//Factor of 10 between ISAW and Mantid
read*=10.;
dspace.push_back(read);
}
for (it = allDetectors.begin(); it != allDetectors.end(); ++it)
Russell Taylor
committed
Geometry::IDetector_const_sptr det = it->second;
//Compute the factor
double offset = 0.0;

Zhou, Wenduo
committed
double factor = Instrument::calcConversion(l1, beamline, beamline_norm, samplePos, det, offset);
offset=dspace[detectorID]/factor -1.0 ;
// Save in the map
try
{
offsetsWS->setValue(detectorID, offset);
}
catch (std::invalid_argument & )
{}
}
}

Zhou, Wenduo
committed
const double CONSTANT = (PhysicalConstants::h * 1e10) / (2.0 * PhysicalConstants::NeutronMass * 1e6);
//-----------------------------------------------------------------------
/**
* Make a map of the conversion factors between tof and D-spacing
* for all pixel IDs in a workspace.

Zhou, Wenduo
committed
* map vulcan should contain the module/module and stack/stack offset
*
* @param vulcan :: map between detector ID and vulcan correction factor.
* @param offsetsWS :: OffsetsWorkspace to be filled.
*/
void LoadDspacemap::CalculateOffsetsFromVulcanFactors(std::map<detid_t, double> & vulcan,
Mantid::DataObjects::OffsetsWorkspace_sptr offsetsWS)
{
// Get a pointer to the instrument contained in the workspace

Zhou, Wenduo
committed
// At this point, instrument VULCAN has been created?
Russell Taylor
committed
Instrument_const_sptr instrument = offsetsWS->getInstrument();

Zhou, Wenduo
committed
g_log.notice() << "Name of instrument = " << instrument->getName() << std::endl;
g_log.notice() << "Input map (dict): size = " << vulcan.size() << std::endl;
// To get all the detector ID's
instrument->getDetectors(allDetectors);

Zhou, Wenduo
committed
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
int numfinds = 0;
g_log.notice() << "Input number of detectors = " << allDetectors.size() << std::endl;
// Get detector information
double l1, beamline_norm;
Kernel::V3D beamline,samplePos;
instrument->getInstrumentParameters(l1,beamline,beamline_norm, samplePos);
/*** A survey of parent detector
std::map<detid_t, bool> parents;
for (it = allDetectors.begin(); it != allDetectors.end(); it++){
int32_t detid = it->first;
// def boost::shared_ptr<const Mantid::Geometry::IDetector> IDetector_const_sptr;
std::string parentname = it->second->getParent()->getComponentID()->getName();
g_log.notice() << "Name = " << parentname << std::endl;
// parents.insert(parentid, true);
}
***/
/*** Here some special configuration for VULCAN is hard-coded here!
* Including (1) Super-Parent Information
***/
Kernel::V3D referencePos;
detid_t anydetinrefmodule = 21*1250+5;
std::map<detid_t, Geometry::IDetector_const_sptr>::iterator det_iter = allDetectors.find(anydetinrefmodule);
if (det_iter == allDetectors.end()){
throw std::invalid_argument("Any Detector ID is Instrument's detector");
}
referencePos = det_iter->second->getParent()->getPos();
double refl2 = referencePos.norm();
double halfcosTwoThetaRef = referencePos.scalar_prod(beamline)/(refl2*beamline_norm);
double sinThetaRef = sqrt(0.5-halfcosTwoThetaRef);
double difcRef = sinThetaRef*(l1+refl2)/CONSTANT;
// Loop over all detectors in instrument to find the offset
for (it = allDetectors.begin(); it != allDetectors.end(); ++it)
{
int detectorID = it->first;
Russell Taylor
committed
Geometry::IDetector_const_sptr det = it->second;
double offset = 0.0;
// Find the vulcan factor;
double vulcan_factor = 0.0;
std::map<detid_t,double>::const_iterator vulcan_iter = vulcan.find(detectorID);

Zhou, Wenduo
committed
if( vulcan_iter != vulcan.end() ){
vulcan_factor = vulcan_iter->second;

Zhou, Wenduo
committed
numfinds ++;
}
// g_log.notice() << "Selected Detector with ID = " << detectorID << " ID2 = " << id2 << std::endl; proved to be same
double intermoduleoffset = 0;
double interstackoffset = 0;
detid_t intermoduleid = detid_t(detectorID/1250)*1250+1250-2;
vulcan_iter = vulcan.find(intermoduleid);
if (vulcan_iter == vulcan.end()){
g_log.error() << "Cannot find inter-module offset ID = " << intermoduleid << std::endl;
} else {
intermoduleoffset = vulcan_iter->second;
}
detid_t interstackid = detid_t(detectorID/1250)*1250+1250-1;
vulcan_iter = vulcan.find(interstackid);
if (vulcan_iter == vulcan.end()){
g_log.error() << "Cannot find inter-module offset ID = " << intermoduleid << std::endl;
} else {
interstackoffset = vulcan_iter->second;
}
/*** This is the previous way to correct upon DIFC[module center pixel]
// The actual factor is 10^(-value_in_the_file)
vulcan_factor = pow(10.0,-vulcan_factor);
// At this point, tof_corrected = vulcan_factor * tof_input
// So this is the offset
offset = vulcan_factor - 1.0;

Zhou, Wenduo
committed
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
326
327
***/
/*** New approach to correct based on DIFC of each pixel
* Equation: offset = DIFC^(pixel)/DIFC^(parent)*(1+vulcan_offset)-1
* offset should be close to 0
***/
// 1. calculate DIFC
Kernel::V3D detPos;
detPos = det->getPos();
// Now detPos will be set with respect to samplePos
detPos -= samplePos;
double l2 = detPos.norm();
double halfcosTwoTheta = detPos.scalar_prod(beamline) / (l2 * beamline_norm);
double sinTheta = sqrt(0.5 - halfcosTwoTheta);
double difc_pixel = sinTheta*(l1+l2)/CONSTANT;
// Kernel::V3D parentPos = det->getParent()->getPos();
// parentPos -= samplePos;
// double l2parent = parentPos.norm();
// double halfcosTwoThetaParent = parentPos.scalar_prod(beamline)/(l2 * beamline_norm);
// double sinThetaParent = sqrt(0.5 - halfcosTwoThetaParent);
// double difc_parent = sinThetaParent*(l1+l2parent)/CONSTANT;
/*** Offset Replicate Previous Result
offset = difc_pixel/difc_parent*(pow(10.0, -vulcan_factor))-1.0;
***/
offset = difc_pixel/difcRef*(pow(10.0, -(vulcan_factor+intermoduleoffset+interstackoffset)))-1.0;
// Save in the map
try
{
offsetsWS->setValue(detectorID, offset);

Zhou, Wenduo
committed
if (intermoduleid != 27498 &&
intermoduleid != 28748 &&
intermoduleid != 29998 &&
intermoduleid != 33748 &&
intermoduleid != 34998 &&
intermoduleid != 36248){
g_log.error() << "Detector ID = " << detectorID << " Inter-Module ID = " << intermoduleid << std::endl;
throw std::invalid_argument("Indexing error!");
}
catch (std::invalid_argument & )

Zhou, Wenduo
committed
{
g_log.notice() << "Misses Detector ID = " << detectorID << std::endl;
}
} // for
g_log.notice() << "Number of matched detectors =" << numfinds << std::endl;
}
//-----------------------------------------------------------------------
/** Reads an ASCII VULCAN filename where:
*
* 1st column : pixel ID
* 2nd column : float "correction", where corrected_TOF = initial_TOF / 10^correction
*
* @param fileName :: vulcan file name
* @param[out] vulcan :: a map of pixel ID : correction factor in the file (2nd column)
*/
void LoadDspacemap::readVulcanAsciiFile(const std::string& fileName, std::map<detid_t,double> & vulcan)
{
std::ifstream grFile(fileName.c_str());
if (!grFile)
{
g_log.error() << "Unable to open vulcan file " << fileName << std::endl;
return;
}
vulcan.clear();
std::string str;

Zhou, Wenduo
committed
int numentries = 0;
while(getline(grFile,str))
{
if (str.empty() || str[0] == '#') continue;
std::istringstream istr(str);
double correction;
istr >> udet >> correction;
vulcan.insert(std::make_pair(udet,correction));

Zhou, Wenduo
committed
numentries ++;

Zhou, Wenduo
committed
g_log.notice() << "Read Vulcan ASCII File: # Entry = " << numentries << std::endl;
}
/** Structure of the vulcan binary file */
struct VulcanCorrectionFactor
{
/// ID for pixel
double pixelID;
/// Correction factor for pixel
double factor;
};
//-----------------------------------------------------------------------
/** Reads a Binary VULCAN filename where:
*
* 1st 8 bytes : pixel ID
* 2nd 8 bytes : double "correction", where corrected_TOF = initial_TOF / 10^correction
*
* @param fileName :: vulcan file name
* @param[out] vulcan :: a map of pixel ID : correction factor in the file (2nd column)
*/
void LoadDspacemap::readVulcanBinaryFile(const std::string& fileName, std::map<detid_t,double> & vulcan)
{
BinaryFile<VulcanCorrectionFactor> file(fileName);
std::vector<VulcanCorrectionFactor> * results = file.loadAll();
if (results)
{
for (std::vector<VulcanCorrectionFactor>::iterator it = results->begin(); it!= results->end(); ++it)
{
//std::cout << it->pixelID << " :! " << it->factor << std::endl;
vulcan[static_cast<detid_t>(it->pixelID)] = it->factor;