diff --git a/SpecProject/src/SPSAnalysisStage.cpp b/SpecProject/src/SPSAnalysisStage.cpp index ec68a96..c3154e9 100644 --- a/SpecProject/src/SPSAnalysisStage.cpp +++ b/SpecProject/src/SPSAnalysisStage.cpp @@ -15,10 +15,12 @@ namespace Specter { beamIntegrator("beamIntegrator") { SPEC_PROFILE_FUNCTION(); + //Bind some parameters manager->BindParameter(delayFLTime); manager->BindParameter(delayFRTime); manager->BindParameter(delayBLTime); manager->BindParameter(delayBRTime); + //Bind parameters with some default histograms. Saves us the effort of making them in the UI. manager->BindParameter(x1, 600, -300.0, 300.0); manager->BindParameter(x2, 600, -300.0, 300.0); @@ -29,12 +31,24 @@ namespace Specter { manager->BindParameter(cathode, 4096, 0.0, 4096); manager->BindParameter(xavg_sabreCoinc, 600, -300.0, 300.0); - std::vector sabre_list; - for (int i = 0; i < 127; i++) + //Example of injecting experiment specific info. I know that SABRE is only used in 16 channel digitizers, + //so I can make a simple incremental id for use with the UI so that the parameter names are human readable. We map this "simple" id + //to the more robust and universal Specter board/channel UUID using a std::unordered_map + //This is kind of a really simple example of injecting a channel map; more complicated and advanced versions could involve reading + //a text file to get detector ID information, detector channel number, etc. + std::vector sabre_list; //list of names will allow us to create a summary histogram. + uint32_t uuid; + for (uint32_t board = 0; board < 7; board++) { - sabre_list.push_back("sabre_" + std::to_string(i)); - sabre.emplace_back(sabre_list[i]); - manager->BindParameter(sabre[i]); + for (uint32_t channel = 0; channel < 16; channel++) + { + //ImGui & spdlog come prepackaged with the fmt library, so make good use of it! + sabre_list.push_back(fmt::format("sabre_%d", board*16 + channel)); + uuid = Utilities::GetBoardChannelUUID(board, channel); + sabre[uuid] = Parameter(sabre_list.back()); + manager->BindParameter(sabre[uuid]); + } + } //If you want to make a histogram default available, you can add one like this. @@ -52,70 +66,78 @@ namespace Specter { //Do some physics! void SPSAnalysisStage::AnalyzePhysicsEvent(const SpecEvent& event) { - SPEC_PROFILE_FUNCTION(); + //You might want some flags for coincidence cases + //Use statics to avoid allocating extra memory each call (these pipeline functions are called a lot!) + static bool sabreFlag; + //Most analysis stages will start kinda like this. Take the raw event data and - //put it into NavParameters using the hit id. Switches are perfect for this. Can also + //put it into Specter::Parameters using the hit id. Switches are perfect for this. Can also //create mapping classes to use text-file-based id association (commonly called channel maps). - bool sabreFlag = false; + sabreFlag = false; for(auto& hit : event) { - if (hit.id < 127) + //Check the SABRE map first; use iterators from std::unordered_map. + //See std::unordered_map docs for more info if this sort of idiom is unfamiliar + auto iter = sabre.find(hit.id); + if (iter != sabre.end()) { sabreFlag = true; - if (hit.longEnergy > sabre[hit.id].GetValue()) - sabre[hit.id].SetValue(hit.longEnergy); + if (hit.longEnergy > iter->second.GetValue()) + iter->second.SetValue(hit.longEnergy); + continue; } + switch (hit.id) { - case 129: + case s_scintLeftID: { if (hit.longEnergy > scintLeft.GetValue()) scintLeft.SetValue(hit.longEnergy); break; } - case 133: + case s_beamIntID: { beamIntegrator.Increment(); break; } - case 135: + case s_cathodeID: { if (hit.longEnergy > cathode.GetValue()) cathode.SetValue(hit.longEnergy); break; } - case 136: + case s_delayFrontLeftID: { if (!delayFLTime.IsValid()) delayFLTime.SetValue(hit.timestamp / 1.0e3); break; } - case 137: + case s_delayFrontRightID: { if (!delayFRTime.IsValid()) delayFRTime.SetValue(hit.timestamp / 1.0e3); break; } - case 138: + case s_delayBackLeftID: { if (!delayBLTime.IsValid()) delayBLTime.SetValue(hit.timestamp / 1.0e3); break; } - case 139: + case s_delayBackRightID: { if (!delayBRTime.IsValid()) delayBRTime.SetValue(hit.timestamp / 1.0e3); break; } - case 141: + case s_anodeFrontID: { if (hit.longEnergy > anodeFront.GetValue()) anodeFront.SetValue(hit.longEnergy); break; } - case 143: + case s_anodeBackID: { if (hit.longEnergy > anodeBack.GetValue()) anodeBack.SetValue(hit.longEnergy); diff --git a/SpecProject/src/SPSAnalysisStage.h b/SpecProject/src/SPSAnalysisStage.h index fe3ceab..591f994 100644 --- a/SpecProject/src/SPSAnalysisStage.h +++ b/SpecProject/src/SPSAnalysisStage.h @@ -31,7 +31,9 @@ namespace Specter { Parameter cathode; Parameter xavg_sabreCoinc; - std::vector sabre; + //For collections of parameters, prefer std::unordered_map or std::map over vector + //Better with use of UUIDs for board-channel pairs + std::unordered_map sabre; //Create a few variables Variable x1_weight; @@ -39,6 +41,19 @@ namespace Specter { //Create a scaler Scaler beamIntegrator; + + //Define some board-channel ID's that we'll use. The static keyword means that we only need to calculate them once, + //constexpr allows us to use them in a switch (and makes them compile time evaluated) + //Note that to make them static constexpr we use literals (i.e. hardcoded) in the arguments + static constexpr uint32_t s_scintLeftID = Utilities::GetBoardChannelUUID(8, 0); + static constexpr uint32_t s_beamIntID = Utilities::GetBoardChannelUUID(8, 5); + static constexpr uint32_t s_cathodeID = Utilities::GetBoardChannelUUID(8, 7); + static constexpr uint32_t s_delayFrontLeftID = Utilities::GetBoardChannelUUID(8, 8); + static constexpr uint32_t s_delayFrontRightID = Utilities::GetBoardChannelUUID(8, 9); + static constexpr uint32_t s_delayBackLeftID = Utilities::GetBoardChannelUUID(8, 10); + static constexpr uint32_t s_delayBackRightID = Utilities::GetBoardChannelUUID(8, 11); + static constexpr uint32_t s_anodeFrontID = Utilities::GetBoardChannelUUID(8, 13); + static constexpr uint32_t s_anodeBackID = Utilities::GetBoardChannelUUID(8, 15); }; } \ No newline at end of file diff --git a/Specter/src/CMakeLists.txt b/Specter/src/CMakeLists.txt index 3af82ef..5f939f5 100644 --- a/Specter/src/CMakeLists.txt +++ b/Specter/src/CMakeLists.txt @@ -103,6 +103,8 @@ target_sources(Specter PRIVATE Specter/Physics/Daqromancy/DYFileSource.cpp Specter/Physics/Daqromancy/DYOnlineSource.h Specter/Physics/Daqromancy/DYOnlineSource.cpp + Specter/Utils/Functions.h + Specter/Utils/Functions.cpp ) #ImPlot sources diff --git a/Specter/src/Specter.h b/Specter/src/Specter.h index 075e584..c8f59c8 100644 --- a/Specter/src/Specter.h +++ b/Specter/src/Specter.h @@ -34,5 +34,6 @@ #include "Specter/Events/Event.h" #include "Specter/Utils/TestServerLayer.h" #include "Specter/Utils/Instrumentor.h" +#include "Specter/Utils/Functions.h" #endif diff --git a/Specter/src/Specter/Physics/Caen/CompassOnlineSource.cpp b/Specter/src/Specter/Physics/Caen/CompassOnlineSource.cpp index 890fcf0..819b856 100644 --- a/Specter/src/Specter/Physics/Caen/CompassOnlineSource.cpp +++ b/Specter/src/Specter/Physics/Caen/CompassOnlineSource.cpp @@ -82,7 +82,7 @@ namespace Specter { m_datum.shortEnergy = m_currentHit.energyShort; m_datum.calEnergy = m_currentHit.energyCalibrated; m_datum.timestamp = m_currentHit.timestamp; - m_datum.id = m_currentHit.board * m_nchannels_per_board + m_currentHit.channel; + m_datum.id = Utilities::GetBoardChannelUUID(m_currentHit.board, m_currentHit.channel); return m_datum; } diff --git a/Specter/src/Specter/Physics/Caen/CompassRun.cpp b/Specter/src/Specter/Physics/Caen/CompassRun.cpp index d81ae59..1992179 100644 --- a/Specter/src/Specter/Physics/Caen/CompassRun.cpp +++ b/Specter/src/Specter/Physics/Caen/CompassRun.cpp @@ -147,7 +147,7 @@ namespace Specter { m_datum.shortEnergy = m_hit.energyShort; m_datum.calEnergy = m_hit.energyCalibrated; m_datum.timestamp = m_hit.timestamp; - m_datum.id = m_hit.board * m_nchannels_per_board + m_hit.channel; + m_datum.id = Utilities::GetBoardChannelUUID(m_hit.board, m_hit.channel); } return m_datum; diff --git a/Specter/src/Specter/Physics/Daqromancy/DYFileSource.cpp b/Specter/src/Specter/Physics/Daqromancy/DYFileSource.cpp index 8fefdf1..6084bfb 100644 --- a/Specter/src/Specter/Physics/Daqromancy/DYFileSource.cpp +++ b/Specter/src/Specter/Physics/Daqromancy/DYFileSource.cpp @@ -108,7 +108,7 @@ namespace Specter { m_datum.longEnergy = m_dyHit.energy; m_datum.shortEnergy = m_dyHit.energyShort; m_datum.timestamp = m_dyHit.timestamp; - m_datum.id = m_dyHit.board * m_channelsPerBoard + m_dyHit.channel; + m_datum.id = Utilities::GetBoardChannelUUID(m_dyHit.board, m_dyHit.channel); } return m_datum; } diff --git a/Specter/src/Specter/Physics/Daqromancy/DYOnlineSource.cpp b/Specter/src/Specter/Physics/Daqromancy/DYOnlineSource.cpp index 2747761..19f7ca2 100644 --- a/Specter/src/Specter/Physics/Daqromancy/DYOnlineSource.cpp +++ b/Specter/src/Specter/Physics/Daqromancy/DYOnlineSource.cpp @@ -27,7 +27,7 @@ namespace Specter { m_datum.longEnergy = m_dyHit.energy; m_datum.shortEnergy = m_dyHit.energyShort; m_datum.timestamp = m_dyHit.timestamp; - m_datum.id = m_dyHit.board * m_channelsPerBoard + m_dyHit.channel; + m_datum.id = Utilities::GetBoardChannelUUID(m_dyHit.board, m_dyHit.channel); } else { diff --git a/Specter/src/Specter/Utils/Functions.cpp b/Specter/src/Specter/Utils/Functions.cpp new file mode 100644 index 0000000..74eb389 --- /dev/null +++ b/Specter/src/Specter/Utils/Functions.cpp @@ -0,0 +1,8 @@ +#include "Functions.h" + +namespace Specter { + + namespace Utilities { + + } +} \ No newline at end of file diff --git a/Specter/src/Specter/Utils/Functions.h b/Specter/src/Specter/Utils/Functions.h new file mode 100644 index 0000000..ba54e7c --- /dev/null +++ b/Specter/src/Specter/Utils/Functions.h @@ -0,0 +1,19 @@ +#ifndef SPEC_FUNCTIONS_H +#define SPEC_FUNCTIONS_H + +namespace Specter { + + namespace Utilities + { + //Use Szudzik pairing function to convert board/channel number pair to a single universal unqiue identifier (UUID) + //Allows us to unqiuely id board-channel combo even with a set of boards that don't have the same number of channels + //It's constexpr, since for each board/channel pair the value should be evaluated at compile time (and allows us to use values in a switch) + //This is mostly syntactic sugar. When board and channel are constexpr (read: literals) it gives a constexpr value, otherwise behaves same as any other function + constexpr uint32_t GetBoardChannelUUID(uint32_t board, uint32_t channel) + { + return board >= channel ? (board * board + board + channel) : (channel * channel + board); + } + } +} + +#endif \ No newline at end of file diff --git a/Specter/src/specpch.h b/Specter/src/specpch.h index 5584155..6eb052e 100644 --- a/Specter/src/specpch.h +++ b/Specter/src/specpch.h @@ -18,5 +18,6 @@ #include "Specter/Core/Logger.h" #include "Specter/Utils/Instrumentor.h" +#include "Specter/Utils/Functions.h" #endif \ No newline at end of file