1
0
Fork 0
mirror of https://github.com/gwm17/Specter.git synced 2024-11-26 12:18:51 -05:00

Add Ritual data source. Cleanup DataSource, PhysicsEventBuilder, child classes.

This commit is contained in:
Gordon McCann 2023-03-30 20:43:02 -04:00
parent 6c5b7d17a7
commit 88173a16cf
20 changed files with 366 additions and 48 deletions

View File

@ -125,6 +125,10 @@ target_sources(Specter PRIVATE
Specter/Utils/RandomGenerator.h Specter/Utils/RandomGenerator.h
Specter/Utils/ThreadSafeQueue.h Specter/Utils/ThreadSafeQueue.h
Specter/Core/EntryPoint.h Specter/Core/EntryPoint.h
Specter/Physics/ritual/RitualOnlineSource.h
Specter/Physics/ritual/RitualOnlineSource.cpp
Specter/Physics/ritual/RitualClient.cpp
Specter/Physics/ritual/RitualClient.h
) )
#ImPlot sources #ImPlot sources

View File

@ -31,7 +31,7 @@ namespace Specter {
SPEC_PROFILE_FUNCTION(); SPEC_PROFILE_FUNCTION();
static bool result = false; static bool result = false;
static std::vector<DataSource::SourceType> availTypes = { DataSource::SourceType::CompassOnline, DataSource::SourceType::CompassOffline, DataSource::SourceType::DaqromancyOnline, static std::vector<DataSource::SourceType> availTypes = { DataSource::SourceType::CompassOnline, DataSource::SourceType::CompassOffline, DataSource::SourceType::DaqromancyOnline,
DataSource::SourceType::DaqromancyOffline, DataSource::SourceType::CharonOnline }; DataSource::SourceType::DaqromancyOffline, DataSource::SourceType::CharonOnline, DataSource::SourceType::RitualOnline };
result = false; result = false;
if (m_openFlag) if (m_openFlag)
{ {
@ -114,6 +114,12 @@ namespace Specter {
ImGui::InputText("Hostname", &m_args.location); ImGui::InputText("Hostname", &m_args.location);
ImGui::InputText("Port", &m_args.port); ImGui::InputText("Port", &m_args.port);
} }
else if (m_args.type == DataSource::SourceType::RitualOnline)
{
ImGui::InputText("Hostname", &m_args.location);
ImGui::InputText("Port", &m_args.port);
ImGui::InputScalar("Coinc. Window (ps)", ImGuiDataType_U64, &m_args.coincidenceWindow);
}
if (ImGui::Button("Ok")) if (ImGui::Button("Ok"))
{ {

View File

@ -80,10 +80,7 @@ namespace Specter {
m_datum.timestamp = m_currentHit.timestamp; m_datum.timestamp = m_currentHit.timestamp;
m_datum.id = Utilities::GetBoardChannelUUID(m_currentHit.board, m_currentHit.channel); m_datum.id = Utilities::GetBoardChannelUUID(m_currentHit.board, m_currentHit.channel);
if(m_eventBuilder.AddDatum(m_datum)) m_eventBuilder.AddDatum(m_datum);
{
m_isEventReady = true;
}
} }
void CompassOnlineSource::FillBuffer() void CompassOnlineSource::FillBuffer()

View File

@ -40,11 +40,13 @@ namespace Specter {
virtual ~CompassOnlineSource() override; virtual ~CompassOnlineSource() override;
virtual void ProcessData() override; virtual void ProcessData() override;
virtual const std::vector<SpecEvent>& GetEvents() override virtual std::vector<SpecEvent> GetEvents() override
{ {
m_isEventReady = false; auto temp = m_eventBuilder.GetReadyEvents();
return m_eventBuilder.GetReadyEvents(); m_eventBuilder.ClearReadyEvents();
return temp;
} }
virtual const bool IsEventReady() const override { return m_eventBuilder.IsEventReady(); }
private: private:
void InitConnection(const std::string& hostname, const std::string& port); void InitConnection(const std::string& hostname, const std::string& port);

View File

@ -146,10 +146,7 @@ namespace Specter {
m_datum.timestamp = m_hit.timestamp; m_datum.timestamp = m_hit.timestamp;
m_datum.id = Utilities::GetBoardChannelUUID(m_hit.board, m_hit.channel); m_datum.id = Utilities::GetBoardChannelUUID(m_hit.board, m_hit.channel);
if(m_eventBuilder.AddDatum(m_datum)) m_eventBuilder.AddDatum(m_datum);
{
m_isEventReady = true;
}
} }
} }

View File

@ -37,14 +37,16 @@ namespace Specter {
CompassRun(const std::string& dir, uint64_t coincidenceWindow); CompassRun(const std::string& dir, uint64_t coincidenceWindow);
virtual ~CompassRun(); virtual ~CompassRun();
virtual void ProcessData() override; virtual void ProcessData() override;
virtual const std::vector<SpecEvent>& GetEvents() override virtual std::vector<SpecEvent> GetEvents() override
{ {
m_isEventReady = false; auto temp = m_eventBuilder.GetReadyEvents();
return m_eventBuilder.GetReadyEvents(); m_eventBuilder.ClearReadyEvents();
return temp;
} }
inline void SetDirectory(const std::string& dir) { m_directory = dir; CollectFiles(); } void SetDirectory(const std::string& dir) { m_directory = dir; CollectFiles(); }
inline void SetShiftMap(const std::string& filename) { m_smap.SetFile(filename); } void SetShiftMap(const std::string& filename) { m_smap.SetFile(filename); }
virtual const bool IsEventReady() const override { return m_eventBuilder.IsEventReady(); }
private: private:
void CollectFiles(); void CollectFiles();

View File

@ -105,9 +105,6 @@ namespace Specter {
m_datum.shortEnergy = m_dyHit.energyShort; m_datum.shortEnergy = m_dyHit.energyShort;
m_datum.timestamp = m_dyHit.timestamp; m_datum.timestamp = m_dyHit.timestamp;
m_datum.id = Utilities::GetBoardChannelUUID(m_dyHit.board, m_dyHit.channel); m_datum.id = Utilities::GetBoardChannelUUID(m_dyHit.board, m_dyHit.channel);
if(m_eventBuilder.AddDatum(m_datum)) m_eventBuilder.AddDatum(m_datum);
{
m_isEventReady = true;
}
} }
} }

