diff --git a/Code/Mantid/Framework/DataHandling/inc/MantidDataHandling/Load.h b/Code/Mantid/Framework/DataHandling/inc/MantidDataHandling/Load.h index 5b5e6087eeb9be7d8805931edec4649881c027e9..2b0c7e6c99e43e70379e3d418b1d9989db1d1d46 100644 --- a/Code/Mantid/Framework/DataHandling/inc/MantidDataHandling/Load.h +++ b/Code/Mantid/Framework/DataHandling/inc/MantidDataHandling/Load.h @@ -101,6 +101,8 @@ namespace Mantid API::IAlgorithm_sptr m_loader; /// The name of the property that will be passed the property from our Filename std::string m_filenamePropName; + /// Indicate whether a collection of files should be loaded into a single workspace. + bool m_loadMultipleAsOne; /// Mutex for temporary fix for #5963 static Poco::Mutex m_mutex; }; diff --git a/Code/Mantid/Framework/DataHandling/inc/MantidDataHandling/LoadFITS.h b/Code/Mantid/Framework/DataHandling/inc/MantidDataHandling/LoadFITS.h index 06ee83f0b034eccfdaf95040cef4fec99f38ee74..9c54ea0a5408e8629334237e20091352c15f3d25 100644 --- a/Code/Mantid/Framework/DataHandling/inc/MantidDataHandling/LoadFITS.h +++ b/Code/Mantid/Framework/DataHandling/inc/MantidDataHandling/LoadFITS.h @@ -2,7 +2,26 @@ #define MANTID_DATAHANDLING_LOADFITS_H_ #include "MantidAPI/IFileLoader.h" - +#include <string> +#include <sstream> +#include <map> +#include <vector> + +using namespace std; + +struct FITSInfo { + vector<string> headerItems; + map<string, string> headerKeys; + int bitsPerPixel; + int numberOfAxis; + vector<int> axisPixelLengths; + double tof; + double timeBin; + long int countsInImage; + long int numberOfTriggers; + string extension; + string filePath; +}; namespace Mantid { @@ -58,6 +77,14 @@ namespace DataHandling /// Execution code void exec(); + /// Parses the header values for the FITS file + bool parseHeader(FITSInfo &headerInfo); + void loadSingleBinFromFile(Mantid::API::MatrixWorkspace_sptr &workspace, FITSInfo &fitsInfo, MantidVecPtr &x, long spetraCount, long binIndex); + + API::MatrixWorkspace_sptr initAndPopulateHistogramWorkspace(); + + vector<FITSInfo> m_allHeaderInfo; + ///// Implement abstract Algorithm methods //void init(); ///// Implement abstract Algorithm methods @@ -86,9 +113,7 @@ namespace DataHandling }; - - - + } // namespace DataHandling } // namespace Mantid diff --git a/Code/Mantid/Framework/DataHandling/src/Load.cpp b/Code/Mantid/Framework/DataHandling/src/Load.cpp index 3e9be99234919b47dbbe9671a253d7d65d5961e4..ec4e7d39b898d8bf9b67e23f37cbe292c3978635 100644 --- a/Code/Mantid/Framework/DataHandling/src/Load.cpp +++ b/Code/Mantid/Framework/DataHandling/src/Load.cpp @@ -225,11 +225,18 @@ namespace Mantid const auto & props = loader->getProperties(); for(auto it = props.begin(); it != props.end(); ++it) { - if(auto *fp = dynamic_cast<API::FileProperty*>(*it)) + auto *fp = dynamic_cast<API::MultipleFileProperty*>(*it); + auto *fp2 = dynamic_cast<API::FileProperty*>(*it); + if(fp) { m_filenamePropName = fp->name(); break; } + if(fp2) + { + m_filenamePropName = fp2->name(); + break; + } } if(m_filenamePropName.empty()) { @@ -296,6 +303,7 @@ namespace Mantid exts.push_back(".h5"); exts.push_back(".hd5"); exts.push_back(".sqw"); + exts.push_back(".fits"); declareProperty(new MultipleFileProperty("Filename", exts), "The name of the file(s) to read, including the full or relative " @@ -323,11 +331,15 @@ namespace Mantid * Executes the algorithm. */ void Load::exec() - { + { std::vector<std::vector<std::string> > fileNames = getProperty("Filename"); - if(isSingleFile(fileNames)) - { + // Test for loading as a single file + IAlgorithm_sptr loader = getFileLoader(fileNames[0][0]); + m_loadMultipleAsOne = dynamic_cast<MultipleFileProperty*>(loader->getPointerToProperty("Filename")) != NULL; + + if(isSingleFile(fileNames) || m_loadMultipleAsOne) + { // This is essentially just the same code that was called before multiple files were supported. loadSingleFile(); } diff --git a/Code/Mantid/Framework/DataHandling/src/LoadFITS.cpp b/Code/Mantid/Framework/DataHandling/src/LoadFITS.cpp index 2275a68b8699b835b46b44082a262f2d24c1c724..7c2717abc86dcad78c67337ebb950f5a7cb6e153 100644 --- a/Code/Mantid/Framework/DataHandling/src/LoadFITS.cpp +++ b/Code/Mantid/Framework/DataHandling/src/LoadFITS.cpp @@ -2,7 +2,21 @@ #include "MantidDataObjects/EventWorkspace.h" #include "MantidAPI/FileProperty.h" +#include "MantidAPI/MultipleFileProperty.h" #include "MantidAPI/RegisterFileLoader.h" + +#include "MantidAPI/SpectraAxis.h" +#include "MantidAPI/NumericAxis.h" +#include "MantidGeometry/Objects/ShapeFactory.h" +#include "MantidGeometry/Instrument/ReferenceFrame.h" +#include "MantidGeometry/Instrument/RectangularDetector.h" +#include "MantidKernel/UnitFactory.h" +#include "MantidDataObjects/Workspace2D.h" + +#include <Poco/BinaryReader.h> +#include <boost/algorithm/string.hpp> +#include <boost/lexical_cast.hpp> + //#include "MantidAPI/WorkspaceValidators.h" //#include "MantidKernel/UnitFactory.h" //#include "MantidGeometry/Instrument.h" @@ -19,276 +33,320 @@ using namespace Mantid::DataHandling; using namespace Mantid::API; +using namespace Mantid::Geometry; using namespace Mantid::Kernel; +using namespace std; +using namespace boost::algorithm; +using namespace boost; +using Poco::BinaryReader; + + +using Mantid::MantidVec; +using Mantid::MantidVecPtr; + + namespace Mantid { namespace DataHandling { - // Register the algorithm into the AlgorithmFactory - DECLARE_FILELOADER_ALGORITHM(LoadFITS); - - int LoadFITS::confidence(Kernel::FileDescriptor & descriptor) const - { - return (descriptor.extension() == ".fits" || descriptor.extension() == ".fit") ? 80 : 0; - } - - /** - * Execute the algorithm. - */ - void LoadFITS::exec() - { - // Delete the output workspace name if it existed - std::string outName = getPropertyValue("OutputWorkspace"); - if (AnalysisDataService::Instance().doesExist(outName)) - AnalysisDataService::Instance().remove(outName); - - // Get the name of the file. - std::string filenameBin = getPropertyValue("Filename"); - - size_t nBins = 1; - double tofMinBoundary = 5; - double tofMaxBoundary = 5; - - //// 100 for "loading neutron counts", 100 for "creating neutron event lists", 100 for "loading neutron events" - //Progress prog(this, 0.0, 1.0, 100 + 100 + 100); - //prog.doReport("creating instrument"); - - // Create a workspace - DataObjects::EventWorkspace_sptr eventWS(new DataObjects::EventWorkspace()); - - eventWS->initialize( - nHist, - nBins + 1, // number of TOF bin boundaries - nBins); - - // Set the units - eventWS->getAxis(0)->unit() = UnitFactory::Instance().create("TOF"); - eventWS->setYUnit("Counts"); - - // ??? - //eventWS->setYUnitLabel("Counts"); - - eventWS->setTitle("my title"); - eventWS->mutableRun().addProperty("Filename", filenameBin); - //eventWS->mutableRun().addProperty("run_number", 1); - //eventWS->mutableRun().addProperty("run_start", "1991-01-01T00:00:00", true ); - //eventWS->mutableRun().addProperty("duration", duration[0], units); - - // Build instrument geometry - - // Create a new instrument and set its name - std::string instrumentname = "BILBY"; - Geometry::Instrument_sptr instrument(new Geometry::Instrument(instrumentname)); - eventWS->setInstrument(instrument); - - // Add dummy source and samplepos to instrument - - // Create an instrument component wich will represent the sample position. - Geometry::ObjComponent *samplepos = new Geometry::ObjComponent("Sample",instrument.get()); - instrument->add(samplepos); - instrument->markAsSamplePos(samplepos); - // Put the sample in the centre of the coordinate system - samplepos->setPos(0.0,0.0,0.0); - - // Create a component to represent the source - Geometry::ObjComponent *source = new Geometry::ObjComponent("Source",instrument.get()); - instrument->add(source); - instrument->markAsSource(source); - - // Read in the L1 value and place the source at (0,0,-L1) - double l1 = 3949.1824; - source->setPos(0.0,0.0,-1.0*l1); - - // Create a component for the detector. - - size_t xPixelCount = HISTO_BINS_X / 6; - size_t yPixelCount = HISTO_BINS_Y; - size_t pixelCount = xPixelCount * yPixelCount; - - // We assumed that these are the dimensions of the detector, and height is in y direction and width is in x direction - double width = 0.4; // meters - double height = 1.0; - - // We assumed that individual pixels have the same size and shape of a cuboid with dimensions: - double pixel_width = width / static_cast<double>(xPixelCount); - double pixel_height = height / static_cast<double>(yPixelCount); - - // Create size strings for shape creation - std::string pixel_width_str = boost::lexical_cast<std::string>(pixel_width / 2); - std::string pixel_height_str = boost::lexical_cast<std::string>(pixel_height / 2); - std::string pixel_depth_str = "0.00001"; // Set the depth of a pixel to a very small number - - // Define shape of a pixel as an XML string. See http://www.mantidproject.org/HowToDefineGeometricShape for details - // on shapes in Mantid. - std::string detXML = - "<cuboid id=\"pixel\">" - "<left-front-bottom-point x=\"+"+pixel_width_str+"\" y=\"-"+pixel_height_str+"\" z=\"0\" />" - "<left-front-top-point x=\"+"+pixel_width_str+"\" y=\"-"+pixel_height_str+"\" z=\""+pixel_depth_str+"\" />" - "<left-back-bottom-point x=\"-"+pixel_width_str+"\" y=\"-"+pixel_height_str+"\" z=\"0\" />" - "<right-front-bottom-point x=\"+"+pixel_width_str+"\" y=\"+"+pixel_height_str+"\" z=\"0\" />" - "</cuboid>"; - - // Create a shape object which will be shared by all pixels. - Geometry::Object_sptr shape = Geometry::ShapeFactory().createShape(detXML); - - double detectorZ = 5; - double angle = 10; - - double curtZOffset = width / 2 * sin(angle * 3.14159265359 / 180); - - if (!filenameHdf.empty()) { - NeXus::NXRoot root(filenameHdf); - NeXus::NXEntry entry = root.openFirstEntry(); - - } - - // 6 detector banks are available - - // curtain 1 - AddDetectorBank( - instrument, - xPixelCount, - yPixelCount, - 0 * pixelCount, - shape, - width, - height, - Kernel::V3D(+(width + height) / 2, 0, detectorZ - curtZOffset), - Kernel::Quat( 0, Kernel::V3D(0, 0, 1)) * Kernel::Quat(angle, Kernel::V3D(0, 1, 0))); - - // curtain 2 - AddDetectorBank( - instrument, - xPixelCount, - yPixelCount, - 1 * pixelCount, - shape, - width, - height, - Kernel::V3D(-(width + height) / 2, 0, detectorZ - curtZOffset), - Kernel::Quat(180, Kernel::V3D(0, 0, 1)) * Kernel::Quat(angle, Kernel::V3D(0, 1, 0))); - - // curtain 3 - AddDetectorBank( - instrument, - xPixelCount, - yPixelCount, - 2 * pixelCount, - shape, - width, - height, - Kernel::V3D(0, +(width + height) / 2, detectorZ - curtZOffset), - Kernel::Quat( 90, Kernel::V3D(0, 0, 1)) * Kernel::Quat(angle, Kernel::V3D(0, 1, 0))); - - // curtain 4 - AddDetectorBank( - instrument, - xPixelCount, - yPixelCount, - 3 * pixelCount, - shape, - width, - height, - Kernel::V3D(0, -(width + height) / 2, detectorZ - curtZOffset), - Kernel::Quat(-90, Kernel::V3D(0, 0, 1)) * Kernel::Quat(angle, Kernel::V3D(0, 1, 0))); - - // back 1 - AddDetectorBank( - instrument, - xPixelCount, - yPixelCount, - 4 * pixelCount, - shape, - width, - height, - Kernel::V3D(-width / 2 - 0.05, 0, detectorZ), - Kernel::Quat(180, Kernel::V3D(0, 0, 1))); - - // back 2 - AddDetectorBank( - instrument, - xPixelCount, - yPixelCount, - 5 * pixelCount, - shape, - width, - height, - Kernel::V3D(+width / 2 + 0.05, 0, detectorZ), - Kernel::Quat( 0, Kernel::V3D(0, 0, 1))); - - // load events - - size_t numberHistograms = eventWS->getNumberHistograms(); - - std::vector<EventVector_pt> eventVectors(numberHistograms, NULL); - std::vector<size_t> eventCounts(numberHistograms, 0); - std::vector<detid_t> detIDs = instrument->getDetectorIDs(); - - // count total events per pixel to reserve necessary memory - LoadFile_Counts(prog, filenameBin, HISTO_BINS_X, HISTO_BINS_Y, tofMinBoundary, tofMaxBoundary, eventCounts); - - // for progress notifications - size_t progCount = 100; - size_t progStep = numberHistograms / progCount; - size_t progNext = progStep; - - auto progMsg = "creating neutron event lists"; - prog.doReport(progMsg); - for (size_t i = 0; i != numberHistograms; ++i) { - DataObjects::EventList& eventList = eventWS->getEventList(i); - - eventList.setSortOrder(DataObjects::PULSETIME_SORT); // why not PULSETIME[TOF]_SORT ? - eventList.reserve(eventCounts[i]); - eventList.setDetectorID(detIDs[i]); - eventList.setSpectrumNo(detIDs[i]); - - DataObjects::getEventsFrom(eventList, eventVectors[i]); - - if ((progNext <= i) && (progCount != 0)) { - prog.report(progMsg); - progNext += progStep; - progCount--; - } - } - if (progCount != 0) - prog.reportIncrement(progCount, progMsg); - - double shortest_tof(0.0), longest_tof(0.0); - LoadFile_Events(prog, filenameBin, HISTO_BINS_X, HISTO_BINS_Y, tofMinBoundary, tofMaxBoundary, eventVectors, shortest_tof, longest_tof); - - cow_ptr<MantidVec> axis; - MantidVec& xRef = axis.access(); - xRef.resize(2, 0.0); - if (longest_tof != 0.0) { - xRef[0] = std::max(0.0, shortest_tof - 1); // just to make sure the bins hold it all - xRef[1] = longest_tof + 1; - } - eventWS->setAllX(axis); - - setProperty("OutputWorkspace", eventWS); - } - - /** - * 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 BBY file. - std::vector<std::string> exts; - - // Declare the Filename algorithm property. Mandatory. Sets the path to the file to load. - exts.clear(); - exts.push_back(".fit"); - declareProperty( - new API::FileProperty("Filename", "", API::FileProperty::Load, exts), - "The input filename of the stored data"); - - declareProperty( - new API::WorkspaceProperty<API::IEventWorkspace>("OutputWorkspace", "", Kernel::Direction::Output)); - } - + // Register the algorithm into the AlgorithmFactory + DECLARE_FILELOADER_ALGORITHM(LoadFITS); + + int LoadFITS::confidence(Kernel::FileDescriptor & descriptor) const + { + // TODO should 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; + } + + /** + * Execute the algorithm. + */ + void LoadFITS::exec() + { + // TODO check that each map check actually has the key required when searched for. raise error if not. + + // Create FITS file information for each file selected + std::vector<std::string> paths; + boost::split(paths, getPropertyValue("Filename"), boost::is_any_of(",")); + + m_allHeaderInfo.resize(paths.size()); + + // Check each header is valid for this loader, - standard (no extension to FITS), and has two axis + bool headerValid = true; + + for(int i=0; i<paths.size();++i) + { + m_allHeaderInfo[i].extension = ""; + m_allHeaderInfo[i].filePath = paths[i]; + // Get various pieces of information from the file header which are used to create the workspace + if(parseHeader(m_allHeaderInfo[i])) + { + // Get and convert specific header values which will help when parsing the data + // BITPIX, NAXIS, NAXISi (where i = 1..NAXIS, e.g. NAXIS2 for two axis), TOF, TIMEBIN, N_COUNTS, N_TRIGS + try + { + m_allHeaderInfo[i].bitsPerPixel = lexical_cast<int>(m_allHeaderInfo[i].headerKeys["BITPIX"]); + m_allHeaderInfo[i].numberOfAxis = lexical_cast<int>(m_allHeaderInfo[i].headerKeys["NAXIS"]); + + for(int j=0; j<m_allHeaderInfo[i].numberOfAxis; ++j) + { + string keyName = "NAXIS" + lexical_cast<string>(j+1); + m_allHeaderInfo[i].axisPixelLengths.push_back(lexical_cast<int>(m_allHeaderInfo[i].headerKeys[keyName])); + } + + m_allHeaderInfo[i].tof = lexical_cast<double>(m_allHeaderInfo[i].headerKeys["TOF"]); + m_allHeaderInfo[i].timeBin = lexical_cast<double>(m_allHeaderInfo[i].headerKeys["TIMEBIN"]); + m_allHeaderInfo[i].countsInImage = lexical_cast<long int>(m_allHeaderInfo[i].headerKeys["N_COUNTS"]); + m_allHeaderInfo[i].numberOfTriggers = lexical_cast<long int>(m_allHeaderInfo[i].headerKeys["N_TRIGS"]); + m_allHeaderInfo[i].extension = m_allHeaderInfo[i].headerKeys["XTENSION"]; // Various extensions are available to the FITS format, and must be parsed differently if this is present + } + catch(bad_lexical_cast &) + { + //todo write error and fail this load with invalid data in file. + } + + if(m_allHeaderInfo[i].extension != "") headerValid = false; + if(m_allHeaderInfo[i].numberOfAxis != 2) headerValid = false; + + // Test current item has same axis values as first item. + if(m_allHeaderInfo[0].axisPixelLengths[0] != m_allHeaderInfo[i].axisPixelLengths[0]) headerValid = false; + if(m_allHeaderInfo[0].axisPixelLengths[1] != m_allHeaderInfo[i].axisPixelLengths[1]) headerValid = false; + } + + } + + // Check the format is correct and create the Workspace + if(headerValid) + { + // No extension is set, therefore it's the standard format which we can parse. + + // Delete the output workspace name if it existed + std::string outName = getPropertyValue("OutputWorkspace"); + if (AnalysisDataService::Instance().doesExist(outName)) AnalysisDataService::Instance().remove(outName); + + MatrixWorkspace_sptr ws; + + ws = initAndPopulateHistogramWorkspace(); + + // Assign it to the output workspace property + setProperty("OutputWorkspace",ws); + } + else + { + // Invalid files, record error + // TODO + + } + } + + /** + * 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; + + // Declare the Filename algorithm property. Mandatory. Sets the path to the file to load. + exts.clear(); + exts.push_back(".fits"); + exts.push_back(".fit"); + + // Specify as a MultipleFileProperty to alert loader we want multiple selected files to be loaded into a single workspace. + declareProperty(new MultipleFileProperty("Filename", exts), "The input filename of the stored data"); + + declareProperty(new API::WorkspaceProperty<API::MatrixWorkspace>("OutputWorkspace", "", Kernel::Direction::Output)); + } + + + bool LoadFITS::parseHeader(FITSInfo &headerInfo) + { + // TODO test file exists, test file can be read, make it return false if failed. + bool ranSuccessfully = true; + ifstream istr(headerInfo.filePath, ios::binary); + Poco::BinaryReader reader(istr); + + // Iterate 80 bytes at a time until header is parsed | 2880 bytes is the fixed header length of FITS + // 2880/80 = 36 iterations required + for(int i=0; i < 36; ++i) + { + // Keep vect of each header item, including comments, and also keep a map of individual keys. + string part; + reader.readRaw(80,part); + headerInfo.headerItems.push_back(part); + + // Add key/values - these are separated by the = symbol. + // If it doesn't have an = it's a comment to ignore. All keys should be unique + int eqPos = part.find('='); + if(eqPos > 0) + { + string key = part.substr(0, eqPos); + string value = part.substr(eqPos+1); + + // Comments are added after the value separated by a / symbol. Remove. + int slashPos = value.find('/'); + if(slashPos > 0) value = value.substr(0, slashPos); + + boost::trim(key); + boost::trim(value); + headerInfo.headerKeys[key] = value; + } + } + + istr.close(); + + return ranSuccessfully; + } + + //---------------------------------------------------------------------------------------------- + /** Create histogram workspace + */ + MatrixWorkspace_sptr LoadFITS::initAndPopulateHistogramWorkspace() + { + // TODO will take vector of FITSInfo for multiple files and load all into workspace + + MantidVecPtr x; + x.access().resize(m_allHeaderInfo.size() + 1); + + // X = TIMEBIN value + x.access()[0] = m_allHeaderInfo[0].timeBin; + x.access()[1] = m_allHeaderInfo[0].timeBin + m_allHeaderInfo[0].tof; + + long spectraCount = 0; + if(m_allHeaderInfo[0].numberOfAxis > 0) spectraCount += m_allHeaderInfo[0].axisPixelLengths[0]; + + // Presumably 2 axis, but futureproofing. + for(int i=1;i<m_allHeaderInfo[0].numberOfAxis;++i) + { + spectraCount *= m_allHeaderInfo[0].axisPixelLengths[i]; + } + + MatrixWorkspace_sptr retVal(new DataObjects::Workspace2D); + retVal->initialize(spectraCount, m_allHeaderInfo.size()+1, m_allHeaderInfo.size()); + + IAlgorithm_sptr loadInst = createChildAlgorithm("LoadInstrument"); + + try + { + std::string directoryName = Kernel::ConfigService::Instance().getInstrumentDirectory(); + directoryName = directoryName + "/IMAT_Definition.xml"; + + loadInst->setPropertyValue("Filename", directoryName); + loadInst->setProperty<MatrixWorkspace_sptr>("Workspace", retVal); + loadInst->execute(); + } + catch (std::exception ex) + { + g_log.information("Cannot load the instrument definition. " + string(ex.what()) ); + } + + for(int i=0; i<m_allHeaderInfo.size();++i) + { + loadSingleBinFromFile(retVal, m_allHeaderInfo[i], x, spectraCount, i); + } + + retVal->mutableRun().addProperty("Filename", m_allHeaderInfo[0].filePath); + + // Set the Unit of the X Axis + try + { + retVal->getAxis(0)->unit() = UnitFactory::Instance().create("TOF"); + } + catch ( Exception::NotFoundError & ) + { + retVal->getAxis(0)->unit() = UnitFactory::Instance().create("Label"); + Unit_sptr unit = retVal->getAxis(0)->unit(); + boost::shared_ptr<Units::Label> label = boost::dynamic_pointer_cast<Units::Label>(unit); + label->setLabel("TOF", "TOF"); + } + + retVal->setYUnit("Counts"); + retVal->setTitle("Test Workspace"); + + return retVal; + } + + + + void LoadFITS::loadSingleBinFromFile(MatrixWorkspace_sptr &workspace, FITSInfo &fitsInfo, MantidVecPtr &x, long spectraCount, long binIndex) + { + // READ DATA + ifstream istr(fitsInfo.filePath, ios::binary); + Poco::BinaryReader reader(istr); + string tmp; + reader.readRaw(2880, tmp); // Read header as full block to skip to data + // read bitdepth*naxis1 num of bits for first row? repeat naxis2 number of times. + int bytesPerRow = (fitsInfo.bitsPerPixel*fitsInfo.axisPixelLengths[0])/8; + + int allDataSizeBytes = (fitsInfo.bitsPerPixel*fitsInfo.axisPixelLengths[0]*fitsInfo.axisPixelLengths[1])/8 ; + string allData; + reader >> allData; + stringstream ss; + ss << allData; + + int currPixel, currRow = 0; + int8_t tmp8; + int16_t tmp16; + int32_t tmp32; + + for(int i=0;i<fitsInfo.axisPixelLengths[1]; ++i) // loop rows + { + // Read all columns on this row. As MantidVecPt->setData expects vectors, populate data vectors for y and e. + //data.push_back(vector<double>()); + currRow = i*fitsInfo.axisPixelLengths[0]; + + for(int j=0; j<fitsInfo.axisPixelLengths[0];++j) + { + double val = 0; + switch(fitsInfo.bitsPerPixel) + { + case 8: + ss >> tmp8; + val = static_cast<double>(tmp8); + case 16: // 2 bytes uint_16 + ss >> tmp16; + val = static_cast<double>(tmp16); + break; + case 32: + ss >> tmp32; + val = static_cast<double>(tmp32); + break; + default: + // TODO unhandled, report error. + break; + } + + currPixel = currRow + j; + workspace->setX(currPixel,x); + + //workspace->setData(currPixel,y,e); + workspace->dataY(currPixel)[binIndex] = val; + workspace->dataE(currPixel)[binIndex] = sqrt(val); + //workspace->dataX(currPixel)[binIndex] = x[0]; + + workspace->getSpectrum(currPixel)->setDetectorID(detid_t(currPixel)); + workspace->getSpectrum(currPixel)->setSpectrumNo(specid_t(currPixel+1)); + } + + } + + + + } } -} \ No newline at end of file +} + +// TODO: Correctly populate X values. + +// about 12 seconds creating child algorithm +// about 18 s loading idf + +// can probably create a vect for each bin and populate them all at once. faster? +// +// std::clock_t start; +// double duration; +// start = std::clock(); +//duration = ( std::clock() - start ) / (double) CLOCKS_PER_SEC; \ No newline at end of file diff --git a/Code/Mantid/instrument/IMAT_Definition.xml b/Code/Mantid/instrument/IMAT_Definition.xml new file mode 100644 index 0000000000000000000000000000000000000000..6d3a86471bb3befe35d983648e20fd7759846b20 --- /dev/null +++ b/Code/Mantid/instrument/IMAT_Definition.xml @@ -0,0 +1,115 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- For help on the notation used to specify an Instrument Definition File +see http://www.mantidproject.org/IDF --> +<instrument xmlns="http://www.mantidproject.org/IDF/1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.mantidproject.org/IDF/1.0 Schema/IDFSchema.xsd" +name="IMAT" valid-from ="1900-01-31 23:59:59" +valid-to ="2014-08-12 23:59:59" +last-modified="2014-08-12 00:00:00"> + <defaults> + <length unit="meter"/> + <angle unit="degree"/> + <reference-frame> + <!-- The z-axis is set parallel to and in the direction of the beam. the +y-axis points up and the coordinate system is right handed. --> + <along-beam axis="z"/> + <pointing-up axis="y"/> + <handedness val="right"/> + </reference-frame> + <default-view axis-view="z-"/> + </defaults> + <!-- BRIEF DESCRIPTION OF SANS2d INSTRUMENT: +Data provided by Richard Heenan (and Freddie) for the SANS2D instrument +12/06/09 this version has X & Y coords detector swapped so orientation +is correct for temporary wiring table. +18/06/09 better distances for detectors and both at L2=4m, front at X=-1.1m +26/06/09 swap front & rear as names wrong, translate front in opposite direction +21/07/09 remove the 150mm sideways shift (i.e. back to symmetrical detector coords) +to simplify manipulations in Mantid and help allow for detector mapping not quite +as expected. +01/02/10 very small chang eto pixel size 191*5.1=974.2=2*487.05 (was 487.4) +- note have to swap x= and y= in Anders output list ! +02/04/12 Put in 'no shape monitors' for possible in the future monitors +with ID 5-8 +--> + <!-- LIST OF PHYSICAL COMPONENTS (which the instrument consists of) --> + <!-- source and sample-position components --> + <component type="source"> + <location /> + </component> + <type name="source" is="Source" /> + <component type="some-sample-holder"> + <location z="19.281"/> + </component> + <type name="some-sample-holder" is="SamplePos" /> + <!-- detector components (including monitors) --> + <component type="monitors" idlist="monitors"> + <location /> + </component> + <type name="monitors"> + <component type="monitor-tbd"> + <!-- better positions and shapes will be defined later --> + <location z="7.217" name="monitor1"/> + <location z="17.937" name="monitor2"/> + </component> + <component type="Moderator-Monitor3"> + <!-- transmisssion detector, either in or out of beam --> + <location z="19.497" name="monitor3"/> + </component> + <component type="monitor-tbd"> + <!-- better positions and shapes will be defined later --> + <location z="30.0" name="monitor4"/> + </component> + <!-- Putting in monitors, which are defined in raw/neuxs +files, and have detector IDs, but currently not physically present +on the instrument. Defined with no geometric shape, as they do not +physically exist, and with a dummy position --> + <component type="no shape monitor"> + <location z="0" name="placeholder monitor"/> + <location z="0" name="placeholder monitor"/> + <location z="0" name="placeholder monitor"/> + <location z="0" name="placeholder monitor"/> + </component> + </type> + <type name="monitor-tbd" is="monitor"> + <cylinder id="some-shape"> + <centre-of-bottom-base r="0.0" t="0.0" p="0.0" /> + <axis x="0.0" y="0.0" z="1.0" /> + <radius val="0.01" /> + <height val="0.03" /> + </cylinder> + </type> + <type name="Moderator-Monitor3" is="monitor"> + <percent-transparency val="99.9" /> + <cuboid id="shape"> + <left-front-bottom-point x="0.0125" y="-0.0125" z="0.0" /> + <left-front-top-point x="0.0125" y="-0.0125" z="0.005" /> + <left-back-bottom-point x="-0.0125" y="-0.0125" z="0.0" /> + <right-front-bottom-point x="0.0125" y="0.0125" z="0.0" /> + </cuboid> + <algebra val="shape" /> + </type> + <type name="no shape monitor" is="monitor" /> + <component type="detector-bank" idstart="2000000" idfillbyfirst="y" idstep="1000" idstepbyrow="1"> + <location x="1.1" z="23.281" name="front-detector"/> + </component> + <component type="detector-bank" idstart="1000000" idfillbyfirst="y" idstep="1000" idstepbyrow="1"> + <location z="23.281" name="rear-detector"/> + </component> + <type name="detector-bank" is="rectangular_detector" type="pixel" + xpixels="512" xstart="-0.48705" xstep="+0.0051" + ypixels="512" ystart="-0.48705" ystep="+0.0051" > + </type> + <type name="pixel" is="detector"> + <cuboid id="shape"> + <left-front-bottom-point x="0.005104167" y="-0.005104167" z="0.0" /> + <left-front-top-point x="0.005104167" y="-0.005104167" z="0.000005" /> + <left-back-bottom-point x="-0.005104167" y="-0.005104167" z="0.0" /> + <right-front-bottom-point x="0.005104167" y="0.005104167" z="0.0" /> + </cuboid> + <algebra val="shape" /> + </type> + <!-- DETECTOR and MONITOR ID LISTS --> + <idlist idname="monitors"> + <id start="1" end="8" /> + </idlist> +</instrument> \ No newline at end of file