Isis 3.0 Object Programmers' Reference |
Home |
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,<); 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,<); 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 }