UsefulAdu5Pat.cxx
1 
9 #include "AnitaVersion.h"
10 #include "UsefulAdu5Pat.h"
11 #include <iostream>
12 #include "TTimeStamp.h"
13 #include "AnitaDataset.h"
14 #include "FFTtools.h"
15 
16 #ifdef ENABLE_VECTORIZE
17 #include "vectormath_trig.h"
18 #define VEC_T double
19 #define VEC_N 4
20 #define VEC Vec4d
21 #define IVEC Vec4i
22 #endif
23 
24 
25 
26 ClassImp(UsefulAdu5Pat);
27 
28 UsefulAdu5Pat::UsefulAdu5Pat()
29  : Adu5Pat()
30 {
31  //Default Constructor
32  fIncludeGroupDelay=0;
33  pitch = AnitaStaticAdu5Offsets::pitch;
34  roll = AnitaStaticAdu5Offsets::roll;
35  heading += AnitaStaticAdu5Offsets::heading;
36  longitude = 0;
37  latitude = 0;
38  altitude = 0;
39  fThetaWave=0;
40  fPhiWave=0;
41  fSourceLongitude=-1;
42  fSourceLatitude=-1;
43  fBalloonCoords[0]=0;
44  fBalloonCoords[1]=0;
45  fBalloonCoords[2]=0;
46  fBalloonHeight=0;
47  fBalloonLonCache=0;
48  fBalloonLatCache=0;
49  fBalloonAltCache=0;
50  fDebug = false;
51  fInterpSurfaceAboveGeoid = false;
52  fSurfaceCloseEnoughIter = 1.0;
53  setMaxLoopIterations();
54 }
55 
56 UsefulAdu5Pat::UsefulAdu5Pat(const Adu5Pat *patPtr)
57  : Adu5Pat(*patPtr)
58 {
59  fIncludeGroupDelay=0;
60 
61  pitch = AnitaStaticAdu5Offsets::pitch;
62  roll = AnitaStaticAdu5Offsets::roll;
63  heading += AnitaStaticAdu5Offsets::heading;
64 
65  if(heading>=360){
66  heading-=360;
67  }
68  if(heading<0){
69  heading+=360;
70  }
71  // fThetaWave=0;
72  // fPhiWave=0;
73  // fSourceLongitude=-1;
74  // fSourceLatitude=-1;
75  fBalloonLonCache=0;
76  fBalloonLatCache=0;
77  fBalloonAltCache=0;
78  fDebug = false;
79  fInterpSurfaceAboveGeoid = false;
80  fSurfaceCloseEnoughIter = 1.0;
83 }
84 
85 
87 {
88 
89 }
90 
91 
93 
94  if(longitude!=fBalloonLonCache ||
95  latitude!=fBalloonLatCache ||
96  altitude!=fBalloonAltCache){
97 
98  AnitaGeomTool::Instance()->getCartesianCoords(latitude,
99  longitude,
100  altitude,
101  fBalloonCoords);
102  fBalloonPos.SetXYZ(fBalloonCoords[0],fBalloonCoords[1],fBalloonCoords[2]);
103  fBalloonTheta=fBalloonPos.Theta();
104  fBalloonPhi=fBalloonPos.Phi();
105  if(fBalloonPhi<0){
106  fBalloonPhi+=TMath::TwoPi();
107  }
108  fBalloonHeight=fBalloonPos.Mag();
109 
110  fBalloonLonCache = longitude;
111  fBalloonLatCache = latitude;
112  fBalloonAltCache = altitude;
113  }
114 }
115 
116 
117 void UsefulAdu5Pat::getThetaAndPhiWaveWillySeavey(Double_t &thetaWave, Double_t &phiWave)
118 {
122  thetaWave, phiWave);
123 }
124 
125 void UsefulAdu5Pat::getThetaAndPhiWaveWillyBorehole(Double_t &thetaWave,Double_t &phiWave)
126 {
130  thetaWave, phiWave);
131 }
132 
133 
134 void UsefulAdu5Pat::getThetaAndPhiWaveTaylorDome(Double_t &thetaWave, Double_t &phiWave)
135 {
136  return getThetaAndPhiWave(AnitaLocations::LONGITUDE_TD,
137  AnitaLocations::LATITUDE_TD,
138  AnitaLocations::ALTITUDE_TD,
139  thetaWave, phiWave);
140 }
141 
142 
143 int UsefulAdu5Pat::getSourceLonAndLatAltZero(Double_t phiWave, Double_t thetaWave, Double_t &sourceLon, Double_t &sourceLat) {
144  return getSourceLonAndLatAtDesiredAlt(phiWave, thetaWave, sourceLon, sourceLat, 0.0);
145 }
146 
147 
148 
149 
150 
151 void UsefulAdu5Pat::accountForPitchAndRollInPhiWaveThetaWave(Double_t& phiWave, Double_t& thetaWave) const {
152 
153 
155  Double_t tempPhiWave=phiWave;
156  Double_t tempThetaWave=TMath::PiOver2()-thetaWave;
157 
158  TVector3 rollAxis = geom->fRollRotationAxis;
159  TVector3 pitchAxis = geom->fPitchRotationAxis;
160 
161  TVector3 arbDir;
162  arbDir.SetMagThetaPhi(1,tempThetaWave,-1*tempPhiWave);
163 
164  arbDir.Rotate(heading*TMath::DegToRad(),geom->fHeadingRotationAxis);
165  rollAxis.Rotate((heading)*TMath::DegToRad(),geom->fHeadingRotationAxis);
166  pitchAxis.Rotate((heading)*TMath::DegToRad(),geom->fHeadingRotationAxis);
167 
168  arbDir.Rotate(pitch*TMath::DegToRad(),pitchAxis);
169  rollAxis.Rotate(pitch*TMath::DegToRad(),pitchAxis);
170  arbDir.Rotate(roll*TMath::DegToRad(),rollAxis);//roll and pitch
171 
172  tempPhiWave=arbDir.Phi();
173  if(tempPhiWave>TMath::TwoPi()) {
174  tempPhiWave-=TMath::TwoPi();
175  }
176  if(tempPhiWave<0) {
177  tempPhiWave+=TMath::TwoPi();
178  }
179  tempThetaWave=arbDir.Theta();
180 
181 
182  thetaWave = tempThetaWave;
183  phiWave = tempPhiWave;
184 }
185 
186 
187 
188 
189 int UsefulAdu5Pat::getSourceLonAndLatAtDesiredAlt(Double_t phiWave, Double_t thetaWave, Double_t &sourceLon, Double_t &sourceLat, Double_t desiredAlt = 0.0)
190 {
191 
192  if(fPhiWave!=phiWave) fPhiWave=phiWave;
193  if(fThetaWave!=thetaWave) fThetaWave=thetaWave;
194 
195  Double_t tempPhiWave=phiWave;
196  Double_t tempThetaWave=thetaWave;
197 
198  if(heading>=0 && heading<=360) {
199  accountForPitchAndRollInPhiWaveThetaWave(tempPhiWave, tempThetaWave);
200  }
201  else{
202  std::cerr << "Error in " << __PRETTY_FUNCTION__ << ": Bad heading = " << heading << std::endl;
203  sourceLon = -9999;
204  sourceLat = -9999;
205  desiredAlt = -9999;
206  return -1;
207  }
208 
210  Double_t reBalloon=geom->getDistanceToCentreOfEarth(latitude)+desiredAlt; // ACG mod
211  Double_t re=reBalloon;
212  Double_t nextRe=re;
213  Double_t reh=reBalloon+altitude;
214 
215  const Double_t sintw = TMath::Sin(tempThetaWave);
216  const Double_t costw = TMath::Cos(tempThetaWave);
217 
218  do {
219  //Okay so effectively what we do here is switch to cartesian coords with the balloon at RE_balloon + altitude and then try to find where the line at thetaWave cuts the Earth's surface.
220  //This is iterative because the Earth is cruel and isn't flat, and I couldn't be bothered to work out how to do it more elegantly.
221  re=nextRe;
222 
223  Double_t sqrtArg(re*re-reh*reh*sintw*sintw);
224  if(sqrtArg<0) {
225  // No solution possible
226  sourceLon = -9999;
227  sourceLat = -9999;
228  desiredAlt = -9999;
229  return 0;
230  }
231  Double_t L=reh*costw - TMath::Sqrt(sqrtArg);
232  Double_t sinThetaL=L*sintw/re;
233  Double_t sourceTheta=TMath::ASin(sinThetaL);
234 
235  fSourcePos.SetXYZ(0, 0, re);
236  fSourcePos.RotateY(sourceTheta);
237  fSourcePos.RotateZ(-1*tempPhiWave);
238 
239  fSourcePos.RotateY(fBalloonTheta);
240  fSourcePos.RotateZ(fBalloonPhi);
241 
242  Double_t sourceVec[3];
243  fSourcePos.GetXYZ(sourceVec);
244 
245  Double_t sourceAlt;
246  geom->getLatLonAltFromCartesian(sourceVec,sourceLat,sourceLon,sourceAlt);
247  nextRe=geom->getDistanceToCentreOfEarth(sourceLat);
248 
249  } while(TMath::Abs(nextRe-re)>1);
250 
251  return 1;
252 }
253 
254 
255 
256 int UsefulAdu5Pat::getSourceLonAndLatAtAlt(Double_t phiWave, Double_t thetaWave, Double_t &sourceLon, Double_t &sourceLat,Double_t &sourceAltitude) {
257 
258  if(fPhiWave!=phiWave) fPhiWave=phiWave;
259  if(fThetaWave!=thetaWave) fThetaWave=thetaWave;
260  return getSourceLonAndLatAtAlt2(phiWave, thetaWave, sourceLon, sourceLat, sourceAltitude, fMaxLoopIterations, &fSourcePos);
261 }
262 
263 
264 
265 
266 // Version of getSourceLonAndLatAtAlt which does not update fThetaWave, fPhiWave, fSourcePos (clears up the output of data race thread safety checks)
267 int UsefulAdu5Pat::getSourceLonAndLatAtAlt2(Double_t phiWave, Double_t thetaWave, Double_t &sourceLon, Double_t &sourceLat,Double_t &sourceAltitude, Int_t maxLoopIterations, TVector3* sourcePosOptional) const
268 {
269  // TGraph* grTest = NULL;
270  // if(fDebug){
271  // grTests.push_back(new TGraph());
272  // grTest = grTests.back();
273  // grTest->SetName(TString::Format("grTest_%lu", grTests.size()-1));
274  // grTest->SetTitle(TString::Format("%luth Graph, #theta = %4.2lf", grTests.size()-1, -thetaWave*TMath::RadToDeg()));
275  // }
276 
277  Double_t tempPhiWave = phiWave;
278  Double_t tempThetaWave = thetaWave;
279  TVector3 sourcePosIfNoOptionalPtrPassed;
280 
281  TVector3& sourcePos = sourcePosOptional ? *sourcePosOptional : sourcePosIfNoOptionalPtrPassed;
282 
283  if(heading>=0 && heading<=360) {
284  accountForPitchAndRollInPhiWaveThetaWave(tempPhiWave, tempThetaWave);
285  }
286  else{
287  std::cerr << "Error in " << __PRETTY_FUNCTION__ << ": Bad heading = " << heading << std::endl;
288  sourceLon = -9999;
289  sourceLat = -9999;
290  sourceAltitude = -9999;
291  return -1;
292  }
293 
295 
296  Double_t reBalloon = geom->getDistanceToCentreOfEarth(latitude); // reBalloon, radius of earth where balloon is
297  Double_t chosenAlt = surfaceAboveGeoid(longitude,latitude); // ChosenAlt, the ice surface below balloon
298  Double_t re = reBalloon+chosenAlt; // re, radius of earth at balloon plus ice height above geoid
299  Double_t nextRe = re; // nextRe, radius of geoid+ice at next iteration
300  Double_t reh = reBalloon+altitude; // reh, radius of earth at balloon plus balloon altitude
301 
302  if(fDebug){
303  std::cout << "balloon: lat = " << latitude << ", lon = " << longitude << ", re = " << reBalloon+chosenAlt << ", surface elevation = " << chosenAlt << std::endl;
304  // std::cout << "phiWave = " << phiWave << ", thetaWave = " << thetaWave << ", fPhiWave = " << fPhiWave << ", fThetaWave = " << fThetaWave << std::endl;
305  std::cout << "heading = " << heading << ", pitch = " << pitch << ", roll = " << roll << std::endl;
306  }
307 
308  int inTheLoop = 0;
309  Double_t lastButOneRe = 0; // in case we get stuck in the while loop - this is a bad method and needs to be improved!
310  Double_t lastButTwoRe = 0; // in case we get stuck in the while loop - this is a bad method and needs to be improved!
311  Double_t lastButThreeRe = 0; // in case we get stuck in the while loop - this is a bad method and needs to be improved!
312  Double_t lastButFourRe = 0; // in case we get stuck in the while loop - this is a bad method and needs to be improved!
313 
314  // default for maxLoopIterations is -1, which means use the member variable value.
315  // here, we force this...
316  maxLoopIterations = maxLoopIterations < 0 ? fMaxLoopIterations : maxLoopIterations;
317 
318  const double deltaReCloseEnough = fSurfaceCloseEnoughIter;
319  Bool_t ocillatingAroundSolution = false;
320  Bool_t tooManyLoops = false;
321 
322  const Double_t sintw = TMath::Sin(tempThetaWave);
323  const Double_t costw = TMath::Cos(tempThetaWave);
324 
325  do {
331  if(inTheLoop>3){lastButFourRe = lastButThreeRe;}
332  if(inTheLoop>2){lastButThreeRe = lastButTwoRe;}
333  if(inTheLoop>1){lastButTwoRe = lastButOneRe;}
334  if(inTheLoop>0){lastButOneRe = re;}
335  re = nextRe;
336  inTheLoop++;
337 
338  Double_t sqrtArg = re*re - reh*reh*sintw*sintw;
339  // clearly we're going for some kind of trigonometric relation here
340  // re = radius of earth under balloon + chosenAlt
341  // reh = radius of earth under balloon + balloon altitude
342  // sintw = sin(thetaWave)
343 
344  if(sqrtArg<0) {
345  if(fDebug){
346  std::cerr << "Error in " << __PRETTY_FUNCTION__ << ", no solution possible! Returning 0\n";
347  // std::cerr << "re = " << re << ", reh = " << reh << ", sintw = " << sintw << ", tempThetaWave = " << tempThetaWave << "\n";
348  // std::cerr << "re*re = " << re*re << ", reh*reh*sintw*sintw = " << reh*reh*sintw*sintw << "\n";
349  // std::cerr << "sqrtArg = " << sqrtArg << std::endl;
350  }
351  return 0;
352  }
353 
354  Double_t L = reh*costw - TMath::Sqrt(sqrtArg);
355  Double_t sinThetaL = L*sintw/re;
356  Double_t sourceTheta = TMath::ASin(sinThetaL);
357 
358  sourcePos.SetXYZ(0, 0, re); // Put the source at the south pole at height, re
359 
360  /* Move the source to near the balloon? */
361  sourcePos.RotateY(sourceTheta);
362  sourcePos.RotateZ(-1*tempPhiWave);
363  sourcePos.RotateY(fBalloonTheta);
364  sourcePos.RotateZ(fBalloonPhi);
365 
366  Double_t sourceVec[3];
367  sourcePos.GetXYZ(sourceVec);
368  Double_t sourceAlt;
369  geom->getLatLonAltFromCartesian(sourceVec,sourceLat,sourceLon,sourceAlt);
370  chosenAlt = surfaceAboveGeoid(sourceLon,sourceLat);
371  nextRe = geom->getDistanceToCentreOfEarth(sourceLat) + chosenAlt;
372 
373 
374  // if(fDebug && grTest){
375  // grTest->SetPoint(grTest->GetN(), inTheLoop, nextRe-re);
376  // }
377 
378  if(fDebug && maxLoopIterations - inTheLoop < 3){
379  std::cerr << "Debug in " << __PRETTY_FUNCTION__ << ": inTheLoop = " << inTheLoop
380  << ", sourceLon = " << sourceLon << ", sourceLat = " << sourceLat << ", sourceAlt = " << sourceAlt
381  << ", re = " << re << ", lastButOneRe-re = " << lastButOneRe-re << ", lastButTwoRe-re = " << lastButTwoRe-re
382  << ", lastButThreeRe-re = " << lastButThreeRe-re << ", lastButFourRe-re = " << lastButFourRe-re
383  << ", TMath::Abs(lastButOneRe-nextRe) = " << TMath::Abs(lastButOneRe-nextRe) << "\n";
384  }
385 
386  const int numLoopChecks = 4;
387  const double deltaRes[numLoopChecks] = {TMath::Abs(lastButOneRe-nextRe),
388  TMath::Abs(lastButTwoRe-nextRe),
389  TMath::Abs(lastButThreeRe-nextRe),
390  TMath::Abs(lastButFourRe-nextRe)};
391  int smallestRe = TMath::LocMin(numLoopChecks, deltaRes);
392  if(deltaRes[smallestRe] <= deltaReCloseEnough){
393  if(fDebug){
394  const double Res[numLoopChecks] = {lastButOneRe, lastButTwoRe, lastButThreeRe, lastButFourRe};
395  const char* whichRe[numLoopChecks] = {"lastButOneRe", "lastButTwoRe", "lastButThreeRe", "lastButFourRe"};
396  std::cerr << "Breaking out due to small enough difference over several loop iterations, nextRe = "
397  << nextRe << ", " << whichRe[smallestRe] << " = " << Res[smallestRe]
398  << ", abs(" << whichRe[smallestRe] << " - nextRe) = " << deltaRes[smallestRe] << std::endl;
399  }
400  ocillatingAroundSolution = true;
401  break;
402  }
403 
404 
405  if(inTheLoop>maxLoopIterations){
406  if(fDebug){
407  std::cerr << "Debug in " << __PRETTY_FUNCTION__ << ": Breaking out due to too many loop iterations! inTheLoop > " << maxLoopIterations
408  << " (default value, fMaxLoopIterations = " << fMaxLoopIterations << ")" << std::endl;
409  }
410  tooManyLoops=1;
411  break;
412  }
413 
414  } while(TMath::Abs(nextRe-re)>deltaReCloseEnough);
415 
416  sourceAltitude = chosenAlt;
417 
418  if(ocillatingAroundSolution){
419  // It converged although the loop oscillated around the true solution a bit,
420  // so let's trust this one and not overwrite the source lon/lat/alt with error values
421  return 2;
422  }
423  else if(tooManyLoops){
424  // We couldn't get to the true answer in quite a lot of iterations, so we probably don't trust the answer in this case.
425  sourceLon = -9999;
426  sourceLat = -9999;
427  sourceAltitude = -9999;
428  return 3;
429  }
430  else if(TMath::Nint(chosenAlt)==-9999){
431  // I think this means the source altitude is off the edge of the Rampdem map, so it's probably nonsense
432  sourceLon = -9999;
433  sourceLat = -9999;
434  sourceAltitude = -9999;
435  return 4;
436  }
437  else{
438  // It converged on the first attempt
439  return 1;
440  }
441 }
442 
443 
444 
445 
446 
447 
448 
449 
450 
451 
452 int UsefulAdu5Pat::traceBackToContinent3(Double_t phiWave, Double_t thetaWave,
453  Double_t * lon, Double_t * lat, Double_t *alt,
454  Double_t * theta_adjustment_required) const{
455 
456  double deltaAlt = 0;
457  bool wantBestPosition = theta_adjustment_required ? true : false;
458 
459  if(theta_adjustment_required){
460  *theta_adjustment_required = 0;
461  }
462 
463  int success = getSourceLonAndLatAtAlt3(phiWave, thetaWave, *lon, *lat, *alt, &deltaAlt, wantBestPosition);
464 
465  if(success==3 && wantBestPosition){ // then we need to figure out
466 
467  double newThetaWave, newPhiWave;
468  getThetaAndPhiWave2(*lon, *lat, *alt, newThetaWave, newPhiWave);
469 
470  // a la Cosmin's: defined to be positive if the adjustment is downwards, which is positive.
471  *theta_adjustment_required = newThetaWave - thetaWave;
472  }
473 
474  return success;
475 }
476 
477 
478 
479 
480 
481 
482 
483 int UsefulAdu5Pat::getSourceLonAndLatAtAlt3(Double_t phiWave, Double_t thetaWave,
484  Double_t &sourceLon, Double_t &sourceLat,Double_t &sourceAltitude,
485  double* deltaAltIfNoIntersectection, bool returnBestPositionIfNoIntersection) const
486 {
487 
488  if(thetaWave <= 0){
489  if(fDebug){
490  std::cout << "No chance! " << std::endl;
491  }
492  return 0;
493  }
494 
495  // TGraph* grTest = NULL;
496  // if(fDebug){
497  // grTests.push_back(new TGraph());
498  // grTest = grTests.back();
499  // grTest->SetName(TString::Format("grTest_%lu", grTests.size()-1));
500  // grTest->SetTitle(TString::Format("%luth Graph, #theta = %4.2lf", grTests.size()-1, -thetaWave*TMath::RadToDeg()));
501  // }
502 
503  // the hard problem, is to find the unit vector from the payload...
504  // Following that vector to the ground is relatively easy...
505  const TVector3 unitVector = getUnitVectorAlongThetaWavePhiWave(thetaWave, phiWave);
506 
508  Double_t anitaPosition[3];
509  geom->getCartesianCoords(latitude, longitude, altitude, anitaPosition);
510  const TVector3 anitaVector(anitaPosition);
511 
512 
513  // here we scale the delta vector so that it's vertical component is 1m.
514  // This significantly reduces the number of iterations required for near horizon events
515  const TVector3 inwardNorm = anitaVector.Unit();
516  const double scale = TMath::Abs(1./inwardNorm.Dot(unitVector));
517  const TVector3 deltaVector = scale*unitVector;
518  // const TVector3 deltaVector = unitVector;
519 
520 
521  double minAbsDeltaAlt = DBL_MAX;
522  double bestLon, bestLat, bestAlt, bestDeltaAlt;
523 
524  int best_i = -1;
525  int best_last_i = -1;
526 
527  for(int precise=0; precise <= 1; precise++){
528 
529  int i = precise == 0 ? 0 : best_last_i;
530  int last_i = 0;
531 
532  double deltaAlt = DBL_MAX;
533  double firstDeltaAlt = DBL_MAX;
534 
535  while(deltaAlt <= firstDeltaAlt){
536 
537  const TVector3 rayVector = i*deltaVector + anitaPosition; // ray position
538  double rayLat, rayLon, rayAlt;
539  double rayPosition[3];
540  rayVector.GetXYZ(rayPosition);
541  geom->getLatLonAltFromCartesian(rayPosition, rayLat, rayLon, rayAlt);
542 
543  double surfaceAlt = surfaceAboveGeoid(rayLon, rayLat);
544  deltaAlt = rayAlt - surfaceAlt;
545 
546  if(firstDeltaAlt==DBL_MAX){
547  firstDeltaAlt = deltaAlt;
548  }
549 
550  // if(fDebug && grTest){
551  // grTest->SetPoint(grTest->GetN(), i, deltaAlt);
552  // }
553 
554 
555  // is this the best we've done so far?
556  double absDeltaAlt = fabs(deltaAlt);
557  if(absDeltaAlt < minAbsDeltaAlt){
558  bestLon = rayLon;
559  bestLat = rayLat;
560  bestAlt = surfaceAlt;
561  bestDeltaAlt = deltaAlt;
562  best_i = i;
563  best_last_i = last_i;
564  minAbsDeltaAlt = absDeltaAlt;
565  }
566 
567 
568  if(deltaAlt <= 0){
569  // Then we cut the surface at this iteration...
570  // Presumably, with a small step size since deltaAlt approached 0.
571  // There's no need to explore the minimum, so set the values and return.
572  sourceLon = rayLon;
573  sourceLat = rayLat;
574  sourceAltitude = surfaceAlt;
575  if(deltaAltIfNoIntersectection){
576  *deltaAltIfNoIntersectection = deltaAlt;
577  }
578  return 1; // this means successfully cut the surface!
579  }
580 
581  last_i = i;
582  i++;
583  if(precise==0){ // if we're a long way off, take bigger steps...
584  if(deltaAlt > 10000){
585  i+=1999;
586  }
587  if(deltaAlt > 5000){
588  i+=999;
589  }
590  else if(deltaAlt > 1000){
591  i+=499;
592  }
593  else if(deltaAlt > 500){
594  i+=99;
595  }
596  else if(deltaAlt > 100){
597  i+=19;
598  }
599  }
600  }
601  }
602 
603  if(returnBestPositionIfNoIntersection){
604  sourceLon = bestLon;
605  sourceLat = bestLat;
606  sourceAltitude = bestAlt;
607  }
608  else{
609  sourceLon = -9999;
610  sourceLat = -9999;
611  sourceAltitude = -9999;
612  }
613  if(deltaAltIfNoIntersectection){
614  *deltaAltIfNoIntersectection = bestDeltaAlt;
615  }
616 
617  // if(grTest){
618  // grTest->SetTitle(TString::Format("%s: best_i = %d", grTest->GetTitle(), best_i));
619  // }
620  return 3;
621 }
622 
623 
624 
625 
635 TVector3 UsefulAdu5Pat::getUnitVectorAlongThetaWavePhiWave(double thetaWave, double phiWave) const{
636 
638  Double_t anitaPosition[3];
639  geom->getCartesianCoords(latitude, longitude, altitude, anitaPosition);
640 
641  // now I need to get a vector pointing along thetaWave and phiWave from ANITA's position
642  // so let's get theta and phi wave from an arbitrary position close to the payload,
643  // evaluate theta/phi expected and rotate that vector around ANITA's position
644  // until it aligns with phiWave...
645 
646  // This is just due north of ANITA
647  double testLon = longitude;
648  double testLat = latitude - 0.1; // if ANITA could be at the north pole, this might not work
649  double testAlt = altitude;
650 
651  double testThetaWave, testPhiWave;
652  getThetaAndPhiWave2(testLon, testLat, testAlt, testThetaWave, testPhiWave);
653 
654  // if(fDebug){
655  // std::cout << "testPhiWave from directly due north of ANITA..." << std::endl;
656  // std::cout << "testPhiWave (Degrees) = " << testPhiWave*TMath::RadToDeg() << ", for reference heading = " << heading << std::endl;
657  // }
658 
659  Double_t testPosition[3];
660  geom->getCartesianCoords(testLat, testLon, testAlt, testPosition);
661 
662  TVector3 testVector(testPosition);
663  const TVector3 unitAnita = TVector3(anitaPosition).Unit();
664  testVector.Rotate(-testPhiWave, unitAnita); // if we were to recalculate the phiWave expected, it would now point to 0
665 
666  // if(fDebug){
667  // testVector.GetXYZ(testPosition);
668  // geom->getLatLonAltFromCartesian(testPosition, testLat, testLon, testAlt);
669  // getThetaAndPhiWave2(testLon, testLat, testAlt, testThetaWave, testPhiWave);
670  // std::cout << "After phi rotation, step 1 , phiWave should equal 0 (or 360)" << std::endl;
671  // std::cout << "testPhiWave (Degrees) = " << testPhiWave*TMath::RadToDeg()
672  // << ", testThetaWave (Degrees) = " << testThetaWave*TMath::RadToDeg() << std::endl;
673  // }
674 
675  testVector.Rotate(phiWave, unitAnita); // if we were to recalculate the phiWave expected, it would now point to phiWave
676 
677  testVector.GetXYZ(testPosition);
678  geom->getLatLonAltFromCartesian(testPosition, testLat, testLon, testAlt);
679  getThetaAndPhiWave2(testLon, testLat, testAlt, testThetaWave, testPhiWave);
680 
681  // if(fDebug){
682  // std::cout << "After phi rotation, step 2, testPhiWave should equal phiWave..." << std::endl;
683  // std::cout << "In degrees..." << std::endl;
684  // std::cout << "phiWave (Degrees) = " << phiWave*TMath::RadToDeg()
685  // << ", thetaWave (Degrees) = " << thetaWave*TMath::RadToDeg() << std::endl;
686  // std::cout << "testPhiWave (Degrees) = " << testPhiWave*TMath::RadToDeg()
687  // << ", testThetaWave (Degrees) = " << testThetaWave*TMath::RadToDeg() << std::endl;
688  // }
689 
690  // now need to raise/lower the point described by testVector such that thetaWave is correct
691  // i.e. set the magnitude of the testVector such that thetaWave is correct
692  //
693  //
694  // O
695  // Earth Centre (Origin) o
696  // |\ a
697  // t | \
698  // | \
699  // ANITA o---o "Test Vector"
700  // A T
701 
702  // O, A, T are the angles
703  // o, a, t are the lengths. I'm trying to find the length a for a given angle A.
704  // a / sin(A) = t / sin(T)
705  //
706  // t = anitaPosition.Mag();
707  // A = (pi/2 - thetaWave);
708  // O = angle between ANITA and the test vector
709  // T = pi - A - O
710  // so...
711  // a = sin(A) * t / (pi - A - O)
712  TVector3 anitaVector(anitaPosition);
713 
714  double A = TMath::PiOver2() - thetaWave;
715  double O = testVector.Angle(anitaPosition); //angle between the vectors
716  double T = TMath::Pi() - A - O;
717  double t = anitaVector.Mag();
718  double a = TMath::Sin(A)*(t/TMath::Sin(T));
719 
720  testVector.SetMag(a);
721 
722  // if(fDebug){
723  // testVector.GetXYZ(testPosition);
724  // geom->getLatLonAltFromCartesian(testPosition, testLat, testLon, testAlt);
725  // getThetaAndPhiWave2(testLon, testLat, testAlt, testThetaWave, testPhiWave);
726  // std::cout << "After setting mangitude, testThetaWave should equal thetaWave too!" << std::endl;
727  // std::cout << "testPhiWave (Degrees) = " << testPhiWave*TMath::RadToDeg()
728  // << ", testThetaWave (Degrees) = " << testThetaWave*TMath::RadToDeg() << std::endl;
729  // }
730 
731  TVector3 deltaVec = testVector - anitaPosition;
732  return deltaVec.Unit();
733 }
734 
735 
736 
737 
738 
739 
740 void UsefulAdu5Pat::getThetaAndPhiWaveWaisDivide(Double_t &thetaWave, Double_t &phiWave)
741 {
742  return getThetaAndPhiWave(AnitaLocations::getWaisLongitude(), AnitaLocations::getWaisLatitude(),AnitaLocations::getWaisAltitude(),thetaWave,phiWave);
743 }
744 
745 void UsefulAdu5Pat::getThetaAndPhiWaveLDB(Double_t &thetaWave, Double_t &phiWave)
746 {
748 }
749 
750 
751 
752 void UsefulAdu5Pat::getThetaAndPhiWave(Double_t sourceLon, Double_t sourceLat, Double_t sourceAlt, Double_t &thetaWave, Double_t &phiWave) {
753  getThetaAndPhiWave2(sourceLon, sourceLat, sourceAlt, thetaWave, phiWave, &fSourcePos);
754 }
755 
756 
757 
758 void UsefulAdu5Pat::getThetaAndPhiWave2(Double_t sourceLon, Double_t sourceLat, Double_t sourceAlt, Double_t &thetaWave, Double_t &phiWave, TVector3* sourcePos) const {
759 
760  Double_t pSource[3]={0};
762  geom->getCartesianCoords(TMath::Abs(sourceLat),sourceLon,sourceAlt,pSource);
763  TVector3 sourcePosStack;
764  sourcePos = sourcePos ? sourcePos : &sourcePosStack;
765  sourcePos->SetXYZ(pSource[0],pSource[1],pSource[2]);
766  getThetaAndPhiWaveCart(sourcePos, thetaWave, phiWave);
767 
768 }
769 
770 void UsefulAdu5Pat::getThetaAndPhiWaveCart(TVector3 * sourcePos, Double_t & thetaWave, Double_t& phiWave) const
771 {
773  //Rotate such that balloon is at 0,0,fBalloonHeight
774  sourcePos->RotateZ(-1*fBalloonPhi);
775  sourcePos->RotateY(-1*fBalloonTheta);
776 
777  //Now find thetaWave and phiWave
778  thetaWave = TMath::ATan((fBalloonHeight-sourcePos->Z())/TMath::Sqrt(sourcePos->X()*sourcePos->X() + sourcePos->Y()*sourcePos->Y()));
779 
780  // phiWave is just atan(yp/xp)
781  // It only looks confusing to make sure I get the sign and 0-360 convention
782  phiWave = 0;
783  if(sourcePos->X()==0) {
784  phiWave = TMath::PiOver2();
785  if(sourcePos->Y()<0)
786  phiWave += TMath::Pi();
787  }
788  else if(sourcePos->X()<0) {
789  phiWave = TMath::Pi()+TMath::ATan(sourcePos->Y()/sourcePos->X());
790  }
791  else {
792  phiWave = TMath::ATan(sourcePos->Y()/sourcePos->X());
793  if(sourcePos->Y()<0) {
794  phiWave += TMath::TwoPi();
795  }
796  }
797 
798  TVector3 rollAxis = geom->fRollRotationAxis;
799  TVector3 pitchAxis = geom->fPitchRotationAxis;
800 
801  Double_t tempThetaWave=TMath::PiOver2()-thetaWave;
802 
803  if(heading>=0 && heading<=360) {
804  TVector3 arbDir; //
805  arbDir.SetMagThetaPhi(1,tempThetaWave,-1*phiWave);
806 
807  rollAxis.Rotate(heading*TMath::DegToRad(),geom->fHeadingRotationAxis);
808  pitchAxis.Rotate(heading*TMath::DegToRad(),geom->fHeadingRotationAxis);
809  rollAxis.Rotate(pitch*TMath::DegToRad(),pitchAxis);
810 
811  arbDir.Rotate(-1.*roll*TMath::DegToRad(),rollAxis);
812  arbDir.Rotate(-1*pitch*TMath::DegToRad(),pitchAxis);
813  arbDir.Rotate(-1*heading*TMath::DegToRad(),geom->fHeadingRotationAxis);
814 
815  phiWave = arbDir.Phi();
816  phiWave *= -1;
817  if(phiWave>TMath::TwoPi()) {
818  phiWave-=TMath::TwoPi();
819  }
820  if(phiWave<0) {
821  phiWave+=TMath::TwoPi();
822  }
823  thetaWave=TMath::PiOver2()-arbDir.Theta();
824  }
825 }
826 
827 
828 
829 
830 Double_t UsefulAdu5Pat::getGroupDelay(Double_t phiToAntBoresight)
831 {
832  Double_t phiDeg=phiToAntBoresight*TMath::RadToDeg();
833  Double_t delayTime=(phiDeg*phiDeg*phiDeg*phiDeg)*1.45676e-8;
834  delayTime-=(phiDeg*phiDeg)*5.01452e-6;
835  return delayTime;
836 }
837 
838 
839 
840 
841 
842 void UsefulAdu5Pat::getThetaWaveAtBase(Double_t baseLon, Double_t baseLat, Double_t baseAlt, Double_t &thetaWave) {
843 
844  //gets the theta from a base to the balloon - can check if we are beyond horizon
845 
846  Double_t pSource[3]={0};
847  AnitaGeomTool::Instance()->getCartesianCoords(TMath::Abs(baseLat),baseLon,baseAlt,pSource);
848  fSourcePos.SetXYZ(pSource[0], pSource[1], pSource[2]);
849 
850  //make copy of balloon position and rotate it such that base is at 0,0,baseAlt
851  TVector3 rotatedBalloonPos = fBalloonPos;
852  rotatedBalloonPos.RotateZ(-1*fSourcePos.Phi());
853  rotatedBalloonPos.RotateY(-1*fSourcePos.Theta());
854 
855  TVector3 rotatedBase = fSourcePos;
856  rotatedBase.RotateZ(-1*fSourcePos.Phi());
857  rotatedBase.RotateY(-1*fSourcePos.Theta());
858 
859  //Now find thetaWave
860  thetaWave=TMath::ATan((rotatedBase.Z()-rotatedBalloonPos.Z())/TMath::Sqrt(rotatedBalloonPos.X()*rotatedBalloonPos.X() + rotatedBalloonPos.Y()*rotatedBalloonPos.Y()));
861 
862 }
863 
864 
865 Double_t UsefulAdu5Pat::getDeltaTExpected(Int_t ant1, Int_t ant2,Double_t sourceLon, Double_t sourceLat, Double_t sourceAlt)
866 {
867  Double_t tempTheta,tempPhi;
868  if(fSourceAltitude!=sourceAlt || fSourceLongitude!=sourceLon || fSourceLatitude!=sourceLat){
869  getThetaAndPhiWave(sourceLon,sourceLat,sourceAlt,tempTheta,tempPhi);
870  }
871 
872 
874  //Now fThetaWave and fPhiWave should be correctly set.
875  Double_t phi1=geom->getAntPhiPositionRelToAftFore(ant1);
876  Double_t r1=geom->getAntR(ant1);
877  Double_t z1=geom->getAntZ(ant1);
878 
879  Double_t phi2=geom->getAntPhiPositionRelToAftFore(ant2);
880  Double_t r2=geom->getAntR(ant2);
881  Double_t z2=geom->getAntZ(ant2);
882 
883  Double_t tanThetaW=TMath::Tan(fThetaWave);
884  Double_t part1=z1*tanThetaW - r1 * TMath::Cos(fPhiWave-phi1);
885  Double_t part2=z2*tanThetaW - r2 * TMath::Cos(fPhiWave-phi2);
886 
887  Double_t geomTime= 1e9*((TMath::Cos(fThetaWave) * (part1 - part2))/C_LIGHT); //returns time in ns
888  if(fIncludeGroupDelay) {
889  Double_t phi1Diff=geom->getPhiDiff(fPhiWave,phi1);
890  Double_t delay1=getGroupDelay(phi1Diff);
891  Double_t phi2Diff=geom->getPhiDiff(fPhiWave,phi2);
892  Double_t delay2=getGroupDelay(phi2Diff);
893  geomTime+=(delay1-delay2);
894  }
895 
896 
897  return geomTime;
898 }
899 
900 
901 
902 Double_t UsefulAdu5Pat::getDeltaTExpected(Int_t ant1, Int_t ant2,Double_t phiWave, Double_t thetaWave)
903 {
904 
905  if(fPhiWave!=phiWave || fThetaWave!=thetaWave){
906  fThetaWave=thetaWave;
907  fPhiWave=phiWave;
908  }
909 
911  Double_t phi1=geom->getAntPhiPositionRelToAftFore(ant1);
912  Double_t r1=geom->getAntR(ant1);
913  Double_t z1=geom->getAntZ(ant1);
914 
915  Double_t phi2=geom->getAntPhiPositionRelToAftFore(ant2);
916  Double_t r2=geom->getAntR(ant2);
917  Double_t z2=geom->getAntZ(ant2);
918 
919  Double_t tanThetaW=TMath::Tan(fThetaWave);
920  Double_t part1=z1*tanThetaW - r1 * TMath::Cos(fPhiWave-phi1);
921  Double_t part2=z2*tanThetaW - r2 * TMath::Cos(fPhiWave-phi2);
922 
923  return 1e9*((TMath::Cos(fThetaWave) * (part1 - part2))/C_LIGHT); //returns time in ns
924 }
925 
926 
927 //does not take into account anita's position/heading...
928 Double_t UsefulAdu5Pat::getDeltaTExpected(Int_t ant1,Int_t ant2,Double_t cosPhi,Double_t sinPhi,Double_t cosTheta,Double_t sinTheta)
929 {
930  Double_t x1,y1,z1;
932  geom->getAntXYZ(ant1,x1,y1,z1);
933 
934  Double_t x2,y2,z2;
935  geom->getAntXYZ(ant2,x2,y2,z2);
936 
937  Double_t part1 = x1*cosTheta*cosPhi + y1*cosTheta*sinPhi + z1*sinTheta;
938  Double_t part2 = x2*cosTheta*cosPhi + y2*cosTheta*sinPhi + z2*sinTheta;
939  return 1e9 * (part1 - part2) / C_LIGHT;
940 
941 }
942 
943 
944 Double_t UsefulAdu5Pat::getDeltaTWillySeavey(Int_t ant1, Int_t ant2)
945 {
946  return getDeltaTExpected(ant1, ant2,
950 }
951 
952 Double_t UsefulAdu5Pat::getDeltaTWillyBorehole(Int_t ant1, Int_t ant2)
953 {
954  return getDeltaTExpected(ant1, ant2,
958 }
959 
960 Double_t UsefulAdu5Pat::getDeltaTTaylor(Int_t ant1, Int_t ant2)
961 {
962  return getDeltaTExpected(ant1, ant2,
963  AnitaLocations::LONGITUDE_TD,
964  AnitaLocations::LATITUDE_TD,
965  AnitaLocations::ALTITUDE_TD);
966 }
967 
968 Double_t UsefulAdu5Pat::getDeltaTTaylorOpt(Int_t ant1, Int_t ant2, Double_t *deltaR, Double_t *deltaZ, Double_t *deltaPhi)
969 {
970  return getDeltaTExpectedOpt(ant1, ant2,
971  AnitaLocations::LONGITUDE_TD,
972  AnitaLocations::LATITUDE_TD,
973  AnitaLocations::ALTITUDE_TD,
974  deltaR, deltaZ,deltaPhi);
975 }
976 
977 
978 Double_t UsefulAdu5Pat::getDeltaTExpectedOpt(Int_t ant1, Int_t ant2,Double_t sourceLon, Double_t sourceLat, Double_t sourceAlt, Double_t *deltaR, Double_t *deltaZ, Double_t *deltaPhi)
979 {
980  Double_t tempTheta,tempPhi;
981  if(fSourceAltitude!=sourceAlt || fSourceLongitude!=sourceLon || fSourceLatitude!=sourceLat)
982  getThetaAndPhiWave(sourceLon,sourceLat,sourceAlt,tempTheta,tempPhi);
983 
984  //Now fThetaWave and fPhiWave should be correctly set.
986  Double_t phi1=geom->getAntPhiPositionRelToAftFore(ant1)+deltaPhi[ant1];
987  Double_t r1=geom->getAntR(ant1)+deltaR[ant1];
988  Double_t z1=geom->getAntZ(ant1)+deltaZ[ant1];
989 
990  Double_t phi2=geom->getAntPhiPositionRelToAftFore(ant2)+deltaPhi[ant2];
991  Double_t r2=geom->getAntR(ant2)+deltaR[ant2];
992  Double_t z2=geom->getAntZ(ant2)+deltaZ[ant2];
993 
994  // std::cout << ant1 << deltaPhi[ant1] << " " << deltaPhi[ant2]<< std::endl;
995 
996  Double_t tanThetaW=TMath::Tan(fThetaWave);
997  Double_t part1=z1*tanThetaW - r1 * TMath::Cos(fPhiWave-phi1);
998  Double_t part2=z2*tanThetaW - r2 * TMath::Cos(fPhiWave-phi2);
999 
1000  return 1e9*((TMath::Cos(fThetaWave) * (part1 - part2))/C_LIGHT); //returns time in ns
1001 }
1002 
1003 
1004 Double_t UsefulAdu5Pat::getDeltaTSeaveyOpt(Int_t ant1, Int_t ant2, Double_t *deltaR, Double_t *deltaZ, Double_t *deltaPhi)
1005 {
1006  return getDeltaTExpectedSeaveyOpt(ant1, ant2,
1010  deltaR, deltaZ,deltaPhi);
1011 }
1012 
1013 Double_t UsefulAdu5Pat::getDeltaTExpectedSeaveyOpt(Int_t ant1, Int_t ant2,Double_t sourceLon, Double_t sourceLat, Double_t sourceAlt, Double_t *deltaR, Double_t *deltaZ, Double_t *deltaPhi)
1014 {
1015  Double_t tempTheta,tempPhi;
1016  if(fSourceAltitude!=sourceAlt || fSourceLongitude!=sourceLon || fSourceLatitude!=sourceLat){
1017  getThetaAndPhiWave(sourceLon,sourceLat,sourceAlt,tempTheta,tempPhi);
1018  }
1019 
1020  //Now fThetaWave and fPhiWave should be correctly set.
1022  Double_t phi1=geom->getAntPhiPositionRelToAftFore(ant1)+deltaPhi[ant1];
1023  Double_t r1=geom->getAntR(ant1)+deltaR[ant1];
1024  Double_t z1=geom->getAntZ(ant1)+deltaZ[ant1];
1025 
1026  Double_t phi2=geom->getAntPhiPositionRelToAftFore(ant2)+deltaPhi[ant2];
1027  Double_t r2=geom->getAntR(ant2)+deltaR[ant2];
1028  Double_t z2=geom->getAntZ(ant2)+deltaZ[ant2];
1029 
1030  // std::cout << ant1 << deltaPhi[ant1] << " " << deltaPhi[ant2]<< std::endl;
1031 
1032  Double_t tanThetaW=TMath::Tan(fThetaWave);
1033  Double_t part1=z1*tanThetaW - r1 * TMath::Cos(fPhiWave-phi1);
1034  Double_t part2=z2*tanThetaW - r2 * TMath::Cos(fPhiWave-phi2);
1035 
1036  return 1e9*((TMath::Cos(fThetaWave) * (part1 - part2))/C_LIGHT); //returns time in ns
1037 }
1038 
1039 
1040 UInt_t UsefulAdu5Pat::getTaylorDomeTriggerTimeNs() const
1041 {
1042  return getTriggerTimeNsFromSource(AnitaLocations::LATITUDE_TD,
1043  AnitaLocations::LONGITUDE_TD,
1044  AnitaLocations::ALTITUDE_TD);
1045 }
1046 
1048 {
1049  return getTriggerTimeNsFromSource(AnitaLocations::getWaisLatitude(),
1050  AnitaLocations::getWaisLongitude(),
1051  AnitaLocations::getWaisAltitude());
1052 }
1053 
1055 {
1059 }
1060 
1062 {
1066 }
1067 
1068 
1069 
1070 Double_t UsefulAdu5Pat::getDistanceFromSource(Double_t sourceLat, Double_t sourceLong, Double_t sourceAlt) const
1071 {
1072  // static Double_t pTaylor[3]={0};
1073  Double_t pTaylor[3]={0};
1074  AnitaGeomTool::Instance()->getCartesianCoords(sourceLat,
1075  sourceLong,
1076  sourceAlt,
1077  pTaylor);
1078  Double_t s2 = ((pTaylor[0]-fBalloonCoords[0])*(pTaylor[0]-fBalloonCoords[0]) +
1079  (pTaylor[1]-fBalloonCoords[1])*(pTaylor[1]-fBalloonCoords[1]) +
1080  (pTaylor[2]-fBalloonCoords[2])*(pTaylor[2]-fBalloonCoords[2]));
1081  Double_t distanceToFly=TMath::Sqrt(s2);
1082  return distanceToFly;
1083 }
1084 
1085 
1086 
1087 
1088 
1089 UInt_t UsefulAdu5Pat::getTriggerTimeNsFromSource(Double_t sourceLat, Double_t sourceLong, Double_t sourceAlt) const
1090 {
1091  Double_t distanceToFly = getDistanceFromSource(sourceLat, sourceLong, sourceAlt);
1092  Double_t timeOfFlight=distanceToFly/C_LIGHT;
1093  timeOfFlight*=1e9;
1094  // Double_t expTime=timeOfFlight-40e3;
1095  Double_t expTime=timeOfFlight;//-40e3;
1096  UInt_t expTrigTime=(UInt_t)expTime;
1097 
1098  // std::cout << distanceToFly << "\t" << timeOfFlight << "\n";
1099  return expTrigTime;
1100 
1101 
1102 }
1103 
1104 
1105 
1106 Double_t UsefulAdu5Pat::getAngleBetweenPayloadAndSource(Double_t sourceLon, Double_t sourceLat, Double_t sourceAlt) { //ACG additional function
1108  Double_t thetaBalloon=geom->getThetaFromLat(TMath::Abs(latitude));
1109  Double_t phiBalloon=geom->getPhiFromLon(longitude);
1110  Double_t balloonHeight=geom->getGeoid(thetaBalloon)+altitude;
1111 
1112  Double_t thetaSource=geom->getThetaFromLat(TMath::Abs(sourceLat));
1113  Double_t phiSource=geom->getPhiFromLon(sourceLon);
1114  Double_t radiusSource=geom->getGeoid(thetaSource)+sourceAlt;
1115 
1116  //Get vector from Earth's centre to source
1117  fSourcePos.SetX(radiusSource*TMath::Sin(thetaSource)*TMath::Cos(phiSource));
1118  fSourcePos.SetY(radiusSource*TMath::Sin(thetaSource)*TMath::Sin(phiSource));
1119  fSourcePos.SetZ(radiusSource*TMath::Cos(thetaSource));
1120 
1121  //Rotate such that balloon is at 0,0,balloonHeight
1122 
1123  fSourcePos.RotateZ(-1*phiBalloon);
1124  fSourcePos.RotateY(-1*thetaBalloon);
1125 
1126  Double_t dotProduct=balloonHeight*fSourcePos.Z();//+0*X+0*Y
1127  Double_t magSource=TMath::Sqrt(fSourcePos.X()*fSourcePos.X() + fSourcePos.Y()*fSourcePos.Y()+fSourcePos.Z()*fSourcePos.Z());
1128  Double_t magBalloon=balloonHeight;
1129 
1130  Double_t phiEarthCenter=TMath::ACos(TMath::Abs(dotProduct/(magSource*magBalloon)));
1131 
1132  return phiEarthCenter;
1133 
1134 }
1135 
1136 
1137 //---------------------------------------------------------------------------------------------------------
1148  //work out the angle to the Sun for heading 0
1149  TTimeStamp theTime = this->realTime;
1150 
1151  UInt_t hour = 0;
1152  UInt_t min = 0;
1153  UInt_t sec = 0;
1154  theTime.GetTime(true,0,&hour,&min,&sec);
1155  Int_t timeOfDay = hour*3600 + min*60 + sec;
1156 
1157 
1158  // this would make 12pm at 180 degrees to sun - so we have to subtract 180 from the result
1159  Int_t secondsPerDay = (24*60*60);
1160  Double_t zeroLonAngleToSun = 360*Double_t(timeOfDay)/secondsPerDay;
1161 
1162 
1163  zeroLonAngleToSun-=180.;
1164  Double_t thisLonAngleToSun = zeroLonAngleToSun+this->longitude;
1165 
1166  while(thisLonAngleToSun<-180) thisLonAngleToSun+=360.;
1167  while(thisLonAngleToSun>180) thisLonAngleToSun-=360.;
1168 
1169  return thisLonAngleToSun;
1170 }
1171 
1172 
1173 
1174 
1175 
1176 //---------------------------------------------------------------------------------------------------------
1183  Double_t sunAngle = UsefulAdu5Pat::getAzimuthOfSunRelativeToNorth();
1184  Double_t sunAngleAtHeading = sunAngle + this->heading;
1185 
1186  while(sunAngleAtHeading<-180) sunAngleAtHeading+=360;
1187  while(sunAngleAtHeading>180) sunAngleAtHeading-=360;
1188 
1189  return sunAngleAtHeading;
1190 
1191 }
1192 
1193 
1194 
1195 
1196 //---------------------------------------------------------------------------------------------------------
1205 Double_t UsefulAdu5Pat::getDifferencePointingToSun(Double_t phiAngle, Bool_t inputInDegrees) const {
1206 
1207  if(phiAngle>9999 || phiAngle<-9999){
1208  std::cerr << "UsefulAdu5Pat::getDifferencePointingToSun() " << phiAngle << " ignore\n";
1209  return -9999.;
1210  }
1211 
1212  Double_t sunAngle = UsefulAdu5Pat::getAzimuthOfSun();
1213 
1214  Double_t angleFromSun=0;
1215  if(inputInDegrees==false){
1216  angleFromSun = sunAngle - phiAngle*TMath::RadToDeg();
1217  }
1218  else{
1219  angleFromSun = sunAngle - phiAngle;
1220  }
1221 
1222  while(angleFromSun<-180){
1223  angleFromSun+=360;
1224  }
1225  while(angleFromSun>=180){
1226  angleFromSun-=360;
1227  }
1228 
1229  //always returns degrees
1230  return angleFromSun;
1231 
1232 }
1233 
1234 
1235 
1244 void UsefulAdu5Pat::getSunPosition(Double_t& phiDeg, Double_t& thetaDeg) const{
1245 
1246  // Declaration of some constants
1247  const Double_t dEarthMeanRadius = 6371.01; // In km
1248  const Double_t dAstronomicalUnit =149597890; // In km
1249 
1250 
1251  TTimeStamp timeStamp = realTime;
1252  UInt_t year, month, day;
1253  timeStamp.GetDate(true, 0, &year, &month, &day);
1254  UInt_t hour, min, sec;
1255  timeStamp.GetTime(true, 0, &hour, &min, &sec);
1256 
1257  // std::cerr << year << "-" << month << "-" << day << "\t" << hour << ":" << min << ":" << sec << std::endl;
1258 
1259  // need to convert from unsigned to signed ints otherwise this bastard breaks
1260  Int_t iDay = day;
1261  Int_t iMonth = month;
1262  Int_t iYear = year;
1263 
1264  // Main variables
1265  Double_t dAzimuth;
1266  Double_t dZenithAngle;
1267  Double_t dElapsedJulianDays;
1268  Double_t dDecimalHours;
1269  Double_t dEclipticLongitude;
1270  Double_t dEclipticObliquity;
1271  Double_t dRightAscension;
1272  Double_t dDeclination;
1273 
1274  // Auxiliary variables
1275  Double_t dY;
1276  Double_t dX;
1277 
1278  // Calculate difference in days between the current Julian Day
1279  // and JD 2451545.0, which is noon 1 January 2000 Universal Time
1280  {
1281  Double_t dJulianDate;
1282  long int liAux1;
1283  long int liAux2;
1284  // Calculate time of the day in UT decimal hours
1285  dDecimalHours = (double)hour + ((double)min + (double)sec / 60.0 ) / 60.0;
1286  // Calculate current Julian Day
1287  liAux1 =(iMonth-14)/12;
1288  liAux2=(1461*(iYear + 4800 + liAux1))/4 + (367*(iMonth
1289  - 2-12*liAux1))/12- (3*((iYear + 4900
1290  + liAux1)/100))/4+iDay-32075;
1291  dJulianDate=(double)(liAux2)-0.5+dDecimalHours/24.0;
1292  // Calculate difference between current Julian Day and JD 2451545.0
1293  dElapsedJulianDays = dJulianDate-2451545.0;
1294  }
1295 
1296  // Calculate ecliptic coordinates (ecliptic longitude and obliquity of the
1297  // ecliptic in radians but without limiting the angle to be less than 2*Pi
1298  // (i.e., the result may be greater than 2*Pi)
1299  {
1300  Double_t dMeanLongitude;
1301  Double_t dMeanAnomaly;
1302  Double_t dOmega;
1303  dOmega=2.1429-0.0010394594*dElapsedJulianDays;
1304  dMeanLongitude = 4.8950630+ 0.017202791698*dElapsedJulianDays; // Radians
1305  dMeanAnomaly = 6.2400600+ 0.0172019699*dElapsedJulianDays;
1306  dEclipticLongitude = dMeanLongitude + 0.03341607*sin( dMeanAnomaly )
1307  + 0.00034894*sin( 2*dMeanAnomaly )-0.0001134
1308  -0.0000203*sin(dOmega);
1309  dEclipticObliquity = 0.4090928 - 6.2140e-9*dElapsedJulianDays
1310  +0.0000396*cos(dOmega);
1311  }
1312 
1313  // Calculate celestial coordinates ( right ascension and declination ) in radians
1314  // but without limiting the angle to be less than 2*Pi (i.e., the result may be
1315  // greater than 2*Pi)
1316  {
1317  Double_t dSin_EclipticLongitude;
1318  dSin_EclipticLongitude= sin( dEclipticLongitude );
1319  dY = cos( dEclipticObliquity ) * dSin_EclipticLongitude;
1320  dX = cos( dEclipticLongitude );
1321  dRightAscension = atan2( dY,dX );
1322  if( dRightAscension < 0.0 ) dRightAscension = dRightAscension + TMath::TwoPi();
1323  dDeclination = asin( sin( dEclipticObliquity )*dSin_EclipticLongitude );
1324  }
1325 
1326  // Calculate local coordinates ( azimuth and zenith angle ) in degrees
1327  {
1328  Double_t dGreenwichMeanSiderealTime;
1329  Double_t dLocalMeanSiderealTime;
1330  Double_t dLatitudeInRadians;
1331  Double_t dHourAngle;
1332  Double_t dCos_Latitude;
1333  Double_t dSin_Latitude;
1334  Double_t dCos_HourAngle;
1335  Double_t dParallax;
1336  dGreenwichMeanSiderealTime = 6.6974243242 +
1337  0.0657098283*dElapsedJulianDays
1338  + dDecimalHours;
1339  dLocalMeanSiderealTime = (dGreenwichMeanSiderealTime*15
1340  + longitude)*TMath::DegToRad();
1341  dHourAngle = dLocalMeanSiderealTime - dRightAscension;
1342  dLatitudeInRadians = latitude*TMath::DegToRad();
1343  dCos_Latitude = cos( dLatitudeInRadians );
1344  dSin_Latitude = sin( dLatitudeInRadians );
1345  dCos_HourAngle= cos( dHourAngle );
1346  dZenithAngle = (acos( dCos_Latitude*dCos_HourAngle
1347  *cos(dDeclination) + sin( dDeclination )*dSin_Latitude));
1348  dY = -sin( dHourAngle );
1349  dX = tan( dDeclination )*dCos_Latitude - dSin_Latitude*dCos_HourAngle;
1350  dAzimuth = atan2( dY, dX );
1351  if ( dAzimuth < 0.0 )
1352  dAzimuth = dAzimuth + TMath::TwoPi();
1353  dAzimuth = dAzimuth/TMath::DegToRad();
1354  // Parallax Correction
1355  dParallax=(dEarthMeanRadius/dAstronomicalUnit)
1356  *sin(dZenithAngle);
1357  dZenithAngle=(dZenithAngle
1358  + dParallax)/TMath::DegToRad();
1359  }
1360 
1361  // std::cerr << dAzimuth << "\t" << dZenithAngle << std::endl;
1362 
1363  // finally we need to convert to ANITA's coordinates
1364  // from my testing...
1365  // dAzimuth = pat->heading - recoPhiDeg;
1366  // therefore
1367 
1368  phiDeg = heading - dAzimuth;
1369  while(phiDeg < -180) phiDeg += 360;
1370  while(phiDeg >= 180) phiDeg -= 360;
1371 
1372  // and theta for these guys runs from
1373  thetaDeg = dZenithAngle - 90;
1374 
1375  // thetaDeg = dZenithAngle;
1376  // phiDeg = dAzimuth;
1377 
1378  }
1379 
1380 int UsefulAdu5Pat::traceBackToContinent(Double_t phiWave, Double_t thetaWave,
1381  Double_t * lon_ptr, Double_t * lat_ptr, Double_t * alt_ptr,
1382  Double_t * adj_ptr, Double_t max_adjust, Int_t max_iter) const {
1383 
1384  if(fDebug){
1385  std::cerr << "Debug info in " << __PRETTY_FUNCTION__ << ":\n";
1386  }
1387 
1388 
1389  if (thetaWave + max_adjust < 0){
1390  if(fDebug){
1391  std::cerr << "thetaWave + max_adjust < 0... no chance! returning 0!" << std::endl;
1392  }
1393  return 0; // no chance
1394  }
1395 
1396  Double_t lon,lat,alt;
1397  Double_t last_theta_tried =0;
1398  Double_t last_successful_theta = 0;
1399  Double_t last_failed_theta = 0;
1400 
1401  double last_good_lat = -9999;
1402  double last_good_lon = -9990;
1403  double last_good_alt = -9999;
1404  Int_t iter = 0;
1405 
1406  while(iter++ < max_iter)
1407  {
1408  Double_t theta_try = last_theta_tried == 0 ? thetaWave
1409  : last_theta_tried == thetaWave
1410  ? thetaWave+max_adjust
1411  : (last_successful_theta + last_failed_theta)/2;
1412 
1413  if(fDebug){
1414  std::cerr << "iter = " << iter << ", theta_try (degrees) = " << theta_try*TMath::RadToDeg()
1415  << ", last_successful_theta (degrees) = " << last_successful_theta*TMath::RadToDeg() << "\n";
1416  }
1417 
1418  last_theta_tried = theta_try;
1419 
1420  // bool odb = fDebug;
1421  // fDebug = false;
1422  int success = getSourceLonAndLatAtAlt2(phiWave, theta_try, lon, lat, alt);
1423  // fDebug = odb;
1424 
1425  int moarLoops = 0;
1426  const int crazyNumberOfPowersOfTen = 2; // if this gets too big, this will get out of hand...
1427  while(success==3 && moarLoops < crazyNumberOfPowersOfTen){
1428  int maxLoopIter = fMaxLoopIterations * pow(10, 1+moarLoops);
1429  if(fDebug){
1430  std::cerr << "Got non-convergent solution in getSourceLonAndLatAtAlt2... will try again with " << maxLoopIter << " loops...\n";
1431  }
1432  // odb = fDebug;
1433  // fDebug = false;
1434  success = getSourceLonAndLatAtAlt2(phiWave, theta_try, lon, lat, alt, maxLoopIter);
1435  // fDebug = odb;
1436  moarLoops++;
1437  }
1438 
1439  if(fDebug){
1440  std::cerr << "getSourceLonAndLatAtAlt2: success = " << success << "\n";
1441  }
1442 
1443  if (success == 1 || success == 2)
1444  {
1445  if (iter == 1) //this was the first try and it was a success
1446  {
1447  if (lon_ptr) *lon_ptr = lon;
1448  if (lat_ptr) *lat_ptr = lat;
1449  if (alt_ptr) *alt_ptr = alt;
1450  if (adj_ptr) *adj_ptr = 0;
1451  if(fDebug){
1452  std::cerr << "success on first try! Returning 1" << std::endl;
1453  }
1454  return 1;
1455  }
1456 
1457 
1458  last_good_lat = lat;
1459  last_good_lon = lon;
1460  last_good_alt = alt;
1461  last_successful_theta = theta_try;
1462 
1463  }
1464  else
1465  {
1466  if (theta_try == thetaWave + max_adjust)
1467  {
1468  if(fDebug){
1469  std::cerr << "theta_try = thetaWave + max_adjust = " << theta_try << "... it's hopeless! returning 0" << std::endl;
1470  }
1471  //it's hopeless.
1472  return 0;
1473  }
1474 
1475  last_failed_theta = theta_try;
1476  }
1477  }
1478 
1479  if (lat_ptr) *lat_ptr = last_good_lat;
1480  if (lon_ptr) *lon_ptr = last_good_lon;
1481  if (alt_ptr) *alt_ptr = last_good_alt;
1482  if (adj_ptr) *adj_ptr = last_successful_theta - thetaWave;
1483 
1484  if(fDebug){
1485  std::cerr << "Got here! Returning 2... iter = " << iter
1486  << ", last_successful_theta (degrees) = " << last_successful_theta*TMath::RadToDeg()
1487  << ", adjustment (degrees) = " << (last_successful_theta - thetaWave)*TMath::RadToDeg()
1488  << std::endl;
1489  }
1490 
1491  return 2;
1492 }
1493 
1494 
1495 
1496 // this is the static version!
1497 Double_t UsefulAdu5Pat::getReflectionAngle(Double_t plAlt, Double_t el, Double_t imAlt){
1498 
1499  Double_t result = -9999;
1500  const Double_t EARTH_POLAR_RADIUS = 6378000;
1501  if (el < -5.0) {
1502  Double_t theta = M_PI / 2.0 - (el * M_PI / 180.0);
1503  Double_t er = EARTH_POLAR_RADIUS;
1504  Double_t plH = er + plAlt;
1505  Double_t costr = cos(theta);
1506  Double_t d = -plH*costr - sqrt(plH*plH*costr*costr - 2*er*(plAlt-imAlt) - plAlt*plAlt + imAlt*imAlt);
1507  // alpha = angle over earth curvature from payload to image; < 3deg so don't bother w/asin
1508  Double_t alpha = d * sin(theta) / (er+imAlt);
1509  //Double_t alpha = asin(d * sin(theta) / (er+imAlt));
1510  Double_t td = M_PI + 2*alpha - theta;
1511  result = (90.0 - 180.0*td/M_PI);
1512  }
1513  return result;
1514 }
1515 
1516 Double_t UsefulAdu5Pat::getReflectionAngle(Double_t el, Double_t imAlt) const {
1517  return getReflectionAngle(this->altitude, el, imAlt);
1518 }
1519 
1520 
1521 int UsefulAdu5Pat::astronomicalCoordinates(Double_t phiWave, Double_t thetaWave, Double_t * RA_ptr, Double_t * dec_ptr, Double_t * l_ptr, Double_t * b_ptr) const
1522 {
1523 #if ROOT_VERSION_CODE < ROOT_VERSION(6,0,0)
1524  std::cerr << "Your version of ROOT does not support all the features of eventReaderRoot\n";
1525  return 0;
1526 #else
1527 
1528 
1529  // I used coordinate conversions based on Az going north
1530  double Az = phiWave - heading;
1531  double el = -thetaWave;
1532 
1533 
1534  //to radians
1535  Az *= M_PI/180;
1536  el *= M_PI/180;
1537  double lat = latitude * M_PI/180;
1538 
1539 
1540  //declination
1541  double dec = asin( sin(lat) * sin(el) + cos(lat) *cos(el) *cos(Az));
1542 
1543  //hour angle
1544  double h = atan2 ( sin(Az) , -cos(Az)* sin(lat) + tan(el) * cos(lat));
1545 
1546 // printf("%f\n", h * 12 / M_PI);
1547  TTimeStamp ts ( (time_t) realTime, (timeOfDay % 1000) * 1e6);
1548 
1549  //should this be AsLAST or AsLMST? Need to find a real astronomer
1550  // Also, the UT1 offset seems like a royal pain
1551  double lst = ts.AsLMST(longitude);
1552 
1553  // printf("lst: %f\n", lst);
1554 
1555  lst*= ( M_PI / 12); //hour -> radians
1556  double RA = lst -h;
1557 
1558  // Perform wrapping if RA is not within the expected range
1559  RA = FFTtools::wrap(RA,2*TMath::Pi());
1560 
1561  if (RA_ptr) *RA_ptr = RA * 12 / M_PI;
1562  if (dec_ptr) *dec_ptr = dec* 180 / M_PI;
1563 
1564  if (!l_ptr && ! b_ptr) return 0;
1565 
1566  //we gotta precess to B1950
1567 
1568  double b1950 = 2433282.4235; // julian day of B1950
1569  double jd = ts.AsJulianDate();
1570 // printf("%f\n",jd);
1571  double T = ( jd - 2451545) / (36525); // offset from J2000 in centidays... ?
1572  double t = (b1950 - jd) / 36525; //offset from B1950... in centidays?
1573  double sectodeg = 1./3600 ;
1574 
1575  //tons of magic numbers! stolen from DMTPC code. Sorry Asher.
1576  double zeta = (2306.2181*sectodeg+1.39656*sectodeg*T-0.000139*sectodeg*T*T)*t+
1577  (0.30188*sectodeg-0.000344*sectodeg*T)*t*t+
1578  0.017998*sectodeg*t*t*t;
1579  double z = (2306.2181*sectodeg+1.39656*sectodeg*T-0.000139*sectodeg*T*T)*t+
1580  (1.09468*sectodeg+0.000066*sectodeg*T)*t*t+
1581  0.018203*sectodeg*t*t*t;
1582  double theta = (2004.3109*sectodeg-0.85330*sectodeg*T-0.000217*sectodeg*T*T)*t-
1583  (0.42665*sectodeg+0.000217*sectodeg*T)*t*t+0.041833*sectodeg*t*t*t;
1584  zeta *=M_PI/180;
1585  z *=M_PI/180;
1586  theta *=M_PI/180;
1587 
1588 
1589  double A = cos(dec)*sin(RA+zeta);
1590  double B = cos(theta)*cos(dec)*cos(RA+zeta)-sin(theta)*sin(dec);
1591  double C = sin(theta)*cos(dec)*cos(RA+zeta)+cos(theta)*sin(dec);
1592 
1593  double ra1950 = (atan2(A,B)+z);
1594  double dec1950 = asin(C);
1595 
1596 
1597  if (l_ptr)
1598  {
1599  *l_ptr = 303 - 180 / M_PI *
1600  atan2( sin(192.25 * M_PI/180 - ra1950),
1601  cos (192.25 * M_PI/180 - ra1950) * sin(27.5 * M_PI/180) - tan(dec1950) * cos (27.4 * M_PI/180)
1602  );
1603 
1604  while (*l_ptr > 180) *l_ptr -= 360 ;
1605  while (*l_ptr < -180) *l_ptr += 360 ;
1606 
1607 
1608  }
1609 
1610 
1611  if (b_ptr)
1612  {
1613  *b_ptr = 180 / M_PI * asin(
1614  sin(dec1950) * sin(27.4 * M_PI/180) +
1615  cos(dec1950) * cos(27.4 * M_PI/180) * cos (192.25 * M_PI/180 - ra1950)
1616  ) ;
1617 
1618  }
1619 
1620  return 0;
1621 #endif
1622 
1623 }
1624 int UsefulAdu5Pat::fromRADec(int N, const Double_t * RA, const Double_t * dec, Double_t * phi, Double_t *theta) const
1625 {
1626 #if ROOT_VERSION_CODE < ROOT_VERSION(6,0,0)
1627  std::cerr << "Your version of ROOT does not support all the features of eventReaderRoot\n";
1628  return 0;
1629 #else
1630 
1631  TTimeStamp ts ( (time_t) realTime, (timeOfDay % 1000) * 1e6);
1632 
1633  //should this be AsLAST or AsLMST? Need to find a real astronomer
1634  // Also, the UT1 offset seems like a royal pain
1635  double lst = ts.AsLMST(longitude);
1636 
1637  double lat = latitude * (M_PI /180);
1638  double sin_lat = sin(lat);
1639  double cos_lat = cos(lat);
1640 
1641 
1642 
1643  int istart = 0;
1644 #ifdef ENABLE_VECTORIZE
1645  int nit = N / VEC_N;
1646 
1647  istart = nit * VEC_N;
1648 
1649  if (nit > 0)
1650  {
1651 
1652  VEC vheading(heading);
1653  VEC vlst(lst);
1654  VEC vsin_lat(sin_lat);
1655  VEC vcos_lat(cos_lat);
1656  VEC vh;
1657  VEC vra;
1658  VEC vdec;
1659  VEC vcos_dec;
1660  VEC vsin_dec;
1661  VEC vcos_h;
1662  VEC vsin_h;
1663  VEC vel;
1664  VEC vaz;
1665  VEC vphi;
1666  VEC vtheta;
1667 
1668  for (int i = 0; i < nit; i++)
1669  {
1670  vra.load(RA+i*VEC_N);
1671  vdec.load(dec+i*VEC_N);
1672  vh = vlst-vra;
1673  vh *= (M_PI/12);
1674  vdec *= M_PI/180;
1675 
1676  vcos_dec = cos(vdec);
1677  vsin_dec = sin(vdec);
1678  vcos_h = cos(vh);
1679  vsin_h = sin(vh);
1680 
1681  vaz = atan2(vcos_dec * vsin_h, -vcos_h * vsin_lat * vcos_dec + vsin_dec * vcos_lat);
1682  vel = asin(vsin_lat * vsin_dec + vcos_lat * vcos_dec * vcos_h);
1683 
1684  vphi = vheading + vaz * 180/M_PI;
1685  vtheta = -vel * 180/M_PI;
1686  vphi = vphi - 360 * floor(vphi/360) ;
1687 
1688  vphi.store(phi+i*VEC_N);
1689  vtheta.store(theta+i*VEC_N);
1690  }
1691 
1692  }
1693 #endif
1694 
1695 
1696  for (int i = istart; i < N; i++)
1697  {
1698  double h = lst - RA[i]; //hour angle
1699  h*= ( M_PI / 12); //hour -> radians
1700  double dc = dec[i] * M_PI/180;
1701 
1702  double Az = atan2( cos(dc) * sin(h), -cos(h) * sin_lat* cos(dc) + sin(dc) * cos_lat);
1703  double el = asin(sin_lat * sin(dc) + cos_lat * cos(dc) * cos(h));
1704 
1705  phi[i] = FFTtools::wrap(heading + Az * (180/M_PI),360);
1706  theta[i] = - el * (180/M_PI);
1707  }
1708  return 0;
1709 #endif
1710 
1711 }
1712 
1713 
1714 
1715 int UsefulAdu5Pat::fromRADec(Double_t RA, Double_t dec, Double_t * phi, Double_t *theta) const
1716 {
1717 #if ROOT_VERSION_CODE < ROOT_VERSION(6,0,0)
1718  std::cerr << "Your version of ROOT does not support all the features of eventReaderRoot\n";
1719  return 0;
1720 #else
1721 
1722  TTimeStamp ts ( (time_t) realTime, (timeOfDay % 1000) * 1e6);
1723 
1724  //should this be AsLAST or AsLMST? Need to find a real astronomer
1725  // Also, the UT1 offset seems like a royal pain
1726  double lst = ts.AsLMST(longitude);
1727  double h = lst - RA; //hour angle
1728  h*= ( M_PI / 12); //hour -> radians
1729  dec *= (M_PI/180); //deg to radians
1730 
1731  double lat = latitude * (M_PI /180);
1732  double Az = atan2( cos(dec) * sin(h), -cos(h) * sin(lat)* cos(dec) + sin(dec) * cos(lat));
1733  double el = asin(sin(lat) * sin(dec) + cos(lat) * cos(dec) * cos(h));
1734 
1735  if (phi) *phi = heading + Az * (180/M_PI);
1736  if (theta) *theta = - el * (180/M_PI);
1737  return 0;
1738 #endif
1739 
1740 }
1741 
1742 
1743 
1744 
1745 
1746 
1747 void UsefulAdu5Pat::getThetaAndPhiWaveHiCal(Double_t& thetaWave, Double_t& phiWave){
1748 
1749  Double_t hiCalLon, hiCalLat, hiCalAlt;
1750  AnitaDataset::hiCal(realTime, hiCalLon, hiCalLat, hiCalAlt);
1751 
1752  if(hiCalAlt == -9999){
1753  thetaWave = -9999;
1754  phiWave = -9999;
1755  }
1756  else {
1757  getThetaAndPhiWave(hiCalLon, hiCalLat, hiCalAlt, thetaWave, phiWave);
1758  }
1759 }
1760 
1761 
1762 
1763 
1764 
1765 void UsefulAdu5Pat::getThetaAndPhiWaveOfRayAtInfinity(const TVector3 & p0, const TVector3 & v0, Double_t & theta, Double_t & phi, Bool_t plus, Double_t eps, Double_t tstep, TVector3 * testp) const
1766 {
1767  tstep = fabs(tstep);
1768  if (!plus) tstep *= -1;
1769 
1770  double last_theta, last_phi;
1771  TVector3 test = p0;
1772  getThetaAndPhiWaveCart(&test, last_theta, last_phi);
1773 
1774  int istep = 1;
1775  while(true)
1776  {
1777 // test.Print();
1778  test = p0 - v0*tstep*istep;
1779 
1780  getThetaAndPhiWaveCart(&test, theta, phi);
1781 // printf("%g %g :: %g %g\n",theta,last_theta, phi,last_phi);
1782  if (fabs(theta-last_theta) < eps && fabs(phi-last_phi) < eps)
1783  {
1784  if (testp) *testp = test;
1785  return;
1786  }
1787  last_theta = theta;
1788  last_phi = phi;
1789 
1790  istep++;
1791  }
1792 }
1793 
Double_t getDeltaTWillyBorehole(Int_t ant1, Int_t ant2)
const Double_t LATITUDE_SIPLE
Latitude of Siple dome pulser.
Double_t getThetaFromLat(Double_t lat)
Converts latitude to polar angle.
int getSourceLonAndLatAtDesiredAlt(Double_t phiWave, Double_t thetaWave, Double_t &sourceLon, Double_t &sourceLat, Double_t desiredAlt)
Destructor.
Double_t getDifferencePointingToSun(Double_t phiAngle, Bool_t inputInDegrees=true) const
Quick way of getting difference between any azimuth phi and the sun&#39;s azimuth phi.
Float_t pitch
in degrees
Definition: Adu5Pat.h:46
int getSourceLonAndLatAtAlt2(Double_t phiWave, Double_t thetaWave, Double_t &sourceLon, Double_t &sourceLat, Double_t &sourceAltitude, Int_t maxLoopIter=-1, TVector3 *sourcePosOptional=NULL) const
Double_t getGeoid(Double_t theta)
Returns the geoid radiuus as a function of theta (the polar angle?)
TVector3 getUnitVectorAlongThetaWavePhiWave(double thetaWave, double phiWave) const
static void hiCal(UInt_t unixTime, Double_t &longitude, Double_t &latitude, Double_t &altitude)
Double_t getAntPhiPositionRelToAftFore(Int_t ant, AnitaPol::AnitaPol_t pol=AnitaPol::kVertical)
get antenna phi position relative to ADU5 AFT-FORE line
static Double_t getReflectionAngle(Double_t plAlt, Double_t imageEl, Double_t imageAlt)
Currently just does direct events...
Adu5Pat – The ADU5 Position and Attitude Data.
Definition: Adu5Pat.h:26
void getThetaAndPhiWaveLDB(Double_t &thetaWave, Double_t &phiWave)
UInt_t getWaisDivideTriggerTimeNs() const
Gets the time of flight to Taylor Dome.
Double_t getAntZ(Int_t ant, AnitaPol::AnitaPol_t pol=AnitaPol::kVertical)
get antenna z position
Float_t latitude
In degrees.
Definition: Adu5Pat.h:42
void getThetaAndPhiWaveWillySeavey(Double_t &thetaWave, Double_t &phiWave)
Float_t longitude
In degrees.
Definition: Adu5Pat.h:43
static Double_t getPhiDiff(Double_t firstPhi, Double_t secondPhi)
Returns the angular difference between two phi values (in radians)
UInt_t realTime
Time from the GPS unit.
Definition: Adu5Pat.h:37
UInt_t getTriggerTimeNsFromSource(Double_t sourceLat, Double_t sourceLong, Double_t sourceAlt) const
Gets the time of flight to LDB camp.
Double_t getAntR(Int_t ant, AnitaPol::AnitaPol_t pol=AnitaPol::kVertical)
get antenna r position
void getThetaWaveAtBase(Double_t baseLon, Double_t baseLat, Double_t baseAlt, Double_t &thetaWave)
void getThetaAndPhiWave(Double_t sourceLon, Double_t sourceLat, Double_t sourceAlt, Double_t &thetaWave, Double_t &phiWave)
const double LONGITUDE_SURF_SEAVEY
Longitude of surface seavey.
UInt_t getLDBTriggerTimeNs() const
Gets the time of flight to Siple.
void getAntXYZ(Int_t ant, Double_t &x, Double_t &y, Double_t &z, AnitaPol::AnitaPol_t pol=AnitaPol::kVertical)
get antenna cartesian coordinates (from photogrammetry)
void setMaxLoopIterations(Int_t n=50)
double surfaceAboveGeoid(Double_t lon, Double_t lat) const
UInt_t getSipleTriggerTimeNs() const
Gets the time of flight to Wais Divide.
Double_t getDeltaTExpected(Int_t ant1, Int_t ant2, Double_t sourceLon, Double_t sourceLat, Double_t sourceAlt)
void getThetaAndPhiWaveWaisDivide(Double_t &thetaWave, Double_t &phiWave)
Float_t altitude
In metres.
Definition: Adu5Pat.h:44
const double ALTITUDE_BH
Altitude of borehole antenna.
void getThetaAndPhiWaveTaylorDome(Double_t &thetaWave, Double_t &phiWave)
Double_t getAzimuthOfSunRelativeToNorth() const
Calculates the azimuth position of the sun if ANITA was facing directly north, relies on timeOfDay...
Double_t getDeltaTTaylor(Int_t ant1, Int_t ant2)
Double_t getAzimuthOfSun() const
void getSunPosition(Double_t &phiDeg, Double_t &thetaDeg) const
Uses realTime, latitude, longitude to calculate the sun&#39;s position.
void getThetaAndPhiWaveCart(TVector3 *sourcePos, Double_t &thetaWave, Double_t &phiWave) const
~UsefulAdu5Pat()
Assignment constructor.
const Double_t LATITUDE_LDB
Latitude at LDB.
Double_t getDeltaTWillySeavey(Int_t ant1, Int_t ant2)
As UsefulAnitaEvent is to RawAnitaEvent, UsefulAdu5Pat is to Adu5Pat. Well not quite as useful but yo...
Definition: UsefulAdu5Pat.h:39
const Double_t LONGITUDE_LDB
Longitude at LDB.
int getSourceLonAndLatAtAlt(Double_t phiWave, Double_t thetaWave, Double_t &sourceLon, Double_t &sourceLat, Double_t &sourceAltitude)
const double ALTITUDE_SURF_SEAVEY
Altitude of surface seavey.
int traceBackToContinent(Double_t phiWave, Double_t thetaWave, Double_t *lon, Double_t *lat, Double_t *alt, Double_t *theta_adjustment_required, Double_t max_theta_adjustment=TMath::Pi()/180, Int_t max_iter=10) const
const double LONGITUDE_BH
Longitude of borehole antenna.
Double_t getPhiFromLon(Double_t lon)
Converts longitude to azimuthal angle.
Double_t getDistanceFromSource(Double_t sourceLat, Double_t sourceLong, Double_t sourceAlt) const
Gets time of flight from any source.
void wrap(size_t N, double *vals, double period=360)
Definition: FFTtools.cxx:2851
UInt_t timeOfDay
in ms since the start of the day
Definition: Adu5Pat.h:41
const Double_t LONGITUDE_SIPLE
Longitude of Siple dome pulser.
int astronomicalCoordinates(Double_t phiWave, Double_t thetaWave, Double_t *RA=0, Double_t *dec=0, Double_t *l=0, Double_t *b=0) const
void updateCartesianBalloonInfo()
const Double_t ALTITUDE_SIPLE
Altitude of Siple dome pulser according to http://mapcarta.com/25623620.
Float_t heading
0 is facing north, 180 is facing south
Definition: Adu5Pat.h:45
int traceBackToContinent3(Double_t phiWave, Double_t thetaWave, Double_t *lon, Double_t *lat, Double_t *alt, Double_t *theta_adjustment_required) const
void getThetaAndPhiWaveOfRayAtInfinity(const TVector3 &p0, const TVector3 &v0, Double_t &thetaWave, Double_t &phiWave, Bool_t plus_infinity=true, Double_t eps=0.00001 *TMath::DegToRad(), Double_t step=10e7, TVector3 *testPosition=0) const
void getThetaAndPhiWave2(Double_t sourceLon, Double_t sourceLat, Double_t sourceAlt, Double_t &thetaWave, Double_t &phiWave, TVector3 *sourcePos=NULL) const
static AnitaGeomTool * Instance(int anita_version=0)
Instance generator. If version_number == 0, uses AnitaVersion::get();.
AnitaGeomTool – The ANITA Geometry Tool.
Definition: AnitaGeomTool.h:48
const double LATITUDE_SURF_SEAVEY
Latitude of surface seavey.
const double LATITUDE_BH
Latitude if borehole antenna.
const Double_t ALTITUDE_LDB
Altitude at LDB.