USGS

Isis 3.0 Application Source Code Reference

Home

SpkSegment.cpp

Go to the documentation of this file.
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, &lt);
00425     ltEpochs[i] = epochs[i] - lt;
00426   }
00427   return (ltEpochs);
00428 }
00429 };  // namespace Isis
00430