Adding new tasks and moving old ones for 'Femto3D' package#3675
Adding new tasks and moving old ones for 'Femto3D' package#3675glromane wants to merge 0 commit intoAliceO2Group:masterfrom
Conversation
Please consider the following formatting changes to AliceO2Group#3675
victor-gonzalez
left a comment
There was a problem hiding this comment.
Please, use the same sub-directories structure for Femto3D as the other functional areas, as for example FemtoUniverse
Have in mind that the mandate is that there should be only one derived data datamodel for Femto analysis. There has been extensive work in this area and such a datamodel already exists. We will further iterate on that (see my e-mail)
|
There are only few comments like that, but please try to reduce the amount of commented code in the future PR. Like here: |
Please consider the following formatting changes to AliceO2Group#3675
|
Dear Victor, Thanks a lot for today's discussion. As agreed, here we commit our tasks with the proper order. Sincerely yours, Gleb. |
victor-gonzalez
left a comment
There was a problem hiding this comment.
Thanks for reallocating the source files in the suggested structure
For the actual code, please, consider the suggested comments, specially the one encouraging the use of the standard O2Physics mixed events framework and not to replicate in memory what is received from tables
PWGCF/Femto3D/Core/femto3dPairTask.h
Outdated
|
|
||
| class FemtoParticle | ||
| { | ||
| public: | ||
| FemtoParticle() {} | ||
| FemtoParticle(TLorentzVector* fourmomentum, const float& eta, const float& phi); | ||
| // FemtoParticle(TLorentzVector* fourmomentum); | ||
| FemtoParticle(const float& E, const float& px, const float& py, const float& pz, const float& eta, const float& phi); | ||
| // FemtoParticle(const float& E, const float& px, const float& py, const float& pz); | ||
| FemtoParticle(const FemtoParticle& obj); | ||
| FemtoParticle(const FemtoParticle* obj); | ||
| ~FemtoParticle(); | ||
| FemtoParticle& operator=(const FemtoParticle& obj); | ||
|
|
||
| void Set4momentum(TLorentzVector* fourmomentum) { _fourmomentum = fourmomentum; } | ||
| void SetEta(const float& eta) { _eta = eta; } | ||
| void SetPhi(const float& phi) { _phi = phi; } | ||
| void SetSign(const float& sign) { _sign = sign; } | ||
| void SetMagField(const float& magField) { _magField = magField; } | ||
|
|
||
| TLorentzVector* Get4momentum() const { return _fourmomentum; } | ||
| float GetEta() const { return _eta; } | ||
| float GetPhi() const { return _phi; } | ||
| float GetPhiStar(const float& radius = 1.2) { return _phi + asin(-0.3 * _magField * _sign * radius / (2.0 * _fourmomentum->Pt())); } | ||
| float GetMagField() const { return _magField; } | ||
|
|
||
| private: | ||
| float _eta, _phi, _sign, _magField = 0.0; | ||
| TLorentzVector* _fourmomentum; | ||
| }; | ||
|
|
||
| FemtoParticle::FemtoParticle(TLorentzVector* fourmomentum, const float& eta, const float& phi) | ||
| { | ||
| _fourmomentum = fourmomentum; | ||
| _eta = eta; | ||
| _phi = phi; | ||
| } | ||
|
|
||
| // FemtoParticle::FemtoParticle(TLorentzVector* fourmomentum){ | ||
| // _fourmomentum = fourmomentum; | ||
| // } | ||
|
|
||
| FemtoParticle::FemtoParticle(const float& E, const float& px, const float& py, const float& pz, const float& eta, const float& phi) | ||
| { | ||
| _fourmomentum = new TLorentzVector(px, py, pz, E); | ||
| _eta = eta; | ||
| _phi = phi; | ||
| } | ||
|
|
||
| // FemtoParticle::FemtoParticle(const float& E, const float& px, const float& py, const float& pz){ | ||
| // _fourmomentum = new TLorentzVector(*px, *py, *pz, *E); | ||
| // } | ||
|
|
||
| FemtoParticle::FemtoParticle(const FemtoParticle& obj) | ||
| { | ||
| Set4momentum(obj.Get4momentum()); | ||
| SetEta(obj.GetEta()); | ||
| SetPhi(obj.GetPhi()); | ||
| } | ||
|
|
||
| FemtoParticle::FemtoParticle(const FemtoParticle* obj) | ||
| { | ||
| Set4momentum(obj->Get4momentum()); | ||
| SetEta(obj->GetEta()); | ||
| SetPhi(obj->GetPhi()); | ||
| } | ||
|
|
||
| FemtoParticle::~FemtoParticle() | ||
| { | ||
| } | ||
|
|
||
| FemtoParticle& FemtoParticle::operator=(const FemtoParticle& obj) | ||
| { | ||
| if (this != &obj) { | ||
| Set4momentum(obj.Get4momentum()); | ||
| SetEta(obj.GetEta()); | ||
| SetPhi(obj.GetPhi()); | ||
| } | ||
|
|
||
| return *this; | ||
| } | ||
|
|
||
| //==================================================================================== | ||
|
|
||
| class FemtoPair | ||
| { | ||
| public: | ||
| FemtoPair(){}; | ||
| FemtoPair(FemtoParticle* first, FemtoParticle* second) | ||
| { | ||
| _first = first; | ||
| _second = second; | ||
| } | ||
| FemtoPair(FemtoParticle* first, FemtoParticle* second, const bool& isidentical) | ||
| { | ||
| _first = first; | ||
| _second = second; | ||
| _isidentical = isidentical; | ||
| } | ||
|
|
||
| FemtoPair(const FemtoPair& obj) | ||
| { | ||
| SetFirstParticle(obj.GetFirstParticle()); | ||
| SetSecondParticle(obj.GetSecondParticle()); | ||
| } | ||
| FemtoPair(const FemtoPair* obj) | ||
| { | ||
| SetFirstParticle(obj->GetFirstParticle()); | ||
| SetSecondParticle(obj->GetSecondParticle()); | ||
| } | ||
| ~FemtoPair() {} | ||
| FemtoPair& operator=(const FemtoPair& obj) | ||
| { | ||
| if (this != &obj) { | ||
| SetFirstParticle(obj.GetFirstParticle()); | ||
| SetSecondParticle(obj.GetSecondParticle()); | ||
| } | ||
| return *this; | ||
| } | ||
|
|
||
| void SetFirstParticle(FemtoParticle* first) { _first = first; } | ||
| void SetSecondParticle(FemtoParticle* second) { _second = second; } | ||
| void SetIdentical(const bool& isidentical) { _isidentical = isidentical; } | ||
|
|
||
| FemtoParticle* GetFirstParticle() const { return _first; } | ||
| FemtoParticle* GetSecondParticle() const { return _second; } | ||
| bool IsIdentical() { return _isidentical; } | ||
|
|
||
| bool IsClosePair(const float& deta = 0.01, const float& dphi = 0.01, const float& radius = 1.2); | ||
| float GetEtaDiff() const { return _first->GetEta() - _second->GetEta(); } | ||
| float GetPhiStarDiff(const float& radius = 1.2) const { return _first->GetPhiStar(radius) - _second->GetPhiStar(radius); } | ||
| float GetKstar() const; | ||
|
|
||
| private: | ||
| FemtoParticle* _first; | ||
| FemtoParticle* _second; | ||
| bool _isidentical = true; | ||
| }; | ||
|
|
||
| bool FemtoPair::IsClosePair(const float& deta, const float& dphi, const float& radius) | ||
| { | ||
| if (_first == NULL || _second == NULL) | ||
| return true; | ||
| if (!(_first->GetMagField() * _second->GetMagField())) | ||
| return true; | ||
| if (abs(GetEtaDiff()) < deta || abs(GetPhiStarDiff(radius)) < dphi) | ||
| return true; | ||
|
|
||
| return false; | ||
| } | ||
|
|
||
| float FemtoPair::GetKstar() const | ||
| { | ||
| if (_first == NULL || _second == NULL) | ||
| return -1000; | ||
| if (!(_first->GetMagField() * _second->GetMagField())) | ||
| return -1000; | ||
|
|
||
| TLorentzVector* first4momentum = new TLorentzVector(*(_first->Get4momentum())); | ||
| TLorentzVector* second4momentum = new TLorentzVector(*(_second->Get4momentum())); | ||
|
|
||
| if (_isidentical) { | ||
| TLorentzVector fourmomentadiff = *first4momentum - *second4momentum; | ||
| return 0.5 * abs(fourmomentadiff.Mag()); | ||
| } else { | ||
| TLorentzVector fourmomentasum = *first4momentum + *second4momentum; | ||
|
|
||
| first4momentum->Boost((-1) * fourmomentasum.BoostVector()); | ||
| second4momentum->Boost((-1) * fourmomentasum.BoostVector()); | ||
|
|
||
| TVector3 qinv = first4momentum->Vect() - second4momentum->Vect(); | ||
| return 0.5 * abs(qinv.Mag()); | ||
| } | ||
| } |
There was a problem hiding this comment.
If you need these structures they should be under an appropriate namespace
There was a problem hiding this comment.
Fixed, put them in the "o2::aod::singletrackselector::" namespace.
| } // namespace singletrackselector | ||
|
|
||
| DECLARE_SOA_TABLE_FULL(SingleTrackSel, "SelTracks", "AOD", "STSEL", // Table of the variables for single track selection. | ||
| o2::soa::Index<>, |
There was a problem hiding this comment.
Please, keep the plural for the table and the singular for the iterator
|
|
||
| template <typename TrackType> | ||
| inline bool TPCselection(TrackType const& track, std::pair<int, std::vector<float>> const& PIDcuts) | ||
| { |
There was a problem hiding this comment.
Do you really need the pair structure?
It seems it is created for an ephemeral life and at a per particle basis.
This will definitely have an impact in your job execution.
There was a problem hiding this comment.
This structure contains a PDG/PIDcuts pair and if I'm not mistaken the pair is created in only ones at the beginning of a task (QA of PairTask) and this function only reads it since it's by a "const" reference.
| // if satisfied, want to continue in the upper loop (over tracks) -- skip the current track | ||
| // cannot use simple 'continue' since it will be applied to the current loop, so have to use 'goto' | ||
| if (TOFselection(track, std::make_pair(i, rejectWithinNsigmaTOF))) { | ||
| goto skip; |
There was a problem hiding this comment.
Please, no goto
Use meaningful name variables to control the execution flow
There was a problem hiding this comment.
I put a flag instead. No 'goto' anymore.
| break; // break the loop with particlesToKeep after the 'if' condition is satisfied -- don't want double entries | ||
| } | ||
|
|
||
| skip:; // here we send with 'goto' |
There was a problem hiding this comment.
Please, no labels
Use meaningful name variables to control the execution flow
| Particle = new FemtoParticle(track.energy(particle_mass(_particlePDG_1)), track.px(), track.py(), track.pz(), track.eta(), track.phi()); | ||
| Particle->SetSign(_sign_1); | ||
| Particle->SetMagField(collision.magField()); | ||
| selectedtracks_1[track.singleCollSelId()].push_back(Particle); | ||
|
|
||
| registry.fill(HIST("p_first"), track.p()); | ||
| if (_particlePDG_1 == 2212) { | ||
| registry.fill(HIST("nsigmaTOF_first"), track.p(), track.tofNSigmaPr()); | ||
| registry.fill(HIST("nsigmaTPC_first"), track.p(), track.tpcNSigmaPr()); | ||
| } | ||
| if (_particlePDG_1 == 1000010020) { | ||
| registry.fill(HIST("nsigmaTOF_first"), track.p(), track.tofNSigmaDe()); | ||
| registry.fill(HIST("nsigmaTPC_first"), track.p(), track.tpcNSigmaDe()); | ||
| } |
There was a problem hiding this comment.
You are replicating in memory everything that you get from the tables with a much more inefficient way of accessing to the stored information.
This will have a huge penalty in execution time and in memory requirements
This goes against the O2 execution model (SoA vs AoS)
It seems that one of the reasons for storing the information is for extracting the mixed event results
You have to use the mixed events framework that is standard in O2Physics
It works without any kind of data replication
There was a problem hiding this comment.
Maybe it doesn't seem right but I'll try to explain why I think it's more convenient to use it like this. The main reason is the mixing (I put a more detailed comment about the mixing in the main reply). Since we need to store some info per particle for the mixing later I decided to use this "FemtoParticle" object that contains the bare minimum: pT, Eta, Phi, magField and signedPDG (updated in the last commit wrt to the previous one -- now consumes less memory).
Actually I was trying to store iterators/pointers to the tracks but the ones that are created after slicing or filtering are transient (temporary) ones and cannot be used to access an object (for the mixing) after the selection. So, I don't see any other way to do it apart from creating another additional table which would lead to duplication anyway. But using the class "FemtoPatricle" is more convenient because I can put there needed functions, pass the object to the "FemtoPair" etc.
| Particle = new FemtoParticle(track.energy(particle_mass(_particlePDG_2)), track.px(), track.py(), track.pz(), track.eta(), track.phi()); | ||
| Particle->SetSign(_sign_2); | ||
| Particle->SetMagField(collision.magField()); | ||
| selectedtracks_2[track.singleCollSelId()].push_back(Particle); | ||
|
|
||
| registry.fill(HIST("p_second"), track.p()); | ||
| if (_particlePDG_2 == 2212) { | ||
| registry.fill(HIST("nsigmaTOF_second"), track.p(), track.tofNSigmaPr()); | ||
| registry.fill(HIST("nsigmaTPC_second"), track.p(), track.tpcNSigmaPr()); | ||
| } | ||
| if (_particlePDG_2 == 1000010020) { | ||
| registry.fill(HIST("nsigmaTOF_second"), track.p(), track.tofNSigmaDe()); | ||
| registry.fill(HIST("nsigmaTPC_second"), track.p(), track.tpcNSigmaDe()); | ||
| } |
There was a problem hiding this comment.
Same comment as above
| if (IsIdentical) { // start of same event identical | ||
|
|
||
| for (auto i = selectedtracks_1.begin(); i != selectedtracks_1.end(); i++) { // start of same event identical | ||
| if ((i->second).size() < 2) | ||
| continue; | ||
|
|
||
| std::vector<std::vector<int>> comb_idx; | ||
| comb(comb_idx, (i->second).size(), 2); | ||
|
|
||
| for (auto indx : comb_idx) { | ||
| FemtoPair* Pair = new FemtoPair((i->second)[indx[0]], (i->second)[indx[1]], IsIdentical); | ||
| if (!Pair->IsClosePair(_deta, _dphi, _radiusTPC)) | ||
| registry.fill(HIST("SE"), Pair->GetKstar()); // close pair separation doesn't work properly, need eta and phi at some position in the barrel | ||
| } | ||
| } // end of same event identical | ||
|
|
||
| for (auto i = mixbins.begin(); i != mixbins.end(); i++) { // start of mixed event identical | ||
| if ((i->second).size() < 2) | ||
| continue; | ||
|
|
||
| std::vector<std::vector<int>> comb_idx; | ||
| comb(comb_idx, (i->second).size(), 2); | ||
|
|
||
| for (auto indx : comb_idx) { | ||
| int colId_1 = (i->second)[indx[0]]; | ||
| int colId_2 = (i->second)[indx[1]]; | ||
|
|
||
| for (auto ii : selectedtracks_1[colId_1]) { | ||
| for (auto iii : selectedtracks_1[colId_2]) { | ||
| FemtoPair* Pair = new FemtoPair(ii, iii, IsIdentical); | ||
| if (!Pair->IsClosePair(_deta, _dphi, _radiusTPC)) | ||
| registry.fill(HIST("ME"), Pair->GetKstar()); | ||
| } | ||
| } | ||
| } | ||
| } // end of mixed event identical | ||
|
|
||
| } //====================================== end of mixing identical ====================================== | ||
|
|
||
| else { //====================================== mixing non-identical ====================================== | ||
|
|
||
| for (auto i = selectedtracks_1.begin(); i != selectedtracks_1.end(); i++) { // start of same event non-identical | ||
|
|
||
| auto j = selectedtracks_2.find(i->first); | ||
| if (j == selectedtracks_2.end()) | ||
| continue; | ||
|
|
||
| for (auto ii : i->second) { | ||
| for (auto iii : j->second) { | ||
| FemtoPair* Pair = new FemtoPair(ii, iii, IsIdentical); | ||
| if (!Pair->IsClosePair(_deta, _dphi, _radiusTPC)) | ||
| registry.fill(HIST("SE"), Pair->GetKstar()); // close pair separation doesn't work properly, need eta and phi at some position in the barrel | ||
| } | ||
| } | ||
| } // end of same event non-identical | ||
|
|
||
| for (auto i = mixbins.begin(); i != mixbins.end(); i++) { // start of mixed event non-identical | ||
| if ((i->second).size() < 2) | ||
| continue; | ||
|
|
||
| std::vector<std::vector<int>> comb_idx; | ||
| comb(comb_idx, (i->second).size(), 2); | ||
|
|
||
| for (auto indx : comb_idx) { | ||
| int colId_1 = (i->second)[indx[0]]; | ||
| int colId_2 = (i->second)[indx[1]]; | ||
|
|
||
| for (auto ii : selectedtracks_1[colId_1]) { | ||
| for (auto iii : selectedtracks_2[colId_2]) { | ||
| FemtoPair* Pair = new FemtoPair(ii, iii, IsIdentical); | ||
| if (!Pair->IsClosePair(_deta, _dphi, _radiusTPC)) | ||
| registry.fill(HIST("ME"), Pair->GetKstar()); | ||
| } | ||
| } | ||
| } | ||
| } // end of mixed event non-idetical | ||
|
|
||
| } //====================================== end of mixing non-identical ====================================== |
There was a problem hiding this comment.
Same comment as above
There was a problem hiding this comment.
Here you're right. I fixed this and now I use only one "FemtoPair" object and just change the stored objects inside it. Thanks for pointing it out to me.
Please consider the following formatting changes to AliceO2Group#3675
Dear Victor, thanks for your comments, here is my overall reply (I also commented on your separate comments). I took into account your suggestions and applied them in the new commit. First, for the tables I cannot use filtering for the PID selection which means that even in the filtered with the track cuts table I will have lots of unwanted entries. And if I pass the table with the "fake" tracks to the mixer (as in the FemtoDream) I'll have lots of "fake" pairs to process the PID selection for. The number of pairs scales as n*(n-1) (x2 because it's a pair) and I think it's very inefficient and instead I do the PID before the mixing and pairs I build doesn't need to be checked anymore. So, instead of 2n(n-1) PID checks, I do it only n-times. Yes, for that I need to store the info and allocate memory but I gain a lot in CPU efficiency. And for the use of O2 mixing algorithm after the PID I'd need to make another table and duplicate the objects anyway, so it's the same only use of the "FemtoParticle" class is much more convenient for me. There are also some other for wrt to the previous commit made for the sake of efficiency (for example I got rid of the function that does the permutations and replaced it with just nested loops). We will continue working on improvements and of course, if we don't meet the hyper loop requirements we will deal with it, but before we need to have our tasks there to test and see how to proceed. If there is something unclear, please, tell me, I'll give you more details. Thank you. Sincerely yours, Gleb. |
|
We cannot approve the code as it is Consider this procedure. Once you have your filtered collisions/tracks, your derived data, consider using an additional column you can join to your filtered tracks table which will tag your filtered tracks according to your selection criteria; then use the standard O2 mixed events after filtering the filtered tracks over the additional column If you plan to elaborate more on your code exclude everything which is not the filter |
|
Let me comment as well. Indeed memory copy needs to be avoided here. For example instead of creating a Very important is also to use the O2 mixing event framework. This was created to avoid the buffers which we had in AliPhysics for storing the objects which slowed down the processing significantly. It works very well, you can define the mixing bins you need yourself and you get the events to mix with automatically. |
|
Just to add: if you think something is missing in the O2 event mixing framework, please let us know. We can organize a short slot in the WP4/14 meeting and it can be discussed if it cannot be resolved by simply replying here... |
--Implementing small changes in "singletrackselector" task and moving them to "Femto3D" folder in PWGCF branch;
--adding a QA task that uses tables from "singletrackselector";
--adding a femto task that does mixing, pair creation for obtaining a femtoscopic correlation function;