From eea8e49b34ca0eb99a5c79fc9b113b73dbac39e9 Mon Sep 17 00:00:00 2001 From: Christine Kim Date: Fri, 2 Feb 2024 20:14:33 -0700 Subject: [PATCH 01/12] Current state --- isis/src/base/objs/Table/Table.cpp | 55 ++++++++++++ isis/src/base/objs/Table/Table.h | 1 + .../src/base/objs/TableRecord/TableRecord.cpp | 18 +++- isis/src/base/objs/TableRecord/TableRecord.h | 2 + isis/src/control/apps/jigsaw/jigsaw.cpp | 85 ++++++++++++++++--- isis/src/control/apps/jigsaw/jigsaw.xml | 28 ++++++ isis/tests/TableTests.cpp | 30 +++++++ 7 files changed, 206 insertions(+), 13 deletions(-) diff --git a/isis/src/base/objs/Table/Table.cpp b/isis/src/base/objs/Table/Table.cpp index 330d422815..4879f84fb0 100644 --- a/isis/src/base/objs/Table/Table.cpp +++ b/isis/src/base/objs/Table/Table.cpp @@ -7,6 +7,7 @@ find files of those names at the top level of this repository. **/ #include "Table.h" #include +#include #include #include "Blob.h" @@ -137,6 +138,60 @@ namespace Isis { } } + /** + * This constructor takes in a string to create a Table object. + * + * @param tableName The name o the Table to be read + * @param tableStr The table string + * @param fieldDelimiter The delimiter to separate fields with + */ + Table::Table(const QString &tableName, const std::string &tableString, const char &fieldDelimiter) { + p_name = tableName; + + std::stringstream tableStream; + tableStream << tableString; + + // Create fieldNames <-- refactor in progress + std::vector tableLinesStringList; + std::string line; + while(std::getline(tableStream, line, '\n')) { + tableLinesStringList.push_back(line); + } + + int numOfFieldValues = tableLinesStringList.size() - 1; // minus the header line + + std::string fieldNamesLineString = tableLinesStringList.front(); + std::stringstream fieldNamesStringStream; + fieldNamesStringStream << fieldNamesLineString; + + std::vector fieldNames; + std::string fieldNameString; + while(std::getline(fieldNamesStringStream, fieldNameString, fieldDelimiter)) { + fieldNames.push_back(QString::fromStdString(fieldNameString)); + } + + // Clear error flags and set pointer back to beginning + tableStream.clear(); + tableStream.seekg(0, ios::beg); + + // Add records to table + std::string recordString; + int index = 0; + while(std::getline(tableStream, recordString, '\n')) { + // skip first line bc that's the header line + if (index == 0) { + index++; + continue; + } + + TableRecord tableRecord(recordString, fieldDelimiter, fieldNames, numOfFieldValues); + p_record = tableRecord; + std::cout << "Adding record" << std::endl; + this->operator+=(tableRecord); + index++; + } + } + /** * Initialize a Table from a Blob that has been read from a file. diff --git a/isis/src/base/objs/Table/Table.h b/isis/src/base/objs/Table/Table.h index c5db233568..7179141ed6 100644 --- a/isis/src/base/objs/Table/Table.h +++ b/isis/src/base/objs/Table/Table.h @@ -79,6 +79,7 @@ namespace Isis { Table(const QString &tableName, const QString &file, const Pvl &fileHeader); Table(const Table &other); + Table(const QString &tableName, const std::string &tableString, const char &fieldDelimiter); Table &operator=(const Isis::Table &other); ~Table(); diff --git a/isis/src/base/objs/TableRecord/TableRecord.cpp b/isis/src/base/objs/TableRecord/TableRecord.cpp index 12384d46c4..0beff0e7a3 100644 --- a/isis/src/base/objs/TableRecord/TableRecord.cpp +++ b/isis/src/base/objs/TableRecord/TableRecord.cpp @@ -8,6 +8,7 @@ find files of those names at the top level of this repository. **/ #include "TableRecord.h" #include +#include #include #include @@ -21,6 +22,21 @@ namespace Isis { TableRecord::TableRecord(){ } + TableRecord::TableRecord(std::string tableRecordStr, char fieldDelimiter, + std::vector fieldNames, int numOfFieldValues) { + std::stringstream tableRecordStream; + tableRecordStream << tableRecordStr; + + std::string fieldStr; + int i = 0; + while(std::getline(tableRecordStream, fieldStr, fieldDelimiter)) { + TableField tableField(fieldNames[i], TableField::Double); + tableField = std::stod(fieldStr); // convert string to double + p_fields.push_back(tableField); + i++; + } + } + //! Destroys the TableRecord object TableRecord::~TableRecord() { } @@ -155,7 +171,7 @@ namespace Isis { Isis::TableField &field = p_fields[f]; field = (void *)&buf[sbyte]; sbyte += field.bytes(); - } + } } /** diff --git a/isis/src/base/objs/TableRecord/TableRecord.h b/isis/src/base/objs/TableRecord/TableRecord.h index ed610f38db..0df1a3cff2 100644 --- a/isis/src/base/objs/TableRecord/TableRecord.h +++ b/isis/src/base/objs/TableRecord/TableRecord.h @@ -38,6 +38,8 @@ namespace Isis { class TableRecord { public: TableRecord(); + TableRecord(std::string tableRecordStr, char fieldDelimiter, + std::vector fieldNames, int numOfFieldValues); ~TableRecord(); diff --git a/isis/src/control/apps/jigsaw/jigsaw.cpp b/isis/src/control/apps/jigsaw/jigsaw.cpp index 69ba090cda..85b6d7f3ac 100644 --- a/isis/src/control/apps/jigsaw/jigsaw.cpp +++ b/isis/src/control/apps/jigsaw/jigsaw.cpp @@ -7,6 +7,11 @@ find files of those names at the top level of this repository. **/ /* SPDX-License-Identifier: CC0-1.0 */ #include +#include +#include +#include +#include +#include #include #include @@ -14,6 +19,7 @@ find files of those names at the top level of this repository. **/ #include #include + #include "Blob.h" #include "BundleAdjust.h" #include "BundleObservationSolveSettings.h" @@ -35,6 +41,8 @@ find files of those names at the top level of this repository. **/ #include "jigsaw.h" using namespace std; +using namespace HighFive; + namespace Isis { @@ -130,24 +138,25 @@ namespace Isis { bundleSolution->outputResiduals(); } - // write lidar csv output file - if (ui.GetBoolean("LIDAR_CSV")) { - bundleSolution->outputLidarCSV(); - } + // write lidar csv output file + if (ui.GetBoolean("LIDAR_CSV")) { + bundleSolution->outputLidarCSV(); + } // write updated control net bundleAdjustment->controlNet()->Write(ui.GetFileName("ONET")); - // write updated lidar data file - if (ui.WasEntered("LIDARDATA")) { - if (ui.GetString("OLIDARFORMAT") == "JSON") { - bundleAdjustment->lidarData()->write(ui.GetFileName("OLIDARDATA"),LidarData::Format::Json); - } - else { - bundleAdjustment->lidarData()->write(ui.GetFileName("OLIDARDATA"),LidarData::Format::Binary); + // write updated lidar data file + if (ui.WasEntered("LIDARDATA")) { + if (ui.GetString("OLIDARFORMAT") == "JSON") { + bundleAdjustment->lidarData()->write(ui.GetFileName("OLIDARDATA"),LidarData::Format::Json); + } + else { + bundleAdjustment->lidarData()->write(ui.GetFileName("OLIDARDATA"),LidarData::Format::Binary); + } } - } PvlGroup gp("JigsawResults"); + QString adjustmentOutputFilename; // Update the cube pointing if requested but ONLY if bundle has converged if (ui.GetBoolean("UPDATE") ) { if ( !bundleAdjustment->isConverged() ) { @@ -156,6 +165,19 @@ namespace Isis { throw IException(IException::Unknown, msg, _FILEINFO_); } else { + if (ui.GetFileName("ADJUSTMENT_OUTPUT") == NULL) { + gp += PvlKeyword("Status","If UPDATE=True then must specify bundle adjustment values to update cube files."); + QString msg = "ADJUSTMENT_OUTPUT value is missing"; + throw IException(IException::Unknown, msg, _FILEINFO_); + } + adjustmentOutputFilename = ui.GetFileName("ADJUSTMENT_OUTPUT"); + std::cout << "AdjustmentOutputFilename=" << adjustmentOutputFilename << std::endl; + // Initialize dataset for adjustment tables + File file(adjustmentOutputFilename.toStdString(), File::Truncate); + + + std::vector adjustment_list; + for (int i = 0; i < bundleAdjustment->numberOfImages(); i++) { Process p; CubeAttributeInput inAtt; @@ -176,7 +198,9 @@ namespace Isis { // Update the image parameters QString jigComment = "Jigged = " + Isis::iTime::CurrentLocalTime(); + if (c->hasBlob("CSMState", "String")) { + std::cout << "Cube has CSMState blob" << std::endl; Blob csmStateBlob("CSMState", "String"); // Read the BLOB from the cube to propagate things like the model // and plugin name @@ -193,9 +217,46 @@ namespace Isis { spvector.Label().addComment(jigComment); c->write(cmatrix); c->write(spvector); + + QString serialNumber = bundleAdjustment->serialNumberList()->serialNumber(i); + QString cmatrixName = cmatrix.Name(); + QString spvectorName = spvector.Name(); + std::cout << "serialNumber=" << serialNumber.toStdString() << std::endl; + + std::string cmatrixKey = serialNumber.toStdString() + "/" + cmatrixName.toStdString(); + std::string spvectorKey = serialNumber.toStdString() + "/" + spvectorName.toStdString(); + + if (adjustmentOutputFilename != NULL) { + + std::string cmatrixTableStr = Table::toString(cmatrix).toStdString(); + DataSet dataset = file.createDataSet(cmatrixKey, cmatrixTableStr); + std::string spvectorTableStr = Table::toString(spvector).toStdString(); + dataset = file.createDataSet(spvectorKey, spvectorTableStr); + + // TODO: Add metadata to h5 file + PvlKeyword timeDependentFrames = c->label()->findObject(cmatrixName).findKeyword("TimeDependentFrames"); + } + if (ui.WasEntered("ADJUSTMENT_INPUT")) { + QString adjustmentInputFilename = ui.GetFileName("ADJUSTMENT_INPUT"); + std::cout << "AdjustmentInputFilename=" << adjustmentInputFilename << std::endl; + File fileRead(adjustmentInputFilename.toStdString(), File::ReadOnly); + DataSet datasetRead = fileRead.getDataSet(cmatrixKey); + std::vector cmatrixData; + datasetRead.read(cmatrixData); + for (int i = 0; i < cmatrixData.size(); i++) { + Table cmatrixTable(QString::fromStdString(cmatrixKey), cmatrixData[i], ','); + // WIP <--- + } + } + + // flag = output to this file } p.WriteHistory(*c); } + // std::cout << "Writing out dataset" << std::endl; + // dataset.write(adjustment_list); + // std::cout <<"After writing to dataset" << std::endl; + gp += PvlKeyword("Status", "Camera pointing updated"); } } diff --git a/isis/src/control/apps/jigsaw/jigsaw.xml b/isis/src/control/apps/jigsaw/jigsaw.xml index 118c834b89..acbd292d71 100644 --- a/isis/src/control/apps/jigsaw/jigsaw.xml +++ b/isis/src/control/apps/jigsaw/jigsaw.xml @@ -680,6 +680,34 @@ + + filename + input + + Outputs adjustment values + + + "Outputs adjustment values" + + + *.h5 + + + + + filename + input + + Reads in adjustment values + + + "Reads in adjustment values" + + + *.h5 + + + filename none diff --git a/isis/tests/TableTests.cpp b/isis/tests/TableTests.cpp index b8da823ec9..ee00d25515 100644 --- a/isis/tests/TableTests.cpp +++ b/isis/tests/TableTests.cpp @@ -295,3 +295,33 @@ TEST(TableTests, Clear) { EXPECT_EQ(t.Records(), 0); } + +TEST(TableTests, FromString) { + std::string tableStr = "J2000Ang1,J2000Ang2,J2000Ang3\n" + "-1.0261086365746,1.3843980236775,0.97666760713915\n" + "-0.026127047776247,0.034245411189199,0.0052635095732964\n" + "-0.005717949450684,-0.0039014897927048,2.3750859084069e-05\n" + "260093852.48957,46.12915199995,2.0\n"; + + std::cout << "tableStr=" << tableStr << std::endl; + + QString tableName = QString::fromStdString("TestTableName"); + + std::stringstream tableStrStream; + tableStrStream << tableStr; + + Table table(tableName, tableStr, ','); + std::cout << "Created table with table string" << std::endl; + std::cout << "Table name=" << table.Name().toStdString() << std::endl; + std::cout << "Table recordFields=" << static_cast(table.RecordFields()) << std::endl; + std::cout << "Table recordSize=" << static_cast(table.RecordSize()) << std::endl; + + for (int i = 0; i < table.Records(); i++) { + std::cout << "Table[" << i << "] record=" << TableRecord::toString(table[i]).toStdString() << std::endl; + } + + QString tableToString = Table::toString(table); + std::cout << "tableToString=" << tableToString.toStdString() << std::endl; + + EXPECT_EQ(tableStr, tableToString.toStdString()); +} From 017d83846bc504a2728a803045583c0f751429f7 Mon Sep 17 00:00:00 2001 From: Christine Kim Date: Thu, 13 Jun 2024 16:26:35 -0400 Subject: [PATCH 02/12] Save and apply bundle values --- environment.yml | 1 + isis/src/base/objs/Table/Table.cpp | 9 +- .../src/base/objs/TableRecord/TableRecord.cpp | 10 +- isis/src/control/apps/jigsaw/jigsaw.cpp | 102 +++++++++--------- isis/src/control/apps/jigsaw/jigsaw.xml | 2 + 5 files changed, 70 insertions(+), 54 deletions(-) diff --git a/environment.yml b/environment.yml index 46c8f27070..0ccbbc1835 100644 --- a/environment.yml +++ b/environment.yml @@ -26,6 +26,7 @@ dependencies: - graphviz - gsl>=2.6 - hdf5>=1.14.2,<1.14.3.0a0 + - highfive - icu - inja - jama diff --git a/isis/src/base/objs/Table/Table.cpp b/isis/src/base/objs/Table/Table.cpp index 4879f84fb0..34b3aa1549 100644 --- a/isis/src/base/objs/Table/Table.cpp +++ b/isis/src/base/objs/Table/Table.cpp @@ -141,7 +141,7 @@ namespace Isis { /** * This constructor takes in a string to create a Table object. * - * @param tableName The name o the Table to be read + * @param tableName The name of the Table to be read * @param tableStr The table string * @param fieldDelimiter The delimiter to separate fields with */ @@ -151,7 +151,6 @@ namespace Isis { std::stringstream tableStream; tableStream << tableString; - // Create fieldNames <-- refactor in progress std::vector tableLinesStringList; std::string line; while(std::getline(tableStream, line, '\n')) { @@ -186,10 +185,14 @@ namespace Isis { TableRecord tableRecord(recordString, fieldDelimiter, fieldNames, numOfFieldValues); p_record = tableRecord; - std::cout << "Adding record" << std::endl; this->operator+=(tableRecord); index++; } + + // Add fields + for (int f = 0; f < p_record.Fields(); f++) { + p_label.addGroup(p_record[f].pvlGroup()); + } } diff --git a/isis/src/base/objs/TableRecord/TableRecord.cpp b/isis/src/base/objs/TableRecord/TableRecord.cpp index 0beff0e7a3..7e72df9915 100644 --- a/isis/src/base/objs/TableRecord/TableRecord.cpp +++ b/isis/src/base/objs/TableRecord/TableRecord.cpp @@ -22,6 +22,14 @@ namespace Isis { TableRecord::TableRecord(){ } + /** + * TableRecord constructor + * + * @param tableRecordStr Table record string + * @param fieldDelimiter The delimiter to separate fields with + * @param fieldNames Table header names + * @param numOfFieldValues Number of fields (rows) + */ TableRecord::TableRecord(std::string tableRecordStr, char fieldDelimiter, std::vector fieldNames, int numOfFieldValues) { std::stringstream tableRecordStream; @@ -32,7 +40,7 @@ namespace Isis { while(std::getline(tableRecordStream, fieldStr, fieldDelimiter)) { TableField tableField(fieldNames[i], TableField::Double); tableField = std::stod(fieldStr); // convert string to double - p_fields.push_back(tableField); + this->operator+=(tableField); i++; } } diff --git a/isis/src/control/apps/jigsaw/jigsaw.cpp b/isis/src/control/apps/jigsaw/jigsaw.cpp index de59337304..f2de034e49 100644 --- a/isis/src/control/apps/jigsaw/jigsaw.cpp +++ b/isis/src/control/apps/jigsaw/jigsaw.cpp @@ -157,6 +157,7 @@ namespace Isis { } PvlGroup gp("JigsawResults"); QString adjustmentOutputFilename; + QString adjustmentInputFilename; // Update the cube pointing if requested but ONLY if bundle has converged if (ui.GetBoolean("UPDATE") ) { if ( !bundleAdjustment->isConverged() ) { @@ -165,18 +166,6 @@ namespace Isis { throw IException(IException::Unknown, msg, _FILEINFO_); } else { - if (ui.GetFileName("ADJUSTMENT_OUTPUT") == NULL) { - gp += PvlKeyword("Status","If UPDATE=True then must specify bundle adjustment values to update cube files."); - QString msg = "ADJUSTMENT_OUTPUT value is missing"; - throw IException(IException::Unknown, msg, _FILEINFO_); - } - adjustmentOutputFilename = ui.GetFileName("ADJUSTMENT_OUTPUT"); - std::cout << "AdjustmentOutputFilename=" << adjustmentOutputFilename << std::endl; - // Initialize dataset for adjustment tables - File file(adjustmentOutputFilename.toStdString(), File::Truncate); - - - std::vector adjustment_list; for (int i = 0; i < bundleAdjustment->numberOfImages(); i++) { Process p; @@ -211,52 +200,65 @@ namespace Isis { c->write(csmStateBlob); } else { - Table cmatrix = bundleAdjustment->cMatrix(i); - cmatrix.Label().addComment(jigComment); - Table spvector = bundleAdjustment->spVector(i); - spvector.Label().addComment(jigComment); - c->write(cmatrix); - c->write(spvector); - - QString serialNumber = bundleAdjustment->serialNumberList()->serialNumber(i); - QString cmatrixName = cmatrix.Name(); - QString spvectorName = spvector.Name(); - std::cout << "serialNumber=" << serialNumber.toStdString() << std::endl; - - std::string cmatrixKey = serialNumber.toStdString() + "/" + cmatrixName.toStdString(); - std::string spvectorKey = serialNumber.toStdString() + "/" + spvectorName.toStdString(); - - if (adjustmentOutputFilename != NULL) { - + if (ui.WasEntered("ADJUSTMENT_OUTPUT")) { + QString adjustmentOutputFilename = ui.GetFileName("ADJUSTMENT_OUTPUT"); + File file(adjustmentOutputFilename.toStdString(), File::Truncate); + + // Write bundle adjustment values to cube + Table cmatrix = bundleAdjustment->cMatrix(i); + cmatrix.Label().addComment(jigComment); + Table spvector = bundleAdjustment->spVector(i); + spvector.Label().addComment(jigComment); + c->write(cmatrix); + c->write(spvector); + + QString serialNumber = bundleAdjustment->serialNumberList()->serialNumber(i); + QString cmatrixName = cmatrix.Name(); + QString spvectorName = spvector.Name(); + + std::string cmatrixKey = serialNumber.toStdString() + "/" + cmatrixName.toStdString(); + std::string spvectorKey = serialNumber.toStdString() + "/" + spvectorName.toStdString(); + + // Save bundle adjustment values to HDF5 file std::string cmatrixTableStr = Table::toString(cmatrix).toStdString(); DataSet dataset = file.createDataSet(cmatrixKey, cmatrixTableStr); std::string spvectorTableStr = Table::toString(spvector).toStdString(); dataset = file.createDataSet(spvectorKey, spvectorTableStr); - - // TODO: Add metadata to h5 file - PvlKeyword timeDependentFrames = c->label()->findObject(cmatrixName).findKeyword("TimeDependentFrames"); + } else if (ui.WasEntered("ADJUSTMENT_INPUT")) { + adjustmentInputFilename = ui.GetFileName("ADJUSTMENT_INPUT"); + File file(adjustmentInputFilename.toStdString(), File::ReadOnly); + Table cmatrix = bundleAdjustment->cMatrix(i); + Table spvector = bundleAdjustment->spVector(i); + + QString serialNumber = bundleAdjustment->serialNumberList()->serialNumber(i); + QString cmatrixName = cmatrix.Name(); + QString spvectorName = spvector.Name(); + + std::string cmatrixKey = serialNumber.toStdString() + "/" + cmatrixName.toStdString(); + std::string spvectorKey = serialNumber.toStdString() + "/" + spvectorName.toStdString(); + + // Read h5 into table + DataSet datasetRead = file.getDataSet(cmatrixKey); + auto cmatrixData = datasetRead.read(); + Table cmatrixTable(cmatrixName, cmatrixData, ','); + + datasetRead = file.getDataSet(spvectorKey); + auto spvectorData = datasetRead.read(); + Table spvectorTable(spvectorName, spvectorData, ','); + + // Write bundle adjustment values out + cmatrixTable.Label().addComment(jigComment); + c->write(cmatrixTable); + spvectorTable.Label().addComment(jigComment); + c->write(spvectorTable); + } else { + gp += PvlKeyword("Status","If UPDATE=True then must specify either ADJUSTMENT_OUTPUT or ADJUSTMENT_INPUT."); + QString msg = "Either ADJUSTMENT_OUTPUT or ADJUSTMENT_INPUT is missing."; + throw IException(IException::Unknown, msg, _FILEINFO_); } - if (ui.WasEntered("ADJUSTMENT_INPUT")) { - QString adjustmentInputFilename = ui.GetFileName("ADJUSTMENT_INPUT"); - std::cout << "AdjustmentInputFilename=" << adjustmentInputFilename << std::endl; - File fileRead(adjustmentInputFilename.toStdString(), File::ReadOnly); - DataSet datasetRead = fileRead.getDataSet(cmatrixKey); - std::vector cmatrixData; - datasetRead.read(cmatrixData); - for (int i = 0; i < cmatrixData.size(); i++) { - Table cmatrixTable(QString::fromStdString(cmatrixKey), cmatrixData[i], ','); - // WIP <--- - } - } - - // flag = output to this file } p.WriteHistory(*c); } - // std::cout << "Writing out dataset" << std::endl; - // dataset.write(adjustment_list); - // std::cout <<"After writing to dataset" << std::endl; - gp += PvlKeyword("Status", "Camera pointing updated"); } } diff --git a/isis/src/control/apps/jigsaw/jigsaw.xml b/isis/src/control/apps/jigsaw/jigsaw.xml index acbd292d71..b68dde5453 100644 --- a/isis/src/control/apps/jigsaw/jigsaw.xml +++ b/isis/src/control/apps/jigsaw/jigsaw.xml @@ -682,6 +682,7 @@ filename + none input Outputs adjustment values @@ -696,6 +697,7 @@ filename + none input Reads in adjustment values From d3274eb18f3bf65d48babb84afb2bfe9b9e815f1 Mon Sep 17 00:00:00 2001 From: Christine Kim Date: Fri, 14 Jun 2024 15:52:02 -0400 Subject: [PATCH 03/12] Add test --- isis/src/control/apps/jigsaw/jigsaw.cpp | 4 +- isis/tests/FunctionalTestsJigsaw.cpp | 50 +++++++++++++++++++++++++ 2 files changed, 51 insertions(+), 3 deletions(-) diff --git a/isis/src/control/apps/jigsaw/jigsaw.cpp b/isis/src/control/apps/jigsaw/jigsaw.cpp index f2de034e49..552cb0e17a 100644 --- a/isis/src/control/apps/jigsaw/jigsaw.cpp +++ b/isis/src/control/apps/jigsaw/jigsaw.cpp @@ -156,8 +156,6 @@ namespace Isis { } } PvlGroup gp("JigsawResults"); - QString adjustmentOutputFilename; - QString adjustmentInputFilename; // Update the cube pointing if requested but ONLY if bundle has converged if (ui.GetBoolean("UPDATE") ) { if ( !bundleAdjustment->isConverged() ) { @@ -225,7 +223,7 @@ namespace Isis { std::string spvectorTableStr = Table::toString(spvector).toStdString(); dataset = file.createDataSet(spvectorKey, spvectorTableStr); } else if (ui.WasEntered("ADJUSTMENT_INPUT")) { - adjustmentInputFilename = ui.GetFileName("ADJUSTMENT_INPUT"); + QString adjustmentInputFilename = ui.GetFileName("ADJUSTMENT_INPUT"); File file(adjustmentInputFilename.toStdString(), File::ReadOnly); Table cmatrix = bundleAdjustment->cMatrix(i); Table spvector = bundleAdjustment->spVector(i); diff --git a/isis/tests/FunctionalTestsJigsaw.cpp b/isis/tests/FunctionalTestsJigsaw.cpp index 3abcc3cfe2..74d6b489b9 100644 --- a/isis/tests/FunctionalTestsJigsaw.cpp +++ b/isis/tests/FunctionalTestsJigsaw.cpp @@ -15,6 +15,11 @@ #include "CSMCamera.h" #include "LidarData.h" #include "SerialNumber.h" +#include "BundleAdjust.h" +#include "BundleSettings.h" +#include +#include + #include "jigsaw.h" @@ -1867,3 +1872,48 @@ TEST_F(LidarNetwork, FunctionalTestJigsawLidar) { } } + +TEST_F(ApolloNetwork, FunctionalTestJigsawSaveApplyValues) { + QVector args = {"spsolve=position", + "update=yes", + "bundleout_txt=no", + "cnet="+controlNetPath, + "fromlist="+tempDir.path() + "/cubes.lis", + "onet="+tempDir.path()+"/apollo_out.net", + "file_prefix="+tempDir.path()+"/", + "adjustment_output="+tempDir.path()+"/apollo_jigsaw.h5",}; + + UserInterface ui(APP_XML, args); + + jigsaw(ui); + + // Check apollow_jigsaw.h5 was created + QString bundleOutput = tempDir.path()+"/apollo_jigsaw.h5"; + HighFive::File file(bundleOutput.toStdString(), HighFive::File::ReadWrite); + + std::string datasetName = "/APOLLO15/METRIC/1971-08-01T15:37:39.428"; + QString cmatrixName = "InstrumentPointing"; + QString spvectorName = "InstrumentPosition"; + std::string cmatrixKey = datasetName + "/" + cmatrixName.toStdString(); + std::string spvectorKey = datasetName + "/" + spvectorName.toStdString(); + + HighFive::DataSet datasetRead = file.getDataSet(cmatrixKey); + auto cmatrixData = datasetRead.read(); + Table cmatrixTable(cmatrixName, cmatrixData, ','); + std::string cmatrixTableStr = Table::toString(cmatrixTable).toStdString(); + + datasetRead = file.getDataSet(spvectorKey); + auto spvectorData = datasetRead.read(); + Table spvectorTable(spvectorName, spvectorData, ','); + std::string spvectorTableStr = Table::toString(spvectorTable).toStdString(); + + EXPECT_EQ(cmatrixTable.RecordFields(), 8); + EXPECT_EQ(spvectorTable.RecordFields(), 7); + + EXPECT_EQ(cmatrixTableStr, + "J2000Q0,J2000Q1,J2000Q2,J2000Q3,AV1,AV2,AV3,ET\n0.72889620121855,0.66172757646101,-0.1261913882606,0.12207651669777,4.29360266307594e-04,6.9419874212449e-04,-6.23609851587137e-04,-896818899.38874\n"); + EXPECT_EQ(spvectorTableStr, + "J2000X,J2000Y,J2000Z,J2000XV,J2000YV,J2000ZV,ET\n491.19844009026,1198.1045282857,1313.7703671439,1.5198029518433,-0.58925196165899,-0.046463883259045,-896818899.38874\n"); + + file.flush(); +} From b44f75b14e3a40be7b77da083aa2b3398e70cc15 Mon Sep 17 00:00:00 2001 From: Christine Kim Date: Fri, 14 Jun 2024 16:48:04 -0400 Subject: [PATCH 04/12] Update changelog --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8b92b39893..f09632ac70 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -42,6 +42,9 @@ release. - Fixed a bug in QVIEW's Stretch tool where the default min/max type was not an available option [#5289](https://github.com/DOI-USGS/ISIS3/issues/5289) - Fixed a bug in QVIEW where images would double load if loaded from the commandline [#5505](https://github.com/DOI-USGS/ISIS3/pull/5505) +### Added +- Added option to save and apply bundle adjustment values in `jigsaw` [#4474](https://github.com/DOI-USGS/ISIS3/issues/4474) + ## [8.2.0] - 2024-04-18 ### Changed From 470bb293380495c2001a654748f3212ad20d4394 Mon Sep 17 00:00:00 2001 From: Christine Kim Date: Tue, 6 Aug 2024 16:43:22 -0400 Subject: [PATCH 05/12] Update yaml and fix for loop issue --- environment.yml | 2 +- isis/src/control/apps/jigsaw/jigsaw.cpp | 141 ++++++++++++++---------- 2 files changed, 81 insertions(+), 62 deletions(-) diff --git a/environment.yml b/environment.yml index 50921224c4..9fca007e68 100644 --- a/environment.yml +++ b/environment.yml @@ -26,7 +26,7 @@ dependencies: - gmp - graphviz - conda-forge::gsl >=2.6, <2.7 - - hdf5>=1.14.2,<1.14.3.0a0 + - hdf5 - highfive - icu - inja diff --git a/isis/src/control/apps/jigsaw/jigsaw.cpp b/isis/src/control/apps/jigsaw/jigsaw.cpp index 552cb0e17a..b8bd1d816b 100644 --- a/isis/src/control/apps/jigsaw/jigsaw.cpp +++ b/isis/src/control/apps/jigsaw/jigsaw.cpp @@ -165,6 +165,10 @@ namespace Isis { } else { + // Update the image parameters + QString jigComment = "Jigged = " + Isis::iTime::CurrentLocalTime(); + + // Loop through images for (int i = 0; i < bundleAdjustment->numberOfImages(); i++) { Process p; CubeAttributeInput inAtt; @@ -183,9 +187,6 @@ namespace Isis { break; } - // Update the image parameters - QString jigComment = "Jigged = " + Isis::iTime::CurrentLocalTime(); - if (c->hasBlob("CSMState", "String")) { std::cout << "Cube has CSMState blob" << std::endl; Blob csmStateBlob("CSMState", "String"); @@ -197,66 +198,84 @@ namespace Isis { csmStateBlob.Label().addComment(jigComment); c->write(csmStateBlob); } - else { - if (ui.WasEntered("ADJUSTMENT_OUTPUT")) { - QString adjustmentOutputFilename = ui.GetFileName("ADJUSTMENT_OUTPUT"); - File file(adjustmentOutputFilename.toStdString(), File::Truncate); - - // Write bundle adjustment values to cube - Table cmatrix = bundleAdjustment->cMatrix(i); - cmatrix.Label().addComment(jigComment); - Table spvector = bundleAdjustment->spVector(i); - spvector.Label().addComment(jigComment); - c->write(cmatrix); - c->write(spvector); - - QString serialNumber = bundleAdjustment->serialNumberList()->serialNumber(i); - QString cmatrixName = cmatrix.Name(); - QString spvectorName = spvector.Name(); - - std::string cmatrixKey = serialNumber.toStdString() + "/" + cmatrixName.toStdString(); - std::string spvectorKey = serialNumber.toStdString() + "/" + spvectorName.toStdString(); - - // Save bundle adjustment values to HDF5 file - std::string cmatrixTableStr = Table::toString(cmatrix).toStdString(); - DataSet dataset = file.createDataSet(cmatrixKey, cmatrixTableStr); - std::string spvectorTableStr = Table::toString(spvector).toStdString(); - dataset = file.createDataSet(spvectorKey, spvectorTableStr); - } else if (ui.WasEntered("ADJUSTMENT_INPUT")) { - QString adjustmentInputFilename = ui.GetFileName("ADJUSTMENT_INPUT"); - File file(adjustmentInputFilename.toStdString(), File::ReadOnly); - Table cmatrix = bundleAdjustment->cMatrix(i); - Table spvector = bundleAdjustment->spVector(i); - - QString serialNumber = bundleAdjustment->serialNumberList()->serialNumber(i); - QString cmatrixName = cmatrix.Name(); - QString spvectorName = spvector.Name(); - - std::string cmatrixKey = serialNumber.toStdString() + "/" + cmatrixName.toStdString(); - std::string spvectorKey = serialNumber.toStdString() + "/" + spvectorName.toStdString(); - - // Read h5 into table - DataSet datasetRead = file.getDataSet(cmatrixKey); - auto cmatrixData = datasetRead.read(); - Table cmatrixTable(cmatrixName, cmatrixData, ','); - - datasetRead = file.getDataSet(spvectorKey); - auto spvectorData = datasetRead.read(); - Table spvectorTable(spvectorName, spvectorData, ','); - - // Write bundle adjustment values out - cmatrixTable.Label().addComment(jigComment); - c->write(cmatrixTable); - spvectorTable.Label().addComment(jigComment); - c->write(spvectorTable); - } else { - gp += PvlKeyword("Status","If UPDATE=True then must specify either ADJUSTMENT_OUTPUT or ADJUSTMENT_INPUT."); - QString msg = "Either ADJUSTMENT_OUTPUT or ADJUSTMENT_INPUT is missing."; - throw IException(IException::Unknown, msg, _FILEINFO_); - } - } + p.WriteHistory(*c); } + + // Check for adjustment files + if (ui.WasEntered("ADJUSTMENT_OUTPUT")) { + QString adjustmentOutputFilename = ui.GetFileName("ADJUSTMENT_OUTPUT"); + File file(adjustmentOutputFilename.toStdString(), File::Truncate); + + // Loop through images + for (int i = 0; i < bundleAdjustment->numberOfImages(); i++) { + Process p; + CubeAttributeInput inAtt; + Cube *c = p.SetInputCube(bundleAdjustment->fileName(i), inAtt, ReadWrite); + + // Write bundle adjustment values to cube + Table cmatrix = bundleAdjustment->cMatrix(i); + cmatrix.Label().addComment(jigComment); + Table spvector = bundleAdjustment->spVector(i); + spvector.Label().addComment(jigComment); + c->write(cmatrix); + c->write(spvector); + + QString serialNumber = bundleAdjustment->serialNumberList()->serialNumber(i); + QString cmatrixName = cmatrix.Name(); + QString spvectorName = spvector.Name(); + + std::string cmatrixKey = serialNumber.toStdString() + "/" + cmatrixName.toStdString(); + std::string spvectorKey = serialNumber.toStdString() + "/" + spvectorName.toStdString(); + + // Save bundle adjustment values to HDF5 file + std::string cmatrixTableStr = Table::toString(cmatrix).toStdString(); + DataSet dataset = file.createDataSet(cmatrixKey, cmatrixTableStr); + std::string spvectorTableStr = Table::toString(spvector).toStdString(); + dataset = file.createDataSet(spvectorKey, spvectorTableStr); + + p.WriteHistory(*c); + } + } else if (ui.WasEntered("ADJUSTMENT_INPUT")) { + QString adjustmentInputFilename = ui.GetFileName("ADJUSTMENT_INPUT"); + File file(adjustmentInputFilename.toStdString(), File::ReadOnly); + for (int i = 0; i < bundleAdjustment->numberOfImages(); i++) { + Process p; + CubeAttributeInput inAtt; + Cube *c = p.SetInputCube(bundleAdjustment->fileName(i), inAtt, ReadWrite); + + Table cmatrix = bundleAdjustment->cMatrix(i); + Table spvector = bundleAdjustment->spVector(i); + + QString serialNumber = bundleAdjustment->serialNumberList()->serialNumber(i); + QString cmatrixName = cmatrix.Name(); + QString spvectorName = spvector.Name(); + + std::string cmatrixKey = serialNumber.toStdString() + "/" + cmatrixName.toStdString(); + std::string spvectorKey = serialNumber.toStdString() + "/" + spvectorName.toStdString(); + + // Read h5 into table + DataSet datasetRead = file.getDataSet(cmatrixKey); + auto cmatrixData = datasetRead.read(); + Table cmatrixTable(cmatrixName, cmatrixData, ','); + + datasetRead = file.getDataSet(spvectorKey); + auto spvectorData = datasetRead.read(); + Table spvectorTable(spvectorName, spvectorData, ','); + + // Write bundle adjustment values out + cmatrixTable.Label().addComment(jigComment); + c->write(cmatrixTable); + spvectorTable.Label().addComment(jigComment); + c->write(spvectorTable); + + p.WriteHistory(*c); + } + } else { + gp += PvlKeyword("Status","If UPDATE=True then must specify either ADJUSTMENT_OUTPUT or ADJUSTMENT_INPUT."); + QString msg = "Either ADJUSTMENT_OUTPUT or ADJUSTMENT_INPUT is missing."; + throw IException(IException::Unknown, msg, _FILEINFO_); + } gp += PvlKeyword("Status", "Camera pointing updated"); } } From c9d2d13aaef0e6278d98e19df246cd15a1a3095d Mon Sep 17 00:00:00 2001 From: Christine Kim Date: Thu, 8 Aug 2024 11:24:22 -0400 Subject: [PATCH 06/12] Address test failures --- isis/src/control/apps/jigsaw/jigsaw.cpp | 75 ++++++++++++++----------- isis/src/control/apps/jigsaw/jigsaw.xml | 64 +++++++++++---------- isis/tests/FunctionalTestsJigsaw.cpp | 9 ++- 3 files changed, 80 insertions(+), 68 deletions(-) diff --git a/isis/src/control/apps/jigsaw/jigsaw.cpp b/isis/src/control/apps/jigsaw/jigsaw.cpp index b8bd1d816b..b4f875dd5c 100644 --- a/isis/src/control/apps/jigsaw/jigsaw.cpp +++ b/isis/src/control/apps/jigsaw/jigsaw.cpp @@ -168,6 +168,24 @@ namespace Isis { // Update the image parameters QString jigComment = "Jigged = " + Isis::iTime::CurrentLocalTime(); + // Need to prep the adjustment file first + QString adjustmentType; + unsigned adjustmentFileEnum = 0; + QString adjustmentFilename; + bool placeholderAdjustmentFileExists = false; + if (ui.WasEntered("ADJUSTMENT_OUTPUT")) { + adjustmentFilename = ui.GetFileName("ADJUSTMENT_OUTPUT"); + adjustmentFileEnum = File::Truncate; + } else if (ui.WasEntered("ADJUSTMENT_INPUT")) { + adjustmentFilename = ui.GetFileName("ADJUSTMENT_INPUT"); + adjustmentFileEnum = File::ReadOnly; + } else { + placeholderAdjustmentFileExists = true; + adjustmentFilename = "/tmp/placeholder_adj.tmp"; + adjustmentFileEnum = File::Create; + } + File file(adjustmentFilename.toStdString(), adjustmentFileEnum); + // Loop through images for (int i = 0; i < bundleAdjustment->numberOfImages(); i++) { Process p; @@ -188,7 +206,6 @@ namespace Isis { } if (c->hasBlob("CSMState", "String")) { - std::cout << "Cube has CSMState blob" << std::endl; Blob csmStateBlob("CSMState", "String"); // Read the BLOB from the cube to propagate things like the model // and plugin name @@ -197,22 +214,7 @@ namespace Isis { csmStateBlob.setData(modelState.c_str(), modelState.size()); csmStateBlob.Label().addComment(jigComment); c->write(csmStateBlob); - } - - p.WriteHistory(*c); - } - - // Check for adjustment files - if (ui.WasEntered("ADJUSTMENT_OUTPUT")) { - QString adjustmentOutputFilename = ui.GetFileName("ADJUSTMENT_OUTPUT"); - File file(adjustmentOutputFilename.toStdString(), File::Truncate); - - // Loop through images - for (int i = 0; i < bundleAdjustment->numberOfImages(); i++) { - Process p; - CubeAttributeInput inAtt; - Cube *c = p.SetInputCube(bundleAdjustment->fileName(i), inAtt, ReadWrite); - + } else if (ui.WasEntered("ADJUSTMENT_OUTPUT")) { // Write bundle adjustment values to cube Table cmatrix = bundleAdjustment->cMatrix(i); cmatrix.Label().addComment(jigComment); @@ -233,17 +235,7 @@ namespace Isis { DataSet dataset = file.createDataSet(cmatrixKey, cmatrixTableStr); std::string spvectorTableStr = Table::toString(spvector).toStdString(); dataset = file.createDataSet(spvectorKey, spvectorTableStr); - - p.WriteHistory(*c); - } - } else if (ui.WasEntered("ADJUSTMENT_INPUT")) { - QString adjustmentInputFilename = ui.GetFileName("ADJUSTMENT_INPUT"); - File file(adjustmentInputFilename.toStdString(), File::ReadOnly); - for (int i = 0; i < bundleAdjustment->numberOfImages(); i++) { - Process p; - CubeAttributeInput inAtt; - Cube *c = p.SetInputCube(bundleAdjustment->fileName(i), inAtt, ReadWrite); - + } else if (ui.WasEntered("ADJUSTMENT_INPUT")) { Table cmatrix = bundleAdjustment->cMatrix(i); Table spvector = bundleAdjustment->spVector(i); @@ -268,13 +260,28 @@ namespace Isis { c->write(cmatrixTable); spvectorTable.Label().addComment(jigComment); c->write(spvectorTable); - - p.WriteHistory(*c); + } else { + std::cout << "ADJUSTMENT ERROR????" << std::endl; + gp += PvlKeyword("Status","If UPDATE=True then must specify either ADJUSTMENT_OUTPUT or ADJUSTMENT_INPUT or must be csminit'd."); + QString msg = "If UPDATE=True, must run csminit on cubes or specify either ADJUSTMENT_OUTPUT or ADJUSTMENT_INPUT."; + throw IException(IException::Unknown, msg, _FILEINFO_); + } + p.WriteHistory(*c); + } + + // Check if temp adjustment file was created + // Delete if so + if (placeholderAdjustmentFileExists) { + int status = remove(adjustmentFilename.toStdString().c_str()); + if (status != 0) { + PvlGroup tempAdjustmentFileWarning("TemporaryAdjustmentFileWarning"); + tempAdjustmentFileWarning.addKeyword(PvlKeyword("Warning", "The placeholder adjustment file \ + " + adjustmentFilename + "was \ + not removed properly.")); + if(log) { + log->addLogGroup(tempAdjustmentFileWarning); + } } - } else { - gp += PvlKeyword("Status","If UPDATE=True then must specify either ADJUSTMENT_OUTPUT or ADJUSTMENT_INPUT."); - QString msg = "Either ADJUSTMENT_OUTPUT or ADJUSTMENT_INPUT is missing."; - throw IException(IException::Unknown, msg, _FILEINFO_); } gp += PvlKeyword("Status", "Camera pointing updated"); } diff --git a/isis/src/control/apps/jigsaw/jigsaw.xml b/isis/src/control/apps/jigsaw/jigsaw.xml index b68dde5453..a802112c28 100644 --- a/isis/src/control/apps/jigsaw/jigsaw.xml +++ b/isis/src/control/apps/jigsaw/jigsaw.xml @@ -680,36 +680,6 @@ - - filename - none - input - - Outputs adjustment values - - - "Outputs adjustment values" - - - *.h5 - - - - - filename - none - input - - Reads in adjustment values - - - "Reads in adjustment values" - - - *.h5 - - - filename none @@ -915,7 +885,9 @@ from the solution if the adjustment converges. The results are written to the SPICE blobs attached to the cube, overwriting the previous values. If this option is not selected, the cube files are not - changed. All other output files are still created. + changed. All other output files are still created. Unless the cubes have a + CSMState blob attached, must either define ADJUSTMENT_OUTPUT or ADJUSTMENT_INPUT + if UPDATE is true. boolean @@ -1865,6 +1837,36 @@ no + + + filename + none + input + + Outputs adjustment values + + + "Outputs adjustment values" + + + *.h5 + + + + + filename + none + input + + Reads in adjustment values + + + "Reads in adjustment values" + + + *.h5 + + diff --git a/isis/tests/FunctionalTestsJigsaw.cpp b/isis/tests/FunctionalTestsJigsaw.cpp index 74d6b489b9..0cb40da995 100644 --- a/isis/tests/FunctionalTestsJigsaw.cpp +++ b/isis/tests/FunctionalTestsJigsaw.cpp @@ -491,7 +491,8 @@ TEST_F(ObservationPair, FunctionalTestJigsawCamSolveAll) { QString outCnetFileName = prefix.path() + "/outTemp.net"; QVector args = {"fromlist="+cubeListFile, "cnet="+cnetPath, "onet="+outCnetFileName, "observations=yes", "update=yes", "Cksolvedegree=3", - "Camsolve=all", "twist=no", "Spsolve=none", "Radius=no", "imagescsv=on", "file_prefix="+prefix.path()+"/"}; + "Camsolve=all", "twist=no", "Spsolve=none", "Radius=no", "imagescsv=on", "file_prefix="+prefix.path()+"/", + "adjustment_output=adj_temp.h5"}; UserInterface options(APP_XML, args); @@ -1744,7 +1745,8 @@ TEST_F(LidarNetwork, FunctionalTestJigsawLidar) { "cnet=" + controlNetPath, "fromlist=" + cubeListFile, "onet=" + tempDir.path() + "/no_lidar.net", - "file_prefix=" + tempDir.path() + "/no_lidar"}; + "file_prefix=" + tempDir.path() + "/no_lidar", + "adjustment_output=" + tempDir.path() + "/adj_out.h5"}; UserInterface ui1(APP_XML, args1); jigsaw(ui1); @@ -1768,7 +1770,8 @@ TEST_F(LidarNetwork, FunctionalTestJigsawLidar) { "lidardata=" + lidarDataPath, "olidardata=" + tempDir.path() + "/lidar_out.json", "olidarformat=json", - "lidar_csv=yes"}; + "lidar_csv=yes", + "adjustment_output=" + tempDir.path() + "/adj_out.h5"}; UserInterface ui2(APP_XML, args2); jigsaw(ui2); From f9897f35e95c46e0f05f17e65dfdac1cc2c1d580 Mon Sep 17 00:00:00 2001 From: Christine Kim Date: Thu, 8 Aug 2024 13:34:04 -0400 Subject: [PATCH 07/12] Make adjustment_output and _input optional --- isis/src/control/apps/jigsaw/jigsaw.cpp | 10 ++++++---- isis/src/control/apps/jigsaw/jigsaw.xml | 4 +--- isis/tests/FunctionalTestsJigsaw.cpp | 9 +++------ 3 files changed, 10 insertions(+), 13 deletions(-) diff --git a/isis/src/control/apps/jigsaw/jigsaw.cpp b/isis/src/control/apps/jigsaw/jigsaw.cpp index b4f875dd5c..d76e17827c 100644 --- a/isis/src/control/apps/jigsaw/jigsaw.cpp +++ b/isis/src/control/apps/jigsaw/jigsaw.cpp @@ -261,10 +261,12 @@ namespace Isis { spvectorTable.Label().addComment(jigComment); c->write(spvectorTable); } else { - std::cout << "ADJUSTMENT ERROR????" << std::endl; - gp += PvlKeyword("Status","If UPDATE=True then must specify either ADJUSTMENT_OUTPUT or ADJUSTMENT_INPUT or must be csminit'd."); - QString msg = "If UPDATE=True, must run csminit on cubes or specify either ADJUSTMENT_OUTPUT or ADJUSTMENT_INPUT."; - throw IException(IException::Unknown, msg, _FILEINFO_); + Table cmatrix = bundleAdjustment->cMatrix(i); + cmatrix.Label().addComment(jigComment); + Table spvector = bundleAdjustment->spVector(i); + spvector.Label().addComment(jigComment); + c->write(cmatrix); + c->write(spvector); } p.WriteHistory(*c); } diff --git a/isis/src/control/apps/jigsaw/jigsaw.xml b/isis/src/control/apps/jigsaw/jigsaw.xml index a802112c28..0049a97e4b 100644 --- a/isis/src/control/apps/jigsaw/jigsaw.xml +++ b/isis/src/control/apps/jigsaw/jigsaw.xml @@ -885,9 +885,7 @@ from the solution if the adjustment converges. The results are written to the SPICE blobs attached to the cube, overwriting the previous values. If this option is not selected, the cube files are not - changed. All other output files are still created. Unless the cubes have a - CSMState blob attached, must either define ADJUSTMENT_OUTPUT or ADJUSTMENT_INPUT - if UPDATE is true. + changed. All other output files are still created. boolean diff --git a/isis/tests/FunctionalTestsJigsaw.cpp b/isis/tests/FunctionalTestsJigsaw.cpp index 0cb40da995..74d6b489b9 100644 --- a/isis/tests/FunctionalTestsJigsaw.cpp +++ b/isis/tests/FunctionalTestsJigsaw.cpp @@ -491,8 +491,7 @@ TEST_F(ObservationPair, FunctionalTestJigsawCamSolveAll) { QString outCnetFileName = prefix.path() + "/outTemp.net"; QVector args = {"fromlist="+cubeListFile, "cnet="+cnetPath, "onet="+outCnetFileName, "observations=yes", "update=yes", "Cksolvedegree=3", - "Camsolve=all", "twist=no", "Spsolve=none", "Radius=no", "imagescsv=on", "file_prefix="+prefix.path()+"/", - "adjustment_output=adj_temp.h5"}; + "Camsolve=all", "twist=no", "Spsolve=none", "Radius=no", "imagescsv=on", "file_prefix="+prefix.path()+"/"}; UserInterface options(APP_XML, args); @@ -1745,8 +1744,7 @@ TEST_F(LidarNetwork, FunctionalTestJigsawLidar) { "cnet=" + controlNetPath, "fromlist=" + cubeListFile, "onet=" + tempDir.path() + "/no_lidar.net", - "file_prefix=" + tempDir.path() + "/no_lidar", - "adjustment_output=" + tempDir.path() + "/adj_out.h5"}; + "file_prefix=" + tempDir.path() + "/no_lidar"}; UserInterface ui1(APP_XML, args1); jigsaw(ui1); @@ -1770,8 +1768,7 @@ TEST_F(LidarNetwork, FunctionalTestJigsawLidar) { "lidardata=" + lidarDataPath, "olidardata=" + tempDir.path() + "/lidar_out.json", "olidarformat=json", - "lidar_csv=yes", - "adjustment_output=" + tempDir.path() + "/adj_out.h5"}; + "lidar_csv=yes"}; UserInterface ui2(APP_XML, args2); jigsaw(ui2); From 6965c55f110a98a39ef6b07682e4a0a73383e16f Mon Sep 17 00:00:00 2001 From: Christine Kim Date: Fri, 6 Sep 2024 11:34:38 -0400 Subject: [PATCH 08/12] Update workflow, added new param adjustmentout_h5, updated docs --- isis/src/control/apps/jigsaw/jigsaw.cpp | 84 +++++++++++++++---------- isis/src/control/apps/jigsaw/jigsaw.xml | 29 ++++----- 2 files changed, 66 insertions(+), 47 deletions(-) diff --git a/isis/src/control/apps/jigsaw/jigsaw.cpp b/isis/src/control/apps/jigsaw/jigsaw.cpp index d76e17827c..ee47fe8b3c 100644 --- a/isis/src/control/apps/jigsaw/jigsaw.cpp +++ b/isis/src/control/apps/jigsaw/jigsaw.cpp @@ -156,6 +156,48 @@ namespace Isis { } } PvlGroup gp("JigsawResults"); + QString jigComment = "Jigged = " + Isis::iTime::CurrentLocalTime(); + + // ALWAYS* WRITE OUT ADJUSTMENT VALUES + // Do NOT write out if ADJUSTMENT_INPUT is set bc + // the tables will be overwritten anyway + // Do NOT write out for cubes w/ CSMState (TODO) + if (ui.GetBoolean("ADJUSTMENTOUT_H5")) { + if (!ui.WasEntered("ADJUSTMENT_INPUT")) + { + // Prep file config + std::filesystem::path cwd = std::filesystem::current_path(); + std::string cwdPath = cwd.string(); + std::string adjustmentFilename = cwdPath + "/adjustment_out.h5"; + File file(adjustmentFilename, File::Truncate); + + for (int i = 0; i < bundleAdjustment->numberOfImages(); i++) { + Process p; + CubeAttributeInput inAtt; + Cube *c = p.SetInputCube(bundleAdjustment->fileName(i), inAtt, ReadWrite); + // Only for ISIS adjustment values + if (!c->hasBlob("CSMState", "String")) { + Table cmatrix = bundleAdjustment->cMatrix(i); + Table spvector = bundleAdjustment->spVector(i); + + QString serialNumber = bundleAdjustment->serialNumberList()->serialNumber(i); + QString cmatrixName = cmatrix.Name(); + QString spvectorName = spvector.Name(); + + std::string cmatrixKey = serialNumber.toStdString() + "/" + cmatrixName.toStdString(); + std::string spvectorKey = serialNumber.toStdString() + "/" + spvectorName.toStdString(); + + // Save bundle adjustment values to HDF5 file + std::string cmatrixTableStr = Table::toString(cmatrix).toStdString(); + DataSet dataset = file.createDataSet(cmatrixKey, cmatrixTableStr); + std::string spvectorTableStr = Table::toString(spvector).toStdString(); + dataset = file.createDataSet(spvectorKey, spvectorTableStr); + } + } + file.flush(); + } + } + // Update the cube pointing if requested but ONLY if bundle has converged if (ui.GetBoolean("UPDATE") ) { if ( !bundleAdjustment->isConverged() ) { @@ -164,19 +206,12 @@ namespace Isis { throw IException(IException::Unknown, msg, _FILEINFO_); } else { - - // Update the image parameters - QString jigComment = "Jigged = " + Isis::iTime::CurrentLocalTime(); - // Need to prep the adjustment file first QString adjustmentType; unsigned adjustmentFileEnum = 0; QString adjustmentFilename; bool placeholderAdjustmentFileExists = false; - if (ui.WasEntered("ADJUSTMENT_OUTPUT")) { - adjustmentFilename = ui.GetFileName("ADJUSTMENT_OUTPUT"); - adjustmentFileEnum = File::Truncate; - } else if (ui.WasEntered("ADJUSTMENT_INPUT")) { + if (ui.WasEntered("ADJUSTMENT_INPUT")) { adjustmentFilename = ui.GetFileName("ADJUSTMENT_INPUT"); adjustmentFileEnum = File::ReadOnly; } else { @@ -184,7 +219,7 @@ namespace Isis { adjustmentFilename = "/tmp/placeholder_adj.tmp"; adjustmentFileEnum = File::Create; } - File file(adjustmentFilename.toStdString(), adjustmentFileEnum); + File fileRead(adjustmentFilename.toStdString(), adjustmentFileEnum); // Loop through images for (int i = 0; i < bundleAdjustment->numberOfImages(); i++) { @@ -214,28 +249,9 @@ namespace Isis { csmStateBlob.setData(modelState.c_str(), modelState.size()); csmStateBlob.Label().addComment(jigComment); c->write(csmStateBlob); - } else if (ui.WasEntered("ADJUSTMENT_OUTPUT")) { - // Write bundle adjustment values to cube - Table cmatrix = bundleAdjustment->cMatrix(i); - cmatrix.Label().addComment(jigComment); - Table spvector = bundleAdjustment->spVector(i); - spvector.Label().addComment(jigComment); - c->write(cmatrix); - c->write(spvector); - - QString serialNumber = bundleAdjustment->serialNumberList()->serialNumber(i); - QString cmatrixName = cmatrix.Name(); - QString spvectorName = spvector.Name(); - - std::string cmatrixKey = serialNumber.toStdString() + "/" + cmatrixName.toStdString(); - std::string spvectorKey = serialNumber.toStdString() + "/" + spvectorName.toStdString(); - - // Save bundle adjustment values to HDF5 file - std::string cmatrixTableStr = Table::toString(cmatrix).toStdString(); - DataSet dataset = file.createDataSet(cmatrixKey, cmatrixTableStr); - std::string spvectorTableStr = Table::toString(spvector).toStdString(); - dataset = file.createDataSet(spvectorKey, spvectorTableStr); - } else if (ui.WasEntered("ADJUSTMENT_INPUT")) { + } + + if (ui.WasEntered("ADJUSTMENT_INPUT")) { Table cmatrix = bundleAdjustment->cMatrix(i); Table spvector = bundleAdjustment->spVector(i); @@ -247,11 +263,11 @@ namespace Isis { std::string spvectorKey = serialNumber.toStdString() + "/" + spvectorName.toStdString(); // Read h5 into table - DataSet datasetRead = file.getDataSet(cmatrixKey); + DataSet datasetRead = fileRead.getDataSet(cmatrixKey); auto cmatrixData = datasetRead.read(); Table cmatrixTable(cmatrixName, cmatrixData, ','); - datasetRead = file.getDataSet(spvectorKey); + datasetRead = fileRead.getDataSet(spvectorKey); auto spvectorData = datasetRead.read(); Table spvectorTable(spvectorName, spvectorData, ','); @@ -261,6 +277,7 @@ namespace Isis { spvectorTable.Label().addComment(jigComment); c->write(spvectorTable); } else { + // Write bundle adjustment values to cube Table cmatrix = bundleAdjustment->cMatrix(i); cmatrix.Label().addComment(jigComment); Table spvector = bundleAdjustment->spVector(i); @@ -268,6 +285,7 @@ namespace Isis { c->write(cmatrix); c->write(spvector); } + p.WriteHistory(*c); } diff --git a/isis/src/control/apps/jigsaw/jigsaw.xml b/isis/src/control/apps/jigsaw/jigsaw.xml index 0049a97e4b..865f428357 100644 --- a/isis/src/control/apps/jigsaw/jigsaw.xml +++ b/isis/src/control/apps/jigsaw/jigsaw.xml @@ -36,7 +36,10 @@ adjustment. The initial states of the points are tagged as a priori in the control network, and their final states are tagged as adjusted. Updated camera information is only written to the cube labels if the bundle - converges and the UPDATE parameter is selected. + converges and the UPDATE parameter is selected. In addition to UPDATE being + true and bundle converging, if the ADJUSTMENT_INPUT is set to an HDF5 file containing + bundle adjustment values (usually the HDF5 output file from ADJUSTMENTOUT_H5), those + values can be applied to the cube labels.