View File

@ -14,12 +14,15 @@ namespace Specter {
virtual ~DYFileSource(); virtual ~DYFileSource();
virtual void ProcessData() override; virtual void ProcessData() override;
virtual const std::vector<SpecEvent>& GetEvents() override virtual std::vector<SpecEvent> GetEvents() override
{ {
m_isEventReady = false; auto temp = m_eventBuilder.GetReadyEvents();
return m_eventBuilder.GetReadyEvents(); m_eventBuilder.ClearReadyEvents();
return temp;
} }
virtual const bool IsEventReady() const override { return m_eventBuilder.IsEventReady(); }
private: private:
void CollectFiles(); void CollectFiles();
bool GetNextHit(); bool GetNextHit();

View File

@ -28,8 +28,7 @@ namespace Specter {
m_datum.shortEnergy = m_dyHit.energyShort; m_datum.shortEnergy = m_dyHit.energyShort;
m_datum.timestamp = m_dyHit.timestamp; m_datum.timestamp = m_dyHit.timestamp;
m_datum.id = Utilities::GetBoardChannelUUID(m_dyHit.board, m_dyHit.channel); m_datum.id = Utilities::GetBoardChannelUUID(m_dyHit.board, m_dyHit.channel);
if(m_eventBuilder.AddDatum(m_datum)) m_eventBuilder.AddDatum(m_datum);
m_isEventReady = true;
} }
} }
} }

View File

