From dc740de48a62d07a71c6af1f05f7df0d0e49caba Mon Sep 17 00:00:00 2001 From: jgrosseo Date: Fri, 26 May 2006 14:48:32 +0000 Subject: [PATCH] o) adding log tags to all files o) AliSelector: Changing the way the header is accessed: Before it was a tree friend, this results in mismatch as soon as one ESD file is corrupt. Now it is accessed similar to the method used for the kinematics tree. o) Adding second library PWG0selectors, this is only for the build system, because selectors are compiled on-the-fly when they are used in the Process function o) Analysis now splitted in AnalysisESDSelector and AnalysisMCSelector --- PWG0/AliSelector.cxx | 85 +++++++++- PWG0/AliSelector.h | 13 +- PWG0/AliSelectorRL.cxx | 2 + PWG0/AliSelectorRL.h | 2 + PWG0/CorrectionMatrix2D.cxx | 2 + PWG0/CorrectionMatrix2D.h | 2 + PWG0/CreateESDChain.C | 23 ++- PWG0/Makefile | 2 + PWG0/PWG0baseLinkDef.h | 2 - PWG0/PWG0selectorsLinkDef.h | 15 ++ PWG0/dNdEta/AlidNdEtaAnalysisESDSelector.cxx | 160 +++++++++++++++++++ PWG0/dNdEta/AlidNdEtaAnalysisESDSelector.h | 30 ++++ PWG0/dNdEta/AlidNdEtaAnalysisMCSelector.cxx | 45 +++++- PWG0/dNdEta/AlidNdEtaAnalysisMCSelector.h | 8 +- PWG0/dNdEta/AlidNdEtaAnalysisSelector.cxx | 124 ++------------ PWG0/dNdEta/AlidNdEtaAnalysisSelector.h | 18 +-- PWG0/dNdEta/AlidNdEtaCorrectionSelector.cxx | 13 +- PWG0/dNdEta/AlidNdEtaCorrectionSelector.h | 2 + PWG0/dNdEta/dNdEtaAnalysis.cxx | 2 + PWG0/dNdEta/dNdEtaAnalysis.h | 2 + PWG0/dNdEta/dNdEtaCorrection.cxx | 32 ++-- PWG0/dNdEta/dNdEtaCorrection.h | 3 + PWG0/dNdEta/drawCorrection.C | 6 +- PWG0/dNdEta/makeCorrection2.C | 7 +- PWG0/dNdEta/testAnalysis2.C | 11 +- PWG0/esdTrackCuts/AliESDtrackCuts.cxx | 4 +- PWG0/esdTrackCuts/AliESDtrackCuts.h | 2 + PWG0/esdTrackCuts/testESDtrackCuts.C | 2 + PWG0/libPWG0base.pkg | 8 +- PWG0/libPWG0selectors.pkg | 14 ++ PWG0/ptSpectra/makeCorrectionPtEta.C | 2 + 31 files changed, 465 insertions(+), 178 deletions(-) create mode 100644 PWG0/PWG0selectorsLinkDef.h create mode 100644 PWG0/dNdEta/AlidNdEtaAnalysisESDSelector.cxx create mode 100644 PWG0/dNdEta/AlidNdEtaAnalysisESDSelector.h create mode 100644 PWG0/libPWG0selectors.pkg diff --git a/PWG0/AliSelector.cxx b/PWG0/AliSelector.cxx index 12d390d3fc2..ba7dec0ab2a 100644 --- a/PWG0/AliSelector.cxx +++ b/PWG0/AliSelector.cxx @@ -1,3 +1,5 @@ +/* $Id$ */ + // The class definition in esdV0.h has been generated automatically // by the ROOT utility TTree::MakeSelector(). This class is derived // from the ROOT class TSelector. For more information on the TSelector @@ -31,6 +33,7 @@ #include #include #include +#include #include @@ -40,8 +43,11 @@ AliSelector::AliSelector() : TSelector(), fChain(0), fESD(0), - fHeader(0), - fKineFile(0) + fCountFiles(0), + fKineFile(0), + fHeaderFile(0), + fHeaderTree(0), + fHeader(0) { // // Constructor. Initialization of pointers @@ -76,8 +82,6 @@ void AliSelector::SlaveBegin(TTree * tree) AliDebug(AliLog::kDebug, "=======SLAVEBEGIN========"); AliDebug(AliLog::kDebug, Form("Hostname: %s", gSystem->HostName())); AliDebug(AliLog::kDebug, Form("Time: %s", gSystem->Now().AsString())); - TFile *f = fChain->GetCurrentFile(); - AliDebug(AliLog::kDebug, f->GetName()); TString option = GetOption(); } @@ -110,9 +114,9 @@ void AliSelector::Init(TTree *tree) if (fESD != 0) AliDebug(AliLog::kInfo, "INFO: Found ESD branch in chain."); - fChain->SetBranchAddress("Header", &fHeader); + /*fChain->SetBranchAddress("Header", &fHeader); if (fHeader != 0) - AliDebug(AliLog::kInfo, "INFO: Found event header branch in chain."); + AliDebug(AliLog::kInfo, "INFO: Found event header branch in chain.");*/ } Bool_t AliSelector::Notify() @@ -128,10 +132,15 @@ Bool_t AliSelector::Notify() AliDebug(AliLog::kDebug, Form("Hostname: %s", gSystem->HostName())); AliDebug(AliLog::kDebug, Form("Time: %s", gSystem->Now().AsString())); + ++fCountFiles; TFile *f = fChain->GetCurrentFile(); - AliDebug(AliLog::kInfo, Form("Processing file %s", f->GetName())); + AliDebug(AliLog::kInfo, Form("Processing %d. file %s", fCountFiles, f->GetName())); DeleteKinematicsFile(); + DeleteHeaderFile(); + + /*TChain* headerChain = dynamic_cast (((TFriendElement*) fChain->GetListOfFriends()->First())->GetTree()); + AliDebug(AliLog::kInfo, Form("Header File: %s", headerChain->GetCurrentFile()->GetName()));*/ return kTRUE; } @@ -166,6 +175,8 @@ Bool_t AliSelector::Process(Long64_t entry) fChain->GetTree()->GetEntry(entry); + /* + // debugging if (fESD) AliDebug(AliLog::kDebug, Form("ESD: We have %d tracks.", fESD->GetNumberOfTracks())); @@ -175,6 +186,7 @@ Bool_t AliSelector::Process(Long64_t entry) TTree* kinematics = GetKinematics(); if (kinematics) AliDebug(AliLog::kDebug, Form("Kinematics: We have %lld particles.", kinematics->GetEntries())); + */ return kTRUE; } @@ -186,6 +198,7 @@ void AliSelector::SlaveTerminate() // on each slave server. DeleteKinematicsFile(); + DeleteHeaderFile(); } void AliSelector::Terminate() @@ -211,6 +224,8 @@ TTree* AliSelector::GetKinematics() TString fileName(fChain->GetCurrentFile()->GetName()); fileName.ReplaceAll("AliESDs", "Kinematics"); + AliDebug(AliLog::kInfo, Form("Opening %s", fileName.Data())); + fKineFile = TFile::Open(fileName); if (!fKineFile) return 0; @@ -266,6 +281,53 @@ void AliSelector::DeleteKinematicsFile() } } +AliHeader* AliSelector::GetHeader() +{ + // Returns header corresponding to current ESD active in fChain + // Loads the header from galice.root, the file is identified by replacing "AliESDs" to + // "galice" in the file path of the ESD file. This is a hack, to be changed! + + if (!fHeaderFile || !fHeaderTree) + { + if (!fChain->GetCurrentFile()) + return 0; + + TString fileName(fChain->GetCurrentFile()->GetName()); + fileName.ReplaceAll("AliESDs", "galice"); + + AliDebug(AliLog::kInfo, Form("Opening %s", fileName.Data())); + + fHeaderFile = TFile::Open(fileName); + if (!fHeaderFile) + return 0; + + fHeaderTree = dynamic_cast (fHeaderFile->Get("TE")); + if (!fHeaderTree) + return 0; + + fHeaderTree->SetBranchAddress("Header", &fHeader); + } + + fHeaderTree->GetEntry(fChain->GetTree()->GetReadEntry()); + + return fHeader; +} + +void AliSelector::DeleteHeaderFile() +{ + // + // Closes the kinematics file and deletes the pointer. + // + + if (fHeaderFile) + { + fHeaderFile->Close(); + delete fHeaderFile; + fHeaderTree = 0; + fHeader = 0; + } +} + Bool_t AliSelector::IsPrimaryCharged(TParticle* aParticle, Int_t aTotalPrimaries) const { // @@ -275,13 +337,19 @@ Bool_t AliSelector::IsPrimaryCharged(TParticle* aParticle, Int_t aTotalPrimaries // if the particle has a daughter primary, we do not want to count it if (aParticle->GetFirstDaughter() != -1 && aParticle->GetFirstDaughter() < aTotalPrimaries) + { + AliDebug(AliLog::kDebug+1, "Dropping particle because it has a daughter among the primaries."); return kFALSE; + } Int_t pdgCode = TMath::Abs(aParticle->GetPdgCode()); // skip quarks and gluon if (pdgCode <= 10 || pdgCode == 21) + { + AliDebug(AliLog::kDebug+1, "Dropping particle because it is a quark or gluon."); return kFALSE; + } if (strcmp(aParticle->GetName(),"XXX") == 0) { @@ -298,7 +366,10 @@ Bool_t AliSelector::IsPrimaryCharged(TParticle* aParticle, Int_t aTotalPrimaries } if (pdgPart->Charge() == 0) + { return kFALSE; + AliDebug(AliLog::kDebug+1, "Dropping particle because it is not charged."); + } return kTRUE; } diff --git a/PWG0/AliSelector.h b/PWG0/AliSelector.h index 4a8c16ac23a..3150b4d9fd5 100644 --- a/PWG0/AliSelector.h +++ b/PWG0/AliSelector.h @@ -1,3 +1,5 @@ +/* $Id$ */ + #ifndef ALISELECTOR_H #define ALISELECTOR_H @@ -28,17 +30,24 @@ class AliSelector : public TSelector { protected: TTree* GetKinematics(); + AliHeader* GetHeader(); Bool_t IsPrimaryCharged(TParticle* aParticle, Int_t aTotalPrimaries) const; TChain *fChain; //! pointer to the analyzed TTree or TChain AliESD* fESD; //! "ESD" branch in fChain - AliHeader* fHeader; //! "TE" branch in fChain, contains event header + + Int_t fCountFiles; // Nr. of current file private: void DeleteKinematicsFile(); + void DeleteHeaderFile(); + + TFile* fKineFile; //! pointer to Kinematics.root if the file was opened - TFile* fKineFile; //! pointer to Kinematics.root if the file was opened + TFile* fHeaderFile; //! pointer to galice.root, if the file was opened + TTree* fHeaderTree; //! + AliHeader* fHeader; //! ClassDef(AliSelector,0); }; diff --git a/PWG0/AliSelectorRL.cxx b/PWG0/AliSelectorRL.cxx index 7384fd7c16b..845eec36b45 100644 --- a/PWG0/AliSelectorRL.cxx +++ b/PWG0/AliSelectorRL.cxx @@ -1,3 +1,5 @@ +/* $Id$ */ + #include "AliSelectorRL.h" #include diff --git a/PWG0/AliSelectorRL.h b/PWG0/AliSelectorRL.h index ae0e252946f..c774290db00 100644 --- a/PWG0/AliSelectorRL.h +++ b/PWG0/AliSelectorRL.h @@ -1,3 +1,5 @@ +/* $Id$ */ + #ifndef ALISELECTORRL_H #define ALISELECTORRL_H diff --git a/PWG0/CorrectionMatrix2D.cxx b/PWG0/CorrectionMatrix2D.cxx index ce174504241..74b5cbcb5ea 100644 --- a/PWG0/CorrectionMatrix2D.cxx +++ b/PWG0/CorrectionMatrix2D.cxx @@ -1,3 +1,5 @@ +/* $Id$ */ + #include "CorrectionMatrix2D.h" //____________________________________________________________________ diff --git a/PWG0/CorrectionMatrix2D.h b/PWG0/CorrectionMatrix2D.h index 96cc060894c..28ea819b47e 100644 --- a/PWG0/CorrectionMatrix2D.h +++ b/PWG0/CorrectionMatrix2D.h @@ -1,3 +1,5 @@ +/* $Id$ */ + #ifndef CORRECTIONMATRIX2D_H #define CORRECTIONMATRIX2D_H diff --git a/PWG0/CreateESDChain.C b/PWG0/CreateESDChain.C index 0524dc1b39f..f25e1531281 100644 --- a/PWG0/CreateESDChain.C +++ b/PWG0/CreateESDChain.C @@ -1,5 +1,16 @@ -TChain* CreateESDChainFromDir(const char* aDataDir, Int_t aRuns = 20, Bool_t aAddHeader = kTRUE) +/* $Id$ */ + +// Helper macros for creating chains + +TChain* CreateESDChainFromDir(const char* aDataDir, Int_t aRuns = 20, Int_t offset = 0, Bool_t aAddHeader = kTRUE) { + // creates chain of files in a given directory. The structure is expected as: + // //AliESDs.root + // //galice.root (when flag is set) + // //AliESDs.root + // //galice.root (when flag is set) + // ... + if (!aDataDir) return 0; @@ -23,6 +34,12 @@ TChain* CreateESDChainFromDir(const char* aDataDir, Int_t aRuns = 20, Bool_t aAd if (!presentDir || !presentDir->IsDirectory() || strcmp(presentDir->GetName(), ".") == 0 || strcmp(presentDir->GetName(), "..") == 0) continue; + if (offset > 0) + { + --offset; + continue; + } + if (count++ == aRuns) break; @@ -44,6 +61,10 @@ TChain* CreateESDChainFromDir(const char* aDataDir, Int_t aRuns = 20, Bool_t aAd TChain* CreateESDChainFromList(const char* listFile, Int_t aRuns = 20, Bool_t aAddHeader = kTRUE) { + // Creates a chain from a file which contains a list of ESD files + // if is set, the filename of the galice.root file is created by replacing + // AliESDs to galice in the esd file name + if (!listFile) return 0; diff --git a/PWG0/Makefile b/PWG0/Makefile index 6fcfbf24932..3700a1a2b7e 100644 --- a/PWG0/Makefile +++ b/PWG0/Makefile @@ -1,3 +1,5 @@ +# $Id$ + PACKAGE = PWG0base include $(ROOTSYS)/test/Makefile.arch diff --git a/PWG0/PWG0baseLinkDef.h b/PWG0/PWG0baseLinkDef.h index dec411b15e2..26ff721ba58 100644 --- a/PWG0/PWG0baseLinkDef.h +++ b/PWG0/PWG0baseLinkDef.h @@ -11,9 +11,7 @@ #pragma link C++ class AliSelector+; #pragma link C++ class AliSelectorRL+; -#pragma link C++ class AlidNdEtaCorrectionSelector+; #pragma link C++ class AlidNdEtaAnalysisSelector+; -#pragma link C++ class AlidNdEtaAnalysisMCSelector+; #pragma link C++ class dNdEtaAnalysis+; #pragma link C++ class dNdEtaCorrection+; diff --git a/PWG0/PWG0selectorsLinkDef.h b/PWG0/PWG0selectorsLinkDef.h new file mode 100644 index 00000000000..09e5345cb93 --- /dev/null +++ b/PWG0/PWG0selectorsLinkDef.h @@ -0,0 +1,15 @@ +#ifdef __CINT__ +/* Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. * + * See cxx source for full Copyright notice */ + +/* $Id$ */ + +#pragma link off all globals; +#pragma link off all classes; +#pragma link off all functions; + +#pragma link C++ class AlidNdEtaCorrectionSelector+; +#pragma link C++ class AlidNdEtaAnalysisMCSelector+; +#pragma link C++ class AlidNdEtaAnalysisESDSelector+; + +#endif diff --git a/PWG0/dNdEta/AlidNdEtaAnalysisESDSelector.cxx b/PWG0/dNdEta/AlidNdEtaAnalysisESDSelector.cxx new file mode 100644 index 00000000000..0a32b3fc2f4 --- /dev/null +++ b/PWG0/dNdEta/AlidNdEtaAnalysisESDSelector.cxx @@ -0,0 +1,160 @@ +/* $Id$ */ + +#include "AlidNdEtaAnalysisESDSelector.h" + +#include +#include +#include +#include + +#include +#include + +#include "esdTrackCuts/AliESDtrackCuts.h" +#include "dNdEtaCorrection.h" +#include "dNdEtaAnalysis.h" + +ClassImp(AlidNdEtaAnalysisESDSelector) + +AlidNdEtaAnalysisESDSelector::AlidNdEtaAnalysisESDSelector() : + AlidNdEtaAnalysisSelector(), + fEsdTrackCuts(0), + fdNdEtaCorrection(0) +{ + // + // Constructor. Initialization of pointers + // +} + +AlidNdEtaAnalysisESDSelector::~AlidNdEtaAnalysisESDSelector() +{ + // + // Destructor + // + + // histograms are in the output list and deleted when the output + // list is deleted by the TSelector dtor +} + +void AlidNdEtaAnalysisESDSelector::SlaveBegin(TTree * tree) +{ + // The SlaveBegin() function is called after the Begin() function. + // When running with PROOF SlaveBegin() is called on each slave server. + // The tree argument is deprecated (on PROOF 0 is passed). + + AlidNdEtaAnalysisSelector::SlaveBegin(tree); + + if (fChain) + { + fEsdTrackCuts = dynamic_cast (fChain->GetUserInfo()->FindObject("AliESDtrackCuts")); + fdNdEtaCorrection = dynamic_cast (fChain->GetUserInfo()->FindObject("dNdEtaCorrection")); + } + + if (!fEsdTrackCuts) + AliDebug(AliLog::kError, "ERROR: Could not read EsdTrackCuts from user info."); + + if (!fEsdTrackCuts) + AliDebug(AliLog::kError, "ERROR: Could not read dNdEtaCorrection from user info."); +} + +Bool_t AlidNdEtaAnalysisESDSelector::Process(Long64_t entry) +{ + // The Process() function is called for each entry in the tree (or possibly + // keyed object in the case of PROOF) to be processed. The entry argument + // specifies which entry in the currently loaded tree is to be processed. + // It can be passed to either TTree::GetEntry() or TBranch::GetEntry() + // to read either all or the required parts of the data. When processing + // keyed objects with PROOF, the object is already loaded and is available + // via the fObject pointer. + // + // This function should contain the "body" of the analysis. It can contain + // simple or elaborate selection criteria, run algorithms on the data + // of the event and typically fill histograms. + + // WARNING when a selector is used with a TChain, you must use + // the pointer to the current TTree to call GetEntry(entry). + // The entry is always the local entry number in the current tree. + // Assuming that fChain is the pointer to the TChain being processed, + // use fChain->GetTree()->GetEntry(entry). + + if (AlidNdEtaAnalysisSelector::Process(entry) == kFALSE) + return kFALSE; + + // Check prerequisites + if (!fESD) + { + AliDebug(AliLog::kError, "ESD branch not available"); + return kFALSE; + } + + if (!fEsdTrackCuts) + { + AliDebug(AliLog::kError, "fESDTrackCuts not available"); + return kFALSE; + } + + // ######################################################## + // get the EDS vertex + const AliESDVertex* vtxESD = fESD->GetVertex(); + + // the vertex should be reconstructed + if (strcmp(vtxESD->GetName(),"default")==0) + return kTRUE; + + Double_t vtx_res[3]; + vtx_res[0] = vtxESD->GetXRes(); + vtx_res[1] = vtxESD->GetYRes(); + vtx_res[2] = vtxESD->GetZRes(); + + // the resolution should be reasonable??? + if (vtx_res[2]==0 || vtx_res[2]>0.1) + return kTRUE; + + Double_t vtx[3]; + vtxESD->GetXYZ(vtx); + + // ######################################################## + // loop over esd tracks + Int_t nTracks = fESD->GetNumberOfTracks(); + for (Int_t t=0; tGetTrack(t); + if (!esdTrack) + { + AliDebug(AliLog::kError, Form("ERROR: Could not retrieve track %d.", t)); + continue; + } + + // cut the esd track? + if (!fEsdTrackCuts->AcceptTrack(esdTrack)) + continue; + + Double_t p[3]; + esdTrack->GetConstrainedPxPyPz(p); // ### TODO or GetInnerPxPyPy / GetOuterPxPyPy + TVector3 vector(p); + + Float_t theta = vector.Theta(); + Float_t eta = -TMath::Log(TMath::Tan(theta/2.)); + + Float_t correction = fdNdEtaCorrection->GetCorrection(vtx[2], eta); + + fdNdEtaAnalysis->FillTrack(vtx[2], eta, correction); + + } // end of track loop + + // for event count per vertex + fdNdEtaAnalysis->FillEvent(vtx[2]); + + return kTRUE; +} + +void AlidNdEtaAnalysisESDSelector::WriteObjects() +{ + AlidNdEtaAnalysisSelector::WriteObjects(); + + if (fEsdTrackCuts) + fEsdTrackCuts->SaveHistograms("esd_tracks_cuts"); + + if (fdNdEtaCorrection) + fdNdEtaCorrection->SaveHistograms(); +} diff --git a/PWG0/dNdEta/AlidNdEtaAnalysisESDSelector.h b/PWG0/dNdEta/AlidNdEtaAnalysisESDSelector.h new file mode 100644 index 00000000000..56842e5c07f --- /dev/null +++ b/PWG0/dNdEta/AlidNdEtaAnalysisESDSelector.h @@ -0,0 +1,30 @@ +/* $Id$ */ + +#ifndef ALIDNDETAANALYSISESDSELECTOR_H +#define ALIDNDETAANALYSISESDSELECTOR_H + +#include "AlidNdEtaAnalysisSelector.h" + +class AliESDtrackCuts; +class dNdEtaCorrection; + +class AlidNdEtaAnalysisESDSelector : public AlidNdEtaAnalysisSelector { + public: + AlidNdEtaAnalysisESDSelector(); + virtual ~AlidNdEtaAnalysisESDSelector(); + + virtual void SlaveBegin(TTree *tree); + virtual Bool_t Process(Long64_t entry); + + protected: + virtual void WriteObjects(); + + AliESDtrackCuts* fEsdTrackCuts; // Object containing the parameters of the esd track cuts + dNdEtaCorrection* fdNdEtaCorrection; // correction map + + private: + + ClassDef(AlidNdEtaAnalysisESDSelector, 0); +}; + +#endif diff --git a/PWG0/dNdEta/AlidNdEtaAnalysisMCSelector.cxx b/PWG0/dNdEta/AlidNdEtaAnalysisMCSelector.cxx index f2241a696ed..f74e1a85f64 100644 --- a/PWG0/dNdEta/AlidNdEtaAnalysisMCSelector.cxx +++ b/PWG0/dNdEta/AlidNdEtaAnalysisMCSelector.cxx @@ -1,3 +1,5 @@ +/* $Id$ */ + #include "AlidNdEtaAnalysisMCSelector.h" #include @@ -6,16 +8,19 @@ #include #include #include +#include #include #include #include "dNdEtaAnalysis.h" + ClassImp(AlidNdEtaAnalysisMCSelector) -AlidNdEtaAnalysisMCSelector::AlidNdEtaAnalysisMCSelector(TTree * tree) : - AlidNdEtaAnalysisSelector(tree) +AlidNdEtaAnalysisMCSelector::AlidNdEtaAnalysisMCSelector() : + AlidNdEtaAnalysisSelector(), + fVertex(0) { // // Constructor. Initialization of pointers @@ -34,6 +39,8 @@ void AlidNdEtaAnalysisMCSelector::Init(TTree *tree) AlidNdEtaAnalysisSelector::Init(tree); tree->SetBranchStatus("ESD", 0); + + fVertex = new TH3F("vertex", "vertex", 50, -50, 50, 50, -50, 50, 50, -50, 50); } Bool_t AlidNdEtaAnalysisMCSelector::Process(Long64_t entry) @@ -44,11 +51,21 @@ Bool_t AlidNdEtaAnalysisMCSelector::Process(Long64_t entry) return kFALSE; TTree* particleTree = GetKinematics(); - if (!fHeader || !particleTree) + if (!particleTree) + { + AliDebug(AliLog::kError, "Kinematics not available"); return kFALSE; + } + + AliHeader* header = GetHeader(); + if (!header) + { + AliDebug(AliLog::kError, "Header not available"); + return kFALSE; + } // get the MC vertex - AliGenEventHeader* genHeader = fHeader->GenEventHeader(); + AliGenEventHeader* genHeader = header->GenEventHeader(); TArrayF vtxMC(3); genHeader->PrimaryVertex(vtxMC); @@ -59,12 +76,15 @@ Bool_t AlidNdEtaAnalysisMCSelector::Process(Long64_t entry) particleTree->SetBranchStatus("fPx", 1); particleTree->SetBranchStatus("fPy", 1); particleTree->SetBranchStatus("fPz", 1); - + particleTree->SetBranchStatus("fVx", 1); + particleTree->SetBranchStatus("fVy", 1); + particleTree->SetBranchStatus("fVz", 1); + TParticle* particle = 0; particleTree->SetBranchAddress("Particles", &particle); - Int_t nPrim = fHeader->GetNprimary(); - Int_t nTotal = fHeader->GetNtrack(); + Int_t nPrim = header->GetNprimary(); + Int_t nTotal = header->GetNtrack(); for (Int_t i_mc = nTotal - nPrim; i_mc < nTotal; ++i_mc) { @@ -76,9 +96,20 @@ Bool_t AlidNdEtaAnalysisMCSelector::Process(Long64_t entry) if (IsPrimaryCharged(particle, nPrim) == kFALSE) continue; + AliDebug(AliLog::kDebug+1, Form("Accepted primary %d, unique ID: %d", i_mc, particle->GetUniqueID())); + fdNdEtaAnalysis->FillTrack(vtxMC[2], particle->Eta(), 1); + fVertex->Fill(particle->Vx(), particle->Vy(), particle->Vz()); } fdNdEtaAnalysis->FillEvent(vtxMC[2]); return kTRUE; } + +void AlidNdEtaAnalysisMCSelector::Terminate() +{ + AlidNdEtaAnalysisSelector::Terminate(); + + new TCanvas; + fVertex->Draw(); +} diff --git a/PWG0/dNdEta/AlidNdEtaAnalysisMCSelector.h b/PWG0/dNdEta/AlidNdEtaAnalysisMCSelector.h index ca1a0d09608..4f54eb8d77a 100644 --- a/PWG0/dNdEta/AlidNdEtaAnalysisMCSelector.h +++ b/PWG0/dNdEta/AlidNdEtaAnalysisMCSelector.h @@ -1,19 +1,25 @@ +/* $Id$ */ + #ifndef ALIDNDETAANALYSISSELECTORMC_H #define ALIDNDETAANALYSISSELECTORMC_H #include "AlidNdEtaAnalysisSelector.h" +class TH3F; + class AlidNdEtaAnalysisMCSelector : public AlidNdEtaAnalysisSelector { public: - AlidNdEtaAnalysisMCSelector(TTree *tree=0); + AlidNdEtaAnalysisMCSelector(); virtual ~AlidNdEtaAnalysisMCSelector(); virtual void Init(TTree *tree); virtual Bool_t Process(Long64_t entry); + virtual void Terminate(); protected: private: + TH3F* fVertex; ClassDef(AlidNdEtaAnalysisMCSelector, 0); }; diff --git a/PWG0/dNdEta/AlidNdEtaAnalysisSelector.cxx b/PWG0/dNdEta/AlidNdEtaAnalysisSelector.cxx index 75076d08fa0..26e2a6ea9cf 100644 --- a/PWG0/dNdEta/AlidNdEtaAnalysisSelector.cxx +++ b/PWG0/dNdEta/AlidNdEtaAnalysisSelector.cxx @@ -1,24 +1,23 @@ +/* $Id$ */ + #include "AlidNdEtaAnalysisSelector.h" #include #include #include #include +#include #include #include -#include "esdTrackCuts/AliESDtrackCuts.h" -#include "dNdEtaCorrection.h" #include "dNdEtaAnalysis.h" ClassImp(AlidNdEtaAnalysisSelector) -AlidNdEtaAnalysisSelector::AlidNdEtaAnalysisSelector(TTree *) : +AlidNdEtaAnalysisSelector::AlidNdEtaAnalysisSelector() : AliSelector(), - fEsdTrackCuts(0), fdNdEtaAnalysis(0), - fdNdEtaCorrection(0), fdNdEtaAnalysisFinal(0) { // @@ -45,102 +44,6 @@ void AlidNdEtaAnalysisSelector::SlaveBegin(TTree * tree) AliSelector::SlaveBegin(tree); fdNdEtaAnalysis = new dNdEtaAnalysis("dndeta"); - - if (fChain) - { - fEsdTrackCuts = dynamic_cast (fChain->GetUserInfo()->FindObject("AliESDtrackCuts")); - fdNdEtaCorrection = dynamic_cast (fChain->GetUserInfo()->FindObject("dNdEtaCorrection")); - } - - if (!fEsdTrackCuts) - AliDebug(AliLog::kError, "ERROR: Could not read EsdTrackCuts from user info."); - - if (!fEsdTrackCuts) - AliDebug(AliLog::kWarning, "ERROR: Could not read dNdEtaCorrection from user info."); - - AliLog::SetClassDebugLevel("AliESDtrackCuts", 1); -} - -Bool_t AlidNdEtaAnalysisSelector::Process(Long64_t entry) -{ - // The Process() function is called for each entry in the tree (or possibly - // keyed object in the case of PROOF) to be processed. The entry argument - // specifies which entry in the currently loaded tree is to be processed. - // It can be passed to either TTree::GetEntry() or TBranch::GetEntry() - // to read either all or the required parts of the data. When processing - // keyed objects with PROOF, the object is already loaded and is available - // via the fObject pointer. - // - // This function should contain the "body" of the analysis. It can contain - // simple or elaborate selection criteria, run algorithms on the data - // of the event and typically fill histograms. - - // WARNING when a selector is used with a TChain, you must use - // the pointer to the current TTree to call GetEntry(entry). - // The entry is always the local entry number in the current tree. - // Assuming that fChain is the pointer to the TChain being processed, - // use fChain->GetTree()->GetEntry(entry). - - if (AliSelector::Process(entry) == kFALSE) - return kFALSE; - - // Check prerequisites - if (!fESD || !fEsdTrackCuts) - return kFALSE; - - // ######################################################## - // get the EDS vertex - const AliESDVertex* vtxESD = fESD->GetVertex(); - - // the vertex should be reconstructed - if (strcmp(vtxESD->GetName(),"default")==0) - return kTRUE; - - Double_t vtx_res[3]; - vtx_res[0] = vtxESD->GetXRes(); - vtx_res[1] = vtxESD->GetYRes(); - vtx_res[2] = vtxESD->GetZRes(); - - // the resolution should be reasonable??? - if (vtx_res[2]==0 || vtx_res[2]>0.1) - return kTRUE; - - Double_t vtx[3]; - vtxESD->GetXYZ(vtx); - - // ######################################################## - // loop over esd tracks - Int_t nTracks = fESD->GetNumberOfTracks(); - for (Int_t t=0; tGetTrack(t); - if (!esdTrack) - { - AliDebug(AliLog::kError, Form("ERROR: Could not retrieve track %d.", t)); - continue; - } - - // cut the esd track? - if (!fEsdTrackCuts->AcceptTrack(esdTrack)) - continue; - - Double_t p[3]; - esdTrack->GetConstrainedPxPyPz(p); // ### TODO or GetInnerPxPyPy / GetOuterPxPyPy - TVector3 vector(p); - - Float_t theta = vector.Theta(); - Float_t eta = -TMath::Log(TMath::Tan(theta/2.)); - - Float_t correction = fdNdEtaCorrection->GetCorrection(vtx[2], eta); - - fdNdEtaAnalysis->FillTrack(vtx[2], eta, correction); - - } // end of track loop - - // for event count per vertex - fdNdEtaAnalysis->FillEvent(vtx[2]); - - return kTRUE; } void AlidNdEtaAnalysisSelector::SlaveTerminate() @@ -193,17 +96,18 @@ void AlidNdEtaAnalysisSelector::Terminate() fdNdEtaAnalysisFinal->Finish(); TFile* fout = new TFile("out.root","RECREATE"); - - if (fEsdTrackCuts) - fEsdTrackCuts->SaveHistograms("esd_tracks_cuts"); - - if (fdNdEtaCorrection) - fdNdEtaCorrection->SaveHistograms(); - - fdNdEtaAnalysisFinal->SaveHistograms(); - + WriteObjects(); fout->Write(); fout->Close(); fdNdEtaAnalysisFinal->DrawHistograms(); } + +void AlidNdEtaAnalysisSelector::WriteObjects() +{ + // Write objects to output file + // this is an extra function to be overloaded... + // + + fdNdEtaAnalysisFinal->SaveHistograms(); +} diff --git a/PWG0/dNdEta/AlidNdEtaAnalysisSelector.h b/PWG0/dNdEta/AlidNdEtaAnalysisSelector.h index 52d3afd173e..552ba3a54e8 100644 --- a/PWG0/dNdEta/AlidNdEtaAnalysisSelector.h +++ b/PWG0/dNdEta/AlidNdEtaAnalysisSelector.h @@ -1,33 +1,29 @@ +/* $Id$ */ + #ifndef ALIDNDETAANALYSISSELECTOR_H #define ALIDNDETAANALYSISSELECTOR_H #include "AliSelector.h" -class AliESDtrackCuts; -class dNdEtaCorrection; class dNdEtaAnalysis; class AlidNdEtaAnalysisSelector : public AliSelector { public: - AlidNdEtaAnalysisSelector(TTree *tree=0); + AlidNdEtaAnalysisSelector(); virtual ~AlidNdEtaAnalysisSelector(); virtual void SlaveBegin(TTree *tree); - virtual Bool_t Process(Long64_t entry); virtual void SlaveTerminate(); virtual void Terminate(); protected: - AliESDtrackCuts* fEsdTrackCuts; // Object containing the parameters of the esd track cuts - - dNdEtaAnalysis* fdNdEtaAnalysis; // contains the intermediate histograms (on each slave) + virtual void WriteObjects(); - dNdEtaCorrection* fdNdEtaCorrection; // correction map - dNdEtaAnalysis* fdNdEtaAnalysisFinal; // contains the final histograms + dNdEtaAnalysis* fdNdEtaAnalysis; // contains the intermediate histograms (on each slave) + dNdEtaAnalysis* fdNdEtaAnalysisFinal; // contains the final histograms private: - - ClassDef(AlidNdEtaAnalysisSelector, 0); + ClassDef(AlidNdEtaAnalysisSelector, 0); }; #endif diff --git a/PWG0/dNdEta/AlidNdEtaCorrectionSelector.cxx b/PWG0/dNdEta/AlidNdEtaCorrectionSelector.cxx index 373f4ffa05f..f415d6c09a9 100644 --- a/PWG0/dNdEta/AlidNdEtaCorrectionSelector.cxx +++ b/PWG0/dNdEta/AlidNdEtaCorrectionSelector.cxx @@ -1,3 +1,5 @@ +/* $Id$ */ + #include "AlidNdEtaCorrectionSelector.h" #include @@ -107,9 +109,10 @@ Bool_t AlidNdEtaCorrectionSelector::Process(Long64_t entry) return kFALSE; } - if (!fHeader) + AliHeader* header = GetHeader(); + if (!header) { - AliDebug(AliLog::kError, "Header branch not available"); + AliDebug(AliLog::kError, "Header not available"); return kFALSE; } @@ -138,7 +141,7 @@ Bool_t AlidNdEtaCorrectionSelector::Process(Long64_t entry) // ######################################################## // get the MC vertex - AliGenEventHeader* genHeader = fHeader->GenEventHeader(); + AliGenEventHeader* genHeader = header->GenEventHeader(); TArrayF vtxMC(3); genHeader->PrimaryVertex(vtxMC); @@ -149,8 +152,8 @@ Bool_t AlidNdEtaCorrectionSelector::Process(Long64_t entry) TParticle* particle = 0; particleTree->SetBranchAddress("Particles", &particle); - Int_t nPrim = fHeader->GetNprimary(); - Int_t nTotal = fHeader->GetNtrack(); + Int_t nPrim = header->GetNprimary(); + Int_t nTotal = header->GetNtrack(); for (Int_t i_mc = nTotal - nPrim; i_mc < nTotal; ++i_mc) { diff --git a/PWG0/dNdEta/AlidNdEtaCorrectionSelector.h b/PWG0/dNdEta/AlidNdEtaCorrectionSelector.h index 11f60865081..6b6a28888d8 100644 --- a/PWG0/dNdEta/AlidNdEtaCorrectionSelector.h +++ b/PWG0/dNdEta/AlidNdEtaCorrectionSelector.h @@ -1,3 +1,5 @@ +/* $Id$ */ + #ifndef ALIDNDETACORRECTIONSELECTOR_H #define ALIDNDETACORRECTIONSELECTOR_H diff --git a/PWG0/dNdEta/dNdEtaAnalysis.cxx b/PWG0/dNdEta/dNdEtaAnalysis.cxx index 3d0590a550d..ae704487101 100644 --- a/PWG0/dNdEta/dNdEtaAnalysis.cxx +++ b/PWG0/dNdEta/dNdEtaAnalysis.cxx @@ -1,3 +1,5 @@ +/* $Id$ */ + #include "dNdEtaAnalysis.h" #include diff --git a/PWG0/dNdEta/dNdEtaAnalysis.h b/PWG0/dNdEta/dNdEtaAnalysis.h index aeff7068ce5..86783f45491 100644 --- a/PWG0/dNdEta/dNdEtaAnalysis.h +++ b/PWG0/dNdEta/dNdEtaAnalysis.h @@ -1,3 +1,5 @@ +/* $Id$ */ + #ifndef DNDETANALYSIS_H #define DNDETANALYSIS_H diff --git a/PWG0/dNdEta/dNdEtaCorrection.cxx b/PWG0/dNdEta/dNdEtaCorrection.cxx index 0ddaf6f37c8..d3dcd14ca02 100644 --- a/PWG0/dNdEta/dNdEtaCorrection.cxx +++ b/PWG0/dNdEta/dNdEtaCorrection.cxx @@ -1,3 +1,5 @@ +/* $Id$ */ + #include "dNdEtaCorrection.h" #include @@ -55,14 +57,14 @@ dNdEtaCorrection::Finish() { void dNdEtaCorrection::RemoveEdges(Float_t cut, Int_t nBinsVtx, Int_t nBinsEta) { - // remove edges of correction histogram by removing - // - bins with content less than cut + // remove edges of correction histogram by removing + // - bins with content bigger than cut // - bins next to bins with zero bin content - + Int_t nBinsX = hEtaVsVtx_corr->GetNbinsX(); Int_t nBinsY = hEtaVsVtx_corr->GetNbinsY(); - // set bin content to zero for bins with content smaller cut + // set bin content to zero for bins with content bigger than cut for (Int_t bx=0; bx<=nBinsX; bx++) { for (Int_t by=0; by<=nBinsY; by++) { if (hEtaVsVtx_corr->GetBinContent(bx,by)>cut) { @@ -75,28 +77,28 @@ dNdEtaCorrection::RemoveEdges(Float_t cut, Int_t nBinsVtx, Int_t nBinsEta) { // set bin content to zero for bins next to bins with zero TH2F* tmp = (TH2F*)hEtaVsVtx_corr->Clone("tmp"); tmp->Reset(); - + Bool_t done = kFALSE; Int_t nBinsVtxCount = 0; Int_t nBinsEtaCount = 0; - while (!done) { - if (nBinsVtxCountGetBinContent(bx+1,by)==0)|| + if ((hEtaVsVtx_corr->GetBinContent(bx+1,by)==0)|| (hEtaVsVtx_corr->GetBinContent(bx-1,by)==0)) - tmp->SetBinContent(bx,by,1); - + tmp->SetBinContent(bx,by,1); + } } - if (nBinsEtaCountGetBinContent(bx,by+1)==0)|| + if ((hEtaVsVtx_corr->GetBinContent(bx,by+1)==0)|| (hEtaVsVtx_corr->GetBinContent(bx,by-1)==0)) - tmp->SetBinContent(bx,by,1); + tmp->SetBinContent(bx,by,1); } - } + } for (Int_t bx=0; bx<=nBinsX; bx++) { for (Int_t by=0; by<=nBinsY; by++) { if (tmp->GetBinContent(bx,by)==1) { @@ -109,7 +111,7 @@ dNdEtaCorrection::RemoveEdges(Float_t cut, Int_t nBinsVtx, Int_t nBinsEta) { nBinsEtaCount++; if ((nBinsVtxCount>=nBinsVtx)&&(nBinsEtaCount>=nBinsEta)) done=kTRUE; } - tmp->Delete(); + tmp->Delete(); } diff --git a/PWG0/dNdEta/dNdEtaCorrection.h b/PWG0/dNdEta/dNdEtaCorrection.h index ccf7e7f1b2c..7a3ceb0f15b 100644 --- a/PWG0/dNdEta/dNdEtaCorrection.h +++ b/PWG0/dNdEta/dNdEtaCorrection.h @@ -1,6 +1,9 @@ +/* $Id$ */ + #ifndef DNDETACORRECTION_H #define DNDETACORRECTION_H + // ------------------------------------------------------ // // Class to handle corrections for dN/dEta measurements diff --git a/PWG0/dNdEta/drawCorrection.C b/PWG0/dNdEta/drawCorrection.C index e151d020214..4a819bc52d0 100644 --- a/PWG0/dNdEta/drawCorrection.C +++ b/PWG0/dNdEta/drawCorrection.C @@ -1,7 +1,9 @@ +/* $Id$ */ + void drawCorrection() { - gSystem->Load("libdNdEta.so"); - + gSystem->Load("libPWG0base"); + dNdEtaCorrection* dNdEtaMap = new dNdEtaCorrection(); dNdEtaMap->LoadCorrection("correction_map.root"); diff --git a/PWG0/dNdEta/makeCorrection2.C b/PWG0/dNdEta/makeCorrection2.C index 9fdc840834b..f134856b8a7 100644 --- a/PWG0/dNdEta/makeCorrection2.C +++ b/PWG0/dNdEta/makeCorrection2.C @@ -1,3 +1,5 @@ +/* $Id$ */ + // // Script to make correction maps for dndeta measurements using the // dNdEtaCorrection class. @@ -7,12 +9,11 @@ #include "../CreateESDChain.C" -void makeCorrection2(Char_t* dataDir, Int_t nRuns=20) +void makeCorrection2(Char_t* dataDir, Int_t nRuns=20, Int_t offset = 0) { gSystem->Load("libPWG0base"); - gSystem->SetIncludePath("-I$ALICE_ROOT/PWG0"); - TChain* chain = CreateESDChainFromDir(dataDir, nRuns); + TChain* chain = CreateESDChainFromDir(dataDir, nRuns, offset, kFALSE); fEsdTrackCuts = new AliESDtrackCuts(); fEsdTrackCuts->DefineHistograms(1); diff --git a/PWG0/dNdEta/testAnalysis2.C b/PWG0/dNdEta/testAnalysis2.C index a01a379dd2c..e7928b1e5f9 100644 --- a/PWG0/dNdEta/testAnalysis2.C +++ b/PWG0/dNdEta/testAnalysis2.C @@ -1,3 +1,5 @@ +/* $Id$ */ + // // Script to test the dN/dEta analysis using the dNdEtaAnalysis and // dNdEtaCorrection classes. Note that there is a cut on the events, @@ -8,12 +10,11 @@ #include "../CreateESDChain.C" -testAnalysis2(Char_t* dataDir, Int_t nRuns=20, Bool_t aMC = kFALSE) +testAnalysis2(Char_t* dataDir, Int_t nRuns=20, Int_t offset=0, Bool_t aMC = kFALSE) { gSystem->Load("libPWG0base"); - gSystem->SetIncludePath("-I$ALICE_ROOT/PWG0"); - TChain* chain = CreateESDChainFromDir(dataDir, nRuns); + TChain* chain = CreateESDChainFromDir(dataDir, nRuns, offset, kFALSE); // ######################################################## // selection of esd tracks @@ -34,12 +35,12 @@ testAnalysis2(Char_t* dataDir, Int_t nRuns=20, Bool_t aMC = kFALSE) { dNdEtaCorrection* dNdEtaCorrection = new dNdEtaCorrection(); dNdEtaCorrection->LoadHistograms("correction_map.root","dndeta_correction"); - dNdEtaCorrection->RemoveEdges(2,0,2); + dNdEtaCorrection->RemoveEdges(2, 0, 2); chain->GetUserInfo()->Add(dNdEtaCorrection); } - TString selectorName = ((aMC == kFALSE) ? "AlidNdEtaAnalysisSelector" : "AlidNdEtaAnalysisMCSelector"); + TString selectorName = ((aMC == kFALSE) ? "AlidNdEtaAnalysisESDSelector" : "AlidNdEtaAnalysisMCSelector"); AliLog::SetClassDebugLevel(selectorName, AliLog::kInfo); diff --git a/PWG0/esdTrackCuts/AliESDtrackCuts.cxx b/PWG0/esdTrackCuts/AliESDtrackCuts.cxx index 6fa20577f18..eba881f8fc6 100644 --- a/PWG0/esdTrackCuts/AliESDtrackCuts.cxx +++ b/PWG0/esdTrackCuts/AliESDtrackCuts.cxx @@ -1,3 +1,5 @@ +/* $Id$ */ + #include "AliESDtrackCuts.h" #include @@ -282,7 +284,7 @@ AliESDtrackCuts::AcceptTrack(AliESDtrack* esdTrack) { // Float_t nSigmaToVertex = -1; if (bRes[0]!=0 && bRes[1]!=0) - nSigmaToVertex = TMath::Sqrt(TMath::Power(b[0]/bRes[0],2) + TMath::Power(b[1]/bRes[1],2)); + nSigmaToVertex = TMath::Sqrt(TMath::Power(b[0]/bRes[0],2) + TMath::Power(b[1]/bRes[1],2)); // getting the kinematic variables of the track // (assuming the mass is known) diff --git a/PWG0/esdTrackCuts/AliESDtrackCuts.h b/PWG0/esdTrackCuts/AliESDtrackCuts.h index e5bdc03d4af..5f62c925e49 100644 --- a/PWG0/esdTrackCuts/AliESDtrackCuts.h +++ b/PWG0/esdTrackCuts/AliESDtrackCuts.h @@ -1,3 +1,5 @@ +/* $Id$ */ + #ifndef ALIESDTRACKCUTS_H #define ALIESDTRACKCUTS_H diff --git a/PWG0/esdTrackCuts/testESDtrackCuts.C b/PWG0/esdTrackCuts/testESDtrackCuts.C index 7c35b809dbb..decbd45bdf4 100644 --- a/PWG0/esdTrackCuts/testESDtrackCuts.C +++ b/PWG0/esdTrackCuts/testESDtrackCuts.C @@ -1,3 +1,5 @@ +/* $Id$ */ + testESDtrackCuts(Char_t* dataDir=, Int_t nRuns=10) { Char_t str[256]; diff --git a/PWG0/libPWG0base.pkg b/PWG0/libPWG0base.pkg index 0bc6f7e8de3..155d8d40455 100644 --- a/PWG0/libPWG0base.pkg +++ b/PWG0/libPWG0base.pkg @@ -1,8 +1,8 @@ +# $Id$ + HDRS = AliSelector.h \ AliSelectorRL.h \ - dNdEta/AlidNdEtaCorrectionSelector.h \ dNdEta/AlidNdEtaAnalysisSelector.h \ - dNdEta/AlidNdEtaAnalysisMCSelector.h \ dNdEta/dNdEtaAnalysis.h \ dNdEta/dNdEtaCorrection.h \ esdTrackCuts/AliESDtrackCuts.h \ @@ -10,10 +10,6 @@ HDRS = AliSelector.h \ SRCS = $(HDRS:.h=.cxx) -#PARBLACKLIST = dNdEta/AlidNdEtaCorrectionSelector.h \ -# dNdEta/AlidNdEtaAnalysisSelector.h \ -# dNdEta/AlidNdEtaAnalysisMCSelector.h - DHDR= PWG0baseLinkDef.h EINCLUDE= diff --git a/PWG0/libPWG0selectors.pkg b/PWG0/libPWG0selectors.pkg new file mode 100644 index 00000000000..32eda39b7cb --- /dev/null +++ b/PWG0/libPWG0selectors.pkg @@ -0,0 +1,14 @@ +# $Id$ + +# this library contains the selectors, which are loaded on the fly when one uses a given selector +# thus this library is never used, it just exists for the build system to check if everything compiles + +HDRS = dNdEta/AlidNdEtaCorrectionSelector.h \ + dNdEta/AlidNdEtaAnalysisMCSelector.h \ + dNdEta/AlidNdEtaAnalysisESDSelector.h + +SRCS = $(HDRS:.h=.cxx) + +DHDR= PWG0selectorsLinkDef.h + +EINCLUDE= diff --git a/PWG0/ptSpectra/makeCorrectionPtEta.C b/PWG0/ptSpectra/makeCorrectionPtEta.C index 644c73c9da1..37b05b3f0ad 100644 --- a/PWG0/ptSpectra/makeCorrectionPtEta.C +++ b/PWG0/ptSpectra/makeCorrectionPtEta.C @@ -1,3 +1,5 @@ +/* $Id$ */ + // // Script to calculate PtvsEta correction map using the CorrectionMatrix2D class. // -- 2.39.3