Skip to content

Commit

Permalink
Support loading multiperiod data without any processing. Re #7954
Browse files Browse the repository at this point in the history
  • Loading branch information
mantid-roman committed Oct 25, 2013
1 parent 944e5c0 commit 37a9649
Show file tree
Hide file tree
Showing 4 changed files with 116 additions and 45 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ namespace Mantid
// Initialize the event buffer
void initEventBuffer(const TCPStreamEventDataSetup& setup);
// Save received event data in the buffer workspace
void saveEvents(const std::vector<TCPStreamEventNeutron>& data, const Mantid::Kernel::DateAndTime& pulseTime);
void saveEvents(const std::vector<TCPStreamEventNeutron> &data, const Kernel::DateAndTime &pulseTime, const size_t period);
// Set the spectra-detector map
void loadSpectraMap();
// Load the instrument
Expand All @@ -151,7 +151,7 @@ namespace Mantid
boost::shared_ptr<std::runtime_error> m_backgroundException;

/// Used to buffer events between calls to extractData()
DataObjects::EventWorkspace_sptr m_eventBuffer;
std::vector<DataObjects::EventWorkspace_sptr> m_eventBuffer;
/// Protects m_eventBuffer
Poco::FastMutex m_mutex;
/// Run start time
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ namespace LiveData

void replaceChunk(Mantid::API::Workspace_sptr chunkWS);
void addChunk(Mantid::API::Workspace_sptr chunkWS);
void addMatrixWSChunk(const std::string &algoName, API::Workspace_sptr accumWS, API::Workspace_sptr chunkWS);
void appendChunk(Mantid::API::Workspace_sptr chunkWS);

void doSortEvents(Mantid::API::Workspace_sptr ws);
Expand Down
84 changes: 58 additions & 26 deletions Code/Mantid/Framework/LiveData/src/ISISLiveEventDataListener.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -165,28 +165,45 @@ void ISISLiveEventDataListener::start(Kernel::DateAndTime startTime)
// return a workspace with collected events
boost::shared_ptr<API::Workspace> ISISLiveEventDataListener::extractData()
{
if ( !m_eventBuffer )
if ( !m_eventBuffer[0] )
{
throw LiveData::Exception::NotYet("The workspace has not yet been initialized.");
}

//Make a brand new EventWorkspace
DataObjects::EventWorkspace_sptr temp = boost::dynamic_pointer_cast<DataObjects::EventWorkspace>(
API::WorkspaceFactory::Instance().create("EventWorkspace", m_eventBuffer->getNumberHistograms(), 2, 1));
Poco::ScopedLock<Poco::FastMutex> scopedLock( m_mutex);

//Copy geometry over.
API::WorkspaceFactory::Instance().initializeFromParent(m_eventBuffer, temp, false);
std::vector<DataObjects::EventWorkspace_sptr> outWorkspaces(m_numberOfPeriods);
for(size_t i = 0; i < static_cast<size_t>(m_numberOfPeriods); ++i)
{

//Make a brand new EventWorkspace
DataObjects::EventWorkspace_sptr temp = boost::dynamic_pointer_cast<DataObjects::EventWorkspace>(
API::WorkspaceFactory::Instance().create("EventWorkspace", m_eventBuffer[i]->getNumberHistograms(), 2, 1));

//Copy geometry over.
API::WorkspaceFactory::Instance().initializeFromParent(m_eventBuffer[i], temp, false);

// Clear out the old logs
temp->mutableRun().clearTimeSeriesLogs();

// Clear out the old logs
temp->mutableRun().clearTimeSeriesLogs();
// Swap the workspaces
std::swap(m_eventBuffer[i], temp);

// Lock the mutex and swap the workspaces
outWorkspaces[i] = temp;
}

if ( m_numberOfPeriods > 1 )
{
Poco::ScopedLock<Poco::FastMutex> scopedLock( m_mutex);
std::swap(m_eventBuffer, temp);
} // mutex automatically unlocks here
// create a workspace group in case the data are multiperiod
auto workspaceGroup = API::WorkspaceGroup_sptr( new API::WorkspaceGroup );
for(size_t i = 0; i < static_cast<size_t>(m_numberOfPeriods); ++i)
{
workspaceGroup->addWorkspace( outWorkspaces[i] );
}
return workspaceGroup;
}

return temp;
return outWorkspaces[0];
}

