6060#include < cstdlib>
6161#include < map>
6262#include < memory>
63+ #include < set>
6364#include < string>
6465#include < string_view>
6566#include < utility>
@@ -184,6 +185,14 @@ struct FlowGfwNonflow {
184185 bool correctionsLoaded = false ;
185186 } correctionsConfig;
186187
188+ struct MultipletConfig {
189+ std::size_t representativeConfigIndex;
190+ int order;
191+ std::shared_ptr<TProfile> profile;
192+ };
193+
194+ std::map<std::string, MultipletConfig> effectiveMultiplets;
195+
187196 // Outputs
188197 OutputObj<FlowContainer> fFC {FlowContainer (" FlowContainer" )};
189198 OutputObj<FlowContainer> fFCgen {FlowContainer (" FlowContainer_gen" )};
@@ -234,11 +243,11 @@ struct FlowGfwNonflow {
234243
235244 // Generic Framework
236245 GFW * fGFW = new GFW ();
237- std::vector<GFW ::CorrConfig> corrconfigs;
246+ std::vector<GFW ::CorrConfig> corrconfigs{} ;
238247 TRandom3* fRndm = new TRandom3(0 );
239248 TAxis* fPtAxis = nullptr ;
240249 int lastRun = -1 ;
241- std::map <std::string, std::shared_ptr<TProfile>> recipNHistograms ;
250+ std::vector <std::string> multipletKeys{} ;
242251
243252 // Track selection - DCA functions
244253 TF1 * fPtDepDCAxy = nullptr ;
@@ -395,10 +404,6 @@ struct FlowGfwNonflow {
395404 }
396405 for (auto i = 0 ; i < gfwMemberCache.configs .GetSize (); ++i) {
397406 corrconfigs.push_back (fGFW ->GetCorrelatorConfig (gfwMemberCache.configs .GetCorrs ()[i], gfwMemberCache.configs .GetHeads ()[i], gfwMemberCache.configs .GetpTDifs ()[i] != 0 ));
398- const auto & head = gfwMemberCache.configs .GetHeads ()[i];
399- std::string histName = " inverseN" ;
400- histName += head;
401- recipNHistograms[histName] = registry.add <TProfile>(histName, " centrality (%); " , HistType::kTProfile , {centAxis});
402407 }
403408 if (corrconfigs.empty ()) {
404409 LOGF (error, " Configuration contains vectors of different size - check the GFWCorrConfig configurable" );
@@ -414,6 +419,13 @@ struct FlowGfwNonflow {
414419 fFCgen ->Initialize (oba, multAxis, cfgNbootstrap);
415420 delete oba;
416421
422+ // Identify unique multiplet setups and populate with identifying keys
423+ identifyUniqueMultipletKeys (multipletKeys, corrconfigs, centAxis); // For now keep centrality axis hardcoded
424+ LOGF (info, " Unique multiplet keys for current configuration setup" );
425+ for (const auto & key : multipletKeys) {
426+ LOGF (info, key);
427+ }
428+
417429 const auto & ptPtGaps = cfgPtPtGaps->getData ();
418430 for (uint32_t i = 0 ; i < ptPtGaps.rows ; ++i) {
419431 const auto etaMin = ptPtGaps (i, 0 );
@@ -512,6 +524,84 @@ struct FlowGfwNonflow {
512524 }
513525 }
514526
527+ void identifyUniqueMultipletKeys (std::vector<std::string>& keys, const std::vector<GFW ::CorrConfig>& configs, AxisSpec xAxis)
528+ {
529+ std::set<std::string> uniqueKeys (keys.begin (), keys.end ());
530+ const auto & regionNames = gfwMemberCache.regions .GetNames ();
531+ std::size_t representativeConfigIndex = 0 ;
532+ for (std::size_t configIndex = 0 ; configIndex < configs.size (); ++configIndex) {
533+ const auto & config = configs[configIndex];
534+ // TODO: Support pT-differential and explicit-overlap configurations.
535+ if (config.pTDif ) {
536+ continue ;
537+ }
538+
539+ if (config.Regs .size () != config.Hars .size ()) {
540+ LOGF (error,
541+ " Cannot construct multiplet key for %s: "
542+ " %zu region groups but %zu harmonic groups" ,
543+ config.Head .c_str (),
544+ config.Regs .size (),
545+ config.Hars .size ());
546+ continue ;
547+ }
548+
549+ std::string key;
550+ int totalOrder = 0 ;
551+ bool valid = true ;
552+
553+ for (std::size_t group = 0 ; group < config.Regs .size (); ++group) {
554+ const auto & regionIndices = config.Regs [group];
555+ const auto & harmonics = config.Hars [group];
556+
557+ if (regionIndices.size () != 1 || harmonics.empty ()) {
558+ LOGF (error,
559+ " Cannot construct simple multiplet key for %s, group %zu: "
560+ " expected one region and at least one harmonic" ,
561+ config.Head .c_str (),
562+ group);
563+ valid = false ;
564+ break ;
565+ }
566+
567+ const int regionIndex = regionIndices.front ();
568+ if (regionIndex < 0 ||
569+ static_cast <std::size_t >(regionIndex) >= regionNames.size ()) {
570+ LOGF (error,
571+ " Invalid region index %d in configuration %s" ,
572+ regionIndex,
573+ config.Head .c_str ());
574+ valid = false ;
575+ break ;
576+ }
577+
578+ const int regionOrder = static_cast <int >(harmonics.size ());
579+ totalOrder += regionOrder;
580+
581+ if (!key.empty ()) {
582+ key += " _" ;
583+ }
584+
585+ key += regionNames[regionIndex];
586+ key += " _" ;
587+ key += std::to_string (regionOrder);
588+ }
589+
590+ if (!valid || key.empty ()) {
591+ continue ;
592+ }
593+
594+ key += " _" ;
595+ key += std::to_string (totalOrder);
596+
597+ if (uniqueKeys.insert (key).second ) {
598+ keys.push_back (std::move (key));
599+ MultipletConfig currentMultipletConfig{configIndex, totalOrder, registry.add <TProfile>(Form (" %s" , keys.back ().c_str ()), Form (" ; centrality ; N_{%d}" , totalOrder), {HistType::kTProfile , {xAxis}})};
600+ effectiveMultiplets[keys.back ()] = currentMultipletConfig;
601+ }
602+ }
603+ }
604+
515605 int getMagneticField (uint64_t timestamp)
516606 {
517607 // TODO done only once (and not per run). Will be replaced by CCDBConfigurable
@@ -745,21 +835,24 @@ struct FlowGfwNonflow {
745835 fFCpt ->fillCMProfiles (centmult, rndm);
746836 fFCpt ->fillCMSubeventProfiles (centmult, rndm);
747837
838+ for (auto & [key, multiplet] : effectiveMultiplets) {
839+ const auto & config = corrconfigs.at (multiplet.representativeConfigIndex );
840+ const double dnx = fGFW ->Calculate (config, 0 , true ).real ();
841+
842+ if (dnx > 0 .) {
843+ const double multPower = std::pow (multiplicity, multiplet.order - 1 );
844+ if (multPower > 0 .) {
845+ multiplet.profile ->Fill (centmult, 1 . / multPower, dnx);
846+ }
847+ }
848+ }
849+
748850 for (std::size_t l_ind = 0 ; l_ind < corrconfigs.size (); ++l_ind) {
749851 if (!corrconfigs.at (l_ind).pTDif ) {
750852 auto dnx = fGFW ->Calculate (corrconfigs.at (l_ind), 0 , true ).real ();
751853 if (dnx == 0 ) {
752854 continue ;
753855 }
754- const auto corrOrder = gfwMemberCache.configs .GetHeads ()[l_ind].back ();
755- const auto & head = gfwMemberCache.configs .GetHeads ()[l_ind];
756- std::string histName = " inverseN" ;
757- histName += head;
758- const int m = corrOrder - ' 0' ;
759- double multPower = std::pow (multiplicity, m - 1 );
760- if (multPower != 0 ) {
761- recipNHistograms.at (histName)->Fill (centmult, 1 . / multPower, dnx);
762- }
763856 auto val = fGFW ->Calculate (corrconfigs.at (l_ind), 0 , false ).real () / dnx;
764857 if (std::abs (val) < 1 ) {
765858 fFC ->FillProfile (corrconfigs.at (l_ind).Head .c_str (), centmult, val, cfgUseMultiplicityFlowWeights ? dnx : 1.0 , rndm);
0 commit comments