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 = 0 ;
190+ int order = 0 ;
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,72 @@ 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+
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, " Cannot construct multiplet key for %s: %zu region groups but %zu harmonic groups" , config.Head .c_str (), config.Regs .size (), config.Hars .size ());
541+ continue ;
542+ }
543+
544+ std::string key;
545+ int totalOrder = 0 ;
546+ bool valid = true ;
547+
548+ for (std::size_t group = 0 ; group < config.Regs .size (); ++group) {
549+ const auto & regionIndices = config.Regs [group];
550+ const auto & harmonics = config.Hars [group];
551+
552+ if (regionIndices.size () != 1 || harmonics.empty ()) {
553+ LOGF (error, " Cannot construct simple multiplet key for %s, group %zu: expected one region and at least one harmonic" , config.Head .c_str (), group);
554+ valid = false ;
555+ break ;
556+ }
557+
558+ const int regionIndex = regionIndices.front ();
559+ if (regionIndex < 0 ||
560+ static_cast <std::size_t >(regionIndex) >= regionNames.size ()) {
561+ LOGF (error, " Invalid region index %d in configuration %s" , regionIndex, config.Head .c_str ());
562+ valid = false ;
563+ break ;
564+ }
565+
566+ const int regionOrder = static_cast <int >(harmonics.size ());
567+ totalOrder += regionOrder;
568+
569+ if (!key.empty ()) {
570+ key += " _" ;
571+ }
572+
573+ key += regionNames[regionIndex];
574+ key += " _" ;
575+ key += std::to_string (regionOrder);
576+ }
577+
578+ if (!valid || key.empty ()) {
579+ continue ;
580+ }
581+
582+ key += " _" ;
583+ key += std::to_string (totalOrder);
584+
585+ if (uniqueKeys.insert (key).second ) {
586+ keys.push_back (std::move (key));
587+ MultipletConfig currentMultipletConfig{configIndex, totalOrder, registry.add <TProfile>(Form (" %s" , keys.back ().c_str ()), Form (" ; centrality ; N_{%d}" , totalOrder), {HistType::kTProfile , {xAxis}})};
588+ effectiveMultiplets[keys.back ()] = currentMultipletConfig;
589+ }
590+ }
591+ }
592+
515593 int getMagneticField (uint64_t timestamp)
516594 {
517595 // TODO done only once (and not per run). Will be replaced by CCDBConfigurable
@@ -745,21 +823,24 @@ struct FlowGfwNonflow {
745823 fFCpt ->fillCMProfiles (centmult, rndm);
746824 fFCpt ->fillCMSubeventProfiles (centmult, rndm);
747825
826+ for (const auto & [key, multiplet] : effectiveMultiplets) {
827+ const auto & config = corrconfigs.at (multiplet.representativeConfigIndex );
828+ const double dnx = fGFW ->Calculate (config, 0 , true ).real ();
829+
830+ if (dnx > 0 .) {
831+ const double multPower = std::pow (multiplicity, multiplet.order - 1 );
832+ if (multPower > 0 .) {
833+ multiplet.profile ->Fill (centmult, 1 . / multPower, dnx);
834+ }
835+ }
836+ }
837+
748838 for (std::size_t l_ind = 0 ; l_ind < corrconfigs.size (); ++l_ind) {
749839 if (!corrconfigs.at (l_ind).pTDif ) {
750840 auto dnx = fGFW ->Calculate (corrconfigs.at (l_ind), 0 , true ).real ();
751841 if (dnx == 0 ) {
752842 continue ;
753843 }
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- }
763844 auto val = fGFW ->Calculate (corrconfigs.at (l_ind), 0 , false ).real () / dnx;
764845 if (std::abs (val) < 1 ) {
765846 fFC ->FillProfile (corrconfigs.at (l_ind).Head .c_str (), centmult, val, cfgUseMultiplicityFlowWeights ? dnx : 1.0 , rndm);
0 commit comments