1 #include "AntarcticAtmosphere.h" 6 #include "TObjString.h" 11 #ifdef USE_GEOGRAPHIC_LIB 12 #include "GeographicLib/Geoid.hpp" 16 const double REARTH = 6369;
17 const double GMR = 34.163195;
30 static double htab[] = {0.0, 11.0, 20.0, 32.0, 47.0, 51.0, 71.0, 84.852 };
31 static double ttab[] = { 288.15, 216.65, 216.65, 228.65, 270.65, 270.65, 214.65, 186.946 };
32 static double ptab[] = { 1.0, 2.233611E-1, 5.403295E-2, 8.5666784E-3, 1.0945601E-3, 6.6063531E-4, 3.9046834E-5, 3.68501E-6 };
33 static double gtab[] = {-6.5, 0.0, 1.0, 2.8, 0.0, -2.8, -2.0, 0.0 };
35 static int us_atmosphere(
double alt_km,
double * rel_rho,
double * rel_P,
double * rel_T)
42 double sigma, delta, theta;
44 h = alt_km * REARTH / (alt_km + REARTH);
66 tlocal = tbase + tgrad * deltah;
68 theta = tlocal / ttab[0];
72 delta = ptab[i] * exp(- GMR*deltah / tbase);
76 delta = ptab[i] * pow(tbase / tlocal , GMR/tgrad);
88 int AntarcticAtmosphere::StandardUS::computeAtmosphere(
double h, Pars *p,
double phi)
const 93 int ret = us_atmosphere(h/1e3, &p->rho, &p->P, &p->T);
96 p->rho *= 1.225 * sea_level_T / sea_level_P;
97 p->N = 77.6 * p->P / p->T;
102 double AntarcticAtmosphere::ArtificialInversion::correction(
double h)
const 104 if (h > hmax)
return 1;
105 else return 1 - (hmax - h)/hmax * Amax;
110 int AntarcticAtmosphere::ArtificialInversion::computeAtmosphere(
double h, Pars *p,
double phi)
const 113 int ret = m.computeAtmosphere(h,p);
114 p->T *= correction(h);
115 p->rho *= correction(h);
116 p->N *= correction(h);
120 double AntarcticAtmosphere::ArtificialInversion::get(
double h, Par p,
double phi)
const 124 if (p == REFRACTIVITY)
return m.get(h,p) * correction(h);
125 else if (p == TEMPERATURE)
return m.get(h,p) * correction(h);
126 else if (p == DENSITY)
return m.get(h,p) * correction(h);
127 else return m.get(h,p) ;
132 int AntarcticAtmosphere::ExponentialRefractivity::computeAtmosphere(
double h, Pars *p,
double phi)
const 136 int ret = us_atmosphere(h/1e3, &p->rho, &p->P, &p->T);
139 p->rho *= 1.225 * sea_level_T / sea_level_P;
140 p->N = k_A * exp(-k_B * h);
144 double AntarcticAtmosphere::ExponentialRefractivity::get(
double h, Par p,
double phi)
const 148 if (p == REFRACTIVITY)
return k_A * exp(-k_B* h) ;
150 computeAtmosphere(h,&x);
168 #ifdef USE_GEOGRAPHIC_LIB 170 static const GeographicLib::Geoid & geoid2008_1()
172 static GeographicLib::Geoid g(
"egm2008-1");
176 static GeographicLib::Geoid & geoid96_5()
178 static GeographicLib::Geoid g(
"egm96-5");
182 static const GeographicLib::Geoid & getGeoid(AntarcticAtmosphere::Geoid g)
186 case AntarcticAtmosphere::EGM2008_1:
187 return geoid2008_1();
193 double AntarcticAtmosphere::MSLtoWGS84(
double h,
double lat,
double lon, Geoid g)
195 return getGeoid(g).ConvertHeight ( lat, lon, h, GeographicLib::Geoid::GEOIDTOELLIPSOID);
198 double AntarcticAtmosphere::WGS84toMSL(
double lat,
double lon,
double alt, Geoid g)
200 return getGeoid(g).ConvertHeight(lat,lon,alt, GeographicLib::Geoid::ELLIPSOIDTOGEOID);
203 double AntarcticAtmosphere::WGS84toMSL(
const Adu5Pat * pat, Geoid g)
205 return getGeoid(g).ConvertHeight ( pat->
latitude, pat->
longitude, pat->
altitude, GeographicLib::Geoid::ELLIPSOIDTOGEOID);
210 double AntarcticAtmosphere::WGS84toMSL(
const Adu5Pat * pat, Geoid g )
212 static int nagged = 0;
216 fprintf(stderr,
"Need GeographicLib for MSL conversions\n");
223 double AntarcticAtmosphere::WGS84toMSL(
double lat,
double lon,
double alt, Geoid g)
226 static int nagged = 0;
230 fprintf(stderr,
"Need GeographicLib for MSL conversions\n");
236 double AntarcticAtmosphere::MSLtoWGS84(
double h,
double lat,
double lon, Geoid g)
238 static int nagged = 0;
242 fprintf(stderr,
"Need GeographicLib for MSL conversions\n");
252 TGraph * AntarcticAtmosphere::AtmosphericModel::makeGraph(
double hmin,
double hmax,
int nh, Par p,
bool alt_on_x,
double phi)
const 255 TGraph * g =
new TGraph(nh);
257 (alt_on_x ? g->GetYaxis() : g->GetXaxis())->SetTitle( p== DENSITY ?
"Density (kg/m^3)" :
258 p== PRESSURE ?
"Pressure (hPa) " :
259 p== TEMPERATURE ?
"Temperature (K)" :
260 "(n - 1) #times 10^{6}");
262 (alt_on_x ? g->GetXaxis() : g->GetYaxis())->SetTitle(
"Height above MSL (m)");
265 for (
int i = 0; i < nh; i++)
267 double h = hmin + i*(hmax-hmin)/(nh-1);
269 double val =
get(h,p,phi);
271 g->SetPoint(i, h,val);
273 g->SetPoint(i, val,h);
280 double AntarcticAtmosphere::AtmosphericModel::get(
double h, Par p,
double phi)
const 283 computeAtmosphere(h,&x,phi);
302 static ExponentialRefractivity er(315,0.1361e-3);
309 static const char * sp_base =
"ftp://amrc.ssec.wisc.edu/pub/southpole/radiosonde";
320 bool operator< (
const atm_meas & other)
const 328 int AntarcticAtmosphere::SPRadiosonde::computeAtmosphere(
double h, Pars *p,
double phi)
const 331 p->rho = h > rho.GetX()[rho.GetN()-1] ? rhofit.Eval(h) : rho.Eval(h);
332 p->P = h > P.GetX()[P.GetN()-1] ? Pfit.Eval(h) : P.Eval(h);
333 p->T = h > T.GetX()[T.GetN()-1] ? Tfit.Eval(h) : T.Eval(h);
334 p->N = h > N.GetX()[N.GetN()-1] ? Nfit.Eval(h) : N.Eval(h);
342 Nfit(
"Nfit",
"expo",10e3,50e3) ,
343 Pfit(
"Pfit",
"expo",10e3,50e3) ,
344 Tfit(
"Tfit",
"expo",10e3,50e3) ,
345 rhofit(
"rhofit",
"expo",10e3,50e3)
349 char * local_dir = getenv(
"RADIOSONDE_DIR");
350 cmd.Form(
"%s %s/%d/%02d%02d%02d%02ddat.txt",local_dir ?
"cat " :
"curl", local_dir ? local_dir : sp_base,year,mon,day,year % 100, early? 0 :late_time);
351 TString data = gSystem->GetFromPipe(cmd.Data());
356 fprintf(stderr,
"Haven't implemented parsing older radiosonde profiles yet...\n");
360 my_name.Form(
"SP Radiosonde %d-%d-%d %s", year,mon,day, early ?
" early " :
"late");
364 TObjArray *lines = data.Tokenize(
"\n");
365 lines->SetOwner(
true);
370 std::vector<atm_meas> v;
374 for (
int i = 10; i < lines->GetEntries(); i++)
376 const char * line = ((TObjString*)lines->At(i))->GetString().Data();
379 float hPa,T,dwp,speed;
380 sscanf(line,
"%d %d %g %g %g %d %g %d", &s,&h,&hPa,&T,&dwp,&rh,&speed,&dir);
389 double EF=1+1e-4 * (2.2 +m.P*(0.00382 + 6.4e-7 * (T*T)));
390 const double a = 6.115;
391 const double b = 23.036;
392 const double c = 279.82;
393 const double d = 333.7;
394 double e_s = EF * a * exp( (( b-T/d)*T)/(T+c));
396 double e= e_s*rh/100.;
398 m.N = 77.6 * m.P / m.T - 5.6 * e / m.T + 3e5 * e / (m.T*m.T);
400 m.rho = (m.P*100) / (287.058 *m.T);
405 std::sort(v.begin(), v.end());
412 for (
unsigned i = 0; i < v.size(); i++)
415 P.SetPoint(i, v[i].h, v[i].P);
416 T.SetPoint(i, v[i].h, v[i].T);
417 N.SetPoint(i, v[i].h, v[i].N);
418 rho.SetPoint(i, v[i].h, v[i].rho);
421 #if ROOT_VERSION_CODE >= ROOT_VERSION(6,7,0) 422 P.SetBit(TGraph::kIsSortedX);
423 T.SetBit(TGraph::kIsSortedX);
424 N.SetBit(TGraph::kIsSortedX);
425 rho.SetBit(TGraph::kIsSortedX);
431 rho.Fit(&rhofit,
"RQ");
435 int AntarcticAtmosphere::InterpolatedAtmosphere::computeAtmosphere(
double h,
Pars * p,
double phi)
const 439 if (atms.size()==0)
return 1;
443 (*atms.begin()).second->computeAtmosphere(h,p,phi);
449 std::set<std::pair<double,const AtmosphericModel*> >::const_iterator it = atms.lower_bound(std::pair<double,const AtmosphericModel*>(phi,0));
452 if (it == atms.begin())
454 (*atms.begin()).second->computeAtmosphere(h,p,phi);
459 if (it == atms.end())
462 (*atms.rbegin()).second->computeAtmosphere(h,p,phi);
468 double phi1 = (*it).first;
469 const AtmosphericModel * m1 =(*it).second;
471 double phi0 = (*it).first;
472 const AtmosphericModel * m0 =(*it).second;
474 double frac= phi1==phi0 ? 0.5: (phi-phi0)/(phi1-phi0);
480 m0->computeAtmosphere(h,&p0,phi);
481 m1->computeAtmosphere(h,&p1,phi);
483 p->rho = p0.rho * (1-frac) + frac*p1.rho;
484 p->P = p0.P * (1-frac) + frac*p1.P;
485 p->T = p0.T * (1-frac) + frac*p1.T;
486 p->N = p0.N * (1-frac) + frac*p1.N;
Adu5Pat – The ADU5 Position and Attitude Data.
Float_t latitude
In degrees.
Float_t longitude
In degrees.
SPRadiosonde(int year, int month, int day, bool early=true)
Float_t altitude
In metres.