Newer
Older
//----------------------------------------------------------------------
// Includes
//----------------------------------------------------------------------
#include "MantidDataHandling/LoadISISNexus2.h"
#include "MantidDataHandling/LoadEventNexus.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/RegisterFileLoader.h"
#include "MantidAPI/SpectrumDetectorMapping.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
{
DECLARE_NEXUS_FILELOADER_ALGORITHM(LoadISISNexus2);
Sofia Antony
committed
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
{}
/**
* 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 LoadISISNexus2::confidence(Kernel::NexusDescriptor & descriptor) const
{
if(descriptor.pathOfTypeExists("/raw_data_1","NXentry")) return 80;
return 0;
}
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 and run details");
// load run details
Gigg, Martyn Anthony
committed
loadRunDetails(local_workspace, entry);
// Test if IDF exists in Nexus otherwise load default instrument
bool foundInstrument = LoadEventNexus::runLoadIDFFromNexus(m_filename, local_workspace, "raw_data_1", this);
local_workspace->updateSpectraUsing(SpectrumDetectorMapping(spec(),udet(),udet.dim0()));
if (!foundInstrument)
{
runLoadInstrument(local_workspace);
}
// Load logs and sample information
m_cppFile->openPath(entry.path());
local_workspace->loadSampleAndLogInfoNexus(m_cppFile);
// Load logs and sample information further information... See mainteance ticket #8697
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);
// 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");
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
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.begin() + 1; spec != m_spec_list.end(); ++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
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
// 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.begin(); it != m_spectraBlocks.end(); ++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.begin(); block != m_spectraBlocks.end(); ++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)->setValue(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)->setValue(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();
// Space-separate the fields
char * nxsHdr = char_data();
char header[86] = {};
const size_t byte = sizeof(char);
const char fieldSep(' ');
size_t fieldWidths[7] = {3, 5, 20, 24, 12, 8, 8};
char * srcStart = nxsHdr;
char * destStart = header;
for(size_t i = 0; i < 7; ++i)
{
size_t width = fieldWidths[i];
memcpy(destStart, srcStart, width*byte);
srcStart += width;
destStart += width;
memset(destStart, fieldSep, byte); // insert separator
destStart += 1;
}
runDetails.addProperty("run_header", std::string(header, header + 86));
Gigg, Martyn Anthony
committed
// 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);
}
Gigg, Martyn Anthony
committed
} // namespace DataHandling