@ -13,12 +13,15 @@ namespace Specter {
virtual ~DYOnlineSource(); virtual ~DYOnlineSource();
virtual void ProcessData() override; virtual void ProcessData() override;
virtual const std::vector<SpecEvent>& GetEvents() override virtual std::vector<SpecEvent> GetEvents() override
{ {
m_isEventReady = false; auto temp = m_eventBuilder.GetReadyEvents();
return m_eventBuilder.GetReadyEvents(); m_eventBuilder.ClearReadyEvents();
return temp;
} }
virtual const bool IsEventReady() const override { return m_eventBuilder.IsEventReady(); }
private: private:
DaqGrimoire::DYClient m_clientConnection; DaqGrimoire::DYClient m_clientConnection;
DaqGrimoire::DYListData m_dyHit; DaqGrimoire::DYListData m_dyHit;

View File

@ -12,6 +12,7 @@
#include "Daqromancy/DYFileSource.h" #include "Daqromancy/DYFileSource.h"
#include "Daqromancy/DYOnlineSource.h" #include "Daqromancy/DYOnlineSource.h"
#include "nscldaq/CharonOnlineSource.h" #include "nscldaq/CharonOnlineSource.h"
#include "ritual/RitualOnlineSource.h"
namespace Specter { namespace Specter {
@ -25,6 +26,7 @@ namespace Specter {
case DataSource::SourceType::DaqromancyOffline: return new DYFileSource(args.location, args.coincidenceWindow); case DataSource::SourceType::DaqromancyOffline: return new DYFileSource(args.location, args.coincidenceWindow);
case DataSource::SourceType::DaqromancyOnline: return new DYOnlineSource(args.location, args.port, args.coincidenceWindow); case DataSource::SourceType::DaqromancyOnline: return new DYOnlineSource(args.location, args.port, args.coincidenceWindow);
case DataSource::SourceType::CharonOnline: return new CharonOnlineSource(args.location, args.port); case DataSource::SourceType::CharonOnline: return new CharonOnlineSource(args.location, args.port);
case DataSource::SourceType::RitualOnline: return new RitualOnlineSource(args.location, args.port, args.coincidenceWindow);
case DataSource::SourceType::None: return nullptr; case DataSource::SourceType::None: return nullptr;
} }
SPEC_WARN("Invalid DataSourceType at CreateDataSource!"); SPEC_WARN("Invalid DataSourceType at CreateDataSource!");
@ -41,6 +43,7 @@ namespace Specter {
case DataSource::SourceType::DaqromancyOffline: return "DaqromancyOffline"; case DataSource::SourceType::DaqromancyOffline: return "DaqromancyOffline";
case DataSource::SourceType::DaqromancyOnline: return "DaqromancyOnline"; case DataSource::SourceType::DaqromancyOnline: return "DaqromancyOnline";
case DataSource::SourceType::CharonOnline: return "CharonOnline"; case DataSource::SourceType::CharonOnline: return "CharonOnline";
case DataSource::SourceType::RitualOnline: return "RitualOnline";
} }
return "None"; return "None";

View File

@ -25,23 +25,23 @@ namespace Specter {
CompassOffline, CompassOffline,
DaqromancyOnline, DaqromancyOnline,
DaqromancyOffline, DaqromancyOffline,
CharonOnline CharonOnline,
RitualOnline
}; };
DataSource(uint64_t coincidenceWindow = 0) : DataSource(uint64_t coincidenceWindow = 0) :
m_validFlag(false), m_isEventReady(false), m_eventBuilder(coincidenceWindow) m_validFlag(false), m_eventBuilder(coincidenceWindow)
{ {
} }
virtual ~DataSource() {}; virtual ~DataSource() {};
virtual void ProcessData() = 0; virtual void ProcessData() = 0;
virtual const std::vector<SpecEvent>& GetEvents() = 0; virtual std::vector<SpecEvent> GetEvents() = 0;
inline bool IsValid() { return m_validFlag; } virtual const bool IsEventReady() const = 0;
inline bool IsEventReady() { return m_isEventReady; } bool IsValid() { return m_validFlag; }
protected: protected:
bool m_validFlag; bool m_validFlag;
bool m_isEventReady;
SpecData m_datum; SpecData m_datum;
PhysicsEventBuilder m_eventBuilder; PhysicsEventBuilder m_eventBuilder;
}; };

View File

