Modules/FdSimulation/TelescopeSimulatorKG2/Mirror.cc
Go to the documentation of this file.
1 
9 #include "Mirror.h"
10 #include "RTFunctions.h"
11 
12 #include <utl/Math.h>
13 #include <utl/MathConstants.h>
14 #include <utl/AugerUnits.h>
15 #include <utl/ErrorLogger.h>
16 #include <utl/Photon.h>
17 #include <utl/Point.h>
18 #include <utl/Vector.h>
19 #include <utl/CoordinateSystemPtr.h>
20 #include <utl/RandomEngine.h>
21 #include <utl/TabulatedFunction.h>
22 
23 #include <fdet/Telescope.h>
24 #include <fdet/Mirror.h>
25 
26 #include <CLHEP/Random/Randomize.h>
27 
28 #include <TPolyLine3D.h>
29 #include <TObjArray.h>
30 
31 #include <iostream>
32 
33 using namespace TelescopeSimulatorKG2;
34 using namespace utl;
35 using namespace std;
36 
37 using CLHEP::RandFlat;
38 using CLHEP::RandGauss;
39 
40 
41 // these are constants used for the segmentation of the mirror sphere
42 const int gNSegments = 6;
43 const double gMirrorWidth = 3.5*m;
44 
45 
47  const fdet::Telescope& tel,
48  const double mirrorSize,
49  const double mirrorSegmentSigma,
50  const double mirrorRadiusSigma,
51  const double mirrorAbsorptionTop,
52  const double mirrorAbsorptionBot,
53  const utl::TabulatedFunction* const mirrorDiffusionTop,
54  const utl::TabulatedFunction* const mirrorDiffusionBot) :
55  fRandom(rndm),
56  fMirrorSize(mirrorSize),
57  fMirrorSegmentSigma(mirrorSegmentSigma),
58  fMirrorRadiusSigma(mirrorRadiusSigma),
59  fMirrorAbsorptionTop(mirrorAbsorptionTop),
60  fMirrorAbsorptionBot(mirrorAbsorptionBot),
61  fMirrorDiffusionTop(mirrorDiffusionTop),
62  fMirrorDiffusionBot(mirrorDiffusionBot),
63  fTelCS(tel.GetTelescopeCoordinateSystem()),
64  fOrigin(0,0,0, fTelCS),
65  fReflectivity(tel.GetMirror().GetReflectivity()),
66  fRCurv(tel.GetMirror().GetRadiusOfCurvature()),
67  fSigma(tel.GetMirror().GetSigmaNormal())
68 { }
69 
70 
71 RTNext
72 Mirror::Trace(const utl::Photon& photonIn, utl::Photon& photonOut)
73 {
74  if (photonIn.GetDirection().GetZ(fTelCS) > 0) {
75  photonOut = photonIn;
76  ostringstream err;
77  err << "Missed Mirror : nDir>0";
78  ERROR(err);
79  return eLost;
80  }
81 
82  RTFunctions::IntersectionList intersections;
83  const int sphereStatus = RTFunctions::Sphere(fOrigin, fRCurv, photonIn, intersections);
84  if (sphereStatus <= 0) {
85  photonOut = photonIn;
86  ostringstream err;
87  err << "Missed Mirror : " << sphereStatus << " !!!";
88  ERROR(err);
89  return eLost;
90  }
91 
92  // always choose latter intersection, we want to hit inside of sphere
93  // photonOut is the photon when it hits the mirror
94  photonOut = intersections.back().first;
95  Vector normal = intersections.back().second;
96 
97  // dimensions of the mirror +/- 33.07 deg in latitude and longitude by default (change in TelescopeSimulatorKG2 --> MirrorSize)
98  // or use GetMirrorSegment(posOnSphere) that was implemented for the deformed mirror
99  const Point posOnSphere = photonOut.GetPosition();
100 
101  //position of photon on mirror
102  //latitude --> used to describe changing dust layer across mirror in vertical direction
103  const double horizontalPosOnMirror = asin(posOnSphere.GetY(fTelCS) / fRCurv); // longitude
104  const double verticalPosOnMirror = asin(posOnSphere.GetX(fTelCS) / fRCurv); // latitude
105 
106  // if mirror size is set to -1 in TelescopeSimulatorKG2.xml.in --> no mirror boundary, i.e. mirror is a complete hemisphere
107  // if a physical mirror size is given (0 deg < mirrorSize < 90 deg), check now if photon hits mirror
108  //if (fMirrorSize > 0) {
109  if (false) {
110  if (abs(horizontalPosOnMirror) > fMirrorSize || abs(verticalPosOnMirror) > fMirrorSize) {
111  //cout << posOnSphere.GetX(fTelCS) / mm << ','
112  // << posOnSphere.GetY(fTelCS) / mm << ','
113  // << posOnSphere.GetZ(fTelCS) / mm << '\n';
114  return eLost;
115  }
116  }
117 
118  if (true) { // mirror gaps
119  bool lost = false;
120  const bool HARDDEBUG = false;
121  if (1) {
122  // gaps between mirror segments for KA mirrors
123  const int nSeg = 3; // number of segments per row/col per Quadrant
124  const double mirrorGapWidth = 5*mm; // educated guess
125  const double angGapWidth = 2 * fRCurv * asin(0.5*mirrorGapWidth / fRCurv); // approx 10 deg at equator
126  const double mirrorSegmentHeight = 650*mm; // = width of segment at equator
127  const double mirrorSegmentAngWidth = 2 * fRCurv * asin(0.5*mirrorSegmentHeight / fRCurv);
128 
129  /*
130  \_______/
131  ________ <-- gap
132  / \ <-- corner diamond
133  | |
134  | O | <-- ceter hole
135  | |
136  \________/
137  */
138 
139  const Vector::Triple xyz = (posOnSphere - fOrigin).GetCoordinates(fTelCS);
140  const double& x = xyz.get<0>();
141 
142  // mirror height limit
143  if (abs(x) > nSeg*mirrorSegmentHeight) {
144  lost = true;
145  } else {
146  const double& y = xyz.get<1>();
147  const double& z = -xyz.get<2>();
148  const double phi = fRCurv * atan2(y, z);
149  // mirror width limit
150  if (abs(phi) > nSeg*mirrorSegmentAngWidth) {
151  lost = true;
152  } else {
153  const double h = abs(x - int(x/mirrorSegmentHeight) * mirrorSegmentHeight);
154  // horizontal gaps between mirror segments
155  if (h < mirrorGapWidth)
156  lost = true;
157  else {
158  const double w = abs(phi - int(phi/mirrorSegmentAngWidth) * mirrorSegmentAngWidth);
159  // vertical gaps between mirror segments
160  if (w < angGapWidth)
161  lost = true;
162  else {
163  const double dh = h - 0.5*mirrorSegmentHeight;
164  const double dw = w - 0.5*mirrorSegmentHeight;
165  const double holeRadius = 10 * mm; // see technical drawing
166  // central holes in the segments
167  if (dh*dh + dw*dw < holeRadius*holeRadius)
168  lost = true;
169  else {
170  const double xe = 0.5 * mirrorSegmentHeight - abs(dh);
171  const double ye = 0.5 * mirrorSegmentHeight - abs(dw);
172  const double d = 20 * mm; // see technical drawing
173  // corner of the segement
174  if (xe + ye < d)
175  lost = true;
176  }
177  }
178  }
179  }
180  }
181  } else { // czech mirrors
182  const double mirrorGapWidth = 5*mm; // educated guess
183  const double angGapWidth = 2 * fRCurv * asin(0.5*mirrorGapWidth / fRCurv); // approx 10 deg at equator
184  const double mirrorSegmentHeight = 624.7*mm; //approx
185  const double mirrorSegmentHalfWidth = 0.5 * 541*mm; //approx
186  const double mirrorSegmentAngHalfWidth = 2 * fRCurv * asin(0.5*mirrorSegmentHalfWidth / fRCurv);
187  //const double mirrorSegmentAngHalfWidth = 4.53952*deg;
188 
189  const Vector::Triple xyz = (posOnSphere - fOrigin).GetCoordinates(fTelCS);
190  const double& x = xyz.get<0>();
191  const double& y = xyz.get<1>();
192  const double& z = -xyz.get<2>();
193  const double phi = fRCurv * atan2(y, z);
194 
195  const vector<double> segEle {-3.98*deg, 11.9316*deg, -19.9279*deg, 28.0239*deg};
196  const vector<double> segSideHight {((488.15 - 155.15) / 2) * mm, ((467.87 - 143.99) / 2) * mm,
197  ((466.56 - 151.11) / 2) * mm, ((472.67 - 133.77) / 2) * mm};
198 
199  // mirror height limit
200  if (!lost && abs(x) > 3*mirrorSegmentHeight)
201  lost = true;
202  // mirror width limit
203  if (!lost && abs(phi) > 8.3*mirrorSegmentAngHalfWidth)
204  lost = true;
205 
206  // vertical gaps between mirror segments
207  if (!lost) {
208  const double w = abs(phi - int(phi/mirrorSegmentAngHalfWidth) * mirrorSegmentAngHalfWidth);
209  if (w < angGapWidth) {
210  const bool odd = bool(int(phi/mirrorSegmentAngHalfWidth)%2);
211  const int s = odd ? 1 : -1;
212  for (unsigned int i = 0; i < 4; ++i) {
213  const double theta = fRCurv * (atan2(-x, z) + s * segEle.at(i));
214  if (abs(theta) < segSideHight.at(i))
215  lost = true;
216  }
217  }
218  }
219 
220  // central holes in segemnts
221  if (!lost) {
222  const bool odd = bool(int(phi/mirrorSegmentAngHalfWidth)%2);
223  const int s = odd ? 1 : -1;
224  const double holeRadius = 15*mm;
225  for (unsigned int i = 0; i < 4; ++i) {
226  const double dPhi_halfSegm = 4.53952*deg;
227  const double dPhi0 = odd ? dPhi_halfSegm : 0*deg;
228  for (unsigned int j = 0; j < 4; ++j) {
229  const double thetaA = fRCurv * (atan2(-x, z) - s * segEle.at(i));
230  double phiA = fRCurv * (atan2(y, z) + j * 2 * dPhi_halfSegm + dPhi0);
231  if (thetaA*thetaA + phiA*phiA < holeRadius*holeRadius)
232  lost = true;
233  phiA = fRCurv * (atan2(y, z) - j * 2 * dPhi_halfSegm - dPhi0);
234  if (thetaA*thetaA + phiA*phiA < holeRadius*holeRadius)
235  lost = true;
236  }
237  }
238  }
239 
240  // 'trianlgular' gaps between the hexagons
241  if (!lost) {
242 
243  }
244 
245  }
246 
247  if (lost) {
248  if (HARDDEBUG) {
249  cout << posOnSphere.GetX(fTelCS) / mm << ','
250  << posOnSphere.GetY(fTelCS) / mm << ','
251  << posOnSphere.GetZ(fTelCS) / mm << '\n';
252  }
253  return eLost;
254  }
255  } // end mirror gaps
256 
257  // the deformed mirror is/will not be used -> kick out some day
258  if (fMirrorSegmentSigma > 0 || fMirrorRadiusSigma > 0) {
259  const MirrorSegment& ms = GetMirrorSegment(posOnSphere);
260  const int sphereStatus2 = RTFunctions::Sphere(ms.origin, ms.radius, photonIn, intersections);
261  if (sphereStatus2 <= 0) {
262  photonOut = photonIn;
263  ostringstream err;
264  err << "Missed MirrorSegment : status=" << sphereStatus2 << " index=" << ms.index << " !!!";
265  ERROR(err);
266  return eLost;
267  }
268  photonOut = intersections.back().first;
269  normal = intersections.back().second;
270  }
271 
272  // CAREFUL!!! mirror reflectivity is NOT 100%!!!
273  // study of mirror test documentation showed
274  // mean of 88% total reflectivity, 90% of this light in spot
275  // At the moment, photons are absorbed but also part of the light goes to the diffuse part
276  // CHECK!!!
277 
278  const double reflectedOrNot = RandFlat::shoot(&fRandom.GetEngine(), 0, 1);
279  const double photonWL = photonOut.GetWavelength();
280  if (reflectedOrNot > fReflectivity.Y(photonWL)) {
281  return eLost; // absorbed
282  } else {
283  // reflect photon on mirror
284  RTFunctions::Reflection(photonOut, normal, photonOut);
285 
287  // use light distribution from mirror measurements in Nov 2014 (results from Lenka)
288  // only do diffusion if diffusion function is given in xml AND fDoNoHalo==0, aka the TabulatedFunction is not NULL
289  const Vector mirrordiffusion =
291  photonOut.SetDirection(mirrordiffusion);
292  }
293 
295  RTFunctions::Absorption(photonOut, fMirrorAbsorptionTop, fMirrorAbsorptionBot, verticalPosOnMirror, photonOut, fMirrorSize);
296 
297  return eCamera;
298  }
299 }
300 
301 
304 {
305  // If there is a per mirror-segment random component
306  // First: index mirror-segments
307  const double segmentWidth = gMirrorWidth / gNSegments;
308  const double x = p.GetX(fTelCS);
309  const double y = p.GetY(fTelCS);
310  const int ix = x / segmentWidth - (x < 0 ? 1 : 0);
311  const int iy = y / segmentWidth - (y < 0 ? 1 : 0);
312  const int index = ix * 1000 + iy; // arbitrary but unique mirror-segment index
313 
314  if (!fSegments.count(index)) { // if this mirror-segment is new -> create it
315 
316  const double radius = RandGauss::shoot(&fRandom.GetEngine(), fRCurv, fMirrorRadiusSigma);
317  const double centerSegmentX = (0.5 + ix) * segmentWidth;
318  const double centerSegmentY = (0.5 + iy) * segmentWidth;
319  const double centerSegmentZ = -sqrt(pow(fRCurv, 2) - pow(centerSegmentX, 2) - pow(centerSegmentY, 2));
320  const Point centerSegment(centerSegmentX, centerSegmentY, centerSegmentZ, fTelCS);
321  const Vector dirSegment(centerSegment - fOrigin);
322 
323  const double elevationSegment = atan(centerSegmentX / fRCurv);
324 
325  CoordinateSystemPtr aux1CS = CoordinateSystem::Translation(dirSegment, fTelCS);
326  CoordinateSystemPtr aux2CS = CoordinateSystem::RotationY(-elevationSegment, aux1CS);
327  CoordinateSystemPtr aux3CS = CoordinateSystem::RotationX((centerSegmentY < 0 ? -1 : 1) * (-dirSegment).GetTheta(aux2CS), aux2CS);
328 
329  const double phi = RandFlat::shoot(&fRandom.GetEngine(), 0, 360*deg);
330  const double theta = acos(RandFlat::shoot(&fRandom.GetEngine(), cos(fMirrorSegmentSigma), 1));
331  //const double theta = acos(cos(fMirrorSegmentSigma));
332 
333  CoordinateSystemPtr aux4CS = CoordinateSystem::RotationZ(phi, aux3CS);
334  CoordinateSystemPtr aux5CS = CoordinateSystem::RotationY(theta, aux4CS);
335  CoordinateSystemPtr msCS = CoordinateSystem::RotationZ(-phi, aux5CS);
336 
337  //const Vector delta(sinTheta*cos(phi), sinTheta*sin(phi), cosTheta, aux3CS);
338  const Vector delta(0,0,1, msCS);
339  const Point originPrime(centerSegment + delta * radius);
340 
341  //cout << " creating " << index << " " << phi/deg << " " << theta/deg << " " << fMirrorSegmentSigma/deg << " " << cos(fMirrorSegmentSigma) << endl;
342 
343  fSegments[index] = MirrorSegment(index, originPrime, radius, msCS);
344  }
345  return fSegments[index];
346 }
347 
348 
349 TObjArray*
351 {
352  TObjArray* const objs = new TObjArray();
353 
354  const int color = 1;
355  const int size = 2;
356 
357  const double width = gMirrorWidth; // total width
358  const int nSeg = gNSegments;
359  const int nSubSeg = 3; // sub structure mirror segments... (at least 1!)
360 
361  const double segWidth = width / nSeg;
362 
363  //cout << " width=" <<width << " segWidth=" << segWidth << endl;
364 
365  for (int i = 0; i < nSeg; ++i) {
366 
367  for (int j = 0; j < nSeg; ++j) {
368 
369  //const int color = 1 + j + i*nSeg;
370 
371  const double x_mir = -gMirrorWidth / 2 + (0.5 + i) * segWidth;
372  const double y_mir = -gMirrorWidth / 2 + (0.5 + j) * segWidth;
373 
374  //cout << " draw: " << i << j << endl;
375  const MirrorSegment& ms = GetMirrorSegment(Point(x_mir, y_mir, 0, fTelCS));
376  const double r = ms.radius;
377 
378  const double d = segWidth / nSubSeg;
379 
380  /*cout << " draw: " << i << " " << j << " " << x_mir << " " << y_mir << " "
381  << " index=" << ms.index << " r=" << ms.radius << " "
382  << ms.origin.GetX(fTelCS)<< " "
383  << ms.origin.GetY(fTelCS)<< " "
384  << ms.origin.GetZ(fTelCS)<< " "
385  << endl;*/
386 
387  for (int k = 0; k < nSubSeg; ++k) {
388 
389  for (int l = 0; l < nSubSeg; ++l) {
390 
391  const double x1 = -segWidth / 2 + k * d;
392  const double y1 = -segWidth / 2 + l * d;
393  const double z1 = r - sqrt(pow(r, 2) - pow(x1, 2) - pow(y1, 2));
394  const Point p1(x1, y1, z1, ms.cs);
395 
396  //cout << " z1=" << z1 << " " << p1.GetZ(ms.cs) << " " << p1.GetZ(fTelCS) << endl;
397 
398  const double x2 = -segWidth / 2 + (k + 1) * d;
399  const double y2 = -segWidth / 2 + l * d;
400  const double z2 = r - sqrt(pow(r, 2) - pow(x2, 2) - pow(y2, 2));
401  const Point p2(x2, y2, z2, ms.cs);
402 
403  const double x3 = -segWidth / 2 + k * d;
404  const double y3 = -segWidth / 2 + (l + 1) * d;
405  const double z3 = r - sqrt(pow(r, 2) - pow(x3, 2) - pow(y3, 2));
406  const Point p3(x3, y3, z3, ms.cs);
407 
408  const double x4 = -segWidth / 2 + (k + 1) * d;
409  const double y4 = -segWidth / 2 + (l + 1) * d;
410  const double z4 = r - sqrt(pow(r, 2) - pow(x4, 2) - pow(y4, 2));
411  const Point p4(x4, y4, z4, ms.cs);
412 
413  TPolyLine3D* const l1 = new TPolyLine3D(5);
414  l1->SetLineColor(color);
415  l1->SetLineWidth(size);
416  l1->SetPoint(0, p1.GetX(fTelCS), p1.GetY(fTelCS), p1.GetZ(fTelCS));
417  l1->SetPoint(1, p2.GetX(fTelCS), p2.GetY(fTelCS), p2.GetZ(fTelCS));
418  l1->SetPoint(2, p4.GetX(fTelCS), p4.GetY(fTelCS), p4.GetZ(fTelCS));
419  l1->SetPoint(3, p3.GetX(fTelCS), p3.GetY(fTelCS), p3.GetZ(fTelCS));
420  l1->SetPoint(4, p1.GetX(fTelCS), p1.GetY(fTelCS), p1.GetZ(fTelCS));
421 
422  l1->Draw();
423  objs->AddLast(l1);
424  }
425  }
426  }
427  }
428  return objs;
429 }
std::vector< PhotonNormalPair > IntersectionList
Definition: /RTFunctions.h:47
constexpr double mm
Definition: AugerUnits.h:113
Point object.
Definition: Point.h:32
RandomEngineType & GetEngine()
Definition: RandomEngine.h:32
void Reflection(const utl::Photon &photonIn, const Vector &normal, utl::Photon &photonOut)
Definition: /RTFunctions.cc:33
Class to hold collection (x,y) points and provide interpolation between them.
void Absorption(const utl::Photon &photonIn, const double filterAbsorptionFactor, utl::Photon &photonOut)
Definition: /RTFunctions.cc:49
double pow(const double x, const unsigned int i)
constexpr double deg
Definition: AugerUnits.h:140
RTNext Trace(const utl::Photon &photonIn, utl::Photon &photonOut)
constexpr double ms
Definition: AugerUnits.h:164
boost::shared_ptr< const CoordinateTransformer > CoordinateSystemPtr
Shared pointer for coordinate systems.
boost::tuple< double, double, double > Triple
Coordinate triple for easy getting or setting of coordinates.
Definition: Triple.h:15
constexpr double s
Definition: AugerUnits.h:163
double GetX(const CoordinateSystemPtr &coordinateSystem) const
Definition: BasicVector.h:206
Wraps the random number engine used to generate distributions.
Definition: RandomEngine.h:27
double abs(const SVector< n, T > &v)
Vector MirrorDiffusion(utl::RandomEngine &rndm, const Vector &specularDir, const utl::TabulatedFunction *mirrorDiffusionTop, const utl::TabulatedFunction *mirrorDiffusionBot, const double verticalPosOnMirror)
Mirror(utl::RandomEngine &rndm, const fdet::Telescope &tel, const double mirrorSize, const double mirrorSegmentSigma, const double mirrorRadiusSigma, const double mirrorAbsorptionTop, const double mirrorAbsorptionBot, const utl::TabulatedFunction *const mirrorDiffusionTop, const utl::TabulatedFunction *const mirrorDiffusionBot)
const utl::Vector & GetDirection() const
Definition: Photon.h:26
double GetY(const CoordinateSystemPtr &coordinateSystem) const
Definition: BasicVector.h:209
Detector description interface for Telescope-related data.
Vector object.
Definition: Vector.h:30
bool Sphere(const Point &origin, const double radius, const utl::Photon &photonIn, IntersectionList &intersection)
double GetWavelength() const
Definition: Photon.h:27
double GetZ(const CoordinateSystemPtr &coordinateSystem) const
Definition: BasicVector.h:212
double Y(const double x) const
Get or interpolate the Y value that corresponds to parameter x.
#define ERROR(message)
Macro for logging error messages.
Definition: ErrorLogger.h:165
constexpr double m
Definition: AugerUnits.h:121
void SetDirection(const utl::Vector &v)
Definition: Photon.h:34
const utl::Point & GetPosition() const
Definition: Photon.h:25

, generated on Tue Sep 26 2023.