PlotGOES.cc
Go to the documentation of this file.
1 
9 // Keep all further includes in the header
10 #include "PlotGOES.h"
11 
12 using namespace PlotGOESNS;
13 
15 {}
16 
18 {}
19 
22 {
23  const std::string bTopStr("PlotGOES");
24  const utl::Branch bTop(fwk::CentralConfig::GetInstance()->GetTopBranch(bTopStr));
25 
26  if (!bTop) {
27  FATAL("Could not find branch " + bTopStr);
28  return eFailure;
29  }
30 
31  bTop.GetChild("TimeStart").GetData(fTimeStart);
32  bTop.GetChild("TimeFinish").GetData(fTimeFinish);
33  fTimeStep = bTop.GetChild("TimeStep").Get<double>();
34 
35  bTop.GetChild("PlotFormats").GetData(fPlotFormats);
36 
37  {
38  std::string str;
39  bTop.GetChild("PlotFDFOV").GetData(str);
40  if (str == "on")
41  fPlotFDFOV = true;
42  else if (str == "off")
43  fPlotFDFOV = false;
44  else {
45  FATAL("Unrecognised setting \"" + str + "\" to <PlotFDFOV>");
46  return eFailure;
47  }
48  }
49 
50  return eSuccess;
51 }
52 
55 {
56  // Prepare ROOT plotting
57  //
58 
59  // For paper
60  const int textFont(132); // Times new roman
61  const double textSize(0.06);
62  const bool showTitle(true);
63 
64  // For poster
65  // const int textFont(42); // Helvetica
66  // const double textSize(0.055);
67  // const bool showTitle(false);
68 
69  gStyle->SetTitleFont(textFont, ""); // Hist title
70  gStyle->SetTitleFont(textFont, "XYZ"); // Axis titles
71  gStyle->SetLabelFont(textFont, "XYZ");
72 
73  const int canvasW(800);
74  const int canvasH(600);
75 
76  // Set margins
77  const double marginH(0.12); // 0.1 is default
78  const double marginW((1 - (1 - 2*marginH)*canvasH/canvasW)/2); // Square plot
79  gStyle->SetPadLeftMargin(marginW);
80  gStyle->SetPadRightMargin(marginW);
81  gStyle->SetPadTopMargin(marginH);
82  gStyle->SetPadBottomMargin(marginH);
83 
84  // Palette
85  {
86  const int nStops(6); // Points between which to linearly interpolate
87  const int nColours(255); // True depth of palette
88 
89  double stops[nStops] = {0.0, 0.2, 0.4, 0.6, 0.8, 1.0};
90  double r[nStops] = {1.0, 1.0, 0.9, 0.8, 0.7, 0.6};
91  double g[nStops] = {1.0, 1.0, 0.9, 0.8, 0.7, 0.6};
92  double b[nStops] = {1.0, 1.0, 0.9, 0.8, 0.7, 0.6};
93 
94  TColor::CreateGradientColorTable(nStops, stops, r, g, b, nColours);
95  }
96 
97  // Constants
98  //
99 
100  // The standard point on tile 19H which we tend to use as an origin when drawing the array
101  const double augerEasting(440000.0);
102  const double augerNorthing(6060000.0);
103 
104  // Use https://maps.auger.org.ar to select station IDs around the edge
105  // This list starts at the top left (near Coihueco) and goes clockwise
106  int nStations(35);
107  unsigned int edgeIDs[nStations] = {
108  1047, 1041, 1051, 979, 985, 1549, 1506, 1483, 1501, 1131,
109  1133, 1145, 1148, 1666, 1668, 1676, 790, 1175, 768, 496,
110  572, 531, 462, 476, 321, 379, 388, 377, 1260, 1247,
111  945, 618, 1314, 615, 787
112  };
113 
114  det::Detector& det( det::Detector::GetInstance() );
115  const sdet::SDetector& sdet( det.GetSDetector() );
116  const fdet::FDetector& fdet( det.GetFDetector() );
118 
119  // Choose a time when all the stations in the above list exist
120  det.Update( utl::UTCDateTime(2020, 1, 1).GetTimeStamp() );
121 
122  // Fill a graph with the locations of the stations, wrapped back around
123  TGraph sdArray;
124  double pair[2];
125  for (int iSDID(0); iSDID < nStations; ++iSDID) {
126  utl::Point p( sdet.GetStation(edgeIDs[iSDID]).GetPosition() );
128 
129  const double utmX((utmP.GetEasting() - augerEasting)/utl::km);
130  const double utmY((utmP.GetNorthing() - augerNorthing)/utl::km);
131 
132  if (iSDID == 0) {
133  pair[0] = utmX;
134  pair[1] = utmY;
135  }
136 
137  sdArray.SetPoint(sdArray.GetN(), utmX, utmY);
138  }
139  sdArray.SetPoint(sdArray.GetN(), pair[0], pair[1]);
140 
141  // Fill a vector with polygons showing the outline of the FD telescope fields of view
142  std::vector<TPolyLine> telFOVs;
143  for (auto itEye( fdet.EyesBegin() ); itEye != fdet.EyesEnd(); ++itEye) {
144  // Skip HEAT, virtual eyes, etc
145  if (itEye->GetId() > 4)
146  continue;
147 
148  const utl::CoordinateSystemPtr eyeCS( itEye->GetEyeCoordinateSystem() );
149 
150  /* Because each telescope has an independent pointing which isn't guaranteed to be
151  exactly 30 degrees apart from the previous, we need to smooth things over a little bit by
152  forcing each telescope FOV after the first one to overlap with the previous one. The
153  consequence of not doing this is that some borders between telescopes clearly have two
154  lines that are very close together, which clutters the plot */
155  bool usePrevPoint(false);
156  utl::UTMPoint prevC(0.0, 0.0, 0.0, wgs84); // unset
157 
158  for (auto itTel( itEye->TelescopesBegin() ); itTel != itEye->TelescopesEnd(); ++itTel) {
159  const utl::Vector& telAxis( itTel->GetAxis() );
160  const utl::Point& telBase( itTel->GetPosition() );
161 
162  const utl::UTMPoint ptB(telBase, wgs84);
163 
164  // Positive and negative rotations about a vertical Z axis (think right-hand rule)
167 
168  const utl::Vector ptBtoPtA(rotN*telAxis);
169  utl::UTMPoint ptA(telBase + 20*utl::km*ptBtoPtA, wgs84);
170 
171  const utl::Vector ptBtoPtC(rotP*telAxis);
172  const utl::UTMPoint ptC(telBase + 20*utl::km*ptBtoPtC, wgs84);
173 
174  // Swap out point A for the previous point C, if this isn't the first telescope for an eye
175  if (usePrevPoint)
176  ptA = prevC;
177  else
178  usePrevPoint = true;
179  prevC = ptC;
180 
181  const int v(3); // 3 vertices for an open triangle
182 
183  double xPts[v] = {
184  ptA.GetEasting() ,
185  ptB.GetEasting() ,
186  ptC.GetEasting()
187  };
188 
189  double yPts[v] = {
190  ptA.GetNorthing() ,
191  ptB.GetNorthing() ,
192  ptC.GetNorthing()
193  };
194 
195  // Reference to relative origin; convert to km
196  for (int i(0); i < v; ++i) {
197  xPts[i] = (xPts[i] - augerEasting)/utl::km;
198  yPts[i] = (yPts[i] - augerNorthing)/utl::km;
199  } // i
200 
201  telFOVs.emplace_back(v, xPts, yPts);
202  } // itTel
203  } // itEye
204 
205  //
206 
207  // Loop over times
208  for (utl::TimeStamp detTime(fTimeStart); detTime <= fTimeFinish; detTime += fTimeStep) {
209  det.Update(detTime);
210  const atm::GOESDB& goesdb( det.GetAtmosphere().GetGOESDB() );
211 
212  // Always get these again, as they may become time-dependent in future
213  const double pixW( goesdb.GetPixelWidthEasting() );
214  const double pixH( goesdb.GetPixelWidthNorthing() );
215  const unsigned int nPix( goesdb.GetNumberOfPixels() );
216 
217  TH2Poly hist;
218  bool noData(false);
219 
220  // This technique is to get all the cloud probabilities at once, because we intend to plot all of them. If your application does not need to get *all* the cloud probabilities, then you should probably loop over your desired pixels and get them individually
221 
223  try {
224  pixMap = goesdb.GetAllCloudProbabilities();
225  }
227  continue;
228  }
229 
230  for (unsigned int iPix(0); iPix < nPix; ++iPix) {
231  double prob(0.0);
232  try {
233  // Cloud prob is 0, 0.2, 0.4, 0.6, or 0.8! These are lower bounds
234  prob = pixMap.at(iPix);
235 
236  // Add 0.1 so the val is in the middle of the 20%-wide region it represents
237  prob += 0.1;
238  }
239  catch (std::out_of_range&) {
240  noData = true;
241  break;
242  }
243 
244  const utl::UTMPoint& pix( goesdb.GetPixelCenter(iPix) );
245  const double pixX( pix.GetEasting() );
246  const double pixY( pix.GetNorthing() );
247 
248  const int v(5); // 5 vertices for a closed rectangle
249 
250  double xPts[v] = {
251  pixX - pixW / 2.0 ,
252  pixX + pixW / 2.0 ,
253  pixX + pixW / 2.0 ,
254  pixX - pixW / 2.0 ,
255  pixX - pixW / 2.0
256  };
257 
258  double yPts[v] = {
259  pixY + pixH / 2.0 ,
260  pixY + pixH / 2.0 ,
261  pixY - pixH / 2.0 ,
262  pixY - pixH / 2.0 ,
263  pixY + pixH / 2.0
264  };
265 
266  // Reference to relative origin; convert to km
267  for (int i(0); i < v; ++i) {
268  xPts[i] = (xPts[i] - augerEasting)/utl::km;
269  yPts[i] = (yPts[i] - augerNorthing)/utl::km;
270  } // i
271 
272  // Add the bin and set its value
273  hist.SetBinContent(hist.AddBin(v, xPts, yPts), prob);
274  } // iPix
275 
276  if (noData) {
277  std::ostringstream status;
278  status << "Missing pixel data at " << detTime;
279  WARNING(status);
280  continue;
281  }
282 
283  // Add extra points outside of range, so we can SetRangeUser() further out
284  hist.AddBin(-10, -10, -10, -10);
285  hist.AddBin(85, 85, 85, 85);
286 
287  // Plotting
288  {
289  TCanvas canv("canv", "", canvasW, canvasH);
290  canv.SetCanvasSize(canvasW, canvasH);
291 
292  {
293  std::ostringstream conv;
294  conv << utl::UTCDateTime(detTime);
295  hist.SetTitle( conv.str().c_str() );
296  }
297 
298  hist.SetStats(false);
299  hist.SetTitleSize(1.1*textSize);
300 
301  if (!showTitle)
302  hist.SetTitle("");
303 
304  TAxis* histX( hist.GetXaxis() );
305  TAxis* histY( hist.GetYaxis() );
306  TAxis* histZ( hist.GetZaxis() );
307 
308  histX->SetTitle("Relative easting (km)");
309  histX->SetTitleOffset(0.95);
310  histX->CenterTitle();
311  histX->SetTitleSize(textSize);
312  histX->SetLabelSize(textSize);
313  histX->SetRangeUser(-5, 75);
314 
315  histY->SetTitle("Relative northing (km)");
316  histY->SetTitleOffset(0.95);
317  histY->CenterTitle();
318  histY->SetTitleSize(textSize);
319  histY->SetLabelSize(textSize);
320  histY->SetRangeUser(0, 80);
321 
322  histZ->SetTitle("Cloud probability");
323  histZ->SetTitleOffset(0.95);
324  histZ->CenterTitle();
325  histZ->SetTitleSize(textSize);
326  histZ->SetLabelSize(textSize);
327  histZ->RotateTitle();
328  histZ->SetRangeUser(0, 1);
329  histZ->SetNdivisions(1005);
330 
331  // There are only 5 levels, so clip to those
332  hist.SetContour(5);
333 
334  hist.Draw("colz");
335 
336  sdArray.SetLineColor(1);
337  sdArray.SetLineWidth(2);
338  sdArray.Draw("same l");
339 
340  if (fPlotFDFOV) {
341  for (auto itFOV( telFOVs.begin() ); itFOV != telFOVs.end(); ++itFOV) {
342  itFOV->SetLineColor(1);
343  itFOV->SetLineStyle(2);
344  itFOV->Draw();
345  } // itFOV
346  }
347 
348  for (auto itF(fPlotFormats.begin()); itF != fPlotFormats.end(); ++itF) {
349  std::ostringstream conv;
350  conv << detTime.GetGPSSecond() << "." << *itF;
351  canv.SaveAs( conv.str().c_str() );
352  } // itF
353  }
354  }
355 
356  return eSuccess;
357 }
358 
361 {
362  return eSuccess;
363 }
utl::TimeInterval fTimeStep
Definition: PlotGOES.h:75
void Update(const utl::TimeStamp &time, const bool invData=true, const bool invComp=true, const bool forceRadio=false)
Update detector: deletes currently constructed stations and sets new time.
Definition: Detector.cc:179
Point object.
Definition: Point.h:32
Report success to RunController.
Definition: VModule.h:62
constexpr double km
Definition: AugerUnits.h:125
Detector description interface for GOES cloud data.
Definition: GOESDB.h:29
Class to hold and convert a point in geodetic coordinates.
Definition: UTMPoint.h:40
#define FATAL(message)
Macro for logging fatal messages.
Definition: ErrorLogger.h:167
Branch GetChild(const std::string &childName) const
Get child of this Branch by child name.
Definition: Branch.cc:211
double GetNorthing() const
Get the northing.
Definition: UTMPoint.h:206
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
const atm::Atmosphere & GetAtmosphere() const
Definition: Detector.h:113
T Get() const
Definition: Branch.h:271
utl::TimeStamp fTimeStart
Definition: PlotGOES.h:73
boost::shared_ptr< const CoordinateTransformer > CoordinateSystemPtr
Shared pointer for coordinate systems.
Class representing a document branch.
Definition: Branch.h:107
Exception to use in case requested data not found in the database with detailed printout.
Reference ellipsoids for UTM transformations.
const GOESDB & GetGOESDB() const
low-level interface to the cloud information from the GOES database
Top of the hierarchy of the detector description interface.
Definition: Detector.h:81
const sdet::SDetector & GetSDetector() const
Definition: Detector.cc:119
double GetEasting() const
Get the easting.
Definition: UTMPoint.h:209
static const ReferenceEllipsoid & GetWGS84()
Get the auger standard ellipsoid: wgs84.
const fdet::FDetector & GetFDetector() const
Definition: Detector.cc:131
std::map< unsigned int, double > ProbabilityMap
Definition: GOESDB.h:32
constexpr double degree
std::vector< std::string > fPlotFormats
Definition: PlotGOES.h:77
constexpr double g
Definition: AugerUnits.h:200
#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
virtual ~PlotGOES()
Definition: PlotGOES.cc:17
ResultFlag
Flag returned by module methods to the RunController.
Definition: VModule.h:60
utl::TimeStamp fTimeFinish
Definition: PlotGOES.h:74
static CentralConfig * GetInstance()
Use this the first time you get an instance of central configuration.
Vector object.
Definition: Vector.h:30
Detector description interface for SDetector-related data.
Definition: SDetector.h:42
Report failure to RunController, causing RunController to terminate execution.
Definition: VModule.h:64
static TransformationMatrix RotationZ(const double angle)
Rotation by angle about Z axis.
fwk::VModule::ResultFlag Finish()
Finish: invoked at end of the run (NOT end of the event)
Definition: PlotGOES.cc:360
fwk::VModule::ResultFlag Run(evt::Event &event)
Run: invoked once per event.
Definition: PlotGOES.cc:54
fwk::VModule::ResultFlag Init()
Initialize: invoked at beginning of run (NOT beginning of event)
Definition: PlotGOES.cc:21

, generated on Tue Sep 26 2023.