7#include "SpicePosition.h"
17#include "BasisFunction.h"
18#include "IException.h"
19#include "LeastSquares.h"
20#include "LineEquation.h"
21#include "NaifStatus.h"
22#include "NumericalApproximation.h"
23#include "PolynomialUnivariate.h"
24#include "TableField.h"
26using json = nlohmann::json;
38 init(targetCode, observerCode,
false);
71 bool swapObserverTarget) {
72 init(targetCode, observerCode, swapObserverTarget);
88 const bool &swapObserverTarget) {
112 m_swapObserverTarget = swapObserverTarget;
117 if ( m_swapObserverTarget ) {
187 QString abcorr(correction);
188 abcorr.remove(QChar(
' '));
189 abcorr = abcorr.toUpper();
191 validAbcorr <<
"NONE" <<
"LT" <<
"LT+S" <<
"CN" <<
"CN+S"
192 <<
"XLT" <<
"XLT+S" <<
"XCN" <<
"XCN+S";
194 if (validAbcorr.indexOf(abcorr) >= 0) {
198 QString msg =
"Invalid abberation correction [" + correction +
"]";
199 throw IException(IException::Programmer, msg, _FILEINFO_);
300 QString msg =
"A SpicePosition cache has already been created";
301 throw IException(IException::Programmer, msg, _FILEINFO_);
304 if(startTime > endTime) {
305 QString msg =
"Argument startTime must be less than or equal to endTime";
306 throw IException(IException::Programmer, msg, _FILEINFO_);
309 if((startTime != endTime) && (size == 1)) {
310 QString msg =
"Cache size must be more than 1 if startTime endTime differ";
311 throw IException(IException::Programmer, msg, _FILEINFO_);
321 std::vector<ale::State> stateCache;
322 for(
int i = 0; i < size; i++) {
325 ale::State currentState = ale::State(ale::Vec3d(
p_coordinate));
327 currentState.velocity = ale::Vec3d(
p_velocity);
329 stateCache.push_back(currentState);
370 throw IException(IException::Programmer,
"SpicePosition::LoadCache(json) only supports Spice source", _FILEINFO_);
377 p_cacheTime = isdPos[
"ephemeris_times"].get<std::vector<double>>();
381 std::vector<ale::State> stateCache;
383 for (
auto it = isdPos[
"positions"].begin(); it != isdPos[
"positions"].end(); it++) {
384 int index = it - isdPos[
"positions"].begin();
385 std::vector<double> pos = it->get<std::vector<double>>();
386 std::vector<double> vel = isdPos[
"velocities"][index];
387 stateCache.push_back(ale::State(ale::Vec3d(pos), ale::Vec3d(vel)));
391 for (
auto it = isdPos[
"positions"].begin(); it != isdPos[
"positions"].end(); it++) {
392 std::vector<double> pos = {it->at(0).get<
double>(), it->at(1).get<
double>(), it->at(2).get<
double>()};
393 stateCache.push_back(ale::State(ale::Vec3d(pos)));
433 QString msg =
"A SpicePosition cache has already been created";
434 throw IException(IException::Programmer, msg, _FILEINFO_);
438 if(table.Label().hasKeyword(
"SpkTableStartTime")) {
441 if(table.Label().hasKeyword(
"SpkTableEndTime")) {
444 if(table.Label().hasKeyword(
"SpkTableOriginalSize")) {
445 p_fullCacheSize = toDouble(table.Label().findKeyword(
"SpkTableOriginalSize")[0]);
450 if(!table.Label().hasKeyword(
"CacheType")) {
453 else if(table.Label().findKeyword(
"CacheType")[0] ==
"Linear") {
456 else if(table.Label().findKeyword(
"CacheType")[0] ==
"HermiteSpline") {
461 else if(table.Label().findKeyword(
"CacheType")[0] ==
"PolyFunction") {
465 throw IException(IException::Io,
466 "Invalid value for CacheType keyword in the table "
471 std::vector<ale::State> stateCache;
474 for (
int r = 0; r < table.Records(); r++) {
475 TableRecord &rec = table[r];
476 if (rec.Fields() == 7) {
479 else if (rec.Fields() == 4) {
483 QString msg =
"Expecting four or seven fields in the SpicePosition table";
484 throw IException(IException::Programmer, msg, _FILEINFO_);
487 ale::State currentState(ale::Vec3d((
double)rec[0],
494 currentState.velocity = ale::Vec3d((
double)rec[3],
499 stateCache.push_back(currentState);
510 std::vector<double> coeffX, coeffY, coeffZ;
512 for (
int r = 0; r < table.Records() - 1; r++) {
513 TableRecord &rec = table[r];
515 if(rec.Fields() != 3) {
518 coeffX.push_back((
double)rec[0]);
519 coeffY.push_back((
double)rec[1]);
520 coeffZ.push_back((
double)rec[2]);
523 TableRecord &rec = table[table.Records()-1];
524 double baseTime = (double)rec[0];
525 double timeScale = (double)rec[1];
526 double degree = (double)rec[2];
561 TableField x(
"J2000X", TableField::Double);
562 TableField y(
"J2000Y", TableField::Double);
563 TableField z(
"J2000Z", TableField::Double);
570 TableField vx(
"J2000XV", TableField::Double);
571 TableField vy(
"J2000YV", TableField::Double);
572 TableField vz(
"J2000ZV", TableField::Double);
578 TableField t(
"ET", TableField::Double);
582 Table table(tableName, record);
586 std::vector<ale::State> stateCache =
m_state->getStates();
587 for (
int i = 0; i < (int)stateCache.size(); i++) {
588 record[inext++] = stateCache[i].position.x;
589 record[inext++] = stateCache[i].position.y;
590 record[inext++] = stateCache[i].position.z;
592 record[inext++] = stateCache[i].velocity.x;
593 record[inext++] = stateCache[i].velocity.y;
594 record[inext++] = stateCache[i].velocity.z;
613 TableField spacecraftX(
"J2000SVX", TableField::Double);
614 TableField spacecraftY(
"J2000SVY", TableField::Double);
615 TableField spacecraftZ(
"J2000SVZ", TableField::Double);
618 record += spacecraftX;
619 record += spacecraftY;
620 record += spacecraftZ;
622 Table table(tableName, record);
624 for(
int cindex = 0; cindex <
p_degree + 1; cindex++) {
643 throw IException(IException::Io,
644 "Cannot create Table, no Cache is loaded.",
660 QString tabletype =
"";
663 tabletype =
"Linear";
666 tabletype =
"HermiteSpline";
669 tabletype =
"PolyFunction";
672 table.Label() += PvlKeyword(
"CacheType", tabletype);
676 table.Label() += PvlKeyword(
"SpkTableStartTime");
680 table.Label() += PvlKeyword(
"SpkTableEndTime");
684 table.Label() += PvlKeyword(
"SpkTableOriginalSize");
710 QString msg =
"Only cached positions can be returned as a line cache of positions and time";
711 throw IException(IException::Programmer, msg, _FILEINFO_);
714 return Cache(tableName);
737 QString msg =
"The SpicePosition has not yet been fit to a function";
738 throw IException(IException::Programmer, msg, _FILEINFO_);
750 std::vector<ale::State> stateCache;
751 for (std::vector<double>::size_type pos = 0; pos <
p_cacheTime.size(); pos++) {
764 std::vector<ale::State> stateCache;
766 std::vector<double> timeCache;
771 m_state =
new ale::States(timeCache, stateCache);
800 if(cacheTimeSize == 1)
return Cache(tableName);
804 return Cache(tableName);
809 QString msg =
"A SpicePosition polynomial function has not been created yet";
810 throw IException(IException::Programmer, msg, _FILEINFO_);
843 double extremumXtime = -b1 / (2.*c1) +
p_baseTime;
845 if(extremumXtime < firstTime) {
846 extremumXtime = firstTime;
848 if(extremumXtime > lastTime) {
849 extremumXtime = lastTime;
854 double extremumYtime = -b2 / (2.*c2) +
p_baseTime;
856 if(extremumYtime < firstTime) {
857 extremumYtime = firstTime;
859 if(extremumYtime > lastTime) {
860 extremumYtime = lastTime;
865 double extremumZtime = -b3 / (2.*c3) +
p_baseTime;
867 if(extremumZtime < firstTime) {
868 extremumZtime = firstTime;
870 if(extremumZtime > lastTime) {
871 extremumZtime = lastTime;
895 std::vector<ale::State> stateCache;
896 for(
int i = 0; i < (int)
p_cacheTime.size(); i++) {
920 return Cache(tableName);
931 std::vector<double> XC, YC, ZC;
938 int size =
m_state->getStates().size();
942 else if (size == 2) {
961 std::vector<double> time;
984 for(
int cIndex = 0; cIndex < 3; cIndex++) {
986 slope[cIndex] = posline.
Slope();
989 XC.push_back(intercept[0]);
990 XC.push_back(slope[0]);
991 YC.push_back(intercept[1]);
992 YC.push_back(slope[1]);
993 ZC.push_back(intercept[2]);
994 ZC.push_back(slope[2]);
1002 for(std::vector<double>::size_type pos = 0; pos <
p_cacheTime.size(); pos++) {
1055 const std::vector<double>& YC,
1056 const std::vector<double>& ZC,
1104 std::vector<double>& YC,
1105 std::vector<double>& ZC) {
1168 SpicePosition::PartialType partialVar,
int coeffIndex) {
1171 std::vector<double> coordinate(3, 0);
1174 int coordIndex = partialVar;
1209 SpicePosition::PartialType partialVar,
int coeffIndex) {
1212 std::vector<double> dvelocity(3, 0);
1215 int coordIndex = partialVar;
1218 double derivative = 0.;
1221 double Epsilon = 1.0e-15;
1222 if (fabs(time) <= Epsilon) time = 0.0;
1226 derivative = coeffIndex * pow(time, coeffIndex-1) /
p_timeScale;
1229 dvelocity[coordIndex] = derivative;
1245 double derivative = 1.;
1248 if(coeffIndex > 0 && coeffIndex <=
p_degree) {
1249 derivative = pow(time, coeffIndex);
1251 else if(coeffIndex == 0) {
1255 QString msg =
"Unable to evaluate the derivative of the SPICE position fit polynomial for "
1256 "the given coefficient index [" +
toString(coeffIndex) +
"]. "
1257 "Index is negative or exceeds degree of polynomial ["
1259 throw IException(IException::Programmer, msg, _FILEINFO_);
1274 QString msg =
"No velocity vector available";
1275 throw IException(IException::Programmer, msg, _FILEINFO_);
1297 state =
m_state->getStates().front();
1326 ale::State state =
m_state->getState(
p_et, ale::SPLINE);
1337 throw IException(IException::Io,
"No velocities available. Cannot calculate Hermite Cache.",
1378 ale::Vec3d velocity =
m_state->getVelocities()[0];
1407 std::vector<double> hermiteVelocity =
p_velocity;
1410 for (
int index = 0; index < 3; index++) {
1468 throw IException(IException::Programmer,
1469 "Source type is not Memcache, cannot convert.",
1473 ale::States *tempStates =
new ale::States(
m_state->minimizeCache(tolerance));
1521 for(
int icoef =
p_degree + 1; icoef <= degree; icoef++) {
1522 coefX.push_back(0.);
1523 coefY.push_back(0.);
1524 coefZ.push_back(0.);
1531 std::vector<double> coefX(degree + 1),
1535 for(
int icoef = 0; icoef <= degree; icoef++) {
1579 double cacheSlope = 0.0;
1613 double velocity = 0.;
1615 for (
int icoef=1; icoef <=
p_degree; icoef++) {
1638 double diffTime = timeEt -
p_et;
1639 std::vector<double> extrapPos(3, 0.);
1657 throw IException(IException::Programmer,
1658 "Hermite coordinates only available for PolyFunctionOverHermiteConstant",
1667 return hermiteCoordinate;
1752 const QString &refFrame,
1753 const QString &abcorr,
1754 double state[6],
bool &hasVelocity,
1755 double &lightTime)
const {
1761 spkez_c((SpiceInt) target, (SpiceDouble) et, refFrame.toLatin1().data(),
1762 abcorr.toLatin1().data(), (SpiceInt) observer, state, &lightTime);
1767 SpiceBoolean spfailure = failed_c();
1770 hasVelocity =
false;
1772 spkezp_c((SpiceInt) target, (SpiceDouble) et, refFrame.toLatin1().data(),
1773 abcorr.toLatin1().data(), (SpiceInt) observer, state, &lightTime);
1804 const bool &hasVelocity) {
1810 if ( hasVelocity ) {
1824 if (m_swapObserverTarget) {
double Evaluate(const std::vector< double > &vars)
Compute the equation using the input variables.
int Coefficients() const
Returns the number of coefficients for the equation.
double Coefficient(int i) const
Returns the ith coefficient.
void SetCoefficients(const std::vector< double > &coefs)
Set the coefficients for the equation.
Generic least square fitting class.
int Solve(Isis::LeastSquares::SolveMethod method=SVD)
After all the data has been registered through AddKnown, invoke this method to solve the system of eq...
void AddKnown(const std::vector< double > &input, double expected, double weight=1.0)
Invoke this method for each set of knowns.
Utility class for creating and using cartesean line equations.
double Slope()
Compute the slope of the line.
double Intercept()
Compute the intercept of the line.
static void CheckErrors(bool resetNaif=true)
This method looks for any naif errors that might have occurred.
Nth degree Polynomial with one variable.
double DPolynomial(const int coeffIndex)
Evaluate the derivative of the fit polynomial (parabola) defined by the given coefficients with respe...
void Memcache2HermiteCache(double tolerance)
This method reduces the cache for position, time and velocity to the minimum number of values needed ...
void ComputeBaseTime()
Compute the base time using cached times.
Table LineCache(const QString &tableName)
Return a table with J2000 to reference positions.
double p_timeScale
Time scale used in fit equations.
std::vector< double > p_coordinate
J2000 position at time et.
double GetTimeBias() const
Returns the value of the time bias added to ET.
double ComputeVelocityInTime(PartialType var)
Compute the velocity with respect to time instead of scaled time.
Source p_source
Enumerated value for the location of the SPK information used.
std::vector< double > p_coefficients[3]
Coefficients of polynomials fit to 3 coordinates.
void SetOverrideBaseTime(double baseTime, double timeScale)
Set an override base time to be used with observations on scanners to allow all images in an observat...
virtual void SetEphemerisTimeSpice()
This is a protected method that is called by SetEphemerisTime() when Source type is Spice.
void GetPolynomial(std::vector< double > &XC, std::vector< double > &YC, std::vector< double > &ZC)
Return the coefficients of a polynomial fit to each of the three coordinates of the position for the ...
void setLightTime(const double &lightTime)
Inheritors can set the light time if indicated.
const std::vector< double > & Velocity()
Return the current J2000 velocity.
void ReloadCache()
Cache J2000 positions over existing cached time range using polynomials.
Source
This enum indicates the status of the object.
@ HermiteCache
Object is reading from splined table.
@ PolyFunction
Object is calculated from nth degree polynomial.
@ Memcache
Object is reading from cached table.
@ Spice
Object is reading directly from the kernels.
@ PolyFunctionOverHermiteConstant
Object is reading from splined.
ale::States * m_state
!< Light time correction
void LoadCache(double startTime, double endTime, int size)
Cache J2000 position over a time range.
double p_baseTime
Base time used in fit equations.
void SetEphemerisTimeMemcache()
This is a protected method that is called by SetEphemerisTime() when Source type is Memcache.
void LoadTimeCache()
Load the time cache.
int p_observerCode
observer body code
void SetPolynomial(const Source type=PolyFunction)
Set the coefficients of a polynomial fit to each of the components (X, Y, Z) of the position vector f...
Table LoadHermiteCache(const QString &tableName)
Cache J2000 position over existing cached time range using polynomials stored as Hermite cubic spline...
std::vector< double > Extrapolate(double timeEt)
Extrapolate position for a given time assuming a constant velocity.
void setStateVector(const double state[6], const bool &hasVelocity)
Sets the state of target relative to observer.
double m_lt
!< Swap traditional order
std::vector< double > p_cacheTime
iTime for corresponding position
std::vector< double > p_velocity
J2000 velocity at time et.
double p_overrideTimeScale
Value set by caller to override computed time scale.
bool p_degreeApplied
Flag indicating whether or not a polynomial.
bool p_hasVelocity
Flag to indicate velocity is available.
void ClearCache()
Removes the entire cache from memory.
double p_fullCacheEndTime
Original end time of the complete cache after spiceinit.
int getTargetCode() const
Returns target code.
double p_overrideBaseTime
Value set by caller to override computed base time.
const std::vector< double > & GetCenterCoordinate()
Compute and return the coordinate at the center time.
void CacheLabel(Table &table)
Add labels to a SpicePosition table.
double scaledTime() const
Return the scaled time.
int p_targetCode
target body code
double getAdjustedEphemerisTime() const
Returns adjusted ephemeris time.
std::vector< double > CoordinatePartial(SpicePosition::PartialType partialVar, int coeffIndex)
Set the coefficients of a polynomial fit to each of the three coordinates of the position vector for ...
void SetEphemerisTimeHermiteCache()
This is a protected method that is called by SetEphemerisTime() when Source type is HermiteCache.
virtual double EphemerisTime() const
Return the current ephemeris time.
void init(int targetCode, int observerCode, const bool &swapObserverTarget=false)
Internal initialization of the object support observer/target swap.
double p_et
Current ephemeris time.
void SetTimeBias(double timeBias)
Apply a time bias when invoking SetEphemerisTime method.
virtual ~SpicePosition()
Destructor.
double p_timeBias
iTime bias when reading kernels
void SetEphemerisTimePolyFunction()
This is a protected method that is called by SetEphemerisTime() when Source type is PolyFunction.
int getObserverCode() const
Returns observer code.
virtual const std::vector< double > & SetEphemerisTime(double et)
Return J2000 coordinate at given time.
SpicePosition(int targetCode, int observerCode)
Construct an empty SpicePosition class using valid body codes.
void SetEphemerisTimePolyFunctionOverHermiteConstant()
This is a protected method that is called by SetEphemerisTime() when Source type is PolyFunctionOverH...
double GetLightTime() const
Return the light time coorection value.
double p_fullCacheSize
Orignial size of the complete cache after spiceinit.
std::vector< double > HermiteCoordinate()
This method returns the Hermite coordinate for the current time for PolyFunctionOverHermiteConstant f...
OverrideType p_override
Time base and scale override options;.
int p_degree
Degree of polynomial function fit to the coordinates of the position.
double p_fullCacheStartTime
Original start time of the complete cache after spiceinit.
virtual const std::vector< double > & Coordinate()
Return the current J2000 position.
void computeStateVector(double et, int target, int observer, const QString &refFrame, const QString &abcorr, double state[6], bool &hasVelocity, double &lightTime) const
Computes the state vector of the target w.r.t observer.
QString p_aberrationCorrection
Light time correction to apply.
virtual void SetAberrationCorrection(const QString &correction)
Set the aberration correction (light time)
void SetPolynomialDegree(int degree)
Set the polynomial degree.
std::vector< double > VelocityPartial(SpicePosition::PartialType partialVar, int coeffIndex)
Compute the derivative of the velocity with respect to the specified variable.
Table Cache(const QString &tableName)
Return a table with J2000 positions.
virtual QString GetAberrationCorrection() const
Returns current state of stellar aberration correction.
This is free and unencumbered software released into the public domain.
QString toString(const LinearAlgebra::Vector &vector, int precision)
A global function to format LinearAlgebra::Vector as a QString with the given precision.