@ -26,16 +26,16 @@ namespace Specter {
{ {
} }
bool PhysicsEventBuilder::AddDatum(const SpecData& datum) void PhysicsEventBuilder::AddDatum(const SpecData& datum)
{ {
SPEC_PROFILE_FUNCTION(); SPEC_PROFILE_FUNCTION();
if (datum.timestamp == 0) //Ignore empty data (need a valid timestamp) if (datum.timestamp == 0) //Ignore empty data (need a valid timestamp)
return false; return;
m_dataBuffer[m_bufferIndex] = datum; m_dataBuffer[m_bufferIndex] = datum;
m_bufferIndex++; m_bufferIndex++;
if (m_bufferIndex < s_maxDataBuffer) //If we haven't filled the buffer keep going if (m_bufferIndex < s_maxDataBuffer) //If we haven't filled the buffer keep going
return false; return;
else if (m_sortFlag) else if (m_sortFlag)
std::sort(m_dataBuffer.begin(), m_dataBuffer.end(), [](SpecData& i, SpecData& j) { return i.timestamp < j.timestamp; }); std::sort(m_dataBuffer.begin(), m_dataBuffer.end(), [](SpecData& i, SpecData& j) { return i.timestamp < j.timestamp; });
@ -59,10 +59,9 @@ namespace Specter {
} }
} }
m_bufferIndex = 0; m_bufferIndex = 0;
return true;
} }
const std::vector<SpecEvent>& PhysicsEventBuilder::GetReadyEvents() const std::vector<SpecEvent> PhysicsEventBuilder::GetReadyEvents() const
{ {
return m_readyEvents; return m_readyEvents;
} }

View File

