MultipleScatterer.cc
Go to the documentation of this file.
1 #include "MultipleScatterer.h"
2 
3 #include <utl/Reader.h>
4 #include <utl/ReferenceEllipsoid.h>
5 #include <utl/AugerUnits.h>
6 #include <utl/RandomEngine.h>
7 #include <utl/AugerUnits.h>
8 #include <utl/MathConstants.h>
9 
10 #include <fwk/CentralConfig.h>
11 #include <fwk/RandomEngineRegistry.h>
12 
13 #include <fevt/FdConstants.h>
14 
15 #include <atm/Atmosphere.h>
16 #include <det/Detector.h>
17 
18 #include <vector>
19 
20 #include <CLHEP/Random/Randomize.h>
21 using CLHEP::RandFlat;
22 
23 using namespace utl;
24 
26 {
28  utl::Branch topB = cc->GetTopBranch("MultipleScatterer");
29  topB.GetChild("MaxTime").GetData(MaxTime);
30  topB.GetChild("MaxZeta").GetData(MaxZeta);
31  const string modelString = topB.GetChild("fAerosolModel").Get<string>();
32  if (modelString == "eLongtin")
33  fAerosolModel = eLongtin;
34  else if (modelString == "eHG01")
35  fAerosolModel = eHG01;
36  else if (modelString == "eHG05")
37  fAerosolModel = eHG05;
38  else if (modelString == "eHG09")
39  fAerosolModel = eHG09;
40  else {
41  ostringstream err;
42  err << " Unknown aerosol model: " << modelString
43  << ", switching to default eHG05";
44  ERROR(err);
45  fAerosolModel = eHG05;
46  }
47  fRandomEngine = &fwk::RandomEngineRegistry::GetInstance().Get(fwk::RandomEngineRegistry::eDetector);
48 }
49 
50 
51 void
53  const utl::Photon& PhotonDirect,
54  const utl::Point& PointOfDetection,
55  std::vector<utl::Photon>& photonVector)
56 {
57  const double wavelength = PhotonDirect.GetWavelength();
58  const atm::Atmosphere& atmo = det::Detector::GetInstance().GetAtmosphere();
59 
60  const double mieAtt = atmo.EvaluateMieAttenuation(PointOfOrigin,PointOfDetection,wavelength);
61  const double rayAtt = atmo.EvaluateRayleighAttenuation(PointOfOrigin,PointOfDetection,wavelength);
62 
63  const double Transmission = rayAtt*mieAtt;
64 
65  AddPhotons(PointOfOrigin, PhotonDirect, Transmission, photonVector);
66 }
67 
68 
69 
70 void
72  const utl::Photon& PhotonDirect,
73  const double Transmission,
74  std::vector<utl::Photon>& photonVector)
75 {
76 
77  if (PhotonDirect.GetSource() == fevt::FdConstants::eFluorTotal) {
78  INFO(" Photon source eFluorTotal ");
79  return;
80  }
81  if (PhotonDirect.GetSource() != fevt::FdConstants::eFluorDirect)
82  return;
83 
85  double height1 = wgs84.PointToLatitudeLongitudeHeight(PointOfOrigin).get<2>();
86  double height = height1 / kilometer;
87  double OptDistance = - log (Transmission);
88 
89  if ((height > 0.) && (height < 15.) && (OptDistance < 5.)) {
90  //limits of application of parameterization
91 
92  double TimeBin = 100 * nanosecond;
93 
94  double zeta;
95  double weightfactor;
96 
97  for (double Time = (0 * nanosecond); Time < MaxTime; Time+=TimeBin) {
98  if (GetRandomZeta(zeta, weightfactor, Time, OptDistance, height, MaxZeta)) {
99 
100 
101  Photon newPhoton = PhotonDirect;
102  const Vector& photonDir = PhotonDirect.GetDirection();
103  double timeScatt = PhotonDirect.GetTime().GetInterval();
104 
105  if (weightfactor > 1.) {
106  double weight = PhotonDirect.GetWeight();
107  newPhoton.SetWeight(weight * weightfactor);
108  }
109 
110  const CoordinateSystemPtr& PhotonDirCS = photonDir.GetCoordinateSystem();
111 
112  // new coordinate system, photonDir along Z axis
113  double theta = photonDir.GetTheta(PhotonDirCS);
114  double phi = photonDir.GetPhi(PhotonDirCS);
115 
116  CoordinateSystemPtr newCS(
118  CoordinateSystem::RotationZ(phi,PhotonDirCS)));
119 
120  // random change of photon direction
121  double thetaRandom = zeta;
122  double phiRandom = RandFlat::shoot(&fRandomEngine->GetEngine(), 0.0, 2*kPi);
123 
124  Vector newphotonDir(cos(phiRandom)*sin(thetaRandom),
125  sin(phiRandom)*sin(thetaRandom),cos(thetaRandom),newCS);
126 
127  newPhoton.SetDirection(newphotonDir);
128 
129  // random change of time within given time bin
130  double timeRandom = RandFlat::shoot(&fRandomEngine->GetEngine(), 0.0, 100.);
131  timeScatt += (Time + timeRandom * nanosecond);
132 
133  newPhoton.SetTime(TimeInterval(timeScatt));
135 
136  // make photon
137  photonVector.push_back(newPhoton);
138  }
139 
140  }
141  }
142 }
143 
144 bool
145 MultipleScatterer::GetRandomZeta(double& zeta, double& weightfactor,
146  double Time, double OptDistance,
147  double height, double MaxZeta)
148 {
149  double A(0), B(0), C(0), D(0), E(0), F(0), G(0), H(0);
150  Time = Time / utl::ns;
151 
152  if (Time < 200){
153  switch(fAerosolModel) {
154  case eLongtin:
155  A = (0.00152 + 0.0000165 * Time) * pow (OptDistance, (0.0826+0.00525*Time))
156  * exp(-0.644*height) + 0.0000569 + 0.0000011 * Time;
157  B = -0.0504 * height * OptDistance + (-0.17+0.000766*Time)*OptDistance
158  - 0.0323 * height - 1.78 + 0.00814 * Time;
159  C = 3.59e-6 * OptDistance + (2.03e-7 + 1.65e-9*Time)*height + 2.44e-6 - 6.2e-8 * Time;
160  break;
161  case eHG01:
162  A = (0.000272 + 7.88e-6 * Time) * pow (OptDistance, (-0.248+0.0061*Time))
163  * exp(-0.456*height) + 4.04e-5 + 1.29e-6 * Time;
164  B = -0.0372 * height * OptDistance + (-0.272+0.000413*Time)*OptDistance
165  - 0.00927 * height - 2.04 + 0.009 * Time;
166  C = 1.61e-6 * OptDistance + (-1.56e-8 + 2.82e-9*Time)*height + 1.64e-6 - 5.09e-8 * Time;
167  break;
168  case eHG05:
169  A = (0.00123 + 1.6e-5 * Time) * pow (OptDistance, (0.0346+0.00544*Time))
170  * exp(-0.637*height) + 5.49e-5 + 1.15e-6 * Time;
171  B = -0.0495 * height * OptDistance + (-0.186+0.000749*Time)*OptDistance
172  - 0.0292 * height - 1.82 + 0.00831 * Time;
173  C = 2.98e-6 * OptDistance + (1.41e-7 + 2.03e-9*Time)*height + 2.3e-6 - 5.62e-8 * Time;
174  break;
175  case eHG09:
176  A = (0.0128 - 4.4e-5 * Time) * pow (OptDistance, (0.607+0.0026*Time))
177  * exp(-0.43*height) + 0.000474 - 5.66e-6 * Time;
178  B = (0.0343 - 0.000747 * Time) * height * OptDistance + (-0.178+0.0023*Time)*OptDistance
179  + (-0.0132 - 0.000584 * Time) * height - 1.33 + 0.00665 * Time;
180  C = (-4.34e-6 - 1.35e-6 * Time) * OptDistance + (4.73e-6 + 2.61e-7 * Time) * height
181  - 1.18-5 - 8.11e-7 * Time;
182  break;
183  default:
184  ERROR("No valid multiple satter model specified");
185  break;
186  }
187 
188  double ScattLight = IntegralA(A,B,C,MaxZeta);
189  double ScattAngle = RandFlat::shoot(&fRandomEngine->GetEngine(), 0.0, 1.0);
190 
191  if (ScattLight>1) {
192  weightfactor = ScattLight;
193  ScattAngle *= weightfactor;
194  }
195  else
196  weightfactor = 1.;
197 
198 
199  if (ScattAngle > ScattLight)
200  return false;
201  else {
202  double k = 0.*degree;
203  double l = MaxZeta;
204  double Accuracy = 0.1*degree;
205  zeta = -1.*degree;
206  int NMax = 20;
207 
208  // find angle by bisection of cumulative
209  while (NMax>0) {
210  double m = (k+l)/2;
211  double val = IntegralA(A,B,C,m);
212  if (val == ScattAngle || (l-k) < Accuracy) {
213  zeta = m;
214  return true;
215  }
216  if (val > ScattAngle)
217  l = m;
218  else
219  k = m;
220  --NMax;
221  }
222  WARNING(" maxIter reached!!! ");
223  return false;
224  }
225 
226  }
227  else {
228  switch(fAerosolModel) {
229  case eLongtin:
230  D = 128 * OptDistance * exp(-0.329 * height) * pow (Time, -1.76);
231  E = (-81.3 * OptDistance + 21.8) * height * pow (Time, -0.857);
232  F = 2004 * OptDistance * exp (-0.103*height) * pow (Time, -2.22);
233  G = (-132 * height * OptDistance + 78.4 * height - 600) * pow (Time, -0.833);
234  H = 0.0207 * exp(-0.367*OptDistance) * exp(-0.371*height) * pow(Time, (0.0812*height-1.54));
235  break;
236  case eHG01:
237  D = 43 * OptDistance * exp(-0.098 * height) * pow (Time, -1.72);
238  E = (-55.4 * OptDistance + 18) * height * pow (Time, -0.829);
239  F = 2275 * OptDistance * exp (-0.0586*height) * pow (Time, -2.26);
240  G = (-151 * height * OptDistance + 78.6 * height - 457) * pow (Time, -0.814);
241  H = 22.1 * exp(-9.99*OptDistance) * exp(-2.99*height) * pow(Time, (0.0258*height-0.881));
242  break;
243  case eHG05:
244  D = 90.7 * OptDistance * exp(-0.215 * height) * pow (Time, -1.77);
245  E = (-74.6 * OptDistance + 19.8) * height * pow (Time, -0.863);
246  F = 4260 * OptDistance * exp (-0.297*height) * pow (Time, -2.24);
247  G = (-130 * height * OptDistance + 77.2 * height - 613) * pow (Time, -0.829);
248  H = 0.0141 * exp(-0.286*OptDistance) * exp(-0.415*height) * pow(Time, (0.0748*height-1.44));
249  break;
250  case eHG09:
251  D = 161 * OptDistance * exp(-0.068 * height) * pow (Time, -1.45);
252  E = (-60.2 * OptDistance + 38.5) * height * pow (Time, -0.244);
253  F = 934 * OptDistance * exp (-0.0437*height) * pow (Time, -2.16);
254  G = (-49.5 * height * OptDistance + 7164 * height - 1340) * pow (Time, -0.824);
255  H = -0.0854 * exp(0.263*OptDistance) * exp(-0.767*height) * pow(Time, (-1.11));
256  break;
257  default: break;
258  }
259 
260  double ScattLight = IntegralB(D,E,F,G,H,MaxZeta);
261  double ScattAngle = RandFlat::shoot(&fRandomEngine->GetEngine(), 0.0, 1.0);
262 
263  if (ScattLight>1) {
264  weightfactor = ScattLight;
265  ScattAngle *= weightfactor;
266  }
267  else
268  weightfactor = 1.;
269 
270 
271  if (ScattAngle > ScattLight)
272  return false;
273  else {
274  double k = 0.*degree;
275  double l = MaxZeta;
276  double Accuracy = 0.1*degree;
277  zeta = -1.*degree;
278  int NMax = 20;
279 
280  // find angle by bisection of cumulative
281  while (NMax>0) {
282  double m = (k+l)/2;
283  double val = IntegralB(D,E,F,G,H,m);
284  if (val == ScattAngle || (l-k) < Accuracy) {
285  zeta = m;
286  return true;
287  }
288  if (val > ScattAngle)
289  l = m;
290  else
291  k = m;
292  --NMax;
293  }
294  WARNING(" maxIter reached!!! ");
295  return false;
296  }
297  }
298 }
299 
300 double
301 MultipleScatterer::IntegralA(double A, double B, double C, double zeta)
302 {
303  double integr, integr0, integr1;
304  double x = zeta/radian;
305  double x0 = 0.1*degree/radian;
306  A *= pow(57.295779513, B);
307 
308  if (x > x0) {
309  // series expansion of the integral
310  if (B == -2) {
311  integr1 = log(x) - x*x/12 + pow(x, 4)/480;
312  integr0 = log(x0) - x0*x0/12 + pow(x0, 4)/480;
313  } else if (B == -4) {
314  integr1 = -1/(2*x*x) - log(x)/6 + x*x/240;
315  integr0 = -1/(2*x0*x0) - log(x0)/6 + x0*x0/240;
316  } else if (B == -6) {
317  integr1 = -1/(4*pow(x, 4)) + 1/(12*x*x) + log(x)/120;
318  integr0 = -1/(4*pow(x0, 4)) + 1/(12*x0*x0) + log(x0)/120;
319  } else {
320  integr1 = pow(x, B)*(x*x/(2+B) - pow(x, 4)/(6*(4+B)) + pow(x, 6)/(120*(6+B)));
321  integr0 = pow(x0, B)*(x0*x0/(2+B) - pow(x0, 4)/(6*(4+B)) + pow(x0, 6)/(120*(6+B)));
322  }
323  integr = (A * integr1 - C * cos(zeta)) - (A * integr0 - C * cos(x0*radian));
324  integr += (A * pow(x0, B) + C) * 1.5230867e-6; //normalized contribution from image center
325  integr *= 20626.48062; //2*pi*180^2/pi^2
326  } else {
327  integr = (A * pow(x0, B) + C) * (1. - cos(zeta));
328  integr *= 20626.48062;
329  }
330 
331  return integr;
332 }
333 
334 double
335 MultipleScatterer::IntegralB(double D, double E, double F,
336  double G, double H, double zeta)
337 {
338  E *= 57.295779513;
339  G *= 57.295779513;
340  double integr;
341  integr = -H*cos(zeta) + (D*exp(E * zeta/radian)*(-cos(zeta)+E*sin(zeta)))/(1+E*E)
342  + (F*exp(G * zeta/radian)*(-cos(zeta)+G*sin(zeta)))/(1+G*G)
343  - (-H - D/(1+E*E) - F/(1+G*G));
344  integr *= 20626.48062; //2*pi*180^2/pi^2
345  return integr;
346 }
Top of the interface to Atmosphere information.
double IntegralA(double A, double B, double C, double zeta)
Point object.
Definition: Point.h:32
double GetPhi(const CoordinateSystemPtr &coordinateSystem) const
azimuth (phi) angle in spherical and cylindrical coordinates
Definition: BasicVector.h:254
void AddPhotons(const utl::Point &PointOfOrigin, const utl::Photon &PhotonDirect, const utl::Point &PointOfDetection, std::vector< utl::Photon > &photonVector)
atm::AttenuationResult EvaluateMieAttenuation(const utl::Point &xInit, const utl::Point &xFinal, const std::vector< double > &wLength) const
double GetTheta(const CoordinateSystemPtr &coordinateSystem) const
zenith (theta) angle in spherical coordinates
Definition: BasicVector.h:248
CoordinateSystemPtr GetCoordinateSystem() const
Get the coordinate system of the current internal representation.
Definition: BasicVector.h:234
constexpr double radian
Definition: AugerUnits.h:130
#define INFO(message)
Macro for logging informational messages.
Definition: ErrorLogger.h:161
double GetWeight() const
weight assigned to the photon
Definition: Photon.h:21
Branch GetChild(const std::string &childName) const
Get child of this Branch by child name.
Definition: Branch.cc:211
double pow(const double x, const unsigned int i)
int GetSource() const
source of the photons. Should use Eye::LightSource enum types
Definition: Photon.h:24
T Get() const
Definition: Branch.h:271
boost::shared_ptr< const CoordinateTransformer > CoordinateSystemPtr
Shared pointer for coordinate systems.
Class representing a document branch.
Definition: Branch.h:107
Reference ellipsoids for UTM transformations.
constexpr double kPi
Definition: MathConstants.h:24
constexpr double nanosecond
Definition: AugerUnits.h:143
atm::AttenuationResult EvaluateRayleighAttenuation(const utl::Point &xInit, const utl::Point &xFinal, const std::vector< double > &wLength) const
Compute Rayleigh attenuation between points.
void SetSource(const int source)
Definition: Photon.h:32
Triple PointToLatitudeLongitudeHeight(const Point &thePoint) const
Convert Point to Lat/Long/Height.
static Policy::type RotationY(const double angle, const CoordinateSystemPtr &theCS)
Construct from rotation about Y axis.
static const ReferenceEllipsoid & GetWGS84()
Get the auger standard ellipsoid: wgs84.
constexpr double degree
static Policy::type RotationZ(const double angle, const CoordinateSystemPtr &theCS)
Construct from rotation about Z axis.
void SetWeight(const double w)
source of the photons. Should use Eye::LightSource enum types
Definition: Photon.h:31
#define WARNING(message)
Macro for logging warning messages.
Definition: ErrorLogger.h:163
void GetData(bool &b) const
Overloads of the GetData member template function.
Definition: Branch.cc:644
double GetInterval() const
Get the time interval as a double (in Auger base units)
Definition: TimeInterval.h:69
const utl::Vector & GetDirection() const
Definition: Photon.h:26
A TimeInterval is used to represent time elapsed between two events.
Definition: TimeInterval.h:43
bool GetRandomZeta(double &zeta, double &weightfactor, double Time, double OptDistance, double height, double MaxZeta)
static CentralConfig * GetInstance()
Use this the first time you get an instance of central configuration.
constexpr double kilometer
Definition: AugerUnits.h:93
Vector object.
Definition: Vector.h:30
double IntegralB(double D, double E, double F, double G, double H, double zeta)
Main configuration utility.
Definition: CentralConfig.h:51
constexpr double ns
Definition: AugerUnits.h:162
double GetWavelength() const
Definition: Photon.h:27
void SetTime(const utl::TimeInterval &t)
Definition: Photon.h:36
#define ERROR(message)
Macro for logging error messages.
Definition: ErrorLogger.h:165
constexpr double m
Definition: AugerUnits.h:121
utl::TimeInterval GetTime() const
Definition: Photon.h:28
void SetDirection(const utl::Vector &v)
Definition: Photon.h:34
utl::Branch GetTopBranch(const std::string &id)
Get top branch for moduleConfigLink with given id (XML files)

, generated on Tue Sep 26 2023.