@@ -49,15 +49,14 @@ struct ParticleCompositionCorrection {
4949 - support collision systems beyond pp
5050 - add QA task illustrating improved mc/data matching of DCA distributions after scaling of secondaries
5151 - extend PCC weight table by columns with systematic variations (up/down)
52- - investigate why particles can be their own mothers
53- - investigate why histogram registry writing does not respect subfolder structure
5452 */
5553
5654 Service<o2::framework::O2DatabasePDG> pdg;
5755 o2::ccdb::CcdbApi ccdbApi;
5856
5957 Configurable<bool > skipAll{" skipAll" , false , " run table producer in dummy mode, i.e. skip all computations and fill with 1" };
6058 Configurable<bool > skipSec{" skipSec" , false , " dont calculate weights for secondaries" };
59+ Configurable<bool > skipNonPhysicalPrim{" skipNonPhysicalPrim" , true , " dont calculate weights for particles that are not (originating from) physical primaries; i.e. reject (decays of) pi0 etc." };
6160 Configurable<float > etaCut{" etaCut" , 0 .8f , " eta cut" };
6261 Configurable<float > ptMinCut{" ptMinCut" , 0 .15f , " pt min cut" };
6362 Configurable<float > ptMaxCut{" ptMaxCut" , 10 .f , " pt max cut" };
@@ -74,6 +73,8 @@ struct ParticleCompositionCorrection {
7473 void init (InitContext const & cfgc);
7574 void process (aod::McCollisions::iterator const & mcCollision, aod::McParticles const & particles);
7675
76+ std::tuple<float , float , float > getWeights (aod::McParticles const & particles, aod::McParticles::iterator const & particle, std::map<int32_t , std::tuple<float , float , float >>& storedWeights, float dNdEta);
77+
7778 HistogramRegistry histos;
7879};
7980
@@ -108,7 +109,7 @@ void ParticleCompositionCorrection::init(InitContext const&)
108109 histos.add (" frac/data/kaon" , " " , kTProfile , {ptAxis});
109110 histos.add (" frac/data/proton" , " " , kTProfile , {ptAxis});
110111 histos.add (" frac/data/sigma" , " " , kTProfile , {ptAxis});
111- histos.addClone (" frac/data/" , " frac/mc/" ); // FIXME: bug in writer/registry moves one histogram out of subfolder...
112+ histos.addClone (" frac/data/" , " frac/mc/" );
112113
113114 histos.add (" weight/pion" , " " , kTProfile , {ptAxis});
114115 histos.add (" weight/kaon" , " " , kTProfile , {ptAxis});
@@ -120,6 +121,105 @@ void ParticleCompositionCorrection::init(InitContext const&)
120121 }
121122}
122123
124+ std::tuple<float , float , float > ParticleCompositionCorrection::getWeights (aod::McParticles const & particles, aod::McParticles::iterator const & particle, std::map<int32_t , std::tuple<float , float , float >>& storedWeights, float dNdEta)
125+ {
126+ static const std::tuple<float , float , float > noWeights = {1 .f , 1 .f , 1 .f };
127+
128+ if (skipAll || std::abs (particle.eta ()) > etaCut || particle.pt () < ptMinCut || particle.pt () > ptMaxCut) {
129+ return noWeights;
130+ }
131+
132+ if (particle.producedByGenerator ()) {
133+ if (skipNonPhysicalPrim && !particle.isPhysicalPrimary ()) {
134+ return noWeights;
135+ }
136+ auto absPDGCode = std::abs (particle.pdgCode ());
137+ // translate abs PDG code to PID variable of neural networks (0: pion, 1: kaon, 2: proton, 3: sigma)
138+ static const std::map<int , float > mapPID = {
139+ {PDG_t::kPiPlus , 0 .f },
140+ {PDG_t::kPi0 , 0 .f },
141+ {PDG_t::kKPlus , 1 .f },
142+ {PDG_t::kK0Short , 1 .f },
143+ {PDG_t::kK0Long , 1 .f },
144+ {PDG_t::kProton , 2 .f },
145+ {PDG_t::kNeutron , 2 .f },
146+ {PDG_t::kSigmaPlus , 3 .f },
147+ {PDG_t::kSigmaMinus , 3 .f },
148+ {PDG_t::kLambda0 , 3 .f },
149+ {PDG_t::kSigma0 , 3 .f },
150+ {PDG_t::kXiMinus , 3 .f },
151+ // TODO: potentially extend by xi0/eta/omega/rho/phi/Delta...
152+ // pdg codes defined in AliceO2/Common/Constants/include/CommonConstants/PhysicsConstants.h
153+ // e.g. o2::constants::physics::Pdg::kEta
154+ };
155+
156+ if (auto iterMapPID = mapPID.find (absPDGCode); iterMapPID != mapPID.end ()) {
157+ // LOGP(info, "scaling a {} with status code {} from process {}", particle.pdgCode(), particle.getGenStatusCode(), particle.getProcess());
158+ float pt = particle.pt ();
159+
160+ // calculate particle fractions and corresponding weight for given reference particle
161+ std::vector<std::vector<float >> input = {{dNdEta}, {pt}, {iterMapPID->second }};
162+ float fracData = particleFractionsData.evalModel (input)[0 ];
163+ float fracMC = particleFractionsMC.evalModel (input)[0 ];
164+ float weight = (fracMC) ? fracData / fracMC : 1 .f ;
165+ std::tuple<float , float , float > weights = {weight, weight, weight};
166+ if (!skipSec && particle.has_daughters ()) {
167+ storedWeights[particle.index ()] = weights;
168+ }
169+ if (enableQAHistos && particle.isPhysicalPrimary () && std::abs (particle.eta ()) < 0.8 ) { // o2-linter: disable=magic-number (usual range of charged-partilce measurements)
170+ if (iterMapPID->first == PDG_t::kPiPlus ) {
171+ histos.fill (HIST (" frac/data/pion" ), pt, fracData);
172+ histos.fill (HIST (" frac/mc/pion" ), pt, fracMC);
173+ histos.fill (HIST (" weight/pion" ), pt, weight);
174+ }
175+ if (iterMapPID->first == PDG_t::kKPlus ) {
176+ histos.fill (HIST (" frac/data/kaon" ), pt, fracData);
177+ histos.fill (HIST (" frac/mc/kaon" ), pt, fracMC);
178+ histos.fill (HIST (" weight/kaon" ), pt, weight);
179+ }
180+ if (iterMapPID->first == PDG_t::kProton ) {
181+ histos.fill (HIST (" frac/data/proton" ), pt, fracData);
182+ histos.fill (HIST (" frac/mc/proton" ), pt, fracMC);
183+ histos.fill (HIST (" weight/proton" ), pt, weight);
184+ }
185+ if (iterMapPID->first == PDG_t::kSigmaPlus || iterMapPID->first == PDG_t::kSigmaMinus ) {
186+ histos.fill (HIST (" frac/data/sigma" ), pt, fracData);
187+ histos.fill (HIST (" frac/mc/sigma" ), pt, fracMC);
188+ histos.fill (HIST (" weight/sigma" ), pt, weight);
189+ }
190+ }
191+ return weights;
192+ }
193+ } else if (!skipSec) {
194+ auto refParticleID = particle.index ();
195+ // LOGP(error, "Particle [{}] {} from process {}", refParticleID, particle.pdgCode(), particle.getProcess());
196+ while (!particles.iteratorAt (refParticleID).producedByGenerator () && particles.iteratorAt (refParticleID).has_mothers ()) {
197+ auto motherID = particles.iteratorAt (refParticleID).mothersIds ()[0 ] - particles.offset ();
198+ // LOGP(error, "-> mom [{}] {} from process {}", motherID, particles.iteratorAt(motherID).pdgCode(), particles.iteratorAt(motherID).getProcess());
199+ refParticleID = motherID;
200+ }
201+
202+ if (storedWeights.find (refParticleID) == storedWeights.end ()) {
203+ // LOGP(error, " no ref particle stored for particle {} from process {}!!", particle.pdgCode(), particle.getProcess());
204+ return noWeights;
205+ }
206+
207+ if (enableQAHistos) {
208+ float weight = get<0 >(storedWeights.at (refParticleID));
209+ auto pdgParticle = pdg->GetParticle (particle.pdgCode ());
210+ if (pdgParticle && pdgParticle->Charge () != 0 .) {
211+ if (particle.getProcess () == TMCProcess::kPDecay ) {
212+ histos.fill (HIST (" weight/secDec" ), particle.pt (), weight);
213+ } else if (particle.getProcess () == TMCProcess::kPHInhelastic || particle.getProcess () == TMCProcess::kPHadronic || particle.getProcess () == TMCProcess::kPHElastic ) {
214+ histos.fill (HIST (" weight/secMat" ), particle.pt (), weight);
215+ }
216+ }
217+ }
218+ return storedWeights.at (refParticleID);
219+ }
220+ return noWeights;
221+ }
222+
123223void ParticleCompositionCorrection::process (aod::McCollisions::iterator const &, aod::McParticles const & particles)
124224{
125225 // determine dNdEta of the collision
@@ -138,100 +238,9 @@ void ParticleCompositionCorrection::process(aod::McCollisions::iterator const&,
138238 ++dNdEta;
139239 }
140240
141- // fill particle composition table with corresponding weights
241+ std::map< int32_t , std::tuple< float , float , float >> storedWeights;
142242 for (const auto & particle : particles) {
143- float weight = 1 .f ;
144-
145- // calculate weights only inside the configured kinematic range
146- if (!skipAll && std::abs (particle.eta ()) < etaCut && particle.pt () > ptMinCut && particle.pt () < ptMaxCut) {
147- auto refParticleID = particle.index ();
148-
149- // find initial particle of secondaries from decays or interactions with material
150- while (!particles.iteratorAt (refParticleID).producedByGenerator () && particles.iteratorAt (refParticleID).has_mothers ()) {
151- if (skipSec) {
152- break ;
153- }
154- const auto & mother = particle.mothers_first_as <aod::McParticles>();
155- auto motherID = mother.globalIndex () - particles.offset ();
156- if (motherID == static_cast <uint64_t >(refParticleID)) {
157- // FIXME: this needs to be investigated!
158- // LOGP(error, " - !!! particle is its own mother: {} (pdg: {}) status: {} ; process: {}", motherID, mother.pdgCode(), mother.getGenStatusCode(), mother.getProcess());
159- break ;
160- }
161- refParticleID = motherID;
162- }
163-
164- if (const auto & refParticle = particles.iteratorAt (refParticleID); refParticle.producedByGenerator ()) {
165-
166- auto absPDGCode = std::abs (refParticle.pdgCode ());
167- // translate abs PDG code to PID variable of neural networks (0: pion, 1: kaon, 2: proton, 3: sigma)
168- static const std::map<int , float > mapPID = {
169- {PDG_t::kPiPlus , 0 .f },
170- {PDG_t::kPi0 , 0 .f },
171- {PDG_t::kKPlus , 1 .f },
172- {PDG_t::kK0Short , 1 .f },
173- {PDG_t::kK0Long , 1 .f },
174- {PDG_t::kProton , 2 .f },
175- {PDG_t::kNeutron , 2 .f },
176- {PDG_t::kSigmaPlus , 3 .f },
177- {PDG_t::kSigmaMinus , 3 .f },
178- {PDG_t::kLambda0 , 3 .f },
179- {PDG_t::kSigma0 , 3 .f },
180- {PDG_t::kXiMinus , 3 .f },
181- // TODO: potentially extend by xi0/eta/omega/rho/phi/Delta...
182- // pdg codes defined in AliceO2/Common/Constants/include/CommonConstants/PhysicsConstants.h
183- // e.g. o2::constants::physics::Pdg::kEta
184- };
185-
186- if (auto iterMapPID = mapPID.find (absPDGCode); iterMapPID != mapPID.end ()) {
187- // LOGP(info, "scaling a {} with status code {} from process {}", particle.pdgCode(), particle.getGenStatusCode(), particle.getProcess());
188- float pt = refParticle.pt ();
189-
190- // calculate particle fractions and corresponding weight for given reference particle
191- std::vector<std::vector<float >> input = {{dNdEta}, {pt}, {iterMapPID->second }};
192- float fracData = particleFractionsData.evalModel (input)[0 ];
193- float fracMC = particleFractionsMC.evalModel (input)[0 ];
194- if (fracMC) {
195- weight = fracData / fracMC;
196- }
197-
198- if (enableQAHistos && std::abs (particle.eta ()) < 0.8 ) { // o2-linter: disable=magic-number (usual range of charged-partilce measurements)
199- if (particle.isPhysicalPrimary ()) {
200- if (iterMapPID->first == PDG_t::kPiPlus ) {
201- histos.fill (HIST (" frac/data/pion" ), pt, fracData);
202- histos.fill (HIST (" frac/mc/pion" ), pt, fracMC);
203- histos.fill (HIST (" weight/pion" ), pt, weight);
204- }
205- if (iterMapPID->first == PDG_t::kKPlus ) {
206- histos.fill (HIST (" frac/data/kaon" ), pt, fracData);
207- histos.fill (HIST (" frac/mc/kaon" ), pt, fracMC);
208- histos.fill (HIST (" weight/kaon" ), pt, weight);
209- }
210- if (iterMapPID->first == PDG_t::kProton ) {
211- histos.fill (HIST (" frac/data/proton" ), pt, fracData);
212- histos.fill (HIST (" frac/mc/proton" ), pt, fracMC);
213- histos.fill (HIST (" weight/proton" ), pt, weight);
214- }
215- if (iterMapPID->first == PDG_t::kSigmaPlus || iterMapPID->first == PDG_t::kSigmaMinus ) {
216- histos.fill (HIST (" frac/data/sigma" ), pt, fracData);
217- histos.fill (HIST (" frac/mc/sigma" ), pt, fracMC);
218- histos.fill (HIST (" weight/sigma" ), pt, weight);
219- }
220- } else {
221- auto pdgParticle = pdg->GetParticle (particle.pdgCode ());
222- if (pdgParticle && pdgParticle->Charge () != 0 .) {
223- // fill the decay daughter info only (usually there is max. one parent generation so no relevant double counting here)
224- if (particle.getProcess () == TMCProcess::kPDecay ) {
225- histos.fill (HIST (" weight/secDec" ), pt, weight);
226- } else if (particle.getProcess () == TMCProcess::kPHInhelastic ) {
227- histos.fill (HIST (" weight/secMat" ), pt, weight);
228- }
229- }
230- }
231- }
232- }
233- }
234- }
235- pccTable (weight, weight, weight); // TODO: put here systematic variations of the weights
243+ auto [weight, weightSysUp, weightSysDown] = getWeights (particles, particle, storedWeights, dNdEta);
244+ pccTable (weight, weightSysUp, weightSysDown);
236245 }
237246}
0 commit comments