diff --git a/.travis.yml b/.travis.yml index c0a3508a18e0c272bbe356d3c9a963f2f401e274..c45f09e3cbeebab22f3fff825cead621ca5252a5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -33,12 +33,12 @@ install: # Install a supported cmake version (>= 3.10) - | if [ "$TRAVIS_OS_NAME" == "linux" ]; then - wget https://repo.continuum.io/miniconda/Miniconda3-latest-Linux-x86_64.sh -O miniconda.sh; + wget https://repo.anaconda.com/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" + - source $HOME/miniconda/etc/profile.d/conda.sh - conda install -y -c conda-forge cmake script: @@ -50,7 +50,7 @@ script: - cd .. after_success: - - conda install -y -q conda-build anaconda-client + - conda install -y -q conda-build anaconda-client # Pull the libcsm for the build from our anaconda channel - conda config --add channels usgs-astrogeology - conda config --set anaconda_upload no diff --git a/CMakeLists.txt b/CMakeLists.txt index 68be97371eecb2a0f5a82e82774f13b4d1e0ad59..98a82aef9b3af518408d63416f3a6f2a995222f8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -25,6 +25,7 @@ add_library(usgscsm SHARED src/UsgsAstroPlugin.cpp src/UsgsAstroFrameSensorModel.cpp src/UsgsAstroLsSensorModel.cpp + src/UsgsAstroSarSensorModel.cpp src/Distortion.cpp src/Utilities.cpp) diff --git a/include/usgscsm/UsgsAstroSarSensorModel.h b/include/usgscsm/UsgsAstroSarSensorModel.h index 384c9fa0fe61ea3da8d48de1dabcdb6fa45f8049..021203a259d9c3f6c50e8121960dbb37bc9f7296 100644 --- a/include/usgscsm/UsgsAstroSarSensorModel.h +++ b/include/usgscsm/UsgsAstroSarSensorModel.h @@ -17,7 +17,7 @@ class UsgsAstroSarSensorModel : public csm::RasterGM, virtual public csm::Settab virtual std::string getModelState() const; - std::string constructStateFromIsd(const std::string imageSupportData, csm::WarningList *list) const; + static std::string constructStateFromIsd(const std::string imageSupportData, csm::WarningList *list); static std::string getModelNameFromModelState(const std::string& model_state); @@ -194,7 +194,6 @@ class UsgsAstroSarSensorModel : public csm::RasterGM, virtual public csm::Settab //////////////////////////// static const std::string _SENSOR_MODEL_NAME; - static const std::string _STATE_KEYWORD[]; static const int NUM_PARAM_TYPES; static const std::string PARAM_STRING_ALL[]; static const csm::param::Type PARAM_CHAR_ALL[]; diff --git a/include/usgscsm/Utilities.h b/include/usgscsm/Utilities.h index 0f329449a3e467d47fe8350accb703ec50bc5c50..d7d89eec99e4384459cd4bd3365b0c4dd9ec67b8 100644 --- a/include/usgscsm/Utilities.h +++ b/include/usgscsm/Utilities.h @@ -92,6 +92,9 @@ double getCenterTime(nlohmann::json isd, csm::WarningList *list=nullptr); std::vector<double> getIntegrationStartLines(nlohmann::json isd, csm::WarningList *list=nullptr); std::vector<double> getIntegrationStartTimes(nlohmann::json isd, csm::WarningList *list=nullptr); std::vector<double> getIntegrationTimes(nlohmann::json isd, csm::WarningList *list=nullptr); +double getExposureDuration(nlohmann::json isd, csm::WarningList *list=nullptr); +double getScaledPixelWidth(nlohmann::json isd, csm::WarningList *list=nullptr); +std::vector<double> getScaleConversionCoefficients(nlohmann::json isd, csm::WarningList *list=nullptr); int getSampleSumming(nlohmann::json isd, csm::WarningList *list=nullptr); int getLineSumming(nlohmann::json isd, csm::WarningList *list=nullptr); double getFocalLength(nlohmann::json isd, csm::WarningList *list=nullptr); diff --git a/src/UsgsAstroSarSensorModel.cpp b/src/UsgsAstroSarSensorModel.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b3716f5fe1b0e6b4f35e55eeb38438c367ddff06 --- /dev/null +++ b/src/UsgsAstroSarSensorModel.cpp @@ -0,0 +1,138 @@ +#include "UsgsAstroSarSensorModel.h" +#include "Utilities.h" + +#include <string.h> + +#include <json/json.hpp> + +using json = nlohmann::json; +using namespace std; + +const string UsgsAstroSarSensorModel::_SENSOR_MODEL_NAME = "USGS_ASTRO_SAR_SENSOR_MODEL"; +const int UsgsAstroSarSensorModel::NUM_PARAMETERS = 6; +const string UsgsAstroSarSensorModel::PARAMETER_NAME[] = +{ + "IT Pos. Bias ", // 0 + "CT Pos. Bias ", // 1 + "Rad Pos. Bias ", // 2 + "X Vel. Bias ", // 3 + "Y Vel. Bias ", // 4 + "Z Vel. Bias " // 5 +}; + +const int UsgsAstroSarSensorModel::NUM_PARAM_TYPES = 4; +const string UsgsAstroSarSensorModel::PARAM_STRING_ALL[] = +{ + "NONE", + "FICTITIOUS", + "REAL", + "FIXED" +}; +const csm::param::Type + UsgsAstroSarSensorModel::PARAM_CHAR_ALL[] = +{ + csm::param::NONE, + csm::param::FICTITIOUS, + csm::param::REAL, + csm::param::FIXED +}; + +string UsgsAstroSarSensorModel::constructStateFromIsd( + const string imageSupportData, + csm::WarningList *warnings +) { + json isd = json::parse(imageSupportData); + json state = {}; + + csm::WarningList* parsingWarnings = new csm::WarningList; + + int num_params = NUM_PARAMETERS; + + state["m_modelName"] = getSensorModelName(isd, parsingWarnings); + state["m_imageIdentifier"] = getImageId(isd, parsingWarnings); + state["m_sensorName"] = getSensorName(isd, parsingWarnings); + state["m_platformName"] = getPlatformName(isd, parsingWarnings); + + state["m_nLines"] = getTotalLines(isd, parsingWarnings); + state["m_nSamples"] = getTotalSamples(isd, parsingWarnings); + + // Zero computed state values + state["m_referencePointXyz"] = std::vector<double>(3, 0.0); + + // sun_position and velocity are required for getIlluminationDirection + state["m_sunPosition"]= getSunPositions(isd, parsingWarnings); + state["m_sunVelocity"]= getSunVelocities(isd, parsingWarnings); + + state["m_centerEphemerisTime"] = getCenterTime(isd, parsingWarnings); + state["m_startingEphemerisTime"] = getStartingTime(isd, parsingWarnings); + + state["m_exposureDuration"] = getExposureDuration(isd, parsingWarnings); + + try { + state["m_dtEphem"] = isd.at("dt_ephemeris"); + } + catch(...) { + parsingWarnings->push_back( + csm::Warning( + csm::Warning::DATA_NOT_AVAILABLE, + "dt_ephemeris not in ISD", + "UsgsAstroSarSensorModel::constructStateFromIsd()")); + } + + try { + state["m_t0Ephem"] = isd.at("t0_ephemeris"); + } + catch(...) { + parsingWarnings->push_back( + csm::Warning( + csm::Warning::DATA_NOT_AVAILABLE, + "t0_ephemeris not in ISD", + "UsgsAstroSarSensorModel::constructStateFromIsd()")); + } + + state["m_positions"] = getSensorPositions(isd, parsingWarnings); + state["m_velocities"] = getSensorVelocities(isd, parsingWarnings); + + state["m_currentParameterValue"] = std::vector<double>(NUM_PARAMETERS, 0.0); + + // get radii + state["m_minorAxis"] = getSemiMinorRadius(isd, parsingWarnings); + state["m_majorAxis"] = getSemiMajorRadius(isd, parsingWarnings); + + // set identifiers + state["m_platformIdentifier"] = getPlatformName(isd, parsingWarnings); + state["m_sensorIdentifier"] = getSensorName(isd, parsingWarnings); + + // get reference_height + state["m_minElevation"] = -1000; + state["m_maxElevation"] = 1000; + + // SAR specific values + state["m_scaledPixelWidth"] = getScaledPixelWidth(isd, parsingWarnings); + state["m_scaleConversionCoefficients"] = getScaleConversionCoefficients(isd, parsingWarnings); + + // Default to identity covariance + state["m_covariance"] = + std::vector<double>(NUM_PARAMETERS * NUM_PARAMETERS, 0.0); + for (int i = 0; i < NUM_PARAMETERS; i++) { + state["m_covariance"][i * NUM_PARAMETERS + i] = 1.0; + } + + if (!parsingWarnings->empty()) { + if (warnings) { + warnings->insert(warnings->end(), parsingWarnings->begin(), parsingWarnings->end()); + } + delete parsingWarnings; + parsingWarnings = nullptr; + throw csm::Error(csm::Error::SENSOR_MODEL_NOT_CONSTRUCTIBLE, + "ISD is invalid for creating the sensor model.", + "UsgsAstroSarSensorModel::constructStateFromIsd"); + } + + delete parsingWarnings; + parsingWarnings = nullptr; + + // The state data will still be updated when a sensor model is created since + // some state data is not in the ISD and requires a SM to compute them. + return state.dump(); +} diff --git a/src/Utilities.cpp b/src/Utilities.cpp index cf2f4047b38c2cfc4ea76af72ac8fc6fa559e5f3..29963774c84f5329874345204425b706288525e1 100644 --- a/src/Utilities.cpp +++ b/src/Utilities.cpp @@ -1103,3 +1103,54 @@ std::vector<double> getSensorOrientations(json isd, csm::WarningList *list) { } return quaternions; } + +double getExposureDuration(nlohmann::json isd, csm::WarningList *list) { + double duration; + try { + duration = isd.at("line_exposure_duration"); + } + catch (...) { + if (list) { + list->push_back( + csm::Warning( + csm::Warning::DATA_NOT_AVAILABLE, + "Could not parse the line exposure duration.", + "Utilities::getExposureDuration()")); + } + } + return duration; +} + +double getScaledPixelWidth(nlohmann::json isd, csm::WarningList *list) { + double width; + try { + width = isd.at("scaled_pixel_width"); + } + catch (...) { + if (list) { + list->push_back( + csm::Warning( + csm::Warning::DATA_NOT_AVAILABLE, + "Could not parse the scaled pixel width.", + "Utilities::getScaledPixelWidth()")); + } + } + return width; +} + +std::vector<double> getScaleConversionCoefficients(nlohmann::json isd, csm::WarningList *list) { + std::vector<double> coefficients; + try { + coefficients = isd.at("range_conversion_coefficients").get<std::vector<double>>(); + } + catch (...) { + if (list) { + list->push_back( + csm::Warning( + csm::Warning::DATA_NOT_AVAILABLE, + "Could not parse the range conversion coefficients and times.", + "Utilities::getScaleConversionCoefficients()")); + } + } + return coefficients; +} diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 3948c05f5bbe3b5a1d4302e55e39484bfb61fa8a..c107704737ccd6f68249bb993ee8a716c0bf9b54 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -6,6 +6,7 @@ add_executable(runCSMCameraModelTests FrameCameraTests.cpp LineScanCameraTests.cpp DistortionTests.cpp + SarTests.cpp ISDParsingTests.cpp UtilitiesTests.cpp) if(WIN32) diff --git a/tests/Fixtures.h b/tests/Fixtures.h index 9872f328022e68798859d000d85ee7a74da0e345..0b400a80982321b046bc5fc9f721822cab3ac508 100644 --- a/tests/Fixtures.h +++ b/tests/Fixtures.h @@ -4,6 +4,7 @@ #include "UsgsAstroPlugin.h" #include "UsgsAstroFrameSensorModel.h" #include "UsgsAstroLsSensorModel.h" +#include "UsgsAstroSarSensorModel.h" #include <json/json.hpp> @@ -305,6 +306,17 @@ class TwoLineScanSensorModels : public ::testing::Test { } }; +////////////////// +// SAR Fixtures // +////////////////// +class SarIsdTest : public ::testing::Test { + protected: + csm::Isd isd; + + virtual void SetUp() { + isd.setFilename("data/orbitalSar.img"); + } +}; #endif diff --git a/tests/ISDParsingTests.cpp b/tests/ISDParsingTests.cpp index 3c2c0625bf1fa983dc71ed541027e97070acfd81..736cc11d8059696f1965954bfb66f813aade5b8f 100644 --- a/tests/ISDParsingTests.cpp +++ b/tests/ISDParsingTests.cpp @@ -311,3 +311,34 @@ TEST(ISDParsing, SensorOrientations) { std::vector<double> rotations = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}; EXPECT_EQ(rotations, getSensorOrientations(isd)); } + +TEST(ISDParsing, getExposureDuration) { + json isd = {{"line_exposure_duration", 0.45}}; + EXPECT_EQ(getExposureDuration(isd), 0.45); +} + +TEST(ISDParsing, getScaledPixelWidth) { + json isd = {{"scaled_pixel_width", 7.5}}; + EXPECT_EQ(getScaledPixelWidth(isd), 7.5); +} + +TEST(ISDParsing, getScaleConversionCoefficients) { + json isd = {{"range_conversion_coefficients", + {300, 1, 0.1, 0.01, + 400, 2, 0.2, 0.02, + 500, 3, 0.3, 0.03}}}; + std::vector<double> coefficients = getScaleConversionCoefficients(isd); + ASSERT_EQ(coefficients.size(), 12); + EXPECT_EQ(coefficients[0], 300); + EXPECT_EQ(coefficients[1], 1); + EXPECT_EQ(coefficients[2], 0.1); + EXPECT_EQ(coefficients[3], 0.01); + EXPECT_EQ(coefficients[4], 400); + EXPECT_EQ(coefficients[5], 2); + EXPECT_EQ(coefficients[6], 0.2); + EXPECT_EQ(coefficients[7], 0.02); + EXPECT_EQ(coefficients[8], 500); + EXPECT_EQ(coefficients[9], 3); + EXPECT_EQ(coefficients[10], 0.3); + EXPECT_EQ(coefficients[11], 0.03); +} diff --git a/tests/SarTests.cpp b/tests/SarTests.cpp new file mode 100644 index 0000000000000000000000000000000000000000..500fa9bdeeca0452222fdf561f7bbfa111acb6ba --- /dev/null +++ b/tests/SarTests.cpp @@ -0,0 +1,35 @@ +#define _USE_MATH_DEFINES + +#include "UsgsAstroSarSensorModel.h" + +#include "Warning.h" + +#include <json/json.hpp> +#include <gtest/gtest.h> + +#include <math.h> +#include <string> +#include <fstream> +#include <iostream> + +using json = nlohmann::json; + +TEST(SarTests, stateFromIsd) { + std::ifstream isdFile("data/orbitalSar.json"); + json isdJson; + isdFile >> isdJson; + std::string isdString = isdJson.dump(); + csm::WarningList warnings; + std::string stateString; + try { + stateString = UsgsAstroSarSensorModel::constructStateFromIsd(isdString, &warnings); + } + catch(...) { + for (auto &warn: warnings) { + std::cerr << "Warning in " << warn.getFunction() << std::endl; + std::cerr << " " << warn.getMessage() << std::endl; + } + FAIL() << "constructStateFromIsd errored"; + } + EXPECT_TRUE(warnings.empty()); +} diff --git a/tests/data/orbitalSar.json b/tests/data/orbitalSar.json new file mode 100644 index 0000000000000000000000000000000000000000..dd8dfdd2872d75f46af7807a14f29d6c893c9642 --- /dev/null +++ b/tests/data/orbitalSar.json @@ -0,0 +1,119 @@ +{ + "name_model": "USGS_ASTRO_SAR_MODEL", + "image_identifier" : "test_sar.img", + "name_platform": "TEST LUNAR PLATFORM", + "name_sensor": "TEST SAR", + "image_lines": 1000, + "image_samples": 1000, + "starting_ephemeris_time": 0.0, + "center_ephemeris_time": 2.5, + "ending_ephemeris_time": 5.0, + "radii": { + "semimajor": 1737.4, + "semiminor": 1737.4, + "unit": "km" + }, + "wavelength" : 0.125, + "line_exposure_duration" : 0.005, + "scaled_pixel_width" : 7.5, + "t0_ephemeris": 0.0, + "dt_ephemeris": 0.25, + "sensor_position": { + "positions": + [[ 3.73740000e+06, 0.00000000e+00, -0.00000000e+00], + [ 3.73739991e+06, 0.00000000e+00, -8.06679515e+02], + [ 3.73739965e+06, 0.00000000e+00, -1.61335899e+03], + [ 3.73739922e+06, 0.00000000e+00, -2.42003839e+03], + [ 3.73739861e+06, 0.00000000e+00, -3.22671768e+03], + [ 3.73739782e+06, 0.00000000e+00, -4.03339682e+03], + [ 3.73739687e+06, 0.00000000e+00, -4.84007577e+03], + [ 3.73739573e+06, 0.00000000e+00, -5.64675450e+03], + [ 3.73739443e+06, 0.00000000e+00, -6.45343296e+03], + [ 3.73739295e+06, 0.00000000e+00, -7.26011112e+03], + [ 3.73739129e+06, 0.00000000e+00, -8.06678895e+03], + [ 3.73738947e+06, 0.00000000e+00, -8.87346640e+03], + [ 3.73738746e+06, 0.00000000e+00, -9.68014343e+03], + [ 3.73738529e+06, 0.00000000e+00, -1.04868200e+04], + [ 3.73738294e+06, 0.00000000e+00, -1.12934961e+04], + [ 3.73738041e+06, 0.00000000e+00, -1.21001717e+04], + [ 3.73737771e+06, 0.00000000e+00, -1.29068467e+04], + [ 3.73737484e+06, 0.00000000e+00, -1.37135211e+04], + [ 3.73737179e+06, 0.00000000e+00, -1.45201949e+04], + [ 3.73736857e+06, 0.00000000e+00, -1.53268679e+04], + [ 3.73736518e+06, 0.00000000e+00, -1.61335403e+04]], + "velocities": + [[-0.00000000e+00, 0.00000000e+00, -3.73740000e+06], + [-8.06679515e+02, 0.00000000e+00, -3.73739991e+06], + [-1.61335899e+03, 0.00000000e+00, -3.73739965e+06], + [-2.42003839e+03, 0.00000000e+00, -3.73739922e+06], + [-3.22671768e+03, 0.00000000e+00, -3.73739861e+06], + [-4.03339682e+03, 0.00000000e+00, -3.73739782e+06], + [-4.84007577e+03, 0.00000000e+00, -3.73739687e+06], + [-5.64675450e+03, 0.00000000e+00, -3.73739573e+06], + [-6.45343296e+03, 0.00000000e+00, -3.73739443e+06], + [-7.26011112e+03, 0.00000000e+00, -3.73739295e+06], + [-8.06678895e+03, 0.00000000e+00, -3.73739129e+06], + [-8.87346640e+03, 0.00000000e+00, -3.73738947e+06], + [-9.68014343e+03, 0.00000000e+00, -3.73738746e+06], + [-1.04868200e+04, 0.00000000e+00, -3.73738529e+06], + [-1.12934961e+04, 0.00000000e+00, -3.73738294e+06], + [-1.21001717e+04, 0.00000000e+00, -3.73738041e+06], + [-1.29068467e+04, 0.00000000e+00, -3.73737771e+06], + [-1.37135211e+04, 0.00000000e+00, -3.73737484e+06], + [-1.45201949e+04, 0.00000000e+00, -3.73737179e+06], + [-1.53268679e+04, 0.00000000e+00, -3.73736857e+06], + [-1.61335403e+04, 0.00000000e+00, -3.73736518e+06]], + "unit": "m" + }, + "range_conversion_coefficients" : [ + 0.0, 7.99423808710000e+04, 6.92122900000000e-01, 3.40193700000000e-06, -2.39924200000000e-11, + 0.25, 7.99423795700000e+04, 6.90795300000000e-01, 3.41377900000000e-06, -2.40431400000000e-11, + 0.5, 7.99423784790000e+04, 6.89923300000000e-01, 3.42142300000000e-06, -2.40714100000000e-11, + 0.75, 7.99423782970000e+04, 6.89091700000000e-01, 3.42877300000000e-06, -2.41021200000000e-11, + 1.0, 7.99423774910000e+04, 6.88258400000000e-01, 3.43615000000000e-06, -2.41318800000000e-11, + 1.25, 7.99423754720000e+04, 6.87466400000000e-01, 3.44310000000000e-06, -2.41596100000000e-11, + 1.5, 7.99423758230000e+04, 6.86672900000000e-01, 3.45009800000000e-06, -2.41882400000000e-11, + 1.75, 7.99423758680000e+04, 6.85920500000000e-01, 3.45672500000000e-06, -2.42163000000000e-11, + 2.0, 7.99423737430000e+04, 6.85166800000000e-01, 3.46335100000000e-06, -2.42427900000000e-11, + 2.25, 7.99423758150000e+04, 6.84453800000000e-01, 3.46968000000000e-06, -2.42686600000000e-11, + 2.5, 7.99423733480000e+04, 6.83783000000000e-01, 3.47554900000000e-06, -2.42912800000000e-11, + 2.75, 7.99423731540000e+04, 6.83111300000000e-01, 3.48141500000000e-06, -2.43158100000000e-11, + 3.0, 7.99423745960000e+04, 6.82480900000000e-01, 3.48693900000000e-06, -2.43373700000000e-11, + 3.25, 7.99423723580000e+04, 6.81849000000000e-01, 3.49252600000000e-06, -2.43599300000000e-11, + 3.5, 7.99423734150000e+04, 6.81259600000000e-01, 3.49765400000000e-06, -2.43799400000000e-11, + 3.75, 7.99423726230000e+04, 6.80711700000000e-01, 3.50247300000000e-06, -2.43988600000000e-11, + 4.0, 7.99423708550000e+04, 6.80163500000000e-01, 3.50722300000000e-06, -2.44181200000000e-11, + 4.25, 7.99423717720000e+04, 6.79614100000000e-01, 3.51201600000000e-06, -2.44370400000000e-11, + 4.5, 7.99423706730000e+04, 6.79149600000000e-01, 3.51607500000000e-06, -2.44520600000000e-11, + 4.75, 7.99423710670000e+04, 6.78430200000000e-01, 3.52233100000000e-06, -2.44771700000000e-11 + ], + "sun_position": { + "positions": [ + [10000.0, 10000.0, 10000.0], + [10000.0, 10000.0, 10000.0], + [10000.0, 10000.0, 10000.0], + [10000.0, 10000.0, 10000.0], + [10000.0, 10000.0, 10000.0], + [10000.0, 10000.0, 10000.0], + [10000.0, 10000.0, 10000.0], + [10000.0, 10000.0, 10000.0], + [10000.0, 10000.0, 10000.0], + [10000.0, 10000.0, 10000.0], + [10000.0, 10000.0, 10000.0], + [10000.0, 10000.0, 10000.0], + [10000.0, 10000.0, 10000.0], + [10000.0, 10000.0, 10000.0], + [10000.0, 10000.0, 10000.0], + [10000.0, 10000.0, 10000.0], + [10000.0, 10000.0, 10000.0], + [10000.0, 10000.0, 10000.0], + [10000.0, 10000.0, 10000.0], + [10000.0, 10000.0, 10000.0], + [10000.0, 10000.0, 10000.0] + ], + "velocities": [ + [0.0, 0.0, 0.0] + ], + "unit": "km" + } +}