1 #include "GeoMagnetic.h" 8 #include "TObjString.h" 10 #include "RampdemReader.h" 11 #include "AntarcticaBackground.h" 15 #include "AnitaGeomTool.h" 16 #include "UsefulAdu5Pat.h" 17 #include "TGraphAntarctica.h" 26 bool doneInit =
false;
27 const int numPoly = 14;
28 std::vector<double> factorials(2*numPoly, 0);
29 std::map<int, std::vector<double> > g_vs_time;
30 std::map<int, std::vector<double> > h_vs_time;
31 const double earth_radius = 6371.2e3;
32 TF1* fAssocLegendre[numPoly][numPoly] = {{NULL}};
38 const double dTheta = 0.01*TMath::DegToRad();
39 const double dPhi = 0.01*TMath::DegToRad();
44 TGraph grAtmosDensity;
59 inline double getIndex(
int n,
int m){
67 void getGaussCoefficients(){
69 const char* anitaUtilInstallDir = getenv(
"ANITA_UTIL_INSTALL_DIR");
70 if(!anitaUtilInstallDir){
71 std::cerr <<
"Warning in " << __FILE__ <<
", ANITA_UTIL_INSTALL_DIR not set" << std::endl;
73 TString fileName = TString::Format(
"%s/share/anitaCalib/igrf12coeffs.txt", anitaUtilInstallDir);
74 std::ifstream coeffs(fileName);
77 std::cerr <<
"Error in " << __FILE__ <<
" unable to find " << fileName.Data() << std::endl;
80 const int expectedTokens = 28;
81 std::vector<std::vector<TString> > igrfDataTableStrings;
84 std::getline(coeffs, line);
88 TString s = line.c_str();
91 s.ReplaceAll(
"\r",
"");
93 TObjArray* tokens = s.Tokenize(
' ');
94 int numTokens = tokens->GetEntries();
97 igrfDataTableStrings.push_back(std::vector<TString>());
99 if(numTokens!=expectedTokens){
100 std::cerr <<
"Warning parsing " << fileName <<
", found " << numTokens <<
" tokens in line..." << std::endl;
101 std::cerr << line << std::endl;
104 for(
int i=0; i < numTokens; i++){
105 TString thisS = ((TObjString*)tokens->At(i))->GetString();
106 igrfDataTableStrings.back().push_back(thisS);
114 const int numRows = igrfDataTableStrings.size();
118 std::vector<TString>& headerRow2 = igrfDataTableStrings.at(1);
121 std::map<unsigned, int> colToYear;
122 for(
unsigned col=3; col < headerRow2.size() - 1; col++){
123 int year = atoi(headerRow2[col].Data());
124 colToYear[col] = year;
129 for(
int row=2; row < numRows; row++){
130 std::vector<TString>& thisRow = igrfDataTableStrings.at(row);
133 const TString& g_or_h = thisRow[0];
134 const int n = atoi(thisRow[1].Data());
135 const int m = atoi(thisRow[2].Data());
137 int index = getIndex(n, m);
141 for(
unsigned col=3; col < thisRow.size() - 1; col++){
142 int year = colToYear[col];
144 std::map<int, std::vector<double> >::iterator it;
149 it = g_vs_time.find(year);
150 if(it!=g_vs_time.end()){
151 it->second.at(index) = atof(thisRow.at(col).Data());
154 g_vs_time[year] = std::vector<double>(numPoly*numPoly, 0);
155 g_vs_time[year].at(index) = atof(thisRow.at(col).Data());
159 else if (g_or_h ==
"h"){
160 it = h_vs_time.find(year);
161 if(it!=h_vs_time.end()){
162 it->second.at(index) = atof(thisRow.at(col).Data());
165 h_vs_time[year] = std::vector<double>(numPoly*numPoly, 0);
166 h_vs_time[year].at(index) = atof(thisRow.at(col).Data());
170 std::cerr <<
"Warning! Unknown coefficient " << g_or_h <<
"[" << n <<
"][" << m <<
"]" << std::endl;
188 void prepareGeoMagnetics(){
191 getGaussCoefficients();
192 for(
int i=0 ; i< 2*numPoly; i++){
193 factorials.at(i) = TMath::Factorial(i);
196 for(
int n=1; n < numPoly; n++){
197 for(
int m=0; m <=n; m++){
198 if(!fAssocLegendre[n][m]){
199 TString name = TString::Format(
"fAssocLegendre_%d_%d", n, m);
200 TString formula = TString::Format(
"ROOT::Math::assoc_legendre(%d, %d, x)", n, m);
201 fAssocLegendre[n][m] =
new TF1(name, formula, -1, 1);
207 const int numAtmospherePoints = 8;
208 double heights[numAtmospherePoints] = {-611, 11019, 20063, 32162, 47350, 51413, 71802, 86000};
209 double densities[numAtmospherePoints] = {1.2985, 0.3639, 0.0880, 0.0132, 0.0020, 0, 0, 0 };
210 for(
int i=0; i < numAtmospherePoints; i++){
211 grAtmosDensity.SetPoint(i, heights[i], densities[i]);
213 grAtmosDensity.SetTitle(
"Atmospheric density (International Standard); Altitude above MSL (m); Densities (kg/m^{3})");
214 grAtmosDensity.SetName(
"grAtmosDensity");
215 grAtmosDensity.Fit(
"expo",
"Q");
216 fExpAtmos = (TF1*) grAtmosDensity.FindObject(
"expo");
218 std::cerr <<
"Warning in " << __FILE__ <<
" unable to find exponential fit to atmosphere..." << std::endl;
236 double getFactorial(
int i){
238 std::cerr <<
"Too high factorial requested!" << std::endl;
241 return factorials[i];
255 double unixTimeToFractionalYear(UInt_t unixTime){
256 TDatime t2(unixTime);
257 int thisYear = t2.GetYear();
258 TDatime t1(thisYear, 0, 0, 0, 0, 0);
259 UInt_t unixTimeYearStart = t1.Convert();
260 TDatime t3(thisYear+1, 0, 0, 0, 0, 0);
261 UInt_t unixTimeNextYear = t3.Convert();
262 double year = thisYear;
263 year += double(unixTime - unixTimeYearStart)/double(unixTimeNextYear - unixTimeYearStart);
283 void lonLatAltToSpherical(
double lon,
double lat,
double alt,
double& r,
double& theta,
double& phi){
286 double x = cartesian[0];
287 double y = cartesian[1];
288 double z = cartesian[2];
291 z = lat >= 0 ? TMath::Abs(z) : -TMath::Abs(z);
293 r = TMath::Sqrt(x*x + y*y + z*z);
294 theta = r > 0 ? TMath::ACos(z/r) : 0;
295 phi = -TMath::ATan2(y, x) + 0.5*TMath::Pi();
296 phi = phi >= TMath::Pi() ? phi - TMath::TwoPi() : phi;
314 TVector3 lonLatAltToVector(
double lon,
double lat,
double alt){
315 double r, theta, phi;
316 lonLatAltToSpherical(lon, lat, alt, r, theta, phi);
318 v.SetMagThetaPhi(r, theta, phi);
336 void sphericalToLatLonAlt(
double& lon,
double& lat,
double& alt,
double r,
double theta,
double phi){
338 double x = r*TMath::Sin(phi)*TMath::Sin(theta);
339 double y = r*TMath::Cos(phi)*TMath::Sin(theta);
340 double z = r*TMath::Cos(theta);
341 double cartesian[3] = {x, y, z};
344 g->getLatLonAltFromCartesian(cartesian, lat, lon, alt);
347 lat = theta*TMath::RadToDeg() <= 90 ? -lat : lat;
360 void vectorToLonLatAlt(
double& lon,
double& lat,
double& alt,
const TVector3& v){
361 sphericalToLatLonAlt(lon, lat, alt, v.Mag(), v.Theta(), v.Phi());
387 void GeoMagnetic::setDebug(
bool db){
406 double GeoMagnetic::g(UInt_t unixTime,
int n,
int m){
407 prepareGeoMagnetics();
409 int index = getIndex(n, m);
410 return g_vs_time[year].at(index);
428 double GeoMagnetic::h(UInt_t unixTime,
int n,
int m){
429 prepareGeoMagnetics();
431 int index = getIndex(n, m);
432 return h_vs_time[year].at(index);
456 double evalSchmidtQuasiNormalisedAssociatedLegendre(
int n,
int m,
double x){
458 double norm = m == 0 ? 1 : TMath::Sqrt(2*getFactorial(n-m)/getFactorial(n+m));
459 double P_n_m = norm*fAssocLegendre[n][m]->Eval(x);
461 if(TMath::IsNaN(P_n_m)){
462 std::cerr <<
"You got a NaN... " << norm <<
"\t" << m <<
"\t" << n <<
"\t" << x << std::endl;
482 double GeoMagnetic::getPotentialAtSpherical(UInt_t unixTime,
double r,
double theta,
double phi){
483 prepareGeoMagnetics();
488 for(
int n=1; n < numPoly; n++){
489 for(
int m=0; m <= n; m++){
493 double this_g = GeoMagnetic::g(unixTime, n, m);
495 part += this_g*TMath::Cos(mPhi);
497 double this_h = GeoMagnetic::h(year, n, m);
499 part += this_h*TMath::Sin(mPhi);
503 double cosTheta = TMath::Cos(theta);
504 double P_n_m = evalSchmidtQuasiNormalisedAssociatedLegendre(n, m, cosTheta);
505 part *= earth_radius*pow(earth_radius/r, n+1)*P_n_m;
508 if(TMath::IsNaN(part)){
509 std::cout << earth_radius <<
"\t" << r <<
"\t" << pow(earth_radius/r, n+1) <<
"\t" << this_g <<
"\t" << cos(mPhi) <<
"\t" << this_h <<
"\t" << sin(mPhi) <<
"\t" << P_n_m << std::endl;
536 double GeoMagnetic::getPotentialAtLonLatAlt(UInt_t unixTime,
double lon,
double lat,
double alt){
537 prepareGeoMagnetics();
539 double r, theta, phi;
540 lonLatAltToSpherical(lon, lat, alt, r, theta, phi);
541 return getPotentialAtSpherical(unixTime, r, theta, phi);
558 double GeoMagnetic::X_atLonLatAlt(UInt_t unixTime,
double lon,
double lat,
double alt){
559 prepareGeoMagnetics();
560 double r, phi, theta;
561 lonLatAltToSpherical(lon, lat, alt, r, theta, phi);
563 return X_atSpherical(unixTime, r, theta, phi);
578 double GeoMagnetic::X_atSpherical(UInt_t unixTime,
double r,
double theta,
double phi){
579 prepareGeoMagnetics();
580 double V0 = getPotentialAtSpherical(unixTime, r, theta, phi);
581 double V1 = getPotentialAtSpherical(unixTime, r, theta+dTheta, phi);
582 double BX = (V1-V0)/(dTheta*r);
599 double GeoMagnetic::Y_atLonLatAlt(UInt_t unixTime,
double lon,
double lat,
double alt){
600 prepareGeoMagnetics();
601 double r, phi, theta;
602 lonLatAltToSpherical(lon, lat, alt, r, theta, phi);
603 return Y_atSpherical(unixTime, lon, lat, alt);
617 double GeoMagnetic::Y_atSpherical(UInt_t unixTime,
double r,
double theta,
double phi){
618 prepareGeoMagnetics();
619 double V0 = getPotentialAtSpherical(unixTime, r, theta, phi);
620 double V1 = getPotentialAtSpherical(unixTime, r, theta, phi+dPhi);
621 double BY = -(V1-V0)/(dPhi*r*TMath::Sin(theta));
638 double GeoMagnetic::Z_atLonLatAlt(UInt_t unixTime,
double lon,
double lat,
double alt){
639 prepareGeoMagnetics();
640 double r, theta, phi;
641 lonLatAltToSpherical(lon, lat, alt, r, theta, phi);
642 return Z_atSpherical(unixTime, r, theta, phi);
657 TCanvas* GeoMagnetic::plotFieldAtAltitude(UInt_t unixTime,
double altitude){
659 TCanvas* c =
new TCanvas();
662 int nx = bg->GetNbinsX();
663 int ny = bg->GetNbinsY();
665 bg->SetBit(kCanDelete);
667 const int arrowEvery = 20;
668 for(
int by=1; by <= ny; by+=arrowEvery){
669 double northing = bg->GetYaxis()->GetBinLowEdge(by);
670 for(
int bx=1; bx <= nx; bx+=arrowEvery){
671 double easting = bg->GetXaxis()->GetBinLowEdge(bx);
674 FieldPoint* f =
new FieldPoint(unixTime, lon, lat, altitude);
675 f->SetBit(kMustCleanup);
676 f->SetBit(kCanDelete);
701 double GeoMagnetic::Z_atSpherical(UInt_t unixTime,
double r,
double theta,
double phi){
702 prepareGeoMagnetics();
704 double V0 = getPotentialAtSpherical(unixTime, r, theta, phi);
705 double V1 = getPotentialAtSpherical(unixTime, r+dr, theta, phi);
706 double BZ = (V1-V0)/dr;
720 double lon, lat, alt;
721 double r = fPosition.Mag();
722 double theta = fPosition.Theta();
723 double phi = fPosition.Phi();
725 sphericalToLatLonAlt(lon, lat, alt, r, theta, phi);
729 TVector3 position = fPosition;
730 position += fDrawScaleFactor*fField;
731 sphericalToLatLonAlt(lon, lat, alt, position.Mag(), position.Theta(), position.Phi());
750 fPosition = position;
751 fUnixTime = unixTime;
752 calculateFieldAtPosition();
765 GeoMagnetic::FieldPoint::FieldPoint(UInt_t unixTime,
double lon,
double lat,
double alt) : TArrow(0, 0, 0, 0, 0.001,
"|>"), fPosition(),fField(), fDrawScaleFactor(10)
767 double r, theta, phi;
768 lonLatAltToSpherical(lon, lat, alt, r, theta, phi);
769 fPosition.SetMagThetaPhi(r, theta, phi);
770 fUnixTime = unixTime;
771 calculateFieldAtPosition();
781 void GeoMagnetic::FieldPoint::calculateFieldAtPosition(){
783 double r = fPosition.Mag();
784 double theta = fPosition.Theta();
785 double phi = fPosition.Phi();
787 double X = X_atSpherical(fUnixTime, r, theta, phi);
788 double Y = Y_atSpherical(fUnixTime, r, theta, phi);
789 double Z = Z_atSpherical(fUnixTime, r, theta, phi);
802 SetLineColor(B_r > 0 ? kRed : kBlue);
805 double cos_theta = TMath::Cos(theta);
806 double sin_theta = TMath::Sin(theta);
807 double cos_phi = TMath::Cos(phi);
808 double sin_phi = TMath::Sin(phi);
811 double x = sin_theta*cos_phi*B_r + cos_theta*cos_phi*B_theta - sin_phi*B_phi;
812 double y = sin_theta*sin_phi*B_r + cos_theta*sin_phi*B_theta + cos_phi*B_phi;
813 double z = cos_theta*B_r - sin_theta*B_theta + 0;
815 fField.SetXYZ(x, y, z);
830 TVector3 GeoMagnetic::specularReflection(
const TVector3& incidentPoyntingVector,
const TVector3& surfaceNormal){
833 TVector3 reflectionPointToSource = -1*incidentPoyntingVector;
834 TVector3 reflectionPointToDestination = 2*(reflectionPointToSource.Dot(surfaceNormal))*surfaceNormal - reflectionPointToSource;
835 return reflectionPointToDestination;
848 TCanvas* GeoMagnetic::plotFresnelReflection(){
850 const int nSteps = 90;
851 double d_theta_i = TMath::PiOver2()/nSteps;
853 const TVector3 surfaceNormal(0, 0, 1);
854 const TVector3 x_hat(1, 0, 0);
855 const TVector3 y_hat(0, 1, 0);
857 const double pol_angle = 45*TMath::DegToRad();
859 const double E_mag = 1;
861 TGraph* grThetas =
new TGraph();
862 TGraph* gr_r_p =
new TGraph();
863 TGraph* gr_r_s =
new TGraph();
865 for(
int i=0; i <= nSteps; i++){
866 double theta_i = d_theta_i * i;
868 TVector3 incidentRay = -surfaceNormal;
869 incidentRay.RotateY(theta_i);
871 TVector3 E = E_mag*y_hat;
872 E.Rotate(pol_angle, incidentRay);
875 std::cout <<
"theta_i = " << theta_i*TMath::RadToDeg() <<
" degrees, (incidentRay . E) = " << incidentRay.Dot(E) << std::endl;
876 std::cout <<
"Incident ray = (" << incidentRay.X() <<
", " << incidentRay.Y() <<
", " << incidentRay.Z() <<
")" << std::endl;
877 std::cout <<
"E = (" << E.X() <<
", " << E.Y() <<
", " << E.Z() <<
")" << std::endl;
880 double E_s_initial = E.Y();
881 double E_p_initial = TMath::Sqrt(E.X()*E.X() + E.Z()*E.Z());
883 TVector3 reflectedRay = fresnelReflection(incidentRay, surfaceNormal, E);
886 TVector3 npi = incidentRay.Cross(reflectedRay).Unit();
887 std::cout <<
"normal to the plane of incidence = (" << npi.X() <<
", " << npi.Y() <<
", " << npi.Z() <<
")" << std::endl;
890 double theta_r = surfaceNormal.Angle(reflectedRay);
891 double theta_i_2 = surfaceNormal.Angle(-incidentRay);
893 grThetas->SetPoint(grThetas->GetN(), theta_i_2*TMath::RadToDeg(), theta_r*TMath::RadToDeg());
895 double E_s_reflected = E.Y();
896 double E_p_reflected = TMath::Sqrt(E.X()*E.X() + E.Z()*E.Z());
898 double r_p = TMath::Abs(E_p_initial) > 0 ? E_p_reflected/E_p_initial : 0;
899 double r_s = TMath::Abs(E_s_initial) > 0 ? E_s_reflected/E_s_initial : 0;
901 gr_r_p->SetPoint(gr_r_p->GetN(), theta_i_2*TMath::RadToDeg(), r_p);
902 gr_r_s->SetPoint(gr_r_s->GetN(), theta_i_2*TMath::RadToDeg(), r_s);
905 TCanvas* c1 =
new TCanvas();
908 grThetas->SetTitle(
"Law of reflection; Angle of incidence, #theta_{i} (Degrees); Angle of reflection #theta_{r} (Degrees)");
910 grThetas->SetBit(kCanDelete);
914 TLegend* l1b =
new TLegend(0.15, 0.55, 0.6, 0.85);
915 gr_r_p->SetTitle(
"E-field amplitude reflection coefficients; Incident angle, #theta_{i} (Degrees); Reflection coefficient");
916 gr_r_p->SetLineColor(kRed);
918 gr_r_p->SetBit(kCanDelete);
921 gr_r_p->SetMaximum(r_max);
922 gr_r_p->SetMinimum(r_min);
923 gr_r_p->GetXaxis()->SetRangeUser(0, 90);
924 gr_r_s->Draw(
"lsame");
925 gr_r_s->SetBit(kCanDelete);
926 TGraph* grBrewster =
new TGraph();
927 double brewster_angle = TMath::RadToDeg()*TMath::ATan2(n_ice, n_air);
928 grBrewster->SetPoint(0, brewster_angle, r_min);
929 grBrewster->SetPoint(1, brewster_angle, r_max);
930 grBrewster->SetLineStyle(2);
931 grBrewster->SetLineColor(kMagenta);
932 grBrewster->Draw(
"lsame");
933 grBrewster->SetBit(kCanDelete);
935 l1b->AddEntry(gr_r_s,
"r_s (E-field perpendicular to plane of incidence)",
"l");
936 l1b->AddEntry(gr_r_p,
"r_p (H-field perpendicular to plane of incidence)",
"l");
937 l1b->AddEntry(grBrewster,
"Brewster angle",
"l");
938 l1b->SetBit(kCanDelete);
960 TVector3 GeoMagnetic::fresnelReflection(
const TVector3& incidentPoyntingVector,
const TVector3& surfaceNormal, TVector3& electricFieldVec,
double n1,
double n2){
962 double theta_i = surfaceNormal.Angle(-incidentPoyntingVector);
963 double cos_theta_i = TMath::Cos(theta_i);
964 double sin_theta_i = TMath::Sin(theta_i);
967 double cos_theta_t = TMath::Sqrt(1 - (n1*n1*sin_theta_i*sin_theta_i/(n2*n2)));
969 const TVector3 reflectedPoyntingVector = specularReflection(incidentPoyntingVector, surfaceNormal);
984 TVector3 normalToPlaneOfIncidence = incidentPoyntingVector.Cross(reflectedPoyntingVector).Unit();
986 if(normalToPlaneOfIncidence.Mag()==0){
988 normalToPlaneOfIncidence.SetXYZ(0, 1, 0);
991 double r_s = (n1*cos_theta_i - n2*cos_theta_t)/(n1*cos_theta_i + n2*cos_theta_t);
992 double r_p = (n2*cos_theta_i - n1*cos_theta_t)/(n2*cos_theta_i + n1*cos_theta_t);
994 const TVector3 z_hat_local = surfaceNormal.Unit();
995 const TVector3 y_hat_local = normalToPlaneOfIncidence;
996 const TVector3 x_hat_local = y_hat_local.Cross(z_hat_local);
998 double E_s = electricFieldVec.Dot(y_hat_local);
999 double E_p_x = electricFieldVec.Dot(x_hat_local);
1000 double E_p_z = electricFieldVec.Dot(z_hat_local);
1002 double reflected_E_s = r_s*E_s;
1003 double reflected_E_p_x = r_p*E_p_x;
1004 double reflected_E_p_z = r_p*E_p_z;
1006 TVector3 reflectedElectricFieldVec = reflected_E_p_x*x_hat_local + reflected_E_s*y_hat_local + reflected_E_p_z*z_hat_local;
1009 std::cout <<
"incident angle = " << theta_i*TMath::RadToDeg() <<
" degrees, transmission angle = " << TMath::ACos(cos_theta_t)*TMath::RadToDeg() <<
" degrees" << std::endl;
1010 std::cout <<
"cos(theta_i) = " << cos_theta_i <<
", cos(theta_t) = " << cos_theta_t << std::endl;
1011 std::cout <<
"r_s(theta_i) = " << r_s <<
", r_p(theta_i) = " << r_p << std::endl;
1013 if(TMath::Abs((x_hat_local.Cross(y_hat_local) - z_hat_local).Mag()) > 1e-19){
1014 std::cout <<
"Checking that my unit vectors make sense..." << std::endl;
1015 std::cout <<
"|x| = " << x_hat_local.Mag() <<
", |y| = " << y_hat_local.Mag() <<
", |z| = " << z_hat_local.Mag() << std::endl;
1016 std::cout <<
"x.y = " << x_hat_local.Dot(y_hat_local) <<
", x.z = " << x_hat_local.Dot(z_hat_local) <<
", x.z = " << y_hat_local.Dot(z_hat_local) << std::endl;
1017 std::cout <<
"|(x.Cross(y)) - z| = " << (x_hat_local.Cross(y_hat_local) - z_hat_local).Mag() << std::endl;
1019 std::cout <<
"Original electric field = (" << electricFieldVec.X() <<
", " << electricFieldVec.Y() <<
", " << electricFieldVec.Z() <<
")" << std::endl;
1020 std::cout <<
"Reflected electric field = (" << reflectedElectricFieldVec.X() <<
", " << reflectedElectricFieldVec.Y() <<
", " << reflectedElectricFieldVec.Z() <<
")" << std::endl;
1021 std::cout << std::endl;
1025 electricFieldVec = reflectedElectricFieldVec;
1028 return reflectedPoyntingVector;
1043 TVector3 GeoMagnetic::getUnitVectorAlongThetaWavePhiWave(
UsefulAdu5Pat& usefulPat,
double phiWave,
double thetaWave){
1044 prepareGeoMagnetics();
1055 double testLat = usefulPat.
latitude - 0.1;
1056 double testAlt = usefulPat.
altitude;
1058 double testThetaWave, testPhiWave;
1061 TVector3 testVector = lonLatAltToVector(testLon, testLat, testAlt);
1064 std::cout <<
"Before rotation..." << std::endl;
1065 std::cout << testLon <<
"\t" << testLat <<
"\t" << testAlt << std::endl;
1066 std::cout << testThetaWave <<
"\t" << testPhiWave << std::endl;
1067 std::cout << testThetaWave*TMath::RadToDeg() <<
"\t" << testPhiWave*TMath::RadToDeg() << std::endl;
1073 const TVector3 unitAnita = anitaPosition.Unit();
1074 testVector.Rotate(-testPhiWave, unitAnita);
1075 testVector.Rotate(phiWave, unitAnita);
1077 vectorToLonLatAlt(testLon, testLat, testAlt, testVector);
1081 std::cout <<
"After phi rotation..." << std::endl;
1082 std::cout << testLon <<
"\t" << testLat <<
"\t" << testAlt << std::endl;
1083 std::cout << testThetaWave <<
"\t" << testPhiWave << std::endl;
1084 std::cout << testThetaWave*TMath::RadToDeg() <<
"\t" << testPhiWave*TMath::RadToDeg() << std::endl;
1109 double A = TMath::PiOver2() - thetaWave;
1110 double O = testVector.Angle(anitaPosition);
1111 double T = TMath::Pi() - A - O;
1112 double t = anitaPosition.Mag();
1113 double a = TMath::Sin(A)*(t/TMath::Sin(T));
1116 std::cout << thetaWave*TMath::RadToDeg() <<
"\t" << A*TMath::RadToDeg() <<
"\t" << O*TMath::RadToDeg() <<
"\t" << T*TMath::RadToDeg() << std::endl;
1117 std::cout << a <<
"\t" << t <<
"\t" << a - t << std::endl;
1120 testVector.SetMag(a);
1123 vectorToLonLatAlt(testLon, testLat, testAlt, testVector);
1125 std::cout <<
"After setting mangitude..." << std::endl;
1126 std::cout << testLon <<
"\t" << testLat <<
"\t" << testAlt << std::endl;
1127 std::cout << testThetaWave <<
"\t" << testPhiWave << std::endl;
1128 std::cout << testThetaWave*TMath::RadToDeg() <<
"\t" << testPhiWave*TMath::RadToDeg() << std::endl;
1131 TVector3 deltaVec = testVector - anitaPosition;
1132 return deltaVec.Unit();
1149 double GeoMagnetic::getExpectedPolarisation(
UsefulAdu5Pat& usefulPat,
double phiWave,
double thetaWave,
1152 prepareGeoMagnetics();
1155 std::cout <<
"Anita position = " << usefulPat.
longitude <<
"\t" << usefulPat.
latitude <<
"\t" << usefulPat.
altitude << std::endl;
1161 double reflectionLon=0, reflectionLat=0, reflectionAlt=0, deltaTheta=100;
1164 int hitsGround = usefulPat.
traceBackToContinent(phiWave, thetaWave, &reflectionLon, &reflectionLat, &reflectionAlt, &deltaTheta);
1166 TVector3 destination;
1167 TVector3 destinationToSource;
1168 bool directCosmicRay = hitsGround == 0 ? true :
false;
1173 TVector3 surfaceNormal;
1174 TVector3 reflectionToAnita;
1177 if(directCosmicRay){
1179 std::cout <<
"I'm a direct Cosmic Ray! (" << hitsGround <<
") " << deltaTheta <<
"\t" << reflectionLon <<
"\t" << reflectionLat <<
"\t" << reflectionAlt << std::endl;
1181 destination = anitaPosition;
1182 destinationToSource = getUnitVectorAlongThetaWavePhiWave(usefulPat, phiWave, thetaWave);
1186 std::cout <<
"I'm a reflected Cosmic Ray! (" << hitsGround <<
") " << deltaTheta <<
"\t" << reflectionLon <<
"\t" << reflectionLat <<
"\t" << reflectionAlt << std::endl;
1188 destination = lonLatAltToVector(reflectionLon, reflectionLat, reflectionAlt);
1190 reflectionToAnita = anitaPosition - destination;
1194 surfaceNormal = (lonLatAltToVector(reflectionLon, reflectionLat, reflectionAlt + 1) - destination).Unit();
1197 TVector3 incomingVector = specularReflection(reflectionToAnita, surfaceNormal);
1200 destinationToSource = -incomingVector.Unit();
1204 TVector3 cosmicRayAtmosphericEntry = getInitialPosition(destination, destinationToSource);
1207 const TVector3 cosmicRayDirection = -destinationToSource.Unit();
1210 TVector3 xMaxPosition = getXMaxPosition(cosmicRayAtmosphericEntry, cosmicRayDirection, xMax);
1213 FieldPoint fp(usefulPat.
realTime, xMaxPosition);
1215 std::cout <<
"FieldPoint position:" << fp.posX() <<
"," << fp.posY() <<
","<< fp.posZ() << std::endl;
1216 std::cout <<
"FieldPoint vector:" << fp.componentX() <<
"," << fp.componentY() <<
","<< fp.componentZ() << std::endl;
1222 TVector3 EVec = fp.field().Cross(cosmicRayDirection).Unit();
1224 std::cout <<
"EVec: (" << EVec.X() <<
"," << EVec.Y() <<
"," << EVec.Z() <<
")" << std::endl;
1227 if(!directCosmicRay){
1229 TVector3 reflectionToAnita2 = fresnelReflection(cosmicRayDirection, surfaceNormal, EVec);
1232 double shouldBeZero = reflectionToAnita.Angle(reflectionToAnita2);
1233 std::cout <<
"Doing the reflection on the way back... the angle between reflectionToAnita and reflectionToAnita2 = " << shouldBeZero << std::endl;
1242 TVector3 vPolAxis = getUnitVectorAlongThetaWavePhiWave(usefulPat, phiWave, -80*TMath::DegToRad());
1245 TVector3 hPolAxis = getUnitVectorAlongThetaWavePhiWave(usefulPat, phiWave + TMath::PiOver2(), 0);
1248 TVector3 antennaAxis = getUnitVectorAlongThetaWavePhiWave(usefulPat, phiWave, -10*TMath::DegToRad());
1249 std::cout <<
"The dot products of any pair of the antenna axis, hPolAxis, vPolAxis should be zero..." << std::endl;
1250 std::cout <<
"antennaAxis dot hPolAxis = " << antennaAxis.Dot(hPolAxis) << std::endl;
1251 std::cout <<
"antennaAxis dot vPolAxis = " << antennaAxis.Dot(vPolAxis) << std::endl;
1252 std::cout <<
"hPolAxis dot vPolAxis = " << hPolAxis.Dot(vPolAxis) << std::endl;
1256 double vPolComponent = EVec.Dot(vPolAxis);
1257 double hPolComponent = EVec.Dot(hPolAxis);
1259 std::cout <<
"vPolComponent: " << vPolComponent << std::endl;
1260 std::cout <<
"hPolComponent: " << hPolComponent << std::endl;
1264 double polarisationAngle = TMath::ATan(vPolComponent/hPolComponent);
1266 return polarisationAngle;
1282 double GeoMagnetic::getExpectedPolarisationUpgoing(
UsefulAdu5Pat& usefulPat,
double phiWave,
double thetaWave,
1285 std::cout <<
"----------------GeoMagnetic::getExpectedPolarisationUpgoing(): Begin." << std::endl;
1287 prepareGeoMagnetics();
1291 std::cout <<
"Anita position = " << usefulPat.
longitude <<
"\t" << usefulPat.
latitude <<
"\t" << usefulPat.
altitude << std::endl;
1297 double reflectionLon=0, reflectionLat=0, reflectionAlt=0, deltaTheta=100;
1298 int hitsGround = usefulPat.
traceBackToContinent(phiWave, thetaWave, &reflectionLon, &reflectionLat, &reflectionAlt, &deltaTheta);
1300 TVector3 destination;
1301 TVector3 destinationToSource;
1302 bool directCosmicRay = hitsGround == 0 ? true :
false;
1307 if(directCosmicRay){
1309 std::cout <<
"I'm pointed above the horizon! I can't be an upgoing event! Exiting..." << std::endl;
1310 std::cout <<
"deltaTheta=" << deltaTheta <<
" hitsGround=" << hitsGround << std::endl;
1316 std::cout <<
"I'm pointed at the continent! " << deltaTheta <<
"\t" << reflectionLon <<
"\t" << reflectionLat <<
"\t" << reflectionAlt << std::endl;
1318 destination = lonLatAltToVector(reflectionLon, reflectionLat, reflectionAlt);
1319 destinationToSource = getUnitVectorAlongThetaWavePhiWave(usefulPat, phiWave, thetaWave);
1322 const TVector3 surfaceNormal = (lonLatAltToVector(reflectionLon, reflectionLat, reflectionAlt + 1) - destination).Unit();
1325 const TVector3 cosmicRayDirection = -destinationToSource.Unit();
1327 double emergenceAngle = surfaceNormal.Angle(cosmicRayDirection);
1329 std::cout <<
"surfaceNormal: (" << surfaceNormal.X() <<
"," << surfaceNormal.Y() <<
"," << surfaceNormal.Z() <<
")" << std::endl;
1330 std::cout <<
"cosmicRayDirection: (" << cosmicRayDirection.X() <<
"," << cosmicRayDirection.Y() <<
"," << cosmicRayDirection.Z() <<
")" << std::endl;
1331 std::cout <<
"Emergence Angle: " << emergenceAngle << std::endl;
1337 TVector3 xMaxPosition = destination+cosmicRayDirection*pathLength;
1341 std::cout <<
"anitaPosition: (" << anitaPosition.X() <<
"," << anitaPosition.Y() <<
"," << anitaPosition.Z() <<
")" << std::endl;
1342 std::cout <<
"destination: (" << destination.X() <<
"," << destination.Y() <<
"," << destination.Z() <<
")" << std::endl;
1343 std::cout <<
"destinationToSource: (" << destinationToSource.X() <<
"," << destinationToSource.Y() <<
"," << destinationToSource.Z() <<
")" << std::endl;
1344 std::cout <<
"cosmicRayDirection: (" << cosmicRayDirection.X() <<
"," << cosmicRayDirection.Y() <<
"," << cosmicRayDirection.Z() <<
")" << std::endl;
1345 std::cout <<
"xMaxPosition: (" << xMaxPosition.X() <<
"," << xMaxPosition.Y() <<
"," << xMaxPosition.Z() <<
")" << std::endl;
1350 FieldPoint fp(usefulPat.
realTime, xMaxPosition);
1352 std::cout <<
"FieldPoint: pos=(" << fp.posX() <<
"," << fp.posY() <<
"," << fp.posZ() <<
")" << std::endl;
1353 std::cout <<
" comp=(" << fp.componentX() <<
"," << fp.componentY() <<
"," << fp.componentZ() << std::endl;
1361 TVector3 EVec = fp.field().Cross(cosmicRayDirection).Unit();
1363 std::cout <<
"EVec: (" << EVec.X() <<
"," << EVec.Y() <<
"," << EVec.Z() <<
")" << std::endl;
1371 TVector3 vPolAxis = getUnitVectorAlongThetaWavePhiWave(usefulPat, phiWave, -80*TMath::DegToRad());
1374 TVector3 hPolAxis = getUnitVectorAlongThetaWavePhiWave(usefulPat, phiWave + TMath::PiOver2(), 0);
1377 double vPolComponent = EVec.Dot(vPolAxis);
1378 double hPolComponent = EVec.Dot(hPolAxis);
1380 std::cout <<
"vPolComponent: " << vPolComponent << std::endl;
1381 std::cout <<
"hPolComponent: " << hPolComponent << std::endl;
1385 double polarisationAngle = TMath::ATan(vPolComponent/hPolComponent);
1387 return polarisationAngle;
1401 TCanvas* GeoMagnetic::plotAtmosphere(){
1402 prepareGeoMagnetics();
1404 static int maxCanvas = 0;
1408 grAtmosDensity.Draw(
"al");
1416 double GeoMagnetic::getAtmosphericDensity(
double altitude){
1417 prepareGeoMagnetics();
1419 return fExpAtmos->Eval(altitude);
1435 TVector3 GeoMagnetic::getInitialPosition(
const TVector3& destination,
const TVector3& destinationToSource){
1436 prepareGeoMagnetics();
1438 if(TMath::Abs(destinationToSource.Mag() -1) > 1e-14){
1439 std::cerr <<
"Warning in " << __PRETTY_FUNCTION__ <<
", was expecting a unit vector, didn't get one. " 1440 <<
"Got " << 1.0-destinationToSource.Mag() <<
" away from mag==1... This calculation might be wonky... " << std::endl;
1445 const double desiredAlt = 80e3;
1446 TVector3 initialPosition = destination;
1447 double initialLon, initialLat, initialAlt;
1448 vectorToLonLatAlt(initialLon, initialLat, initialAlt, initialPosition);
1450 std::cout <<
"Initial alt = " << initialAlt <<
", (desiredAlt = " << desiredAlt <<
")" << std::endl;
1452 while(initialAlt < desiredAlt){
1453 initialPosition += 1e3*destinationToSource;
1454 vectorToLonLatAlt(initialLon, initialLat, initialAlt, initialPosition);
1458 std::cout <<
"Got initial position... " << initialLon <<
"\t" << initialLat <<
"\t" << initialAlt << std::endl;
1461 return initialPosition;
1477 TVector3 GeoMagnetic::getXMaxPosition(
const TVector3& initialPosition,
const TVector3& cosmicRayDirection,
1479 prepareGeoMagnetics();
1481 TVector3 currentPosition = initialPosition;
1482 double currentAtmosphereTraversed = 0;
1483 double dx = cosmicRayDirection.Mag();
1487 TGraph* grAltPath = debug ?
new TGraph() : NULL;
1490 double initialAlt = 0;
1491 while(currentAtmosphereTraversed < xMax){
1493 currentPosition += cosmicRayDirection;
1494 double currentLon, currentLat, currentAlt;
1495 vectorToLonLatAlt(currentLon, currentLat, currentAlt, currentPosition);
1498 initialAlt= currentAlt;
1502 if(debug && currentAtmosphereTraversed == 0){
1503 std::cout <<
"Finding xMax position... " << xMax <<
" Initial position... " << currentLon <<
"\t" << currentLat <<
"\t" << currentAlt <<
"\t" << currentAtmosphereTraversed << std::endl;
1506 currentAtmosphereTraversed += getAtmosphericDensity(currentAlt)*dx;
1508 if(debug && currentAtmosphereTraversed >= xMax){
1509 std::cout <<
"Found xMax position... " << xMax <<
" Initial position... " << currentLon <<
"\t" << currentLat <<
"\t" << currentAlt <<
"\t" << currentAtmosphereTraversed << std::endl;
1513 if(currentAlt > lastAlt && lastAlt > initialAlt){
1514 std::cerr <<
"Warning in " <<__PRETTY_FUNCTION__ <<
", unable to find xMax, terminating loop." << std::endl;
1515 std::cerr <<
"Current position = " << currentLon <<
"\t" << currentLat <<
"\t" << currentAlt <<
"\t" << currentAtmosphereTraversed << std::endl;
1520 grAltPath->SetPoint(numSteps, dx*numSteps, currentAlt);
1523 lastAlt = currentAlt;
1527 static int maxCanvas = 0;
1531 grAltPath->SetTitle(
"Cosmic Ray Altitude vs. distance traversed; Distance through atmosphere (m); Altitude (m)");
1532 grAltPath->SetBit(kCanDelete);
1533 grAltPath->Draw(
"al");
1538 return currentPosition;
virtual void Draw(Option_t *opt="")
Float_t latitude
In degrees.
Float_t longitude
In degrees.
UInt_t realTime
Time from the GPS unit.
void getThetaAndPhiWave(Double_t sourceLon, Double_t sourceLat, Double_t sourceAlt, Double_t &thetaWave, Double_t &phiWave)
Float_t altitude
In metres.
FieldPoint(UInt_t unixTime, double lon, double lat, double alt)
Inelasticity distributions: stores parametrizations and picks inelasticities.
As UsefulAnitaEvent is to RawAnitaEvent, UsefulAdu5Pat is to Adu5Pat. Well not quite as useful but yo...
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
static void LonLatToEastingNorthing(Double_t lon, Double_t lat, Double_t &easting, Double_t &northing)
virtual void Draw(Option_t *opt="")
static void EastingNorthingToLonLat(Double_t easting, Double_t northing, Double_t &lon, Double_t &lat)