2929#include " Common/DataModel/Multiplicity.h"
3030#include " Common/DataModel/Centrality.h"
3131#include " PWGMM/Mult/DataModel/bestCollisionTable.h"
32+ #include " TFormula.h"
3233
3334// __________________________________________
3435// MultModule
@@ -245,9 +246,13 @@ struct standardConfigurables : o2::framework::ConfigurableGroup {
245246 o2::framework::Configurable<int > minNclsITSibGlobalTrack{" minNclsITSibGlobalTrack" , 1 , " min. number of ITSib clusters for global tracks" };
246247
247248 // ccdb information
248- o2::framework::Configurable<std::string> ccdbPathVtxZ{" ccdbPathVtxZ" , " Centrality/Calibration" , " The CCDB path for centrality/multiplicity information" };
249+ o2::framework::Configurable<std::string> ccdbPathVtxZ{" ccdbPathVtxZ" , " Centrality/Calibration" , " The CCDB path for vertex-Z calibration" };
250+ o2::framework::Configurable<std::string> ccdbPathCentrality{" ccdbPathCentrality" , " Centrality/Estimators" , " The CCDB path for centrality information" };
249251 o2::framework::Configurable<std::string> reconstructionPass{" reconstructionPass" , " " , {" Apass to use when fetching the calibration tables. Empty (default) does not check for any pass. Use `metadata` to fetch it from the AO2D metadata. Otherwise it will override the metadata." }};
250252
253+ // centrality operation
254+ o2::framework::Configurable<std::string> generatorName{" generatorName" , " " , {" Specify if and only if this is MC. Typical: PYTHIA" }};
255+ o2::framework::Configurable<bool > embedINELgtZEROselection{" embedINELgtZEROselection" , false , {" Option to do percentile 100.5 if not INELgtZERO" }};
251256};
252257
253258class MultModule
@@ -257,6 +262,7 @@ class MultModule
257262 {
258263 // constructor
259264 mRunNumber = 0 ;
265+ mRunNumberCentrality = 0 ;
260266 lCalibLoaded = false ;
261267 lCalibObjects = nullptr ;
262268 hVtxZFV0A = nullptr ;
@@ -269,6 +275,7 @@ class MultModule
269275
270276 // internal: calib related, vtx-z profiles
271277 int mRunNumber ;
278+ int mRunNumberCentrality ;
272279 bool lCalibLoaded;
273280 TList* lCalibObjects;
274281 TProfile* hVtxZFV0A;
@@ -282,14 +289,90 @@ class MultModule
282289 // (N.B.: will be invisible to the outside, create your own copies)
283290 o2::common::multiplicity::standardConfigurables internalOpts;
284291
292+ // _________________________________________________
293+ // centrality-related objects
294+ struct TagRun2V0MCalibration {
295+ bool mCalibrationStored = false ;
296+ TFormula* mMCScale = nullptr ;
297+ float mMCScalePars [6 ] = {0.0 };
298+ TH1* mhVtxAmpCorrV0A = nullptr ;
299+ TH1* mhVtxAmpCorrV0C = nullptr ;
300+ TH1* mhMultSelCalib = nullptr ;
301+ } Run2V0MInfo;
302+ struct TagRun2V0ACalibration {
303+ bool mCalibrationStored = false ;
304+ TH1* mhVtxAmpCorrV0A = nullptr ;
305+ TH1* mhMultSelCalib = nullptr ;
306+ } Run2V0AInfo;
307+ struct TagRun2SPDTrackletsCalibration {
308+ bool mCalibrationStored = false ;
309+ TH1* mhVtxAmpCorr = nullptr ;
310+ TH1* mhMultSelCalib = nullptr ;
311+ } Run2SPDTksInfo;
312+ struct TagRun2SPDClustersCalibration {
313+ bool mCalibrationStored = false ;
314+ TH1* mhVtxAmpCorrCL0 = nullptr ;
315+ TH1* mhVtxAmpCorrCL1 = nullptr ;
316+ TH1* mhMultSelCalib = nullptr ;
317+ } Run2SPDClsInfo;
318+ struct TagRun2CL0Calibration {
319+ bool mCalibrationStored = false ;
320+ TH1* mhVtxAmpCorr = nullptr ;
321+ TH1* mhMultSelCalib = nullptr ;
322+ } Run2CL0Info;
323+ struct TagRun2CL1Calibration {
324+ bool mCalibrationStored = false ;
325+ TH1* mhVtxAmpCorr = nullptr ;
326+ TH1* mhMultSelCalib = nullptr ;
327+ } Run2CL1Info;
328+ struct CalibrationInfo {
329+ std::string name = " " ;
330+ bool mCalibrationStored = false ;
331+ TH1* mhMultSelCalib = nullptr ;
332+ float mMCScalePars [6 ] = {0.0 };
333+ TFormula* mMCScale = nullptr ;
334+ explicit CalibrationInfo (std::string name)
335+ : name(name),
336+ mCalibrationStored(false ),
337+ mhMultSelCalib(nullptr ),
338+ mMCScalePars{0.0 },
339+ mMCScale (nullptr )
340+ {
341+ }
342+ bool isSane (bool fatalize = false )
343+ {
344+ if (!mhMultSelCalib) {
345+ return true ;
346+ }
347+ for (int i = 1 ; i < mhMultSelCalib->GetNbinsX () + 1 ; i++) {
348+ if (mhMultSelCalib->GetXaxis ()->GetBinLowEdge (i) > mhMultSelCalib->GetXaxis ()->GetBinUpEdge (i)) {
349+ if (fatalize) {
350+ LOG (fatal) << " Centrality calibration table " << name << " has bins with low edge > up edge" ;
351+ }
352+ LOG (warning) << " Centrality calibration table " << name << " has bins with low edge > up edge" ;
353+ return false ;
354+ }
355+ }
356+ return true ;
357+ }
358+ };
359+
360+ CalibrationInfo fv0aInfo = CalibrationInfo(" FV0" );
361+ CalibrationInfo ft0mInfo = CalibrationInfo(" FT0" );
362+ CalibrationInfo ft0aInfo = CalibrationInfo(" FT0A" );
363+ CalibrationInfo ft0cInfo = CalibrationInfo(" FT0C" );
364+ CalibrationInfo ft0cVariant1Info = CalibrationInfo(" FT0Cvar1" );
365+ CalibrationInfo fddmInfo = CalibrationInfo(" FDD" );
366+ CalibrationInfo ntpvInfo = CalibrationInfo(" NTracksPV" );
367+ CalibrationInfo nGlobalInfo = CalibrationInfo(" NGlobal" );
368+ CalibrationInfo mftInfo = CalibrationInfo(" MFT" );
369+
370+
285371 template <typename TConfigurables, typename TInitContext>
286372 void init (TConfigurables const & opts, TInitContext& context)
287373 {
288374 // read in configurations from the task where it's used
289375 internalOpts = opts;
290-
291- mRunNumber = 0 ;
292-
293376 internalOpts.mEnabledTables .resize (nTablesConst, 0 );
294377
295378 LOGF (info, " Configuring tables to generate" );
@@ -333,6 +416,7 @@ class MultModule
333416 }
334417
335418 mRunNumber = 0 ;
419+ mRunNumberCentrality = 0 ;
336420 lCalibLoaded = false ;
337421 hVtxZFV0A = nullptr ;
338422 hVtxZFT0A = nullptr ;
@@ -344,10 +428,12 @@ class MultModule
344428
345429 // __________________________________________________
346430 template <typename TCollision, typename TTracks, typename TBCs, typename TZdc, typename TFV0A, typename TFV0C, typename TFT0>
347- void collisionProcessRun2 (TCollision const & collision, TTracks const & tracks, TBCs const & bcs, TZdc const & zdc, TFV0A const & fv0a, TFV0C const & fv0c, TFT0 const & ft0 )
431+ o2::common::multiplicity::multEntry collisionProcessRun2 (TCollision const & collision, TTracks const & tracks, TBCs const & bcs, TZdc const & zdc, TFV0A const & fv0a, TFV0C const & fv0c, TFT0 const & ft0 )
348432 {
349433 // initialize properties
350434 o2::common::multiplicity::multEntry mults;
435+
436+ return mults;
351437 }
352438
353439 // __________________________________________________
@@ -665,6 +751,169 @@ class MultModule
665751 mults[collision.globalIndex ()].multMFTAllTracks = nAllTracks;
666752 mults[collision.globalIndex ()].multMFTTracks = nTracks;
667753 }
754+
755+ // __________________________________________________
756+ template <typename TCCDB, typename TMetadata, typename TBC>
757+ void ConfigureCentralityRun3 (TCCDB& ccdb, TMetadata const & metadataInfo, TBC const & bc){
758+ if (bc.runNumber () != mRunNumberCentrality ) {
759+ mRunNumberCentrality = bc.runNumber (); // mark that this run has been attempted already regardless of outcome
760+ LOGF (info, " centrality loading procedure for timestamp=%llu, run number=%d" , bc.timestamp (), bc.runNumber ());
761+ TList* callst = nullptr ;
762+ // Check if the ccdb path is a root file
763+ if (internalOpts.ccdbPathCentrality .value .find (" .root" ) != std::string::npos) {
764+ TFile f (internalOpts.ccdbPathCentrality .value .c_str (), " READ" );
765+ f.GetObject (internalOpts.reconstructionPass .value .c_str (), callst);
766+ if (!callst) {
767+ f.ls ();
768+ LOG (fatal) << " No calibration list " << internalOpts.reconstructionPass .value << " found." ;
769+ }
770+ } else {
771+ if (internalOpts.reconstructionPass .value == " " ) {
772+ callst = ccdb->template getForRun <TList>(internalOpts.ccdbPathCentrality , bc.runNumber ());
773+ } else if (internalOpts.reconstructionPass .value == " metadata" ) {
774+ std::map<std::string, std::string> metadata;
775+ metadata[" RecoPassName" ] = metadataInfo.get (" RecoPassName" );
776+ LOGF (info, " Loading CCDB for reconstruction pass (from metadata): %s" , metadataInfo.get (" RecoPassName" ));
777+ callst = ccdb->template getSpecificForRun <TList>(internalOpts.ccdbPathCentrality , bc.runNumber (), metadata);
778+ } else {
779+ std::map<std::string, std::string> metadata;
780+ metadata[" RecoPassName" ] = internalOpts.reconstructionPass .value ;
781+ LOGF (info, " Loading CCDB for reconstruction pass (from provided argument): %s" , internalOpts.reconstructionPass .value );
782+ callst = ccdb->template getSpecificForRun <TList>(internalOpts.ccdbPathCentrality , bc.runNumber (), metadata);
783+ }
784+ }
785+
786+ fv0aInfo.mCalibrationStored = false ;
787+ ft0mInfo.mCalibrationStored = false ;
788+ ft0aInfo.mCalibrationStored = false ;
789+ ft0cInfo.mCalibrationStored = false ;
790+ ft0cVariant1Info.mCalibrationStored = false ;
791+ fddmInfo.mCalibrationStored = false ;
792+ ntpvInfo.mCalibrationStored = false ;
793+ nGlobalInfo.mCalibrationStored = false ;
794+ mftInfo.mCalibrationStored = false ;
795+ if (callst != nullptr ) {
796+ LOGF (info, " Getting new histograms with %d run number for %d run number" , mRunNumber , bc.runNumber ());
797+ auto getccdb = [callst, bc](struct CalibrationInfo & estimator, const o2::framework::Configurable<std::string> generatorName) { // TODO: to consider the name inside the estimator structure
798+ estimator.mhMultSelCalib = reinterpret_cast <TH1*>(callst->FindObject (TString::Format (" hCalibZeq%s" , estimator.name .c_str ()).Data ()));
799+ estimator.mMCScale = reinterpret_cast <TFormula*>(callst->FindObject (TString::Format (" %s-%s" , generatorName->c_str (), estimator.name .c_str ()).Data ()));
800+ if (estimator.mhMultSelCalib != nullptr ) {
801+ if (generatorName->length () != 0 ) {
802+ LOGF (info, " Retrieving MC calibration for %d, generator name: %s" , bc.runNumber (), generatorName->c_str ());
803+ if (estimator.mMCScale != nullptr ) {
804+ for (int ixpar = 0 ; ixpar < 6 ; ++ixpar) {
805+ estimator.mMCScalePars [ixpar] = estimator.mMCScale ->GetParameter (ixpar);
806+ LOGF (info, " Parameter index %i value %.5f" , ixpar, estimator.mMCScalePars [ixpar]);
807+ }
808+ } else {
809+ LOGF (warning, " MC Scale information from %s for run %d not available" , estimator.name .c_str (), bc.runNumber ());
810+ }
811+ }
812+ estimator.mCalibrationStored = true ;
813+ estimator.isSane ();
814+ } else {
815+ LOGF (info, " Calibration information from %s for run %d not available, will fill this estimator with invalid values and continue (no crash)." , estimator.name .c_str (), bc.runNumber ());
816+ }
817+ };
818+
819+ // invoke loading only for requested centralities
820+ if (internalOpts.mEnabledTables [kCentFV0As ])
821+ getccdb (fv0aInfo, internalOpts.generatorName );
822+ if (internalOpts.mEnabledTables [kCentFT0Ms ])
823+ getccdb (ft0mInfo, internalOpts.generatorName );
824+ if (internalOpts.mEnabledTables [kCentFT0As ])
825+ getccdb (ft0aInfo, internalOpts.generatorName );
826+ if (internalOpts.mEnabledTables [kCentFT0Cs ])
827+ getccdb (ft0cInfo, internalOpts.generatorName );
828+ if (internalOpts.mEnabledTables [kCentFT0CVariant1s ])
829+ getccdb (ft0cVariant1Info, internalOpts.generatorName );
830+ if (internalOpts.mEnabledTables [kCentFDDMs ])
831+ getccdb (fddmInfo, internalOpts.generatorName );
832+ if (internalOpts.mEnabledTables [kCentNTPVs ])
833+ getccdb (ntpvInfo, internalOpts.generatorName );
834+ if (internalOpts.mEnabledTables [kCentNGlobals ])
835+ getccdb (nGlobalInfo, internalOpts.generatorName );
836+ if (internalOpts.mEnabledTables [kCentMFTs ])
837+ getccdb (mftInfo, internalOpts.generatorName );
838+ } else {
839+ LOGF (info, " Centrality calibration is not available in CCDB for run=%d at timestamp=%llu, will fill tables with dummy values" , bc.runNumber (), bc.timestamp ());
840+ }
841+ }
842+ }
843+
844+ // __________________________________________________
845+ template <typename TCCDB, typename TMetadata, typename TBC, typename TMultBuffer, typename TOutputGroup>
846+ void generateCentralities (TCCDB& ccdb, TMetadata const & metadataInfo, TBC const & bc, TMultBuffer const & mults, TOutputGroup& cursors){
847+ // takes multiplicity buffer and generates the desirable centrality values (if any)
848+
849+ // first step: did someone actually ask for it? Otherwise, go home
850+ if (
851+ internalOpts.mEnabledTables [kCentRun2V0Ms ] || internalOpts.mEnabledTables [kCentRun2V0As ] ||
852+ internalOpts.mEnabledTables [kCentRun2SPDTrks ] || internalOpts.mEnabledTables [kCentRun2SPDClss ] ||
853+ internalOpts.mEnabledTables [kCentRun2CL0s ] || internalOpts.mEnabledTables [kCentRun2CL1s ] ||
854+ internalOpts.mEnabledTables [kCentFV0As ] || internalOpts.mEnabledTables [kCentFT0Ms ] ||
855+ internalOpts.mEnabledTables [kCentFT0As ] || internalOpts.mEnabledTables [kCentFT0Cs ] ||
856+ internalOpts.mEnabledTables [kCentFT0CVariant1s ] || internalOpts.mEnabledTables [kCentFDDMs ] ||
857+ internalOpts.mEnabledTables [kCentNTPVs ] || internalOpts.mEnabledTables [kCentNGlobals ] ||
858+ internalOpts.mEnabledTables [kCentMFTs ])
859+ {
860+ // check and update centrality calibration objects for Run 3
861+ ConfigureCentralityRun3 (ccdb, metadataInfo, bc);
862+
863+ /* ***********************************************************
864+ * @brief Populates a table with data based on the given calibration information and multiplicity.
865+ *
866+ * @param table The table to populate.
867+ * @param estimator The calibration information.
868+ * @param multiplicity The multiplicity value.
869+ *************************************************************/
870+
871+ auto populateTable = [&](auto & table, struct CalibrationInfo & estimator, float multiplicity, bool isInelGt0) {
872+ const bool assignOutOfRange = internalOpts.embedINELgtZEROselection && !isInelGt0;
873+ auto scaleMC = [](float x, float pars[6 ]) {
874+ return std::pow (((pars[0 ] + pars[1 ] * std::pow (x, pars[2 ])) - pars[3 ]) / pars[4 ], 1 .0f / pars[5 ]);
875+ };
876+
877+ float percentile = 105 .0f ;
878+ float scaledMultiplicity = multiplicity;
879+ if (estimator.mCalibrationStored ) {
880+ if (estimator.mMCScale != nullptr ) {
881+ scaledMultiplicity = scaleMC (multiplicity, estimator.mMCScalePars );
882+ LOGF (debug, " Unscaled %s multiplicity: %f, scaled %s multiplicity: %f" , estimator.name .c_str (), multiplicity, estimator.name .c_str (), scaledMultiplicity);
883+ }
884+ percentile = estimator.mhMultSelCalib ->GetBinContent (estimator.mhMultSelCalib ->FindFixBin (scaledMultiplicity));
885+ if (assignOutOfRange)
886+ percentile = 100 .5f ;
887+ }
888+ LOGF (debug, " %s centrality/multiplicity percentile = %.0f for a zvtx eq %s value %.0f" , estimator.name .c_str (), percentile, estimator.name .c_str (), scaledMultiplicity);
889+ table (percentile);
890+ return percentile;
891+ };
892+
893+ // populate centralities
894+ for (size_t iEv = 0 ; iEv < mults.size (); iEv++) {
895+ bool isInelGt0 = (mults[iEv].multNContribsEta1 > 0 );
896+ if (internalOpts.mEnabledTables [kCentFV0As ])
897+ populateTable (cursors.centFV0A , fv0aInfo, mults[iEv].multFV0AZeq , isInelGt0);
898+ if (internalOpts.mEnabledTables [kCentFT0Ms ])
899+ populateTable (cursors.centFT0M , ft0mInfo, mults[iEv].multFT0AZeq + mults[iEv].multFT0CZeq , isInelGt0);
900+ if (internalOpts.mEnabledTables [kCentFT0As ])
901+ populateTable (cursors.centFT0A , ft0aInfo, mults[iEv].multFT0AZeq , isInelGt0);
902+ if (internalOpts.mEnabledTables [kCentFT0Cs ])
903+ populateTable (cursors.centFT0C , ft0cInfo, mults[iEv].multFT0CZeq , isInelGt0);
904+ if (internalOpts.mEnabledTables [kCentFT0CVariant1s ])
905+ populateTable (cursors.centFT0CVariant1 , ft0cVariant1Info, mults[iEv].multFT0CZeq , isInelGt0);
906+ if (internalOpts.mEnabledTables [kCentFDDMs ])
907+ populateTable (cursors.centFDDM , fddmInfo, mults[iEv].multFDDAZeq + mults[iEv].multFDDCZeq , isInelGt0);
908+ if (internalOpts.mEnabledTables [kCentNTPVs ])
909+ populateTable (cursors.centNTPV , ntpvInfo, mults[iEv].multNContribs , isInelGt0);
910+ if (internalOpts.mEnabledTables [kCentNGlobals ])
911+ populateTable (cursors.centNGlobals , nGlobalInfo, mults[iEv].multGlobalTracks , isInelGt0);
912+ if (internalOpts.mEnabledTables [kCentMFTs ])
913+ populateTable (cursors.centMFTs , mftInfo, mults[iEv].multMFTTracks , isInelGt0);
914+ }
915+ }
916+ }
668917}; // end BuilderModule
669918
670919} // namespace multiplicity
0 commit comments