From 13d63d32bae306d368ddf2a8a03fbbcc031f3b53 Mon Sep 17 00:00:00 2001
From: Kelvin Rodriguez <kr788@nau.edu>
Date: Wed, 8 Apr 2020 14:38:57 -0700
Subject: [PATCH] Updated isd (#345)

* before merge storm

* std::invalid_arg doesn't exist?

* added more std except for linux

* we :heart: C++ OOP, now featuring 100% more boilerplate

* tests

* comments

* FromThis to_this thanks to VIM shortcuts because damn

* miniconda download for mac seems to have died

* comments

* more consistant tabbing
---
 .travis.yml                                 |   2 +-
 ale/formatters/formatter.py                 |  81 ++--
 include/InterpUtils.h                       |  51 ++-
 include/Isd.h                               |  28 +-
 include/Orientations.h                      |  23 +-
 include/Rotation.h                          |  16 +-
 include/States.h                            | 202 +++++-----
 include/Util.h                              |  49 +--
 include/Vectors.h                           |  28 ++
 include/ale.h                               |  44 ---
 src/InterpUtils.cpp                         | 181 ++++++++-
 src/Isd.cpp                                 |  12 +-
 src/Orientations.cpp                        |  51 ++-
 src/Rotation.cpp                            |  16 +-
 src/States.cpp                              |  76 ++--
 src/Util.cpp                                | 249 +++++++++---
 src/ale.cpp                                 | 192 +--------
 tests/ctests/IsdTests.cpp                   | 270 +++++++++----
 tests/ctests/OrientationsTest.cpp           |  10 +-
 tests/ctests/StatesTest.cpp                 | 415 ++++++++++----------
 tests/pytests/data/isds/cassiniiss_isd.json |  72 ++--
 tests/pytests/data/isds/ctx_isd.json        |  72 ++--
 tests/pytests/data/isds/dawnfc_isd.json     |  72 ++--
 tests/pytests/data/isds/kaguyami_isd.json   |  72 ++--
 tests/pytests/data/isds/kaguyatc_isd.json   |  72 ++--
 tests/pytests/data/isds/lrolroc_isd.json    |  76 ++--
 tests/pytests/data/isds/messmdis_isd.json   |  72 ++--
 tests/pytests/test_formatter.py             |  64 +--
 28 files changed, 1466 insertions(+), 1102 deletions(-)
 create mode 100644 include/Vectors.h

diff --git a/.travis.yml b/.travis.yml
index bcff8d8..8b4bddd 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -35,7 +35,7 @@ install:
     if [ "$TRAVIS_OS_NAME" == "linux" ]; then
       wget https://repo.continuum.io/miniconda/Miniconda3-latest-Linux-x86_64.sh -O miniconda.sh;
     else
-      curl -o miniconda.sh  https://repo.continuum.io/miniconda/Miniconda3-latest-MacOSX-x86_64.sh;
+      curl -o miniconda.sh  https://repo.anaconda.com/miniconda/Miniconda3-latest-MacOSX-x86_64.sh;
     fi
   - bash miniconda.sh -b -p $HOME/miniconda
   - export PATH="$HOME/miniconda/bin:$PATH"
diff --git a/ale/formatters/formatter.py b/ale/formatters/formatter.py
index b745149..8b3b8a4 100644
--- a/ale/formatters/formatter.py
+++ b/ale/formatters/formatter.py
@@ -26,10 +26,10 @@ def to_isd(driver):
 
     meta_data = {}
 
-    meta_data['IsisCameraVersion'] = driver.sensor_model_version
+    meta_data['isis_camera_version'] = driver.sensor_model_version
 
     # interiror orientation
-    meta_data['NaifKeywords'] = driver.naif_keywords
+    meta_data['naif_keywords'] = driver.naif_keywords
     meta_data['detector_sample_summing'] = driver.sample_summing
     meta_data['detector_line_summing'] = driver.line_summing
     meta_data['focal_length_model'] = {
@@ -89,21 +89,24 @@ def to_isd(driver):
 
     # Reverse the frame order because ISIS orders frames as
     # (destination, intermediate, ..., intermediate, source)
-    instrument_pointing['TimeDependentFrames'] = shortest_path(frame_chain, destination_frame, 1)
+    instrument_pointing['time_dependent_frames'] = shortest_path(frame_chain, destination_frame, 1)
     time_dependent_rotation = frame_chain.compute_rotation(1, destination_frame)
-    instrument_pointing['CkTableStartTime'] = time_dependent_rotation.times[0]
-    instrument_pointing['CkTableEndTime'] = time_dependent_rotation.times[-1]
-    instrument_pointing['CkTableOriginalSize'] = len(time_dependent_rotation.times)
-    instrument_pointing['EphemerisTimes'] = time_dependent_rotation.times
-    instrument_pointing['Quaternions'] = time_dependent_rotation.quats[:, [3, 0, 1, 2]]
-    instrument_pointing['AngularVelocity'] = time_dependent_rotation.av
+    instrument_pointing['ck_table_start_time'] = time_dependent_rotation.times[0]
+    instrument_pointing['ck_table_end_time'] = time_dependent_rotation.times[-1]
+    instrument_pointing['ck_table_original_size'] = len(time_dependent_rotation.times)
+    instrument_pointing['ephemeris_times'] = time_dependent_rotation.times
+    instrument_pointing['quaternions'] = time_dependent_rotation.quats[:, [3, 0, 1, 2]]
+    instrument_pointing['angular_velocity'] = time_dependent_rotation.av
+
+    # reference frame should be the last frame in the chain
+    instrument_pointing["reference_frame"] = instrument_pointing['time_dependent_frames'][-1]
 
     # Reverse the frame order because ISIS orders frames as
     # (destination, intermediate, ..., intermediate, source)
-    instrument_pointing['ConstantFrames'] = shortest_path(frame_chain, sensor_frame, destination_frame)
+    instrument_pointing['constant_frames'] = shortest_path(frame_chain, sensor_frame, destination_frame)
     constant_rotation = frame_chain.compute_rotation(destination_frame, sensor_frame)
-    instrument_pointing['ConstantRotation'] = constant_rotation.rotation_matrix().flatten()
-    meta_data['InstrumentPointing'] = instrument_pointing
+    instrument_pointing['constant_rotation'] = constant_rotation.rotation_matrix().flatten()
+    meta_data['instrument_pointing'] = instrument_pointing
 
     body_rotation = {}
     source_frame, destination_frame, time_dependent_target_frame = frame_chain.last_time_dependent_frame_between(target_frame, 1)
@@ -111,51 +114,57 @@ def to_isd(driver):
     if source_frame != 1:
         # Reverse the frame order because ISIS orders frames as
         # (destination, intermediate, ..., intermediate, source)
-        body_rotation['TimeDependentFrames'] = shortest_path(frame_chain, source_frame, 1)
+        body_rotation['time_dependent_frames'] = shortest_path(frame_chain, source_frame, 1)
         time_dependent_rotation = frame_chain.compute_rotation(1, source_frame)
-        body_rotation['CkTableStartTime'] = time_dependent_rotation.times[0]
-        body_rotation['CkTableEndTime'] = time_dependent_rotation.times[-1]
-        body_rotation['CkTableOriginalSize'] = len(time_dependent_rotation.times)
-        body_rotation['EphemerisTimes'] = time_dependent_rotation.times
-        body_rotation['Quaternions'] = time_dependent_rotation.quats[:, [3, 0, 1, 2]]
-        body_rotation['AngularVelocity'] = time_dependent_rotation.av
+        body_rotation['ck_table_start_time'] = time_dependent_rotation.times[0]
+        body_rotation['ck_table_end_time'] = time_dependent_rotation.times[-1]
+        body_rotation['ck_table_original_size'] = len(time_dependent_rotation.times)
+        body_rotation['ephemeris_times'] = time_dependent_rotation.times
+        body_rotation['quaternions'] = time_dependent_rotation.quats[:, [3, 0, 1, 2]]
+        body_rotation['angular_velocity'] = time_dependent_rotation.av
 
     if source_frame != target_frame:
         # Reverse the frame order because ISIS orders frames as
         # (destination, intermediate, ..., intermediate, source)
-        body_rotation['ConstantFrames'] = shortest_path(frame_chain, target_frame, source_frame)
+        body_rotation['constant_frames'] = shortest_path(frame_chain, target_frame, source_frame)
         constant_rotation = frame_chain.compute_rotation(source_frame, target_frame)
-        body_rotation['ConstantRotation'] = constant_rotation.rotation_matrix().flatten()
+        body_rotation['constant_rotation'] = constant_rotation.rotation_matrix().flatten()
 
-    meta_data['BodyRotation'] = body_rotation
+    body_rotation["reference_frame"] = destination_frame
+    meta_data['body_rotation'] = body_rotation
 
     j2000_rotation = frame_chain.compute_rotation(target_frame, 1)
 
     instrument_position = {}
     positions, velocities, times = driver.sensor_position
-    instrument_position['SpkTableStartTime'] = times[0]
-    instrument_position['SpkTableEndTime'] = times[-1]
-    instrument_position['SpkTableOriginalSize'] = len(times)
-    instrument_position['EphemerisTimes'] = times
+    instrument_position['spk_table_start_time'] = times[0]
+    instrument_position['spk_table_end_time'] = times[-1]
+    instrument_position['spk_table_original_size'] = len(times)
+    instrument_position['ephemeris_times'] = times
     # Rotate positions and velocities into J2000 then scale into kilometers
     velocities = j2000_rotation.rotate_velocity_at(positions, velocities, times)/1000
     positions = j2000_rotation.apply_at(positions, times)/1000
-    instrument_position['Positions'] = positions
-    instrument_position['Velocities'] = velocities
-    meta_data['InstrumentPosition'] = instrument_position
+    instrument_position['positions'] = positions
+    instrument_position['velocities'] = velocities
+    instrument_position["reference_frame"] = destination_frame
+
+    meta_data['instrument_position'] = instrument_position
 
     sun_position = {}
     positions, velocities, times = driver.sun_position
-    sun_position['SpkTableStartTime'] = times[0]
-    sun_position['SpkTableEndTime'] = times[-1]
-    sun_position['SpkTableOriginalSize'] = len(times)
-    sun_position['EphemerisTimes'] = times
+    sun_position['spk_table_start_time'] = times[0]
+    sun_position['spk_table_end_time'] = times[-1]
+    sun_position['spk_table_original_size'] = len(times)
+    sun_position['ephemeris_times'] = times
     # Rotate positions and velocities into J2000 then scale into kilometers
     velocities = j2000_rotation.rotate_velocity_at(positions, velocities, times)/1000
     positions = j2000_rotation.apply_at(positions, times)/1000
-    sun_position['Positions'] = positions
-    sun_position['Velocities'] = velocities
-    meta_data['SunPosition'] = sun_position
+    sun_position['positions'] = positions
+    sun_position['velocities'] = velocities
+    sun_position["reference_frame"] = destination_frame
+
+    meta_data['sun_position'] = sun_position
+
 
     # check that there is a valid sensor model name
     if 'name_model' not in meta_data:
diff --git a/include/InterpUtils.h b/include/InterpUtils.h
index ecd533f..b7a2bed 100644
--- a/include/InterpUtils.h
+++ b/include/InterpUtils.h
@@ -3,9 +3,25 @@
 
 #include <vector>
 
-#include "Util.h"
+#include "Vectors.h"
 
 namespace ale {
+
+  enum RotationInterpolation {
+    SLERP, // Spherical interpolation
+    NLERP // Normalized linear interpolation
+  };
+
+  /// Interpolation enum for defining different methods of interpolation
+  enum PositionInterpolation {
+    /// Interpolate using linear interpolation
+    LINEAR = 0,
+    /// Interpolate using a cubic spline
+    SPLINE = 1,
+    /// Interpolate using Lagrange polynomials up to 8th order
+    LAGRANGE = 2,
+  };
+
   /**
    * Linearly interpolate between two values.
    * @param x The first value.
@@ -22,7 +38,7 @@ namespace ale {
    */
   std::vector<double> linearInterpolate(const std::vector<double> &x, const std::vector<double> &y, double t);
 
-  ale::Vec3d linearInterpolate(const ale::Vec3d &x, const ale::Vec3d &y, double t);
+  Vec3d linearInterpolate(const Vec3d &x, const Vec3d &y, double t);
 
   /**
    * Compute the index of the first time to use when interpolating at a given time.
@@ -40,6 +56,37 @@ namespace ale {
    */
    std::vector<double> orderedVecMerge(const std::vector<double> &x, const std::vector<double> &y);
 
+
+   /** The following helper functions are used to calculate the reduced states cache and cubic hermite
+   to interpolate over it. They were migrated, with minor modifications, from
+   Isis::NumericalApproximation **/
+
+   /** Evaluates a cubic hermite at time, interpTime, between the appropriate two points in x. **/
+   double evaluateCubicHermite(const double interpTime, const std::vector<double>& derivs,
+                            const std::vector<double>& x, const std::vector<double>& y);
+
+   /** Evaluate velocities using a Cubic Hermite Spline at a time a, within some interval in x, **/
+   double evaluateCubicHermiteFirstDeriv(const double interpTime, const std::vector<double>& deriv,
+                                     const std::vector<double>& times, const std::vector<double>& y);
+
+   double lagrangeInterpolate(const std::vector<double>& times, const std::vector<double>& values,
+                           double time, int order=8);
+   double lagrangeInterpolateDerivative(const std::vector<double>& times, const std::vector<double>& values,
+                                     double time, int order=8);
+
+   /**
+    *@brief Interpolates the spacecrafts position along a path generated from a set of points,
+              times, and a time of observation
+    *@param points A double vector of points
+    *@param times A double vector of times
+    *@param time A double to use as the time of observation
+    *@param interp An interpolation enum dictating what type of interpolation to use
+    *@param d The order of the derivative to generate when interpolating
+                    (Currently supports 0, 1, and 2)
+    *@return
+   */
+   double interpolate(std::vector<double> points, std::vector<double> times, double time, PositionInterpolation interp, int d);
+
 }
 
 #endif
diff --git a/include/Isd.h b/include/Isd.h
index c1a544c..e5e609a 100644
--- a/include/Isd.h
+++ b/include/Isd.h
@@ -5,11 +5,13 @@
 #include <vector>
 #include <map>
 
-#include "Util.h"
+#include <nlohmann/json.hpp>
+
 #include "Distortion.h"
 
-//#include "Rotation.h"
-//#include "State.h"
+#include "Rotation.h"
+#include "States.h"
+#include "Orientations.h"
 
 namespace ale {
 
@@ -24,7 +26,7 @@ namespace ale {
     std::string name_platform;
     std::string image_id;
     std::string name_sensor;
-
+    
     double semi_major;
     double semi_minor;
 
@@ -59,19 +61,17 @@ namespace ale {
     double starting_ephemeris_time;
     double center_ephemeris_time;
 
-    double t0_ephemeris_time;
-    double dt_ephemeris_time;
-
-    double t0_quaternions;
-    double dt_quaternions;
-
     json naif_keywords;
+    
+    PositionInterpolation interpMethod;
+    
+    Rotation const_rotation; 
 
-    //Positions sensor_pos;
-    //Positions sun_pos;
+    States inst_pos;
+    States sun_pos;
 
-    //Rotation sensor_orientation;
-    //Rotation body_orientaion;
+    Orientations inst_pointing;
+    Orientations body_rotation;
   };
 }
 
diff --git a/include/Orientations.h b/include/Orientations.h
index 902e8a6..cf193de 100644
--- a/include/Orientations.h
+++ b/include/Orientations.h
@@ -12,6 +12,7 @@ namespace ale {
      * Construct a default empty orientation object
      */
     Orientations() {};
+    
     /**
      * Construct an orientation object give a set of rotations
      * and optionally angular velocities at specific times.
@@ -19,8 +20,13 @@ namespace ale {
     Orientations(
       const std::vector<Rotation> &rotations,
       const std::vector<double> &times,
-      const std::vector<Vec3d> &avs = std::vector<ale::Vec3d>()
+      const std::vector<Vec3d> &avs = std::vector<ale::Vec3d>(),
+      const int refFrame = 1, 
+      const Rotation &constRot = Rotation(1, 0, 0, 0),
+      const std::vector<int> const_frames = std::vector<int>(), 
+      const std::vector<int> time_dependent_frames = std::vector<int>() 
     );
+
     /**
      * Orientations destructor
      */
@@ -29,9 +35,13 @@ namespace ale {
     /**
      * Const accessor methods
      */
-    std::vector<Rotation> rotations() const;
-    std::vector<ale::Vec3d> angularVelocities() const;
-    std::vector<double> times() const;
+    std::vector<Rotation> getRotations() const;
+    std::vector<ale::Vec3d> getAngularVelocities() const;
+    std::vector<double> getTimes() const;
+    std::vector<int> getConstantFrames() const; 
+    std::vector<int> getTimeDependentFrames() const;
+    int getReferenceFrame() const;
+    Rotation getConstantRotation() const; 
 
     /**
      * Get the interpolated rotation at a specific time.
@@ -40,6 +50,7 @@ namespace ale {
       double time,
       RotationInterpolation interpType=SLERP
     ) const;
+    
     /**
      * Get the interpolated angular velocity at a specific time
      */
@@ -75,6 +86,10 @@ namespace ale {
     std::vector<Rotation> m_rotations;
     std::vector<ale::Vec3d> m_avs;
     std::vector<double> m_times;
+    std::vector<int> m_timeDepFrames; 
+    std::vector<int> m_constFrames; 
+    Rotation m_constRotation;
+    int m_refFrame; 
   };
 }
 
diff --git a/include/Rotation.h b/include/Rotation.h
index c3ffbf1..f3f056c 100644
--- a/include/Rotation.h
+++ b/include/Rotation.h
@@ -5,15 +5,10 @@
 #include <vector>
 
 #include "States.h"
-#include "Util.h"
+#include "Vectors.h"
 
 namespace ale {
 
-  enum RotationInterpolation {
-    SLERP, // Spherical interpolation
-    NLERP // Normalized linear interpolation
-  };
-
   /**
    * A generic 3D rotation.
    */
@@ -24,8 +19,7 @@ namespace ale {
        */
       Rotation();
       /**
-       * Construct a rotation from a quaternion.
-       *
+       * Construct a rotation from a quaternion
        * @param w The scalar component of the quaternion.
        * @param x The x value of the vector component of the quaternion.
        * @param y The y value of the vector component of the quaternion.
@@ -82,7 +76,7 @@ namespace ale {
        *
        * @return The state rotation matrix in row-major order.
        */
-      std::vector<double> toStateRotationMatrix(const ale::Vec3d &av) const;
+      std::vector<double> toStateRotationMatrix(const Vec3d &av) const;
       /**
        * The rotation as Euler angles.
        *
@@ -107,9 +101,9 @@ namespace ale {
        *
        * @return The rotated vector.
        */
-      ale::Vec3d operator()(const ale::Vec3d &av) const;
+      Vec3d operator()(const Vec3d &av) const;
 
-      ale::State operator()(const ale::State &state, const ale::Vec3d& av = Vec3d(0.0, 0.0, 0.0)) const;
+      State operator()(const State &state, const Vec3d& av = Vec3d(0.0, 0.0, 0.0)) const;
       /**
        * Get the inverse rotation.
        */
diff --git a/include/States.h b/include/States.h
index b204c8f..37de4e4 100644
--- a/include/States.h
+++ b/include/States.h
@@ -1,113 +1,113 @@
 #ifndef ALE_STATES_H
 #define ALE_STATES_H
 
-#include<vector>
+#include <vector>
 #include <stdexcept>
-#include <ale.h>
 
-#include "Util.h"
 
-namespace ale {
+#include "Vectors.h"
+#include "InterpUtils.h"
 
-/** A state vector with position and velocity*/
-struct State {
-  Vec3d position;
-  Vec3d velocity;
-
-  // Accepts a {x, y, z, vx, vy, vz} vector
-  State(const std::vector<double>& vec) {
-    if (vec.size() != 6) {
-      throw std::invalid_argument("Input vector must have 6 entries.");
-    }
-    position = {vec[0], vec[1], vec[2]};
-    velocity = {vec[3], vec[4], vec[5]};
+namespace ale {
+  /** A state vector with position and velocity*/
+  struct State {
+    Vec3d position;
+    Vec3d velocity;
+
+    // Accepts a {x, y, z, vx, vy, vz} vector
+    State(const std::vector<double>& vec) {
+      if (vec.size() != 6) {
+        throw std::invalid_argument("Input vector must have 6 entries.");
+      }
+      position = {vec[0], vec[1], vec[2]};
+      velocity = {vec[3], vec[4], vec[5]};
+    };
+
+    State(Vec3d position, Vec3d velocity) : position(position), velocity(velocity) {};
+    State() {};
   };
 
-  State(ale::Vec3d position, ale::Vec3d velocity) : position(position), velocity(velocity) {};
-  State() {};
-};
-
-class States {
-  public:
-    // Constructors
-    States();
-    States(const std::vector<double>& ephemTimes, const std::vector<ale::Vec3d>& positions,
-           int refFrame=1);
-
-    States(const std::vector<double>& ephemTimes, const std::vector<ale::Vec3d>& positions,
-           const std::vector<ale::Vec3d>& velocities, int refFrame=1);
-
-    States(const std::vector<double>& ephemTimes, const std::vector<ale::State>& states,
-           int refFrame=1);
-
-    ~States();
-
-    // Getters
-    std::vector<ale::State> getStates() const; //! Returns state vectors (6-element positions&velocities)
-    std::vector<ale::Vec3d> getPositions() const; //! Returns the current positions
-    std::vector<ale::Vec3d> getVelocities() const; //! Returns the current velocities
-    std::vector<double> getTimes() const; //! Returns the current times
-    int getReferenceFrame() const; //! Returns reference frame as NAIF ID
-    bool hasVelocity() const; //! Returns true if any velocities have been provided
-
-  /**
-   * Returns a single state by interpolating state.
-   * If the Cache has been minimized, a cubic hermite is used to interpolate the
-   * position and velocity over the reduced cache.
-   * If not, a standard lagrange interpolation will be done.
-   *
-   * @param time Time to get a value at
-   * @param interp Interpolation type to use. Will be ignored if cache is minimized.
-   *
-   * @return ale::State
-   */
-    ale::State getState(double time, ale::interpolation interp=LINEAR) const;
-
-    /** Gets a position at a single time. Operates the same way as getState() **/
-    ale::Vec3d getPosition(double time, ale::interpolation interp=LINEAR) const;
-
-    /** Gets a velocity at a single time. Operates the same way as getState() **/
-    ale::Vec3d getVelocity(double time, ale::interpolation interp=LINEAR) const;
-
-    /** Returns the first ephemeris time **/
-    double getStartTime();
-
-    /** Returns the last ephemeris time **/
-    double getStopTime();
-
-  /**
-   * Perform a cache reduction. After running this, getStates(), getPositions(),
-   * and getVelocities() will return vectors of reduced size, and getState(),
-   * getPosition(), and getVelocity() will
-   * returns values interpolated over the reduced cache using a cubic hermite spline
-   *
-   * Adapted from Isis::SpicePosition::reduceCache().
-   *
-   * @param tolerance Maximum error between hermite approximation and original value.
-   */
-    States minimizeCache(double tolerance=0.01);
-
-  private:
-
-  /**
-   * Calculates the points (indicies) which need to be kept for the hermite spline to
-   * interpolate between to mantain a maximum error of tolerance.
-   *
-   * Adapted from Isis::SpicePosition::HermiteIndices.
-   *
-   * @param tolerance Maximum error between hermite approximation and original value.
-   * @param indexList The list of indicies that need to be kept.
-   * @param baseTime Scaled base time for fit
-   * @param timeScale Time scale for fit.
-   *
-   * @return std::vector<int>
-   */
-    std::vector<int> hermiteIndices(double tolerance, std::vector <int> indexList,
-                                    double baseTime, double timeScale);
-    std::vector<ale::State> m_states; //! Represent at states internally to keep pos, vel together
-    std::vector<double> m_ephemTimes; //! Time in seconds
-    int m_refFrame;  //! Naif IDs for reference frames
-  };
+  class States {
+    public:
+      // Constructors
+      States();
+      States(const std::vector<double>& ephemTimes, const std::vector<Vec3d>& positions,
+             int refFrame=1);
+
+      States(const std::vector<double>& ephemTimes, const std::vector<Vec3d>& positions,
+             const std::vector<Vec3d>& velocities, int refFrame=1);
+
+      States(const std::vector<double>& ephemTimes, const std::vector<State>& states,
+             int refFrame=1);
+
+      ~States();
+
+      // Getters
+      std::vector<State> getStates() const; //! Returns state vectors (6-element positions&velocities)
+      std::vector<Vec3d> getPositions() const; //! Returns the current positions
+      std::vector<Vec3d> getVelocities() const; //! Returns the current velocities
+      std::vector<double> getTimes() const; //! Returns the current times
+      int getReferenceFrame() const; //! Returns reference frame as NAIF ID
+      bool hasVelocity() const; //! Returns true if any velocities have been provided
+
+    /**
+     * Returns a single state by interpolating state.
+     * If the Cache has been minimized, a cubic hermite is used to interpolate the
+     * position and velocity over the reduced cache.
+     * If not, a standard lagrange interpolation will be done.
+     *
+     * @param time Time to get a value at
+     * @param interp Interpolation type to use. Will be ignored if cache is minimized.
+     *
+     * @return State
+     */
+      State getState(double time, PositionInterpolation interp=LINEAR) const;
+
+      /** Gets a position at a single time. Operates the same way as getState() **/
+      Vec3d getPosition(double time, PositionInterpolation interp=LINEAR) const;
+
+      /** Gets a velocity at a single time. Operates the same way as getState() **/
+      Vec3d getVelocity(double time, PositionInterpolation interp=LINEAR) const;
+
+      /** Returns the first ephemeris time **/
+      double getStartTime();
+
+      /** Returns the last ephemeris time **/
+      double getStopTime();
+
+    /**
+     * Perform a cache reduction. After running this, getStates(), getPositions(),
+     * and getVelocities() will return vectors of reduced size, and getState(),
+     * getPosition(), and getVelocity() will
+     * returns values interpolated over the reduced cache using a cubic hermite spline
+     *
+     * Adapted from Isis::SpicePosition::reduceCache().
+     *
+     * @param tolerance Maximum error between hermite approximation and original value.
+     */
+      States minimizeCache(double tolerance=0.01);
+
+    private:
+
+    /**
+     * Calculates the points (indicies) which need to be kept for the hermite spline to
+     * interpolate between to mantain a maximum error of tolerance.
+     *
+     * Adapted from Isis::SpicePosition::HermiteIndices.
+     *
+     * @param tolerance Maximum error between hermite approximation and original value.
+     * @param indexList The list of indicies that need to be kept.
+     * @param baseTime Scaled base time for fit
+     * @param timeScale Time scale for fit.
+     *
+     * @return std::vector<int>
+     */
+      std::vector<int> hermiteIndices(double tolerance, std::vector <int> indexList,
+                                      double baseTime, double timeScale);
+      std::vector<State> m_states; //! Represent as states internally to keep pos, vel together
+      std::vector<double> m_ephemTimes; //! Time in seconds
+      int m_refFrame;  //! Naif IDs for reference frames
+    };
 }
 
 #endif
diff --git a/include/Util.h b/include/Util.h
index 1023183..6d1d69b 100644
--- a/include/Util.h
+++ b/include/Util.h
@@ -4,38 +4,37 @@
 #include <string>
 #include <nlohmann/json.hpp>
 
-#include "Isd.h"
+#include "InterpUtils.h"
 #include "Distortion.h"
+#include "States.h"
+#include "Orientations.h"
+#include "Vectors.h"
 
 namespace ale {
   using json = nlohmann::json;
 
-  /** A 3D cartesian vector */
-  struct Vec3d {
-    double x;
-    double y;
-    double z;
-
-    // Accepts an {x,y,z} vector
-    Vec3d(const std::vector<double>& vec) {
-      if (vec.size() != 3) {
-        throw std::invalid_argument("Input vector must have 3 entries.");
+  template<typename T>
+  std::vector<T> getJsonArray(json obj) {
+    std::vector<T> positions;
+    try {
+      for (auto &location : obj) {
+        positions.push_back(location.get<T>());
       }
-      x = vec[0];
-      y = vec[1];
-      z = vec[2];
-    };
+    } catch (...) {
+      throw std::runtime_error("Could not parse the json array.");
+    }
+    return positions;
+  }
 
-    Vec3d(double x, double y, double z) : x(x), y(y), z(z) {};
-    Vec3d() : x(0.0), y(0.0), z(0.0) {};
-  };
 
+  PositionInterpolation getInterpolationMethod(json isd);
   double getMinHeight(nlohmann::json isd);
   std::string getSensorModelName(json isd);
   std::string getImageId(json isd);
   std::string getSensorName(json isd);
   std::string getPlatformName(json isd);
   std::string getLogFile(nlohmann::json isd);
+  std::string getIsisCameraVersion(json isd);
   int getTotalLines(json isd);
   int getTotalSamples(json isd);
   double getStartingTime(json isd);
@@ -57,10 +56,16 @@ namespace ale {
   double getSemiMinorRadius(json isd);
   DistortionType getDistortionModel(json isd);
   std::vector<double> getDistortionCoeffs(json isd);
-  std::vector<double> getSunPositions(json isd);
-  std::vector<double> getSensorPositions(json isd);
-  std::vector<double> getSensorVelocities(json isd);
-  std::vector<double> getSensorOrientations(json isd);
+  
+  std::vector<double> getJsonDoubleArray(json obj);
+  std::vector<Vec3d> getJsonVec3dArray(json obj);
+  std::vector<Rotation> getJsonQuatArray(json obj);
+
+  States getInstrumentPosition(json isd);
+  States getSunPosition(json isd);
+
+  Orientations getBodyRotation(json isd);
+  Orientations getInstrumentPointing(json isd);
 }
 
 #endif
diff --git a/include/Vectors.h b/include/Vectors.h
new file mode 100644
index 0000000..3992073
--- /dev/null
+++ b/include/Vectors.h
@@ -0,0 +1,28 @@
+#ifndef ALE_VECTORS_H
+#define ALE_VECTORS_H
+
+#include <stdexcept>
+
+namespace ale {
+  /** A 3D cartesian vector */
+  struct Vec3d {
+    double x;
+    double y;
+    double z;
+
+    // Accepts an {x,y,z} vector
+    Vec3d(const std::vector<double>& vec) {
+      if (vec.size() != 3) {
+        throw std::invalid_argument("Input vector must have 3 entries.");
+      }
+      x = vec[0];
+      y = vec[1];
+      z = vec[2];
+    };
+
+    Vec3d(double x, double y, double z) : x(x), y(y), z(z) {};
+    Vec3d() : x(0.0), y(0.0), z(0.0) {};
+  };
+}
+
+#endif
diff --git a/include/ale.h b/include/ale.h
index a81a777..a6469a3 100644
--- a/include/ale.h
+++ b/include/ale.h
@@ -4,55 +4,11 @@
 #include <string>
 #include <vector>
 
-#include "InterpUtils.h"
 
 #include <nlohmann/json.hpp>
 
 namespace ale {
 
-  /// Interpolation enum for defining different methods of interpolation
-  enum interpolation {
-    /// Interpolate using linear interpolation
-    LINEAR = 0,
-    /// Interpolate using a cubic spline
-    SPLINE = 1,
-    /// Interpolate using Lagrange polynomials up to 8th order
-    LAGRANGE = 2,
-  };
-
-
-  // Temporarily moved interpolation and associated helper functions over from States. Will be
-  // move to interpUtils in the future.
-
-  /** The following helper functions are used to calculate the reduced states cache and cubic hermite
-  to interpolate over it. They were migrated, with minor modifications, from
-  Isis::NumericalApproximation **/
-
-  /** Evaluates a cubic hermite at time, interpTime, between the appropriate two points in x. **/
-  double evaluateCubicHermite(const double interpTime, const std::vector<double>& derivs,
-                              const std::vector<double>& x, const std::vector<double>& y);
-
-  /** Evaluate velocities using a Cubic Hermite Spline at a time a, within some interval in x, **/
-  double evaluateCubicHermiteFirstDeriv(const double interpTime, const std::vector<double>& deriv,
-                                       const std::vector<double>& times, const std::vector<double>& y);
-
-  double lagrangeInterpolate(const std::vector<double>& times, const std::vector<double>& values,
-                             double time, int order=8);
-  double lagrangeInterpolateDerivative(const std::vector<double>& times, const std::vector<double>& values,
-                                       double time, int order=8);
-
-  /**
-   *@brief Interpolates the spacecrafts position along a path generated from a set of points,
-                times, and a time of observation
-   *@param points A double vector of points
-   *@param times A double vector of times
-   *@param time A double to use as the time of observation
-   *@param interp An interpolation enum dictating what type of interpolation to use
-   *@param d The order of the derivative to generate when interpolating
-                      (Currently supports 0, 1, and 2)
-   *@return
-   */
-  double interpolate(std::vector<double> points, std::vector<double> times, double time, interpolation interp, int d);
   std::string loads(std::string filename, std::string props="", std::string formatter="usgscsm", bool verbose=true);
 
   nlohmann::json load(std::string filename, std::string props="", std::string formatter="usgscsm", bool verbose=true);
diff --git a/src/InterpUtils.cpp b/src/InterpUtils.cpp
index 0a1b665..ae44954 100644
--- a/src/InterpUtils.cpp
+++ b/src/InterpUtils.cpp
@@ -1,6 +1,7 @@
 #include "InterpUtils.h"
 
 #include <exception>
+#include <stdexcept>
 
 #include <algorithm>
 #include <unordered_set>
@@ -21,8 +22,8 @@ namespace ale {
     return interpVec;
   }
 
-  ale::Vec3d linearInterpolate(const ale::Vec3d &x, const ale::Vec3d &y, double t) {
-    ale::Vec3d interpVec;
+  Vec3d linearInterpolate(const Vec3d &x, const Vec3d &y, double t) {
+    Vec3d interpVec;
 
     interpVec.x = linearInterpolate(x.x, y.x, t);
     interpVec.y = linearInterpolate(x.y, y.y, t);
@@ -58,4 +59,180 @@ namespace ale {
     std::sort(merged.begin(), merged.end());
     return merged;
   }
+
+
+  /** The following helper functions are used to calculate the reduced states cache and cubic hermite
+  to interpolate over it. They were migrated, with minor modifications, from
+  Isis::NumericalApproximation **/
+
+
+  /** Evaluates a cubic hermite at time, interpTime, between the appropriate two points in x. **/
+  double evaluateCubicHermite(const double interpTime, const std::vector<double>& derivs,
+                              const std::vector<double>& x, const std::vector<double>& y) {
+    if( (derivs.size() != x.size()) || (derivs.size() != y.size()) ) {
+       throw std::invalid_argument("EvaluateCubicHermite - The size of the first derivative vector does not match the number of (x,y) data points.");
+    }
+
+    // Find the interval in which "a" exists
+    int lowerIndex = interpolationIndex(x, interpTime);
+
+    double x0, x1, y0, y1, m0, m1;
+    // interpTime is contained within the interval (x0,x1)
+    x0 = x[lowerIndex];
+    x1 = x[lowerIndex+1];
+    // the corresponding known y-values for x0 and x1
+    y0 = y[lowerIndex];
+    y1 = y[lowerIndex+1];
+    // the corresponding known tangents (slopes) at (x0,y0) and (x1,y1)
+    m0 = derivs[lowerIndex];
+    m1 = derivs[lowerIndex+1];
+
+    double h, t;
+    h = x1 - x0;
+    t = (interpTime - x0) / h;
+    return (2 * t * t * t - 3 * t * t + 1) * y0 + (t * t * t - 2 * t * t + t) * h * m0 + (-2 * t * t * t + 3 * t * t) * y1 + (t * t * t - t * t) * h * m1;
+  }
+
+  /** Evaluate velocities using a Cubic Hermite Spline at a time a, within some interval in x, **/
+ double evaluateCubicHermiteFirstDeriv(const double interpTime, const std::vector<double>& deriv,
+                                       const std::vector<double>& times, const std::vector<double>& y) {
+    if(deriv.size() != times.size()) {
+       throw std::invalid_argument("EvaluateCubicHermiteFirstDeriv - The size of the first derivative vector does not match the number of (x,y) data points.");
+    }
+
+    // find the interval in which "interpTime" exists
+    int lowerIndex = interpolationIndex(times, interpTime);
+
+    double x0, x1, y0, y1, m0, m1;
+
+    // interpTime is contained within the interval (x0,x1)
+    x0 = times[lowerIndex];
+    x1 = times[lowerIndex+1];
+
+    // the corresponding known y-values for x0 and x1
+    y0 = y[lowerIndex];
+    y1 = y[lowerIndex+1];
+
+    // the corresponding known tangents (slopes) at (x0,y0) and (x1,y1)
+    m0 = deriv[lowerIndex];
+    m1 = deriv[lowerIndex+1];
+
+    double h, t;
+    h = x1 - x0;
+    t = (interpTime - x0) / h;
+    if(h != 0.0) {
+      return ((6 * t * t - 6 * t) * y0 + (3 * t * t - 4 * t + 1) * h * m0 + (-6 * t * t + 6 * t) * y1 + (3 * t * t - 2 * t) * h * m1) / h;
+
+    }
+    else {
+      throw std::invalid_argument("Error in evaluating cubic hermite velocities, values at"
+                                  "lower and upper indicies are exactly equal.");
+    }
+  }
+
+  double lagrangeInterpolate(const std::vector<double>& times,
+                             const std::vector<double>& values,
+                             double time, int order) {
+    // Ensure the times and values have the same length
+    if (times.size() != values.size()) {
+      throw std::invalid_argument("Times and values must have the same length.");
+    }
+
+    // Get the correct interpolation window
+    int index = interpolationIndex(times, time);
+    int windowSize = std::min(index + 1, (int) times.size() - index - 1);
+    windowSize = std::min(windowSize, (int) order / 2);
+    int startIndex = index - windowSize + 1;
+    int endIndex = index + windowSize + 1;
+
+    // Interpolate
+    double result = 0;
+    for (int i = startIndex; i < endIndex; i++) {
+      double weight = 1;
+      double numerator = 1;
+      for (int j = startIndex; j < endIndex; j++) {
+        if (i == j) {
+          continue;
+        }
+        weight *= times[i] - times[j];
+        numerator *= time - times[j];
+      }
+      result += numerator * values[i] / weight;
+    }
+    return result;
+  }
+
+  double lagrangeInterpolateDerivative(const std::vector<double>& times,
+                                       const std::vector<double>& values,
+                                       double time, int order) {
+    // Ensure the times and values have the same length
+    if (times.size() != values.size()) {
+      throw std::invalid_argument("Times and values must have the same length.");
+    }
+
+    // Get the correct interpolation window
+    int index = interpolationIndex(times, time);
+    int windowSize = std::min(index + 1, (int) times.size() - index - 1);
+    windowSize = std::min(windowSize, (int) order / 2);
+    int startIndex = index - windowSize + 1;
+    int endIndex = index + windowSize + 1;
+
+    // Interpolate
+    double result = 0;
+    for (int i = startIndex; i < endIndex; i++) {
+      double weight = 1;
+      double derivativeWeight = 0;
+      double numerator = 1;
+      for (int j = startIndex; j < endIndex; j++) {
+        if (i == j) {
+          continue;
+        }
+        weight *= times[i] - times[j];
+        numerator *= time - times[j];
+        derivativeWeight += 1.0 / (time - times[j]);
+      }
+      result += numerator * values[i] * derivativeWeight / weight;
+    }
+    return result;
+  }
+
+ double interpolate(std::vector<double> points, std::vector<double> times, double time, PositionInterpolation interp, int d) {
+   size_t numPoints = points.size();
+   if (numPoints < 2) {
+     throw std::invalid_argument("At least two points must be input to interpolate over.");
+   }
+   if (points.size() != times.size()) {
+     throw std::invalid_argument("Must have the same number of points as times.");
+   }
+
+   int order;
+   switch(interp) {
+     case LINEAR:
+       order = 2;
+       break;
+     case SPLINE:
+       order = 4;
+       break;
+     case LAGRANGE:
+       order = 8;
+       break;
+     default:
+       throw std::invalid_argument("Invalid interpolation option, must be LINEAR, SPLINE, or LAGRANGE.");
+   }
+
+   double result;
+   switch(d) {
+     case 0:
+       result = lagrangeInterpolate(times, points, time, order);
+       break;
+     case 1:
+       result = lagrangeInterpolateDerivative(times, points, time, order);
+       break;
+     default:
+       throw std::invalid_argument("Invalid derivitive option, must be 0 or 1.");
+   }
+
+   return result;
+ }
+
 }
diff --git a/src/Isd.cpp b/src/Isd.cpp
index cd0e145..5f099b1 100644
--- a/src/Isd.cpp
+++ b/src/Isd.cpp
@@ -1,7 +1,7 @@
+
 #include "Isd.h"
 #include "Util.h"
 
-
 ale::Isd::Isd(std::string isd_file) {
   json isd = json::parse(isd_file);
 
@@ -41,4 +41,12 @@ ale::Isd::Isd(std::string isd_file) {
 
   distortion_model = getDistortionModel(isd);
   distortion_coefficients = getDistortionCoeffs(isd);
-}
+  
+  interpMethod = getInterpolationMethod(isd); 
+   
+  inst_pos = getInstrumentPosition(isd);
+  sun_pos = getSunPosition(isd);
+  
+  inst_pointing = getInstrumentPointing(isd);
+  body_rotation = getBodyRotation(isd); 
+ }
diff --git a/src/Orientations.cpp b/src/Orientations.cpp
index c99e536..811d100 100644
--- a/src/Orientations.cpp
+++ b/src/Orientations.cpp
@@ -7,9 +7,13 @@ namespace ale {
   Orientations::Orientations(
     const std::vector<Rotation> &rotations,
     const std::vector<double> &times,
-    const std::vector<ale::Vec3d> &avs
+    const std::vector<Vec3d> &avs,
+    const int refFrame, 
+    const Rotation &const_rot, 
+    const std::vector<int> const_frames, 
+    const std::vector<int> time_dependent_frames
   ) :
-    m_rotations(rotations), m_avs(avs), m_times(times) {
+    m_rotations(rotations), m_avs(avs), m_times(times), m_refFrame(refFrame), m_timeDepFrames(time_dependent_frames), m_constFrames(const_frames), m_constRotation(const_rot) {
     if (m_rotations.size() < 2 || m_times.size() < 2) {
       throw std::invalid_argument("There must be at least two rotations and times.");
     }
@@ -22,20 +26,35 @@ namespace ale {
   }
 
 
-  std::vector<Rotation> Orientations::rotations() const {
+  std::vector<Rotation> Orientations::getRotations() const {
     return m_rotations;
   }
 
 
-  std::vector<ale::Vec3d> Orientations::angularVelocities() const {
+  std::vector<Vec3d> Orientations::getAngularVelocities() const {
     return m_avs;
   }
 
 
-  std::vector<double> Orientations::times() const {
+  std::vector<double> Orientations::getTimes() const {
     return m_times;
   }
+  
+  std::vector<int> Orientations::getTimeDependentFrames() const {
+    return m_timeDepFrames; 
+  }
 
+  std::vector<int> Orientations::getConstantFrames() const {
+    return m_constFrames; 
+  }
+  
+  int Orientations::getReferenceFrame() const {
+    return m_refFrame; 
+  }
+
+  Rotation Orientations::getConstantRotation() const {
+    return m_constRotation; 
+  }
 
   Rotation Orientations::interpolate(
     double time,
@@ -47,16 +66,16 @@ namespace ale {
   }
 
 
-  ale::Vec3d Orientations::interpolateAV(double time) const {
+  Vec3d Orientations::interpolateAV(double time) const {
     int interpIndex = interpolationIndex(m_times, time);
     double t = (time - m_times[interpIndex]) / (m_times[interpIndex + 1] - m_times[interpIndex]);
-    ale::Vec3d interpAv = ale::Vec3d(linearInterpolate(m_avs[interpIndex], m_avs[interpIndex + 1], t));
+    Vec3d interpAv = Vec3d(linearInterpolate(m_avs[interpIndex], m_avs[interpIndex + 1], t));
     return interpAv;
   }
 
-  ale::Vec3d Orientations::rotateVectorAt(
+  Vec3d Orientations::rotateVectorAt(
     double time,
-    const ale::Vec3d &vector,
+    const Vec3d &vector,
     RotationInterpolation interpType,
     bool invert
   ) const {
@@ -65,19 +84,19 @@ namespace ale {
   }
 
 
-  ale::State Orientations::rotateStateAt(
+  State Orientations::rotateStateAt(
     double time,
-    const ale::State &state,
+    const State &state,
     RotationInterpolation interpType,
     bool invert
   ) const {
     Rotation interpRot = interpolate(time, interpType);
-    ale::Vec3d av(0.0, 0.0, 0.0);
+    Vec3d av(0.0, 0.0, 0.0);
     if (!m_avs.empty()) {
       av = interpolateAV(time);
     }
     if (invert) {
-      ale::Vec3d negAv = interpRot(av);
+      Vec3d negAv = interpRot(av);
       av = {-negAv.x, -negAv.y, -negAv.z};
       interpRot = interpRot.inverse();
     }
@@ -88,12 +107,12 @@ namespace ale {
   Orientations &Orientations::operator*=(const Orientations &rhs) {
     std::vector<double> mergedTimes = orderedVecMerge(m_times, rhs.m_times);
     std::vector<Rotation> mergedRotations;
-    std::vector<ale::Vec3d> mergedAvs;
+    std::vector<Vec3d> mergedAvs;
     for (double time: mergedTimes) {
       Rotation rhsRot = rhs.interpolate(time);
       mergedRotations.push_back(interpolate(time)*rhsRot);
-      ale::Vec3d combinedAv = rhsRot.inverse()(interpolateAV(time));
-      ale::Vec3d rhsAv = rhs.interpolateAV(time);
+      Vec3d combinedAv = rhsRot.inverse()(interpolateAV(time));
+      Vec3d rhsAv = rhs.interpolateAV(time);
       combinedAv.x += rhsAv.x;
       combinedAv.y += rhsAv.y;
       combinedAv.z += rhsAv.z;
diff --git a/src/Rotation.cpp b/src/Rotation.cpp
index bda92fc..3778a03 100644
--- a/src/Rotation.cpp
+++ b/src/Rotation.cpp
@@ -39,7 +39,7 @@ namespace ale {
    * as the AV from the destination to the source. This matches how NAIF
    * defines AV.
    */
-  Eigen::Quaterniond::Matrix3 avSkewMatrix(const ale::Vec3d& av) {
+  Eigen::Quaterniond::Matrix3 avSkewMatrix(const Vec3d& av) {
     Eigen::Quaterniond::Matrix3 avMat;
     avMat <<  0.0,    av.z, -av.y,
              -av.z,  0.0,    av.x,
@@ -153,7 +153,7 @@ namespace ale {
   }
 
 
-  std::vector<double> Rotation::toStateRotationMatrix(const ale::Vec3d &av) const {
+  std::vector<double> Rotation::toStateRotationMatrix(const Vec3d &av) const {
     Eigen::Quaterniond::Matrix3 rotMat = m_impl->quat.toRotationMatrix();
     Eigen::Quaterniond::Matrix3 avMat = avSkewMatrix(av);
     Eigen::Quaterniond::Matrix3 dtMat = rotMat * avMat;
@@ -195,19 +195,19 @@ namespace ale {
   }
 
 
-  ale::Vec3d Rotation::operator()(const ale::Vec3d &vector) const {
+  Vec3d Rotation::operator()(const Vec3d &vector) const {
     Eigen::Vector3d eigenVector(vector.x, vector.y, vector.z);
     Eigen::Vector3d rotatedVector = m_impl->quat._transformVector(eigenVector);
     std::vector<double> tempVec = std::vector<double>(rotatedVector.data(), rotatedVector.data() + rotatedVector.size());
     return Vec3d(tempVec);
   }
 
-  ale::State Rotation::operator()(
-        const ale::State& state,
-        const ale::Vec3d& av
+  State Rotation::operator()(
+        const State& state,
+        const Vec3d& av
   ) const {
-    ale::Vec3d position = state.position;
-    ale::Vec3d velocity = state.velocity;
+    Vec3d position = state.position;
+    Vec3d velocity = state.velocity;
 
     Eigen::Vector3d positionVector(position.x, position.y, position.z);
     Eigen::Vector3d velocityVector(velocity.x, velocity.y, velocity.z);
diff --git a/src/States.cpp b/src/States.cpp
index 5c98461..ad38d10 100644
--- a/src/States.cpp
+++ b/src/States.cpp
@@ -7,14 +7,14 @@
 
 namespace ale {
 
-   // Empty constructor
-   States::States() : m_refFrame(0) {
+  // Empty constructor
+  States::States() : m_refFrame(0) {
     m_states = {};
     m_ephemTimes = {};
   }
 
 
-  States::States(const std::vector<double>& ephemTimes, const std::vector<ale::Vec3d>& positions,
+  States::States(const std::vector<double>& ephemTimes, const std::vector<Vec3d>& positions,
                  int refFrame) :
     m_ephemTimes(ephemTimes), m_refFrame(refFrame) {
     // Construct State vector from position and velocity vectors
@@ -23,15 +23,15 @@ namespace ale {
       throw std::invalid_argument("Length of times must match number of positions");
     }
 
-    ale::Vec3d velocities = {0.0, 0.0, 0.0};
-    for (ale::Vec3d position : positions) {
-      m_states.push_back(ale::State(position, velocities));
+    Vec3d velocities = {0.0, 0.0, 0.0};
+    for (Vec3d position : positions) {
+      m_states.push_back(State(position, velocities));
     }
   }
 
 
-  States::States(const std::vector<double>& ephemTimes, const std::vector<ale::Vec3d>& positions,
-                 const std::vector<ale::Vec3d>& velocities, int refFrame) :
+  States::States(const std::vector<double>& ephemTimes, const std::vector<Vec3d>& positions,
+                 const std::vector<Vec3d>& velocities, int refFrame) :
     m_ephemTimes(ephemTimes), m_refFrame(refFrame) {
 
     if ((positions.size() != ephemTimes.size())||(ephemTimes.size() != velocities.size())) {
@@ -39,12 +39,12 @@ namespace ale {
     }
 
     for (int i=0; i < positions.size() ;i++) {
-      m_states.push_back(ale::State(positions[i], velocities[i]));
+      m_states.push_back(State(positions[i], velocities[i]));
     }
   }
 
 
-  States::States(const std::vector<double>& ephemTimes, const std::vector<ale::State>& states,
+  States::States(const std::vector<double>& ephemTimes, const std::vector<State>& states,
                  int refFrame) :
   m_ephemTimes(ephemTimes), m_states(states), m_refFrame(refFrame) {
     if (states.size() != ephemTimes.size()) {
@@ -56,26 +56,26 @@ namespace ale {
   States::~States() {}
 
   // Getters
-  std::vector<ale::State> States::getStates() const {
+  std::vector<State> States::getStates() const {
     return m_states;
   }
 
-  std::vector<ale::Vec3d> States::getPositions() const {
+  std::vector<Vec3d> States::getPositions() const {
     // extract positions from state vector
-    std::vector<ale::Vec3d> positions;
+    std::vector<Vec3d> positions;
 
-    for(ale::State state : m_states) {
+    for(State state : m_states) {
         positions.push_back(state.position);
     }
     return positions;
   }
 
 
-  std::vector<ale::Vec3d> States::getVelocities() const {
+  std::vector<Vec3d> States::getVelocities() const {
     // extract velocities from state vector
-    std::vector<ale::Vec3d> velocities;
+    std::vector<Vec3d> velocities;
 
-    for(ale::State state : m_states) {
+    for(State state : m_states) {
         velocities.push_back(state.velocity);
     }
     return velocities;
@@ -93,20 +93,20 @@ namespace ale {
 
 
   bool States::hasVelocity() const {
-    std::vector<ale::Vec3d> velocities = getVelocities();
-    bool allZero = std::all_of(velocities.begin(), velocities.end(), [](ale::Vec3d vec)
+    std::vector<Vec3d> velocities = getVelocities();
+    bool allZero = std::all_of(velocities.begin(), velocities.end(), [](Vec3d vec)
                                { return vec.x==0.0 && vec.y==0.0 && vec.z==0.0; });
     return !allZero;
   }
 
 
-  ale::State States::getState(double time, ale::interpolation interp) const {
-    int lowerBound = ale::interpolationIndex(m_ephemTimes, time);
+  State States::getState(double time, PositionInterpolation interp) const {
+    int lowerBound = interpolationIndex(m_ephemTimes, time);
     // try to copy the surrounding 8 points as that's the most possibly needed
     int interpStart = std::max(0, lowerBound - 3);
     int interpStop = std::min(lowerBound + 4, (int) m_ephemTimes.size() - 1);
 
-    ale::State state;
+    State state;
     std::vector<double> xs, ys, zs, vxs, vys, vzs, interpTimes;
 
     for (int i = interpStart; i <= interpStop; i++) {
@@ -120,7 +120,7 @@ namespace ale {
       vzs.push_back(state.velocity.z);
     }
 
-    ale::Vec3d position, velocity;
+    Vec3d position, velocity;
 
     if ( interp == LINEAR || (interp == SPLINE && !hasVelocity())) {
       position = {interpolate(xs,  interpTimes, time, interp, 0),
@@ -140,26 +140,26 @@ namespace ale {
         scaledEphemTimes.push_back(interpTimes[i] - baseTime);
       }
       double sTime = time - baseTime;
-      position.x = ale::evaluateCubicHermite(sTime, vxs, scaledEphemTimes, xs);
-      position.y = ale::evaluateCubicHermite(sTime, vys, scaledEphemTimes, ys);
-      position.z = ale::evaluateCubicHermite(sTime, vzs, scaledEphemTimes, zs);
+      position.x = evaluateCubicHermite(sTime, vxs, scaledEphemTimes, xs);
+      position.y = evaluateCubicHermite(sTime, vys, scaledEphemTimes, ys);
+      position.z = evaluateCubicHermite(sTime, vzs, scaledEphemTimes, zs);
 
-      velocity.x = ale::evaluateCubicHermiteFirstDeriv(sTime, vxs, scaledEphemTimes, xs);
-      velocity.y = ale::evaluateCubicHermiteFirstDeriv(sTime, vys, scaledEphemTimes, ys);
-      velocity.z = ale::evaluateCubicHermiteFirstDeriv(sTime, vzs, scaledEphemTimes, zs);
+      velocity.x = evaluateCubicHermiteFirstDeriv(sTime, vxs, scaledEphemTimes, xs);
+      velocity.y = evaluateCubicHermiteFirstDeriv(sTime, vys, scaledEphemTimes, ys);
+      velocity.z = evaluateCubicHermiteFirstDeriv(sTime, vzs, scaledEphemTimes, zs);
     }
-    return ale::State(position, velocity);
+    return State(position, velocity);
   }
 
 
-  ale::Vec3d States::getPosition(double time, ale::interpolation interp) const {
-    ale::State interpState = getState(time, interp);
+  Vec3d States::getPosition(double time, PositionInterpolation interp) const {
+    State interpState = getState(time, interp);
     return interpState.position;
   }
 
 
-  ale::Vec3d States::getVelocity(double time, ale::interpolation interp) const {
-    ale::State interpState = getState(time, interp);
+  Vec3d States::getVelocity(double time, PositionInterpolation interp) const {
+    State interpState = getState(time, interp);
     return interpState.velocity;
   }
 
@@ -200,7 +200,7 @@ namespace ale {
     std::vector <int> indexList = hermiteIndices(tolerance, inputIndices, baseTime, timeScale);
 
     // Update m_states and m_ephemTimes to only save the necessary indicies in the index list
-    std::vector<ale::State> tempStates;
+    std::vector<State> tempStates;
     std::vector<double> tempTimes;
 
     for(int i : indexList) {
@@ -237,9 +237,9 @@ namespace ale {
         sTime = (m_ephemTimes[line] - baseTime) / timeScale;
 
         // find the errors at each value
-        xerror = fabs(ale::evaluateCubicHermite(sTime, vx, scaledEphemTimes, x) - m_states[line].position.x);
-        yerror = fabs(ale::evaluateCubicHermite(sTime, vy, scaledEphemTimes, y) - m_states[line].position.y);
-        zerror = fabs(ale::evaluateCubicHermite(sTime, vz, scaledEphemTimes, z) - m_states[line].position.z);
+        xerror = fabs(evaluateCubicHermite(sTime, vx, scaledEphemTimes, x) - m_states[line].position.x);
+        yerror = fabs(evaluateCubicHermite(sTime, vy, scaledEphemTimes, y) - m_states[line].position.y);
+        zerror = fabs(evaluateCubicHermite(sTime, vz, scaledEphemTimes, z) - m_states[line].position.z);
 
         if(xerror > tolerance || yerror > tolerance || zerror > tolerance) {
           // if any error is greater than tolerance, no need to continue looking, break
diff --git a/src/Util.cpp b/src/Util.cpp
index f93d765..0a042e4 100644
--- a/src/Util.cpp
+++ b/src/Util.cpp
@@ -1,8 +1,21 @@
 #include <stdexcept>
+#include <algorithm>
+#include <iostream>
 
 #include "Util.h"
 
-std::string ale::getSensorModelName(json isd) {
+namespace ale {
+
+bool iequals(const std::string& a, const std::string& b) {
+    return std::equal(a.begin(), a.end(),
+                      b.begin(),
+                      [](char a, char b) {
+                          return tolower(a) == tolower(b);
+                      });
+}
+
+
+std::string getSensorModelName(json isd) {
   std::string name = "";
   try {
     name = isd.at("name_model");
@@ -12,7 +25,7 @@ std::string ale::getSensorModelName(json isd) {
   return name;
 }
 
-std::string ale::getImageId(json isd) {
+std::string getImageId(json isd) {
   std::string id = "";
   try {
     id = isd.at("image_identifier");
@@ -22,7 +35,7 @@ std::string ale::getImageId(json isd) {
   return id;
 }
 
-std::string ale::getSensorName(json isd) {
+std::string getSensorName(json isd) {
   std::string name = "";
   try {
     name = isd.at("name_sensor");
@@ -32,7 +45,18 @@ std::string ale::getSensorName(json isd) {
   return name;
 }
 
-std::string ale::getPlatformName(json isd) {
+std::string getIsisCameraVersion(json isd) {
+  std::string name = "";
+  try {
+    name = isd.at("IsisCameraVersion");
+  } catch (...) {
+    throw std::runtime_error("Could not parse the sensor name.");
+  }
+  return name;
+}
+
+
+std::string getPlatformName(json isd) {
   std::string name = "";
   try {
     name = isd.at("name_platform");
@@ -42,7 +66,7 @@ std::string ale::getPlatformName(json isd) {
   return name;
 }
 
-std::string ale::getLogFile(nlohmann::json isd) {
+std::string getLogFile(json isd) {
   std::string file = "";
   try {
     file = isd.at("log_file");
@@ -52,7 +76,7 @@ std::string ale::getLogFile(nlohmann::json isd) {
   return file;
 }
 
-int ale::getTotalLines(json isd) {
+int getTotalLines(json isd) {
   int lines = 0;
   try {
     lines = isd.at("image_lines");
@@ -63,7 +87,7 @@ int ale::getTotalLines(json isd) {
   return lines;
 }
 
-int ale::getTotalSamples(json isd) {
+int getTotalSamples(json isd) {
   int samples = 0;
   try {
     samples = isd.at("image_samples");
@@ -74,7 +98,7 @@ int ale::getTotalSamples(json isd) {
   return samples;
 }
 
-double ale::getStartingTime(json isd) {
+double getStartingTime(json isd) {
   double time = 0.0;
   try {
     time = isd.at("starting_ephemeris_time");
@@ -84,7 +108,7 @@ double ale::getStartingTime(json isd) {
   return time;
 }
 
-double ale::getCenterTime(json isd) {
+double getCenterTime(json isd) {
   double time = 0.0;
   try {
     time = isd.at("center_ephemeris_time");
@@ -94,7 +118,28 @@ double ale::getCenterTime(json isd) {
   return time;
 }
 
-std::vector<std::vector<double>> ale::getLineScanRate(json isd) {
+PositionInterpolation getInterpolationMethod(json isd) {
+  std::string interpMethod = "linear";
+  try {
+    interpMethod = isd.at("interpolation_method");
+     
+    if (iequals(interpMethod, "linear")) {
+      return PositionInterpolation::LINEAR;
+    }
+    else if (iequals(interpMethod, "spline")){ 
+      return PositionInterpolation::SPLINE;
+    } 
+    else if (iequals(interpMethod, "lagrange")) {
+      return PositionInterpolation::LAGRANGE;
+    }
+  } catch (...) {
+    throw std::runtime_error("Could not parse the interpolation method.");
+  }
+  
+  return PositionInterpolation::LINEAR;
+}
+
+std::vector<std::vector<double>> getLineScanRate(json isd) {
   std::vector<std::vector<double>> lines;
   try {
     for (auto &scanRate : isd.at("line_scan_rate")) {
@@ -108,7 +153,7 @@ std::vector<std::vector<double>> ale::getLineScanRate(json isd) {
 }
 
 
-int ale::getSampleSumming(json isd) {
+int getSampleSumming(json isd) {
   int summing = 0;
   try {
     summing = isd.at("detector_sample_summing");
@@ -119,7 +164,7 @@ int ale::getSampleSumming(json isd) {
   return summing;
 }
 
-int ale::getLineSumming(json isd) {
+int getLineSumming(json isd) {
   int summing = 0;
   try {
     summing = isd.at("detector_line_summing");
@@ -130,7 +175,7 @@ int ale::getLineSumming(json isd) {
   return summing;
 }
 
-double ale::getFocalLength(json isd) {
+double getFocalLength(json isd) {
   double length = 0.0;
   try {
     length = isd.at("focal_length_model").at("focal_length");
@@ -140,7 +185,7 @@ double ale::getFocalLength(json isd) {
   return length;
 }
 
-double ale::getFocalLengthUncertainty(json isd) {
+double getFocalLengthUncertainty(json isd) {
   double uncertainty = 1.0;
   try {
     uncertainty = isd.at("focal_length_model").value("focal_uncertainty", uncertainty);
@@ -150,7 +195,7 @@ double ale::getFocalLengthUncertainty(json isd) {
   return uncertainty;
 }
 
-std::vector<double> ale::getFocal2PixelLines(json isd) {
+std::vector<double> getFocal2PixelLines(json isd) {
   std::vector<double> transformation;
   try {
     transformation = isd.at("focal2pixel_lines").get<std::vector<double>>();
@@ -161,7 +206,7 @@ std::vector<double> ale::getFocal2PixelLines(json isd) {
   return transformation;
 }
 
-std::vector<double> ale::getFocal2PixelSamples(json isd) {
+std::vector<double> getFocal2PixelSamples(json isd) {
   std::vector<double> transformation;
   try {
     transformation = isd.at("focal2pixel_samples").get<std::vector<double>>();
@@ -172,7 +217,7 @@ std::vector<double> ale::getFocal2PixelSamples(json isd) {
   return transformation;
 }
 
-double ale::getDetectorCenterLine(json isd) {
+double getDetectorCenterLine(json isd) {
   double line;
   try {
     line = isd.at("detector_center").at("line");
@@ -182,7 +227,7 @@ double ale::getDetectorCenterLine(json isd) {
   return line;
 }
 
-double ale::getDetectorCenterSample(json isd) {
+double getDetectorCenterSample(json isd) {
   double sample;
   try {
     sample = isd.at("detector_center").at("sample");
@@ -192,7 +237,7 @@ double ale::getDetectorCenterSample(json isd) {
   return sample;
 }
 
-double ale::getDetectorStartingLine(json isd) {
+double getDetectorStartingLine(json isd) {
   double line;
   try {
     line = isd.at("starting_detector_line");
@@ -202,7 +247,7 @@ double ale::getDetectorStartingLine(json isd) {
   return line;
 }
 
-double ale::getDetectorStartingSample(json isd) {
+double getDetectorStartingSample(json isd) {
   double sample;
   try {
     sample = isd.at("starting_detector_sample");
@@ -212,7 +257,7 @@ double ale::getDetectorStartingSample(json isd) {
   return sample;
 }
 
-double ale::getMinHeight(json isd) {
+double getMinHeight(json isd) {
   double height = 0.0;
   try {
     json referenceHeight = isd.at("reference_height");
@@ -225,7 +270,7 @@ double ale::getMinHeight(json isd) {
   return height;
 }
 
-double ale::getMaxHeight(json isd) {
+double getMaxHeight(json isd) {
   double height = 0.0;
   try {
     json referenceHeight = isd.at("reference_height");
@@ -239,7 +284,7 @@ double ale::getMaxHeight(json isd) {
   return height;
 }
 
-double ale::getSemiMajorRadius(json isd) {
+double getSemiMajorRadius(json isd) {
   double radius = 0.0;
   try {
     json radii = isd.at("radii");
@@ -253,7 +298,7 @@ double ale::getSemiMajorRadius(json isd) {
   return radius;
 }
 
-double ale::getSemiMinorRadius(json isd) {
+double getSemiMinorRadius(json isd) {
   double radius = 0.0;
   try {
     json radii = isd.at("radii");
@@ -269,7 +314,7 @@ double ale::getSemiMinorRadius(json isd) {
 
 // Converts the distortion model name from the ISD (string) to the enumeration
 // type. Defaults to transverse
-ale::DistortionType ale::getDistortionModel(json isd) {
+DistortionType getDistortionModel(json isd) {
   try {
     json distoriton_subset = isd.at("optical_distortion");
 
@@ -294,10 +339,10 @@ ale::DistortionType ale::getDistortionModel(json isd) {
   return DistortionType::TRANSVERSE;
 }
 
-std::vector<double> ale::getDistortionCoeffs(json isd) {
+std::vector<double> getDistortionCoeffs(json isd) {
   std::vector<double> coefficients;
 
-  ale::DistortionType distortion = getDistortionModel(isd);
+  DistortionType distortion = getDistortionModel(isd);
 
   switch (distortion) {
   case DistortionType::TRANSVERSE: {
@@ -411,62 +456,142 @@ std::vector<double> ale::getDistortionCoeffs(json isd) {
   return coefficients;
 }
 
-std::vector<double> ale::getSunPositions(json isd) {
-  std::vector<double> positions;
+std::vector<Vec3d> getJsonVec3dArray(json obj) {
+  std::vector<Vec3d> positions;
   try {
-    json jayson = isd.at("sun_position");
-    for (auto &location : jayson.at("positions")) {
-      positions.push_back(location[0].get<double>());
-      positions.push_back(location[1].get<double>());
-      positions.push_back(location[2].get<double>());
+    for (auto &location : obj) {
+      Vec3d vec(location[0].get<double>(),location[1].get<double>(), location[2].get<double>() );
+      positions.push_back(vec);
     }
   } catch (...) {
-    throw std::runtime_error("Could not parse the sun positions.");
+    throw std::runtime_error("Could not parse the 3D vector array.");
   }
   return positions;
 }
 
-std::vector<double> ale::getSensorPositions(json isd) {
-  std::vector<double> positions;
+
+std::vector<Rotation> getJsonQuatArray(json obj) {
+  std::vector<Rotation> quats;
   try {
-    json jayson = isd.at("sensor_position");
-    for (auto &location : jayson.at("positions")) {
-      positions.push_back(location[0].get<double>());
-      positions.push_back(location[1].get<double>());
-      positions.push_back(location[2].get<double>());
+    for (auto &location : obj) {
+      Rotation vec(location[0].get<double>(),location[1].get<double>(), location[2].get<double>(), location[3].get<double>() );
+      quats.push_back(vec);
     }
   } catch (...) {
-    throw std::runtime_error("Could not parse the sensor positions.");
+    throw std::runtime_error("Could not parse the quaternion json object.");
   }
-  return positions;
+  return quats;
 }
 
-std::vector<double> ale::getSensorVelocities(json isd) {
-  std::vector<double> velocities;
+
+States getInstrumentPosition(json isd) {
   try {
-    json jayson = isd.at("sensor_position");
-    for (auto &velocity : jayson.at("velocities")) {
-      velocities.push_back(velocity[0].get<double>());
-      velocities.push_back(velocity[1].get<double>());
-      velocities.push_back(velocity[2].get<double>());
+    json ipos = isd.at("instrument_position");
+    std::vector<Vec3d> positions = getJsonVec3dArray(ipos.at("positions"));
+    std::vector<double> times = getJsonArray<double>(ipos.at("ephemeris_times")); 
+    int refFrame = ipos.at("reference_frame").get<int>();
+    
+    bool hasVelocities = ipos.find("velocities") != ipos.end();
+    
+    if (hasVelocities) {
+      std::vector<Vec3d> velocities = getJsonVec3dArray(ipos.at("velocities")); 
+      return States(times, positions, velocities, refFrame);  
     }
+    
+    return States(times, positions, refFrame);
   } catch (...) {
-    throw std::runtime_error("Could not parse the sensor velocities.");
+    throw std::runtime_error("Could not parse the instrument position");
   }
-  return velocities;
 }
 
-std::vector<double> ale::getSensorOrientations(json isd) {
-  std::vector<double> quaternions;
+
+States getSunPosition(json isd) {
   try {
-    for (auto &quaternion : isd.at("sensor_orientation").at("quaternions")) {
-      quaternions.push_back(quaternion[0]);
-      quaternions.push_back(quaternion[1]);
-      quaternions.push_back(quaternion[2]);
-      quaternions.push_back(quaternion[3]);
+    json spos = isd.at("sun_position");
+    std::vector<Vec3d> positions = getJsonVec3dArray(spos.at("positions"));
+    std::vector<double> times = getJsonArray<double>(spos.at("ephemeris_times")); 
+    int refFrame = spos.at("reference_frame").get<int>();
+    bool hasVelocities = spos.find("velocities") != spos.end();
+    
+    if (hasVelocities) {
+      std::vector<Vec3d> velocities = getJsonVec3dArray(spos.at("velocities")); 
+      return States(times, positions, velocities, refFrame);  
     }
+    
+    return States(times, positions, refFrame);
+  
   } catch (...) {
-    throw std::runtime_error("Could not parse the sensor orientations.");
+    throw std::runtime_error("Could not parse the sun position");
   }
-  return quaternions;
+}
+
+Orientations getInstrumentPointing(json isd) { 
+  try {
+    json pointing = isd.at("instrument_pointing");
+    
+    std::vector<Rotation> rotations = getJsonQuatArray(pointing.at("quaternions"));
+    std::vector<double> times = getJsonArray<double>(pointing.at("ephemeris_times")); 
+    std::vector<Vec3d> velocities = getJsonVec3dArray(pointing.at("angular_velocities"));
+    int refFrame = pointing.at("reference_frame").get<int>(); 
+    
+    std::vector<int> constFrames;
+    if (pointing.find("constant_frames") != pointing.end()){
+      constFrames  = getJsonArray<int>(pointing.at("constant_frames"));
+    }
+    
+    std::vector<int> timeDepFrames; 
+    if (pointing.find("time_dependent_frames") != pointing.end()){
+      timeDepFrames = getJsonArray<int>(pointing.at("time_dependent_frames"));
+    }
+
+    std::vector<double> rotArray = {1,0,0,0,1,0,0,0,1};
+    if (pointing.find("time_dependent_frames") != pointing.end()){
+      rotArray = getJsonArray<double>(pointing.at("constant_rotation"));
+    } 
+
+    Rotation constRot(rotArray);
+
+    Orientations orientation(rotations, times, velocities, refFrame, constRot, constFrames, timeDepFrames);  
+    
+    return orientation;
+  
+  } catch (...) {
+    throw std::runtime_error("Could not parse the instrument pointing");
+  } 
+}
+
+Orientations getBodyRotation(json isd) { 
+  try {
+    json bodrot = isd.at("body_rotation");
+    std::vector<Rotation> rotations = getJsonQuatArray(bodrot.at("quaternions"));
+    std::vector<double> times = getJsonArray<double>(bodrot.at("ephemeris_times")); 
+    std::vector<Vec3d> velocities = getJsonVec3dArray(bodrot.at("angular_velocities")); 
+   
+    int refFrame = bodrot.at("reference_frame").get<int>(); 
+    
+    std::vector<int> constFrames;
+    if (bodrot.find("constant_frames") != bodrot.end()){
+      constFrames  = getJsonArray<int>(bodrot.at("constant_frames"));
+    }
+    
+    std::vector<int> timeDepFrames; 
+    if (bodrot.find("time_dependent_frames") != bodrot.end()){
+      timeDepFrames = getJsonArray<int>(bodrot.at("time_dependent_frames"));
+    }
+
+    std::vector<double> rotArray = {1,0,0,0,1,0,0,0,1};
+    if (bodrot.find("constant_rotation") != bodrot.end()){
+      rotArray = getJsonArray<double>(bodrot.at("constant_rotation"));
+    } 
+
+    Rotation constRot(rotArray);
+
+    Orientations orientation(rotations, times, velocities, refFrame, constRot, constFrames, timeDepFrames);  
+    return orientation;
+  
+  } catch (...) {
+    throw std::runtime_error("Could not parse the body rotation");
+  } 
+}
+
 }
diff --git a/src/ale.cpp b/src/ale.cpp
index efb41c2..1fab2d9 100644
--- a/src/ale.cpp
+++ b/src/ale.cpp
@@ -5,193 +5,14 @@
 #include <iostream>
 #include <Python.h>
 
-#include <algorithm>
 #include <string>
 #include <iostream>
 #include <stdexcept>
 
 using json = nlohmann::json;
-using namespace std;
 
 namespace ale {
 
-
-  // Temporarily moved over from States.cpp. Will be moved into interpUtils in the future.
-
-  /** The following helper functions are used to calculate the reduced states cache and cubic hermite
-  to interpolate over it. They were migrated, with minor modifications, from
-  Isis::NumericalApproximation **/
-
-
-  /** Evaluates a cubic hermite at time, interpTime, between the appropriate two points in x. **/
-  double evaluateCubicHermite(const double interpTime, const std::vector<double>& derivs,
-                              const std::vector<double>& x, const std::vector<double>& y) {
-    if( (derivs.size() != x.size()) || (derivs.size() != y.size()) ) {
-       throw std::invalid_argument("EvaluateCubicHermite - The size of the first derivative vector does not match the number of (x,y) data points.");
-    }
-
-    // Find the interval in which "a" exists
-    int lowerIndex = ale::interpolationIndex(x, interpTime);
-
-    double x0, x1, y0, y1, m0, m1;
-    // interpTime is contained within the interval (x0,x1)
-    x0 = x[lowerIndex];
-    x1 = x[lowerIndex+1];
-    // the corresponding known y-values for x0 and x1
-    y0 = y[lowerIndex];
-    y1 = y[lowerIndex+1];
-    // the corresponding known tangents (slopes) at (x0,y0) and (x1,y1)
-    m0 = derivs[lowerIndex];
-    m1 = derivs[lowerIndex+1];
-
-    double h, t;
-    h = x1 - x0;
-    t = (interpTime - x0) / h;
-    return (2 * t * t * t - 3 * t * t + 1) * y0 + (t * t * t - 2 * t * t + t) * h * m0 + (-2 * t * t * t + 3 * t * t) * y1 + (t * t * t - t * t) * h * m1;
-  }
-
-  /** Evaluate velocities using a Cubic Hermite Spline at a time a, within some interval in x, **/
- double evaluateCubicHermiteFirstDeriv(const double interpTime, const std::vector<double>& deriv,
-                                       const std::vector<double>& times, const std::vector<double>& y) {
-    if(deriv.size() != times.size()) {
-       throw std::invalid_argument("EvaluateCubicHermiteFirstDeriv - The size of the first derivative vector does not match the number of (x,y) data points.");
-    }
-
-    // find the interval in which "interpTime" exists
-    int lowerIndex = ale::interpolationIndex(times, interpTime);
-
-    double x0, x1, y0, y1, m0, m1;
-
-    // interpTime is contained within the interval (x0,x1)
-    x0 = times[lowerIndex];
-    x1 = times[lowerIndex+1];
-
-    // the corresponding known y-values for x0 and x1
-    y0 = y[lowerIndex];
-    y1 = y[lowerIndex+1];
-
-    // the corresponding known tangents (slopes) at (x0,y0) and (x1,y1)
-    m0 = deriv[lowerIndex];
-    m1 = deriv[lowerIndex+1];
-
-    double h, t;
-    h = x1 - x0;
-    t = (interpTime - x0) / h;
-    if(h != 0.0) {
-      return ((6 * t * t - 6 * t) * y0 + (3 * t * t - 4 * t + 1) * h * m0 + (-6 * t * t + 6 * t) * y1 + (3 * t * t - 2 * t) * h * m1) / h;
-
-    }
-    else {
-      throw std::invalid_argument("Error in evaluating cubic hermite velocities, values at"
-                                  "lower and upper indicies are exactly equal.");
-    }
-  }
-
-  double lagrangeInterpolate(const std::vector<double>& times,
-                             const std::vector<double>& values,
-                             double time, int order) {
-    // Ensure the times and values have the same length
-    if (times.size() != values.size()) {
-      throw invalid_argument("Times and values must have the same length.");
-    }
-
-    // Get the correct interpolation window
-    int index = interpolationIndex(times, time);
-    int windowSize = min(index + 1, (int) times.size() - index - 1);
-    windowSize = min(windowSize, (int) order / 2);
-    int startIndex = index - windowSize + 1;
-    int endIndex = index + windowSize + 1;
-
-    // Interpolate
-    double result = 0;
-    for (int i = startIndex; i < endIndex; i++) {
-      double weight = 1;
-      double numerator = 1;
-      for (int j = startIndex; j < endIndex; j++) {
-        if (i == j) {
-          continue;
-        }
-        weight *= times[i] - times[j];
-        numerator *= time - times[j];
-      }
-      result += numerator * values[i] / weight;
-    }
-    return result;
-  }
-
-  double lagrangeInterpolateDerivative(const std::vector<double>& times,
-                                       const std::vector<double>& values,
-                                       double time, int order) {
-    // Ensure the times and values have the same length
-    if (times.size() != values.size()) {
-      throw invalid_argument("Times and values must have the same length.");
-    }
-
-    // Get the correct interpolation window
-    int index = interpolationIndex(times, time);
-    int windowSize = min(index + 1, (int) times.size() - index - 1);
-    windowSize = min(windowSize, (int) order / 2);
-    int startIndex = index - windowSize + 1;
-    int endIndex = index + windowSize + 1;
-
-    // Interpolate
-    double result = 0;
-    for (int i = startIndex; i < endIndex; i++) {
-      double weight = 1;
-      double derivativeWeight = 0;
-      double numerator = 1;
-      for (int j = startIndex; j < endIndex; j++) {
-        if (i == j) {
-          continue;
-        }
-        weight *= times[i] - times[j];
-        numerator *= time - times[j];
-        derivativeWeight += 1.0 / (time - times[j]);
-      }
-      result += numerator * values[i] * derivativeWeight / weight;
-    }
-    return result;
-  }
-
- double interpolate(vector<double> points, vector<double> times, double time, interpolation interp, int d) {
-   size_t numPoints = points.size();
-   if (numPoints < 2) {
-     throw invalid_argument("At least two points must be input to interpolate over.");
-   }
-   if (points.size() != times.size()) {
-     throw invalid_argument("Must have the same number of points as times.");
-   }
-
-   int order;
-   switch(interp) {
-     case LINEAR:
-       order = 2;
-       break;
-     case SPLINE:
-       order = 4;
-       break;
-     case LAGRANGE:
-       order = 8;
-       break;
-     default:
-       throw invalid_argument("Invalid interpolation option, must be LINEAR, SPLINE, or LAGRANGE.");
-   }
-
-   double result;
-   switch(d) {
-     case 0:
-       result = lagrangeInterpolate(times, points, time, order);
-       break;
-     case 1:
-       result = lagrangeInterpolateDerivative(times, points, time, order);
-       break;
-     default:
-       throw invalid_argument("Invalid derivitive option, must be 0 or 1.");
-   }
-
-   return result;
- }
-
  std::string getPyTraceback() {
     PyObject* err = PyErr_Occurred();
     if (err != NULL) {
@@ -212,7 +33,7 @@ namespace ale {
         Py_DECREF(module_name);
 
         if (pyth_module == NULL) {
-            throw runtime_error("getPyTraceback - Failed to import Python traceback Library");
+            throw std::runtime_error("getPyTraceback - Failed to import Python traceback Library");
         }
 
         pyth_func = PyObject_GetAttrString(pyth_module, "format_exception");
@@ -239,6 +60,7 @@ namespace ale {
     return "";
  }
 
+
  std::string loads(std::string filename, std::string props, std::string formatter, bool verbose) {
      static bool first_run = true;
      if(first_run) {
@@ -250,7 +72,7 @@ namespace ale {
      // Import the file as a Python module.
      PyObject *pModule = PyImport_Import(PyUnicode_FromString("ale"));
      if(!pModule) {
-       throw runtime_error("Failed to import ale. Make sure the ale python library is correctly installed.");
+       throw std::runtime_error("Failed to import ale. Make sure the ale python library is correctly installed.");
      }
      // Create a dictionary for the contents of the module.
      PyObject *pDict = PyModule_GetDict(pModule);
@@ -260,7 +82,7 @@ namespace ale {
      if(!pFunc) {
        // import errors do not set a PyError flag, need to use a custom
        // error message instead.
-       throw runtime_error("Failed to import ale.loads function from Python."
+       throw std::runtime_error("Failed to import ale.loads function from Python."
                            "This Usually indicates an error in the Ale Python Library."
                            "Check if Installed correctly and the function ale.loads exists.");
      }
@@ -268,7 +90,7 @@ namespace ale {
      // Create a Python tuple to hold the arguments to the method.
      PyObject *pArgs = PyTuple_New(3);
      if(!pArgs) {
-       throw runtime_error(getPyTraceback());
+       throw std::runtime_error(getPyTraceback());
      }
 
      // Set the Python int as the first and second arguments to the method.
@@ -285,14 +107,14 @@ namespace ale {
      PyObject* pResult = PyObject_CallObject(pFunc, pArgs);
 
      if(!pResult) {
-        throw invalid_argument("No Valid instrument found for label.");
+        throw std::invalid_argument("No Valid instrument found for label.");
      }
 
      PyObject *pResultStr = PyObject_Str(pResult);
      PyObject *temp_bytes = PyUnicode_AsUTF8String(pResultStr); // Owned reference
 
      if(!temp_bytes){
-       throw invalid_argument(getPyTraceback());
+       throw std::invalid_argument(getPyTraceback());
      }
      std::string cResult;
      char *temp_str = PyBytes_AS_STRING(temp_bytes); // Borrowed pointer
diff --git a/tests/ctests/IsdTests.cpp b/tests/ctests/IsdTests.cpp
index 112b552..1e5bc3b 100644
--- a/tests/ctests/IsdTests.cpp
+++ b/tests/ctests/IsdTests.cpp
@@ -7,6 +7,7 @@
 #include "ale.h"
 #include "Isd.h"
 #include "Util.h"
+#include "Vectors.h"
 
 void ASSERT_DOUBLE_VECTOR_EQ(std::vector<double> v1, std::vector<double> v2) {
   ASSERT_EQ(v1.size(), v2.size()) << "The two input vectors are different in size";
@@ -30,10 +31,11 @@ void ASSERT_DOUBLE_2D_VECTOR_EQ(std::vector<std::vector<double>> v1, std::vector
 }
 
 TEST(Isd, Constructor) {
-  std::string json_str = "{\"image_identifier\":\"TEST_IMAGE\",\"sensor_position\":{\"ephemeris_times\":[297088762.24158406,297088762.3917441,297088762.5419041,297088762.69206405,297088762.84222406,297088762.9923841],\"positions\":[[-1885.29806756,913.1652236,-2961.966828],[-1885.59280128,912.7436266,-2961.91056824],[-1885.88749707,912.32201117,-2961.85424884],[-1886.18215477,911.90037749,-2961.79786985],[-1886.47677475,911.47872522,-2961.7414312],[-1886.77135665,911.05705456,-2961.68493293]],\"velocities\":[[-1.9629237646703683,-2.80759072221274,0.37446657801485306],[-1.9626712192798401,-2.807713482051373,0.3748636774173111],[-1.9624186346660286,-2.807836185534424,0.3752607691067297],[-1.9621660109346446,-2.8079588326107823,0.37565785291714804],[-1.9619133478903363,-2.8080814233753033,0.37605492915558875],[-1.961660645638678,-2.8082039577768683,0.37645199765665144]],\"position_units\":\"KM\",\"time_units\":\"S\",\"reference_frame\":1},\"sun_position\":{\"ephemeris_times\":[297088762.24158406,297088762.3917441,297088762.5419041,297088762.69206405,297088762.84222406,297088762.9923841],\"positions\":[[-1885.29806756,913.1652236,-2961.966828]],\"velocities\":[[-1.9629237646703683,-2.80759072221274,0.37446657801485306]],\"position_units\":\"KM\",\"time_units\":\"S\",\"reference_frame\":1},\"sensor_orientation\":{\"time_dependent_framess\":[-74000,-74900,1],\"constant_frames\":[-74021,-74020,-74699,-74690,-74000],\"reference_frame\":1,\"constant_rotation\":[0.9999995608798441,-1.51960241928035e-05,0.0009370214510594064,1.5276552075356694e-05,0.9999999961910578,-8.593317911879532e-05,-0.000937020141647677,8.594745584079714e-05,0.9999995573030465],\"ephemeris_times\":[297088762.24158406,297088762.3917441,297088762.5419041,297088762.69206405,297088762.84222406,297088762.9923841],\"quaternions\":[[0.42061125,0.18606223,-0.23980124,0.85496338],[0.42062261,0.18612356,-0.23976951,0.85495335],[0.42063547,0.18618438,-0.23973759,0.85494273],[0.42064763,0.18624551,-0.2397057,0.85493237],[0.42065923,0.18630667,-0.23967382,0.85492228],[0.42067144,0.18636687,-0.23964185,0.85491211]],\"angular_velocities\":[[-0.0006409728984903079,0.0005054077299115119,0.0004718267948468069],[-0.0006410700774431097,0.0005044862657976017,0.0004731836236807216],[-0.0006408186407087456,0.0004992170698116158,0.0004802237192760833],[-0.0006363961683672021,0.0004989647975959612,0.00047654664046286975],[-0.0006376443791903504,0.0004996117504290811,0.00047678850931380653],[-0.0006404093657132724,0.0005028749658176146,0.0004805228583087444]]},\"body_rotation\":{\"time_dependent_frames\":[10014,1],\"reference_frame\":1,\"ephemeris_times\":[297088762.24158406,297088762.3917441,297088762.5419041,297088762.69206405,297088762.84222406,297088762.9923841],\"quaternions\":[[-0.8371209459443085,0.2996928944391797,0.10720760458181891,0.4448811306448063],[-0.8371185783490869,0.2996934649760026,0.1072060096645597,0.4448855856569007],[-0.8371162107293473,0.2996940355045328,0.10720441474371896,0.44489004065791765],[-0.8371138430875174,0.2996946060241849,0.1072028198209324,0.44489449564328926],[-0.8371114754203602,0.2996951765357392,0.10720122489401934,0.44489895061910595],[-0.8371091077303039,0.29969574703861046,0.10719962996461516,0.4449034055807993]],\"angular_velocities\":[[3.16238646979841e-05,-2.880432898124293e-05,5.6520131658726165e-05],[3.1623864697983686e-05,-2.880432898124763e-05,5.652013165872402e-05],[3.162386469798325e-05,-2.880432898125237e-05,5.652013165872185e-05],[3.162386469798283e-05,-2.880432898125708e-05,5.6520131658719694e-05],[3.1623864697982405e-05,-2.8804328981261782e-05,5.6520131658717505e-05],[3.162386469798195e-05,-2.88043289812665e-05,5.652013165871536e-05]]},\"radii\":{\"semimajor\":3396.19,\"semiminor\":3376.2,\"unit\":\"km\"},\"detector_sample_summing\":1,\"detector_line_summing\":1,\"focal_length_model\":{\"focal_length\":352.9271664},\"detector_center\":{\"line\":0.430442527,\"sample\":2542.96099},\"starting_detector_line\":0,\"starting_detector_sample\":0,\"focal2pixel_lines\":[0.0,142.85714285714,0.0],\"focal2pixel_samples\":[0.0,0.0,142.85714285714],\"optical_distortion\":{\"radial\":{\"coefficients\":[-0.0073433925920054505,2.8375878636241697e-05,1.2841989124027099e-08]}},\"image_lines\":400,\"image_samples\":5056,\"name_platform\":\"MARS_RECONNAISSANCE_ORBITER\",\"name_sensor\":\"CONTEXT CAMERA\",\"reference_height\":{\"maxheight\":1000,\"minheight\":-1000,\"unit\":\"m\"},\"name_model\":\"USGS_ASTRO_LINE_SCANNER_SENSOR_MODEL\",\"interpolation_method\":\"lagrange\",\"line_scan_rate\":[[0.5,-0.37540000677108765,0.001877]],\"starting_ephemeris_time\":297088762.24158406,\"center_ephemeris_time\":297088762.61698407,\"t0_ephemeris\":-0.37540000677108765,\"dt_ephemeris\":0.15016000270843505,\"t0_quaternion\":-0.37540000677108765,\"dt_quaternion\":0.15016000270843505,\"naif_keywords\":{}}";
+  std::string json_str = "{\"image_identifier\":\"TEST_IMAGE\",\"instrument_position\":{\"ephemeris_times\":[297088762.24158406,297088762.3917441,297088762.5419041,297088762.69206405,297088762.84222406,297088762.9923841],\"positions\":[[-1885.29806756,913.1652236,-2961.966828],[-1885.59280128,912.7436266,-2961.91056824],[-1885.88749707,912.32201117,-2961.85424884],[-1886.18215477,911.90037749,-2961.79786985],[-1886.47677475,911.47872522,-2961.7414312],[-1886.77135665,911.05705456,-2961.68493293]],\"velocities\":[[-1.9629237646703683,-2.80759072221274,0.37446657801485306],[-1.9626712192798401,-2.807713482051373,0.3748636774173111],[-1.9624186346660286,-2.807836185534424,0.3752607691067297],[-1.9621660109346446,-2.8079588326107823,0.37565785291714804],[-1.9619133478903363,-2.8080814233753033,0.37605492915558875],[-1.961660645638678,-2.8082039577768683,0.37645199765665144]],\"position_units\":\"KM\",\"time_units\":\"S\",\"reference_frame\":1},\"sun_position\":{\"ephemeris_times\":[297088762.24158406],\"positions\":[[-1885.29806756,913.1652236,-2961.966828]],\"velocities\":[[-1.9629237646703683,-2.80759072221274,0.37446657801485306]],\"position_units\":\"KM\",\"time_units\":\"S\",\"reference_frame\":1},\"instrument_pointing\":{\"time_dependent_frames\":[-74000,-74900,1],\"constant_frames\":[-74021,-74020,-74699,-74690,-74000],\"reference_frame\":1,\"constant_rotation\":[0.9999995608798441,-1.51960241928035e-05,0.0009370214510594064,1.5276552075356694e-05,0.9999999961910578,-8.593317911879532e-05,-0.000937020141647677,8.594745584079714e-05,0.9999995573030465],\"ephemeris_times\":[297088762.24158406,297088762.3917441,297088762.5419041,297088762.69206405,297088762.84222406,297088762.9923841],\"quaternions\":[[0.42061125,0.18606223,-0.23980124,0.85496338],[0.42062261,0.18612356,-0.23976951,0.85495335],[0.42063547,0.18618438,-0.23973759,0.85494273],[0.42064763,0.18624551,-0.2397057,0.85493237],[0.42065923,0.18630667,-0.23967382,0.85492228],[0.42067144,0.18636687,-0.23964185,0.85491211]],\"angular_velocities\":[[-0.0006409728984903079,0.0005054077299115119,0.0004718267948468069],[-0.0006410700774431097,0.0005044862657976017,0.0004731836236807216],[-0.0006408186407087456,0.0004992170698116158,0.0004802237192760833],[-0.0006363961683672021,0.0004989647975959612,0.00047654664046286975],[-0.0006376443791903504,0.0004996117504290811,0.00047678850931380653],[-0.0006404093657132724,0.0005028749658176146,0.0004805228583087444]]},\"body_rotation\":{\"time_dependent_frames\":[10014,1],\"reference_frame\":1,\"ephemeris_times\":[297088762.24158406,297088762.3917441,297088762.5419041,297088762.69206405,297088762.84222406,297088762.9923841],\"quaternions\":[[-0.8371209459443085,0.2996928944391797,0.10720760458181891,0.4448811306448063],[-0.8371185783490869,0.2996934649760026,0.1072060096645597,0.4448855856569007],[-0.8371162107293473,0.2996940355045328,0.10720441474371896,0.44489004065791765],[-0.8371138430875174,0.2996946060241849,0.1072028198209324,0.44489449564328926],[-0.8371114754203602,0.2996951765357392,0.10720122489401934,0.44489895061910595],[-0.8371091077303039,0.29969574703861046,0.10719962996461516,0.4449034055807993]],\"angular_velocities\":[[3.16238646979841e-05,-2.880432898124293e-05,5.6520131658726165e-05],[3.1623864697983686e-05,-2.880432898124763e-05,5.652013165872402e-05],[3.162386469798325e-05,-2.880432898125237e-05,5.652013165872185e-05],[3.162386469798283e-05,-2.880432898125708e-05,5.6520131658719694e-05],[3.1623864697982405e-05,-2.8804328981261782e-05,5.6520131658717505e-05],[3.162386469798195e-05,-2.88043289812665e-05,5.652013165871536e-05]]},\"radii\":{\"semimajor\":3396.19,\"semiminor\":3376.2,\"unit\":\"km\"},\"detector_sample_summing\":1,\"detector_line_summing\":1,\"focal_length_model\":{\"focal_length\":352.9271664},\"detector_center\":{\"line\":0.430442527,\"sample\":2542.96099},\"starting_detector_line\":0,\"starting_detector_sample\":0,\"focal2pixel_lines\":[0.0,142.85714285714,0.0],\"focal2pixel_samples\":[0.0,0.0,142.85714285714],\"optical_distortion\":{\"radial\":{\"coefficients\":[-0.0073433925920054505,2.8375878636241697e-05,1.2841989124027099e-08]}},\"image_lines\":400,\"image_samples\":5056,\"name_platform\":\"MARS_RECONNAISSANCE_ORBITER\",\"name_sensor\":\"CONTEXT CAMERA\",\"reference_height\":{\"maxheight\":1000,\"minheight\":-1000,\"unit\":\"m\"},\"name_model\":\"USGS_ASTRO_LINE_SCANNER_SENSOR_MODEL\",\"interpolation_method\":\"lagrange\",\"line_scan_rate\":[[0.5,-0.37540000677108765,0.001877]],\"starting_ephemeris_time\":297088762.24158406,\"center_ephemeris_time\":297088762.61698407,\"t0_ephemeris\":-0.37540000677108765,\"dt_ephemeris\":0.15016000270843505,\"t0_quaternion\":-0.37540000677108765,\"dt_quaternion\":0.15016000270843505,\"naif_keywords\":{}}";
 
   ale::Isd isd(json_str);
-
+  
+  
   ASSERT_EQ(isd.usgscsm_name_model, "USGS_ASTRO_LINE_SCANNER_SENSOR_MODEL");
   ASSERT_EQ(isd.name_platform, "MARS_RECONNAISSANCE_ORBITER");
   ASSERT_EQ(isd.image_id, "TEST_IMAGE");
@@ -148,113 +150,241 @@ TEST(Isd, BadLogFile) {
 }
 
 TEST(Isd, GetSunPositions) {
-  ale::json j;
-  j["sun_position"]["positions"] = {{1, 2, 3}, {4, 5, 6}};
-  std::vector<double> positions = ale::getSunPositions(j);
-  ASSERT_EQ(positions.size(), 6);
-  EXPECT_DOUBLE_EQ(positions[0], 1);
-  EXPECT_DOUBLE_EQ(positions[1], 2);
-  EXPECT_DOUBLE_EQ(positions[2], 3);
-  EXPECT_DOUBLE_EQ(positions[3], 4);
-  EXPECT_DOUBLE_EQ(positions[4], 5);
-  EXPECT_DOUBLE_EQ(positions[5], 6);
+  ale::json jsunpos  = {
+    {"sun_position",{
+       {"ephemeris_times", {300}},
+       {"positions", {{10, 12, 13}}},
+       {"reference_frame", 2}
+  }}};
+
+  ale::States sunPosObj = ale::getSunPosition(jsunpos);
+  std::vector<ale::Vec3d> position = sunPosObj.getPositions();
+  std::vector<ale::Vec3d> velocity = sunPosObj.getVelocities();
+
+  ASSERT_EQ(sunPosObj.getStates().size(), 1);
+  ASSERT_EQ(sunPosObj.getReferenceFrame(), 2);
+  ASSERT_EQ(sunPosObj.getTimes()[0], 300);
+  
+  ASSERT_EQ(position[0].x, 10);
+  ASSERT_EQ(position[0].y, 12);
+  ASSERT_EQ(position[0].z, 13);
+
+  ASSERT_EQ(velocity[0].x, 0);
+  ASSERT_EQ(velocity[0].y, 0);
+  ASSERT_EQ(velocity[0].z, 0);
+
+  jsunpos["sun_position"]["velocities"] = {{1, 2, 3}};
+  
+  sunPosObj = ale::getSunPosition(jsunpos);
+  velocity = sunPosObj.getVelocities();
+  
+  ASSERT_EQ(velocity[0].x, 1);
+  ASSERT_EQ(velocity[0].y, 2);
+  ASSERT_EQ(velocity[0].z, 3);
 }
 
 TEST(Isd, NoSunPositions) {
   ale::json j;
   try {
-    ale::getSunPositions(j);
+    ale::getSunPosition(j);
     FAIL() << "Expected an exception to be thrown";
   }
   catch(std::exception &e) {
-    EXPECT_EQ(std::string(e.what()), "Could not parse the sun positions.");
+    EXPECT_EQ(std::string(e.what()), "Could not parse the sun position");
   }
   catch(...) {
-    FAIL() << "Expected an Excpetion with message: \"Could not parse the sun positions.\"";
+    FAIL() << "Expected an Excpetion with message: \"Could not parse the sun position.\"";
   }
 }
 
-TEST(Isd, GetSensorPositions) {
-  ale::json j;
-  j["sensor_position"]["positions"] = {{1, 2, 3}, {4, 5, 6}};
-  std::vector<double> positions = ale::getSensorPositions(j);
-  ASSERT_EQ(positions.size(), 6);
-  EXPECT_DOUBLE_EQ(positions[0], 1);
-  EXPECT_DOUBLE_EQ(positions[1], 2);
-  EXPECT_DOUBLE_EQ(positions[2], 3);
-  EXPECT_DOUBLE_EQ(positions[3], 4);
-  EXPECT_DOUBLE_EQ(positions[4], 5);
-  EXPECT_DOUBLE_EQ(positions[5], 6);
-}
+TEST(Isd, GetInstrumentPositions) {
+  ale::json jinstpos  = {
+    {"instrument_position",{
+       {"ephemeris_times", {300, 400}},
+       {"positions", {{10, 11, 12}, {11, 12,13}}},
+       {"reference_frame", 4}
+  }}};
+
+  ale::States instPosObj = ale::getInstrumentPosition(jinstpos);
+  std::vector<ale::Vec3d> positions = instPosObj.getPositions();
+  std::vector<ale::Vec3d> velocities = instPosObj.getVelocities();
+  
+  ASSERT_EQ(instPosObj.getStates().size(), 2);
+  ASSERT_EQ(instPosObj.getReferenceFrame(), 4);
+  
+  ASSERT_EQ(instPosObj.getTimes()[0], 300);
+  ASSERT_EQ(instPosObj.getTimes()[1], 400);
+  
+  ASSERT_EQ(positions[0].x, 10);
+  ASSERT_EQ(positions[0].y, 11);
+  ASSERT_EQ(positions[0].z, 12);
+
+  ASSERT_EQ(positions[1].x, 11);
+  ASSERT_EQ(positions[1].y, 12);
+  ASSERT_EQ(positions[1].z, 13);
+  
+  ASSERT_EQ(velocities[0].x, 0);
+  ASSERT_EQ(velocities[0].y, 0);
+  ASSERT_EQ(velocities[0].z, 0);
+
+  jinstpos["instrument_position"]["velocities"] = {{0, 1, 2}, {3, 4, 5}};
+  
+  instPosObj = ale::getInstrumentPosition(jinstpos);
+  velocities = instPosObj.getVelocities();
+  
+  ASSERT_EQ(velocities[0].x, 0);
+  ASSERT_EQ(velocities[0].y, 1);
+  ASSERT_EQ(velocities[0].z, 2);
+
+  ASSERT_EQ(velocities[1].x, 3);
+  ASSERT_EQ(velocities[1].y, 4);
+  ASSERT_EQ(velocities[1].z, 5);
+
+ }
 
 TEST(Isd, NoSensorPositions) {
   ale::json j;
   try {
-    ale::getSensorPositions(j);
+    ale::getInstrumentPosition(j);
     FAIL() << "Expected an exception to be thrown";
   }
   catch(std::exception &e) {
-    EXPECT_EQ(std::string(e.what()), "Could not parse the sensor positions.");
+    EXPECT_EQ(std::string(e.what()), "Could not parse the instrument position");
   }
   catch(...) {
-    FAIL() << "Expected an Excpetion with message: \"Could not parse the sensor positions.\"";
+    FAIL() << "Expected an Excpetion with message: \"Could not parse the instrument position\"";
   }
 }
 
-TEST(Isd, GetSensorVelocities)
-{
-  ale::json j;
-  j["sensor_position"]["velocities"] = {{1, 2, 3}, {4, 5, 6}};
-  std::vector<double> velocities = ale::getSensorVelocities(j);
-  ASSERT_EQ(velocities.size(), 6);
-  EXPECT_DOUBLE_EQ(velocities[0], 1);
-  EXPECT_DOUBLE_EQ(velocities[1], 2);
-  EXPECT_DOUBLE_EQ(velocities[2], 3);
-  EXPECT_DOUBLE_EQ(velocities[3], 4);
-  EXPECT_DOUBLE_EQ(velocities[4], 5);
-  EXPECT_DOUBLE_EQ(velocities[5], 6);
-}
-
-TEST(Isd, NoSensorVelocities) {
-  ale::json j;
-  try {
-    ale::getSensorVelocities(j);
-    FAIL() << "Expected an exception to be thrown";
-  }
-  catch(std::exception &e) {
-    EXPECT_EQ(std::string(e.what()), "Could not parse the sensor velocities.");
-  }
-  catch(...) {
-    FAIL() << "Expected an Excpetion with message: \"Could not parse the sensor velocities.\"";
-  }
-}
+TEST(Isd, GetInstrumentPointing) {
+  ale::json pointing  = {
+    {"instrument_pointing",{
+       {"ephemeris_times", {300, 600}},
+       {"quaternions", {{1,2,3,4}, {4,3,2,1}}},
+       {"angular_velocities", {{11,12,13}, {21,22,23}}},
+       {"reference_frame", 2},
+       {"time_dependent_frames", {1,2,3}},
+       {"constant_frames", {4,5,6}},
+       {"constant_rotation", {-1,0,0,0,-1,0,0,0,-1}}
+  }}};
 
-TEST(Isd, GetSensorOrientations)
-{
-  ale::json j;
-  j["sensor_orientation"]["quaternions"] = {{1, 2, 3, 4}};
-  std::vector<double> quats = ale::getSensorOrientations(j);
-  ASSERT_EQ(quats.size(), 4);
-  EXPECT_DOUBLE_EQ(quats[0], 1);
-  EXPECT_DOUBLE_EQ(quats[1], 2);
-  EXPECT_DOUBLE_EQ(quats[2], 3);
-  EXPECT_DOUBLE_EQ(quats[3], 4);
+  ale::Orientations instPointing = ale::getInstrumentPointing(pointing);
+  std::vector<ale::Rotation> rotations = instPointing.getRotations();
+  std::vector<ale::Vec3d> velocities = instPointing.getAngularVelocities();
+  std::vector<int> constFrames = instPointing.getConstantFrames(); 
+  std::vector<int> timeDepFrames = instPointing.getTimeDependentFrames(); 
+
+  ASSERT_EQ(rotations.size(), 2);
+  ASSERT_EQ(instPointing.getReferenceFrame(), 2);
+  ASSERT_EQ(instPointing.getTimes()[0], 300);
+  ASSERT_EQ(instPointing.getTimes()[1], 600);
+
+  ASSERT_EQ(constFrames[0], 4);
+  ASSERT_EQ(constFrames[1], 5);
+  ASSERT_EQ(constFrames[2], 6);
+
+  ASSERT_EQ(timeDepFrames[0], 1);
+  ASSERT_EQ(timeDepFrames[1], 2);
+  ASSERT_EQ(timeDepFrames[2], 3);
+
+  ASSERT_DOUBLE_EQ(rotations[0].toQuaternion()[0], 0.18257418583505536);
+  ASSERT_DOUBLE_EQ(rotations[0].toQuaternion()[1], 0.36514837167011072);
+  ASSERT_DOUBLE_EQ(rotations[0].toQuaternion()[2], 0.54772255750516607);
+  ASSERT_DOUBLE_EQ(rotations[0].toQuaternion()[3], 0.73029674334022143);
+ 
+  ASSERT_DOUBLE_EQ(rotations[1].toQuaternion()[0], 0.73029674334022143);
+  ASSERT_DOUBLE_EQ(rotations[1].toQuaternion()[1], 0.54772255750516607);
+  ASSERT_DOUBLE_EQ(rotations[1].toQuaternion()[2], 0.36514837167011072);
+  ASSERT_DOUBLE_EQ(rotations[1].toQuaternion()[3], 0.18257418583505536);
+   
+  ASSERT_DOUBLE_EQ(velocities[0].x, 11);
+  ASSERT_DOUBLE_EQ(velocities[0].y, 12);
+  ASSERT_DOUBLE_EQ(velocities[0].z, 13); 
+  
+  ASSERT_DOUBLE_EQ(velocities[1].x, 21);
+  ASSERT_DOUBLE_EQ(velocities[1].y, 22);
+  ASSERT_DOUBLE_EQ(velocities[1].z, 23);
+  
+  std::vector<double> rotmat = instPointing.getConstantRotation().toQuaternion();
+  ASSERT_DOUBLE_EQ(rotmat[0], 0);
+  ASSERT_DOUBLE_EQ(rotmat[1], 1);
+  ASSERT_DOUBLE_EQ(rotmat[2], 0);
+  ASSERT_DOUBLE_EQ(rotmat[3], 0);
 }
 
+
 TEST(Isd, NoSensorOrientations) {
   ale::json j;
   try {
-    ale::getSensorOrientations(j);
+    ale::getInstrumentPointing(j);
     FAIL() << "Expected an exception to be thrown";
   }
   catch(std::exception &e) {
-    EXPECT_EQ(std::string(e.what()), "Could not parse the sensor orientations.");
+    EXPECT_EQ(std::string(e.what()), "Could not parse the instrument pointing");
   }
   catch(...) {
-    FAIL() << "Expected an Excpetion with message: \"Could not parse the sensor orientations.\"";
+    FAIL() << "Expected an Excpetion with message: \"Could not parse the instrument pointing\"";
   }
 }
 
+TEST(Isd, GetBodyRotation) {
+  ale::json br = {
+    {"body_rotation",{
+       {"ephemeris_times", {300, 600}},
+       {"quaternions", {{1,2,3,4}, {4,3,2,1}}},
+       {"angular_velocities", {{11,12,13}, {21,22,23}}},
+       {"reference_frame", 2},
+       {"time_dependent_frames", {1,2,3}},
+       {"constant_frames", {4,5,6}},
+       {"constant_rotation", {-1,0,0,0,-1,0,0,0,-1}}
+  }}};
+
+  ale::Orientations bodyRot = ale::getBodyRotation(br);
+  std::vector<ale::Rotation> rotations = bodyRot.getRotations();
+  std::vector<ale::Vec3d> velocities = bodyRot.getAngularVelocities();
+  std::vector<int> constFrames = bodyRot.getConstantFrames(); 
+  std::vector<int> timeDepFrames = bodyRot.getTimeDependentFrames(); 
+
+  ASSERT_EQ(rotations.size(), 2);
+  ASSERT_EQ(bodyRot.getReferenceFrame(), 2);
+  ASSERT_EQ(bodyRot.getTimes()[0], 300);
+  ASSERT_EQ(bodyRot.getTimes()[1], 600);
+
+  ASSERT_EQ(constFrames[0], 4);
+  ASSERT_EQ(constFrames[1], 5);
+  ASSERT_EQ(constFrames[2], 6);
+
+  ASSERT_EQ(timeDepFrames[0], 1);
+  ASSERT_EQ(timeDepFrames[1], 2);
+  ASSERT_EQ(timeDepFrames[2], 3);
+
+  ASSERT_DOUBLE_EQ(rotations[0].toQuaternion()[0], 0.18257418583505536);
+  ASSERT_DOUBLE_EQ(rotations[0].toQuaternion()[1], 0.36514837167011072);
+  ASSERT_DOUBLE_EQ(rotations[0].toQuaternion()[2], 0.54772255750516607);
+  ASSERT_DOUBLE_EQ(rotations[0].toQuaternion()[3], 0.73029674334022143);
+ 
+  ASSERT_DOUBLE_EQ(rotations[1].toQuaternion()[0], 0.73029674334022143);
+  ASSERT_DOUBLE_EQ(rotations[1].toQuaternion()[1], 0.54772255750516607);
+  ASSERT_DOUBLE_EQ(rotations[1].toQuaternion()[2], 0.36514837167011072);
+  ASSERT_DOUBLE_EQ(rotations[1].toQuaternion()[3], 0.18257418583505536);
+  
+  ASSERT_DOUBLE_EQ(velocities[0].x, 11);
+  ASSERT_DOUBLE_EQ(velocities[0].y, 12);
+  ASSERT_DOUBLE_EQ(velocities[0].z, 13); 
+  
+  ASSERT_DOUBLE_EQ(velocities[1].x, 21);
+  ASSERT_DOUBLE_EQ(velocities[1].y, 22);
+  ASSERT_DOUBLE_EQ(velocities[1].z, 23);
+  
+  std::vector<double> rotmat = bodyRot.getConstantRotation().toQuaternion();
+  ASSERT_DOUBLE_EQ(rotmat[0], 0);
+  ASSERT_DOUBLE_EQ(rotmat[1], 1);
+  ASSERT_DOUBLE_EQ(rotmat[2], 0);
+  ASSERT_DOUBLE_EQ(rotmat[3], 0);
+}
+
+
+
 TEST(Isd, BadNameModel) {
   std::string bad_json_str("{}");
   try {
diff --git a/tests/ctests/OrientationsTest.cpp b/tests/ctests/OrientationsTest.cpp
index 03f0d93..3c39252 100644
--- a/tests/ctests/OrientationsTest.cpp
+++ b/tests/ctests/OrientationsTest.cpp
@@ -30,9 +30,9 @@ class OrientationTest : public ::testing::Test {
 };
 
 TEST_F(OrientationTest, ConstructorAccessors) {
-  vector<Rotation> outputRotations = orientations.rotations();
-  vector<double> outputTimes = orientations.times();
-  vector<Vec3d> outputAvs = orientations.angularVelocities();
+  vector<Rotation> outputRotations = orientations.getRotations();
+  vector<double> outputTimes = orientations.getTimes();
+  vector<Vec3d> outputAvs = orientations.getAngularVelocities();
   ASSERT_EQ(outputRotations.size(), rotations.size());
   for (size_t i = 0; i < outputRotations.size(); i++) {
     vector<double> quats = rotations[i].toQuaternion();
@@ -98,7 +98,7 @@ TEST_F(OrientationTest, RotateAt) {
 TEST_F(OrientationTest, RotationMultiplication) {
   Rotation rhs( 0.5, 0.5, 0.5, 0.5);
   orientations *= rhs;
-  vector<Rotation> outputRotations = orientations.rotations();
+  vector<Rotation> outputRotations = orientations.getRotations();
   vector<vector<double>> expectedQuats = {
     {-0.5, 0.5, 0.5, 0.5},
     {-1.0, 0.0, 0.0, 0.0},
@@ -116,7 +116,7 @@ TEST_F(OrientationTest, RotationMultiplication) {
 TEST_F(OrientationTest, OrientationMultiplication) {
   Orientations duplicateOrientations(orientations);
   orientations *= duplicateOrientations;
-  vector<Rotation> outputRotations = orientations.rotations();
+  vector<Rotation> outputRotations = orientations.getRotations();
   vector<vector<double>> expectedQuats = {
     {-0.5, 0.5, 0.5, 0.5},
     {-0.5,-0.5,-0.5,-0.5},
diff --git a/tests/ctests/StatesTest.cpp b/tests/ctests/StatesTest.cpp
index 224aec7..d4ccdf3 100644
--- a/tests/ctests/StatesTest.cpp
+++ b/tests/ctests/StatesTest.cpp
@@ -1,29 +1,30 @@
 #include "gtest/gtest.h"
 
-#include "States.h"
-
 #include <cmath>
 #include <exception>
 
+#include "States.h"
+#include "Vectors.h"
+
 using namespace std;
 using namespace ale;
 
 TEST(StatesTest, DefaultConstructor) {
   States defaultState;
-  vector<ale::State> states = defaultState.getStates();
+  vector<State> states = defaultState.getStates();
   EXPECT_EQ(states.size(), 0);
 }
 
 TEST(StatesTest, ConstructorPositionNoVelocity) {
   std::vector<double> ephemTimes = {0.0, 1.0, 2.0, 3.0};
-  std::vector<ale::Vec3d> positions = {
-    ale::Vec3d(4.0, 1.0, 4.0),
-    ale::Vec3d (5.0, 2.0, 3.0),
-    ale::Vec3d (6.0, 3.0, 2.0),
-    ale::Vec3d (7.0, 4.0, 1.0)};
+  std::vector<Vec3d> positions = {
+    Vec3d(4.0, 1.0, 4.0),
+    Vec3d (5.0, 2.0, 3.0),
+    Vec3d (6.0, 3.0, 2.0),
+    Vec3d (7.0, 4.0, 1.0)};
 
   States noVelocityState(ephemTimes, positions);
-  vector<ale::State> states = noVelocityState.getStates();
+  vector<State> states = noVelocityState.getStates();
   EXPECT_EQ(states.size(), 4);
   EXPECT_NEAR(states[0].position.x, 4.0, 1e-10);
   EXPECT_NEAR(states[0].position.y, 1.0, 1e-10);
@@ -41,20 +42,20 @@ TEST(StatesTest, ConstructorPositionNoVelocity) {
 
 TEST(StatesTest, ConstructorPositionAndVelocity) {
   std::vector<double> ephemTimes = {0.0, 1.0, 2.0, 3.0};
-  std::vector<ale::Vec3d> positions = {
-    ale::Vec3d(4.0, 1.0, 4.0),
-    ale::Vec3d (5.0, 2.0, 3.0),
-    ale::Vec3d (6.0, 3.0, 2.0),
-    ale::Vec3d (7.0, 4.0, 1.0)};
-
-  std::vector<ale::Vec3d> velocities = {
-    ale::Vec3d(-4.0, -1.0, -4.0),
-    ale::Vec3d(-5.0, -2.0, -3.0),
-    ale::Vec3d(-6.0, -3.0, -2.0),
-    ale::Vec3d(-7.0, -4.0, -1.0)};
+  std::vector<Vec3d> positions = {
+    Vec3d(4.0, 1.0, 4.0),
+    Vec3d (5.0, 2.0, 3.0),
+    Vec3d (6.0, 3.0, 2.0),
+    Vec3d (7.0, 4.0, 1.0)};
+
+  std::vector<Vec3d> velocities = {
+    Vec3d(-4.0, -1.0, -4.0),
+    Vec3d(-5.0, -2.0, -3.0),
+    Vec3d(-6.0, -3.0, -2.0),
+    Vec3d(-7.0, -4.0, -1.0)};
 
   States positionVelocityState(ephemTimes, positions, velocities);
-  vector<ale::State> states = positionVelocityState.getStates();
+  vector<State> states = positionVelocityState.getStates();
   EXPECT_EQ(states.size(), 4);
   EXPECT_NEAR(states[0].position.x, 4.0, 1e-10);
   EXPECT_NEAR(states[0].position.y, 1.0, 1e-10);
@@ -73,25 +74,25 @@ TEST(StatesTest, ConstructorPositionAndVelocity) {
 TEST(StatesTest, ConstructorStates) {
   std::vector<double> ephemTimes = {0.0, 1.0, 2.0, 3.0};
 
-  std::vector<ale::Vec3d> positions = {
-    ale::Vec3d(4.0, 1.0, 4.0),
-    ale::Vec3d (5.0, 2.0, 3.0),
-    ale::Vec3d (6.0, 3.0, 2.0),
-    ale::Vec3d (7.0, 4.0, 1.0)};
+  std::vector<Vec3d> positions = {
+    Vec3d(4.0, 1.0, 4.0),
+    Vec3d (5.0, 2.0, 3.0),
+    Vec3d (6.0, 3.0, 2.0),
+    Vec3d (7.0, 4.0, 1.0)};
 
-  std::vector<ale::Vec3d> velocities = {
-    ale::Vec3d(-4.0, -1.0, -4.0),
-    ale::Vec3d(-5.0, -2.0, -3.0),
-    ale::Vec3d(-6.0, -3.0, -2.0),
-    ale::Vec3d(-7.0, -4.0, -1.0)};
+  std::vector<Vec3d> velocities = {
+    Vec3d(-4.0, -1.0, -4.0),
+    Vec3d(-5.0, -2.0, -3.0),
+    Vec3d(-6.0, -3.0, -2.0),
+    Vec3d(-7.0, -4.0, -1.0)};
 
-  std::vector<ale::State> stateVector;
+  std::vector<State> stateVector;
   for (int i=0; i < positions.size(); i++) {
-    stateVector.push_back(ale::State(positions[i], velocities[i]));
+    stateVector.push_back(State(positions[i], velocities[i]));
   }
 
   States statesState(ephemTimes, stateVector, 1);
-  vector<ale::State> states = statesState.getStates();
+  vector<State> states = statesState.getStates();
   EXPECT_EQ(states.size(), 4);
   EXPECT_NEAR(states[0].position.x, 4.0, 1e-10);
   EXPECT_NEAR(states[0].position.y, 1.0, 1e-10);
@@ -129,25 +130,25 @@ protected:
     values were obtained using the derivative of the above functions at the defined
     ephemeris times in ephemTimes.
     **/
-    std::vector<ale::Vec3d> positions = {
-      ale::Vec3d(4, 0, 0),
-      ale::Vec3d(5, 3, 0.064),
-      ale::Vec3d(6, 4, 0.512),
-      ale::Vec3d(7, 3, 1.728)};
-
-    std::vector<ale::Vec3d> velocities = {
-      ale::Vec3d(1, 4, 0),
-      ale::Vec3d(1, 2, 0.48),
-      ale::Vec3d(1, 0, 1.92),
-      ale::Vec3d(1, -2, 4.32)};
-
-    std::vector<ale::State> stateVector;
+    std::vector<Vec3d> positions = {
+      Vec3d(4, 0, 0),
+      Vec3d(5, 3, 0.064),
+      Vec3d(6, 4, 0.512),
+      Vec3d(7, 3, 1.728)};
+
+    std::vector<Vec3d> velocities = {
+      Vec3d(1, 4, 0),
+      Vec3d(1, 2, 0.48),
+      Vec3d(1, 0, 1.92),
+      Vec3d(1, -2, 4.32)};
+
+    std::vector<State> stateVector;
     for (int i=0; i < positions.size(); i++) {
-      stateVector.push_back(ale::State(positions[i], velocities[i]));
+      stateVector.push_back(State(positions[i], velocities[i]));
     }
 
-    states = new ale::States(ephemTimes, stateVector);
-    statesNoVelocity = new ale::States(ephemTimes, positions);
+    states = new States(ephemTimes, stateVector);
+    statesNoVelocity = new States(ephemTimes, positions);
   }
 
   void TearDown() override {
@@ -167,10 +168,10 @@ protected:
 TEST_F(TestState, getPosition) {
   double time = 1.5;
 
-  ale::Vec3d linear_position = states->getPosition(time, LINEAR);
-  ale::Vec3d spline_position = states->getPosition(time, SPLINE);
-  ale::Vec3d linear_no_vel_position = statesNoVelocity->getPosition(time, LINEAR);
-  ale::Vec3d spline_no_vel_position = statesNoVelocity->getPosition(time, SPLINE);
+  Vec3d linear_position = states->getPosition(time, LINEAR);
+  Vec3d spline_position = states->getPosition(time, SPLINE);
+  Vec3d linear_no_vel_position = statesNoVelocity->getPosition(time, LINEAR);
+  Vec3d spline_no_vel_position = statesNoVelocity->getPosition(time, SPLINE);
 
   double linear_x = 5.5;
   double linear_y = 3.5;
@@ -193,10 +194,10 @@ TEST_F(TestState, getPosition) {
 
 TEST_F(TestState, getVelocity) {
   double time = 1.5;
-  ale::Vec3d linear_velocity = states->getVelocity(time, LINEAR);
-  ale::Vec3d spline_velocity = states->getVelocity(time, SPLINE);
-  ale::Vec3d linear_no_vel_velocity = statesNoVelocity->getVelocity(time, LINEAR);
-  ale::Vec3d spline_no_vel_velocity = statesNoVelocity->getVelocity(time, SPLINE);
+  Vec3d linear_velocity = states->getVelocity(time, LINEAR);
+  Vec3d spline_velocity = states->getVelocity(time, SPLINE);
+  Vec3d linear_no_vel_velocity = statesNoVelocity->getVelocity(time, LINEAR);
+  Vec3d spline_no_vel_velocity = statesNoVelocity->getVelocity(time, SPLINE);
 
   EXPECT_NEAR(linear_velocity.x, 1, 1e-10);
   EXPECT_NEAR(linear_velocity.y, 1, 1e-10);
@@ -237,7 +238,7 @@ TEST_F(TestState, getReferenceFrame) {
 }
 
 TEST_F(TestState, getPositions) {
-  std::vector<ale::Vec3d> positions = states->getPositions();
+  std::vector<Vec3d> positions = states->getPositions();
   EXPECT_EQ(positions.size(), 4);
   EXPECT_NEAR(positions[0].x, 4.0, 1e-10);
   EXPECT_NEAR(positions[0].y, 0.0, 1e-10);
@@ -253,19 +254,19 @@ TEST_F(TestState, getPositions) {
 TEST(StatesTest, minimizeCache_true) {
   //create information that can be reduced
   std::vector<double> ephemTimes = {0.0, 1.0, 2.0, 3.0, 4.0};
-  std::vector<ale::Vec3d> positions = {
-    ale::Vec3d(5.0, 3.0, 0.0),
-    ale::Vec3d(5.6, 5.1875, 0.3),
-    ale::Vec3d(7.0, 6.0, 1.0),
-    ale::Vec3d(10.025, 5.5625, 2.5125),
-    ale::Vec3d(15.0, 4.0, 5.0)};
+  std::vector<Vec3d> positions = {
+    Vec3d(5.0, 3.0, 0.0),
+    Vec3d(5.6, 5.1875, 0.3),
+    Vec3d(7.0, 6.0, 1.0),
+    Vec3d(10.025, 5.5625, 2.5125),
+    Vec3d(15.0, 4.0, 5.0)};
 
   States withVelocityState(ephemTimes, positions, positions, 1);
 
-  vector<ale::State> states = withVelocityState.getStates();
+  vector<State> states = withVelocityState.getStates();
   EXPECT_EQ(states.size(), 5);
   States minimizedStates = withVelocityState.minimizeCache(1);
-  vector<ale::State> states_min = minimizedStates.getStates();
+  vector<State> states_min = minimizedStates.getStates();
   EXPECT_EQ(states_min.size(), 4);
 }
 
@@ -273,29 +274,29 @@ TEST(StatesTest, minimizeCache_true) {
 TEST(StatesTest, minimizeCache_false) {
   //create information that cannot be reduced
   std::vector<double> ephemTimes = {0.0, 1.0, 2.0, 3.0, 4.0};
-  std::vector<ale::Vec3d> positions = {
-    ale::Vec3d(5.0, 3.0, 0.0),
-    ale::Vec3d(6.5, 4.0, 1.0),
-    ale::Vec3d(7.0, 6.0, 1.0),
-    ale::Vec3d(8.7, 3.0, 3.0),
-    ale::Vec3d(15.0, 4.0, 5.0)};
+  std::vector<Vec3d> positions = {
+    Vec3d(5.0, 3.0, 0.0),
+    Vec3d(6.5, 4.0, 1.0),
+    Vec3d(7.0, 6.0, 1.0),
+    Vec3d(8.7, 3.0, 3.0),
+    Vec3d(15.0, 4.0, 5.0)};
 
   //create states with no velocity information
   States noVelocityState(ephemTimes, positions);
-  vector<ale::State> states = noVelocityState.getStates();
+  vector<State> states = noVelocityState.getStates();
   EXPECT_EQ(states.size(), 5);
 
   ASSERT_THROW(noVelocityState.minimizeCache(), std::invalid_argument);
 
-  std::vector<ale::Vec3d> velocities = {
-    ale::Vec3d(5.0, 3.0, 0.0),
-    ale::Vec3d(6.5, 4.0, 1.0),
-    ale::Vec3d(7.0, 6.0, 1.0),
-    ale::Vec3d(8.7, 3.0, 3.0),
-    ale::Vec3d(15.0, 4.0, 5.0)};
+  std::vector<Vec3d> velocities = {
+    Vec3d(5.0, 3.0, 0.0),
+    Vec3d(6.5, 4.0, 1.0),
+    Vec3d(7.0, 6.0, 1.0),
+    Vec3d(8.7, 3.0, 3.0),
+    Vec3d(15.0, 4.0, 5.0)};
 
   States withVelocityState(ephemTimes, positions, velocities, 1);
-  vector<ale::State> states_min = withVelocityState.getStates();
+  vector<State> states_min = withVelocityState.getStates();
   EXPECT_EQ(states_min.size(), 5);
 }
 
@@ -308,132 +309,132 @@ TEST(StatesTest, minimizeCache_matchesISIS) {
   // 362681869.7384
   std::vector<double> ephemTimes = {362681633.613412,362681649.355078,362681665.096744,362681680.83841,362681696.580076,362681712.321741,362681728.063407,362681743.805073,362681759.546739,362681775.288405,362681791.030071,362681806.771737,362681822.513403,362681838.255068,362681853.996734,362681869.7384,362681885.480066,362681901.221732,362681916.963398,362681932.705064,362681948.44673,362681964.188395,362681979.930061,362681995.671727,362682011.413393,362682027.155059,362682042.896725,362682058.638391,362682074.380057,362682090.121722,362682105.863388,362682121.605054,362682137.34672,362682153.088386,362682168.830052,362682184.571718,362682200.313384,362682216.055049,362682231.796715,362682247.538381,362682263.280047,362682279.021713,362682294.763379,362682310.505045,362682326.246711,362682341.988376,362682357.730042,362682373.471708,362682389.213374,362682404.95504,362682420.696706,362682436.438372,362682452.180037,362682467.921703,362682483.663369,362682499.405035,362682515.146701,362682530.888367,362682546.630033,362682562.371699,362682578.113365};
 
-  std::vector<ale::Vec3d> positions = {
-ale::Vec3d(-17382.7468835417, 96577.8576989543, 16364.0677257831),
-ale::Vec3d(-17382.9888346502, 96576.3340464433, 16363.6197071606),
-ale::Vec3d(-17383.2307847157, 96574.8103941707, 16363.1716886571),
-ale::Vec3d(-17383.472735884, 96573.2867410342, 16362.7236700492),
-ale::Vec3d(-17383.7146860391, 96571.7630881361, 16362.2756515455),
-ale::Vec3d(-17383.9566372671, 96570.2394343143, 16361.8276329373),
-ale::Vec3d(-17384.1985874818, 96568.715780731, 16361.3796144184),
-ale::Vec3d(-17384.4405387696, 96567.1921262539, 16360.9315958249),
-ale::Vec3d(-17384.6824890441, 96565.668472045, 16360.4835773057),
-ale::Vec3d(-17384.9244393485, 96564.1448175084, 16360.0355588162),
-ale::Vec3d(-17385.1663907556, 96562.6211619886, 16359.5875402223),
-ale::Vec3d(-17385.4083410899, 96561.0975068265, 16359.1395216879),
-ale::Vec3d(-17385.650292527, 96559.5738506513, 16358.6915030937),
-ale::Vec3d(-17385.8922429508, 96558.050194804, 16358.2434845738),
-ale::Vec3d(-17386.1341944775, 96556.526538033, 16357.7954659943),
-ale::Vec3d(-17386.3761449312, 96555.0028814707, 16357.3474474742),// position to test
-ale::Vec3d(-17386.6180964878, 96553.4792240146, 16356.8994288944),
-ale::Vec3d(-17386.8600470013, 96551.9555667671, 16356.4514103591),
-ale::Vec3d(-17387.1019987069, 96550.4319087152, 16356.003391794),
-ale::Vec3d(-17387.3439492802, 96548.9082508421, 16355.5553732733),
-ale::Vec3d(-17387.5859009562, 96547.3845920454, 16355.1073546781),
-ale::Vec3d(-17387.8278515892, 96545.8609335467, 16354.659336187),
-ale::Vec3d(-17388.0698022818, 96544.3372746906, 16354.2113176809),
-ale::Vec3d(-17388.3117540474, 96542.8136149108, 16353.7632991002),
-ale::Vec3d(-17388.5537048296, 96541.2899553993, 16353.3152806087),
-ale::Vec3d(-17388.7956566549, 96539.766294994, 16352.8672620277),
-ale::Vec3d(-17389.0376074372, 96538.2426347973, 16352.4192435359),
-ale::Vec3d(-17389.2795593521, 96536.7189737366, 16351.9712249249),
-ale::Vec3d(-17389.5215102239, 96535.1953128845, 16351.5232064478),
-ale::Vec3d(-17389.7634621985, 96533.6716511088, 16351.0751878513),
-ale::Vec3d(-17390.0054131003, 96532.1479896013, 16350.627169374),
-ale::Vec3d(-17390.2473651048, 96530.6243272596, 16350.1791507773),
-ale::Vec3d(-17390.4893161259, 96529.100665067, 16349.7311322847),
-ale::Vec3d(-17390.7312681604, 96527.5770019805, 16349.2831137176),
-ale::Vec3d(-17390.9732192412, 96526.0533391921, 16348.8350952099),
-ale::Vec3d(-17391.2151713652, 96524.5296754503, 16348.3870766424),
-ale::Vec3d(-17391.4571224462, 96523.0060120065, 16347.9390581494),
-ale::Vec3d(-17391.6990736166, 96521.4823481456, 16347.4910396562),
-ale::Vec3d(-17391.9410258302, 96519.9586833909, 16347.0430210884),
-ale::Vec3d(-17392.1829770008, 96518.435018964, 16346.59500258),
-ale::Vec3d(-17392.4249293039, 96516.9113535837, 16346.1469840417),
-ale::Vec3d(-17392.666880564, 96515.3876884717, 16345.6989655182),
-ale::Vec3d(-17392.9088328673, 96513.8640223764, 16345.2509469647),
-ale::Vec3d(-17393.1507842169, 96512.340356609, 16344.8029284856),
-ale::Vec3d(-17393.3927366097, 96510.8166898881, 16344.354909917),
-ale::Vec3d(-17393.6346879893, 96509.2930234355, 16343.9068914228),
-ale::Vec3d(-17393.8766404716, 96507.7693560891, 16343.4588728688),
-ale::Vec3d(-17394.1185918513, 96506.2456889215, 16343.0108543743),
-ale::Vec3d(-17394.3605443934, 96504.7220208899, 16342.5628358051),
-ale::Vec3d(-17394.6024958924, 96503.1983530967, 16342.1148173252),
-ale::Vec3d(-17394.8444484644, 96501.6746844097, 16341.6667987558),
-ale::Vec3d(-17395.0863999934, 96500.1510159612, 16341.2187802906),
-ale::Vec3d(-17395.3283526549, 96498.6273466784, 16340.7707617209),
-ale::Vec3d(-17395.5703042734, 96497.1036775447, 16340.3227432554),
-ale::Vec3d(-17395.8122558622, 96495.5800080833, 16339.8747247748),
-ale::Vec3d(-17396.0542086133, 96494.0563377578, 16339.4267061899),
-ale::Vec3d(-17396.2961603214, 96492.5326676411, 16338.9786877239),
-ale::Vec3d(-17396.5381131323, 96491.0089966602, 16338.5306691834),
-ale::Vec3d(-17396.7800648703, 96489.4853258881, 16338.0826506874),
-ale::Vec3d(-17397.0220177409, 96487.9616541922, 16337.6346321317),
-ale::Vec3d(-17397.2639695387, 96486.4379827647, 16337.1866136653)
+  std::vector<Vec3d> positions = {
+Vec3d(-17382.7468835417, 96577.8576989543, 16364.0677257831),
+Vec3d(-17382.9888346502, 96576.3340464433, 16363.6197071606),
+Vec3d(-17383.2307847157, 96574.8103941707, 16363.1716886571),
+Vec3d(-17383.472735884, 96573.2867410342, 16362.7236700492),
+Vec3d(-17383.7146860391, 96571.7630881361, 16362.2756515455),
+Vec3d(-17383.9566372671, 96570.2394343143, 16361.8276329373),
+Vec3d(-17384.1985874818, 96568.715780731, 16361.3796144184),
+Vec3d(-17384.4405387696, 96567.1921262539, 16360.9315958249),
+Vec3d(-17384.6824890441, 96565.668472045, 16360.4835773057),
+Vec3d(-17384.9244393485, 96564.1448175084, 16360.0355588162),
+Vec3d(-17385.1663907556, 96562.6211619886, 16359.5875402223),
+Vec3d(-17385.4083410899, 96561.0975068265, 16359.1395216879),
+Vec3d(-17385.650292527, 96559.5738506513, 16358.6915030937),
+Vec3d(-17385.8922429508, 96558.050194804, 16358.2434845738),
+Vec3d(-17386.1341944775, 96556.526538033, 16357.7954659943),
+Vec3d(-17386.3761449312, 96555.0028814707, 16357.3474474742),// position to test
+Vec3d(-17386.6180964878, 96553.4792240146, 16356.8994288944),
+Vec3d(-17386.8600470013, 96551.9555667671, 16356.4514103591),
+Vec3d(-17387.1019987069, 96550.4319087152, 16356.003391794),
+Vec3d(-17387.3439492802, 96548.9082508421, 16355.5553732733),
+Vec3d(-17387.5859009562, 96547.3845920454, 16355.1073546781),
+Vec3d(-17387.8278515892, 96545.8609335467, 16354.659336187),
+Vec3d(-17388.0698022818, 96544.3372746906, 16354.2113176809),
+Vec3d(-17388.3117540474, 96542.8136149108, 16353.7632991002),
+Vec3d(-17388.5537048296, 96541.2899553993, 16353.3152806087),
+Vec3d(-17388.7956566549, 96539.766294994, 16352.8672620277),
+Vec3d(-17389.0376074372, 96538.2426347973, 16352.4192435359),
+Vec3d(-17389.2795593521, 96536.7189737366, 16351.9712249249),
+Vec3d(-17389.5215102239, 96535.1953128845, 16351.5232064478),
+Vec3d(-17389.7634621985, 96533.6716511088, 16351.0751878513),
+Vec3d(-17390.0054131003, 96532.1479896013, 16350.627169374),
+Vec3d(-17390.2473651048, 96530.6243272596, 16350.1791507773),
+Vec3d(-17390.4893161259, 96529.100665067, 16349.7311322847),
+Vec3d(-17390.7312681604, 96527.5770019805, 16349.2831137176),
+Vec3d(-17390.9732192412, 96526.0533391921, 16348.8350952099),
+Vec3d(-17391.2151713652, 96524.5296754503, 16348.3870766424),
+Vec3d(-17391.4571224462, 96523.0060120065, 16347.9390581494),
+Vec3d(-17391.6990736166, 96521.4823481456, 16347.4910396562),
+Vec3d(-17391.9410258302, 96519.9586833909, 16347.0430210884),
+Vec3d(-17392.1829770008, 96518.435018964, 16346.59500258),
+Vec3d(-17392.4249293039, 96516.9113535837, 16346.1469840417),
+Vec3d(-17392.666880564, 96515.3876884717, 16345.6989655182),
+Vec3d(-17392.9088328673, 96513.8640223764, 16345.2509469647),
+Vec3d(-17393.1507842169, 96512.340356609, 16344.8029284856),
+Vec3d(-17393.3927366097, 96510.8166898881, 16344.354909917),
+Vec3d(-17393.6346879893, 96509.2930234355, 16343.9068914228),
+Vec3d(-17393.8766404716, 96507.7693560891, 16343.4588728688),
+Vec3d(-17394.1185918513, 96506.2456889215, 16343.0108543743),
+Vec3d(-17394.3605443934, 96504.7220208899, 16342.5628358051),
+Vec3d(-17394.6024958924, 96503.1983530967, 16342.1148173252),
+Vec3d(-17394.8444484644, 96501.6746844097, 16341.6667987558),
+Vec3d(-17395.0863999934, 96500.1510159612, 16341.2187802906),
+Vec3d(-17395.3283526549, 96498.6273466784, 16340.7707617209),
+Vec3d(-17395.5703042734, 96497.1036775447, 16340.3227432554),
+Vec3d(-17395.8122558622, 96495.5800080833, 16339.8747247748),
+Vec3d(-17396.0542086133, 96494.0563377578, 16339.4267061899),
+Vec3d(-17396.2961603214, 96492.5326676411, 16338.9786877239),
+Vec3d(-17396.5381131323, 96491.0089966602, 16338.5306691834),
+Vec3d(-17396.7800648703, 96489.4853258881, 16338.0826506874),
+Vec3d(-17397.0220177409, 96487.9616541922, 16337.6346321317),
+Vec3d(-17397.2639695387, 96486.4379827647, 16337.1866136653)
   };
 
-std::vector<ale::Vec3d> velocities = {
-ale::Vec3d(-0.0153700718765843, -0.0967910279657348, -0.0284606828741588),
-ale::Vec3d(-0.0153700737931066, -0.096791048945897, -0.0284606828190555),
-ale::Vec3d(-0.0153700757092848, -0.0967910699268904, -0.0284606827640637),
-ale::Vec3d(-0.0153700776250131, -0.0967910909088181, -0.0284606827092379),
-ale::Vec3d(-0.0153700795403742, -0.0967911118915676, -0.0284606826545261),
-ale::Vec3d(-0.0153700814553067, -0.0967911328752586, -0.0284606825999784),
-ale::Vec3d(-0.015370083369856, -0.0967911538597701, -0.0284606825455435),
-ale::Vec3d(-0.0153700852839879, -0.0967911748452176, -0.0284606824912741),
-ale::Vec3d(-0.0153700871977456, -0.0967911958314943, -0.0284606824371165),
-ale::Vec3d(-0.0153700891110573, -0.0967912168186004, -0.0284606823830493),
-ale::Vec3d(-0.0153700910239836, -0.0967912378066924, -0.0284606823291967),
-ale::Vec3d(-0.0153700929365416, -0.0967912587956045, -0.0284606822754565),
-ale::Vec3d(-0.0153700948486603, -0.0967912797854579, -0.0284606822218836),
-ale::Vec3d(-0.0153700967604118, -0.0967913007761374, -0.0284606821684221),
-ale::Vec3d(-0.0153700986717228, -0.0967913217677527, -0.0284606821151287),// velocity to test
-ale::Vec3d(-0.0153701005826786, -0.0967913427601938, -0.0284606820619469),
-ale::Vec3d(-0.0153701024931907, -0.0967913637535689, -0.0284606820089321),
-ale::Vec3d(-0.0153701044033458, -0.0967913847477737, -0.0284606819560303),
-ale::Vec3d(-0.0153701063130629, -0.0967914057429141, -0.0284606819032941),
-ale::Vec3d(-0.0153701082224151, -0.0967914267388804, -0.0284606818506722),
-ale::Vec3d(-0.0153701101313204, -0.0967914477357808, -0.0284606817982155),
-ale::Vec3d(-0.0153701120398714, -0.0967914687335107, -0.0284606817458717),
-ale::Vec3d(-0.0153701139480175, -0.096791489732125, -0.028460681693667),
-ale::Vec3d(-0.0153701158557277, -0.0967915107316699, -0.0284606816416301),
-ale::Vec3d(-0.0153701177630685, -0.0967915317320424, -0.0284606815897053),
-ale::Vec3d(-0.0153701196699842, -0.0967915527333597, -0.0284606815379469),
-ale::Vec3d(-0.0153701215765303, -0.0967915737354921, -0.028460681486301),
-ale::Vec3d(-0.0153701234826341, -0.0967915947385677, -0.0284606814348225),
-ale::Vec3d(-0.0153701253883785, -0.0967916157424725, -0.0284606813834553),
-ale::Vec3d(-0.0153701272936794, -0.0967916367473043, -0.0284606813322556),
-ale::Vec3d(-0.015370129198612, -0.0967916577529709, -0.0284606812811673),
-ale::Vec3d(-0.0153701311031148, -0.0967916787595734, -0.0284606812302468),
-ale::Vec3d(-0.0153701330072486, -0.0967916997669981, -0.0284606811794379),
-ale::Vec3d(-0.0153701349109495, -0.0967917207753623, -0.0284606811287951),
-ale::Vec3d(-0.0153701368142852, -0.0967917417845576, -0.0284606810782657),
-ale::Vec3d(-0.0153701387171744, -0.0967917627946783, -0.0284606810279025),
-ale::Vec3d(-0.0153701406197154, -0.0967917838056372, -0.0284606809776528),
-ale::Vec3d(-0.0153701425218418, -0.0967918048174734, -0.0284606809275409),
-ale::Vec3d(-0.0153701444235427, -0.0967918258302474, -0.0284606808775962),
-ale::Vec3d(-0.0153701463248632, -0.0967918468438453, -0.0284606808277636),
-ale::Vec3d(-0.0153701482257517, -0.0967918678583828, -0.028460680778098),
-ale::Vec3d(-0.0153701501262747, -0.0967918888737514, -0.0284606807285448),
-ale::Vec3d(-0.0153701520263642, -0.0967919098900505, -0.0284606806791581),
-ale::Vec3d(-0.0153701539260803, -0.0967919309071788, -0.0284606806298831),
-ale::Vec3d(-0.0153701558253628, -0.0967919519252454, -0.0284606805807748),
-ale::Vec3d(-0.0153701577242883, -0.0967919729441372, -0.028460680531779),
-ale::Vec3d(-0.0153701596227715, -0.0967919939639688, -0.0284606804829498),
-ale::Vec3d(-0.0153701615208887, -0.0967920149846261, -0.0284606804342323),
-ale::Vec3d(-0.015370163418563, -0.0967920360062177, -0.028460680385682),
-ale::Vec3d(-0.0153701653158791, -0.0967920570286386, -0.0284606803372438),
-ale::Vec3d(-0.0153701672127516, -0.0967920780520043, -0.0284606802889809),
-ale::Vec3d(-0.0153701691092572, -0.0967920990761938, -0.0284606802408221),
-ale::Vec3d(-0.0153701710053287, -0.0967921201013125, -0.0284606801928288),
-ale::Vec3d(-0.0153701729010412, -0.096792141127264, -0.0284606801449487),
-ale::Vec3d(-0.0153701747963447, -0.0967921621540997, -0.0284606800972071),
-ale::Vec3d(-0.0153701766912129, -0.096792183181868, -0.0284606800496334),
-ale::Vec3d(-0.0153701785857075, -0.0967922042104672, -0.0284606800021717),
-ale::Vec3d(-0.0153701804797747, -0.0967922252399974, -0.0284606799548765),
-ale::Vec3d(-0.0153701823734752, -0.0967922462703656, -0.0284606799076943),
-ale::Vec3d(-0.0153701842667371, -0.0967922673016664, -0.0284606798606782),
-ale::Vec3d(-0.015370186159624, -0.0967922883337961, -0.0284606798137744)
+std::vector<Vec3d> velocities = {
+Vec3d(-0.0153700718765843, -0.0967910279657348, -0.0284606828741588),
+Vec3d(-0.0153700737931066, -0.096791048945897, -0.0284606828190555),
+Vec3d(-0.0153700757092848, -0.0967910699268904, -0.0284606827640637),
+Vec3d(-0.0153700776250131, -0.0967910909088181, -0.0284606827092379),
+Vec3d(-0.0153700795403742, -0.0967911118915676, -0.0284606826545261),
+Vec3d(-0.0153700814553067, -0.0967911328752586, -0.0284606825999784),
+Vec3d(-0.015370083369856, -0.0967911538597701, -0.0284606825455435),
+Vec3d(-0.0153700852839879, -0.0967911748452176, -0.0284606824912741),
+Vec3d(-0.0153700871977456, -0.0967911958314943, -0.0284606824371165),
+Vec3d(-0.0153700891110573, -0.0967912168186004, -0.0284606823830493),
+Vec3d(-0.0153700910239836, -0.0967912378066924, -0.0284606823291967),
+Vec3d(-0.0153700929365416, -0.0967912587956045, -0.0284606822754565),
+Vec3d(-0.0153700948486603, -0.0967912797854579, -0.0284606822218836),
+Vec3d(-0.0153700967604118, -0.0967913007761374, -0.0284606821684221),
+Vec3d(-0.0153700986717228, -0.0967913217677527, -0.0284606821151287),// velocity to test
+Vec3d(-0.0153701005826786, -0.0967913427601938, -0.0284606820619469),
+Vec3d(-0.0153701024931907, -0.0967913637535689, -0.0284606820089321),
+Vec3d(-0.0153701044033458, -0.0967913847477737, -0.0284606819560303),
+Vec3d(-0.0153701063130629, -0.0967914057429141, -0.0284606819032941),
+Vec3d(-0.0153701082224151, -0.0967914267388804, -0.0284606818506722),
+Vec3d(-0.0153701101313204, -0.0967914477357808, -0.0284606817982155),
+Vec3d(-0.0153701120398714, -0.0967914687335107, -0.0284606817458717),
+Vec3d(-0.0153701139480175, -0.096791489732125, -0.028460681693667),
+Vec3d(-0.0153701158557277, -0.0967915107316699, -0.0284606816416301),
+Vec3d(-0.0153701177630685, -0.0967915317320424, -0.0284606815897053),
+Vec3d(-0.0153701196699842, -0.0967915527333597, -0.0284606815379469),
+Vec3d(-0.0153701215765303, -0.0967915737354921, -0.028460681486301),
+Vec3d(-0.0153701234826341, -0.0967915947385677, -0.0284606814348225),
+Vec3d(-0.0153701253883785, -0.0967916157424725, -0.0284606813834553),
+Vec3d(-0.0153701272936794, -0.0967916367473043, -0.0284606813322556),
+Vec3d(-0.015370129198612, -0.0967916577529709, -0.0284606812811673),
+Vec3d(-0.0153701311031148, -0.0967916787595734, -0.0284606812302468),
+Vec3d(-0.0153701330072486, -0.0967916997669981, -0.0284606811794379),
+Vec3d(-0.0153701349109495, -0.0967917207753623, -0.0284606811287951),
+Vec3d(-0.0153701368142852, -0.0967917417845576, -0.0284606810782657),
+Vec3d(-0.0153701387171744, -0.0967917627946783, -0.0284606810279025),
+Vec3d(-0.0153701406197154, -0.0967917838056372, -0.0284606809776528),
+Vec3d(-0.0153701425218418, -0.0967918048174734, -0.0284606809275409),
+Vec3d(-0.0153701444235427, -0.0967918258302474, -0.0284606808775962),
+Vec3d(-0.0153701463248632, -0.0967918468438453, -0.0284606808277636),
+Vec3d(-0.0153701482257517, -0.0967918678583828, -0.028460680778098),
+Vec3d(-0.0153701501262747, -0.0967918888737514, -0.0284606807285448),
+Vec3d(-0.0153701520263642, -0.0967919098900505, -0.0284606806791581),
+Vec3d(-0.0153701539260803, -0.0967919309071788, -0.0284606806298831),
+Vec3d(-0.0153701558253628, -0.0967919519252454, -0.0284606805807748),
+Vec3d(-0.0153701577242883, -0.0967919729441372, -0.028460680531779),
+Vec3d(-0.0153701596227715, -0.0967919939639688, -0.0284606804829498),
+Vec3d(-0.0153701615208887, -0.0967920149846261, -0.0284606804342323),
+Vec3d(-0.015370163418563, -0.0967920360062177, -0.028460680385682),
+Vec3d(-0.0153701653158791, -0.0967920570286386, -0.0284606803372438),
+Vec3d(-0.0153701672127516, -0.0967920780520043, -0.0284606802889809),
+Vec3d(-0.0153701691092572, -0.0967920990761938, -0.0284606802408221),
+Vec3d(-0.0153701710053287, -0.0967921201013125, -0.0284606801928288),
+Vec3d(-0.0153701729010412, -0.096792141127264, -0.0284606801449487),
+Vec3d(-0.0153701747963447, -0.0967921621540997, -0.0284606800972071),
+Vec3d(-0.0153701766912129, -0.096792183181868, -0.0284606800496334),
+Vec3d(-0.0153701785857075, -0.0967922042104672, -0.0284606800021717),
+Vec3d(-0.0153701804797747, -0.0967922252399974, -0.0284606799548765),
+Vec3d(-0.0153701823734752, -0.0967922462703656, -0.0284606799076943),
+Vec3d(-0.0153701842667371, -0.0967922673016664, -0.0284606798606782),
+Vec3d(-0.015370186159624, -0.0967922883337961, -0.0284606798137744)
 };
 
 States testState(ephemTimes, positions, velocities);
@@ -441,7 +442,7 @@ States minimizedState = testState.minimizeCache();
 
 // Test the ability to recover the original coordinates and velocity within the tolerance
 // from the reduced cache. (Aribtrarily selected the 15th index.)
-ale::State result = minimizedState.getState(362681869.7384);
+State result = minimizedState.getState(362681869.7384);
 EXPECT_NEAR(result.position.x, -17386.3761449312, 1e-5);
 EXPECT_NEAR(result.position.y, 96555.0028814707, 1e-4);
 EXPECT_NEAR(result.position.z, 16357.3474474742, 1e-5);
@@ -450,7 +451,7 @@ EXPECT_NEAR(result.velocity.y, -0.0967913217677527, 1e-6);
 EXPECT_NEAR(result.velocity.z, -0.0284606821151287, 1e-6);
 
 // Get all the states to check that they match exactly with ISIS's reduced cache:
-std::vector<ale::State> results = minimizedState.getStates();
+std::vector<State> results = minimizedState.getStates();
 EXPECT_NEAR(results[0].position.x, -17382.7468835417, 1e-8);
 EXPECT_NEAR(results[0].position.y, 96577.8576989543, 1e-8);
 EXPECT_NEAR(results[0].position.z, 16364.0677257831, 1e-8);
diff --git a/tests/pytests/data/isds/cassiniiss_isd.json b/tests/pytests/data/isds/cassiniiss_isd.json
index 872b187..78ae8e5 100644
--- a/tests/pytests/data/isds/cassiniiss_isd.json
+++ b/tests/pytests/data/isds/cassiniiss_isd.json
@@ -1,6 +1,6 @@
 {
-  "IsisCameraVersion": 1,
-  "NaifKeywords": {
+  "isis_camera_version": 1,
+  "naif_keywords": {
     "BODY602_RADII": [
       256.6,
       251.4,
@@ -215,18 +215,19 @@
     "semiminor": 248.3,
     "unit": "km"
   },
-  "InstrumentPointing": {
-    "TimeDependentFrames": [
+  "instrument_pointing": {
+    "reference_frame" : 1, 
+    "time_dependent_frames": [
       -82000,
       1
     ],
-    "CkTableStartTime": 376938208.24072826,
-    "CkTableEndTime": 376938208.24072826,
-    "CkTableOriginalSize": 1,
-    "EphemerisTimes": [
+    "ck_table_start_time": 376938208.24072826,
+    "ck_table_end_time": 376938208.24072826,
+    "ck_table_original_size": 1,
+    "ephemeris_times": [
       376938208.24072826
     ],
-    "Quaternions": [
+    "quaternions": [
       [
         -0.714592970784935,
         0.21489250965350096,
@@ -234,19 +235,19 @@
         -0.4979453636940545
       ]
     ],
-    "AngularVelocity": [
+    "angular_velocity": [
       [
         -0.0007574572640014708,
         -0.0003505925165897519,
         -0.00010610139650303626
       ]
     ],
-    "ConstantFrames": [
+    "constant_frames": [
       14082360,
       -82360,
       -82000
     ],
-    "ConstantRotation": [
+    "constant_rotation": [
       -0.0014870197280318354,
       -0.00017182872562465645,
       0.9999988796229811,
@@ -258,18 +259,19 @@
       -0.00017097242433417037
     ]
   },
-  "BodyRotation": {
-    "TimeDependentFrames": [
+  "body_rotation": {
+    "reference_frame" : 1, 
+    "time_dependent_frames": [
       10040,
       1
     ],
-    "CkTableStartTime": 376938208.24072826,
-    "CkTableEndTime": 376938208.24072826,
-    "CkTableOriginalSize": 1,
-    "EphemerisTimes": [
+    "ck_table_start_time": 376938208.24072826,
+    "ck_table_end_time": 376938208.24072826,
+    "ck_table_original_size": 1,
+    "ephemeris_times": [
       376938208.24072826
     ],
-    "Quaternions": [
+    "quaternions": [
       [
         -0.49726210411698374,
         0.01884225276113552,
@@ -277,7 +279,7 @@
         0.8657572318545625
       ]
     ],
-    "AngularVelocity": [
+    "angular_velocity": [
       [
         4.544323197605555e-06,
         3.902625629848413e-06,
@@ -285,21 +287,22 @@
       ]
     ]
   },
-  "InstrumentPosition": {
-    "SpkTableStartTime": 376938208.24072826,
-    "SpkTableEndTime": 376938208.24072826,
-    "SpkTableOriginalSize": 1,
-    "EphemerisTimes": [
+  "instrument_position": {
+    "reference_frame" : 1, 
+    "spk_table_start_time": 376938208.24072826,
+    "spk_table_end_time": 376938208.24072826,
+    "spk_table_original_size": 1,
+    "ephemeris_times": [
       376938208.24072826
     ],
-    "Positions": [
+    "positions": [
       [
         21961.77283021467,
         10151.980187116338,
         -3287.1339343305876
       ]
     ],
-    "Velocities": [
+    "velocities": [
       [
         5.455579135911339,
         -3.302834463297056,
@@ -307,21 +310,22 @@
       ]
     ]
   },
-  "SunPosition": {
-    "SpkTableStartTime": 376938208.24072826,
-    "SpkTableEndTime": 376938208.24072826,
-    "SpkTableOriginalSize": 1,
-    "EphemerisTimes": [
+  "sun_position": {
+    "reference_frame" : 1, 
+    "spk_table_start_time": 376938208.24072826,
+    "spk_table_end_time": 376938208.24072826,
+    "spk_table_original_size": 1,
+    "ephemeris_times": [
       376938208.24072826
     ],
-    "Positions": [
+    "positions": [
       [
         1342712164.7010403,
         521645736.9735198,
         157522069.3546536
       ]
     ],
-    "Velocities": [
+    "velocities": [
       [
         -15.573457955043763,
         5.743795762971043,
diff --git a/tests/pytests/data/isds/ctx_isd.json b/tests/pytests/data/isds/ctx_isd.json
index 4b99577..22fdae6 100644
--- a/tests/pytests/data/isds/ctx_isd.json
+++ b/tests/pytests/data/isds/ctx_isd.json
@@ -1,6 +1,6 @@
 {
-    "IsisCameraVersion": 1,
-    "NaifKeywords": {
+    "isis_camera_version": 1,
+    "naif_keywords": {
         "BODY499_RADII": [
             3396.19,
             3396.19,
@@ -211,16 +211,17 @@
         "semiminor": 3376.2,
         "unit": "km"
     },
-    "InstrumentPointing": {
-        "TimeDependentFrames": [
+    "instrument_pointing": {
+        "reference_frame" : 1, 
+        "time_dependent_frames": [
             -74000,
             -74900,
             1
         ],
-        "CkTableStartTime": 297088762.24158406,
-        "CkTableEndTime": 297088762.9923841,
-        "CkTableOriginalSize": 6,
-        "EphemerisTimes": [
+        "ck_table_start_time": 297088762.24158406,
+        "ck_table_end_time": 297088762.9923841,
+        "ck_table_original_size": 6,
+        "ephemeris_times": [
             297088762.24158406,
             297088762.3917441,
             297088762.5419041,
@@ -228,7 +229,7 @@
             297088762.84222406,
             297088762.9923841
         ],
-        "Quaternions": [
+        "quaternions": [
             [
                 0.42061124835443375,
                 0.1860622266332136,
@@ -266,7 +267,7 @@
                 0.8549121108185723
             ]
         ],
-        "AngularVelocity": [
+        "angular_velocity": [
             [
                 -0.0006409728984903079,
                 0.0005054077299115119,
@@ -298,14 +299,14 @@
                 0.0004805228583087444
             ]
         ],
-        "ConstantFrames": [
+        "constant_frames": [
             -74021,
             -74020,
             -74699,
             -74690,
             -74000
         ],
-        "ConstantRotation": [
+        "constant_rotation": [
             0.9999995608798441,
             -1.51960241928035e-05,
             0.0009370214510594064,
@@ -317,15 +318,16 @@
             0.9999995573030465
         ]
     },
-    "BodyRotation": {
-        "TimeDependentFrames": [
+    "body_rotation": {
+        "reference_frame" : 1, 
+        "time_dependent_frames": [
             10014,
             1
         ],
-        "CkTableStartTime": 297088762.24158406,
-        "CkTableEndTime": 297088762.9923841,
-        "CkTableOriginalSize": 6,
-        "EphemerisTimes": [
+        "ck_table_start_time": 297088762.24158406,
+        "ck_table_end_time": 297088762.9923841,
+        "ck_table_original_size": 6,
+        "ephemeris_times": [
             297088762.24158406,
             297088762.3917441,
             297088762.5419041,
@@ -333,7 +335,7 @@
             297088762.84222406,
             297088762.9923841
         ],
-        "Quaternions": [
+        "quaternions": [
             [
                 -0.8371209459443085,
                 0.2996928944391797,
@@ -371,7 +373,7 @@
                 0.4449034055807993
             ]
         ],
-        "AngularVelocity": [
+        "angular_velocity": [
             [
                 3.16238646979841e-05,
                 -2.880432898124293e-05,
@@ -404,11 +406,12 @@
             ]
         ]
     },
-    "InstrumentPosition": {
-        "SpkTableStartTime": 297088762.24158406,
-        "SpkTableEndTime": 297088762.9923841,
-        "SpkTableOriginalSize": 6,
-        "EphemerisTimes": [
+    "instrument_position": {
+        "reference_frame" : 1, 
+        "spk_table_start_time": 297088762.24158406,
+        "spk_table_end_time": 297088762.9923841,
+        "spk_table_original_size": 6,
+        "ephemeris_times": [
             297088762.24158406,
             297088762.3917441,
             297088762.5419041,
@@ -416,7 +419,7 @@
             297088762.84222406,
             297088762.9923841
         ],
-        "Positions": [
+        "positions": [
             [
                 -1885.298067561683,
                 913.165223601331,
@@ -448,7 +451,7 @@
                 -2961.684932934942
             ]
         ],
-        "Velocities": [
+        "velocities": [
             [
                 -1.9629237646703683,
                 -2.80759072221274,
@@ -481,21 +484,22 @@
             ]
         ]
     },
-    "SunPosition": {
-        "SpkTableStartTime": 297088762.61698407,
-        "SpkTableEndTime": 297088762.61698407,
-        "SpkTableOriginalSize": 1,
-        "EphemerisTimes": [
+    "sun_position": {
+        "reference_frame" : 1, 
+        "spk_table_start_time": 297088762.61698407,
+        "spk_table_end_time": 297088762.61698407,
+        "spk_table_original_size": 1,
+        "ephemeris_times": [
             297088762.61698407
         ],
-        "Positions": [
+        "positions": [
             [
                 -208246643.08248276,
                 -7677087.066457123,
                 2103548.956999197
             ]
         ],
-        "Velocities": [
+        "velocities": [
             [
                 -0.21020163267146563,
                 -23.901883517440407,
diff --git a/tests/pytests/data/isds/dawnfc_isd.json b/tests/pytests/data/isds/dawnfc_isd.json
index 30db623..643c73f 100644
--- a/tests/pytests/data/isds/dawnfc_isd.json
+++ b/tests/pytests/data/isds/dawnfc_isd.json
@@ -1,6 +1,6 @@
 {
-  "IsisCameraVersion": 2,
-  "NaifKeywords": {
+  "isis_camera_version": 2,
+  "naif_keywords": {
     "BODY2000001_RADII": [
       482.0,
       482.0,
@@ -146,19 +146,20 @@
     "semiminor": 446.0,
     "unit": "km"
   },
-  "InstrumentPointing": {
-    "TimeDependentFrames": [
+  "instrument_pointing": {
+    "reference_frame" : 1,
+    "time_dependent_frames": [
       -203120,
       -203000,
       1
     ],
-    "CkTableStartTime": 488002614.62294483,
-    "CkTableEndTime": 488002614.62294483,
-    "CkTableOriginalSize": 1,
-    "EphemerisTimes": [
+    "ck_table_start_time": 488002614.62294483,
+    "ck_table_end_time": 488002614.62294483,
+    "ck_table_original_size": 1,
+    "ephemeris_times": [
       488002614.62294483
     ],
-    "Quaternions": [
+    "quaternions": [
       [
         0.5213647259158684,
         -0.17475033868107043,
@@ -166,18 +167,18 @@
         -0.8240749322251953
       ]
     ],
-    "AngularVelocity": [
+    "angular_velocity": [
       [
         -2.0163095864499935e-05,
         2.0665280555081777e-08,
         3.996105121476586e-06
       ]
     ],
-    "ConstantFrames": [
+    "constant_frames": [
       -203126,
       -203120
     ],
-    "ConstantRotation": [
+    "constant_rotation": [
       1.0,
       0.0,
       0.0,
@@ -189,18 +190,19 @@
       1.0
     ]
   },
-  "BodyRotation": {
-    "TimeDependentFrames": [
+  "body_rotation": {
+    "reference_frame" : 1,
+    "time_dependent_frames": [
       10101,
       1
     ],
-    "CkTableStartTime": 488002614.62294483,
-    "CkTableEndTime": 488002614.62294483,
-    "CkTableOriginalSize": 1,
-    "EphemerisTimes": [
+    "ck_table_start_time": 488002614.62294483,
+    "ck_table_end_time": 488002614.62294483,
+    "ck_table_original_size": 1,
+    "ephemeris_times": [
       488002614.62294483
     ],
-    "Quaternions": [
+    "quaternions": [
       [
         -0.7323907260895571,
         0.1890116253358707,
@@ -208,7 +210,7 @@
         0.6504211272382237
       ]
     ],
-    "AngularVelocity": [
+    "angular_velocity": [
       [
         2.770977343153026e-05,
         -7.064167352871139e-05,
@@ -216,21 +218,22 @@
       ]
     ]
   },
-  "InstrumentPosition": {
-    "SpkTableStartTime": 488002614.62294483,
-    "SpkTableEndTime": 488002614.62294483,
-    "SpkTableOriginalSize": 1,
-    "EphemerisTimes": [
+  "instrument_position": {
+    "reference_frame" : 1,
+    "spk_table_start_time": 488002614.62294483,
+    "spk_table_end_time": 488002614.62294483,
+    "spk_table_original_size": 1,
+    "ephemeris_times": [
       488002614.62294483
     ],
-    "Positions": [
+    "positions": [
       [
         -678.145360419934,
         2026.1409618562566,
         -4375.770027129584
       ]
     ],
-    "Velocities": [
+    "velocities": [
       [
         0.01836093913952242,
         -0.10035442890342972,
@@ -238,21 +241,22 @@
       ]
     ]
   },
-  "SunPosition": {
-    "SpkTableStartTime": 488002614.62294483,
-    "SpkTableEndTime": 488002614.62294483,
-    "SpkTableOriginalSize": 1,
-    "EphemerisTimes": [
+  "sun_position": {
+    "reference_frame" : 1, 
+    "spk_table_start_time": 488002614.62294483,
+    "spk_table_end_time": 488002614.62294483,
+    "spk_table_original_size": 1,
+    "ephemeris_times": [
       488002614.62294483
     ],
-    "Positions": [
+    "positions": [
       [
         -184987783.06715,
         343341745.2043138,
         199532284.61700404
       ]
     ],
-    "Velocities": [
+    "velocities": [
       [
         -15.334993792176247,
         -7.083164572551847,
diff --git a/tests/pytests/data/isds/kaguyami_isd.json b/tests/pytests/data/isds/kaguyami_isd.json
index dc629c0..da5cff2 100644
--- a/tests/pytests/data/isds/kaguyami_isd.json
+++ b/tests/pytests/data/isds/kaguyami_isd.json
@@ -1,6 +1,6 @@
  {
-  "IsisCameraVersion": 1,
-  "NaifKeywords": {
+  "isis_camera_version": 1,
+  "naif_keywords": {
     "BODY301_RADII": [
       1737.4,
       1737.4,
@@ -161,15 +161,16 @@
     "semiminor": 1737.4,
     "unit": "km"
   },
-  "InstrumentPointing": {
-    "TimeDependentFrames": [
+  "instrument_pointing": {
+    "reference_frame" : 1, 
+    "time_dependent_frames": [
       -131000,
       1
     ],
-    "CkTableStartTime": 261664552.50899568,
-    "CkTableEndTime": 261664564.98897073,
-    "CkTableOriginalSize": 15,
-    "EphemerisTimes": [
+    "ck_table_start_time": 261664552.50899568,
+    "ck_table_end_time": 261664564.98897073,
+    "ck_table_original_size": 15,
+    "ephemeris_times": [
       261664552.50899568,
       261664553.40042248,
       261664554.29184926,
@@ -186,7 +187,7 @@
       261664564.09754393,
       261664564.98897073
     ],
-    "Quaternions": [
+    "quaternions": [
       [
         -0.051661051153873275,
         -0.7006601262613299,
@@ -278,7 +279,7 @@
         0.6820651599944132
       ]
     ],
-    "AngularVelocity": [
+    "angular_velocity": [
       [
         -0.0009538064837455751,
         -0.0012094992518424988,
@@ -355,12 +356,12 @@
         -0.00023185169696807864
       ]
     ],
-    "ConstantFrames": [
+    "constant_frames": [
       -131330,
       -131320,
       -131000
     ],
-    "ConstantRotation": [
+    "constant_rotation": [
       0.9999999022105177,
       -0.00041337792156500403,
       -0.00015715485723418282,
@@ -372,15 +373,16 @@
       0.9999992088034335
     ]
   },
-  "BodyRotation": {
-    "TimeDependentFrames": [
+  "body_rotation": {
+    "reference_frame" : 1, 
+    "time_dependent_frames": [
       10020,
       1
     ],
-    "CkTableStartTime": 261664552.50899568,
-    "CkTableEndTime": 261664564.98897073,
-    "CkTableOriginalSize": 15,
-    "EphemerisTimes": [
+    "ck_table_start_time": 261664552.50899568,
+    "ck_table_end_time": 261664564.98897073,
+    "ck_table_original_size": 15,
+    "ephemeris_times": [
       261664552.50899568,
       261664553.40042248,
       261664554.29184926,
@@ -397,7 +399,7 @@
       261664564.09754393,
       261664564.98897073
     ],
-    "Quaternions": [
+    "quaternions": [
       [
         -0.9710661094490091,
         0.18926293156500895,
@@ -489,7 +491,7 @@
         -0.14114626872597225
       ]
     ],
-    "AngularVelocity": [
+    "angular_velocity": [
       [
         4.161664897473834e-08,
         -1.004371630350468e-06,
@@ -567,11 +569,12 @@
       ]
     ]
   },
-  "InstrumentPosition": {
-    "SpkTableStartTime": 261664552.50899568,
-    "SpkTableEndTime": 261664564.98897073,
-    "SpkTableOriginalSize": 15,
-    "EphemerisTimes": [
+  "instrument_position": {
+    "reference_frame" : 1, 
+    "spk_table_start_time": 261664552.50899568,
+    "spk_table_end_time": 261664564.98897073,
+    "spk_table_original_size": 15,
+    "ephemeris_times": [
       261664552.50899568,
       261664553.40042248,
       261664554.29184926,
@@ -588,7 +591,7 @@
       261664564.09754393,
       261664564.98897073
     ],
-    "Positions": [
+    "positions": [
       [
         1779.1765541938503,
         397.6505395849898,
@@ -665,7 +668,7 @@
         130.957798262226
       ]
     ],
-    "Velocities": [
+    "velocities": [
       [
         -0.003688959644644985,
         0.615208251928988,
@@ -743,21 +746,22 @@
       ]
     ]
   },
-  "SunPosition": {
-    "SpkTableStartTime": 261664558.7489832,
-    "SpkTableEndTime": 261664558.7489832,
-    "SpkTableOriginalSize": 1,
-    "EphemerisTimes": [
+  "sun_position": {
+    "reference_frame" : 1, 
+    "spk_table_start_time": 261664558.7489832,
+    "spk_table_end_time": 261664558.7489832,
+    "spk_table_original_size": 1,
+    "ephemeris_times": [
       261664558.7489832
     ],
-    "Positions": [
+    "positions": [
       [
         133875301.95654832,
         63045454.87068491,
         27346357.260941397
       ]
     ],
-    "Velocities": [
+    "velocities": [
       [
         -12.93006737143756,
         25.242392040919338,
diff --git a/tests/pytests/data/isds/kaguyatc_isd.json b/tests/pytests/data/isds/kaguyatc_isd.json
index 97c62f2..9c07ca0 100644
--- a/tests/pytests/data/isds/kaguyatc_isd.json
+++ b/tests/pytests/data/isds/kaguyatc_isd.json
@@ -1,6 +1,6 @@
 {
-  "IsisCameraVersion": 1,
-  "NaifKeywords": {
+  "isis_camera_version": 1,
+  "naif_keywords": {
     "BODY301_RADII": [
       1737.4,
       1737.4,
@@ -191,15 +191,16 @@
     "semiminor": 1737.4,
     "unit": "km"
   },
-  "InstrumentPointing": {
-    "TimeDependentFrames": [
+  "instrument_pointing": {
+    "reference_frame" : 1,
+    "time_dependent_frames": [
       -131000,
       1
     ],
-    "CkTableStartTime": 292234259.82293594,
-    "CkTableEndTime": 292234262.42293596,
-    "CkTableOriginalSize": 6,
-    "EphemerisTimes": [
+    "ck_table_start_time": 292234259.82293594,
+    "ck_table_end_time": 292234262.42293596,
+    "ck_table_original_size": 6,
+    "ephemeris_times": [
       292234259.82293594,
       292234260.3429359,
       292234260.86293596,
@@ -207,7 +208,7 @@
       292234261.902936,
       292234262.42293596
     ],
-    "Quaternions": [
+    "quaternions": [
       [
         -0.11368345174719045,
         0.09298596444784424,
@@ -245,7 +246,7 @@
         -0.968551426254611
       ]
     ],
-    "AngularVelocity": [
+    "angular_velocity": [
       [
         0.0030447825014591214,
         0.00010000000000000005,
@@ -277,12 +278,12 @@
         -5.421010862427522e-20
       ]
     ],
-    "ConstantFrames": [
+    "constant_frames": [
       -131350,
       -131320,
       -131000
     ],
-    "ConstantRotation": [
+    "constant_rotation": [
       0.9662180936858615,
       -0.0009130086708890376,
       -0.25772419725207507,
@@ -294,15 +295,16 @@
       0.9662183691750111
     ]
   },
-  "BodyRotation": {
-    "TimeDependentFrames": [
+  "body_rotation": {
+    "reference_frame" : 1,
+    "time_dependent_frames": [
       10020,
       1
     ],
-    "CkTableStartTime": 292234259.82293594,
-    "CkTableEndTime": 292234262.42293596,
-    "CkTableOriginalSize": 6,
-    "EphemerisTimes": [
+    "ck_table_start_time": 292234259.82293594,
+    "ck_table_end_time": 292234262.42293596,
+    "ck_table_original_size": 6,
+    "ephemeris_times": [
       292234259.82293594,
       292234260.3429359,
       292234260.86293596,
@@ -310,7 +312,7 @@
       292234261.902936,
       292234262.42293596
     ],
-    "Quaternions": [
+    "quaternions": [
       [
         -0.9366199858891122,
         0.18349494110821096,
@@ -348,7 +350,7 @@
         -0.290467693256969
       ]
     ],
-    "AngularVelocity": [
+    "angular_velocity": [
       [
         5.82758225576212e-08,
         -1.019441640177111e-06,
@@ -381,11 +383,12 @@
       ]
     ]
   },
-  "InstrumentPosition": {
-    "SpkTableStartTime": 292234259.82293594,
-    "SpkTableEndTime": 292234262.42293596,
-    "SpkTableOriginalSize": 6,
-    "EphemerisTimes": [
+  "instrument_position": {
+    "reference_frame" : 1,
+    "spk_table_start_time": 292234259.82293594,
+    "spk_table_end_time": 292234262.42293596,
+    "spk_table_original_size": 6,
+    "ephemeris_times": [
       292234259.82293594,
       292234260.3429359,
       292234260.86293596,
@@ -393,7 +396,7 @@
       292234261.902936,
       292234262.42293596
     ],
-    "Positions": [
+    "positions": [
       [
         242.79442620277422,
         738.203001908958,
@@ -425,7 +428,7 @@
         -1613.827152851969
       ]
     ],
-    "Velocities": [
+    "velocities": [
       [
         -1.5862908231149133,
         -0.28618937128869254,
@@ -458,21 +461,22 @@
       ]
     ]
   },
-  "SunPosition": {
-    "SpkTableStartTime": 292234261.12293595,
-    "SpkTableEndTime": 292234261.12293595,
-    "SpkTableOriginalSize": 1,
-    "EphemerisTimes": [
+  "sun_position": {
+    "reference_frame" : 1, 
+    "spk_table_start_time": 292234261.12293595,
+    "spk_table_end_time": 292234261.12293595,
+    "spk_table_original_size": 1,
+    "ephemeris_times": [
       292234261.12293595
     ],
-    "Positions": [
+    "positions": [
       [
         144178551.68571115,
         37762451.38900038,
         16383592.932550186
       ]
     ],
-    "Velocities": [
+    "velocities": [
       [
         -7.182591994538903,
         27.132956790118943,
diff --git a/tests/pytests/data/isds/lrolroc_isd.json b/tests/pytests/data/isds/lrolroc_isd.json
index e5a3cc8..256820d 100644
--- a/tests/pytests/data/isds/lrolroc_isd.json
+++ b/tests/pytests/data/isds/lrolroc_isd.json
@@ -1,6 +1,6 @@
 {
-  "IsisCameraVersion": 2,
-  "NaifKeywords": {
+  "isis_camera_version": 2,
+  "naif_keywords": {
     "BODY301_RADII": [
       1737.4,
       1737.4,
@@ -191,16 +191,17 @@
     "semiminor": 1737.4,
     "unit": "km"
   },
-  "InstrumentPointing": {
-    "TimeDependentFrames": [
+  "instrument_pointing": {
+    "reference_frame" : 1, 
+    "time_dependent_frames": [
       -85600,
       -85000,
       1
     ],
-    "CkTableStartTime": 302228504.36824864,
-    "CkTableEndTime": 302228504.7816205,
-    "CkTableOriginalSize": 6,
-    "EphemerisTimes": [
+    "ck_table_start_time": 302228504.36824864,
+    "ck_table_end_time": 302228504.7816205,
+    "ck_table_original_size": 6,
+    "ephemeris_times": [
       302228504.36824864,
       302228504.450923,
       302228504.5335974,
@@ -208,7 +209,7 @@
       302228504.6989461,
       302228504.7816205
     ],
-    "Quaternions": [
+    "quaternions": [
       [
         0.22984449090659237,
         0.8562360121526155,
@@ -246,7 +247,7 @@
         0.4625562996626938
       ]
     ],
-    "AngularVelocity": [
+    "angular_velocity": [
       [
         0.00015796288676771882,
         -0.0007643782570599635,
@@ -278,10 +279,10 @@
         -0.00032321391571062645
       ]
     ],
-    "ConstantFrames": [
+    "constant_frames": [
       -85600
     ],
-    "ConstantRotation": [
+    "constant_rotation": [
       1.0,
       0.0,
       0.0,
@@ -293,15 +294,16 @@
       1.0
     ]
   },
-  "BodyRotation": {
-    "TimeDependentFrames": [
+  "body_rotation": {
+    "reference_frame" : 1, 
+    "time_dependent_frames": [
       31006,
       1
     ],
-    "CkTableStartTime": 302228504.36824864,
-    "CkTableEndTime": 302228504.7816205,
-    "CkTableOriginalSize": 6,
-    "EphemerisTimes": [
+    "ck_table_start_time": 302228504.36824864,
+    "ck_table_end_time": 302228504.7816205,
+    "ck_table_original_size": 6,
+    "ephemeris_times": [
       302228504.36824864,
       302228504.450923,
       302228504.5335974,
@@ -309,7 +311,7 @@
       302228504.6989461,
       302228504.7816205
     ],
-    "Quaternions": [
+    "quaternions": [
       [
         -0.8896294526439446,
         0.18337484217069425,
@@ -347,7 +349,7 @@
         0.41209238745406124
       ]
     ],
-    "AngularVelocity": [
+    "angular_velocity": [
       [
         6.23828510009553e-08,
         -1.0257490014652093e-06,
@@ -379,12 +381,12 @@
         2.4553540362574277e-06
       ]
     ],
-    "ConstantFrames": [
+    "constant_frames": [
       31001,
       31007,
       31006
     ],
-    "ConstantRotation": [
+    "constant_rotation": [
       0.9999998732547144,
       -0.00032928542237557133,
       0.00038086961867138755,
@@ -396,11 +398,12 @@
       0.9999999274681067
     ]
   },
-  "InstrumentPosition": {
-    "SpkTableStartTime": 302228504.36824864,
-    "SpkTableEndTime": 302228504.7816205,
-    "SpkTableOriginalSize": 6,
-    "EphemerisTimes": [
+  "instrument_position": {
+    "reference_frame" : 1, 
+    "spk_table_start_time": 302228504.36824864,
+    "spk_table_end_time": 302228504.7816205,
+    "spk_table_original_size": 6,
+    "ephemeris_times": [
       302228504.36824864,
       302228504.450923,
       302228504.5335974,
@@ -408,7 +411,7 @@
       302228504.6989461,
       302228504.7816205
     ],
-    "Positions": [
+    "positions": [
       [
         -1516.1039882048947,
         -668.6745734893002,
@@ -440,7 +443,7 @@
         901.6112334649276
       ]
     ],
-    "Velocities": [
+    "velocities": [
       [
         -0.8710817993164441,
         0.3913754105818205,
@@ -473,21 +476,22 @@
       ]
     ]
   },
-  "SunPosition": {
-    "SpkTableStartTime": 302228504.5749346,
-    "SpkTableEndTime": 302228504.5749346,
-    "SpkTableOriginalSize": 1,
-    "EphemerisTimes": [
+  "sun_position": {
+    "reference_frame" : 1, 
+    "spk_table_start_time": 302228504.5749346,
+    "spk_table_end_time": 302228504.5749346,
+    "spk_table_original_size": 1,
+    "ephemeris_times": [
       302228504.5749346
     ],
-    "Positions": [
+    "positions": [
       [
         -91885596.62561405,
         111066639.06681778,
         48186230.75049895
       ]
     ],
-    "Velocities": [
+    "velocities": [
       [
         -23.97582426247181,
         -15.920790540011309,
diff --git a/tests/pytests/data/isds/messmdis_isd.json b/tests/pytests/data/isds/messmdis_isd.json
index 785f18d..2b00095 100644
--- a/tests/pytests/data/isds/messmdis_isd.json
+++ b/tests/pytests/data/isds/messmdis_isd.json
@@ -1,6 +1,6 @@
 {
-  "IsisCameraVersion": 2,
-  "NaifKeywords": {
+  "isis_camera_version": 2,
+  "naif_keywords": {
     "BODY199_RADII": [
       2439.4,
       2439.4,
@@ -226,21 +226,22 @@
     "semiminor": 2439.4,
     "unit": "km"
   },
-  "InstrumentPointing": {
-    "TimeDependentFrames": [
+  "instrument_pointing": {
+    "reference_frame" : 1, 
+    "time_dependent_frames": [
       -236890,
       -236892,
       -236880,
       -236000,
       1
     ],
-    "CkTableStartTime": 483122606.85252464,
-    "CkTableEndTime": 483122606.85252464,
-    "CkTableOriginalSize": 1,
-    "EphemerisTimes": [
+    "ck_table_start_time": 483122606.85252464,
+    "ck_table_end_time": 483122606.85252464,
+    "ck_table_original_size": 1,
+    "ephemeris_times": [
       483122606.85252464
     ],
-    "Quaternions": [
+    "quaternions": [
       [
         -0.38021468192232416,
         -0.021997068527329248,
@@ -248,19 +249,19 @@
         0.27977075522196615
       ]
     ],
-    "AngularVelocity": [
+    "angular_velocity": [
       [
         0.0003701285091906918,
         -0.001206909830636917,
         -0.0006642955353786956
       ]
     ],
-    "ConstantFrames": [
+    "constant_frames": [
       -236820,
       -236800,
       -236890
     ],
-    "ConstantRotation": [
+    "constant_rotation": [
       0.001686595916635364,
       0.9999610949473945,
       0.008658174508642313,
@@ -272,18 +273,19 @@
       -0.0006446663904859373
     ]
   },
-  "BodyRotation": {
-    "TimeDependentFrames": [
+  "body_rotation": {
+    "reference_frame" : 1, 
+    "time_dependent_frames": [
       10011,
       1
     ],
-    "CkTableStartTime": 483122606.85252464,
-    "CkTableEndTime": 483122606.85252464,
-    "CkTableOriginalSize": 1,
-    "EphemerisTimes": [
+    "ck_table_start_time": 483122606.85252464,
+    "ck_table_end_time": 483122606.85252464,
+    "ck_table_original_size": 1,
+    "ephemeris_times": [
       483122606.85252464
     ],
-    "Quaternions": [
+    "quaternions": [
       [
         -0.5879173675268659,
         0.18448696708540518,
@@ -291,7 +293,7 @@
         0.7703286686634552
       ]
     ],
-    "AngularVelocity": [
+    "angular_velocity": [
       [
         1.1327218036111434e-07,
         -5.824482156869511e-07,
@@ -299,21 +301,22 @@
       ]
     ]
   },
-  "InstrumentPosition": {
-    "SpkTableStartTime": 483122606.85252464,
-    "SpkTableEndTime": 483122606.85252464,
-    "SpkTableOriginalSize": 1,
-    "EphemerisTimes": [
+  "instrument_position": {
+    "reference_frame" : 1, 
+    "spk_table_start_time": 483122606.85252464,
+    "spk_table_end_time": 483122606.85252464,
+    "spk_table_original_size": 1,
+    "ephemeris_times": [
       483122606.85252464
     ],
-    "Positions": [
+    "positions": [
       [
         1844.0372778075634,
         -966.4783452894468,
         1322.8443003595244
       ]
     ],
-    "Velocities": [
+    "velocities": [
       [
         -2.6146204732071476,
         -0.30506722068884373,
@@ -321,21 +324,22 @@
       ]
     ]
   },
-  "SunPosition": {
-    "SpkTableStartTime": 483122606.85252464,
-    "SpkTableEndTime": 483122606.85252464,
-    "SpkTableOriginalSize": 1,
-    "EphemerisTimes": [
+  "sun_position": {
+    "reference_frame" : 1,
+    "spk_table_start_time": 483122606.85252464,
+    "spk_table_end_time": 483122606.85252464,
+    "spk_table_original_size": 1,
+    "ephemeris_times": [
       483122606.85252464
     ],
-    "Positions": [
+    "positions": [
       [
         11805116.23980372,
         -39513888.58935088,
         -22331586.84185954
       ]
     ],
-    "Velocities": [
+    "velocities": [
       [
         56.903276907758496,
         11.401211521119633,
diff --git a/tests/pytests/test_formatter.py b/tests/pytests/test_formatter.py
index 1f63d02..7d6d8f7 100644
--- a/tests/pytests/test_formatter.py
+++ b/tests/pytests/test_formatter.py
@@ -298,53 +298,53 @@ def test_interpolation_method(test_line_scan_driver):
 
 def test_camera_version(driver):
     meta_data = formatter.to_isd(driver)
-    assert meta_data['IsisCameraVersion'] == 1
+    assert meta_data['isis_camera_version'] == 1
 
 def test_instrument_pointing(driver):
     meta_data = formatter.to_isd(driver)
-    pointing = meta_data['InstrumentPointing']
-    assert pointing['TimeDependentFrames'] == [1000, 1]
-    assert pointing['ConstantFrames'] == [1010, 1000]
-    np.testing.assert_equal(pointing['ConstantRotation'], np.array([1., 0., 0., 0., 1., 0., 0., 0., 1.]))
-    assert pointing['CkTableStartTime'] == 800
-    assert pointing['CkTableEndTime'] == 900
-    assert pointing['CkTableOriginalSize'] == 2
-    np.testing.assert_equal(pointing['EphemerisTimes'], np.array([800, 900]))
-    np.testing.assert_equal(pointing['Quaternions'], np.array([[-1, 0, 0, 0], [-1, 0, 0, 0]]))
+    pointing = meta_data['instrument_pointing']
+    assert pointing['time_dependent_frames'] == [1000, 1]
+    assert pointing['constant_frames'] == [1010, 1000]
+    np.testing.assert_equal(pointing['constant_rotation'], np.array([1., 0., 0., 0., 1., 0., 0., 0., 1.]))
+    assert pointing['ck_table_start_time'] == 800
+    assert pointing['ck_table_end_time'] == 900
+    assert pointing['ck_table_original_size'] == 2
+    np.testing.assert_equal(pointing['ephemeris_times'], np.array([800, 900]))
+    np.testing.assert_equal(pointing['quaternions'], np.array([[-1, 0, 0, 0], [-1, 0, 0, 0]]))
 
 def test_instrument_position(driver):
     meta_data = formatter.to_isd(driver)
-    position = meta_data['InstrumentPosition']
-    assert position['SpkTableStartTime'] == 850
-    assert position['SpkTableEndTime'] == 850
-    assert position['SpkTableOriginalSize'] == 1
-    np.testing.assert_equal(position['EphemerisTimes'], np.array([850]))
-    np.testing.assert_equal(position['Positions'], np.array([[0, 0.001, 0.002]]))
-    np.testing.assert_equal(position['Velocities'], np.array([[0, -0.001, -0.002]]))
+    position = meta_data['instrument_position']
+    assert position['spk_table_start_time'] == 850
+    assert position['spk_table_end_time'] == 850
+    assert position['spk_table_original_size'] == 1
+    np.testing.assert_equal(position['ephemeris_times'], np.array([850]))
+    np.testing.assert_equal(position['positions'], np.array([[0, 0.001, 0.002]]))
+    np.testing.assert_equal(position['velocities'], np.array([[0, -0.001, -0.002]]))
 
 def test_body_rotation(driver):
     meta_data = formatter.to_isd(driver)
-    rotation = meta_data['BodyRotation']
-    assert rotation['TimeDependentFrames'] == [100, 1]
-    assert rotation['CkTableStartTime'] == 800
-    assert rotation['CkTableEndTime'] == 900
-    assert rotation['CkTableOriginalSize'] == 2
-    np.testing.assert_equal(rotation['EphemerisTimes'], np.array([800, 900]))
-    np.testing.assert_equal(rotation['Quaternions'], np.array([[-1, 0, 0, 0], [-1, 0, 0, 0]]))
+    rotation = meta_data['body_rotation']
+    assert rotation['time_dependent_frames'] == [100, 1]
+    assert rotation['ck_table_start_time'] == 800
+    assert rotation['ck_table_end_time'] == 900
+    assert rotation['ck_table_original_size'] == 2
+    np.testing.assert_equal(rotation['ephemeris_times'], np.array([800, 900]))
+    np.testing.assert_equal(rotation['quaternions'], np.array([[-1, 0, 0, 0], [-1, 0, 0, 0]]))
 
 def test_sun_position(driver):
     meta_data = formatter.to_isd(driver)
-    position = meta_data['SunPosition']
-    assert position['SpkTableStartTime'] == 850
-    assert position['SpkTableEndTime'] == 850
-    assert position['SpkTableOriginalSize'] == 1
-    np.testing.assert_equal(position['EphemerisTimes'], np.array([850]))
-    np.testing.assert_equal(position['Positions'], np.array([[0.0, 0.001, 0.002]]))
-    np.testing.assert_equal(position['Velocities'], np.array([[0.0, -0.001, -0.002]]))
+    position = meta_data['sun_position']
+    assert position['spk_table_start_time'] == 850
+    assert position['spk_table_end_time'] == 850
+    assert position['spk_table_original_size'] == 1
+    np.testing.assert_equal(position['ephemeris_times'], np.array([850]))
+    np.testing.assert_equal(position['positions'], np.array([[0.0, 0.001, 0.002]]))
+    np.testing.assert_equal(position['velocities'], np.array([[0.0, -0.001, -0.002]]))
 
 def test_naif_keywords(driver):
     meta_data = formatter.to_isd(driver)
-    assert meta_data['NaifKeywords'] == {
+    assert meta_data['naif_keywords'] == {
         'keyword_1' : 0,
         'keyword_2' : 'test'
     }
-- 
GitLab