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/ListValidator.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"
Gigg, Martyn Anthony
committed
#include "MantidGeometry/Instrument/Detector.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 <climits>
#include <sstream>
#include <cctype>
Gigg, Martyn Anthony
committed
#include <functional>
#include <algorithm>
namespace DataHandling
Russell Taylor
committed
{
DECLARE_NEXUS_FILELOADER_ALGORITHM(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() :
m_filename(), m_instrument_name(), m_samplename(), m_numberOfSpectra(0), m_numberOfSpectraInFile(0),
m_numberOfPeriods(0), m_numberOfPeriodsInFile(0), m_numberOfChannels(0), m_numberOfChannelsInFile(0),
m_have_detector(false),m_range_supplied(true), m_spec_min(0), m_spec_max(EMPTY_INT()),
m_load_selected_spectra(false),m_specInd2specNum_map(),m_spec2det_map(),
m_entrynumber(0), m_tof_data(), m_proton_charge(0.),
m_spec(), m_monitors(), m_logCreator(), m_progress()
Gigg, Martyn Anthony
committed
{}
* Return the confidence criteria for 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
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)");
declareProperty(new PropertyWithValue<bool>("LoadMonitorsSeparately", false, Direction::Input),
"If true, loads monitors and puts them into separate workspace");
std::vector<std::string> monitorOptions;
monitorOptions.push_back("Include");
monitorOptions.push_back("Exclude");
monitorOptions.push_back("Separate");
std::map<std::string,std::string> monitorOptionsAliases;
monitorOptionsAliases["1"] = "Separate";
monitorOptionsAliases["0"] = "Exclude";
declareProperty("LoadMonitors","Exclude", boost::make_shared<Kernel::StringListValidator>(monitorOptions,monitorOptionsAliases),
"Option to control the loading of monitors.\n"
"Allowed options are Include,Exclude, Separate.\n"
"Include:Include option would load monitors with the workspace. If the time binning for the monitors is different from the\n"
"binning of the detectors this option is equivalent to Separate option\n"
"Exclude:The default is Exclude option excludes monitors from the output workspace.\n"
"Separate:The Separate option loads monitors into a separate workspace called OutputWorkspace_monitor.\n"
"Defined aliases:\n"
"1: Equivalent to Separate.\n"
"0: Equivalent to Exclude.\n");
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
std::vector<int64_t> mon_spectra_num;
int64_t max_spectra_num(LONG_MIN);
int64_t min_spectra_num(LONG_MAX);
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();
int64_t ind = *index();
m_monitors[ind ] = it->nxname;
mon_spectra_num.push_back(ind);
if (ind > max_spectra_num)max_spectra_num=ind;
if (ind < min_spectra_num)min_spectra_num=ind;
Gigg, Martyn Anthony
committed
++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();
if(max_spectra_num > m_numberOfSpectra)
m_numberOfSpectra += mon_spectra_num.size();
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);
if(m_load_selected_spectra)
m_spec2det_map = SpectrumDetectorMapping(spec(),udet(),udet.dim0());
else
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 maintenance 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 multi-period 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_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
}
build the list of spectra to load and include into spectra-detectors map
@param spec_list -- list of spectra to load
void LoadISISNexus2::buildSpectraInd2SpectraNumMap(const std::vector<int64_t> &spec_list)
if(spec_list.size()>0)
auto start_point = spec_list.begin();
for(auto it =start_point ;it!=spec_list.end();it++)
ic = it-start_point;
m_specInd2specNum_map.insert(std::pair<int64_t,specid_t>(ic,static_cast<specid_t>(*it)));
else
{
if(m_range_supplied)
ic = m_specInd2specNum_map.size();
m_specInd2specNum_map.insert(std::pair<int64_t,specid_t>(i-m_spec_min+ic,static_cast<specid_t>(i)));
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 and identify if partial data should be loaded.
Gigg, Martyn Anthony
committed
*/
void LoadISISNexus2::checkOptionalProperties()
Gigg, Martyn Anthony
committed
{
// optional properties specify that only some spectra have to be loaded
m_load_selected_spectra = false;
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;
m_load_selected_spectra = true;
Russell Taylor
committed
Gigg, Martyn Anthony
committed
if( m_spec_max == EMPTY_INT() )
m_spec_max = m_numberOfSpectra;
m_load_selected_spectra = true;
Russell Taylor
committed
Gigg, Martyn Anthony
committed
// Sanity check for min/max
if( m_spec_min > m_spec_max )
Russell Taylor
committed
{
throw std::invalid_argument("Inconsistent range properties. SpectrumMin is larger than SpectrumMax.");
Gigg, Martyn Anthony
committed
}
Gigg, Martyn Anthony
committed
{
std::string err="Inconsistent range property. SpectrumMax is larger than number of spectra: "+boost::lexical_cast<std::string>(m_numberOfSpectra );
throw std::invalid_argument(err);
Gigg, Martyn Anthony
committed
}
// Check the entry number
m_entrynumber = getProperty("EntryNumber");
if( static_cast<int>(m_entrynumber) > m_numberOfPeriods || m_entrynumber < 0 )
Gigg, Martyn Anthony
committed
{
std::string err="Invalid entry number entered. File contains "+boost::lexical_cast<std::string>(m_numberOfPeriods )+ " period. ";
throw std::invalid_argument(err);
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
std::vector<int64_t> spec_list = getProperty("SpectrumList");
if( ! spec_list.empty() )
m_load_selected_spectra = true;
// Sort the list so that we can check it's range
std::sort(spec_list.begin(), spec_list.end());
if( spec_list.back() > static_cast<int64_t>(m_numberOfSpectra) )
std::string err="A spectra number in the spectra list exceeds total number of "+boost::lexical_cast<std::string>(m_numberOfSpectra )+ " spectra ";
throw std::invalid_argument(err);
}
//Check no negative numbers have been passed
std::vector<int64_t>::iterator itr =
std::find_if(spec_list.begin(), spec_list.end(), std::bind2nd(std::less<int>(), 0));
if( itr != spec_list.end() )
throw std::invalid_argument("Negative SpectraList property encountered.");
}
range_check in_range(m_spec_min, m_spec_max);
if( m_range_supplied )
{
spec_list.erase(remove_if(spec_list.begin(), spec_list.end(), in_range), spec_list.end());
// combine spectra numbers from ranges and the list
if (spec_list.size()>0)
{
spec_list.push_back(static_cast<specid_t>(i));
// Sort the list so that lower spectra indexes correspond to smaller spectra ID-s
std::sort(spec_list.begin(), spec_list.end());
}
Russell Taylor
committed
{
Gigg, Martyn Anthony
committed
m_range_supplied = true;
Russell Taylor
committed
}
if (m_load_selected_spectra)
{
buildSpectraInd2SpectraNumMap(spec_list);
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_specInd2specNum_map.empty() )
Gigg, Martyn Anthony
committed
{
auto itSpec= m_specInd2specNum_map.begin();
int64_t hist = itSpec->second;
SpectraBlock block(hist,hist,false);
itSpec++;
for(; itSpec != m_specInd2specNum_map.end(); ++itSpec)
// try to put all consecutive numbers in same block
bool isMonitor = m_monitors.find( hist ) != m_monitors.end();
if ( isMonitor || itSpec->second!= hist + 1 )
{
block.last = hist;
block.isMonitor = isMonitor;
m_spectraBlocks.push_back( block );
if ( isMonitor ) includedMonitors.push_back( hist );
block = SpectraBlock(itSpec ->second,itSpec ->second,false);
hist = itSpec ->second;
hist = m_specInd2specNum_map.rbegin()->second;
block.last = hist;
if ( m_monitors.find( hist ) != m_monitors.end() )
{
includedMonitors.push_back( hist );
block.isMonitor = true;
}
m_spectraBlocks.push_back( block );
return m_specInd2specNum_map.size();
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
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
// 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);
if (m_load_selected_spectra)
{
//local_workspace->getAxis(1)->setValue(hist_index, static_cast<specid_t>(it->first));
auto spec = local_workspace->getSpectrum(hist_index);
specid_t specID = m_specInd2specNum_map.at(hist_index);
spec->setDetectorIDs(m_spec2det_map.getDetectorIDsForSpectrumNo(specID));
spec->setSpectrumNo(specID);
}
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 the list members that are lower than the required spectrum
const int * const spec_begin = m_spec.get();
// When reading in blocks we need to be careful that the range is exactly divisible by the block-size
Gigg, Martyn Anthony
committed
// 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 block-size
Janik Zikovsky
committed
* @param data :: The NXDataSet object
Janik Zikovsky
committed
* @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);
if (m_load_selected_spectra)
{
//local_workspace->getAxis(1)->setValue(hist, static_cast<specid_t>(spec_num));
auto spec = local_workspace->getSpectrum(hist);
specid_t specID = m_specInd2specNum_map.at(hist);
// set detectors corresponding to spectra Number
spec->setDetectorIDs(m_spec2det_map.getDetectorIDsForSpectrumNo(specID));
// set correct spectra Number
spec->setSpectrumNo(specID);
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);
Gigg, Martyn Anthony
committed
//
// Some details are only stored in the VMS comparability block so we'll pull everything from there
Gigg, Martyn Anthony
committed
// 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);
if( i < 6 ) // no space after last field
{
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
* @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 additional 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