diff --git a/isis/src/viking/apps/vikcal/tsts/Makefile b/isis/src/viking/apps/vikcal/tsts/Makefile deleted file mode 100644 index 46d84c74c2..0000000000 --- a/isis/src/viking/apps/vikcal/tsts/Makefile +++ /dev/null @@ -1,4 +0,0 @@ -BLANKS = "%-6s" -LENGTH = "%-40s" - -include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/viking/apps/vikcal/tsts/default/Makefile b/isis/src/viking/apps/vikcal/tsts/default/Makefile deleted file mode 100644 index 0e89dd8f96..0000000000 --- a/isis/src/viking/apps/vikcal/tsts/default/Makefile +++ /dev/null @@ -1,9 +0,0 @@ -APPNAME = vikcal - -include $(ISISROOT)/make/isismake.tsts - -commands: - $(APPNAME) from=$(INPUT)/f387a06.cub \ - to=$(OUTPUT)/vikcalTruth.cub > /dev/null; - $(APPNAME) from=$(INPUT)/f319b18.cub \ - to=$(OUTPUT)/vikcalCameraTruth.cub > /dev/null; diff --git a/isis/src/viking/apps/vikcal/vikcal.cpp b/isis/src/viking/apps/vikcal/vikcal.cpp new file mode 100644 index 0000000000..847800d732 --- /dev/null +++ b/isis/src/viking/apps/vikcal/vikcal.cpp @@ -0,0 +1,141 @@ +/** 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 "SpecialPixel.h" +#include "ProcessByLine.h" +#include "UserInterface.h" +#include "Pvl.h" +#include "CalParameters.h" + +#include "vikcal.h" + +using namespace std; + +namespace Isis { + + static void cal(vector &in, + vector &out); + + static CalParameters *calParam; + static bool linear; + + void vikcal(UserInterface &ui) { + const QString in = ui.GetFileName("FROM"); + + // Open the input cube + Cube icube(in, "r"); + + vikcal(&icube, ui); + } + + + void vikcal(Cube *icube, UserInterface &ui) { + // We will be processing by line + ProcessByLine p; + + // The linear option can never be true in Isis2, if it is needed, comment out + // the following line, and uncomment the line below it. Also, add the code + // segment found in the CalParameters documentation to the vikcal.xml file + linear = false; + + // linear = ui.GetBoolean("LINEAR"); + const QString in = icube->fileName(); + + // Open the input cube + calParam = new CalParameters(in, icube); + Progress prog; + + // If the file has already been calibrated, throw an error + if(icube->hasGroup("Radiometry")) { + QString msg = "The Viking image [" + icube->fileName() + "] has already " + "been radiometrically calibrated"; + throw IException(IException::User, msg, _FILEINFO_); + } + + CubeAttributeInput dcf; + CubeAttributeInput fff; + const QString gainFile = (QString)FileName(calParam->GainFile()).expanded(); + const QString offsetFile = (QString)FileName(calParam->OffsetFile()).expanded(); + + // Setup the input cubes + p.SetInputCube(icube); + p.SetInputCube(offsetFile, dcf); + p.SetInputCube(gainFile, fff); + + // Setup the output cube + Cube *ocube = p.SetOutputCubeStretch("TO", &ui); + + // Set up and add the radiometry group to the output cube label + PvlGroup calgrp("Radiometry"); + + calgrp.addComment("Calibration equation in vikcal"); + calgrp.addComment("DI(l,s) = (1.0/(exp*w1))*G(l,s)*(gain*DR(l,s)+DC(l,s)+offt+offc)"); + calgrp.addComment("with w1 = w0*((dist0*dist0) / (dist1*dist1))"); + calgrp.addComment("and offt(l,s) = A*l + B*l*l + C*s + D*l*s + E"); + calgrp += PvlKeyword("offc", toString(calParam->Offset())); + calgrp += PvlKeyword("exp", toString(calParam->Exposure())); + calgrp += PvlKeyword("gain", toString(calParam->Gain())); + calgrp += PvlKeyword("DR", in); + calgrp += PvlKeyword("DC", calParam->OffsetFile()); + calgrp += PvlKeyword("G", calParam->GainFile()); + + calgrp += PvlKeyword("w0", toString(calParam->Omega0())); + calgrp += PvlKeyword("w1", toString(calParam->Omega1())); + calgrp += PvlKeyword("dist0", toString(calParam->Distance())); + calgrp += PvlKeyword("dist1", toString(calParam->Dist1())); + calgrp += PvlKeyword("1.0/exp*w1", toString(1.0 / (calParam->Exposure() * calParam->Omega1()))); + + calgrp += PvlKeyword("Acoeff", toString(calParam->Acoeff())); + calgrp += PvlKeyword("Bcoeff", toString(calParam->Bcoeff())); + calgrp += PvlKeyword("Ccoeff", toString(calParam->Ccoeff())); + calgrp += PvlKeyword("Dcoeff", toString(calParam->Dcoeff())); + calgrp += PvlKeyword("Ecoeff", toString(calParam->Ecoeff())); + + ocube->putGroup(calgrp); + + // Start the calibration process + p.StartProcess(cal); + p.EndProcess(); + } + + void cal(vector &in, vector &out) { + + Buffer &inp = *in[0]; // Input Cube + Buffer &dcf = *in[1]; // Dark Current File + Buffer &fff = *in[2]; // Flat Field File + Buffer &outp = *out[0]; // Output Cube + + // Loop for each pixel in the line. + for(int i = 0; i < inp.size(); i++) { + if(IsSpecial(inp[i])) { + outp[i] = inp[i]; + } + else if(IsSpecial(fff[i]) || IsSpecial(dcf[i])) { + outp[i] = Isis::Null; + } + else { + double offc = calParam->TimeBasedOffset(inp.Line(), i + 1); + double dnraw = (inp[i] * calParam->Gain()) + dcf[i] + offc; + + // The linear option can never be true in isis2, and therefore, this + // section of the code has not been tested. + if(linear == true) { + double temp = (dnraw / calParam->NormalizingPower()); + for(int i = 1; i < calParam->LinearityPower(); i++) { + temp *= (dnraw / calParam->NormalizingPower()); + } + dnraw = calParam->Acoeff() * dnraw + calParam->Bcoeff() * temp; + } + + double xmlt = 1.0 / (calParam->Exposure() * calParam->Omega1()); + outp[i] = xmlt * fff[i] * dnraw; + } + } + + } +} \ No newline at end of file diff --git a/isis/src/viking/apps/vikcal/vikcal.h b/isis/src/viking/apps/vikcal/vikcal.h new file mode 100644 index 0000000000..fbe6433c57 --- /dev/null +++ b/isis/src/viking/apps/vikcal/vikcal.h @@ -0,0 +1,12 @@ +#ifndef vikcal_h // Change this to your app name in all lower case suffixed with _h (e.g. campt_h, cam2map_h etc.) +#define vikcal_h + +#include "Cube.h" +#include "UserInterface.h" + +namespace Isis{ + extern void vikcal(Cube *cube, UserInterface &ui); + extern void vikcal(UserInterface &ui); +} + +#endif \ No newline at end of file diff --git a/isis/tests/FunctionalTestsVikcal.cpp b/isis/tests/FunctionalTestsVikcal.cpp new file mode 100644 index 0000000000..76fdcf7f58 --- /dev/null +++ b/isis/tests/FunctionalTestsVikcal.cpp @@ -0,0 +1,90 @@ +#include "Fixtures.h" +#include "Pvl.h" +#include "PvlGroup.h" +#include "TestUtilities.h" +#include "Histogram.h" + +#include "vikcal.h" + +#include "gtest/gtest.h" + +using namespace Isis; + +static QString APP_XML = FileName("$ISISROOT/bin/xml/vikcal.xml").expanded(); + +TEST_F(DefaultCube, FunctionalTestVikcalDefault) { + // Note: DefaultCube is a viking image + + QString outCubeFileName = tempDir.path() + "/outTemp.cub"; + QVector args = {"to="+outCubeFileName}; + + UserInterface options(APP_XML, args); + try { + vikcal(testCube, options); + } + catch (IException &e) { + FAIL() << "Unable to open image: " << e.what() << std::endl; + } + + Cube oCube(outCubeFileName, "r"); + + PvlGroup radGroup = oCube.label()->findObject("IsisCube").findGroup("Radiometry"); + + EXPECT_DOUBLE_EQ((double)radGroup.findKeyword("offc"), 0); + EXPECT_DOUBLE_EQ((double)radGroup.findKeyword("exp"), 7.73); + EXPECT_DOUBLE_EQ((double)radGroup.findKeyword("gain"), 1.0); + EXPECT_DOUBLE_EQ((double)radGroup.findKeyword("w0"), 90.36); + EXPECT_DOUBLE_EQ((double)radGroup.findKeyword("w1"), 119.84873964656); + EXPECT_DOUBLE_EQ((double)radGroup.findKeyword("dist0"), 243840000.0); + EXPECT_DOUBLE_EQ((double)radGroup.findKeyword("dist1"), 211727039.58284); + EXPECT_DOUBLE_EQ((double)radGroup.findKeyword("1.0/exp*w1"), 0.0010794114853583); + + Histogram *oCubeStats = oCube.histogram(); + + EXPECT_DOUBLE_EQ(oCubeStats->Average(), 0.14601107854966053); + EXPECT_DOUBLE_EQ(oCubeStats->Sum(), 184914.12430735352); + EXPECT_DOUBLE_EQ(oCubeStats->ValidPixels(), 1266439); + EXPECT_DOUBLE_EQ(oCubeStats->StandardDeviation(), 0.07892281197170499); +} + + +TEST_F(DefaultCube, FunctionalTestCtxcalCameraComparison) { + // Note: DefaultCube is a viking image + + QString outCubeFileNameCam = tempDir.path() + "/outTemp.cub"; + QVector args = {"to="+outCubeFileNameCam}; + + UserInterface options(APP_XML, args); + + try { + vikcal(testCube, options); + } + catch (IException &e) { + FAIL() << "Unable to open image: " << e.what() << std::endl; + } + + // force camera to not construct + Pvl *lab = testCube->label(); + lab->deleteObject("NaifKeywords"); + + QString outCubeFileNameNoCam = tempDir.path() + "/outTempNoCam.cub"; + args = {"to="+outCubeFileNameNoCam}; + + try { + vikcal(testCube, options); + } + catch (IException &e) { + FAIL() << "Unable to open image: " << e.what() << std::endl; + } + + Cube oNoCamCube(outCubeFileNameCam, "r"); + Cube oCamCube(outCubeFileNameCam, "r"); + + Pvl *noCamLab = oNoCamCube.label(); + Pvl *camLab = oCamCube.label(); + + EXPECT_DOUBLE_EQ((double)noCamLab->findObject("IsisCube").findGroup("Radiometry").findKeyword("dist1"), + (double)camLab->findObject("IsisCube").findGroup("Radiometry").findKeyword("dist1")); + + EXPECT_DOUBLE_EQ((double)noCamLab->findObject("IsisCube").findGroup("Radiometry").findKeyword("dist1"), 211727039.58284); +} \ No newline at end of file