Isis 3.0 Application Source Code Reference |
Home |
00001 /** 00002 * @file 00003 * $Revision: 2661 $ 00004 * $Date: 2011-06-16 15:40:56 -0700 (Thu, 16 Jun 2011) $ 00005 * $Id: SpkSegment.cpp 2661 2011-06-16 22:40:56Z slambright@GS.DOI.NET $ 00006 * 00007 * Unless noted otherwise, the portions of Isis written by the USGS are 00008 * public domain. See individual third-party library and package descriptions 00009 * for intellectual property information, user agreements, and related 00010 * information. 00011 * 00012 * Although Isis has been used by the USGS, no warranty, expressed or 00013 * implied, is made by the USGS as to the accuracy and functioning of such 00014 * software and related material nor shall the fact of distribution 00015 * constitute any such warranty, and no responsibility is assumed by the 00016 * USGS in connection therewith. 00017 * 00018 * For additional information, launch 00019 * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html 00020 * in a browser or see the Privacy & Disclaimers page on the Isis website, 00021 * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on 00022 * http://www.usgs.gov/privacy.html. 00023 */ 00024 #include <string> 00025 #include <vector> 00026 #include <numeric> 00027 #include <iostream> 00028 #include <iomanip> 00029 #include <sstream> 00030 #include <algorithm> 00031 #include <functional> 00032 00033 00034 #include "SpkSegment.h" 00035 #include "iString.h" 00036 #include "Filename.h" 00037 #include "Cube.h" 00038 #include "Camera.h" 00039 #include "Table.h" 00040 #include "NaifStatus.h" 00041 #include "iException.h" 00042 00043 #include "naif/SpiceUsr.h" 00044 #define PURE_METHODS_PRESENT 1 00045 00046 using namespace std; 00047 00048 namespace Isis { 00049 00050 /** Default constructor */ 00051 SpkSegment::SpkSegment() : SpiceSegment() { 00052 init(); 00053 } 00054 00055 /** Constructor from ISIS cube file by name of the cube */ 00056 SpkSegment::SpkSegment(const std::string &fname) : SpiceSegment() { 00057 init(); 00058 Cube cube; 00059 cube.open(fname); 00060 SpiceSegment::init(cube); 00061 import(cube); 00062 } 00063 00064 /** Constructor from ISIS cube object */ 00065 SpkSegment::SpkSegment(Cube &cube) : SpiceSegment(cube) { 00066 init(); 00067 import(cube); 00068 } 00069 00070 /** 00071 * @brief Load and process SPICE data from an ISIS cube object 00072 * 00073 * This method extracts SPK SPICE date from an ISIS cube object. This object 00074 * must have been spiceinit'ed at a minimum and, by definition, have a 00075 * supporting camera model. 00076 * 00077 * SPK data is extracted from the SpicePosition object via the Table it provides 00078 * of this information. The SPICE position state vectors are potentially 00079 * trasformed to the proper state for target body, center body and reference 00080 * frame. 00081 * 00082 * @author kbecker (5/2/2011) 00083 * 00084 * @param cube Cube to generate SPICE segment from 00085 * 00086 * @internal 00087 * @history 2011-05-27 Debbie A. Cook - Added call to create Hermite cache 00088 * to make this option available for testing. 00089 * This will need to be an option in the future. 00090 */ 00091 void SpkSegment::import(Cube &cube) { 00092 typedef std::vector<std::string> StrList; 00093 00094 // Extract ISIS SPK blob and transform to CK 3 content 00095 NaifStatus::CheckErrors(); 00096 try { 00097 00098 Camera *camera(cube.getCamera()); 00099 Kernels kernels = getKernels(); 00100 00101 // Load necessary kernels and id frames 00102 kernels.Load("PCK,LSK,FK,SPK,EXTRA"); 00103 #if defined(PURE_METHODS_PRESENT) 00104 _body = camera->SpkTargetId(); 00105 _center = camera->SpkCenterId(); 00106 _refFrame = getNaifName(camera->SpkReferenceId()); 00107 #else 00108 // This probably covers 95% of the missions - really needs the pure methods 00109 _body = camera->NaifSpkCode(); 00110 _center = camera->NaifBodyCode(); 00111 _refFrame = getNaifName(1); 00112 #endif 00113 _bodyFrame = getNaifName(_body); 00114 _centerFrame = getNaifName(_center); 00115 00116 // Get the SPICE data 00117 // spkCache = camera->InstrumentPosition()->LineCache("SpkSegment"); 00118 Table spkCache = camera->InstrumentPosition()->LoadHermiteCache("SpkSegment"); 00119 getStates(*camera, load(spkCache), _states, _epochs, _hasVV); 00120 00121 // Save current time 00122 SpicePosition *ipos(camera->InstrumentPosition()); 00123 double currentTime = ipos->EphemerisTime(); 00124 00125 00126 00127 #if 0 00128 //// This is currently determined to not be required and needs to bei 00129 //// turned off. (2011-05-17 KJB) 00130 00131 // Adjust times for aberration and light time corrections. Note this 00132 // is a kludge only needed until we correct this on read by spiceinit 00133 _epochs = adjustTimes(*camera, _epochs); 00134 #endif 00135 00136 // Add records with 3 milliseconds padding to top and bottom of records 00137 // const double Epsilon(3.0e-3); 00138 const double Epsilon(3.0e-3); 00139 00140 // Pad the top and bottom of the 00141 _states = expand(1, 1, _states); 00142 _epochs = expand(1, 1, _epochs); 00143 00144 int ndim1(_states.dim1()); 00145 int ndim2(_states.dim2()); 00146 00147 // Add record to top of states 00148 SVector stateT(ndim2, _states[1]); // Map to to first record 00149 double sTime = _epochs[1] - Epsilon; 00150 SVector s0 = makeState(ipos, _epochs[1], stateT, sTime); 00151 SVector(ndim2, _states[0]).inject(s0); 00152 _epochs[0] = sTime; 00153 00154 // Add record to bottom of states 00155 stateT = SVector(ndim2, _states[ndim1-2]); 00156 sTime = _epochs[ndim1-2] + Epsilon; 00157 s0 = makeState(ipos, _epochs[ndim1-2], stateT, sTime); 00158 SVector(ndim2, _states[ndim1-1]).inject(s0); 00159 _epochs[ndim1-1] = sTime; 00160 00161 // Restore saved time and determine degree of NAIF interpolation 00162 ipos->SetEphemerisTime(currentTime); 00163 _degree = std::min((int) MaximumDegree, _states.dim1()-1); 00164 // Ensure the degree is odd and less that the even value 00165 _degree = (((_degree - 1) / 2) * 2) + 1; 00166 00167 00168 #if 0 00169 // Prints state vectors 00170 for ( int i = 0 ; i < size() ; i++ ) { 00171 cout << i << ":"; 00172 for ( int j = 0 ; j < _states.dim2() ; j++ ) { 00173 cout << " " << setw(26) << setprecision(13) << _states[i][j]; 00174 } 00175 cout << " " << setw(26) << setprecision(13) << _epochs[i] << "\n"; 00176 } 00177 #endif 00178 setStartTime(_epochs[0]); 00179 setEndTime(_epochs[size(_epochs)-1]); 00180 00181 } catch ( iException &ie ) { 00182 ostringstream mess; 00183 mess << "Failed to construct SPK content from ISIS file " << Source(); 00184 ie.Message(iException::User, mess.str(), _FILEINFO_); 00185 throw; 00186 } 00187 00188 return; 00189 } 00190 00191 /** 00192 * @brief Convert J2000 positions to frame relative to center body 00193 * 00194 * This method converts the data from SpicePostion to state vectors relative to 00195 * the center of motion of the object identified by body. The return results 00196 * will be ready to write to (at least) SPK kernels of type 9 and 13. 00197 * 00198 * The "states" parameters will be a matrix of the form states[nrecs][6], where 00199 * "nrecs" is the number of states in the table, and times[nrecs] corresponds 00200 * to TDB time for each nrecs record. 00201 * 00202 * PreRequisites: 00203 * The internal _body, _center and _refFrame are required to be defined prior 00204 * to calling this routine. 00205 * The FK kernel is likely to be required to be loaded in the NAIF kernel 00206 * pool so that frame translations can occur. The caller is burdened with 00207 * ensuring the kernel is loaded. 00208 * 00209 * @author Kris Becker - 2/21/2011 00210 * 00211 * @param camera Camera object for the data 00212 * @param spice Data from the SpicePosition::LineCache method 00213 * @param states Matrix containing "nrecs" states vectors 00214 * @param times TBD epoch times for each record 00215 */ 00216 void SpkSegment::getStates(Camera &camera, const SMatrix &spice, 00217 SMatrix &states, SVector &epochs, bool &hasVV) 00218 const { 00219 int nrecs = size(spice); 00220 int nelems = spice.dim2(); 00221 states = SMatrix(nrecs, 6, 0.0); // Initialize to 0 should no deltas exist 00222 epochs = SVector(nrecs); 00223 hasVV = (nelems == 7); 00224 00225 // cout << "Number Records: " << nrecs << "\n"; 00226 00227 // Extract contents 00228 for ( int i = 0 ; i < nrecs ; i++ ) { 00229 // cout << "Rec: " << i; 00230 for ( int j = 0 ; j < (nelems-1) ; j++ ) { 00231 states[i][j] = spice[i][j]; 00232 // cout << " " << setw(26) << setprecision(13) << _states[i][j]; 00233 } 00234 epochs[i] = spice[i][nelems-1]; 00235 // cout << " " << setw(26) << setprecision(13) << _epochs[i] << "\n"; 00236 } 00237 00238 // Compute state rotations relative to the reference frame 00239 string j2000 = getNaifName(1); // ISIS stores in J2000 00240 if (j2000 != _refFrame) { 00241 for (int n = 0 ; n < nrecs ; n++) { 00242 SpiceDouble xform[6][6]; 00243 sxform_c(j2000.c_str(), _refFrame.c_str(), epochs[n], xform); 00244 mxvg_c(xform, states[n], 6, 6, states[n]); 00245 } 00246 } 00247 00248 return; 00249 } 00250 00251 /** 00252 * @brief Make a new state vector from the current state and time 00253 * 00254 * This method creates a new state from the given state0 using the position 00255 * object and current time, time0, at that position. timeT is the new time of 00256 * the desired state. 00257 * 00258 * @author kbecker (5/2/2011) 00259 * 00260 * @param position Position object for the state 00261 * @param time0 Current time for give state 00262 * @param state0 Current state vector 00263 * @param timeT Desired time of the new state 00264 * 00265 * @return SpkSegment::SVector New state at timeT 00266 * @internal 00267 * @history 2011-06-03 Debbie A. Cook Put extrapolation code back 00268 * in use since it gives the best results. 00269 */ 00270 SpkSegment::SVector SpkSegment::makeState(SpicePosition *position, const double &time0, 00271 const SVector &state0, const double &timeT) const { 00272 00273 00274 SVector stateT = state0.copy(); 00275 // The code below seems to be working well for fixing the ends so I am putting it back in DAC 00276 #if 1 00277 position->SetEphemerisTime(time0); 00278 std::vector<double> tstate = position->Extrapolate(timeT); 00279 int nElems = std::min((int) tstate.size(), state0.dim1()); 00280 for ( int i = 0 ; i < nElems ; i++ ) { 00281 stateT[i] = tstate[i]; 00282 } 00283 #endif 00284 // for ( int i = 3 ; i < stateT.dim1() ; i++ ) { 00285 // stateT[i] = 0.0; 00286 // } 00287 00288 return (stateT); 00289 } 00290 00291 /** 00292 * @brief Construct a comment for the given segment 00293 * 00294 * @author kbecker (5/2/2011) 00295 * 00296 * @return std::string Comment string for the segment 00297 */ 00298 std::string SpkSegment::getComment() const { 00299 ostringstream comment; 00300 00301 comment << 00302 "\n-----------------------------------------------------------------------\n" << 00303 " File: " << Filename(Source()).Name() << endl << 00304 " Segment ID: " << Id() << " (ProductId)" << endl << 00305 " StartTime: " << utcStartTime() << endl << 00306 " EndTime: " << utcEndTime() << endl << 00307 " Target Body: " << "Body " << _body << ", " << _bodyFrame << endl << 00308 " Center Body: " << "Body " << _center << ", " << _centerFrame << endl << 00309 " RefFrame: " << _refFrame << endl << 00310 " Records: " << size() << endl; 00311 00312 string hasVV = (_hasVV) ? "YES" : "NO"; 00313 comment << 00314 " HasVV: " << hasVV << endl; 00315 00316 comment << 00317 " PolyDegree: " << _degree << endl << 00318 " CamVersion: " << CameraVersion() << endl; 00319 std::vector<std::string> klist = getKernels().getKernelList(); 00320 if ( klist.size() > 0 ) { 00321 comment << 00322 " Kernels: \n"; 00323 for ( unsigned int i = 0 ; i < klist.size() ; i++ ) { 00324 comment << 00325 " " << klist[i] << endl; 00326 } 00327 } 00328 00329 return (string(comment.str())); 00330 } 00331 00332 /** 00333 * @brief Initialize object parameters 00334 * 00335 * @author kbecker (5/2/2011) 00336 */ 00337 void SpkSegment::init() { 00338 _body = _center = 1; 00339 _bodyFrame = _centerFrame = _refFrame = ""; 00340 _states = SMatrix(0,0); 00341 _epochs = SVector(0); 00342 _hasVV = false; 00343 _degree = 1; 00344 return; 00345 } 00346 00347 /** 00348 * @brief Load the SPK segements from the ISIS table object 00349 * 00350 * This method extracts position vectors, velocity vectors (if they exist) and 00351 * epochs (times) from an ISIS SpicePosition BLOB/table. The table content 00352 * (number of fields) determine if the vectors exist. 00353 * 00354 * @author kbecker (5/2/2011) 00355 * 00356 * @param table SpicePosition Table to extract SPK data 00357 * 00358 * @return SpkSegment::SMatrix Returns SPK data 00359 */ 00360 SpkSegment::SMatrix SpkSegment::load(Table &table) { 00361 00362 // Allocate the internal cache and transfer. 00363 // Makes some assumptions about the format of the SPICE table in that 00364 // all fields are double. 00365 int nrecs = table.Records(); 00366 TableRecord &rec = table[0]; 00367 int nvals = rec.Fields(); 00368 00369 // Ensure the table has the expected format, error out if not valid. 00370 // if ( !((nvals == 7) || (nvals == 4)) ) { 00371 // ostringstream mess; 00372 // mess << "SPICE (SPK) Table " << table.Name() 00373 // << " must have 7 (with velocity vectors) or 4 fields but has " 00374 // << nvals; 00375 // throw iException::Message(iException::User, mess.str(), _FILEINFO_); 00376 // } 00377 00378 // Extract contents 00379 SMatrix spice = SMatrix(nrecs,nvals); 00380 for ( int i = 0 ; i < nrecs ; i++ ) { 00381 TableRecord &rec = table[i]; 00382 for ( int f = 0 ; f < rec.Fields() ; f++ ) { 00383 TableField &field = rec[f]; 00384 spice[i][f] = (double) field; 00385 } 00386 } 00387 return (spice); 00388 } 00389 00390 /** 00391 * @brief Adjust times for stellar aberration and light time 00392 * 00393 * This method adjusts the times for stellar aberration and light time 00394 * correction if needed. This is only a temporary fix until it is corrected in 00395 * the SpicePosition class. 00396 * 00397 * Prerequisites: Upon calling this method, the appropriate SPK must be loaded. 00398 * The reference frame (_refFrame), typically "J2000", must also be defined. 00399 * 00400 * Currently, several missions do not apply these corrections. These are 00401 * LunarOrbiter and Mariner10. 00402 * 00403 * @author kbecker (5/2/2011) 00404 * 00405 * @param epochs Times to correct for aberration and light time 00406 * 00407 * @return SpkSegment::SVector Corrected/adjust times 00408 */ 00409 SpkSegment::SVector SpkSegment::adjustTimes(Camera &camera, 00410 const SVector &epochs) const { 00411 00412 SpiceInt observer = camera.NaifSpkCode(); 00413 00414 // Don't adjust the following spacecraft: 00415 SpiceInt LunarOrbiter(-533), Mariner10(-76); 00416 if (observer == LunarOrbiter) return (epochs); 00417 if (observer == Mariner10) return (epochs); 00418 00419 SpiceInt target = camera.NaifBodyCode(); 00420 SVector ltEpochs(epochs.dim1()); 00421 for ( int i = 0 ; i < epochs.dim1() ; i++ ) { 00422 SpiceDouble lt; 00423 SpiceDouble state[6]; 00424 spkez_c(observer, epochs[i], _refFrame.c_str(), "LT+S", target, state, <); 00425 ltEpochs[i] = epochs[i] - lt; 00426 } 00427 return (ltEpochs); 00428 } 00429 }; // namespace Isis 00430