From 262e29a10e8d9fecce68acf1ff162ee048e4fcd7 Mon Sep 17 00:00:00 2001 From: sophieMu2e Date: Tue, 24 Mar 2026 08:12:59 -0500 Subject: [PATCH] updates for viewing data --- examples/extracted_MDC2020.fcl | 1 + examples/extracted_MDC2025.fcl | 39 +++++- examples/nominal_MDC2020.fcl | 1 + examples/nominal_MDC2025.fcl | 6 +- fcl/extracted.fcl | 63 +++++---- fcl/nominal.fcl | 2 +- inc/EventDisplayManager.hh | 33 ++++- src/DataInterface.cc | 249 +++++++++++++++++---------------- src/EventDisplayManager.cc | 29 +++- src/Mu2eEventDisplay_module.cc | 60 +++++--- 10 files changed, 308 insertions(+), 175 deletions(-) diff --git a/examples/extracted_MDC2020.fcl b/examples/extracted_MDC2020.fcl index 6ceaac3..d1c6023 100644 --- a/examples/extracted_MDC2020.fcl +++ b/examples/extracted_MDC2020.fcl @@ -9,6 +9,7 @@ physics.analyzers.Mu2eEventDisplay.gdmlname :"Offline/gen/gdml/mu2e_extracted_MDC2020.gdml" services.TFileService.fileName: "/dev/null" services.GeometryService.inputFile: "Offline/Mu2eG4/geom/geom_common_extracted_MDC2020.txt" +physics.analyzers.Mu2eEventDisplay.geometry : "extracted_2020" physics.EndPath : [ @sequence::REveDis.seqBase] physics.REvePath : @local::REvePath diff --git a/examples/extracted_MDC2025.fcl b/examples/extracted_MDC2025.fcl index c507d45..58f1115 100644 --- a/examples/extracted_MDC2025.fcl +++ b/examples/extracted_MDC2025.fcl @@ -3,10 +3,47 @@ #include "Offline/fcl/minimalMessageService.fcl" #include "Offline/fcl/standardProducers.fcl" #include "Offline/fcl/standardServices.fcl" +#include "EventDisplay/fcl/prolog.fcl" #include "EventDisplay/fcl/extracted.fcl" -physics.analyzers.Mu2eEventDisplay.gdmlname :"Offline/gen/gdml/mu2e_extracted.gdml" +services : @local::Services.Reco + +process_name : Nominal + +source : { module_type : RootInput } + +physics : +{ + analyzers : { @table::REveDis.analyzers} + producers : { @table::REveDis.producers } + filters : { @table::REveDis.filters } +} + +# print statements +physics.analyzers.Mu2eEventDisplay.diagLevel : 10 + +# the path +physics.EndPath : [ @sequence::REveDis.seqBase] +physics.REvePath : @local::REvePath +physics.trigger_paths : ["REvePath" ] +physics.analyzers.Mu2eEventDisplay.SelectEvents : ["REvePath" ] + +source.inputCommands: ["keep *", + "drop mu2e::CaloClusters_CaloClusterFast_*_*" + ] + +# useless file name +services.TFileService.fileName: "/dev/null" + +physics.analyzers.Mu2eEventDisplay.gdmlname :"Offline/gen/gdml/mu2e_extracted.gdml" +physics.analyzers.Mu2eEventDisplay.geometry : "extracted_2025" +physics.analyzers.Mu2eEventDisplay.filler.addCrvClusters : false +physics.analyzers.Mu2eEventDisplay.filler.addCrvRecoPulse : true +physics.analyzers.Mu2eEventDisplay.filler.addCaloDigis : true +physics.analyzers.Mu2eEventDisplay.filler.addClusters : false +physics.analyzers.Mu2eEventDisplay.filler.addKalSeeds : false +physics.analyzers.Mu2eEventDisplay.extracted : true services.TFileService.fileName: "/dev/null" services.GeometryService.inputFile: "Offline/Mu2eG4/geom/geom_common_extracted.txt" diff --git a/examples/nominal_MDC2020.fcl b/examples/nominal_MDC2020.fcl index 5c1faf1..154b329 100644 --- a/examples/nominal_MDC2020.fcl +++ b/examples/nominal_MDC2020.fcl @@ -21,6 +21,7 @@ physics : # print statements physics.analyzers.Mu2eEventDisplay.diagLevel : 10 +physics.analyzers.Mu2eEventDisplay.geometry : "nominal_2020" # the path physics.EndPath : [ @sequence::REveDis.seqBase] diff --git a/examples/nominal_MDC2025.fcl b/examples/nominal_MDC2025.fcl index 6867abf..dfbaa1a 100644 --- a/examples/nominal_MDC2025.fcl +++ b/examples/nominal_MDC2025.fcl @@ -21,7 +21,11 @@ physics : # print statements physics.analyzers.Mu2eEventDisplay.diagLevel : 10 - +physics.analyzers.Mu2eEventDisplay.geometry : "nominal_2025" +physics.analyzers.Mu2eEventDisplay.filler.addCrvClusters : true +physics.analyzers.Mu2eEventDisplay.filler.addCrvRecoPulse : true +physics.analyzers.Mu2eEventDisplay.filler.addSimParts : true +physics.analyzers.Mu2eEventDisplay.filler.addCaloDigis : true # the path physics.EndPath : [ @sequence::REveDis.seqBase] physics.REvePath : @local::REvePath diff --git a/fcl/extracted.fcl b/fcl/extracted.fcl index 58f6c34..ca3838d 100644 --- a/fcl/extracted.fcl +++ b/fcl/extracted.fcl @@ -1,29 +1,40 @@ -#include "EventDisplay/fcl/prolog.fcl" +# author : Sophie Middleton +# purpose : example fo nominal geometry i.e. not extracted -services : @local::Services.Reco -process_name : Extracted -source : { module_type : RootInput } -physics : -{ - analyzers : { @table::REveDis.analyzers} - producers : { @table::REveDis.producers } - filters : { @table::REveDis.filters } -} +# geometry options +Mu2eEventDisplay.showCrv : true +Mu2eEventDisplay.showPS : false +Mu2eEventDisplay.showTS : false +Mu2eEventDisplay.showDS : false +Mu2eEventDisplay.addCrvBars : true +Mu2eEventDisplay.addKalInter : true +Mu2eEventDisplay.addCrystalHits : true +Mu2eEventDisplay.filler.addHelixSeeds : false +Mu2eEventDisplay.filler.addKalSeeds : true +Mu2eEventDisplay.filler.addClusters : true +Mu2eEventDisplay.filler.addHits : false # adds ComboHits +Mu2eEventDisplay.filler.addCrvClusters : true +Mu2eEventDisplay.filler.addCrvRecoPulse : true +Mu2eEventDisplay.filler.addTimeClusters : false +Mu2eEventDisplay.filler.addSimParts : false +Mu2eEventDisplay.addTrkStrawHits : true +Mu2eEventDisplay.addTrkCaloHits : true +Mu2eEventDisplay.filler.addCosmicTrackSeeds : false +Mu2eEventDisplay.filler.addMCTraj : true +Mu2eEventDisplay.filler.addHelixSeeds : false +Mu2eEventDisplay.specifyTag : false -physics.analyzers.Mu2eEventDisplay.showCrv : true -physics.analyzers.Mu2eEventDisplay.showST: false -physics.analyzers.Mu2eEventDisplay.addCrvBars : true -physics.analyzers.Mu2eEventDisplay.filler.addCrvRecoPulse: true -physics.analyzers.Mu2eEventDisplay.filler.addCrvClusters : false -physics.analyzers.Mu2eEventDisplay.filler.addCosmicTrackSeeds : false -physics.analyzers.Mu2eEventDisplay.addCrystalHits : true -physics.analyzers.Mu2eEventDisplay.addKalInter : true -physics.analyzers.Mu2eEventDisplay.addTrkStrawHits : true -physics.analyzers.Mu2eEventDisplay.filler.addKalSeeds : true -physics.analyzers.Mu2eEventDisplay.filler.addTrkHits : false -physics.analyzers.Mu2eEventDisplay.filler.addClusters : false //CaloClusters -physics.analyzers.Mu2eEventDisplay.filler.addHits : false //ComboHits -physics.analyzers.Mu2eEventDisplay.filler.addSimParts : true +Mu2eEventDisplay.seqMode : true +Mu2eEventDisplay.strawdisplay : false + +Mu2eEventDisplay.diagLevel : 10 + +# the path +physics.EndPath : [ @sequence::REveDis.seqBase] +physics.REvePath : @local::REvePath +physics.trigger_paths : ["REvePath" ] +Mu2eEventDisplay.SelectEvents : ["REvePath" ] + +# useless file name +services.TFileService.fileName: "/dev/null" -physics.analyzers.Mu2eEventDisplay.extracted : true -physics.analyzers.Mu2eEventDisplay.seqMode : true diff --git a/fcl/nominal.fcl b/fcl/nominal.fcl index 4e766c2..770a3c5 100644 --- a/fcl/nominal.fcl +++ b/fcl/nominal.fcl @@ -14,7 +14,7 @@ Mu2eEventDisplay.filler.addKalSeeds : true Mu2eEventDisplay.filler.addClusters : true Mu2eEventDisplay.filler.addHits : false # adds ComboHits Mu2eEventDisplay.filler.addCrvClusters : true -Mu2eEventDisplay.filler.addCrvRecoPulse : false +Mu2eEventDisplay.filler.addCrvRecoPulse : true Mu2eEventDisplay.filler.addTimeClusters : false Mu2eEventDisplay.filler.addSimParts : false Mu2eEventDisplay.addTrkStrawHits : true diff --git a/inc/EventDisplayManager.hh b/inc/EventDisplayManager.hh index 144bf71..dfafc56 100644 --- a/inc/EventDisplayManager.hh +++ b/inc/EventDisplayManager.hh @@ -8,10 +8,13 @@ #include #include #include +#include +#include #include "EventDisplay/inc/GUI.hh" #include "EventDisplay/inc/TextSelect.hh" #include "nlohmann/json.hpp" #include +#include "Offline/ConfigTools/inc/SimpleConfig.hh" namespace ROOT::Experimental { class REveManager; @@ -25,21 +28,24 @@ namespace mu2e { * Inherits from ROOT::Experimental::REveElement to receive browser commands. */ class EventDisplayManager : public ROOT::Experimental::REveElement { - public: - // Default constructor required by ROOT's dictionary generation mechanism. - EventDisplayManager() = default; + private: + // Default constructor is private to prevent ROOT from creating uninitialized instances. + EventDisplayManager() = default; + public: /** * @brief Primary constructor for initializing thread synchronization and manager pointers. * @param eveMgr The global REveManager instance. * @param cv The condition variable for inter-thread signaling (notify/wait). * @param m The mutex for protecting access and for condition variable use. * @param fGui Pointer to the custom GUI element instance. + * @param geometry The initial geometry type (e.g., "2020", "2025"). */ explicit EventDisplayManager(ROOT::Experimental::REveManager* eveMgr, std::condition_variable& cv, std::mutex& m, - GUI *fGui); + GUI *fGui, + const std::string& geometry = "2025"); // --- REve Command Methods (Invoked by browser buttons) --- @@ -75,6 +81,19 @@ namespace mu2e { * @param textId The assigned REve Element ID. */ void setTextSelectId(std::uint32_t textId); + + /** + * @brief Set the current geometry type and update the corresponding TextSelect element ID. + * @param geomType The geometry type (e.g., "2020", "2025"). + */ + void setGeometry(const std::string& geomType); + + /** + * @brief Get the TextSelect element ID for the current geometry. + * @return The element ID corresponding to the current geometry type. + */ + std::uint32_t getTextSelectIdForGeometry() const; + int id_; void setid(int id){ id_ = id;} private: @@ -95,6 +114,12 @@ namespace mu2e { // this is kept for direct access if necessary (but is less robust). TextSelect *fText_{nullptr}; + // Current geometry type (e.g., "2020", "2025") + std::string currentGeometry_{"2025"}; + + // Mapping of geometry types to TextSelect element IDs + static const std::map geometryToElementIdMap; + }; } diff --git a/src/DataInterface.cc b/src/DataInterface.cc index a5883b4..2e8536e 100644 --- a/src/DataInterface.cc +++ b/src/DataInterface.cc @@ -28,22 +28,27 @@ void DataInterface::AddCaloDigis(REX::REveManager *&eveMng, bool firstLoop_, /*if(!firstLoop_){ scene->DestroyElements();; }*/ - std::cout << "[DataInterface] AddCaloDigi: Restoring Original Z-Position Logic" << std::endl; + std::cout << "[DataInterface] AddCaloDigi: Plotting raw CaloDigis (colored by amplitude/ADC)" << std::endl; std::vector calodigi_list = std::get<1>(calodigi_tuple); std::vector names = std::get<0>(calodigi_tuple); - // Find the Global Time Range (min/max t0) - double max_t0 = -1e6; - double min_t0 = 1e6; + // Find the Global Energy Range (min/max amplitude from waveforms) + double max_amp = -1e6; + double min_amp = 1e6; bool found_digis = false; for(const auto* calodigicol : calodigi_list){ if(calodigicol && !calodigicol->empty()){ found_digis = true; for(const auto& digi : *calodigicol){ - double t0 = digi.t0(); - if(t0 > max_t0) max_t0 = t0; - if(t0 < min_t0) min_t0 = t0; + const std::vector& waveform = digi.waveform(); + // Find max amplitude in this waveform + double max_wf_val = 0.0; + for(const auto& sample : waveform){ + if(sample > max_wf_val) max_wf_val = sample; + } + if(max_wf_val > max_amp) max_amp = max_wf_val; + if(max_wf_val < min_amp) min_amp = max_wf_val; } } } @@ -53,21 +58,10 @@ void DataInterface::AddCaloDigis(REX::REveManager *&eveMng, bool firstLoop_, return; } - if (max_t0 == min_t0) { - max_t0 += 1.0; + if (max_amp == min_amp) { + max_amp += 1.0; } - // Define the Color Gradient (Palette) - const Int_t NRGBs = 5; - const Int_t NCont = 255; - Double_t stops[NRGBs] = { 0.00, 0.34, 0.61, 0.84, 1.00 }; - Double_t red[NRGBs] = { 0.00, 0.00, 0.87, 1.00, 0.51 }; - Double_t green[NRGBs] = { 0.00, 0.81, 1.00, 0.20, 0.00 }; - Double_t blue[NRGBs] = { 0.51, 1.00, 0.12, 0.00, 0.00 }; - - TColor::CreateGradientColorTable(NRGBs, stops, red, green, blue, NCont); - gStyle->SetNumberContours(NCont); - // Visualization Loop for(unsigned int j = 0; j < calodigi_list.size(); j++){ @@ -91,11 +85,33 @@ void DataInterface::AddCaloDigis(REX::REveManager *&eveMng, bool firstLoop_, Crystal const &crystal = cal.crystal(cryID); - // Calculate Color based on t0 + // Extract maximum amplitude from waveform + const std::vector& waveform = digi.waveform(); + double max_amplitude = 0.0; + for(const auto& sample : waveform){ + if(sample > max_amplitude) max_amplitude = sample; + } + + // Calculate Color based on amplitude (ADC/Energy) using shades of orange Color_t color; - double normalized_t0 = (digi.t0() - min_t0) / (max_t0 - min_t0); - int colorIdx = static_cast(normalized_t0 * (NCont - 1)); - color = gStyle->GetColorPalette(colorIdx); + double normalized_amp = (max_amplitude - min_amp) / (max_amp - min_amp); + + // Map normalized amplitude to shades of orange (light for low energy, dark for high energy) + if (normalized_amp < 0.2) { + color = TColor::GetColor(255, 200, 0); // Very light orange + } + else if (normalized_amp < 0.4) { + color = TColor::GetColor(255, 165, 0); // Light orange + } + else if (normalized_amp < 0.6) { + color = TColor::GetColor(255, 140, 0); // Medium orange + } + else if (normalized_amp < 0.8) { + color = TColor::GetColor(200, 100, 20); // Dark orange + } + else { + color = TColor::GetColor(139, 69, 19); // Very dark orange/brown (darkest - most energetic) + } // Geometry and Position (Matching Original Logic) double crystalXLen = pointmmTocm(crystal.size().x()); @@ -122,9 +138,11 @@ void DataInterface::AddCaloDigis(REX::REveManager *&eveMng, bool firstLoop_, std::string label = " CaloDigi Instance = " + names[j] + '\n' + " Crystal ID = " + std::to_string(cryID) + '\n' + " SiPM. = "+std::to_string(sipmID)+ '\n' + + " Max Amplitude (ADC) = "+std::to_string(max_amplitude)+" " + '\n' + " t0 = "+std::to_string(digi.t0())+" ns " + '\n' + " peakPos = "+std::to_string(digi.peakpos()); + std::cout << "[DataInterface] Adding CaloDigi: " << digi.t0() << std::endl; // A. Draw Crystal Center (Point Set) auto ps1 = new REX::REvePointSet(label.c_str(), label.c_str(), 0); auto ps2 = new REX::REvePointSet(label.c_str(), label.c_str(), 0); @@ -148,6 +166,7 @@ void DataInterface::AddCaloDigis(REX::REveManager *&eveMng, bool firstLoop_, // B. Draw Crystal Volume (REveBox) std::string crytitle = "Crystal ID = " + std::to_string(cryID) + '\n' + + " Max Amplitude (ADC) = " + std::to_string(max_amplitude) + '\n' + " Time = " + std::to_string(digi.t0()) + " ns "; auto b = new REX::REveBox(crytitle.c_str(), crytitle.c_str()); @@ -589,7 +608,7 @@ void DataInterface::AddCrvInfo(REX::REveManager *&eveMng, bool firstLoop_, /*if(!firstLoop_){ scene->DestroyElements();; }*/ - std::cout << "[DataInterface::AddCrvInfo() ] - Coloring by Pulse Height (White Start, More Variation)" << std::endl; + std::cout << "[DataInterface::AddCrvInfo() ] - Coloring by Time Window" << std::endl; std::vector crvpulse_list = std::get<1>(crvpulse_tuple); std::vector names = std::get<0>(crvpulse_tuple); @@ -597,19 +616,23 @@ void DataInterface::AddCrvInfo(REX::REveManager *&eveMng, bool firstLoop_, mu2e::GeomHandle CRS; mu2e::GeomHandle det; - // Find the Global Pulse Height Range (min/max) - double max_height = 0.0; - double min_height = 1e6; + // Find the Global Pulse Time Range (min/max) and collect all pulses + double max_time = -1e6; + double min_time = 1e6; bool found_pulses = false; + std::vector all_pulse_times; - if(crvpulse_list.size() != 0){ + if( !crvpulse_list.empty()){ + std::cout << "[DataInterface::AddCrvInfo() ] Found " << crvpulse_list.size() << " Crv Reco Pulse Collections." << std::endl; for(const auto* crvRecoPulse : crvpulse_list){ if(crvRecoPulse && !crvRecoPulse->empty()){ found_pulses = true; for(const auto& crvpulse : *crvRecoPulse){ - double height = crvpulse.GetPulseHeight(); - if(height > max_height) max_height = height; - if(height < min_height) min_height = height; + double time = crvpulse.GetPulseTime(); + std::cout << "Found Crv Reco Pulse with time: " << time << " ns" << std::endl; + all_pulse_times.push_back(time); + if(time > max_time) max_time = time; + if(time < min_time) min_time = time; } } } @@ -620,21 +643,24 @@ void DataInterface::AddCrvInfo(REX::REveManager *&eveMng, bool firstLoop_, return; } - // Handle cases where all pulses have the same height - if (max_height == min_height) { - max_height += 1.0; - } - - // Define the Color Gradient (Palette) - const Int_t NRGBs = 7; - const Int_t NCont = 255; - - Double_t stops[NRGBs] = { 0.00, 0.15, 0.30, 0.50, 0.70, 0.85, 1.00 }; - Double_t red[NRGBs] = { 1.00, 0.90, 0.60, 0.00, 0.00, 0.50, 0.80 }; - Double_t green[NRGBs] = { 1.00, 0.90, 0.80, 0.60, 0.00, 0.00, 0.10 }; - Double_t blue[NRGBs] = { 1.00, 0.90, 0.80, 0.80, 1.00, 0.80, 0.00 }; + // Define time window size (in ns) - adjust this parameter to group pulses differently + const double time_window_size = 500.0; // 100 ns windows - Int_t palette_start_index = TColor::CreateGradientColorTable(NRGBs, stops, red, green, blue, NCont); + // Calculate number of time windows needed + double time_range = max_time - min_time; + int num_windows = static_cast(std::ceil(time_range / time_window_size)) + 1; + + // Define a set of distinct colors for time windows + std::vector time_window_colors = { + kRed, kGreen, kBlue, kYellow, kMagenta, kCyan, + kOrange, kSpring, kTeal, kAzure, kViolet, kPink, + kRed+2, kGreen+2, kBlue+2, kYellow+2, kMagenta+2, kCyan+2, + kRed+1, kGreen+1 + }; + + // If we need more colors than we have, cycle through them + std::cout << "[DataInterface::AddCrvInfo() ] Time range: " << min_time << " to " << max_time + << " ns (range: " << time_range << " ns), num_windows: " << num_windows << std::endl; // Visualization Loop for(unsigned int i=0; i < crvpulse_list.size(); i++){ @@ -642,41 +668,27 @@ void DataInterface::AddCrvInfo(REX::REveManager *&eveMng, bool firstLoop_, if(crvRecoPulse->size() != 0){ - std::string temp_title = "Crv Reco Pulses: " + names[i]; - auto ps1 = new REX::REvePointSet(temp_title.c_str(), temp_title.c_str(), 0); auto allcrvbars = new REX::REveCompound(("CrvHitBars_" + std::to_string(i)).c_str(), ("Crv Hit Bars: " + names[i]).c_str(), 1); - std::string final_ps1_title = temp_title; - + std::cout << "[DataInterface::AddCrvInfo() ] Processing Crv Reco Pulse Collection: " << names[i] << " with " << crvRecoPulse->size() << " pulses " << std::endl; for(unsigned int j=0; j< crvRecoPulse->size(); j++){ mu2e::CrvRecoPulse const &crvpulse = (*crvRecoPulse)[j]; - // Calculate Pulse Height Based Color - Color_t hit_color; + // Calculate Time Window Based Color + double pulse_time = crvpulse.GetPulseTime(); - // Define a minimum range (e.g., 1.0 ADC count) to prevent color collapse - const double kMinRange = 1.0; - - double pulse_height = crvpulse.GetPulseHeight(); - double actual_range = max_height - min_height; - - // Use the larger of the actual range or the minimum required range (kMinRange) - double range = (actual_range < kMinRange) ? kMinRange : actual_range; - - // Calculate the normalized height (0.0 to 1.0) using the adjusted range - double normalized_height = (pulse_height - min_height) / range; - - // Clamp the normalized height between 0 and 1 - if (normalized_height < 0) normalized_height = 0; - if (normalized_height > 1) normalized_height = 1; - - // Map normalized height (0 to 1) to the color index (0 to NCont-1) - int colorIdx = palette_start_index + static_cast(normalized_height * (NCont - 1)); - - hit_color = TColor::GetColor(colorIdx); - + // Determine which time window this pulse belongs to + int time_window_index = static_cast(std::floor((pulse_time - min_time) / time_window_size)); + if (time_window_index < 0) time_window_index = 0; + if (time_window_index >= num_windows) time_window_index = num_windows - 1; + + // Get color from predefined color array, cycling if necessary + Color_t hit_color = time_window_colors[time_window_index % time_window_colors.size()]; + + std::cout << "Found Crv Reco Pulse with time: " << pulse_time << " ns, window: " << time_window_index + << ", color: " << hit_color << std::endl; // Geometry Setup const mu2e::CRSScintillatorBarIndex &crvBarIndex = crvpulse.GetScintillatorBarIndex(); @@ -686,16 +698,14 @@ void DataInterface::AddCrvInfo(REX::REveManager *&eveMng, bool firstLoop_, CLHEP::Hep3Vector crvCounterPos = crvCounter.getPosition(); CLHEP::Hep3Vector pointInMu2e = det->toDetector(crvCounterPos); - // DETAILED PULSE TITLE (Used for REveBox mouseover) - std::string pulsetitle = " Crv Pulse Collection: " + names[i] + '\n' + // DETAILED PULSE TITLE (Used for individual point labels) + std::string pulsetitle = " Crv Pulse #" + std::to_string(j) + " - " + names[i] + '\n' + " SiPM Channel ID: " + std::to_string(crvpulse.GetSiPMNumber()) + '\n' + " Crv Bar ID: " + std::to_string(crvBarIndex.asInt()) + '\n' - + " Pulse Time: " + std::to_string(crvpulse.GetPulseTime()) + " ns" + '\n' - + " Pulse Height: " + std::to_string(crvpulse.GetPulseHeight()) + " ADC (Color)" + '\n' + + " Pulse Time: " + std::to_string(crvpulse.GetPulseTime()) + " ns (Time Window: " + std::to_string(time_window_index) + ")" + '\n' + + " Pulse Height: " + std::to_string(crvpulse.GetPulseHeight()) + " ADC" + '\n' + " Pedestal: " + std::to_string(crvpulse.GetPedestal()) + " ADC"; char const *pulsetitle_c = pulsetitle.c_str(); - - final_ps1_title = "Crv Pulses: " + names[i] + " (Last Pulse Details: " + '\n' + pulsetitle; // A. Draw Crv Bar (REveBox) if(addCrvBars){ @@ -804,25 +814,20 @@ void DataInterface::AddCrvInfo(REX::REveManager *&eveMng, bool firstLoop_, } } - // B. Add Reco Pulse Marker (Point Set) + // B. Add individual Reco Pulse Point with its own label + auto ps1 = new REX::REvePointSet(pulsetitle_c, pulsetitle_c, 1); ps1->SetNextPoint(pointmmTocm(pointInMu2e.x()), pointmmTocm(pointInMu2e.y()), pointmmTocm(pointInMu2e.z())); + ps1->SetMarkerColor(hit_color); + ps1->SetMarkerStyle(DataInterface::mstyle); + ps1->SetMarkerSize(DataInterface::msize); + scene->AddElement(ps1); } // End of individual pulse loop - // Post-Loop: Set the final, detailed title on the PointSet - ps1->SetTitle(final_ps1_title.c_str()); - // Add Compounds/Collections to Scene if (!extracted && addCrvBars) { scene->AddElement(allcrvbars); } - - // Draw reco pulse collection (markers) - ps1->SetMarkerColor(i + 3); - ps1->SetMarkerStyle(DataInterface::mstyle); - ps1->SetMarkerSize(DataInterface::msize); - - if(ps1->GetSize() != 0) scene->AddElement(ps1); } } } @@ -845,9 +850,9 @@ void DataInterface::AddCrvClusters(REX::REveManager *&eveMng, bool firstLoop_, if (crvpulse_list.size() == 0) return; - // Find the Global Pulse Height Range (min/max) for ALL pulses in ALL clusters - double max_height = 0.0; - double min_height = 1e6; + // Find the Global Pulse Time Range (min/max) for ALL pulses in ALL clusters + double max_time = -1e6; + double min_time = 1e6; bool found_pulses = false; for (const auto* crvClusters : crvpulse_list) { @@ -856,9 +861,9 @@ void DataInterface::AddCrvClusters(REX::REveManager *&eveMng, bool firstLoop_, for (const auto& crvpulsePtr : crvclu.GetCrvRecoPulses()) { if (crvpulsePtr) { found_pulses = true; - double height = crvpulsePtr->GetPulseHeight(); - if(height > max_height) max_height = height; - if(height < min_height) min_height = height; + double time = crvpulsePtr->GetPulseTime(); + if(time > max_time) max_time = time; + if(time < min_time) min_time = time; } } } @@ -870,20 +875,23 @@ void DataInterface::AddCrvClusters(REX::REveManager *&eveMng, bool firstLoop_, return; } - // Handle cases where all pulses have the same height - if (max_height == min_height) { - max_height += 1.0; - } + // Define time window size (in ns) - adjust this parameter to group pulses differently + const double time_window_size = 50000.0; // 50 ms windows (400 ms total span / ~8 windows) - // Define the Color Gradient (Palette) - const Int_t NRGBs = 7; - const Int_t NCont = 255; - Double_t stops[NRGBs] = { 0.00, 0.15, 0.30, 0.50, 0.70, 0.85, 1.00 }; - Double_t red[NRGBs] = { 1.00, 0.90, 0.60, 0.00, 0.00, 0.50, 0.80 }; - Double_t green[NRGBs] = { 1.00, 0.90, 0.80, 0.60, 0.00, 0.00, 0.10 }; - Double_t blue[NRGBs] = { 1.00, 0.90, 0.80, 0.80, 1.00, 0.80, 0.00 }; - Int_t palette_start_index = TColor::CreateGradientColorTable(NRGBs, stops, red, green, blue, NCont); - const double kMinRange = 1.0; // Define a minimum range to prevent color collapse + // Calculate number of time windows needed + double time_range = max_time - min_time; + int num_windows = static_cast(std::ceil(time_range / time_window_size)) + 1; + + // Define a set of distinct colors for time windows + std::vector time_window_colors = { + kRed, kGreen, kBlue, kYellow, kMagenta, kCyan, + kOrange, kSpring, kTeal, kAzure, kViolet, kPink, + kRed+2, kGreen+2, kBlue+2, kYellow+2, kMagenta+2, kCyan+2, + kRed+1, kGreen+1 + }; + + std::cout << "[DataInterface::AddCrvClusters() ] Time range: " << min_time << " to " << max_time + << " ns (range: " << time_range << " ns), num_windows: " << num_windows << std::endl; // Visualization Loop for(unsigned int i=0; i < crvpulse_list.size(); i++){ @@ -922,17 +930,17 @@ void DataInterface::AddCrvClusters(REX::REveManager *&eveMng, bool firstLoop_, const mu2e::CRSScintillatorBarDetail &barDetail = crvCounter.getBarDetail(); CLHEP::Hep3Vector crvCounterPos = crvCounter.getPosition(); - // Calculate Pulse Height Based Color + // Calculate Time Window Based Color + double pulse_time = crvpulse->GetPulseTime(); double pulse_height = crvpulse->GetPulseHeight(); - double actual_range = max_height - min_height; - double range = (actual_range < kMinRange) ? kMinRange : actual_range; - - double normalized_height = (pulse_height - min_height) / range; - if (normalized_height < 0) normalized_height = 0; - if (normalized_height > 1) normalized_height = 1; - - int colorIdx = palette_start_index + static_cast(normalized_height * (NCont - 1)); - Color_t hit_color = TColor::GetColor(colorIdx); + + // Determine which time window this pulse belongs to + int time_window_index = static_cast(std::floor((pulse_time - min_time) / time_window_size)); + if (time_window_index < 0) time_window_index = 0; + if (time_window_index >= num_windows) time_window_index = num_windows - 1; + + // Get color from predefined color array, cycling if necessary + Color_t hit_color = time_window_colors[time_window_index % time_window_colors.size()]; // Base Geometry Setup @@ -949,7 +957,8 @@ void DataInterface::AddCrvClusters(REX::REveManager *&eveMng, bool firstLoop_, std::string pulsetitle = " Crv Bar Hit for tag : " + names[i] + '\n' + "Bar ID: " + std::to_string(crvBarIndex.asInt()) + '\n' - + "Pulse Height: " + std::to_string(pulse_height) + " ADC (Color)" + '\n' + + "Pulse Time: " + std::to_string(pulse_time) + " ns (Time Window: " + std::to_string(time_window_index) + ", Color)" + '\n' + + "Pulse Height: " + std::to_string(pulse_height) + " ADC" + '\n' + "Coincidence start time: " + std::to_string(crvclu.GetStartTime()) + '\n' + "Coincidence end time: " + std::to_string(crvclu.GetEndTime()); char const *pulsetitle_c = pulsetitle.c_str(); diff --git a/src/EventDisplayManager.cc b/src/EventDisplayManager.cc index f0ad526..ba04beb 100644 --- a/src/EventDisplayManager.cc +++ b/src/EventDisplayManager.cc @@ -1,6 +1,6 @@ #include "EventDisplay/inc/EventDisplayManager.hh" namespace mu2e { - + // --- Constructor Implementation --- /** * @brief Constructs the EventDisplayManager singleton instance. @@ -10,12 +10,18 @@ namespace mu2e { * @param cv The condition variable for thread signaling. * @param m The mutex for thread synchronization. * @param fGui The pointer to the custom GUI element. + * @param geometry The initial geometry type (e.g., "2020", "2025"). */ +std::string drawfilename("EventDisplay/config/guiutils_current.txt"); +SimpleConfig drawconfig(drawfilename); + + EventDisplayManager::EventDisplayManager( ROOT::Experimental::REveManager* eveMgr, std::condition_variable& cv, std::mutex& m, - GUI *fGui) + GUI *fGui, + const std::string& geometry) : REveElement{"EventManager"}, eveMng_{eveMgr}, @@ -57,8 +63,9 @@ void EventDisplayManager::autoplay(int x) if (ROOT::Experimental::gEve != nullptr) { // 1. Retrieve the generic REveElement using the global manager (gEve) and the Element ID. - // The function name should be FindElementWithId(fTextId_)but I found that this does not work so I hardcoded FIXME - ROOT::Experimental::REveElement* element = ROOT::Experimental::gEve->FindElementById(4336); + // Use geometry-based lookup instead of hardcoded ID. + //std::uint32_t elementId = getTextSelectIdForGeometry(); + ROOT::Experimental::REveElement* element = ROOT::Experimental::gEve->FindElementById(drawconfig.getInt("GUIID")); if (element != nullptr) { // 2. Safely cast the generic element to the specific TextSelect type. @@ -91,6 +98,15 @@ void EventDisplayManager::setTextSelectId(std::uint32_t textId) { std::cout << "[EventDisplayManager::setTextSelectId] fTextId_ set to: " << fTextId_ << std::endl; } +/** + * @brief Set the current geometry type. + * @param geomType The geometry type (e.g., "2020", "2025"). + */ +void EventDisplayManager::setGeometry(const std::string& geomType) { + currentGeometry_ = geomType; + std::cout << "[EventDisplayManager::setGeometry] Geometry set to: '" << currentGeometry_ << "'" << std::endl; +} + // --- Core Lookup and Command Execution --- /** @@ -107,8 +123,9 @@ void mu2e::EventDisplayManager::goToRunEvent(int runId, int eventId) if (ROOT::Experimental::gEve != nullptr) { // 1. Retrieve the generic REveElement using the global manager (gEve) and the Element ID. - // The function name should be FindElementWithId(fTextId_)but I found that this does not work so I hardcoded FIXME - ROOT::Experimental::REveElement* element = ROOT::Experimental::gEve->FindElementById(4336); + // Use geometry-based lookup instead of hardcoded ID. + //std::uint32_t elementId = getTextSelectIdForGeometry(); + ROOT::Experimental::REveElement* element = ROOT::Experimental::gEve->FindElementById(drawconfig.getInt("GUIID")); if (element != nullptr) { // 2. Safely cast the generic element to the specific TextSelect type. diff --git a/src/Mu2eEventDisplay_module.cc b/src/Mu2eEventDisplay_module.cc index 431c32f..29e0b29 100644 --- a/src/Mu2eEventDisplay_module.cc +++ b/src/Mu2eEventDisplay_module.cc @@ -43,6 +43,7 @@ #include #include #include +#include //Offline: #pragma GCC diagnostic push @@ -132,6 +133,7 @@ namespace mu2e fhicl::Atom extracted{Name("extracted"), Comment(""),false}; fhicl::Atom showEM{Name("showEM"), Comment(""),false}; fhicl::Atom seqMode{Name("seqMode"), Comment("turn off for go to any event functionality"),true}; + fhicl::Atomgeometry{Name("geometry"),Comment("geometry type (nominal_2020 or nominal_2025)"),"nominal_2025"}; }; typedef art::EDAnalyzer::Table Parameters; @@ -203,6 +205,7 @@ namespace mu2e std::unique_ptr fText{nullptr}; std::unique_ptr fPrint{nullptr}; REX::REveManager* eveMng_{nullptr}; + std::string geometry_; std::unique_ptr eventMgr_{nullptr}; double eventid_; double runid_; @@ -216,7 +219,7 @@ namespace mu2e GeomOptions geomOpts; ConfigFileLookupPolicy configFile; }; - +} Mu2eEventDisplay::Mu2eEventDisplay(const Parameters& conf) : art::EDAnalyzer(conf), @@ -245,6 +248,7 @@ namespace mu2e strawdisplay_(conf().strawdisplay()), extracted_(conf().extracted()), showEM_(conf().showEM()), + geometry_(conf().geometry()), seqMode_(conf().seqMode()) { geomOpts.fill(showCrv_,showPS_, showTS_, showDS_, show2D_, caloVST_, showST_, extracted_, showSTM_, showCalo_, showTracker_, showCaloCrystals_, showEM_ ); @@ -260,7 +264,30 @@ namespace mu2e void Mu2eEventDisplay::beginJob(){ if(diagLevel_ == 1) std::cout<<"[Mu2eEventDisplay : beginJob()] -- starting ..."<( eveMng_, cv_, m_, - fGui.get() + fGui.get(), + "2025" // Not used; geometry loaded from config file in constructor ); + std::cout << "[Mu2eEventDisplay::setup_eve()] EventDisplayManager created and geometry loaded" << std::endl; + //#eventMgr_->setGeometry("2025"); // --- Scene Setup --- // Get the top-level scene, the "World," which is the container for all elements. @@ -615,11 +643,11 @@ void Mu2eEventDisplay::FillAnyCollection(const art::Event& evt, std::vectorAddElement(fText.get()); world->AddElement(eventMgr_.get()); world->AddElement(fPrint.get()); - world->AddElement(fGui.get()); + //world->AddElement(fGui.get()); // --- Final Linking and Command Registration --- - eventMgr_->setTextSelectId(fText->GetElementId()); + //#eventMgr_->setTextSelectId(fText->GetElementId()); // Register commands that the GUI buttons will execute. The command is routed to the // method on the specified element (eventMgr_.get() or fPrint.get()). @@ -627,7 +655,7 @@ void Mu2eEventDisplay::FillAnyCollection(const art::Event& evt, std::vectorAddCommand("NextEvent", "sap-icon://step", eventMgr_.get(), "NextEvent()"); world->AddCommand("PrintMCInfo", "sap-icon://step", fPrint.get(), "PrintMCInfo()"); world->AddCommand("PrintRecoInfo", "sap-icon://step", fPrint.get(), "PrintRecoInfo()"); - eventMgr_->setid(fText->GetElementId() ); + //#eventMgr_->setid(fText->GetElementId() ); // --- Signal Art Thread to Proceed --- // Acquire a lock on the mutex. @@ -635,7 +663,7 @@ void Mu2eEventDisplay::FillAnyCollection(const art::Event& evt, std::vectorGetElementId() << std::endl; + std::cout << "[DEBUG] TextSelect object ID assigned: " << fText->GetElementId() << std::endl; } @@ -714,6 +742,6 @@ void Mu2eEventDisplay::FillAnyCollection(const art::Event& evt, std::vector