Newer
Older
//----------------------------------------------------------------------
// Includes
//----------------------------------------------------------------------
#include "MantidDataHandling/LoadISISNexus2.h"
#include "MantidKernel/ArrayProperty.h"
#include "MantidKernel/BoundedValidator.h"
#include "MantidKernel/ConfigService.h"
#include "MantidKernel/LogParser.h"
#include "MantidKernel/LogFilter.h"
#include "MantidKernel/TimeSeriesProperty.h"
#include "MantidKernel/UnitFactory.h"
Gigg, Martyn Anthony
committed
#include "MantidAPI/FileProperty.h"
#include "MantidAPI/LoadAlgorithmFactory.h"
#include "MantidAPI/SpectraDetectorMap.h"
Gigg, Martyn Anthony
committed
#include "MantidGeometry/Instrument/Detector.h"
#include "MantidGeometry/Instrument/XMLlogfile.h"
Gigg, Martyn Anthony
committed
#include <nexus/NeXusFile.hpp>
#include <nexus/NeXusException.hpp>
Gigg, Martyn Anthony
committed
Gigg, Martyn Anthony
committed
#include <Poco/Path.h>
#include <Poco/DateTimeFormatter.h>
#include <Poco/DateTimeParser.h>
#include <Poco/DateTimeFormat.h>
Steve Williams
committed
#include <boost/lexical_cast.hpp>
#include <sstream>
#include <cctype>
Gigg, Martyn Anthony
committed
#include <functional>
#include <algorithm>
namespace DataHandling
Russell Taylor
committed
{
Gigg, Martyn Anthony
committed
// Register the algorithm into the algorithm factory
DECLARE_ALGORITHM(LoadISISNexus2)
Sofia Antony
committed
DECLARE_LOADALGORITHM(LoadISISNexus2)
Gigg, Martyn Anthony
committed
using namespace Kernel;
using namespace API;
using namespace NeXus;
Gigg, Martyn Anthony
committed
Gigg, Martyn Anthony
committed
/// Empty default constructor
LoadISISNexus2::LoadISISNexus2() :
Sofia Antony
committed
m_filename(), m_instrument_name(), m_samplename(), m_numberOfSpectra(0), m_numberOfSpectraInFile(0),
Gigg, Martyn Anthony
committed
m_numberOfPeriods(0), m_numberOfPeriodsInFile(0), m_numberOfChannels(0), m_numberOfChannelsInFile(0),
m_have_detector(false), m_spec_min(0), m_spec_max(EMPTY_INT()), m_spec_list(),
m_entrynumber(0), m_range_supplied(true), m_tof_data(), m_proton_charge(0.),
m_spec(), m_monitors(), m_logCreator(), m_progress()
Gigg, Martyn Anthony
committed
{}
Gigg, Martyn Anthony
committed
/// Initialisation method.
void LoadISISNexus2::init()
Gigg, Martyn Anthony
committed
{
Gigg, Martyn Anthony
committed
std::vector<std::string> exts;
Peterson, Peter
committed
exts.push_back(".nxs");
exts.push_back(".n*");
Gigg, Martyn Anthony
committed
declareProperty(new FileProperty("Filename", "", FileProperty::Load, exts),
"The name of the Nexus file to load" );
declareProperty(new WorkspaceProperty<Workspace>("OutputWorkspace","",Direction::Output));
auto mustBePositive = boost::make_shared<BoundedValidator<int64_t> >();
Gigg, Martyn Anthony
committed
mustBePositive->setLower(0);
Gigg, Martyn Anthony
committed
declareProperty("SpectrumMin",(int64_t)0, mustBePositive);
declareProperty("SpectrumMax",(int64_t)EMPTY_INT(), mustBePositive);
Gigg, Martyn Anthony
committed
declareProperty(new ArrayProperty<int64_t>("SpectrumList"));
declareProperty("EntryNumber", (int64_t)0, mustBePositive,
Gigg, Martyn Anthony
committed
"The particular entry number to read (default: Load all workspaces and creates a workspace group)");
Gigg, Martyn Anthony
committed
}
Sofia Antony
committed
Gigg, Martyn Anthony
committed
/** Executes the algorithm. Reading in the file and creating and populating
* the output workspace
*
* @throw Exception::FileError If the Nexus file cannot be found/opened
* @throw std::invalid_argument If the optional properties are set to invalid values
*/
void LoadISISNexus2::exec()
Gigg, Martyn Anthony
committed
{
Gigg, Martyn Anthony
committed
m_filename = getPropertyValue("Filename");
// Create the root Nexus class
NXRoot root(m_filename);
// "Open" the same file but with the C++ interface
m_cppFile = new ::NeXus::File(root.m_fileID);
// Open the raw data group 'raw_data_1'
NXEntry entry = root.openEntry("raw_data_1");
Gigg, Martyn Anthony
committed
// Read in the instrument name from the Nexus file
m_instrument_name = entry.getString("name");
//Test if we have a detector block
Gigg, Martyn Anthony
committed
try
Gigg, Martyn Anthony
committed
{
NXClass det_class = entry.openNXGroup("detector_1");
NXInt spectrum_index = det_class.openNXInt("spectrum_index");
Gigg, Martyn Anthony
committed
spectrum_index.load();
ndets = spectrum_index.dim0();
Russell Taylor
committed
// We assume that this spectrum list increases monotonically
m_spec = spectrum_index.sharedBuffer();
m_spec_end = m_spec.get() + ndets;
Gigg, Martyn Anthony
committed
m_have_detector = true;
}
catch(std::runtime_error &)
{
ndets = 0;
Gigg, Martyn Anthony
committed
}
NXInt nsp1 = entry.openNXInt("isis_vms_compat/NSP1");
Gigg, Martyn Anthony
committed
nsp1.load();
NXInt udet = entry.openNXInt("isis_vms_compat/UDET");
Gigg, Martyn Anthony
committed
udet.load();
NXInt spec = entry.openNXInt("isis_vms_compat/SPEC");
Gigg, Martyn Anthony
committed
spec.load();
//Pull out the monitor blocks, if any exist
for(std::vector<NXClassInfo>::const_iterator it = entry.groups().begin();
Gigg, Martyn Anthony
committed
it != entry.groups().end(); ++it)
{
if (it->nxclass == "NXmonitor") // Count monitors
{
NXInt index = entry.openNXInt(std::string(it->nxname) + "/spectrum_index");
Gigg, Martyn Anthony
committed
index.load();
m_monitors[*index()] = it->nxname;
++nmons;
}
}
Gigg, Martyn Anthony
committed
if( ndets == 0 && nmons == 0 )
{
g_log.error() << "Invalid NeXus structure, cannot find detector or monitor blocks.";
throw std::runtime_error("Inconsistent NeXus file structure.");
}
Gigg, Martyn Anthony
committed
Gigg, Martyn Anthony
committed
if( ndets == 0 )
Gigg, Martyn Anthony
committed
{
Gigg, Martyn Anthony
committed
//Grab the number of channels
NXInt chans = entry.openNXInt(m_monitors.begin()->second + "/data");
Gigg, Martyn Anthony
committed
m_numberOfPeriodsInFile = m_numberOfPeriods = chans.dim0();
m_numberOfSpectraInFile = m_numberOfSpectra = nmons;
m_numberOfChannelsInFile = m_numberOfChannels = chans.dim2();
Gigg, Martyn Anthony
committed
}
Gigg, Martyn Anthony
committed
else
{
NXData nxData = entry.openNXData("detector_1");
NXInt data = nxData.openIntData();
Gigg, Martyn Anthony
committed
m_numberOfPeriodsInFile = m_numberOfPeriods = data.dim0();
m_numberOfSpectraInFile = m_numberOfSpectra = nsp1[0];
m_numberOfChannelsInFile = m_numberOfChannels = data.dim2();
Gigg, Martyn Anthony
committed
if( nmons > 0 && m_numberOfSpectra == static_cast<size_t>(data.dim1()) )
Gigg, Martyn Anthony
committed
{
m_monitors.clear();
}
}
Gigg, Martyn Anthony
committed
// Check input is consistent with the file, throwing if not
checkOptionalProperties();
// Fill up m_spectraBlocks
size_t total_specs = prepareSpectraBlocks();
Gigg, Martyn Anthony
committed
m_progress = boost::shared_ptr<API::Progress>(new Progress(this, 0.0, 1.0, total_specs * m_numberOfPeriods));
DataObjects::Workspace2D_sptr local_workspace = boost::dynamic_pointer_cast<DataObjects::Workspace2D>
(WorkspaceFactory::Instance().create("Workspace2D", total_specs, x_length, m_numberOfChannels));
Russell Taylor
committed
// Set the units on the workspace to TOF & Counts
Gigg, Martyn Anthony
committed
local_workspace->getAxis(0)->unit() = UnitFactory::Instance().create("TOF");
Russell Taylor
committed
local_workspace->setYUnit("Counts");
Gigg, Martyn Anthony
committed
//Load instrument and other data once then copy it later
m_progress->report("Loading instrument");
Gigg, Martyn Anthony
committed
loadRunDetails(local_workspace, entry);
m_cppFile->openPath(entry.path());
std::string parameterString;
try { // Try to get instrument info from instrument and sample sections of Nexus file
local_workspace->loadExperimentInfoNexus( m_cppFile, parameterString );
} catch(std::exception & ) { // No valid instrument and sample section found
parameterString="not found";
}
if( parameterString == "not found") {
//Populate the Spectra Map with parameters from IDF file and use LoadInstrument algorithm
local_workspace->replaceSpectraMap(new SpectraDetectorMap(spec(),udet(),udet.dim0()));
runLoadInstrument(local_workspace);
} else { // Use parameters got from instrument section of Nexus file
local_workspace->readParameterMap(parameterString);
}
Gigg, Martyn Anthony
committed
loadSampleData(local_workspace, entry);
Roman Tolchenov
committed
m_progress->report("Loading logs");
Gigg, Martyn Anthony
committed
// Load first period outside loop
m_progress->report("Loading data");
if( ndets > 0 )
Gigg, Martyn Anthony
committed
{
Gigg, Martyn Anthony
committed
//Get the X data
NXFloat timeBins = entry.openNXFloat("detector_1/time_of_flight");
Gigg, Martyn Anthony
committed
timeBins.load();
m_tof_data.reset(new MantidVec(timeBins(), timeBins() + x_length));
Gigg, Martyn Anthony
committed
}
int64_t firstentry = (m_entrynumber > 0) ? m_entrynumber : 1;
Gigg, Martyn Anthony
committed
loadPeriodData(firstentry, entry, local_workspace);
local_workspace->updateSpectraUsingMap();
// Clone the workspace at this point to provide a base object for future workspace generation.
DataObjects::Workspace2D_sptr period_free_workspace = boost::dynamic_pointer_cast<DataObjects::Workspace2D>
(WorkspaceFactory::Instance().create(local_workspace));
createPeriodLogs(firstentry, local_workspace);
Gigg, Martyn Anthony
committed
if( m_numberOfPeriods > 1 && m_entrynumber == 0 )
{
WorkspaceGroup_sptr wksp_group(new WorkspaceGroup);
Steve Williams
committed
wksp_group->setTitle(local_workspace->getTitle());
Gigg, Martyn Anthony
committed
//This forms the name of the group
const std::string base_name = getPropertyValue("OutputWorkspace") + "_";
const std::string prop_name = "OutputWorkspace_";
for( int p = 1; p <= m_numberOfPeriods; ++p )
Gigg, Martyn Anthony
committed
{
std::ostringstream os;
os << p;
m_progress->report("Loading period " + os.str());
Steve Williams
committed
if( p > 1 )
{
local_workspace = boost::dynamic_pointer_cast<DataObjects::Workspace2D>
(WorkspaceFactory::Instance().create(period_free_workspace));
Steve Williams
committed
loadPeriodData(p, entry, local_workspace);
createPeriodLogs(p, local_workspace);
// Check consistency of logs data for multiperiod workspaces and raise warnings where necessary.
validateMultiPeriodLogs(local_workspace);
Steve Williams
committed
}
declareProperty(new WorkspaceProperty<Workspace>(prop_name + os.str(), base_name + os.str(), Direction::Output));
wksp_group->addWorkspace(local_workspace);
Steve Williams
committed
setProperty(prop_name + os.str(), boost::static_pointer_cast<Workspace>(local_workspace));
Gigg, Martyn Anthony
committed
}
// The group is the root property value
setProperty("OutputWorkspace", boost::dynamic_pointer_cast<Workspace>(wksp_group));
}
else
{
setProperty("OutputWorkspace", boost::dynamic_pointer_cast<Workspace>(local_workspace));
}
Russell Taylor
committed
// Clear off the member variable containers
m_spec_list.clear();
m_tof_data.reset();
m_spec.reset();
m_monitors.clear();
Gigg, Martyn Anthony
committed
}
Gigg, Martyn Anthony
committed
// Function object for remove_if STL algorithm
namespace
Gigg, Martyn Anthony
committed
{
Gigg, Martyn Anthony
committed
//Check the numbers supplied are not in the range and erase the ones that are
struct range_check
Gigg, Martyn Anthony
committed
{
range_check(int64_t min, int64_t max) : m_min(min), m_max(max) {}
Gigg, Martyn Anthony
committed
{
return (x >= m_min && x <= m_max);
}
private:
Gigg, Martyn Anthony
committed
};
Gigg, Martyn Anthony
committed
}
Russell Taylor
committed
/**
Check for a set of synthetic logs associated with multi-period log data. Raise warnings where necessary.
*/
void LoadISISNexus2::validateMultiPeriodLogs(Mantid::API::MatrixWorkspace_sptr ws)
{
const Run& run = ws->run();
if(!run.hasProperty("current_period"))
{
g_log.warning("Workspace has no current_period log.");
}
if(!run.hasProperty("nperiods"))
{
g_log.warning("Workspace has no nperiods log");
}
if(!run.hasProperty("proton_charge_by_period"))
{
g_log.warning("Workspace has not proton_charge_by_period log");
}
}
Gigg, Martyn Anthony
committed
/**
* Check the validity of the optional properties of the algorithm
*/
void LoadISISNexus2::checkOptionalProperties()
Gigg, Martyn Anthony
committed
{
Gigg, Martyn Anthony
committed
m_spec_min = getProperty("SpectrumMin");
m_spec_max = getProperty("SpectrumMax");
Russell Taylor
committed
Gigg, Martyn Anthony
committed
if( m_spec_min == 0 && m_spec_max == EMPTY_INT() )
{
m_range_supplied = false;
}
Russell Taylor
committed
Gigg, Martyn Anthony
committed
if( m_spec_min == 0 )
{
m_spec_min = 1;
}
Russell Taylor
committed
Gigg, Martyn Anthony
committed
if( m_spec_max == EMPTY_INT() )
{
m_spec_max = m_numberOfSpectra;
}
Russell Taylor
committed
Gigg, Martyn Anthony
committed
// Sanity check for min/max
if( m_spec_min > m_spec_max )
Russell Taylor
committed
{
Gigg, Martyn Anthony
committed
g_log.error() << "Inconsistent range properties. SpectrumMin is larger than SpectrumMax." << std::endl;
throw std::invalid_argument("Inconsistent range properties defined.");
}
Gigg, Martyn Anthony
committed
{
g_log.error() << "Inconsistent range property. SpectrumMax is larger than number of spectra: "
<< m_numberOfSpectra << std::endl;
throw std::invalid_argument("Inconsistent range properties defined.");
}
// Check the entry number
m_entrynumber = getProperty("EntryNumber");
if( static_cast<int>(m_entrynumber) > m_numberOfPeriods || m_entrynumber < 0 )
Gigg, Martyn Anthony
committed
{
Gigg, Martyn Anthony
committed
g_log.error() << "Invalid entry number entered. File contains " << m_numberOfPeriods << " period. "
<< std::endl;
throw std::invalid_argument("Invalid entry number.");
Gigg, Martyn Anthony
committed
}
Gigg, Martyn Anthony
committed
if( m_numberOfPeriods == 1 )
Gigg, Martyn Anthony
committed
{
Gigg, Martyn Anthony
committed
m_entrynumber = 1;
Russell Taylor
committed
}
Gigg, Martyn Anthony
committed
//Check the list property
m_spec_list = getProperty("SpectrumList");
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
if( ! m_spec_list.empty() )
{
// Sort the list so that we can check it's range
std::sort(m_spec_list.begin(), m_spec_list.end());
if( m_spec_list.back() > static_cast<int64_t>(m_numberOfSpectra) )
{
g_log.error() << "Inconsistent SpectraList property defined for a total of " << m_numberOfSpectra
<< " spectra." << std::endl;
throw std::invalid_argument("Inconsistent property defined");
}
//Check no negative numbers have been passed
std::vector<int64_t>::iterator itr =
std::find_if(m_spec_list.begin(), m_spec_list.end(), std::bind2nd(std::less<int>(), 0));
if( itr != m_spec_list.end() )
{
g_log.error() << "Negative SpectraList property encountered." << std::endl;
throw std::invalid_argument("Inconsistent property defined.");
}
range_check in_range(m_spec_min, m_spec_max);
if( m_range_supplied )
{
m_spec_list.erase(remove_if(m_spec_list.begin(), m_spec_list.end(), in_range), m_spec_list.end());
}
}
else
Russell Taylor
committed
{
Gigg, Martyn Anthony
committed
m_range_supplied = true;
Russell Taylor
committed
}
Gigg, Martyn Anthony
committed
namespace
{
/// Compare two spectra blocks for ordering
bool compareSpectraBlocks(const LoadISISNexus2::SpectraBlock& block1, const LoadISISNexus2::SpectraBlock& block2)
Gigg, Martyn Anthony
committed
{
bool res = block1.last < block2.first;
if ( !res )
{
assert( block2.last < block1.first );
}
return res;
Gigg, Martyn Anthony
committed
}
Gigg, Martyn Anthony
committed
/**
* Analyze the spectra ranges and prepare a list contiguous blocks. Each monitor must be
* in a separate block.
* @return :: Number of spectra to load.
*/
size_t LoadISISNexus2::prepareSpectraBlocks()
{
std::vector<int64_t> includedMonitors;
// fill in the data block descriptor vector
if ( ! m_spec_list.empty() )
Gigg, Martyn Anthony
committed
{
int64_t hist = m_spec_list[0];
SpectraBlock block(hist,hist,false);
for(auto spec = m_spec_list.cbegin() + 1; spec != m_spec_list.cend(); ++spec)
{
// try to put all consequtive numbers in same block
bool isMonitor = m_monitors.find( hist ) != m_monitors.end();
if ( isMonitor || *spec != hist + 1 )
{
block.last = hist;
block.isMonitor = isMonitor;
m_spectraBlocks.push_back( block );
if ( isMonitor ) includedMonitors.push_back( hist );
block = SpectraBlock(*spec,*spec,false);
}
hist = *spec;
}
// push the last block
hist = m_spec_list.back();
block.last = hist;
if ( m_monitors.find( hist ) != m_monitors.end() )
{
includedMonitors.push_back( hist );
block.isMonitor = true;
}
m_spectraBlocks.push_back( block );
Gigg, Martyn Anthony
committed
}
// put in the spectra range, possibly breaking it into parts by monitors
int64_t first = m_spec_min;
for(int64_t hist = first; hist < m_spec_max; ++hist)
{
if ( m_monitors.find( hist ) != m_monitors.end() )
{
if ( hist != first )
{
m_spectraBlocks.push_back( SpectraBlock( first, hist - 1, false ) );
}
m_spectraBlocks.push_back( SpectraBlock( hist, hist, true) );
includedMonitors.push_back( hist );
first = hist + 1;
}
}
if ( first == m_spec_max && m_monitors.find( first ) != m_monitors.end() )
{
m_spectraBlocks.push_back( SpectraBlock( first, m_spec_max, true ) );
includedMonitors.push_back( m_spec_max );
}
else
Gigg, Martyn Anthony
committed
{
m_spectraBlocks.push_back( SpectraBlock( first, m_spec_max, false ) );
Gigg, Martyn Anthony
committed
}
// sort and check for overlapping
if ( m_spectraBlocks.size() > 1 )
{
std::sort( m_spectraBlocks.begin(), m_spectraBlocks.end(), compareSpectraBlocks );
}
Gigg, Martyn Anthony
committed
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
// remove monitors that weren't requested
if ( m_monitors.size() != includedMonitors.size() )
{
if ( includedMonitors.empty() )
{
m_monitors.clear();
}
else
{
for(auto it = m_monitors.begin(); it != m_monitors.end(); )
{
if ( std::find( includedMonitors.begin(), includedMonitors.end(), it->first ) == includedMonitors.end() )
{
auto it1 = it;
++it;
m_monitors.erase( it1 );
}
else
{
++it;
}
}
}
}
// count the number of spectra
size_t nSpec = 0;
for( auto it = m_spectraBlocks.cbegin(); it != m_spectraBlocks.cend(); ++it )
{
nSpec += it->last - it->first + 1;
}
return nSpec;
Gigg, Martyn Anthony
committed
/**
* Load a given period into the workspace
Janik Zikovsky
committed
* @param period :: The period number to load (starting from 1)
* @param entry :: The opened root entry node for accessing the monitor and data nodes
* @param local_workspace :: The workspace to place the data in
Gigg, Martyn Anthony
committed
*/
void LoadISISNexus2::loadPeriodData(int64_t period, NXEntry & entry, DataObjects::Workspace2D_sptr local_workspace)
int64_t hist_index = 0;
int64_t period_index(period - 1);
//int64_t first_monitor_spectrum = 0;
for(auto block = m_spectraBlocks.cbegin(); block != m_spectraBlocks.cend(); ++block)
auto it = m_monitors.find( block->first );
assert( it != m_monitors.end() );
NXData monitor = entry.openNXData(it->second);
NXInt mondata = monitor.openIntData();
m_progress->report("Loading monitor");
mondata.load(1,static_cast<int>(period-1)); // TODO this is just wrong
MantidVec& Y = local_workspace->dataY(hist_index);
Y.assign(mondata(),mondata() + m_numberOfChannels);
MantidVec& E = local_workspace->dataE(hist_index);
std::transform(Y.begin(), Y.end(), E.begin(), dblSqrt);
local_workspace->getAxis(1)->spectraNo(hist_index) = static_cast<specid_t>(it->first);
NXFloat timeBins = monitor.openNXFloat("time_of_flight");
timeBins.load();
local_workspace->dataX(hist_index).assign(timeBins(),timeBins() + timeBins.dim0());
hist_index++;
}
Gigg, Martyn Anthony
committed
{
NXData nxdata = entry.openNXData("detector_1");
NXDataSetTyped<int> data = nxdata.openIntData();
data.open();
//Start with thelist members that are lower than the required spectrum
const int * const spec_begin = m_spec.get();
Gigg, Martyn Anthony
committed
// When reading in blocks we need to be careful that the range is exactly divisible by the blocksize
// and if not have an extra read of the left overs
const int64_t rangesize = block->last - block->first + 1;
int64_t spectra_no = block->first;
Russell Taylor
committed
// For this to work correctly, we assume that the spectrum list increases monotonically
int64_t filestart = std::lower_bound(spec_begin,m_spec_end,spectra_no) - spec_begin;
Gigg, Martyn Anthony
committed
if( fullblocks > 0 )
{
Gigg, Martyn Anthony
committed
{
loadBlock(data, blocksize, period_index, filestart, hist_index, spectra_no, local_workspace);
filestart += blocksize;
}
}
int64_t finalblock = rangesize - (fullblocks * blocksize);
Gigg, Martyn Anthony
committed
if( finalblock > 0 )
{
loadBlock(data, finalblock, period_index, filestart, hist_index, spectra_no, local_workspace);
}
}
}
Steve Williams
committed
const std::string title = entry.getString("title");
local_workspace->setTitle(title);
// write the title into the log file (run object)
Anders Markvardsen
committed
local_workspace->mutableRun().addProperty("run_title", title, true);
catch (std::runtime_error &)
{
g_log.debug() << "No title was found in the input file, " << getPropertyValue("Filename") << std::endl;
}
Gigg, Martyn Anthony
committed
* Creates period log data in the workspace
* @param period :: period number
* @param local_workspace :: workspace to add period log data to.
void LoadISISNexus2::createPeriodLogs(int64_t period, DataObjects::Workspace2D_sptr local_workspace)
m_logCreator->addPeriodLogs(static_cast<int>(period), local_workspace->mutableRun());
Gigg, Martyn Anthony
committed
/**
* Perform a call to nxgetslab, via the NexusClasses wrapped methods for a given blocksize
Janik Zikovsky
committed
* @param data :: The NXDataSet object
* @param blocksize :: The blocksize to use
* @param period :: The period number
* @param start :: The index within the file to start reading from (zero based)
* @param hist :: The workspace index to start reading into
* @param spec_num :: The spectrum number that matches the hist variable
* @param local_workspace :: The workspace to fill the data with
Gigg, Martyn Anthony
committed
*/
void LoadISISNexus2::loadBlock(NXDataSetTyped<int> & data, int64_t blocksize, int64_t period, int64_t start,
int64_t &hist, int64_t& spec_num,
Gigg, Martyn Anthony
committed
DataObjects::Workspace2D_sptr local_workspace)
data.load(static_cast<int>(blocksize), static_cast<int>(period), static_cast<int>(start)); // TODO this is just wrong
Gigg, Martyn Anthony
committed
int *data_start = data();
int *data_end = data_start + m_numberOfChannels;
Gigg, Martyn Anthony
committed
while( hist < final )
{
m_progress->report("Loading data");
MantidVec& Y = local_workspace->dataY(hist);
Y.assign(data_start, data_end);
data_start += m_numberOfChannels; data_end += m_numberOfChannels;
MantidVec& E = local_workspace->dataE(hist);
std::transform(Y.begin(), Y.end(), E.begin(), dblSqrt);
// Populate the workspace. Loop starts from 1, hence i-1
local_workspace->setX(hist, m_tof_data);
local_workspace->getAxis(1)->spectraNo(hist)= static_cast<specid_t>(spec_num);
Gigg, Martyn Anthony
committed
++hist;
++spec_num;
}
Gigg, Martyn Anthony
committed
/// Run the Child Algorithm LoadInstrument (or LoadInstrumentFromNexus)
Gigg, Martyn Anthony
committed
void LoadISISNexus2::runLoadInstrument(DataObjects::Workspace2D_sptr localWorkspace)
Gigg, Martyn Anthony
committed
IAlgorithm_sptr loadInst = createChildAlgorithm("LoadInstrument");
Gigg, Martyn Anthony
committed
// Now execute the Child Algorithm. Catch and log any error, but don't stop.
Gigg, Martyn Anthony
committed
bool executionSuccessful(true);
try
{
loadInst->setPropertyValue("InstrumentName", m_instrument_name);
Gigg, Martyn Anthony
committed
loadInst->setProperty<MatrixWorkspace_sptr> ("Workspace", localWorkspace);
Gigg, Martyn Anthony
committed
loadInst->setProperty("RewriteSpectraMap", false);
Gigg, Martyn Anthony
committed
loadInst->execute();
}
catch( std::invalid_argument&)
{
g_log.information("Invalid argument to LoadInstrument Child Algorithm");
Gigg, Martyn Anthony
committed
executionSuccessful = false;
}
catch (std::runtime_error&)
{
g_log.information("Unable to successfully run LoadInstrument Child Algorithm");
Gigg, Martyn Anthony
committed
executionSuccessful = false;
}
Gigg, Martyn Anthony
committed
if( executionSuccessful )
{
// If requested update the instrument to positions in the data file
Gigg, Martyn Anthony
committed
const Geometry::ParameterMap & pmap = localWorkspace->instrumentParameters();
Russell Taylor
committed
if( pmap.contains(localWorkspace->getInstrument()->getComponentID(),"det-pos-source") )
Gigg, Martyn Anthony
committed
{
Russell Taylor
committed
boost::shared_ptr<Geometry::Parameter> updateDets = pmap.get(localWorkspace->getInstrument()->getComponentID(),"det-pos-source");
std::string value = updateDets->value<std::string>();
if(value.substr(0,8) == "datafile" )
Gigg, Martyn Anthony
committed
{
IAlgorithm_sptr updateInst = createChildAlgorithm("UpdateInstrumentFromFile");
Gigg, Martyn Anthony
committed
updateInst->setProperty<MatrixWorkspace_sptr>("Workspace", localWorkspace);
updateInst->setPropertyValue("Filename", m_filename);
if(value == "datafile-ignore-phi" )
{
updateInst->setProperty("IgnorePhi", true);
g_log.information("Detector positions in IDF updated with positions in the data file except for the phi values");
}
else
{
g_log.information("Detector positions in IDF updated with positions in the data file");
Gigg, Martyn Anthony
committed
// We want this to throw if it fails to warn the user that the information is not correct.
updateInst->execute();
}
}
}
Gigg, Martyn Anthony
committed
Gigg, Martyn Anthony
committed
/**
* Load data about the run
Janik Zikovsky
committed
* @param local_workspace :: The workspace to load the run information in to
* @param entry :: The Nexus entry
Gigg, Martyn Anthony
committed
*/
void LoadISISNexus2::loadRunDetails(DataObjects::Workspace2D_sptr local_workspace, NXEntry & entry)
Gigg, Martyn Anthony
committed
{
Gigg, Martyn Anthony
committed
API::Run & runDetails = local_workspace->mutableRun();
Gigg, Martyn Anthony
committed
// Charge is stored as a float
m_proton_charge = static_cast<double>(entry.getFloat("proton_charge"));
runDetails.setProtonCharge(m_proton_charge);
Gigg, Martyn Anthony
committed
std::string run_num = boost::lexical_cast<std::string>(entry.getInt("run_number"));
Gigg, Martyn Anthony
committed
runDetails.addProperty("run_number", run_num);
//
// Some details are only stored in the VMS compatability block so we'll pull everything from there
// for consistency
NXClass vms_compat = entry.openNXGroup("isis_vms_compat");
Gigg, Martyn Anthony
committed
// Run header
NXChar char_data = vms_compat.openNXChar("HDR");
Gigg, Martyn Anthony
committed
char_data.load();
runDetails.addProperty("run_header", std::string(char_data(),80));
// Data details on run not the workspace
runDetails.addProperty("nspectra", static_cast<int>(m_numberOfSpectraInFile));
runDetails.addProperty("nchannels", static_cast<int>(m_numberOfChannelsInFile));
runDetails.addProperty("nperiods", static_cast<int>(m_numberOfPeriodsInFile));
// RPB struct info
NXInt rpb_int = vms_compat.openNXInt("IRPB");
Gigg, Martyn Anthony
committed
rpb_int.load();
Gigg, Martyn Anthony
committed
runDetails.addProperty("dur", rpb_int[0]); // actual run duration
runDetails.addProperty("durunits", rpb_int[1]); // scaler for above (1=seconds)
Gigg, Martyn Anthony
committed
runDetails.addProperty("dur_freq", rpb_int[2]); // testinterval for above (seconds)
runDetails.addProperty("dmp", rpb_int[3]); // dump interval
Gigg, Martyn Anthony
committed
runDetails.addProperty("dmp_units", rpb_int[4]); // scaler for above
runDetails.addProperty("dmp_freq", rpb_int[5]); // interval for above
runDetails.addProperty("freq", rpb_int[6]); // 2**k where source frequency = 50 / 2**k
Gigg, Martyn Anthony
committed
// Now double data
NXFloat rpb_dbl = vms_compat.openNXFloat("RRPB");
Gigg, Martyn Anthony
committed
rpb_dbl.load();
Gigg, Martyn Anthony
committed
runDetails.addProperty("gd_prtn_chrg", static_cast<double>(rpb_dbl[7])); // good proton charge (uA.hour)
runDetails.addProperty("tot_prtn_chrg", static_cast<double>(rpb_dbl[8])); // total proton charge (uA.hour)
Gigg, Martyn Anthony
committed
runDetails.addProperty("goodfrm",rpb_int[9]); // good frames
runDetails.addProperty("rawfrm", rpb_int[10]); // raw frames
Gigg, Martyn Anthony
committed
runDetails.addProperty("dur_wanted", rpb_int[11]); // requested run duration (units as for "duration" above)
Gigg, Martyn Anthony
committed
runDetails.addProperty("dur_secs", rpb_int[12]); // actual run duration in seconds
runDetails.addProperty("mon_sum1", rpb_int[13]); // monitor sum 1
runDetails.addProperty("mon_sum2", rpb_int[14]); // monitor sum 2
runDetails.addProperty("mon_sum3",rpb_int[15]); // monitor sum 3
Gigg, Martyn Anthony
committed
// End date and time is stored separately in ISO format in the "raw_data1/endtime" class
char_data = entry.openNXChar("end_time");
char_data.load();
std::string end_time_iso = std::string(char_data(), 19);
runDetails.addProperty("run_end", end_time_iso);
Gigg, Martyn Anthony
committed
char_data = entry.openNXChar("start_time");
char_data.load();
std::string start_time_iso = std::string(char_data(), 19);
runDetails.addProperty("run_start", start_time_iso);
Gigg, Martyn Anthony
committed
runDetails.addProperty("rb_proposal",rpb_int[21]); // RB (proposal) number
vms_compat.close();
}
/**
* Parse an ISO formatted date-time string into separate date and time strings
Janik Zikovsky
committed
* @param datetime_iso :: The string containing the ISO formatted date-time
* @param date :: An output parameter containing the date from the original string or ??-??-???? if the format is unknown
* @param time :: An output parameter containing the time from the original string or ??-??-?? if the format is unknown
Gigg, Martyn Anthony
committed
*/
void LoadISISNexus2::parseISODateTime(const std::string & datetime_iso, std::string & date, std::string & time) const
{
Gigg, Martyn Anthony
committed
try
{
Gigg, Martyn Anthony
committed
Poco::DateTime datetime_output;
int timezone_diff(0);
Poco::DateTimeParser::parse(Poco::DateTimeFormat::ISO8601_FORMAT, datetime_iso, datetime_output, timezone_diff);
date = Poco::DateTimeFormatter::format(datetime_output, "%d-%m-%Y", timezone_diff);
time = Poco::DateTimeFormatter::format(datetime_output, "%H:%M:%S", timezone_diff);
Gigg, Martyn Anthony
committed
}
catch(Poco::SyntaxException&)
{
Gigg, Martyn Anthony
committed
date = "\?\?-\?\?-\?\?\?\?";
time = "\?\?:\?\?:\?\?";
g_log.warning() << "Cannot parse end time from entry in Nexus file.\n";
Gigg, Martyn Anthony
committed
}
Gigg, Martyn Anthony
committed
}
Gigg, Martyn Anthony
committed
/**
* Load data about the sample
Janik Zikovsky
committed
* @param local_workspace :: The workspace to load the logs to.
* @param entry :: The Nexus entry
Gigg, Martyn Anthony
committed
*/
void LoadISISNexus2::loadSampleData(DataObjects::Workspace2D_sptr local_workspace, NXEntry & entry)
Gigg, Martyn Anthony
committed
/// Sample geometry
NXInt spb = entry.openNXInt("isis_vms_compat/SPB");
Gigg, Martyn Anthony
committed
// Just load the index we need, not the whole block. The flag is the third value in
spb.load(1, 2);
int geom_id = spb[0];
Sofia Antony
committed
local_workspace->mutableSample().setGeometryFlag(spb[0]);
Gigg, Martyn Anthony
committed
NXFloat rspb = entry.openNXFloat("isis_vms_compat/RSPB");
Gigg, Martyn Anthony
committed
// Just load the indices we need, not the whole block. The values start from the 4th onward
rspb.load(3, 3);
double thick(rspb[0]), height(rspb[1]), width(rspb[2]);
Sofia Antony
committed
local_workspace->mutableSample().setThickness(thick);
local_workspace->mutableSample().setHeight(height);
local_workspace->mutableSample().setWidth(width);
Gigg, Martyn Anthony
committed
g_log.debug() << "Sample geometry - ID: " << geom_id << ", thickness: " << thick << ", height: " << height << ", width: " << width << "\n";
Gigg, Martyn Anthony
committed
/** Load logs from Nexus file. Logs are expected to be in
* /raw_data_1/runlog group of the file. Call to this method must be done
* within /raw_data_1 group.
Janik Zikovsky
committed
* @param ws :: The workspace to load the logs to.
Gigg, Martyn Anthony
committed
*/
void LoadISISNexus2::loadLogs(DataObjects::Workspace2D_sptr ws, NXEntry & entry)
Gigg, Martyn Anthony
committed
{
IAlgorithm_sptr alg = createChildAlgorithm("LoadNexusLogs", 0.0, 0.5);
Gigg, Martyn Anthony
committed
alg->setPropertyValue("Filename", this->getProperty("Filename"));
alg->setProperty<MatrixWorkspace_sptr>("Workspace", ws);
try
Gigg, Martyn Anthony
committed
catch(std::runtime_error&)
Gigg, Martyn Anthony
committed
g_log.warning() << "Unable to load run logs. There will be no log "
<< "data associated with this workspace\n";
Gigg, Martyn Anthony
committed
return;
Roman Tolchenov
committed
}
// For ISIS Nexus only, fabricate an addtional log containing an array of proton charge information from the periods group.
try
{
NXClass protonChargeClass = entry.openNXGroup("periods");
NXFloat periodsCharge = protonChargeClass.openNXFloat("proton_charge");
periodsCharge.load();
size_t nperiods = periodsCharge.dim0();
std::vector<double> chargesVector(nperiods);
std::copy(periodsCharge(), periodsCharge() + nperiods, chargesVector.begin());
ArrayProperty<double>* protonLogData = new ArrayProperty<double>("proton_charge_by_period", chargesVector);
ws->mutableRun().addProperty(protonLogData);
}
catch(std::runtime_error&)
{
this->g_log.debug("Cannot read periods information from the nexus file. This group may be absent.");
}
// Populate the instrument parameters.
Roman Tolchenov
committed
ws->populateInstrumentParameters();
// Make log creator object and add the run status log
m_logCreator.reset(new ISISRunLogs(ws->run(), m_numberOfPeriods));
m_logCreator->addStatusLog(ws->mutableRun());
Gigg, Martyn Anthony
committed
}
Gigg, Martyn Anthony
committed
double LoadISISNexus2::dblSqrt(double in)
{
return sqrt(in);
}
Sofia Antony
committed
/**This method does a quick file type check by looking at the first 100 bytes of the file
* @param filePath- path of the file including name.
Janik Zikovsky
committed
* @param nread :: no.of bytes read
Gigg, Martyn Anthony
committed
* @param header :: The first 100 bytes of the file as a union
Sofia Antony
committed
* @return true if the given file is of type which can be loaded by this algorithm
*/
Gigg, Martyn Anthony
committed
bool LoadISISNexus2::quickFileCheck(const std::string& filePath, size_t nread,const file_header& header)
Sofia Antony
committed
{
std::string extn=extension(filePath);
bool bnexs(false);
(!extn.compare("nxs")||!extn.compare("nx5"))?bnexs=true:bnexs=false;
Sofia Antony
committed
/*
Gigg, Martyn Anthony
committed
* HDF files have magic cookie in the first 4 bytes
Sofia Antony
committed
*/
Gigg, Martyn Anthony
committed
if ( ((nread >= sizeof(unsigned)) && (ntohl(header.four_bytes) == g_hdf_cookie)) || bnexs )
Sofia Antony
committed
{
//hdf
return true;
}
Gigg, Martyn Anthony
committed
else if ( (nread >= sizeof(g_hdf5_signature)) &&
Gigg, Martyn Anthony
committed
(!memcmp(header.full_hdr, g_hdf5_signature, sizeof(g_hdf5_signature))) )
Sofia Antony
committed
{
//hdf5
return true;
}
return false;
}
/**checks the file by opening it and reading few lines
Janik Zikovsky
committed
* @param filePath :: name of the file inluding its path
Sofia Antony
committed
* @return an integer value how much this algorithm can load the file
*/
int LoadISISNexus2::fileCheck(const std::string& filePath)
{
Gigg, Martyn Anthony
committed
using namespace ::NeXus;
int confidence(0);
try
Sofia Antony
committed
{
Gigg, Martyn Anthony
committed
::NeXus::File file = ::NeXus::File(filePath);
// Open the base group called 'entry'
file.openGroup("raw_data_1", "NXentry");
// If all this succeeded then we'll assume this is an ISIS NeXus file
confidence = 80;
Sofia Antony
committed
}
Gigg, Martyn Anthony
committed
catch(::NeXus::Exception&)
Sofia Antony
committed
{
}
Gigg, Martyn Anthony
committed
return confidence;
Sofia Antony
committed
}
Gigg, Martyn Anthony
committed
} // namespace DataHandling