diff --git a/isis/src/base/objs/CSMCamera/CSMCamera.cpp b/isis/src/base/objs/CSMCamera/CSMCamera.cpp index 427d44a690..4168cec1cc 100644 --- a/isis/src/base/objs/CSMCamera/CSMCamera.cpp +++ b/isis/src/base/objs/CSMCamera/CSMCamera.cpp @@ -774,6 +774,41 @@ namespace Isis { } + /** + * Get the indices of the parameters in a set. + * + * @param paramSet The set of indices to get + * + * @returns @b std::vector Vector of the parameter indices + */ + std::vector CSMCamera::getParameterIndices(csm::param::Set paramSet) const { + return m_model->getParameterSetIndices(paramSet); + } + + + /** + * Adjust the value of a parameter. + * + * @param index The index of the parameter to update + * @param correction Value to add to the parameter's current value + */ + void CSMCamera::applyParameterCorrection(int index, double correction) { + double currentValue = m_model->getParameterValue(index); + m_model->setParameterValue(index, currentValue + correction); + } + + + /** + * Get the covariance between two parameters. + * + * @param index1 The index of the first parameter + * @param index2 The index of the second parameter + */ + double CSMCamera::getParameterCovariance(int index1, int index2) { + return m_model->getParameterCovariance(index1, index2); + } + + /** * Set the time and update the sensor position and orientation. * diff --git a/isis/src/base/objs/CSMCamera/CSMCamera.h b/isis/src/base/objs/CSMCamera/CSMCamera.h index a2d50664b1..85bc910945 100644 --- a/isis/src/base/objs/CSMCamera/CSMCamera.h +++ b/isis/src/base/objs/CSMCamera/CSMCamera.h @@ -116,6 +116,10 @@ namespace Isis { virtual double RightAscension(); virtual double Declination(); + std::vector getParameterIndices(csm::param::Set paramSet) const; + void applyParameterCorrection(int index, double correction); + double getParameterCovariance(int index1, int index2); + protected: void setTarget(Pvl label); diff --git a/isis/src/control/objs/BundleUtilities/AbstractBundleObservation.h b/isis/src/control/objs/BundleUtilities/AbstractBundleObservation.h index 66dd18fbe6..4f69626728 100644 --- a/isis/src/control/objs/BundleUtilities/AbstractBundleObservation.h +++ b/isis/src/control/objs/BundleUtilities/AbstractBundleObservation.h @@ -18,7 +18,6 @@ find files of those names at the top level of this repository. **/ #include "LinearAlgebra.h" namespace Isis { - class BundleObservationSolveSettings; /** * @brief Class for bundle observations @@ -43,7 +42,7 @@ namespace Isis { virtual AbstractBundleObservation &operator=(const AbstractBundleObservation &src); // copy method - // not implementedn in BundleObservation either??? + // not implementedn in BundleObservation either??? // virtual void copy(const AbstractBundleObservation &src); virtual void append(const BundleImageQsp &value); @@ -61,7 +60,7 @@ namespace Isis { virtual LinearAlgebra::Vector &adjustedSigmas(); - virtual const BundleObservationSolveSettingsQsp solveSettings() = 0; + virtual const BundleObservationSolveSettingsQsp solveSettings() = 0; virtual int numberParameters(); virtual bool applyParameterCorrections(LinearAlgebra::Vector corrections); @@ -73,7 +72,7 @@ namespace Isis { virtual QStringList parameterList(); virtual QStringList imageNames(); - private: + protected: QString m_observationNumber; /**< This is typically equivalent to serial number except in the case of "observation mode" (e.g. Lunar Orbiter) where for each image in the diff --git a/isis/src/control/objs/CsmBundleObservation/CsmBundleObservation.cpp b/isis/src/control/objs/CsmBundleObservation/CsmBundleObservation.cpp new file mode 100644 index 0000000000..c0a235ee52 --- /dev/null +++ b/isis/src/control/objs/CsmBundleObservation/CsmBundleObservation.cpp @@ -0,0 +1,876 @@ +/** This is free and unencumbered software released into the public domain. + +The authors of ISIS do not claim copyright on the contents of this file. +For more details about the LICENSE terms and the AUTHORS, you will +find files of those names at the top level of this repository. **/ + +/* SPDX-License-Identifier: CC0-1.0 */ + +#include "CsmBundleObservation.h" + +#include +#include +#include +#include + +#include "BundleImage.h" +#include "BundleObservationSolveSettings.h" +#include "BundleTargetBody.h" +#include "Camera.h" +#include "CSMCamera.h" +#include "LinearAlgebra.h" +#include "SpicePosition.h" +#include "SpiceRotation.h" + +using namespace std; + +namespace Isis { + + /** + * Constructs a CsmBundleObservation initialized to a default state. + */ + CsmBundleObservation::CsmBundleObservation() { + } + + + /** + * Constructs a CsmBundleObservation from an BundleImage, an instrument id, an observation + * number to assign to this CsmBundleObservation, and a target body. + * + * @param image QSharedPointer to the primary image in the observation + * @param observationNumber Observation number of the observation + * @param instrumentId Id of the instrument for the observation + * @param bundleTargetBody QSharedPointer to the target body of the observation + */ + CsmBundleObservation::CsmBundleObservation(BundleImageQsp image, QString observationNumber, + QString instrumentId, BundleTargetBodyQsp bundleTargetBody) : AbstractBundleObservation(image, observationNumber, instrumentId, bundleTargetBody) { + if (bundleTargetBody) { + QString msg = "Target body parameters cannot be solved for with CSM observations."; + throw IException(IException::User, msg, _FILEINFO_); + } + } + + + /** + * Creates a copy of another CsmBundleObservation. + * + * @param src Reference to the CsmBundleObservation to copy + */ + CsmBundleObservation::CsmBundleObservation(const CsmBundleObservation &src) : AbstractBundleObservation(src) { + m_solveSettings = src.m_solveSettings; + m_paramIndices = src.m_paramIndices; + } + + + /** + * Destructor. + * + * Contained BundleImages will remain until all shared pointers are deleted. + */ + CsmBundleObservation::~CsmBundleObservation() { + } + + + /** + * Assignment operator + * + * Assigns the state of the source CsmBundleObservation to this CsmBundleObservation + * + * @param CsmBundleObservation Reference to the source CsmBundleObservation to assign from + * + * @return @b CsmBundleObservation& Reference to this CsmBundleObservation + */ + CsmBundleObservation &CsmBundleObservation::operator=(const CsmBundleObservation &src) { + if (&src != this) { + m_solveSettings = src.m_solveSettings; + m_paramIndices = src.m_paramIndices; + } + return *this; + } + + + /** + * Set solve parameters + * + * @param solveSettings The solve settings to use + * + * @return @b bool Returns true if settings were successfully set + * + * @internal + * @todo initParameterWeights() doesn't return false, so this methods always + * returns true. + */ + bool CsmBundleObservation::setSolveSettings(CsmBundleObservationSolveSettingsQsp solveSettings) { + // TODO implement for CSM + + m_solveSettings = solveSettings; + + CSMCamera *csmCamera = dynamic_cast(front()->camera()); + + m_paramIndices = csmCamera->getParameterIndices(solveSettings->solveSet()); + int nParams = m_paramIndices.size(); + + m_weights.resize(nParams); + m_weights.clear(); + m_corrections.resize(nParams); + m_corrections.clear(); + m_adjustedSigmas.resize(nParams); + m_adjustedSigmas.clear(); + m_aprioriSigmas.resize(nParams); + + for (int i = 0; i < nParams; i++) { + m_aprioriSigmas[i] = csmCamera->getParameterCovariance(m_paramIndices[i], m_paramIndices[i]); + } + + return true; + } + + + // TODO change this to CSM solve settings once compute partials is updated + /** + * Accesses the solve settings + * + * @return @b const BundleObservationSolveSettingsQsp Returns a pointer to the solve + * settings for this CsmBundleObservation + */ + const BundleObservationSolveSettingsQsp CsmBundleObservation::solveSettings() { + return BundleObservationSolveSettingsQsp(nullptr); + } + + + /** + * Applies the parameter corrections + * + * @param corrections Vector of corrections to apply + * + * @throws IException::Unknown "Instrument position is NULL, but position solve option is + * [not NoPositionFactors]" + * @throws IException::Unknown "Instrument position is NULL, but pointing solve option is + * [not NoPointingFactors]" + * @throws IException::Unknown "Unable to apply parameter corrections to CsmBundleObservation." + * + * @return @b bool Returns true upon successful application of corrections + * + * @internal + * @todo always returns true? + */ + bool CsmBundleObservation::applyParameterCorrections(LinearAlgebra::Vector corrections) { + // Check that the correction vector is the correct size + if (corrections.size() != m_paramIndices.size()) { + QString msg = "Invalid correction vector passed to observation."; + IException(IException::Programmer, msg, _FILEINFO_); + } + + // Apply the corrections to the CSM camera + CSMCamera *csmCamera = dynamic_cast(front()->camera()); + for (size_t i = 0; i < corrections.size(); i++) { + csmCamera->applyParameterCorrection(m_paramIndices[i], corrections[i]); + } + + // Accumulate the total corrections + m_corrections += corrections; + + return true; + } + + + /** + * Returns the number of total parameters there are for solving + * + * The total number of parameters is equal to the number of position parameters and number of + * pointing parameters + * + * @return @b int Returns the number of parameters there are + */ + int CsmBundleObservation::numberParameters() { + return m_paramIndices.size(); + } + + + /** + * @brief Creates and returns a formatted QString representing the bundle coefficients and + * parameters + * + * @depricated The function formatBundleOutputString is depricated as of ISIS 3.9 + * and will be removed in ISIS 4.0 + * + * @param errorPropagation Boolean indicating whether or not to attach more information + * (corrections, sigmas, adjusted sigmas...) to the output QString + * @param imageCSV Boolean which is set to true if the function is being + * called from BundleSolutionInfo::outputImagesCSV(). It is set to false by default + * for backwards compatibility. + * + * @return @b QString Returns a formatted QString representing the CsmBundleObservation + * + * @internal + * @history 2016-10-26 Ian Humphrey - Default values are now provided for parameters that are + * not being solved. Fixes #4464. + */ +QString CsmBundleObservation::formatBundleOutputString(bool errorPropagation, bool imageCSV) { + // TODO implement for CSM + + // std::cerr << "The function formatBundleOutputString is depricated as of ISIS 3.9" + // "and will be removed in ISIS 4.0" << std::endl; + + // std::vector coefX; + // std::vector coefY; + // std::vector coefZ; + // std::vector coefRA; + // std::vector coefDEC; + // std::vector coefTWI; + + // int nPositionCoefficients = m_solveSettings->numberCameraPositionCoefficientsSolved(); + // int nPointingCoefficients = m_solveSettings->numberCameraAngleCoefficientsSolved(); + + // // Indicate if we need to obtain default position or pointing values + // bool useDefaultPosition = false; + // bool useDefaultPointing = false; + // // Indicate if we need to use default values when not solving twist + // bool useDefaultTwist = !(m_solveSettings->solveTwist()); + + // // If we aren't solving for position, set the number of coefficients to 1 so we can output the + // // instrumentPosition's center coordinate values for X, Y, and Z + // if (nPositionCoefficients == 0) { + // nPositionCoefficients = 1; + // useDefaultPosition = true; + // } + // // If we arent' solving for pointing, set the number of coefficients to 1 so we can output the + // // instrumentPointing's center angles for RA, DEC, and TWI + // if (nPointingCoefficients == 0) { + // nPointingCoefficients = 1; + // useDefaultPointing = true; + // } + + // // Force number of position and pointing parameters to each be 3 (X,Y,Z; RA,DEC,TWI) + // // so we can always output a value for them + // int nPositionParameters = 3 * nPositionCoefficients; + // int nPointingParameters = 3 * nPointingCoefficients; + // int nParameters = nPositionParameters + nPointingParameters; + + // coefX.resize(nPositionCoefficients); + // coefY.resize(nPositionCoefficients); + // coefZ.resize(nPositionCoefficients); + // coefRA.resize(nPointingCoefficients); + // coefDEC.resize(nPointingCoefficients); + // coefTWI.resize(nPointingCoefficients); + + // if (m_instrumentPosition) { + // if (!useDefaultPosition) { + // m_instrumentPosition->GetPolynomial(coefX, coefY, coefZ); + // } + // // Use the position's center coordinate if not solving for spacecraft position + // else { + // const std::vector centerCoord = m_instrumentPosition->GetCenterCoordinate(); + // coefX[0] = centerCoord[0]; + // coefY[0] = centerCoord[1]; + // coefZ[0] = centerCoord[2]; + // } + // } + + // if (m_instrumentRotation) { + // if (!useDefaultPointing) { + // m_instrumentRotation->GetPolynomial(coefRA, coefDEC, coefTWI); + // } + // // Use the pointing's center angles if not solving for pointing (rotation) + // else { + // const std::vector centerAngles = m_instrumentRotation->GetCenterAngles(); + // coefRA[0] = centerAngles[0]; + // coefDEC[0] = centerAngles[1]; + // coefTWI[0] = centerAngles[2]; + // } + // } + + // // for convenience, create vectors of parameters names and values in the correct sequence + // std::vector finalParameterValues; + // QStringList parameterNamesList; + + // if (!imageCSV) { + + // QString str("%1(t%2)"); + + // if (nPositionCoefficients > 0) { + // for (int i = 0; i < nPositionCoefficients; i++) { + // finalParameterValues.push_back(coefX[i]); + // if (i == 0) + // parameterNamesList.append( str.arg(" X ").arg("0") ); + // else + // parameterNamesList.append( str.arg(" ").arg(i) ); + // } + // for (int i = 0; i < nPositionCoefficients; i++) { + // finalParameterValues.push_back(coefY[i]); + // if (i == 0) + // parameterNamesList.append( str.arg(" Y ").arg("0") ); + // else + // parameterNamesList.append( str.arg(" ").arg(i) ); + // } + // for (int i = 0; i < nPositionCoefficients; i++) { + // finalParameterValues.push_back(coefZ[i]); + // if (i == 0) + // parameterNamesList.append( str.arg(" Z ").arg("0") ); + // else + // parameterNamesList.append( str.arg(" ").arg(i) ); + // } + // } + // if (nPointingCoefficients > 0) { + // for (int i = 0; i < nPointingCoefficients; i++) { + // finalParameterValues.push_back(coefRA[i] * RAD2DEG); + // if (i == 0) + // parameterNamesList.append( str.arg(" RA ").arg("0") ); + // else + // parameterNamesList.append( str.arg(" ").arg(i) ); + // } + // for (int i = 0; i < nPointingCoefficients; i++) { + // finalParameterValues.push_back(coefDEC[i] * RAD2DEG); + // if (i == 0) + // parameterNamesList.append( str.arg("DEC ").arg("0") ); + // else + // parameterNamesList.append( str.arg(" ").arg(i) ); + // } + // for (int i = 0; i < nPointingCoefficients; i++) { + // finalParameterValues.push_back(coefTWI[i] * RAD2DEG); + // if (i == 0) + // parameterNamesList.append( str.arg("TWI ").arg("0") ); + // else + // parameterNamesList.append( str.arg(" ").arg(i) ); + // } + // } + + // }// end if(!imageCSV) + + // else { + // if (nPositionCoefficients > 0) { + // for (int i = 0; i < nPositionCoefficients; i++) { + // finalParameterValues.push_back(coefX[i]); + // } + // for (int i = 0; i < nPositionCoefficients; i++) { + // finalParameterValues.push_back(coefY[i]); + // } + // for (int i = 0; i < nPositionCoefficients; i++) { + // finalParameterValues.push_back(coefZ[i]); + // } + // } + // if (nPointingCoefficients > 0) { + // for (int i = 0; i < nPointingCoefficients; i++) { + // finalParameterValues.push_back(coefRA[i] * RAD2DEG); + // } + // for (int i = 0; i < nPointingCoefficients; i++) { + // finalParameterValues.push_back(coefDEC[i] * RAD2DEG); + // } + // for (int i = 0; i < nPointingCoefficients; i++) { + // finalParameterValues.push_back(coefTWI[i] * RAD2DEG); + // } + // } + // }//end else + + // // Save the list of parameter names we've accumulated above + // m_parameterNamesList = parameterNamesList; + + // QString finalqStr = ""; + // QString qStr = ""; + + // // Set up default values when we are using default position + // QString sigma = "N/A"; + // QString adjustedSigma = "N/A"; + // double correction = 0.0; + + // // this implies we're writing to bundleout.txt + // if (!imageCSV) { + // // position parameters + // for (int i = 0; i < nPositionParameters; i++) { + // // If not using the default position, we can correctly access sigmas and corrections + // // members + // if (!useDefaultPosition) { + // correction = m_corrections(i); + // adjustedSigma = QString::number(m_adjustedSigmas[i], 'f', 8); + // sigma = ( IsSpecial(m_aprioriSigmas[i]) ? "FREE" : toString(m_aprioriSigmas[i], 8) ); + // } + // if (errorPropagation) { + // qStr = QString("%1%2%3%4%5%6\n"). + // arg( parameterNamesList.at(i) ). + // arg(finalParameterValues[i] - correction, 17, 'f', 8). + // arg(correction, 21, 'f', 8). + // arg(finalParameterValues[i], 20, 'f', 8). + // arg(sigma, 18). + // arg(adjustedSigma, 18); + // } + // else { + // qStr = QString("%1%2%3%4%5%6\n"). + // arg( parameterNamesList.at(i) ). + // arg(finalParameterValues[i] - correction, 17, 'f', 8). + // arg(correction, 21, 'f', 8). + // arg(finalParameterValues[i], 20, 'f', 8). + // arg(sigma, 18). + // arg("N/A", 18); + // } + // finalqStr += qStr; + // } + + // // We need to use an offset of -3 (1 coef; X,Y,Z) if we used the default center coordinate + // // (i.e. we did not solve for position), as m_corrections and m_*sigmas are populated + // // according to which parameters are solved + // int offset = 0; + // if (useDefaultPosition) { + // offset = 3; + // } + // // pointing parameters + // for (int i = nPositionParameters; i < nParameters; i++) { + // if (!useDefaultPointing) { + // // If solving camera and not solving for twist, provide default values for twist to + // // prevent bad indexing into m_corrections and m_*sigmas + // // TWIST is last parameter, which corresponds to nParameters - nPointingCoefficients + // if ( (i >= nParameters - nPointingCoefficients) && useDefaultTwist) { + // correction = 0.0; + // adjustedSigma = "N/A"; + // sigma = "N/A"; + // } + // else { + // correction = m_corrections(i - offset); + // adjustedSigma = QString::number(m_adjustedSigmas(i-offset) * RAD2DEG, 'f', 8); + // sigma = ( IsSpecial(m_aprioriSigmas[i - offset]) ? "FREE" : + // toString(m_aprioriSigmas[i-offset], 8) ); + // } + // } + // // We are using default pointing, so provide default correction and sigma values to output + // else { + // correction = 0.0; + // adjustedSigma = "N/A"; + // sigma = "N/A"; + // } + // if (errorPropagation) { + // qStr = QString("%1%2%3%4%5%6\n"). + // arg( parameterNamesList.at(i) ). + // arg( (finalParameterValues[i] - correction * RAD2DEG), 17, 'f', 8). + // arg(correction * RAD2DEG, 21, 'f', 8). + // arg(finalParameterValues[i], 20, 'f', 8). + // arg(sigma, 18). + // arg(adjustedSigma, 18); + // } + // else { + // qStr = QString("%1%2%3%4%5%6\n"). + // arg( parameterNamesList.at(i) ). + // arg( (finalParameterValues[i] - correction * RAD2DEG), 17, 'f', 8). + // arg(correction * RAD2DEG, 21, 'f', 8). + // arg(finalParameterValues[i], 20, 'f', 8). + // arg(sigma, 18). + // arg("N/A", 18); + // } + // finalqStr += qStr; + // } + + // } + // // this implies we're writing to images.csv + // else { + // // position parameters + // for (int i = 0; i < nPositionParameters; i++) { + // if (!useDefaultPosition) { + // correction = m_corrections(i); + // adjustedSigma = QString::number(m_adjustedSigmas[i], 'f', 8); + // sigma = ( IsSpecial(m_aprioriSigmas[i]) ? "FREE" : toString(m_aprioriSigmas[i], 8) ); + // } + // // Provide default values for position if not solving position + // else { + // correction = 0.0; + // adjustedSigma = "N/A"; + // sigma = "N/A"; + // } + // qStr = ""; + // if (errorPropagation) { + // qStr += toString(finalParameterValues[i] - correction) + ","; + // qStr += toString(correction) + ","; + // qStr += toString(finalParameterValues[i]) + ","; + // qStr += sigma + ","; + // qStr += adjustedSigma + ","; + // } + // else { + // qStr += toString(finalParameterValues[i] - correction) + ","; + // qStr += toString(correction) + ","; + // qStr += toString(finalParameterValues[i]) + ","; + // qStr += sigma + ","; + // qStr += "N/A,"; + // } + // finalqStr += qStr; + // } + + // // If not solving position, we need to offset access to correction and sigma members by -3 + // // (X,Y,Z) since m_corrections and m_*sigmas are populated according to which parameters are + // // solved + // int offset = 0; + // if (useDefaultPosition) { + // offset = 3; + // } + // // pointing parameters + // for (int i = nPositionParameters; i < nParameters; i++) { + // if (!useDefaultPointing) { + // // Use default values if solving camera but not solving for TWIST to prevent bad indexing + // // into m_corrections and m_*sigmas + // if ( (i >= nParameters - nPointingCoefficients) && useDefaultTwist) { + // correction = 0.0; + // adjustedSigma = "N/A"; + // sigma = "N/A"; + // } + // else { + // correction = m_corrections(i - offset); + // adjustedSigma = QString::number(m_adjustedSigmas(i-offset) * RAD2DEG, 'f', 8); + // sigma = ( IsSpecial(m_aprioriSigmas[i-offset]) ? "FREE" : + // toString(m_aprioriSigmas[i-offset], 8) ); + // } + // } + // // Provide default values for pointing if not solving pointing + // else { + // correction = 0.0; + // adjustedSigma = "N/A"; + // sigma = "N/A"; + // } + // qStr = ""; + // if (errorPropagation) { + // qStr += toString(finalParameterValues[i] - correction * RAD2DEG) + ","; + // qStr += toString(correction * RAD2DEG) + ","; + // qStr += toString(finalParameterValues[i]) + ","; + // qStr += sigma + ","; + // qStr += adjustedSigma + ","; + // } + // else { + // qStr += toString(finalParameterValues[i] - correction * RAD2DEG) + ","; + // qStr += toString(correction * RAD2DEG) + ","; + // qStr += toString(finalParameterValues[i]) + ","; + // qStr += sigma + ","; + // qStr += "N/A,"; + // } + // finalqStr += qStr; + // } + // } + + return ""; +} + + + /** + * @brief Takes in an open std::ofstream and writes out information which goes into the + * bundleout.txt file. + * + * @param fpOut The open std::ofstream object which is passed in from + * BundleSolutionInfo::outputText() + * @param errorPropagation Boolean indicating whether or not to attach more information + * (corrections, sigmas, adjusted sigmas...) to the output. + */ + void CsmBundleObservation::bundleOutputString(std::ostream &fpOut, bool errorPropagation) { + // TODO implement for CSM + + // char buf[4096]; + + // QVector finalParameterValues; + // int nPositionCoefficients, nPointingCoefficients; + // bool useDefaultPosition, useDefaultPointing,useDefaultTwist; + + // bundleOutputFetchData(finalParameterValues, + // nPositionCoefficients,nPointingCoefficients, + // useDefaultPosition,useDefaultPointing,useDefaultTwist); + + // int nPositionParameters = 3 * nPositionCoefficients; + // int nPointingParameters = 3 * nPointingCoefficients; + // int nParameters = nPositionParameters + nPointingParameters; + + // // for convenience, create vectors of parameters names and values in the correct sequence + // QStringList parameterNamesListX,parameterNamesListY,parameterNamesListZ, + // parameterNamesListRA,parameterNamesListDEC,parameterNamesListTWI, + // parameterNamesList; + // QStringList correctionUnitListX,correctionUnitListY,correctionUnitListZ, + // correctionUnitListRA,correctionUnitListDEC,correctionUnitListTWI, + // correctionUnitList; + + // QString str("%1(%2) "); + // QString str2("%1(%2) "); + // QString strN("%1(%2)"); + + + // if (nPositionCoefficients > 0) { + // for (int j = 0; j < nPositionCoefficients;j++) { + // if (j == 0) { + // parameterNamesListX.append(str.arg(" X ").arg("km")); + // parameterNamesListY.append(str.arg(" Y ").arg("km")); + // parameterNamesListZ.append(str.arg(" Z ").arg("km")); + // correctionUnitListX.append("m"); + // correctionUnitListY.append("m"); + // correctionUnitListZ.append("m"); + // } //end inner-if + + // else if (j==1) { + // parameterNamesListX.append( str2.arg(" ").arg("km/s") ); + // parameterNamesListY.append( str2.arg(" ").arg("km/s") ); + // parameterNamesListZ.append( str2.arg(" ").arg("km/s") ); + // correctionUnitListX.append("m/s"); + // correctionUnitListY.append("m/s"); + // correctionUnitListZ.append("m/s"); + // } + // else { + // QString str("%1(%2)"); + // parameterNamesListX.append(strN.arg(" ").arg("km/s^"+toString(j) ) ); + // parameterNamesListY.append(strN.arg(" ").arg("km/s^"+toString(j) ) ); + // parameterNamesListZ.append(strN.arg(" ").arg("km/s^"+toString(j) ) ); + // correctionUnitListX.append("m/s^"+toString(j)); + // correctionUnitListY.append("m/s^"+toString(j)); + // correctionUnitListZ.append("m/s^"+toString(j)); + // } + // }//end for + // }//end outer-if + + // if (nPointingCoefficients > 0) { + // for (int j = 0; j < nPointingCoefficients;j++) { + // if (j == 0) { + // parameterNamesListRA.append(str.arg(" RA ").arg("dd")); + // parameterNamesListDEC.append(str.arg("DEC ").arg("dd")); + // parameterNamesListTWI.append(str.arg("TWI ").arg("dd")); + // correctionUnitListRA.append("dd"); + // correctionUnitListDEC.append("dd"); + // correctionUnitListTWI.append("dd"); + // } //end inner-if + + // else if (j==1) { + // parameterNamesListRA.append( str2.arg(" ").arg("dd/s") ); + // parameterNamesListDEC.append( str2.arg(" ").arg("dd/s") ); + // parameterNamesListTWI.append( str2.arg(" ").arg("dd/s") ); + // correctionUnitListRA.append("dd/s"); + // correctionUnitListDEC.append("dd/s"); + // correctionUnitListTWI.append("dd/s"); + // } + // else { + // parameterNamesListRA.append(strN.arg(" ").arg("dd/s^"+toString(j) ) ); + // parameterNamesListDEC.append(strN.arg(" ").arg("dd/s^"+toString(j) ) ); + // parameterNamesListTWI.append(strN.arg(" ").arg("dd/s^"+toString(j) ) ); + // correctionUnitListRA.append("dd/s^"+toString(j)); + // correctionUnitListDEC.append("dd/s^"+toString(j)); + // correctionUnitListTWI.append("dd/s^"+toString(j)); + // } + // }//end for + // }// end outer-if + + // //Put all of the parameter names together into one QStringList + // parameterNamesList.append(parameterNamesListX); + // parameterNamesList.append(parameterNamesListY); + // parameterNamesList.append(parameterNamesListZ); + // parameterNamesList.append(parameterNamesListRA); + // parameterNamesList.append(parameterNamesListDEC); + // parameterNamesList.append(parameterNamesListTWI); + + // //Put all of the correction unit names together into one QStringList + // correctionUnitList.append(correctionUnitListX); + // correctionUnitList.append(correctionUnitListY); + // correctionUnitList.append(correctionUnitListZ); + // correctionUnitList.append(correctionUnitListDEC); + // correctionUnitList.append(correctionUnitListRA); + // correctionUnitList.append(correctionUnitListTWI); + + // // Save the list of parameter names we've accumulated above + // m_parameterNamesList = parameterNamesList; + + // // Set up default values when we are using default position + // QString sigma = "N/A"; + // QString adjustedSigma = "N/A"; + // double correction = 0.0; + + // // position parameters + // for (int i = 0; i < nPositionParameters; i++) { + // // If not using the default position, we can correctly access sigmas and corrections + // // members + // if (!useDefaultPosition) { + // correction = m_corrections(i); + // adjustedSigma = QString::number(m_adjustedSigmas[i], 'f', 8); + // sigma = ( IsSpecial(m_aprioriSigmas[i]) ? "FREE" : toString(m_aprioriSigmas[i], 8) ); + // } + + // sprintf(buf,"%s",parameterNamesList.at(i).toStdString().c_str() ); + // fpOut << buf; + // sprintf(buf,"%18.8lf ",finalParameterValues[i] - correction); + // fpOut << buf; + // sprintf(buf,"%20.8lf ",correction); + // fpOut << buf; + // sprintf(buf,"%23.8lf ",finalParameterValues[i]); + // fpOut << buf; + // sprintf(buf," "); + // fpOut << buf; + // sprintf(buf,"%6s",sigma.toStdString().c_str()); + // fpOut << buf; + // sprintf(buf," "); + // fpOut << buf; + // if (errorPropagation) { + // sprintf(buf,"%s",adjustedSigma.toStdString().c_str()); + // } + // else { + // sprintf(buf,"%s","N/A"); + // } + // fpOut<= nParameters - nPointingCoefficients) && useDefaultTwist) { + // correction = 0.0; + // adjustedSigma = "N/A"; + // sigma = "N/A"; + // } + // else { + // correction = m_corrections(i - offset); + // adjustedSigma = QString::number(m_adjustedSigmas(i-offset) * RAD2DEG, 'f', 8); + // sigma = ( IsSpecial(m_aprioriSigmas[i - offset]) ? "FREE" : + // toString(m_aprioriSigmas[i-offset], 8) ); + // } + // } + // // We are using default pointing, so provide default correction and sigma values to output + // else { + // correction = 0.0; + // adjustedSigma = "N/A"; + // sigma = "N/A"; + // } + + // sprintf(buf,"%s",parameterNamesList.at(i).toStdString().c_str() ); + // fpOut << buf; + // sprintf(buf,"%18.8lf ",(finalParameterValues[i]*RAD2DEG - correction*RAD2DEG)); + // fpOut << buf; + // sprintf(buf,"%20.8lf ",(correction*RAD2DEG)); + // fpOut << buf; + // sprintf(buf,"%23.8lf ",(finalParameterValues[i]*RAD2DEG)); + // fpOut << buf; + // sprintf(buf," "); + // fpOut << buf; + // sprintf(buf,"%6s",sigma.toStdString().c_str()); + // fpOut << buf; + // sprintf(buf," "); + // fpOut << buf; + // if (errorPropagation) { + // sprintf(buf,"%s",adjustedSigma.toStdString().c_str()); + // } + // else { + // sprintf(buf,"%s","N/A"); + // } + // fpOut< finalParameterValues; + // int nPositionCoefficients, nPointingCoefficients; + // bool useDefaultPosition, useDefaultPointing,useDefaultTwist; + + // bundleOutputFetchData(finalParameterValues, + // nPositionCoefficients,nPointingCoefficients, + // useDefaultPosition,useDefaultPointing,useDefaultTwist); + + // int nPositionParameters = 3 * nPositionCoefficients; + // int nPointingParameters = 3 * nPointingCoefficients; + // int nParameters = nPositionParameters + nPointingParameters; + + // QString finalqStr = ""; + + // // Set up default values when we are using default position + // QString sigma = "N/A"; + // QString adjustedSigma = "N/A"; + // double correction = 0.0; + + // // Position parameters + // for (int i = 0; i < nPositionParameters; i++) { + // if (!useDefaultPosition) { + // correction = m_corrections(i); + // adjustedSigma = QString::number(m_adjustedSigmas[i], 'f', 8); + // sigma = ( IsSpecial(m_aprioriSigmas[i]) ? "FREE" : toString(m_aprioriSigmas[i], 8) ); + // } + // // Provide default values for position if not solving position + // else { + // correction = 0.0; + // adjustedSigma = "N/A"; + // sigma = "N/A"; + // } + + // finalqStr += toString(finalParameterValues[i] - correction) + ","; + // finalqStr += toString(correction) + ","; + // finalqStr += toString(finalParameterValues[i]) + ","; + // finalqStr += sigma + ","; + // if (errorPropagation) { + // finalqStr += adjustedSigma + ","; + // } + // else { + // finalqStr += "N/A,"; + // } + + // } + + // // If not solving position, we need to offset access to correction and sigma members by -3 + // // (X,Y,Z) since m_corrections and m_*sigmas are populated according to which parameters are + // // solved + // int offset = 0; + // if (useDefaultPosition) { + // offset = 3; + // } + // // pointing parameters + // for (int i = nPositionParameters; i < nParameters; i++) { + // if (!useDefaultPointing) { + // // Use default values if solving camera but not solving for TWIST to prevent bad indexing + // // into m_corrections and m_*sigmas + // if ( (i >= nParameters - nPointingCoefficients) && useDefaultTwist) { + // correction = 0.0; + // adjustedSigma = "N/A"; + // sigma = "N/A"; + // } + // else { + // correction = m_corrections(i - offset); + // adjustedSigma = QString::number(m_adjustedSigmas(i-offset) * RAD2DEG, 'f', 8); + // sigma = ( IsSpecial(m_aprioriSigmas[i-offset]) ? "FREE" : + // toString(m_aprioriSigmas[i-offset], 8) ); + // } + // } + // // Provide default values for pointing if not solving pointing + // else { + // correction = 0.0; + // adjustedSigma = "N/A"; + // sigma = "N/A"; + // } + + // finalqStr += toString(finalParameterValues[i]*RAD2DEG - correction * RAD2DEG) + ","; + // finalqStr += toString(correction * RAD2DEG) + ","; + // finalqStr += toString(finalParameterValues[i]*RAD2DEG) + ","; + // finalqStr += sigma + ","; + // if (errorPropagation) { + // finalqStr += adjustedSigma + ","; + // } + // else { + // finalqStr += "N/A,"; + // } + + // } + + return ""; + } +} diff --git a/isis/src/control/objs/CsmBundleObservation/CsmBundleObservation.h b/isis/src/control/objs/CsmBundleObservation/CsmBundleObservation.h new file mode 100644 index 0000000000..e393541b97 --- /dev/null +++ b/isis/src/control/objs/CsmBundleObservation/CsmBundleObservation.h @@ -0,0 +1,79 @@ +#ifndef CsmBundleObservation_h +#define CsmBundleObservation_h + +/** This is free and unencumbered software released into the public domain. + +The authors of ISIS do not claim copyright on the contents of this file. +For more details about the LICENSE terms and the AUTHORS, you will +find files of those names at the top level of this repository. **/ + +/* SPDX-License-Identifier: CC0-1.0 */ + +#include +#include + +#include "BundleImage.h" +#include "CsmBundleObservationSolveSettings.h" +#include "BundleObservationSolveSettings.h" +#include "BundleTargetBody.h" +#include "LinearAlgebra.h" +#include "AbstractBundleObservation.h" + +namespace Isis { + + /** + * @brief Class for bundle observations + * + * This class is used for creating a bundle observation. Contained BundleImages are stored as + * shared pointers, so they will be automatically deleted when all shared pointers are deleted. + * + * @ingroup ControlNetworks + * + * @author 2021-04-19 Jesse Mapel + * + */ + class CsmBundleObservation : public AbstractBundleObservation { + + public: + // default constructor + CsmBundleObservation(); + + // constructor + CsmBundleObservation(BundleImageQsp image, QString observationNumber, QString instrumentId, + BundleTargetBodyQsp bundleTargetBody); + + // copy constructor + CsmBundleObservation(const CsmBundleObservation &src); + + // destructor + ~CsmBundleObservation(); + + // equals operator + CsmBundleObservation &operator=(const CsmBundleObservation &src); + + // copy method + void copy(const CsmBundleObservation &src); + + bool setSolveSettings(CsmBundleObservationSolveSettingsQsp solveSettings); + + int numberParameters(); + + const BundleObservationSolveSettingsQsp solveSettings(); + + bool applyParameterCorrections(LinearAlgebra::Vector corrections); + + void bundleOutputString(std::ostream &fpOut,bool errorPropagation); + QString bundleOutputCSV(bool errorPropagation); + + QString formatBundleOutputString(bool errorPropagation, bool imageCSV=false); + + private: + bool initParameterWeights(); + + private: + CsmBundleObservationSolveSettingsQsp m_solveSettings; //!< Solve settings for this observation. + std::vector m_paramIndices; //!< The indices of the parameters the observation is solving for + }; +} + +#endif // CsmBundleObservation_h diff --git a/isis/src/control/objs/CsmBundleObservation/CsmBundleObservationSolveSettings.cpp b/isis/src/control/objs/CsmBundleObservation/CsmBundleObservationSolveSettings.cpp new file mode 100644 index 0000000000..f47a2846fb --- /dev/null +++ b/isis/src/control/objs/CsmBundleObservation/CsmBundleObservationSolveSettings.cpp @@ -0,0 +1,29 @@ +/** This is free and unencumbered software released into the public domain. + +The authors of ISIS do not claim copyright on the contents of this file. +For more details about the LICENSE terms and the AUTHORS, you will +find files of those names at the top level of this repository. **/ + +/* SPDX-License-Identifier: CC0-1.0 */ + +#include "CsmBundleObservationSolveSettings.h" + +namespace Isis { + + /** + * Create the solution settings for a CSM observation + * + * @param solveSet the CSM set of parameters to solve for + */ + CsmBundleObservationSolveSettings::CsmBundleObservationSolveSettings(csm::param::Set solveSet) + : m_solveSet(solveSet) {} + + /** + * Return the set of parameters to solve for + * + * @returns @b csm::param::Set + */ + csm::param::Set CsmBundleObservationSolveSettings::solveSet() { + return m_solveSet; + } +} \ No newline at end of file diff --git a/isis/src/control/objs/CsmBundleObservation/CsmBundleObservationSolveSettings.h b/isis/src/control/objs/CsmBundleObservation/CsmBundleObservationSolveSettings.h new file mode 100644 index 0000000000..821a9ccc5b --- /dev/null +++ b/isis/src/control/objs/CsmBundleObservation/CsmBundleObservationSolveSettings.h @@ -0,0 +1,42 @@ +#ifndef CsmBundleObservationSolveSettings_h +#define CsmBundleObservationSolveSettings_h + +/** This is free and unencumbered software released into the public domain. + +The authors of ISIS do not claim copyright on the contents of this file. +For more details about the LICENSE terms and the AUTHORS, you will +find files of those names at the top level of this repository. **/ + +/* SPDX-License-Identifier: CC0-1.0 */ + +#include +#include + +namespace Isis { + + /** + * @brief Class to hold solve settings for CSM observations + * + * @ingroup ControlNetworks + * + * @author 2021-04-19 Jesse Mapel + * + */ + class CsmBundleObservationSolveSettings { + + public: + CsmBundleObservationSolveSettings(csm::param::Set solveSet); + ~CsmBundleObservationSolveSettings(); + + csm::param::Set solveSet(); + + private: + csm::param::Set m_solveSet; //! The set of parameters to solve for + + }; + + typedef QSharedPointer CsmBundleObservationSolveSettingsQsp; + +} + +#endif // CsmBundleObservationSolveSettings_h \ No newline at end of file diff --git a/isis/tests/CSMCameraTests.cpp b/isis/tests/CSMCameraTests.cpp index 5c3fedc3c8..9935fcf20d 100644 --- a/isis/tests/CSMCameraTests.cpp +++ b/isis/tests/CSMCameraTests.cpp @@ -4,6 +4,7 @@ #include "csm/csm.h" #include "csm/Ellipsoid.h" +#include "CSMCamera.h" #include "Fixtures.h" #include "iTime.h" #include "Latitude.h" @@ -250,6 +251,49 @@ TEST_F(CSMCameraSetFixture, EmissionAngle) { } +TEST_F(CSMCameraFixture, getParameterIndices) { + std::vector paramIndices = {0, 1, 2}; + EXPECT_CALL(mockModel, getNumParameters()) + .Times(1) + .WillOnce(::testing::Return(3)); + EXPECT_CALL(mockModel, getParameterType(0)) + .Times(1) + .WillOnce(::testing::Return(csm::param::REAL)); + EXPECT_CALL(mockModel, getParameterType(1)) + .Times(1) + .WillOnce(::testing::Return(csm::param::REAL)); + EXPECT_CALL(mockModel, getParameterType(2)) + .Times(1) + .WillOnce(::testing::Return(csm::param::REAL)); + + std::vector indices = dynamic_cast(testCam)->getParameterIndices(csm::param::ADJUSTABLE); + ASSERT_EQ(indices.size(), paramIndices.size()); + for (size_t i = 0; i < paramIndices.size(); i++) { + EXPECT_EQ(indices[i], paramIndices[i]) << "Error at index " << i; + } +} + + +TEST_F(CSMCameraFixture, applyParameterCorrection) { + EXPECT_CALL(mockModel, getParameterValue(2)) + .Times(1) + .WillOnce(::testing::Return(0.5)); + EXPECT_CALL(mockModel, setParameterValue(2, 1.5)) + .Times(1); + + dynamic_cast(testCam)->applyParameterCorrection(2, 1.0); +} + + +TEST_F(CSMCameraFixture, getParameterCovariance) { + EXPECT_CALL(mockModel, getParameterCovariance(2, 3)) + .Times(1) + .WillOnce(::testing::Return(0.5)); + + EXPECT_EQ(dynamic_cast(testCam)->getParameterCovariance(2, 3), 0.5); +} + + TEST_F(CSMCameraFixture, SetTime) { try {