bool ISISLiveEventDataListener::isConnected()
Expand Down Expand Up @@ -236,7 +253,7 @@ void ISISLiveEventDataListener::run()
Mantid::Kernel::DateAndTime pulseTime = m_startTime + static_cast<double>( events.head_n.frame_time_zero );
// Save the pulse charge in the logs
double protons = static_cast<double>( events.head_n.protons );
m_eventBuffer->mutableRun().getTimeSeriesProperty<double>( PROTON_CHARGE_PROPERTY)
m_eventBuffer[0]->mutableRun().getTimeSeriesProperty<double>( PROTON_CHARGE_PROPERTY)
->addValue( pulseTime, protons );

events.data.resize(events.head_n.nevents);
Expand Down Expand Up @@ -265,7 +282,7 @@ void ISISLiveEventDataListener::run()
}

// store the events
saveEvents( events.data, pulseTime );
saveEvents( events.data, pulseTime, events.head_n.period );
}

} catch (std::runtime_error &e) { // exception handler for generic runtime exceptions
Expand Down Expand Up @@ -306,15 +323,17 @@ void ISISLiveEventDataListener::initEventBuffer(const TCPStreamEventDataSetup &s
// Create an event workspace for the output
auto workspace = API::WorkspaceFactory::Instance().create( "EventWorkspace", m_numberOfSpectra, 2, 1 );

m_eventBuffer.resize(m_numberOfPeriods);

// save this workspace as the event buffer
m_eventBuffer = boost::dynamic_pointer_cast<DataObjects::EventWorkspace>( workspace );
if ( !m_eventBuffer )
m_eventBuffer[0] = boost::dynamic_pointer_cast<DataObjects::EventWorkspace>( workspace );
if ( !m_eventBuffer[0] )
{
throw std::runtime_error("Failed to create an event workspace");
}
// Set the units
m_eventBuffer->getAxis(0)->unit() = Kernel::UnitFactory::Instance().create("TOF");
m_eventBuffer->setYUnit( "Counts");
m_eventBuffer[0]->getAxis(0)->unit() = Kernel::UnitFactory::Instance().create("TOF");
m_eventBuffer[0]->setYUnit( "Counts");

// Set the spectra-detector maping
loadSpectraMap();
Expand All @@ -325,24 +344,37 @@ void ISISLiveEventDataListener::initEventBuffer(const TCPStreamEventDataSetup &s

// Set the run number
std::string run_num = boost::lexical_cast<std::string>( setup.head_setup.run_number );
m_eventBuffer->mutableRun().addLogData( new Mantid::Kernel::PropertyWithValue<std::string>(RUN_NUMBER_PROPERTY, run_num) );
m_eventBuffer[0]->mutableRun().addLogData( new Mantid::Kernel::PropertyWithValue<std::string>(RUN_NUMBER_PROPERTY, run_num) );

// Add the proton charge property
m_eventBuffer->mutableRun().addLogData( new Mantid::Kernel::TimeSeriesProperty<double>(PROTON_CHARGE_PROPERTY) );
m_eventBuffer[0]->mutableRun().addLogData( new Mantid::Kernel::TimeSeriesProperty<double>(PROTON_CHARGE_PROPERTY) );

if ( m_numberOfPeriods > 1 )
{
for(size_t i = 1; i < static_cast<size_t>(m_numberOfPeriods); ++i)
{
// create an event workspace for each period
m_eventBuffer[i] = boost::dynamic_pointer_cast<DataObjects::EventWorkspace>(
API::WorkspaceFactory::Instance().create("EventWorkspace", m_eventBuffer[0]->getNumberHistograms(), 2, 1));

//Copy geometry over.
API::WorkspaceFactory::Instance().initializeFromParent(m_eventBuffer[0], m_eventBuffer[i], false);
}
}
}

/**
* Save received event data in the buffer workspace.
* @param data :: A vector with events.
*/
void ISISLiveEventDataListener::saveEvents(const std::vector<TCPStreamEventNeutron> &data, const Kernel::DateAndTime &pulseTime)
void ISISLiveEventDataListener::saveEvents(const std::vector<TCPStreamEventNeutron> &data, const Kernel::DateAndTime &pulseTime, const size_t period)
{
Poco::ScopedLock<Poco::FastMutex> scopedLock(m_mutex);

for(auto it = data.begin(); it != data.end(); ++it)
{
Mantid::DataObjects::TofEvent event( it->time_of_flight, pulseTime );
m_eventBuffer->getEventList( it->spectrum ).addEventQuickly( event );
m_eventBuffer[period]->getEventList( it->spectrum ).addEventQuickly( event );
}
}

Expand All @@ -364,11 +396,11 @@ void ISISLiveEventDataListener::loadSpectraMap()
if ( ndet < nspec ) nspec = ndet;
for(size_t i = 0; i < static_cast<size_t>(nspec); ++i)
{
m_eventBuffer->getSpectrum(i)->setSpectrumNo( spec[i] );
m_eventBuffer[0]->getSpectrum(i)->setSpectrumNo( spec[i] );
}

// set up the mapping
m_eventBuffer->updateSpectraUsing(API::SpectrumDetectorMapping(spec, udet));
m_eventBuffer[0]->updateSpectraUsing(API::SpectrumDetectorMapping(spec, udet));
}

/**
Expand All @@ -380,7 +412,7 @@ void ISISLiveEventDataListener::loadInstrument(const std::string &instrName)
API::Algorithm_sptr alg = API::AlgorithmFactory::Instance().create("LoadInstrument",-1);
alg->initialize();
alg->setPropertyValue("InstrumentName",instrName);
alg->setProperty("Workspace", m_eventBuffer);
alg->setProperty("Workspace", m_eventBuffer[0]);
alg->setProperty("RewriteSpectraMap", false);
alg->setChild(true);
alg->execute();
Expand Down
72 changes: 55 additions & 17 deletions Code/Mantid/Framework/LiveData/src/LoadLiveData.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -300,29 +300,67 @@ namespace LiveData
// Choose the appropriate algorithm to add chunks
std::string algoName = "PlusMD";
MatrixWorkspace_sptr mws = boost::dynamic_pointer_cast<MatrixWorkspace>(chunkWS);
if (mws) algoName = "Plus";
// ISIS multi-period data come in workspace groups
WorkspaceGroup_sptr gws = boost::dynamic_pointer_cast<WorkspaceGroup>(chunkWS);
if (mws || gws) algoName = "Plus";

IAlgorithm_sptr alg = this->createChildAlgorithm(algoName);
alg->setProperty("LHSWorkspace", m_accumWS);
alg->setProperty("RHSWorkspace", chunkWS);
alg->setProperty("OutputWorkspace", m_accumWS);
alg->execute();
if (!alg->isExecuted())
if ( gws )
{
throw std::runtime_error("Error when calling " + alg->name() + " to add the chunk of live data. See log.");
WorkspaceGroup_sptr accum_gws = boost::dynamic_pointer_cast<WorkspaceGroup>(m_accumWS);
if ( !accum_gws )
{
throw std::runtime_error("Two workspace groups are expected.");
}
if ( accum_gws->getNumberOfEntries() != gws->getNumberOfEntries() )
{
throw std::runtime_error("Accumulation and chunk workspace groups are expected to have the same size.");
}
// binary operations cannot handle groups passed by pointers, so add members one by one
for(size_t i = 0; i < static_cast<size_t>(gws->getNumberOfEntries()); ++i)
{
addMatrixWSChunk( algoName, accum_gws->getItem(i), gws->getItem(i) );
}
}
else
{
// Get the output as the generic Workspace type
Property * prop = alg->getProperty("OutputWorkspace");
IWorkspaceProperty * wsProp = dynamic_cast<IWorkspaceProperty*>(prop);
if (!wsProp)
throw std::runtime_error("The " + alg->name() + " Algorithm's OutputWorkspace property is not a WorkspaceProperty!");
Workspace_sptr temp = wsProp->getWorkspace();
m_accumWS = temp;
// just add the chunk
addMatrixWSChunk( algoName, m_accumWS, chunkWS );
}
// And sort the events, if any
doSortEvents(m_accumWS);
}

//----------------------------------------------------------------------------------------------
/**
* Add a matrix workspace to the accumulation workspace.
*
* @param algoName :: Name of algorithm which will be adding the workspaces.
* @param accumWS :: accumulation matrix workspace
* @param chunkWS :: processed live data chunk matrix workspace
*/
void LoadLiveData::addMatrixWSChunk(const std::string& algoName, Workspace_sptr accumWS, Workspace_sptr chunkWS)
{
IAlgorithm_sptr alg = this->createChildAlgorithm(algoName);
alg->setProperty("LHSWorkspace", accumWS);
alg->setProperty("RHSWorkspace", chunkWS);
alg->setProperty("OutputWorkspace", accumWS);
alg->execute();
if (!alg->isExecuted())
{
throw std::runtime_error("Error when calling " + alg->name() + " to add the chunk of live data. See log.");
}
else
{
// Is this really necessary?

// Get the output as the generic Workspace type
Property * prop = alg->getProperty("OutputWorkspace");
IWorkspaceProperty * wsProp = dynamic_cast<IWorkspaceProperty*>(prop);
if (!wsProp)
throw std::runtime_error("The " + alg->name() + " Algorithm's OutputWorkspace property is not a WorkspaceProperty!");
Workspace_sptr temp = wsProp->getWorkspace();
accumWS = temp;
// And sort the events, if any
doSortEvents(accumWS);
}
}


Expand Down

0 comments on commit 37a9649

Please sign in to comment.