From d00208835b249ff51d59fc5f3c24d7fcd98765d2 Mon Sep 17 00:00:00 2001
From: Kristin Berry <kberry@usgs.gov>
Date: Fri, 12 Feb 2021 08:51:27 -0700
Subject: [PATCH] Updated state string to begin with the sensor model name as
 per the CSM standard. (#326)

Co-authored-by: Kristin Berry <kberry@gyro.wr.usgs.gov>
---
 include/usgscsm/Utilities.h       |  2 ++
 src/UsgsAstroFrameSensorModel.cpp |  9 ++++++---
 src/UsgsAstroLsSensorModel.cpp    |  7 ++++---
 src/UsgsAstroPlugin.cpp           |  4 ++--
 src/UsgsAstroSarSensorModel.cpp   |  7 ++++---
 src/Utilities.cpp                 |  9 +++++++++
 tests/Fixtures.h                  |  2 +-
 tests/FrameCameraTests.cpp        |  5 +++++
 tests/LineScanCameraTests.cpp     |  6 +++---
 tests/UtilitiesTests.cpp          | 12 ++++++++++++
 10 files changed, 48 insertions(+), 15 deletions(-)

diff --git a/include/usgscsm/Utilities.h b/include/usgscsm/Utilities.h
index 9807ecd..2e41bfd 100644
--- a/include/usgscsm/Utilities.h
+++ b/include/usgscsm/Utilities.h
@@ -166,4 +166,6 @@ std::vector<double> getSensorVelocities(nlohmann::json isd,
 std::vector<double> getSensorOrientations(nlohmann::json isd,
                                           csm::WarningList *list = nullptr);
 double getWavelength(nlohmann::json isd, csm::WarningList *list = nullptr);
+nlohmann::json stateAsJson(std::string modelState);
+
 #endif  // INCLUDE_USGSCSM_UTILITIES_H_
diff --git a/src/UsgsAstroFrameSensorModel.cpp b/src/UsgsAstroFrameSensorModel.cpp
index 6bce4fe..e5bb483 100644
--- a/src/UsgsAstroFrameSensorModel.cpp
+++ b/src/UsgsAstroFrameSensorModel.cpp
@@ -728,7 +728,8 @@ std::string UsgsAstroFrameSensorModel::getModelState() const {
        {m_referencePointXyz.x, m_referencePointXyz.y, m_referencePointXyz.z}},
       {"m_currentParameterCovariance", m_currentParameterCovariance}};
 
-  return state.dump();
+  std::string stateString = getModelName() + "\n" + state.dump();
+  return stateString;
 }
 
 bool UsgsAstroFrameSensorModel::isValidModelState(
@@ -756,7 +757,7 @@ bool UsgsAstroFrameSensorModel::isValidModelState(
                                                "m_iTransS",
                                                "m_iTransL"};
 
-  json jsonState = json::parse(stringState);
+  json jsonState = stateAsJson(stringState);
   std::vector<std::string> missingKeywords;
 
   for (auto &key : requiredKeywords) {
@@ -811,7 +812,9 @@ bool UsgsAstroFrameSensorModel::isValidIsd(const std::string &Isd,
 
 void UsgsAstroFrameSensorModel::replaceModelState(
     const std::string &stringState) {
-  json state = json::parse(stringState);
+
+  json state = stateAsJson(stringState);
+
   MESSAGE_LOG("Replacing model state");
   // The json library's .at() will except if key is missing
   try {
diff --git a/src/UsgsAstroLsSensorModel.cpp b/src/UsgsAstroLsSensorModel.cpp
index 340d550..6362a21 100644
--- a/src/UsgsAstroLsSensorModel.cpp
+++ b/src/UsgsAstroLsSensorModel.cpp
@@ -127,7 +127,7 @@ void UsgsAstroLsSensorModel::replaceModelState(const std::string& stateString) {
   MESSAGE_LOG("Replacing model state")
 
   reset();
-  auto j = json::parse(stateString);
+  auto j = stateAsJson(stateString);
   int num_params = NUM_PARAMETERS;
 
   m_imageIdentifier = j["m_imageIdentifier"].get<std::string>();
@@ -282,7 +282,7 @@ void UsgsAstroLsSensorModel::replaceModelState(const std::string& stateString) {
 std::string UsgsAstroLsSensorModel::getModelNameFromModelState(
     const std::string& model_state) {
   // Parse the string to JSON
-  auto j = json::parse(model_state);
+  auto j = stateAsJson(model_state);
   // If model name cannot be determined, return a blank string
   std::string model_name;
 
@@ -437,7 +437,8 @@ std::string UsgsAstroLsSensorModel::getModelState() const {
   state["m_sunVelocity"] = m_sunVelocity;
   MESSAGE_LOG("num sun velocities: {} ", m_sunVelocity.size())
 
-  return state.dump();
+  std::string stateString = getModelName() + "\n" + state.dump();
+  return stateString;
 }
 
 //***************************************************************************
diff --git a/src/UsgsAstroPlugin.cpp b/src/UsgsAstroPlugin.cpp
index 07945b7..93fa085 100644
--- a/src/UsgsAstroPlugin.cpp
+++ b/src/UsgsAstroPlugin.cpp
@@ -219,7 +219,7 @@ std::string UsgsAstroPlugin::loadImageSupportData(
 
 std::string UsgsAstroPlugin::getModelNameFromModelState(
     const std::string &modelState, csm::WarningList *warnings) const {
-  auto state = json::parse(modelState);
+  auto state = stateAsJson(modelState);
 
   std::string name = state.value<std::string>("name_model", "");
   MESSAGE_LOG("Get model name from model state. State: {}, Name: {}",
@@ -353,7 +353,7 @@ csm::Model *UsgsAstroPlugin::constructModelFromISD(
 csm::Model *UsgsAstroPlugin::constructModelFromState(
     const std::string &modelState, csm::WarningList *warnings) const {
   MESSAGE_LOG("Runing constructModelFromState with modelState: {}", modelState);
-  json state = json::parse(modelState);
+  json state = stateAsJson(modelState);
   std::string modelName = state["m_modelName"];
   MESSAGE_LOG("Using model name: {}", modelName);
 
diff --git a/src/UsgsAstroSarSensorModel.cpp b/src/UsgsAstroSarSensorModel.cpp
index 6decb3e..523f190 100644
--- a/src/UsgsAstroSarSensorModel.cpp
+++ b/src/UsgsAstroSarSensorModel.cpp
@@ -146,7 +146,7 @@ string UsgsAstroSarSensorModel::getModelNameFromModelState(
     const string& model_state) {
   MESSAGE_LOG("Getting model name from model state: {}", model_state);
   // Parse the string to JSON
-  auto j = json::parse(model_state);
+  auto j = stateAsJson(model_state);
   // If model name cannot be determined, return a blank string
   string model_name;
 
@@ -219,7 +219,7 @@ void UsgsAstroSarSensorModel::replaceModelState(const string& argState) {
   reset();
 
   MESSAGE_LOG("Replacing model state with: {}", argState);
-  auto stateJson = json::parse(argState);
+  auto stateJson = stateAsJson(argState);
 
   m_imageIdentifier = stateJson["m_imageIdentifier"].get<string>();
   m_platformIdentifier = stateJson["m_platformIdentifier"].get<string>();
@@ -330,7 +330,8 @@ string UsgsAstroSarSensorModel::getModelState() const {
   state["m_scaleConversionTimes"] = m_scaleConversionTimes;
   state["m_covariance"] = m_covariance;
 
-  return state.dump();
+  std::string stateString = getModelName() + "\n" + state.dump();
+  return stateString;
 }
 
 csm::ImageCoord UsgsAstroSarSensorModel::groundToImage(
diff --git a/src/Utilities.cpp b/src/Utilities.cpp
index 60a63e1..279c46d 100644
--- a/src/Utilities.cpp
+++ b/src/Utilities.cpp
@@ -1314,3 +1314,12 @@ double getWavelength(json isd, csm::WarningList *list) {
   }
   return wavelength;
 }
+
+json stateAsJson(std::string modelState) {
+  std::size_t found = modelState.find_first_of("\n");
+
+  if (found == std::string::npos) {
+    found = 0;
+  }
+  return json::parse(modelState.begin() + found, modelState.end());
+}
diff --git a/tests/Fixtures.h b/tests/Fixtures.h
index 6b8060c..a6c8848 100644
--- a/tests/Fixtures.h
+++ b/tests/Fixtures.h
@@ -194,7 +194,7 @@ class FrameStateTest : public ::testing::Test {
     if (sensorModel) {
       sensorModel->getModelState();
       std::string modelState = sensorModel->getModelState();
-      auto state = nlohmann::json::parse(modelState);
+      auto state = stateAsJson(modelState);
       state[key] = newValue;
       sensorModel->replaceModelState(state.dump());
 
diff --git a/tests/FrameCameraTests.cpp b/tests/FrameCameraTests.cpp
index 327fb05..a6f2acb 100644
--- a/tests/FrameCameraTests.cpp
+++ b/tests/FrameCameraTests.cpp
@@ -693,6 +693,11 @@ TEST_F(FrameSensorModelLogging, IsValidModelState) {
   sensorModel->isValidModelState("{\"test_key\" : \"test_string\"}", nullptr);
 }
 
+
+TEST_F(FrameSensorModelLogging, IsValidModelStateNew) {
+  sensorModel->isValidModelState(sensorModel->getModelState(), nullptr);
+}
+
 TEST_F(FrameSensorModelLogging, IsValidIsd) {
   sensorModel->isValidIsd("{\"test_key\" : \"test_string\"}", nullptr);
 }
diff --git a/tests/LineScanCameraTests.cpp b/tests/LineScanCameraTests.cpp
index c9165c9..f55f965 100644
--- a/tests/LineScanCameraTests.cpp
+++ b/tests/LineScanCameraTests.cpp
@@ -116,7 +116,7 @@ TEST_F(OrbitalLineScanSensorModel, getIlluminationDirectionStationary) {
   // Get state information, replace sun position / velocity to hit third case:
   //  One position, no velocity.
   std::string state = sensorModel->getModelState();
-  json jState = json::parse(state);
+  json jState = stateAsJson(state);
   jState["m_sunPosition"] = std::vector<double>{100.0, 100.0, 100.0};
   jState["m_sunVelocity"] = std::vector<double>{};
   sensorModel->replaceModelState(jState.dump());
@@ -154,7 +154,7 @@ TEST_F(OrbitalLineScanSensorModel, getSunPositionLinear) {
   // Get state information, replace sun position / velocity to hit third case:
   //  One position, no velocity.
   std::string state = sensorModel->getModelState();
-  json jState = json::parse(state);
+  json jState = stateAsJson(state);
   jState["m_sunPosition"] = std::vector<double>{100.0, 100.0, 100.0};
   jState["m_sunVelocity"] = std::vector<double>{50.0, 50.0, 50.0};
   sensorModel->replaceModelState(jState.dump());
@@ -169,7 +169,7 @@ TEST_F(OrbitalLineScanSensorModel, getSunPositionStationary) {
   // Get state information, replace sun position / velocity to hit third case:
   //  One position, no velocity.
   std::string state = sensorModel->getModelState();
-  json jState = json::parse(state);
+  json jState = stateAsJson(state);
   jState["m_sunPosition"] = std::vector<double>{100.0, 100.0, 100.0};
   jState["m_sunVelocity"] = std::vector<double>{};
   sensorModel->replaceModelState(jState.dump());
diff --git a/tests/UtilitiesTests.cpp b/tests/UtilitiesTests.cpp
index 21fe02d..1a6fcd9 100644
--- a/tests/UtilitiesTests.cpp
+++ b/tests/UtilitiesTests.cpp
@@ -465,3 +465,15 @@ TEST(UtilitiesTests, vectorProjection) {
   EXPECT_DOUBLE_EQ(rejectZ.y, 2.0);
   EXPECT_DOUBLE_EQ(rejectZ.z, 0.0);
 }
+
+TEST(UtilitiesTests, stateAsJsonWithModel) {
+  std::string modelState = "{\"test_key\":\"test_string\"}";
+  json state = stateAsJson("MODEL_NAME\n"+modelState);
+  EXPECT_STREQ(modelState.c_str(), state.dump().c_str());
+}
+
+TEST(UtilitiesTests, stateAsJsonWithoutModel) {
+  std::string modelState = "{\"test_key\":\"test_string\"}";
+  json state = stateAsJson(modelState);
+  EXPECT_STREQ(modelState.c_str(), state.dump().c_str());
+}
-- 
GitLab