Tools/InclinedShowers/TankResponse/Tabular/TankResponse.cc
Go to the documentation of this file.
1 #include "TankResponse.h"
2 
3 #include <utl/AugerException.h>
4 #include <utl/Reader.h>
5 #include <utl/Branch.h>
6 #include <utl/AugerUnits.h>
7 
8 #include <utl/Math.h>
9 
10 #include <vector>
11 #include <sstream>
12 #include <iostream>
13 #include <limits>
14 
15 #ifdef _OPENMP
16  #include <omp.h>
17 #endif
18 
19 #include <boost/lexical_cast.hpp>
20 
21 using namespace TabularTankResponseNS;
22 using namespace utl;
23 using namespace std;
24 using namespace boost;
25 using namespace tls;
26 
27 // not available in some compiler collections
28 inline double sqrt(const size_t x) { return sqrt(double(x)); }
29 
30 inline
31 void
32 Trafo(size_t& i, double&z, const double x, const size_t n, const double x0, const double dx)
33 {
34  if (std::isnan(x))
35  {
36  i = 0;
37  z = x;
38  }
39  else if (x <= x0)
40  {
41  i = 0;
42  z = 0;
43  }
44  else if (x >= x0+dx)
45  {
46  i = n-1;
47  z = 0;
48  }
49  else
50  {
51  z = (x-x0)/dx*(n-1);
52  i = static_cast<size_t>(z);
53  z -= i;
54  }
55 }
56 
57 struct PdfData {
58  double fX;
59  double fY;
60  vector<double> fPDF;
61 };
62 
65 {
66  static TankResponse singleton(branch);
67  return singleton;
68 }
69 
71 {
72  size_t nmuons;
73  branch.GetChild("NMuons").GetData(nmuons);
74 
75  string filename;
76  branch.GetChild("DataFile").GetData(filename);
77 
78  branch.GetChild("PDFSmoothing").GetData(fSmooth);
79 
80  const Branch b = Reader(filename).GetTopBranch();
81 
82  const double nan = numeric_limits<double>::quiet_NaN();
83  fNX = 0;
84  fNY = 0;
85  double xrange[2] = { nan, nan };
86  double yrange[2] = { nan, nan };
87  fDS = 0;
88 
89  // discover grid properties and read pdfs
90  vector<PdfData> pdfs;
91  for (Branch bpdf = b.GetFirstChild(); bpdf; bpdf = bpdf.GetNextSibling())
92  {
93  AttributeMap am = bpdf.GetAttributes();
94  const double x = lexical_cast<double>(am["x"])*degree;
95  const double y = lexical_cast<double>(am["y"])+log10(meter);
96  fDS = lexical_cast<double>(am["ds"]);
97 
98  if (std::isnan(xrange[0]) || x < xrange[0] || xrange[1] < x)
99  {
100  ++fNX;
101  if (x < xrange[0] || std::isnan(xrange[0])) xrange[0] = x;
102  if (x > xrange[1] || std::isnan(xrange[1])) xrange[1] = x;
103  }
104 
105  if (std::isnan(yrange[0]) || y < yrange[0] || yrange[1] < y)
106  {
107  ++fNY;
108  if (y < yrange[0] || std::isnan(yrange[0])) yrange[0] = y;
109  if (y > yrange[1] || std::isnan(yrange[1])) yrange[1] = y;
110  }
111  pdfs.push_back(PdfData());
112  pdfs.back().fX = x;
113  pdfs.back().fY = y;
114  bpdf.GetData(pdfs.back().fPDF);
115  }
116 
117  if (yrange[0]==yrange[1])
118  {
119  // no y-dependency, set accepted range to something arbitrary,
120  // constant extrapolation is done automatically
121  yrange[0] = 0;
122  yrange[1] = 1;
123  }
124 
125  fX = xrange[0];
126  fDX = xrange[1]-xrange[0];
127  fY = yrange[0];
128  fDY = yrange[1]-yrange[0];
129  fMean.resize(extents[fNX][fNY]);
130  fSigma.resize(extents[fNX][fNY]);
131  fCdf.resize(extents[fNX][fNY][nmuons]);
132 
133  cout << "TabularTankResponse convolving";
134  #ifdef _OPENMP
135  #pragma omp parallel for
136  #endif
137  for (size_t i = 0; i < pdfs.size(); ++i)
138  {
139  cout << "." << flush;
140  const vector<double>& pdf = pdfs[i].fPDF;
141  const double x = pdfs[i].fX;
142  const double y = pdfs[i].fY;
143 
144  const size_t ix = round((x-xrange[0])/(xrange[1]-xrange[0])*(fNX-1));
145  const size_t iy = round((y-yrange[0])/(yrange[1]-yrange[0])*(fNY-1));
146 
147  const size_t n = pdf.size();
148 
149  // numerical auto-convolution step:
150  // without compiler optimization assignment operators of vector
151  // and multi_array are a serious bottlenecks here,
152  // so I operate on memory directly
153  const double* input = &pdf.front();
154  for (size_t m = 0; m < nmuons; ++m)
155  {
156  fCdf[ix][iy][m].resize(1+(m+1)*n);
157  double* data = &fCdf[ix][iy][m].front();
158  data[0] = 0;
159 
160  if (m == 0)
161  {
162  double sum = 0;
163  double vsum = 0;
164  double vvsum = 0;
165  /* Expectation of piecewise constant p.d.f.:
166  * int dx x f(x) = sum_i f[i] 1/2 (x[i+1]^2-x[i]^2)
167  * = sum_i 1/2 f[i] ds^2 (2i+1)
168  * = sum_i f[i] ds^2 (i+1/2)
169  * Second moment analog:
170  * int dx x^2 f(x) = sum_i f[i] 1/3 (x[i+1]^3-x[i]^3)
171  * = sum_i f[i] ds^3 (i^2 + i + 1/3)
172  */
173  for (size_t i = 0; i < n; ++i)
174  {
175  data[1+i] = input[i];
176  sum += input[i];
177  vsum += input[i]*(i+0.5);
178  vvsum += input[i]*(i*i+i+1.0/3.0);
179  }
180  vsum *= fDS; // one ds cancels when dividing by sum term
181  vvsum *= fDS*fDS; // one ds cancels when dividing by sum term
182  fMean[ix][iy] = vsum/sum;
183  fSigma[ix][iy] = sqrt(vvsum/sum - fMean[ix][iy]*fMean[ix][iy]);
184  }
185  else
186  {
187  const double* zero = &fCdf[ix][iy][0].front();
188  const double* prev = &fCdf[ix][iy][m-1].front();
189  for (size_t i = 0; i < (m+1)*n; ++i)
190  {
191  data[1+i] = 0;
192  for (size_t j = i >= n ? i-n+1 : 0; j <= min(i,m*n-1); ++j)
193  data[1+i] += zero[1+i-j]*prev[1+j];
194  }
195  }
196  }
197 
198  for (size_t m = 0; m < nmuons; ++m)
199  {
200  // compute CDF from PDF
201  double* data = &fCdf[ix][iy][m].front();
202  size_t i = 0;
203  for (; i < (m+1)*n && data[i+1] > 0; ++i)
204  data[1+i] = data[i] + data[1+i];
205 
206  // Normalize CDF
207  const double mean = fMean[ix][iy]*(m+1);
208  const double sigma = fSigma[ix][iy]*sqrt(m+1);
209  const double cTrans = NormalCDF((i+0.5)*fDS, mean, sigma);
210  for (size_t j = 0; j < i; ++j)
211  data[j] *= cTrans / data[i];
212  for (size_t j = i; j < (m+1)*n; ++j)
213  data[j] = NormalCDF((j+0.5)*fDS, mean, sigma);
214  }
215  } // loop over pdfs
216  cout << endl;
217 }
218 
219 double
220 TankResponse::PDF(const double signal,
221  const double theta,
222  const double r,
223  const ulong nmuons)
224  const
225 {
226  // no need to check ranges, constant extrapolation is done automatically
227  double result = 0;
228 
229  if (nmuons <= fCdf.shape()[2])
230  {
231  const double h = fSmooth*fDS;
232  double sm = signal - h; if (sm < 0) sm = 0;
233  const double sp = signal + h;
234 
235  const double cm = CDF(sm, theta, r, nmuons);
236  const double cp = CDF(sp, theta, r, nmuons);
237  result = (cp-cm)/(sp-sm);
238  }
239  else
240  {
241  const double m = Mean(theta, r, nmuons);
242  const double s = StDev(theta, r, nmuons);
243  result = NormalPDF(signal, m, s);
244  }
245 
246  return result;
247 }
248 
249 double
250 TankResponse::CDF(const double signalmax,
251  const double theta,
252  const double r,
253  const ulong nmuons)
254  const
255 {
256  // no need to check ranges, constant extrapolation is done automatically
257  if (nmuons == 0)
258  return signalmax > 0;
259 
260  if (nmuons <= fCdf.shape()[2])
261  {
262  size_t ix, iy;
263  double zx, zy;
264  Trafo(ix,zx,theta,fNX,fX,fDX);
265  Trafo(iy,zy,log10(r),fNY,fY,fDY);
266 
267  const vector<double>& v00 = fCdf[ix ][iy ][nmuons-1];
268  const vector<double>& v01 = fCdf[ix ][min(iy+1, fNY-1)][nmuons-1];
269  const vector<double>& v10 = fCdf[min(ix+1, fNX-1)][iy ][nmuons-1];
270  const vector<double>& v11 = fCdf[min(ix+1, fNX-1)][min(iy+1, fNY-1)][nmuons-1];
271 
272  // interpolation idea from USC group (original in USCInterTankResponse)
273  const double z = (signalmax-Mean(theta, r, nmuons))/StDev(theta, r, nmuons);
274  const double sqrtn = sqrt(nmuons);
275  const double m00 = fMean[ix][iy]*nmuons;
276  const double m01 = fMean[ix][min(iy+1, fNY-1)]*nmuons;
277  const double m10 = fMean[min(ix+1, fNX-1)][iy]*nmuons;
278  const double m11 = fMean[min(ix+1, fNX-1)][min(iy+1, fNY-1)]*nmuons;
279  const double s00 = fSigma[ix][iy]*sqrtn;
280  const double s01 = fSigma[ix][min(iy+1, fNY-1)]*sqrtn;
281  const double s10 = fSigma[min(ix+1, fNX-1)][iy]*sqrtn;
282  const double s11 = fSigma[min(ix+1, fNX-1)][min(iy+1, fNY-1)]*sqrtn;
283  const double p00 = EvaluateCdf(v00,s00*z+m00, m00, s00);
284  const double p01 = EvaluateCdf(v01,s01*z+m01, m01, s01);
285  const double p10 = EvaluateCdf(v10,s10*z+m10, m10, s10);
286  const double p11 = EvaluateCdf(v11,s11*z+m11, m11, s11);
287  return (1.0-zx)*(1.0-zy)*p00
288  +(1.0-zx)* zy *p01
289  + zx *(1.0-zy)*p10
290  + zx * zy *p11;
291  }
292  else
293  {
294  const double m = Mean(theta, r, nmuons);
295  const double s = StDev(theta, r, nmuons);
296  return NormalCDF(signalmax, m, s);
297  }
298 }
299 
300 double
301 TankResponse::Mean(const double theta,
302  const double r,
303  const ulong nmuons)
304  const
305 {
306  // no need to check ranges, constant extrapolation is done automatically
307  size_t ix, iy;
308  double zx, zy;
309  Trafo(ix,zx,theta,fNX,fX,fDX);
310  Trafo(iy,zy,log10(r),fNY,fY,fDY);
311 
312  return ((1.0-zx)*(1.0-zy)*fMean[ix ][iy ]
313  +(1.0-zx)* zy *fMean[ix ][min(iy+1, fNY-1)]
314  + zx *(1.0-zy)*fMean[min(ix+1, fNX-1)][iy ]
315  + zx * zy *fMean[min(ix+1, fNX-1)][min(iy+1, fNY-1)])*nmuons;
316 }
317 
318 double
319 TankResponse::StDev(const double theta,
320  const double r,
321  const ulong nmuons)
322  const
323 {
324  // no need to check ranges, constant extrapolation is done automatically
325  size_t ix, iy;
326  double zx, zy;
327  Trafo(ix,zx,theta,fNX,fX,fDX);
328  Trafo(iy,zy,log10(r),fNY,fY,fDY);
329 
330  return ((1.0-zx)*(1.0-zy)*fSigma[ix ][iy ]
331  +(1.0-zx)* zy *fSigma[ix ][min(iy+1, fNY-1)]
332  + zx *(1.0-zy)*fSigma[min(ix+1, fNX-1)][iy ]
333  + zx * zy *fSigma[min(ix+1, fNX-1)][min(iy+1, fNY-1)])*sqrt(nmuons);
334 }
virtual double StDev(const double theta, const double r, const ulong muons) const
Standard deviation of signal, given fixed number of muons.
const double degree
virtual double PDF(const double signal, const double theta, const double r, const ulong muons) const
PDF of signal, given a fixed number of muons.
unsigned long ulong
Definition: VTankResponse.h:28
virtual double CDF(const double threshold, const double theta, const double r, const ulong muons) const
Probability of signal begin smaller than smax, given a fixed number of muons.
std::map< std::string, std::string > AttributeMap
Definition: Branch.h:24
const double meter
Definition: GalacticUnits.h:29
Branch GetChild(const std::string &childName) const
Get child of this Branch by child name.
Definition: Branch.cc:211
double NormalPDF(const double x)
double NormalCDF(const double x)
Branch GetTopBranch() const
Get the top Branch (represents same entity as document node)
Definition: Reader.h:45
Branch GetNextSibling() const
Get next sibling of this branch.
Definition: Branch.cc:284
Utility for parsing XML files.
Definition: Reader.h:25
Class representing a document branch.
Definition: Branch.h:107
constexpr double s
Definition: AugerUnits.h:163
const Data result[]
void GetData(bool &b) const
Overloads of the GetData member template function.
Definition: Branch.cc:644
virtual double Mean(const double theta, const double r, const ulong muons) const
Average signal, given fixed number of muons.
uint16_t * data
Definition: dump1090.h:228
constexpr double cm
Definition: AugerUnits.h:117
Branch GetFirstChild() const
Get first child of this Branch.
Definition: Branch.cc:98
double Mean(const std::vector< double > &v)
Definition: Functions.h:31
char * filename
Definition: dump1090.h:266
void Trafo(size_t &i, double &z, const double x, const size_t n, const double x0, const double dx)
constexpr double m
Definition: AugerUnits.h:121

, generated on Tue Sep 26 2023.