Newer
Older
#include "MantidDataHandling/LoadDspacemap.h"
#include "MantidAPI/FileProperty.h"
#include "MantidDataHandling/LoadCalFile.h"
#include "MantidDataObjects/EventWorkspace.h"
#include "MantidDataObjects/GroupingWorkspace.h"
#include "MantidDataObjects/OffsetsWorkspace.h"
#include "MantidGeometry/IDetector.h"
#include "MantidKernel/BinaryFile.h"
#include "MantidKernel/ListValidator.h"
#include "MantidKernel/PhysicalConstants.h"
#include "MantidKernel/UnitFactory.h"
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() {}
//----------------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------------
/** Initialize the algorithm's properties.
*/
void LoadDspacemap::init() {
// 3 properties for getting the right instrument
LoadCalFile::getInstrument3WaysInit(this);
const std::vector<std::string> exts{".dat", ".bin"};
declareProperty(Kernel::make_unique<FileProperty>("Filename", "",
FileProperty::Load, exts),
"The DspacemapFile containing the d-space mapping.");
std::vector<std::string> propOptions{"POWGEN", "VULCAN-ASCII",
"VULCAN-Binary"};
declareProperty("FileType", "POWGEN",
boost::make_shared<StringListValidator>(propOptions),
"The type of file being read.");
declareProperty(Kernel::make_unique<WorkspaceProperty<OffsetsWorkspace>>(
"OutputWorkspace", "", Direction::Output),
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
"An output OffsetsWorkspace.");
}
//----------------------------------------------------------------------------------------------
/** Execute the algorithm.
*/
void LoadDspacemap::exec() {
// Get the instrument
Instrument_const_sptr inst = LoadCalFile::getInstrument3Ways(this);
// Read in the calibration data
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.
std::map<detid_t, double> vulcan;
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);
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
}
//-----------------------------------------------------------------------
/**
* 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
Instrument_const_sptr instrument = offsetsWS->getInstrument();
double l1;
Kernel::V3D beamline, samplePos;
double beamline_norm;
instrument->getInstrumentParameters(l1, beamline, beamline_norm, samplePos);
// To get all the detector ID's
detid2det_map allDetectors;
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);
}
detid2det_map::const_iterator it;
for (it = allDetectors.begin(); it != allDetectors.end(); ++it) {
detid_t detectorID = it->first;
Geometry::IDetector_const_sptr det = it->second;
// Compute the factor
double offset = 0.0;
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 &) {
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
}
}
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.
* 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
// At this point, instrument VULCAN has been created?
Instrument_const_sptr instrument = offsetsWS->getInstrument();
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
detid2det_map allDetectors;
instrument->getDetectors(allDetectors);
detid2det_map::const_iterator it;
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;
auto 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;
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);
if (vulcan_iter != vulcan.end()) {
vulcan_factor = vulcan_iter->second;
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
***/
/*** 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

Zhou, Wenduo
committed
***/
// 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;
***/

Zhou, Wenduo
committed
offset =
difc_pixel / difcRef * (pow(10.0, -(vulcan_factor + intermoduleoffset +
interstackoffset))) -
1.0;
// Save in the map
try {
offsetsWS->setValue(detectorID, offset);
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!");

Zhou, Wenduo
committed
} catch (std::invalid_argument &) {
g_log.notice() << "Misses Detector ID = " << detectorID << std::endl;
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
} // 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;
int numentries = 0;
while (getline(grFile, str)) {
if (str.empty() || str[0] == '#')
continue;
std::istringstream istr(str);
int32_t udet;
double correction;
istr >> udet >> correction;
vulcan.emplace(udet, correction);
}
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
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();
for (auto &result : results) {
vulcan[static_cast<detid_t>(result.pixelID)] = result.factor;
} // namespace Mantid
} // namespace DataHandling