Skip to content

Commit 96e8aa2

Browse files
Merge branch 'AliceO2Group:master' into master
2 parents 9ed16b2 + e12caba commit 96e8aa2

File tree

427 files changed

+50448
-17880
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

427 files changed

+50448
-17880
lines changed

.github/workflows/labeler.yml

Lines changed: 33 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -41,73 +41,73 @@ jobs:
4141
labels = os.environ['labels']
4242
tags = {
4343
"infrastructure": "Infrastructure",
44+
"scripts": "Scripts",
45+
"tools": "Tools",
4446
"common": "Common",
47+
"trigger": "Trigger",
48+
"dpg": "DPG",
49+
"tutorial": "Tutorial",
4550
"alice3": "ALICE3",
4651
"pwgcf": "PWGCF",
4752
"pwgdq": "PWGDQ",
4853
"pwgem": "PWGEM",
4954
"pwghf": "PWGHF",
5055
"pwgje": "PWGJE",
5156
"pwglf": "PWGLF",
57+
"pwgmm": "PWGMM",
5258
"pwgud": "PWGUD",
53-
"dpg": "DPG",
54-
"trigger": "Trigger",
55-
"tutorial": "Tutorial",
5659
}
5760
print(f'PR title: "{title}"')
5861
print(f'PR labels: "{labels}"')
5962
tags_relevant = [tags[label] for label in tags if label in labels.split(",")]
6063
print("Relevant title tags:", ",".join(tags_relevant))
61-
passed = True
62-
prefix_good = ",".join(tags_relevant)
63-
prefix_good = f"[{prefix_good}] "
64-
print(f"Generated prefix: {prefix_good}")
65-
replace_title = 0
66-
title_new = title
64+
prefix_generated = ",".join(tags_relevant)
65+
prefix_generated = f"[{prefix_generated}] "
66+
print(f"Generated prefix: {prefix_generated}")
67+
found_tags = False
68+
title_new = title.strip()
6769
# If there is a prefix which contains a known tag, check it for correct tags, and reformat it if needed.
6870
# If there is a prefix which does not contain any known tag, add the tag prefix.
6971
# If there is no prefix, add the tag prefix.
70-
if match := re.match(r"\[?(\w[\w, /\+-]+)[\]:]+ ", title):
72+
if match := re.match(r" *\[?(\w[\w,/\+\- ]+)[\]: ]+ ", title):
7173
prefix_title = match.group(1)
7274
words_prefix_title = prefix_title.replace(",", " ").replace("/", " ").split()
73-
title_stripped = title[len(match.group()) :]
75+
title_stripped = title[len(match.group()) :].strip()
7476
print(f'PR title prefix: "{prefix_title}" -> tags: {words_prefix_title}')
7577
print(f'Stripped PR title: "{title_stripped}"')
7678
if any(tag in words_prefix_title for tag in tags.values()):
79+
found_tags = True
80+
passed = True
7781
for tag in tags.values():
7882
if tag in tags_relevant and tag not in words_prefix_title:
7983
print(f'::error::Relevant tag "{tag}" not found in the prefix of the PR title.')
8084
passed = False
8185
if tag not in tags_relevant and tag in words_prefix_title:
8286
print(f'::error::Irrelevant tag "{tag}" found in the prefix of the PR title.')
8387
passed = False
84-
# Format a valid prefix.
85-
if passed:
86-
prefix_good = ",".join(w for w in prefix_title.replace(",", " ").split() if w)
87-
prefix_good = f"[{prefix_good}] "
88-
print(f"::notice::Reformatted prefix: {prefix_good}")
89-
if match.group() != prefix_good:
90-
replace_title = 1
91-
title_new = prefix_good + title_stripped
88+
if not passed:
89+
print("::error::Problems were found in the PR title prefix.")
90+
print('::notice::Use the form "tags: title" or "[tags] title".')
91+
sys.exit(1)
92+
# Form a valid title with the existing prefix.
93+
prefix_good = ",".join(w for w in prefix_title.replace(",", " ").split() if w)
94+
prefix_good = f"[{prefix_good}] "
95+
print(f'::notice::Reformatted prefix: "{prefix_good}"')
96+
title_new = prefix_good + title_stripped
9297
else:
9398
print("::warning::No known tags found in the prefix.")
94-
if tags_relevant:
95-
replace_title = 1
96-
title_new = prefix_good + title
99+
title_new = " ".join((*match.group().split(), title_stripped))
97100
else:
98101
print("::warning::No valid prefix found in the PR title.")
99-
if tags_relevant:
100-
replace_title = 1
101-
title_new = prefix_good + title
102-
if not passed:
103-
print("::error::Problems were found in the PR title prefix.")
104-
print('::notice::Use the form "tags: title" or "[tags] title".')
105-
sys.exit(1)
106-
if replace_title:
107-
print("::warning::The PR title prefix with tags needs to be added or adjusted.")
108-
print(f'::warning::New title: "{title_new}".')
102+
if not found_tags and tags_relevant:
103+
title_new = prefix_generated + title_new.strip()
104+
replace_title = 0
105+
if title_new == title:
106+
print("::notice::The PR title is fine.")
109107
else:
110-
print("::notice::The PR title prefix is fine.")
108+
replace_title = 1
109+
print("::warning::The PR title needs to be adjusted.")
110+
print(f'::warning::New title: "{title_new}".')
111111
with open(os.environ["GITHUB_OUTPUT"], "a", encoding="utf-8") as fh:
112112
print(f"replace={replace_title}", file=fh)
113113
print(f"title={title_new}", file=fh)

