2222#define COMMON_TOOLS_PID_PIDTPCMODULE_H_
2323
2424#include " Common/CCDB/ctpRateFetcher.h"
25+ #include " Common/Core/CollisionTypeHelper.h"
2526#include " Common/Core/PID/TPCPIDResponse.h"
2627#include " Common/Core/TableHelper.h"
2728#include " Common/DataModel/PIDResponseTPC.h"
2829#include " Common/TableProducer/PID/pidTPCBase.h"
2930#include " Tools/ML/model.h"
3031
32+ #include < DataFormatsParameters/GRPLHCIFData.h>
3133#include < Framework/AnalysisDataModel.h>
3234#include < Framework/AnalysisHelpers.h>
3335#include < Framework/Configurable.h>
@@ -127,13 +129,13 @@ struct pidTPCConfigurables : o2::framework::ConfigurableGroup {
127129 o2::framework::Configurable<int > useNetworkHe{" useNetworkHe" , 1 , {" Switch for applying neural network on the helium3 mass hypothesis (if network enabled) (set to 0 to disable)" }};
128130 o2::framework::Configurable<int > useNetworkAl{" useNetworkAl" , 1 , {" Switch for applying neural network on the alpha mass hypothesis (if network enabled) (set to 0 to disable)" }};
129131 o2::framework::Configurable<float > networkBetaGammaCutoff{" networkBetaGammaCutoff" , 0.45 , {" Lower value of beta-gamma to override the NN application" }};
130- o2::framework::Configurable<std::string> irSource{ " irSource " , " ZNC hadronic " , " Estimator of the interaction rate (Recommended: pp --> T0VTX, Pb-Pb --> ZNC hadronic) " };
132+ o2::framework::Configurable<std::string> cfgPathGrpLhcIf{ " ccdb-path-grplhcif " , " GLO/Config/GRPLHCIF " , " Path on the CCDB for the GRPLHCIF object " };
131133};
132134
133135// helper getter - FIXME should be separate
134136int getPIDIndex (const int pdgCode) // Get O2 PID index corresponding to MC PDG code
135137{
136- switch (abs (pdgCode)) {
138+ switch (std:: abs (pdgCode)) {
137139 case 11 :
138140 return o2::track::PID::Electron;
139141 case 13 :
@@ -214,6 +216,10 @@ class pidTPCModule
214216 std::vector<int > speciesNetworkFlags = std::vector<int >(9 );
215217 std::string networkVersion;
216218
219+ // To get automatically the proper Hadronic Rate
220+ std::string irSource = " " ;
221+ o2::common::core::CollisionSystemType::collType collsys = o2::common::core::CollisionSystemType::kCollSysUndef ;
222+
217223 // Parametrization configuration
218224 bool useCCDBParam = false ;
219225
@@ -323,6 +329,14 @@ class pidTPCModule
323329 }
324330 LOG (info) << " Successfully retrieved TPC PID object from CCDB for timestamp " << time << " , period " << headers[" LPMProductionTag" ] << " , recoPass " << headers[" RecoPassName" ];
325331 metadata[" RecoPassName" ] = headers[" RecoPassName" ]; // Force pass number for NN request to match retrieved BB
332+ o2::parameters::GRPLHCIFData* grpo = ccdb->template getForTimeStamp <o2::parameters::GRPLHCIFData>(pidTPCopts.cfgPathGrpLhcIf .value , time);
333+ LOG (info) << " collision type::" << CollisionSystemType::getCollisionTypeFromGrp (grpo);
334+ collsys = CollisionSystemType::getCollisionTypeFromGrp (grpo);
335+ if (collsys == CollisionSystemType::kCollSyspp ) {
336+ irSource = std::string (" T0VTX" );
337+ } else {
338+ irSource = std::string (" ZNC hadronic" );
339+ }
326340 response->PrintAll ();
327341 }
328342 }
@@ -368,8 +382,8 @@ class pidTPCModule
368382 } // end init
369383
370384 // __________________________________________________
371- template <typename TCCDB, typename TCCDBApi, typename C, typename M, typename T, typename B>
372- std::vector<float > createNetworkPrediction (TCCDB& ccdb, TCCDBApi& ccdbApi, C const & collisions, M const & mults, T const & tracks, B const & bcs, const size_t size)
385+ template <typename TCCDB, typename TCCDBApi, typename M, typename T, typename B>
386+ std::vector<float > createNetworkPrediction (TCCDB& ccdb, TCCDBApi& ccdbApi, soa::Join<aod::Collisions, aod::EvSels> const & collisions, M const & mults, T const & tracks, B const & bcs, const size_t size)
373387 {
374388
375389 std::vector<float > network_prediction;
@@ -397,6 +411,14 @@ class pidTPCModule
397411 }
398412 LOG (info) << " Successfully retrieved TPC PID object from CCDB for timestamp " << bc.timestamp () << " , period " << headers[" LPMProductionTag" ] << " , recoPass " << headers[" RecoPassName" ];
399413 metadata[" RecoPassName" ] = headers[" RecoPassName" ]; // Force pass number for NN request to match retrieved BB
414+ o2::parameters::GRPLHCIFData* grpo = ccdb->template getForTimeStamp <o2::parameters::GRPLHCIFData>(pidTPCopts.cfgPathGrpLhcIf .value , bc.timestamp ());
415+ LOG (info) << " Collision type::" << CollisionSystemType::getCollisionTypeFromGrp (grpo);
416+ collsys = CollisionSystemType::getCollisionTypeFromGrp (grpo);
417+ if (collsys == CollisionSystemType::kCollSyspp ) {
418+ irSource = std::string (" T0VTX" );
419+ } else {
420+ irSource = std::string (" ZNC hadronic" );
421+ }
400422 response->PrintAll ();
401423 }
402424
@@ -430,11 +452,26 @@ class pidTPCModule
430452 uint64_t counter_track_props = 0 ;
431453 int loop_counter = 0 ;
432454
455+ // To load the Hadronic rate once for each collision
456+ float hadronicRateBegin = 0 .;
457+ std::vector<float > hadronicRateForCollision (collisions.size (), 0 .0f );
458+ size_t i = 0 ;
459+ for (const auto & collision : collisions) {
460+ const auto & bc = collision.template bc_as <B>();
461+ hadronicRateForCollision[i] = mRateFetcher .fetch (ccdb.service , bc.timestamp (), bc.runNumber (), irSource) * 1 .e -3 ;
462+ i++;
463+ }
464+ auto bc = bcs.begin ();
465+ hadronicRateBegin = mRateFetcher .fetch (ccdb.service , bc.timestamp (), bc.runNumber (), irSource) * 1 .e -3 ; // kHz
466+
433467 // Filling a std::vector<float> to be evaluated by the network
434468 // Evaluation on single tracks brings huge overhead: Thus evaluation is done on one large vector
435- for (int i = 0 ; i < 9 ; i++) { // Loop over particle number for which network correction is used
436- float hadronicRate = 0 .;
437- uint64_t timeStamp_bcOld = 0 ;
469+ static constexpr int NParticleTypes = 9 ;
470+ constexpr int ExpectedInputDimensionsNNV2 = 7 ;
471+ constexpr int ExpectedInputDimensionsNNV3 = 8 ;
472+ constexpr auto NetworkVersionV2 = " 2" ;
473+ constexpr auto NetworkVersionV3 = " 3" ;
474+ for (int i = 0 ; i < NParticleTypes; i++) { // Loop over particle number for which network correction is used
438475 for (auto const & trk : tracks) {
439476 if (!trk.hasTPC ()) {
440477 continue ;
@@ -450,20 +487,24 @@ class pidTPCModule
450487 track_properties[counter_track_props + 3 ] = o2::track::pid_constants::sMasses [i];
451488 track_properties[counter_track_props + 4 ] = trk.has_collision () ? mults[trk.collisionId ()] / 11000 . : 1 .;
452489 track_properties[counter_track_props + 5 ] = std::sqrt (nNclNormalization / trk.tpcNClsFound ());
453- if (input_dimensions == 7 && networkVersion == " 2 " ) {
490+ if (input_dimensions == ExpectedInputDimensionsNNV2 && networkVersion == NetworkVersionV2 ) {
454491 track_properties[counter_track_props + 6 ] = trk.has_collision () ? collisions.iteratorAt (trk.collisionId ()).ft0cOccupancyInTimeRange () / 60000 . : 1 .;
455492 }
456- if (input_dimensions == 8 && networkVersion == " 3 " ) {
493+ if (input_dimensions == ExpectedInputDimensionsNNV3 && networkVersion == NetworkVersionV3 ) {
457494 track_properties[counter_track_props + 6 ] = trk.has_collision () ? collisions.iteratorAt (trk.collisionId ()).ft0cOccupancyInTimeRange () / 60000 . : 1 .;
458495 if (trk.has_collision ()) {
459- auto trk_bc = (collisions.iteratorAt (trk.collisionId ())).template bc_as <B>();
460- if (trk_bc.timestamp () != timeStamp_bcOld) {
461- hadronicRate = mRateFetcher .fetch (ccdb.service , trk_bc.timestamp (), trk_bc.runNumber (), pidTPCopts.irSource .value ) * 1 .e -3 ;
496+ if (collsys == CollisionSystemType::kCollSyspp ) {
497+ track_properties[counter_track_props + 7 ] = hadronicRateForCollision[trk.collisionId ()] / 1500 .;
498+ } else {
499+ track_properties[counter_track_props + 7 ] = hadronicRateForCollision[trk.collisionId ()] / 50 .;
462500 }
463- timeStamp_bcOld = trk_bc.timestamp ();
464- track_properties[counter_track_props + 7 ] = hadronicRate / 50 .;
465501 } else {
466- track_properties[counter_track_props + 7 ] = 1 ;
502+ // asign Hadronic Rate at beginning of run if track does not belong to a collision
503+ if (collsys == CollisionSystemType::kCollSyspp ) {
504+ track_properties[counter_track_props + 7 ] = hadronicRateBegin / 1500 .;
505+ } else {
506+ track_properties[counter_track_props + 7 ] = hadronicRateBegin / 50 .;
507+ }
467508 }
468509 }
469510 counter_track_props += input_dimensions;
@@ -493,7 +534,7 @@ class pidTPCModule
493534
494535 // __________________________________________________
495536 template <typename T, typename NSF, typename NST>
496- void makePidTables (const int flagFull, NSF& tableFull, const int flagTiny, NST& tableTiny, const o2::track::PID::ID pid, const float tpcSignal, const T& trk, const long multTPC, const std::vector<float >& network_prediction, const int & count_tracks, const int & tracksForNet_size)
537+ void makePidTables (const int flagFull, NSF& tableFull, const int flagTiny, NST& tableTiny, const o2::track::PID::ID pid, const float tpcSignal, const T& trk, const int64_t multTPC, const std::vector<float >& network_prediction, const int & count_tracks, const int & tracksForNet_size)
497538 {
498539 if (flagFull != 1 && flagTiny != 1 ) {
499540 return ;
@@ -526,22 +567,24 @@ class pidTPCModule
526567
527568 float nSigma = -999 .f ;
528569 float bg = trk.tpcInnerParam () / o2::track::pid_constants::sMasses [pid]; // estimated beta-gamma for network cutoff
570+ constexpr int NumOutputNodesSymmetricSigma = 2 ;
571+ constexpr int NumOutputNodesAsymmetricSigma = 3 ;
529572 if (pidTPCopts.useNetworkCorrection && speciesNetworkFlags[pid] && trk.has_collision () && bg > pidTPCopts.networkBetaGammaCutoff ) {
530573
531574 // Here comes the application of the network. The output--dimensions of the network determine the application: 1: mean, 2: sigma, 3: sigma asymmetric
532575 // For now only the option 2: sigma will be used. The other options are kept if there would be demand later on
533576 if (network.getNumOutputNodes () == 1 ) { // Expected mean correction; no sigma correction
534577 nSigma = (tpcSignal - network_prediction[count_tracks + tracksForNet_size * pid] * expSignal) / expSigma;
535- } else if (network.getNumOutputNodes () == 2 ) { // Symmetric sigma correction
536- expSigma = (network_prediction[2 * (count_tracks + tracksForNet_size * pid) + 1 ] - network_prediction[2 * (count_tracks + tracksForNet_size * pid)]) * expSignal;
537- nSigma = (tpcSignal / expSignal - network_prediction[2 * (count_tracks + tracksForNet_size * pid)]) / (network_prediction[2 * (count_tracks + tracksForNet_size * pid) + 1 ] - network_prediction[2 * (count_tracks + tracksForNet_size * pid)]);
538- } else if (network.getNumOutputNodes () == 3 ) { // Asymmetric sigma corection
539- if (tpcSignal / expSignal >= network_prediction[3 * (count_tracks + tracksForNet_size * pid)]) {
540- expSigma = (network_prediction[3 * (count_tracks + tracksForNet_size * pid) + 1 ] - network_prediction[3 * (count_tracks + tracksForNet_size * pid)]) * expSignal;
541- nSigma = (tpcSignal / expSignal - network_prediction[3 * (count_tracks + tracksForNet_size * pid)]) / (network_prediction[3 * (count_tracks + tracksForNet_size * pid) + 1 ] - network_prediction[3 * (count_tracks + tracksForNet_size * pid)]);
578+ } else if (network.getNumOutputNodes () == NumOutputNodesSymmetricSigma ) { // Symmetric sigma correction
579+ expSigma = (network_prediction[NumOutputNodesSymmetricSigma * (count_tracks + tracksForNet_size * pid) + 1 ] - network_prediction[NumOutputNodesSymmetricSigma * (count_tracks + tracksForNet_size * pid)]) * expSignal;
580+ nSigma = (tpcSignal / expSignal - network_prediction[NumOutputNodesSymmetricSigma * (count_tracks + tracksForNet_size * pid)]) / (network_prediction[NumOutputNodesSymmetricSigma * (count_tracks + tracksForNet_size * pid) + 1 ] - network_prediction[NumOutputNodesSymmetricSigma * (count_tracks + tracksForNet_size * pid)]);
581+ } else if (network.getNumOutputNodes () == NumOutputNodesAsymmetricSigma ) { // Asymmetric sigma corection
582+ if (tpcSignal / expSignal >= network_prediction[NumOutputNodesAsymmetricSigma * (count_tracks + tracksForNet_size * pid)]) {
583+ expSigma = (network_prediction[NumOutputNodesAsymmetricSigma * (count_tracks + tracksForNet_size * pid) + 1 ] - network_prediction[NumOutputNodesAsymmetricSigma * (count_tracks + tracksForNet_size * pid)]) * expSignal;
584+ nSigma = (tpcSignal / expSignal - network_prediction[NumOutputNodesAsymmetricSigma * (count_tracks + tracksForNet_size * pid)]) / (network_prediction[NumOutputNodesAsymmetricSigma * (count_tracks + tracksForNet_size * pid) + 1 ] - network_prediction[NumOutputNodesAsymmetricSigma * (count_tracks + tracksForNet_size * pid)]);
542585 } else {
543- expSigma = (network_prediction[3 * (count_tracks + tracksForNet_size * pid)] - network_prediction[3 * (count_tracks + tracksForNet_size * pid) + 2 ]) * expSignal;
544- nSigma = (tpcSignal / expSignal - network_prediction[3 * (count_tracks + tracksForNet_size * pid)]) / (network_prediction[3 * (count_tracks + tracksForNet_size * pid)] - network_prediction[3 * (count_tracks + tracksForNet_size * pid) + 2 ]);
586+ expSigma = (network_prediction[NumOutputNodesAsymmetricSigma * (count_tracks + tracksForNet_size * pid)] - network_prediction[NumOutputNodesAsymmetricSigma * (count_tracks + tracksForNet_size * pid) + 2 ]) * expSignal;
587+ nSigma = (tpcSignal / expSignal - network_prediction[NumOutputNodesAsymmetricSigma * (count_tracks + tracksForNet_size * pid)]) / (network_prediction[NumOutputNodesAsymmetricSigma * (count_tracks + tracksForNet_size * pid)] - network_prediction[NumOutputNodesAsymmetricSigma * (count_tracks + tracksForNet_size * pid) + 2 ]);
545588 }
546589 } else {
547590 LOGF (fatal, " Network output-dimensions incompatible!" );
@@ -556,8 +599,8 @@ class pidTPCModule
556599 };
557600
558601 // __________________________________________________
559- template <typename TCCDB, typename TCCDBApi, typename TBCs, typename TCollisions, typename TTracks, typename TTracksQA, typename TProducts>
560- void process (TCCDB& ccdb, TCCDBApi& ccdbApi, TBCs const & bcs, TCollisions const & cols, TTracks const & tracks, TTracksQA const & tracksQA, TProducts& products)
602+ template <typename TCCDB, typename TCCDBApi, typename TBCs, typename TTracks, typename TTracksQA, typename TProducts>
603+ void process (TCCDB& ccdb, TCCDBApi& ccdbApi, TBCs const & bcs, soa::Join<aod::Collisions, aod::EvSels> const & cols, TTracks const & tracks, TTracksQA const & tracksQA, TProducts& products)
561604 {
562605 if (tracks.size () == 0 ) {
563606 return ; // empty protection
@@ -568,9 +611,9 @@ class pidTPCModule
568611 }
569612
570613 // preparatory step: we need the multiplicities for each collision
571- std::vector<int > pidmults;
572- long totalTPCtracks = 0 ;
573- long totalTPCnotStandalone = 0 ;
614+ std::vector<int64_t > pidmults;
615+ int64_t totalTPCtracks = 0 ;
616+ int64_t totalTPCnotStandalone = 0 ;
574617 pidmults.resize (cols.size (), 0 );
575618
576619 // faster counting
@@ -627,19 +670,33 @@ class pidTPCModule
627670
628671 // _______________________________________
629672 // process tracksQA in case present
630- std::vector<int64_t > indexTrack2TrackQA;
673+ std::vector<int64_t > indexTrack2TrackQA (outTable_size, - 1 ) ;
631674 if constexpr (soa::is_table<TTracksQA>) {
632675 for (const auto & trackQA : tracksQA) {
633676 indexTrack2TrackQA[trackQA.trackId ()] = trackQA.globalIndex ();
634677 }
635678 }
636679 // _______________________________________
637680
681+ // Fill Hadronic rate per collision in case CorrectedDEdx is requested
682+ std::vector<float > hadronicRateForCollision (cols.size (), 0 .0f );
683+ float hadronicRateBegin = 0 .0f ;
684+ if (pidTPCopts.useCorrecteddEdx ) {
685+ size_t i = 0 ;
686+ for (const auto & collision : cols) {
687+ const auto & bc = collision.template bc_as <aod::BCsWithTimestamps>();
688+ hadronicRateForCollision[i] = mRateFetcher .fetch (ccdb.service , bc.timestamp (), bc.runNumber (), irSource) * 1 .e -3 ;
689+ i++;
690+ }
691+ auto bc = bcs.begin ();
692+ hadronicRateBegin = mRateFetcher .fetch (ccdb.service , bc.timestamp (), bc.runNumber (), irSource) * 1 .e -3 ; // kHz
693+ }
694+
638695 for (auto const & trk : tracks) {
639696 // get the TPC signal to be used in the PID
640697 float tpcSignalToEvaluatePID = trk.tpcSignal ();
641698
642- int multTPC = 0 ;
699+ int64_t multTPC = 0 ;
643700 if (trk.has_collision ()) {
644701 multTPC = pidmults[trk.collisionId ()];
645702 }
@@ -662,24 +719,25 @@ class pidTPCModule
662719 int occupancy;
663720 if (trk.has_collision ()) {
664721 auto collision = cols.iteratorAt (trk.collisionId ());
665- auto bc = collision.template bc_as <aod::BCsWithTimestamps>();
666- const int runnumber = bc.runNumber ();
667- hadronicRate = mRateFetcher .fetch (ccdb.service , bc.timestamp (), runnumber, " ZNC hadronic" ) * 1 .e -3 ; // kHz
722+ hadronicRate = hadronicRateForCollision[trk.collisionId ()];
668723 occupancy = collision.trackOccupancyInTimeRange ();
669724 } else {
670- auto bc = bcs.begin ();
671- const int runnumber = bc.runNumber ();
672- hadronicRate = mRateFetcher .fetch (ccdb.service , bc.timestamp (), runnumber, " ZNC hadronic" ) * 1 .e -3 ; // kHz
725+ hadronicRate = hadronicRateBegin;
673726 occupancy = 0 ;
674727 }
675728
729+ constexpr float kExpectedTPCSignalMIP = 50 .0f ;
730+ constexpr float kMaxAllowedRatio = 1 .05f ;
731+ constexpr float kMinAllowedRatio = 0 .05f ;
732+ constexpr float kMaxAllowedOcc = 12 .0f ;
733+
676734 float fTPCSignal = tpcSignalToEvaluatePID;
677735 float fNormMultTPC = multTPC / 11000 .;
678736
679737 float fTrackOccN = occupancy / 1000 .;
680738 float fOccTPCN = fNormMultTPC * 10 ; // (fNormMultTPC*10).clip(0,12)
681- if (fOccTPCN > 12 )
682- fOccTPCN = 12 ;
739+ if (fOccTPCN > kMaxAllowedOcc )
740+ fOccTPCN = kMaxAllowedOcc ;
683741 else if (fOccTPCN < 0 )
684742 fOccTPCN = 0 ;
685743
@@ -688,11 +746,11 @@ class pidTPCModule
688746 float a1pt = std::abs (trk.signed1Pt ());
689747 float a1pt2 = a1pt * a1pt;
690748 float atgl = std::abs (trk.tgl ());
691- float mbb0R = 50 / fTPCSignal ;
692- if (mbb0R > 1.05 )
693- mbb0R = 1.05 ;
694- else if (mbb0R < 0.05 )
695- mbb0R = 0.05 ;
749+ float mbb0R = kExpectedTPCSignalMIP / fTPCSignal ;
750+ if (mbb0R > kMaxAllowedRatio )
751+ mbb0R = kMaxAllowedRatio ;
752+ else if (mbb0R < kMinAllowedRatio )
753+ mbb0R = kMinAllowedRatio ;
696754 // float mbb0R = max(0.05, min(50 / fTPCSignal, 1.05));
697755 float a1ptmbb0R = a1pt * mbb0R;
698756 float atglmbb0R = atgl * mbb0R;
@@ -702,11 +760,11 @@ class pidTPCModule
702760
703761 float fTPCSignalN_CR0 = str_dedx_correction.fReal_fTPCSignalN (vec_occu, vec_track);
704762
705- float mbb0R1 = 50 / (fTPCSignal / fTPCSignalN_CR0 );
706- if (mbb0R1 > 1.05 )
707- mbb0R1 = 1.05 ;
708- else if (mbb0R1 < 0.05 )
709- mbb0R1 = 0.05 ;
763+ float mbb0R1 = kExpectedTPCSignalMIP / (fTPCSignal / fTPCSignalN_CR0 );
764+ if (mbb0R1 > kMaxAllowedRatio )
765+ mbb0R1 = kMaxAllowedRatio ;
766+ else if (mbb0R1 < kMinAllowedRatio )
767+ mbb0R1 = kMinAllowedRatio ;
710768
711769 std::vector<float > vec_track1 = {mbb0R1, a1pt, atgl, atgl * mbb0R1, a1pt * mbb0R1, side, a1pt2};
712770 float fTPCSignalN_CR1 = str_dedx_correction.fReal_fTPCSignalN (vec_occu, vec_track1);
@@ -738,6 +796,14 @@ class pidTPCModule
738796 }
739797 }
740798 LOG (info) << " Successfully retrieved TPC PID object from CCDB for timestamp " << bc.timestamp () << " , period " << headers[" LPMProductionTag" ] << " , recoPass " << headers[" RecoPassName" ];
799+ o2::parameters::GRPLHCIFData* grpo = ccdb->template getForTimeStamp <o2::parameters::GRPLHCIFData>(pidTPCopts.cfgPathGrpLhcIf .value , bc.timestamp ());
800+ LOG (info) << " Collisions type::" << CollisionSystemType::getCollisionTypeFromGrp (grpo);
801+ collsys = CollisionSystemType::getCollisionTypeFromGrp (grpo);
802+ if (collsys == CollisionSystemType::kCollSyspp ) {
803+ irSource = std::string (" T0VTX" );
804+ } else {
805+ irSource = std::string (" ZNC hadronic" );
806+ }
741807 response->PrintAll ();
742808 }
743809
0 commit comments