Newer
Older
#include "MantidAPI/FileProperty.h"
Federico Montesino Pouzols
committed
#include "MantidAPI/MultipleFileProperty.h"
#include "MantidAPI/NumericAxis.h"
#include "MantidDataHandling/LoadFITS.h"
#include "MantidDataObjects/Workspace2D.h"
Federico Montesino Pouzols
committed
#include "MantidKernel/BoundedValidator.h"
#include <boost/algorithm/string.hpp>
Federico Montesino Pouzols
committed
#include <Poco/BinaryReader.h>
#include <Poco/FileStream.h>
#include <Poco/Path.h>
using namespace Mantid::API;
using namespace Mantid::Kernel;
namespace Mantid {
namespace DataHandling {
// Register the algorithm into the AlgorithmFactory
DECLARE_FILELOADER_ALGORITHM(LoadFITS)
const std::string LoadFITS::g_BIT_DEPTH_NAME = "BitDepthName";
const std::string LoadFITS::g_ROTATION_NAME = "RotationName";
const std::string LoadFITS::g_AXIS_NAMES_NAME = "AxisNames";
const std::string LoadFITS::g_IMAGE_KEY_NAME = "ImageKeyName";
const std::string LoadFITS::g_HEADER_MAP_NAME = "HeaderMapFile";
Federico Montesino Pouzols
committed
const std::string LoadFITS::g_defaultImgType = "SAMPLE";
Federico Montesino Pouzols
committed
/**
* Constructor. Just initialize everything to prevent issues.
*/
Federico Montesino Pouzols
committed
LoadFITS::LoadFITS()
: m_headerScaleKey(), m_headerOffsetKey(), m_headerBitDepthKey(),
m_headerRotationKey(), m_headerImageKeyKey(), m_headerAxisNameKeys(),
Federico Montesino Pouzols
committed
m_mapFile(), m_pixelCount(0) {
setupDefaultKeywordNames();
}
/**
* Return the confidence with with this algorithm can load the file
* @param descriptor A descriptor for the file
* @returns An integer specifying the confidence level. 0 indicates it will not
* be used
*/
int LoadFITS::confidence(Kernel::FileDescriptor &descriptor) const {
// Should really improve this to check the file header (of first file at
// least) to make sure it contains the fields wanted
return (descriptor.extension() == ".fits" || descriptor.extension() == ".fit")
? 80
: 0;
}
/**
* Initialise the algorithm. Declare properties which can be set before execution
* (input) or
* read from after the execution (output).
*/
void LoadFITS::init() {
// Specify file extensions which can be associated with a FITS file.
std::vector<std::string> exts, exts2;
// Declare the Filename algorithm property. Mandatory. Sets the path to the
// file to load.
exts.clear();
exts.push_back(".fits");
exts.push_back(".fit");
exts2.push_back(".*");
declareProperty(new MultipleFileProperty("Filename", exts),
Federico Montesino Pouzols
committed
"The name of the input file (note that you can give "
"multiple file names separated by commas).");
declareProperty(new API::WorkspaceProperty<API::Workspace>(
"OutputWorkspace", "", Kernel::Direction::Output));
Federico Montesino Pouzols
committed
declareProperty(
new Kernel::PropertyWithValue<bool>("LoadAsRectImg", false,
Kernel::Direction::Input),
"If enabled (not by default), the output Workspace2D will have "
"one histogram per row and one bin per pixel, such that a 2D "
"color plot (color fill plot) will display an image.");
Federico Montesino Pouzols
committed
auto zeroOrPosDbl = boost::make_shared<BoundedValidator<double>>();
zeroOrPosDbl->setLower(0.0);
declareProperty("FilterNoiseLevel", 0.0, zeroOrPosDbl,
"Threshold to remove noisy pixels. Try 50 for example.");
Federico Montesino Pouzols
committed
auto posInt = boost::make_shared<BoundedValidator<int>>();
posInt->setLower(1);
declareProperty("BinSize", 1, posInt,
"Rebunch n*n on both axes, generating pixels with sums of "
Federico Montesino Pouzols
committed
"blocks of n by n original pixels.");
Federico Montesino Pouzols
committed
auto posDbl = boost::make_shared<BoundedValidator<double>>();
posDbl->setLower(std::numeric_limits<double>::epsilon());
declareProperty("Scale", 80.0, posDbl, "Pixels per cm.",
Kernel::Direction::Input);
new FileProperty(g_HEADER_MAP_NAME, "", FileProperty::OptionalDirectory,
Federico Montesino Pouzols
committed
"", Kernel::Direction::Input),
"A file mapping header key names to non-standard names [line separated "
"values in the format KEY=VALUE, e.g. BitDepthName=BITPIX] - do not use "
"this if you want to keep compatibility with standard FITS files.");
* Execute the algorithm.
*/
// for non-standard headers, by default won't do anything
Federico Montesino Pouzols
committed
std::string fName = getPropertyValue("Filename");
std::vector<std::string> paths;
boost::split(paths, fName, boost::is_any_of(","));
Federico Montesino Pouzols
committed
int binSize = getProperty("BinSize");
double noiseThresh = getProperty("FilterNoiseLevel");
Federico Montesino Pouzols
committed
bool loadAsRectImg = getProperty("LoadAsRectImg");
Federico Montesino Pouzols
committed
const std::string outWSName = getPropertyValue("OutputWorkspace");
doLoadFiles(paths, outWSName, loadAsRectImg, binSize, noiseThresh);
}
/**
* Load header(s) from FITS file(s) into FITSInfo header
* struct(s). This is usually the first step when loading FITS files
* into workspaces or anything else. In the simplest case, paths has
* only one string and only one header struct is added in headers.
*
* @param paths File name(s)
* @param headers Vector where to store the header struct(s)
*
* @throws std::runtime_error if issues are found in the headers
*/
void LoadFITS::doLoadHeaders(const std::vector<std::string> &paths,
std::vector<FITSInfo> &headers) {
headers.resize(paths.size());
for (size_t i = 0; i < paths.size(); ++i) {
headers[i].extension = "";
headers[i].filePath = paths[i];
Federico Montesino Pouzols
committed
Federico Montesino Pouzols
committed
// Get various pieces of information from the file header which are used
// to
try {
parseHeader(headers[i]);
} catch (std::exception &e) {
Federico Montesino Pouzols
committed
// Unable to parse the header, throw.
throw std::runtime_error(
"Severe problem found while parsing the header of "
"this FITS file (" +
paths[i] +
"). This file may not be standard FITS. Error description: " +
e.what());
Federico Montesino Pouzols
committed
}
// Get and convert specific standard header values which will are
// needed to know how to load the data: BITPIX, NAXIS, NAXISi (where i =
// 1..NAXIS, e.g. NAXIS2 for two axis).
Federico Montesino Pouzols
committed
try {
Federico Montesino Pouzols
committed
std::string tmpBitPix = headers[i].headerKeys[m_headerBitDepthKey];
Federico Montesino Pouzols
committed
if (boost::contains(tmpBitPix, "-")) {
boost::erase_all(tmpBitPix, "-");
headers[i].isFloat = true;
Federico Montesino Pouzols
committed
} else {
headers[i].isFloat = false;
Federico Montesino Pouzols
committed
}
Federico Montesino Pouzols
committed
try {
headers[i].bitsPerPixel = boost::lexical_cast<int>(tmpBitPix);
Federico Montesino Pouzols
committed
} catch (std::exception &e) {
throw std::runtime_error(
"Coult not interpret the entry number of bits per pixel (" +
m_headerBitDepthKey + ") as an integer. Error: " + e.what());
}
// Check that the files use bit depths of either 8, 16 or 32
if (headers[i].bitsPerPixel != 8 && headers[i].bitsPerPixel != 16 &&
headers[i].bitsPerPixel != 32 && headers[i].bitsPerPixel != 64)
throw std::runtime_error(
"This algorithm only supports 8, 16, 32 or 64 "
"bits per pixel. The header of file '" +
paths[i] + "' says that its bit depth is: " +
boost::lexical_cast<std::string>(headers[i].bitsPerPixel));
} catch (std::exception &e) {
throw std::runtime_error(
"Failed to process the '" + m_headerBitDepthKey +
"' entry (bits per pixel) in the header of this file: " + paths[i] +
". Error description: " + e.what());
}
try {
Loading
Loading full blame...