.github/workflows/mega-linter.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ jobs:
3838
id: ml
3939
# You can override MegaLinter flavor used to have faster performances
4040
# More info at https://megalinter.io/flavors/
41-
uses: oxsecurity/megalinter@v9.2.0
41+
uses: oxsecurity/megalinter@v9.3.0
4242
env:
4343
# All available variables are described in documentation:
4444
# https://megalinter.io/configuration/

ALICE3/Core/Decayer.h

Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
// Copyright 2019-2020 CERN and copyright holders of ALICE O2.
2+
// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders.
3+
// All rights not expressly granted are reserved.
4+
//
5+
// This software is distributed under the terms of the GNU General Public
6+
// License v3 (GPL Version 3), copied verbatim in the file "COPYING".
7+
//
8+
// In applying this license CERN does not waive the privileges and immunities
9+
// granted to it by virtue of its status as an Intergovernmental Organization
10+
// or submit itself to any jurisdiction.
11+
12+
///
13+
/// \file Decayer.h
14+
/// \author Jesper Karlsson Gumprecht
15+
/// \since 15/12/2025
16+
/// \brief Basic class to handle short-lived particle decays in the fast simulation
17+
///
18+
19+
#ifndef ALICE3_CORE_DECAYER_H_
20+
#define ALICE3_CORE_DECAYER_H_
21+
22+
#include "ALICE3/Core/TrackUtilities.h"
23+
24+
#include "ReconstructionDataFormats/Track.h"
25+
26+
#include <TDatabasePDG.h>
27+
#include <TDecayChannel.h>
28+
#include <TGenPhaseSpace.h>
29+
#include <TLorentzVector.h>
30+
#include <TParticlePDG.h>
31+
#include <TRandom3.h>
32+
33+
#include <array>
34+
#include <cmath>
35+
#include <string>
36+
#include <vector>
37+
38+
namespace o2
39+
{
40+
namespace upgrade
41+
{
42+
43+
class Decayer
44+
{
45+
public:
46+
// Default constructor
47+
Decayer() = default;
48+
49+
template <typename TDatabase>
50+
std::vector<o2::upgrade::OTFParticle> decayParticle(const TDatabase& pdgDB, const o2::track::TrackParCov& track, const int pdgCode)
51+
{
52+
const auto& particleInfo = pdgDB->GetParticle(pdgCode);
53+
const int charge = particleInfo->Charge() / 3;
54+
const double mass = particleInfo->Mass();
55+
std::array<float, 3> mom;
56+
std::array<float, 3> pos;
57+
track.getPxPyPzGlo(mom);
58+
track.getXYZGlo(pos);
59+
60+
const double u = mRand3.Uniform(0, 1);
61+
const double ctau = o2::constants::physics::LightSpeedCm2S * particleInfo->Lifetime(); // cm
62+
const double betaGamma = track.getP() / mass;
63+
const double rxyz = -betaGamma * ctau * std::log(1 - u);
64+
double vx, vy, vz;
65+
double px, py, e;
66+
67+
if (!charge) {
68+
vx = pos[0] + rxyz * (mom[0] / track.getP());
69+
vy = pos[1] + rxyz * (mom[1] / track.getP());
70+
vz = pos[2] + rxyz * (mom[2] / track.getP());
71+
px = mom[0];
72+
py = mom[1];
73+
} else {
74+
float sna, csa;
75+
o2::math_utils::CircleXYf_t circle;
76+
track.getCircleParams(mBz, circle, sna, csa);
77+
const double rxy = rxyz / std::sqrt(1. + track.getTgl() * track.getTgl());
78+
const double theta = rxy / circle.rC;
79+
80+
vx = ((pos[0] - circle.xC) * std::cos(theta) - (pos[1] - circle.yC) * std::sin(theta)) + circle.xC;
81+
vy = ((pos[1] - circle.yC) * std::cos(theta) + (pos[0] - circle.xC) * std::sin(theta)) + circle.yC;
82+
vz = mom[2] + rxyz * (mom[2] / track.getP());
83+
84+
px = mom[0] * std::cos(theta) - mom[1] * std::sin(theta);
85+
py = mom[1] * std::cos(theta) + mom[0] * std::sin(theta);
86+
}
87+
88+
double brTotal = 0.;
89+
e = std::sqrt(mass * mass + px * px + py * py + mom[2] * mom[2]);
90+
for (int ch = 0; ch < particleInfo->NDecayChannels(); ++ch) {
91+
brTotal += particleInfo->DecayChannel(ch)->BranchingRatio();
92+
}
93+
94+
double brSum = 0.;
95+
std::vector<double> dauMasses;
96+
std::vector<int> pdgCodesDaughters;
97+
const double randomChannel = mRand3.Uniform(0., brTotal);
98+
for (int ch = 0; ch < particleInfo->NDecayChannels(); ++ch) {
99+
brSum += particleInfo->DecayChannel(ch)->BranchingRatio();
100+
if (randomChannel < brSum) {
101+
for (int dau = 0; dau < particleInfo->DecayChannel(ch)->NDaughters(); ++dau) {
102+
const int pdgDau = particleInfo->DecayChannel(ch)->DaughterPdgCode(dau);
103+
pdgCodesDaughters.push_back(pdgDau);
104+
const auto& dauInfo = pdgDB->GetParticle(pdgDau);
105+
dauMasses.push_back(dauInfo->Mass());
106+
}
107+
break;
108+
}
109+
}
110+
111+
TLorentzVector tlv(px, py, mom[2], e);
112+
TGenPhaseSpace decay;
113+
decay.SetDecay(tlv, dauMasses.size(), dauMasses.data());
114+
decay.Generate();
115+
116+
std::vector<o2::upgrade::OTFParticle> decayProducts;
117+
for (size_t i = 0; i < dauMasses.size(); ++i) {
118+
o2::upgrade::OTFParticle particle;
119+
TLorentzVector dau = *decay.GetDecay(i);
120+
particle.setPDG(pdgCodesDaughters[i]);
121+
particle.setVxVyVz(vx, vy, vz);
122+
particle.setPxPyPzE(dau.Px(), dau.Py(), dau.Pz(), dau.E());
123+
decayProducts.push_back(particle);
124+
}
125+
126+
return decayProducts;
127+
}
128+
129+
void setSeed(const int seed)
130+
{
131+
mRand3.SetSeed(seed); // For decay length sampling
132+
gRandom->SetSeed(seed); // For TGenPhaseSpace
133+
}
134+
135+
void setBField(const double b) { mBz = b; }
136+
137+
private:
138+
TRandom3 mRand3;
139+
double mBz;
140+
};
141+
142+
} // namespace upgrade
143+
} // namespace o2
144+
145+
#endif // ALICE3_CORE_DECAYER_H_

