USGS

Isis 3.0 Object Programmers' Reference

Home

Spice.cpp

Go to the documentation of this file.
00001 
00023 #include <cfloat>
00024 #include "Spice.h"
00025 #include "iString.h"
00026 #include "iException.h"
00027 #include "Filename.h"
00028 #include "Constants.h"
00029 #include "NaifStatus.h"
00030 
00031 using namespace std;
00032 namespace Isis {
00052   // TODO: DOCUMENT EVERYTHING
00053   Spice::Spice (Isis::Pvl &lab) {
00054     NaifStatus::CheckErrors();
00055 
00056     // Initialization
00057     p_startTime = 0.0;
00058     p_endTime = 0.0;
00059     p_cacheSize = 0;
00060     p_et = -DBL_MAX;
00061 
00062     // Get the kernel group and load main kernels
00063     Isis::PvlGroup kernels = lab.FindGroup("Kernels",Isis::Pvl::Traverse);
00064 
00065     // Get the time padding first
00066     if(kernels.HasKeyword("StartPadding")) {
00067       p_startTimePadding = kernels["StartPadding"][0];
00068     }
00069     else {
00070       p_startTimePadding = 0.0;
00071     }
00072 
00073     if(kernels.HasKeyword("EndPadding")) {
00074       p_endTimePadding  = kernels["EndPadding"][0];
00075     }
00076     else {
00077       p_endTimePadding = 0.0;
00078     }
00079 
00080 
00081 //  Modified  to load planetary ephemeris SPKs before s/c SPKs since some 
00082 //  missions (e.g., MESSENGER) may augment the s/c SPK with new planet 
00083 //  ephemerides. (2008-02-27 (KJB))
00084     Load(kernels["TargetPosition"]);
00085 
00086     if (kernels.HasKeyword("SpacecraftPosition")) {
00087       Load(kernels["SpacecraftPosition"]);
00088     }
00089     else {
00090       Load(kernels["InstrumentPosition"]);
00091     }
00092 
00093     if (kernels.HasKeyword("SpacecraftPointing")) {
00094       Load(kernels["SpacecraftPointing"]);
00095     }
00096     else {
00097       Load(kernels["InstrumentPointing"]);
00098     }
00099 
00100     if (kernels.HasKeyword("Frame")) {
00101       Load(kernels["Frame"]);
00102     }
00103 
00104     if (kernels.HasKeyword("Extra")) {
00105       Load(kernels["Extra"]);
00106     }
00107 
00108     Load(kernels["TargetAttitudeShape"]);
00109     Load(kernels["Instrument"]);
00110     Load(kernels["InstrumentAddendum"]);  // Always load after instrument
00111     Load(kernels["LeapSecond"]);
00112     Load(kernels["SpacecraftClock"]);
00113 
00114     // Get NAIF ik, spk, sclk, and ck codes
00115     //
00116     //    Use ikcode to get parameters from instrument kernel such as focal
00117     //    length, distortions, focal plane maps, etc
00118     //
00119     //    Use spkcode to get spacecraft position from spk file
00120     //
00121     //    Use sclkcode to transform times from et to tics
00122     //
00123     //    Use ckcode to transform between frames
00124     //
00125     //    Use bodycode to obtain radii and attitude (pole position/omega0)
00126     //
00127     //    Use spkbodycode to read body position from spk
00128     
00129     string trykey = "NaifIkCode";
00130     if (kernels.HasKeyword("NaifFrameCode")) trykey = "NaifFrameCode";
00131     p_ikCode = (int) kernels[trykey];
00132     
00133     p_spkCode = p_ikCode / 1000;
00134     p_sclkCode = p_spkCode;
00135     p_ckCode = p_ikCode;
00136     
00137     Isis::PvlGroup &inst = lab.FindGroup("Instrument",Isis::Pvl::Traverse);
00138     p_target = (string) inst["TargetName"];
00139     
00140     if (iString(p_target).UpCase() == "SKY") {
00141       p_bodyCode = p_spkCode;
00142       p_radii[0] = p_radii[1] = p_radii[2] = 1.0;
00143       p_sky = true;
00144     }
00145     else {
00146       p_bodyCode = NaifBodyCode();
00147       SpiceInt n;
00148       bodvar_c(p_bodyCode,"RADII",&n,p_radii);
00149       p_sky = false;
00150     }
00151     p_spkBodyCode = p_bodyCode;
00152     
00153     // Override them if they exist in the labels
00154     if (kernels.HasKeyword("NaifSpkCode")) p_spkCode = (int) kernels["NaifSpkCode"];
00155     if (kernels.HasKeyword("NaifCkCode")) p_ckCode = (int) kernels["NaifCkCode"];
00156     if (kernels.HasKeyword("NaifSclkCode")) p_sclkCode = (int) kernels["NaifSclkCode"];
00157     if (kernels.HasKeyword("NaifBodyCode")) p_bodyCode = (int) kernels["NaifBodyCode"];
00158     if (!p_sky) {
00159       if (kernels.HasKeyword("NaifSpkBodyCode")) p_spkBodyCode = (int) kernels["NaifSpkBodyCode"];
00160     }
00161     
00162     // Create our SpicePosition and SpiceRotation objects
00163     p_bodyRotation = 0;
00164     p_instrumentRotation = 0;
00165     p_instrumentPosition = 0;
00166     p_sunPosition = 0;
00167     
00168     if (p_sky) {
00169       // Create the identity rotation for sky targets
00170       // Everything in bodyfixed will really be J2000
00171       p_bodyRotation = new SpiceRotation(1);
00172     }
00173     else {
00174       char frameName[32];
00175       SpiceInt frameCode;
00176       SpiceBoolean found;
00177       cidfrm_c (p_spkBodyCode, sizeof(frameName), &frameCode, frameName, &found);
00178 
00179       if (!found) { 
00180         string naifTarget = string("IAU_") + iString(p_target).UpCase();
00181         namfrm_c(naifTarget.c_str(),&frameCode);
00182         if (frameCode == 0) {
00183           string msg = "Can not find NAIF code for [" + naifTarget + "]";
00184           throw Isis::iException::Message(Isis::iException::Io,msg,_FILEINFO_);
00185         }
00186       }
00187       p_bodyRotation = new SpiceRotation(frameCode);
00188     }
00189     p_instrumentRotation = new SpiceRotation(p_ckCode);
00190     p_instrumentPosition = new SpicePosition(p_spkCode,p_spkBodyCode);
00191     p_sunPosition = new SpicePosition(10,p_bodyCode);
00192     
00193     // Check to see if we have nadir pointing that needs to be computed &
00194     // See if we have table blobs to load
00195     if (iString((std::string)kernels["TargetPosition"]).UpCase() == "TABLE") {
00196       if (kernels["TargetPosition"].Size() != 0) {
00197         Table t("SunPosition",lab.Filename());
00198         p_sunPosition->LoadCache(t);
00199       
00200         Table t2("BodyRotation",lab.Filename());
00201         p_bodyRotation->LoadCache(t2);
00202         if (t2.Label().HasKeyword("SolarLongitude")) {
00203           p_solarLongitude = t2.Label()["SolarLongitude"];
00204         }
00205         else {
00206           SolarLongitude();
00207         }
00208       }
00209     }
00210 
00211 
00212     if (kernels.HasKeyword("InstrumentPointing")) {
00213       for(int elem = 0; elem < kernels["InstrumentPointing"].Size(); elem ++) {
00214         if (iString((std::string)kernels["InstrumentPointing"][elem]).UpCase() == "NADIR") {
00215           delete p_instrumentRotation;
00216           p_instrumentRotation = new SpiceRotation(p_ikCode,p_spkBodyCode);
00217         }
00218         else if (iString((std::string)kernels["InstrumentPointing"][elem]).UpCase() == "TABLE") {
00219           Table t("InstrumentPointing",lab.Filename());
00220           p_instrumentRotation->LoadCache(t);
00221         }
00222       }
00223     }
00224 
00225     if (kernels.HasKeyword("InstrumentPosition")) {
00226       if (kernels["InstrumentPosition"].Size() != 0) {
00227         if (iString((std::string)kernels["InstrumentPosition"]).UpCase() == "TABLE") {
00228           Table t("InstrumentPosition",lab.Filename());
00229           p_instrumentPosition->LoadCache(t);
00230         }
00231       }
00232     }
00233 
00234     NaifStatus::CheckErrors();
00235   }
00236 
00237 
00239   void Spice::Load(Isis::PvlKeyword &key) {
00240     NaifStatus::CheckErrors();
00241 
00242     for (int i=0; i<key.Size(); i++) {
00243       if (key[i] == "") continue;
00244       if (iString(key[i]).UpCase() == "NULL") continue;
00245       if (iString(key[i]).UpCase() == "NADIR") continue;
00246       if (iString(key[i]).UpCase() == "TABLE") continue;
00247       Isis::Filename file(key[i]);
00248       if (!file.exists()) {
00249         string msg = "Spice file does not exist [" + file.Expanded() + "]";
00250         throw Isis::iException::Message(Isis::iException::Io,msg,_FILEINFO_);
00251       }
00252       string fileName(file.Expanded());
00253       furnsh_c(fileName.c_str());
00254       p_kernels.push_back((string)key[i]);
00255     }
00256 
00257     NaifStatus::CheckErrors();
00258   }
00259 
00263   Spice::~Spice () {
00264     NaifStatus::CheckErrors();
00265 
00266     if (p_bodyRotation != 0) delete p_bodyRotation;
00267     if (p_instrumentRotation != 0) delete p_instrumentRotation;
00268     if (p_instrumentPosition != 0) delete p_instrumentPosition;
00269     if (p_sunPosition != 0) delete p_sunPosition;
00270 
00271     // Unload the kernels (TODO: Can this be done faster)
00272     for (unsigned int i=0; i<p_kernels.size(); i++) {
00273       Isis::Filename file(p_kernels[i]);
00274       string fileName(file.Expanded());
00275       unload_c(fileName.c_str());
00276     }
00277 
00278     NaifStatus::CheckErrors();
00279   }
00280 
00298   void Spice::CreateCache (double startTime, double endTime, int cacheSize) {
00299     NaifStatus::CheckErrors();
00300 
00301     // Check for errors
00302     if (cacheSize <= 0) {
00303       string msg = "Argument cacheSize must be greater than zero";
00304       throw Isis::iException::Message(Isis::iException::Programmer,msg,_FILEINFO_);
00305     }
00306 
00307     if (startTime > endTime) {
00308       string msg = "Argument startTime must be less than or equal to endTime";
00309       throw Isis::iException::Message(Isis::iException::Programmer,msg,_FILEINFO_);
00310     }
00311 
00312     if (p_cacheSize > 0) {
00313       string msg = "A cache has already been created";
00314       throw Isis::iException::Message(Isis::iException::Programmer,msg,_FILEINFO_);
00315     }
00316 
00317     if(cacheSize == 1 && (p_startTimePadding != 0 || p_endTimePadding != 0)) {
00318       string msg = "This instrument does not support time padding";
00319       throw Isis::iException::Message(Isis::iException::User,msg,_FILEINFO_);
00320     }
00321 
00322     double avgTime = (startTime + endTime) / 2.0;
00323     ComputeSolarLongitude(avgTime);
00324 
00325     // Cache everything
00326     if (!p_bodyRotation->IsCached()) {
00327       p_bodyRotation->LoadCache(startTime-p_startTimePadding, endTime+p_endTimePadding, cacheSize);
00328     }
00329 
00330     if (!p_instrumentRotation->IsCached()) {
00331       p_instrumentRotation->LoadCache(startTime-p_startTimePadding, endTime+p_endTimePadding, cacheSize);
00332     }
00333 
00334     if (!p_instrumentPosition->IsCached()) {
00335       p_instrumentPosition->LoadCache(startTime-p_startTimePadding, endTime+p_endTimePadding, cacheSize);
00336     }
00337 
00338     // TODO: Investigate if sun cache size can be set to one or two.
00339     if (!p_sunPosition->IsCached()) {
00340       p_sunPosition->LoadCache(startTime-p_startTimePadding, endTime+p_endTimePadding, cacheSize);
00341     }
00342 
00343     // Save the time and cache size
00344     p_startTime = startTime;
00345     p_endTime = endTime;
00346     p_cacheSize = cacheSize;
00347     p_et = -DBL_MAX;
00348 
00349     // Unload the kernels (TODO: Can this be done faster)
00350     for (unsigned int i=0; i<p_kernels.size(); i++) {
00351       Isis::Filename file(p_kernels[i]);
00352       string fileName(file.Expanded());
00353       unload_c(fileName.c_str());
00354     }
00355     p_kernels.clear();
00356 
00357     NaifStatus::CheckErrors();
00358   }
00359 
00366   void Spice::CreateCache (double time) {
00367     CreateCache(time,time,1);
00368   }
00369 
00382   void Spice::SetEphemerisTime (const double et) {
00383     p_et = et;
00384 
00385     p_bodyRotation->SetEphemerisTime(et);
00386     p_instrumentRotation->SetEphemerisTime(et);
00387     p_instrumentPosition->SetEphemerisTime(et);
00388     p_sunPosition->SetEphemerisTime(et);
00389 
00390     std::vector<double> uB = p_bodyRotation->ReferenceVector(p_sunPosition->Coordinate());
00391     p_uB[0] = uB[0];
00392     p_uB[1] = uB[1];
00393     p_uB[2] = uB[2];
00394 
00395     ComputeSolarLongitude(p_et);
00396   }
00397 
00403   void Spice::InstrumentPosition (double p[3]) const {
00404     if (p_et == -DBL_MAX) {
00405       std::string msg = "You must call SetEphemerisTime first";
00406       throw iException::Message(iException::Programmer,msg,_FILEINFO_);
00407     }
00408 
00409     std::vector<double> sB = p_bodyRotation->ReferenceVector(p_instrumentPosition->Coordinate());
00410     p[0] = sB[0];
00411     p[1] = sB[1];
00412     p[2] = sB[2];
00413   }
00414 
00415 
00421   void Spice::InstrumentVelocity (double v[3]) const {
00422     if (p_et == -DBL_MAX) {
00423       std::string msg = "You must call SetEphemerisTime first";
00424       throw iException::Message(iException::Programmer,msg,_FILEINFO_);
00425     }
00426 
00427     std::vector<double> vB = p_bodyRotation->ReferenceVector(p_instrumentPosition->Velocity());
00428     v[0] = vB[0];
00429     v[1] = vB[1];
00430     v[2] = vB[2];
00431   }
00432 
00439   void Spice::SunPosition (double p[3]) const {
00440     if (p_et == -DBL_MAX) {
00441       std::string msg = "You must call SetEphemerisTime first";
00442       throw iException::Message(iException::Programmer,msg,_FILEINFO_);
00443     }
00444 
00445     p[0] = p_uB[0];
00446     p[1] = p_uB[1];
00447     p[2] = p_uB[2];
00448   }
00449 
00455   double Spice::TargetCenterDistance() const {
00456     std::vector<double> sB = p_bodyRotation->ReferenceVector(p_instrumentPosition->Coordinate());
00457     return sqrt(pow(sB[0],2) + pow(sB[1],2) + pow(sB[2],2));
00458   }
00459 
00467   void Spice::Radii (double r[3]) const {
00468     r[0] = p_radii[0];
00469     r[1] = p_radii[1];
00470     r[2] = p_radii[2];
00471   }
00472 
00480   SpiceInt Spice::NaifBodyCode() const {
00481     SpiceInt code;
00482     SpiceBoolean found;
00483     bodn2c_c (p_target.c_str(), &code, &found);
00484     if (!found) {
00485       string msg = "Could not convert Target [" + p_target +
00486                    "] to NAIF code";
00487       throw Isis::iException::Message(Isis::iException::Io,msg,_FILEINFO_);
00488     }
00489 
00490     return (int) code;
00491   }
00492 
00498   SpiceInt Spice::NaifSpkCode() const {
00499     return p_spkCode;
00500   }
00501 
00507   SpiceInt Spice::NaifCkCode() const {
00508     return p_ckCode;
00509   }
00510 
00516   SpiceInt Spice::NaifIkCode() const {
00517     return p_ikCode;
00518   }
00519 
00520   // Return naif sclk code
00521   SpiceInt Spice::NaifSclkCode() const {
00522     return p_sclkCode;
00523   }
00536   SpiceInt Spice::GetInteger(const std::string &key, int index) {
00537     NaifStatus::CheckErrors();
00538 
00539     SpiceBoolean found;
00540     SpiceInt value;
00541     SpiceInt n;
00542     gipool_c (key.c_str(),(SpiceInt)index,1,&n,&value,&found);
00543     if (!found) {
00544       string msg = "Can not find [" + key + "] in instrument kernels";
00545       throw Isis::iException::Message(Isis::iException::Io,msg,_FILEINFO_);
00546     }
00547 
00548     NaifStatus::CheckErrors();
00549 
00550     return value;
00551   }
00552 
00564   SpiceDouble Spice::GetDouble(const std::string &key, int index) {
00565     NaifStatus::CheckErrors();
00566 
00567     SpiceBoolean found;
00568     SpiceDouble value;
00569     SpiceInt n;
00570     gdpool_c (key.c_str(),(SpiceInt)index,1,&n,&value,&found);
00571     if (!found) {
00572       string msg = "Can not find [" + key + "] in instrument kernels";
00573       throw Isis::iException::Message(Isis::iException::Io,msg,_FILEINFO_);
00574     }
00575 
00576     NaifStatus::CheckErrors();
00577 
00578     return value;
00579   }
00580 
00593   string Spice::GetString(const std::string &key, int index) {
00594     NaifStatus::CheckErrors();
00595 
00596     SpiceBoolean found;
00597     SpiceInt n;
00598     char cstr[512];
00599     gcpool_c (key.c_str(),(SpiceInt)index,1,512,&n,cstr,&found);
00600     if (!found) {
00601       string msg = "Can not find [" + key + "] in instrument kernels";
00602       throw Isis::iException::Message(Isis::iException::Io,msg,_FILEINFO_);
00603     }
00604 
00605     NaifStatus::CheckErrors();
00606 
00607     return string(cstr);
00608   }
00609 
00618   void Spice::SubSpacecraftPoint (double &lat, double &lon) {
00619     NaifStatus::CheckErrors();
00620 
00621     if (p_et == -DBL_MAX) {
00622       std::string msg = "You must call SetEphemerisTime first";
00623       throw iException::Message(iException::Programmer,msg,_FILEINFO_);
00624     }
00625 
00626     SpiceDouble usB[3],dist;
00627     std::vector<double> vsB = p_bodyRotation->ReferenceVector(p_instrumentPosition->Coordinate());
00628     SpiceDouble sB[3];
00629     sB[0] = vsB[0];
00630     sB[1] = vsB[1];
00631     sB[2] = vsB[2];
00632     unorm_c (sB,usB,&dist);
00633 
00634     SpiceDouble a = p_radii[0];
00635     SpiceDouble b = p_radii[1];
00636     SpiceDouble c = p_radii[2];
00637 
00638     SpiceDouble originB[3];
00639     originB[0] = originB[1] = originB[2] = 0.0;
00640 
00641     SpiceBoolean found;
00642     SpiceDouble subB[3];
00643     surfpt_c (originB,usB,a,b,c,subB,&found);
00644 
00645     SpiceDouble mylon,mylat;
00646     reclat_c (subB,&a,&mylon,&mylat);
00647     lat = mylat * 180.0 / Isis::PI;
00648     lon = mylon * 180.0 / Isis::PI;
00649     if (lon < 0.0) lon += 360.0;
00650 
00651     NaifStatus::CheckErrors();
00652   }
00653 
00662   void Spice::SubSolarPoint (double &lat, double &lon) {
00663     NaifStatus::CheckErrors();
00664 
00665     if (p_et == -DBL_MAX) {
00666       std::string msg = "You must call SetEphemerisTime first";
00667       throw iException::Message(iException::Programmer,msg,_FILEINFO_);
00668     }
00669 
00670     SpiceDouble uuB[3],dist;
00671     unorm_c (p_uB,uuB,&dist);
00672 
00673     SpiceDouble a = p_radii[0];
00674     SpiceDouble b = p_radii[1];
00675     SpiceDouble c = p_radii[2];
00676 
00677     SpiceDouble originB[3];
00678     originB[0] = originB[1] = originB[2] = 0.0;
00679 
00680     SpiceBoolean found;
00681     SpiceDouble subB[3];
00682     surfpt_c (originB,uuB,a,b,c,subB,&found);
00683 
00684     SpiceDouble mylon,mylat;
00685     reclat_c (subB,&a,&mylon,&mylat);
00686     lat = mylat * 180.0 / Isis::PI;
00687     lon = mylon * 180.0 / Isis::PI;
00688     if (lon < 0.0) lon += 360.0;
00689 
00690     NaifStatus::CheckErrors();
00691   }
00692 
00693   void Spice::ComputeSolarLongitude(double et) {
00694     NaifStatus::CheckErrors();
00695     
00696     if (iString(Target()).UpCase() == "SKY") {
00697       p_solarLongitude = -999.0;
00698       return;
00699     } 
00700 
00701     if (p_bodyRotation->IsCached()) return;
00702 
00703     double tipm[3][3], npole[3];
00704     char frameName[32];
00705     SpiceInt frameCode;
00706     SpiceBoolean found;
00707 
00708     cidfrm_c (p_spkBodyCode, sizeof(frameName), &frameCode, frameName, &found);
00709 
00710     if ( found ) {
00711       pxform_c("J2000",frameName,et,tipm);
00712     }
00713     else {
00714       tipbod_c("J2000",p_spkBodyCode,et,tipm);
00715     }
00716  
00717     for (int i=0; i<3; i++) {
00718       npole[i] = tipm[2][i];
00719     }
00720 
00721     double state[6], lt;
00722     spkez_c(p_spkBodyCode,et,"J2000","NONE",10,state,&lt);
00723 
00724     double uavel[3];
00725     ucrss_c(state,&state[3],uavel);
00726 
00727     double x[3], y[3], z[3];
00728     vequ_c(uavel,z);
00729     ucrss_c(npole,z,x);
00730     ucrss_c(z,x,y);
00731 
00732     double trans[3][3];
00733     for (int i=0; i<3; i++) {
00734       trans[0][i] = x[i];
00735       trans[1][i] = y[i];
00736       trans[2][i] = z[i];
00737     }
00738 
00739     spkez_c(10,et,"J2000","LT+S",p_spkBodyCode,state,&lt);
00740 
00741     double pos[3];
00742     mxv_c(trans,state,pos);
00743 
00744     double radius, ls, lat;
00745     reclat_c(pos,&radius,&ls,&lat);
00746     ls *= 180.0 / Isis::PI;
00747     if (ls < 0.0) ls += 360.0;
00748     else if (ls > 360.0) ls -= 360.0;
00749     p_solarLongitude = ls;
00750 
00751     NaifStatus::CheckErrors();
00752   }
00753 
00754 
00760    double Spice::SolarLongitude() {
00761      ComputeSolarLongitude(p_et);
00762      return p_solarLongitude;
00763    }
00764 
00765 
00772   bool Spice::HasKernels(Isis::Pvl &lab) {
00773 
00774     // Get the kernel group and check main kernels
00775     Isis::PvlGroup kernels = lab.FindGroup("Kernels",Isis::Pvl::Traverse);
00776     std::vector<string> keywords;
00777     keywords.push_back("TargetPosition");
00778 
00779     if (kernels.HasKeyword("SpacecraftPosition")) {
00780       keywords.push_back("SpacecraftPosition");
00781     }
00782     else {
00783       keywords.push_back("InstrumentPosition");
00784     }
00785 
00786     if (kernels.HasKeyword("SpacecraftPointing")) {
00787       keywords.push_back("SpacecraftPointing");
00788     }
00789     else {
00790       keywords.push_back("InstrumentPointing");
00791     }
00792 
00793     if (kernels.HasKeyword("Frame")) {
00794       keywords.push_back("Frame");
00795     }
00796 
00797     if (kernels.HasKeyword("Extra")) {
00798       keywords.push_back("Extra");
00799     }
00800 
00801     Isis::PvlKeyword key;
00802     for (int ikey = 0; ikey < (int) keywords.size(); ikey++) {
00803       key = kernels[ikey];
00804 
00805       for (int i=0; i<key.Size(); i++) {
00806         if (key[i] == "") return false;
00807         if (iString(key[i]).UpCase() == "NULL") return false;
00808         if (iString(key[i]).UpCase() == "NADIR") return false;
00809         if (iString(key[i]).UpCase() == "TABLE") return false;
00810       }
00811     }
00812     return true;
00813   }
00814 }