|
Isis 3.0 Application Source Code Reference |
Home |
00001 #include "Isis.h" 00002 #include <algorithm>// sort, unique 00003 #include <cmath> 00004 #include <cstdlib> 00005 #include <iterator>//unique 00006 #include <iostream> // unique 00007 #include <QString> 00008 #include <sstream> 00009 #include <vector> 00010 #include "Brick.h" 00011 #include "Buffer.h" 00012 #include "Camera.h" 00013 #include "CisscalFile.h" 00014 #include "CissLabels.h" 00015 #include "Cube.h" 00016 #include "DarkCurrent.h" 00017 #include "FileName.h" 00018 #include "LeastSquares.h" 00019 #include "NumericalApproximation.h" 00020 #include "PolynomialUnivariate.h" 00021 #include "ProcessByLine.h" 00022 #include "Preference.h" 00023 #include "PvlGroup.h" 00024 #include "SpecialPixel.h" 00025 #include "Stretch.h" 00026 #include "Table.h" 00027 #include "UserInterface.h" 00028 #include "IException.h" 00029 #include "IString.h" 00030 00031 using namespace Isis; 00032 using namespace std; 00033 00034 // Working functions and parameters 00035 namespace gbl { 00036 //global methods 00037 void BitweightCorrect(Buffer &in); 00038 void Calibrate(vector<Buffer *> &in, vector<Buffer *> &out); 00039 void ComputeBias(); 00040 void CopyInput(Buffer &in); 00041 void CreateBitweightStretch(FileName bitweightTable); 00042 FileName FindBitweightFile(); 00043 vector<double> OverclockFit(); 00044 void Linearize(); 00045 void FindDustRingParameters(); 00046 FileName FindFlatFile(); 00047 void FindCorrectionFactors(); 00048 void DNtoElectrons(); 00049 void FindShutterOffset(); 00050 void DivideByAreaPixel(); 00051 void FindEfficiencyFactor(QString fluxunits); 00052 QString GetCalibrationDirectory(QString calibrationType); 00053 00054 //global variables 00055 CissLabels *cissLab; 00056 Cube *incube; 00057 PvlGroup calgrp; 00058 Stretch stretch; 00059 int numberOfOverclocks; 00060 vector <double> bias; 00061 vector <vector <double> > bitweightCorrected; 00062 //dark subtraction variables 00063 vector <vector <double> > dark_DN; 00064 // flatfield variables 00065 FileName dustFile; 00066 FileName mottleFile; 00067 double strengthFactor; 00068 bool dustCorrection, mottleCorrection, flatCorrection; 00069 //DN to Flux variables 00070 double trueGain; 00071 bool divideByExposure; 00072 Brick *offset; 00073 double solidAngle; 00074 double opticsArea; 00075 double sumFactor; 00076 double efficiencyFactor; 00077 //correction factor variables 00078 double polarizationFactor; 00079 double correctionFactor; 00080 } 00081 00082 void IsisMain() { 00083 // Initialize Globals 00084 UserInterface &ui = Application::GetUserInterface(); 00085 gbl::cissLab = new CissLabels(ui.GetFileName("FROM")); 00086 gbl::incube = NULL; 00087 gbl::stretch.ClearPairs(); 00088 gbl::numberOfOverclocks = 0; 00089 gbl::bias.clear(); 00090 gbl::dustFile = ""; 00091 gbl::mottleFile = ""; 00092 gbl::strengthFactor = 1.0; 00093 gbl::dustCorrection = false; 00094 gbl::mottleCorrection = false; 00095 gbl::flatCorrection = false; 00096 gbl::trueGain = 1.0; 00097 gbl::divideByExposure = false; 00098 gbl::offset = NULL; // initialize pointer to null or 0? 00099 gbl::solidAngle = 1.0; 00100 gbl::opticsArea = 1.0; 00101 gbl::sumFactor = 1.0; 00102 gbl::efficiencyFactor = 1.0; 00103 gbl::polarizationFactor = 1.0; 00104 gbl::correctionFactor = 1.0; 00105 00106 // Set up our ProcessByLine objects 00107 // we will take 2 passes through the input cube 00108 ProcessByLine firstpass; 00109 ProcessByLine secondpass; 00110 // for the first pass, use the input cube. 00111 gbl::incube = firstpass.SetInputCube("FROM"); // CopyInput() or BitweightCorrect() parameter in 00112 // for the second pass, set input cube to "FROM" due to requirements of 00113 // ProcessByLine that there be at least 1 input buffer before setting the 00114 // output buffer, however this cube is not used in the Calibrate method, 00115 // instead the bitweightCorrected vector is used as the initial values before 00116 // the rest of the calibration steps are performed. 00117 gbl::incube = secondpass.SetInputCube("FROM"); // Calibrate() parameter in[0] 00118 // we need to set output cube at the beginning of the program to check right 00119 // away for CubeCustomization IsisPreference and throw an error, if necessary. 00120 Cube *outcube = secondpass.SetOutputCube("TO"); // Calibrate() parameter out[0] 00121 00122 // resize 2dimensional vectors 00123 gbl::bitweightCorrected.resize(gbl::incube->sampleCount()); 00124 gbl::dark_DN.resize(gbl::incube->sampleCount()); 00125 for(unsigned int i = 0; i < gbl::bitweightCorrected.size(); i++) { 00126 gbl::bitweightCorrected[i].resize(gbl::incube->lineCount()); 00127 gbl::dark_DN[i].resize(gbl::incube->lineCount()); 00128 } 00129 00130 // Add the radiometry group 00131 gbl::calgrp.SetName("Radiometry"); 00132 00133 // The first ProcessByLine pass will either compute bitweight values or copy input values 00134 00135 // BITWEIGHT CORRECTION 00136 gbl::calgrp += PvlKeyword("BitweightCorrectionPerformed", "Yes"); 00137 gbl::calgrp.FindKeyword("BitweightCorrectionPerformed").AddComment("Bitweight Correction Parameters"); 00138 // Bitweight correction is not applied to Lossy-compressed or Table-converted images 00139 if(gbl::cissLab->CompressionType() == "Lossy") { 00140 gbl::calgrp.FindKeyword("BitweightCorrectionPerformed").SetValue("No: Lossy compressed"); 00141 gbl::calgrp += PvlKeyword("BitweightFile", "Not applicable: No bitweight correction"); 00142 firstpass.Progress()->SetText("Lossy compressed: skip bitweight correction as insignificant.\nCopying input image..."); 00143 firstpass.StartProcess(gbl::CopyInput); 00144 firstpass.EndProcess(); 00145 } 00146 else if(gbl::cissLab->DataConversionType() == "Table") { 00147 gbl::calgrp.FindKeyword("BitweightCorrectionPerformed").SetValue("No: Table converted"); 00148 gbl::calgrp += PvlKeyword("BitweightFile", "Not applicable: No bitweight correction"); 00149 firstpass.Progress()->SetText("Table converted: skip bitweight correction as insignificant.\nCopying input image..."); 00150 firstpass.StartProcess(gbl::CopyInput); 00151 firstpass.EndProcess(); 00152 } 00153 // Skip bitweight correction for GainState==0, there is no data for this case, 00154 // see ground calibration report 5.1.9 Uneven Bit Weighting 00155 else if(gbl::cissLab->GainState() == 0) { 00156 gbl::calgrp.FindKeyword("BitweightCorrectionPerformed").SetValue("No: No bitweight calibration file for GainState 0."); 00157 gbl::calgrp += PvlKeyword("BitweightFile", "Not applicable: No bitweight correction."); 00158 firstpass.Progress()->SetText("No bitweight calibration file for GainState 0: skip bitweight correction.\nCopying input image..."); 00159 firstpass.StartProcess(gbl::CopyInput); 00160 firstpass.EndProcess(); 00161 } 00162 else { // Bitweight correction 00163 FileName bitweightFile = gbl::FindBitweightFile(); 00164 if(!bitweightFile.fileExists()) { // bitweight file not found, stop calibration 00165 throw IException(IException::Io, 00166 "Unable to calibrate image. BitweightFile ***" 00167 + bitweightFile.expanded() + "*** not found.", _FILEINFO_); 00168 } 00169 else { 00170 gbl::calgrp += PvlKeyword("BitweightFile", bitweightFile.expanded()); 00171 gbl::CreateBitweightStretch(bitweightFile); 00172 firstpass.Progress()->SetText("Computing bitweight correction..."); 00173 firstpass.StartProcess(gbl::BitweightCorrect); 00174 firstpass.EndProcess(); 00175 } 00176 }// THIS ENDS FIRST PROCESS 00177 00178 // Compute global values needed for the rest of the calibration steps 00179 00180 //Subtract bias (debias) 00181 gbl::ComputeBias(); 00182 00183 //Dark current subtraction 00184 try { 00185 DarkCurrent dark(*gbl::cissLab); 00186 gbl::dark_DN = dark.ComputeDarkDN(); 00187 gbl::calgrp += PvlKeyword("DarkSubtractionPerformed", "Yes"); 00188 gbl::calgrp.FindKeyword("DarkSubtractionPerformed").AddComment("Dark Current Subtraction Parameters"); 00189 gbl::calgrp += PvlKeyword("DarkParameterFile", dark.DarkParameterFile().expanded()); 00190 if(gbl::cissLab->NarrowAngle()) { 00191 gbl::calgrp += PvlKeyword("BiasDistortionTable", dark.BiasDistortionTable().expanded()); 00192 } 00193 else { 00194 gbl::calgrp += PvlKeyword("BiasDistortionTable", "ISSWA: No bias distortion table used"); 00195 } 00196 } 00197 catch(IException &e) { // cannot perform dark current, stop calibration 00198 e.print(); 00199 throw IException(e, IException::Unknown, 00200 "Unable to calibrate image. Dark current calculations failed.", 00201 _FILEINFO_); 00202 } 00203 00204 //Linearity Correction 00205 gbl::Linearize(); 00206 00207 //Dust Ring Correction 00208 gbl::FindDustRingParameters(); 00209 //Flat Field Correction 00210 FileName flatFile = gbl::FindFlatFile(); 00211 00212 //DN to Flux Correction 00213 gbl::DNtoElectrons(); 00214 gbl::FindShutterOffset(); 00215 gbl::DivideByAreaPixel(); 00216 gbl::FindEfficiencyFactor(ui.GetString("UNITS")); 00217 00218 //Correction Factor 00219 // Set the remaining necessary input cube files for second pass 00220 CubeAttributeInput att; 00221 gbl::FindCorrectionFactors(); 00222 if(gbl::flatCorrection) { // Calibrate() parameter in[1] 00223 secondpass.SetInputCube(flatFile.expanded(), att); 00224 } 00225 if(gbl::dustCorrection) { // Calibrate() parameter in[2] 00226 secondpass.SetInputCube(gbl::dustFile.expanded(), att); 00227 } 00228 if(gbl::mottleCorrection) { // Calibrate() parameter in[3] 00229 secondpass.SetInputCube(gbl::mottleFile.expanded(), att); 00230 } 00231 // this pass will call the Calibrate method 00232 secondpass.Progress()->SetText("Calibrating image..."); 00233 outcube->putGroup(gbl::calgrp); 00234 secondpass.StartProcess(gbl::Calibrate); 00235 secondpass.EndProcess(); 00236 gbl::calgrp.Clear(); 00237 return; 00238 00239 } //END MAIN 00240 00241 /** 00242 * This calibration method runs through all calibration steps. 00243 * It takes a vector of input buffers that contains the 00244 * input image and, if needed, the flat field image, the 00245 * dustring correction image, and the mottle correction image. 00246 * The vector of output buffers will only contain one element: 00247 * the output image. 00248 * 00249 * @param in Vector of pointers to input buffers for the second 00250 * process in IsisMain() 00251 * @param out Vector of pointers to output buffer. 00252 * @internal 00253 * @history 2008-11-05 Jeannie Walldren - Original version 00254 * @history 2009-05-27 Jeannie Walldren - Added polarization 00255 * factor correction. Updated ConstOffset value per 00256 * new idl cisscal version, 3.6. 00257 */ 00258 void gbl::Calibrate(vector<Buffer *> &in, vector<Buffer *> &out) { 00259 Buffer *flat = 0; 00260 Buffer *dustCorr = 0; 00261 Buffer *mottleCorr = 0; 00262 if(gbl::flatCorrection) { 00263 flat = in[1]; 00264 } 00265 if(gbl::dustCorrection) { 00266 dustCorr = in[2]; 00267 if(gbl::mottleCorrection) { 00268 mottleCorr = in[3]; 00269 } 00270 } 00271 Buffer &outLine = *out[0]; 00272 //get line index of output 00273 int lineIndex = outLine.Line() - 1; 00274 for(unsigned int sampIndex = 0; sampIndex < gbl::bitweightCorrected.size(); sampIndex++) { 00275 if(IsValidPixel(gbl::bitweightCorrected[sampIndex][lineIndex])) { 00276 00277 /////////////////////////////////////////////////////////////////////////////////////////////////////////// 00278 // STEP 1) set output to bitweight corrected values 00279 outLine[sampIndex] = bitweightCorrected[sampIndex][lineIndex]; 00280 00281 /////////////////////////////////////////////////////////////////////////////////////////////////////////// 00282 // STEP 2) remove bias (debias) 00283 if(gbl::numberOfOverclocks) { 00284 outLine[sampIndex] = outLine[sampIndex] - gbl::bias[lineIndex]; 00285 } 00286 else { 00287 outLine[sampIndex] = outLine[sampIndex] - gbl::bias[0]; 00288 } 00289 00290 /////////////////////////////////////////////////////////////////////////////////////////////////////////// 00291 // idl cisscal step "REMOVE 2-HZ NOISE" skipped 00292 // -- this is more of a filter than calibration 00293 00294 /////////////////////////////////////////////////////////////////////////////////////////////////////////// 00295 // STEP 3) remove dark current 00296 outLine[sampIndex] = outLine[sampIndex] - gbl::dark_DN[sampIndex][lineIndex]; 00297 00298 /////////////////////////////////////////////////////////////////////////////////////////////////////////// 00299 // idl cisscal step "ANTI-BLOOMING CORRECTION" skipped 00300 // -- this is more of a filter than calibration 00301 00302 /////////////////////////////////////////////////////////////////////////////////////////////////////////// 00303 // STEP 4) linearity correction (linearize) 00304 if(outLine[sampIndex] < 0) { 00305 outLine[sampIndex] = (outLine[sampIndex]) * (gbl::stretch.Map(0)); 00306 } 00307 else { 00308 outLine[sampIndex] = (outLine[sampIndex]) * (gbl::stretch.Map((int) outLine[sampIndex])); 00309 } 00310 00311 /////////////////////////////////////////////////////////////////////////////////////////////////////////// 00312 // STEP 5) flatfield correction 00313 // 5a1: dust ring correction 00314 if(gbl::dustCorrection) { 00315 outLine[sampIndex] = (outLine[sampIndex]) * ((*dustCorr)[sampIndex]); 00316 // 5a2: mottle correction 00317 if(gbl::mottleCorrection) { 00318 outLine[sampIndex] = (outLine[sampIndex]) * (1 - ((gbl::strengthFactor) * ((*mottleCorr)[sampIndex]) / 1000.0)); 00319 } 00320 } 00321 // 5b: divide by flats 00322 if(gbl::flatCorrection) { 00323 outLine[sampIndex] = outLine[sampIndex] / ((*flat)[sampIndex]); 00324 } 00325 00326 /////////////////////////////////////////////////////////////////////////////////////////////////////////// 00327 // STEP 6) convert DN to flux 00328 // 6a DN to Electrons 00329 outLine[sampIndex] = outLine[sampIndex] * gbl::trueGain; 00330 // 6b Divide By Exposure Time 00331 // JPL confirm that these values must be subtracted thus: 00332 if(gbl::divideByExposure) { 00333 double exposureTime = gbl::cissLab->ExposureDuration() - (*gbl::offset)[gbl::offset->Index(sampIndex+1, 1, 1)]; 00334 // IDL documentation: 00335 // Need to develop way to subtract constant offset discussed in 00336 // section 4.3 of Ground Calibration Report. Right now just use 1 ms 00337 // for all cases. 00338 // CORRECTION: New analysis of Vega images points to a value more like 00339 // 2.85 ms (correct to within about 0.05 ms for the NAC, less certain 00340 // for the WAC. Use this until better data available. (12/1/2005 - BDK) 00341 // UPDATE: Used azimuthal ring scans to pin down WAC to around 1.8 ms. 00342 // (1/18/2006 - BDK) 00343 double ConstOffset; 00344 if(gbl::cissLab->InstrumentId() == "ISSNA") { 00345 ConstOffset = 2.85; 00346 } 00347 else { 00348 ConstOffset = 1.8; 00349 } 00350 exposureTime = exposureTime - ConstOffset; 00351 outLine[sampIndex] = outLine[sampIndex] * 1000 / exposureTime; // 1000 to scale ms to seconds 00352 } 00353 // 6c Divide By Area Pixel 00354 outLine[sampIndex] = outLine[sampIndex] * gbl::sumFactor / (gbl::solidAngle * gbl::opticsArea); 00355 // 6d Divide By Efficiency 00356 outLine[sampIndex] = outLine[sampIndex] / gbl::efficiencyFactor; 00357 00358 /////////////////////////////////////////////////////////////////////////////////////////////////////////// 00359 // STEP 7) correction factors 00360 outLine[sampIndex] = outLine[sampIndex] / (gbl::correctionFactor * gbl::polarizationFactor); 00361 00362 /////////////////////////////////////////////////////////////////////////////////////////////////////////// 00363 } 00364 else { 00365 outLine[sampIndex] = bitweightCorrected[sampIndex][lineIndex]; 00366 } 00367 } 00368 return; 00369 } 00370 00371 00372 //=====4 Bitweight Methods=======================================================================// 00373 // These methods are modelled after IDL CISSCAL's cassimg_bitweightcorrect.pro 00374 00375 /** 00376 * The purpose of this method is to copy the input to output if 00377 * no bitweight correction occurs. 00378 * 00379 * @param in Input buffer for the first process in IsisMain() 00380 * @internal 00381 * @history 2008-11-05 Jeannie Walldren - Original version 00382 * @history 2008-12-22 Jeannie Walldren - Fixed bug in calls 00383 * to resize() method. 00384 * @history 2009-01-26 Jeannie Walldren - Moved resizing of 00385 * 2-dimensional vectors to main method 00386 */ 00387 void gbl::CopyInput(Buffer &in) { 00388 // find line index 00389 int lineIndex = in.Line() - 1; 00390 for(int sampIndex = 0; sampIndex < in.size(); sampIndex++) { 00391 // assign input value to image vector 00392 gbl::bitweightCorrected[sampIndex][lineIndex] = in[sampIndex]; 00393 } 00394 return; 00395 } 00396 00397 /** 00398 * This method is modelled after IDL CISSCAL's 00399 * cassimg_bitweightcorrect.pro. The purpose is to correct the 00400 * image for uneven bit weights. This is done using one of 00401 * several tables developed from the ground calibration 00402 * exercises table depends on InstrumentId, GainModeId, and 00403 * OpticsTemperature. 00404 * 00405 * @param in Input buffer for the first process in IsisMain() 00406 * @internal 00407 * @history 2008-11-05 Jeannie Walldren - Original version 00408 * @history 2009-01-26 Jeannie Walldren - Moved resizing of 00409 * 2-dimensional vectors to main method 00410 */ 00411 void gbl::BitweightCorrect(Buffer &in) { 00412 // find line index 00413 int lineIndex = in.Line() - 1; 00414 // loop through samples of this line 00415 for(int sampIndex = 0; sampIndex < in.size(); sampIndex++) { 00416 // map bitweight corrected image output values to buffer input values 00417 if(IsValidPixel(in[sampIndex])) { 00418 gbl::bitweightCorrected[sampIndex][lineIndex] = gbl::stretch.Map(in[sampIndex]); 00419 } 00420 //Handle special pixels 00421 else { 00422 gbl::bitweightCorrected[sampIndex][lineIndex] = in[sampIndex]; 00423 } 00424 } 00425 return; 00426 } 00427 00428 00429 /** 00430 * This method sets up the strech for the conversion from file. 00431 * It is used by the BitweightCorrect() method to map LUT 00432 * values. 00433 * 00434 * @param bitweightTable Name of the bitweight table for this 00435 * image. 00436 * 00437 * @internal 00438 * @history 2008-11-05 Jeannie Walldren - Original version 00439 */ 00440 void gbl::CreateBitweightStretch(FileName bitweightTable) { 00441 CisscalFile *stretchPairs = new CisscalFile(bitweightTable.expanded()); 00442 // Create the stretch pairs 00443 double stretch1 = 0, stretch2; 00444 gbl::stretch.ClearPairs(); 00445 for(int i = 0; i < stretchPairs->LineCount(); i++) { 00446 QString line; 00447 stretchPairs->GetLine(line); 00448 line = line.simplified().trimmed(); 00449 00450 QStringList tokens = line.split(QRegExp("[, ]"), QString::SkipEmptyParts); 00451 foreach (QString token, tokens) { 00452 stretch2 = toDouble(token); 00453 gbl::stretch.AddPair(stretch1, stretch2); 00454 stretch1 = stretch1 + 1.0; 00455 } 00456 } 00457 stretchPairs->Close(); 00458 return; 00459 } 00460 00461 /** 00462 * This method is modelled after IDL CISSCAL's 00463 * cassimg_bitweightcorrect.pro. The purpose is to find the 00464 * look up table file name for this image. 00465 * 00466 * The table to be used depends on: 00467 * Camera NAC or WAC 00468 * GainState 1, 2 or 3 <=> GainModeId 95, 29, or 12 Optics temp. -10, +5 or 00469 * +25 00470 * 00471 * @return <B>FileName</B> Name of the bitweight file 00472 * 00473 * @internal 00474 * @history 2008-11-05 Jeannie Walldren - Original version 00475 */ 00476 FileName gbl::FindBitweightFile() { 00477 // Get the directory where the CISS bitweight directory is 00478 QString bitweightName; 00479 00480 if(gbl::cissLab->NarrowAngle()) { 00481 bitweightName += "nac"; 00482 } 00483 else { 00484 bitweightName += "wac"; 00485 } 00486 QString gainState(toString(gbl::cissLab->GainState())); 00487 bitweightName = bitweightName + "g" + gainState; 00488 00489 if(gbl::cissLab->FrontOpticsTemp() < -5.0) { 00490 bitweightName += "m10_bwt.tab"; 00491 } 00492 else if(gbl::cissLab->FrontOpticsTemp() < 25.0) { 00493 bitweightName += "p5_bwt.tab"; 00494 } 00495 else { 00496 bitweightName += "p25_bwt.tab"; 00497 } 00498 return FileName(gbl::GetCalibrationDirectory("bitweight") + bitweightName); 00499 } 00500 //=====End Bitweight Methods=====================================================================// 00501 00502 //=====2 Debias Methods============================================================================// 00503 //These methods are modelled after IDL CISSCAL's cassimg_debias.pro 00504 00505 /** 00506 * This method is modelled after IDL CISSCAL's 00507 * cassimg_debias.pro. The purpose is to compute the bias 00508 * (zero-exposure DN level of CCD chip) to be subtracted in the 00509 * Calibrate() method. 00510 * There are two ways to do this 00511 * 1. (DEFAULT) using overclocked pixel array taken out of 00512 * binary line prefix 00513 * 2. subtract BiasMeanStrip value found in labels 00514 * 00515 * @internal 00516 * @history 2008-11-05 Jeannie Walldren - Original version 00517 * @history 2009-05-27 Jeannie Walldren - Commented out table 00518 * if-statement as done idl cisscal version 3.6. 00519 */ 00520 void gbl::ComputeBias() { 00521 gbl::calgrp += PvlKeyword("BiasSubtractionPerformed", "Yes"); 00522 gbl::calgrp.FindKeyword("BiasSubtractionPerformed").AddComment("Bias Subtraction Parameters"); 00523 00524 QString fsw(gbl::cissLab->FlightSoftwareVersion()); 00525 double flightSoftwareVersion; 00526 00527 if(fsw == "Unknown") { 00528 flightSoftwareVersion = 0.0;// cassimg_readlabels.pro sets this to 1.3, we treat this as 1.2??? 00529 } 00530 else { 00531 flightSoftwareVersion = toDouble(fsw); 00532 } 00533 // check overclocked pixels exist 00534 if(gbl::cissLab->CompressionType() != "Lossy") { 00535 if(flightSoftwareVersion < 1.3) { // (1.2=CAS-ISS2 or Unknown=0.0=CAS-ISS) 00536 gbl::numberOfOverclocks = 1; 00537 } 00538 else { //if(1.3=CAS-ISS3 or 1.4=CAS-ISS4) 00539 gbl::numberOfOverclocks = 2; 00540 } 00541 gbl::calgrp += PvlKeyword("BiasSubtractionMethod", "Overclock fit"); 00542 } 00543 // otherwise overclocked pixels are invalid and must use bias strip mean where possible 00544 else { // overclocks array is corrupt for lossy images (see cassimg_readvic.pro) 00545 #if 0 00546 // 2009-04-27 Jeannie Walldren 00547 // following code comment out in new idl cisscal version, 3.6: 00548 if(gbl::cissLab->DataConversionType() == "Table") { // Lossy + Table = no debias 00549 gbl::calgrp.FindKeyword("BiasSubtractionPerformed").SetValue("No: Table converted and Lossy compressed"); 00550 gbl::calgrp += PvlKeyword("BiasSubtractionMethod", "Not applicable: No bias subtraction"); 00551 gbl::calgrp += PvlKeyword("NumberOfOverclocks", "Not applicable: No bias subtraction"); 00552 gbl::bias.resize(1); 00553 gbl::bias[0] = 0.0; 00554 return; 00555 } 00556 #endif 00557 00558 // according to SIS if 1.2 or 1.3 and Lossy, ignore bias strip mean - invalid data 00559 if(flightSoftwareVersion <= 1.3) { // Lossy + 1.2 or 1.3 = no debias 00560 gbl::calgrp.FindKeyword("BiasSubtractionPerformed").SetValue("No: Lossy compressed on CAS-ISS2 or CAS-ISS3"); 00561 gbl::calgrp += PvlKeyword("BiasSubtractionMethod", "Not applicable: No bias subtraction"); 00562 gbl::calgrp += PvlKeyword("NumberOfOverclocks", "Not applicable: No bias subtraction"); 00563 gbl::bias.resize(1); 00564 gbl::bias[0] = 0.0; 00565 return; 00566 } 00567 gbl::calgrp += PvlKeyword("BiasSubtractionMethod", "Bias strip mean"); 00568 gbl::numberOfOverclocks = 0;//overclocks array is corrupt for lossy images 00569 } 00570 //Choose bias subtraction method 00571 if(gbl::numberOfOverclocks) { // use overclocked pixels as default 00572 gbl::bias = gbl::OverclockFit(); 00573 } 00574 else { // use BiasStripMean in image label if can't use overclock 00575 gbl::bias.resize(1); 00576 gbl::bias[0] = gbl::cissLab->BiasStripMean(); 00577 } 00578 gbl::calgrp += PvlKeyword("NumberOfOverclocks", toString(gbl::numberOfOverclocks)); 00579 return; 00580 } 00581 00582 /** 00583 * This method is modelled after IDL CISSCAL's 00584 * cassimg_define.pro method, CassImg::OverclockAvg(). This 00585 * access function computes line-averaged overclocked pixel 00586 * values and returns a linear fit of these values. 00587 * 00588 * @return <B>vector <double> </B> Results of linear fit 00589 * 00590 * @internal 00591 * @history 2008-11-05 Jeannie Walldren - Original version 00592 */ 00593 vector<double> gbl::OverclockFit() { 00594 vector< vector <double> > overclocks; 00595 // Read overclocked info from table saved during ciss2isis 00596 // table should have 3 columns: 00597 // -col 3 is the "average" of the overclocked pixels 00598 // -if there are 2 overclocks, columns 1 and 2 contain them 00599 // -otherwise column 1 is all null and we use column 2 00600 Table overClkTable("ISS Prefix Pixels"); 00601 gbl::incube->read(overClkTable); 00602 for(int i = 0; i < overClkTable.Records(); i++) { 00603 overclocks.push_back(overClkTable[i]["OverclockPixels"]); 00604 } 00605 00606 vector<double> overclockfit, eqn, avg; 00607 PolynomialUnivariate poly(1); 00608 LeastSquares lsq(poly); 00609 //get overclocked averages 00610 for(unsigned int i = 0; i < overclocks.size(); i++) { 00611 avg.push_back(overclocks[i][2]); 00612 } 00613 if(avg[0] > 2 * avg[1]) { 00614 avg[0] = avg[1]; 00615 } 00616 00617 // initialize eqn 00618 eqn.push_back(0.0); 00619 for(unsigned int i = 0; i < avg.size(); i++) { 00620 // if avg is a special pixel, we must change to integer values so we don't throw off the linear fit 00621 if(avg[i] == Isis::NULL2) { 00622 avg[i] = 0; 00623 } 00624 if(avg[i] == Isis::HIGH_REPR_SAT2) { 00625 if(gbl::cissLab->DataConversionType() == "Table") { 00626 avg[i] = 4095; 00627 } 00628 else { 00629 avg[i] = 255; 00630 } 00631 } 00632 eqn[0] = (double)(i + 1); 00633 // add to least squares variable 00634 lsq.AddKnown(eqn, avg[i]); 00635 } 00636 // solve linear fit 00637 lsq.Solve(LeastSquares::QRD); 00638 for(unsigned int i = 0; i < overclocks.size(); i++) { 00639 eqn[0] = (double)(i + 1); 00640 overclockfit.push_back(lsq.Evaluate(eqn)); 00641 00642 } 00643 //return a copy of the vector of linear fitted overclocks 00644 // this will be used as the bias 00645 return overclockfit; 00646 } 00647 //=====End Debias Methods========================================================================// 00648 00649 00650 //=====Subtract Dark Methods=====================================================================// 00651 // THESE ARE CONTAINED IN THE CLASS DARKCURRENT 00652 //=====End Subtract Dark Methods=================================================================// 00653 00654 00655 //=====1 Linearize Methods=========================================================================// 00656 //This method is modelled after IDL CISSCAL's cassimg_linearise.pro 00657 00658 /** 00659 * This method is modelled after IDL CISSCAL's 00660 * cassimg_linearise.pro. The purpose is to correct the image 00661 * for non-linearity. 00662 * 00663 * @internal 00664 * @history 2008-11-05 Jeannie Walldren - Original version 00665 */ 00666 void gbl::Linearize() { 00667 // These are the correction factor tables from the referenced documents 00668 // For each gain state there are a list of DNs where measurements 00669 // were performed and the corresponding correction factors C 00670 // The correction is then performed as DN'=DN*Cdn 00671 // Where Cdn is an interpolation for C from the tabulated values 00672 00673 QString lut; 00674 int gainState = gbl::cissLab->GainState(); 00675 if(gbl::cissLab->NarrowAngle()) { 00676 switch(gainState) { 00677 case 0: 00678 lut = "NAC0.lut"; 00679 break; 00680 case 1: 00681 lut = "NAC1.lut"; 00682 break; 00683 case 2: 00684 lut = "NAC2.lut"; 00685 break; 00686 case 3: 00687 lut = "NAC3.lut"; 00688 break; 00689 default: 00690 throw IException(IException::Unknown, 00691 "Input file contains invalid GainState. See Software Interface Specification (SIS), Version 1.1, page 86.", 00692 _FILEINFO_); 00693 } 00694 } 00695 else { 00696 switch(gainState) { 00697 case 0: 00698 lut = "WAC0.lut"; 00699 break; 00700 case 1: 00701 lut = "WAC1.lut"; 00702 break; 00703 case 2: 00704 lut = "WAC2.lut"; 00705 break; 00706 case 3: 00707 lut = "WAC3.lut"; 00708 break; 00709 default: 00710 throw IException(IException::Unknown, 00711 "Input file contains invalid GainState. See Software Interface Specification (SIS), Version 1.1, page 86.", 00712 _FILEINFO_); 00713 } 00714 } 00715 vector <double> DN_VALS, C_VALS; 00716 // Get the directory where the CISS linearize directory is. 00717 FileName linearLUT(gbl::GetCalibrationDirectory("linearize") + lut); 00718 if(!linearLUT.fileExists()) { 00719 throw IException(IException::Io, 00720 "Unable to calibrate image. LinearityCorrectionTable ***" 00721 + linearLUT.expanded() + "*** not found.", _FILEINFO_); 00722 } 00723 gbl::calgrp += PvlKeyword("LinearityCorrectionPerformed", "Yes"); 00724 gbl::calgrp.FindKeyword("LinearityCorrectionPerformed").AddComment("Linearity Correction Parameters"); 00725 gbl::calgrp += PvlKeyword("LinearityCorrectionTable", linearLUT.expanded()); 00726 00727 TextFile *pairs = new TextFile(linearLUT.expanded()); 00728 for(int i = 0; i < pairs->LineCount(); i++) { 00729 QString line; 00730 pairs->GetLine(line, true); 00731 line = line.simplified(); 00732 QStringList tokens = line.split(" "); 00733 DN_VALS.push_back(toDouble(tokens.takeFirst())); 00734 C_VALS.push_back(toDouble(tokens.takeFirst())); 00735 } 00736 pairs->Close(); 00737 00738 // ASSUMPTION: C will not change significantly over fractional DN 00739 // If this is not the case, then can perform simple second interpolation 00740 // between DNs while mapping LUT onto the image 00741 NumericalApproximation linearInterp(NumericalApproximation::Linear); 00742 for(unsigned int i = 0; i < DN_VALS.size(); i++) { 00743 linearInterp.AddData(DN_VALS[i], C_VALS[i]); 00744 } 00745 00746 // Create the stretch pairs 00747 gbl::stretch.ClearPairs(); 00748 for(unsigned int i = 0; i < 4096; i++) { 00749 double j = linearInterp.Evaluate((double) i); 00750 gbl::stretch.AddPair(i, j); 00751 } 00752 // Map LUT onto image, defending against out-of-range DN values 00753 return; 00754 } 00755 //=====End Linearize Methods=====================================================================// 00756 00757 00758 //=====2 Flatfield Methods=========================================================================// 00759 // These methods are modelled after IDL CISSCAL's cassimg_dustringcorrect.pro and cassimg_dividebyflats.pro 00760 00761 /** 00762 * This method is modelled after IDL CISSCAL's 00763 * cassimg_dustringcorrect.pro. The purpose is to find the 00764 * files and value needed to perform dustring correction and 00765 * mottle correction: dustFile, mottleFile, strengthFactor. 00766 * 00767 * @internal 00768 * @history 2008-11-05 Jeannie Walldren - Original version 00769 * @history 2009-05-27 Jeannie Walldren - Changed to read 00770 * effective wavelength from 5th column of file 00771 * (rather than 3rd) since effective wavelength file 00772 * updated with new idl cisscal version, 3.6. Added 00773 * effective wavelength to calibration group in 00774 * labels. 00775 */ 00776 void gbl::FindDustRingParameters() { 00777 // No dustring or mottle correction for WAC 00778 if(gbl::cissLab->WideAngle()) { 00779 gbl::dustCorrection = false; 00780 gbl::mottleCorrection = false; 00781 gbl::calgrp += PvlKeyword("DustRingCorrectionPerformed", "No: ISSWA"); 00782 gbl::calgrp.FindKeyword("DustRingCorrectionPerformed").AddComment("DustRing Correction Parameters"); 00783 gbl::calgrp += PvlKeyword("DustRingFile", "Not applicable: No dustring correction"); 00784 gbl::calgrp += PvlKeyword("MottleCorrectionPerformed", "No: dustring correction"); 00785 gbl::calgrp += PvlKeyword("MottleFile", "Not applicable: No dustring correction"); 00786 gbl::calgrp += PvlKeyword("EffectiveWavelengthFile", "Not applicable: No dustring correction"); 00787 gbl::calgrp += PvlKeyword("StrengthFactor", "Not applicable: No dustring correction"); 00788 return; 00789 } 00790 00791 // dustring correct for NAC 00792 gbl::dustCorrection = true; 00793 gbl::calgrp += PvlKeyword("DustRingCorrectionPerformed", "Yes"); 00794 gbl::calgrp.FindKeyword("DustRingCorrectionPerformed").AddComment("DustRing Correction Parameters"); 00795 // get name of dust file 00796 gbl::dustFile = (gbl::GetCalibrationDirectory("dustring") + "nac_dustring_venus." 00797 + gbl::cissLab->InstrumentModeId() + ".cub"); 00798 if(!gbl::dustFile.fileExists()) { // dustring file not found, stop calibration 00799 throw IException(IException::Io, 00800 "Unable to calibrate image. DustRingFile ***" 00801 + gbl::dustFile.expanded() + "*** not found.", _FILEINFO_); 00802 } 00803 gbl::calgrp += PvlKeyword("DustRingFile", gbl::dustFile.expanded()); 00804 00805 // No mottle correct for summation mode other than 1 00806 if(gbl::cissLab->SummingMode() != 1) { 00807 gbl::mottleCorrection = false; 00808 gbl::calgrp += PvlKeyword("MottleCorrectionPerformed", "No: Summing mode is " + toString(gbl::cissLab->SummingMode())); 00809 gbl::calgrp += PvlKeyword("MottleFile", "Not applicable: No mottle correction"); 00810 gbl::calgrp += PvlKeyword("EffectiveWavelengthFile", "Not applicable: No mottle correction"); 00811 gbl::calgrp += PvlKeyword("StrengthFactor", "Not applicable: No mottle correction"); 00812 return; 00813 } 00814 00815 // No Mottling correction for images before sclk=1444733393: (i.e., 2003-286T10:28:04) 00816 if(gbl::cissLab->ImageNumber() < 1455892746) { 00817 gbl::mottleFile = ""; 00818 gbl::mottleCorrection = false; 00819 gbl::calgrp += PvlKeyword("MottleCorrectionPerformed", "No: Image before 2003-286T10:28:04"); 00820 gbl::calgrp += PvlKeyword("MottleFile", "Not applicable: No mottle correction"); 00821 gbl::calgrp += PvlKeyword("EffectiveWavelengthFile", "Not applicable: No mottle correction"); 00822 gbl::calgrp += PvlKeyword("StrengthFactor", "Not applicable: No mottle correction"); 00823 return; 00824 } 00825 00826 // Mottling correction for full images after 2003-286T10:28:04 00827 gbl::mottleFile = (gbl::GetCalibrationDirectory("duString") + "nac_mottle_1444733393.full.cub"); 00828 if(!gbl::mottleFile.fileExists()) { // mottle file not found, stop calibration 00829 throw IException(IException::Io, 00830 "Unable to calibrate image. MottleFile ***" 00831 + gbl::mottleFile.expanded() + "*** not found.", _FILEINFO_); 00832 } 00833 gbl::mottleCorrection = true; 00834 gbl::calgrp += PvlKeyword("MottleCorrectionPerformed", "Yes"); 00835 gbl::calgrp += PvlKeyword("MottleFile", gbl::mottleFile.expanded()); 00836 00837 // determine strength factor, need effective wavelength of filter 00838 vector <int> filterIndex(2); 00839 filterIndex[0] = gbl::cissLab->FilterIndex()[0]; 00840 filterIndex[1] = gbl::cissLab->FilterIndex()[1]; 00841 if(filterIndex[0] == 17 && filterIndex[1] == 18) { //filter combo CL1/CL2 00842 filterIndex[0] = -1; 00843 } 00844 if((filterIndex[0] < 17 && filterIndex[1] < 17) || (filterIndex[0] >= 17 && filterIndex[1] >= 17)) { 00845 gbl::strengthFactor = 0.0; 00846 // use effective wavelength to estimate strength factor: 00847 FileName effectiveWavelength(gbl::GetCalibrationDirectory("efficiency") + "na_effwl.tab"); 00848 if(!effectiveWavelength.fileExists()) { // effectivewavelength file not found, stop calibration 00849 throw IException(IException::Io, 00850 "Unable to calibrate image. EffectiveWavelengthFile ***" 00851 + effectiveWavelength.expanded() + "*** not found.", _FILEINFO_); 00852 } 00853 gbl::calgrp += PvlKeyword("EffectiveWavelengthFile", effectiveWavelength.expanded()); 00854 CisscalFile *effwlDB = new CisscalFile(effectiveWavelength.expanded()); 00855 QString col1, col2, col3, col4, col5; 00856 double effwl; 00857 for(int i = 0; i < effwlDB->LineCount(); i++) { 00858 QString line; 00859 effwlDB->GetLine(line); 00860 line = line.simplified(); 00861 00862 QStringList cols = line.split(" "); 00863 00864 col1 = cols.takeFirst(); 00865 if(col1 == gbl::cissLab->FilterName()[0]) { 00866 col2 = cols.takeFirst(); 00867 if(col2 == gbl::cissLab->FilterName()[1]) { 00868 col3 = cols.takeFirst(); // central wavelength of filter combo 00869 col4 = cols.takeFirst(); // full-width at half-maximum (FWHM) of filter combo 00870 col5 = cols.takeFirst(); // effective wavelength 00871 if(col5 == "") { 00872 // Couldn't find a match in the database 00873 gbl::calgrp.FindKeyword("MottleCorrectionPerformed").SetValue("Yes: EffectiveWavelengthFile contained no factor for filter combination, used strengthFactor of 1.0"); 00874 gbl::strengthFactor = 1.0; 00875 } 00876 else { 00877 effwl = toDouble(col5); 00878 gbl::calgrp += PvlKeyword("EffectiveWavelength", toString(effwl)); 00879 gbl::strengthFactor = 1.30280 - 0.000717552 * effwl; 00880 } 00881 break; 00882 } 00883 else { 00884 continue; 00885 } 00886 } 00887 else { 00888 continue; 00889 } 00890 } 00891 effwlDB->Close(); 00892 if(gbl::strengthFactor == 0.0) { 00893 gbl::calgrp.FindKeyword("MottleCorrectionPerformed").SetValue("Yes: EffectiveWavelengthFile contained no factor for filter combination, used strengthFactor of 1.0"); 00894 gbl::strengthFactor = 1.0; 00895 } 00896 } 00897 else {//if(filterIndex[0] > 17 || filterIndex[1] > 17 ) 00898 gbl::calgrp += PvlKeyword("EffectiveWavelengthFile", "No effective wavelength file used"); 00899 switch(filterIndex[0]) { 00900 case 0: 00901 gbl::strengthFactor = 1.119; 00902 break; 00903 case 1: 00904 gbl::strengthFactor = 1.186; 00905 break; 00906 case 3: 00907 gbl::strengthFactor = 1.00; 00908 break; 00909 case 6: 00910 gbl::strengthFactor = 0.843; 00911 break; 00912 case 8: 00913 gbl::strengthFactor = 0.897; 00914 break; 00915 case 10: 00916 gbl::strengthFactor = 0.780; 00917 break; 00918 case -1: 00919 gbl::strengthFactor = 0.763; 00920 break; 00921 default: 00922 switch(filterIndex[1]) { 00923 case 2: 00924 gbl::strengthFactor = 1.069; 00925 break; 00926 case 4: 00927 gbl::strengthFactor = 0.833; 00928 break; 00929 case 5: 00930 gbl::strengthFactor = 0.890; 00931 break; 00932 case 7: 00933 gbl::strengthFactor = 0.997; 00934 break; 00935 case 9: 00936 gbl::strengthFactor = 0.505; 00937 break; 00938 case 11: 00939 gbl::strengthFactor = 0.764; 00940 break; 00941 case 12: 00942 gbl::strengthFactor = 0.781; 00943 break; 00944 case 13: 00945 gbl::strengthFactor = 0.608; 00946 break; 00947 case 14: 00948 gbl::strengthFactor = 0.789; 00949 break; 00950 case 15: 00951 gbl::strengthFactor = 0.722; 00952 break; 00953 case 16: 00954 gbl::strengthFactor = 0.546; 00955 break; 00956 default: 00957 throw IException(IException::Unknown, 00958 "Input file contains invalid FilterName. See Software Interface Specification (SIS) Appendix A, Table 8.2.", 00959 _FILEINFO_); 00960 } 00961 } 00962 } 00963 gbl::calgrp += PvlKeyword("StrengthFactor", toString(gbl::strengthFactor)); 00964 return; 00965 } 00966 00967 /** 00968 * This method is modelled after IDL CISSCAL's 00969 * cassimg_dividebyflats.pro. The purpose is to find the flat 00970 * field file needed to correct the image for sensitivity 00971 * variations across the field by dividing by flat field image. 00972 * 00973 * @return <B>FileName</B> Name of the flat file for this image. 00974 * @internal 00975 * @history 2008-11-05 Jeannie Walldren - Original version 00976 */ 00977 FileName gbl::FindFlatFile() { 00978 // There is a text database file in the slope files directory 00979 // that maps filter combinations (and camera temperature) 00980 // to the corresponding slope field files. 00981 // according to slope_info.txt, slope_db_1 is original, slope_db_2 is the best and slope_db_3 is newest but has some issues 00982 FileName flatFile; 00983 FileName slopeDatabaseName(gbl::GetCalibrationDirectory("slope") + "slope_db_2.tab"); 00984 if(!slopeDatabaseName.fileExists()) { // slope database not found, stop calibration 00985 throw IException(IException::Io, 00986 "Unable to calibrate image. SlopeDataBase ***" 00987 + slopeDatabaseName.expanded() + "*** not found.", _FILEINFO_); 00988 } 00989 gbl::calgrp += PvlKeyword("FlatfieldCorrectionPerformed", "Yes"); 00990 gbl::calgrp.FindKeyword("FlatfieldCorrectionPerformed").AddComment("Flatfield Correction Parameters"); 00991 gbl::calgrp += PvlKeyword("SlopeDataBase", slopeDatabaseName.expanded()); 00992 gbl::flatCorrection = true; 00993 00994 // Find the best-match flat file 00995 // Choose a nominal optics temp name as per ISSCAL 00996 QString frontOpticsTemp(""); 00997 if(gbl::cissLab->FrontOpticsTemp() < -5.0) { 00998 frontOpticsTemp += "m10"; 00999 } 01000 else if(gbl::cissLab->FrontOpticsTemp() < 25.0) { 01001 frontOpticsTemp += "p5"; 01002 } 01003 else { 01004 frontOpticsTemp += "p25"; 01005 } 01006 // Require match for instrument, temperature range name, Filter1, filter2 01007 CisscalFile *slopeDB = new CisscalFile(slopeDatabaseName.expanded()); 01008 QString col1, col2, col3, col4, col5, col6, col7, col8; 01009 for(int i = 0; i < slopeDB->LineCount(); i++) { 01010 QString line; 01011 slopeDB->GetLine(line); //assigns value to line 01012 line = line.simplified(); 01013 QStringList cols = line.split(" "); 01014 cols.replaceInStrings(QRegExp("(^'|'$)"), ""); 01015 01016 col1 = cols.takeFirst(); 01017 if(col1 == gbl::cissLab->InstrumentId()) { 01018 col2 = cols.takeFirst(); 01019 if((col2 == frontOpticsTemp) || (gbl::cissLab->WideAngle())) { 01020 col3 = cols.takeFirst(); 01021 if(col3 == gbl::cissLab->FilterName()[0]) { 01022 col4 = cols.takeFirst(); 01023 if(col4 == gbl::cissLab->FilterName()[1]) { 01024 col5 = cols.takeFirst();// col5 = gainstate (not used) 01025 col6 = cols.takeFirst();// col6 = antiblooming state (not used) 01026 col7 = cols.takeFirst();// col7 = file number (not used) 01027 col8 = cols.takeFirst();// col8 = slope file name 01028 break; 01029 } 01030 else { 01031 continue; 01032 } 01033 } 01034 else { 01035 continue; 01036 } 01037 } 01038 else { 01039 continue; 01040 } 01041 } 01042 else { 01043 continue; 01044 } 01045 } 01046 slopeDB->Close(); 01047 01048 if(col8 == "") { // error in slope database, stop calibration 01049 // Couldn't find a match in the database 01050 throw IException(IException::Io, 01051 "Unable to calibrate image. SlopeDataBase contained no factor for combination:" 01052 + gbl::cissLab->InstrumentId() + ":" + frontOpticsTemp + ":" 01053 + gbl::cissLab->FilterName()[0] + ":" + gbl::cissLab->FilterName()[1] + ".", 01054 _FILEINFO_); 01055 } 01056 //Column 8 contains version of slopefile from which our flatfiles are derived 01057 int j = col8.indexOf("."); 01058 //attatch version number to "flat" by skipping 01059 // the first 5 characters("SLOPE") and skipping 01060 // any thing after "." ("IMG") 01061 col8 = "flat" + col8.mid(5, (j - 5) + 1); 01062 flatFile = (gbl::GetCalibrationDirectory("slope/flat") + col8 01063 + gbl::cissLab->InstrumentModeId() + ".cub"); 01064 gbl::calgrp += PvlKeyword("FlatFile", flatFile.expanded()); 01065 if(!flatFile.fileExists()) { // flat file not found, stop calibration 01066 throw IException(IException::Io, 01067 "Unable to calibrate image. FlatFile ***" 01068 + flatFile.expanded() + "*** not found.", _FILEINFO_); 01069 } 01070 return flatFile; 01071 } 01072 //=====End Flatfield Methods=====================================================================// 01073 01074 //=====5 Convert DN to Flux Methods================================================================// 01075 // These methods are modelled after IDL CISSCAL's cassimg_dntoelectrons.pro, cassimg_dividebyexpot.pro, 01076 // cassimg_dividebyareapixel.pro, cassimg_dividebyefficiency.pro 01077 01078 /** 01079 * This method is modelled after IDL CISSCAL's 01080 * cassimg_dntoelectrons.pro. The purpose is to find the true 01081 * gain needed to multiply image by gain constant (convert DN to 01082 * electrons). 01083 * 01084 * @internal 01085 * @history 2008-11-05 Jeannie Walldren - Original version 01086 * @history 2009-05-27 Jeannie Walldren - Removed return 01087 * statement and added else statement so that the 01088 * TrueGain keyword is added in any case. 01089 */ 01090 void gbl::DNtoElectrons() { 01091 gbl::calgrp += PvlKeyword("DNtoFluxPerformed", "Yes"); 01092 gbl::calgrp.FindKeyword("DNtoFluxPerformed").AddComment("DN to Flux Parameters"); 01093 gbl::calgrp += PvlKeyword("DNtoElectrons", "Yes"); 01094 // Gain used for an image is documented by the GainModID attribute 01095 // of the image. Nominal values are as follow: 01096 // 01097 // Attribute Gain Usual Nominal Gain 01098 // Value state mode (e- per DN) 01099 // "1400K" 0 SUM4 215 01100 // "400K" 1 SUM2 95 01101 // "100K" 2 FULL 29 01102 // "40K" 3 FULL 12 01103 if(gbl::cissLab->NarrowAngle()) { 01104 switch(gbl::cissLab->GainState()) { 01105 case 0: 01106 gbl::trueGain = 30.27 / 0.135386; 01107 break; 01108 case 1: 01109 gbl::trueGain = 30.27 / 0.309569; 01110 break; 01111 case 2: 01112 gbl::trueGain = 30.27 / 1.0; 01113 break; 01114 case 3: 01115 gbl::trueGain = 30.27 / 2.357285; 01116 break; 01117 default: // invalid gainstate, unable to convert DN to electrons, stop calibration 01118 throw IException(IException::Unknown, 01119 "Input file contains invalid GainState. See Software Interface Specification (SIS), Version 1.1, page 86.", 01120 _FILEINFO_); 01121 } 01122 } 01123 else { 01124 switch(gbl::cissLab->GainState()) { 01125 case 0: 01126 gbl::trueGain = 27.68 / 0.125446; 01127 break; 01128 case 1: 01129 gbl::trueGain = 27.68 / 0.290637; 01130 break; 01131 case 2: 01132 gbl::trueGain = 27.68 / 1.0; 01133 break; 01134 case 3: 01135 gbl::trueGain = 27.68 / 2.360374; 01136 break; 01137 default: // invalid gainstate, unable to convert DN to electrons, stop calibration 01138 throw IException(IException::Unknown, 01139 "Input file contains invalid GainState. See Software Interface Specification (SIS), Version 1.1, page 86.", 01140 _FILEINFO_); 01141 } 01142 } 01143 gbl::calgrp += PvlKeyword("TrueGain", toString(gbl::trueGain)); 01144 return; 01145 } 01146 01147 /** 01148 * This method is modelled after IDL CISSCAL's 01149 * cassimg_dividebyexpot.pro. The purpose is to find the 01150 * shutter offset needed to divide a Cassini image by corrected 01151 * exposure time, correcting for shutter offset effects (sample 01152 * dependency of actual exposure time). 01153 * 01154 * @internal 01155 * @history 2008-11-05 Jeannie Walldren - Original version 01156 */ 01157 void gbl::FindShutterOffset() { 01158 // Don't do this for zero-exposure images! 01159 if(gbl::cissLab->ExposureDuration() == 0.0) { // exposuretime = 0, stop calibration 01160 throw IException(IException::Unknown, 01161 "Unable to calibrate image. Cannot divide by exposure time for zero exposure image.", 01162 _FILEINFO_); 01163 } 01164 gbl::calgrp += PvlKeyword("DividedByExposureTime", "Yes"); 01165 gbl::divideByExposure = true; 01166 // Define whereabouts of shutter offset files 01167 QString offsetFileName(""); 01168 if(gbl::cissLab->NarrowAngle()) { 01169 offsetFileName += (gbl::GetCalibrationDirectory("offset") + "nacfm_so_"); 01170 } 01171 else { 01172 offsetFileName += (gbl::GetCalibrationDirectory("offset") + "wacfm_so_"); 01173 } 01174 if(gbl::cissLab->FrontOpticsTemp() < -5.0) { 01175 offsetFileName += "m10."; 01176 } 01177 else if(gbl::cissLab->FrontOpticsTemp() < 25.0) { 01178 offsetFileName += "p5."; 01179 } 01180 else { 01181 offsetFileName += "p25."; 01182 } 01183 offsetFileName += (gbl::cissLab->InstrumentModeId() + ".cub"); 01184 FileName shutterOffsetFile(offsetFileName); 01185 if(!shutterOffsetFile.fileExists()) { // shutter offset file not found, stop calibration 01186 throw IException(IException::Io, 01187 "Unable to calibrate image. ShutterOffsetFile ***" 01188 + shutterOffsetFile.expanded() + "*** not found.", _FILEINFO_); 01189 } 01190 gbl::calgrp += PvlKeyword("ShutterOffsetFile", shutterOffsetFile.expanded()); 01191 Cube offsetCube; 01192 offsetCube.open(shutterOffsetFile.expanded()); 01193 gbl::offset = new Brick(gbl::incube->sampleCount(), 1, 1, offsetCube.pixelType()); 01194 gbl::offset->SetBasePosition(1, 1, 1); 01195 offsetCube.read(*gbl::offset); 01196 offsetCube.close(); 01197 return; 01198 // Pixel value is now flux (electrons per second) 01199 } 01200 01201 /** 01202 * This method is modelled after IDL CISSCAL's 01203 * cassimg_dividebyareapixel.pro. The purpose is to find the 01204 * values needed to normalise the image by dividing by area of 01205 * optics and by solid angle subtended by a pixel. 01206 * 01207 * @internal 01208 * @history 2008-11-05 Jeannie Walldren - Original version 01209 */ 01210 void gbl::DivideByAreaPixel() { 01211 // These values as per ISSCAL 01212 // SolidAngle is (FOV of Optics) / (Number of Pixels) 01213 // OpticsArea is (Diameter of Primary Mirror)^2 * Pi/4 01214 // We will adjust here for the effects of SUM modes 01215 // (which effectively give pixels of 4 or 16 times normal size) 01216 01217 gbl::calgrp += PvlKeyword("DividedByAreaPixel", "Yes"); 01218 if(gbl::cissLab->NarrowAngle()) { 01219 gbl::solidAngle = 3.6 * pow(10.0, -11.0); 01220 gbl::opticsArea = 264.84; 01221 } 01222 else { 01223 gbl::solidAngle = 3.6 * pow(10.0, -9); 01224 gbl::opticsArea = 29.32; 01225 } 01226 // Normalize summed images to real pixels 01227 01228 // sumFactor is the inverse of the square of the summing mode, 01229 // it was expressed in IDL as the following: 01230 // [gbl::sumFactor = (gbl::incube->sampleCount()/1024.0)*(gbl::incube->lineCount()/1024.0);] 01231 gbl::sumFactor = 1 / pow(gbl::cissLab->SummingMode(), 2.0); 01232 gbl::calgrp += PvlKeyword("SolidAngle", toString(gbl::solidAngle)); 01233 gbl::calgrp += PvlKeyword("OpticsArea", toString(gbl::opticsArea)); 01234 gbl::calgrp += PvlKeyword("SumFactor", toString(gbl::sumFactor)); 01235 return; 01236 } 01237 01238 /** 01239 * This method is modelled after IDL CISSCAL's 01240 * cassimg_dividebyefficiency.pro. The purpose is to find the 01241 * efficiency factor for the given flux units. This value is 01242 * used to correct the image for filter and CCD efficiency. 01243 * 01244 * @b Note: For "I/F", The results diverge from the IDL results 01245 * due to differences in the way they calculate solar distance. 01246 * However, the DN results are still within 0.2% after we divide 01247 * by efficiency factor. 01248 * 01249 * @internal 01250 * @history 2008-11-05 Jeannie Walldren - Original version of 01251 * FindEfficiencyFactor_IoverF() and 01252 * FindEfficiencyFactor_IntensityUnits() written. 01253 * @history 2009-02-12 Jeannie Walldren - Modified 01254 * FindEfficiencyFactor_IoverF() code to make a 01255 * second attempt to find the planet if the 01256 * Isis::Camera class fails to find it at the center 01257 * point of the cube. Previously, if the target was 01258 * not found, an exception was thrown. Now the 01259 * SubSpacecraftPoint() method from Isis::Camera 01260 * class is used to try to locate the target before 01261 * throwing the exception. 01262 * @history 2009-05-27 Jeannie Walldren - Joined 01263 * FindEfficiencyFactor_IoverF() and 01264 * FindEfficiencyFactor_IntensityUnits() into 01265 * FindEfficiencyFactor() per new idl cisscal 01266 * version, 3.6, updates. This version no longer uses 01267 * the effic_db (now called omega0) to calculate the 01268 * efficiency factor for intensity units. Now, the 01269 * method is not far off from the I/F method. 01270 */ 01271 01272 void gbl::FindEfficiencyFactor(QString fluxunits) { 01273 01274 gbl::calgrp += PvlKeyword("DividedByEfficiency", "Yes"); 01275 gbl::calgrp += PvlKeyword("EfficiencyFactorMethod", fluxunits); 01276 vector<double> lambda; // lambda will contain all wavelength vectors used 01277 01278 //--- 1) CREATE LINEAR APPROXIMATION FROM SYSTEM TRANSMISSION FILE ---------- 01279 // find system transmission file (T0*T1*T2*QE) 01280 01281 FileName transfile(gbl::GetCalibrationDirectory("efficiency/systrans") 01282 + gbl::cissLab->InstrumentId().toLower() 01283 + gbl::cissLab->FilterName()[0].toLower() 01284 + gbl::cissLab->FilterName()[1].toLower() + "_systrans.tab"); 01285 if(!transfile.fileExists()) { // transmission file not found, stop calibration 01286 throw IException(IException::Io, 01287 "Unable to calibrate image. TransmissionFile ***" 01288 + transfile.expanded() + "*** not found.", _FILEINFO_); 01289 } 01290 // read in system transmission to find transmitted wavelength and flux 01291 gbl::calgrp += PvlKeyword("TransmissionFile", transfile.expanded()); 01292 CisscalFile *trans = new CisscalFile(transfile.expanded()); 01293 vector<double> wavelengthT, transmittedFlux; 01294 double x, y; 01295 for(int i = 0; i < trans->LineCount(); i++) { 01296 QString line; 01297 trans->GetLine(line); //assigns value to line 01298 line = line.simplified().trimmed(); 01299 if(line == "") { 01300 break; 01301 } 01302 x = toDouble(line.split(" ")[0]); 01303 y = toDouble(line.split(" ")[1]); 01304 wavelengthT.push_back(x); 01305 transmittedFlux.push_back(y); 01306 } 01307 trans->Close(); 01308 // wavelength and flux are in descending order, reverse to ascending order 01309 if(wavelengthT[0] > wavelengthT.back()) { 01310 reverse(wavelengthT.begin(), wavelengthT.end()); 01311 reverse(transmittedFlux.begin(), transmittedFlux.end()); 01312 } 01313 lambda = wavelengthT; 01314 // Create Linear approximation from the transmitted data 01315 NumericalApproximation newtrans(NumericalApproximation::Linear); 01316 for(unsigned int i = 0; i < transmittedFlux.size(); i++) { 01317 newtrans.AddData(wavelengthT[i], transmittedFlux[i]); 01318 } 01319 01320 //--- 2) CREATE LINEAR APPROXIMATION FROM QUANTUM EFFICIENCY FILE ----------- 01321 // find quantum efficiency file 01322 FileName qecorrfile; 01323 if(gbl::cissLab->NarrowAngle()) { 01324 qecorrfile = gbl::GetCalibrationDirectory("correction") + "nac_qe_correction.tab"; 01325 } 01326 else { 01327 qecorrfile = gbl::GetCalibrationDirectory("correction") + "wac_qe_correction.tab"; 01328 } 01329 if(!qecorrfile.fileExists()) { // quantum efficiency file not found, stop calibration 01330 throw IException(IException::Io, 01331 "Unable to calibrate image. QuantumEfficiencyFile ***" 01332 + qecorrfile.expanded() + "*** not found.", _FILEINFO_); 01333 } 01334 // read qe file to find qe wavelength and correction 01335 gbl::calgrp += PvlKeyword("QuantumEfficiencyFile", qecorrfile.expanded()); 01336 CisscalFile *qeCorr = new CisscalFile(qecorrfile.expanded()); 01337 vector<double> wavelengthQE, qecorrection; 01338 for(int i = 0; i < qeCorr->LineCount(); i++) { 01339 QString line; 01340 qeCorr->GetLine(line); //assigns value to line 01341 line = line.simplified().trimmed(); 01342 if(line == "") { 01343 break; 01344 } 01345 x = toDouble(line.split(" ").first()); 01346 y = toDouble(line.split(" ").last()); 01347 wavelengthQE.push_back(x); 01348 qecorrection.push_back(y); 01349 lambda.push_back(x); 01350 } 01351 qeCorr->Close(); 01352 // wavelength and qecorr are in descending order, reverse to ascending order 01353 if(wavelengthQE[0] > wavelengthQE.back()) { 01354 reverse(wavelengthQE.begin(), wavelengthQE.end()); 01355 reverse(qecorrection.begin(), qecorrection.end()); 01356 } 01357 // Create Linear approximation from the qe data 01358 NumericalApproximation newqecorr(NumericalApproximation::Linear); 01359 for(unsigned int i = 0; i < qecorrection.size(); i++) { 01360 newqecorr.AddData(wavelengthQE[i], qecorrection[i]); 01361 } 01362 01363 01364 // these variables will be defined in the if-statement 01365 QString units; 01366 double minlam, maxlam; 01367 vector<double> fluxproduct1, fluxproduct2; 01368 01369 if(fluxunits == "INTENSITY") { 01370 gbl::calgrp += PvlKeyword("SpectralFile", "Not applicable: Intensity Units chosen"); 01371 gbl::calgrp += PvlKeyword("SolarDistance", "Not applicable: Intensity Units chosen"); 01372 //--- 3a) SORT AND MAKE LAMBDA UNIQUE, REMOVE OUTLIERS, ------------------- 01373 //--- FIND FLUX PRODUCTS TO BE INTERPOLATED --------------------------- 01374 units = "phot/cm^2/s/nm/ster"; 01375 01376 // lambda domain min is the largest of the minimum wavelength values (rounded up) 01377 minlam = ceil(max(wavelengthT.front(), wavelengthQE.front())); 01378 // lambda domain max is the smallest of the maximum wavelength values (rounded down) 01379 maxlam = floor(min(wavelengthT.back(), wavelengthQE.back())); 01380 01381 // NumericalApproximation requires lambda to be sorted 01382 sort(lambda.begin(), lambda.end()); 01383 // NumericalApproximation requires lambda to be unique 01384 vector<double>::iterator it = unique(lambda.begin(), lambda.end()); 01385 lambda.resize(it - lambda.begin()); 01386 01387 // remove any values that fall below minlam 01388 while(lambda[0] < minlam) { 01389 lambda.erase(lambda.begin()); 01390 } 01391 01392 // remove any values that fall above maxlam 01393 while(lambda[lambda.size()-1] > maxlam) { 01394 lambda.erase(lambda.end() - 1); 01395 } 01396 01397 for(unsigned int i = 0; i < lambda.size(); i++) { 01398 double a = newtrans.Evaluate(lambda[i]); 01399 double b = newqecorr.Evaluate(lambda[i]); 01400 fluxproduct1.push_back(a * b); 01401 } 01402 fluxproduct2 = fluxproduct1; 01403 } 01404 else {// if(fluxunits == "I/F") { 01405 //--- 3b) CALCULATE SOLAR DISTANCE, --------------------------------------- 01406 // --- CREATE LINEAR APPROXIMATION FROM SPECTRAL FILE ------------------ 01407 //--- SORT AND MAKE LAMBDA UNIQUE, REMOVE OUTLIERS, ------------------- 01408 //--- FIND FLUX PRODUCTS TO BE INTERPOLATED --------------------------- 01409 01410 units = "I/F"; 01411 01412 // find spectral file 01413 FileName specfile(gbl::GetCalibrationDirectory("efficiency") + "solarflux.tab"); 01414 if(!specfile.fileExists()) { // spectral file not found, stop calibration 01415 throw IException(IException::Io, 01416 "Unable to calibrate image using I/F. SpectralFile ***" 01417 + specfile.expanded() + "*** not found.", _FILEINFO_); 01418 } 01419 gbl::calgrp += PvlKeyword("SpectralFile", specfile.expanded()); 01420 01421 // get distance from sun (AU): 01422 double angstromsToNm = 10.0; 01423 double distFromSun = 0; 01424 try { 01425 Camera *cam = gbl::incube->camera(); 01426 bool camSuccess = cam->SetImage(gbl::incube->sampleCount() / 2, gbl::incube->lineCount() / 2); 01427 if(!camSuccess) {// the camera was unable to find the planet at the center of the image 01428 double lat, lon; 01429 // find values for lat/lon directly below spacecraft 01430 cam->subSpacecraftPoint(lat, lon); 01431 // use these values to set the ground coordinates 01432 cam->SetUniversalGround(lat, lon); 01433 } 01434 distFromSun = cam->SolarDistance(); 01435 } 01436 catch(IException &e) { // unable to get solar distance, can't divide by efficiency, stop calibration 01437 throw IException(IException::Unknown, 01438 "Unable to calibrate image using I/F. Cannot calculate Solar Distance using Isis::Camera object.", 01439 _FILEINFO_); 01440 } 01441 if(distFromSun <= 0) { // solar distance <= 0, can't divide by efficiency, stop calibration 01442 throw IException(IException::Unknown, 01443 "Unable to calibrate image using I/F. Solar Distance calculated is less than or equal to 0.", 01444 _FILEINFO_); 01445 } 01446 gbl::calgrp += PvlKeyword("SolarDistance", toString(distFromSun)); 01447 01448 // read spectral file to find wavelength and flux 01449 CisscalFile *spectral = new CisscalFile(specfile.expanded()); 01450 vector<double> wavelengthF, flux; 01451 for(int i = 0; i < spectral->LineCount(); i++) { 01452 QString line; 01453 spectral->GetLine(line); //assigns value to line 01454 line = line.simplified().trimmed(); 01455 if(line == "") { 01456 break; 01457 } 01458 x = toDouble(line.split(" ").first()) / angstromsToNm; 01459 y = toDouble(line.split(" ").last()) * angstromsToNm; 01460 wavelengthF.push_back(x); 01461 flux.push_back(y); 01462 lambda.push_back(x); 01463 } 01464 spectral->Close(); 01465 // wavelength is in descending order, reverse to ascending order 01466 if(wavelengthF[0] > wavelengthF.back()) { 01467 reverse(wavelengthF.begin(), wavelengthF.end()); 01468 reverse(flux.begin(), flux.end()); 01469 } 01470 // Create Linear Approximation 01471 NumericalApproximation newflux(NumericalApproximation::Linear); 01472 for(unsigned int i = 0; i < flux.size(); i++) { 01473 newflux.AddData(wavelengthF[i], flux[i]); 01474 } 01475 01476 // lambda domain min is the largest of the minimum wavelength values (rounded up) 01477 minlam = ceil(max(wavelengthF.front(), max(wavelengthT.front(), wavelengthQE.front()))); 01478 // lambda domain max is the smallest of the maximum wavelength values (rounded down) 01479 maxlam = floor(min(wavelengthF.back(), min(wavelengthT.back(), wavelengthQE.back()))); 01480 01481 // NumericalApproximation requires lambda to be sorted 01482 sort(lambda.begin(), lambda.end()); 01483 // NumericalApproximation requires lambda to be unique 01484 vector<double>::iterator it = unique(lambda.begin(), lambda.end()); 01485 lambda.resize(it - lambda.begin()); 01486 01487 // remove any values that fall below minlam 01488 while(lambda[0] < minlam) { 01489 lambda.erase(lambda.begin()); 01490 } 01491 01492 // remove any values that fall above maxlam 01493 while(lambda[lambda.size()-1] > maxlam) { 01494 lambda.erase(lambda.end() - 1); 01495 } 01496 01497 for(unsigned int i = 0; i < lambda.size(); i++) { 01498 double a = newtrans.Evaluate(lambda[i]); 01499 double b = newqecorr.Evaluate(lambda[i]); 01500 double c = newflux.Evaluate(lambda[i]) / (Isis::PI * pow(distFromSun, 2.0)); 01501 fluxproduct1.push_back(a * b * c); 01502 fluxproduct2.push_back(a * b); 01503 } 01504 } 01505 01506 //--- 4) CALCULATE EFFICIENCY FACTOR AND TOTAL EFFICIENCY ------------------- 01507 //--- USING LAMBDA AND FLUX PRODUCTS ------------------------------------- 01508 NumericalApproximation spline1(NumericalApproximation::CubicNatural); 01509 NumericalApproximation spline2(NumericalApproximation::CubicNatural); 01510 spline1.AddData(lambda, fluxproduct1); 01511 spline2.AddData(lambda, fluxproduct2); 01512 gbl::efficiencyFactor = spline1.BoolesRule(spline1.DomainMinimum(), spline1.DomainMaximum()); 01513 double efficiency = spline2.BoolesRule(spline2.DomainMinimum(), spline2.DomainMaximum()); 01514 gbl::calgrp += PvlKeyword("EfficiencyFactor", toString(gbl::efficiencyFactor), units); 01515 gbl::calgrp += PvlKeyword("TotalEfficiency", toString(efficiency)); 01516 01517 // Cannot divide by 0.0 01518 if(gbl::efficiencyFactor == 0) { 01519 throw IException(IException::Unknown, 01520 "Unable to calibrate image using I/F. Cannot divide by efficiency factor of 0.", 01521 _FILEINFO_); 01522 } 01523 return; 01524 } 01525 01526 01527 //=====End DN to Flux Methods====================================================================// 01528 01529 01530 //=====1 Correction Factors Methods================================================================// 01531 01532 /** 01533 * This method is modelled after IDL CISSCAL's 01534 * cassimg_correctionfactors.pro. The purpose is to find the 01535 * correction factor, i.e. the value used to correct the image 01536 * for ad-hoc factors. 01537 * 01538 * @internal 01539 * @history 2008-11-05 Jeannie Walldren - Original version 01540 * @history 2009-05-27 Jeannie Walldren - Renamed from 01541 * FindCorrectionFactor since code was added to find 01542 * the polarization correction factor, when 01543 * available. 01544 */ 01545 void gbl::FindCorrectionFactors() { 01546 QString filter1 = gbl::cissLab->FilterName()[0]; 01547 QString filter2 = gbl::cissLab->FilterName()[1]; 01548 // check if polarized filters 01549 if(filter1 == "IRP0" || filter1 == "P120" || filter1 == "P60" || filter1 == "P0" 01550 || filter2 == "IRP90" || filter2 == "IRP0") { 01551 FileName polarizationFactorFile(gbl::GetCalibrationDirectory("correction") + "pol_correction.tab"); 01552 if(!polarizationFactorFile.fileExists()) { // correction factor file not found, stop calibration 01553 throw IException(IException::Io, 01554 "Unable to calibrate image. PolarizationFactorFile ***" 01555 + polarizationFactorFile.expanded() + "*** not found.", _FILEINFO_); 01556 } 01557 gbl::calgrp += PvlKeyword("PolarizationFactorPerformed", "Yes"); 01558 gbl::calgrp.FindKeyword("PolarizationFactorPerformed").AddComment("Correction Factor Parameters"); 01559 gbl::calgrp += PvlKeyword("PolarizationFactorFile", polarizationFactorFile.expanded()); 01560 CisscalFile *polFact = new CisscalFile(polarizationFactorFile.expanded()); 01561 gbl::polarizationFactor = 0.0; 01562 QString col1, col2, col3, col4; 01563 for(int i = 0; i < polFact->LineCount(); i++) { 01564 QString line; 01565 polFact->GetLine(line); //assigns value to line 01566 line = line.simplified().trimmed(); 01567 QStringList cols = line.split(" "); 01568 col1 = cols.takeFirst(); 01569 if(col1 == gbl::cissLab->InstrumentId()) { 01570 col2 = cols.takeFirst(); 01571 if(col2 == gbl::cissLab->FilterName()[0]) { 01572 col3 = cols.takeFirst(); 01573 if(col3 == gbl::cissLab->FilterName()[1]) { 01574 col4 = cols.takeFirst(); 01575 if(col4 == "") { 01576 gbl::polarizationFactor = 1.0; 01577 // dividing by polarization factor of 1.0 implies this correction is not performed 01578 gbl::calgrp.FindKeyword("PolarizationFactorPerformed").SetValue("No: PolarizationFactorFile contained no factor for filter combination"); 01579 } 01580 else { 01581 gbl::polarizationFactor = toDouble(col4); 01582 } 01583 break; 01584 } 01585 else { 01586 continue; 01587 } 01588 } 01589 else { 01590 continue; 01591 } 01592 } 01593 else { 01594 continue; 01595 } 01596 } 01597 polFact->Close(); 01598 01599 // if no factor was found for instrument ID and filter combination 01600 if(gbl::polarizationFactor == 0.0) { 01601 gbl::polarizationFactor = 1.0; 01602 // dividing by polarization factor of 1.0 implies this correction is not performed 01603 gbl::calgrp.FindKeyword("PolarizationFactorPerformed").SetValue("No: PolarizationFactorFile contained no factor for filter combination"); 01604 } 01605 else { 01606 // polarization factor is defined such that they are applied with the correction factor for the related CLR/Filter pair 01607 if(gbl::cissLab->InstrumentId() == "ISSNA") { 01608 filter1 = "CL1"; 01609 } 01610 if(gbl::cissLab->InstrumentId() == "ISSWA") { 01611 filter2 = "CL2"; 01612 } 01613 } 01614 gbl::calgrp += PvlKeyword("PolarizationFactor", toString(gbl::polarizationFactor)); 01615 01616 } 01617 else { 01618 // no polarization correction - gbl::polarizationFactor already initialized to 1 in main() 01619 gbl::calgrp += PvlKeyword("PolarizationFactorPerformed", "No"); 01620 gbl::calgrp.FindKeyword("PolarizationFactorPerformed").AddComment("Correction Factor Parameters"); 01621 } 01622 // Get the directory where the CISS calibration directories are. 01623 FileName correctionFactorFile(gbl::GetCalibrationDirectory("correction") + "correctionfactors_qecorr.tab"); 01624 if(!correctionFactorFile.fileExists()) { // correction factor file not found, stop calibration 01625 throw IException(IException::Io, 01626 "Unable to calibrate image. CorrectionFactorFile ***" 01627 + correctionFactorFile.expanded() + "*** not found.", _FILEINFO_); 01628 } 01629 gbl::calgrp += PvlKeyword("CorrectionFactorPerformed", "Yes"); 01630 gbl::calgrp += PvlKeyword("CorrectionFactorFile", correctionFactorFile.expanded()); 01631 CisscalFile *corrFact = new CisscalFile(correctionFactorFile.expanded()); 01632 gbl::correctionFactor = 0.0; 01633 QString col1, col2, col3, col4; 01634 for(int i = 0; i < corrFact->LineCount(); i++) { 01635 QString line; 01636 corrFact->GetLine(line); //assigns value to line 01637 line = line.simplified().trimmed(); 01638 QStringList cols = line.split(" "); 01639 col1 = cols.takeFirst(); 01640 if(col1 == gbl::cissLab->InstrumentId()) { 01641 col2 = cols.takeFirst(); 01642 if(col2 == filter1) { 01643 col3 = cols.takeFirst(); 01644 if(col3 == filter2) { 01645 col4 = cols.takeFirst(); 01646 if(col4 == "") { 01647 gbl::correctionFactor = 1.0; 01648 // dividing by correction factor of 1.0 implies this correction is not performed 01649 gbl::calgrp.FindKeyword("CorrectionFactorPerformed").SetValue("No: CorrectionFactorFile contained no factor for filter combination"); 01650 } 01651 else { 01652 gbl::correctionFactor = toDouble(col4); 01653 } 01654 break; 01655 } 01656 else { 01657 continue; 01658 } 01659 } 01660 else { 01661 continue; 01662 } 01663 } 01664 else { 01665 continue; 01666 } 01667 } 01668 corrFact->Close(); 01669 01670 // if no factor was found for instrument ID and filter combination 01671 if(gbl::correctionFactor == 0.0) { 01672 gbl::correctionFactor = 1.0; 01673 // dividing by correction factor of 1.0 implies this correction is not performed 01674 gbl::calgrp.FindKeyword("CorrectionFactorPerformed").SetValue("No: CorrectionFactorFile contained no factor for filter combination"); 01675 } 01676 gbl::calgrp += PvlKeyword("CorrectionFactor", toString(gbl::correctionFactor)); 01677 return; 01678 } 01679 //=====End Correction Factor Methods=============================================================// 01680 01681 /** 01682 * This method returns an QString containing the path of a 01683 * Cassini calibration directory 01684 * 01685 * @param calibrationType 01686 * @return <b>IString</b> Path of the calibration directory 01687 * 01688 * @internal 01689 * @history 2008-11-05 Jeannie Walldren - Original version 01690 */ 01691 QString gbl::GetCalibrationDirectory(QString calibrationType) { 01692 // Get the directory where the CISS calibration directories are. 01693 PvlGroup &dataDir = Preference::Preferences().FindGroup("DataDirectory"); 01694 QString missionDir = (QString) dataDir["Cassini"]; 01695 return missionDir + "/calibration/" + calibrationType + "/"; 01696 } 01697