]> git.uio.no Git - u/mrichter/AliRoot.git/commitdiff
First version of the PS QA macros (K.McDermont,A.Kalweit,S.Bjelogrlic)
authorzconesa <zconesa@f7af4fe6-9843-0410-8265-dc069ae4e863>
Fri, 11 Jan 2013 17:42:31 +0000 (17:42 +0000)
committerzconesa <zconesa@f7af4fe6-9843-0410-8265-dc069ae4e863>
Fri, 11 Jan 2013 17:42:31 +0000 (17:42 +0000)
ANALYSIS/macros/PhysSelQA/AliPSQA.cxx [new file with mode: 0644]
ANALYSIS/macros/PhysSelQA/AliPSQA.h [new file with mode: 0644]
ANALYSIS/macros/PhysSelQA/AliPSQAVisualization.cxx [new file with mode: 0644]
ANALYSIS/macros/PhysSelQA/AliPSQAVisualization.h [new file with mode: 0644]
ANALYSIS/macros/PhysSelQA/PSQA.C [new file with mode: 0644]
ANALYSIS/macros/PhysSelQA/PSQAV.C [new file with mode: 0644]

diff --git a/ANALYSIS/macros/PhysSelQA/AliPSQA.cxx b/ANALYSIS/macros/PhysSelQA/AliPSQA.cxx
new file mode 100644 (file)
index 0000000..2d54999
--- /dev/null
@@ -0,0 +1,710 @@
+/////////////////////////////////////
+// Created by: Kevin McDermott     //
+// email: kmcderm3@nd.edu          //
+// CERN Summer Student 2012        //
+// University of Notre Dame du Lac //
+//                                 // 
+// Revision: 1.0                   //
+// Created on: August 6, 2012      //
+/////////////////////////////////////
+
+#include "AliPSQA.h"
+ClassImp(AliPSQA)
+
+AliPSQA::AliPSQA():
+TObject(),
+  fRunNumbers(0)
+{
+  // Default constructor settings for private data members
+  fQAcycle = 0; 
+  fLocalMode = kTRUE;
+  fGridPath = ""; 
+  fPSInput = ""; 
+  fLocalPath = "";
+  fROOTInput = "";
+  fOutRootName = "";
+  fCacheDirectory = "";
+  fRootOutDirectory = "";
+  fTxtOutDirectory = "";
+  fListBadFiles = new TList;
+  fNGoodRuns = 0; //Files that are not empty
+  fNTrigClasses = 0;
+  fNTrigChannels = 0;
+  fTxtFileName = "";
+  fSaveCache = kFALSE;
+  fDrawAllTGraphs = kFALSE;
+  fSaveQAValToTxtFile = kFALSE;
+  fSaveQAToROOTFile = kFALSE;
+
+  // Initialize the macro
+  InitializeRuns("");
+  InitializeTriggers("","");
+  InitializePlots("");
+
+  InitializeRowTrigSet();
+  InitializeFilled(); // Set once per object
+  InitializeValidRun();
+}
+
+//________________________________________________________________________________________________
+AliPSQA::~AliPSQA(){
+  delete[] fRunNumbers;
+  delete[] fTrigClasses;
+  delete[] fTrigChannels;
+       for(Int_t i=0;i<15;i++){
+               for(Int_t j=0;j<30;j++){
+                       for(Int_t k=0;k<2;k++){
+                               for(Int_t l=0;l<fgkNTrigLogic;l++){
+                                       delete[]  fGraphs[i][j][k][l];
+                               }
+                       }
+               }
+       }
+ // delete[] fGraphs;
+  delete[] fPlots;
+  delete[] fQAColumnsNumeratorP;
+  delete[] fQAColumnsDenominatorP;
+  delete[] fQAColumnsNumeratorM;
+  delete[] fQAColumnsDenominatorM;
+  delete fListBadFiles;
+}
+
+//________________________________________________________________________________________________
+void AliPSQA::InitializeRuns(const Char_t * listOfRuns)
+{
+  // without vectors, this process is quite contrived... Why doesn't ROOT have STL vectors??????
+
+  Int_t run_num; //run number from list
+  ifstream input_runs; //text file object
+  input_runs.open(listOfRuns, ios::in );  //open the text file
+
+  Int_t NRuns = 0; //number of runs to be processed 
+  while(input_runs >> run_num) { // count number of runs
+    NRuns++;
+  }
+
+  fNRuns = NRuns; // Set private data member to total runs to be processed
+  input_runs.close(); // reset the file
+
+  fRunNumbers = new Int_t [fNRuns]; // initialize private data member with number of runs
+  input_runs.open(listOfRuns, ios::in ); // open the ifstream again
+  for (Int_t irun = 0; irun < fNRuns; irun++){ 
+    input_runs >> fRunNumbers[irun]; // fill this array with run numbers
+  }
+
+  input_runs.close();
+
+  if (fNRuns == 0) {
+    Printf("Could not initialize run List !");
+    return;
+  }
+  
+}
+
+//________________________________________________________________________________________________
+void AliPSQA::InitializeTriggers(const Char_t * listOfTriggerNames, const Char_t * listOfTrigChannels){
+
+  TString trignames; //trigger names from list
+  ifstream input_tn; //text file object
+  input_tn.open(listOfTriggerNames, ios::in );  //open the text file
+  Int_t Ntn = 0; //number of trigger names to be used
+  
+  while ( input_tn >> trignames ) { // count number of trigger names
+    Ntn++;
+  }
+  
+  fNTrigClasses = Ntn; // Set private data member to total trigger names to be used
+  input_tn.close(); // reset the file
+
+  fTrigClasses = new TString [fNTrigClasses]; // initialize private data member with number of trig names
+  input_tn.open(listOfTriggerNames, ios::in );
+  for (Int_t itrigclass = 0; itrigclass < fNTrigClasses; itrigclass++) { // read in trig names, fill private data members
+    input_tn >> fTrigClasses[itrigclass];
+  }
+
+  input_tn.close();  
+
+  TString trigchan; //trigger names from list
+  ifstream input_tc; //text file object
+  input_tc.open(listOfTrigChannels, ios::in );  //open the text file
+  Int_t Ntc = 0; //number of trigger names to be used
+  
+  while ( input_tc >> trigchan ) { // count number of trigger names
+    Ntc++;
+  }
+  
+  fNTrigChannels = Ntc; // Set private data member to total trigger names to be used
+  input_tc.close(); // reset the file
+
+  fTrigChannels = new TString [fNTrigChannels]; // initialize private data member with number of trig names
+  input_tc.open(listOfTrigChannels, ios::in );
+  for (Int_t itrigchannel = 0; itrigchannel < fNTrigChannels; itrigchannel++) { // read in trig names, fill private data members
+    input_tc >> fTrigChannels[itrigchannel]; 
+  }
+
+  input_tc.close();  
+}
+
+//________________________________________________________________________________________________
+void AliPSQA::InitializePlots(const Char_t * listOfPlots){   // Allocate memory for all fGraphs
+
+  // First Dimension is the name of the TGraphErrors from list file
+
+  TString plotnames; //trigger names from list
+  ifstream input_pn; //text file object
+  input_pn.open(listOfPlots, ios::in );  //open the text file
+  Int_t Npn = 0; //number of trigger names to be used
+  
+  while ( input_pn >> plotnames ) { // count number of trigger names
+    Npn++;
+  }
+  
+  fNPlots = Npn; // Set private data member to total trigger names to be used
+  input_pn.close(); // reset the file
+
+  fPlots = new TString [fNPlots]; // initialize private data member with number of trig names
+  input_pn.open(listOfPlots, ios::in );
+       
+       cout << "Number of Plots : " << fNPlots << endl;
+       
+  for (Int_t iplot = 0; iplot < fNPlots; iplot++) { // read in trig names, fill private data members
+    input_pn >> fPlots[iplot];
+  }
+
+  input_pn.close();
+
+  // Set the Names of the Plots
+  fQAColumnsNumeratorP = new TString [fNPlots];
+  fQAColumnsDenominatorP = new TString [fNPlots];
+  for (Int_t iplot = 0; iplot < fNPlots; iplot++){
+    SetQAColumnLabelForPlots(iplot); // Set fQAColumn for each pair of variables to be analyzed, keeping the "_" for plot names
+  }
+  
+  // Set the Names of the columns to be used, see GetQAVals and PlotQA
+  fQAColumnsNumeratorM = new TString [fNPlots];
+  fQAColumnsDenominatorM = new TString [fNPlots];
+  for (Int_t iplot = 0; iplot < fNPlots; iplot++){
+    SetQAColumnLabelForMatching(iplot); // Set fQAColumn for each pair of variables to be analyzed, removing all "_", needed for string matching of fHistStats
+  }
+
+  // Allocate Memory for all trending Plots
+
+  for (Int_t i = 0; i < fNPlots; i++){
+    for (Int_t j = 0; j < fNTrigClasses; j++) {
+      for (Int_t k = 0; k < fNTrigChannels; k++) {
+       for (Int_t l = 0; l < fgkNTrigLogic; l++){ // Settings for Graphs 
+         fGraphs[i][j][k][l] = new TGraphErrors(fNRuns);
+         fGraphs[i][j][k][l]->SetName(Form("%s_over_%s_for_%s_%s_Trigger_%02i",fQAColumnsNumeratorP[i].Data(),fQAColumnsDenominatorP[i].Data(),fTrigClasses[j].Data(),fTrigChannels[k].Data(), l));
+         fGraphs[i][j][k][l]->SetTitle(Form("%s over %s for %s [%s] Trigger %02i",fQAColumnsNumeratorM[i].Data(),fQAColumnsDenominatorM[i].Data(),fTrigClasses[j].Data(),fTrigChannels[k].Data(), l));
+         fGraphs[i][j][k][l]->GetXaxis()->SetTitle("Run Number");
+         fGraphs[i][j][k][l]->GetYaxis()->SetTitle(Form("%s/%s",fQAColumnsNumeratorM[i].Data(),fQAColumnsDenominatorM[i].Data()));
+         fGraphs[i][j][k][l]->SetMarkerStyle(6);
+               
+               cout << "Names : " << fGraphs[i][j][k][l]->GetName() << endl;
+       }       
+      }
+    }
+  }
+  
+}
+
+//________________________________________________________________________________________________
+void AliPSQA::SetQAColumnLabelForPlots(Int_t iplot){
+
+  Ssiz_t start  = fPlots[iplot].First('h'); // h in fGraph
+  Ssiz_t finish = fPlots[iplot].Last('O'); // O in Over, first O may be from FO
+  Ssiz_t length = fPlots[iplot].Length();
+
+  TString label[2];
+  label[0] = TString(fPlots[iplot]( start + 1, finish - start - 1)); // Shift one over from the 'h'
+  label[1] = TString(fPlots[iplot]( finish + 4, length - finish - 4 ));  //Shift five over from the 'O' 
+
+  fQAColumnsNumeratorP[iplot]   = label[0];
+  fQAColumnsDenominatorP[iplot] = label[1];
+}
+
+//________________________________________________________________________________________________
+void AliPSQA::SetQAColumnLabelForMatching(Int_t iplot){
+  fQAColumnsNumeratorM[iplot] = fQAColumnsNumeratorP[iplot].Copy();
+  fQAColumnsDenominatorM[iplot] =  fQAColumnsDenominatorP[iplot].Copy();
+  
+  if(fQAColumnsNumeratorM[iplot].Contains("_")){ // Plot name contains _ in name
+    fQAColumnsNumeratorM[iplot].ReplaceAll("_",1," ",1);
+  }
+  if(fQAColumnsDenominatorM[iplot].Contains("_")){ // Plot name contains _ in name
+    fQAColumnsDenominatorM[iplot].ReplaceAll("_",1," ",1);
+  }
+}
+
+//________________________________________________________________________________________________
+void AliPSQA::InitializeRowTrigSet(){ // Reset the check for each unique trig combo to false for each run
+  for (Int_t i = 0; i < fNTrigClasses; i++) {
+    for (Int_t j = 0; j < fNTrigChannels; j++) {
+      for (Int_t k = 0; k < fgkNTrigLogic; k++){
+       fRowTrigSet[i][j][k] = kFALSE;
+      }
+    }
+  }
+}
+
+//________________________________________________________________________________________________
+void AliPSQA::InitializeFilled(){ // Initialize check to see if a trending plot should be written to a ROOT file
+  for (Int_t i = 0; i < fNPlots; i++){
+    for (Int_t j = 0; j < fNTrigClasses; j++) {
+      for (Int_t k = 0; k < fNTrigChannels; k++) {
+       for (Int_t l = 0; l < fgkNTrigLogic; l++){
+         fFilled[i][j][k][l] = kFALSE;
+       }
+      }
+    }
+  }
+}
+
+//________________________________________________________________________________________________
+void AliPSQA::InitializeValidRun(){ // Reset the check for a valid run for each run
+  for (Int_t i = 0; i < fNTrigClasses; i++) {
+    for (Int_t j = 0; j < fNTrigChannels; j++) {
+      for (Int_t k = 0; k < fgkNTrigLogic; k++){
+       fValidRun[i][j][k] = kFALSE;
+      }
+    }
+  }
+}
+//________________________________________________________________________________________________
+void AliPSQA::CacheFiles(){
+  
+  for(Int_t irun = 0; irun < fNRuns; irun++){
+
+    fCacheDirectory        = Form("%s/%09i/%s",fCachePath.Data(),fRunNumbers[irun],fPSInput.Data());
+    TString cacheFile      = Form("%s/%s",fCacheDirectory.Data(),fROOTInput.Data());
+  
+    // Check first to see if the root file exists, have to declare a dummy FileStat_t to use gSystem->GetPathInfo
+    // GetPathInfo returns 0 if path/file exists, 1 if it does not
+
+    FileStat_t dummy_filestat;
+
+    if(gSystem->GetPathInfo(cacheFile.Data(), dummy_filestat) == 1){ // file does not exist
+      // make this directory if cache directory does not exist, to prevent overwriting cached files already stored
+      if (gSystem->GetPathInfo(fCacheDirectory.Data(), dummy_filestat) == 1) { // cache directory does not exist
+       MakeDir(fCacheDirectory);
+      }
+    
+      TString gridFile = ""; // full path for grid file
+      // Get the grid path of the corresponding file to be cached
+      if(fPSInput.Contains("AOD")){ //Include QA Cycle for AODS
+       gridFile.Form("alien://%s/%09d/%s%3.3d/%s",fGridPath.Data(),fRunNumbers[irun],fPSInput.Data(),fQAcycle,fROOTInput.Data());
+      }
+      else{ // Do not Include QA Cycle for AODS
+       gridFile.Form("alien://%s/%09d/%s/%s",fGridPath.Data(),fRunNumbers[irun],fPSInput.Data(),fROOTInput.Data());
+      }
+
+      // copy to the directory 
+      TString cpCache = "alien_cp ";
+      cpCache+=gridFile;
+      cpCache+=" "; // copy to the current directory to directory specified
+      cpCache+=fCacheDirectory; 
+      gSystem->Exec(cpCache); // copy to the directory 
+    }
+  }
+}
+
+//________________________________________________________________________________________________
+
+void AliPSQA::MakeDir(TString dir){ // have to pass a private data member, kinda ugly, but otherwise use sentinel values or copy this function three times...
+  TString mkDir = "mkdir -p ";
+  mkDir += dir.Data();
+  gSystem->Exec(mkDir); // mkdir for the cache/output
+}
+
+//________________________________________________________________________________________________
+Bool_t AliPSQA::ComputeQAPerRun(){
+  for(Int_t irun = 0; irun < fNRuns; irun++){
+    
+    // Reset RowTrigSet to kFALSE for every run
+    
+    InitializeRowTrigSet();
+    InitializeValidRun();
+    
+    TFile *rootfile = 0; // root file to be used
+    TString filename = ""; // full path directory of root file to be used
+
+    filename = GetRootFileName(irun, filename);
+    Printf("\nBegin reading: %s", filename.Data());
+    rootfile=TFile::Open(filename.Data());
+
+         cout << "filename processed = " << filename << endl;
+         
+    // If the file is not available, continue
+    if(!rootfile){
+      Printf("File %d is not available.\n",fRunNumbers[irun]);
+      fListBadFiles->Add(new TObjString(Form("No root file found in path: %s",filename.Data())));
+      continue;
+    }
+
+    // Get the relevant histogram, fHistStatistics
+    TH2D * hStats = (TH2D*) rootfile->Get("fHistStatistics");
+    if(!hStats){
+      fListBadFiles->Add(new TObjString(Form("fHistStats not found in path: %s",filename.Data())));
+      continue;
+    }
+
+    // Create output to be stored in a txt file, to be used for webpage
+    std::ofstream outfile; // to be used to make a txtfile
+    OpenTxtFile(irun, outfile);
+
+    Bool_t oneFilledGraphPerRun = kTRUE; // Check to see if run has any entries
+
+    // Loop over all possible values of & and * to generate data for each run
+    
+    for(Int_t itrigclass = 0; itrigclass < fNTrigClasses; itrigclass++){
+      for(Int_t itrigchannel = 0; itrigchannel < fNTrigChannels; itrigchannel++){
+        for(Int_t itriglogic = 0; itriglogic < fgkNTrigLogic; itriglogic++){
+            fValidRun[itrigclass][itrigchannel][itriglogic] = ProcessQA(itrigclass, itrigchannel, itriglogic, irun, hStats, outfile);
+            // Set boolean once to check if run contains any data
+            if( (oneFilledGraphPerRun == kFALSE) && (fValidRun[itrigclass][itrigchannel][itriglogic] == kTRUE) ) {
+                oneFilledGraphPerRun = kTRUE;
+            }
+        }
+      }
+    }
+    
+    if (oneFilledGraphPerRun == kTRUE){
+      cout << "Wrote " << Form("%s/%s_%09i.txt",fTxtOutDirectory.Data(),fTxtFileName.Data(),fRunNumbers[irun]) << endl;
+      fNGoodRuns++;
+    }
+    else {
+      fListBadFiles->Add(new TObjString(Form("No events found in path %s",filename.Data())));
+    }
+    // Close the txt file, need a new one every run
+    outfile.close();
+  }// End loop over runs
+
+  if (fSaveQAToROOTFile){
+    SaveQAPlots(); // Will write all good graphs (after being cleaned up) to a root file.  Will make output directory if it does not exist
+  }
+      
+  cout << "Files Statistics" << endl;
+  cout << " Total Runs [" << fNRuns << "]" << endl;
+  cout << " Good  Runs [" << fNGoodRuns << "]" <<  endl;
+  
+  if (fNGoodRuns != 0){
+    return kTRUE;
+  }
+  else{
+    return kFALSE;
+  }
+}// End ComputeQAPerRun()
+
+//________________________________________________________________________________________________
+TString AliPSQA::GetRootFileName(Int_t irun, TString filename){
+  // check if QA file is available and open it
+  // try different QA train outputs
+  if(!fLocalMode){ // Run on Alien
+    if(fPSInput.Contains("AOD")){ //Include QA Cycle for AODS
+      filename.Form("alien://%s/%09d/%s%3.3d/%s",fGridPath.Data(),fRunNumbers[irun],fPSInput.Data(),fQAcycle,fROOTInput.Data());
+    }
+    else{ // Do not Include QA Cycle for AODS
+      filename.Form("alien://%s/%09d/%s/%s",fGridPath.Data(),fRunNumbers[irun],fPSInput.Data(),fROOTInput.Data());
+    }
+  }
+  else{ // Run locally, either cached files, or some other directory
+    filename.Form("%s/%09d/%s/%s",fLocalPath.Data(),fRunNumbers[irun],fPSInput.Data(),fROOTInput.Data());
+  }
+  return filename;
+}
+
+//________________________________________________________________________________________________
+void AliPSQA::OpenTxtFile(Int_t irun, std::ofstream & outfile){ // Create a text file per run of qavals
+  TString txtfile = "";
+  txtfile.Form("%s/%s_%09i.txt",fTxtOutDirectory.Data(),fTxtFileName.Data(),fRunNumbers[irun]);
+  outfile.open(txtfile.Data(), ios::out);
+}
+
+//________________________________________________________________________________________________
+
+Bool_t AliPSQA::ProcessQA(Int_t itrigclass, Int_t itrigchannel, Int_t itriglogic, Int_t irun, TH2D* hStats, std::ofstream & outfile){
+  
+  Int_t ibiny = SearchYLabels(itrigclass, itrigchannel, itriglogic, hStats);
+  if (ibiny < 0){ // ifibiny = -1, (no labels match) returns false for ProcessQA, skip this combo of * and & 
+    return kFALSE;
+  }
+  
+  Bool_t isNotTotallyEmpty = kFALSE; // Check to see if qa is totally empty, assume totally empty
+  Double_t qavals[2]; // qavals[0] = All event hits, used to check if run is empty, qavals[1] = actual qa value being processed for a given run, and trig combo
+
+  for (Int_t iplot = 0; iplot < fNPlots; iplot++){ // Loop over all plots to get qa vals and plot them
+   
+    Int_t ibinx[2] = {-1,-1}; // if ibinx = -1 (if no labels match), then move to next column
+    SearchXLabels(iplot, ibinx, hStats); 
+    if ( (ibinx[0] < 0) || (ibinx[1] < 0) ){ 
+      continue;
+    }
+
+    // Get QA Vals if all labels are valid
+
+    GetQAVals(hStats, ibinx, ibiny, qavals);
+    if ( (qavals[0] < 1e-6) || (qavals[1] < 1e-6) ){ // if no events in PS, then continue
+      continue;
+    }
+    else{ // otherwise, fill plots and save to txt file
+      if (isNotTotallyEmpty == kFALSE){
+       isNotTotallyEmpty = kTRUE;
+      }
+      
+      // Part of loop to save the output data
+
+      if (fSaveQAToROOTFile){ 
+       PlotQA(iplot, itrigclass, itrigchannel, itriglogic, irun, qavals);
+      }
+      
+      if (fSaveQAValToTxtFile){ // if true, save a text file of all qavals per run
+       // First Check to make sure path exists to save data
+       FileStat_t dummy_filestat;
+       if (gSystem->GetPathInfo(fTxtOutDirectory.Data(), dummy_filestat) == 1) { // output directory does not exist
+         MakeDir(fTxtOutDirectory); // therefore make it
+       }
+       SaveQAValToTxtFile(iplot, itrigclass, itrigchannel, itriglogic, qavals, outfile);
+      }
+    }
+  }
+  return isNotTotallyEmpty;
+}
+
+//________________________________________________________________________________________________
+Int_t AliPSQA::SearchYLabels(Int_t itrigclass, Int_t itrigchannel, Int_t itriglogic, TH2D* hStats){ // returns the ybin to get data
+  // Search for each unique combination of * and & along y-axis of fHistStats
+  Int_t trigMask[3]; // trigMask[0] = trig class, reduced &val; trigMask[1] = trig channel/partition, from &val if 30th bit is on; trigMask[2] = *val, trig logic
+
+  Int_t nbiny = hStats->GetNbinsY();
+  
+  for(Int_t ibiny = 1; ibiny <= nbiny; ibiny++){ // Y-Axis for fHistStats starts at bin 1
+    TString label = hStats->GetYaxis()->GetBinLabel(ibiny);
+    // Check the trig logic and trig mask
+
+    GetTrigMask(label, trigMask);
+    //parse the label to return whether fast or slow --> return trigMaskChannel
+
+    if( (trigMask[0]==itrigclass) && (trigMask[1]==itrigchannel) && (trigMask[2]==itriglogic) ) { // set for unique trig class, channel, and trig number
+      
+      if (fRowTrigSet[itrigclass][itrigchannel][itriglogic] == kFALSE){
+       fRowTrigSet[itrigclass][itrigchannel][itriglogic] = kTRUE;
+       return ibiny;  // set ybin to get data; 
+      }
+    }
+  }    
+  return -1; // returns -1 if there is no matching y label
+}
+
+//________________________________________________________________________________________________
+void AliPSQA::GetTrigMask(TString label, Int_t * trigMask){
+  // Ssiz_t -> int returned for length of string, at this index
+
+  Ssiz_t start  = label.First('&');
+  Ssiz_t finish = label.First('*');
+  Ssiz_t length = label.Length();
+  
+  TString maskLabel( label( start+1, finish - start - 1 ) ); // returns the substring between the & and *
+  Int_t   maskInt = maskLabel.Atoi(); // Convert string to int (the int is in decimal form)
+  
+  TString logicLabel( label( finish+1, length - finish) );
+  Int_t   triglogic = logicLabel.Atoi(); // trig logic number, from *val
+
+  // convert int to binary check for what channel it is and see what class/mask
+
+  ////////////////////////////////
+
+  // Converts int to string with the binary representation --> code snippet taken from online
+
+  TString binary = DecInttToBinTString(maskInt);
+
+  ///////////////////////////////
+
+  Ssiz_t secondbit = binary.Last('1');
+  Ssiz_t binlength = binary.Length();
+  
+  Int_t trigclass; // trig class name
+  Int_t trigchannel; // fast or regular?
+
+  if (binlength != 31){ //Regular channel, 30th bit for kFast is off
+    trigclass   = binlength - 1; // equivalent statements = secondbit - 1 = firstbit - 1 = length - firstbit
+    trigchannel = 0;
+  }
+  else{ //Fast channel, if more than just regular vs fast is specified, must modify parsing and provide more robust else-ifs
+    trigclass   = binlength - secondbit -1;
+    trigchannel = 1;
+  }
+  trigMask[0] = trigclass;
+  trigMask[1] = trigchannel;
+  trigMask[2] = triglogic;
+}
+
+//________________________________________________________________________________________________
+TString AliPSQA::DecInttToBinTString(Int_t maskInt){
+  if ( maskInt == 0 ) return "0";
+  if ( maskInt == 1 ) return "1";
+  
+  if ( maskInt % 2 == 0 ){
+    return (DecInttToBinTString(maskInt / 2) + "0");
+  }
+  else{
+    return (DecInttToBinTString(maskInt / 2) + "1");
+  }
+}
+
+//________________________________________________________________________________________________
+void AliPSQA::SearchXLabels(Int_t iplot, Int_t * ibinx, TH2D * hStats){
+
+  // Search x-axis for label matching qa column val to be used
+  Int_t nbinx = hStats->GetNbinsX(); // Total nbins in x-axis
+  
+  for (Int_t jbinx = 1; jbinx <= nbinx; jbinx++){ // look for the column value for numerator
+    TString label = hStats->GetXaxis()->GetBinLabel(jbinx);
+    if (label.CompareTo(fQAColumnsNumeratorM[iplot].Data(), TString::kExact) == 0){ // CompareTo returns 0 if the two TStrings are the same
+      ibinx[0] = jbinx;
+      break;
+    }
+  }
+
+  for (Int_t jbinx = 1; jbinx <= nbinx; jbinx++){ // look for the column value for denominator
+    TString label = hStats->GetXaxis()->GetBinLabel(jbinx);
+    if (label.CompareTo(fQAColumnsDenominatorM[iplot].Data(), TString::kExact) == 0){ // CompareTo returns 0 if the two TStrings are the same
+      ibinx[1] = jbinx;
+      break;
+    }
+  }
+}
+
+//________________________________________________________________________________________________
+void AliPSQA::GetQAVals(TH2D * hStats, Int_t * ibinx, Int_t ibiny, Double_t * qavals){ 
+  qavals[0] = hStats->GetBinContent(ibinx[0],ibiny); // QAval of the first column called, numerator 
+  qavals[1] = hStats->GetBinContent(ibinx[1],ibiny); // QAval demoninator for ratio
+}
+
+//________________________________________________________________________________________________
+void AliPSQA::PlotQA(Int_t iplot, Int_t itrigclass, Int_t itrigchannel, Int_t itriglogic, Int_t irun, Double_t * qavals){
+  fGraphs[iplot][itrigclass][itrigchannel][itriglogic]->SetPoint(irun, fRunNumbers[irun], qavals[0]/qavals[1]); // QA Val for the plot
+  fGraphs[iplot][itrigclass][itrigchannel][itriglogic]->SetPointError(irun, 0., GetError(qavals, iplot)); // QA val error for correlated subsets
+  
+  if (fFilled[iplot][itrigclass][itrigchannel][itriglogic] == kFALSE){
+    fFilled[iplot][itrigclass][itrigchannel][itriglogic] = kTRUE; // need this boolean for later to only save filled graphs
+  }
+}
+
+//________________________________________________________________________________________________
+Double_t AliPSQA::GetError(Double_t * qavals, Int_t iplot){
+  Double_t error;
+  if ( fQAColumnsDenominatorM[iplot].CompareTo("Trigger class", TString::kExact) == 0) { // Set error if one QA val is subset of other
+    error = UncNRatioCorrelated(qavals);
+  }
+  else{ // Set error for correlated sets, but not subsets of each other
+    error = ErrorRatioNotSubsets(qavals);
+  }
+  return error;
+}
+
+//________________________________________________________________________________________________
+Double_t AliPSQA::UncNRatioCorrelated(Double_t * qavals)
+{
+  Double_t eff = qavals[0] / qavals[1];
+  Double_t err = TMath::Sqrt( eff*(1.0-eff) ) / TMath::Sqrt( qavals[1] );
+  return err;
+}
+
+//________________________________________________________________________________________________
+Double_t AliPSQA::ErrorRatioNotSubsets(Double_t * qavals)
+{
+  Double_t qa0err = TMath::Power((TMath::Sqrt(qavals[0]) / qavals[0]), 2);
+  Double_t qa1err = TMath::Power((TMath::Sqrt(qavals[1]) / qavals[1]), 2);
+  Double_t err = TMath::Sqrt(qa0err + qa1err) * (qavals[0] / qavals[1]);
+  return err;
+}
+
+//________________________________________________________________________________________________
+void AliPSQA::SaveQAValToTxtFile(Int_t iplot, Int_t itrigclass, Int_t itrigchannel, Int_t itriglogic,  Double_t * qavals, std::ofstream & outfile){
+  outfile << "PS: \"" << fTrigClasses[itrigclass].Data() << " [" << fTrigChannels[itrigchannel].Data() << "] Trigger " << itriglogic << "\":" << fQAColumnsNumeratorP[iplot].Data() << "/" << fQAColumnsDenominatorP[iplot].Data() << ", " << qavals[0]/qavals[1] << ", " << GetError(qavals, iplot) << endl; // store qavals in txt file
+}
+
+//________________________________________________________________________________________________
+void AliPSQA::SaveQAPlots(){ // Return a boolean to see if QA check produced any plots
+
+  // First check to see if output directory exists, otherwise create it
+  FileStat_t dummy_filestat;
+  if (gSystem->GetPathInfo(fRootOutDirectory.Data(), dummy_filestat) == 1) { // output directory does not exist
+    MakeDir(fRootOutDirectory);
+  }
+
+  // Save the output in a root file only if fFilled for that plot == kTRUE
+  
+  TFile * rootfile = new TFile(Form("%s/%s",fRootOutDirectory.Data(),fOutRootName.Data()),"RECREATE");
+  rootfile->cd();
+  for (Int_t iplot = 0; iplot < fNPlots; iplot++){
+    for (Int_t itrigclass = 0; itrigclass < fNTrigClasses; itrigclass++){
+      for (Int_t itrigchannel = 0; itrigchannel < fNTrigChannels; itrigchannel++){
+       for (Int_t itriglogic = 0; itriglogic < fgkNTrigLogic; itriglogic++){
+               cout << "File name : " << fGraphs[iplot][itrigclass][itrigchannel][itriglogic]->GetName() << " filled? yes/no " << fFilled[iplot][itrigclass][itrigchannel][itriglogic] << endl; 
+         if (fFilled[iplot][itrigclass][itrigchannel][itriglogic] == kTRUE){
+                 
+           CleanUpGraphs(fGraphs[iplot][itrigclass][itrigchannel][itriglogic]);
+           fGraphs[iplot][itrigclass][itrigchannel][itriglogic]->Write();
+                 
+                 //cout << "Written to file : " << fGraphs[iplot][itrigclass][itrigchannel][itriglogic]->GetName() << endl; 
+         }
+       } 
+      }
+    }
+  }
+  cout << "Wrote " << Form("%s/%s",fRootOutDirectory.Data(),fOutRootName.Data()) << endl;
+  rootfile->Close();
+  delete rootfile;
+}
+
+//________________________________________________________________________________________________
+void AliPSQA::CleanUpGraphs(TGraphErrors * plot){ // Clean up default values of graphs to be saved in ROOT file
+
+  // Have to unfortunately change the looping variables, scary, I know, but otherwise the file will not be cleaned up correctly.  See documentation on ROOT page for RemovePoint and GetPoint.
+
+  Double_t x;
+  Double_t y;
+  for (Int_t irun = 0; irun < plot->GetN(); irun++){
+    plot->GetPoint(irun, x, y);
+    if ( (TMath::Abs(x) < 1e-6) && (TMath::Abs(y) < 1e-6) ){
+      plot->RemovePoint(irun);
+      irun--;
+    }
+  }
+}
+
+//________________________________________________________________________________________________
+void AliPSQA::DrawAllTGraphs(){
+
+  gStyle->SetOptStat(0);
+  gStyle->SetPalette(1);
+  gStyle->SetCanvasColor(10);
+  gStyle->SetFrameFillColor(10);
+  // do not use scientific notation for run number
+  TGaxis::SetMaxDigits(6);
+  
+  TCanvas * c1;
+  
+  for (Int_t i = 0; i < fNPlots; i++){
+    for (Int_t j = 0; j < fNTrigClasses; j++){
+      for (Int_t k = 0; k < fNTrigChannels; k++){
+       for (Int_t l = 0; l < fgkNTrigLogic; l++){
+         if (fFilled[i][j][k][l] == kTRUE){
+           c1 = new TCanvas;
+           c1->cd();
+           fGraphs[i][j][k][l]->SetName(Form("%s_over_%s_for_%s_%s_Trigger_%02i",fQAColumnsNumeratorP[i].Data(),fQAColumnsDenominatorP[i].Data(),fTrigClasses[j].Data(),fTrigChannels[k].Data(), l));
+           fGraphs[i][j][k][l]->SetTitle(Form("%s over %s for %s [%s] Trigger %02i",fQAColumnsNumeratorM[i].Data(),fQAColumnsDenominatorM[i].Data(),fTrigClasses[j].Data(),fTrigChannels[k].Data(), l));
+           fGraphs[i][j][k][l]->GetXaxis()->SetTitle("Run Number");
+           fGraphs[i][j][k][l]->GetYaxis()->SetTitle(Form("%s/%s",fQAColumnsNumeratorM[i].Data(),fQAColumnsDenominatorM[i].Data()));
+            
+           fGraphs[i][j][k][l]->Draw("AP");
+         }
+       } 
+      }
+    }
+  }
+}
+
diff --git a/ANALYSIS/macros/PhysSelQA/AliPSQA.h b/ANALYSIS/macros/PhysSelQA/AliPSQA.h
new file mode 100644 (file)
index 0000000..1a904ee
--- /dev/null
@@ -0,0 +1,197 @@
+/////////////////////////////////////
+// Created by: Kevin McDermott     //
+// email: kmcderm3@nd.edu          //
+// CERN Summer Student 2012        //
+// University of Notre Dame du Lac //
+//                                 // 
+// Revision: 1.0                   //
+// Created on: August 6, 2012      //
+/////////////////////////////////////
+
+#ifndef ALIPSQA_H
+#define ALIPSQA_H
+
+#if !defined(__CINT__) || defined(__MAKECINT__)
+#include "TCanvas.h"
+#include "TH2D.h"
+#include "TGraphErrors.h"
+#include "TFile.h"
+#include "TMath.h"
+#include "TList.h"
+#include <Riostream.h>
+#include "TSystem.h"
+#include "TGaxis.h"
+#include "TStyle.h"
+#endif
+
+class AliPSQA : public TObject
+{
+ public: 
+  AliPSQA();
+  ~AliPSQA();
+  
+  // Functions listed in order of their appearance in the macro/class
+
+  // Initializers in constructor
+
+  void InitializeRuns(const Char_t * listOfRuns);
+  void InitializeTriggers(const Char_t * listOfTriggerNames, const Char_t * listOfTrigMaskChannel);
+  void InitializePlots(const Char_t * listOfPlots);
+  void SetQAColumnLabelForPlots(Int_t iplot);
+  void SetQAColumnLabelForMatching(Int_t iplot);
+  void InitializeRowTrigSet();
+  void InitializeFilled();
+  void InitializeValidRun();
+  
+  // In order of calls in macro
+
+  void CacheFiles(); // Potential First call in macro
+  void MakeDir(TString dir);
+
+  Bool_t ComputeQAPerRun(); // Second call in macro
+  TString GetRootFileName(Int_t irun, TString filename);
+  void OpenTxtFile(Int_t irun, ofstream & outfile);
+  Bool_t ProcessQA(Int_t itrigclass, Int_t itrigchannel, Int_t itriglogic, Int_t irun, TH2D* hStats, ofstream & outfile);
+  Int_t SearchYLabels(Int_t itrigclass, Int_t itrigchannel, Int_t itriglogic, TH2D* hStats);
+  void GetTrigMask(TString label, Int_t * trigMask);
+  TString DecInttToBinTString(Int_t maskInt);
+  void SearchXLabels(Int_t iplot, Int_t * ibinx, TH2D * hStats);
+  void GetQAVals(TH2D * hstats, Int_t * ibinx, Int_t ibiny,  Double_t * qavals);
+  void PlotQA(Int_t iplot, Int_t itrigclass, Int_t itrigchannel, Int_t itriglogic, Int_t irun, Double_t * qavals);  
+  Double_t GetError(Double_t * qavals, Int_t iplot);
+  Double_t UncNRatioCorrelated(Double_t * qavals);
+  Double_t ErrorRatioNotSubsets(Double_t * qavals);
+  void SaveQAValToTxtFile(Int_t iplot, Int_t itrigclass, Int_t itrigchannel, Int_t itriglogic,  Double_t * qavals, ofstream& outfile);
+  void SaveQAPlots(); 
+  void CleanUpGraphs(TGraphErrors * plot); 
+
+  TList * GetBadFiles(){return fListBadFiles;}; // Potential third call in macro
+
+  void DrawAllTGraphs(); // Potential fourth call in macro
+
+  // Getters and Setters for macro conditions
+  
+  void    SetSaveCache(Bool_t save){fSaveCache = save;};
+  Bool_t  GetSaveCache(){return fSaveCache;};
+
+  void    SetCachePath(TString cpath){fCachePath = cpath;};
+  TString GetCachePath(){return fCachePath;};
+
+  void    SetLocalMode(Bool_t mode){fLocalMode = mode;};
+  Bool_t  GetLocalMode(){return fLocalMode;};
+
+  void    SetLocalPath(TString lpath){fLocalPath = lpath;};
+  TString GetLocalPath(){return fLocalPath;};
+
+  void    SetGridPath(TString gpath){fGridPath = gpath;};
+  TString GetGridPath(){return fGridPath;}; 
+
+  void    SetPSInput(TString input){fPSInput = input;};
+  TString GetPSInput(){return fPSInput;};
+
+  void    SetROOTInput(TString RI){fROOTInput = RI;};
+  TString GetROOTInput(){return fROOTInput;};
+
+  void    SetRootOutDirectory(TString out){fRootOutDirectory = out;};
+  TString GetRootOutDirectory(){return fRootOutDirectory;};  
+
+  void    SetTxtOutDirectory(TString out){fTxtOutDirectory = out;};
+  TString GetTxtOutDirectory(){return fTxtOutDirectory;}; 
+
+  void    SetOutRootName(TString name){fOutRootName = name;};
+  TString GetOutRootName(){return fOutRootName;};
+
+  void    SetSaveQAValToTxtFile(Bool_t savetxt){fSaveQAValToTxtFile = savetxt;};
+  Bool_t  GetSaveQAValToTxtFile(){return fSaveQAValToTxtFile;};
+
+  void    SetTxtFileName(TString txt){fTxtFileName = txt;};
+  TString GetTxtFileName(){return fTxtFileName;};  
+
+  void    SetSaveQAToROOTFile(Bool_t saverf){fSaveQAToROOTFile = saverf;};
+  Bool_t  GetSaveQAToROOTFile(){return fSaveQAToROOTFile;};
+
+  void    SetDrawAllTGraphs(Bool_t drawall){fDrawAllTGraphs = drawall;};
+  Bool_t  GetDrawAllTGraphs(){return fDrawAllTGraphs;};
+
+  // Legacy get/set
+
+  void    SetQACycle(Int_t cycle){fQAcycle = cycle;};
+  Int_t   GetQACycle(){return fQAcycle;};
+
+ private: 
+  TString fROOTInput; // name of root file to be analyzed
+  Int_t *fRunNumbers; // Runs to be used in macro
+  Int_t fNRuns; // Number of Runs used in macro
+  TString * fPlots; // List of plots to be generated
+  Int_t fNPlots; // Set number of plots to be used/qa numbers to be calculated per trig combo and run
+  TString * fQAColumnsNumeratorP; // Sub strings from fPlots, used for naming plots and the key for the online interface, numerator variable
+  TString * fQAColumnsDenominatorP; // Sub strings from fPlots, used for naming plots and the key for the online interface, denominator variable
+  TString * fQAColumnsNumeratorM; // Sub strings from fPlots, used for searching of x-axis, numerator variable
+  TString * fQAColumnsDenominatorM; // Sub strings from fPlots, used for searching of x-axis, denominator variable
+
+  // Cache Variables
+
+  Bool_t  fSaveCache; // Bool to save files to cache locally
+  TString fCachePath; // cache subdirectory to be saved, subdirectory name specified in macro
+  TString fCacheDirectory; // full path directory to save files, in the format of Form("%s/%09i/%s",fCachePath.Data(),fRunNumbers[irun],fPSInput.Data()) 
+  
+  // Grid location variables
+
+  TString fGridPath; // Location on the Grid for files to be processed
+  TString fPSInput; // Subdirectory for physics selection files to be used as input for macro
+  Int_t fQAcycle; // ??
+
+  // Local run variables
+
+  Bool_t fLocalMode; // Run on the Grid or Locally
+  TString fLocalPath; // Location of files to be processed locally
+  
+  // Variables for storing output
+
+  Bool_t fSaveQAToROOTFile;
+  TString fOutRootName;  // Name of macro output root file
+  TString fRootOutDirectory; // Path for root output
+  
+  Bool_t fSaveQAValToTxtFile;
+  TString fTxtFileName; // txt file name for each run
+  TString fTxtOutDirectory; // Path for txt output files
+
+  TList * fListBadFiles; // List of runs with no event data
+  Int_t fNGoodRuns; // Number of Good Files
+
+  Bool_t fDrawAllTGraphs;
+
+  // Trigger Info
+
+  TString * fTrigClasses; // Mapped trigger name from & trig mask
+  Int_t fNTrigClasses; // Number of triggers used, given by number of trigger names
+  
+
+  /////////////////////////////////QUASI HARD-CODED ////////////////////////////////////
+  ////////////////////// fTrigChannels[0] == Regular, fTrigChannels[1] == Fast, done this way in the case more partitions are needed, change the implementation, and otherwise just specify to loop over regular channels or fast channels, 
+
+
+  TString * fTrigChannels; // Mapped names for fast/regular channels, room for more
+  Int_t fNTrigChannels; // Number of trigger channels used
+  
+  ////////////////////////////////// !!!!!!!!!!!!!! Needs to be automated, hard code for now!!!!!!!!!!
+
+
+  ///////////////////////////////  ///////////////////////////////  ///////////////////////////////
+  static const Int_t fgkNTrigLogic = 18;
+  ///////////////////////////////  ///////////////////////////////  ///////////////////////////////
+
+
+  ////////////////////////////////// !!!!!!!!!!!!!! Needs to be automated, hard code for now!!!!!!!!!!
+
+  TGraphErrors * fGraphs[15][30][2][fgkNTrigLogic]; // Plots to be generated
+  Bool_t fRowTrigSet[30][2][fgkNTrigLogic]; // Check to make sure a specific combination of & and * is checked for a given run
+  Bool_t fValidRun[30][2][fgkNTrigLogic];  // Check to see if the run produces any valid plots
+  Bool_t fFilled[15][30][2][fgkNTrigLogic]; // Check to see if the run produces a specific plot
+
+  ClassDef(AliPSQA,1)
+
+};
+
+#endif
diff --git a/ANALYSIS/macros/PhysSelQA/AliPSQAVisualization.cxx b/ANALYSIS/macros/PhysSelQA/AliPSQAVisualization.cxx
new file mode 100644 (file)
index 0000000..be104d0
--- /dev/null
@@ -0,0 +1,405 @@
+/////////////////////////////////////
+// Created by: Kevin McDermott     //
+// email: kmcderm3@nd.edu          //
+// CERN Summer Student 2012        //
+// University of Notre Dame du Lac //
+//                                 // 
+// Revision: 1.0                   //
+// Created on: August 6, 2012      //
+/////////////////////////////////////
+
+#include "AliPSQAVisualization.h"
+
+ClassImp(AliPSQAVisualization)
+
+AliPSQAVisualization::AliPSQAVisualization(): // Default constructor 
+TObject()
+{
+  // Initialize some private data members from AliPSQAV
+  fInDirectory = "";
+  fROOTInput = "";
+  fSavePDFs = kFALSE;
+  fOutDirectory = "";
+  fOutPDFName = ""; 
+  fOutEPSName = "";
+  fDrawOverPlot = kFALSE;
+  fOverPlotTitle = "";
+  fMaximum = -1000;
+  fMinimum =  1000;
+  fScaleAuto = kFALSE;
+  fUseColorArray = kFALSE;
+  fMultMax = 0;
+  fDivMin = 0;
+  InitializeColorArray("");
+  InitializeSelectedPlots("");
+}
+
+//________________________________________________________________________________________________
+AliPSQAVisualization::~AliPSQAVisualization(){
+  delete[] fCanvas;
+  delete[] fDrawPlot;
+  delete[] fSelectedPlots;
+  delete[] fColors;
+  delete fOverLegend;
+}
+
+//________________________________________________________________________________________________
+void AliPSQAVisualization::InitializeColorArray(const Char_t * listOfColors){ // Function to custom set color array used for plots, not essential
+  Color_t colors; //color enums from list
+  ifstream input_data_col; //text file object
+  input_data_col.open(listOfColors, ios::in );  //open the text file
+  Int_t Ncol = 0; //number of color names to be used
+  
+  while ( input_data_col >> colors ) { // count number of color names
+    Ncol++;
+  }
+  
+  fNColors = Ncol; // Set private data member to total color names to be used
+  input_data_col.close(); // reset the file
+
+  fColors = new Color_t [fNColors]; // initialize private data member with number of trig names
+  input_data_col.open(listOfColors, ios::in );
+  for (Int_t icol = 0; icol < fNColors; icol++){
+    input_data_col >> fColors[icol];
+  }
+
+  input_data_col.close();  
+}
+
+//________________________________________________________________________________________________
+void AliPSQAVisualization::InitializeSelectedPlots(const Char_t * listOfPlots){
+  TString plotnames; //plot names from list
+  ifstream input_data_pn; //text file object
+       if(!listOfPlots) cout << "No list of plots" << endl;
+  input_data_pn.open(listOfPlots, ios::in );  //open the text file
+  Int_t Npn = 0; //number of plot names to be used
+  
+  while ( input_data_pn >> plotnames ) { // count number of plot names
+    Npn++;
+    }
+
+  fNSelectedPlots = Npn; // Set private data member to total plot names to be used
+  input_data_pn.close(); // reset the file
+       cout << "Number of selected plots = " << fNSelectedPlots << endl;
+  fSelectedPlots = new TString [fNSelectedPlots]; // initialize private data member with number of trig names
+  input_data_pn.open(listOfPlots, ios::in );
+  for (Int_t iplot = 0; iplot < fNSelectedPlots; iplot++){
+    input_data_pn >> fSelectedPlots[iplot];
+         
+         cout << "Plots to process :" << fSelectedPlots[iplot] << endl;
+         
+  }
+
+  input_data_pn.close();  
+}
+
+//________________________________________________________________________________________________
+void AliPSQAVisualization::PostProcessQA(){
+
+       if(!fROOTInput) cout << "No .root file found" << endl;
+       
+       
+       //cout << "Sto morendo qua? 1" << endl;
+  gStyle->SetOptStat(0);
+  gStyle->SetPalette(1);
+  gStyle->SetFillColor(10);
+  gStyle->SetOptStat(0);
+  gStyle->SetOptTitle(1);
+   // do not use scientific notation for run number
+  TGaxis::SetMaxDigits(6);
+  //cout << "Sto morendo qua? 2" << endl;
+  ConvertTGraphErrorsToTH1Ds();  // Convert all plots to TH1D's from specified plot list
+  //cout << "Sto morendo qua? 3" << endl;
+  fCanvas = new TCanvas[fNSelectedPlots]; // Allocate memory for the canvases to draw PostProcessing
+  
+   
+  if ((fDrawOverPlot) || (fSaveOverPlotPDF) || (fSaveOverPlotEPS)){
+    fOverLegend = new TLegend(0.55,0.625,.75,.85);
+    if (fScaleAuto){
+      ScaleMinAndMax();
+    }
+  }
+
+  if ((fSavePDFs) || (fSaveOverPlotPDF) || (fSaveOverPlotEPS)){
+    FileStat_t dummy_filestat;
+    if (gSystem->GetPathInfo(fOutDirectory.Data(), dummy_filestat) == 1) { // cache directory does not exist
+      MakeDir(fOutDirectory);
+    }
+  }
+
+  for (Int_t iplot = 0; iplot < fNSelectedPlots; iplot++){ // Loop over the number of plots to be made pretty and drawn
+    DrawSelected(iplot); // Draw the Selected plots, decide later whether to have them open/save them
+  
+    if (fSavePDFs){ // Write the canvas to the PDF file if kTRUE
+      SavePDFs(iplot);
+    }
+
+    if (!fDrawSelected){ // Close the canvas if you do not want to see the plot
+      fCanvas[iplot].Close();
+    }
+
+    if ( (fDrawOverPlot) || (fSaveOverPlotPDF) || (fSaveOverPlotEPS) ) { // Set points and draw overplot if any are true
+      if (fUseColorArray){
+       DrawOverPlotCA(iplot);
+      }
+      else{
+       DrawOverPlotNoCA(iplot);
+      }
+    }
+    else if( (!fDrawOverPlot) && ( (fSaveOverPlotPDF) || (fSaveOverPlotEPS) ) ) { // Set the points to save to and/or pdf/eps but then close it outside the loop
+      if (fUseColorArray){
+       DrawOverPlotCA(iplot);
+      }
+      else{
+       DrawOverPlotNoCA(iplot);
+      }
+    }  
+  }
+
+  if (fSaveOverPlotPDF){ // Save the overplot to pdf
+    SaveOverPlotPDF();
+  }
+  if (fSaveOverPlotEPS){ // Save the overplot to eps
+    SaveOverPlotEPS();
+  }
+  if (!fDrawOverPlot){ // Close if you do not want to see it
+    fOverCanvas.Close();
+  }
+}
+
+//________________________________________________________________________________________________
+void AliPSQAVisualization::ConvertTGraphErrorsToTH1Ds(){
+  
+       fRootFile = TFile::Open(Form("%s",fROOTInput.Data()));
+       
+       
+  fDrawPlot = new TH1D[fNSelectedPlots]; // Array of TH1D's to be converted
+  
+  for (Int_t iplot = 0; iplot < fNSelectedPlots; iplot++){
+    // Variables from the old TGraphErrors needed to draw TH1Fs
+    // Uncomment if seg fault returns TGraph::GetX (this=0x0), as last printout will say which graph is not correct
+    cout << fInDirectory.Data() << "/" << fROOTInput.Data() << ": " << fSelectedPlots[iplot].Data() << endl;
+
+         
+         
+         cout << "Problem is here? " << fSelectedPlots[iplot].Data() << endl;
+    TGraphErrors * TGEplot  = (TGraphErrors*) fRootFile->Get(fSelectedPlots[iplot].Data());
+         if(!TGEplot) {
+                 cout << "Missing plot : " <<   fSelectedPlots[iplot].Data() << endl;
+                 continue;
+         }
+         
+    Double_t     * TGEx     = TGEplot->GetX(); // needed to properly index the x-axis (run numbers)
+    Double_t     * TGEy     = TGEplot->GetY(); // array of double_t's, qaval
+    Int_t        TGEnpoints = TGEplot->GetN(); // number of points used in the TGE
+    Double_t      * TGEey   = TGEplot->GetEY(); // array of double_t's corresponding to the errors in the TGE
+    TString      TGEname    = TGEplot->GetName();  
+    TString      TGEtitle   = TGEplot->GetTitle(); 
+    // Parameters for the to be drawn TH1D
+    TString     TH1Dname  = TGEname.Data();
+    TH1Dname  += "_TH1D";
+    TString     TH1Dtitle = TGEtitle.Data();
+    TH1Dtitle += " TH1D";
+    // See Below for the strange numbering of bins
+
+    Int_t       TH1Dxnbin = TGEnpoints;
+    Int_t       TH1Dxlow  = 1;
+    Int_t       TH1Dxhigh = TH1Dxnbin + 1;
+    // Declare the new plot to be drawn as a TH1D
+    
+    fDrawPlot[iplot].SetBins(TH1Dxnbin, TH1Dxlow, TH1Dxhigh); // start with bin label 1, up through bin number +1 (TH1D bin numbering has strange conventions, as zero bin is the underflow bin)
+
+    fDrawPlot[iplot].SetNameTitle(TH1Dname.Data(),TH1Dtitle.Data());
+    fDrawPlot[iplot].GetXaxis()->SetTitle("Run Number");
+    TString TH1Dytitle = SetDrawSelectedYTitle(TGEtitle);
+    fDrawPlot[iplot].SetYTitle(TH1Dytitle.Data());
+
+    for (Int_t ibin = 1; ibin < TH1Dxnbin+1; ibin++){ // everything shifted off by one because tgraph starts at zero, th1f starts bins at 1
+      fDrawPlot[iplot].SetBinContent(fDrawPlot[iplot].FindBin(ibin),TGEy[ibin-1]); // y[i-1] is the bin in plot
+      fDrawPlot[iplot].SetBinError(fDrawPlot[iplot].FindBin(ibin),TGEey[ibin-1]);
+      
+      Int_t TH1Dx = Int_t(TGEx[ibin-1]); // x[i-1] = actual bin label in plot
+      TString TH1DxBinLabel = Form("%i",TH1Dx);
+      fDrawPlot[iplot].GetXaxis()->SetBinLabel(fDrawPlot[iplot].FindBin(ibin), TH1DxBinLabel.Data());
+      fDrawPlot[iplot].GetXaxis()->SetTitleSize(.05); // default = 4%, made it 5%
+    }
+    //
+    // adding some drawing options
+    //
+    fDrawPlot[iplot].SetMarkerStyle(20);
+    fDrawPlot[iplot].SetMarkerSize(1.4);
+    fDrawPlot[iplot].SetMarkerColor(kBlue);
+    fDrawPlot[iplot].SetLineColor(kBlue);
+    fDrawPlot[iplot].GetYaxis()->SetRangeUser(-0.001,1.05);
+    fDrawPlot[iplot].GetXaxis()->LabelsOption("V");
+  }
+}
+
+//________________________________________________________________________________________________
+TString AliPSQAVisualization::SetDrawSelectedYTitle(TString TGEtitle){
+  
+  Ssiz_t start  = 0;  
+  Ssiz_t first_o = TGEtitle.First('o'); // o in over, lowercase o that appears first is the over
+  Ssiz_t first_f = TGEtitle.First('f');
+
+  TString label[2];
+  label[0] = TString(TGEtitle( start , first_o - start - 1)); // Shift one over from the 'h'
+  label[1] = TString(TGEtitle( first_o + 4, first_f - first_o - 4 ));  //Shift five over from the 'O' 
+
+  // Make this substitution to make legend smaller
+  
+  if (label[1].Contains("Trigger class")){
+    label[1].ReplaceAll("Trigger class","All");
+  }
+
+  TString yTH1Dtitle = label[0];
+  yTH1Dtitle += " / ";
+  yTH1Dtitle += label[1];
+
+  return yTH1Dtitle;
+}
+
+//________________________________________________________________________________________________
+void AliPSQAVisualization::ScaleMinAndMax(){ // Get maximum and minimum value of traghs to set bounds for overplot
+  Double_t tmp_max; // max values from tgraphs
+  Double_t tmp_min; // min values from tgraphs
+
+  for (Int_t iplot = 0; iplot < fNSelectedPlots; iplot++){ // Loop over the number of plots to be made 
+    // Set maximum
+    tmp_max = fDrawPlot[iplot].GetMaximum();
+    if (tmp_max > fMaximum){
+       fMaximum = tmp_max;
+    }
+    // Set minimum
+    tmp_min = fDrawPlot[iplot].GetMinimum();
+    if (tmp_max < fMinimum){
+      fMinimum = tmp_min;
+    }
+  }
+
+  // Set the min to be lower and max to be higher so that all points can be seen
+  fMaximum *= fMultMax;
+  fMinimum /= fDivMin;
+}
+
+//________________________________________________________________________________________________
+void AliPSQAVisualization::MakeDir(TString dir){ // have to pass a private data member, kinda ugly, but otherwise use sentinel values or copy this function three times... taken from AliPSQA
+  TString mkDir = "mkdir -p ";
+  mkDir += dir.Data();
+  gSystem->Exec(mkDir); // mkdir for the cache/output
+}
+
+//________________________________________________________________________________________________
+void AliPSQAVisualization::DrawSelected(Int_t iplot){
+   fCanvas[iplot].cd(); // write to this canvas first
+   fCanvas[iplot].SetBottomMargin(0.15); // default 0.15
+   fCanvas[iplot].SetRightMargin(0.02);
+   fDrawPlot[iplot].GetXaxis()->SetTitleOffset(1.6);
+   fDrawPlot[iplot].Draw("E P X0"); // draw the new plot to canvas
+}
+
+//________________________________________________________________________________________________
+void AliPSQAVisualization::DrawOverPlotCA(Int_t iplot){
+  if (iplot == 0){
+    fOverCanvas.cd();
+    fDrawPlot[iplot].SetMarkerColor(fColors[iplot]); // iplot == 0 for Color_t == white...
+    fDrawPlot[iplot].SetMarkerStyle(Style_t(iplot+20)); // 20 = big circle, afterwards, useful styles, otherwise too small
+    fDrawPlot[iplot].SetLineColor(fColors[iplot]);
+    fDrawPlot[iplot].SetTitle(fOverPlotTitle);
+    fOverLegend->AddEntry(&fDrawPlot[iplot],fDrawPlot[iplot].GetYaxis()->GetTitle(),"lep");
+    fDrawPlot[iplot].GetYaxis()->SetTitle("");
+    fDrawPlot[iplot].GetYaxis()->SetRangeUser(fMinimum, fMaximum);
+    fDrawPlot[iplot].Draw("E P X0");
+  }
+  else if (iplot == (fNSelectedPlots - 1) ){ 
+    fOverCanvas.cd();
+    fDrawPlot[iplot].SetMarkerColor(fColors[iplot]);
+    fDrawPlot[iplot].SetMarkerStyle(Style_t(iplot+20)); // 20 = big circle, afterwards, useful styles, otherwise too small
+    fDrawPlot[iplot].SetLineColor(fColors[iplot]);
+    fDrawPlot[iplot].SetTitle(fOverPlotTitle);
+    fOverLegend->AddEntry(&fDrawPlot[iplot],fDrawPlot[iplot].GetYaxis()->GetTitle(),"lep");
+    fDrawPlot[iplot].GetYaxis()->SetTitle("");
+    fDrawPlot[iplot].Draw("E P X0 SAME");
+    //    fOverLegend->Draw();
+  }
+  else{
+    fOverCanvas.cd();
+    fDrawPlot[iplot].SetMarkerColor(fColors[iplot]);
+    fDrawPlot[iplot].SetMarkerStyle(Style_t(iplot+20)); // 20 = big circle, afterwards, useful styles, otherwise too small
+    fDrawPlot[iplot].SetLineColor(fColors[iplot]);
+    fDrawPlot[iplot].SetTitle(fOverPlotTitle);
+    fOverLegend->AddEntry(&fDrawPlot[iplot],fDrawPlot[iplot].GetYaxis()->GetTitle(),"lep");
+    fDrawPlot[iplot].GetYaxis()->SetTitle("");
+    fDrawPlot[iplot].Draw("E P X0 SAME");
+  }
+}
+
+//________________________________________________________________________________________________
+void AliPSQAVisualization::DrawOverPlotNoCA(Int_t iplot){
+  if (iplot == 0){
+    fOverCanvas.cd();
+    fDrawPlot[iplot].SetMarkerColor(Color_t(iplot+1)); // iplot == 0 for Color_t == white...
+    fDrawPlot[iplot].SetMarkerStyle(Style_t(iplot+20)); // 20 = big circle, afterwards, useful styles, otherwise too small
+    fDrawPlot[iplot].SetLineColor(Color_t(iplot+1));
+    fDrawPlot[iplot].SetTitle(fOverPlotTitle);
+    fOverLegend->AddEntry(&fDrawPlot[iplot],fDrawPlot[iplot].GetYaxis()->GetTitle(),"lep");
+    fDrawPlot[iplot].GetYaxis()->SetTitle("");
+    fDrawPlot[iplot].GetYaxis()->SetRangeUser(fMinimum, fMaximum);
+    fDrawPlot[iplot].Draw("E P X0");
+  }
+  else if (iplot == (fNSelectedPlots - 1) ){ 
+    fOverCanvas.cd();
+    fDrawPlot[iplot].SetMarkerColor(Color_t(iplot+1));
+    fDrawPlot[iplot].SetMarkerStyle(Style_t(iplot+20)); // 20 = big circle, afterwards, useful styles, otherwise too small
+    fDrawPlot[iplot].SetLineColor(Color_t(iplot+1));
+    fDrawPlot[iplot].SetTitle(fOverPlotTitle);
+    fOverLegend->AddEntry(&fDrawPlot[iplot],fDrawPlot[iplot].GetYaxis()->GetTitle(),"lep");
+    fDrawPlot[iplot].GetYaxis()->SetTitle("");
+    fDrawPlot[iplot].Draw("E P X0 SAME");
+    fOverLegend->Draw();
+  }
+  else{
+    fOverCanvas.cd();
+    fDrawPlot[iplot].SetMarkerColor(Color_t(iplot+1));
+    fDrawPlot[iplot].SetMarkerStyle(Style_t(iplot+20)); // 20 = big circle, afterwards, useful styles, otherwise too small
+    fDrawPlot[iplot].SetLineColor(Color_t(iplot+1));
+    fDrawPlot[iplot].SetTitle(fOverPlotTitle);
+    fOverLegend->AddEntry(&fDrawPlot[iplot],fDrawPlot[iplot].GetYaxis()->GetTitle(),"lep");
+    fDrawPlot[iplot].GetYaxis()->SetTitle("");
+    fDrawPlot[iplot].Draw("P SAME");
+  }
+}
+
+//________________________________________________________________________________________________
+void AliPSQAVisualization::SavePDFs(Int_t iplot){
+  if ( iplot == 0 ){ // Open the PDF file if to be saved and save the first plot
+    fCanvas[iplot].Print(Form("%s/%s(",fOutDirectory.Data(),fOutPDFName.Data()),"pdf");
+         
+  }
+  else if ( (iplot == (fNSelectedPlots - 1)) && (!fSaveOverPlotPDF) ){ // Close the PDF and save the last plot
+    fCanvas[iplot].Print(Form("%s/%s)",fOutDirectory.Data(),fOutPDFName.Data()),"pdf");
+           fCanvas[iplot].SaveAs(Form("%s/%s_%d.pdf",fOutDirectory.Data(),fOutPDFName.Data(),iplot));
+  }
+  else{ // Save the PDF with the inbetween plots
+    fCanvas[iplot].Print(Form("%s/%s",fOutDirectory.Data(),fOutPDFName.Data()),"pdf");
+  }
+}
+
+//________________________________________________________________________________________________
+void AliPSQAVisualization::SaveOverPlotPDF(){
+  fOverCanvas.cd();
+  if (fSavePDFs){
+    fOverCanvas.Print(Form("%s/%s)",fOutDirectory.Data(),fOutPDFName.Data()),"pdf");
+       
+  }
+  else{
+    fOverCanvas.Print(Form("%s/%s",fOutDirectory.Data(),fOutPDFName.Data()),"pdf");
+  }
+}
+
+//________________________________________________________________________________________________
+void AliPSQAVisualization::SaveOverPlotEPS(){
+  fOverCanvas.cd();
+  fOverCanvas.Print(Form("%s/%s",fOutDirectory.Data(),fOutEPSName.Data()),"eps");
+}
+
diff --git a/ANALYSIS/macros/PhysSelQA/AliPSQAVisualization.h b/ANALYSIS/macros/PhysSelQA/AliPSQAVisualization.h
new file mode 100644 (file)
index 0000000..6db840a
--- /dev/null
@@ -0,0 +1,153 @@
+/////////////////////////////////////
+// Created by: Kevin McDermott     //
+// email: kmcderm3@nd.edu          //
+// CERN Summer Student 2012        //
+// University of Notre Dame du Lac //
+//                                 // 
+// Revision: 1.0                   //
+// Created on: August 6, 2012      //
+/////////////////////////////////////
+
+#ifndef ALIPSQAVISUALIZATION_H
+#define ALIPSQAVISUALIZATION_H
+
+#if !defined(__CINT__) || defined(__MAKECINT__)
+#include "TCanvas.h"
+#include "TH1D.h"
+#include "TGraphErrors.h"
+#include "TFile.h"
+#include <Riostream.h>
+#include "TGaxis.h"
+#include "TStyle.h"
+#include "TLegend.h"
+#include "TSystem.h"
+#endif
+
+class AliPSQAVisualization : public TObject
+{
+ public: 
+  AliPSQAVisualization();
+  virtual ~AliPSQAVisualization();
+  
+  void InitializeSelectedPlots(const Char_t * listOfPlots);
+  void InitializeColorArray(const Char_t * listOfColors); // called only if fUseColorArray == kTRUE
+
+  void PostProcessQA(); // First call of macro
+  void ScaleMinAndMax(); // called only if fScaleAuto == kTRUE
+  void MakeDir(TString dir); // called if anything is to be saved, first check to make sure directory exists.
+  void DrawSelected(Int_t iplot);
+  void ConvertTGraphErrorsToTH1Ds();
+  TString SetDrawSelectedYTitle(TString TGEtitle);
+  void SavePDFs(Int_t iplot);
+  void DrawOverPlotCA(Int_t iplot);
+  void DrawOverPlotNoCA(Int_t iplot);
+  void SaveOverPlotPDF(); 
+  void SaveOverPlotEPS(); 
+
+  // Getters and setters from the macro
+
+  void     SetInDirectory(TString indir){fInDirectory = indir;};
+  TString  GetInDirectory(){return fInDirectory;};
+
+  void     SetROOTInput(TString RI){fROOTInput = RI;};
+  TString  GetROOTInput(){return fROOTInput;};
+    
+  void     SetSavePDFs(Bool_t pdf){fSavePDFs = pdf;};
+  Bool_t   GetSavePDFs(){return fSavePDFs;};
+  
+  void     SetSaveOverPlotPDF(Bool_t pdf){fSaveOverPlotPDF = pdf;};
+  Bool_t   GetSaveOverPlotPDF(){return fSaveOverPlotPDF;};
+
+  void     SetOutPDFName(TString name){fOutPDFName = name;};
+  TString  GetOutPDFName(){return fOutPDFName;};
+
+  void     SetSaveOverPlotEPS(Bool_t eps){fSaveOverPlotEPS = eps;};
+  Bool_t   GetSaveOverPlotEPS(){return fSaveOverPlotEPS;};
+  
+  void     SetOutEPSName(TString name){fOutEPSName = name;};
+  TString  GetOutEPSName(){return fOutEPSName;};
+
+  void     SetOutDirectory(TString out){fOutDirectory = out;};
+  TString  GetOutDirectory(){return fOutDirectory;};  
+
+  void     SetDrawSelected(Bool_t select){fDrawSelected = select;};
+  Bool_t   GetDrawSelected(){return fDrawSelected;};
+
+  void     SetUseColorArray(Bool_t ca){fUseColorArray = ca;};
+  Bool_t   GetUseColorArray(){return fUseColorArray;};
+
+  void     SetDrawOverPlot(Bool_t op){fDrawOverPlot = op;};
+  Bool_t   GetDrawOverPlot(){return fDrawOverPlot;};
+
+  void     SetOverPlotTitle(TString opt){fOverPlotTitle = opt;};
+  TString  GetOverPlotTitle(){return fOverPlotTitle;};
+
+  // Scaling Options
+
+  void     SetScaleAuto(Bool_t sa){fScaleAuto = sa;};
+  Bool_t   GetScaleAuto(){return fScaleAuto;};
+
+  void     SetScaleAutoDivMin(Double_t div_min){fDivMin = div_min;};
+  Double_t GetScaleAutoDivMin(){return fDivMin;};
+
+  void     SetScaleAutoMultMax(Double_t mult_max){fMultMax = mult_max;};
+  Double_t GetScaleAutoMultMax(){return fMultMax;};
+
+  void     SetScaleManMin(Double_t min){fMinimum = min;};
+  Double_t GetScaleManMin(){return fMinimum;};
+
+  void     SetScaleManMax(Double_t max){fMaximum = max;};
+  Double_t GetScaleManMax(){return fMaximum;};
+
+ private:
+  // Input variables
+  TString * fSelectedPlots; // List of plots to be turned from tragphs to th1ds
+  Int_t     fNSelectedPlots; // number of plots to be turned from tgraphs to th1ds
+  TString   fInDirectory; // input directory of root file, most likely the one just analyzed from AliPSQA
+  TString   fROOTInput; // name of root file specified by user
+  TFile *   fRootFile; // Root file to be used to produce plots
+  
+  // Save DrawSelected
+  Bool_t  fDrawSelected;
+
+  // Save PDF variables
+  
+  Bool_t  fSavePDFs; // if kTRUE, save pdfs of th1ds
+  TString fOutDirectory; // save pdfs to this directory
+  TString fOutPDFName; // common pdf name, group pdf files together
+
+  // Overplot variables
+
+  Bool_t  fDrawOverPlot; // if kTrue, save overplot of all the th1ds
+  TString fOverPlotTitle; // title specified by user for overplot, most likely the name of the trigger mask, channel, and logic
+  Bool_t    fSaveOverPlotPDF; //if ktrue, save overplot to pdf file
+  TCanvas   fOverCanvas; // Overplot canvas
+  TLegend * fOverLegend; // Overplot legend
+  Bool_t    fSaveOverPlotEPS; // if ktrue, save overplot eps file
+  TString   fOutEPSName; // eps file name for overplot together
+
+  // Overplot color array variables
+  
+  Bool_t    fUseColorArray; // if ktrue, use colorarray specified in a list file
+  Color_t * fColors; // set in a list file, using enums of colors (just use AliRoot and type in the color, e.g. root [0] kBlue returns (const enum EColor)600)
+  Int_t fNColors; // number of colors used
+
+  // Overplot Scaling Variables
+
+  Bool_t   fScaleAuto; // If kTRUE, set scaling automatically with GetMinAndMax()
+  Double_t fMultMax; // Auto scaling factor, multiply the max
+  Double_t fDivMin; // Auto scaling factor, divide the min
+
+  Double_t fMinimum; // Maximum val in selected tgraphs, used for setting range for overplot
+  Double_t fMaximum; // Minimum val in selected tgraphs, used for setting range for overplot
+
+  // Plotting variables needed
+
+  TCanvas * fCanvas; // new array in InitializeDrawSelected with the amount of fNDrawSelected
+  TH1D *  fDrawPlot; // new array in InitializeDrawSelected with the amount of fNDrawSelected
+  
+  ClassDef(AliPSQAVisualization, 1)
+
+};
+
+#endif
diff --git a/ANALYSIS/macros/PhysSelQA/PSQA.C b/ANALYSIS/macros/PhysSelQA/PSQA.C
new file mode 100644 (file)
index 0000000..81988eb
--- /dev/null
@@ -0,0 +1,57 @@
+#include "AliPSQA.h"\r
+\r
+void PSQA() {\r
+  //\r
+  // Produce QA  output of physics selection.\r
+  // Opens selected files for QA, then processes the historgrams necessary, \r
+  // prints results to a root file and/or text files specified by user.\r
+  //\r
+  //  Please read the README in case the documentation provided in this macro, .h, and .cxx files is not enough!\r
+  //\r
+  //gROOT->LoadMacro("AliPSQA.cxx++g");\r
+  AliPSQA * QAobject = new AliPSQA;  // Initialize relevant object\r
+  //\r
+  // configure relevant parameters\r
+  //\r
+  Bool_t runFromLocalInputFiles = kTRUE; // if kTRUE, run over either cache or test, otherwise use alien files\r
+  Bool_t saveTxtFiles           = kTRUE; \r
+  Bool_t saveRootFile           = kTRUE;\r
+  Bool_t drawGraphs             = kTRUE;\r
+  //\r
+  // settings\r
+  //\r
+  QAobject->InitializeRuns("../QAoutputPerPeriod/12d_Pass1/GoodRunList.list"); \r
+  QAobject->SetLocalPath("../InputFilesFromGridPerPeriod/12d_Pass1/"); // Location of files to be processed locally (whether test or cache)\r
+  QAobject->SetTxtOutDirectory("../QAoutputPerPeriod/12d_Pass1/"); // Path for macro output text files\r
+  QAobject->SetRootOutDirectory("../QAoutputPerPeriod/12d_Pass1/"); // Path for macro output root files\r
+  QAobject->SetOutRootName("LHC12d_PSQA.root");\r
+  //\r
+  QAobject->SetPSInput(""); // Subdirectory for files to be processed, which pass to use\r
+  QAobject->SetROOTInput("event_stat.root"); //root file to be processed\r
+  QAobject->InitializeTriggers("triggerNames.list","triggerMaskChannels.list"); // trig names to be used, plus trig channels (fast vs regular)\r
+  QAobject->InitializePlots("plots.list");     //Initialize macro with QA plots to be used\r
+  QAobject->SetTxtFileName("PSQA_"); // This is appended with the run name and .txt\r
+  //\r
+  // enable settings\r
+  //\r
+  QAobject->SetLocalMode(runFromLocalInputFiles); \r
+  QAobject->SetSaveQAValToTxtFile(saveTxtFiles);\r
+  QAobject->SetSaveQAToROOTFile(saveRootFile);\r
+  //\r
+  // run and extract    \r
+  //\r
+  Bool_t goodQACheck = QAobject->ComputeQAPerRun();\r
+  //\r
+  // Print a list of the runs that failed, with some hint as to why they failed. Implementation file has comments.\r
+  //\r
+  QAobject->GetBadFiles()->Print();\r
+  //\r
+  if (goodQACheck == kFALSE){return;} // No plots saved at all, skip altogether the option to plot all canvases.\r
+  //\r
+  QAobject->SetDrawAllTGraphs(drawGraphs); // If kTRUE, will draw all TGraphErrors saved in the ROOT file.\r
+  if (QAobject->GetDrawAllTGraphs()){\r
+    QAobject->DrawAllTGraphs();\r
+  }\r
+\r
+};\r
+\r
diff --git a/ANALYSIS/macros/PhysSelQA/PSQAV.C b/ANALYSIS/macros/PhysSelQA/PSQAV.C
new file mode 100644 (file)
index 0000000..586dd3e
--- /dev/null
@@ -0,0 +1,51 @@
+#include "AliPSQAVisualization.h"
+
+void PSQAV(){
+  //
+  // make nice plots for presentations of the Phys.Sel. QA
+  //
+  AliPSQAVisualization * QAVobject1 = new AliPSQAVisualization;
+  //
+  Bool_t useAutoScale    = kTRUE;
+  Bool_t savePDFs        = kTRUE;
+  Bool_t drawSelected    = kTRUE;  // draw all plots on the screen
+  Bool_t drawOverPlot    = kTRUE;  // if true, draw to canvas to see
+  Bool_t saveOverPlotPdf = kTRUE;  // if true, write to pdf file
+  Bool_t saveOverPlotEps = kTRUE;  // if true, write to eps file
+  //
+  // configuration -- choose the input directory and file
+  //
+  QAVobject1->SetROOTInput("../QAoutputPerPeriod/12d_Pass1/LHC12d_PSQA.root");
+  QAVobject1->InitializeSelectedPlots("../QAoutputPerPeriod/12d_Pass1/selectedPlots.list");
+       //QAVobject1->InitializeSelectedPlots("plots.list");
+  QAVobject1->SetOutDirectory("../QAoutputPerPeriod/12d_Pass1/plots");
+  QAVobject1->SetOutPDFName("PlotsLHC12d_pass.pdf");
+  QAVobject1->SetOutEPSName("PlotsLHC12d_pass.eps");
+  QAVobject1->SetOverPlotTitle("");
+  //
+  // settings
+  //
+  QAVobject1->SetSavePDFs(savePDFs);
+  QAVobject1->SetDrawSelected(drawSelected);
+  QAVobject1->SetDrawOverPlot(drawOverPlot);
+  QAVobject1->SetSaveOverPlotPDF(saveOverPlotPdf);
+  QAVobject1->SetSaveOverPlotEPS(saveOverPlotEps); // if true, write to eps file
+  QAVobject1->SetUseColorArray(kTRUE);
+  //
+  QAVobject1->InitializeColorArray("colorArray.list"); // Set the color enums for the overplot
+    /// Use Auto Scale? See README.
+  QAVobject1->SetScaleAuto(useAutoScale);
+  if (QAVobject1->GetScaleAuto()) { 
+    QAVobject1->SetScaleAutoDivMin(1.1);
+    QAVobject1->SetScaleAutoMultMax(1.1);
+  } else {
+    QAVobject1->SetScaleManMin(0.0);
+    QAVobject1->SetScaleManMax(1.1);
+  }
+  //
+       cout << "Here we are?" << endl;
+       
+  QAVobject1->PostProcessQA();
+
+ cout << "Done?" << endl;
+};