--- /dev/null
+/////////////////////////////////////
+// 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");
+ }
+ }
+ }
+ }
+ }
+}
+
--- /dev/null
+/////////////////////////////////////
+// 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
--- /dev/null
+/////////////////////////////////////
+// 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");
+}
+
--- /dev/null
+/////////////////////////////////////
+// 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
--- /dev/null
+#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
--- /dev/null
+#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;
+};