FDetector/Telescope.cc
Go to the documentation of this file.
1 #include <boost/lexical_cast.hpp>
2 
3 #include <utl/Point.h>
4 #include <utl/Vector.h>
5 #include <utl/ErrorLogger.h>
6 #include <utl/AugerUnits.h>
7 #include <utl/Reader.h>
8 #include <utl/TimeStamp.h>
9 #include <utl/TimeInterval.h>
10 #include <utl/UTCDateTime.h>
11 #include <utl/TabulatedFunction.h>
12 #include <utl/MathConstants.h>
13 #include <utl/Math.h>
14 #include <utl/AugerException.h>
15 #include <utl/AugerUnits.h>
16 #include <utl/Md5Sum.h>
17 #include <utl/UTMPoint.h>
18 #include <utl/ReferenceEllipsoid.h>
19 
20 #include <det/VManager.h>
21 #include <det/Detector.h>
22 
23 #include <fevt/Pixel.h>
24 
25 #include <fdet/FDetector.h>
26 #include <fdet/Channel.h>
27 #include <fdet/Pixel.h>
28 #include <fdet/Eye.h>
29 #include <fdet/Diaphragm.h>
30 #include <fdet/Mirror.h>
31 #include <fdet/Filter.h>
32 #include <fdet/Corrector.h>
33 #include <fdet/Camera.h>
34 #include <fdet/Telescope.h>
35 
36 #include <fwk/CoordinateSystemRegistry.h>
37 #include <fwk/LocalCoordinateSystem.h>
38 
39 #include <set>
40 
41 using namespace std;
42 using namespace utl;
43 using namespace det;
44 using namespace fwk;
45 
46 
47 namespace fdet {
48 
49  Telescope::Telescope(const unsigned int eyeId, const unsigned int telescopeId) :
50  fEyeId(eyeId),
51  fTelescopeId(telescopeId)
52  {
53  fEyeIdString = boost::lexical_cast<string>(fEyeId);
54  fTelescopeIdString = boost::lexical_cast<string>(fTelescopeId);
55  }
56 
57 
59  {
60  for (InternalChannelCollection::const_iterator cIt = fChannel.begin();
61  cIt != fChannel.end(); ++cIt)
62  delete cIt->second;
63 
64  for (InternalPixelCollection::const_iterator pIt = fPixel.begin();
65  pIt != fPixel.end(); ++pIt)
66  delete pIt->second;
67 
68  delete fConfigSignatureStr;
69  delete fConfigSignature;
70  delete fPosition;
71  delete fAxis;
72  delete fCommissionTime;
73  delete fDecommissionTime;
75  delete fTelPointingId;
76  delete fTelPointingPhiMap;
78  delete fDiaphragm;
79  delete fMirror;
80  delete fFilter;
81  delete fCorrector;
82  delete fCamera;
83  }
84 
85 
86  const std::string&
87  Telescope::GetConfigSignature(const std::string& module)
88  const
89  {
90  if (module != fConfigSignatureModule)
91  GetConfigSignatureStr(module);
92  if (!fConfigSignature)
93  fConfigSignature = new string(Md5Sum(GetConfigSignatureStr(module)).GetHexDigest());
94  return *fConfigSignature;
95  }
96 
97 
98  const std::string&
99  Telescope::GetConfigSignatureStr(const std::string& module)
100  const
101  {
102  if (module != fConfigSignatureModule) {
103  delete fConfigSignature;
104  fConfigSignature = 0;
105  delete fConfigSignatureStr;
107  fConfigSignatureModule = module;
108  }
109 
111  return *fConfigSignatureStr;
112 
113  ostringstream configSS;
114 
115  configSS << "Module : " << module << "\n";
116  const double refWl = Detector::GetInstance().GetFDetector().GetReferenceLambda();
117  configSS << "RefWavelength: " << refWl/nanometer << "nm\n";
118 
119  configSS << "Filter : T=";
120  bool first = true;
121  const TabulatedFunction& filtTrans = GetFilter().GetTransmittance();
122  for (unsigned int iF = 0; iF < filtTrans.GetNPoints(); ++iF)
123  if (filtTrans[iF].Y() != 0) {
124  configSS << (!first ? ", " : "") << filtTrans[iF].X()/nanometer << "nm:" << filtTrans[iF].Y();
125  first = false;
126  }
127  configSS << '\n';
128 
129  const bool hasCorrector = HasCorrectorRing();
130  configSS << "Corrector : " << (hasCorrector ? "yes" : "no");
131  if (hasCorrector) {
132  configSS << '\n'
133  << " R1=" << GetCorrector().GetInnerRadius()/m
134  << "m, R2=" << GetCorrector().GetOuterRadius()/m
135  << "m, Tm=" << GetCorrector().GetMeanLensThickness()/m << "m,\n"
136  << " RI=";
137  first = true;
139  for (unsigned int iR = 0; iR<lensRI.GetNPoints(); ++iR) {
140  if (lensRI[iR].Y() != 0) {
141  configSS << (!first ? ", " : "") << lensRI[iR].X()/nanometer << "nm:" << lensRI[iR].Y();
142  first = false;
143  }
144  }
145  configSS << ",\n T=";
146  first = true;
148  for (unsigned int iT = 0; iT<lensT.GetNPoints(); ++iT) {
149  if (lensT[iT].Y() != 0) {
150  configSS << (!first ? ", " : "") << lensT[iT].X()/nanometer << "nm:" << lensT[iT].Y();
151  first = false;
152  }
153  }
154  }
155  configSS << '\n';
156 
157  configSS << "Mirror : Radius=" << GetMirror().GetRadiusOfCurvature()/m << "m,\n";
158  configSS << " R=";
159  first = true;
160  const TabulatedFunction& mirRef = GetMirror().GetReflectivity();
161  for (unsigned int iM = 0; iM<mirRef.GetNPoints(); ++iM)
162  if (mirRef[iM].Y() != 0) {
163  configSS << (!first ? ", " : "") << mirRef[iM].X()/nanometer << "nm:" << mirRef[iM].Y();
164  first = false;
165  }
166  configSS << '\n';
167 
168  const fdet::Pixel& detPixel = GetPixel(1);
169  const fdet::Channel& detChannel = GetChannel(detPixel.GetChannelId()); // mapped channel
170  configSS << "Camera : Merc=" << GetCamera().GetMercedesEfficiency()
171  << ", R_f=" << GetCamera().GetRadiusFocal()
172  << ", H_m=" << GetCamera().GetMercedesHeight()
173  << ", dd_m=" << GetCamera().GetMercedesBase()
174  << ", nCols=" << GetCamera().GetLastColumn()-GetCamera().GetFirstColumn() + 1
175  << ", nRows=" << GetCamera().GetLastRow()-GetCamera().GetFirstRow() + 1
176  << ", Omega=" << GetCamera().GetEta()
177  << ", gain=" << detChannel.GetElectronicsGain()
178  << '\n';
179  const TabulatedFunction& qEff = detPixel.GetQEfficiency();
180  configSS << " Qeff=";
181  first = true;
182  for (unsigned int iF = 0; iF < qEff.GetNPoints(); ++iF) {
183  if (qEff[iF].Y() != 0) {
184  configSS << (!first ? ", " : "") << qEff[iF].X()/nanometer << "nm:" << qEff[iF].Y();
185  first = false;
186  }
187  }
188  fConfigSignatureStr = new string(configSS.str());
189  return *fConfigSignatureStr;
190  }
191 
192 
193  const Channel&
194  Telescope::GetChannel(const unsigned int channelId)
195  const
196  {
197  InternalChannelCollection::const_iterator cIt = fChannel.find(channelId);
198 
199  if (cIt != fChannel.end())
200 
201  return *cIt->second;
202 
203  else {
204  if (channelId < GetFirstChannelId() || channelId > GetLastChannelId()) {
205  ostringstream err;
206  err << "Channel Id=" << channelId << " is out of range; "
207  "min=" << GetFirstChannelId() << " max=" << GetLastChannelId();
208  ERROR(err);
209  throw NonExistentComponentException(err.str());
210  }
211 
212  const Channel* const ch = new Channel(fEyeId, fTelescopeId,
213  channelId,
216  fChannel[channelId] = ch;
217  return *ch;
218  }
219  }
220 
221 
222  const Channel&
223  Telescope::GetChannel(const fdet::Pixel& p)
224  const
225  {
226  return GetChannel(p.GetChannelId());
227  }
228 
229 
230  const Channel&
231  Telescope::GetChannel(const fevt::Pixel& p)
232  const
233  {
234  return GetChannel(GetPixel(p.GetId()).GetChannelId());
235  }
236 
237 
238  Point
239  Telescope::GetPosition()
240  const
241  {
242  if (!fPosition) {
243  const fdet::FDetector& theFDet = Detector::GetInstance().GetFDetector();
244  const fdet::Eye& realEye = theFDet.GetEye(GetParentPhysicalEyeId());
245  const CoordinateSystemPtr realEyeCoordinateSystem = realEye.GetEyeCoordinateSystem();
246  double bay_angle;
247  GetTelescopeData(bay_angle, "bay_angle", "telescope", "telescope bay angle");
248  double bay_distance;
249  GetTelescopeData(bay_distance, "bay_distance", "telescope", "telescope bay distance");
250  fPosition = new Point(bay_distance*cos(bay_angle), bay_distance*sin(bay_angle), 0, realEyeCoordinateSystem);
251  }
252  return *fPosition;
253  }
254 
255 
257  Telescope::GetTelescopeCoordinateSystem()
258  const
259  {
260  if (!fCoordinateSystem) {
261  const CoordinateSystemPtr telCS = LocalCoordinateSystem::Create(GetPosition());
262 
263  const double axisphi = GetAxis().GetPhi(telCS);
264 
265  const CoordinateSystemPtr auxCS =
266  CoordinateSystem::RotationZ(axisphi, telCS);
267 
268  const double theta = GetAxis().GetTheta(auxCS);
269 
270  // Set z-axis of the telescope CS = telescope axis
271  fCoordinateSystem = CoordinateSystem::RotationY(theta, auxCS);
272  }
273  return fCoordinateSystem;
274  }
275 
276 
277  bool
278  Telescope::HasCorrectorRing()
279  const
280  {
281  return GetDiaphragm().HasCorrectorRing();
282  }
283 
284 
285  double
286  Telescope::GetDiaphragmRadius()
287  const
288  {
289  return GetDiaphragm().GetRadius();
290  }
291 
292 
293  double
294  Telescope::GetDiaphragmArea()
295  const
296  {
297  return GetDiaphragm().GetArea();
298  }
299 
300 
301  const TimeStamp&
302  Telescope::GetCommissionTime()
303  const
304  {
305  if (!fCommissionTime) {
306  string timeString;
307  GetTelescopeData(timeString, "commission", "telescope", "telescope commission time");
308  fCommissionTime = new TimeStamp(boost::lexical_cast<UTCDateTime>(timeString).GetTimeStamp());
309  }
310 
311  return *fCommissionTime;
312  }
313 
314 
315  const TimeStamp&
316  Telescope::GetDecommissionTime()
317  const
318  {
319  if (!fDecommissionTime) {
320  string timeString;
321  GetTelescopeData(timeString, "decommission", "telescope", "telescope decommission time");
322  fDecommissionTime = new TimeStamp(boost::lexical_cast<UTCDateTime>(timeString).GetTimeStamp());
323  }
324 
325  return *fDecommissionTime;
326  }
327 
328 
329  const Pixel&
330  Telescope::GetPixel(const unsigned int pixelId)
331  const
332  {
333  if (pixelId < GetFirstPixelId() || pixelId > GetLastPixelId()) {
334  ostringstream err;
335  err << "Pixel Id=" << pixelId << " is out of range; "
336  << "min=" << GetFirstPixelId() << " max=" << GetLastPixelId();
337  ERROR(err);
338  throw NonExistentComponentException(err.str());
339  }
340 
341  const InternalPixelCollection::const_iterator pIt = fPixel.find(pixelId);
342 
343  if (pIt != fPixel.end())
344  return *pIt->second;
345  else {
346  Pixel* const pix = new Pixel(fEyeId, fTelescopeId, pixelId,
347  GetParentPhysicalEyeIdString(),
348  GetParentPhysicalIdString());
349  fPixel[pixelId] = pix;
350  return *pix;
351  }
352  }
353 
354 
355  const Pixel&
356  Telescope::GetPixel(const unsigned int row, const unsigned int col)
357  const
358  {
359  const unsigned int pixelId = GetLastRow()*(col-1) + row;
360  return GetPixel(pixelId);
361  }
362 
363 
364  const Diaphragm&
365  Telescope::GetDiaphragm()
366  const
367  {
368  if (!fDiaphragm)
369  fDiaphragm = new Diaphragm(fEyeId, fTelescopeId,
370  GetParentPhysicalEyeIdString(),
371  GetParentPhysicalIdString());
372  return *fDiaphragm;
373  }
374 
375 
376  const Mirror&
377  Telescope::GetMirror()
378  const
379  {
380  if (!fMirror)
381  fMirror = new Mirror(fEyeId, fTelescopeId,
382  GetParentPhysicalEyeIdString(),
383  GetParentPhysicalIdString());
384  return *fMirror;
385  }
386 
387 
388  const Filter&
389  Telescope::GetFilter()
390  const
391  {
392  if (!fFilter)
393  fFilter = new Filter(fEyeId, fTelescopeId,
394  GetParentPhysicalEyeIdString(),
395  GetParentPhysicalIdString());
396  return *fFilter;
397  }
398 
399 
400  const Corrector&
401  Telescope::GetCorrector()
402  const
403  {
404  if (!fCorrector)
405  fCorrector = new Corrector(fEyeId, fTelescopeId,
406  GetParentPhysicalEyeIdString(),
407  GetParentPhysicalIdString());
408  return *fCorrector;
409  }
410 
411 
412  const Camera&
413  Telescope::GetCamera()
414  const
415  {
416  if (!fCamera)
417  fCamera = new Camera(fEyeId, fTelescopeId,
418  GetParentPhysicalEyeIdString(),
419  GetParentPhysicalIdString());
420  return *fCamera;
421  }
422 
423 
424  void
425  Telescope::CacheTelescopePointing()
426  const
427  {
428  if (!fTelPointingId)
429  GetTelescopeData(fTelPointingId, "pointing", "telescope", "telescope optical axis default pointing id");
430 
431  if (!fTelPointingPhiMap) {
432  GetTelescopeData(fTelPointingPhiMap, "opticalAxisPhi", "telescope", "telescope optical axis phi");
433 
434  if (!fTelPointingElevationMap)
435  GetTelescopeData(fTelPointingElevationMap, "opticalAxisElevation", "telescope", "telescope optical axis elevation");
436 
437  if (IsVirtual()) {
438  // The axis phi and elevation are defined relative to the eye coordinate
439  // system. Here the values are transformed from physical eye coordinate
440  // system to the one of the virtual eye.
441  const fdet::FDetector& theFDet = Detector::GetInstance().GetFDetector();
442  const fdet::Eye& eye = theFDet.GetEye(fEyeId);
443  const fdet::Eye& realEye = theFDet.GetEye(GetParentPhysicalEyeId());
444  const CoordinateSystemPtr eyeCoordinateSystem = eye.GetEyeCoordinateSystem();
445  const CoordinateSystemPtr realEyeCoordinateSystem = realEye.GetEyeCoordinateSystem();
446 
447  for (PointingAngleSet::iterator phiIt = fTelPointingPhiMap->begin(),
448  end = fTelPointingPhiMap->end(); phiIt != end; ++phiIt) {
449  const PointingAngleSet::iterator elevationIt = fTelPointingElevationMap->find(phiIt->first);
450  if (elevationIt == fTelPointingElevationMap->end())
451  cout << "This should never happen! Found azimuth without corresponding elevation" << endl;
452 
453  const double azimuth = phiIt->second;
454  const double elevation = elevationIt->second;
455 
456  utl::Vector axis(1., kPi/2 - elevation, azimuth,
457  realEyeCoordinateSystem, Vector::kSpherical);
458  const double newAzimuth = axis.GetPhi(eyeCoordinateSystem);
459  const double newElevation = kPi/2 - axis.GetTheta(eyeCoordinateSystem);
460 
461  phiIt->second = newAzimuth;
462  elevationIt->second = newElevation;
463  }
464  } // end if IsVirtual
465  }
466  }
467 
468 
469  std::string
470  Telescope::GetTelescopePointingId()
471  const
472  {
473  if (!fTelPointingId)
474  CacheTelescopePointing();
475  return *fTelPointingId;
476  }
477 
478 
480  Telescope::GetTelescopePointingPhi()
481  const
482  {
483  if (!fTelPointingPhiMap)
484  CacheTelescopePointing();
485  return *fTelPointingPhiMap;
486  }
487 
488 
490  Telescope::GetTelescopePointingElevation()
491  const
492  {
493  if (!fTelPointingElevationMap)
494  CacheTelescopePointing();
495  return *fTelPointingElevationMap;
496  }
497 
498 
500  Telescope::GetAxis()
501  const
502  {
503  if (!fTelPointingId) {
504 
505  CacheTelescopePointing();
506 
507  if (fTelPointingElevationMap->find(*fTelPointingId) == fTelPointingElevationMap->end() ||
508  fTelPointingPhiMap->find(*fTelPointingId) == fTelPointingPhiMap->end()) {
509 
510  ostringstream err;
511  err << "Failure reading Fd telescope pointing (eye: " << fEyeId << ", tel: " << fTelescopeId << ") from telescope list XML: "
512  "the pointing that corresponds to the Id: \'" << *fTelPointingId << "\' does not exist. The config knows about: \n";
513  for (PointingAngleSet::const_iterator iPointing = fTelPointingElevationMap->begin();
514  iPointing != fTelPointingElevationMap->end(); ++iPointing)
515  err << " pointing id: \'" << iPointing->first << "\' at elevation: " << iPointing->second << "\n";
516  ERROR(err);
517  throw NonExistentComponentException(err.str());
518  }
519  } // end if we haven't read the pointing info yet
520 
521  if (!fAxis) {
522  const double azimuth = fTelPointingPhiMap->find(*fTelPointingId)->second;
523  const double elevation = fTelPointingElevationMap->find(*fTelPointingId)->second;
524 
525  const fdet::Eye& eye = Detector::GetInstance().GetFDetector().GetEye(fEyeId);
526  const CoordinateSystemPtr eyeCoordinateSystem = eye.GetEyeCoordinateSystem();
527  fAxis = new Vector(1, kPi/2 - elevation, azimuth,
528  eyeCoordinateSystem, Vector::kSpherical);
529  }
530 
531  return *fAxis;
532  }
533 
534 
535  void
536  Telescope::GenerateOutOfBorderPixels()
537  const
538  {
539  // top and bottom
540  const int rowInc = GetLastRow() - GetFirstRow() + 2;
541  for (unsigned int row = GetFirstRow() - 1; row <= GetLastRow() + 1; row += rowInc) {
542  // starting from first-1 and going to last+1 to include the corners
543  for (unsigned int col = GetFirstColumn()-1; col <= GetLastColumn()+1; ++col) {
544  const utl::Vector dir = GetCameraPixelDirection(row, col);
545  fOutBorderPixelsDir.push_back(dir);
546  }
547  }
548 
549  // left and right
550  const int colInc = GetLastColumn() - GetFirstColumn() + 2;
551  for (unsigned int col = GetFirstColumn() - 1; col <= GetLastColumn() + 1;
552  col += colInc) {
553  for (unsigned int row = GetFirstRow(); row <= GetLastRow(); ++row) {
554  const utl::Vector dir = GetCameraPixelDirection(row, col);
555  fOutBorderPixelsDir.push_back(dir);
556  }
557  }
558  }
559 
560 
562  Telescope::OutOfBorderPixelsBegin()
563  const
564  {
565  if (!fOutBorderPixelsDir.size())
566  GenerateOutOfBorderPixels();
567  return fOutBorderPixelsDir.begin();
568  }
569 
570 
572  Telescope::OutOfBorderPixelsEnd()
573  const
574  {
575  if (!fOutBorderPixelsDir.size())
576  GenerateOutOfBorderPixels();
577  return fOutBorderPixelsDir.end();
578  }
579 
580 
581  OFFLINE_DEFINE_CONST_ITERATOR_RANGE(OutOfBorderPixelsIterator, Telescope, OutOfBorderPixels)
582 
583 
584  double
585  Telescope::GetModelWavelengthDependence(const double wavelength)
586  const
587  {
588  const utl::TabulatedFunction& mirrorRefl = GetMirror().GetReflectivity();
589  const utl::TabulatedFunction& filterTrans = GetFilter().GetTransmittance();
590 
591  // mercedes reflections, when it potentially gets wavelength-dependent ...
592  const double mercEff = GetCamera().GetMercedesEfficiency();
593  const double meanRefl = GetCamera().GetMercedesReflections();
594  const double meanMercEff = pow(mercEff, meanRefl);
595 
596  const TabulatedFunction& Qeff = GetPixel(1).GetQEfficiency();
597 
598  double eff = mirrorRefl.Y(wavelength) * filterTrans.Y(wavelength) *
599  Qeff.Y(wavelength) *
600  meanMercEff; // for eventual future use
601 
602  if (HasCorrectorRing()) {
603  const utl::TabulatedFunction& lensTrans = GetCorrector().GetTransmittance();
604  const utl::TabulatedFunction& lensRI = GetCorrector().GetRefractiveIndex();
605  const double meanLensThickness = GetCorrector().GetMeanLensThickness();
606 
607  //# internal transmission thru 11mm, x=transmission thru 10mm
608 
609  if (lensTrans.Y(wavelength) == 0)
610  return 0;
611 
612  const double internal_absorption
613  = exp(meanLensThickness/(10.*mm)*log(lensTrans.Y(wavelength)));
614 
615  //# transmission at air - glass interface, normal incidence
616  // there is about 3.5% reflection from 0 to >20 deg
617  const double n = lensRI.Y(wavelength);
618  const double T_air_glass = 1 - Sqr((n-1)/(n+1));
619 
620  //# fraction of aperture covered by corrector ring
621  // effectively fracArea is larger, since shadowing by the camera is mostly in the hole of the lens
622  const double fracArea = 1 - Sqr(0.85/1.1);
623 
624  //# total effective transmittance (plus 2 glass-air interfaces)
625  const double lensTransmission = 1 + fracArea * (internal_absorption * Sqr(T_air_glass) - 1);
626  //# just internal transmittance
627  //const double lensTransmission = 1 + fracArea * (internal_absorption - 1);
628 
629  eff *= lensTransmission;
630  }
631  return eff;
632  }
633 
634 
635  double
636  Telescope::GetModelRelativeEfficiency(const double wavelength)
637  const
638  {
639  const double refWl = Detector::GetInstance().GetFDetector().GetReferenceLambda();
640  return GetModelWavelengthDependence(wavelength) / GetModelWavelengthDependence(refWl);
641  }
642 
643 
644  double
645  Telescope::GetModelMeanEfficiency(const string& configSignature, const double wavelength)
646  const
647  {
648  const CoordinateSystemPtr& telCS = GetTelescopeCoordinateSystem();
649  double meanPixelEff = 0;
650  int nPix = 0;
651  for (unsigned int i = GetFirstPixelId(); i <= GetLastPixelId(); ++i) {
652  ++nPix;
653  const Pixel& pixel = GetPixel(i);
654  const double cosTheta = pixel.GetDirection().GetCosTheta(telCS);
655  meanPixelEff += 1 / (pixel.GetSimulatedEndToEndCalibration(configSignature) * cosTheta);
656  }
657  meanPixelEff *= GetModelRelativeEfficiency(wavelength);
658  if (nPix)
659  meanPixelEff /= nPix;
660  return meanPixelEff;
661  }
662 
663 
664  double
665  Telescope::GetMeasuredRelativeEfficiency(const double wavelength)
666  const
667  {
668  const utl::TabulatedFunction& eff = GetMeasuredRelativeEfficiency();
669  return eff.Y(wavelength);
670  }
671 
672 
674  Telescope::GetMeasuredRelativeEfficiency()
675  const
676  {
677  if (!fMeasuredRelativeEfficiency) {
678  utl::TabulatedFunction measuredEff;
679  GetTelescopeData(measuredEff, "relativeResponse", "telescope", "telescope relative response");
680  const double refWl = Detector::GetInstance().GetFDetector().GetReferenceLambda();
681  fMeasuredRelativeEfficiency = new TabulatedFunction;
682  for (unsigned int i = 0; i < measuredEff.GetNPoints(); ++i) {
683  fMeasuredRelativeEfficiency->PushBack(measuredEff.GetX(i), measuredEff.GetY(i)/measuredEff.Y(refWl));
684  }
685  }
686  return *fMeasuredRelativeEfficiency;
687  }
688 
689 
690  // delegate these issues to the camera
691  unsigned int
692  Telescope::GetFirstRow()
693  const
694  {
695  return GetCamera().GetFirstRow();
696  }
697 
698 
699  unsigned int
700  Telescope::GetFirstColumn()
701  const
702  {
703  return GetCamera().GetFirstColumn();
704  }
705 
706 
707  unsigned int
708  Telescope::GetLastRow()
709  const
710  {
711  return GetCamera().GetLastRow();
712  }
713 
714 
715  unsigned int
716  Telescope::GetLastColumn()
717  const
718  {
719  return GetCamera().GetLastColumn();
720  }
721 
722 
723  unsigned int
724  Telescope::GetLastPixelId()
725  const
726  {
727  const Camera& cam = GetCamera();
728  return cam.GetLastColumn() * cam.GetLastRow();
729  }
730 
731 
732  double
733  Telescope::GetUpTimeFraction()
734  const
735  {
736  UpdateFdUpTime();
737  return fUpTimeFraction;
738  }
739 
740 
741  bool
742  Telescope::IsInAquisition()
743  const
744  {
745  UpdateFdUpTime();
746  return fUpTimeFraction > 0;
747  }
748 
749 
750  int
751  Telescope::GetDAQStatus()
752  const
753  {
754  UpdateFdUpTime();
755  return fStatus;
756  }
757 
758 
759  void
760  Telescope::UpdateFdUpTime()
761  const
762  {
763  if (fUpTimeValidityStamp.IsValid())
764  return;
765 
766  int startTime;
767  GetTelescopeData(startTime, "uptime_gpsStart", "telescope", "start validity telescope up time");
768  int endTime;
769  GetTelescopeData(endTime, "uptime_gpsStop", "telescope", "end validity telescope up time");
770  GetTelescopeData(fUpTimeFraction, "uptime_fraction", "telescope", "telescope up time fraction");
771  GetTelescopeData(fStatus, "status", "telescope", "telescope DAQ status");
772  fUpTimeValidityStamp.SetValidityInterval(startTime, endTime);
773  }
774 
775 
776  void
778  {
779  // Update any volatile telescope properties
780 
781  if (fIdOfParentPhysicalEye < 0) {
782  fIdOfParentPhysicalEye = 0; // default to being a physical telescope
783  fIdOfParentPhysicalTelescope = 0;
784  GetTelescopeData(fIdOfParentPhysicalEye, "fromEye", "virtualTelescope",
785  "parent eye id of virtual telescope");
786  GetTelescopeData(fIdOfParentPhysicalTelescope, "fromTelescope", "virtualTelescope",
787  "parent telescope id of virtual telescope");
788 
789  fIdOfParentPhysicalEyeString
790  = boost::lexical_cast<string>(fIdOfParentPhysicalEye);
791  fIdOfParentPhysicalTelescopeString
792  = boost::lexical_cast<string>(fIdOfParentPhysicalTelescope);
793  }
794 
795  delete fTelPointingId;
796  fTelPointingId = 0;
797 
798  delete fAxis;
799  fAxis = 0;
800 
801  delete fConfigSignature;
802  fConfigSignature = 0;
803  delete fConfigSignatureStr;
804  fConfigSignatureStr = 0;
805 
806  fCoordinateSystem.reset();
807  fOutBorderPixelsDir.clear();
808 
809  if (fDiaphragm)
810  fDiaphragm->Update();
811  if (fMirror)
812  fMirror->Update();
813  if (fFilter)
814  fFilter->Update();
815  if (fCorrector)
816  fCorrector->Update();
817  if (fCamera)
818  fCamera->Update();
819 
820  for (InternalChannelCollection::const_iterator cIt = fChannel.begin();
821  cIt != fChannel.end(); ++cIt)
822  cIt->second->Update();
823 
824  for (InternalPixelCollection::const_iterator pIt = fPixel.begin();
825  pIt != fPixel.end(); ++pIt)
826  pIt->second->Update();
827  }
828 
829 
830  void
831  Telescope::CachePixelCalibrations()
832  const
833  {
834  if (fCalibValidityStamp.IsValid())
835  return;
836 
837  vector<int> pixelStatus;
838  GetTelescopeData(pixelStatus, "status", "fd_calib", "pixel status");
839  const unsigned int statusSize = pixelStatus.size();
840 
841  // Delete all pixel calibs in the telescope if
842  // the validty interval has expired and
843  // get new calibration status
844  for (unsigned int i = GetFirstPixelId(); i <= GetLastPixelId(); ++i) {
845  const Pixel& pixel = GetPixel(i);
846  pixel.fWavelengthCalib.Clear();
847  if (i >= statusSize)
848  pixel.fPixelStatus = Pixel::eUnknown;
849  else
850  switch (pixelStatus[i]) {
851  case 0:
852  pixel.fPixelStatus = Pixel::eGood;
853  break;
854  case 1:
855  pixel.fPixelStatus = Pixel::eBadCalibration;
856  break;
857  case 2:
858  pixel.fPixelStatus = Pixel::eUnknown;
859  break;
860  default:
861  pixel.fPixelStatus = Pixel::eUnknown;
862  break;
863  }
864  }
865 
866  GetTelescopeData(fCalibMap, "pixel_calibs", "fd_calib", "pixel calibration");
867 
868  // Fill pixels from data retrieved above
869  for (unsigned int iPixelId = GetFirstPixelId();
870  iPixelId <= GetLastPixelId(); ++iPixelId) {
871 
872  if (fCalibMap.find(iPixelId) != fCalibMap.end()) {
873 
874  TabulatedFunction& pixCal = GetPixel(iPixelId).fWavelengthCalib;
875 
876  // done in this tortuous way because TabulatedFunction is so crap and
877  // has no sensible assignment operator
878  TabulatedFunction& cachedTabFunc = fCalibMap.find(iPixelId)->second;
879 
880  for (TabulatedFunction::Iterator tIt = cachedTabFunc.Begin();
881  tIt != cachedTabFunc.End(); ++tIt) {
882  pixCal.PushBack(tIt->X(), tIt->Y());
883  }
884 
885  pixCal.SetBoundaryTolerance(0.1*nanometer);
886 
887  } else {
888 
889  const string err = "Failure reading FD calibration from database";
890  ERROR(err);
892 
893  }
894  }
895 
896  int startTime;
897  GetTelescopeData(startTime, "start_time", "fd_calib", "pixel calibration start validity");
898  int endTime;
899  GetTelescopeData(endTime, "end_time", "fd_calib", "pixel calibration end validity");
900  fCalibValidityStamp.SetValidityInterval(startTime, endTime);
901  }
902 
903  void
904  Telescope::CachePixelOpticalEfficiencyCorrections()
905  const
906  {
907  if (fOpticalEfficiencyValidityStamp.IsValid())
908  return;
909 
910  vector<int> pixelStatus;
911  GetTelescopeData(pixelStatus, "status", "fd_optical_efficiency", "pixel status");
912  const unsigned int statusSize = pixelStatus.size();
913 
914  // Delete all pixel optical efficiency corrections in the telescope if
915  // the validty interval has expired and
916  // get new optical efficiency correction status
917  for (unsigned int i = GetFirstPixelId(); i <= GetLastPixelId(); ++i) {
918  const Pixel& pixel = GetPixel(i);
920  if (i >= statusSize)
921  pixel.fPixelOpticalEfficiencyStatus = Pixel::eUnknown;
922  else
923  switch (pixelStatus[i]) {
924  case 0:
925  pixel.fPixelOpticalEfficiencyStatus = Pixel::eGood;
926  break;
927  case 1:
928  pixel.fPixelOpticalEfficiencyStatus = Pixel::eBadCalibration;
929  break;
930  case 2:
931  pixel.fPixelOpticalEfficiencyStatus = Pixel::eUnknown;
932  break;
933  default:
934  pixel.fPixelOpticalEfficiencyStatus = Pixel::eUnknown;
935  break;
936  }
937  }
938 
939  GetTelescopeData(fOpticalEfficiencyMap, "pixel_optical_efficiency_corrections", "fd_optical_efficiency", "pixel optical efficiency correction");
940 
941  // Fill pixels from data retrieved above
942  for (unsigned int iPixelId = GetFirstPixelId();
943  iPixelId <= GetLastPixelId(); ++iPixelId) {
944 
945  if (fOpticalEfficiencyMap.find(iPixelId) != fOpticalEfficiencyMap.end()) {
946 
947  TabulatedFunction& pixOpticalEfficiency = GetPixel(iPixelId).fWavelengthOpticalEfficiencyCorrection;
948 
949  // done in this tortuous way because TabulatedFunction is so crap and
950  // has no sensible assignment operator
951  TabulatedFunction& cachedTabFunc = fOpticalEfficiencyMap.find(iPixelId)->second;
952 
953  for (TabulatedFunction::Iterator tIt = cachedTabFunc.Begin();
954  tIt != cachedTabFunc.End(); ++tIt) {
955  pixOpticalEfficiency.PushBack(tIt->X(), tIt->Y());
956  }
957 
958  pixOpticalEfficiency.SetBoundaryTolerance(0.1*nanometer);
959 
960  } else {
961 
962  const string err = "Failure reading FD optical efficiency correction from database";
963  ERROR(err);
965 
966  }
967  }
968 
969  int startTime;
970  GetTelescopeData(startTime, "start_time", "fd_optical_efficiency", "pixel optical efficiency start validity");
971  int endTime;
972  GetTelescopeData(endTime, "end_time", "fd_optical_efficiency", "pixel optical efficiency end validity");
973  fOpticalEfficiencyValidityStamp.SetValidityInterval(startTime, endTime);
974  }
975 
976  bool
977  Telescope::CachePixelCloudData()
978  const
979  {
980  // Get all relevant telescope data from the cloud DB in a single shot.
981  // The intention is that this function is not called during the normal
982  // detector Update, but only when Pixel cloud data are explicitly requested
983 
984  try {
985  const VManager& manager = Detector::GetInstance().
986  GetAManagerRegister().GetManager("ACloudSQLManager");
987 
988  vector<vector<int> > pixel_coverage_start_end;
989 
990  const VManager::IndexMap indexMap({
991  { "eyeId", GetParentPhysicalEyeIdString() },
992  { "telescopeId", GetParentPhysicalIdString() }
993  });
994 
995  const VManager::Status status =
996  manager.GetData(pixel_coverage_start_end, "cloud_pixel", "pixel_id, cloud_coverage, start_time, end_time", indexMap);
997 
998  // Exception if no data are found.
999  if (status == VManager::eNotFound || pixel_coverage_start_end.empty())
1000  return false;
1001 
1002  // check if all pixels are present
1003  set<int> pixelsInCloudDB;
1004  for (unsigned int i = 0; i < pixel_coverage_start_end.size(); ++i)
1005  pixelsInCloudDB.insert(pixel_coverage_start_end[i][0]);
1006 
1007  if ( pixelsInCloudDB.size() != GetLastPixelId()-GetFirstPixelId()+1 ) {
1008  ostringstream warn;
1009  warn << "no full telescope in cloud DB --> skip"
1010  << "(nPix=" << fPixel.size() << " nCloud="
1011  << pixelsInCloudDB.size() << ")";
1012  for (unsigned int i = 0; i < pixel_coverage_start_end.size(); ++i) {
1013  cout << " pixel Id: " << pixel_coverage_start_end[i][0]
1014  << " gpsStart: " << pixel_coverage_start_end[i][2]
1015  << " gpsStop: " << pixel_coverage_start_end[i][3]
1016  << endl;
1017  }
1018  WARNING(warn);
1019  return false;
1020  }
1021 
1022  // Unpack the cloud data from the manager. Warning: No further error checks!
1023  for (unsigned int i = 0; i < pixel_coverage_start_end.size(); ++i) {
1024  const int pixelId = pixel_coverage_start_end[i][0];
1025  const int cloudIndex = pixel_coverage_start_end[i][1];
1026  const int gpsStart = pixel_coverage_start_end[i][2];
1027  const int gpsEnd = pixel_coverage_start_end[i][3];
1028 
1029  const Pixel& pixel = GetPixel(pixelId);
1030  pixel.fCloudIndex = cloudIndex;
1031  pixel.fCloudValidityStamp.SetValidityInterval(gpsStart, gpsEnd);
1032  }
1033  } catch (NonExistentComponentException&) {
1034  return false;
1035  }
1036 
1037  return true;
1038  }
1039 
1040 
1046  utl::Vector
1047  Telescope::GetCameraPixelDirection(const unsigned int pixelId)
1048  const
1049  {
1050  if (pixelId < GetFirstPixelId() ||
1051  pixelId > GetLastPixelId()) {
1052  ostringstream err;
1053  err << "Pixel number " << pixelId << " "
1054  "is not in the Camera";
1055  ERROR(err);
1056  throw NonExistentComponentException(err.str());
1057  }
1058  const fdet::Pixel& pix = GetPixel(pixelId);
1059  return GetCameraPixelDirection(pix.GetRow(), pix.GetColumn());
1060  }
1061 
1062 
1067  utl::Vector
1068  Telescope::GetCameraPixelDirection(const unsigned int row, const unsigned int col)
1069  const
1070  {
1071  // algorithm to generate the pixel directions in the camera system
1072  // Developer note:
1073  // If you ever change this, make sure it works for a row/column of pixels
1074  // *beyond* the camera as well. This is used for the out-of-border-pixels!
1075  const double eta0 = GetCamera().GetEta();
1076  const double centerRow = GetCamera().GetCenterRow();
1077  const double centerColumn = GetCamera().GetCenterColumn();
1078  const double dOmega = eta0;
1079  const double dPhi = kSqrt3 * eta0/2;
1080 
1081  // const double oo = (col - ((row%2) ? 10. : 10.5)) * dOmega;
1082  // const double ph = (11.66667 - row) * dPhi;
1083 
1084  const double oo = (col - centerColumn + (row%2)/2.) * dOmega;
1085  const double ph = (centerRow - row) * dPhi;
1086 
1087  const double mcosOO = -cos(oo);
1088  const double z = mcosOO * cos(ph);
1089  const double x = mcosOO * sin(ph);
1090  const double y = sin(oo);
1091 
1092  return Vector(-x, -y, -z, GetTelescopeCoordinateSystem());
1093  }
1094 
1095 
1096  double
1097  Telescope::GetModelMinWavelength()
1098  const
1099  {
1100  double minWavelength = GetMirror().GetReflectivity().XFront();
1101  minWavelength = max(minWavelength, GetFilter().GetTransmittance().XFront());
1102  minWavelength = max(minWavelength, GetCorrector().GetTransmittance().XFront());
1103  minWavelength = max(minWavelength, GetPixel(1).GetQEfficiency().XFront()); // alternatively: loop over all pixels
1104  GetMeasuredRelativeEfficiency(); // just to initialize fMeasuredEfficiency
1105  minWavelength = max(minWavelength, fMeasuredRelativeEfficiency->XFront());
1106  return minWavelength;
1107  }
1108 
1109 
1110  double
1111  Telescope::GetModelMaxWavelength()
1112  const
1113  {
1114  double maxWavelength = GetMirror().GetReflectivity().XBack();
1115  maxWavelength = min(maxWavelength, GetFilter().GetTransmittance().XBack());
1116  maxWavelength = min(maxWavelength, GetCorrector().GetTransmittance().XBack());
1117  maxWavelength = min(maxWavelength, GetPixel(1).GetQEfficiency().XBack()); // alternatively: loop over all pixels
1118  GetMeasuredRelativeEfficiency(); // just to initialize fMeasuredEfficiency
1119  maxWavelength = min(maxWavelength, fMeasuredRelativeEfficiency->XBack());
1120  return maxWavelength;
1121  }
1122 
1123 
1124  // ###########################################################################
1125 
1126  template<typename T>
1127  inline
1128  const T&
1129  Telescope::GetTelescopeData(T*& requestedData,
1130  const string& property,
1131  const string& component,
1132  const string& errorMsg)
1133  const
1134  {
1135  if (!requestedData) {
1136  requestedData = new T;
1137  GetTelescopeData(*requestedData, property, component, errorMsg);
1138  }
1139  return *requestedData;
1140  }
1141 
1142 
1143  template<typename T>
1144  inline
1145  void
1146  Telescope::GetTelescopeData(T& requestedData,
1147  const string& property,
1148  const string& component,
1149  const string& errorMsg)
1150  const
1151  {
1152  const VManager& manager = Detector::GetInstance().GetFManagerRegister();
1153 
1154  VManager::IndexMap indexMap;
1155  // If this is a virtual telescope , fetch the information from the
1156  // real telescope that this virtual telescope resembles
1157  if (IsVirtual() && component != "virtualTelescope") {
1158  indexMap["eyeId"] = fIdOfParentPhysicalEyeString;
1159  indexMap["telescopeId"] = fIdOfParentPhysicalTelescopeString;
1160  } else {
1161  indexMap["eyeId"] = fEyeIdString;
1162  indexMap["telescopeId"] = fTelescopeIdString;
1163  }
1164 
1165  const VManager::Status status =
1166  manager.GetData(requestedData, property, component, indexMap);
1167 
1168  if (status == VManager::eNotFound) {
1169  ostringstream err;
1170  err << "Did not find requested component for " << errorMsg << "; "
1171  << VManager::QueryInfoMessage(property, component, indexMap);
1172  ERROR(err);
1173  throw NonExistentComponentException(err.str());
1174  }
1175  }
1176 
1177 }
PointingAngleSet * fTelPointingPhiMap
Hold the azimuth of the various possible telescope pointing directions.
const utl::Vector & GetDirection() const
pointing direction of this pixel
unsigned int GetFirstColumn() const
Class to compute MD5 checksum Based on the RSA C code, wrapped in an OO fashion.
Definition: Md5Sum.h:27
unsigned int GetNPoints() const
constexpr double mm
Definition: AugerUnits.h:113
constexpr T Sqr(const T &x)
Point object.
Definition: Point.h:32
utl::Point * fPosition
Description of the electronic channel for the 480 channels of the crate.
double GetPhi(const CoordinateSystemPtr &coordinateSystem) const
azimuth (phi) angle in spherical and cylindrical coordinates
Definition: BasicVector.h:254
double GetInnerRadius() const
Inner radius of the ring.
Definition: Corrector.cc:78
unsigned int GetLastColumn() const
std::string fTelescopeIdString
utl::TimeStamp * fCommissionTime
std::string * fConfigSignatureStr
std::string * fConfigSignature
unsigned int GetColumn(const unsigned int pixelid) const
const std::string & GetParentPhysicalEyeIdString() const
double GetTheta(const CoordinateSystemPtr &coordinateSystem) const
zenith (theta) angle in spherical coordinates
Definition: BasicVector.h:248
Class to hold collection (x,y) points and provide interpolation between them.
utl::TabulatedFunction fWavelengthOpticalEfficiencyCorrection
const Corrector & GetCorrector() const
Get the Corrector (corrector ring) object that belongs to the telescope.
double GetEta() const
Camera angular pixel spacing.
double GetCosTheta(const CoordinateSystemPtr &coordinateSystem) const
cos of zenith (theta) angle
Definition: BasicVector.h:251
const utl::TabulatedFunction & GetTransmittance() const
Average transmittance of the filter as a function of the wavelength.
std::string fEyeIdString
const std::string & GetConfigSignature(const std::string &module) const
double GetSimulatedEndToEndCalibration(const std::string &configSignature) const
for the simulated end-to-end calibration constant
Status fPixelOpticalEfficiencyStatus
const Channel & GetChannel(const unsigned int channelId) const
Get Channel by id, throw utl::NonExistentComponentException if n.a.
void Update(std::vector< double > &init, const std::vector< double > &res)
Definition: Util.h:100
const utl::TabulatedFunction & GetTransmittance() const
Transmittance as a function of the wavelength.
Definition: Corrector.cc:110
utl::TabulatedFunction fWavelengthCalib
double GetMercedesHeight() const
Height of the Mercedes.
det::ValidityStamp fCloudValidityStamp
Base class for exceptions trying to access non-existing components.
const Eye & GetEye(const unsigned int eyeId) const
Find eye by numerical Id.
Definition: FDetector.cc:68
Detector description interface for Eye-related data.
Definition: FDetector/Eye.h:45
Interface for detector managers.
Definition: VManager.h:115
void PushBack(const double x, const double y)
const std::string & GetConfigSignatureStr(const std::string &module) const
Diaphragm * fDiaphragm
Hold the diaphragm properties like radius and area.
double pow(const double x, const unsigned int i)
Camera * fCamera
Hold the camera properties like the radius of curvature, Mercedes geometry and efficiency as function...
Corrector * fCorrector
Hold the corrector ring properties like the transmitance as function of the wavelength.
double GetElectronicsGain() const
const Camera & GetCamera() const
Get the Camera object that belongs to the telescope.
std::string fConfigSignatureModule
Detector description interface for FDetector-related data.
Definition: FDetector.h:44
A TimeStamp holds GPS second and nanosecond for some event.
Definition: TimeStamp.h:110
bool HasCorrectorRing() const
flag for corrector ring presence
double GetMercedesEfficiency() const
Average efficiency of the Mercedes.
constexpr double nanometer
Definition: AugerUnits.h:102
const Pixel & GetPixel(const unsigned int pixelId) const
Get Pixel by id, throw utl::NonExistentComponentException if n.a.
Mirror * fMirror
Hold the mirror properties like the reflectivity as function of the wavelength.
unsigned int GetLastChannelId() const
virtual Status GetData(double &returnData, const std::string &componentProperty, const std::string &componentName, const IndexMap &componentIndex) const =0
boost::shared_ptr< const CoordinateTransformer > CoordinateSystemPtr
Shared pointer for coordinate systems.
double GetOuterRadius() const
Outer radius of the ring.
Definition: Corrector.cc:86
unsigned int GetId() const
Definition: FEvent/Pixel.h:31
#define max(a, b)
void SetValidityInterval(const utl::TimeStamp &start, const utl::TimeStamp &stop)
Set the start and end validity times.
Definition: ValidityStamp.h:40
PointingAngleSet * fTelPointingElevationMap
Hold the elevation of the various possible telescope pointing directions.
Fluorescence Detector Pixel event.
Definition: FEvent/Pixel.h:28
unsigned int GetChannelId() const
const utl::TabulatedFunction & GetQEfficiency() const
Average quantum efficiency as a function of the wavelength.
utl::CoordinateSystemPtr GetEyeCoordinateSystem() const
Returns the Eye Coordinate system.
constexpr double kPi
Definition: MathConstants.h:24
InternalPixelCollection fPixel
utl::TimeStamp * fDecommissionTime
constexpr double kSqrt3
Definition: MathConstants.h:31
std::vector< utl::Vector >::const_iterator OutOfBorderPixelsIterator
Description of a corrector ring.
Definition: Corrector.h:36
#define WARNING(message)
Macro for logging warning messages.
Definition: ErrorLogger.h:163
const utl::TabulatedFunction & GetReflectivity() const
Average reflectivity of the segments as a function of the wavelength.
unsigned int GetLastRow() const
if(dataRoot)
Definition: XXMLManager.h:1003
const double & GetY(const unsigned int idx) const
Status fPixelStatus
fTelescopeId(t.GetTelescopeId())
InternalChannelCollection fChannel
std::map< std::string, double > PointingAngleSet
unsigned int GetFirstChannelId() const
double GetRadiusOfCurvature() const
Average radius of curvature for the segments.
double GetMercedesBase() const
Base of the Mercedes.
const utl::TabulatedFunction & GetRefractiveIndex() const
Index of refraction as a funcction of the wavelength.
Definition: Corrector.cc:118
Detector description interface for Telescope-related data.
void SetBoundaryTolerance(const double tolerance)
const Filter & GetFilter() const
Get the filter that belongs to the telescope.
std::map< std::string, std::string > IndexMap
Definition: VManager.h:133
#define OFFLINE_DEFINE_CONST_ITERATOR_RANGE(_ConstIterator_, _Class_, _NamePrefix_)
Definition: IteratorRange.h:35
Description of a pixel.
Vector object.
Definition: Vector.h:30
const double & GetX(const unsigned int idx) const
Filter * fFilter
Hold the filter properties like the trasmitance as function of the wavelength.
const Mirror & GetMirror() const
Get the Mirror object that belongs to the telescope.
const std::string & GetParentPhysicalIdString() const
Description of the diaphragm.
Definition: Diaphragm.h:33
unsigned int fTelescopeId
Description of a filter.
double Y(const double x) const
Get or interpolate the Y value that corresponds to parameter x.
unsigned int GetRow(const unsigned int pixelid) const
double GetMeanLensThickness() const
Mean thickness of the lens.
Definition: Corrector.cc:94
double GetRadiusFocal() const
Radius of focal surface of the camera.
unsigned int GetFirstRow() const
#define ERROR(message)
Macro for logging error messages.
Definition: ErrorLogger.h:165
std::string * fTelPointingId
The id of the default telescope pointing.
constexpr double m
Definition: AugerUnits.h:121
Description of a mirror.
Status
Specifies success or (eventually) various possible failure modes.
Definition: VManager.h:127
Description of a camera.
utl::TabulatedFunction * fMeasuredRelativeEfficiency

, generated on Tue Sep 26 2023.