@@ -53,7 +56,8 @@ file with the IMAGESCSV option and likewise for the point statistics with the OUTPUT_CSV option. RESIDUALS_CSV provides a table of the measured image coordinates, the final sample, line, and overall residuals - of every control measure in both millimeters and pixels. + of every control measure in both millimeters and pixels. ADJUSTMENTOUT_H5 stores bundle + adjustment values in an HDF5 file. Currently, only ISIS adjustment values are saved to file.

Observation Equations

@@ -1769,7 +1773,7 @@ Output file prefix File prefix to prepend for the generated output files. Any prefix that is not a - file path will have an underscore placed between the prefix and file name. + file path will have an underscore placed between the prefix and file name.
@@ -1836,19 +1840,16 @@
- - filename - none - input - - Outputs adjustment values - + + Outputs bundle adjustment values to HDF5 file - adjustment_out.h5 - "Outputs adjustment values" + Selection of this parameter flags output of bundle adjustment + values to a HDF5 file - - *.h5 - + boolean + + yes + From 2f7037413b03b1d3bfa350091e8130c869aed606 Mon Sep 17 00:00:00 2001 From: Christine Kim Date: Mon, 9 Sep 2024 11:52:04 -0400 Subject: [PATCH 09/12] Add orientation check --- .../base/objs/SpiceRotation/SpiceRotation.cpp | 37 +++++++++++-------- 1 file changed, 21 insertions(+), 16 deletions(-) diff --git a/isis/src/base/objs/SpiceRotation/SpiceRotation.cpp b/isis/src/base/objs/SpiceRotation/SpiceRotation.cpp index c5b6c55a59..c4af96fdb7 100644 --- a/isis/src/base/objs/SpiceRotation/SpiceRotation.cpp +++ b/isis/src/base/objs/SpiceRotation/SpiceRotation.cpp @@ -1880,6 +1880,11 @@ namespace Isis { const std::vector &coeffAng3, const Source type) { + if (type == PolyFunctionOverSpice && !m_orientation) { + QString msg = "The quaternion SPICE tables are no longer available. " + "Either re-run spiceinit or set OVEREXISTING to False."; + throw IException(IException::User, msg, _FILEINFO_); + } NaifStatus::CheckErrors(); Isis::PolynomialUnivariate function1(p_degree); Isis::PolynomialUnivariate function2(p_degree); @@ -3253,7 +3258,7 @@ namespace Isis { * @see SpiceRotation::SetEphemerisTime */ void SpiceRotation::setEphemerisTimeMemcache() { - // If the cache has only one rotation, set it + // If the cache has only one rotation, set it NaifStatus::CheckErrors(); if (p_cacheTime.size() == 1) { p_CJ = m_orientation->getRotations()[0].toRotationMatrix(); @@ -3487,23 +3492,23 @@ namespace Isis { p_av[index] += cacheVelocity[index]; } - if (angles[0] <= -1 * pi_c()) { - angles[0] += twopi_c(); - } - else if (angles[0] > pi_c()) { - angles[0] -= twopi_c(); - } + if (angles[0] <= -1 * pi_c()) { + angles[0] += twopi_c(); + } + else if (angles[0] > pi_c()) { + angles[0] -= twopi_c(); + } - if (angles[2] <= -1 * pi_c()) { - angles[2] += twopi_c(); - } - else if (angles[2] > pi_c()) { - angles[2] -= twopi_c(); - } + if (angles[2] <= -1 * pi_c()) { + angles[2] += twopi_c(); + } + else if (angles[2] > pi_c()) { + angles[2] -= twopi_c(); + } - eul2m_c((SpiceDouble) angles[2], (SpiceDouble) angles[1], (SpiceDouble) angles[0], - p_axis3, p_axis2, p_axis1, - (SpiceDouble( *)[3]) &p_CJ[0]); + eul2m_c((SpiceDouble) angles[2], (SpiceDouble) angles[1], (SpiceDouble) angles[0], + p_axis3, p_axis2, p_axis1, + (SpiceDouble( *)[3]) &p_CJ[0]); } From 1a22f920fe2db08be167276336bf44cd2970ddb0 Mon Sep 17 00:00:00 2001 From: Christine Kim Date: Mon, 9 Sep 2024 15:51:19 -0400 Subject: [PATCH 10/12] Update doc --- isis/src/control/apps/jigsaw/jigsaw.xml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/isis/src/control/apps/jigsaw/jigsaw.xml b/isis/src/control/apps/jigsaw/jigsaw.xml index 865f428357..dc39dc9f96 100644 --- a/isis/src/control/apps/jigsaw/jigsaw.xml +++ b/isis/src/control/apps/jigsaw/jigsaw.xml @@ -1857,10 +1857,13 @@ none input - Reads in adjustment values + Reads in and applies adjustment values - "Reads in adjustment values" + Reads in and applies bundle adjustment values from an HDF5 file, + usually the outputted adjustment_out.h5 file. Along with the three + required parameters, UPDATE must be set to YES for the input values + to be read and applied. *.h5 From 1f02160393a8b0d250610f7894928b9418fe7dbf Mon Sep 17 00:00:00 2001 From: Christine Kim Date: Thu, 12 Sep 2024 12:18:11 -0400 Subject: [PATCH 11/12] Address test failures --- isis/src/control/apps/jigsaw/jigsaw.cpp | 19 ++++++++++--------- isis/tests/FunctionalTestsJigsaw.cpp | 7 +++---- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/isis/src/control/apps/jigsaw/jigsaw.cpp b/isis/src/control/apps/jigsaw/jigsaw.cpp index ee47fe8b3c..49517310f3 100644 --- a/isis/src/control/apps/jigsaw/jigsaw.cpp +++ b/isis/src/control/apps/jigsaw/jigsaw.cpp @@ -155,9 +155,12 @@ namespace Isis { bundleAdjustment->lidarData()->write(ui.GetFileName("OLIDARDATA"),LidarData::Format::Binary); } } + PvlGroup gp("JigsawResults"); QString jigComment = "Jigged = " + Isis::iTime::CurrentLocalTime(); + std::string outputFilePrefix = settings->outputFilePrefix().toStdString(); + // ALWAYS* WRITE OUT ADJUSTMENT VALUES // Do NOT write out if ADJUSTMENT_INPUT is set bc // the tables will be overwritten anyway @@ -165,16 +168,15 @@ namespace Isis { if (ui.GetBoolean("ADJUSTMENTOUT_H5")) { if (!ui.WasEntered("ADJUSTMENT_INPUT")) { - // Prep file config - std::filesystem::path cwd = std::filesystem::current_path(); - std::string cwdPath = cwd.string(); - std::string adjustmentFilename = cwdPath + "/adjustment_out.h5"; + std::string adjustmentFilename = outputFilePrefix + "adjustment_out.h5"; + File file(adjustmentFilename, File::Truncate); for (int i = 0; i < bundleAdjustment->numberOfImages(); i++) { Process p; CubeAttributeInput inAtt; Cube *c = p.SetInputCube(bundleAdjustment->fileName(i), inAtt, ReadWrite); + // Only for ISIS adjustment values if (!c->hasBlob("CSMState", "String")) { Table cmatrix = bundleAdjustment->cMatrix(i); @@ -197,7 +199,7 @@ namespace Isis { file.flush(); } } - + // Update the cube pointing if requested but ONLY if bundle has converged if (ui.GetBoolean("UPDATE") ) { if ( !bundleAdjustment->isConverged() ) { @@ -216,7 +218,7 @@ namespace Isis { adjustmentFileEnum = File::ReadOnly; } else { placeholderAdjustmentFileExists = true; - adjustmentFilename = "/tmp/placeholder_adj.tmp"; + adjustmentFilename = QString::fromStdString(outputFilePrefix + "placeholder_adj.tmp"); adjustmentFileEnum = File::Create; } File fileRead(adjustmentFilename.toStdString(), adjustmentFileEnum); @@ -240,6 +242,7 @@ namespace Isis { break; } + // Only apply adjustment_input values for non-CSM for now if (c->hasBlob("CSMState", "String")) { Blob csmStateBlob("CSMState", "String"); // Read the BLOB from the cube to propagate things like the model @@ -249,9 +252,7 @@ namespace Isis { csmStateBlob.setData(modelState.c_str(), modelState.size()); csmStateBlob.Label().addComment(jigComment); c->write(csmStateBlob); - } - - if (ui.WasEntered("ADJUSTMENT_INPUT")) { + } else if (ui.WasEntered("ADJUSTMENT_INPUT")) { Table cmatrix = bundleAdjustment->cMatrix(i); Table spvector = bundleAdjustment->spVector(i); diff --git a/isis/tests/FunctionalTestsJigsaw.cpp b/isis/tests/FunctionalTestsJigsaw.cpp index 74d6b489b9..61d957a41c 100644 --- a/isis/tests/FunctionalTestsJigsaw.cpp +++ b/isis/tests/FunctionalTestsJigsaw.cpp @@ -1880,15 +1880,14 @@ TEST_F(ApolloNetwork, FunctionalTestJigsawSaveApplyValues) { "cnet="+controlNetPath, "fromlist="+tempDir.path() + "/cubes.lis", "onet="+tempDir.path()+"/apollo_out.net", - "file_prefix="+tempDir.path()+"/", - "adjustment_output="+tempDir.path()+"/apollo_jigsaw.h5",}; + "file_prefix="+tempDir.path()+"/"}; UserInterface ui(APP_XML, args); jigsaw(ui); - // Check apollow_jigsaw.h5 was created - QString bundleOutput = tempDir.path()+"/apollo_jigsaw.h5"; + // Check apollo_jigsaw.h5 was created + QString bundleOutput = tempDir.path()+"/adjustment_out.h5"; HighFive::File file(bundleOutput.toStdString(), HighFive::File::ReadWrite); std::string datasetName = "/APOLLO15/METRIC/1971-08-01T15:37:39.428"; From 1a083f662cf02daddbf74e02e249fc314dbfdaab Mon Sep 17 00:00:00 2001 From: Christine Kim Date: Wed, 18 Sep 2024 09:18:40 -0400 Subject: [PATCH 12/12] Address comments --- isis/src/control/apps/jigsaw/jigsaw.cpp | 190 +++++++++++++----------- isis/src/control/apps/jigsaw/jigsaw.xml | 102 +++++++++++-- 2 files changed, 192 insertions(+), 100 deletions(-) diff --git a/isis/src/control/apps/jigsaw/jigsaw.cpp b/isis/src/control/apps/jigsaw/jigsaw.cpp index 49517310f3..ce9a4064b1 100644 --- a/isis/src/control/apps/jigsaw/jigsaw.cpp +++ b/isis/src/control/apps/jigsaw/jigsaw.cpp @@ -55,6 +55,77 @@ namespace Isis { void jigsaw(UserInterface &ui, Pvl *log) { + QString cubeList = ui.GetFileName("FROMLIST"); + + // Check for ADJUSTMENT_INPUT file and apply + try { + if (ui.WasEntered("ADJUSTMENT_INPUT")) { + + // Set default values + ui.Clear("TWIST"); + ui.PutBoolean("TWIST", false); + ui.PutBoolean("BUNDLEOUT_TXT", false); + ui.PutBoolean("IMAGESCSV", false); + ui.PutBoolean("OUTPUT_CSV", false); + ui.PutBoolean("RESIDUALS_CSV", false); + ui.PutBoolean("LIDAR_CSV", false); + ui.PutBoolean("OUTADJUSTMENTH5", false); + + File fileRead(ui.GetFileName("ADJUSTMENT_INPUT").toStdString(), File::ReadOnly); + SerialNumberList *snList = new SerialNumberList(cubeList); + + QString jigApplied = "JigApplied = " + Isis::iTime::CurrentLocalTime(); + + for (int i = 0; i < snList->size(); i++) { + Process p; + CubeAttributeInput inAtt; + Cube *c = p.SetInputCube(snList->fileName(i), inAtt, ReadWrite); + + if (c->hasBlob("CSMState", "String")) { + QString msg = "Unable to apply bundle adjustment values to cubes with CSMState blobs."; + throw IException(IException::User, msg, _FILEINFO_); + } + + QString serialNumber = snList->serialNumber(i); + QString cmatrixName = "InstrumentPointing"; + QString spvectorName = "InstrumentPosition"; + + std::string cmatrixKey = serialNumber.toStdString() + "/" + cmatrixName.toStdString(); + std::string spvectorKey = serialNumber.toStdString() + "/" + spvectorName.toStdString(); + + // Read h5 into table + DataSet datasetRead = fileRead.getDataSet(cmatrixKey); + auto cmatrixData = datasetRead.read(); + Table cmatrixTable(cmatrixName, cmatrixData, ','); + + datasetRead = fileRead.getDataSet(spvectorKey); + auto spvectorData = datasetRead.read(); + Table spvectorTable(spvectorName, spvectorData, ','); + + // Write bundle adjustment values out + cmatrixTable.Label().addComment(jigApplied); + c->write(cmatrixTable); + spvectorTable.Label().addComment(jigApplied); + c->write(spvectorTable); + + p.WriteHistory(*c); + } + + if (log) { + PvlGroup gp("JigsawResults"); + + gp += PvlKeyword("Status", "Bundle adjustment values from [" + ui.GetFileName("ADJUSTMENT_INPUT") + + "] were applied to the cubes in [" + cubeList+ "]"); + log->addLogGroup(gp); + } + + return; + } + } catch (IException &e) { + QString msg = "Unable to apply bundle adjustment values from [" + ui.GetFileName("ADJUSTMENT_INPUT") + "]"; + throw IException(e, IException::User, msg, _FILEINFO_); + } + // Check to make sure user entered something to adjust... Or can just points be in solution? // YES - we should be able to just TRIANGULATE the points in the control net // right now to do this we have to fake out jigsaw by @@ -67,7 +138,6 @@ namespace Isis { } QString cnetFile = ui.GetFileName("CNET"); - QString cubeList = ui.GetFileName("FROMLIST"); // retrieve settings from jigsaw gui BundleSettingsQsp settings = bundleSettings(ui); @@ -85,6 +155,7 @@ namespace Isis { } } settings->setCubeList(cubeList); + BundleAdjust *bundleAdjustment = NULL; try { // Get the held list if entered and prep for bundle adjustment @@ -161,43 +232,38 @@ namespace Isis { std::string outputFilePrefix = settings->outputFilePrefix().toStdString(); - // ALWAYS* WRITE OUT ADJUSTMENT VALUES - // Do NOT write out if ADJUSTMENT_INPUT is set bc - // the tables will be overwritten anyway + // ALWAYS* WRITE OUT ADJUSTMENT VALUES // Do NOT write out for cubes w/ CSMState (TODO) - if (ui.GetBoolean("ADJUSTMENTOUT_H5")) { - if (!ui.WasEntered("ADJUSTMENT_INPUT")) - { - std::string adjustmentFilename = outputFilePrefix + "adjustment_out.h5"; - - File file(adjustmentFilename, File::Truncate); - - for (int i = 0; i < bundleAdjustment->numberOfImages(); i++) { - Process p; - CubeAttributeInput inAtt; - Cube *c = p.SetInputCube(bundleAdjustment->fileName(i), inAtt, ReadWrite); - - // Only for ISIS adjustment values - if (!c->hasBlob("CSMState", "String")) { - Table cmatrix = bundleAdjustment->cMatrix(i); - Table spvector = bundleAdjustment->spVector(i); - - QString serialNumber = bundleAdjustment->serialNumberList()->serialNumber(i); - QString cmatrixName = cmatrix.Name(); - QString spvectorName = spvector.Name(); - - std::string cmatrixKey = serialNumber.toStdString() + "/" + cmatrixName.toStdString(); - std::string spvectorKey = serialNumber.toStdString() + "/" + spvectorName.toStdString(); - - // Save bundle adjustment values to HDF5 file - std::string cmatrixTableStr = Table::toString(cmatrix).toStdString(); - DataSet dataset = file.createDataSet(cmatrixKey, cmatrixTableStr); - std::string spvectorTableStr = Table::toString(spvector).toStdString(); - dataset = file.createDataSet(spvectorKey, spvectorTableStr); - } + if (ui.GetBoolean("OUTADJUSTMENTH5")) { + std::string adjustmentFilename = outputFilePrefix + "adjustment_out.h5"; + + File file(adjustmentFilename, File::Truncate); + + for (int i = 0; i < bundleAdjustment->numberOfImages(); i++) { + Process p; + CubeAttributeInput inAtt; + Cube *c = p.SetInputCube(bundleAdjustment->fileName(i), inAtt, ReadWrite); + + // Only for ISIS adjustment values + if (!c->hasBlob("CSMState", "String")) { + Table cmatrix = bundleAdjustment->cMatrix(i); + Table spvector = bundleAdjustment->spVector(i); + + QString serialNumber = bundleAdjustment->serialNumberList()->serialNumber(i); + QString cmatrixName = cmatrix.Name(); + QString spvectorName = spvector.Name(); + + std::string cmatrixKey = serialNumber.toStdString() + "/" + cmatrixName.toStdString(); + std::string spvectorKey = serialNumber.toStdString() + "/" + spvectorName.toStdString(); + + // Save bundle adjustment values to HDF5 file + std::string cmatrixTableStr = Table::toString(cmatrix).toStdString(); + DataSet dataset = file.createDataSet(cmatrixKey, cmatrixTableStr); + std::string spvectorTableStr = Table::toString(spvector).toStdString(); + dataset = file.createDataSet(spvectorKey, spvectorTableStr); } - file.flush(); } + file.flush(); } // Update the cube pointing if requested but ONLY if bundle has converged @@ -208,20 +274,6 @@ namespace Isis { throw IException(IException::Unknown, msg, _FILEINFO_); } else { - // Need to prep the adjustment file first - QString adjustmentType; - unsigned adjustmentFileEnum = 0; - QString adjustmentFilename; - bool placeholderAdjustmentFileExists = false; - if (ui.WasEntered("ADJUSTMENT_INPUT")) { - adjustmentFilename = ui.GetFileName("ADJUSTMENT_INPUT"); - adjustmentFileEnum = File::ReadOnly; - } else { - placeholderAdjustmentFileExists = true; - adjustmentFilename = QString::fromStdString(outputFilePrefix + "placeholder_adj.tmp"); - adjustmentFileEnum = File::Create; - } - File fileRead(adjustmentFilename.toStdString(), adjustmentFileEnum); // Loop through images for (int i = 0; i < bundleAdjustment->numberOfImages(); i++) { @@ -252,31 +304,6 @@ namespace Isis { csmStateBlob.setData(modelState.c_str(), modelState.size()); csmStateBlob.Label().addComment(jigComment); c->write(csmStateBlob); - } else if (ui.WasEntered("ADJUSTMENT_INPUT")) { - Table cmatrix = bundleAdjustment->cMatrix(i); - Table spvector = bundleAdjustment->spVector(i); - - QString serialNumber = bundleAdjustment->serialNumberList()->serialNumber(i); - QString cmatrixName = cmatrix.Name(); - QString spvectorName = spvector.Name(); - - std::string cmatrixKey = serialNumber.toStdString() + "/" + cmatrixName.toStdString(); - std::string spvectorKey = serialNumber.toStdString() + "/" + spvectorName.toStdString(); - - // Read h5 into table - DataSet datasetRead = fileRead.getDataSet(cmatrixKey); - auto cmatrixData = datasetRead.read(); - Table cmatrixTable(cmatrixName, cmatrixData, ','); - - datasetRead = fileRead.getDataSet(spvectorKey); - auto spvectorData = datasetRead.read(); - Table spvectorTable(spvectorName, spvectorData, ','); - - // Write bundle adjustment values out - cmatrixTable.Label().addComment(jigComment); - c->write(cmatrixTable); - spvectorTable.Label().addComment(jigComment); - c->write(spvectorTable); } else { // Write bundle adjustment values to cube Table cmatrix = bundleAdjustment->cMatrix(i); @@ -289,21 +316,6 @@ namespace Isis { p.WriteHistory(*c); } - - // Check if temp adjustment file was created - // Delete if so - if (placeholderAdjustmentFileExists) { - int status = remove(adjustmentFilename.toStdString().c_str()); - if (status != 0) { - PvlGroup tempAdjustmentFileWarning("TemporaryAdjustmentFileWarning"); - tempAdjustmentFileWarning.addKeyword(PvlKeyword("Warning", "The placeholder adjustment file \ - " + adjustmentFilename + "was \ - not removed properly.")); - if(log) { - log->addLogGroup(tempAdjustmentFileWarning); - } - } - } gp += PvlKeyword("Status", "Camera pointing updated"); } } diff --git a/isis/src/control/apps/jigsaw/jigsaw.xml b/isis/src/control/apps/jigsaw/jigsaw.xml index dc39dc9f96..08abf03688 100644 --- a/isis/src/control/apps/jigsaw/jigsaw.xml +++ b/isis/src/control/apps/jigsaw/jigsaw.xml @@ -36,11 +36,21 @@ adjustment. The initial states of the points are tagged as a priori in the control network, and their final states are tagged as adjusted. Updated camera information is only written to the cube labels if the bundle - converges and the UPDATE parameter is selected. In addition to UPDATE being - true and bundle converging, if the ADJUSTMENT_INPUT is set to an HDF5 file containing - bundle adjustment values (usually the HDF5 output file from ADJUSTMENTOUT_H5), those - values can be applied to the cube labels. + converges and the UPDATE parameter is selected.

+

+ In order to apply bundle values using ADJUSTMENT_INPUT, only the option FROMLIST + must be set. If the ADJUSTMENT_INPUT is set to an HDF5 file containing bundle adjustment values + (usually the HDF5 output file from OUTADJUSTMENTH5), those values can be applied to the + cube labels. The adjustment file entails a group of HDF5 datasets where each dataset + contains the instrument pointing and position for each cube. The dataset key is composed + of the cube serial number and the table name, either "InstrumentPointing" or + "InstrumentPosition", separated by a forward slash "/". For example: +

+
+      SerialNumber: MRO/CTX/1016816309:030
+      Dataset key for instrument pointing: MRO/CTX/1016816309:030/InstrumentPointing
+    

The input control net may be created by finding each image footprint with footprintinit, @@ -56,8 +66,10 @@ file with the IMAGESCSV option and likewise for the point statistics with the OUTPUT_CSV option. RESIDUALS_CSV provides a table of the measured image coordinates, the final sample, line, and overall residuals - of every control measure in both millimeters and pixels. ADJUSTMENTOUT_H5 stores bundle - adjustment values in an HDF5 file. Currently, only ISIS adjustment values are saved to file. + of every control measure in both millimeters and pixels. OUTADJUSTMENTH5 stores bundle + adjustment values in an HDF5 file. Currently, only ISIS adjustment values are saved to file so + if all the cubes in the FROMLIST contain a CSM state blob then the adjustment_out.h5 + file will be created but empty.

Observation Equations

@@ -715,6 +727,9 @@ autoseed or qnet. It contains the control points and associated measures. + + ADJUSTMENT_INPUT + *.net @@ -731,6 +746,9 @@ the final coordinates of the control points and residuals for each measurement. + + ADJUSTMENT_INPUT + *.net @@ -879,6 +897,9 @@ POINT_RADIUS_SIGMA + + ADJUSTMENT_INPUT +
@@ -895,6 +916,9 @@ No + + ADJUSTMENT_INPUT + @@ -1287,6 +1311,7 @@ Yes + Fit polynomial over the existing pointing @@ -1840,11 +1865,12 @@ - + Outputs bundle adjustment values to HDF5 file - adjustment_out.h5 Selection of this parameter flags output of bundle adjustment - values to a HDF5 file + values to an HDF5 file. The HDF5 file may be empty if all the cubes + have CSM states. boolean @@ -1861,13 +1887,67 @@ Reads in and applies bundle adjustment values from an HDF5 file, - usually the outputted adjustment_out.h5 file. Along with the three - required parameters, UPDATE must be set to YES for the input values - to be read and applied. + usually the outputted adjustment_out.h5 file. *.h5 + + ONET + CNET + LIDARDATA + OLIDARDATA + OLIDARFORMAT + SCCONFIG + OBSERVATIONS + RADIUS + UPDATE + OUTLIER_REJECTION + REJECTION_MULTIPLIER + ERRORPROPAGATION + MODEL1 + MAX_MODEL1_C_QUANTILE + MODEL2 + MAX_MODEL2_C_QUANTILE + MODEL3 + MAX_MODEL3_C_QUANTILE + SIGMA0 + MAXITS + CKDEGREE + CKSOLVEDEGREE + CAMSOLVE + + OVEREXISTING + SPKDEGREE + SPKSOLVEDEGREE + SPSOLVE + OVERHERMITE + CSMSOLVESET + CSMSOLVETYPE + CSMSOLVELIST + SOLVETARGETBODY + TBPARAMETERS + CONTROL_POINT_COORDINATE_TYPE_BUNDLE + CONTROL_POINT_COORDINATE_TYPE_REPORTS + POINT_LATITUDE_SIGMA + POINT_LONGITUDE_SIGMA + POINT_RADIUS_SIGMA + POINT_X_SIGMA + POINT_Y_SIGMA + POINT_Z_SIGMA + SPACECRAFT_POSITION_SIGMA + SPACECRAFT_VELOCITY_SIGMA + SPACECRAFT_ACCELERATION_SIGMA + CAMERA_ANGLES_SIGMA + CAMERA_ANGULAR_VELOCITY_SIGMA + CAMERA_ANGULAR_ACCELERATION_SIGMA + +