USCMuonProfile.cc
Go to the documentation of this file.
1 #include "USCMuonProfile.h"
2 #include <tls/TankResponseUtilities.h>
3 
4 #include <vector>
5 #include <sstream>
6 #include <cmath>
7 #include <string>
8 
9 #include <utl/AugerUnits.h>
10 #include <utl/MathConstants.h>
11 #include <utl/Branch.h>
12 #include <utl/AugerException.h>
13 
14 #include <TH2D.h>
15 #include <TFile.h>
16 
17 using namespace USCMuonProfileNS;
18 using namespace utl;
19 using namespace std;
20 using namespace tls;
21 
22 inline
23 double
24 InterpolateHistrogram(const TH2D& h, double x, double y)
25 {
26  double x1(0),x2(0),y1(0),y2(0);
27 
28  int ix = h.GetXaxis()->FindBin(x);
29  int iy = h.GetYaxis()->FindBin(y);
30  if (ix == 1) ix += 1;
31  if (ix == h.GetNbinsX()+1) ix -= 1;
32 
33  x1 = h.GetXaxis()->GetBinCenter(ix);
34  if (x<x1) {
35  --ix;
36  x1 = h.GetXaxis()->GetBinCenter(ix);
37  }
38  x2 = h.GetXaxis()->GetBinCenter(ix+1);
39 
40  y1 = h.GetYaxis()->GetBinCenter(iy);
41  if (y<y1) {
42  --iy;
43  y1 = h.GetYaxis()->GetBinCenter(iy);
44  }
45  y2 = h.GetYaxis()->GetBinCenter(iy+1);
46 
47  const double v00 = h.GetBinContent(ix,iy);
48  const double v01 = h.GetBinContent(ix,iy+1);
49  const double v10 = h.GetBinContent(ix+1,iy);
50  const double v11 = h.GetBinContent(ix+1,iy+1);
51  const double zx = (x-x1)/(x2-x1);
52  const double zy = (y-y1)/(y2-y1);
53  return (1.0-zx)*(1.0-zy)*v00 + (1.0-zx)*zy*v01 + zx*(1.0-zy)*v10 + zx*zy*v11;
54 }
55 
56 
57 inline
58 double
59 Extrapolate(const TH2D& h, double rmax, double r, double zeta)
60 { // extrapolation with formula ln N_\mu = a + b sqrt{r}
61  const double a = log( InterpolateHistrogram( h,rmax*cos(zeta),rmax*sin(zeta) ) );
62  const double b = ( a - log( InterpolateHistrogram( h,0.9*rmax*cos(zeta),0.9*rmax*sin(zeta) ) ) )/(sqrt(rmax)-sqrt(0.9*rmax));
63  return exp(a + b*(sqrt(r)-sqrt(rmax)));
64 }
65 
66 
67 inline
68 double
69 LocalMuonAngle(double x, double y, double theta, double phi)
70 {
71  // Calculate approximate distance of muon production point
72  // with Chebychev polynomial
73 
74  const double c[64] = { 1.323609e+05, 1.187303e+05, 9.395542e+04, 6.895397e+04,
75  4.840035e+04, 3.251341e+04, 2.091493e+04, 1.282508e+04,
76  7.433439e+03, 4.007066e+03, 1.945498e+03, 7.860169e+02,
77  1.895583e+02, -7.845296e+01, -1.691854e+02, -1.726411e+02,
78  -1.390602e+02, -9.562383e+01, -5.631717e+01, -2.703336e+01,
79  -8.487988e+00, 1.335395e+00, 5.137142e+00, 5.495047e+00,
80  4.413872e+00, 3.072145e+00, 1.835842e+00, 6.221296e-01,
81  -6.599210e-01, -1.829552e+00, -2.470651e+00, -2.467011e+00,
82  -1.996112e+00, -1.483970e+00, -1.217739e+00, -1.242982e+00,
83  -1.399658e+00, -1.550564e+00, -1.492873e+00, -1.091996e+00,
84  -4.217213e-01, 3.443991e-01, 1.022913e+00, 1.490880e+00,
85  1.786550e+00, 2.054111e+00, 2.299077e+00, 2.372312e+00,
86  2.122376e+00, 1.491762e+00, 5.303430e-01, -4.858504e-01,
87  -1.286566e+00, -1.638024e+00, -1.536687e+00, -1.157604e+00,
88  -8.427614e-01, -9.519352e-01, -1.534490e+00, -2.439957e+00,
89  -3.454757e+00, -4.376512e+00, -4.991014e+00, -5.234057e+00 };
90 
91  const unsigned int n = 64;
92  const double z = 2*theta/(0.5*utl::kPi)-1.0;
93  double d = 0.0;
94  double dd = 0.0;
95  for (unsigned int i=n-1;i!=0;--i)
96  {
97  const double sv = d;
98  d = 2*z*d - dd + c[i];
99  dd = sv;
100  }
101  d = (z*d + 0.5*c[0] - dd)*utl::meter;
102 
103  const double cosThetaMu = cos(theta)/sqrt( pow(cos(theta),2) + pow(d*cos(phi)*sin(theta)-x,2) + pow(d*sin(phi)*sin(theta)-y,2) );
104  return acos(cosThetaMu);
105 }
106 
107 
109  fDensity(0), fThetaRange(),
110  fTheta(0.), fPhi(0.), fEnergy(10.*EeV),
111  fExponent(1.0), fNMuonScale(1.0), fNMuonScaleEnergy(1.0),
112  fIndexThetaLow(0), fIndexThetaUp(0), fIndexPhiLow(0), fIndexPhiUp(0),
113  fHistDen1(NULL),fHistDen2(NULL),fHistDen3(NULL),fHistDen4(NULL)
114 {
115  Branch b;
116  b = topBranch.GetChild("nMuModel");
117  b.GetChild("exponent").GetData(fExponent);
118  b.GetChild("scale").GetData(fNMuonScale);
119 
120  topBranch.GetChild("thetaRange").GetData(fThetaRange);
121 
122  string pathToDataFile;
123  topBranch.GetChild("directory").GetData(pathToDataFile);
124 
125  fDensity = TFile::Open(pathToDataFile.c_str(),"READ");
126  if (!fDensity) {
127  ostringstream msg;
128  msg << "Could not read histogram file " << pathToDataFile << "\n";
129  throw NoDataForModelException(msg.str());
130  }
131 
133 }
134 
135 void
136 USCMuonProfile::LoadHistograms(double theta, double phi)
137 {
138  const double thetaDeg = theta/degree;
139  const double phiDeg = phi /degree;
140 
141  fIndexThetaLow = Theta2IndexLower(thetaDeg);
142  fIndexThetaUp = Theta2IndexUpper(thetaDeg);
143 
144  const double phiMapDeg = PhiMap(phiDeg);
145  fIndexPhiLow = Phi2IndexLower(phiMapDeg);
146  fIndexPhiUp = Phi2IndexUpper(phiMapDeg);
147 
148  unsigned int id1 = 60000+2000*(fIndexThetaLow)+fIndexPhiLow;
149  unsigned int id2 = 60000+2000*(fIndexThetaLow)+fIndexPhiUp;
150  unsigned int id3 = 60000+2000*(fIndexThetaUp)+fIndexPhiLow;
151  unsigned int id4 = 60000+2000*(fIndexThetaUp)+fIndexPhiUp;
152 
153  ostringstream histoID1;
154  histoID1 << "h" << id1 ;
155 
156  ostringstream histoID2;
157  histoID2 << "h" << id2 ;
158 
159  ostringstream histoID3;
160  histoID3 << "h" << id3 ;
161 
162  ostringstream histoID4;
163  histoID4 << "h" << id4 ;
164 
165  fHistDen1 = static_cast<TH2D*>(fDensity->Get(histoID1.str().c_str()));
166  fHistDen2 = static_cast<TH2D*>(fDensity->Get(histoID2.str().c_str()));
167  fHistDen3 = static_cast<TH2D*>(fDensity->Get(histoID3.str().c_str()));
168  fHistDen4 = static_cast<TH2D*>(fDensity->Get(histoID4.str().c_str()));
169 
170  if(!fHistDen1 || !fHistDen2 || !fHistDen3 || !fHistDen4 ) {
171  ostringstream msg;
172  msg << "the following histograms are missing in file "
173  << fDensity->GetName() << ": ";
174  if(!fHistDen1) msg << histoID1.str().c_str() << " ";
175  if(!fHistDen2) msg << histoID2.str().c_str() << " ";
176  if(!fHistDen3) msg << histoID3.str().c_str() << " ";
177  if(!fHistDen4) msg << histoID4.str().c_str() << " ";
178  msg << endl << "\tTheta: " << thetaDeg
179  << " Phi: " << phiDeg << endl;
180  throw NoDataForModelException(msg.str());
181  }
182 }
183 
184 // Angle in AugerUnits
185 double
186 USCMuonProfile::NMuon(double xpos, double ypos, double theta, double phi, double energy)
187 {
188  SetProfile(theta,phi,energy);
189 
190  const double rperp = rPerpendicular( xpos, ypos, fTheta, fPhi);
191  const double psi = PsiPerpendicular( xpos, ypos, fTheta, fPhi);
192 
193  const double zeta = psi-fBPsi+0.5*kPi;
194  const double xperp = rperp*cos(zeta);
195  const double yperp = rperp*sin(zeta);
196 
197  double dum1,dum2,dum3,dum4;
198  if (fabs(xperp) < 3950. and fabs(yperp) < 3950.)
199  {
200  dum1 = InterpolateHistrogram(*fHistDen1,xperp,yperp);
201  dum2 = InterpolateHistrogram(*fHistDen2,xperp,yperp);
202  dum3 = InterpolateHistrogram(*fHistDen3,xperp,yperp);
203  dum4 = InterpolateHistrogram(*fHistDen4,xperp,yperp);
204  }
205  else
206  { // extrapolation with formula ln N_\mu = a + b sqrt{r}
207  double rmax1 = 1e99;
208  double rmax2 = 1e99;
209  if (fabs(xperp)>3950.) rmax1 = fabs(3950./cos(zeta));
210  if (fabs(yperp)>3950.) rmax2 = fabs(3950./sin(zeta));
211  const double rmax = rmax1 < rmax2 ? rmax1 : rmax2;
212  dum1 = Extrapolate(*fHistDen1,rmax,rperp,zeta);
213  dum2 = Extrapolate(*fHistDen2,rmax,rperp,zeta);
214  dum3 = Extrapolate(*fHistDen3,rmax,rperp,zeta);
215  dum4 = Extrapolate(*fHistDen4,rmax,rperp,zeta);
216  }
217 
218  double thetaMap = fTheta/utl::degree;
219  double phiMap = PhiMap(fPhi/utl::degree);
220 
221  double dummy;
223  {
225  {
226  //do not interpolate. theta phi are exact
227  dummy = dum1;
228  }
229  else
230  {
231  //interpolate only in phi
232  double u1 = Index2Phi(fIndexPhiLow);
233  double u2 = Index2Phi(fIndexPhiUp);
234 
235  double u = (phiMap-u1)/(u2 -u1);
236  dummy = (1-u)*dum1+u*dum2;
237  }
238  }
239  else
240  {
242  {
243  //do not interpolate on phi. interpolate on theta.
244  double t1 = Index2Theta(fIndexThetaLow);
245  double t2 = Index2Theta(fIndexThetaUp);
246 
247  double t = (thetaMap-t1)/(t2-t1);
248 
249  dummy = (1-t)*dum1 +t*dum3;
250  }
251  else
252  {
253  //interpolate on theta and phi
254  double t1 = Index2Theta(fIndexThetaLow);
255  double t2 = Index2Theta(fIndexThetaUp);
256 
257  double t = (thetaMap-t1)/(t2-t1);
258 
259  double u1 = Index2Phi(fIndexPhiLow);
260  double u2 = Index2Phi(fIndexPhiUp);
261 
262  double u = (phiMap-u1)/(u2 -u1);
263  dummy = (1-t)*(1-u)*dum1 + u*(1-t)*dum2 + t*u*dum4 + t*(1-u)*dum3;
264  }
265  }
266 
267  const double localTheta = ThetaMuon(xpos,ypos,theta,phi,energy);
268  const double scale = fNMuonScaleEnergy * cos(localTheta) * TankGroundArea(localTheta);
269  return dummy*scale;
270 }
271 
272 // Angle in AugerUnits
273 double
274 USCMuonProfile::ThetaMuon(double /*xpos*/, double /*ypos*/, double theta, double /*phi*/, double /*energy*/)
275 {
276  // currently no own theta profile implemented in the USC case
277  // return LocalMuonAngle(xpos,ypos,theta,phi);
278  return theta;
279 }
280 
281 // Angle in AugerUnits
282 double
283 USCMuonProfile::EnergyMuon(double xpos, double ypos, double /*theta*/, double /*phi*/, double /*energy*/)
284 {
285  // taken from HAS Model, paper Maximo et al.
286  double r = rPerpendicular(xpos,ypos,fTheta,fPhi);
287  if (r>4000.*m) r = 4000*m;
288 
289  double th = fTheta/deg;
290 
291  double Ap0 = -1.92124e+01;
292  double Ap1 = 8.75452e-01;
293  double Ap2 = -1.19709e-02;
294  double Ap3 = 5.74630e-05;
295  double A = Ap0 + Ap1*th + Ap2*th*th + Ap3*th*th*th;
296 
297 
298  double Bp0 = 3.65857e+00;
299  double Bp1 = -1.61666e-01;
300  double Bp2 = 1.97280e-03;
301  double Bp3 = -8.13659e-06;
302  double B = Bp0 + Bp1*th + Bp2*th*th + Bp3*th*th*th;
303 
304  double LogEMu = A + B*log10(r); //Eq.(8)
305  double E = pow(10,LogEMu); //Energy in GeV
306 
307  //range (1GeV, 1TeV)
308  if (std::isnan(E) || E<1.0) E = 1.0;
309  else if (E>1000.) E=1000.;
310 
311  return E*GeV;
312 }
313 
314 // Internal function, angle in degrees
315 unsigned int
317 {
318  theta = approx(theta);
319  return static_cast<unsigned int>(floor((theta - 60.0)/2.0));
320 }
321 
322 // Internal function, angle in degrees
323 unsigned int
325 {
326  theta = approx(theta);
327  return static_cast<unsigned int>(ceil((theta - 60.0)/2.0));
328 }
329 
330 // Internal function, angle in degrees
331 unsigned int
333 {
334  phi = approx(phi);
335  return static_cast<unsigned int>(floor(phi/5.0))*5;
336 }
337 
338 // Internal function, angle in degrees
339 unsigned int
341 {
342  phi = approx(phi);
343  return static_cast<unsigned int>(ceil(phi/5.0))*5;
344 }
345 
346 // Internal function, angle in degrees
347 double
348 USCMuonProfile::Index2Theta(unsigned int itheta)
349 {
350  return 60.0+ static_cast<double>(2*(itheta));
351 }
352 
353 // Internal function, angle in degrees
354 double
355 USCMuonProfile::Index2Phi(unsigned int iphi)
356 {
357  return 5.0*static_cast<double>(iphi/5);
358 }
359 
360 // Internal function, angle in degrees
361 double
363 {
364 
365  double phiAires = 90.0 - phi - tls::kDeclination/degree;
366 
367  if (phiAires<0) phiAires = 360+phiAires;
368 
369  if (phiAires>180) phiAires = 360 - phiAires;
370 
371  return phiAires;
372 }
373 
374 double USCMuonProfile::GetThetaMin() { return fThetaRange[0]; };
375 double USCMuonProfile::GetThetaMax() { return fThetaRange[1]; };
double Extrapolate(const TH2D &h, double rmax, double r, double zeta)
const double degree
double rPerpendicular(const double xpos, const double ypos, const double theta, const double phi)
radial distance in shower front plane coordinate system
Branch GetChild(const std::string &childName) const
Get child of this Branch by child name.
Definition: Branch.cc:211
void SetProfile(double theta, double phi, double energy)
double pow(const double x, const unsigned int i)
const double EeV
Definition: GalacticUnits.h:34
unsigned int Theta2IndexLower(double theta)
void LoadHistograms(double theta, double phi)
Exception to use in a atmosphere model cannot find data it needs.
constexpr double deg
Definition: AugerUnits.h:140
Class representing a document branch.
Definition: Branch.h:107
constexpr double kPi
Definition: MathConstants.h:24
double NMuon(double xpos, double ypos, double theta, double phi, double energy)
Expected average number of muons per tank, at the given coordinates on the ground, for a certain combination of theta, phi, and energy of the primary particle.
double Index2Theta(unsigned int itheta)
constexpr double meter
Definition: AugerUnits.h:81
double approx(double num, double prec=1e-3)
constexpr double degree
void GetData(bool &b) const
Overloads of the GetData member template function.
Definition: Branch.cc:644
a second level trigger
Definition: XbT2.h:8
double TankGroundArea(const double theta)
Projected ground area of Auger tank seen by muon with zenith angle theta.
unsigned int Phi2IndexUpper(double theta)
static const double kDeclination
kDeclination of geomagnetic field in Malargüe, 2007
double PsiPerpendicular(const double xpos, const double ypos, const double theta, const double phi)
polar angle in shower front plane coordinate system
double GetThetaMax()
Maximum zenith angle, at which the tank response function is defined.
unsigned int Theta2IndexUpper(double theta)
constexpr double GeV
Definition: AugerUnits.h:187
double EnergyMuon(double xpos, double ypos, double theta, double phi, double energy)
Expected average muon energy on the ground, at the given coordinates on the ground, for a certain combination of theta, phi, and energy of the primary particle.
USCMuonProfile(utl::Branch branch)
double GetThetaMin()
Minimum zenith angle, at which the tank response function is defined.
double LocalMuonAngle(double x, double y, double theta, double phi)
unsigned int Phi2IndexLower(double theta)
constexpr double m
Definition: AugerUnits.h:121
double ThetaMuon(double xpos, double ypos, double theta, double phi, double energy)
Expected average muon inclination angle on the ground, at the given coordinates on the ground...
double Index2Phi(unsigned int iphi)
double InterpolateHistrogram(const TH2D &h, double x, double y)
std::vector< double > fThetaRange

, generated on Tue Sep 26 2023.