From c026d9bfc5f8bccb869b41e28c42aad5d83fae19 Mon Sep 17 00:00:00 2001 From: P-A Loizeau <p.-a.loizeau@gsi.de> Date: Mon, 20 Mar 2023 14:05:48 +0100 Subject: [PATCH] [Evt disp] Add event display for CbmTimeslice with CbmEvent array (squashed) - New classes to draw PixelHit depending on (Timeslice, Event) instead of only TreeEntry (=Timeslice in this case) - New classes to draw CbmGlobalTrack depending on (Timeslice, Event) instead of only TreeEntry (=Timeslice in this case) - New CbmTimesliceManager based on FairEventManager + corresponding Editor for the event display GUI - Choice of timeslice with safety check - Choice of event in timeslice with safety check - Calls to GotoEvent methods of new PixelHit and GlobalTrack drawing classes - Pre-sets of Track & PixelHit for sis100e, sis100m and mCBM - Add buttons for next and prev TS in new display - Add views tunned for mCBM in new display - Add support for visibility tuning in xml config + mcbm example - Example macro for mCBM 2022 reco - Add support for align matrices + make unp file optional - Example xml file for geometry view config, tuned for run 2391 and the Nickel setup - Example macro for CBM - Example xml file for geometry view config, tuned for the current SIS100 electron setup - Decouple TS evt display manager from FairEventManager + rel. fixes - Remove inheritance of CbmTimesliceManager from FairEventManager + clone (and cleanup) all required blocks of code from it - Clone FairEveTransparencyControl to CbmTsEveTransparencyControl as only gui element calling FairEventManager instance - Remove call to FairEventManager instance to CbmTimesliceManager one in all Timeslice event display classes - Fix calls to wrong methods in CbmTimeslicePixelHitSetDraw - Fix printout of TS and Event info in main views - Add support for animation and screenshots + fixes --- core/eventdisplay/CMakeLists.txt | 6 + core/eventdisplay/CbmDisplayLinkDef.h | 9 +- core/eventdisplay/CbmTimesliceManager.cxx | 874 ++++++++++++++++++ core/eventdisplay/CbmTimesliceManager.h | 171 ++++ .../CbmTimesliceManagerEditor.cxx | 464 ++++++++++ core/eventdisplay/CbmTimesliceManagerEditor.h | 92 ++ .../CbmTimeslicePixelHitSetDraw.cxx | 157 ++++ .../CbmTimeslicePixelHitSetDraw.h | 42 + core/eventdisplay/CbmTimesliceRecoTracks.cxx | 250 +++++ core/eventdisplay/CbmTimesliceRecoTracks.h | 91 ++ .../eventdisplay/CbmTsEveAnimationControl.cxx | 264 ++++++ core/eventdisplay/CbmTsEveAnimationControl.h | 129 +++ .../CbmTsEveTransparencyControl.cxx | 52 ++ .../CbmTsEveTransparencyControl.h | 37 + macro/.gitignore | 2 + .../beamtime/mcbm2022/event_display_l1reco.C | 104 +++ ..._disp_conf_mcbm_beam_2022_05_23_nickel.xml | 48 + macro/run/event_display_reco_ts.C | 89 ++ macro/run/evt_disp_conf_cbm_sis100e.xml | 46 + 19 files changed, 2924 insertions(+), 3 deletions(-) create mode 100644 core/eventdisplay/CbmTimesliceManager.cxx create mode 100644 core/eventdisplay/CbmTimesliceManager.h create mode 100644 core/eventdisplay/CbmTimesliceManagerEditor.cxx create mode 100644 core/eventdisplay/CbmTimesliceManagerEditor.h create mode 100644 core/eventdisplay/CbmTimeslicePixelHitSetDraw.cxx create mode 100644 core/eventdisplay/CbmTimeslicePixelHitSetDraw.h create mode 100644 core/eventdisplay/CbmTimesliceRecoTracks.cxx create mode 100644 core/eventdisplay/CbmTimesliceRecoTracks.h create mode 100644 core/eventdisplay/CbmTsEveAnimationControl.cxx create mode 100644 core/eventdisplay/CbmTsEveAnimationControl.h create mode 100644 core/eventdisplay/CbmTsEveTransparencyControl.cxx create mode 100644 core/eventdisplay/CbmTsEveTransparencyControl.h create mode 100644 macro/.gitignore create mode 100644 macro/beamtime/mcbm2022/event_display_l1reco.C create mode 100644 macro/beamtime/mcbm2022/evt_disp_conf_mcbm_beam_2022_05_23_nickel.xml create mode 100644 macro/run/event_display_reco_ts.C create mode 100644 macro/run/evt_disp_conf_cbm_sis100e.xml diff --git a/core/eventdisplay/CMakeLists.txt b/core/eventdisplay/CMakeLists.txt index 2457d027c4..7efa64413e 100644 --- a/core/eventdisplay/CMakeLists.txt +++ b/core/eventdisplay/CMakeLists.txt @@ -10,6 +10,12 @@ set(SRCS CbmPointSetArray.cxx CbmPointSetArrayDraw.cxx CbmPointSetArrayEditor.cxx + CbmTimesliceManager.cxx + CbmTimesliceManagerEditor.cxx + CbmTimeslicePixelHitSetDraw.cxx + CbmTimesliceRecoTracks.cxx + CbmTsEveAnimationControl.cxx + CbmTsEveTransparencyControl.cxx ) diff --git a/core/eventdisplay/CbmDisplayLinkDef.h b/core/eventdisplay/CbmDisplayLinkDef.h index f9fb286cae..2503c538ee 100644 --- a/core/eventdisplay/CbmDisplayLinkDef.h +++ b/core/eventdisplay/CbmDisplayLinkDef.h @@ -2,8 +2,6 @@ SPDX-License-Identifier: GPL-3.0-only Authors: Florian Uhlig [committer] */ -// $Id: TrdLinkDef.h,v 1.10 2006/06/20 09:39:59 kresan Exp $ - #ifdef __CINT__ #pragma link off all globals; @@ -17,5 +15,10 @@ #pragma link C++ class CbmPointSetArray; #pragma link C++ class CbmPointSetArrayDraw; #pragma link C++ class CbmPointSetArrayEditor; - +#pragma link C++ class CbmTimesliceManager; +#pragma link C++ class CbmTimesliceManagerEditor; +#pragma link C++ class CbmTimeslicePixelHitSetDraw; +#pragma link C++ class CbmTimesliceRecoTracks; +#pragma link C++ class CbmTsEveAnimationControl; +#pragma link C++ class CbmTsEveTransparencyControl; #endif diff --git a/core/eventdisplay/CbmTimesliceManager.cxx b/core/eventdisplay/CbmTimesliceManager.cxx new file mode 100644 index 0000000000..dc8bdfdeb0 --- /dev/null +++ b/core/eventdisplay/CbmTimesliceManager.cxx @@ -0,0 +1,874 @@ +/* Copyright (C) 2023 Facility for Antiproton and Ion Research in Europe, Darmstadt + SPDX-License-Identifier: GPL-3.0-only + Authors: Pierre-Alain Loizeau[committer] */ + +#include "CbmTimesliceManager.h" + +#include "CbmEvent.h" // For CbmEvent +#include "CbmTimeslicePixelHitSetDraw.h" // For CbmTimeslicePixelHitSetDraw +#include "CbmTimesliceRecoTracks.h" // For CbmTimesliceRecoTracks + +#include "FairRootManager.h" // for FairRootManager +#include "FairTask.h" // for FairTask +#include "FairXMLNode.h" // for FairXMLNode and FairXMLFile + +#include <TClonesArray.h> // for TClonesArray +#include <TDatabasePDG.h> // for TDatabasePDG +#include <TEveBrowser.h> +#include <TEveGeoNode.h> // for TEveGeoTopNode +#include <TEveManager.h> // for TEveManager, gEve +#include <TEveProjectionManager.h> +#include <TEveProjections.h> // for TEveProjection, TEveProjection::k... +#include <TEveScene.h> +#include <TEveText.h> +#include <TEveTrans.h> +#include <TEveViewer.h> +#include <TEveWindow.h> // for TEveWindowPack, TEveWindowSlot +#include <TGFileDialog.h> +#include <TGLAnnotation.h> +#include <TGLCameraOverlay.h> +#include <TGLClip.h> // for TGLClip, TGLClip::kClipPlane, TGL... +#include <TGLFontManager.h> +#include <TGLLightSet.h> +#include <TGLViewer.h> +#include <TGeoBBox.h> +#include <TGeoManager.h> // for gGeoManager, TGeoManager +#include <TGeoNode.h> +#include <TGeoVolume.h> // for TGeoVolume +#include <TVector3.h> + +// +++++++++++++++++++++++++++++++++++++++++++++ Public +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // +CbmTimesliceManager* CbmTimesliceManager::gRinstanceTsMan = 0; + +CbmTimesliceManager* CbmTimesliceManager::Instance() { return gRinstanceTsMan; } + +CbmTimesliceManager::CbmTimesliceManager() : TEveEventManager("CbmTimesliceManager", "") +{ + /// Initialize instance pointer with this object when create directly + gRinstanceTsMan = this; + + fRunAna = FairRunAna::Instance(); + fRootManager = FairRootManager::Instance(); + + AddParticlesToPdgDataBase(); + InitPdgColorMap(); +} + +void CbmTimesliceManager::SetDisplayCbmElectron() +{ + CbmTimeslicePixelHitSetDraw* drawStsHit = new CbmTimeslicePixelHitSetDraw("StsHit", kBlue, kFullSquare); + CbmTimeslicePixelHitSetDraw* drawRichHit = new CbmTimeslicePixelHitSetDraw("RichHit", kCyan, kFullSquare); + CbmTimeslicePixelHitSetDraw* drawTrdHit = new CbmTimeslicePixelHitSetDraw("TrdHit", kYellow, kFullSquare); + CbmTimeslicePixelHitSetDraw* drawTofHit = new CbmTimeslicePixelHitSetDraw("TofHit", kRed, kFullSquare); + CbmTimeslicePixelHitSetDraw* drawPsdHit = new CbmTimeslicePixelHitSetDraw("PsdHit", kOrange, kFullSquare); + + CbmTimesliceRecoTracks* drawTrack = new CbmTimesliceRecoTracks(); + + AddTask(drawStsHit); + AddTask(drawRichHit); + AddTask(drawTrdHit); + AddTask(drawTofHit); + AddTask(drawPsdHit); + + AddTask(drawTrack); +} + +void CbmTimesliceManager::SetDisplayCbmMuon() +{ + CbmTimeslicePixelHitSetDraw* drawMvdHit = new CbmTimeslicePixelHitSetDraw("MvdHit", kBlue, kFullSquare); + CbmTimeslicePixelHitSetDraw* drawStsHit = new CbmTimeslicePixelHitSetDraw("StsHit", kBlue, kFullSquare); + CbmTimeslicePixelHitSetDraw* drawMuchHit = new CbmTimeslicePixelHitSetDraw("MuchHit", kCyan, kFullSquare); + CbmTimeslicePixelHitSetDraw* drawTrdHit = new CbmTimeslicePixelHitSetDraw("TrdHit", kYellow, kFullSquare); + CbmTimeslicePixelHitSetDraw* drawTofHit = new CbmTimeslicePixelHitSetDraw("TofHit", kRed, kFullSquare); + CbmTimeslicePixelHitSetDraw* drawPsdHit = new CbmTimeslicePixelHitSetDraw("PsdHit", kOrange, kFullSquare); + + AddTask(drawMvdHit); + AddTask(drawStsHit); + AddTask(drawMuchHit); + AddTask(drawTrdHit); + AddTask(drawTofHit); + AddTask(drawPsdHit); + + CbmTimesliceRecoTracks* drawTrack = new CbmTimesliceRecoTracks(); + AddTask(drawTrack); +} + +void CbmTimesliceManager::SetDisplayMcbm() +{ + CbmTimeslicePixelHitSetDraw* drawStsHit = new CbmTimeslicePixelHitSetDraw("StsHit", kBlue, kFullSquare); + // CbmTimeslicePixelHitSetDraw* drawMuchHit = new CbmTimeslicePixelHitSetDraw("MuchHit", kCyan, kFullSquare); + CbmTimeslicePixelHitSetDraw* drawTrdHit = new CbmTimeslicePixelHitSetDraw("TrdHit", kYellow, kFullSquare); + CbmTimeslicePixelHitSetDraw* drawTofHit = new CbmTimeslicePixelHitSetDraw("TofHit", kRed, kFullSquare); + CbmTimeslicePixelHitSetDraw* drawRichHit = new CbmTimeslicePixelHitSetDraw("RichHit", kOrange, kFullSquare); + + AddTask(drawStsHit); + //AddTask(drawMuchHit); + AddTask(drawTrdHit); + AddTask(drawTofHit); + AddTask(drawRichHit); + + CbmTimesliceRecoTracks* drawTrack = new CbmTimesliceRecoTracks(); + AddTask(drawTrack); + + fbMcbmViewersEna = true; +} + +void CbmTimesliceManager::SetTransparency(Bool_t use_xml, Int_t trans) +{ + if (use_xml == kFALSE) { + // high transparency + Int_t vis_level = gGeoManager->GetVisLevel(); + TGeoNode* top = gGeoManager->GetTopNode(); + SetTransparencyForLayer(top, vis_level, trans); + } + else { + // normal transparency + if (fXMLConfig != "") { // + LoadXMLSettings(); + } + else { + Int_t vis_level = gGeoManager->GetVisLevel(); + TGeoNode* top = gGeoManager->GetTopNode(); + SetTransparencyForLayer(top, vis_level, 0); + } + } + if (gEve->GetGlobalScene()->GetRnrState()) { + gEve->GetGlobalScene()->SetRnrState(kFALSE); + gEve->GetGlobalScene()->SetRnrState(kTRUE); + gEve->Redraw3D(); + } +} + +void CbmTimesliceManager::SwitchBackground(Bool_t /*light*/) +{ + /// PAL 31/05/2023: No parameter possible to SwitchColorSet of TEveViewerList in recent root versions !?! + gEve->GetViewers()->SwitchColorSet(); +} + +void CbmTimesliceManager::Init(Int_t visopt, Int_t vislvl, Int_t maxvisnds) +{ + TEveManager::Create(); + fRunAna->Init(); + + if (!InitializeMainView(visopt, vislvl, maxvisnds)) { + LOG(fatal) << "CbmTimesliceManager::Init() => Failed main view initialization"; + } + + if (fbMcbmViewersEna) { // + InitializeViewsMcbm(); + } + else { + InitializeViewsCbm(); + } + + fCbmEvents = dynamic_cast<TClonesArray*>(FairRootManager::Instance()->GetObject("CbmEvent")); + + if (nullptr == fCbmEvents) { + LOG(fatal) << "CbmTimesliceManager::Init() => CbmEvents branch not found! Task will be deactivated"; + } +} + +void CbmTimesliceManager::Open() {} +void CbmTimesliceManager::UpdateEditor() {} +void CbmTimesliceManager::Close() {} +void CbmTimesliceManager::DisplaySettings() {} + +Int_t CbmTimesliceManager::Color(int pdg) +{ + if (fPDGToColor.find(pdg) != fPDGToColor.end()) { // + return fPDGToColor[pdg]; + } + return 0; +} + +void CbmTimesliceManager::GotoTimeslice(uint32_t event) +{ + fTimesliceIdx = event; + /// This will force all added tasks to load first event of this TS if possible + FairRunAna::Instance()->Run(static_cast<Long64_t>(fTimesliceIdx)); +} + +void CbmTimesliceManager::NextTimeslice() +{ + /// Check if possible (min/max) + + /// Re-use main method + GotoTimeslice(GetCurrentTimeslice() + 1); +} + +void CbmTimesliceManager::PrevTimeslice() +{ + /// Check if possible (min/max) + + /// Re-use main method + GotoTimeslice(GetCurrentTimeslice() - 1); +} + +void CbmTimesliceManager::GotoEvent(uint32_t event) +{ + fEventIdx = event; + /// Get List of tasks from FairRunAna + TList* taskList = FairRunAna::Instance()->GetMainTask()->GetListOfTasks(); + + /// Tell each of them to go to selected event + for (TObject* task : *taskList) { + if (nullptr != dynamic_cast<CbmTimesliceRecoTracks*>(task)) { + dynamic_cast<CbmTimesliceRecoTracks*>(task)->GotoEvent(event); + } + else if (nullptr != dynamic_cast<CbmTimeslicePixelHitSetDraw*>(task)) { + dynamic_cast<CbmTimeslicePixelHitSetDraw*>(task)->GotoEvent(event); + } + } +} + +void CbmTimesliceManager::NextEvent() +{ + /// Check if possible (min/max) + + /// Re-use main method + GotoEvent(fEventIdx + 1); +} + +void CbmTimesliceManager::PrevEvent() +{ + /// Check if possible (min/max) + + /// Re-use main method + GotoEvent(fEventIdx - 1); +} + +double_t CbmTimesliceManager::GetTimesliceTime() +{ + fTimeTimeslice = FairRootManager::Instance()->GetEventTime(); + return fTimeTimeslice; +} + +double_t CbmTimesliceManager::GetEventTime() +{ + const CbmEvent* event = dynamic_cast<const CbmEvent*>(fCbmEvents->At(fEventIdx)); + fTimeEvent = event->GetTzero(); + return fTimeEvent; +} + +void CbmTimesliceManager::SetTsTimeText(Double_t time) +{ + TString stime; + stime.Form("TS Time: %.2f", time); + stime += " ns"; + fTimesliceTimeText->SetText(stime); +} + +void CbmTimesliceManager::SetTsNumberText(Int_t evtNumber) +{ + TString text = "TS: "; + text += evtNumber; + fTimesliceNumberText->SetText(text); +} + +void CbmTimesliceManager::SetEvtTimeText(Double_t time) +{ + TString stime; + stime.Form("Event Time: %.2f", time); + stime += " ns"; + fEventTimeText->SetText(stime); +} + +void CbmTimesliceManager::SetEvtNumberText(Int_t evtNumber) +{ + TString text = "Event: "; + text += evtNumber; + fEventNumberText->SetText(text); +} + +void CbmTimesliceManager::MakeScreenshot(CbmTsEveAnimationControl::eScreenshotType screenshotType, TString path) +{ + TString filename; + if (path == "") { + const char* filetypes[] = {"PNG", "*.png", "JPG", "*.jpg", 0, 0}; + TGFileInfo fi; + fi.fFileTypes = filetypes; + fi.fIniDir = StrDup("."); + new TGFileDialog(gClient->GetRoot(), gEve->GetMainWindow(), kFDSave, &fi); + if (fi.fFilename == nullptr) { // + return; + } + filename = fi.fFilename; + } + else { + filename = path; + } + + if (fbMcbmViewersEna) { + switch (screenshotType) { + case CbmTsEveAnimationControl::eScreenshotType::k3D: { + gEve->GetDefaultGLViewer()->SavePicture(filename); + break; + } + case CbmTsEveAnimationControl::eScreenshotType::kZX: { + TGLViewer* gl = fViewZX->GetGLViewer(); + gl->SavePicture(filename); + break; + } + case CbmTsEveAnimationControl::eScreenshotType::kZY: { + TGLViewer* gl = fViewZY->GetGLViewer(); + gl->SavePicture(filename); + break; + } + case CbmTsEveAnimationControl::eScreenshotType::kAll: { + TString filename_path = filename(0, filename.Last('.')); + TString filename_ext = filename(filename.Last('.') + 1, 3); + TString filename3d = Form("%s_3d.%s", filename_path.Data(), filename_ext.Data()); + TString filenameZY = Form("%s_ZY.%s", filename_path.Data(), filename_ext.Data()); + TString filenameZX = Form("%s_ZX.%s", filename_path.Data(), filename_ext.Data()); + gEve->GetDefaultGLViewer()->SavePicture(filename3d); + TGLViewer* gl = fViewZY->GetGLViewer(); + gl->SavePicture(filenameZY); + gl = fViewZX->GetGLViewer(); + gl->SavePicture(filenameZX); + break; + } + default: + /// Type missmatch, should never happen if Comboboxes properly set but better safe than sorry + break; + } + } + else { + switch (screenshotType) { + case CbmTsEveAnimationControl::eScreenshotType::k3D: { + gEve->GetDefaultGLViewer()->SavePicture(filename); + break; + } + case CbmTsEveAnimationControl::eScreenshotType::kXY: { + TGLViewer* gl = fRPhiView->GetGLViewer(); + gl->SavePicture(filename); + break; + } + case CbmTsEveAnimationControl::eScreenshotType::kZ: { + TGLViewer* gl = fRhoZView->GetGLViewer(); + gl->SavePicture(filename); + break; + } + case CbmTsEveAnimationControl::eScreenshotType::kAll: { + TString filename_path = filename(0, filename.Last('.')); + TString filename_ext = filename(filename.Last('.') + 1, 3); + TString filename3d = Form("%s_3d.%s", filename_path.Data(), filename_ext.Data()); + TString filenameRphi = Form("%s_XY.%s", filename_path.Data(), filename_ext.Data()); + TString filenameRhoz = Form("%s_Z.%s", filename_path.Data(), filename_ext.Data()); + gEve->GetDefaultGLViewer()->SavePicture(filename3d); + TGLViewer* gl = fRPhiView->GetGLViewer(); + gl->SavePicture(filenameRphi); + gl = fRhoZView->GetGLViewer(); + gl->SavePicture(filenameRhoz); + break; + } + default: + /// Type missmatch, should never happen if Comboboxes properly set but better safe than sorry + break; + } + } +} +// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // + +// ++++++++++++++++++++++++++++++++++++++++++++ Protected +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // +void CbmTimesliceManager::LoadXMLSettings() +{ + /// Complement the FairEventManager with a new keyword for setting the node visibility (+ daughters if recursive > 0) + FairXMLFile xmlfile(fXMLConfig, "read"); + FairXMLNode* xml = xmlfile.GetRootNode(); + for (int i = 0; i < xml->GetNChildren(); i++) { + TString nodename = xml->GetChild(i)->GetName(); + if (nodename.EqualTo("Detectors")) { + TGeoNode* top = gGeoManager->GetTopNode(); + FairXMLNode* top_xml = xml->GetChild(i)->GetChild(0); + if (top_xml != nullptr) { // + LoadXMLDetector(top, top_xml); + } + } + else if (nodename.EqualTo("MCTracksColors")) { + FairXMLNode* colors = xml->GetChild(i); + for (int j = 0; j < colors->GetNChildren(); j++) { + FairXMLNode* color = colors->GetChild(j); + TString pgd_code = color->GetAttrib("pdg")->GetValue(); + TString color_code = color->GetAttrib("color")->GetValue(); + //fPDGToColor[pgd_code.Atoi()] = StringToColor(color_code); + } + } + } + if (gEve->GetGlobalScene()->GetRnrState()) { + gEve->GetGlobalScene()->SetRnrState(kFALSE); + gEve->GetGlobalScene()->SetRnrState(kTRUE); + gEve->Redraw3D(); + } +} + +void CbmTimesliceManager::LoadXMLDetector(TGeoNode* node, FairXMLNode* xml, Int_t depth) +{ + /// Complement the FairEventManager with a new keyword for setting the node visibility (+ daughters if recursive > 0) + TString name = xml->GetAttrib("name")->GetValue(); + TString node_name = node->GetName(); + Bool_t recursive = (xml->GetAttrib("recursive")->GetValue().Length() != 0 && !name.EqualTo(node_name)); + if (recursive && depth == 0) { // + return; + } + TString transparency = xml->GetAttrib("transparency")->GetValue(); + TString color = xml->GetAttrib("color")->GetValue(); + TString visibility = xml->GetAttrib("visibility")->GetValue(); + TString recursive_val = xml->GetAttrib("recursive")->GetValue(); + if (!recursive && "0" != recursive_val) { // + LOG(info) << "LoadXMLDetector called for " << node_name; + } + if (!color.EqualTo("")) { + node->GetVolume()->SetFillColor(StringToColor(color)); + node->GetVolume()->SetLineColor(StringToColor(color)); + } + if (!transparency.EqualTo("")) { // + node->GetVolume()->SetTransparency((Char_t)(transparency.Atoi())); + } + if (!visibility.EqualTo("")) { + bool bVisVal = (0 < visibility.Atoi()); + node->GetVolume()->SetVisibility(bVisVal); + if (!recursive) { // + LOG(info) << "Setting " << node_name << (bVisVal ? " Visible" : " Invisible") // + << ("0" != recursive_val ? " and its daughters also" : ""); + } + } + if (recursive_val.Length() > 0) { + Int_t xml_depth = recursive_val.Atoi(); + /* + /// Original FairRoot counting, led to troubles in my case + if (recursive) { + xml_depth = depth - 1; + } + */ + if (0 < xml_depth) { + for (int i = 0; i < node->GetNdaughters(); i++) { + TGeoNode* daughter_node = node->GetDaughter(i); + LoadXMLDetector(daughter_node, xml, xml_depth); + } + } + } + if (xml->GetNChildren() > 0 && !recursive) { + for (int i = 0; i < node->GetNdaughters(); i++) { + TString subdetector_name = node->GetDaughter(i)->GetName(); + for (int j = 0; j < xml->GetNChildren(); j++) { + FairXMLNode* subnode = xml->GetChild(j); + TString subnode_name = subnode->GetAttrib("name")->GetValue(); + if (subnode_name == subdetector_name) { // + LoadXMLDetector(node->GetDaughter(i), subnode); + } + } + } + } +} + +Int_t CbmTimesliceManager::StringToColor(TString color) const +{ + if (color.Contains("k")) { + Int_t plus_index = color.First('+'); + Int_t minus_index = color.First('-'); + Int_t cut = plus_index; + if (cut == -1) { // + cut = minus_index; + } + if (cut == -1) { // + cut = color.Length(); + } + TString col_name(color(0, cut)); + Int_t col_val = 0; + if (col_name.EqualTo("kWhite")) { // + col_val = 0; + } + else if (col_name.EqualTo("kBlack")) { + col_val = 1; + } + else if (col_name.EqualTo("kGray")) { + col_val = 920; + } + else if (col_name.EqualTo("kRed")) { + col_val = 632; + } + else if (col_name.EqualTo("kGreen")) { + col_val = 416; + } + else if (col_name.EqualTo("kBlue")) { + col_val = 600; + } + else if (col_name.EqualTo("kYellow")) { + col_val = 400; + } + else if (col_name.EqualTo("kMagenta")) { + col_val = 616; + } + else if (col_name.EqualTo("kCyan")) { + col_val = 432; + } + else if (col_name.EqualTo("kOrange")) { + col_val = 800; + } + else if (col_name.EqualTo("kSpring")) { + col_val = 820; + } + else if (col_name.EqualTo("kTeal")) { + col_val = 840; + } + else if (col_name.EqualTo("kAzure")) { + col_val = 860; + } + else if (col_name.EqualTo("kViolet")) { + col_val = 880; + } + else if (col_name.EqualTo("kPink")) { + col_val = 900; + } + TString col_num(color(cut + 1, color.Length())); + if (col_num.Length() > 0) { // + if (color.Contains("+")) { // + col_val += col_num.Atoi(); + } + else { + col_val -= col_num.Atoi(); + } + } + return col_val; + } + else { + return color.Atoi(); + } +} +// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // + +// +++++++++++++++++++++++++++++++++++++++++++++ Private ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // +void CbmTimesliceManager::AddParticlesToPdgDataBase() +{ + // Add particles to the PDG data base + TDatabasePDG* pdgDB = TDatabasePDG::Instance(); + + const Double_t kAu2Gev = 0.9314943228; + const Double_t khSlash = 1.0545726663e-27; + const Double_t kErg2Gev = 1 / 1.6021773349e-3; + const Double_t khShGev = khSlash * kErg2Gev; + const Double_t kYear2Sec = 3600 * 24 * 365.25; + + // Ions + if (!pdgDB->GetParticle(1000010020)) { // + pdgDB->AddParticle("Deuteron", "Deuteron", 2 * kAu2Gev + 8.071e-3, kTRUE, 0, 3, "Ion", 1000010020); + } + + if (!pdgDB->GetParticle(1000010030)) { // + pdgDB->AddParticle("Triton", "Triton", 3 * kAu2Gev + 14.931e-3, kFALSE, khShGev / (12.33 * kYear2Sec), 3, "Ion", + 1000010030); + } + + if (!pdgDB->GetParticle(1000020040)) { // + pdgDB->AddParticle("Alpha", "Alpha", 4 * kAu2Gev + 2.424e-3, kTRUE, khShGev / (12.33 * kYear2Sec), 6, "Ion", + 1000020040); + } + + if (!pdgDB->GetParticle(1000020030)) { // + pdgDB->AddParticle("He3", "He3", 3 * kAu2Gev + 14.931e-3, kFALSE, 0, 6, "Ion", 1000020030); + } + + // Special particles + if (!pdgDB->GetParticle(50000050)) { // + pdgDB->AddParticle("Cherenkov", "Cherenkov", 0, kFALSE, 0, 0, "Special", 50000050); + } + + if (!pdgDB->GetParticle(50000051)) { // + pdgDB->AddParticle("FeedbackPhoton", "FeedbackPhoton", 0, kFALSE, 0, 0, "Special", 50000051); + } +} + +void CbmTimesliceManager::InitPdgColorMap() +{ + fPDGToColor[22] = 623; // photon + fPDGToColor[-2112] = 2; // anti-neutron + fPDGToColor[-11] = 3; // e+ + fPDGToColor[-3122] = 4; // anti-lambda + fPDGToColor[11] = 5; // e- + fPDGToColor[-3222] = 6; // Sigma - + fPDGToColor[12] = 7; // e-neutrino + fPDGToColor[-3212] = 8; // Sigma0 + fPDGToColor[-13] = 9; // mu+ + fPDGToColor[-3112] = 10; // Sigma+ (PB + fPDGToColor[13] = 11; // mu- + fPDGToColor[-3322] = 12; // Xi0 + fPDGToColor[111] = 13; // pi0 + fPDGToColor[-3312] = 14; // Xi+ + fPDGToColor[211] = 15; // pi+ + fPDGToColor[-3334] = 16; // Omega+ (PB) + fPDGToColor[-211] = 17; // pi- + fPDGToColor[-15] = 18; // tau+ + fPDGToColor[130] = 19; // K long + fPDGToColor[15] = 20; // tau - + fPDGToColor[321] = 21; // K+ + fPDGToColor[411] = 22; // D+ + fPDGToColor[-321] = 23; // K- + fPDGToColor[-411] = 24; // D- + fPDGToColor[2112] = 25; // n + fPDGToColor[421] = 26; // D0 + fPDGToColor[2212] = 27; // p + fPDGToColor[-421] = 28; // D0 + fPDGToColor[-2212] = 29; // anti-proton + fPDGToColor[431] = 30; // Ds+ + fPDGToColor[310] = 31; // K short + fPDGToColor[-431] = 32; // anti Ds- + fPDGToColor[221] = 33; // eta + fPDGToColor[4122] = 34; // Lambda_C+ + fPDGToColor[3122] = 35; // Lambda + fPDGToColor[24] = 36; // W+ + fPDGToColor[3222] = 37; // Sigma+ + fPDGToColor[-24] = 38; // W- + fPDGToColor[3212] = 39; // Sigma0 + fPDGToColor[23] = 40; // Z + fPDGToColor[3112] = 41; // Sigma - + fPDGToColor[3322] = 42; // Xi0 + fPDGToColor[3312] = 43; // Xi- + fPDGToColor[3334] = 44; // Omega- (PB) + + fPDGToColor[50000050] = 801; // Cerenkov + + fPDGToColor[1000010020] = 45; // PAL 31/05/2023: ??? + fPDGToColor[1000010030] = 48; // PAL 31/05/2023: ??? + fPDGToColor[1000020040] = 50; // PAL 31/05/2023: ??? + fPDGToColor[1000020030] = 55; // PAL 31/05/2023: ??? +} + +void CbmTimesliceManager::SetTransparencyForLayer(TGeoNode* node, Int_t depth, Char_t transparency) +{ + node->GetVolume()->SetTransparency(transparency); + if (depth <= 0) { // + return; + } + for (int i = 0; i < node->GetNdaughters(); i++) { + TGeoNode* dau = node->GetDaughter(i); + SetTransparencyForLayer(dau, depth - 1, transparency); + } +} + +bool CbmTimesliceManager::InitializeMainView(Int_t visopt, Int_t vislvl, Int_t maxvisnds) +{ + if (gGeoManager == nullptr) { // + return false; + } + TGeoNode* N = gGeoManager->GetTopNode(); + TEveGeoTopNode* TNod = new TEveGeoTopNode(gGeoManager, N, visopt, vislvl, maxvisnds); + + if (!fXMLConfig.EqualTo("")) { // + LoadXMLSettings(); + } + + gEve->AddGlobalElement(TNod); + + gEve->FullRedraw3D(kTRUE); + fEvent = gEve->AddEvent(this); + + fTimesliceNumberText = new TGLAnnotation(gEve->GetDefaultGLViewer(), "TS Number: ", 0.01, 0.94); + fTimesliceNumberText->SetTextSize(0.03); // % of window diagonal + fTimesliceNumberText->SetTextColor(kOrange - 2); + + fTimesliceTimeText = new TGLAnnotation(gEve->GetDefaultGLViewer(), "TS Time: ", 0.01, 0.90); + fTimesliceTimeText->SetTextSize(0.03); // % of window diagonal + fTimesliceTimeText->SetTextColor(kOrange - 2); + + fEventNumberText = new TGLAnnotation(gEve->GetDefaultGLViewer(), "Event Number: ", 0.01, 0.86); + fEventNumberText->SetTextSize(0.03); // % of window diagonal + fEventNumberText->SetTextColor(kOrange - 2); + + fEventTimeText = new TGLAnnotation(gEve->GetDefaultGLViewer(), "Event Time: ", 0.01, 0.82); + fEventTimeText->SetTextSize(0.03); // % of window diagonal + fEventTimeText->SetTextColor(kOrange - 2); + + return true; +} + +void CbmTimesliceManager::InitializeViewsCbm() +{ + fRPhiProjManager = new TEveProjectionManager(TEveProjection::kPT_RPhi); + fRhoZProjManager = new TEveProjectionManager(TEveProjection::kPT_RhoZ); + gEve->AddToListTree(fRPhiProjManager, kFALSE); + gEve->AddToListTree(fRhoZProjManager, kFALSE); + fAxesPhi = new TEveProjectionAxes(fRPhiProjManager); + fAxesRho = new TEveProjectionAxes(fRhoZProjManager); + + fRPhiView = gEve->SpawnNewViewer("RPhi View", ""); + fRPhiScene = gEve->SpawnNewScene("RPhi", "Scene holding axis."); + fRPhiScene->AddElement(fAxesPhi); + + fRhoZView = gEve->SpawnNewViewer("RhoZ View", ""); + fRhoZScene = gEve->SpawnNewScene("RhoZ", "Scene holding axis."); + fRhoZScene->AddElement(fAxesRho); + + SetViewers(fRPhiView, fRhoZView); + + TEveWindowSlot* MultiSlot = TEveWindow::CreateWindowInTab(gEve->GetBrowser()->GetTabRight()); + TEveWindowPack* MultiPack = MultiSlot->MakePack(); + MultiPack->SetElementName("Multi View"); + MultiPack->SetHorizontal(); + MultiPack->SetShowTitleBar(kFALSE); + MultiPack->NewSlot()->MakeCurrent(); + fMultiView = gEve->SpawnNewViewer("3D View (multi)", ""); + // switch off left and right light sources for 3D MultiView + // TODO: investigate and tune which light source directions should be used for best visibility + fMultiView->GetGLViewer()->GetLightSet()->SetLight(TGLLightSet::kLightLeft, false); + fMultiView->GetGLViewer()->GetLightSet()->SetLight(TGLLightSet::kLightRight, false); + // add 3D scenes (first tab) to 3D MultiView + fMultiView->AddScene(gEve->GetGlobalScene()); + fMultiView->AddScene(gEve->GetEventScene()); + + // add slot for RPhi projection on Multi View tab + MultiPack = MultiPack->NewSlot()->MakePack(); + MultiPack->SetShowTitleBar(kFALSE); + MultiPack->NewSlot()->MakeCurrent(); + fMultiRPhiView = gEve->SpawnNewViewer("RPhi View (multi)", ""); + MultiPack->NewSlot()->MakeCurrent(); + fMultiRhoZView = gEve->SpawnNewViewer("RhoZ View (multi)", ""); + + SetViewers(fMultiRPhiView, fMultiRhoZView); + + // don't change reposition camera on each update + fRPhiView->GetGLViewer()->SetResetCamerasOnUpdate(kFALSE); + fRhoZView->GetGLViewer()->SetResetCamerasOnUpdate(kFALSE); + fMultiView->GetGLViewer()->SetResetCamerasOnUpdate(kFALSE); + fMultiRPhiView->GetGLViewer()->SetResetCamerasOnUpdate(kFALSE); + fMultiRhoZView->GetGLViewer()->SetResetCamerasOnUpdate(kFALSE); + fMultiView->GetEveFrame()->HideAllDecorations(); + fMultiRPhiView->GetEveFrame()->HideAllDecorations(); + fMultiRhoZView->GetEveFrame()->HideAllDecorations(); +} + +void CbmTimesliceManager::SetViewers(TEveViewer* RPhi, TEveViewer* RhoZ) +{ + RPhi->GetGLViewer()->SetCurrentCamera(fRphiCam); + // set camera parameters + RPhi->GetGLViewer()->GetCameraOverlay()->SetOrthographicMode(TGLCameraOverlay::kAxis); + RPhi->GetGLViewer()->GetCameraOverlay()->SetShowOrthographic(kTRUE); + // switch off left, right, top and bottom light sources + // TODO: investigate and tune which light source directions should be used for best visibility + RPhi->GetGLViewer()->GetLightSet()->SetLight(TGLLightSet::kLightLeft, false); + RPhi->GetGLViewer()->GetLightSet()->SetLight(TGLLightSet::kLightRight, false); + RPhi->GetGLViewer()->GetLightSet()->SetLight(TGLLightSet::kLightTop, false); + RPhi->GetGLViewer()->GetLightSet()->SetLight(TGLLightSet::kLightBottom, false); + + RhoZ->GetGLViewer()->SetCurrentCamera(fRhoCam); + // set camera parameters + RhoZ->GetGLViewer()->GetCameraOverlay()->SetOrthographicMode(TGLCameraOverlay::kAxis); + RhoZ->GetGLViewer()->GetCameraOverlay()->SetShowOrthographic(kTRUE); + // switch off left, right and front light sources + // TODO: investigate and tune which light source directions should be used for best visibility + RhoZ->GetGLViewer()->GetLightSet()->SetLight(TGLLightSet::kLightLeft, false); + RhoZ->GetGLViewer()->GetLightSet()->SetLight(TGLLightSet::kLightRight, false); + RhoZ->GetGLViewer()->GetLightSet()->SetLight(TGLLightSet::kLightFront, false); + + RPhi->AddScene(fRPhiScene); + RPhi->AddScene(gEve->GetGlobalScene()); + RPhi->AddScene(gEve->GetEventScene()); + RhoZ->AddScene(fRhoZScene); + RhoZ->AddScene(gEve->GetGlobalScene()); + RhoZ->AddScene(gEve->GetEventScene()); +} + +void CbmTimesliceManager::InitializeViewsMcbm() +{ + // FIXME: available only starting from Fairsoft apr22 (did not check in which ROOT version it was introduced) + //fProjManagerZY = new TEveProjectionManager(TEveProjection::kPT_ZY); + fProjManagerZY = new TEveProjectionManager(TEveProjection::kPT_RhoZ); + //fProjManagerZX = new TEveProjectionManager(TEveProjection::kPT_ZX); + fProjManagerZX = new TEveProjectionManager(TEveProjection::kPT_RhoZ); + gEve->AddToListTree(fProjManagerZY, kFALSE); + gEve->AddToListTree(fProjManagerZX, kFALSE); + fAxesZY = new TEveProjectionAxes(fProjManagerZY); + fAxesZX = new TEveProjectionAxes(fProjManagerZX); + + fViewZY = gEve->SpawnNewViewer("ZY View", ""); + fSceneZY = gEve->SpawnNewScene("ZY", "Scene holding axis."); + fSceneZY->AddElement(fAxesZY); + + fViewZX = gEve->SpawnNewViewer("ZX View", ""); + fSceneZX = gEve->SpawnNewScene("ZX", "Scene holding axis."); + fSceneZX->AddElement(fAxesZX); + + SetMcbmViewers(fViewZY, fViewZX); + + TEveWindowSlot* McbmSlot = TEveWindow::CreateWindowInTab(gEve->GetBrowser()->GetTabRight()); + TEveWindowPack* McbmPack = McbmSlot->MakePack(); + McbmPack->SetElementName("mCBM View"); + McbmPack->SetHorizontal(); + McbmPack->SetShowTitleBar(kFALSE); + McbmPack->NewSlot()->MakeCurrent(); + fMcbmView = gEve->SpawnNewViewer("3D View (multi)", ""); + // switch off left and right light sources for 3D MultiView + // TODO: investigate and tune which light source directions should be used for best visibility + //fMcbmView->GetGLViewer()->GetLightSet()->SetLight(TGLLightSet::kLightLeft, false); + //fMcbmView->GetGLViewer()->GetLightSet()->SetLight(TGLLightSet::kLightRight, false); + // add 3D scenes (first tab) to 3D MultiView + fMcbmView->AddScene(gEve->GetGlobalScene()); + fMcbmView->AddScene(gEve->GetEventScene()); + // Center the 3D MultiView + fMcbmView->GetGLViewer()->CurrentCamera().SetCenterVecWarp(0.0, 0.0, 150.0); + + // add slot for XY projection on Multi View tab + McbmPack = McbmPack->NewSlot()->MakePack(); + McbmPack->SetShowTitleBar(kFALSE); + McbmPack->NewSlot()->MakeCurrent(); + fMcbmViewZY = gEve->SpawnNewViewer("ZY View (multi)", ""); + McbmPack->NewSlot()->MakeCurrent(); + fMcbmViewZX = gEve->SpawnNewViewer("ZX View (multi)", ""); + + SetMcbmViewers(fMcbmViewZY, fMcbmViewZX); + + // don't change reposition camera on each update + fViewZY->GetGLViewer()->SetResetCamerasOnUpdate(kFALSE); + fViewZX->GetGLViewer()->SetResetCamerasOnUpdate(kFALSE); + fMcbmView->GetGLViewer()->SetResetCamerasOnUpdate(kFALSE); + fMcbmViewZY->GetGLViewer()->SetResetCamerasOnUpdate(kFALSE); + fMcbmViewZX->GetGLViewer()->SetResetCamerasOnUpdate(kFALSE); + fMcbmView->GetEveFrame()->HideAllDecorations(); + fMcbmViewZY->GetEveFrame()->HideAllDecorations(); + fMcbmViewZX->GetEveFrame()->HideAllDecorations(); + + // Set clear background + fViewZY->GetGLViewer()->SetClearColor(kYellow - 10); + fViewZX->GetGLViewer()->SetClearColor(kYellow - 10); + fMcbmView->GetGLViewer()->SetClearColor(kYellow - 10); + fMcbmViewZY->GetGLViewer()->SetClearColor(kYellow - 10); + fMcbmViewZX->GetGLViewer()->SetClearColor(kYellow - 10); +} + +void CbmTimesliceManager::SetMcbmViewers(TEveViewer* ZY, TEveViewer* ZX) +{ + ZY->GetGLViewer()->SetCurrentCamera(fCamZY); + // set camera parameters + ZY->GetGLViewer()->GetCameraOverlay()->SetOrthographicMode(TGLCameraOverlay::kAxis); + ZY->GetGLViewer()->GetCameraOverlay()->SetShowOrthographic(kTRUE); + // switch off left, right and front light sources + // TODO: investigate and tune which light source directions should be used for best visibility + ZY->GetGLViewer()->GetLightSet()->SetLight(TGLLightSet::kLightLeft, false); + //ZY->GetGLViewer()->GetLightSet()->SetLight(TGLLightSet::kLightRight, false); + ZY->GetGLViewer()->GetLightSet()->SetLight(TGLLightSet::kLightFront, false); + // Set Camera Center + ZY->GetGLViewer()->CurrentCamera().SetCenterVecWarp(0.0, 0.0, 150.0); + + ZY->AddScene(fSceneZY); + ZY->AddScene(gEve->GetGlobalScene()); + ZY->AddScene(gEve->GetEventScene()); + + ZX->GetGLViewer()->SetCurrentCamera(fCamZX); + // set camera parameters + ZX->GetGLViewer()->GetCameraOverlay()->SetOrthographicMode(TGLCameraOverlay::kAxis); + ZX->GetGLViewer()->GetCameraOverlay()->SetShowOrthographic(kTRUE); + // switch off left, right, top and bottom light sources + // TODO: investigate and tune which light source directions should be used for best visibility + ZX->GetGLViewer()->GetLightSet()->SetLight(TGLLightSet::kLightLeft, false); + //ZX->GetGLViewer()->GetLightSet()->SetLight(TGLLightSet::kLightRight, false); + ZX->GetGLViewer()->GetLightSet()->SetLight(TGLLightSet::kLightTop, false); + ZX->GetGLViewer()->GetLightSet()->SetLight(TGLLightSet::kLightBottom, false); + // Set Camera Center + ZX->GetGLViewer()->CurrentCamera().SetCenterVecWarp(0.0, 0.0, 150.0); + + ZX->AddScene(fSceneZX); + ZX->AddScene(gEve->GetGlobalScene()); + ZX->AddScene(gEve->GetEventScene()); +} +// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // + +ClassImp(CbmTimesliceManager) diff --git a/core/eventdisplay/CbmTimesliceManager.h b/core/eventdisplay/CbmTimesliceManager.h new file mode 100644 index 0000000000..6c575cf6db --- /dev/null +++ b/core/eventdisplay/CbmTimesliceManager.h @@ -0,0 +1,171 @@ +/* Copyright (C) 2023 Facility for Antiproton and Ion Research in Europe, Darmstadt + SPDX-License-Identifier: GPL-3.0-only + Authors: Pierre-Alain Loizeau[committer] */ + +/// PAL 31/05/2023: based on FairEventManager from FairRoot v18.6.7 + +#ifndef CbmTimesliceManager_H +#define CbmTimesliceManager_H + +#include "CbmTsEveAnimationControl.h" + +#include "FairRunAna.h" // for FairRunAna + +#include <Rtypes.h> // for Float_t, Int_t, Bool_t, etc +#include <TEveEventManager.h> // for TEveEventManager +#include <TEveProjectionAxes.h> +#include <TGLViewer.h> + +#include <map> + +class FairRootManager; +class FairRunAna; +class FairTask; +class FairXMLNode; + +class TClonesArray; +class TEveProjectionAxes; +class TEveProjectionManager; +class TEveScene; +class TEveText; +class TEveViewer; +class TGeoNode; +class TGLAnnotation; +class TGListTreeItem; + +class CbmTimesliceManager : public TEveEventManager { +public: + static CbmTimesliceManager* Instance(); + CbmTimesliceManager(); + virtual ~CbmTimesliceManager() = default; + + CbmTimesliceManager(const CbmTimesliceManager&) = delete; + CbmTimesliceManager& operator=(const CbmTimesliceManager&) = delete; + + virtual void SetXMLConfig(TString xml_config) { fXMLConfig = xml_config; } + void SetDisplayCbmElectron(); + void SetDisplayCbmMuon(); + void SetDisplayMcbm(); + /** + * set detector's transparency + * @param use_xml use xml colors if available + * @param trans transparency for detector (if xml not used) + */ + virtual void SetTransparency(Bool_t use_xml, Int_t trans); + /** + * switch background color + * @param light use white if true + */ + virtual void SwitchBackground(Bool_t /*light*/); + + virtual void Init(Int_t visopt = 1, Int_t vislvl = 3, Int_t maxvisnds = 10000); + void AddTask(FairTask* t) { fRunAna->AddTask(t); } + + virtual void Open(); + void UpdateEditor(); + virtual void Close(); + virtual Int_t Color(Int_t pdg); + virtual void DisplaySettings(); // *MENU* + virtual void GotoTimeslice(uint32_t timeslice); // *MENU* + virtual void NextTimeslice(); // *MENU* + virtual void PrevTimeslice(); // *MENU* + virtual void GotoEvent(uint32_t event); // *MENU* + virtual void NextEvent(); // *MENU* + virtual void PrevEvent(); // *MENU* + + bool GetMcbmViewersMode() const { return fbMcbmViewersEna; } + virtual uint32_t GetCurrentTimeslice() const { return fTimesliceIdx; } + virtual Int_t GetCurrentEvent() const { return fEventIdx; } + double_t GetTimesliceTime(); ///< current time in ns to display in the event display. + double_t GetEventTime(); ///< current time in ns to display in the event display. + + virtual void SetTsTimeText(Double_t time); + virtual void SetTsNumberText(Int_t tsNumber); + virtual void SetEvtTimeText(Double_t time); + virtual void SetEvtNumberText(Int_t evtNumber); + + void SetClearHandler(Bool_t val) { fClearHandler = val; } ///< Used to indicate to subtask that they should reset + Bool_t GetClearHandler() const { return fClearHandler; } ///< Used to indicate to subtask that they should reset + + /** + * + * @param name name of file with screenshot + * @param proj 0 - 3D view, 1 - RPhi, 2 RhoZ, 3 - all + * @param def_path - default path to screenshot, if empty -user will be asked + */ + void MakeScreenshot(CbmTsEveAnimationControl::eScreenshotType screenshotType, TString def_path = ""); + +protected: + virtual void LoadXMLSettings(); + void LoadXMLDetector(TGeoNode* node, FairXMLNode* xml, Int_t depth = 0); + Int_t StringToColor(TString color) const; + +private: + static CbmTimesliceManager* gRinstanceTsMan; //! + + FairRunAna* fRunAna = nullptr; //! + FairRootManager* fRootManager = nullptr; //! + + TString fXMLConfig = ""; + std::map<int, int> fPDGToColor = {}; + void AddParticlesToPdgDataBase(); + void InitPdgColorMap(); + void SetTransparencyForLayer(TGeoNode* node, Int_t depth, Char_t transparency); + + Bool_t fClearHandler = kFALSE; //! + + TGListTreeItem* fEvent = nullptr; //! + Int_t fEntry = 0; //! + TClonesArray* fCbmEvents = nullptr; //! + uint32_t fTimesliceIdx = 0; //! + uint32_t fEventIdx = 0; //! + double_t fTimeTimeslice = -1; //! + double_t fTimeEvent = -1; //! + + TGLAnnotation* fTimesliceTimeText = nullptr; //! + TGLAnnotation* fTimesliceNumberText = nullptr; //! + TGLAnnotation* fEventTimeText = nullptr; //! + TGLAnnotation* fEventNumberText = nullptr; //! + + TGLViewer::ECameraType fRphiCam = TGLViewer::kCameraOrthoXOY; //! + TGLViewer::ECameraType fRhoCam = TGLViewer::kCameraOrthoZOY; //! + TGLViewer::ECameraType fCamZY = TGLViewer::kCameraOrthoZnOX; //! + TGLViewer::ECameraType fCamZX = TGLViewer::kCameraOrthoZOY; //! + + /// CBM views + TEveViewer* fRPhiView = nullptr; //! + TEveViewer* fRhoZView = nullptr; //! + TEveViewer* fMultiView = nullptr; //! + TEveViewer* fMultiRPhiView = nullptr; //! + TEveViewer* fMultiRhoZView = nullptr; //! + TEveScene* fRPhiScene = nullptr; //! + TEveScene* fRhoZScene = nullptr; //! + TEveProjectionManager* fRPhiProjManager = nullptr; //! + TEveProjectionManager* fRhoZProjManager = nullptr; //! + TEveProjectionAxes* fAxesPhi = nullptr; //! + TEveProjectionAxes* fAxesRho = nullptr; //! + + /// mCBM views + bool fbMcbmViewersEna = false; //! + TEveViewer* fViewZY = nullptr; //! + TEveViewer* fViewZX = nullptr; //! + TEveViewer* fMcbmView = nullptr; //! + TEveViewer* fMcbmViewZY = nullptr; //! + TEveViewer* fMcbmViewZX = nullptr; //! + TEveScene* fSceneZY = nullptr; //! + TEveScene* fSceneZX = nullptr; //! + TEveProjectionManager* fProjManagerZY = nullptr; //! + TEveProjectionManager* fProjManagerZX = nullptr; //! + TEveProjectionAxes* fAxesZY = nullptr; //! + TEveProjectionAxes* fAxesZX = nullptr; //! + + bool InitializeMainView(Int_t visopt, Int_t vislvl, Int_t maxvisnds); + void InitializeViewsCbm(); + void SetViewers(TEveViewer* RPhi, TEveViewer* RhoZ); + void InitializeViewsMcbm(); + void SetMcbmViewers(TEveViewer* ZY, TEveViewer* ZX); + + ClassDef(CbmTimesliceManager, 1); +}; + +#endif // CbmTimesliceManager_H diff --git a/core/eventdisplay/CbmTimesliceManagerEditor.cxx b/core/eventdisplay/CbmTimesliceManagerEditor.cxx new file mode 100644 index 0000000000..95d9aed56c --- /dev/null +++ b/core/eventdisplay/CbmTimesliceManagerEditor.cxx @@ -0,0 +1,464 @@ +/* Copyright (C) 2023 Facility for Antiproton and Ion Research in Europe, Darmstadt + SPDX-License-Identifier: GPL-3.0-only + Authors: Pierre-Alain Loizeau[committer] */ +/// Based on CbmTimesliceManagerEditor class of FairRoot v18.6.7 + +#include "CbmTimesliceManagerEditor.h" + +#include "CbmEvent.h" // For CbmEvent +#include "CbmTimesliceManager.h" // for CbmTimesliceManager +#include "CbmTsEveAnimationControl.h" // for CbmTsEveAnimationControl +#include "CbmTsEveTransparencyControl.h" // for CbmTsEveTransparencyControl + +#include "FairRootManager.h" // for FairRootManager +#include "FairRunAna.h" // for FairRunAna +#include "FairTask.h" // for FairTask + +#include <RtypesCore.h> // for Double_t, Int_t, UInt_t, Bool_t +#include <TChain.h> // for TChain +#include <TClonesArray.h> // for TClonesArray +#include <TEveManager.h> // for TEveManager, gEve +#include <TFile.h> // for TFile +#include <TGButton.h> // for TGTextButton, TGCheckButton +#include <TGComboBox.h> // for TGComboBox +#include <TGLabel.h> // for TGLabel +#include <TGLayout.h> // for TGLayoutHints, kLHintsExpandX +#include <TGNumberEntry.h> // for TGNumberEntry, TGNumberFormat +#include <TGenericClassInfo.h> // for TGenericClassInfo +#include <TGeoManager.h> // for TGeoManager, gGeoManager +#include <TList.h> // for TObjLink, TList +#include <TString.h> // for TString, Form +#include <TSystem.h> // for TSystem, gSystem + +#include <chrono> +#include <iostream> +#include <memory> // for unique_ptr +#include <thread> + +class TGWindow; // lines 36-36 +class TObject; // lines 37-37 + +#define MAXE 5000 + +// CbmTimesliceManagerEditor +// +// Specialization of TGedEditor for proper update propagation to TEveManager. + +CbmTimesliceManagerEditor::CbmTimesliceManagerEditor(const TGWindow* p, Int_t width, Int_t height, UInt_t options, + Pixel_t back) + : TGedFrame(p, width, height, options | kVerticalFrame, back) + , fObject(0) + , fManager(CbmTimesliceManager::Instance()) + , fCurrentEvent(0) + , fGlobalTransparency(nullptr) + , fEventTime(nullptr) + , fScreenshotOpt(nullptr) +{ + Init(); +} + +void CbmTimesliceManagerEditor::SwitchBackground(Bool_t light_background) +{ + fManager->SwitchBackground(light_background); +} + +void CbmTimesliceManagerEditor::Init() +{ + FairRootManager* rootManager = FairRootManager::Instance(); + TChain* chain = rootManager->GetInChain(); + fNbTs = chain->GetEntriesFast(); + + MakeTitle("CbmTimesliceManager Editor"); + TGVerticalFrame* fInfoFrame = CreateEditorTabSubFrame("Info TS"); + TGCompositeFrame* title1 = + new TGCompositeFrame(fInfoFrame, fWidth, 10, kVerticalFrame | kLHintsExpandX | kFixedWidth | kOwnBackground); + + TString Infile = "Input file : "; + TFile* file = FairRootManager::Instance()->GetInChain()->GetFile(); + Infile += file->GetName(); + TGLabel* TFName = new TGLabel(title1, Infile.Data()); + title1->AddFrame(TFName); + + Int_t nodes = gGeoManager->GetNNodes(); + TString NNodes = "No. of Nodes : "; + NNodes += nodes; + TGLabel* NoNode = new TGLabel(title1, NNodes.Data()); + title1->AddFrame(NoNode); + + UInt_t RunId = FairRunAna::Instance()->getRunId(); + TString run = "Run Id : "; + run += RunId; + TGLabel* TRunId = new TGLabel(title1, run.Data()); + title1->AddFrame(TRunId); + + TString ntimeslices = "No of timeslices : "; + ntimeslices += fNbTs; + TGLabel* TNbTimeslices = new TGLabel(title1, ntimeslices.Data()); + title1->AddFrame(TNbTimeslices); + + TGHorizontalFrame* fTsIdx = new TGHorizontalFrame(title1); + TGLabel* lTsIdx = new TGLabel(fTsIdx, "Current TS:"); + fTsIdx->AddFrame(lTsIdx, new TGLayoutHints(kLHintsLeft | kLHintsCenterY, 1, 2, 1, 1)); + fCurrentTimeslice = new TGNumberEntry(fTsIdx, 0., 6, -1, TGNumberFormat::kNESInteger, TGNumberFormat::kNEANonNegative, + TGNumberFormat::kNELLimitMinMax, 0, fNbTs); + fTsIdx->AddFrame(fCurrentTimeslice, new TGLayoutHints(kLHintsLeft, 1, 1, 1, 1)); + fCurrentTimeslice->Connect("ValueSet(Long_t)", "CbmTimesliceManagerEditor", this, "SelectSingleTimeslice()"); + title1->AddFrame(fTsIdx); + + TGHorizontalFrame* fTsTime = new TGHorizontalFrame(title1); + TGLabel* TsTimeLabel = new TGLabel(fTsTime, "TS Time: "); + fTimesliceTime = new TGLabel(fTsTime, ""); + fTsTime->AddFrame(TsTimeLabel); + fTsTime->AddFrame(fTimesliceTime); + title1->AddFrame(fTsTime); + + TString nevent = "No of events in TS : "; + nevent += (Int_t)(-1); + fEventNb = new TGLabel(title1, nevent.Data()); + title1->AddFrame(fEventNb); + + fSelTs = new TGTextButton(title1, "Select TS"); + fSelTs->Connect("Clicked()", "CbmTimesliceManagerEditor", this, "SelectSingleTimeslice()"); + title1->AddFrame(fSelTs, new TGLayoutHints(kLHintsRight | kLHintsExpandX, 5, 5, 1, 1)); + + fPrevTs = new TGTextButton(title1, "Prev TS"); + fPrevTs->Connect("Clicked()", "CbmTimesliceManagerEditor", this, "PrevTimeslice()"); + title1->AddFrame(fPrevTs, new TGLayoutHints(kLHintsRight | kLHintsExpandX, 5, 5, 1, 1)); + + fNextTs = new TGTextButton(title1, "Next TS"); + fNextTs->Connect("Clicked()", "CbmTimesliceManagerEditor", this, "NextTimeslice()"); + title1->AddFrame(fNextTs, new TGLayoutHints(kLHintsRight | kLHintsExpandX, 5, 5, 1, 1)); + + + TGHorizontalFrame* fEvtIdx = new TGHorizontalFrame(title1); + TGLabel* lEvtIdx = new TGLabel(fEvtIdx, "Current Event:"); + fEvtIdx->AddFrame(lEvtIdx, new TGLayoutHints(kLHintsLeft | kLHintsCenterY, 1, 2, 1, 1)); + fCurrentEvent = new TGNumberEntry(fEvtIdx, 0., 6, -1, TGNumberFormat::kNESInteger, TGNumberFormat::kNEANonNegative, + TGNumberFormat::kNELLimitMinMax, 0, -1); + fEvtIdx->AddFrame(fCurrentEvent, new TGLayoutHints(kLHintsLeft, 1, 1, 1, 1)); + fCurrentTimeslice->Connect("ValueSet(Long_t)", "CbmTimesliceManagerEditor", this, "SelectSingleTimeslice()"); + title1->AddFrame(fEvtIdx); + + + TGHorizontalFrame* fEvtTime = new TGHorizontalFrame(title1); + TGLabel* EventTimeLabel = new TGLabel(fEvtTime, "Event Time: "); + fEventTime = new TGLabel(fEvtTime, ""); + fEvtTime->AddFrame(EventTimeLabel); + fEvtTime->AddFrame(fEventTime); + title1->AddFrame(fEvtTime); + + fUpdateEvent = new TGTextButton(title1, "Update Event"); + fUpdateEvent->Connect("Clicked()", "CbmTimesliceManagerEditor", this, "SelectSingleEvent()"); + title1->AddFrame(fUpdateEvent, new TGLayoutHints(kLHintsRight | kLHintsExpandX, 5, 5, 1, 1)); + + fPrevEvent = new TGTextButton(title1, "Prev Event"); + fPrevEvent->Connect("Clicked()", "CbmTimesliceManagerEditor", this, "PrevEvent()"); + title1->AddFrame(fPrevEvent, new TGLayoutHints(kLHintsRight | kLHintsExpandX, 5, 5, 1, 1)); + + fNextEvent = new TGTextButton(title1, "Next Event"); + fNextEvent->Connect("Clicked()", "CbmTimesliceManagerEditor", this, "NextEvent()"); + title1->AddFrame(fNextEvent, new TGLayoutHints(kLHintsRight | kLHintsExpandX, 5, 5, 1, 1)); + + /// Disable all Prev/Next TS buttons until first TS loaded/selected! + fPrevTs->SetEnabled(kFALSE); + fNextTs->SetEnabled(kFALSE); + + /// Disable all Events buttons until first TS loaded/selected! + fUpdateEvent->SetEnabled(kFALSE); + fPrevEvent->SetEnabled(kFALSE); + fNextEvent->SetEnabled(kFALSE); + + + fInfoFrame->AddFrame(title1, new TGLayoutHints(kLHintsTop, 0, 0, 2, 0)); + + //=============== graphics ============================= + TGVerticalFrame* scene_conf = CreateEditorTabSubFrame("Graphics"); + // TGHorizontalFrame* transparency_frame = new TGHorizontalFrame(scene_conf); /// PAL: Unused in FairRoot original?!? + + std::unique_ptr<CbmTsEveTransparencyControl> transparency( + new CbmTsEveTransparencyControl(scene_conf, "Global transparency")); + scene_conf->AddFrame(transparency.release(), new TGLayoutHints(kLHintsNormal, 5, 5, 1, 1)); + + TGCheckButton* backgroundButton = new TGCheckButton(scene_conf, "Light background"); + scene_conf->AddFrame(backgroundButton, new TGLayoutHints(kLHintsRight | kLHintsExpandX, 5, 5, 1, 1)); + backgroundButton->Connect("Toggled(Bool_t)", this->ClassName(), this, "SwitchBackground(Bool_t)"); + + TGGroupFrame* frame_screenshot = new TGGroupFrame(scene_conf, "Screenshot"); + frame_screenshot->SetTitlePos(TGGroupFrame::kCenter); + + frame_screenshot->SetLayoutManager(new TGHorizontalLayout(frame_screenshot)); + + TGTextButton* Screen = new TGTextButton(frame_screenshot, "Make"); + frame_screenshot->AddFrame(Screen, new TGLayoutHints(kLHintsLeft | kLHintsExpandX, 20, 2, 2, 2)); + Screen->Connect("Clicked()", this->ClassName(), this, "MakeScreenshot()"); + + fScreenshotOpt = new TGComboBox(frame_screenshot); + fScreenshotOpt->AddEntry("3D", CbmTsEveAnimationControl::eScreenshotType::k3D); + if (CbmTimesliceManager::Instance()->GetMcbmViewersMode()) { + fScreenshotOpt->AddEntry("ZX", CbmTsEveAnimationControl::eScreenshotType::kZX); + fScreenshotOpt->AddEntry("ZY", CbmTsEveAnimationControl::eScreenshotType::kZY); + } + else { + fScreenshotOpt->AddEntry("RPhi", CbmTsEveAnimationControl::eScreenshotType::kXY); + fScreenshotOpt->AddEntry("RhoZ", CbmTsEveAnimationControl::eScreenshotType::kZ); + } + fScreenshotOpt->AddEntry("All", CbmTsEveAnimationControl::eScreenshotType::kAll); + fScreenshotOpt->Select(0); + fScreenshotOpt->Resize(40, 30); + frame_screenshot->AddFrame(fScreenshotOpt, new TGLayoutHints(kLHintsRight | kLHintsExpandX)); + scene_conf->AddFrame(frame_screenshot, new TGLayoutHints(kLHintsTop | kLHintsExpandX, 1, 1, 2, 1)); + + fAnimation = new CbmTsEveAnimationControl(this, scene_conf, "StartAnimation()", "Animation", fWidth); + fAnimation->SetTsNb(fNbTs); + fAnimation->SetDisplayMcbm(CbmTimesliceManager::Instance()->GetMcbmViewersMode()); + fAnimation->Init(); + + // TODO: fine-tune the position of the elements in the GUI tab + // scene_conf->AddFrame(online_screenshot,new TGLayoutHints(kLHintsRight|kLHintsExpandX)); + + + fCbmEvents = dynamic_cast<TClonesArray*>(rootManager->GetObject("CbmEvent")); + + if (nullptr == fCbmEvents) { + LOG(fatal) << "CbmTimesliceManager::Init() => CbmEvents branch not found! Task will be deactivated"; + } +} + +void CbmTimesliceManagerEditor::SelectSingleTimeslice() +{ + fManager->SetClearHandler(kTRUE); + SelectTimeslice(); +} + +void CbmTimesliceManagerEditor::SelectTimeslice() +{ + fManager->GotoTimeslice(fCurrentTimeslice->GetIntNumber()); + SetTimesliceTimeLabel(CbmTimesliceManager::Instance()->GetTimesliceTime()); + CbmTimesliceManager::Instance()->SetTsTimeText(CbmTimesliceManager::Instance()->GetTimesliceTime()); + CbmTimesliceManager::Instance()->SetTsNumberText(fCurrentTimeslice->GetIntNumber()); + + /// Enable/Disable buttons to avoid invalid accesses + fPrevTs->SetEnabled((0 < fCurrentTimeslice->GetIntNumber()) ? kTRUE : kFALSE); + fNextTs->SetEnabled((fCurrentTimeslice->GetIntNumber() < (fNbTs - 1)) ? kTRUE : kFALSE); + + fNbEventsInTs = fCbmEvents->GetEntriesFast(); + + TString nevent = "No of events in TS : "; + nevent += fNbEventsInTs; + fEventNb->ChangeText(nevent.Data()); + fCurrentEvent->SetLimitValues(0, fNbEventsInTs); + fCurrentEvent->SetIntNumber(0); + fAnimation->SetEvtNb(fNbEventsInTs); + + /// Enable/Disable buttons to avoid invalid accesses + if (0 < fNbEventsInTs) { + fUpdateEvent->SetEnabled(kTRUE); + fPrevEvent->SetEnabled(kFALSE); + if (1 < fNbEventsInTs) { // + fNextEvent->SetEnabled(kTRUE); + } + } + else { + fUpdateEvent->SetEnabled(kFALSE); + fPrevEvent->SetEnabled(kFALSE); + fNextEvent->SetEnabled(kFALSE); + } + + /// Load first event of this TS if possible and Update info text + if (0 < fNbEventsInTs) { // + SelectEvent(); + } +} + +void CbmTimesliceManagerEditor::PrevTimeslice() +{ + LOG(debug1) << "CbmTimesliceManager::PrevTimeslice() => At timeslice " << fCurrentTimeslice->GetIntNumber(); + uint32_t uTsIdx = fCurrentTimeslice->GetIntNumber(); + if (0 < uTsIdx) { // Should be protected by button enabling/disabling, but better safe than sorry + uTsIdx -= 1; + fCurrentTimeslice->SetIntNumber(uTsIdx); + LOG(debug1) << "CbmTimesliceManager::PrevTimeslice() => Setting timeslice to " << uTsIdx << " result " + << fCurrentTimeslice->GetIntNumber(); + + SelectSingleTimeslice(); + } +} + +void CbmTimesliceManagerEditor::NextTimeslice() +{ + LOG(debug1) << "CbmTimesliceManager::NextTimeslice() => At timeslice " << fCurrentTimeslice->GetIntNumber(); + uint32_t uTsIdx = fCurrentTimeslice->GetIntNumber(); + if (uTsIdx < fNbTs - 1) { // Should be protected by button enabling/disabling, but better safe than sorry + uTsIdx += 1; + fCurrentTimeslice->SetIntNumber(uTsIdx); + LOG(debug1) << "CbmTimesliceManager::NextTimeslice() => Setting timeslice to " << uTsIdx << " result " + << fCurrentTimeslice->GetIntNumber(); + + SelectSingleTimeslice(); + } +} + +void CbmTimesliceManagerEditor::SelectSingleEvent() +{ + fManager->SetClearHandler(kTRUE); + SelectEvent(); +} + +void CbmTimesliceManagerEditor::SelectEvent() +{ + LOG(debug1) << "CbmTimesliceManager::SelectEvent() => Going to event " << fCurrentEvent->GetIntNumber(); + fManager->GotoEvent(fCurrentEvent->GetIntNumber()); + SetEventTimeLabel(CbmTimesliceManager::Instance()->GetEventTime()); + CbmTimesliceManager::Instance()->SetEvtTimeText(CbmTimesliceManager::Instance()->GetEventTime()); + CbmTimesliceManager::Instance()->SetEvtNumberText(fCurrentEvent->GetIntNumber()); + + // Enable/Disable buttons to avoid invalid accesses + fPrevEvent->SetEnabled((0 < fCurrentEvent->GetIntNumber()) ? kTRUE : kFALSE); + fNextEvent->SetEnabled((fCurrentEvent->GetIntNumber() < (fNbEventsInTs - 1)) ? kTRUE : kFALSE); +} + +void CbmTimesliceManagerEditor::PrevEvent() +{ + LOG(debug1) << "CbmTimesliceManager::PrevEvent() => At event " << fCurrentEvent->GetIntNumber(); + uint32_t uEventIdx = fCurrentEvent->GetIntNumber(); + if (0 < uEventIdx) { // Should be protected by button enabling/disabling, but better safe than sorry + uEventIdx -= 1; + fCurrentEvent->SetIntNumber(uEventIdx); + LOG(debug1) << "CbmTimesliceManager::PrevEvent() => Setting event to " << uEventIdx << " result " + << fCurrentEvent->GetIntNumber(); + + SelectSingleEvent(); + } +} + +void CbmTimesliceManagerEditor::NextEvent() +{ + LOG(debug1) << "CbmTimesliceManager::NextEvent() => At event " << fCurrentEvent->GetIntNumber(); + uint32_t uEventIdx = fCurrentEvent->GetIntNumber(); + if (uEventIdx < fNbEventsInTs - 1) { // Should be protected by button enabling/disabling, but better safe than sorry + uEventIdx += 1; + fCurrentEvent->SetIntNumber(uEventIdx); + LOG(debug1) << "CbmTimesliceManager::NextEvent() => Setting event to " << uEventIdx << " result " + << fCurrentEvent->GetIntNumber(); + + SelectSingleEvent(); + } +} + +void CbmTimesliceManagerEditor::SetTimesliceTimeLabel(Double_t time) +{ + TString stime; + stime.Form("%.2f", time); + stime += " ns"; + fTimesliceTime->SetText(stime.Data()); + Update(); +} +void CbmTimesliceManagerEditor::SetEventTimeLabel(Double_t time) +{ + TString stime; + stime.Form("%.2f", time); + stime += " ns"; + fEventTime->SetText(stime.Data()); + Update(); +} + +void CbmTimesliceManagerEditor::SetModel(TObject* obj) { fObject = obj; } + +void CbmTimesliceManagerEditor::StartAnimation() +{ + CbmTsEveAnimationControl::eScreenshotType screen = fAnimation->GetScreenshotType(); + + std::chrono::duration<double> secSleepTime(fAnimation->GetAnimFrameSec()); + bool bSleep = (0.0 < fAnimation->GetAnimFrameSec()); + + switch (fAnimation->GetAnimationType()) { + case CbmTsEveAnimationControl::eAnimationType::kEventsInTs: { // Events in selected timeslice + /// Get minimum and maximum event indices, ensured to fit range in TS by buttons updates + uint32_t iEvtMin = static_cast<uint32_t>(fAnimation->GetEventMin()); + uint32_t iEvtMax = static_cast<uint32_t>(fAnimation->GetEventMax()); + uint32_t iEvtStep = static_cast<uint32_t>(fAnimation->GetEventStep()); + + if (fAnimation->GetScreenshotEna()) { // + gSystem->mkdir("event_animations"); + } + for (uint32_t iEvt = iEvtMin; iEvt < iEvtMax; iEvt += iEvtStep) { + fCurrentEvent->SetIntNumber(iEvt); + + if ((iEvtMin == iEvt && kTRUE == fAnimation->GetClearBuffer()) || kFALSE == fAnimation->GetRunContinuous()) { + /// Clear display at startup if requested (should be default for most uses) + /// Clear display after each event if requested (should be default for most uses) + fManager->SetClearHandler(kTRUE); + } + else { + /// Do not clear display between events = accumulate/stack them + fManager->SetClearHandler(kFALSE); + } + + SelectEvent(); + gEve->FullRedraw3D(); + if (fAnimation->GetScreenshotEna()) { // + fManager->MakeScreenshot(screen, Form("event_animations/event_%05i.png", iEvt)); + } + if (bSleep) { + // sleep between events to be able to see them + std::this_thread::sleep_for(secSleepTime); + } + } + break; + } + case CbmTsEveAnimationControl::eAnimationType::kTimeSlices: { // Events in timeslice range + /// Get minimum and maximum TS indices, ensured to fit range in run by buttons updates + uint32_t iTsMin = static_cast<uint32_t>(fAnimation->GetTsMin()); + uint32_t iTsMax = static_cast<uint32_t>(fAnimation->GetTsMax()); + uint32_t iTsStep = static_cast<uint32_t>(fAnimation->GetTsStep()); + + /// Get only event step, min and max set to content of each TS + uint32_t iEvtStep = static_cast<int32_t>(fAnimation->GetEventStep()); + + if (fAnimation->GetScreenshotEna()) { // + gSystem->mkdir("timeslice_animations"); + } + for (uint32_t iTs = iTsMin; iTs < iTsMax; iTs += iTsStep) { + fCurrentTimeslice->SetIntNumber(iTs); + + if (iTsMin == iTs && kTRUE == fAnimation->GetClearBuffer()) { + /// Clear display at startup if requested (should be default for most uses) + fManager->SetClearHandler(kTRUE); + } + + SelectTimeslice(); /// <= This should update all events limits to appropriate values + for (uint32_t iEvt = 0; iEvt < fNbEventsInTs; iEvt += iEvtStep) { + fCurrentEvent->SetIntNumber(iEvt); + + if (kFALSE == fAnimation->GetRunContinuous()) { + /// Clear display after each event if requested (should be default for most uses) + fManager->SetClearHandler(kTRUE); + } + else { + /// Do not clear display between events = accumulate/stack them + fManager->SetClearHandler(kFALSE); + } + + SelectEvent(); + gEve->FullRedraw3D(); + if (fAnimation->GetScreenshotEna()) { // + fManager->MakeScreenshot(screen, Form("timeslice_animations/ts_%05i_event_%05i.png", iTs, iEvt)); + } + if (bSleep) { + // sleep between events to be able to see them + std::this_thread::sleep_for(secSleepTime); + } + } // Event loop + } // TS loop + break; + } + } + LOG(info) << "CbmTimesliceManager::StartAnimation() => Done with animation"; +} + +void CbmTimesliceManagerEditor::MakeScreenshot() +{ + fManager->MakeScreenshot(static_cast<CbmTsEveAnimationControl::eScreenshotType>(fScreenshotOpt->GetSelected())); +} + +ClassImp(CbmTimesliceManagerEditor) diff --git a/core/eventdisplay/CbmTimesliceManagerEditor.h b/core/eventdisplay/CbmTimesliceManagerEditor.h new file mode 100644 index 0000000000..61098e9f21 --- /dev/null +++ b/core/eventdisplay/CbmTimesliceManagerEditor.h @@ -0,0 +1,92 @@ +/* Copyright (C) 2023 Facility for Antiproton and Ion Research in Europe, Darmstadt + SPDX-License-Identifier: GPL-3.0-only + Authors: Pierre-Alain Loizeau[committer] */ +/// Based on CbmTimesliceManagerEditor class of FairRoot v18.6.7 + +#ifndef CbmTimesliceManagerEditor_H +#define CbmTimesliceManagerEditor_H + +#include <Rtypes.h> // for THashConsistencyHolder, ClassDef +#include <RtypesCore.h> // for Int_t, Bool_t, Double_t, UInt_t +#include <TGFrame.h> // for kChildFrame +#include <TGedFrame.h> // for TGedFrame + +#include <GuiTypes.h> // for Pixel_t + +class CbmTimesliceManager; +class CbmTsEveAnimationControl; +class TBuffer; +class TClass; +class TClonesArray; +class TGComboBox; +class TGLabel; +class TGNumberEntry; +class TGWindow; +class TMemberInspector; +class TObject; + +class CbmTimesliceManagerEditor : public TGedFrame { +public: + CbmTimesliceManagerEditor(const TGWindow* p = 0, Int_t width = 250, Int_t height = 30, UInt_t options = kChildFrame, + Pixel_t back = GetDefaultFrameBackground()); + virtual ~CbmTimesliceManagerEditor() = default; + + CbmTimesliceManagerEditor(const CbmTimesliceManagerEditor&) = delete; + CbmTimesliceManagerEditor& operator=(const CbmTimesliceManagerEditor&) = delete; + + /** + * + * @param light_background true if use white background + */ + void SwitchBackground(Bool_t light_background); + + virtual void Init(); + + virtual void SelectSingleTimeslice(); + virtual void SelectTimeslice(); + virtual void PrevTimeslice(); + virtual void NextTimeslice(); + virtual void SelectSingleEvent(); + virtual void SelectEvent(); + virtual void PrevEvent(); + virtual void NextEvent(); + + void SetModel(TObject* obj); + virtual void StartAnimation(); + + /** + * make screenshot + */ + void MakeScreenshot(); + +protected: + TObject* fObject = nullptr; //! + CbmTimesliceManager* fManager = nullptr; //! + TGNumberEntry* fCurrentTimeslice = nullptr; //! + TGNumberEntry* fCurrentEvent = nullptr; //! + TGNumberEntry* fGlobalTransparency = nullptr; //! + TGLabel* fTimesliceTime = nullptr; //! + TGTextButton* fSelTs = nullptr; //! + TGTextButton* fPrevTs = nullptr; //! + TGTextButton* fNextTs = nullptr; //! + TGLabel* fEventNb = nullptr; //! + TGLabel* fEventTime = nullptr; //! + TGTextButton* fUpdateEvent = nullptr; //! + TGTextButton* fPrevEvent = nullptr; //! + TGTextButton* fNextEvent = nullptr; //! + + TGComboBox* fScreenshotOpt = nullptr; //! + CbmTsEveAnimationControl* fAnimation = nullptr; //! + + uint32_t fNbTs = 0; + TClonesArray* fCbmEvents = nullptr; //! + uint32_t fNbEventsInTs = 0; + + void SetTimesliceTimeLabel(Double_t time); + void SetEventTimeLabel(Double_t time); + +private: + ClassDef(CbmTimesliceManagerEditor, 1); +}; + +#endif // CbmTimesliceManagerEditor_H diff --git a/core/eventdisplay/CbmTimeslicePixelHitSetDraw.cxx b/core/eventdisplay/CbmTimeslicePixelHitSetDraw.cxx new file mode 100644 index 0000000000..ef16878450 --- /dev/null +++ b/core/eventdisplay/CbmTimeslicePixelHitSetDraw.cxx @@ -0,0 +1,157 @@ +/* Copyright (C) 2009-2020 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt + SPDX-License-Identifier: GPL-3.0-only + Authors: Florian Uhlig [committer] */ + +#include "CbmTimeslicePixelHitSetDraw.h" + +#include "CbmEvent.h" // for CbmEvent +#include "CbmPixelHit.h" // for CbmPixelHit +#include "CbmTimesliceManager.h" // for CbmTimesliceManager + +#include "FairDataSourceI.h" // for FairDataSourceI +#include "FairTCASource.h" // for FairTCASource +#include <Logger.h> // for LOG, Logger + +#include <Rtypes.h> // for ClassImp +#include <TClonesArray.h> // for TClonesArray +#include <TEveManager.h> // for TEveManager, gEve +#include <TEvePointSet.h> // for TEvePointSet +#include <TEveTreeTools.h> // for TEvePointSelectorConsumer, etc +#include <TVector3.h> // for TVector3 + +CbmTimeslicePixelHitSetDraw::CbmTimeslicePixelHitSetDraw(const char* name, Color_t color, Style_t mstyle, + Int_t iVerbose) + : FairPointSetDraw(name, color, mstyle, iVerbose) +{ + /// Trick to get access to the data source pointer even if private in the base class + /// TODO: switch from legacy constructor to standard constructor of the base class? + /// or break inheritance and make this one standalone by copying the remaining parts of base class? + fLocalDataSourcePtr = new FairTCASource(GetName()); + SetDataSource(fLocalDataSourcePtr); +} + +InitStatus CbmTimeslicePixelHitSetDraw::Init() +{ + LOG(debug) << "CbmTimeslicePixelHitSetDraw::Init()"; + + /// Default initialization on base class + FairPointSetDraw::Init(); + + /// CBM timeslice specific: get array of CbmEvents + FairRootManager* fManager = FairRootManager::Instance(); + fCbmEvents = dynamic_cast<TClonesArray*>(fManager->GetObject("CbmEvent")); + if (nullptr == fCbmEvents) { + LOG(fatal) << "CbmTimeslicePixelHitSetDraw::Init() => CbmEvents branch not found! Task will be deactivated"; + SetActive(kFALSE); + } + + /// Find the data type enum based on the name provided to constructor + /// FIXME: find alternative to hard-coded if block... maybe reverse logic with constructor getting name from enum? + std::string sName = GetName(); // Needed for comparisoon with string literal + if ("MvdHit" == sName) { // + fDataType = ECbmDataType::kMvdHit; + } + else if ("StsHit" == sName) { // + fDataType = ECbmDataType::kStsHit; + } + else if ("RichHit" == sName) { // + fDataType = ECbmDataType::kRichHit; + } + else if ("MuchHit" == sName) { // + fDataType = ECbmDataType::kMuchPixelHit; + } + else if ("TrdHit" == sName) { // + fDataType = ECbmDataType::kTrdHit; + } + else if ("TofHit" == sName) { // + fDataType = ECbmDataType::kTofHit; + } + else if ("PsdHit" == sName) { // + fDataType = ECbmDataType::kPsdHit; + } + else if ("T0Hit" == sName) { // + fDataType = ECbmDataType::kT0Hit; + } + else { + fDataType = ECbmDataType::kUnknown; + } + + if (IsActive()) { return kSUCCESS; } + else { + return kERROR; + } +} + +void CbmTimeslicePixelHitSetDraw::Exec(Option_t* /*option*/) +{ + fLocalDataSourcePtr->Reset(); + fLocalDataSourcePtr->RetrieveData(CbmTimesliceManager::Instance()->GetTimesliceTime()); + + if (0 < fCbmEvents->GetEntriesFast()) { + /// When loading a new TS, load the first event if possible + GotoEvent(0); + } +} + +void CbmTimeslicePixelHitSetDraw::GotoEvent(uint32_t uEventIdx) +{ + LOG(debug) << "CbmTimeslicePixelHitSetDraw::GotoEvent " << uEventIdx << " target " << GetName(); + + if (fCbmEvents->GetEntriesFast() <= static_cast<Int_t>(uEventIdx)) { + LOG(fatal) << "CbmTimeslicePixelHitSetDraw::GotoEvent() => Failure, tried to load event " << uEventIdx + << " while only " << fCbmEvents->GetEntriesFast() << " events available in this TS!!!"; + } + + fEventIdx = uEventIdx; + + CbmEvent* event = dynamic_cast<CbmEvent*>(fCbmEvents->At(uEventIdx)); + + int32_t iNbHitsInTs = fLocalDataSourcePtr->GetNData(); + int32_t iNbHitsInEvent = event->GetNofData(fDataType); + + if (iNbHitsInTs < iNbHitsInEvent) { + LOG(fatal) << "CbmTimeslicePixelHitSetDraw::GotoEvent() => Failure, more " << GetName() << " in event " << uEventIdx + << " than available in the TS: " << iNbHitsInEvent << " VS " << iNbHitsInTs; + } + + if (CbmTimesliceManager::Instance()->GetClearHandler()) { // + Reset(); + } + + TEvePointSet* q = new TEvePointSet(GetName(), iNbHitsInEvent, TEvePointSelectorConsumer::kTVT_XYZ); + q->SetOwnIds(kTRUE); + q->SetMarkerColor(fColor); + q->SetMarkerSize(1.5); + q->SetMarkerStyle(fStyle); + + for (int32_t iHitIdxInEvt = 0; iHitIdxInEvt < iNbHitsInEvent; ++iHitIdxInEvt) { + TVector3 vec(GetVector(fLocalDataSourcePtr->GetData(event->GetIndex(fDataType, iHitIdxInEvt)))); + q->SetNextPoint(vec.X(), vec.Y(), vec.Z()); + // q->SetPointId(GetValue(p, i)); + } + gEve->AddElement(q); + gEve->Redraw3D(kFALSE); + fq = q; +} + +void CbmTimeslicePixelHitSetDraw::Reset() +{ + if (fq != 0) { + fq->Reset(); + gEve->RemoveElement(fq, CbmTimesliceManager::Instance()); + } +} + + +TVector3 CbmTimeslicePixelHitSetDraw::GetVector(TObject* obj) +{ + CbmPixelHit* p = dynamic_cast<CbmPixelHit*>(obj); + if (nullptr == p) { + LOG(fatal) << "CbmTimesliceRecoTracks::GetVector() => Failure, object not derived from CbmPixelHit"; + } + LOG(debug) << "-I- CbmTimeslicePixelHitSetDraw::GetVector: " << p->GetX() << " " << p->GetY() << " " << p->GetZ(); + return TVector3(p->GetX(), p->GetY(), p->GetZ()); +} + + +ClassImp(CbmTimeslicePixelHitSetDraw) diff --git a/core/eventdisplay/CbmTimeslicePixelHitSetDraw.h b/core/eventdisplay/CbmTimeslicePixelHitSetDraw.h new file mode 100644 index 0000000000..2fc7ef7cd1 --- /dev/null +++ b/core/eventdisplay/CbmTimeslicePixelHitSetDraw.h @@ -0,0 +1,42 @@ +/* Copyright (C) 2023 Facility for Antiproton and Ion Research in Europe, Darmstadt + SPDX-License-Identifier: GPL-3.0-only + Authors: Pierre-Alain Loizeau[committer] */ + +#ifndef CbmTimeslicePixelHitSetDraw_H_ +#define CbmTimeslicePixelHitSetDraw_H_ + +#include <CbmDefs.h> // For ECbmDataType + +#include <FairPointSetDraw.h> // for FairPointSetDraw + +#include <Rtypes.h> // for THashConsistencyHolder, ClassDef +#include <RtypesCore.h> // for Color_t, Int_t, Style_t + +class TClonesArray; +class TObject; +class TVector3; + +class CbmTimeslicePixelHitSetDraw : public FairPointSetDraw { +public: + CbmTimeslicePixelHitSetDraw(const char* name, Color_t color, Style_t mstyle, Int_t iVerbose = 1); + virtual ~CbmTimeslicePixelHitSetDraw() = default; + + virtual InitStatus Init(); + virtual void Exec(Option_t* option); + void Reset(); + + void GotoEvent(uint32_t uEventIdx); + +protected: + TVector3 GetVector(TObject* obj); + +private: + FairDataSourceI* fLocalDataSourcePtr = nullptr; //! + TClonesArray* fCbmEvents = nullptr; //! + ECbmDataType fDataType = ECbmDataType::kUnknown; //! + uint32_t fEventIdx = 0; //! + + ClassDef(CbmTimeslicePixelHitSetDraw, 1); +}; + +#endif /* CbmTimeslicePixelHitSetDraw_H_ */ diff --git a/core/eventdisplay/CbmTimesliceRecoTracks.cxx b/core/eventdisplay/CbmTimesliceRecoTracks.cxx new file mode 100644 index 0000000000..b8ad83f856 --- /dev/null +++ b/core/eventdisplay/CbmTimesliceRecoTracks.cxx @@ -0,0 +1,250 @@ +/* Copyright (C) 2023 Facility for Antiproton and Ion Research in Europe, Darmstadt + SPDX-License-Identifier: GPL-3.0-only + Authors: Pierre-Alain Loizeau[committer] */ +#include "CbmTimesliceRecoTracks.h" + +#include "CbmEvent.h" // For CbmEvent +#include "CbmGlobalTrack.h" // for CbmGlobalTrack +#include "CbmHit.h" // for HitType, kMUCHPIXELHIT, kRICHHIT +#include "CbmPixelHit.h" // for CbmPixelHit +#include "CbmRichRing.h" // for CbmRichRing +#include "CbmStsTrack.h" // for CbmStsTrack +#include "CbmTrack.h" // for CbmTrack +#include <CbmTimesliceManager.h> // for CbmTimesliceManager + +#include <FairRootManager.h> // for FairRootManager +#include <FairTask.h> // for FairTask, InitStatus, kERROR, kSUCCESS +#include <FairTrackParam.h> // for FairTrackParam +#include <Logger.h> // for LOG, Logger + +#include <Rtypes.h> // for ClassImp +#include <TClonesArray.h> // for TClonesArray +#include <TEveManager.h> // for TEveManager, gEve +#include <TEvePathMark.h> // for TEvePathMark +#include <TEveTrack.h> // for TEveTrackList, TEveTrack +#include <TEveTrackPropagator.h> // for TEveTrackPropagator +#include <TEveVector.h> // for TEveVector, TEveVectorT +#include <TGenericClassInfo.h> // for TGenericClassInfo +#include <TParticle.h> // for TParticle +#include <TString.h> // for TString +#include <TVector3.h> // for TVector3 + +#include <stdio.h> // for sprintf +#include <string.h> // for strcmp + +// ------------------------------------------------------------------------- +InitStatus CbmTimesliceRecoTracks::Init() +{ + LOG(debug) << "CbmTimesliceRecoTracks::Init()"; + FairRootManager* fManager = FairRootManager::Instance(); + + fCbmEvents = dynamic_cast<TClonesArray*>(fManager->GetObject("CbmEvent")); + fGlobalTracks = dynamic_cast<TClonesArray*>(fManager->GetObject("GlobalTrack")); + fStsTracks = dynamic_cast<TClonesArray*>(fManager->GetObject("StsTrack")); + fMvdHits = dynamic_cast<TClonesArray*>(fManager->GetObject("MvdHit")); + fStsHits = dynamic_cast<TClonesArray*>(fManager->GetObject("StsHit")); + fRichRings = dynamic_cast<TClonesArray*>(fManager->GetObject("RichRing")); + fRichHits = dynamic_cast<TClonesArray*>(fManager->GetObject("RichHit")); + fMuchPixelHits = dynamic_cast<TClonesArray*>(fManager->GetObject("MuchPixelHit")); + fMuchTracks = dynamic_cast<TClonesArray*>(fManager->GetObject("MuchTrack")); + fTrdHits = dynamic_cast<TClonesArray*>(fManager->GetObject("TrdHit")); + fTrdTracks = dynamic_cast<TClonesArray*>(fManager->GetObject("TrdTrack")); + fTofHits = dynamic_cast<TClonesArray*>(fManager->GetObject("TofHit")); + fTofTracks = dynamic_cast<TClonesArray*>(fManager->GetObject("TofTrack")); + + if (nullptr == fCbmEvents) { + LOG(fatal) << "CbmTimesliceRecoTracks::Init() => CbmEvents branch not found! Task will be deactivated"; + SetActive(kFALSE); + } + + LOG(debug1) << "CbmTimesliceRecoTracks::Init() get track list" << fStsTracks; + LOG(debug1) << "CbmTimesliceRecoTracks::Init() create propagator"; + fEventManager = CbmTimesliceManager::Instance(); + LOG(debug1) << "CbmTimesliceRecoTracks::Init() got instance of CbmTimesliceManager "; + + if (IsActive()) { return kSUCCESS; } + else { + return kERROR; + } +} + +void CbmTimesliceRecoTracks::HandlePixelHit(TEveTrack* eveTrack, Int_t& n, const CbmPixelHit* hit, TEveVector* pMom = 0) +{ + eveTrack->SetPoint(n, hit->GetX(), hit->GetY(), hit->GetZ()); + TEveVector pos = TEveVector(hit->GetX(), hit->GetY(), hit->GetZ()); + TEvePathMark path; + path.fV = pos; + path.fTime = 0; + + if (pMom) path.fP = *pMom; + + eveTrack->AddPathMark(path); + ++n; +} + +void CbmTimesliceRecoTracks::HandleTrack(TEveTrack* eveTrack, Int_t& n, const CbmTrack* recoTrack) +{ + Int_t nofHits = recoTrack->GetNofHits(); + + for (Int_t i = 0; i < nofHits; ++i) { + HitType hitType = recoTrack->GetHitType(i); + Int_t hitIndex = recoTrack->GetHitIndex(i); + const CbmPixelHit* pixelHit = 0; + + switch (hitType) { + case kRICHHIT: pixelHit = static_cast<const CbmPixelHit*>(fRichHits->At(hitIndex)); break; + + case kMUCHPIXELHIT: pixelHit = static_cast<const CbmPixelHit*>(fMuchPixelHits->At(hitIndex)); break; + + case kTRDHIT: pixelHit = static_cast<const CbmPixelHit*>(fTrdHits->At(hitIndex)); break; + + case kTOFHIT: pixelHit = static_cast<const CbmPixelHit*>(fTofHits->At(hitIndex)); break; + default: LOG(warn) << "Pixel type " << hitType << " not supported."; + } + + if (0 != pixelHit) HandlePixelHit(eveTrack, n, pixelHit); + } +} + +void CbmTimesliceRecoTracks::HandleStsTrack(TEveTrack* eveTrack, Int_t& n, const CbmStsTrack* stsTrack) +{ + for (Int_t i = 0; i < stsTrack->GetNofMvdHits(); ++i) { + const CbmPixelHit* hit = static_cast<const CbmPixelHit*>(fMvdHits->At(stsTrack->GetMvdHitIndex(i))); + + if (0 == n) { + TVector3 mom3; + stsTrack->GetParamFirst()->Momentum(mom3); + TEveVector mom = TEveVector(mom3.X(), mom3.Y(), mom3.Z()); + HandlePixelHit(eveTrack, n, hit, &mom); + } + else + HandlePixelHit(eveTrack, n, hit); + } + + for (Int_t i = 0; i < stsTrack->GetNofStsHits(); ++i) { + const CbmPixelHit* hit = static_cast<const CbmPixelHit*>(fStsHits->At(stsTrack->GetStsHitIndex(i))); + + if (0 == n) { + TVector3 mom3; + stsTrack->GetParamFirst()->Momentum(mom3); + TEveVector mom = TEveVector(mom3.X(), mom3.Y(), mom3.Z()); + HandlePixelHit(eveTrack, n, hit, &mom); + } + else + HandlePixelHit(eveTrack, n, hit); + } +} + +void CbmTimesliceRecoTracks::Exec(Option_t* /*option*/) +{ + if (0 < fCbmEvents->GetEntriesFast()) { + /// When loading a new TS, load the first event if possible + GotoEvent(0); + } +} +void CbmTimesliceRecoTracks::GotoEvent(uint32_t uEventIdx) +{ + LOG(debug3) << "CbmTimesliceRecoTracks::GotoEvent " << uEventIdx; + + if (fCbmEvents->GetEntriesFast() <= static_cast<Int_t>(uEventIdx)) { + LOG(fatal) << "CbmTimesliceRecoTracks::GotoEvent() => Failure, tried to load event " << uEventIdx << " while only " + << fCbmEvents->GetEntriesFast() << " events available in this TS!!!"; + } + + fEventIdx = uEventIdx; + + if (CbmTimesliceManager::Instance()->GetClearHandler()) { // + Reset(); + } + + CbmEvent* event = dynamic_cast<CbmEvent*>(fCbmEvents->At(uEventIdx)); + + Int_t nofGlobalTracks = event->GetNofData(ECbmDataType::kGlobalTrack); + + for (Int_t iGloTrk = 0; iGloTrk < nofGlobalTracks; ++iGloTrk) { + LOG(debug3) << "CbmTimesliceRecoTracks::GotoEvent " << iGloTrk; + Int_t trkId = event->GetIndex(ECbmDataType::kGlobalTrack, iGloTrk); + const CbmGlobalTrack* globalTrack = dynamic_cast<const CbmGlobalTrack*>(fGlobalTracks->At(trkId)); + Int_t stsId = globalTrack->GetStsTrackIndex(); + Int_t richId = globalTrack->GetRichRingIndex(); + Int_t muchId = globalTrack->GetMuchTrackIndex(); + Int_t trdId = globalTrack->GetTrdTrackIndex(); + Int_t tofId = globalTrack->GetTofTrackIndex(); + Int_t tofHitId = globalTrack->GetTofHitIndex(); + + if (0 > stsId) continue; + + const CbmStsTrack* stsTrack = dynamic_cast<const CbmStsTrack*>(fStsTracks->At(stsId)); + + if (0 == stsTrack) continue; + + Int_t pdg = stsTrack->GetPidHypo(); + TParticle P; + P.SetPdgCode(pdg); + fTrList = GetTrGroup(&P); + TEveTrack* eveTrack = new TEveTrack(&P, pdg, fTrPr); + eveTrack->SetLineColor(fEventManager->Color(pdg)); + Int_t n = 0; + HandleStsTrack(eveTrack, n, stsTrack); + + if (-1 < richId) { + const CbmRichRing* r = dynamic_cast<const CbmRichRing*>(fRichRings->At(richId)); + const CbmPixelHit* rh = dynamic_cast<const CbmPixelHit*>(fRichHits->At(r->GetHit(0))); + CbmPixelHit h(*rh); + h.SetX(r->GetCenterX()); + h.SetY(r->GetCenterY()); + HandlePixelHit(eveTrack, n, &h); + } + else if (-1 < muchId) { + HandleTrack(eveTrack, n, dynamic_cast<const CbmTrack*>(fMuchTracks->At(muchId))); + } + + if (-1 < trdId) HandleTrack(eveTrack, n, dynamic_cast<const CbmTrack*>(fTrdTracks->At(trdId))); + + if (-1 < tofId) HandleTrack(eveTrack, n, dynamic_cast<const CbmTrack*>(fTofTracks->At(tofId))); + else if (-1 < tofHitId) + HandlePixelHit(eveTrack, n, dynamic_cast<const CbmPixelHit*>(fTofHits->At(tofHitId))); + + /// Draw Markers of all hits participating in the track + eveTrack->SetRnrPoints(kTRUE); + + fTrList->AddElement(eveTrack); + LOG(debug3) << "track added " << eveTrack->GetName(); + } + + gEve->Redraw3D(kFALSE); +} +// ------------------------------------------------------------------------- +void CbmTimesliceRecoTracks::Reset() +{ + for (Int_t i = 0; i < fEveTrList->GetEntriesFast(); i++) { + TEveTrackList* ele = (TEveTrackList*) fEveTrList->At(i); + gEve->RemoveElement(ele, fEventManager); + } + fEveTrList->Clear(); +} + +TEveTrackList* CbmTimesliceRecoTracks::GetTrGroup(TParticle* P) +{ + char name_buf[128]; + sprintf(name_buf, "reco_%s", P->GetName()); + fTrList = 0; + for (Int_t i = 0; i < fEveTrList->GetEntriesFast(); i++) { + TEveTrackList* TrListIn = (TEveTrackList*) fEveTrList->At(i); + if (strcmp(TrListIn->GetName(), name_buf) == 0) { + fTrList = TrListIn; + break; + } + } + if (fTrList == 0) { + fTrPr = new TEveTrackPropagator(); + fTrList = new TEveTrackList(name_buf, fTrPr); + fTrList->SetMainColor(fEventManager->Color(P->GetPdgCode())); + fEveTrList->Add(fTrList); + gEve->AddElement(fTrList, fEventManager); + fTrList->SetRnrLine(kTRUE); + } + return fTrList; +} + +ClassImp(CbmTimesliceRecoTracks) diff --git a/core/eventdisplay/CbmTimesliceRecoTracks.h b/core/eventdisplay/CbmTimesliceRecoTracks.h new file mode 100644 index 0000000000..e92ba15c03 --- /dev/null +++ b/core/eventdisplay/CbmTimesliceRecoTracks.h @@ -0,0 +1,91 @@ +/* Copyright (C) 2023 Facility for Antiproton and Ion Research in Europe, Darmstadt + SPDX-License-Identifier: GPL-3.0-only + Authors: Pierre-Alain Loizeau[committer] */ + + +#ifndef CbmTimesliceRecoTracks_H +#define CbmTimesliceRecoTracks_H + +#include <FairTask.h> // for FairTask, InitStatus + +#include <Rtypes.h> // for THashConsistencyHolder, ClassDef +#include <RtypesCore.h> // for Int_t, Double_t, Option_t +#include <TEveVector.h> // for TEveVector +#include <TObjArray.h> // for TObjArray, needed for FairRoot > v18.8.0 +#include <TString.h> // for TString + +class CbmPixelHit; +class CbmStsTrack; +class CbmTrack; + +class TClonesArray; +class TEveTrack; +class TEveTrackList; +class TEveTrackPropagator; +class TObjArray; +class TParticle; + +#ifndef CbmTimesliceManager_H +class CbmTimesliceManager; +#endif // CbmTimesliceManager_H + +class CbmTimesliceRecoTracks : public FairTask { +public: + /** Default constructor **/ + CbmTimesliceRecoTracks() : CbmTimesliceRecoTracks("CbmTimesliceRecoTracks", 0) {} + + + /** Standard constructor + * @param name Name of task + * @param iVerbose Verbosity level + **/ + CbmTimesliceRecoTracks(const char* name, Int_t iVerbose = 1) : FairTask(name, iVerbose) {} + + /** Destructor **/ + virtual ~CbmTimesliceRecoTracks() = default; + + CbmTimesliceRecoTracks(const CbmTimesliceRecoTracks&) = delete; + CbmTimesliceRecoTracks& operator=(const CbmTimesliceRecoTracks&) = delete; + + /** Set verbosity level. For this task and all of the subtasks. **/ + void SetVerbose(Int_t iVerbose) { fVerbose = iVerbose; } + + virtual InitStatus Init(); + virtual void Exec(Option_t* option); + virtual void SetParContainers() { ; } + virtual void Finish() { ; } + + void GotoEvent(uint32_t uEventIdx); + void Reset(); + TEveTrackList* GetTrGroup(TParticle* P); + +protected: + void HandlePixelHit(TEveTrack* eveTrack, Int_t& n, const CbmPixelHit* hit, TEveVector* pMom); + void HandleTrack(TEveTrack* eveTrack, Int_t& n, const CbmTrack* recoTrack); + void HandleStsTrack(TEveTrack* eveTrack, Int_t& n, const CbmStsTrack* stsTrack); + + TClonesArray* fCbmEvents = nullptr; //! + TClonesArray* fGlobalTracks = nullptr; //! + TClonesArray* fMvdHits = nullptr; //! + TClonesArray* fStsHits = nullptr; //! + TClonesArray* fStsTracks = nullptr; //! + TClonesArray* fRichRings = nullptr; //! + TClonesArray* fRichHits = nullptr; //! + TClonesArray* fMuchPixelHits = nullptr; //! + TClonesArray* fMuchTracks = nullptr; //! + TClonesArray* fTrdHits = nullptr; //! + TClonesArray* fTrdTracks = nullptr; //! + TClonesArray* fTofHits = nullptr; //! + TClonesArray* fTofTracks = nullptr; //! + TEveTrackPropagator* fTrPr = nullptr; //! + CbmTimesliceManager* fEventManager = nullptr; //! + TObjArray* fEveTrList = new TObjArray(16); //! + uint32_t fEventIdx = 0; //! + TEveTrackList* fTrList = nullptr; //! + +private: + ClassDef(CbmTimesliceRecoTracks, 1); +}; + + +#endif // CbmTimesliceRecoTracks_H diff --git a/core/eventdisplay/CbmTsEveAnimationControl.cxx b/core/eventdisplay/CbmTsEveAnimationControl.cxx new file mode 100644 index 0000000000..3bdc030bb2 --- /dev/null +++ b/core/eventdisplay/CbmTsEveAnimationControl.cxx @@ -0,0 +1,264 @@ +/* Copyright (C) 2023 Facility for Antiproton and Ion Research in Europe, Darmstadt + SPDX-License-Identifier: GPL-3.0-only + Authors: Pierre-Alain Loizeau[committer] */ + +/* + * FairEveAnimationControl.cxx + * + * Created on: 26 maj 2020 + * Author: Daniel Wielanek + * E-mail: daniel.wielanek@gmail.com + * Warsaw University of Technology, Faculty of Physics + */ +/// PAL 01/06/2023: heavily based on FairEveAnimationControl from FairRoot v18.6.7, for usage with CbmTimesliceManager +#include "CbmTsEveAnimationControl.h" + +CbmTsEveAnimationControl::CbmTsEveAnimationControl(TGedFrame* frame, TGCompositeFrame* tab, TString functionName, + TString name, Int_t width) + : fWidth(width) + , fParent(frame) + , fFunctionName(functionName) + , fTab(tab) +{ + SetName(name); +} + +CbmTsEveAnimationControl::~CbmTsEveAnimationControl() {} + +void CbmTsEveAnimationControl::Init() +{ + TGGroupFrame* animCtrl = new TGGroupFrame(fTab, GetName()); + animCtrl->SetTitlePos(TGGroupFrame::kCenter); + + // -------------------------------- Start "holy" button -------------------------------------------------------------- + fStartButton = new TGTextButton(animCtrl, "Start"); + fStartButton->Resize(80, 25); + animCtrl->AddFrame(fStartButton, new TGLayoutHints(kLHintsLeft | kLHintsExpandX, 5, 5, 5, 5)); + fStartButton->Connect("Clicked()", fParent->ClassName(), fParent, fFunctionName); + fStartButton->SetEnabled(kFALSE); // Enabled only if TS number set to at least 1 + // ------------------------------------------------------------------------------------------------------------------- + + // -------------------------------- Animation type ------------------------------------------------------------------- + TGCompositeFrame* frAnimType = new TGCompositeFrame(animCtrl, fWidth, 30, kHorizontalFrame | kFixedWidth); + TGLabel* gAnimType = new TGLabel(frAnimType, "Animation type:"); + frAnimType->AddFrame(gAnimType, new TGLayoutHints(kLHintsLeft | kLHintsExpandX, 1, 1, 1, 1)); + fTypeOpt = new TGComboBox(frAnimType); + fTypeOpt->AddEntry("Evts in sel. TS", kEventsInTs); + fTypeOpt->AddEntry("Timeslices", kTimeSlices); + fTypeOpt->Select(kTimeSlices); + fTypeOpt->Resize(100, 20); + frAnimType->AddFrame(fTypeOpt, new TGLayoutHints(kLHintsLeft | kLHintsExpandX)); + animCtrl->AddFrame(frAnimType, new TGLayoutHints(kLHintsLeft | kLHintsExpandX)); + fTypeOpt->Connect("Selected (Int_t,Int_t)", this->ClassName(), this, "UpdateEnaDisButtons()"); + + TGCompositeFrame* frSelAnimFrameSec = new TGCompositeFrame(animCtrl, fWidth, 30, kHorizontalFrame | kFixedWidth); + TGLabel* gLabelFrameSec = new TGLabel(frSelAnimFrameSec, "Frame length (s):"); + frSelAnimFrameSec->AddFrame(gLabelFrameSec, new TGLayoutHints(kLHintsLeft | kLHintsExpandX, 1, 1, 2, 1)); + fAnimFrameSec = new TGNumberEntry(frSelAnimFrameSec, 5.0, 6, -1, TGNumberFormat::kNESReal, + TGNumberFormat::kNEANonNegative, TGNumberFormat::kNELLimitMin, 0); + fAnimFrameSec->SetNumber(5.0); + frSelAnimFrameSec->AddFrame(fAnimFrameSec, new TGLayoutHints(kLHintsRight | kLHintsExpandX)); + animCtrl->AddFrame(frSelAnimFrameSec, new TGLayoutHints(kLHintsLeft | kLHintsExpandX)); + // ------------------------------------------------------------------------------------------------------------------- + + // -------------------------------- Event stepping buttons ----------------------------------------------------------- + TGCompositeFrame* frSelEvtMin = new TGCompositeFrame(animCtrl, fWidth, 30, kHorizontalFrame | kFixedWidth); + TGLabel* gLabelEvtMin = new TGLabel(frSelEvtMin, "Min Evt:"); + frSelEvtMin->AddFrame(gLabelEvtMin, new TGLayoutHints(kLHintsLeft | kLHintsExpandX, 1, 1, 2, 1)); + fEvtMin = new TGNumberEntry(frSelEvtMin, 0, 6, -1, TGNumberFormat::kNESInteger, TGNumberFormat::kNEANonNegative, + TGNumberFormat::kNELLimitMinMax, 0, (fNbEvt ? fNbEvt - 1 : 0)); + fEvtMin->SetNumber(0); + frSelEvtMin->AddFrame(fEvtMin, new TGLayoutHints(kLHintsRight | kLHintsExpandX)); + animCtrl->AddFrame(frSelEvtMin, new TGLayoutHints(kLHintsLeft | kLHintsExpandX)); + + TGCompositeFrame* frSelEvtMax = new TGCompositeFrame(animCtrl, fWidth, 30, kHorizontalFrame | kFixedWidth); + TGLabel* gLabelEvtMax = new TGLabel(frSelEvtMax, "Max Evt:"); + frSelEvtMax->AddFrame(gLabelEvtMax, new TGLayoutHints(kLHintsLeft | kLHintsExpandX, 1, 1, 2, 1)); + fEvtMax = new TGNumberEntry(frSelEvtMax, 10, 6, -1, TGNumberFormat::kNESInteger, TGNumberFormat::kNEANonNegative, + TGNumberFormat::kNELLimitMinMax, 0, (fNbEvt ? fNbEvt - 1 : 0)); + fEvtMax->SetNumber((fNbEvt ? fNbEvt - 1 : 0)); + frSelEvtMax->AddFrame(fEvtMax, new TGLayoutHints(kLHintsRight | kLHintsExpandX)); + animCtrl->AddFrame(frSelEvtMax, new TGLayoutHints(kLHintsLeft | kLHintsExpandX)); + + TGCompositeFrame* frSelEvtStep = new TGCompositeFrame(animCtrl, fWidth, 30, kHorizontalFrame | kFixedWidth); + TGLabel* gLabelEvtStep = new TGLabel(frSelEvtStep, "Step Evt:"); + frSelEvtStep->AddFrame(gLabelEvtStep, new TGLayoutHints(kLHintsLeft | kLHintsExpandX, 1, 1, 2, 1)); + fEvtStep = new TGNumberEntry(frSelEvtStep, 0, 6, -1, TGNumberFormat::kNESInteger, TGNumberFormat::kNEAPositive, + TGNumberFormat::kNELLimitMinMax, 1, (fNbEvt ? fNbEvt - 1 : 1)); + fEvtStep->SetNumber(1); + frSelEvtStep->AddFrame(fEvtStep, new TGLayoutHints(kLHintsRight | kLHintsExpandX)); + animCtrl->AddFrame(frSelEvtStep, new TGLayoutHints(kLHintsLeft | kLHintsExpandX)); + + /// In Timeslice mode, scan anyway on all events in each TS, in event mode wait for loading of first TS + /// Not SetEnabled for TGNumberEntry, guessing equivalent is SetState + fEvtMin->SetState(kFALSE); + fEvtMax->SetState(kFALSE); + fEvtStep->SetState(kFALSE); + // ------------------------------------------------------------------------------------------------------------------- + + // -------------------------------- TS stepping buttons -------------------------------------------------------------- + TGCompositeFrame* frSelTsMin = new TGCompositeFrame(animCtrl, fWidth, 30, kHorizontalFrame | kFixedWidth); + TGLabel* gLabelTsMin = new TGLabel(frSelTsMin, "Min Ts:"); + frSelTsMin->AddFrame(gLabelTsMin, new TGLayoutHints(kLHintsLeft | kLHintsExpandX, 1, 1, 2, 1)); + fTsMin = new TGNumberEntry(frSelTsMin, 0, 6, -1, TGNumberFormat::kNESInteger, TGNumberFormat::kNEANonNegative, + TGNumberFormat::kNELLimitMinMax, 0, (fNbTs ? fNbTs - 1 : 0)); + fTsMin->SetNumber(0); + frSelTsMin->AddFrame(fTsMin, new TGLayoutHints(kLHintsRight | kLHintsExpandX)); + animCtrl->AddFrame(frSelTsMin, new TGLayoutHints(kLHintsLeft | kLHintsExpandX)); + + TGCompositeFrame* frSelTsMax = new TGCompositeFrame(animCtrl, fWidth, 30, kHorizontalFrame | kFixedWidth); + TGLabel* gLabelTsMax = new TGLabel(frSelTsMax, "Max Ts:"); + frSelTsMax->AddFrame(gLabelTsMax, new TGLayoutHints(kLHintsLeft | kLHintsExpandX, 1, 1, 2, 1)); + fTsMax = new TGNumberEntry(frSelTsMax, 10, 6, -1, TGNumberFormat::kNESInteger, TGNumberFormat::kNEANonNegative, + TGNumberFormat::kNELLimitMinMax, 0, (fNbTs ? fNbTs - 1 : 0)); + fTsMax->SetNumber((fNbTs ? fNbTs - 1 : 0)); + frSelTsMax->AddFrame(fTsMax, new TGLayoutHints(kLHintsRight | kLHintsExpandX)); + animCtrl->AddFrame(frSelTsMax, new TGLayoutHints(kLHintsLeft | kLHintsExpandX)); + + TGCompositeFrame* frSelTsStep = new TGCompositeFrame(animCtrl, fWidth, 30, kHorizontalFrame | kFixedWidth); + TGLabel* gLabelTsStep = new TGLabel(frSelTsStep, "Step Ts:"); + frSelTsStep->AddFrame(gLabelTsStep, new TGLayoutHints(kLHintsLeft | kLHintsExpandX, 1, 1, 2, 1)); + fTsStep = new TGNumberEntry(frSelTsStep, 0, 6, -1, TGNumberFormat::kNESInteger, TGNumberFormat::kNEAPositive, + TGNumberFormat::kNELLimitMinMax, 1, (fNbTs ? fNbTs - 1 : 1)); + fTsStep->SetNumber(1); + frSelTsStep->AddFrame(fTsStep, new TGLayoutHints(kLHintsRight | kLHintsExpandX)); + animCtrl->AddFrame(frSelTsStep, new TGLayoutHints(kLHintsLeft | kLHintsExpandX)); + + Bool_t bAtLeastOneTs = (0 < fNbTs); + fTsMin->SetState(bAtLeastOneTs); + fTsMax->SetState(bAtLeastOneTs); + fTsStep->SetState(bAtLeastOneTs); + fEvtStep->SetState(bAtLeastOneTs); + fStartButton->SetEnabled(bAtLeastOneTs); + // ------------------------------------------------------------------------------------------------------------------- + + // -------------------------------- Screenshot Ena & type ------------------------------------------------------------ + fBtnScreenshotEna = new TGCheckButton(animCtrl, "Screenshot each event"); + fBtnScreenshotEna->SetOn(); + animCtrl->AddFrame(fBtnScreenshotEna, new TGLayoutHints(kLHintsLeft | kLHintsExpandX)); + fBtnScreenshotEna->Connect("Clicked()", this->ClassName(), this, "UpdateEnaScreenshots()"); + + TGCompositeFrame* frSceneType = new TGCompositeFrame(animCtrl, fWidth, 30, kHorizontalFrame | kFixedWidth); + TGLabel* gLabelType = new TGLabel(frSceneType, "Scene type:"); + frSceneType->AddFrame(gLabelType, new TGLayoutHints(kLHintsLeft | kLHintsExpandX, 1, 1, 2, 1)); + fSceneOpt = new TGComboBox(frSceneType); + fSceneOpt->AddEntry("3D", k3D); + if (fbMcbmViewersEna) { + fSceneOpt->AddEntry("ZX", kZX); + fSceneOpt->AddEntry("ZY", kZY); + } + else { + fSceneOpt->AddEntry("RPhi", kXY); + fSceneOpt->AddEntry("RhoZ", kZ); + } + fSceneOpt->AddEntry("All", kAll); + fSceneOpt->Select(k3D); + fSceneOpt->Resize(100, 20); + frSceneType->AddFrame(fSceneOpt, new TGLayoutHints(kLHintsLeft | kLHintsExpandX)); + animCtrl->AddFrame(frSceneType, new TGLayoutHints(kLHintsLeft | kLHintsExpandX)); + // ------------------------------------------------------------------------------------------------------------------- + + // -------------------------------- Display clear ctrl --------------------------------------------------------------- + fBtnClearBuffer = new TGCheckButton(animCtrl, "Clear Buffer at Start"); + fBtnClearBuffer->SetOn(); + animCtrl->AddFrame(fBtnClearBuffer, new TGLayoutHints(kLHintsLeft | kLHintsExpandX)); + + fBtnRunContinuous = new TGCheckButton(animCtrl, "Run Continuous (stack events)"); + fBtnRunContinuous->SetOn(kFALSE); + animCtrl->AddFrame(fBtnRunContinuous, new TGLayoutHints(kLHintsLeft | kLHintsExpandX)); + // ------------------------------------------------------------------------------------------------------------------- + + fTab->AddFrame(animCtrl, new TGLayoutHints(kLHintsRight | kLHintsExpandX, 1, 1, 2, 1)); + + UpdateTsLimits(); + + fbInitDone = true; +} + +CbmTsEveAnimationControl::eAnimationType CbmTsEveAnimationControl::GetAnimationType() const +{ + return static_cast<eAnimationType>(fTypeOpt->GetSelected()); +} + +Double_t CbmTsEveAnimationControl::GetAnimFrameSec() { return fAnimFrameSec->GetNumber(); } + +Bool_t CbmTsEveAnimationControl::GetScreenshotEna() { return fBtnScreenshotEna->IsOn(); } + +CbmTsEveAnimationControl::eScreenshotType CbmTsEveAnimationControl::GetScreenshotType() const +{ + return static_cast<eScreenshotType>(fSceneOpt->GetSelected()); +} + +Int_t CbmTsEveAnimationControl::GetEventMin() { return fEvtMin->GetNumber(); } + +Int_t CbmTsEveAnimationControl::GetEventMax() { return fEvtMax->GetNumber(); } + +Int_t CbmTsEveAnimationControl::GetEventStep() { return fEvtStep->GetNumber(); } + +Int_t CbmTsEveAnimationControl::GetTsMin() { return fTsMin->GetNumber(); } + +Int_t CbmTsEveAnimationControl::GetTsMax() { return fTsMax->GetNumber(); } + +Int_t CbmTsEveAnimationControl::GetTsStep() { return fTsStep->GetNumber(); } + +Bool_t CbmTsEveAnimationControl::GetRunContinuous() { return fBtnRunContinuous->IsOn(); } + +Bool_t CbmTsEveAnimationControl::GetClearBuffer() { return fBtnClearBuffer->IsOn(); } + +void CbmTsEveAnimationControl::UpdateEnaScreenshots() { fSceneOpt->SetEnabled(fBtnScreenshotEna->IsOn()); } + +void CbmTsEveAnimationControl::UpdateEnaDisButtons() +{ + /// Prevent invalid accesses + Bool_t bAtLeastOneTs = (0 < fNbTs); + if (bAtLeastOneTs) { + fStartButton->SetEnabled(kTRUE); + + Bool_t bTsScanMode = (kTimeSlices == GetAnimationType()); + + /// In Timeslice mode, scan anyway on all events in each TS in range + fEvtMin->SetState(!bTsScanMode); + fEvtMax->SetState(!bTsScanMode); + fEvtStep->SetState(kTRUE); + + /// In Event mode, scan only on events within selected TS + fTsMin->SetState(bTsScanMode); + fTsMax->SetState(bTsScanMode); + fTsStep->SetState(bTsScanMode); + } + else { + fStartButton->SetEnabled(kFALSE); + fEvtMin->SetState(kFALSE); + fEvtMax->SetState(kFALSE); + fEvtStep->SetState(kFALSE); + fTsMin->SetState(kFALSE); + fTsMax->SetState(kFALSE); + fTsStep->SetState(kFALSE); + } +} + +void CbmTsEveAnimationControl::UpdateEventLimits() +{ + fEvtMin->SetLimitValues(0, fNbEvt - 1); + fEvtMax->SetLimitValues(0, fNbEvt - 1); + fEvtStep->SetLimitValues(1, fNbEvt - 1); + + fEvtMin->SetNumber(0); + fEvtMax->SetNumber(fNbEvt - 1); + fEvtStep->SetNumber(1); + + UpdateEnaDisButtons(); +} + +void CbmTsEveAnimationControl::UpdateTsLimits() +{ + fTsMin->SetLimitValues(0, fNbTs - 1); + fTsMax->SetLimitValues(0, fNbTs - 1); + fTsStep->SetLimitValues(1, fNbTs - 1); + + fTsMin->SetNumber(0); + fTsMax->SetNumber(fNbTs - 1); + fTsStep->SetNumber(1); + + UpdateEnaDisButtons(); +} diff --git a/core/eventdisplay/CbmTsEveAnimationControl.h b/core/eventdisplay/CbmTsEveAnimationControl.h new file mode 100644 index 0000000000..1a55499587 --- /dev/null +++ b/core/eventdisplay/CbmTsEveAnimationControl.h @@ -0,0 +1,129 @@ +/* Copyright (C) 2023 Facility for Antiproton and Ion Research in Europe, Darmstadt + SPDX-License-Identifier: GPL-3.0-only + Authors: Pierre-Alain Loizeau[committer] */ + +/* + * FairEveAnimationControl.h + * + * Created on: 26 maj 2020 + * Author: Daniel Wielanek + * E-mail: daniel.wielanek@gmail.com + * Warsaw University of Technology, Faculty of Physics + */ +/// PAL 01/06/2023: Heavily based on FairEveAnimationControl from FairRoot v18.6.7, for usage with CbmTimesliceManager + +#ifndef CBMTSEVEANIMATIONCONTROL_H_ +#define CBMTSEVEANIMATIONCONTROL_H_ + +#include <Rtypes.h> +#include <RtypesCore.h> +#include <TGButton.h> +#include <TGButton.h> // for TGTextButton, TGCheckButton +#include <TGComboBox.h> +#include <TGDoubleSlider.h> +#include <TGFrame.h> +#include <TGLabel.h> +#include <TGNumberEntry.h> +#include <TGedFrame.h> // for TGedFrame +#include <TObject.h> + +#include <GuiTypes.h> + +class CbmTsEveAnimationControl : public TNamed { +public: + enum eAnimationType + { + kEventsInTs = 0, + kTimeSlices = 1 + }; + enum eScreenshotType + { + kAll = 0, + k3D = 1, + kZX = 2, + kZY = 3, + kXY = 4, + kZ = 5 + }; + CbmTsEveAnimationControl(TGedFrame* frame, TGCompositeFrame* tab, TString functionName, TString name = "", + Int_t width = 170); + + virtual ~CbmTsEveAnimationControl(); + + + void SetDisplayMcbm(bool bEna) { fbMcbmViewersEna = bEna; } + + /** + * set name of function called when button is pressed + * @param name + */ + void SetFunctionName(TString name) { fFunctionName = name; }; + + void SetEvtNb(uint32_t uNbEvt) + { + fNbEvt = uNbEvt; + + if (fbInitDone) { // + UpdateEventLimits(); + } + }; + + void SetTsNb(uint32_t uTsNb) + { + fNbTs = uTsNb; + + if (fbInitDone) { // + UpdateTsLimits(); + } + }; + + void Init(); + + eAnimationType GetAnimationType() const; + Double_t GetAnimFrameSec(); + Bool_t GetScreenshotEna(); + eScreenshotType GetScreenshotType() const; + Int_t GetEventMin(); + Int_t GetEventMax(); + Int_t GetEventStep(); + Int_t GetTsMin(); + Int_t GetTsMax(); + Int_t GetTsStep(); + Bool_t GetRunContinuous(); + Bool_t GetClearBuffer(); + + void UpdateEnaScreenshots(); + void UpdateEnaDisButtons(); + void UpdateEventLimits(); + void UpdateTsLimits(); + +private: + const Int_t fWidth; + uint32_t fNbEvt = 0; + uint32_t fNbTs = 0; + + TGedFrame* fParent = nullptr; + TString fFunctionName = ""; + + bool fbMcbmViewersEna = false; //! + bool fbInitDone = false; + + TGCompositeFrame* fTab = nullptr; + TGTextButton* fStartButton = nullptr; + TGComboBox* fTypeOpt = nullptr; + TGNumberEntry* fAnimFrameSec = nullptr; + TGCheckButton* fBtnScreenshotEna = nullptr; + TGComboBox* fSceneOpt = nullptr; + TGNumberEntry* fEvtMin = nullptr; + TGNumberEntry* fEvtMax = nullptr; + TGNumberEntry* fEvtStep = nullptr; + TGNumberEntry* fTsMin = nullptr; + TGNumberEntry* fTsMax = nullptr; + TGNumberEntry* fTsStep = nullptr; + TGCheckButton* fBtnRunContinuous = nullptr; + TGCheckButton* fBtnClearBuffer = nullptr; + + ClassDef(CbmTsEveAnimationControl, 1) +}; + +#endif /* CBMTSEVEANIMATIONCONTROL_H_ */ diff --git a/core/eventdisplay/CbmTsEveTransparencyControl.cxx b/core/eventdisplay/CbmTsEveTransparencyControl.cxx new file mode 100644 index 0000000000..6b58040aeb --- /dev/null +++ b/core/eventdisplay/CbmTsEveTransparencyControl.cxx @@ -0,0 +1,52 @@ +/* Copyright (C) 2023 Facility for Antiproton and Ion Research in Europe, Darmstadt + SPDX-License-Identifier: GPL-3.0-only + Authors: Pierre-Alain Loizeau[committer] */ + +#include "CbmTsEveTransparencyControl.h" + +#include "CbmTimesliceManager.h" // for CbmTimesliceManager + +#include <TGButton.h> // for TGCheckButton +#include <TGNumberEntry.h> // for TGNumberEntry, TGNumberFormat, TGNumbe... + +CbmTsEveTransparencyControl::CbmTsEveTransparencyControl(TGFrame const* parent, char const* label) + : TGHorizontalFrame(parent) + , fCheck(new TGCheckButton(this, label)) + , fNumber(new TGNumberEntry(this, + 80., // initial number + 6, // digitwidth + -1, TGNumberFormat::kNESInteger, TGNumberFormat::kNEANonNegative, + TGNumberFormat::kNELLimitMinMax, + 0, // min + 100)) // max +{ + SetCleanup(kDeepCleanup); + + // display + AddFrame(fCheck); // takes ownership + AddFrame(fNumber); // takes ownership + + // wire up observers + fCheck->Connect("Toggled(Bool_t)", this->ClassName(), this, "Toggled()"); + fNumber->Connect("ValueSet(Long_t)", this->ClassName(), this, "ValueSet()"); +} + +void CbmTsEveTransparencyControl::Toggled() +{ + if (fCheck->IsOn()) { // + CbmTimesliceManager::Instance()->SetTransparency(kFALSE, fNumber->GetIntNumber()); + } + else { + CbmTimesliceManager::Instance()->SetTransparency(kTRUE, fNumber->GetIntNumber()); + } +} + +void CbmTsEveTransparencyControl::ValueSet() +{ + if (fCheck->IsOn()) { // + CbmTimesliceManager::Instance()->SetTransparency(kFALSE, fNumber->GetIntNumber()); + } + else { + CbmTimesliceManager::Instance()->SetTransparency(kTRUE, fNumber->GetIntNumber()); + } +} diff --git a/core/eventdisplay/CbmTsEveTransparencyControl.h b/core/eventdisplay/CbmTsEveTransparencyControl.h new file mode 100644 index 0000000000..bc4e86dbf8 --- /dev/null +++ b/core/eventdisplay/CbmTsEveTransparencyControl.h @@ -0,0 +1,37 @@ +/* Copyright (C) 2023 Facility for Antiproton and Ion Research in Europe, Darmstadt + SPDX-License-Identifier: GPL-3.0-only + Authors: Pierre-Alain Loizeau[committer] */ + +/// PAL 31/05/2023: clone of FairEveTransparencyControl from FairRoot v18.6.7 for usage with CbmTimesliceManager + +#ifndef CBMTSEVETRANSPARENCYCONTROL_H_ +#define CBMTSEVETRANSPARENCYCONTROL_H_ + +#include <Rtypes.h> // for THashConsistencyHolder, ClassDef +#include <RtypesCore.h> // for Bool_t +#include <TGFrame.h> // for TGFrame (ptr only), TGHorizontalFrame +class TBuffer; +class TClass; +class TGCheckButton; +class TGNumberEntry; // lines 16-16 +class TMemberInspector; + +class CbmTsEveTransparencyControl : public TGHorizontalFrame { + TGCheckButton* fCheck; + TGNumberEntry* fNumber; + +public: + CbmTsEveTransparencyControl(TGFrame const* parent, char const* label = "Transparency"); + + TGCheckButton* GetCheck() const { return fCheck; } + TGNumberEntry* GetNumber() const { return fNumber; } + + void Toggled(); // SLOT to receive check button events + void ValueSet(); // SLOT to receive number entry events + + virtual ~CbmTsEveTransparencyControl() {}; + + ClassDef(CbmTsEveTransparencyControl, 1) +}; + +#endif /* CBMTSEVETRANSPARENCYCONTROL_H_ */ diff --git a/macro/.gitignore b/macro/.gitignore new file mode 100644 index 0000000000..1b96abf53a --- /dev/null +++ b/macro/.gitignore @@ -0,0 +1,2 @@ +# Ignore file auto-created by event displays (probably coming from FairRoot or Root) +**/temp_event_display.root diff --git a/macro/beamtime/mcbm2022/event_display_l1reco.C b/macro/beamtime/mcbm2022/event_display_l1reco.C new file mode 100644 index 0000000000..a801f046d4 --- /dev/null +++ b/macro/beamtime/mcbm2022/event_display_l1reco.C @@ -0,0 +1,104 @@ +/* Copyright (C) 2023 Facility for Antiproton and Ion Research in Europe, Darmstadt + SPDX-License-Identifier: GPL-3.0-only + Authors: Pierre-Alain Loizeau[committer] */ + +/// FIXME: add support for alignment file + +void event_display_l1reco(uint32_t uRunId, std::string sRecoFile, std::string sGeoFile, std::string sAlignFile = "", + std::string sXmlGeoConfig = "", std::string sUnpFile = "") +{ + // ----- Logger settings -------------------------------------------------------------------------------------- // + FairLogger::GetLogger()->SetLogScreenLevel("INFO"); + fair::Logger::DefineVerbosity( + "user1", fair::VerbositySpec::Make(fair::VerbositySpec::Info::severity, fair::VerbositySpec::Info::file_line)); + FairLogger::GetLogger()->SetLogVerbosityLevel("user1"); + // ---------------------------------------------------------------------------------------------------------------- // + + + // ----- CbmSetup ----------------------------------------------------------------------------------------------------------------- // + /// Do automatic mapping only if not overridden by user or empty + cbm::mcbm::ToForceLibLoad dummy; /// Needed to trigger loading of the library as no fct dict in ROOT6 and CLING + TString geoSetupTag = ""; + try { + geoSetupTag = cbm::mcbm::GetSetupFromRunId(uRunId); + } + catch (const std::invalid_argument& e) { + std::cout << "Error in mapping from runID to setup name: " << e.what() << std::endl; + return kFALSE; + } + + auto geoSetup = CbmSetup::Instance(); + geoSetup->LoadSetup(geoSetupTag); + + // You can modify the pre-defined setup by using + geoSetup->SetActive(ECbmModuleId::kMvd, kFALSE); + geoSetup->SetActive(ECbmModuleId::kSts, kTRUE); + geoSetup->SetActive(ECbmModuleId::kMuch, kFALSE); + geoSetup->SetActive(ECbmModuleId::kRich, kTRUE); + geoSetup->SetActive(ECbmModuleId::kTrd, kTRUE); + geoSetup->SetActive(ECbmModuleId::kTrd2d, kTRUE); + geoSetup->SetActive(ECbmModuleId::kTof, kTRUE); + geoSetup->SetActive(ECbmModuleId::kPsd, kFALSE); + // ---------------------------------------------------------------------------------------------------------------- // + + // ----- Reconstruction run ----------------------------------------------------------------------------------- // + FairRunAna* fRun = new FairRunAna(); + + FairFileSource* inputSource = new FairFileSource(sRecoFile); + if ("" != sUnpFile) inputSource->AddFriend(sUnpFile); + fRun->SetSource(inputSource); + + FairRootFileSink* outputSink = new FairRootFileSink("temp_event_display.root"); + fRun->SetSink(outputSink); + + fRun->SetGeomFile(sGeoFile.data()); + + if ("" != sAlignFile) { + std::cout << "Applying alignment for file " << sAlignFile << std::endl; + + // Define the basic structure which needs to be filled with information + // This structure is stored in the output file and later passed to the + // FairRoot framework to do the (miss)alignment + std::map<std::string, TGeoHMatrix>* matrices {nullptr}; + + // read matrices from disk + TFile* misalignmentMatrixRootfile = new TFile(sAlignFile.data(), "READ"); + if (misalignmentMatrixRootfile->IsOpen()) { + gDirectory->GetObject("MisalignMatrices", matrices); + misalignmentMatrixRootfile->Close(); + } + else { + std::cout << "Could not open file " << sAlignFile << "\n Exiting"; + return kFALSE; + } + + if (matrices) { fRun->AddAlignmentMatrices(*matrices); } + else { + LOG(error) << "Alignment required but no matrices found." + << "\n Exiting"; + return kFALSE; + } + } + // ---------------------------------------------------------------------------------------------------------------- // + + // ----- Event display ---------------------------------------------------------------------------------------- // + CbmTimesliceManager* fMan = new CbmTimesliceManager(); + fMan->SetXMLConfig(sXmlGeoConfig); + fMan->SetDisplayMcbm(); + // ---------------------------------------------------------------------------------------------------------------- // + + fMan->Init(1, 7); // Make all sensors visible, finer tuning needs to be done in XML file + // fMan->Init(1, 4); + // fMan->Init(1, 5); //make TPF and TRD visible by default + // fMan->Init(1, 6); // make STS sensors visible by default + // fMan->Init(1, 7); // make RICH sensors visible by default + + //-------------- NH display macro --------------------------------------------------------------------------------- // + cout << "customize TEveManager gEve " << gEve << endl; + gEve->GetDefaultGLViewer()->SetClearColor(kYellow - 10); + TGLViewer* v = gEve->GetDefaultGLViewer(); + TGLAnnotation* ann = new TGLAnnotation(v, Form("%u", uRunId), 0.01, 0.98); + ann->SetTextSize(0.03); // % of window diagonal + ann->SetTextColor(4); + // ---------------------------------------------------------------------------------------------------------------- // +} diff --git a/macro/beamtime/mcbm2022/evt_disp_conf_mcbm_beam_2022_05_23_nickel.xml b/macro/beamtime/mcbm2022/evt_disp_conf_mcbm_beam_2022_05_23_nickel.xml new file mode 100644 index 0000000000..146379efe4 --- /dev/null +++ b/macro/beamtime/mcbm2022/evt_disp_conf_mcbm_beam_2022_05_23_nickel.xml @@ -0,0 +1,48 @@ +<xmlconf> +<!-- +- color is handled by the FairEventManager, converted from text to ROOT colors, ignored if "", recursive value is depth +- transparency is handled by the FairEventManager, should be between 1 and 99, ignored if "", recursive value is depth + (0 and 100 theoritically, see https://root-forum.cern.ch/t/make-a-geometry-transparent/47665/9) +- Visibility is boolean and applied to all daughters if recursive set >0 + => To disable a full detector apart from a few leaves, + 1) set the top node to "visibility = 0, recursive = 1" + 2) set each intermediate node to "visibility = 0, recursive = 1" + 3) set the nodes that should be visible to "visibility = 1, recursive = 1" +--> +<Detectors> + <detector name="cave_1" color="" transparency="" visibility="" recursive="0"> + <detector name="pipe_v19f_0" color="" transparency="95" visibility="" recursive="1"></detector> + <detector name="sts_v22e_mcbm_0" color="" transparency="" visibility="0" recursive="1"> + <detector name="Station01_1" color="" transparency="" visibility="1" recursive="1"></detector> + <detector name="Station02_2" color="" transparency="" visibility="1" recursive="1"></detector> + </detector> + <detector name="trd_v22h_mcbm_0" color="" transparency="" visibility="0" recursive="1"> + <detector name="layer01_20101" color="" transparency="" visibility="0" recursive="1"> + <detector name="module9_101001001" color="" transparency="" visibility="0" recursive="1"> + <detector name="PadPlane_1" color="" transparency="" visibility="1" recursive="1"></detector> + </detector> + </detector> + <detector name="layer02_10202" color="" transparency="" visibility="0" recursive="1"> + <detector name="module8_101002001" color="" transparency="" visibility="0" recursive="1"> + <detector name="padcopper_1" color="" transparency="" visibility="1" recursive="1"></detector> + <detector name="padplane_1" color="" transparency="" visibility="1" recursive="1"></detector> + </detector> + </detector> + <detector name="layer03_11303" color="" transparency="" visibility="0" recursive="1"> + <detector name="module8_101303001" color="" transparency="" visibility="0" recursive="1"> + <detector name="padcopper_1" color="" transparency="" visibility="1" recursive="1"></detector> + <detector name="padplane_1" color="" transparency="" visibility="1" recursive="1"></detector> + </detector> + </detector> + </detector> + <detector name="rich_v21c_mcbm_0" color="" transparency="" visibility="0" recursive="1"> + <detector name="box_1" color="" transparency="" visibility="0" recursive="1"> + <detector name="Gas_1" color="" transparency="" visibility="0" recursive="1"> + <detector name="pmt_plane_1" color="" transparency="" visibility="1" recursive="1"></detector> + </detector> + </detector> + </detector> + <detector name="platform_v20a_mcbm_0" color="" transparency="" visibility="0" recursive="1"></detector> + </detector> +</Detectors> +</xmlconf> diff --git a/macro/run/event_display_reco_ts.C b/macro/run/event_display_reco_ts.C new file mode 100644 index 0000000000..a2ab346f05 --- /dev/null +++ b/macro/run/event_display_reco_ts.C @@ -0,0 +1,89 @@ +/* Copyright (C) 2023 Facility for Antiproton and Ion Research in Europe, Darmstadt + SPDX-License-Identifier: GPL-3.0-only + Authors: Pierre-Alain Loizeau[committer] */ + +void event_display_reco_ts(TString geoSetupTag, std::string sRecoFile, std::string sGeoFile, + std::string sAlignFile = "", std::string sXmlGeoConfig = "", std::string sUnpFile = "") +{ + // ----- Logger settings -------------------------------------------------------------------------------------- // + FairLogger::GetLogger()->SetLogScreenLevel("INFO"); + fair::Logger::DefineVerbosity( + "user1", fair::VerbositySpec::Make(fair::VerbositySpec::Info::severity, fair::VerbositySpec::Info::file_line)); + FairLogger::GetLogger()->SetLogVerbosityLevel("user1"); + // ---------------------------------------------------------------------------------------------------------------- // + + + // ----- CbmSetup ----------------------------------------------------------------------------------------------------------------- // + auto geoSetup = CbmSetup::Instance(); + geoSetup->LoadSetup(geoSetupTag); + + // You can modify the pre-defined setup by using + /* + geoSetup->SetActive(ECbmModuleId::kMvd, kFALSE); + geoSetup->SetActive(ECbmModuleId::kSts, kTRUE); + geoSetup->SetActive(ECbmModuleId::kMuch, kFALSE); + geoSetup->SetActive(ECbmModuleId::kRich, kTRUE); + geoSetup->SetActive(ECbmModuleId::kTrd, kTRUE); + geoSetup->SetActive(ECbmModuleId::kTrd2d, kTRUE); + geoSetup->SetActive(ECbmModuleId::kTof, kTRUE); + geoSetup->SetActive(ECbmModuleId::kPsd, kFALSE); + */ + // ---------------------------------------------------------------------------------------------------------------- // + + // ----- Reconstruction run ----------------------------------------------------------------------------------- // + FairRunAna* fRun = new FairRunAna(); + + FairFileSource* inputSource = new FairFileSource(sRecoFile); + inputSource->AddFriend(sUnpFile); + fRun->SetSource(inputSource); + + FairRootFileSink* outputSink = new FairRootFileSink("temp_event_display.root"); + fRun->SetSink(outputSink); + + fRun->SetGeomFile(sGeoFile.data()); + + if ("" != sAlignFile) { + std::cout << "Applying alignment for file " << sAlignFile << std::endl; + + // Define the basic structure which needs to be filled with information + // This structure is stored in the output file and later passed to the + // FairRoot framework to do the (miss)alignment + std::map<std::string, TGeoHMatrix>* matrices {nullptr}; + + // read matrices from disk + TFile* misalignmentMatrixRootfile = new TFile(sAlignFile.data(), "READ"); + if (misalignmentMatrixRootfile->IsOpen()) { + gDirectory->GetObject("MisalignMatrices", matrices); + misalignmentMatrixRootfile->Close(); + } + else { + std::cout << "Could not open file " << sAlignFile << "\n Exiting"; + return kFALSE; + } + + if (matrices) { fRun->AddAlignmentMatrices(*matrices); } + else { + LOG(error) << "Alignment required but no matrices found." + << "\n Exiting"; + return kFALSE; + } + } + // ---------------------------------------------------------------------------------------------------------------- // + + // ----- Event display ---------------------------------------------------------------------------------------- // + CbmTimesliceManager* fMan = new CbmTimesliceManager(); + fMan->SetXMLConfig(sXmlGeoConfig); + fMan->SetDisplayMcbm(); + // ---------------------------------------------------------------------------------------------------------------- // + + fMan->Init(1, 5); // NH display macro + // fMan->Init(1,4,10000); + // fMan->Init(1, 5, 10000); // make STS visible by default + // fMan->Init(1,6,10000); // make MVD visible by default + + //-------------- NH display macro --------------------------------------------------------------------------------- // + cout << "customize TEveManager gEve " << gEve << endl; + gEve->GetDefaultGLViewer()->SetClearColor(kYellow - 10); + TGLViewer* v = gEve->GetDefaultGLViewer(); + // ---------------------------------------------------------------------------------------------------------------- // +} diff --git a/macro/run/evt_disp_conf_cbm_sis100e.xml b/macro/run/evt_disp_conf_cbm_sis100e.xml new file mode 100644 index 0000000000..e103722b00 --- /dev/null +++ b/macro/run/evt_disp_conf_cbm_sis100e.xml @@ -0,0 +1,46 @@ +<xmlconf> +<!-- +- color is handled by the FairEventManager, converted from text to ROOT colors, ignored if "", recursive value is depth +- transparency is handled by the FairEventManager, should be between 1 and 99, ignored if "", recursive value is depth + (0 and 100 theoritically, see https://root-forum.cern.ch/t/make-a-geometry-transparent/47665/9) +- Visibility is boolean and applied to all daughters if recursive set >0 + => To disable a full detector apart from a few leaves, + 1) set the top node to "visibility = 0, recursive = 1" + 2) set each intermediate node to "visibility = 0, recursive = 1" + 3) set the nodes that should be visible to "visibility = 1, recursive = 1" +--> +<Detectors> + <detector name="cave_1" color="" transparency="" visibility="" recursive="0"> + <detector name="platform_v22b_0" color="" transparency="" visibility="0" recursive="1"></detector> + <detector name="magnet_v22a_0" color="" transparency="" visibility="0" recursive="1"></detector> + <detector name="sts_v22c_0" color="" transparency="" visibility="1" recursive="1"> + <detector name="sts_passive_v22c_20" color="" transparency="" visibility="0" recursive="1"></detector> + </detector> + <detector name="rich_v21a_0" color="" transparency="" visibility="1" recursive="1"> + <detector name="rich_container_1" color="" transparency="" visibility="" recursive="1"> + <detector name="rich_gas_1" color="" transparency="" visibility="" recursive="1"> + <detector name="shielding_box_1" color="" transparency="" visibility="0" recursive="1"></detector> + <detector name="shielding_box_2" color="" transparency="" visibility="0" recursive="1"></detector> + <detector name="sens_plane_1" color="" transparency="" visibility="0" recursive="1"></detector> + <detector name="sens_plane_1" color="" transparency="" visibility="0" recursive="1"></detector> + <detector name="RICH_mainframe_1_1" color="" transparency="" visibility="0" recursive="1"></detector> + <detector name="RICH_mainframe_2_1" color="" transparency="" visibility="0" recursive="1"></detector> + </detector> + </detector> + </detector> + <detector name="trd_v20b_1e_0" color="" transparency="" visibility="1" recursive="1"> + <detector name="support_trd1_1" color="" transparency="" visibility="0" recursive="1"></detector> + </detector> + <detector name="tof_v21a_1e_0" color="" transparency="" visibility="1" recursive="1"> + <detector name="Bar_0" color="" transparency="" visibility="0" recursive="1"></detector> + <detector name="Bar_1" color="" transparency="" visibility="0" recursive="1"></detector> + <detector name="Bar_2" color="" transparency="" visibility="0" recursive="1"></detector> + <detector name="Bar_3" color="" transparency="" visibility="0" recursive="1"></detector> + <detector name="Bar_0" color="" transparency="" visibility="0" recursive="1"></detector> + <detector name="Bar_1" color="" transparency="" visibility="0" recursive="1"></detector> + <detector name="Bar_2" color="" transparency="" visibility="0" recursive="1"></detector> + <detector name="Bar_3" color="" transparency="" visibility="0" recursive="1"></detector> + </detector> + </detector> +</Detectors> +</xmlconf> -- GitLab