USGS

Isis 3.0 Application Source Code Reference

Home

clemuvviscal.cpp

Go to the documentation of this file.
00001 #include "Isis.h"
00002 
00003 #include <cmath>
00004 
00005 #include "ProcessByLine.h"
00006 #include "Pixel.h"
00007 #include "Camera.h"
00008 #include "iException.h"
00009 #include "Table.h"
00010 
00011 using namespace std;
00012 using namespace Isis;
00013 
00014 bool conv;
00015 double dcconst;
00016 bool useDcconst;
00017 double focalPlaneTemp;
00018 double exposureDuration;
00019 int offsetModeID;
00020 double gain;
00021 double avgFF;
00022 double cr;
00023 double dist;
00024 double C2;
00025 double correctedExposureDuration;
00026 
00027 const double ACO = 1.062;
00028 const double BCO = -0.1153E-02;
00029 const double CCO = 0.6245E-05;
00030 const double DCO = -0.1216E-07;
00031 const double C3 = 7.13;
00032 const double C4 = -8.177; // Post-readout offset
00033 const double C5 = 15.56;
00034 const double DT = .00068;
00035 
00036 void UvVisCal(std::vector< Isis::Buffer * > &in, std::vector< Isis::Buffer * > &out);
00037 void FixTemp(int);
00038 
00039 void IsisMain() {
00040   // We will be processing by line
00041   ProcessByBrick p;
00042   UserInterface &ui = Application::GetUserInterface();
00043 
00044   // Use the def file for filter constants
00045   Pvl uvvisDef("$clementine1/calibration/uvvis/uvvis.def");
00046 
00047   // Setup the input and output cubes
00048   Cube *icube = p.SetInputCube("FROM");
00049 
00050   Cube *dccube;
00051   if(ui.WasEntered("DCFILE")) {
00052     dccube = p.SetInputCube("DCFILE");
00053   }
00054   else {
00055     string dcfileloc = "$clementine1/calibration/uvvis/";
00056     dcfileloc += "dark_5_15_96.cub";
00057     CubeAttributeInput cubeAtt;
00058     dccube = p.SetInputCube(dcfileloc, cubeAtt);
00059   }
00060 
00061   iString filter = (string)(icube->getGroup("BandBin"))["FilterName"];
00062   filter = filter.DownCase();
00063 
00064   Cube *ffcube;
00065   if(ui.WasEntered("FFFILE")) {
00066     ffcube = p.SetInputCube("FFFILE");
00067   }
00068   else {
00069     // compute default fffile
00070     double compressRatio = (icube->getGroup("Instrument"))["EncodingCompressionRatio"];
00071 
00072     // check to see if cube is compressed or uncompressed
00073     if(compressRatio == 1.0) {
00074       string fffileLoc = "$clementine1/calibration/uvvis/";
00075       fffileLoc += "lu" + filter + "_uncomp_flat_long.cub";
00076       CubeAttributeInput cubeAtt;
00077       ffcube = p.SetInputCube(fffileLoc, cubeAtt);
00078     }
00079     else {
00080       string fffileLoc = "$clementine1/calibration/uvvis/";
00081       fffileLoc += "lu" + filter + "_comp_flat_long.cub";
00082       CubeAttributeInput cubeAtt;
00083       ffcube = p.SetInputCube(fffileLoc, cubeAtt);
00084     }
00085   }
00086 
00087   Cube *ocube = p.SetOutputCube("TO");
00088 
00089   avgFF = uvvisDef.FindGroup("Filter" + filter.UpCase())["AVGFF"];
00090   cr = uvvisDef.FindGroup("Filter" + filter.UpCase())["CO"];
00091   gain = uvvisDef.FindGroup(iString("GainModeID") + iString(icube->getGroup("Instrument")["GainModeID"][0]))["GAIN"];
00092 
00093   useDcconst = ui.WasEntered("DCCONST");
00094   if(useDcconst) {
00095     dcconst = ui.GetDouble("DCCONST");
00096   }
00097   else {
00098     dcconst = 0.0;
00099   }
00100 
00101   conv = ui.GetBoolean("CONV");
00102   exposureDuration = icube->getGroup("Instrument")["ExposureDuration"];
00103   offsetModeID = icube->getGroup("Instrument")["OffsetModeID"];
00104 
00105   if(((string)icube->getGroup("Instrument")["FocalPlaneTemperature"]).compare("UNK") == 0) {
00106     //if FocalPlaneTemp is unknown set it to zero
00107     focalPlaneTemp = 0.0;
00108   }
00109   else {
00110     focalPlaneTemp = icube->getGroup("Instrument")["FocalPlaneTemperature"];
00111   }
00112 
00113   Camera *cam = icube->getCamera();
00114   bool camSuccess = cam->SetImage(icube->getSampleCount() / 2, icube->getLineCount() / 2);
00115 
00116   if(!camSuccess) {
00117     throw iException::Message(iException::Camera, "Unable to calculate the Solar Distance for this cube.", _FILEINFO_);
00118   }
00119 
00120   dist = cam->SolarDistance();
00121 
00122   // If temp. correction set to true, or focal plane temp is zero then use temperature correction
00123   if(ui.GetBoolean("TCOR") || abs(focalPlaneTemp) <= DBL_EPSILON) {
00124     // Temperature correction requires the use of the mission phase
00125     //   (PRELAUNCH, EARTH, LUNAR) and the product ID.
00126     string productID = (string)(icube->getGroup("Archive")["ProductID"]);
00127     char missionPhase = ((string)((icube->getGroup("Archive"))["MissionPhase"])).at(0);
00128     string n1substring(productID.substr(productID.find('.') + 1, productID.length() - 1));
00129     string n2substring(productID.substr(4, productID.find('.') - 1));
00130     int n1 = atoi(n1substring.c_str());
00131     int n2 = atoi(n2substring.c_str());
00132     int phase = 0;
00133 
00134     if(missionPhase == 'L') {
00135       phase = 0;
00136     }
00137     else if(missionPhase == 'E') {
00138       phase = 1;
00139     }
00140     else if(missionPhase == 'P') {
00141       phase = 2;
00142     }
00143     else {
00144       throw iException::Message(iException::Pvl, "Invalid Mission Phase", _FILEINFO_);
00145     }
00146 
00147     // This formula makes the primary search critera the original product ID's extension,
00148     //   the secondary search criteria the mission phase and finally the numerical part of the
00149     //   original product ID.
00150     int imageID = (100000 * n1) + (10000 * phase) + n2;
00151     FixTemp(imageID);
00152   }
00153 
00154   if(focalPlaneTemp <= 0.0) {
00155     focalPlaneTemp = 272.5;
00156   }
00157 
00158   // Start the processing
00159   p.SetBrickSize(icube->getSampleCount(), icube->getLineCount(), 1);
00160   p.StartProcess(UvVisCal);
00161 
00162   // Add the radiometry group
00163   PvlGroup calgrp("Radiometry");
00164   calgrp += PvlKeyword("FlatFieldFile", ffcube->getFilename());
00165 
00166   if(ui.GetString("DARKCURRENT").compare("DCFILE") == 0) {
00167     calgrp += PvlKeyword("DarkCurrentFile", dccube->getFilename());
00168   }
00169   else {
00170     calgrp += PvlKeyword("DarkCurrentConstant", dcconst);
00171   }
00172 
00173   calgrp += PvlKeyword("CorrectedFocalPlaneTemp", focalPlaneTemp);
00174   calgrp += PvlKeyword("C1", avgFF);
00175   calgrp += PvlKeyword("C2", C2);
00176   calgrp += PvlKeyword("C3", C3);
00177   calgrp += PvlKeyword("C4", C4);
00178   calgrp += PvlKeyword("C5", C5);
00179   calgrp += PvlKeyword("CR", cr);
00180   calgrp += PvlKeyword("FrameTransferTimePerRow", cr);
00181   calgrp += PvlKeyword("Gain", gain);
00182   calgrp += PvlKeyword("CorrectedExposureDuration", correctedExposureDuration);
00183   calgrp += PvlKeyword("ConvertToRadiance", conv);
00184 
00185   calgrp += PvlKeyword("ACO", ACO);
00186   calgrp += PvlKeyword("BCO", BCO);
00187   calgrp += PvlKeyword("CCO", CCO);
00188   calgrp += PvlKeyword("DCO", DCO);
00189 
00190   ocube->putGroup(calgrp);
00191   p.EndProcess();
00192 }
00193 
00194 void UvVisCal(std::vector< Isis::Buffer * > &in, std::vector< Isis::Buffer * > &out) {
00195 #define INPUT_CUBE (*in[0])
00196 #define DC_CUBE (*in[1])
00197 #define FF_CUBE (*in[2])
00198 #define OUTPUT_CUBE (*out[0])
00199 
00200   C2 = 0.003737 * exp(0.0908 * (focalPlaneTemp - 273.15));
00201   correctedExposureDuration = exposureDuration + 0.0494;
00202 
00203   double dc = 0.0;
00204   bool valid = false;
00205   double *sum, *ro;
00206 
00207   sum = new double[INPUT_CUBE.SampleDimension()];
00208   ro = new double[INPUT_CUBE.SampleDimension()];
00209 
00210   for(int iSample = 0; iSample < INPUT_CUBE.SampleDimension(); iSample++) {
00211     ro[iSample] = 0.0;
00212     sum[iSample] = 0.0;
00213 
00214     for(int iLine = 0; iLine < INPUT_CUBE.LineDimension(); iLine ++) {
00215       valid = false;
00216       int index = INPUT_CUBE.SampleDimension() * iLine + iSample;
00217 
00218       if(Pixel::IsSpecial(INPUT_CUBE[index])) {
00219         OUTPUT_CUBE[index] = INPUT_CUBE[index];
00220 
00221         if(Pixel::IsHigh(INPUT_CUBE[index])) {
00222           sum[iSample] += 255;
00223         }
00224       }
00225       else {
00226         if(Pixel::IsSpecial(FF_CUBE[index])) {  //check DCFILE
00227           OUTPUT_CUBE[index] = Isis::Null;
00228           sum[iSample] += INPUT_CUBE[index];
00229         }
00230         else {
00231           valid = true;
00232           if(!useDcconst) {
00233             dc = DC_CUBE[index];
00234           }
00235           else {
00236             dc = dcconst;
00237           }
00238         }
00239       }
00240 
00241       if(valid) {
00242         //Global Offset Corrections
00243         double step1_dn = INPUT_CUBE[index] - (C4 * offsetModeID) - C5;
00244         //Gain Correction
00245         double step2_dn = step1_dn / gain;
00246         //Pixel dependent dark current correction
00247         double step3_dn = step2_dn - (dc + C3);
00248         //Non-linearity correction
00249         double xmul = ACO + (BCO * step3_dn) + (CCO * pow(step3_dn, 2)) + (DCO * pow(step3_dn, 3));
00250         double corstep3_dn = step3_dn * xmul;
00251         //Tempurature-dependent offset correction
00252         double rotim = 60.05 + 0.05 * iLine;
00253         double u = correctedExposureDuration + rotim;
00254         double step4_dn = corstep3_dn - (C2 * u);
00255         OUTPUT_CUBE[index] = step4_dn;
00256         sum[iSample] += step4_dn;
00257       }
00258     }
00259 
00260     ro[iSample] = sum[iSample] * DT / (correctedExposureDuration + (288.0 * DT));
00261   }
00262 
00263   for(int iLine = 0; iLine < INPUT_CUBE.LineDimension(); iLine ++) {
00264     for(int iSample = 0; iSample < INPUT_CUBE.SampleDimension(); iSample++) {
00265       valid = false;
00266       int index = INPUT_CUBE.SampleDimension() * iLine + iSample;
00267       if(!Pixel::IsSpecial(INPUT_CUBE[index])) {
00268         if(Pixel::IsSpecial(FF_CUBE[index])) {  //check FFFILE
00269           OUTPUT_CUBE[index] = Isis::Null;
00270         }
00271         else {
00272           valid = true;
00273         }
00274 
00275         if(valid) {
00276           // Frame transfer correction
00277           double step5_dn = OUTPUT_CUBE[index] - ro[iSample];
00278           // Flat-field and exposure time normalization (Units=counts/ms)
00279           double step6_dn = step5_dn / (FF_CUBE[index] * correctedExposureDuration);
00280           // Normalize to sun-moon distance of 1AU
00281           double step7_dn = step6_dn * pow(dist, 2);
00282           // Conversion to radience (L=mW/sr-cm*cm)
00283           double L = step7_dn / avgFF;
00284           // Conversion to reflectance
00285           if(conv) {
00286             OUTPUT_CUBE[index] = step7_dn * cr;
00287           }
00288           else {
00289             OUTPUT_CUBE[index] = L;
00290           }
00291         }
00292       }
00293     }
00294   }
00295 
00296   delete sum;
00297   delete ro;
00298 }
00299 
00300 /*
00301  * In the ISIS2 Fortran we noticed FIXTEMP uses a REAL*4 to store the RIMGID.
00302  * This results in the last digit being lost precision. The table that
00303  * it looks in for data is also store as a REAL*4 again resulting
00304  * in a loss in precision. We believe this makes the lookup table inaccurate.
00305  */
00306 void FixTemp(int imgID) {
00307   string table = "$clementine1/calibration/uvvis/uvvisTemperature.tbl";
00308   Table t("FocalPlaneTemperatures", table);
00309   float currID = t[0]["ImageID"];
00310   int currIndex = 0;
00311 
00312   do {
00313     currID = t[currIndex]["ImageID"];
00314     currIndex ++;
00315   }
00316   while((imgID > currID) && (currIndex < t.Records()));
00317   currIndex --;  // Fixes an out-of-bounds segmentation fault
00318 
00319   // Make sure currIndex makes sense
00320   if(currIndex < 0 || currIndex >= t.Records()) {
00321     focalPlaneTemp = 0;
00322     return;
00323   }
00324 
00325   // Value too small - look up in the table and see if we're closer
00326   if(currID < imgID) {
00327     double diff = imgID - currID;
00328     if((currIndex + 1 < t.Records()) && abs((float)t[currIndex + 1]["ImageID"] - imgID) < diff) {
00329       currIndex ++;
00330     }
00331   }
00332   // Value too big - look down in the table and see if we're closer
00333   else if(currID > imgID) {
00334     double diff = currID - imgID;
00335     if(currIndex - 1 >= 0 && abs((float)t[currIndex - 1]["ImageID"] - imgID) < diff) {
00336       currIndex --;
00337     }
00338   }
00339 
00340   focalPlaneTemp = (float)t[currIndex]["Temp"];
00341 }