BaseList.cxx
1 #include "BaseList.h"
2 #include "AnitaVersion.h"
3 #include "TFile.h"
4 #include "TMath.h"
5 #include <cmath>
6 #include "TTree.h"
7 #include <unistd.h>
8 #include "TROOT.h"
9 #include "TKey.h"
10 #include "AnitaGeomTool.h"
11 
12 #include "TMarker.h"
13 #include "TText.h"
14 #include "TGraph.h"
15 
16 using namespace BaseList;
17 
18 
19 #ifndef DEG2RAD
20 #define DEG2RAD M_PI / 180
21 #endif
22 
23 
24 static void fillBases(std::vector<base> & baseList, int anita)
25 {
26 
27  TString fname;
28  // fname.Form("%s/share/anitaCalib/baseListA%d.root", getenv("ANITA_UTIL_INSTALL_DIR"), anita);
29  fname.Form("%s/share/anitaCalib/baseListRestrictedA%d.root", getenv("ANITA_UTIL_INSTALL_DIR"), anita);
30  TString oldPwd = gDirectory->GetPath();
31  TFile fbase(fname.Data());
32 
33  if (!fbase.IsOpen())
34  {
35  fprintf(stderr,"Couldn't load base list for ANITA %d. Sorry :(\n", anita);
36  return;
37  }
38 
39  //now load each tree
40 
41 
42  TIter iter(fbase.GetListOfKeys());
43  TKey *k;
44 
45  while ((k = (TKey *) iter()))
46  {
47 
48  //only read in TTrees
49  TClass * cl = gROOT->GetClass(k->GetClassName());
50  if (!cl->InheritsFrom("TTree")) continue;
51 
52  TTree * t = (TTree*) k->ReadObj();
53  TString source = t->GetName();
54 
55  std::string * str_name = 0;
56  double lon;
57  double lat;
58  double alt;
59 
60  t->SetBranchAddress("name",&str_name);
61  t->SetBranchAddress("fullLat",&lat);
62  t->SetBranchAddress("fullLong",&lon);
63  t->SetBranchAddress("alt",&alt);
64 
65  for (int i = 0; i < t->GetEntries(); i++)
66  {
67  t->GetEntry(i);
68  baseList.push_back(base(TString(*str_name), source, lat,lon,alt));
69  }
70  }
71  fbase.Close();
72  gDirectory->cd(oldPwd);
73 }
74 
75 
76 static void fillPaths(std::vector<path> & pathList, int anita)
77 {
78 
79  TString fname;
80  fname.Form("%s/share/anitaCalib/transientListRestrictedA%d.root", getenv("ANITA_UTIL_INSTALL_DIR"), anita);
81 
82  //see if we have the restricted list
83 
84  if (access(fname.Data(),R_OK))
85  {
86  fprintf(stderr,"Couldn't find restricted list for ANITA %d (%s). Will try to load unrestricted list. \n", anita, fname.Data());
87  fname.Form("%s/share/anitaCalib/transientListUnrestrictedA%d.root", getenv("ANITA_UTIL_INSTALL_DIR"), anita);
88  }
89  TString oldPwd = gDirectory->GetPath();
90 
91  TFile fpath(fname.Data());
92 
93  if (!fpath.IsOpen())
94  {
95  fprintf(stderr,"Couldn't find unrestricted list for ANITA %d (%s). Sorry :( \n", anita, fname.Data());
96  return;
97  }
98 
99  TIter iter(fpath.GetListOfKeys());
100  TKey *k;
101  while ((k = (TKey *) iter()))
102  {
103 
104  //only read in TTrees
105  TClass * cl = gROOT->GetClass(k->GetClassName());
106  if (!cl->InheritsFrom("TTree")) continue;
107 
108  TTree * t = (TTree*) k->ReadObj();
109 
110  TString source = t->GetName();
111  char callsign_buf[1024]; //
112  double lon;
113  double lat;
114  int alt = -1000;
115  int time;
116 
117  // Try to figure out whether or not this is a flight, from the tree name.
118  // At the time of writing, the flight trees are:
119  // AADTree, USAPFlightRestrTree, USAPFlightUnrestrTree
120  Int_t isFlight = 0;
121  if(source.Contains("AAD") || source.Contains("Flight")){
122  isFlight = 1;
123  }
124 
125  // well, I guess these trees are not as nicely normalized as the others.
126  t->SetBranchAddress("callSign",callsign_buf);
127  if (!t->GetBranch("fullLong")) //this tree has no position data. ignore it
128  {
129  continue ;
130  }
131 
132 
133  t->SetBranchAddress("fullLong",&lon);
134  t->SetBranchAddress("fullLat",&lat);
135  t->SetBranchAddress("timeUTC",&time);
136 
137  if (t->GetBranch("altitude")) // the traverse has no altitude data. Have no fear, we can fill it in ourselves.
138  {
139  t->SetBranchAddress("altitude",&alt);
140  }
141 
142  for (int i = 0; i < t->GetEntries(); i++)
143  {
144  t->GetEntry(i);
145  TString callsign = callsign_buf;
146 
147  // silly type conversion
148  UInt_t unsignedTime = time;
149  Double_t doubleAlt = alt;
150 
151  if(lat >= -90){ // skip unphysical error values
152 
153  path tempPath(TString(callsign.Data()), source, 1, &lat, &lon, &doubleAlt, &unsignedTime);
154  tempPath.isFlight = isFlight;
155  std::vector<path>::iterator it = std::find_if(pathList.begin(), pathList.end(), tempPath);
156  if(it != pathList.end()){
157  it->ts.push_back(tempPath.ts.at(0));
158  it->ps.push_back(tempPath.ps.at(0));
159  }
160  else{
161  pathList.push_back(tempPath);
162  }
163  // std::cout << lon << "\t" << lat << "\t" << callsign.Data() << std::endl;
164  }
165  }
166  }
167  fpath.Close();
168  gDirectory->cd(oldPwd);
169 
170 }
171 
172 // some annoying intermediate classes to be able to use magic statics
173 
174 static std::vector<base> no_bases;
175 static std::vector<path> no_paths;
176 
178 {
179  baselist_impl(int anita)
180  {
181  fillBases(bases, anita);
182  }
183  std::vector<base> bases;
184 
185 };
186 
188 {
189  pathlist_impl(int anita)
190  {
191  fillPaths(paths, anita);
192  }
193  std::vector<path> paths;
194 
195 };
196 
197 
198 
199 static std::vector<base> & bases()
200 {
201  if (AnitaVersion::get() == 2)
202  {
203  static baselist_impl bl(2);
204  return bl.bases;
205  }
206 
207  else if (AnitaVersion::get() == 3)
208  {
209  static baselist_impl bl(3);
210  return bl.bases;
211 
212  }
213  else if (AnitaVersion::get() == 4)
214  {
215  static baselist_impl bl(4);
216  return bl.bases;
217  }
218 
219 
220  fprintf(stderr,"Don't have bases for %d\n", AnitaVersion::get());
221  return no_bases;
222 }
223 
224 static std::vector<path> & paths()
225 {
226 
227  if (AnitaVersion::get() == 3)
228  {
229  static pathlist_impl pl(3);
230  return pl.paths;
231 
232  }
233  else if (AnitaVersion::get() == 4)
234  {
235  static pathlist_impl pl(4);
236  return pl.paths;
237  }
238 
239  fprintf(stderr,"Don't have paths for %d\n", AnitaVersion::get());
240  return no_paths;
241 }
242 
243 const BaseList::base& BaseList::getBase(UInt_t index){
244 
245  index = index < bases().size() ? index : 0;
246  return bases().at(index);
247 }
248 
249 const BaseList::path& BaseList::getPath(UInt_t index){
250 
251  index = index < paths().size() ? index : 0;
252  return paths().at(index);
253 }
254 
255 const BaseList::abstract_base& BaseList::getAbstractBase(UInt_t index){
256 
257  if (index > bases().size() + paths().size()) index = 0;
258  return index < bases().size() ? (const BaseList::abstract_base &) bases().at(index) : (const BaseList::abstract_base &) paths().at(index-bases().size());
259 }
260 
261 
262 size_t BaseList::getNumBases(){
263  return bases().size();
264 }
265 
266 size_t BaseList::getNumPaths() {
267  return paths().size();
268 }
269 
270 size_t BaseList::getNumAbstractBases(){
271  return bases().size() + paths().size();
272 }
273 
274 
275 
276 void BaseList::makeBaseList()
277 {
278  makeEmptyBaseList();
279  fillBases(bases(), AnitaVersion::get());
280  fillPaths(paths(), AnitaVersion::get());
281 }
282 
283 
284 void BaseList::makeEmptyBaseList()
285 {
286  bases().clear(); //DESTROY ALL THE BASES FOR SOME REASON
287 }
288 
289 
290 BaseList::path::path(const TString & name, TString & source,
291  int npoints, const double * lat, const double * lon,
292  const double * alt, const unsigned * time)
293 
294 
295  : name(name) , dataSource(source), ts(time, time + npoints)
296 {
297 
298  ps.reserve(npoints);
299  for (int i = 0; i < npoints; i++)
300  {
301  ps.push_back(AntarcticCoord(AntarcticCoord::WGS84, lat[i], lon[i], alt[i]));
302 // ps[i].to(AntarcticCoord::CARTESIAN); //save as cartesian
303  }
304 
305 
306 }
307 
308 
309 AntarcticCoord BaseList::path::getPosition(unsigned t) const {
310 
311  if (!isValid(t)) return AntarcticCoord(AntarcticCoord::WGS84, 90, 0, 0); // North pole is about as far as we can get!
312 
313  // Components to interpolate with.
314  int l = TMath::BinarySearch(ts.size(), & ts [0], t);
315  int u = l + 1;
316  double low_frac = double(t - ts [l]) / double(ts [u] - ts [l]); // Lower fractional interpolative step.
317  AntarcticCoord cl = ps [l]; // Components in WGS84 coordinates.
318  AntarcticCoord cu = ps [u];
319  // For later use; in case either altitude component isn't defined or negative. RampdemReader convention has longitude listed first, then latitude.
320  double gndl = RampdemReader::SurfaceAboveGeoid(cl.y, cl.x, RampdemReader::surface);
321  double gndu = RampdemReader::SurfaceAboveGeoid(cu.y, cu.x, RampdemReader::surface);
322  double clz = (!cl.z || cl.z < 0) ? gndl : cl.z;
323  double cuz = (!cu.z || cu.z < 0) ? gndu : cu.z;
324  // Geodesic trajectories should correspond to the surface of the WGS84 geoid, so we should zero out z-components.
325  cl.z = 0, cu.z = 0;
326 
327  // Cast vectors into Cartesian.
328  cl.to(AntarcticCoord::CARTESIAN), cu.to(AntarcticCoord::CARTESIAN);
329 
330  // Assuring a geodesic trajectory between components by transforming to a great circle trajectory, we will linearly interpolate a unit auxiliary sphere
331  // in polar gnomonic projection (X, Y, Z) between Cartesian points (x, y, z) ((X, Y, Z) = abs(b / z) * (x / a, y / a, z / b), a = semi-major axis, b = semi-minor axis).
332  // The unit auxiliary sphere is assuming (x / a)^2 + (y / a)^2 + (z / b)^2 = 1.
333  // See (https://www.uwgb.edu/dutchs/structge/sphproj.htm) and (http://mathworld.wolfram.com/StereographicProjection.html) for details.
334  TVector3 g = low_frac * std::abs(1 / cu.z) * cu.v() + (1 - low_frac) * std::abs(1 / cl.z) * cl.v();
335  g(0) *= GEOID_MIN / GEOID_MAX; // GEOID_MIN and GEOID_MAX defined in "AnitaGeomTool.h".
336  g(1) *= GEOID_MIN / GEOID_MAX;
337 
338  // Now to invert the transform, back to Cartesian ((x, y, z) = (1 / R) * (a * X, a * Y, b * Z), R = sqrt(X^2 + Y^2 + Z^2)).
339  AntarcticCoord c = AntarcticCoord(g.Unit());
340  c.x *= GEOID_MAX;
341  c.y *= GEOID_MAX;
342  c.z *= GEOID_MIN;
343 
344  // Return this Cartesian vector back in stereographic.
345  if (clz == gndl && cuz == gndu) {
346 
347  c.to(AntarcticCoord::WGS84);
348  double gnd = RampdemReader::SurfaceAboveGeoid(c.y, c.x, RampdemReader::surface);
349  c.to(AntarcticCoord::STEREOGRAPHIC);
350  c.z = gnd; // What we place as the stereographic z-component is actually the WGS84 component, altitude.
351  } else {
352 
353  c.to(AntarcticCoord::STEREOGRAPHIC);
354  c.z = low_frac * cuz + (1 - low_frac) * clz;
355  }
356 
357  return c;
358 
359 // // Interpolated components.
360 // // For latitude, we first linearly interpolate radial distance in the gnomonic plane (R(lat) = sgn(lat) * (b / a) * cot(lat)).
361 // // Dividing out constants, we just end up linearly interpolating cot(lat), then inverting it to get our latitude.
362 // double cot_lat = low_frac / tan(DEG2RAD * cu.x) + (1 - low_frac) / tan(DEG2RAD * cl.x);
363 // double lat = -90 - atan(cot_lat) / DEG2RAD; // -pi / 2 <= lat < 0 in southern hemispheroid.
364 // // For longitude, we need to unwrap our upper input longitude to insure that shorter longitude difference is taken.
365 // double lonl = cl.y, lonu = cu.y;
366 // if (lonu - lonl < -180) lonu += 360;
367 // else if (lonu - lonl > 180) lonu -= 360;
368 // double lon = low_frac * lonu + (1 - low_frac) * lonl;
369 // lon = fmod(lon + 180, 360) - 180; // Rewrapping longitude. Perhaps unneccessary if going to stereographic projection anyway?
370 // // For altitude, when we don't have an input altitude we use surface value instead.
371 // // If both input altitudes end up being replaced by surface values, we evaluate interpolated altitude at the surface with the interpolated latitude and longitude.
372 // double gndl = RampdemReader::SurfaceAboveGeoid(cl.y, cl.x, RampdemReader::surface);
373 // double gndu = RampdemReader::SurfaceAboveGeoid(cu.y, cu.x, RampdemReader::surface);
374 // double altl = (!cl.z || cl.z < 0) ? gndl : cl.z;
375 // double altu = (!cu.z || cu.z < 0) ? gndu : cu.z;
376 // double alt = (altl == gndl && altu == gndu) ? RampdemReader::SurfaceAboveGeoid(lon, lat, RampdemReader::surface) : low_frac * altu + (1 - low_frac) * altl;
377 //
378 // // Construct the interpolated component vector, then return it stereographically projected.
379 // AntarcticCoord c(AntarcticCoord::WGS84, lat, lon, alt);
380 // c.to(AntarcticCoord::STEREOGRAPHIC);
381 //
382 // return c;
383 
384 // // The orignial code.
385 // AntarcticCoord cl = ps[l].as(AntarcticCoord::CARTESIAN);
386 // AntarcticCoord cu = ps[u].as(AntarcticCoord::CARTESIAN);
387 // double x = low_frac * cl.x + (1-low_frac) * cu.x;
388 // double y = low_frac * cl.y + (1-low_frac) * cu.y;
389 // double z = low_frac * cl.z + (1-low_frac) * cu.z;
390 //
391 // if (z < 0) { //this means the altitude was not actually filled in (e.g for example a traverse), so we need to retrieve it ourselves...
392 //
393 // AntarcticCoord c(AntarcticCoord::CARTESIAN,x,y,0);
394 // c.to(AntarcticCoord::STEREOGRAPHIC);
395 //
396 // c.z = RampdemReader::SurfaceAboveGeoidEN(c.x,c.y, RampdemReader::surface);
397 // return c;
398 // } else {
399 // AntarcticCoord c(AntarcticCoord::WGS84, lat, lon, alt);
400 // c.to(AntarcticCoord::STEREOGRAPHIC);
401 // return c;
402 // }
403 //
404 // //otherwise, we need to fix the altitude
405 //
406 // double alt = low_frac * ps[l].as(AntarcticCoord::WGS84).z + (1-low_frac)*ps[u].as(AntarcticCoord::WGS84).z;
407 //
408 // AntarcticCoord c(AntarcticCoord::WGS84, lat, lon, alt);
409 // AntarcticCoord c(AntarcticCoord::CARTESIAN,x,y,z);
410 // c.to(AntarcticCoord::STEREOGRAPHIC); //this is usually what we'll need
411 // c.z = alt; //fix altitude
412 // return c;
413 }
414 
415 
416 
417 
418 int BaseList::findBases(const char * query, std::vector<int> * matches, bool include_paths)
419 {
420 
421  int first_found = -1;
422  for (unsigned i = 0; i < include_paths ? getNumAbstractBases() : getNumBases(); i++)
423  {
424  const abstract_base & a = getAbstractBase(i);
425 
426  if (strcasestr(a.getName(), query))
427  {
428  if (first_found < 0) first_found = i;
429  if (matches)
430  {
431  matches->push_back(i);
432  }
433  else break;
434  }
435  }
436  return first_found;
437 
438 }
439 
440 void BaseList::base::Draw(const char * opt) const
441 {
442  AntarcticCoord stereo = position.as(AntarcticCoord::STEREOGRAPHIC);
443 
444  if (strchr(opt,'p'))
445  {
446  TMarker * m = new TMarker(stereo.x, stereo.y, 2);
447  m->SetBit(kCanDelete);
448  m->AppendPad();
449  }
450 
451  if (strchr(opt,'t'))
452  {
453  TText * t = new TText(stereo.x + 50e3, stereo.y, getName());
454  t->SetBit(kCanDelete);
455  t->AppendPad();
456  }
457 
458 }
459 
460 void BaseList::path::Draw(const char * opt) const
461 {
462 
463  if (strchr(opt,'p') || strchr(opt,'l'))
464  {
465  TGraph * g = new TGraph;
466  for (unsigned i = 0; i < ps.size(); i++)
467  {
468  AntarcticCoord stereo = ps[i].as(AntarcticCoord::STEREOGRAPHIC);
469  g->SetPoint(i, stereo.x, stereo.y);
470  }
471 
472  g->SetBit(kCanDelete);
473  g->AppendPad(opt);
474  }
475 
476  if (strchr(opt,'t'))
477  {
478  AntarcticCoord stereo = ps[0].as(AntarcticCoord::STEREOGRAPHIC);
479  TText * t = new TText(stereo.x+50e3, stereo.y, getName());
480  t->SetBit(kCanDelete);
481  t->AppendPad();
482  }
483 
484 }
static Double_t SurfaceAboveGeoid(Double_t longitude, Double_t latitude, RampdemReader::dataSet=rampdem)
std::vector< AntarcticCoord > ps
true for flight, false for traverse
Definition: BaseList.h:65