Newer
Older
Russell Taylor
committed
//----------------------------------------------------------------------
// Includes
//----------------------------------------------------------------------
#include "MantidAlgorithms/DiffractionFocussing.h"
#include "MantidAPI/FileProperty.h"
Russell Taylor
committed
#include <limits>
#include <map>
#include <fstream>
namespace Mantid {
namespace Algorithms {
Russell Taylor
committed
// Register the class into the algorithm factory
DECLARE_ALGORITHM(DiffractionFocussing)
Russell Taylor
committed
/// Constructor
DiffractionFocussing::DiffractionFocussing()
: API::Algorithm(), API::DeprecatedAlgorithm() {
this->useAlgorithm("DiffractionFocussing", 2);
Russell Taylor
committed
}
using namespace Kernel;
using API::WorkspaceProperty;
using API::MatrixWorkspace_sptr;
using API::MatrixWorkspace;
using API::FileProperty;
/** Initialisation method. Declares properties to be used in algorithm.
*
*/
void DiffractionFocussing::init() {
declareProperty(new WorkspaceProperty<MatrixWorkspace>("InputWorkspace", "",
Direction::Input),
"The input workspace");
declareProperty(new WorkspaceProperty<MatrixWorkspace>("OutputWorkspace", "",
Direction::Output),
"The result of diffraction focussing of InputWorkspace");
Russell Taylor
committed
declareProperty(
new FileProperty("GroupingFileName", "", FileProperty::Load, ".cal"),
"The name of the CalFile with grouping data");
Russell Taylor
committed
}
/** Executes the algorithm
*
* @throw Exception::FileError If the grouping file cannot be opened or read
*successfully
* @throw runtime_error If unable to run one of the Child Algorithms
*successfully
Russell Taylor
committed
*/
void DiffractionFocussing::exec() {
Russell Taylor
committed
// retrieve the properties
std::string groupingFileName = getProperty("GroupingFileName");
Russell Taylor
committed
// Get the input workspace
MatrixWorkspace_sptr inputW = getProperty("InputWorkspace");
bool dist = inputW->isDistribution();
// do this first to check that a valid file is available before doing any work
std::multimap<int64_t, int64_t> detectorGroups; // <group, UDET>
if (!readGroupingFile(groupingFileName, detectorGroups)) {
throw Exception::FileError("Error reading .cal file", groupingFileName);
Russell Taylor
committed
}
Russell Taylor
committed
API::MatrixWorkspace_sptr tmpW = convertUnitsToDSpacing(inputW);
Russell Taylor
committed
RebinWorkspace(tmpW);
std::set<int64_t> groupNumbers;
for (std::multimap<int64_t, int64_t>::const_iterator d =
detectorGroups.begin();
d != detectorGroups.end(); ++d) {
if (groupNumbers.find(d->first) == groupNumbers.end()) {
Russell Taylor
committed
groupNumbers.insert(d->first);
}
}
int iprogress = 0;
int iprogress_count = static_cast<int>(groupNumbers.size());
int iprogress_step = iprogress_count / 100;
if (iprogress_step == 0)
iprogress_step = 1;
Russell Taylor
committed
std::vector<int64_t> resultIndeces;
for (auto g = groupNumbers.cbegin(); g != groupNumbers.end(); ++g) {
if (iprogress++ % iprogress_step == 0) {
progress(0.68 + double(iprogress) / iprogress_count / 3);
Russell Taylor
committed
}
auto from = detectorGroups.lower_bound(*g);
auto to = detectorGroups.upper_bound(*g);
Russell Taylor
committed
std::vector<detid_t> detectorList;
for (auto d = from; d != to; ++d)
Russell Taylor
committed
detectorList.push_back(static_cast<detid_t>(d->second));
// Want version 1 of GroupDetectors here
API::IAlgorithm_sptr childAlg =
createChildAlgorithm("GroupDetectors", -1.0, -1.0, true, 1);
Russell Taylor
committed
childAlg->setProperty("Workspace", tmpW);
childAlg->setProperty<std::vector<detid_t>>("DetectorList", detectorList);
childAlg->executeAsChildAlg();
Russell Taylor
committed
// get the index of the combined spectrum
int ri = childAlg->getProperty("ResultIndex");
Russell Taylor
committed
resultIndeces.push_back(ri);
}
} catch (...) {
throw std::runtime_error(
"Unable to get Properties from GroupDetectors Child Algorithm");
Russell Taylor
committed
}
}
// Discard left-over spectra, but print warning message giving number
// discarded
Russell Taylor
committed
int discarded = 0;
const int64_t oldHistNumber = tmpW->getNumberHistograms();
API::Axis *spectraAxis = tmpW->getAxis(1);
for (int64_t i = 0; i < oldHistNumber; i++)
if (spectraAxis->spectraNo(i) >= 0 &&
find(resultIndeces.begin(), resultIndeces.end(), i) ==
resultIndeces.end()) {
Russell Taylor
committed
++discarded;
}
g_log.warning() << "Discarded " << discarded
<< " spectra that were not assigned to any group"
<< std::endl;
Russell Taylor
committed
// Running GroupDetectors leads to a load of redundant spectra
// Create a new workspace that's the right size for the meaningful spectra and
// copy them in
Russell Taylor
committed
int64_t newSize = tmpW->blocksize();
API::MatrixWorkspace_sptr outputW = API::WorkspaceFactory::Instance().create(
tmpW, resultIndeces.size(), newSize + 1, newSize);
Russell Taylor
committed
for (int64_t hist = 0; hist < static_cast<int64_t>(resultIndeces.size());
hist++) {
Russell Taylor
committed
int64_t i = resultIndeces[hist];
MantidVec &tmpE = tmpW->dataE(i);
MantidVec &outE = outputW->dataE(hist);
MantidVec &tmpY = tmpW->dataY(i);
MantidVec &outY = outputW->dataY(hist);
MantidVec &tmpX = tmpW->dataX(i);
MantidVec &outX = outputW->dataX(hist);
outE.assign(tmpE.begin(), tmpE.end());
outY.assign(tmpY.begin(), tmpY.end());
outX.assign(tmpX.begin(), tmpX.end());
API::ISpectrum *inSpec = tmpW->getSpectrum(i);
outputW->getSpectrum(hist)->setSpectrumNo(inSpec->getSpectrumNo());
inSpec->setSpectrumNo(-1);
Russell Taylor
committed
}
progress(1.);
outputW->isDistribution(dist);
// Assign it to the output workspace property
setProperty("OutputWorkspace", outputW);
Russell Taylor
committed
return;
}
/// Run ConvertUnits as a Child Algorithm to convert to dSpacing
MatrixWorkspace_sptr DiffractionFocussing::convertUnitsToDSpacing(
const API::MatrixWorkspace_sptr &workspace) {
Russell Taylor
committed
const std::string CONVERSION_UNIT = "dSpacing";
Unit_const_sptr xUnit = workspace->getAxis(0)->unit();
g_log.information() << "Converting units from " << xUnit->label().ascii()
<< " to " << CONVERSION_UNIT << ".\n";
Russell Taylor
committed
API::IAlgorithm_sptr childAlg =
createChildAlgorithm("ConvertUnits", 0.34, 0.66);
Russell Taylor
committed
childAlg->setProperty("InputWorkspace", workspace);
childAlg->setPropertyValue("Target", CONVERSION_UNIT);
childAlg->executeAsChildAlg();
Russell Taylor
committed
return childAlg->getProperty("OutputWorkspace");
}
/// Run Rebin as a Child Algorithm to harmonise the bin boundaries
void DiffractionFocussing::RebinWorkspace(
API::MatrixWorkspace_sptr &workspace) {
Russell Taylor
committed
double min = 0;
double max = 0;
double step = 0;
Russell Taylor
committed
calculateRebinParams(workspace, min, max, step);
Russell Taylor
committed
std::vector<double> paramArray;
paramArray.push_back(min);
paramArray.push_back(-step);
paramArray.push_back(max);
g_log.information() << "Rebinning from " << min << " to " << max << " in "
<< step << " logaritmic steps.\n";
Russell Taylor
committed
API::IAlgorithm_sptr childAlg = createChildAlgorithm("Rebin");
Russell Taylor
committed
childAlg->setProperty<MatrixWorkspace_sptr>("InputWorkspace", workspace);
childAlg->setProperty<std::vector<double>>("Params", paramArray);
childAlg->executeAsChildAlg();
Russell Taylor
committed
workspace = childAlg->getProperty("OutputWorkspace");
}
/** Calculates rebin parameters: the min and max bin boundaries and the
logarithmic step. The aim is to have approx.
Russell Taylor
committed
the same number of bins as in the input workspace.
@param workspace :: The workspace being rebinned
@param min :: (return) The calculated frame starting point
@param max :: (return) The calculated frame ending point
@param step :: (return) The calculated bin width
*/
void DiffractionFocussing::calculateRebinParams(
const API::MatrixWorkspace_const_sptr &workspace, double &min, double &max,
double &step) {
Russell Taylor
committed
min = std::numeric_limits<double>::max();
// for min and max we need to iterate over the data block and investigate each
// one
Russell Taylor
committed
int64_t length = workspace->getNumberHistograms();
for (int64_t i = 0; i < length; i++) {
const MantidVec &xVec = workspace->readX(i);
const double &localMin = xVec[0];
const double &localMax = xVec[xVec.size() - 1];
Russell Taylor
committed
if (localMin != std::numeric_limits<double>::infinity() &&
localMax != std::numeric_limits<double>::infinity()) {
if (localMin < min)
min = localMin;
if (localMax > max)
max = localMax;
Russell Taylor
committed
}
}
Russell Taylor
committed
Russell Taylor
committed
double n = static_cast<double>(workspace->blocksize());
step = (log(max) - log(min)) / n;
Russell Taylor
committed
}
/// Reads in the file with the grouping information
bool DiffractionFocussing::readGroupingFile(
std::string groupingFileName,
std::multimap<int64_t, int64_t> &detectorGroups) {
Russell Taylor
committed
std::ifstream grFile(groupingFileName.c_str());
if (!grFile) {
g_log.error() << "Unable to open grouping file " << groupingFileName
<< std::endl;
Russell Taylor
committed
return false;
}
Russell Taylor
committed
Russell Taylor
committed
detectorGroups.clear();
std::string str;
while (getline(grFile, str)) {
if (str.empty() || str[0] == '#')
continue;
Russell Taylor
committed
std::istringstream istr(str);
Russell Taylor
committed
double offset;
istr >> n >> udet >> offset >> sel >> group;
// Check the line wasn't badly formatted - return a failure if it is
// if ( ! istr.good() ) return false;
// only allow groups with +ve ids
if ((sel) && (group > 0)) {
detectorGroups.emplace(group, udet);
Russell Taylor
committed
}
return true;
}
Russell Taylor
committed
} // namespace Algorithm
} // namespace Mantid