diff --git a/CMakeLists.txt b/CMakeLists.txt index f145a3954c20a75ae4eb6872e1cdc654615dbcbc..ef9f7c64303dfda8a36841001b15e55132d68e57 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -14,36 +14,48 @@ include(GNUInstallDirs) set(CMAKE_CXX_STANDARD 11) +set(ALE_BUILD_LOAD ON CACHE BOOL "If the C++ Python load interface should be built.") + # Third Party Dependencies find_package(Eigen3 3.3 REQUIRED NO_MODULE) find_package(nlohmann_json REQUIRED) -# If there is an Anaconda environment activated, search that for Python first -if(EXISTS $ENV{CONDA_PREFIX}) - message("Searching $ENV{CONDA_PREFIX} for Python libraries") - set(Python_ROOT_DIR $ENV{CONDA_PREFIX}) - set(Python_FIND_STRATEGY LOCATION) +if(ALE_BUILD_LOAD) + # If there is an Anaconda environment activated, search that for Python first + if(EXISTS $ENV{CONDA_PREFIX}) + message("Searching $ENV{CONDA_PREFIX} for Python libraries") + set(Python_ROOT_DIR $ENV{CONDA_PREFIX}) + set(Python_FIND_STRATEGY LOCATION) + endif() + find_package(Python REQUIRED COMPONENTS Development) endif() -find_package(Python REQUIRED COMPONENTS Development) # Library setup set(ALE_BUILD_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/include/") set(ALE_INSTALL_INCLUDE_DIR "include/ale") -add_library(ale SHARED - ${CMAKE_CURRENT_SOURCE_DIR}/src/ale.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/src/InterpUtils.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/src/Rotation.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/src/Orientations.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/src/States.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/src/Isd.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/src/Util.cpp) -set(ALE_HEADERS "${ALE_BUILD_INCLUDE_DIR}/ale.h" - "${ALE_BUILD_INCLUDE_DIR}/InterpUtils.h" - "${ALE_BUILD_INCLUDE_DIR}/Rotation.h" - "${ALE_BUILD_INCLUDE_DIR}/Orientations.h" - "${ALE_BUILD_INCLUDE_DIR}/States.h" - "${ALE_BUILD_INCLUDE_DIR}/Isd.h" - "${ALE_BUILD_INCLUDE_DIR}/Util.h") +set(ALE_SRC_FILES ${CMAKE_CURRENT_SOURCE_DIR}/src/InterpUtils.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/Rotation.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/Orientations.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/States.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/Isd.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/Util.cpp) +set(ALE_HEADER_FILES ${ALE_BUILD_INCLUDE_DIR}/InterpUtils.h + ${ALE_BUILD_INCLUDE_DIR}/Rotation.h + ${ALE_BUILD_INCLUDE_DIR}/Orientations.h + ${ALE_BUILD_INCLUDE_DIR}/States.h + ${ALE_BUILD_INCLUDE_DIR}/Isd.h + ${ALE_BUILD_INCLUDE_DIR}/Util.h) +set(ALE_PRIVATE_LINKS Eigen3::Eigen) +set(ALE_PUBLIC_LINKS nlohmann_json::nlohmann_json) + +if(ALE_BUILD_LOAD) + list(APPEND ALE_SRC_FILES ${CMAKE_CURRENT_SOURCE_DIR}/src/Load.cpp) + list(APPEND ALE_HEADER_FILES ${ALE_BUILD_INCLUDE_DIR}/Load.h) + list(APPEND ALE_PRIVATE_LINKS Python::Python) +endif() + +add_library(ale SHARED ${ALE_SRC_FILES}) + set_target_properties(ale PROPERTIES VERSION ${PROJECT_VERSION} SOVERSION 0) @@ -53,11 +65,8 @@ target_include_directories(ale $<BUILD_INTERFACE:${ALE_BUILD_INCLUDE_DIR}> $<INSTALL_INTERFACE:include>) -target_link_libraries(ale - PRIVATE - Eigen3::Eigen - Python::Python - nlohmann_json::nlohmann_json) +target_link_libraries(ale PRIVATE ${ALE_PRIVATE_LINKS} + PUBLIC ${ALE_PUBLIC_LINKS}) # Optional build tests option (ALE_BUILD_TESTS "Build tests" ON) @@ -89,7 +98,7 @@ install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-config.cmake DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}) # Install the headers -install(FILES ${ALE_HEADERS} DESTINATION ${ALE_INSTALL_INCLUDE_DIR}) +install(FILES ${ALE_HEADER_FILES} DESTINATION ${ALE_INSTALL_INCLUDE_DIR}) # Install the library install(TARGETS ale diff --git a/docs/config b/docs/config index 451ddca521ab483ad7a8e57d110cc68edec9f33a..372715057989a7c44574fbdf7c500ed19c7e28f0 100644 --- a/docs/config +++ b/docs/config @@ -791,7 +791,7 @@ WARN_LOGFILE = # spaces. See also FILE_PATTERNS and EXTENSION_MAPPING # Note: If this tag is empty the current directory is searched. -INPUT = ./include/ale.h ./ale ./src/ +INPUT = ./include/Load.h ./ale ./src/ # This tag can be used to specify the character encoding of the source files # that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses diff --git a/docs/source/library/capi/capi.rst b/docs/source/library/capi/capi.rst index 243294f78ed4275d5e06e8cf0c7a5d8cd26738c7..fb7b1bdacb73d86008c60b1ff27887ed587e88fd 100644 --- a/docs/source/library/capi/capi.rst +++ b/docs/source/library/capi/capi.rst @@ -3,7 +3,7 @@ The :mod:`src` module -.. doxygenfile:: ale.h +.. doxygenfile:: Load.h :project: ale .. versionadded:: 0.1.0 diff --git a/include/Isd.h b/include/Isd.h index e5e609ae6925666af713cc8574e8ba4255c97707..d4ce223db3c7219ca1f748f042865da0b8f6e512 100644 --- a/include/Isd.h +++ b/include/Isd.h @@ -15,8 +15,6 @@ namespace ale { - using json = nlohmann::json; - class Isd { public: @@ -26,7 +24,7 @@ namespace ale { std::string name_platform; std::string image_id; std::string name_sensor; - + double semi_major; double semi_minor; @@ -61,11 +59,11 @@ namespace ale { double starting_ephemeris_time; double center_ephemeris_time; - json naif_keywords; - + nlohmann::json naif_keywords; + PositionInterpolation interpMethod; - - Rotation const_rotation; + + Rotation const_rotation; States inst_pos; States sun_pos; diff --git a/include/Load.h b/include/Load.h new file mode 100644 index 0000000000000000000000000000000000000000..b9f0bbc7cc70a0c163e97516cf29c2db0a4b2e5e --- /dev/null +++ b/include/Load.h @@ -0,0 +1,39 @@ +#ifndef ALE_INCLUDE_ALE_H +#define ALE_INCLUDE_ALE_H + +#include <nlohmann/json.hpp> + +#include <string> + +namespace ale { + /** + * Load all of the metadata for an image into an ISD string. + * This method calls the Python driver structure in ALE to load all + * of the metadata for an image into an ISD string. See the Python + * loads method for how this is implemented on the Python side. + * + * @param filename The filename of the image to load metadata for + * @param props A JSON formatted properties string to pass to the Python drivers. + * Users can specify certain properties that the drivers will use. + * Currently kernels and nadir properties are allowed. See the + * data_naif driver mix-in for details. + * @param formatter A string specifying the format of the output ISD string. + * Currently supported formatters are isis, usgscsm, and ale. + * The isis and usgscsm formatters will be deprecated in the future. + * @param verbose A flag to output what the load function is attempting to do. + * If set to true, information about the drivers load attempts + * to use will be output to standard out. + * + * @returns A string containing a JSON formatted ISD for the image. + */ + std::string loads(std::string filename, std::string props="", std::string formatter="usgscsm", bool verbose=true); + + /** + * Load all of the metadata fro an image into a JSON ISD. + * This method is a convenience wrapper around the loads method that parses the + * string output of loads into a JSON object. + */ + nlohmann::json load(std::string filename, std::string props="", std::string formatter="usgscsm", bool verbose=true); +} + +#endif // ALE_H diff --git a/include/Util.h b/include/Util.h index 6d1d69b3279463397eb9d16c6cc7734cc53f5da6..7150a37b2dc7eee54e55c16179a37a3bf2cb71e1 100644 --- a/include/Util.h +++ b/include/Util.h @@ -11,10 +11,9 @@ #include "Vectors.h" namespace ale { - using json = nlohmann::json; template<typename T> - std::vector<T> getJsonArray(json obj) { + std::vector<T> getJsonArray(nlohmann::json obj) { std::vector<T> positions; try { for (auto &location : obj) { @@ -27,45 +26,45 @@ namespace ale { } - PositionInterpolation getInterpolationMethod(json isd); + PositionInterpolation getInterpolationMethod(nlohmann::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 getSensorModelName(nlohmann::json isd); + std::string getImageId(nlohmann::json isd); + std::string getSensorName(nlohmann::json isd); + std::string getPlatformName(nlohmann::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); - double getCenterTime(json isd); - std::vector<std::vector<double>> getLineScanRate(json isd); - int getSampleSumming(json isd); - int getLineSumming(json isd); - double getFocalLength(json isd); - double getFocalLengthUncertainty(json isd); - std::vector<double> getFocal2PixelLines(json isd); - std::vector<double> getFocal2PixelSamples(json isd); - double getDetectorCenterLine(json isd); - double getDetectorCenterSample(json isd); - double getDetectorStartingLine(json isd); - double getDetectorStartingSample(json isd); - double getMinHeight(json isd); - double getMaxHeight(json isd); - double getSemiMajorRadius(json isd); - double getSemiMinorRadius(json isd); - DistortionType getDistortionModel(json isd); - std::vector<double> getDistortionCoeffs(json isd); - - std::vector<double> getJsonDoubleArray(json obj); - std::vector<Vec3d> getJsonVec3dArray(json obj); - std::vector<Rotation> getJsonQuatArray(json obj); + std::string getIsisCameraVersion(nlohmann::json isd); + int getTotalLines(nlohmann::json isd); + int getTotalSamples(nlohmann::json isd); + double getStartingTime(nlohmann::json isd); + double getCenterTime(nlohmann::json isd); + std::vector<std::vector<double>> getLineScanRate(nlohmann::json isd); + int getSampleSumming(nlohmann::json isd); + int getLineSumming(nlohmann::json isd); + double getFocalLength(nlohmann::json isd); + double getFocalLengthUncertainty(nlohmann::json isd); + std::vector<double> getFocal2PixelLines(nlohmann::json isd); + std::vector<double> getFocal2PixelSamples(nlohmann::json isd); + double getDetectorCenterLine(nlohmann::json isd); + double getDetectorCenterSample(nlohmann::json isd); + double getDetectorStartingLine(nlohmann::json isd); + double getDetectorStartingSample(nlohmann::json isd); + double getMinHeight(nlohmann::json isd); + double getMaxHeight(nlohmann::json isd); + double getSemiMajorRadius(nlohmann::json isd); + double getSemiMinorRadius(nlohmann::json isd); + DistortionType getDistortionModel(nlohmann::json isd); + std::vector<double> getDistortionCoeffs(nlohmann::json isd); + + std::vector<double> getJsonDoubleArray(nlohmann::json obj); + std::vector<Vec3d> getJsonVec3dArray(nlohmann::json obj); + std::vector<Rotation> getJsonQuatArray(nlohmann::json obj); - States getInstrumentPosition(json isd); - States getSunPosition(json isd); + States getInstrumentPosition(nlohmann::json isd); + States getSunPosition(nlohmann::json isd); - Orientations getBodyRotation(json isd); - Orientations getInstrumentPointing(json isd); + Orientations getBodyRotation(nlohmann::json isd); + Orientations getInstrumentPointing(nlohmann::json isd); } #endif diff --git a/include/ale.h b/include/ale.h deleted file mode 100644 index a6469a3c986a9eb5dc9dca8fd9f662c07e6137c6..0000000000000000000000000000000000000000 --- a/include/ale.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef ALE_INCLUDE_ALE_H -#define ALE_INCLUDE_ALE_H - -#include <string> -#include <vector> - - -#include <nlohmann/json.hpp> - -namespace ale { - - 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); - - -} - -#endif // ALE_H diff --git a/src/InterpUtils.cpp b/src/InterpUtils.cpp index ae44954822a5ed8ad3c548cf9cc9d30f0b8ad62b..75fbe156f437dcf15f93bc61fe9535c95184b732 100644 --- a/src/InterpUtils.cpp +++ b/src/InterpUtils.cpp @@ -7,6 +7,7 @@ #include <unordered_set> namespace ale { + double linearInterpolate(double x, double y, double t) { return x + t * (y - x); } diff --git a/src/Isd.cpp b/src/Isd.cpp index 5f099b13ac86784f350df65ecf06597f92d8ebea..8cb674b849146ec3820378fb146d6022c2dd6edb 100644 --- a/src/Isd.cpp +++ b/src/Isd.cpp @@ -2,6 +2,8 @@ #include "Isd.h" #include "Util.h" +using json = nlohmann::json; + ale::Isd::Isd(std::string isd_file) { json isd = json::parse(isd_file); @@ -41,12 +43,12 @@ ale::Isd::Isd(std::string isd_file) { distortion_model = getDistortionModel(isd); distortion_coefficients = getDistortionCoeffs(isd); - - interpMethod = getInterpolationMethod(isd); - + + interpMethod = getInterpolationMethod(isd); + inst_pos = getInstrumentPosition(isd); sun_pos = getSunPosition(isd); - + inst_pointing = getInstrumentPointing(isd); - body_rotation = getBodyRotation(isd); + body_rotation = getBodyRotation(isd); } diff --git a/src/ale.cpp b/src/Load.cpp similarity index 88% rename from src/ale.cpp rename to src/Load.cpp index 1fab2d98b006b4ff5925708f626f9a6145de2eca..676dd6d351175790fac506bd08edb356895559ac 100644 --- a/src/ale.cpp +++ b/src/Load.cpp @@ -1,8 +1,7 @@ -#include "ale.h" +#include "Load.h" #include <nlohmann/json.hpp> -#include <iostream> #include <Python.h> #include <string> @@ -10,9 +9,9 @@ #include <stdexcept> using json = nlohmann::json; +using namespace std; namespace ale { - std::string getPyTraceback() { PyObject* err = PyErr_Occurred(); if (err != NULL) { @@ -33,7 +32,7 @@ namespace ale { Py_DECREF(module_name); if (pyth_module == NULL) { - throw std::runtime_error("getPyTraceback - Failed to import Python traceback Library"); + throw runtime_error("getPyTraceback - Failed to import Python traceback Library"); } pyth_func = PyObject_GetAttrString(pyth_module, "format_exception"); @@ -60,7 +59,6 @@ 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) { @@ -72,7 +70,7 @@ namespace ale { // Import the file as a Python module. PyObject *pModule = PyImport_Import(PyUnicode_FromString("ale")); if(!pModule) { - throw std::runtime_error("Failed to import ale. Make sure the ale python library is correctly installed."); + throw 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); @@ -82,7 +80,7 @@ namespace ale { if(!pFunc) { // import errors do not set a PyError flag, need to use a custom // error message instead. - throw std::runtime_error("Failed to import ale.loads function from Python." + throw 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."); } @@ -90,7 +88,7 @@ namespace ale { // Create a Python tuple to hold the arguments to the method. PyObject *pArgs = PyTuple_New(3); if(!pArgs) { - throw std::runtime_error(getPyTraceback()); + throw runtime_error(getPyTraceback()); } // Set the Python int as the first and second arguments to the method. @@ -107,14 +105,14 @@ namespace ale { PyObject* pResult = PyObject_CallObject(pFunc, pArgs); if(!pResult) { - throw std::invalid_argument("No Valid instrument found for label."); + throw 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 std::invalid_argument(getPyTraceback()); + throw invalid_argument(getPyTraceback()); } std::string cResult; char *temp_str = PyBytes_AS_STRING(temp_bytes); // Borrowed pointer diff --git a/src/Util.cpp b/src/Util.cpp index 0a042e4d33473d670d87f37be13e6f28cc7fc510..103ecee900916d82122cf44cabdbe6b312eddc77 100644 --- a/src/Util.cpp +++ b/src/Util.cpp @@ -4,6 +4,8 @@ #include "Util.h" +using json = nlohmann::json; + namespace ale { bool iequals(const std::string& a, const std::string& b) { @@ -122,20 +124,20 @@ 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")){ + 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; } @@ -488,16 +490,16 @@ States getInstrumentPosition(json isd) { try { json ipos = isd.at("instrument_position"); std::vector<Vec3d> positions = getJsonVec3dArray(ipos.at("positions")); - std::vector<double> times = getJsonArray<double>(ipos.at("ephemeris_times")); + 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); + 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 instrument position"); @@ -509,37 +511,37 @@ States getSunPosition(json isd) { try { json spos = isd.at("sun_position"); std::vector<Vec3d> positions = getJsonVec3dArray(spos.at("positions")); - std::vector<double> times = getJsonArray<double>(spos.at("ephemeris_times")); + 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); + 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 sun position"); } } -Orientations getInstrumentPointing(json isd) { +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<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>(); - + 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; + + std::vector<int> timeDepFrames; if (pointing.find("time_dependent_frames") != pointing.end()){ timeDepFrames = getJsonArray<int>(pointing.at("time_dependent_frames")); } @@ -547,34 +549,34 @@ Orientations getInstrumentPointing(json isd) { 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); - + 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) { +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<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; + + std::vector<int> timeDepFrames; if (bodrot.find("time_dependent_frames") != bodrot.end()){ timeDepFrames = getJsonArray<int>(bodrot.at("time_dependent_frames")); } @@ -582,16 +584,16 @@ Orientations getBodyRotation(json isd) { 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); + 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/tests/ctests/AleTest.cpp b/tests/ctests/AleTest.cpp deleted file mode 100644 index 2afe618d0729a1471ad970e643a5422185e2ce2e..0000000000000000000000000000000000000000 --- a/tests/ctests/AleTest.cpp +++ /dev/null @@ -1,253 +0,0 @@ -#include "gtest/gtest.h" - -#include "ale.h" -#include "Isd.h" - -#include <stdexcept> -#include <cmath> - -#include <Eigen/Core> -#include <Eigen/Geometry> - -using namespace std; - - -TEST(LinearInterpTest, ExampleInterpolation) { - vector<double> times = {0, 1, 2, 3}; - vector<double> data = {0, 2, 1, 0}; - - EXPECT_DOUBLE_EQ(0.0, ale::interpolate(data, times, 0.0, ale::LINEAR, 0)); - EXPECT_DOUBLE_EQ(1.0, ale::interpolate(data, times, 0.5, ale::LINEAR, 0)); - EXPECT_DOUBLE_EQ(2.0, ale::interpolate(data, times, 1.0, ale::LINEAR, 0)); - EXPECT_DOUBLE_EQ(1.5, ale::interpolate(data, times, 1.5, ale::LINEAR, 0)); - EXPECT_DOUBLE_EQ(1.0, ale::interpolate(data, times, 2.0, ale::LINEAR, 0)); - EXPECT_DOUBLE_EQ(0.5, ale::interpolate(data, times, 2.5, ale::LINEAR, 0)); - EXPECT_DOUBLE_EQ(0.0, ale::interpolate(data, times, 3.0, ale::LINEAR, 0)); -} - - -TEST(LinearInterpTest, NoPoints) { - vector<double> times = {}; - vector<double> data = {}; - - EXPECT_THROW(ale::interpolate(data, times, 0.0, ale::LINEAR, 0), invalid_argument); -} - - -TEST(LinearInterpTest, DifferentCounts) { - vector<double> times = { -3, -2, -1, 0, 2}; - vector<double> data = { -3, -2, 1, 2}; - - EXPECT_THROW(ale::interpolate(data, times, 0.0, ale::LINEAR, 0), invalid_argument); -} - - -TEST(LinearInterpTest, Extrapolate) { - vector<double> times = {0, 1, 2, 3}; - vector<double> data = {0, 2, 1, 0}; - - EXPECT_DOUBLE_EQ(ale::interpolate(data, times, -1.0, ale::LINEAR, 0), -2); - EXPECT_DOUBLE_EQ(ale::interpolate(data, times, 4.0, ale::LINEAR, 0), -1); -} - - -TEST(SplineInterpTest, ExampleInterpolation) { - // From http://www.maths.nuigalway.ie/~niall/teaching/Archive/1617/MA378/2-2-CubicSplines.pdf - vector<double> times = {0, 1, 2, 3}; - vector<double> data = {2, 4, 3, 2}; - // function is f(t) = 0.5t^3 - 3t^2 + 4.5t + 2 - - EXPECT_DOUBLE_EQ(ale::interpolate(data, times, 0.0, ale::SPLINE, 0), 2.0); - EXPECT_DOUBLE_EQ(ale::interpolate(data, times, 0.5, ale::SPLINE, 0), 3.0); - EXPECT_DOUBLE_EQ(ale::interpolate(data, times, 1.0, ale::SPLINE, 0), 4.0); - EXPECT_DOUBLE_EQ(ale::interpolate(data, times, 1.5, ale::SPLINE, 0), 3.6875); - EXPECT_DOUBLE_EQ(ale::interpolate(data, times, 2.0, ale::SPLINE, 0), 3.0); - EXPECT_DOUBLE_EQ(ale::interpolate(data, times, 2.5, ale::SPLINE, 0), 2.5); - EXPECT_DOUBLE_EQ(ale::interpolate(data, times, 3.0, ale::SPLINE, 0), 2.0); -} - - -TEST(SplineInterpTest, NoPoints) { - vector<double> times = {}; - vector<double> data = {}; - - EXPECT_THROW(ale::interpolate(data, times, 0.0, ale::SPLINE, 0), invalid_argument); -} - - -TEST(SplineInterpTest, DifferentCounts) { - vector<double> times = { -3, -2, -1, 0, 2}; - vector<double> data = { -3, -2, 1, 2}; - - EXPECT_THROW(ale::interpolate(data, times, 0.0, ale::SPLINE, 0), invalid_argument); -} - - -TEST(PyInterfaceTest, LoadInvalidLabel) { - std::string label = "Not a Real Label"; - EXPECT_THROW(ale::load(label), invalid_argument); -} - - -TEST(PyInterfaceTest, LoadValidLabel) { - std::string label = "../pytests/data/EN1072174528M/EN1072174528M_spiceinit.lbl"; - ale::load(label, "", "isis"); -} - - -TEST(Interpolation, Derivative1) { - vector<double> points = {0, 2, 4}; - vector<double> times = {0, 1, 2}; - EXPECT_NO_THROW(ale::interpolate(points, times, 1, ale::LINEAR, 1)); -} - - -TEST(Interpolation, Derivative2) { - vector<double> points = {0, 0, 0}; - vector<double> times = {0, 1, 2}; - EXPECT_THROW(ale::interpolate(points, times, 1, ale::LINEAR, 2), invalid_argument); -} - - -TEST(Interpolation, InvalidDerivative) { - vector<double> points = {0, 0, 0}; - vector<double> times = {0, 1, 2}; - - EXPECT_THROW(ale::interpolate(points, times, 1, ale::LINEAR, 3), invalid_argument); -} - - -TEST(InterpIndex, InvalidTimes) { - std::vector<double> times = {}; - - EXPECT_THROW(ale::interpolationIndex(times, 0), invalid_argument); -} - - -TEST(EvaluateCubicHermite, SimplePolynomial) { - // Cubic function is y = x^3 - 2x^2 + 1 - // derivative is dy/dx = 3x^2 - 4x - std::vector<double> derivs = {7.0, -1.0}; - std::vector<double> x = {-1.0, 1.0}; - std::vector<double> y = {-2.0, 0.0}; - - EXPECT_DOUBLE_EQ(ale::evaluateCubicHermite(0.0, derivs, x, y), 1.0); -} - -TEST(EvaluateCubicHermite, InvalidDervisXY) { - std::vector<double> derivs = {}; - std::vector<double> x = {1.0}; - std::vector<double> y = {1.0}; - - EXPECT_THROW(ale::evaluateCubicHermite(0.0, derivs, x, y), invalid_argument); -} - - -TEST(EvaluateCubicHermiteFirstDeriv, SimplyPolynomial) { - // Cubic function is y = x^3 - 2x^2 + 1 - // derivative is dy/dx = 3x^2 - 4x - std::vector<double> derivs = {7.0, -1.0}; - std::vector<double> x = {-1.0, 1.0}; - std::vector<double> y = {-2.0, 0.0}; - - EXPECT_DOUBLE_EQ(ale::evaluateCubicHermiteFirstDeriv(0.5, derivs, x, y), -1.25); -} - - -TEST(EvaluateCubicHermiteFirstDeriv, InvalidDervisTimes) { - std::vector<double> derivs = {}; - std::vector<double> times = {1.0}; - std::vector<double> y = {1.0}; - - EXPECT_THROW(ale::evaluateCubicHermiteFirstDeriv(0.0, derivs, times, y), invalid_argument); -} - - -TEST(EvaluateCubicHermiteFirstDeriv, InvalidVelocities) { - std::vector<double> derivs = {5.0, 6.0}; - std::vector<double> times = {1.0, 1.0}; - std::vector<double> y = {1.0}; - - EXPECT_THROW(ale::evaluateCubicHermiteFirstDeriv(0.0, derivs, times, y), invalid_argument); -} - -// The following tests all use the following equations -// -// v = -t^3 - 7x^2 + 3x + 16 -// -// The full set of values is: -// t v -// -3 -83 -// -2 -26 -// -1 5 -// 0 16 -// 1 13 -// 2 2 -// 3 -11 -// 4 -20 -// 5 -19 -// 6 -2 -// 7 37 - -TEST(LagrangeInterpolate, SecondOrder) { - std::vector<double> times = {-3, -2, -1, 0, 1, 3, 5}; - std::vector<double> values = {-83, -26, 5, 16, 13, -11, -19}; - - EXPECT_DOUBLE_EQ(ale::lagrangeInterpolate(times, values, 1.5, 2), 7); -} - - -TEST(LagrangeInterpolate, FourthOrder) { - std::vector<double> times = {-3, -2, -1, 0, 1, 3, 5}; - std::vector<double> values = {-83, -26, 5, 16, 13, -11, -19}; - - EXPECT_DOUBLE_EQ(ale::lagrangeInterpolate(times, values, 1.5, 4), 8.125); -} - - -TEST(LagrangeInterpolate, ReducedOrder) { - std::vector<double> times = {-3, -2, -1, 0, 1, 3, 5}; - std::vector<double> values = {-83, -26, 5, 16, 13, -11, -19}; - - EXPECT_DOUBLE_EQ(ale::lagrangeInterpolate(times, values, 3.5, 4), -13); - EXPECT_DOUBLE_EQ(ale::lagrangeInterpolate(times, values, -2.5, 4), -54.5); -} - - -TEST(LagrangeInterpolate, InvalidArguments) { - std::vector<double> times = {-3, -2, -1, 0, 1, 3, 5}; - std::vector<double> values = {-83, -26, 5, 16, 13}; - EXPECT_THROW(ale::lagrangeInterpolate(times, values, 3.5, 4), invalid_argument); -} - - -TEST(lagrangeInterpolateDerivative, SecondOrder) { - std::vector<double> times = {-3, -2, -1, 0, 1, 3, 5}; - std::vector<double> values = {-83, -26, 5, 16, 13, -11, -19}; - - EXPECT_DOUBLE_EQ(ale::lagrangeInterpolateDerivative(times, values, 1.5, 2), -12); -} - - -TEST(LagrangeInterpolateDerivative, FourthOrder) { - std::vector<double> times = {-3, -2, -1, 0, 1, 3, 5}; - std::vector<double> values = {-83, -26, 5, 16, 13, -11, -19}; - - EXPECT_DOUBLE_EQ(ale::lagrangeInterpolateDerivative(times, values, 1.5, 4), -11.25); -} - - -TEST(LagrangeInterpolateDerivative, ReducedOrder) { - std::vector<double> times = {-3, -2, -1, 0, 1, 3, 5}; - std::vector<double> values = {-83, -26, 5, 16, 13, -11, -19}; - - EXPECT_DOUBLE_EQ(ale::lagrangeInterpolateDerivative(times, values, 3.5, 4), -4); - EXPECT_DOUBLE_EQ(ale::lagrangeInterpolateDerivative(times, values, -2.5, 4), 57); -} - - -TEST(LagrangeInterpolateDerivative, InvalidArguments) { - std::vector<double> times = {-3, -2, -1, 0, 1, 3, 5}; - std::vector<double> values = {-83, -26, 5, 16, 13}; - EXPECT_THROW(ale::lagrangeInterpolateDerivative(times, values, 3.5, 4), invalid_argument); -} diff --git a/tests/ctests/CMakeLists.txt b/tests/ctests/CMakeLists.txt index 226f9292ea8e74766c3ec78054021d02dfa24fb3..cf4ab5253f6039794675d9d8ed5be31b3d485358 100644 --- a/tests/ctests/CMakeLists.txt +++ b/tests/ctests/CMakeLists.txt @@ -1,10 +1,19 @@ cmake_minimum_required(VERSION 3.10) # collect all of the test sources -file(GLOB test_source "${CMAKE_SOURCE_DIR}/tests/ctests/*.cpp") +set (ALE_TEST_SOURCE ${CMAKE_SOURCE_DIR}/tests/ctests/IsdTests.cpp + ${CMAKE_SOURCE_DIR}/tests/ctests/OrientationsTests.cpp + ${CMAKE_SOURCE_DIR}/tests/ctests/RotationTests.cpp + ${CMAKE_SOURCE_DIR}/tests/ctests/StatesTests.cpp + ${CMAKE_SOURCE_DIR}/tests/ctests/TestInterpUtils.cpp + ${CMAKE_SOURCE_DIR}/tests/ctests/TestMain.cpp) + +if(ALE_BUILD_LOAD) + list(APPEND ALE_TEST_SOURCE ${CMAKE_SOURCE_DIR}/tests/ctests/LoadTests.cpp) +endif() # setup test executable -add_executable(runAleTests ${test_source}) +add_executable(runAleTests ${ALE_TEST_SOURCE}) target_link_libraries(runAleTests PRIVATE ale diff --git a/tests/ctests/IsdTests.cpp b/tests/ctests/IsdTests.cpp index 1e5bc3b510a68215e34467429e487c6d8abfdb6f..242e97ddfae4d116505f54740fef71d9b74c2585 100644 --- a/tests/ctests/IsdTests.cpp +++ b/tests/ctests/IsdTests.cpp @@ -4,7 +4,6 @@ #include "gtest/gtest.h" -#include "ale.h" #include "Isd.h" #include "Util.h" #include "Vectors.h" @@ -34,8 +33,8 @@ TEST(Isd, Constructor) { 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"); @@ -73,13 +72,13 @@ TEST(Isd, Constructor) { } TEST(Isd, LogFile) { - ale::json j; + nlohmann::json j; j["log_file"] = "fake/path"; EXPECT_STREQ(ale::getLogFile(j).c_str(), "fake/path"); } TEST(Isd, TransverseDistortion) { - ale::json trans; + nlohmann::json trans; trans["optical_distortion"]["transverse"]["x"] = {1}; trans["optical_distortion"]["transverse"]["y"] = {2}; @@ -91,7 +90,7 @@ TEST(Isd, TransverseDistortion) { } TEST(Isd, RadialDistortion) { - ale::json radial; + nlohmann::json radial; radial["optical_distortion"]["radial"]["coefficients"] = {1, 2}; std::vector<double> coeffs = ale::getDistortionCoeffs(radial); @@ -102,7 +101,7 @@ TEST(Isd, RadialDistortion) { } TEST(Isd, KaguyaLISMDistortion) { - ale::json kaguya; + nlohmann::json kaguya; kaguya["optical_distortion"]["kaguyalism"]["x"] = {1}; kaguya["optical_distortion"]["kaguyalism"]["y"] = {2}; kaguya["optical_distortion"]["kaguyalism"]["boresight_x"] = 3; @@ -118,7 +117,7 @@ TEST(Isd, KaguyaLISMDistortion) { } TEST(Isd, DawnFCDistortion) { - ale::json dawn; + nlohmann::json dawn; dawn["optical_distortion"]["dawnfc"]["coefficients"] = {1, 2}; std::vector<double> coeffs = ale::getDistortionCoeffs(dawn); EXPECT_EQ(ale::getDistortionModel(dawn), ale::DistortionType::DAWNFC); @@ -128,7 +127,7 @@ TEST(Isd, DawnFCDistortion) { } TEST(Isd, LroLrocNACDistortion) { - ale::json lro; + nlohmann::json lro; lro["optical_distortion"]["lrolrocnac"]["coefficients"] = {1, 2}; std::vector<double> coeffs = ale::getDistortionCoeffs(lro); EXPECT_EQ(ale::getDistortionModel(lro), ale::DistortionType::LROLROCNAC); @@ -138,19 +137,19 @@ TEST(Isd, LroLrocNACDistortion) { } TEST(Isd, UnrecognizedDistortion) { - ale::json j; + nlohmann::json j; j["optical_distortion"]["foo"]["x"] = {1}; EXPECT_EQ(ale::getDistortionModel(j), ale::DistortionType::TRANSVERSE); } TEST(Isd, BadLogFile) { - ale::json j; + nlohmann::json j; EXPECT_THROW(ale::getLogFile(j), std::runtime_error); } TEST(Isd, GetSunPositions) { - ale::json jsunpos = { + nlohmann::json jsunpos = { {"sun_position",{ {"ephemeris_times", {300}}, {"positions", {{10, 12, 13}}}, @@ -164,7 +163,7 @@ TEST(Isd, GetSunPositions) { 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); @@ -174,17 +173,17 @@ TEST(Isd, GetSunPositions) { 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; + nlohmann::json j; try { ale::getSunPosition(j); FAIL() << "Expected an exception to be thrown"; @@ -198,7 +197,7 @@ TEST(Isd, NoSunPositions) { } TEST(Isd, GetInstrumentPositions) { - ale::json jinstpos = { + nlohmann::json jinstpos = { {"instrument_position",{ {"ephemeris_times", {300, 400}}, {"positions", {{10, 11, 12}, {11, 12,13}}}, @@ -208,13 +207,13 @@ TEST(Isd, GetInstrumentPositions) { 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); @@ -222,16 +221,16 @@ TEST(Isd, GetInstrumentPositions) { 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); @@ -243,7 +242,7 @@ TEST(Isd, GetInstrumentPositions) { } TEST(Isd, NoSensorPositions) { - ale::json j; + nlohmann::json j; try { ale::getInstrumentPosition(j); FAIL() << "Expected an exception to be thrown"; @@ -257,7 +256,7 @@ TEST(Isd, NoSensorPositions) { } TEST(Isd, GetInstrumentPointing) { - ale::json pointing = { + nlohmann::json pointing = { {"instrument_pointing",{ {"ephemeris_times", {300, 600}}, {"quaternions", {{1,2,3,4}, {4,3,2,1}}}, @@ -271,8 +270,8 @@ TEST(Isd, GetInstrumentPointing) { 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(); + std::vector<int> constFrames = instPointing.getConstantFrames(); + std::vector<int> timeDepFrames = instPointing.getTimeDependentFrames(); ASSERT_EQ(rotations.size(), 2); ASSERT_EQ(instPointing.getReferenceFrame(), 2); @@ -291,20 +290,20 @@ TEST(Isd, GetInstrumentPointing) { 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[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); @@ -314,7 +313,7 @@ TEST(Isd, GetInstrumentPointing) { TEST(Isd, NoSensorOrientations) { - ale::json j; + nlohmann::json j; try { ale::getInstrumentPointing(j); FAIL() << "Expected an exception to be thrown"; @@ -328,7 +327,7 @@ TEST(Isd, NoSensorOrientations) { } TEST(Isd, GetBodyRotation) { - ale::json br = { + nlohmann::json br = { {"body_rotation",{ {"ephemeris_times", {300, 600}}, {"quaternions", {{1,2,3,4}, {4,3,2,1}}}, @@ -342,8 +341,8 @@ TEST(Isd, GetBodyRotation) { 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(); + std::vector<int> constFrames = bodyRot.getConstantFrames(); + std::vector<int> timeDepFrames = bodyRot.getTimeDependentFrames(); ASSERT_EQ(rotations.size(), 2); ASSERT_EQ(bodyRot.getReferenceFrame(), 2); @@ -362,20 +361,20 @@ TEST(Isd, GetBodyRotation) { 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[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); @@ -627,7 +626,7 @@ TEST(Isd, BadDistortionModel) { } TEST(Isd, BadDistortionTransverse) { - ale::json bad_json; + nlohmann::json bad_json; bad_json["optical_distortion"]["transverse"]["x"] = {"NaN"}; bad_json["optical_distortion"]["transverse"]["y"] = {"NaN"}; @@ -645,7 +644,7 @@ TEST(Isd, BadDistortionTransverse) { } TEST(Isd, BadDistortionRadial) { - ale::json bad_json; + nlohmann::json bad_json; bad_json["optical_distortion"]["radial"]["coefficients"] = {"NaN"}; try { @@ -662,7 +661,7 @@ TEST(Isd, BadDistortionRadial) { } TEST(Isd, BadDistortionDawnFC) { - ale::json bad_json; + nlohmann::json bad_json; bad_json["optical_distortion"]["dawnfc"]["coefficients"] = {"NaN"}; try { @@ -679,7 +678,7 @@ TEST(Isd, BadDistortionDawnFC) { } TEST(Isd, BadDistortionKaguyaLISM) { - ale::json bad_json; + nlohmann::json bad_json; bad_json["optical_distortion"]["kaguyalism"]["x"] = {"NaN"}; bad_json["optical_distortion"]["kaguyalism"]["y"] = {"NaN"}; try { @@ -696,7 +695,7 @@ TEST(Isd, BadDistortionKaguyaLISM) { } TEST(Isd, BadDistortionLroLrocNac) { - ale::json bad_json; + nlohmann::json bad_json; bad_json["optical_distortion"]["lrolrocnac"]["coefficients"] = {"NaN"}; try { ale::getDistortionCoeffs(bad_json); diff --git a/tests/ctests/LoadTests.cpp b/tests/ctests/LoadTests.cpp new file mode 100644 index 0000000000000000000000000000000000000000..78c4383ef69c5a69e3f33d5d1b3395357afd13c9 --- /dev/null +++ b/tests/ctests/LoadTests.cpp @@ -0,0 +1,18 @@ +#include "gtest/gtest.h" + +#include "Load.h" + +#include <stdexcept> + +using namespace std; + +TEST(PyInterfaceTest, LoadInvalidLabel) { + std::string label = "Not a Real Label"; + EXPECT_THROW(ale::load(label), invalid_argument); +} + + +TEST(PyInterfaceTest, LoadValidLabel) { + std::string label = "../pytests/data/EN1072174528M/EN1072174528M_spiceinit.lbl"; + ale::load(label, "", "isis"); +} diff --git a/tests/ctests/OrientationsTest.cpp b/tests/ctests/OrientationsTests.cpp similarity index 100% rename from tests/ctests/OrientationsTest.cpp rename to tests/ctests/OrientationsTests.cpp diff --git a/tests/ctests/RotationTest.cpp b/tests/ctests/RotationTests.cpp similarity index 100% rename from tests/ctests/RotationTest.cpp rename to tests/ctests/RotationTests.cpp diff --git a/tests/ctests/StatesTest.cpp b/tests/ctests/StatesTests.cpp similarity index 100% rename from tests/ctests/StatesTest.cpp rename to tests/ctests/StatesTests.cpp diff --git a/tests/ctests/TestInterpUtils.cpp b/tests/ctests/TestInterpUtils.cpp index 6dc2e996d19be95c9c595c40245cd958ee8d1f9f..c1f84530587324c19698bb86a2eac28464e4cb5b 100644 --- a/tests/ctests/TestInterpUtils.cpp +++ b/tests/ctests/TestInterpUtils.cpp @@ -8,6 +8,214 @@ using namespace std; using namespace ale; + +TEST(Interpolation, Derivative1) { + vector<double> points = {0, 2, 4}; + vector<double> times = {0, 1, 2}; + EXPECT_NO_THROW(ale::interpolate(points, times, 1, ale::LINEAR, 1)); +} + +TEST(Interpolation, Derivative2) { + vector<double> points = {0, 0, 0}; + vector<double> times = {0, 1, 2}; + EXPECT_THROW(ale::interpolate(points, times, 1, ale::LINEAR, 2), invalid_argument); +} + +TEST(Interpolation, InvalidDerivative) { + vector<double> points = {0, 0, 0}; + vector<double> times = {0, 1, 2}; + + EXPECT_THROW(ale::interpolate(points, times, 1, ale::LINEAR, 3), invalid_argument); +} + +TEST(InterpIndex, InvalidTimes) { + std::vector<double> times = {}; + + EXPECT_THROW(ale::interpolationIndex(times, 0), invalid_argument); +} + +TEST(EvaluateCubicHermite, SimplePolynomial) { + // Cubic function is y = x^3 - 2x^2 + 1 + // derivative is dy/dx = 3x^2 - 4x + std::vector<double> derivs = {7.0, -1.0}; + std::vector<double> x = {-1.0, 1.0}; + std::vector<double> y = {-2.0, 0.0}; + + EXPECT_DOUBLE_EQ(ale::evaluateCubicHermite(0.0, derivs, x, y), 1.0); +} + +TEST(EvaluateCubicHermite, InvalidDervisXY) { + std::vector<double> derivs = {}; + std::vector<double> x = {1.0}; + std::vector<double> y = {1.0}; + + EXPECT_THROW(ale::evaluateCubicHermite(0.0, derivs, x, y), invalid_argument); +} + +TEST(EvaluateCubicHermiteFirstDeriv, SimplyPolynomial) { + // Cubic function is y = x^3 - 2x^2 + 1 + // derivative is dy/dx = 3x^2 - 4x + std::vector<double> derivs = {7.0, -1.0}; + std::vector<double> x = {-1.0, 1.0}; + std::vector<double> y = {-2.0, 0.0}; + + EXPECT_DOUBLE_EQ(ale::evaluateCubicHermiteFirstDeriv(0.5, derivs, x, y), -1.25); +} + +TEST(EvaluateCubicHermiteFirstDeriv, InvalidDervisTimes) { + std::vector<double> derivs = {}; + std::vector<double> times = {1.0}; + std::vector<double> y = {1.0}; + + EXPECT_THROW(ale::evaluateCubicHermiteFirstDeriv(0.0, derivs, times, y), invalid_argument); +} + +TEST(EvaluateCubicHermiteFirstDeriv, InvalidVelocities) { + std::vector<double> derivs = {5.0, 6.0}; + std::vector<double> times = {1.0, 1.0}; + std::vector<double> y = {1.0}; + + EXPECT_THROW(ale::evaluateCubicHermiteFirstDeriv(0.0, derivs, times, y), invalid_argument); +} + +// The following tests all use the following equations +// +// v = -t^3 - 7x^2 + 3x + 16 +// +// The full set of values is: +// t v +// -3 -83 +// -2 -26 +// -1 5 +// 0 16 +// 1 13 +// 2 2 +// 3 -11 +// 4 -20 +// 5 -19 +// 6 -2 +// 7 37 + +TEST(LagrangeInterpolate, SecondOrder) { + std::vector<double> times = {-3, -2, -1, 0, 1, 3, 5}; + std::vector<double> values = {-83, -26, 5, 16, 13, -11, -19}; + + EXPECT_DOUBLE_EQ(ale::lagrangeInterpolate(times, values, 1.5, 2), 7); +} + +TEST(LagrangeInterpolate, FourthOrder) { + std::vector<double> times = {-3, -2, -1, 0, 1, 3, 5}; + std::vector<double> values = {-83, -26, 5, 16, 13, -11, -19}; + + EXPECT_DOUBLE_EQ(ale::lagrangeInterpolate(times, values, 1.5, 4), 8.125); +} + +TEST(LagrangeInterpolate, ReducedOrder) { + std::vector<double> times = {-3, -2, -1, 0, 1, 3, 5}; + std::vector<double> values = {-83, -26, 5, 16, 13, -11, -19}; + + EXPECT_DOUBLE_EQ(ale::lagrangeInterpolate(times, values, 3.5, 4), -13); + EXPECT_DOUBLE_EQ(ale::lagrangeInterpolate(times, values, -2.5, 4), -54.5); +} + +TEST(LagrangeInterpolate, InvalidArguments) { + std::vector<double> times = {-3, -2, -1, 0, 1, 3, 5}; + std::vector<double> values = {-83, -26, 5, 16, 13}; + EXPECT_THROW(ale::lagrangeInterpolate(times, values, 3.5, 4), invalid_argument); +} + +TEST(lagrangeInterpolateDerivative, SecondOrder) { + std::vector<double> times = {-3, -2, -1, 0, 1, 3, 5}; + std::vector<double> values = {-83, -26, 5, 16, 13, -11, -19}; + + EXPECT_DOUBLE_EQ(ale::lagrangeInterpolateDerivative(times, values, 1.5, 2), -12); +} + +TEST(LagrangeInterpolateDerivative, FourthOrder) { + std::vector<double> times = {-3, -2, -1, 0, 1, 3, 5}; + std::vector<double> values = {-83, -26, 5, 16, 13, -11, -19}; + + EXPECT_DOUBLE_EQ(ale::lagrangeInterpolateDerivative(times, values, 1.5, 4), -11.25); +} + +TEST(LagrangeInterpolateDerivative, ReducedOrder) { + std::vector<double> times = {-3, -2, -1, 0, 1, 3, 5}; + std::vector<double> values = {-83, -26, 5, 16, 13, -11, -19}; + + EXPECT_DOUBLE_EQ(ale::lagrangeInterpolateDerivative(times, values, 3.5, 4), -4); + EXPECT_DOUBLE_EQ(ale::lagrangeInterpolateDerivative(times, values, -2.5, 4), 57); +} + +TEST(LagrangeInterpolateDerivative, InvalidArguments) { + std::vector<double> times = {-3, -2, -1, 0, 1, 3, 5}; + std::vector<double> values = {-83, -26, 5, 16, 13}; + EXPECT_THROW(ale::lagrangeInterpolateDerivative(times, values, 3.5, 4), invalid_argument); +} + +TEST(LinearInterpTest, ExampleInterpolation) { + vector<double> times = {0, 1, 2, 3}; + vector<double> data = {0, 2, 1, 0}; + + EXPECT_DOUBLE_EQ(0.0, ale::interpolate(data, times, 0.0, ale::LINEAR, 0)); + EXPECT_DOUBLE_EQ(1.0, ale::interpolate(data, times, 0.5, ale::LINEAR, 0)); + EXPECT_DOUBLE_EQ(2.0, ale::interpolate(data, times, 1.0, ale::LINEAR, 0)); + EXPECT_DOUBLE_EQ(1.5, ale::interpolate(data, times, 1.5, ale::LINEAR, 0)); + EXPECT_DOUBLE_EQ(1.0, ale::interpolate(data, times, 2.0, ale::LINEAR, 0)); + EXPECT_DOUBLE_EQ(0.5, ale::interpolate(data, times, 2.5, ale::LINEAR, 0)); + EXPECT_DOUBLE_EQ(0.0, ale::interpolate(data, times, 3.0, ale::LINEAR, 0)); +} + +TEST(LinearInterpTest, NoPoints) { + vector<double> times = {}; + vector<double> data = {}; + + EXPECT_THROW(ale::interpolate(data, times, 0.0, ale::LINEAR, 0), invalid_argument); +} + +TEST(LinearInterpTest, DifferentCounts) { + vector<double> times = { -3, -2, -1, 0, 2}; + vector<double> data = { -3, -2, 1, 2}; + + EXPECT_THROW(ale::interpolate(data, times, 0.0, ale::LINEAR, 0), invalid_argument); +} + +TEST(LinearInterpTest, Extrapolate) { + vector<double> times = {0, 1, 2, 3}; + vector<double> data = {0, 2, 1, 0}; + + EXPECT_DOUBLE_EQ(ale::interpolate(data, times, -1.0, ale::LINEAR, 0), -2); + EXPECT_DOUBLE_EQ(ale::interpolate(data, times, 4.0, ale::LINEAR, 0), -1); +} + +TEST(SplineInterpTest, ExampleInterpolation) { + // From http://www.maths.nuigalway.ie/~niall/teaching/Archive/1617/MA378/2-2-CubicSplines.pdf + vector<double> times = {0, 1, 2, 3}; + vector<double> data = {2, 4, 3, 2}; + // function is f(t) = 0.5t^3 - 3t^2 + 4.5t + 2 + + EXPECT_DOUBLE_EQ(ale::interpolate(data, times, 0.0, ale::SPLINE, 0), 2.0); + EXPECT_DOUBLE_EQ(ale::interpolate(data, times, 0.5, ale::SPLINE, 0), 3.0); + EXPECT_DOUBLE_EQ(ale::interpolate(data, times, 1.0, ale::SPLINE, 0), 4.0); + EXPECT_DOUBLE_EQ(ale::interpolate(data, times, 1.5, ale::SPLINE, 0), 3.6875); + EXPECT_DOUBLE_EQ(ale::interpolate(data, times, 2.0, ale::SPLINE, 0), 3.0); + EXPECT_DOUBLE_EQ(ale::interpolate(data, times, 2.5, ale::SPLINE, 0), 2.5); + EXPECT_DOUBLE_EQ(ale::interpolate(data, times, 3.0, ale::SPLINE, 0), 2.0); +} + +TEST(SplineInterpTest, NoPoints) { + vector<double> times = {}; + vector<double> data = {}; + + EXPECT_THROW(ale::interpolate(data, times, 0.0, ale::SPLINE, 0), invalid_argument); +} + +TEST(SplineInterpTest, DifferentCounts) { + vector<double> times = { -3, -2, -1, 0, 2}; + vector<double> data = { -3, -2, 1, 2}; + + EXPECT_THROW(ale::interpolate(data, times, 0.0, ale::SPLINE, 0), invalid_argument); +} + TEST(InterpUtilsTest, LinearInterpolate) { EXPECT_EQ(linearInterpolate(1, 3, 0.5), 2); EXPECT_EQ(linearInterpolate(1, 1, 0.5), 1);