Analysis Software
Documentation for sPHENIX simulation software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
EpFinder.C
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file EpFinder.C
1 #include "EpFinder.h"
2 #include "TVector3.h"
3 #include "TH2D.h"
4 #include "TFile.h"
5 #include "TProfile.h"
6 #include "TProfile2D.h"
7 #include "TClonesArray.h"
8 #include "TMath.h"
9 #include <cassert>
10 #include <iostream>
11 #include <vector>
12 
13 using namespace std;
14 
15 
16 EpFinder::EpFinder(int nEventTypeBins, char const* OutFileName, char const* CorrectionFile, int pbinsx, int pbinsy) : mThresh(0.3), mMax(2.0)
17 {
18 
19  cout << "\n**********\n* Welcome to the Event Plane finder.\n"
20  << "* Please note that when you specify 'order' as an argument to a method,\n"
21  << "* then 1=first-order plane, 2=second-order plane, etc.\n"
22  << "* This code is currently configured to go up to order=" << _EpOrderMax << "\n";
23  cout << "**********\n";
24 
25  mNumberOfEventTypeBins = nEventTypeBins;
26 
27  // ----------------------------------- Stuff read from the "Correction File" -----------------------------------------
28  // "Shift correction" histograms that we INPUT and apply here
29  mCorrectionInputFile = new TFile(CorrectionFile,"READ");
30  if (mCorrectionInputFile->IsZombie()) {
31  std::cout << "EPFinder: Error opening file with Correction Histograms" << std::endl;
32  std::cout << "EPFinder: I will use no weighting at all." << std::endl;
33  for (int order=1; order<_EpOrderMax+1; order++){
34  mEpShiftInput_sin[order-1] = NULL;
35  mEpShiftInput_cos[order-1] = NULL;
36  }
37  mPhiWeightInput = NULL;
38  }
39  else{
40  for (int order=1; order<_EpOrderMax+1; order++){
41  mEpShiftInput_sin[order-1] = (TProfile2D*)mCorrectionInputFile->Get(Form("EpShiftPsi%d_sin",order));
42  mEpShiftInput_cos[order-1] = (TProfile2D*)mCorrectionInputFile->Get(Form("EpShiftPsi%d_cos",order));
43  }
44  mPhiWeightInput = (TH2D*)mCorrectionInputFile->Get(Form("PhiWeight"));
45  }
46  // ----------------------------------- Stuff written to the "Correction File" -----------------------------------------
47  // "Shift correction" histograms that we produce and OUTPUT
48  mCorrectionOutputFile = new TFile(OutFileName,"RECREATE");
49  for (int order=1; order<_EpOrderMax+1; order++){
50  mEpShiftOutput_sin[order-1] = new TProfile2D(Form("EpShiftPsi%d_sin",order),Form("EpShiftPsi%d_sin",order),
51  _EpTermsMax,0.5,1.0*_EpTermsMax+.5,nEventTypeBins,-0.5,(double)nEventTypeBins-0.5,-1.0,1.0);
52  mEpShiftOutput_cos[order-1] = new TProfile2D(Form("EpShiftPsi%d_cos",order),Form("EpShiftPsi%d_cos",order),
53  _EpTermsMax,0.5,1.0*_EpTermsMax+.5,nEventTypeBins,-0.5,(double)nEventTypeBins-0.5,-1.0,1.0);
54  }
55  // Phi weighting histograms based on requested binning
56  if(pbinsx<=0) pbinsx = 1;
57  if(pbinsy<=0) pbinsy = 1;
58 
59  // binning tuned for FEMC, to be made generic in future JGL 8/28/2019
60  // bins are ix,iy
61  mPhiWeightOutput = new TH2D(Form("PhiWeight"),Form("Phi Weight"),pbinsx,-0.5,(pbinsx-0.5),pbinsy,-0.5,(pbinsy-0.5));
62  // just for normalization. discard after use
63  mPhiAveraged = new TH2D(Form("PhiAveraged"),Form("Phi Average"),pbinsx,-0.5,(pbinsx-0.5),pbinsy,-0.5,(pbinsy-0.5));
64 
65 }
66 
68 
69  mCorrectionInputFile->Close();
70 
72  delete mPhiAveraged;
73 
74  mCorrectionOutputFile->Write();
75  mCorrectionOutputFile->Close();
76 
77  cout << "EpFinder is finished!\n\n";
78 }
79 
80 //==================================================================================================================
81 EpInfo EpFinder::Results(std::vector<EpHit> *EpdHits, int EventTypeId){
82 
83  if ((EventTypeId<0)||(EventTypeId>=mNumberOfEventTypeBins)){
84  cout << "You are asking for an undefined EventType - fail!\n";
85  assert(0);
86  }
87 
88  EpInfo result;
89 
90  double pi = TMath::Pi();
91 
92  // This below is for normalizing Q-vectors
93  double TotalWeight4Side[_EpOrderMax][2]; // for normalizing Q-vector: order, (nonPhiWeighted or PhiWeighted) ** depends on Order because eta-weight depends on order
94  for (int phiWeightedOrNo=0; phiWeightedOrNo<2; phiWeightedOrNo++){
95  for (int order=1; order<_EpOrderMax+1; order++){
96  TotalWeight4Side[order-1][phiWeightedOrNo] = 0;
97  }
98  }
99 
100  //--------------------------------- begin loop over hits ---------------------------------------
101  for (unsigned int hit=0; hit<EpdHits->size(); hit++){
102 
103  float nMip = EpdHits->at(hit).nMip;
104  if (nMip<mThresh) continue;
105  double TileWeight = (nMip<mMax)?nMip:mMax;
106  int idx_x = EpdHits->at(hit).ix;
107  int idx_y = EpdHits->at(hit).iy;
108  double phi = EpdHits->at(hit).phi;
109 
110  //---------------------------------
111  // fill Phi Weight histograms to be used in next iteration (if desired)
112  // Obviously, do this BEFORE phi weighting!
113  //---------------------------------
114 
115  if(EpdHits->at(hit).samePhi){
116  mPhiWeightOutput->Fill(idx_x,idx_y,TileWeight);
117  for(unsigned int i = 0; i<EpdHits->at(hit).samePhi->size(); i++){
118  float x = EpdHits->at(hit).samePhi->at(i).first;
119  float y = EpdHits->at(hit).samePhi->at(i).second;
120  mPhiAveraged->Fill(x,y,TileWeight/EpdHits->at(hit).samePhi->size());
121  }
122  }
123 
124  //--------------------------------
125  // now calculate Q-vectors
126  //--------------------------------
127 
128  double PhiWeightedTileWeight = TileWeight;
129  if (mPhiWeightInput) PhiWeightedTileWeight /= mPhiWeightInput->GetBinContent(idx_x+1,idx_y+1);
130 
131  for (int order=1; order<_EpOrderMax+1; order++){
132  double etaWeight = 1.0; // not implemented - JGL 8/27/2019
133  TotalWeight4Side[order-1][0] += fabs(etaWeight) * TileWeight; // yes the fabs() makes sense. The sign in the eta weight is equivalent to a trigonometric phase.
134  TotalWeight4Side[order-1][1] += fabs(etaWeight) * PhiWeightedTileWeight; // yes the fabs() makes sense. The sign in the eta weight is equivalent to a trigonometric phase.
135 
136  double Cosine = cos(phi*(double)order);
137  double Sine = sin(phi*(double)order);
138 
139  result.QrawOneSide[order-1][0] += etaWeight * TileWeight * Cosine;
140  result.QrawOneSide[order-1][1] += etaWeight * TileWeight * Sine;
141 
142  result.QphiWeightedOneSide[order-1][0] += etaWeight * PhiWeightedTileWeight * Cosine;
143  result.QphiWeightedOneSide[order-1][1] += etaWeight * PhiWeightedTileWeight * Sine;
144 
145  }
146  } // loop over hits
147 
148  //--------------------------------- end loop over hits ---------------------------------------
149 
150  // Weights used, so you can "un-normalize" the ring-by-ring Q-vectors.
151  for (int order=1; order<_EpOrderMax+1; order++){
152  result.WheelSumWeightsRaw[order-1] = TotalWeight4Side[order-1][0];
153  result.WheelSumWeightsPhiWeighted[order-1] = TotalWeight4Side[order-1][1];
154  }
155 
156  // at this point, we are finished with the detector hits, and deal only with the Q-vectors,
157 
158  // first, normalize the Q's...
159  for (int order=1; order<_EpOrderMax+1; order++){
160  if (TotalWeight4Side[order-1][0]>0.0001){
161  result.QrawOneSide[order-1][0] /= TotalWeight4Side[order-1][0];
162  result.QrawOneSide[order-1][1] /= TotalWeight4Side[order-1][0];
163  }
164  if (TotalWeight4Side[order-1][1]>0.0001){
165  result.QphiWeightedOneSide[order-1][0] /= TotalWeight4Side[order-1][1];
166  result.QphiWeightedOneSide[order-1][1] /= TotalWeight4Side[order-1][1];
167  }
168  }
169 
170  // at this point, we are finished with the Q-vectors and just use them to get angles Psi
171 
172  //---------------------------------
173  // Calculate unshifted EP angles
174  //---------------------------------
175  for (int order=1; order<_EpOrderMax+1; order++){
176  result.PsiRaw[order-1] = GetPsiInRange(result.QrawOneSide[order-1][0],result.QrawOneSide[order-1][1],order);
177  result.PsiPhiWeighted[order-1] = GetPsiInRange(result.QphiWeightedOneSide[order-1][0],result.QphiWeightedOneSide[order-1][1],order);
178  } // loop over order
179 
180  //---------------------------------
181  // Now shift
182  //---------------------------------
183  for (int order=1; order<_EpOrderMax+1; order++){
184  result.PsiPhiWeightedAndShifted[order-1] = result.PsiPhiWeighted[order-1];
185  if (mEpShiftInput_sin[order-1]) {
186  for (int i=1; i<=_EpTermsMax; i++){
187  double tmp = (double)(order*i);
188  double sinAve = mEpShiftInput_sin[order-1]->GetBinContent(i,EventTypeId+1);
189  double cosAve = mEpShiftInput_cos[order-1]->GetBinContent(i,EventTypeId+1);
190  result.PsiPhiWeightedAndShifted[order-1] +=
191  2.0*(cosAve*sin(tmp*result.PsiPhiWeighted[order-1]) - sinAve*cos(tmp*result.PsiPhiWeighted[order-1]))/tmp;
192  }
193  double AngleWrapAround = 2.0*pi/(double)order;
194  if (result.PsiPhiWeightedAndShifted[order-1]<0) result.PsiPhiWeightedAndShifted[order-1] += AngleWrapAround;
195  else if (result.PsiPhiWeightedAndShifted[order-1]>AngleWrapAround) result.PsiPhiWeightedAndShifted[order-1] -= AngleWrapAround;
196  }
197  }
198 
199  //---------------------------------
200  // Now calculate shift histograms for a FUTURE run (if you want it)
201  //---------------------------------
202  for (int i=1; i<=_EpTermsMax; i++){
203  for (int order=1; order<_EpOrderMax+1; order++){
204  double tmp = (double)(order*i);
205  mEpShiftOutput_sin[order-1]->Fill(i,EventTypeId,sin(tmp*result.PsiPhiWeighted[order-1]));
206  mEpShiftOutput_cos[order-1]->Fill(i,EventTypeId,cos(tmp*result.PsiPhiWeighted[order-1]));
207  }
208  }
209 
210  return result;
211 }
212 
213 double EpFinder::GetPsiInRange(double Qx, double Qy, int order){
214  double temp;
215  if ((Qx==0.0)||(Qy==0.0)) temp=-999;
216  else{
217  temp = atan2(Qy,Qx)/((double)order);
218  double AngleWrapAround = 2.0*TMath::Pi()/(double)order;
219  if (temp<0.0) temp+= AngleWrapAround;
220  else if (temp>AngleWrapAround) temp -= AngleWrapAround;
221  }
222  return temp;
223 }
224 
226  if (order < 1) {
227  cout << "\n*** Invalid order specified ***\n";
228  cout << "order must be 1 (for first-order plane) or higher\n";
229  return true;
230  }
231  if (order > _EpOrderMax) {
232  cout << "\n*** Invalid order specified ***\n";
233  cout << "Maximum order=" << _EpOrderMax << ". To change, edit StEpdUtil/StEpdEpInfo.h\n";
234  return true;
235  }
236  return false;
237 }
238 
240  TString rep = Form("This is the EpFinder Report:\n");
241  rep += Form("Number of EventType bins = %d\n",mNumberOfEventTypeBins);
242  rep += Form("Threshold (in MipMPV units) = %f and MAX weight = %f\n",mThresh,mMax);
243  return rep;
244 }
245