|
Isis 3.0 Application Source Code Reference |
Home |
00001 #include "Isis.h" 00002 #include "ProcessByLine.h" 00003 #include "Buffer.h" 00004 #include "SpecialPixel.h" 00005 #include "TextFile.h" 00006 #include "Camera.h" 00007 00008 using namespace Isis; 00009 using namespace std; 00010 00011 /** 00012 * Shutter file: 00013 * The shutter on the galileo SSI camera took from 00014 * about 1ms at the top of the camera to about 1.5ms 00015 * at the bottom due to friction. The shutter offset file in 00016 * isis 2 is rotated 90 degrees. 00017 * 00018 * Some of the values and equations in the program were verified 00019 * using the book "In Orbit at Jupiter, Contributions of the Galileo 00020 * Science Team," Section H Part I. 00021 */ 00022 00023 // Globals 00024 vector<double> weight; 00025 double scaleFactor0; // Entire scale factor that e is multiplied by 00026 double scaleFactor; // A1 or A2 in the equation, depending on units 00027 double dcScaleFactor; 00028 double exposureDuration; 00029 bool eightBitDarkCube; // Is the dark cube of type unsigned byte? 00030 bool iof; // Determines output units (i.e. I/F or radiance) 00031 double s1; 00032 double s2; 00033 double rsun; 00034 double cubeConversion; 00035 double gainConversion; 00036 00037 void Calibrate(vector<Buffer *> &in, vector<Buffer *> &out); 00038 FileName FindDarkFile(Cube *icube); 00039 FileName FindGainFile(Cube *icube); 00040 FileName FindShutterFile(Cube *icube); 00041 FileName ReadWeightTable(Cube *icube); 00042 FileName GetScaleFactorFile(); 00043 int getGainModeID(Cube *icube); 00044 void calculateScaleFactor0(Cube *icube, Cube *gaincube); 00045 00046 void IsisMain() { 00047 // Initialize Globals 00048 weight.clear(); 00049 dcScaleFactor = 0.0; 00050 exposureDuration = 0.0; 00051 00052 UserInterface &ui = Application::GetUserInterface(); 00053 00054 // Set up our ProcessByLine 00055 ProcessByLine p; 00056 Cube *icube = p.SetInputCube("FROM"); 00057 00058 Isis::CubeAttributeInput inAtt1; 00059 FileName darkFileName = FindDarkFile(icube); 00060 Cube *darkcube = p.SetInputCube(darkFileName.expanded(), inAtt1); 00061 dcScaleFactor = toDouble(darkcube->group("Instrument")["PicScale"][0]); 00062 00063 Isis::CubeAttributeInput inAtt2; 00064 FileName gainFileName = FindGainFile(icube); 00065 Cube *gaincube = p.SetInputCube(gainFileName.expanded(), inAtt2); 00066 00067 Isis::CubeAttributeInput inAtt3; 00068 p.SetInputCube(FindShutterFile(icube).expanded(), inAtt3, Isis::AllMatchOrOne); 00069 00070 Cube *ocube = p.SetOutputCube("TO"); 00071 00072 (ui.GetString("UNITS") == "IOF") ? iof = true : iof = false; 00073 scaleFactor = ui.GetDouble("SCALE"); 00074 00075 if(ui.GetBoolean("BITWEIGHTING")) { 00076 ReadWeightTable(icube); 00077 } 00078 else { 00079 for(int i = 0; i < 256; i++) { 00080 weight.push_back(i); 00081 } 00082 } 00083 00084 calculateScaleFactor0(icube, gaincube); 00085 00086 exposureDuration = toDouble(icube->group("Instrument")["ExposureDuration"][0]) * 1000; 00087 00088 if(darkcube->pixelType() == Isis::UnsignedByte) { 00089 eightBitDarkCube = true; 00090 } 00091 else { 00092 eightBitDarkCube = false; 00093 } 00094 00095 p.StartProcess(Calibrate); 00096 00097 PvlGroup calibrationLog("RadiometricCalibration"); 00098 calibrationLog.AddKeyword(PvlKeyword("From", ui.GetFileName("FROM"))); 00099 00100 FileName shutterFileName = FindShutterFile(icube); 00101 calibrationLog.AddKeyword(PvlKeyword("DarkCurrentFile", darkFileName.originalPath() + "/" + 00102 darkFileName.name())); 00103 calibrationLog.AddKeyword(PvlKeyword("GainFile", gainFileName.originalPath() + "/" + 00104 gainFileName.name())); 00105 calibrationLog.AddKeyword(PvlKeyword("ShutterFile", shutterFileName.originalPath() + "/" + 00106 shutterFileName.name())); 00107 calibrationLog.AddKeyword(PvlKeyword("ScaleFactor", toString(scaleFactor))); 00108 calibrationLog.AddKeyword(PvlKeyword("OutputUnits", iof ? "I/F" : "Radiance")); 00109 if (iof) { 00110 calibrationLog.AddKeyword(PvlKeyword("S1", toString(s1), "I/F per Ft-Lambert")); 00111 calibrationLog.AddKeyword(PvlKeyword("RSUN", toString(rsun), "(Planet-Sun range)/5.2 A.U.")); 00112 calibrationLog.AddKeyword(PvlKeyword("Scale", toString(scaleFactor), "I/F units per DN")); 00113 calibrationLog.AddKeyword(PvlKeyword("GC", toString(cubeConversion), "Cube gain conversion")); 00114 calibrationLog.AddKeyword(PvlKeyword("GG", toString(gainConversion), "Gain file gain conversion")); 00115 calibrationLog.AddKeyword(PvlKeyword("IOF-SCALE0", toString(scaleFactor0), "(S1/Scale)*(GC/GG)/RSUN**2")); 00116 } 00117 else { 00118 calibrationLog.AddKeyword(PvlKeyword("S2", toString(s2), "Nanowatts per Ft-Lambert")); 00119 calibrationLog.AddKeyword(PvlKeyword("Scale", toString(scaleFactor), 00120 "Nanowatts/cm**2/steradian/nanometer/DN")); 00121 calibrationLog.AddKeyword(PvlKeyword("GC", toString(cubeConversion), "Cube gain conversion")); 00122 calibrationLog.AddKeyword(PvlKeyword("GG", toString(gainConversion), "Gain file gain conversion")); 00123 calibrationLog.AddKeyword(PvlKeyword("Radiance-SCALE0", toString(scaleFactor0), "(S2/Scale)*(GC/GG)")); 00124 } 00125 00126 ocube->putGroup(calibrationLog); 00127 Application::Log(calibrationLog); 00128 p.EndProcess(); 00129 } 00130 00131 void Calibrate(vector<Buffer *> &in, vector<Buffer *> &out) { 00132 Buffer &inputFile = *in[0]; 00133 Buffer &darkFile = *in[1]; 00134 Buffer &gainFile = *in[2]; 00135 Buffer &shutterFile = *in[3]; 00136 Buffer &outputFile = *out[0]; 00137 00138 /* 00139 * Calculate this part of the radiometric correction equation: 00140 * 00141 * scaleFactor0 / (t-to) 00142 */ 00143 double scale = scaleFactor0 / (exposureDuration - shutterFile[0]); 00144 00145 for(int samp = 0; samp < inputFile.size(); samp++) { 00146 // Some shutter files are only a single sample. Others may match the number 00147 // of samples in the cube. 00148 int shutterIndex = (shutterFile.size() == 1) ? 0 : samp; 00149 00150 // Don't do anything to special pixels. 00151 if(IsSpecial(inputFile[samp])) { 00152 outputFile[samp] = inputFile[samp]; 00153 continue; 00154 } 00155 00156 if(IsSpecial(darkFile[samp]) || IsSpecial(gainFile[samp]) || IsSpecial(shutterFile[shutterIndex])) { 00157 outputFile[samp] = Isis::Null; 00158 continue; 00159 } 00160 00161 /* 00162 * Calculate this part of the equation: 00163 * e = z(d - dc) 00164 */ 00165 double dn = weight[(unsigned long)(inputFile[samp])]; 00166 00167 double dc; 00168 if (eightBitDarkCube) { 00169 dc = weight[(unsigned long)(darkFile[samp])]; 00170 } 00171 else { 00172 dc = (1.0 / dcScaleFactor) * darkFile[samp]; 00173 } 00174 00175 double e = gainFile[samp] * (dn - dc); 00176 double r = e * scale; 00177 00178 // The following behavior does not match the Isis 2 version of this app. 00179 // In the Isis 2 version, negative I/F were kept in the output, which 00180 // doesn't make sense. 00181 if(r >= 0 || !iof) { 00182 outputFile[samp] = r; 00183 } 00184 else { 00185 outputFile[samp] = Isis::Lrs; 00186 } 00187 } 00188 } 00189 00190 FileName FindDarkFile(Cube *icube) { 00191 QString file = "$galileo/calibration/gll_dc.sav"; 00192 00193 TextFile darkFile(file); 00194 darkFile.SetComment("C"); 00195 QString data; 00196 00197 /** 00198 * The dark current table requires the following information to match: 00199 * Mission,Frame Mode ID,Gain State ID,Frame Rate ID,Extended Exposure,Readout Mode,Image Number 00200 * So let's grab the information we need from the image labels first 00201 */ 00202 int gainModeId = getGainModeID(icube); 00203 00204 int frameRateId = 0; 00205 /** 00206 * Frame rate code 00207 * 1 = 2 1/3 (sec) 00208 * 2 = 8 2/3 00209 * 3 = 30 1/3 00210 * 4 = 60 2/3 00211 * 5 = 15 1/6 00212 */ 00213 if((int)(toDouble(icube->group("Instrument")["FrameDuration"][0])) == 2) frameRateId = 1; 00214 if((int)(toDouble(icube->group("Instrument")["FrameDuration"][0])) == 8) frameRateId = 2; 00215 if((int)(toDouble(icube->group("Instrument")["FrameDuration"][0])) == 30) frameRateId = 3; 00216 if((int)(toDouble(icube->group("Instrument")["FrameDuration"][0])) == 60) frameRateId = 4; 00217 if((int)(toDouble(icube->group("Instrument")["FrameDuration"][0])) == 15) frameRateId = 5; 00218 00219 int exposureTypeId = (icube->group("Instrument")["ExposureType"][0] == "NORMAL") ? 0 : 1; 00220 00221 // We have what we need from the image label, now go through the text file that is our table line by line 00222 // looking for a match. 00223 while(darkFile.GetLine(data)) { 00224 data = data.simplified().trimmed(); 00225 00226 QStringList tokens = data.split(" "); 00227 QString mission = (tokens.count()? tokens.takeFirst() : ""); 00228 if(mission != "GALILEO") { 00229 continue; 00230 } 00231 00232 QString frameMode = (tokens.count()? tokens.takeFirst() : ""); 00233 if(frameMode.at(0) != icube->group("Instrument")["FrameModeId"][0].at(0)) { 00234 continue; 00235 } 00236 00237 QString gainState = (tokens.count()? tokens.takeFirst() : ""); 00238 if(toInt(gainState) != gainModeId) { 00239 continue; 00240 } 00241 00242 QString frameRate = (tokens.count()? tokens.takeFirst() : ""); 00243 if(frameRateId != toInt(frameRate)) { 00244 continue; 00245 } 00246 00247 QString tableExposureTypeId = (tokens.count()? tokens.takeFirst() : ""); 00248 if(toInt(tableExposureTypeId) != exposureTypeId) { 00249 continue; 00250 } 00251 00252 QString readout = (tokens.count()? tokens.takeFirst() : ""); 00253 if(readout.at(0) != icube->group("Instrument")["ReadoutMode"][0].at(0)) { 00254 continue; 00255 } 00256 00257 int minImageNum = toInt(tokens.takeFirst()); 00258 int maxImageNum = toInt(tokens.takeFirst()); 00259 00260 int imageNumber = (int)(toDouble(icube->group("Instrument")["SpacecraftClockStartCount"]) * 100 + 0.5); 00261 QString telemetry = icube->group("Instrument")["TelemetryFormat"][0]; 00262 if(imageNumber > 99757701 && imageNumber < 159999999) { 00263 if((telemetry == "AI8" && (gainState == "1" || gainState == "2")) || 00264 (telemetry == "IM4" && (gainState == "3" || gainState == "4"))) { 00265 imageNumber = 160000001; 00266 } 00267 else { 00268 imageNumber = 1; 00269 } 00270 } 00271 00272 if(imageNumber < minImageNum || imageNumber > maxImageNum) { 00273 continue; 00274 } 00275 00276 // By process of elimination, we found the dark current file successfully. Return it. 00277 return FileName("$galileo/calibration/darkcurrent/" + tokens.takeFirst() + ".cub"); 00278 } 00279 00280 throw IException(IException::Unknown, "Dark current file could not be determined.", _FILEINFO_); 00281 } 00282 00283 FileName FindGainFile(Cube *icube) { 00284 QString file = "$galileo/calibration/gll_gain.sav"; 00285 00286 TextFile gainFile(file); 00287 gainFile.SetComment("C"); 00288 QString data; 00289 00290 int imageNumber = (int)((double)icube->group("Instrument")["SpacecraftClockStartCount"] * 100 + 0.5); 00291 00292 while(gainFile.GetLine(data)) { 00293 data = data.simplified().trimmed(); 00294 00295 QStringList tokens = data.split(" "); 00296 00297 QString mission = tokens.count()? tokens.takeFirst() : ""; 00298 if(mission != "GALILEO") { 00299 continue; 00300 } 00301 00302 /** 00303 * Filter codes 00304 * 0=clear,1=green,2=red,3=violet,4=7560,5=9680,6=7270,7=8890 00305 */ 00306 QString filter = icube->group("BandBin")["FilterNumber"][0]; 00307 if(filter != tokens.takeFirst()) { 00308 continue; 00309 } 00310 00311 QString frameMode = tokens.count()? tokens.takeFirst() : ""; 00312 if(frameMode.at(0) != icube->group("Instrument")["FrameModeId"][0].at(0)) { 00313 continue; 00314 } 00315 00316 int minImageNum = toInt(tokens.takeFirst()); 00317 int maxImageNum = toInt(tokens.takeFirst()); 00318 if(imageNumber < minImageNum || imageNumber > maxImageNum) { 00319 continue; 00320 } 00321 00322 return FileName("$galileo/calibration/gain/" + tokens.takeFirst() + ".cub"); 00323 } 00324 00325 throw IException(IException::Unknown, "Gain file could not be determined.", _FILEINFO_); 00326 } 00327 00328 FileName ReadWeightTable(Cube *icube) { 00329 QString file = "$galileo/calibration/weightTables_v???.sav"; 00330 00331 FileName weightFile(file); 00332 weightFile = weightFile.highestVersion(); 00333 Pvl weightTables(weightFile.expanded()); 00334 QString group = QString("FrameMode") + icube->group("Instrument")["FrameModeId"][0].at(0); 00335 PvlGroup &frameGrp = weightTables.FindGroup(group); 00336 QString keyword = QString("GainState") + ((getGainModeID(icube) < 3) ? QString("12") : QString("34")); 00337 00338 for(int i = 0; i < frameGrp[keyword].Size(); i++) { 00339 weight.push_back(toDouble(frameGrp[keyword][i])); 00340 } 00341 00342 return weightFile; 00343 } 00344 00345 int getGainModeID(Cube *icube) { 00346 int gainModeId = 0; 00347 /** 00348 * Gain mode ID code 00349 * 1 = 400,000 00350 * 2 = 100,000 00351 * 3 = 40,000 00352 * 4 = 10,000 00353 */ 00354 if((int)toDouble(icube->group("Instrument")["GainModeId"][0]) == 4E5) { 00355 gainModeId = 1; 00356 } 00357 else if((int)toDouble(icube->group("Instrument")["GainModeId"][0]) == 1E5) { 00358 gainModeId = 2; 00359 } 00360 else if((int)toDouble(icube->group("Instrument")["GainModeId"][0]) == 4E4) { 00361 gainModeId = 3; 00362 } 00363 else if((int)toDouble(icube->group("Instrument")["GainModeId"][0]) == 1E4) { 00364 gainModeId = 4; 00365 } 00366 else { 00367 throw IException(IException::Unknown, 00368 "Invalid value for Gain Mode ID [" + 00369 icube->group("Instrument")["GainModeId"][0] + 00370 "].", _FILEINFO_); 00371 } 00372 00373 return gainModeId; 00374 } 00375 00376 /* 00377 * Calculates scaleFactor0, which is: 00378 * 00379 * S1 K 00380 * -------- * --- (D/5.2)**2 00381 * A1 Ko 00382 * 00383 * if output units are in I/F, or: 00384 * 00385 * S2 K 00386 * -------- * --- 00387 * A2 Ko 00388 * 00389 * if output units are in radiance. 00390 */ 00391 void calculateScaleFactor0(Cube *icube, Cube *gaincube) { 00392 Pvl conversionFactors(GetScaleFactorFile().expanded()); 00393 PvlKeyword fltToRef, fltToRad; 00394 00395 for(int grp = 0; grp < conversionFactors.Groups(); grp++) { 00396 PvlGroup currGrp = conversionFactors.Group(grp); 00397 00398 // Match target name 00399 if(currGrp.HasKeyword("TargetName")) { 00400 if(!icube->group("Archive")["CalTargetCode"][0].startsWith(currGrp["TargetName"][0])) { 00401 continue; 00402 } 00403 } 00404 00405 // Match MinimumEncounter 00406 if(currGrp.HasKeyword("MinimumTargetName")) { 00407 try { 00408 if((int)currGrp["MinimumTargetName"] > 00409 (int)toInt(icube->group("Archive")["CalTargetCode"][0].mid(0, 2))) { 00410 continue; 00411 } 00412 } 00413 catch(IException &) { 00414 continue; 00415 } 00416 } 00417 00418 fltToRef = currGrp["FloatToRef"]; 00419 fltToRad = currGrp["FloatToRad"]; 00420 } 00421 00422 int filterNumber = toInt(icube->group("BandBin")["FilterNumber"][0]); 00423 00424 if(fltToRef.Size() == 0) { 00425 throw IException(IException::Unknown, 00426 "Unable to find matching reflectance and radiance values for target [" + 00427 icube->group("Instrument")["TargetName"][0] + "] in [" + 00428 GetScaleFactorFile().expanded() + "]", 00429 _FILEINFO_); 00430 } 00431 00432 s1 = toDouble(fltToRef[filterNumber]); 00433 s2 = toDouble(fltToRad[filterNumber]); 00434 cubeConversion = toDouble( conversionFactors["GainRatios"][getGainModeID(icube)-1]); 00435 gainConversion = toDouble(conversionFactors["GainRatios"][getGainModeID(gaincube)-1]); 00436 00437 if (iof) { 00438 Camera *cam = icube->camera(); 00439 bool camSuccess = cam->SetImage(icube->sampleCount() / 2, icube->lineCount() / 2); 00440 00441 if(!camSuccess) { 00442 throw IException(IException::Unknown, 00443 "Unable to calculate the Solar Distance on [" + 00444 icube->fileName() + "]", _FILEINFO_); 00445 } 00446 00447 00448 rsun = cam->SolarDistance() / 5.2; 00449 /* 00450 * We are calculating I/F, so scaleFactor0 is: 00451 * 00452 * S1 K 00453 * -------- * --- (D/5.2)**2 00454 * A1 Ko 00455 */ 00456 scaleFactor0 = (s1 * (cubeConversion / gainConversion) * pow(rsun, 2)) / (scaleFactor); 00457 } 00458 else { 00459 /* 00460 * We are calculating radiance, so scaleFactor0 is: 00461 * 00462 * S2 K 00463 * -------- * --- 00464 * A2 Ko 00465 */ 00466 scaleFactor0 = (s2 / scaleFactor) * (cubeConversion / gainConversion); 00467 } 00468 } 00469 00470 FileName GetScaleFactorFile() { 00471 QString file = "$galileo/calibration/conversionFactors_v???.sav"; 00472 FileName scaleFactor(file); 00473 scaleFactor = scaleFactor.highestVersion(); 00474 return scaleFactor; 00475 } 00476 00477 FileName FindShutterFile(Cube *icube) { 00478 QString file = "$galileo/calibration/shutter/calibration.so02"; 00479 file += icube->group("Instrument")["FrameModeId"][0].at(0); 00480 file += ".cub"; 00481 FileName shutterFile(file); 00482 return shutterFile; 00483 }