]> git.uio.no Git - u/mrichter/AliRoot.git/blame - PWGLF/ThermalFits/AliParticleYield.cxx
fix treename and add a null pointer protection
[u/mrichter/AliRoot.git] / PWGLF / ThermalFits / AliParticleYield.cxx
CommitLineData
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
15using std::endl;
16using std::left;
17using std::setw;
18
19ClassImp(AliParticleYield)
20
21// set statics
22const char * AliParticleYield::kStatusString[] = {"Published", "Preliminary", "Final, but not published", "May change"} ;
23const char * AliParticleYield::kSystemString[] = {"pp", "p-Pb", "Pb-Pb"} ;
24Int_t AliParticleYield::fSignificantDigits = 3;
25
26AliParticleYield::AliParticleYield() :
27TObject(),
28fPdgCode(0),
29fPdgCode2(0),
30fPartName(""),
31fCollisionSystem(0),
32fSqrtS(0),
33fYield(0),
34fStatError(0),
35fSystError(0),
36fNormError(0),
37fYMin(0),
38fYMax(0),
39fStatus(0),
40fMeasurementType(0),
41fCentr(""),
42fIsSum(0),
43fTag("")
44{
45 // constructor
46 AliPDG::AddParticlesToPdgDataBase(); // Make sure that ALICE-defined particles were added to the PDG DB
47}
48
49AliParticleYield::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):
50TObject(),
51fPdgCode(pdg),
52fPdgCode2(0),
53fPartName(""),
54fCollisionSystem(system),
55fSqrtS(sqrts),
56fYield(value),
57fStatError(stat),
58fSystError(syst),
59fNormError(norm),
60fYMin(ymin),
61fYMax(ymax),
62fStatus(status),
63fMeasurementType(type),
64fCentr(centr),
65fIsSum(isSum),
66fTag(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
74AliParticleYield::AliParticleYield(const AliParticleYield& part) :
75TObject(),
76fPdgCode(part.fPdgCode),
77fPdgCode2(part.fPdgCode2),
78fPartName(part.fPartName),
79fCollisionSystem(part.fCollisionSystem),
80fSqrtS(part.fSqrtS),
81fYield(part.fYield),
82fStatError(part.fStatError),
83fSystError(part.fSystError),
84fNormError(part.fNormError),
85fYMin(part.fYMin),
86fYMax(part.fYMax),
87fStatus(part.fStatus),
88fMeasurementType(part.fMeasurementType),
89fCentr(part.fCentr),
90fIsSum(part.fIsSum),
91fTag(part.fTag){
92 // Copy constructor
93}
94
95AliParticleYield::~AliParticleYield() {
96
97}
98
99TTree * 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
115TClonesArray * 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
135TClonesArray * 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
230const 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
306Float_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
320void 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
358const 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
365Double_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
384Float_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
392void 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
407void 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
422Bool_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
436void AliParticleYield::Print (Option_t *) const {
437 // Print
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