From 8fe7922f069ebe7b0f5ac2ebbcfcca3921977575 Mon Sep 17 00:00:00 2001 From: Frederic Julian Linz <f.linz@gsi.de> Date: Mon, 27 Nov 2023 11:22:12 +0000 Subject: [PATCH] Add FSD to AnalysisTreeConverter + Updates to AT binary --- .../analysis_tree_converter/CMakeLists.txt | 2 + .../CbmAnalysisTreeInterfaceLinkDef.h | 2 + .../CbmConverterManager.cxx | 67 ++-- .../CbmFsdHitsConverter.cxx | 306 ++++++++++++++++++ .../CbmFsdHitsConverter.h | 94 ++++++ .../CbmFsdModulesConverter.cxx | 69 ++++ .../CbmFsdModulesConverter.h | 31 ++ .../CbmPsdModulesConverter.cxx | 5 +- .../config/ATConfig_event_ideal.yaml | 3 + .../config/ATConfig_timeslice.yaml | 3 + .../analysis_tree_converter/steer/Config.cxx | 8 + .../analysis_tree_converter/steer/Config.h | 4 + .../analysis_tree_converter/steer/Run.cxx | 31 ++ .../analysis_tree_converter/steer/Run.h | 15 +- .../steer/TaskFactory.cxx | 15 +- .../run_analysis_tree_maker_json_config.C | 10 +- 16 files changed, 631 insertions(+), 34 deletions(-) create mode 100644 analysis/common/analysis_tree_converter/CbmFsdHitsConverter.cxx create mode 100644 analysis/common/analysis_tree_converter/CbmFsdHitsConverter.h create mode 100644 analysis/common/analysis_tree_converter/CbmFsdModulesConverter.cxx create mode 100644 analysis/common/analysis_tree_converter/CbmFsdModulesConverter.h diff --git a/analysis/common/analysis_tree_converter/CMakeLists.txt b/analysis/common/analysis_tree_converter/CMakeLists.txt index 273ea100fa..4d92516b76 100644 --- a/analysis/common/analysis_tree_converter/CMakeLists.txt +++ b/analysis/common/analysis_tree_converter/CMakeLists.txt @@ -14,6 +14,8 @@ set(SRCS CbmStsTracksConverter.cxx CbmSimTracksConverter.cxx CbmPsdModulesConverter.cxx + CbmFsdModulesConverter.cxx + CbmFsdHitsConverter.cxx CbmTofHitsConverter.cxx CbmTrdTracksConverter.cxx CbmRichRingsConverter.cxx diff --git a/analysis/common/analysis_tree_converter/CbmAnalysisTreeInterfaceLinkDef.h b/analysis/common/analysis_tree_converter/CbmAnalysisTreeInterfaceLinkDef.h index eac02d0865..c497cdba8b 100644 --- a/analysis/common/analysis_tree_converter/CbmAnalysisTreeInterfaceLinkDef.h +++ b/analysis/common/analysis_tree_converter/CbmAnalysisTreeInterfaceLinkDef.h @@ -16,6 +16,8 @@ #pragma link C++ class CbmStsTracksConverter + ; #pragma link C++ class CbmTofHitsConverter + ; #pragma link C++ class CbmPsdModulesConverter + ; +#pragma link C++ class CbmFsdModulesConverter + ; +#pragma link C++ class CbmFsdHitsConverter + ; #pragma link C++ class CbmTrdTracksConverter + ; #pragma link C++ class CbmRichRingsConverter + ; //#pragma link C++ class CbmMatchEvents + ; diff --git a/analysis/common/analysis_tree_converter/CbmConverterManager.cxx b/analysis/common/analysis_tree_converter/CbmConverterManager.cxx index 6240f8903d..256d5ffde3 100644 --- a/analysis/common/analysis_tree_converter/CbmConverterManager.cxx +++ b/analysis/common/analysis_tree_converter/CbmConverterManager.cxx @@ -4,18 +4,18 @@ #include "CbmConverterManager.h" +#include "AnalysisTree/DataHeader.hpp" +#include "AnalysisTree/TaskManager.hpp" #include "CbmConverterTask.h" +#include "CbmDefs.h" #include "CbmEvent.h" - #include "TClonesArray.h" #include "TGeoBBox.h" #include "TGeoManager.h" +#include "TString.h" #include <iostream> -#include "AnalysisTree/DataHeader.hpp" -#include "AnalysisTree/TaskManager.hpp" - ClassImp(CbmConverterManager); InitStatus CbmConverterManager::Init() @@ -83,41 +83,56 @@ void CbmConverterManager::FillDataHeader() data_header->SetBeamMomentum(beam_mom_); data_header->SetTimeSliceLength(ts_length_); - auto& psd_mod_pos = data_header->AddDetector(); - const int psd_node_id = 6; - const char* module_name_prefix = "module"; + auto& specDet_mod_pos = data_header->AddDetector(); + TString specDet_names[2] = {(TString) ToString(ECbmModuleId::kPsd), (TString) ToString(ECbmModuleId::kFsd)}; + const char* module_name = "module"; // PSD and FSD modules always contains "module" + + TVector3 frontFaceGlobal; + Int_t nSpecDetModules = 0; + TString specDetNameTag = ""; + + TGeoIterator geoIterator(gGeoManager->GetTopNode()->GetVolume()); + TGeoNode* curNode; + geoIterator.Reset(); // safety to reset to "cave" before the loop starts + while ((curNode = geoIterator())) { + TString nodePath; + geoIterator.GetPath(nodePath); + if (!(nodePath.Contains(specDet_names[0], TString::kIgnoreCase) + || nodePath.Contains(specDet_names[1], TString::kIgnoreCase))) { + geoIterator.Skip(); // skip current branch when it is not FSD => should speed up + continue; // don't do anything for this branch + } - auto* geoMan = gGeoManager; - auto* caveNode = geoMan->GetTopNode(); - auto* psdNode = caveNode->GetDaughter(psd_node_id); - std::cout << "-I- " << psdNode->GetName() << std::endl; + TString nodeName(curNode->GetName()); - auto psdGeoMatrix = psdNode->GetMatrix(); - auto psdBox = (TGeoBBox*) psdNode->GetVolume()->GetShape(); - TVector3 frontFaceLocal(0, 0, -psdBox->GetDZ()); + // spectator detector as a whole + if (nodeName.Contains(specDet_names[0], TString::kIgnoreCase) + || nodeName.Contains(specDet_names[1], TString::kIgnoreCase)) { + specDetNameTag = nodeName; - TVector3 frontFaceGlobal; - psdGeoMatrix->LocalToMaster(&frontFaceLocal[0], &frontFaceGlobal[0]); + auto specDetGeoMatrix = curNode->GetMatrix(); + auto specDetBox = (TGeoBBox*) curNode->GetVolume()->GetShape(); + TVector3 frontFaceLocal(0, 0, -specDetBox->GetDZ()); + specDetGeoMatrix->LocalToMaster(&frontFaceLocal[0], &frontFaceGlobal[0]); + } - for (int i_d = 0; i_d < psdNode->GetNdaughters(); ++i_d) { - auto* daughter = psdNode->GetDaughter(i_d); - TString daughterName(daughter->GetName()); - if (daughterName.BeginsWith(module_name_prefix)) { + // modules of spectator detector + if (nodeName.Contains(module_name)) { + nSpecDetModules++; - auto geoMatrix = daughter->GetMatrix(); + auto geoMatrix = curNode->GetMatrix(); TVector3 translation(geoMatrix->GetTranslation()); - - int modID = daughter->GetNumber(); double x = translation.X(); double y = translation.Y(); - std::cout << "mod" << modID << " : " << Form("(%.3f, %3f)", x, y) << std::endl; - - auto* module = psd_mod_pos.AddChannel(); + auto* module = specDet_mod_pos.AddChannel(); module->SetPosition(x, y, frontFaceGlobal[2]); + LOG(info) << "Module " << nSpecDetModules << " : " << Form("(%.3f, %.3f)", x, y); } } + LOG(info) << "Detector " << specDetNameTag << " with " << nSpecDetModules << " modules"; + task_manager_->SetOutputDataHeader(data_header); } CbmConverterManager::~CbmConverterManager() = default; diff --git a/analysis/common/analysis_tree_converter/CbmFsdHitsConverter.cxx b/analysis/common/analysis_tree_converter/CbmFsdHitsConverter.cxx new file mode 100644 index 0000000000..8e60ee5371 --- /dev/null +++ b/analysis/common/analysis_tree_converter/CbmFsdHitsConverter.cxx @@ -0,0 +1,306 @@ +/* Copyright (C) 2020-2021 Physikalisches Institut, Eberhard Karls Universitaet Tuebingen, Tuebingen + SPDX-License-Identifier: GPL-3.0-only + Authors: Viktor Klochkov [committer] */ + +#include "CbmFsdHitsConverter.h" + +#include "AnalysisTree/Matching.hpp" +#include "CbmDefs.h" +#include "CbmDigiManager.h" +#include "CbmEvent.h" +#include "CbmFsdPoint.h" +#include "CbmGlobalTrack.h" +#include "CbmKFTrack.h" +#include "CbmMCDataArray.h" +#include "CbmMCDataManager.h" +#include "CbmMCTrack.h" +#include "TClonesArray.h" +#include <CbmFsdDigi.h> +#include <CbmFsdHit.h> +#include <CbmGlobalTrack.h> +#include <CbmStsTrack.h> +#include <CbmTofHit.h> +#include <CbmTrackMatchNew.h> + +#include <FairMCPoint.h> +#include <FairRootManager.h> +#include <Logger.h> + +#include <TGeoManager.h> // for TGeoManager, gGeoManager +#include <TGeoMatrix.h> // for TGeoMatrix +#include <TGeoNode.h> // for TGeoIterator, TGeoNode +#include <TGeoShape.h> // for TGeoBBox etc. +#include <TGeoVolume.h> // for TGeoVolume + +#include <AnalysisTree/TaskManager.hpp> +#include <cassert> + +ClassImp(CbmFsdHitsConverter); + +void CbmFsdHitsConverter::Init() +{ + LOG(debug) << " THIS IS A TEST -> CbmFsdHitsConverter is being initialized LUKAS" << std::endl; + + assert(!out_branch_.empty()); + auto* ioman = FairRootManager::Instance(); + + cbm_fsd_hits_ = (TClonesArray*) ioman->GetObject("FsdHit"); + + cbm_global_tracks_ = (TClonesArray*) ioman->GetObject("GlobalTrack"); + cbm_sts_tracks_ = (TClonesArray*) ioman->GetObject("StsTrack"); + cbm_tof_hits_ = (TClonesArray*) ioman->GetObject("TofHit"); + cbm_fsd_hitmatch_ = (TClonesArray*) ioman->GetObject("FsdHitMatch"); + cbm_mc_tracks_ = (TClonesArray*) ioman->GetObject("MCTrack"); + + fDigiMan = CbmDigiManager::Instance(); + fDigiMan->Init(); + if (!fDigiMan->IsMatchPresent(ECbmModuleId::kFsd)) { + LOG(error) << " No FsdDigiMatch input array present !!"; + } + //cbm_fsd_digis_ = (TClonesArray*) ioman->GetObject("FsdDigi"); + //cbm_fsd_digimatch_ = (TClonesArray*) ioman->GetObject("FsdDigiMatch"); + + cbm_mc_manager_ = dynamic_cast<CbmMCDataManager*>(ioman->GetObject("MCDataManager")); + //cbm_mc_tracks_new_ = cbm_mc_manager_->InitBranch("MCTrack"); + cbm_fsd_points_new_ = cbm_mc_manager_->InitBranch("FsdPoint"); + + AnalysisTree::BranchConfig fsd_branch(out_branch_, AnalysisTree::DetType::kHit); + + fsd_branch.AddField<float>("dEdx", "Energy deposition of given FSD hit [GeV]"); + fsd_branch.AddField<float>("t", "Reconstructed time of given FSD hit [ps]"); + fsd_branch.AddField<float>("mass2", "Calculated mass squared from extrapolated global track (by CbmKFTrack) to FSD " + "plane and FSD hit time [GeV^2/c^4]"); + fsd_branch.AddField<float>("l", "Lenght of the extrapolated global track (by CbmKFTrack) to FSD plane [cm]"); + fsd_branch.AddField<float>( + "qp", "charge * momentum of the extrapoleted global track (by CbmKFTrack) to FSD plane [GeV/c]"); + fsd_branch.AddFields<float>( + {"dx", "dy", "dz"}, + "Component of a 3D distance between FSD hit and extrapolated global track (by CbmKFTrack) [cm]"); + fsd_branch.AddField<float>( + "chi2GtrackHit", "chi2 between extrapolated global track (by CbmKFTrack) to FSD plane (?FIXED Z?) and FSD hit"); + fsd_branch.AddField<int>( + "bestMatchedGtrack2HitId", + "Index of best match between extrapolated global track (by CbmKFTrack) and FSD hit based on min chi2GtrackHit"); + fsd_branch.AddField<int>("multMCtracks", "number of MC particles that cotributed by energy deposition to FSD hit"); + fsd_branch.AddField<float>("maxWeightMCtrack", + "weight of matched link from Hit to Point (?highest energy deposition?)"); + fsd_branch.AddField<float>("dtHitPoint", "Time difference between FSD hit and matched MC point [ps]"); + fsd_branch.AddFields<float>({"dxHitPoint", "dyHitPoint", "dzHitPoint"}, + "Component of a 3D distance between FSD hit and matched MC point [cm]"); + + i_edep_ = fsd_branch.GetFieldId("dEdx"); + i_t_ = fsd_branch.GetFieldId("t"); + i_mass2_ = fsd_branch.GetFieldId("mass2"); + i_qp_ = fsd_branch.GetFieldId("qp"); + i_dx_ = fsd_branch.GetFieldId("dx"); + i_l_ = fsd_branch.GetFieldId("l"); + i_dtHP_ = fsd_branch.GetFieldId("dtHitPoint"); + i_dxHP_ = fsd_branch.GetFieldId("dxHitPoint"); + i_chi2_ = fsd_branch.GetFieldId("chi2GtrackHit"); + i_bestMatchedGTrack_ = fsd_branch.GetFieldId("bestMatchedGtrack2HitId"); + i_multMC_ = fsd_branch.GetFieldId("multMCtracks"); + i_topW_ = fsd_branch.GetFieldId("maxWeightMCtrack"); + + if (fsdgtrack_minChi2_ == 0) fsdgtrack_minChi2_ = -1.; + if (fsdgtrack_maxChi2_ == 0) fsdgtrack_maxChi2_ = 10000.; + + auto* man = AnalysisTree::TaskManager::GetInstance(); + man->AddBranch(fsd_hits_, fsd_branch); + man->AddMatching(match_to_, out_branch_, vtx_tracks_2_fsd_); + man->AddMatching(out_branch_, mc_tracks_, fsd_hits_2_mc_tracks_); +} + +FairTrackParam CbmFsdHitsConverter::ExtrapolateGtrack(Double_t zpos, FairTrackParam params) +{ + // follow inspiration from CbmL1TofMerger + FairTrackParam returnParams; + CbmKFTrack kfTrack; + kfTrack.SetTrackParam(params); + kfTrack.Extrapolate(zpos); //this will do straight track extrapolation + kfTrack.GetTrackParam(returnParams); + return returnParams; +} + + +Double_t CbmFsdHitsConverter::Chi2FsdhitGtrack(CbmFsdHit* hit, FairTrackParam inputParams) +{ + FairTrackParam params = ExtrapolateGtrack(hit->GetZ(), inputParams); + + Float_t dX = params.GetX() - hit->GetX(); + Float_t dY = params.GetY() - hit->GetY(); + + Double_t cxx = params.GetCovariance(0, 0) + hit->GetDx() * hit->GetDx(); + Double_t cxy = params.GetCovariance(0, 1) + hit->GetDxy() * hit->GetDxy(); + Double_t cyy = params.GetCovariance(1, 1) + hit->GetDy() * hit->GetDy(); + Double_t chi2 = 0.5 * (dX * dX * cxx - 2 * dX * dY * cxy + dY * dY * cyy) / (cxx * cyy - cxy * cxy); + + return chi2; +} + +void CbmFsdHitsConverter::ProcessData(CbmEvent* event) +{ + assert(cbm_fsd_hits_); + fsd_hits_->ClearChannels(); + vtx_tracks_2_fsd_->Clear(); + fsd_hits_2_mc_tracks_->Clear(); + + auto* out_config_ = AnalysisTree::TaskManager::GetInstance()->GetConfig(); + const auto& branch = out_config_->GetBranchConfig(out_branch_); + + auto rec_tracks_map = GetMatchMap(match_to_); + auto sim_tracks_map = GetMatchMap(mc_tracks_); + + int file_id{0}, event_id{0}; + if (event) { + auto match = event->GetMatch(); + if (!match) return; + file_id = event->GetMatch()->GetMatchedLink().GetFile(); + event_id = event->GetMatch()->GetMatchedLink().GetEntry(); + } + else { + event_id = FairRootManager::Instance()->GetEntryNr(); + } + + const int n_fsd_hits = event ? event->GetNofData(ECbmDataType::kFsdHit) : cbm_fsd_hits_->GetEntriesFast(); + if (n_fsd_hits <= 0) { + LOG(warn) << "No FSD hits!"; + return; + } + + const int n_tracks = event ? event->GetNofData(ECbmDataType::kGlobalTrack) : cbm_global_tracks_->GetEntriesFast(); + if (n_tracks <= 0) { + LOG(warn) << "No Global Tracks!"; + return; + } + + fsd_hits_->Reserve(n_fsd_hits); + + // first loop over all FSD hits + for (Int_t ifh = 0; ifh < n_fsd_hits; ifh++) { + const auto fsdHI = event ? event->GetIndex(ECbmDataType::kFsdHit, ifh) : ifh; + auto* fsdHit = static_cast<CbmFsdHit*>(cbm_fsd_hits_->At(fsdHI)); + + auto& hit = fsd_hits_->AddChannel(branch); + + const Float_t hitX = fsdHit->GetX(); + const Float_t hitY = fsdHit->GetY(); + const Float_t hitZ = fsdHit->GetZ(); + const Float_t eLoss = fsdHit->GetEdep(); + const Float_t time = fsdHit->GetTime(); + + hit.SetPosition(hitX, hitY, hitZ); + hit.SetSignal(time); + hit.SetField(eLoss, i_edep_); + + Int_t multMC = 0; + Float_t highestWeight = 0.; + const auto* fsdHitMatch = dynamic_cast<CbmMatch*>(cbm_fsd_hitmatch_->At(fsdHI)); + if (fsdHitMatch && fsdHitMatch->GetNofLinks() > 0) { + highestWeight = fsdHitMatch->GetMatchedLink().GetWeight(); + + for (int32_t ilDigi = 0; ilDigi < fsdHitMatch->GetNofLinks(); ilDigi++) { + const auto& digiLink = fsdHitMatch->GetLink(ilDigi); + if (digiLink.GetFile() != file_id || digiLink.GetEntry() != event_id) { // match from different event + continue; + } + + const auto* fsdDigiMatch = fDigiMan->GetMatch(ECbmModuleId::kFsd, digiLink.GetIndex()); + if (fsdDigiMatch && fsdDigiMatch->GetNofLinks() > 0) { + for (int32_t ilPoint = 0; ilPoint < fsdDigiMatch->GetNofLinks(); ilPoint++) { + const auto& pointLink = fsdDigiMatch->GetLink(ilPoint); + if (pointLink.GetFile() != file_id || pointLink.GetEntry() != event_id) { // match from different event + continue; + } + + multMC++; // increase counter of MC multiplicity + + // add matching between FSD hit and MC track + const auto* fsdPoint = dynamic_cast<FairMCPoint*>(cbm_fsd_points_new_->Get(pointLink)); + Int_t mc_track_id = fsdPoint->GetTrackID(); + if (mc_track_id >= 0) { + auto it = sim_tracks_map.find(mc_track_id); + if (it != sim_tracks_map.end()) { // match is found + fsd_hits_2_mc_tracks_->AddMatch(hit.GetId(), it->second); + } + } + + // for the "matched" links store the difference between Hit and Point + if (fsdHitMatch->GetMatchedLink().GetIndex() == ilDigi + && fsdDigiMatch->GetMatchedLink().GetIndex() == ilPoint) { + hit.SetField(float(fsdPoint->GetTime() - time), i_dtHP_); + hit.SetField(float(fsdPoint->GetX() - hitX), i_dxHP_); + hit.SetField(float(fsdPoint->GetY() - hitY), i_dxHP_ + 1); + hit.SetField(float(fsdPoint->GetZ() - hitZ), i_dxHP_ + 2); + } + + } // end of loop over links to points + } + } // end of loop over links to digis + } // end of sanity check of FSD hit matches + + const Int_t hitMCmult = multMC; + const Float_t hitTopWeight = highestWeight; + hit.SetField(hitMCmult, i_multMC_); + hit.SetField(hitTopWeight, i_topW_); + + // now matching with Global (reco) tracks + Int_t bestMatchedIndex = -1; + Double_t bestChi2 = 0.; + for (Int_t igt = 0; igt < n_tracks; igt++) { + const auto trackIndex = event ? event->GetIndex(ECbmDataType::kGlobalTrack, igt) : igt; + const auto* globalTrack = static_cast<const CbmGlobalTrack*>(cbm_global_tracks_->At(trackIndex)); + FairTrackParam param_last = *(globalTrack->GetParamLast()); + + Double_t matchingChi2 = Chi2FsdhitGtrack(fsdHit, param_last); + + if (bestChi2 > matchingChi2 || bestMatchedIndex < 0) { + bestChi2 = matchingChi2; + bestMatchedIndex = trackIndex; + } + } // end of loop over GlobalTracks + + const Int_t storedIndex = bestMatchedIndex; + const Float_t storedChi2 = static_cast<Float_t>(bestChi2); + hit.SetField(storedChi2, i_chi2_); + hit.SetField(storedIndex, i_bestMatchedGTrack_); + + if ((bestMatchedIndex >= 0) && (bestChi2 > fsdgtrack_minChi2_) && (bestChi2 < fsdgtrack_maxChi2_)) { + const auto trackIndex = event ? event->GetIndex(ECbmDataType::kGlobalTrack, bestMatchedIndex) : bestMatchedIndex; + const auto* globalTrack = static_cast<const CbmGlobalTrack*>(cbm_global_tracks_->At(trackIndex)); + FairTrackParam param_last = *(globalTrack->GetParamLast()); + FairTrackParam param_fsd = ExtrapolateGtrack(hitZ, param_last); + + TVector3 p_fsd; + param_fsd.Momentum(p_fsd); + + const Float_t p = p_fsd.Mag(); + const Int_t q = param_fsd.GetQp() > 0 ? 1 : -1; + const Float_t l = globalTrack->GetLength(); // l is calculated by global tracking + const Float_t beta = event ? l / ((time - event->GetTzero()) * 29.9792458) : 0; + const Float_t m2 = event ? p * p * (1. / (beta * beta) - 1.) : -1.; + + hit.SetField(m2, i_mass2_); + hit.SetField(float(q * p), i_qp_); + hit.SetField(float(param_fsd.GetX() - hitX), i_dx_); + hit.SetField(float(param_fsd.GetY() - hitY), i_dx_ + 1); + hit.SetField(float(param_fsd.GetZ() - hitZ), i_dx_ + 2); + hit.SetField(l, i_l_); + hit.SetField(time, i_t_); + + if (rec_tracks_map.empty()) { + continue; + } + const Int_t stsTrackIndex = globalTrack->GetStsTrackIndex(); + if (rec_tracks_map.find(stsTrackIndex) != rec_tracks_map.end()) { + vtx_tracks_2_fsd_->AddMatch(rec_tracks_map.find(stsTrackIndex)->second, hit.GetId()); + } + } + } // end of loop over FSD hits +} + + +CbmFsdHitsConverter::~CbmFsdHitsConverter() +{ + delete fsd_hits_; + delete vtx_tracks_2_fsd_; +}; diff --git a/analysis/common/analysis_tree_converter/CbmFsdHitsConverter.h b/analysis/common/analysis_tree_converter/CbmFsdHitsConverter.h new file mode 100644 index 0000000000..2e3ca7abb3 --- /dev/null +++ b/analysis/common/analysis_tree_converter/CbmFsdHitsConverter.h @@ -0,0 +1,94 @@ +/* Copyright (C) 2023 Physikalisches Institut, Eberhard Karls Universitaet Tuebingen, Tuebingen + SPDX-License-Identifier: GPL-3.0-only + Authors: Lukas Chlad [committer] */ + +#ifndef ANALYSIS_TREE_FSDHITSCONVERTER_H +#define ANALYSIS_TREE_FSDHITSCONVERTER_H + +#include "AnalysisTree/Detector.hpp" +#include "CbmConverterTask.h" + +class TClonesArray; +class FairTrackParam; +class CbmMCDataManager; +class CbmMCDataArray; +class CbmDigiManager; +class CbmFsdHit; + +namespace AnalysisTree +{ + class Matching; +} + +class CbmFsdHitsConverter final : public CbmConverterTask { + public: + explicit CbmFsdHitsConverter(std::string out_branch_name, std::string match_to = "") + : CbmConverterTask(std::move(out_branch_name), std::move(match_to)){}; + + ~CbmFsdHitsConverter() final; + + void Init() final; + void ProcessData(CbmEvent* event) final; + void Finish() final{}; + + Double_t GetMinChi2GtrackHit() { return fsdgtrack_minChi2_; }; + Double_t GetMaxChi2GtrackHit() { return fsdgtrack_maxChi2_; }; + void SetMinChi2GtrackHit(Double_t chi2) { fsdgtrack_minChi2_ = chi2; }; + void SetMaxChi2GtrackHit(Double_t chi2) { fsdgtrack_maxChi2_ = chi2; }; + + private: + FairTrackParam ExtrapolateGtrack(Double_t zpos, FairTrackParam params); + Double_t Chi2FsdhitGtrack(CbmFsdHit* hit, FairTrackParam inputParams); + + const std::map<int, int>& GetMatchMap(const std::string& name) const + { + const auto& it = indexes_map_->find(name); + if (it == indexes_map_->end()) { + throw std::runtime_error(name + " is not found to match with FSD hits"); + } + return it->second; + } + std::string mc_tracks_{"SimParticles"}; + + TClonesArray* cbm_global_tracks_{nullptr}; + TClonesArray* cbm_sts_tracks_{nullptr}; + TClonesArray* cbm_tof_hits_{nullptr}; + TClonesArray* cbm_fsd_hits_{nullptr}; + TClonesArray* cbm_fsd_hitmatch_{nullptr}; + TClonesArray* cbm_mc_tracks_{nullptr}; + + CbmDigiManager* fDigiMan{nullptr}; + //TClonesArray* cbm_fsd_digimatch_ {nullptr}; + //TClonesArray* cbm_fsd_digis_ {nullptr}; + + CbmMCDataManager* cbm_mc_manager_{nullptr}; + //CbmMCDataArray* cbm_mc_tracks_new_ {nullptr}; + CbmMCDataArray* cbm_fsd_points_new_{nullptr}; + + AnalysisTree::HitDetector* fsd_hits_{nullptr}; + AnalysisTree::Matching* vtx_tracks_2_fsd_{ + nullptr}; // Matching of Reconstructed Global Tracks (extrapolated via CbmKFTrack to fixed Z) to FSD hits, the matching can be configured by cutting on chi2 + AnalysisTree::Matching* fsd_hits_2_mc_tracks_{ + nullptr}; // Matching of MC Tracks with highest weight (largest energy deposition) to FSD hits + + int i_mass2_{AnalysisTree::UndefValueInt}; + int i_qp_{AnalysisTree::UndefValueInt}; + int i_dx_{AnalysisTree::UndefValueInt}; + int i_t_{AnalysisTree::UndefValueInt}; + int i_l_{AnalysisTree::UndefValueInt}; + int i_edep_{AnalysisTree::UndefValueInt}; + int i_chi2_{AnalysisTree::UndefValueInt}; + int i_bestMatchedGTrack_{AnalysisTree::UndefValueInt}; + int i_multMC_{AnalysisTree::UndefValueInt}; + int i_topW_{AnalysisTree::UndefValueInt}; + int i_dxHP_{AnalysisTree::UndefValueInt}; + int i_dtHP_{AnalysisTree::UndefValueInt}; + + + Double_t fsdgtrack_minChi2_{0.}; + Double_t fsdgtrack_maxChi2_{0.}; + + ClassDef(CbmFsdHitsConverter, 1) +}; + +#endif // ANALYSIS_TREE_FSDHITSCONVERTER_H diff --git a/analysis/common/analysis_tree_converter/CbmFsdModulesConverter.cxx b/analysis/common/analysis_tree_converter/CbmFsdModulesConverter.cxx new file mode 100644 index 0000000000..1609967b0e --- /dev/null +++ b/analysis/common/analysis_tree_converter/CbmFsdModulesConverter.cxx @@ -0,0 +1,69 @@ +/* Copyright (C) 2020-2021 Physikalisches Institut, Eberhard Karls Universität Tuebingen, Tuebingen + SPDX-License-Identifier: GPL-3.0-only + Authors: Viktor Klochkov [committer] */ + +#include "CbmFsdModulesConverter.h" + +#include "AnalysisTree/Detector.hpp" +#include "CbmDefs.h" +#include "CbmEvent.h" +#include "CbmFsdHit.h" +#include "FairRootManager.h" +#include "TClonesArray.h" + +#include <AnalysisTree/TaskManager.hpp> +#include <cassert> +#include <vector> + +ClassImp(CbmFsdModulesConverter); + +void CbmFsdModulesConverter::Init() +{ + assert(!out_branch_.empty()); + auto* ioman = FairRootManager::Instance(); + assert(ioman != nullptr); + cbm_fsd_hits_ = (TClonesArray*) ioman->GetObject("FsdHit"); + + AnalysisTree::BranchConfig fsd_branch(out_branch_, AnalysisTree::DetType::kModule); + + auto* man = AnalysisTree::TaskManager::GetInstance(); + man->AddBranch(fsd_modules_, fsd_branch); +} + + +void CbmFsdModulesConverter::ProcessData(CbmEvent* event) +{ + assert(cbm_fsd_hits_); + fsd_modules_->ClearChannels(); + + CbmFsdHit* hit{nullptr}; + + auto* data_header = AnalysisTree::TaskManager::GetInstance()->GetDataHeader(); + auto* config = AnalysisTree::TaskManager::GetInstance()->GetConfig(); + const auto& branch = config->GetBranchConfig(out_branch_); + + const int n_fsd_modules = data_header->GetModulePositions(0).GetNumberOfChannels(); + + fsd_modules_->Reserve(n_fsd_modules); + for (int i = 0; i < n_fsd_modules; ++i) { + auto& module = fsd_modules_->AddChannel(branch); + } + + const int nFsdHits = event ? event->GetNofData(ECbmDataType::kFsdHit) : cbm_fsd_hits_->GetEntriesFast(); + if (nFsdHits <= 0) { + LOG(warn) << "No FSD hits!"; + return; + } + + for (int i = 0; i < nFsdHits; ++i) { + hit = (CbmFsdHit*) cbm_fsd_hits_->At(i); + if (hit == nullptr) continue; + auto& module = fsd_modules_->Channel(hit->GetModuleId()); + module.SetNumber(i); + module.SetSignal(hit->GetEdep()); + } +} + +void CbmFsdModulesConverter::Finish() {} + +CbmFsdModulesConverter::~CbmFsdModulesConverter() { delete fsd_modules_; }; diff --git a/analysis/common/analysis_tree_converter/CbmFsdModulesConverter.h b/analysis/common/analysis_tree_converter/CbmFsdModulesConverter.h new file mode 100644 index 0000000000..65a42d3267 --- /dev/null +++ b/analysis/common/analysis_tree_converter/CbmFsdModulesConverter.h @@ -0,0 +1,31 @@ +/* Copyright (C) 2020-2021 Physikalisches Institut, Eberhard Karls Universitaet Tuebingen, Tuebingen + SPDX-License-Identifier: GPL-3.0-only + Authors: Viktor Klochkov [committer] */ + +#ifndef ANALYSIS_TREE_FSDMODULESCONVERTER_H_ +#define ANALYSIS_TREE_FSDMODULESCONVERTER_H_ + +#include "AnalysisTree/Detector.hpp" +#include "CbmConverterTask.h" + +class TClonesArray; + +class CbmFsdModulesConverter final : public CbmConverterTask { + public: + explicit CbmFsdModulesConverter(std::string out_branch_name, std::string match_to = "") + : CbmConverterTask(std::move(out_branch_name), std::move(match_to)){}; + + ~CbmFsdModulesConverter() final; + + void Init() final; + void ProcessData(CbmEvent* event) final; + void Finish() final; + + private: + AnalysisTree::ModuleDetector* fsd_modules_{nullptr}; + TClonesArray* cbm_fsd_hits_{nullptr}; + + ClassDef(CbmFsdModulesConverter, 1) +}; + +#endif // ANALYSIS_TREE_FSDMODULESCONVERTER_H_ diff --git a/analysis/common/analysis_tree_converter/CbmPsdModulesConverter.cxx b/analysis/common/analysis_tree_converter/CbmPsdModulesConverter.cxx index 14db617c5a..e3121c71cb 100644 --- a/analysis/common/analysis_tree_converter/CbmPsdModulesConverter.cxx +++ b/analysis/common/analysis_tree_converter/CbmPsdModulesConverter.cxx @@ -50,7 +50,6 @@ void CbmPsdModulesConverter::ProcessData(CbmEvent* event) psd_modules_->Reserve(n_psd_modules); for (int i = 0; i < n_psd_modules; ++i) { auto& module = psd_modules_->AddChannel(branch); - module.SetSignal(0.f); } const int nPsdHits = event ? event->GetNofData(ECbmDataType::kPsdHit) : cbm_psd_hits_->GetEntriesFast(); @@ -62,8 +61,8 @@ void CbmPsdModulesConverter::ProcessData(CbmEvent* event) for (int i = 0; i < nPsdHits; ++i) { hit = (CbmPsdHit*) cbm_psd_hits_->At(i); if (hit == nullptr) continue; - auto& module = psd_modules_->Channel(hit->GetModuleID() - 1); - module.SetNumber(i + 1); + auto& module = psd_modules_->Channel(i); + module.SetNumber(hit->GetModuleID()); module.SetSignal(hit->GetEdep()); } } diff --git a/analysis/common/analysis_tree_converter/config/ATConfig_event_ideal.yaml b/analysis/common/analysis_tree_converter/config/ATConfig_event_ideal.yaml index 16b6c3683d..e1a0779f72 100644 --- a/analysis/common/analysis_tree_converter/config/ATConfig_event_ideal.yaml +++ b/analysis/common/analysis_tree_converter/config/ATConfig_event_ideal.yaml @@ -7,3 +7,6 @@ global: timeslicelength: 1.e5 collisionSystem: "Au+Au" beamMomentum: 12. +fsdhits: + gtrackmatch_minChi2: -1 + gtrackmatch_maxChi2: 10000 diff --git a/analysis/common/analysis_tree_converter/config/ATConfig_timeslice.yaml b/analysis/common/analysis_tree_converter/config/ATConfig_timeslice.yaml index 64e981d91d..a447f5817a 100644 --- a/analysis/common/analysis_tree_converter/config/ATConfig_timeslice.yaml +++ b/analysis/common/analysis_tree_converter/config/ATConfig_timeslice.yaml @@ -7,3 +7,6 @@ global: timeslicelength: 1.e5 collisionSystem: "Au+Au" beamMomentum: 12. +fsdhits: + gtrackmatch_minChi2: -1 + gtrackmatch_maxChi2: 10000 diff --git a/analysis/common/analysis_tree_converter/steer/Config.cxx b/analysis/common/analysis_tree_converter/steer/Config.cxx index f8f12b6664..6105e46600 100644 --- a/analysis/common/analysis_tree_converter/steer/Config.cxx +++ b/analysis/common/analysis_tree_converter/steer/Config.cxx @@ -38,6 +38,10 @@ namespace cbm::atconverter f_glb_tslength = settings["global"]["timeslicelength"].as<float>(); f_glb_system = settings["global"]["collisionSystem"].as<string>(); f_glb_beamMom = settings["global"]["beamMomentum"].as<float>(); + + // --- Fsd hits converter settings + f_fsd_minChi2match = settings["fsdhits"]["gtrackmatch_minChi2"].as<double>(); + f_fsd_maxChi2match = settings["fsdhits"]["gtrackmatch_maxChi2"].as<double>(); } // ---------------------------------------------------------------------------- @@ -83,6 +87,10 @@ namespace cbm::atconverter settings["global"]["collisionSystem"] = f_glb_system; settings["global"]["beamMomentum"] = f_glb_beamMom; + // --- Fsd hits converter settings + settings["fsdhits"]["gtrackmatch_minChi2"] = f_fsd_minChi2match; + settings["fsdhits"]["gtrackmatch_maxChi2"] = f_fsd_maxChi2match; + return settings; } // ---------------------------------------------------------------------------- diff --git a/analysis/common/analysis_tree_converter/steer/Config.h b/analysis/common/analysis_tree_converter/steer/Config.h index 6406533236..ad9d32c7cd 100644 --- a/analysis/common/analysis_tree_converter/steer/Config.h +++ b/analysis/common/analysis_tree_converter/steer/Config.h @@ -94,6 +94,10 @@ namespace cbm::atconverter // --- Event builder ECbmEvbuildType f_evbuild_type = ECbmEvbuildType::Undefined; + + // --- Fsd hits converter settings + float f_fsd_minChi2match = -1.; + float f_fsd_maxChi2match = 10000.; }; } // namespace cbm::atconverter diff --git a/analysis/common/analysis_tree_converter/steer/Run.cxx b/analysis/common/analysis_tree_converter/steer/Run.cxx index 2b300e7f36..70a5aeac6b 100644 --- a/analysis/common/analysis_tree_converter/steer/Run.cxx +++ b/analysis/common/analysis_tree_converter/steer/Run.cxx @@ -65,6 +65,33 @@ namespace cbm::atconverter // -------------------------------------------------------------------------- + // ----- Check existence of reco branch --------------------------------- + void Run::CheckRecoBranch(TTree* tree, ECbmModuleId detector) + { + TString branchName = ToString(detector); + branchName += "Hit"; + if (tree->GetBranchStatus(branchName.Data())) { + LOG(info) << GetName() << ": Found branch " << branchName; + fDataPresent.insert(detector); + } + } + // -------------------------------------------------------------------------- + + + // ----- Check which input reco branches are present -------------------- + void Run::CheckInputBranches(FairFileSource* source) + { + TFile* inFile = source->GetInFile(); + if (!inFile) throw std::runtime_error("No input file"); + TTree* inTree = dynamic_cast<TTree*>(inFile->Get("cbmsim")); + if (!inTree) throw std::runtime_error("No input tree"); + + for (ECbmModuleId detector = ECbmModuleId::kMvd; detector != ECbmModuleId::kNofSystems; ++detector) + CheckRecoBranch(inTree, detector); + } + // -------------------------------------------------------------------------- + + // ----- Create the topology -------------------------------------------- void Run::CreateTopology() { @@ -113,6 +140,10 @@ namespace cbm::atconverter fRun.SetSource(source); fRun.SetSink(new FairRootFileSink(fOutput)); + // --- Check presence of input (reco) branches + LOG(info) << GetName() << ": Checking reco input..."; + CheckInputBranches(source); + // --- Geometry setup LOG(info) << GetName() << ": Loading setup " << fSetupTag; fSetup = CbmSetup::Instance(); diff --git a/analysis/common/analysis_tree_converter/steer/Run.h b/analysis/common/analysis_tree_converter/steer/Run.h index a9f95a19c4..2c5b10b9df 100644 --- a/analysis/common/analysis_tree_converter/steer/Run.h +++ b/analysis/common/analysis_tree_converter/steer/Run.h @@ -11,16 +11,16 @@ #define CBM_ATCONVERTER_STEER_RUN_H 1 #include "CbmDefs.h" +#include "Config.h" #include <FairRunAna.h> #include <TNamed.h> #include <TString.h> +#include <TTree.h> #include <string> -#include "Config.h" - class CbmSetup; class FairTask; @@ -128,6 +128,17 @@ namespace cbm::atconverter bool CheckFile(const char* fileName); + /** @brief Check and mark presence of reco branches + ** @param tree Pointer to ROOT tree + ** @param detector ECbmModuleId + **/ + void CheckRecoBranch(TTree* tree, ECbmModuleId detector); + + + /** @brief Check the presence of reco input branches **/ + void CheckInputBranches(FairFileSource* source); + + /** @brief Create the reconstruction task topology (chain) **/ void CreateTopology(); diff --git a/analysis/common/analysis_tree_converter/steer/TaskFactory.cxx b/analysis/common/analysis_tree_converter/steer/TaskFactory.cxx index 1ccc65e2fe..519a8f933b 100644 --- a/analysis/common/analysis_tree_converter/steer/TaskFactory.cxx +++ b/analysis/common/analysis_tree_converter/steer/TaskFactory.cxx @@ -10,6 +10,8 @@ #include "TaskFactory.h" #include "CbmConverterManager.h" +#include "CbmFsdHitsConverter.h" +#include "CbmFsdModulesConverter.h" #include "CbmKF.h" #include "CbmL1.h" #include "CbmMCDataManager.h" @@ -83,10 +85,19 @@ namespace cbm::atconverter ststracksconverter->SetIsReproduceCbmKFPF(); man->AddTask(ststracksconverter); - man->AddTask(new CbmRichRingsConverter("RichRings", "VtxTracks")); + if (fRun->IsDataPresent(ECbmModuleId::kRich)) man->AddTask(new CbmRichRingsConverter("RichRings", "VtxTracks")); man->AddTask(new CbmTofHitsConverter("TofHits", "VtxTracks")); man->AddTask(new CbmTrdTracksConverter("TrdTracks", "VtxTracks")); - man->AddTask(new CbmPsdModulesConverter("PsdModules")); + if (fRun->IsDataPresent(ECbmModuleId::kPsd)) man->AddTask(new CbmPsdModulesConverter("PsdModules")); + + if (fRun->IsDataPresent(ECbmModuleId::kFsd)) { + man->AddTask(new CbmFsdModulesConverter("FsdModules")); + + CbmFsdHitsConverter* fsdHitsConverter = new CbmFsdHitsConverter("FsdHits", "VtxTracks"); + fsdHitsConverter->SetMinChi2GtrackHit(fRun->fConfig.f_fsd_minChi2match); + fsdHitsConverter->SetMaxChi2GtrackHit(fRun->fConfig.f_fsd_maxChi2match); + man->AddTask(fsdHitsConverter); + } fRun->AddTask(man); } diff --git a/macro/PWG/common/production/run_analysis_tree_maker_json_config.C b/macro/PWG/common/production/run_analysis_tree_maker_json_config.C index 2b4dfa2985..4707b43c1a 100644 --- a/macro/PWG/common/production/run_analysis_tree_maker_json_config.C +++ b/macro/PWG/common/production/run_analysis_tree_maker_json_config.C @@ -158,7 +158,15 @@ void run_analysis_tree_maker_json_config(TString traPath = "test", TString rawPa man->AddTask(new CbmRichRingsConverter("RichRings", "VtxTracks")); man->AddTask(new CbmTofHitsConverter("TofHits", "VtxTracks")); man->AddTask(new CbmTrdTracksConverter("TrdTracks", "VtxTracks")); - man->AddTask(new CbmPsdModulesConverter("PsdModules")); + if (setup->IsActive(ECbmModuleId::kPsd)) man->AddTask(new CbmPsdModulesConverter("PsdModules")); + if (setup->IsActive(ECbmModuleId::kFsd)) { + man->AddTask(new CbmFsdModulesConverter("FsdModules")); + + CbmFsdHitsConverter* taskCbmFsdHitsConverter = new CbmFsdHitsConverter("FsdHits", "VtxTracks"); + taskCbmFsdHitsConverter->SetMinChi2GtrackHit(-1.); + taskCbmFsdHitsConverter->SetMaxChi2GtrackHit(10000.); + man->AddTask(taskCbmFsdHitsConverter); + } run->AddTask(man); -- GitLab