RefractionModel.cxx
1 #include "RefractionModel.h"
2 #include "AntarcticAtmosphere.h"
3 #include "AntarcticaGeometry.h"
4 #include "TEllipse.h"
5 #include "Adu5Pat.h"
6 #include "TH2.h"
7 #include "TGraph.h"
8 
9 
10 const int nH = 5;
11 const int nh = 4;
12 
13 
14 static const double A[nh][nH] =
15 {
16  { 3.5553, 4.7295, 4.4731, 5.1151, 4.8049 },
17  { 3.2987, 3.1228, 4.0890, 3.7471, 4.4854 },
18  { 2.9440, 2.8858, 2.6563, 3.4098, 3.2843 },
19  { 2.4514, 2.6189, 2.4666, 2.8971, 3.1265 }
20 };
21 
22 
23 static const double B[nh][nH] =
24 {
25  { -0.0095, 0.1173, 0.0907, 0.1432, 0.1149 },
26  { 0.0029, -0.0141, 0.0898, 0.0533, 0.1190 },
27  { 0.0001, -0.0052, -0.0245, 0.0517, 0.0406 },
28  { -0.0156, -0.0026, -0.0170, 0.0214, 0.0584 }
29 };
30 
31 
32 static const double C[nh][nH] =
33 {
34  { 4.3780, 4.5653, 4.5795, 4.7217, 4.7491 },
35  { 4.2998, 4.3507, 4.5034, 4.5180, 4.6733 },
36  { 4.2362, 4.2858, 4.3466, 4.4356, 4.4903 },
37  { 4.3714, 4.3139, 4.3234, 4.3701, 4.4639 }
38 };
39 
40 static const double D[nh][nH] =
41 {
42  { 5.0281, 7.0018, 6.3010, 7.9669, 7.1021 },
43  { 5.4476, 5.3225, 6.8895, 5.8489, 7.8475 },
44  { 5.5789, 5.8992, 5.0228, 6.4541, 6.1882 },
45  { 6.4298, 7.4389, 7.0311, 7.2302, 7.9347 }
46 };
47 
48 static const double E[nh][nH] =
49 {
50  { -5.5423, -5.8028, -5.8366, -6.0156, -6.0501 },
51  { -5.4901, -5.5646, -5.7826, -5.7774, -5.9982 },
52  { -5.4010, -5.5246, -5.5159, -5.7338, -5.7958 },
53  { -5.3860, -5.5437, -5.6085, -5.7002, -5.8241 }
54 };
55 
56 static TH2 * hCoeffs[5] = {0};
57 
58 __attribute__ ((constructor))
59 static void init_hists()
60 {
61  for (int coeff = 0; coeff < 5; coeff++)
62  {
63 
64  hCoeffs[coeff] = new TH2D(TString::Format("pg_coeffs_%c", 'A' + coeff),TString::Format("%c Coeffs", 'A' + coeff) ,
65  nh, -0.5e3, 0.35e3, nH, 35.5e3 , 40.5e3);
66 
67  hCoeffs[coeff]->SetDirectory(0);
68 
69  for (int i = 1; i <= nh; i++)
70  {
71  for (int j = 1; j<= nH; j++)
72  {
73  hCoeffs[coeff]->SetBinContent(i,j, (coeff == 0 ? A :
74  coeff == 1 ? B :
75  coeff == 2 ? C :
76  coeff == 3 ? D :
77  E)[i-1][j-1]);
78  }
79  }
80  }
81 }
82 
83 
84 
85 double Refraction::PositionIndependentModel::getElevationCorrection(const Adu5Pat * pat, const AntarcticCoord * source, double * correction_at_source, double dth) const
86 {
87 
88  PayloadParameters pp(pat,*source);
89  double H = AntarcticAtmosphere::WGS84toMSL(pat);
90  AntarcticCoord s = source->as(AntarcticCoord::WGS84);
91  double h = AntarcticAtmosphere::WGS84toMSL(s.x,s.y,s.z);
92 
93  double last_corr = 0;
94  double last_at_source= 0;
95  double theta = pp.source_theta + dth;
96  while(true)
97  {
98 
99  double at_source;
100  double corr = getElevationCorrection(theta, h,H, &at_source);
101 
102  if (!isnan(corr))
103  {
104  last_corr = corr;
105  last_at_source = at_source;
106 
107  if (theta + corr > pp.source_theta);
108  break;
109 
110  }
111  else break;
112 
113  theta += dth;
114  }
115 
116 
117  if (correction_at_source) *correction_at_source = last_at_source;
118  return last_corr;
119 }
120 
121 double Refraction::PGFit::getElevationCorrection(double theta, double h, double H, double * correction_at_source) const
122 {
123 
124  // pin to limits
125  if (h > 4e3) h = 4e3;
126  if (h < 0) h = 0;
127  if (H < 36e3) H = 36e3;
128  if (H > 40e3) H = 40e3;
129 
130  double a = hCoeffs[0]->Interpolate(h,H);
131  double b = hCoeffs[1]->Interpolate(h,H);
132  double c = hCoeffs[2]->Interpolate(h,H);
133  double d = hCoeffs[3]->Interpolate(h,H);
134  double e = hCoeffs[4]->Interpolate(h,H);
135  double el = -theta;
136  return -(a / (el * el) + b / (el) + c * exp(d * (el-e)));
137  if (correction_at_source) *correction_at_source = 0; //we don't provide one
138 }
139 
140 
141 const double speed_of_light=299792458;
142 int Refraction::RaytracerSpherical::raytrace(const Setup * setup, Result * result)
143 {
144 
145  last_path_x.clear();
146  last_path_X.clear();
147  last_path_y.clear();
148  last_path_s.clear();
149  last_path_t.clear();
150  last_R_c = setup->R_c;
151 
152  double r0 = setup->start_alt + setup->R_c;
153  double r1 = setup->end_alt + setup->R_c;
154  double theta = setup->thrown_payload_angle * TMath::DegToRad();
155  double r = r0;
156  double phi=0;
157  double x0 = 0;
158  double y0 = r0;
159 
160  double x= x0;
161  double y= y0;
162  result->ray_distance = 0;
163  result->ray_time = 0;
164  result->reflected = false;
165  result->reflection_angle =-1;
166  result->reflect_xy[0] = 0;
167  result->reflect_xy[1] = 0;
168 
169  double reflect_r = setup->R_c + setup->surface_alt;
170  double X = 0;//really the complement grammage here
171 
172  while (r <= r1)
173  {
174 
175  last_path_x.push_back(x);
176  last_path_X.push_back(X);
177  last_path_y.push_back(y);
178  last_path_s.push_back(result->ray_distance);
179  last_path_t.push_back(result->ray_time);
180  // we want to step in r dphi
181 
182  double dphi = step_size / r;
183  double dr= step_size * tan(theta);
184 
185  bool am_reflecting = false;
186  // check if we are going to bounce off
187  if (r+dr < reflect_r)
188  {
189  am_reflecting = true;
190  dr = reflect_r-r;
191  double temp_step_size = dr/tan(theta);
192  dphi = temp_step_size / r;
193  }
194 
195  double N = m->get(r-setup->R_c, AntarcticAtmosphere::REFRACTIVITY);
196  double N1 = m->get(r-setup->R_c+dr, AntarcticAtmosphere::REFRACTIVITY);
197  double DN = N1-N ;
198  double dn = DN * 1e-6;
199  double n = 1 + N * 1e-6;
200  // printf("%g\n",tan(theta) * r);
201  double dtheta = dn/n/tan(theta) + dphi;
202 // printf("%g %g %g\n", r,theta,dtheta);
203 
204  double dL = sqrt((r*dphi)*(r*dphi) + dr*dr);
205  double rho = m->get(r-setup->R_c,AntarcticAtmosphere::DENSITY);
206  result->ray_distance += dL;
207  if (rho < 0) rho = 0;
208  X += dL*rho;
209  result->ray_time += dL * n / speed_of_light;
210 // printf("%g %g %g %g\n",dphi,dtheta, phi,theta);
211  theta += dtheta;
212  phi += dphi;
213  r += dr;
214  x = r* sin(phi);
215  y = r* cos(phi);
216 
217  if (am_reflecting)
218  {
219  //grammage no longer makes sense. set it to 0 here and everywhere before;
220  X = 0;
221  for (unsigned i =0; i < last_path_X.size(); i++) last_path_X[i] = 0;
222  theta = -theta;
223  result->reflected = true;
224  result->reflection_angle = theta * TMath::RadToDeg();
225  result->reflect_xy[0] = x;
226  result->reflect_xy[1] = y;
227  }
228  }
229 
230  last_path_x.push_back(x);
231  last_path_y.push_back(y);
232  last_path_s.push_back(result->ray_distance);
233  last_path_t.push_back(result->ray_time);
234  last_path_X.push_back(X);
235 
236  for (unsigned i = 0; i < last_path_X.size();i++) last_path_X[i]=X-last_path_X[i];
237  double dx = x- x0;
238  double dy = y- y0;
239  double dM = sqrt(dx*dx + dy*dy);
240 
241  double last_dx = last_path_x[last_path_x.size()-1]-last_path_x[last_path_x.size()-2];
242  double last_dy = last_path_y[last_path_y.size()-1]-last_path_y[last_path_y.size()-2];
243  double last_r = sqrt(last_dx*last_dx + last_dy*last_dy);
244  result->last_dx = last_dx/last_r;
245  result->last_dy = last_dy/last_r;
246  result->full_dx = dx/dM;
247  result->full_dy = dy/dM;
248  result->x = x;
249  result->y = y;
250  result->r = r;
251  result->actual_distance = dM;
252  result->surface_distance = phi * setup->R_c;
253  result->apparent_source_angle = theta * TMath::RadToDeg();
254  result->actual_source_angle = 90 - acos( (dx*x + dy*y) / (r * dM)) *TMath::RadToDeg();
255  result->actual_payload_angle = 90 - acos(dy/dM) * TMath::RadToDeg();
256  return 0;
257 }
258 
259 
260 
261 TGraph* Refraction::RaytracerSpherical::makeXYGraph(TGraph * g) const
262 {
263  if (!g) return new TGraph (last_path_x.size(), &last_path_x[0], &last_path_y[0]);
264  g->Set(last_path_x.size());
265  memcpy(g->GetY(), &last_path_y[0], g->GetN()*sizeof(double));
266  memcpy(g->GetX(), &last_path_x[0], g->GetN()*sizeof(double));
267  return g;
268  //TEllipse * e = new TEllipse(0,0,POLAR_C, POLAR_C);
269 // e->SetLineColor(4);
270 // e->Draw("lsame");
271 
272 }
273 TGraph* Refraction::RaytracerSpherical::makeXTGraph(TGraph *g) const
274 {
275  if (!g) return new TGraph (last_path_x.size(), &last_path_x[0], &last_path_t[0]);
276  g->Set(last_path_x.size());
277  memcpy(g->GetY(), &last_path_t[0], g->GetN()*sizeof(double));
278  memcpy(g->GetX(), &last_path_x[0], g->GetN()*sizeof(double));
279  return g;
280 
281 }
282 
283 
284 TGraph * Refraction::RaytracerSpherical::makePhiAltGraph(TGraph * g) const
285 {
286 
287  if (!g) g = new TGraph(last_path_x.size());
288  else g->Set(last_path_x.size());
289 
290  for (int i = 0; i < g->GetN(); i++)
291  {
292  g->SetPoint(i, 90-atan2(last_path_y[i], last_path_x[i])*TMath::RadToDeg(), sqrt(last_path_x[i]*last_path_x[i] + last_path_y[i]*last_path_y[i])- last_R_c);
293  }
294  return g;
295 }
296 
297 TGraph* Refraction::RaytracerSpherical::makeSTGraph(TGraph *g) const
298 {
299  if (!g) return new TGraph (last_path_x.size(), &last_path_s[0], &last_path_t[0]);
300  g->Set(last_path_x.size());
301  memcpy(g->GetY(), &last_path_t[0], g->GetN()*sizeof(double));
302  memcpy(g->GetX(), &last_path_s[0], g->GetN()*sizeof(double));
303  return g;
304 }
305 
306 
307 double Refraction::RaytracerSpherical::lastMinAlt() const
308 {
309  if (!nSteps()) return -9999;
310 
311  double R2min = last_path_x[0]*last_path_x[0] + last_path_y[0] * last_path_y[0];
312 
313  for (int i =1; i < nSteps(); i++)
314  {
315  double R2= last_path_x[i]*last_path_x[i] + last_path_y[i] * last_path_y[i];
316  if (R2 < R2min) R2min = R2;
317  }
318 
319  return sqrt(R2min) - last_R_c;
320 }
321 
322 TGraph* Refraction::RaytracerSpherical::makeRTGraph(TGraph * g) const
323 {
324  if (!g) g = new TGraph (last_path_t.size());
325  else g->Set(last_path_t.size());
326 
327  for (int i = 0; i < g->GetN(); i++)
328  {
329  g->SetPoint(i,last_path_t[i],sqrt(last_path_x[i]*last_path_x[i] + last_path_y[i]*last_path_y[i]) -last_R_c);
330  }
331  return g;
332 
333 }
334 
335 
336 double Refraction::SphRay::getElevationCorrection(double el, double hSource, double hPayload, double * correction_at_source ) const
337 {
338 
339 
340  UInt_t hash = 0;
341 
342  if (use_cache)
343  {
344  //use a very dumb hash for now, assuming a certain range for the start and end heights and 10 m / 0.01 degree height / angle precision.
345 
346  //box hSource into (0,5000,nearest multiple of 100)
347  hSource = TMath::Max(0., hSource);
348  hSource = TMath::Min(4999., hSource);
349  hSource = ((int)hSource/100) * 100;
350  hash += hSource / 100;
351 
352  //box hPayload into (36000,41000,nearest multiple of 100)
353  hPayload = TMath::Max(36e3, hPayload);
354  hPayload = TMath::Min(40.999e3, hPayload);
355  hPayload = ((int)hPayload/100) * 100;
356  hash += 50 * ((hPayload-36e3) / 100);
357 
358 
359  // box el into (0,90, nearest hundredth of a degree)
360  el = TMath::Min(90.,el);
361  el = TMath::Max(0.,el);
362  el = ((int) (el * 100)) / 100.;
363 // printf("%g %g %g\n", hSource, hPayload, el);
364  hash += 50 * 50 * el * 100;
365 
366  TLockGuard l(&cache_lock);
367  if (cache.count(hash))
368  {
369  if (correction_at_source)
370  *correction_at_source = cache[hash].second;
371  return cache[hash].first;
372  }
373  }
374 
375  //create the ray tracer
376  RaytracerSpherical ray(atm);
377  ray.step_size = step;
378 
379  //compute the horizon angle at the ground
380 
381  double throw_angle = TMath::RadToDeg() * acos ( cos(el * TMath::DegToRad()) * (R_c + hPayload) / (R_c + hSource) * (1 + 1e-6 * atm->get(hPayload, AntarcticAtmosphere::REFRACTIVITY)) / (1 + 1e-6 * atm->get(hSource, AntarcticAtmosphere::REFRACTIVITY)));
382 
383  RaytracerSpherical::Setup s;
384  RaytracerSpherical::Result r;
385  s.save_path = false;
386  s.start_alt = hSource;
387  s.end_alt = hPayload;
388  s.thrown_payload_angle = throw_angle;
389  s.R_c = R_c;
390 
391  ray.raytrace(&s,&r);
392 
393 
394  double answer = r.actual_source_angle - r.apparent_source_angle;
395  double correction = r.actual_payload_angle - s.thrown_payload_angle;
396 
397 
398  if (use_cache)
399  {
400  TLockGuard l(&cache_lock);
401  if (!cache.count(hash))
402  cache[hash] = std::pair<double,double> (answer, correction) ;
403  }
404 
405  if (correction_at_source) *correction_at_source = correction;
406  return answer ;
407 }
408 
409 
410 void Refraction::SphRay::adjustLatitude(double lat, double bearing)
411 {
412  if (use_cache)
413  {
414  TLockGuard l(&cache_lock);
415  cache.clear();
416  }
417 
418 
419  const double a = 6378137.0 ;
420  const double b = 6356752.3;
421  const double ab = a*b;
422  const double ab2inv = 1./(ab*ab);
423  const double a2 = a*a;
424  const double a2inv = 1./a2;
425  const double b2 = b*b;
426  double sin_lat = sin(lat*TMath::DegToRad());
427  double cos_lat = cos(lat*TMath::DegToRad());
428  double sin2_lat = sin_lat*sin_lat;
429  double cos2_lat = cos_lat*cos_lat;
430 
431  double arg = a2*cos2_lat + b2*sin2_lat;
432  double Minv = ab2inv * pow(arg,1.5);
433  double Ninv = a2inv * sqrt(arg);
434 
435  double sin_alpha = sin(bearing*TMath::DegToRad());
436  double cos_alpha = cos(bearing*TMath::DegToRad());
437  double sin2_alpha = sin_alpha*sin_alpha;
438  double cos2_alpha = cos_alpha*cos_alpha;
439 
440  R_c = pow(cos2_alpha*Minv + sin2_alpha*Ninv,-1);
441 
442 }
443 
444 
445 
446 
447 
struct __attribute__((packed))
Debugging use only TURF scaler data.
Adu5Pat – The ADU5 Position and Attitude Data.
Definition: Adu5Pat.h:26