ALICE3/Core/FastTracker.cxx

Lines changed: 18 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -314,88 +314,31 @@ void FastTracker::AddTPC(float phiResMean, float zResMean)
314314
}
315315
}
316316

317-
std::map<std::string, std::map<std::string, std::string>> FastTracker::parseTEnvConfiguration(std::string filename)
317+
void FastTracker::AddGenericDetector(GeometryContainer::GeometryEntry configMap, o2::ccdb::BasicCCDBManager* ccdbManager)
318318
{
319-
std::map<std::string, std::map<std::string, std::string>> configMap;
320-
321-
TEnv env(filename.c_str());
322-
THashList* table = env.GetTable();
323-
std::vector<std::string> layers;
324-
for (int i = 0; i < table->GetEntries(); ++i) {
325-
const std::string key = table->At(i)->GetName();
326-
// key should contain exactly one dot
327-
if (key.find('.') == std::string::npos || key.find('.') != key.rfind('.')) {
328-
LOG(fatal) << "Key " << key << " does not contain exactly one dot";
319+
// Layers
320+
for (const auto& layer : configMap.getLayerNames()) {
321+
if (layer.find("global") != std::string::npos) { // Layers with global tag are skipped
322+
LOG(info) << " Skipping global configuration entry " << layer;
329323
continue;
330324
}
331-
const std::string firstPart = key.substr(0, key.find('.'));
332-
if (std::find(layers.begin(), layers.end(), firstPart) == layers.end()) {
333-
layers.push_back(firstPart);
334-
}
335-
}
336-
env.Print();
337325

338-
// Layers
339-
for (const auto& layer : layers) {
340326
LOG(info) << " Reading layer " << layer;
341-
for (int i = 0; i < table->GetEntries(); ++i) {
342-
const std::string key = table->At(i)->GetName();
343-
if (key.find(layer + ".") == 0) {
344-
const std::string paramName = key.substr(key.find('.') + 1);
345-
const std::string value = env.GetValue(key.c_str(), "");
346-
configMap[layer][paramName] = value;
347-
}
348-
}
349-
}
350-
return configMap;
351-
}
352-
353-
void FastTracker::AddGenericDetector(std::string filename, o2::ccdb::BasicCCDBManager* ccdbManager)
354-
{
355-
LOG(info) << " Adding generic detector from file " << filename;
356-
// If the filename starts with ccdb: then take the file from the ccdb
357-
if (filename.rfind("ccdb:", 0) == 0) {
358-
std::string ccdbPath = filename.substr(5); // remove "ccdb:" prefix
359-
if (ccdbManager == nullptr) {
360-
LOG(fatal) << "CCDB manager is null, cannot retrieve file " << ccdbPath;
361-
return;
362-
}
363-
const std::string outPath = "/tmp/DetGeo/";
364-
filename = Form("%s/%s/snapshot.root", outPath.c_str(), ccdbPath.c_str());
365-
std::ifstream checkFile(filename); // Check if file already exists
366-
if (!checkFile.is_open()) { // File does not exist, retrieve from CCDB
367-
LOG(info) << " --- CCDB source detected for detector geometry " << filename;
368-
std::map<std::string, std::string> metadata;
369-
ccdbManager->getCCDBAccessor().retrieveBlob(ccdbPath, outPath, metadata, 1);
370-
// Add CCDB handling logic here if needed
371-
LOG(info) << " --- Now retrieving geometry configuration from CCDB to: " << filename;
372-
} else { // File exists, proceed to load
373-
LOG(info) << " --- Geometry configuration file already exists: " << filename << ". Skipping download.";
374-
checkFile.close();
375-
}
376-
AddGenericDetector(filename, nullptr);
377-
return;
378-
}
379-
380-
std::map<std::string, std::map<std::string, std::string>> configMap = parseTEnvConfiguration(filename);
381-
// Layers
382-
for (const auto& layer : configMap) {
383-
LOG(info) << " Reading layer " << layer.first;
384-
const float r = std::stof(layer.second.at("r"));
385-
LOG(info) << " Layer " << layer.first << " has radius " << r;
386-
const float z = std::stof(layer.second.at("z"));
387-
const float x0 = std::stof(layer.second.at("x0"));
388-
const float xrho = std::stof(layer.second.at("xrho"));
389-
const float resRPhi = std::stof(layer.second.at("resRPhi"));
390-
const float resZ = std::stof(layer.second.at("resZ"));
391-
const float eff = std::stof(layer.second.at("eff"));
392-
const int type = std::stoi(layer.second.at("type"));
393-
const std::string deadPhiRegions = layer.second.at("deadPhiRegions");
327+
const float r = configMap.getFloatValue(layer, "r");
328+
LOG(info) << " Layer " << layer << " has radius " << r;
329+
const float z = configMap.getFloatValue(layer, "z");
330+
const float x0 = configMap.getFloatValue(layer, "x0");
331+
const float xrho = configMap.getFloatValue(layer, "xrho");
332+
const float resRPhi = configMap.getFloatValue(layer, "resRPhi");
333+
const float resZ = configMap.getFloatValue(layer, "resZ");
334+
const float eff = configMap.getFloatValue(layer, "eff");
335+
const int type = configMap.getIntValue(layer, "type");
336+
const std::string deadPhiRegions = configMap.getValue(layer, "deadPhiRegions", false);
394337

395338
// void AddLayer(TString name, float r, float z, float x0, float xrho, float resRPhi = 0.0f, float resZ = 0.0f, float eff = 0.0f, int type = 0);
396-
LOG(info) << " Adding layer " << layer.first << " r=" << r << " z=" << z << " x0=" << x0 << " xrho=" << xrho << " resRPhi=" << resRPhi << " resZ=" << resZ << " eff=" << eff << " type=" << type << " deadPhiRegions=" << deadPhiRegions;
339+
LOG(info) << " Adding layer " << layer << " r=" << r << " z=" << z << " x0=" << x0 << " xrho=" << xrho << " resRPhi=" << resRPhi << " resZ=" << resZ << " eff=" << eff << " type=" << type << " deadPhiRegions=" << deadPhiRegions;
397340

398-
DetLayer* addedLayer = AddLayer(layer.first.c_str(), r, z, x0, xrho, resRPhi, resZ, eff, type);
341+
DetLayer* addedLayer = AddLayer(layer.c_str(), r, z, x0, xrho, resRPhi, resZ, eff, type);
399342
if (!deadPhiRegions.empty()) { // Taking it as ccdb path or local file
400343
// Check if it begins with ccdb:
401344
if (std::string(deadPhiRegions).rfind("ccdb:", 0) == 0) {
@@ -418,7 +361,7 @@ void FastTracker::AddGenericDetector(std::string filename, o2::ccdb::BasicCCDBMa
418361
addedLayer->setDeadPhiRegions(g);
419362
}
420363
} else {
421-
LOG(debug) << " No dead phi regions for layer " << layer.first;
364+
LOG(debug) << " No dead phi regions for layer " << layer;
422365
}
423366
}
424367
}

0 commit comments

Comments
 (0)