]>
Commit | Line | Data |
---|---|---|
2f86df33 | 1 | #include <iostream> |
2 | #include <fstream> | |
3 | #include <iomanip> | |
4 | #include "AliParticleYield.h" | |
5 | #include "TDatabasePDG.h" | |
6 | #include "AliLog.h" | |
7 | #include "TClonesArray.h" | |
8 | #include "TMath.h" | |
9 | #include "AliPDG.h" | |
10 | #include "TBranch.h" | |
11 | #include "TTree.h" | |
12 | #include "TDirectory.h" | |
13 | #include "TEventList.h" | |
14 | ||
15 | using std::endl; | |
16 | using std::left; | |
17 | using std::setw; | |
18 | ||
19 | ClassImp(AliParticleYield) | |
20 | ||
21 | // set statics | |
22 | const char * AliParticleYield::kStatusString[] = {"Published", "Preliminary", "Final, but not published", "May change"} ; | |
23 | const char * AliParticleYield::kSystemString[] = {"pp", "p-Pb", "Pb-Pb"} ; | |
24 | Int_t AliParticleYield::fSignificantDigits = 3; | |
25 | ||
26 | AliParticleYield::AliParticleYield() : | |
27 | TObject(), | |
28 | fPdgCode(0), | |
29 | fPdgCode2(0), | |
30 | fPartName(""), | |
31 | fCollisionSystem(0), | |
32 | fSqrtS(0), | |
33 | fYield(0), | |
34 | fStatError(0), | |
35 | fSystError(0), | |
36 | fNormError(0), | |
37 | fYMin(0), | |
38 | fYMax(0), | |
39 | fStatus(0), | |
40 | fMeasurementType(0), | |
41 | fCentr(""), | |
42 | fIsSum(0), | |
43 | fTag("") | |
44 | { | |
45 | // constructor | |
46 | AliPDG::AddParticlesToPdgDataBase(); // Make sure that ALICE-defined particles were added to the PDG DB | |
47 | } | |
48 | ||
49 | AliParticleYield::AliParticleYield(Int_t pdg, Int_t system, Float_t sqrts, Float_t value, Float_t stat, Float_t syst, Float_t norm, Float_t ymin, Float_t ymax, Int_t status, Int_t type, TString centr, Int_t isSum, TString tag): | |
50 | TObject(), | |
51 | fPdgCode(pdg), | |
52 | fPdgCode2(0), | |
53 | fPartName(""), | |
54 | fCollisionSystem(system), | |
55 | fSqrtS(sqrts), | |
56 | fYield(value), | |
57 | fStatError(stat), | |
58 | fSystError(syst), | |
59 | fNormError(norm), | |
60 | fYMin(ymin), | |
61 | fYMax(ymax), | |
62 | fStatus(status), | |
63 | fMeasurementType(type), | |
64 | fCentr(centr), | |
65 | fIsSum(isSum), | |
66 | fTag(tag) | |
67 | ||
68 | { | |
69 | // Constructor | |
70 | fPartName = TDatabasePDG::Instance()->GetParticle(fPdgCode)->GetName(); | |
71 | AliPDG::AddParticlesToPdgDataBase(); // Make sure that ALICE-defined particles were added to the PDG DB | |
72 | } | |
73 | ||
74 | AliParticleYield::AliParticleYield(const AliParticleYield& part) : | |
75 | TObject(), | |
76 | fPdgCode(part.fPdgCode), | |
77 | fPdgCode2(part.fPdgCode2), | |
78 | fPartName(part.fPartName), | |
79 | fCollisionSystem(part.fCollisionSystem), | |
80 | fSqrtS(part.fSqrtS), | |
81 | fYield(part.fYield), | |
82 | fStatError(part.fStatError), | |
83 | fSystError(part.fSystError), | |
84 | fNormError(part.fNormError), | |
85 | fYMin(part.fYMin), | |
86 | fYMax(part.fYMax), | |
87 | fStatus(part.fStatus), | |
88 | fMeasurementType(part.fMeasurementType), | |
89 | fCentr(part.fCentr), | |
90 | fIsSum(part.fIsSum), | |
91 | fTag(part.fTag){ | |
92 | // Copy constructor | |
93 | } | |
94 | ||
95 | AliParticleYield::~AliParticleYield() { | |
96 | ||
97 | } | |
98 | ||
99 | TTree * AliParticleYield::ReadFromASCIIFileAsTree(const char * fileName, const char * separators){ | |
100 | // Read the table from an ASCII File and returns a tree of particles. See ReadFromASCIIFile for detailed info on the format | |
101 | TClonesArray * arr = ReadFromASCIIFile(fileName, separators); | |
102 | AliParticleYield * part = 0; | |
103 | TTree * tree = new TTree ("treePart", "Particle Yields and Ratios"); | |
104 | tree->Branch("particles", &part); | |
105 | TIter iterPart (arr); | |
106 | while ((part = (AliParticleYield*) iterPart.Next())){ | |
107 | tree->Fill(); | |
108 | } | |
109 | ||
110 | delete arr; | |
111 | delete part; | |
112 | return tree; | |
113 | } | |
114 | ||
115 | TClonesArray * AliParticleYield::GetEntriesMatchingSelection(TTree * tree, TString selection) { | |
116 | // Returns an array of particles from a tree created with ReadFromASCIIFileAsTree matching the selection. You can use the normal tree sintax for the selection, e.g. "fCentr == \"V0M0010\" && fStatus == 0". | |
117 | ||
118 | TClonesArray * arr = new TClonesArray("AliParticleYield"); | |
119 | AliParticleYield * part = 0; | |
120 | tree->SetBranchAddress("particles", &part); | |
121 | // In order to get the array, we first create an entry list matching the selection using TTree::Draw, and them we loop over all entries in the tree. | |
122 | tree->Draw(">>particlelist", selection);// Produce selection list | |
123 | TEventList *elist = (TEventList*)gDirectory->Get("particlelist"); | |
124 | Int_t npart = elist->GetN(); | |
125 | for(Int_t ipart = 0; ipart < npart; ipart++){ | |
126 | std::cout << ipart << " " << elist->GetEntry(ipart) << std::endl; | |
127 | tree->GetEntry(elist->GetEntry(ipart)); | |
128 | new((*arr)[ipart]) AliParticleYield(*part);// We need to clone part, because it is overwritten by the next read | |
129 | } | |
130 | elist->Delete(); | |
131 | return arr; | |
132 | } | |
133 | ||
134 | ||
135 | TClonesArray * AliParticleYield::ReadFromASCIIFile(const char * fileName, const char * separators){ | |
136 | // Read the table from an ASCII File with the format indicated | |
137 | // below. Returns a TClonesArray of AliParticleyields with the | |
138 | // content of the lines. Lines beginning by "#" are skipped. | |
139 | // The order of the columns is compulsory, but the separator can be set (by default whitespaces are assumed). | |
140 | ||
141 | // The columns should be: | |
142 | // PDG NAME SYSTEM SQRTS VALUE SYST STAT NORM YMIN YMAX STATUS TYPE CENTR ISSUM TAG | |
143 | ||
144 | // PDG should either be an integher or the ratio of two integers (in case of particle ratios), with the following format: | |
145 | // pdgcode/pdgcode2 | |
146 | // NO SPACES ARE ALLOWED IN NAMES AND PDG CODE, unless you use a separator which is not a whitespace | |
147 | ||
148 | // A Header can be present (lines beginning with the word "PDG" are also skipped | |
149 | ||
150 | const Int_t kNCols = 14; // The lines are actually 15, but the last one (TAG) can be empty, so we put 14 here. | |
151 | ||
152 | TClonesArray * arr = new TClonesArray ("AliParticleYield"); | |
153 | ifstream filestream (fileName); | |
154 | TString line; | |
155 | Int_t ipart = 0; | |
156 | while (line.ReadLine(filestream) ) { | |
157 | // Strip trailing and leading whitespaces | |
158 | line = line.Strip(TString::kLeading, ' '); | |
159 | line = line.Strip(TString::kTrailing, ' '); | |
160 | ||
161 | // Skip commented lines and headers | |
162 | if (line.BeginsWith("#")) continue; | |
163 | if (line.BeginsWith("PDG")) continue; | |
164 | ||
165 | // Tokenize line using custom separator | |
166 | TObjArray * cols = line.Tokenize(separators); | |
167 | ||
168 | // Check the number of columns | |
169 | if(cols->GetEntries() < kNCols) { | |
170 | Printf("Wrong number of columns in table %d vs %d expected" , cols->GetEntries(), kNCols); | |
171 | delete arr; | |
172 | return NULL; | |
173 | } | |
174 | ||
175 | // Get Values | |
176 | // get type first, as some operations are type-specific | |
177 | UInt_t type = ((TObjString*)cols->At(11)) ->String().Atoi(); | |
178 | ||
179 | // if it's a ratio, try to get the 2 pdg codes | |
180 | Int_t pdg =0, pdg2 = 0; | |
181 | ||
182 | if (type & kTypeParticleRatio) { | |
183 | TString col0 = ((TObjString*)cols->At(0)) ->String(); | |
184 | TObjArray * tokens = col0.Tokenize("/"); | |
185 | if(tokens->GetEntries() != 2) { | |
186 | Printf("ERROR: Cannot get both PDGs for ratios"); | |
187 | } else { | |
188 | pdg = ((TObjString*)tokens->At(0)) ->String().Atoi(); | |
189 | pdg2 = ((TObjString*)tokens->At(1)) ->String().Atoi(); | |
190 | } | |
191 | } | |
192 | else { | |
193 | pdg = ((TObjString*)cols->At(0)) ->String().Atoi(); | |
194 | } | |
195 | TString name = ((TObjString*)cols->At(1)) ->String(); | |
196 | Int_t system = ((TObjString*)cols->At(2)) ->String().Atoi(); | |
197 | Float_t sqrts = ((TObjString*)cols->At(3)) ->String().Atof(); | |
198 | Float_t yield = ((TObjString*)cols->At(4)) ->String().Atof(); | |
199 | // The "GetError" function can handle % errors. | |
200 | Float_t stat = GetError(((TObjString*)cols->At(5)) ->String(), yield); | |
201 | Float_t syst = GetError(((TObjString*)cols->At(6)) ->String(), yield); | |
202 | Float_t norm = GetError(((TObjString*)cols->At(7)) ->String(), yield); | |
203 | Float_t ymin = ((TObjString*)cols->At(8)) ->String().Atof(); | |
204 | Float_t ymax = ((TObjString*)cols->At(9)) ->String().Atof(); | |
205 | Int_t status = ((TObjString*)cols->At(10)) ->String().Atoi(); | |
206 | TString centr = ((TObjString*)cols->At(12)) ->String(); | |
207 | Int_t issum = ((TObjString*)cols->At(13)) ->String().Atoi(); | |
208 | TString tag = cols->At(14) ? ((TObjString*)cols->At(14)) ->String() : ""; // tag can be empty | |
209 | ||
210 | // Cleanup strings | |
211 | name = name.Strip(TString::kLeading, ' '); | |
212 | name = name.Strip(TString::kTrailing, ' '); | |
213 | centr = centr.Strip(TString::kLeading, ' '); | |
214 | centr = centr.Strip(TString::kTrailing, ' '); | |
215 | tag = tag.Strip(TString::kLeading, ' '); | |
216 | tag = tag.Strip(TString::kTrailing, ' '); | |
217 | ||
218 | // add to array | |
219 | new ((*arr)[ipart]) AliParticleYield(pdg,system,sqrts,yield,stat,syst,norm,ymin,ymax,status,type,centr,issum,tag); | |
220 | ((AliParticleYield*)arr->At(ipart))->SetPartName(name); // Check name and PDG code consistency | |
221 | ((AliParticleYield*)arr->At(ipart))->SetPdgCode2(pdg2); // Set second PDG code in case of ratios | |
222 | ((AliParticleYield*)arr->At(ipart))->CheckTypeConsistency(); | |
223 | ipart ++; | |
224 | } | |
225 | ||
226 | ||
227 | return arr; | |
228 | } | |
229 | ||
230 | const char * AliParticleYield::GetLatexName(Int_t pdg) const { | |
231 | ||
232 | // Returns a TLatex compatible name for the particle | |
233 | // if pdg == 0 uses fPdgcode; | |
234 | // We need the pdg argument for particle ratios | |
235 | ||
236 | if(!pdg && fMeasurementType & kTypeParticleRatio) { | |
237 | // If it's a ratio, we try to build the ratio name. To avoid an infinite loop we have to call GetLatexname with a non-zero argument. | |
238 | static TString name; | |
239 | name =""; | |
240 | name += GetLatexName(fPdgCode); | |
241 | name += " / "; | |
242 | name += GetLatexName(fPdgCode2); | |
243 | return name.Data(); | |
244 | } | |
245 | ||
246 | if(!pdg) pdg = fPdgCode; | |
247 | ||
248 | switch (pdg) { | |
249 | case 211: | |
250 | if (fIsSum) return "(#pi^{+} + #pi^{-})"; | |
251 | return "#pi^{+}"; | |
252 | case -211: | |
253 | return "#pi^{-}"; | |
254 | case 321: | |
255 | if (fIsSum) return "(K^{+} + K^{-})"; | |
256 | return "K^{+}"; | |
257 | case -321: | |
258 | return "K^{-}"; | |
259 | case 2212: | |
260 | if (fIsSum) return "(p + #bar{p})"; | |
261 | return "p"; | |
262 | case -2212: | |
263 | return "#bar^{p}"; | |
264 | case 3122: | |
265 | if (fIsSum) return "(#Omega^{-} + #bar{#Omega}^{+})"; | |
266 | return "#Omega^{-}"; | |
267 | case -3122: | |
268 | return "#bar{#Omega}^{+}"; | |
269 | case 3312: | |
270 | if (fIsSum) return "(#Xi^{-} + #bar{#Xi}^{+})"; | |
271 | return "#Xi^{-}"; | |
272 | case -3312: | |
273 | return "#bar{#Xi}^{+}"; | |
274 | case 3334: | |
275 | if (fIsSum) return "(#Omega^{-} + #bar{#Omega}^{+})"; | |
276 | return "#Omega^{-}"; | |
277 | case -3334: | |
278 | return "#bar{#Omega}^{+}"; | |
279 | case 310: | |
280 | return "K^{0}_{S}"; | |
281 | case 333: | |
282 | return "#phi"; | |
283 | case 313: | |
284 | return "K^{*}"; | |
285 | case 1000010020: | |
286 | if(fIsSum) return "(d + #bar{d})"; | |
287 | return "d";// Deuteron | |
288 | case -1000010020: | |
289 | return "#bar{d}";// Deuteron | |
290 | case 1000020030: | |
291 | if(fIsSum) return "(^{3}He + #bar{^{3}He})"; | |
292 | return "^{3}He"; | |
293 | case -1000020030: | |
294 | return "#bar{^{3}He}"; | |
295 | case 1010010030: | |
296 | if(fIsSum) return "^{3}_{#Lambda}He + #bar{^{3}_{#Lambda}He}"; | |
297 | return "^{3}_{#Lambda}He"; | |
298 | case -1010010030: | |
299 | return "#bar{^{3}_{#Lambda}He}"; | |
300 | } | |
301 | AliWarning("Latex Name not know for this particle"); | |
302 | return fPartName.Data(); | |
303 | ||
304 | } | |
305 | ||
306 | Float_t AliParticleYield::GetTotalError(Bool_t includeNormalization) const { | |
307 | // Returns the total error, including or not the normalization uncertainty | |
308 | // All uncertainties are supposed to be uncorrelated (e.g. summed in quadrature) | |
309 | // If stat and syst are stored separately, the total error is computed summing them in quadrature | |
310 | Float_t error = GetSystError(); | |
311 | if (!(fMeasurementType & kTypeOnlyTotError)) error = TMath::Sqrt(error*error + GetStatError()*GetStatError()); | |
312 | if(includeNormalization) error = TMath::Sqrt(error*error + GetNormError()*GetNormError()); | |
313 | ||
314 | return error; | |
315 | ||
316 | ||
317 | } | |
318 | ||
319 | ||
320 | void AliParticleYield::SaveAsASCIIFile(TClonesArray * arr, const char * fileName, const char * separator, Int_t colWidth){ | |
321 | // Saves the array as an ASCII File with the format indicated | |
322 | // below. | |
323 | ||
324 | // The columns should be: | |
325 | // PDG NAME SYSTEM SQRTS VALUE STAT SYST NORM YMIN YMAX STATUS TYPE CENTR ISSUM TAG | |
326 | ||
327 | ||
328 | ||
329 | ofstream fileOut(fileName); | |
330 | //print header | |
331 | fileOut << FormatCol("PDG", colWidth, separator) << FormatCol("NAME", colWidth, separator) << FormatCol("SYSTEM", colWidth, separator) << FormatCol("SQRTS", colWidth, separator) << FormatCol("VALUE", colWidth, separator) << FormatCol("STAT" , colWidth, separator)<< FormatCol("SYST", colWidth, separator) << FormatCol("NORM", colWidth, separator) << FormatCol("YMIN", colWidth, separator) << FormatCol("YMAX", colWidth, separator) << FormatCol("STATUS", colWidth, separator) << FormatCol("TYPE", colWidth, separator) << FormatCol("CENTR", colWidth, separator) << FormatCol("ISSUM", colWidth, separator) << FormatCol("TAG", colWidth, separator) << endl; | |
332 | ||
333 | TIter iter(arr); | |
334 | AliParticleYield * part = 0; | |
335 | while ((part = (AliParticleYield*) iter.Next())){ | |
336 | fileOut | |
337 | << FormatCol(Form("%d",part->GetPdgCode()) , colWidth , separator) | |
338 | << FormatCol(part->GetPartName() , colWidth , separator) | |
339 | << FormatCol(Form("%d", part->GetCollisionSystem()) , colWidth , separator) | |
340 | << FormatCol(Form("%2.2f", part->GetSqrtS()) , colWidth , separator) | |
341 | << FormatCol(Form("%3.3f", RoundToSignificantFigures(part->GetYield(), fSignificantDigits)) , colWidth , separator) | |
342 | << FormatCol(Form("%3.3f", RoundToSignificantFigures(part->GetStatError(),fSignificantDigits)) , colWidth , separator) | |
343 | << FormatCol(Form("%3.3f", RoundToSignificantFigures(part->GetSystError(),fSignificantDigits)) , colWidth , separator) | |
344 | << FormatCol(Form("%3.3f", RoundToSignificantFigures(part->GetNormError(),fSignificantDigits)) , colWidth , separator) | |
345 | << FormatCol(Form("%2.2f", part->GetYMin()) , colWidth , separator) | |
346 | << FormatCol(Form("%2.2f", part->GetYMax()) , colWidth , separator) | |
347 | << FormatCol(Form("%d",part->GetStatus() ) , colWidth , separator) | |
348 | << FormatCol(Form("%d",part->GetMeasurementType() ) , colWidth , separator) | |
349 | << FormatCol(part->GetCentr() , colWidth , separator) | |
350 | << FormatCol(Form("%d",part->GetIsSum()) , colWidth , separator) | |
351 | << FormatCol(part->GetTag() , colWidth , separator) | |
352 | << endl; | |
353 | } | |
354 | ||
355 | ||
356 | } | |
357 | ||
358 | const char * AliParticleYield::FormatCol(const char * text, Int_t width, const char * sep) { | |
359 | ||
360 | TString format(Form("%%-%ds %s", width, sep)); | |
361 | return Form(format.Data(), text); | |
362 | ||
363 | } | |
364 | ||
365 | Double_t AliParticleYield::RoundToSignificantFigures(double num, int n) { | |
366 | // Rounds num to n significant digits. | |
367 | // Recipe from :http://stackoverflow.com/questions/202302/rounding-to-an-arbitrary-number-of-significant-digits | |
368 | // Basically the log is used to determine the number of leading 0s, than convert to an integer by multipliing by the expo, | |
369 | // round the integer and shift back. | |
370 | if(num == 0) { | |
371 | return 0; | |
372 | } | |
373 | ||
374 | Double_t d = TMath::Ceil(TMath::Log10(num < 0 ? -num: num)); | |
375 | Int_t power = n - (int) d; | |
376 | ||
377 | Double_t magnitude = TMath::Power(10, power); | |
378 | Long_t shifted = TMath::Nint(num*magnitude); | |
379 | return shifted/magnitude; | |
380 | ||
381 | } | |
382 | ||
383 | ||
384 | Float_t AliParticleYield::GetError(TString error, Float_t yield) { | |
385 | // The "GetError" function can handle % errors. | |
386 | if(error.Contains("%")) { | |
387 | return yield * error.Atof()/100; | |
388 | } | |
389 | return error.Atof(); | |
390 | } | |
391 | ||
392 | void AliParticleYield::SetPdgCode(TString partName) { | |
393 | // Set pdg code from part name, if there was a previous name, check if it is consistent | |
394 | TParticlePDG * part = TDatabasePDG::Instance()->GetParticle(partName); | |
395 | if(IsTypeRatio() || fIsSum) return; // Name check does not make sense for ratios and sums | |
396 | if(!part) { | |
397 | AliError(Form("No particle %s in TDatabasePDG", partName.Data())); | |
398 | return; | |
399 | } | |
400 | if(fPdgCode != part->PdgCode() && !(fMeasurementType&kTypeParticleRatio)) { // The consistency check on PDG codes is disabled case of ratios | |
401 | AliError(Form("Name and pdg code are not consistent! fPartName: %s partName %s, pdgcode %d fPdgCode %d", fPartName.Data(), partName.Data(), part->PdgCode(), fPdgCode)); | |
402 | } | |
403 | fPdgCode = part->PdgCode(); | |
404 | ||
405 | } | |
406 | ||
407 | void AliParticleYield::SetPartName(Int_t pdgCode) { | |
408 | // Set part name from pdg code, if there was a previous code, check if it is consistent | |
409 | TParticlePDG * part = TDatabasePDG::Instance()->GetParticle(pdgCode); | |
410 | if(IsTypeRatio() || fIsSum) return; // Name check does not make sense for ratios and sums | |
411 | if(!part) { | |
412 | AliError(Form("No particle with code %d in TDatabasePDG", pdgCode)); | |
413 | return; | |
414 | } | |
415 | if(fPdgCode != part->PdgCode() && !(fMeasurementType&kTypeParticleRatio)) { // The consistency check on particle names is disabled case of ratios | |
416 | AliError(Form("Name and pdg code are not consistent! fPartName: %s partName %s, pdgcode %d fPdgCode %d", fPartName.Data(), part->GetName(), part->PdgCode(), fPdgCode)); | |
417 | } | |
418 | fPartName = part->GetName(); | |
419 | ||
420 | } | |
421 | ||
422 | Bool_t AliParticleYield::CheckTypeConsistency() const { | |
423 | // Check for any inconsistency with the type mask. Returns true if the object is fully consistent. | |
424 | Bool_t isOK = kTRUE; | |
425 | ||
426 | if((fMeasurementType & kTypeOnlyTotError) && GetStatError()) { | |
427 | AliError(Form("Error flagged as total only, but stat error is not 0 (%f)!",GetStatError())); | |
428 | isOK= kFALSE; | |
429 | } else if (!(fMeasurementType & kTypeOnlyTotError) && (!GetStatError() || !GetSystError())) { | |
430 | AliError("Stat or syst errors are null"); | |
431 | } | |
432 | ||
433 | return isOK; | |
434 | } | |
435 | ||
436 | void AliParticleYield::Print (Option_t *) const { | |
437 | ||
438 | Printf("-------------------------------"); | |
439 | CheckTypeConsistency(); | |
440 | Printf("%s [%s] (%d) %s %s", fPartName.Data(), GetLatexName(), fPdgCode, fIsSum ? "particle + antiparticle" : "", fTag.Length() ? Form("[%s]", fTag.Data()) : "" ); | |
441 | Printf("Status: %s, %s", kStatusString[fStatus], fMeasurementType & kTypeLinearInterpolation ? "Interpolated" : "Measured"); | |
442 | Printf("%s , sqrt(s) = %2.2f GeV, %2.2f < y < %2.2f %s", kSystemString[fCollisionSystem], fSqrtS, fYMin, fYMax, fCentr.Data()); | |
443 | if(fMeasurementType & kTypeOnlyTotError) { | |
444 | Printf("%f +- %f (total error)", fYield, fSystError); | |
445 | } | |
446 | else { | |
447 | Printf("%f +- %f (stat) +- %f (syst)", fYield, fStatError, fSystError); | |
448 | } | |
449 | Printf("Normalizaion uncertainty: %f", fNormError); | |
450 | } | |
451 |