@ -21,15 +21,17 @@ namespace Specter {
PhysicsEventBuilder(); PhysicsEventBuilder();
PhysicsEventBuilder(uint64_t windowSize); PhysicsEventBuilder(uint64_t windowSize);
~PhysicsEventBuilder(); ~PhysicsEventBuilder();
inline void SetCoincidenceWindow(uint64_t windowSize) { m_coincWindow = windowSize; } void SetCoincidenceWindow(uint64_t windowSize) { m_coincWindow = windowSize; }
inline void SetSortFlag(bool flag) { m_sortFlag = flag; } void SetSortFlag(bool flag) { m_sortFlag = flag; }
inline void ClearAll() // reset all internal structures void ClearAll() // reset all internal structures
{ {
m_bufferIndex = 0; m_bufferIndex = 0;
m_readyEvents.clear(); m_readyEvents.clear();
} }
bool AddDatum(const SpecData& datum); void ClearReadyEvents() { m_readyEvents.clear(); }
const std::vector<SpecEvent>& GetReadyEvents() const; void AddDatum(const SpecData& datum);
bool IsEventReady() const { return !m_readyEvents.empty(); }
std::vector<SpecEvent> GetReadyEvents() const;
private: private:
bool m_sortFlag; bool m_sortFlag;

View File

@ -5,7 +5,7 @@
namespace Specter { namespace Specter {
CharonOnlineSource::CharonOnlineSource(const std::string& hostname, const std::string& port) : CharonOnlineSource::CharonOnlineSource(const std::string& hostname, const std::string& port) :
DataSource(0), m_client(hostname, port) DataSource(0), m_isEventReady(false), m_client(hostname, port)
{ {
m_validFlag = m_client.IsConnected(); m_validFlag = m_client.IsConnected();
m_readyEvents.emplace_back(); m_readyEvents.emplace_back();

View File

@ -14,16 +14,18 @@ namespace Specter {
virtual ~CharonOnlineSource(); virtual ~CharonOnlineSource();
virtual void ProcessData() override; virtual void ProcessData() override;
virtual const std::vector<SpecEvent>& GetEvents() override virtual std::vector<SpecEvent> GetEvents() override
{ {
m_isEventReady = false; m_isEventReady = false;
return m_readyEvents; return m_readyEvents;
} }
virtual const bool IsEventReady() const override { return m_isEventReady; }
private: private:
void UnpackRawBuffer(); void UnpackRawBuffer();
CharonClient m_client; CharonClient m_client;
bool m_isEventReady;
std::vector<uint8_t> m_rawBuffer; std::vector<uint8_t> m_rawBuffer;
SpecEvent m_event; SpecEvent m_event;
std::vector<SpecEvent> m_readyEvents; std::vector<SpecEvent> m_readyEvents;

View File

@ -0,0 +1,143 @@
#include "RitualClient.h"
namespace Specter {
RitualClient::RitualClient(const std::string& hostname, const std::string& port) :
m_socket(m_context), m_deadline(m_context)
{
Connect(hostname, port);
}
RitualClient::~RitualClient()
{
Disconnect();
}
bool RitualClient::GetData(RitualMessage& reciever)
{
if (m_queue.IsEmpty())
return false;
reciever = m_queue.Front();
m_queue.PopFront();
return true;
}
void RitualClient::Connect(const std::string& hostname, const std::string& port)
{
try
{
asio::ip::tcp::resolver resolver(m_context);
auto end_points = resolver.resolve(hostname, port);
m_deadline.expires_after(std::chrono::seconds(30));
asio::async_connect(m_socket, end_points,
[this, hostname, port](std::error_code ec, asio::ip::tcp::endpoint endpoint)
{
if (!ec)
{
SPEC_INFO("Connected RitualClient to {0}:{1}", endpoint.address(), endpoint.port());
//Turn off our deadline timer
m_deadline.cancel();
ReadSize();
}
else
{
SPEC_WARN("Unable to connect to RitualClient {0}:{1}", hostname, port);
m_socket.close();
}
}
);
m_deadline.async_wait(std::bind(&RitualClient::HandleTimeout, this, std::placeholders::_1));
m_ioThread = std::thread([this]() { m_context.run(); });
}
catch (asio::system_error& e)
{
SPEC_WARN("Unable to connect RitualClient to {0}:{1}", hostname, port);
return;
}
}
void RitualClient::Disconnect()
{
if (IsConnected())
{
asio::post(m_context, [this]() { m_socket.close(); });
}
m_context.stop();
if (m_ioThread.joinable())
m_ioThread.join();
}
void RitualClient::ReadSize()
{
asio::async_read(m_socket, asio::buffer(&m_tempMessage.size, sizeof(m_tempMessage.size)),
[this](std::error_code ec, std::size_t size)
{
if (!ec)
{
m_tempMessage.body.resize(m_tempMessage.size - s_minimumMessageSize);
ReadHitSize();
}
}
);
}
void RitualClient::ReadHitSize()
{
asio::async_read(m_socket, asio::buffer(&m_tempMessage.hitSize, sizeof(m_tempMessage.hitSize)),
[this](std::error_code ec, std::size_t size)
{
if (!ec)
{
ReadDataType();
}
}
);
}
void RitualClient::ReadDataType()
{
asio::async_read(m_socket, asio::buffer(&m_tempMessage.dataType, sizeof(m_tempMessage.dataType)),
[this](std::error_code ec, std::size_t size)
{
if (!ec)
{
ReadBody();
}
}
);
}
void RitualClient::ReadBody()
{
asio::async_read(m_socket, asio::buffer(&m_tempMessage.body, m_tempMessage.body.size()),
[this](std::error_code ec, std::size_t size)
{
if (!ec && size > 0)
{
m_queue.PushBack(m_tempMessage);
}
ReadSize();
}
);
}
void RitualClient::HandleTimeout(const asio::error_code& ec)
{
//If we stop the timer, don't do anything
if (ec == asio::error::operation_aborted)
{
return;
}
//Check to make sure that deadline wasn't asychronously moved
if (m_deadline.expiry() <= asio::steady_timer::clock_type::now())
{
SPEC_WARN("RitualClient timedout at Connect!");
m_socket.close();
m_deadline.expires_at(asio::steady_timer::time_point::max());
}
}
}

View File

@ -0,0 +1,54 @@
#ifndef RITUAL_CLIENT_H
#define RITUAL_CLIENT_H
#include "Specter/Utils/ThreadSafeQueue.h"
#include "Specter/Physics/SpecData.h"
#include <asio.hpp>
#include <thread>
namespace Specter {
struct RitualMessage
{
uint64_t size; //Inclusive size of whole message
uint64_t hitSize; //Size of an individual CoMPASS data hit within the body
uint16_t dataType; //CAEN header (CAEx)
std::vector<uint8_t> body; //Data body
};
class RitualClient
{
public:
RitualClient(const std::string& hostname, const std::string& port);
~RitualClient();
bool GetData(RitualMessage& reciever);
void Connect(const std::string& hostname, const std::string& port);
void Disconnect();
const bool IsConnected() const { return m_socket.is_open(); }
static constexpr uint64_t MinimumMessageSize() { return s_minimumMessageSize; }
private:
void ReadSize();
void ReadHitSize();
void ReadDataType();
void ReadBody();
void HandleTimeout(const asio::error_code& ec);
asio::io_context m_context;
asio::ip::tcp::socket m_socket;
asio::steady_timer m_deadline;
std::thread m_ioThread;
RitualMessage m_tempMessage;
ThreadSafeQueue<RitualMessage> m_queue;
//All messages have a minimum size of size + hitSize + dataType
static constexpr uint64_t s_minimumMessageSize = 64 + 64 + 16;
};
}
#endif

View File

@ -0,0 +1,73 @@
#include "RitualOnlineSource.h"
#include "../Caen/CompassHit.h"
#include "Specter/Utils/Functions.h"
namespace Specter {
RitualOnlineSource::RitualOnlineSource(const std::string& hostname, const std::string& port, uint64_t coincidenceWindow) :
DataSource(coincidenceWindow), m_client(hostname, port)
{
m_eventBuilder.SetSortFlag(true);
m_validFlag = m_client.IsConnected();
}
RitualOnlineSource::~RitualOnlineSource()
{
}
void RitualOnlineSource::ProcessData()
{
if (!m_client.IsConnected())
m_validFlag = false;
if (m_client.GetData(m_recievedMessage))
{
ReadMessage();
}
}
void RitualOnlineSource::ReadMessage()
{
uint64_t nHits = m_recievedMessage.body.size() / m_recievedMessage.hitSize;
uint64_t hitsRead = 0;
uint8_t* bodyPointer = m_recievedMessage.body.data();
CompassHit currentHit;
SpecData convertedHit;
while (hitsRead < nHits)
{
currentHit.board = *((uint16_t*)bodyPointer);
bodyPointer += 2;
currentHit.channel = *((uint16_t*)bodyPointer);
bodyPointer += 2;
currentHit.timestamp = *((uint64_t*)bodyPointer);
bodyPointer += 8;
if (Compass_IsEnergy(m_recievedMessage.dataType))
{
currentHit.energy = *((uint16_t*)bodyPointer);
bodyPointer += 2;
}
if (Compass_IsEnergyCalibrated(m_recievedMessage.dataType))
{
currentHit.energyCalibrated = *((uint16_t*)bodyPointer);
bodyPointer += 8;
}
if (Compass_IsEnergyShort(m_recievedMessage.dataType))
{
currentHit.energyShort = *((uint16_t*)bodyPointer);
bodyPointer += 2;
}
currentHit.flags = *((uint32_t*)bodyPointer);
bodyPointer += 4;
hitsRead++;
convertedHit.id = Utilities::GetBoardChannelUUID(currentHit.board, currentHit.channel);
convertedHit.timestamp = currentHit.timestamp;
convertedHit.longEnergy = currentHit.energy;
convertedHit.shortEnergy = currentHit.energyShort;
convertedHit.calEnergy = currentHit.energyCalibrated;
m_eventBuilder.AddDatum(convertedHit);
}
}
}

View File

@ -0,0 +1,32 @@
#ifndef RITUAL_ONLINE_SOURCE_H
#define RITUAL_ONLINE_SOURCE_H
#include "Specter/Physics/DataSource.h"
#include "RitualClient.h"
namespace Specter {
class RitualOnlineSource : public DataSource
{
public:
RitualOnlineSource(const std::string& hostname, const std::string& port, uint64_t coincidenceWindow);
virtual ~RitualOnlineSource();
virtual void ProcessData() override;
virtual std::vector<SpecEvent> GetEvents() override
{
auto temp = m_eventBuilder.GetReadyEvents();
m_eventBuilder.ClearReadyEvents();
return temp;
}
virtual const bool IsEventReady() const override { return m_eventBuilder.IsEventReady(); }
private:
void ReadMessage();
RitualClient m_client;
RitualMessage m_recievedMessage;
};
}
#endif