|
Isis 3.0 Application Source Code Reference |
Home |
00001 #include "Isis.h" 00002 00003 #include <vector> 00004 #include <stdio.h> 00005 00006 #include <QFile> 00007 00008 #include "Camera.h" 00009 #include "EndianSwapper.h" 00010 #include "IException.h" 00011 #include "IString.h" 00012 #include "LeastSquares.h" 00013 #include "LineManager.h" 00014 #include "PolynomialUnivariate.h" 00015 #include "ProcessByLine.h" 00016 #include "ProgramLauncher.h" 00017 #include "Statistics.h" 00018 #include "Table.h" 00019 #include "UserInterface.h" 00020 00021 using namespace Isis; 00022 using namespace std; 00023 00024 //! map from <sample, band> to dark correction value 00025 map< pair<int, int>, double > sampleBasedDarkCorrections; 00026 00027 //! map from <line, band> to dark correction value 00028 map< pair<int, int>, double > lineBasedDarkCorrections; 00029 00030 //! specific energy corrections for each band of the cube 00031 vector<double> specificEnergyCorrections; 00032 00033 //! list of temp files that need deleted 00034 vector<QString> tempFiles; 00035 00036 //! solar remove coefficient 00037 double solarRemoveCoefficient; 00038 00039 //! Output in I/F units 00040 bool iof; 00041 00042 void calculateDarkCurrent(Cube *); 00043 void calculateVisDarkCurrent(Cube *); 00044 void calculateIrDarkCurrent(Cube *); 00045 00046 void chooseFlatFile(Cube *, ProcessByLine *); 00047 00048 void calculateSpecificEnergy(Cube *); 00049 void calculateSolarRemove(Cube *, ProcessByLine *); 00050 00051 void calibrate(vector<Buffer *> &in, vector<Buffer *> &out); 00052 00053 QString createCroppedFile(Cube *icube, QString cubeFileName, bool flatFile = false); 00054 void GetOffsets(const Pvl &lab, int &finalSampOffset, int &finalLineOffset); 00055 00056 // This is the results group 00057 PvlGroup calibInfo; 00058 00059 void IsisMain() { 00060 UserInterface &ui = Application::GetUserInterface(); 00061 00062 tempFiles.clear(); 00063 specificEnergyCorrections.clear(); 00064 sampleBasedDarkCorrections.clear(); 00065 lineBasedDarkCorrections.clear(); 00066 solarRemoveCoefficient = 1.0; 00067 iof = (ui.GetString("UNITS") == "IOF"); 00068 00069 calibInfo = PvlGroup("Results"); 00070 00071 ProcessByLine p; 00072 Cube *icube = p.SetInputCube("FROM"); 00073 00074 bool isVims = true; 00075 00076 try { 00077 isVims = (icube->label()->FindGroup("Instrument", 00078 Pvl::Traverse)["InstrumentId"][0] == "VIMS"); 00079 } 00080 catch(IException &e) { 00081 isVims = false; 00082 } 00083 00084 if(!isVims) { 00085 QString msg = "The input cube [" + QString(ui.GetAsString("FROM")) + "] is not a Cassini VIMS cube"; 00086 throw IException(IException::User, msg, _FILEINFO_); 00087 } 00088 00089 if(icube->label()->FindObject("IsisCube").HasGroup("AlphaCube")) { 00090 QString msg = "The input cube [" + QString(ui.GetAsString("FROM")) + "] has had its dimensions modified and can not be calibrated"; 00091 throw IException(IException::User, msg, _FILEINFO_); 00092 } 00093 00094 // done first since it's likely to cause an error if one exists 00095 calculateSolarRemove(icube, &p); 00096 00097 if(ui.GetBoolean("DARK")) 00098 calculateDarkCurrent(icube); 00099 00100 chooseFlatFile(icube, &p); 00101 calculateSpecificEnergy(icube); 00102 00103 calibInfo += PvlKeyword("OutputUnits", ((iof) ? "I/F" : "Specific Energy")); 00104 00105 Application::Log(calibInfo); 00106 00107 p.SetOutputCube("TO"); 00108 p.StartProcess(calibrate); 00109 p.EndProcess(); 00110 00111 for(unsigned int i = 0; i < tempFiles.size(); i++) { 00112 QFile::remove(tempFiles[i]); 00113 } 00114 00115 tempFiles.clear(); 00116 } 00117 00118 /** 00119 * This applies the calculated calibration coefficients to the file. 00120 * 00121 * @param inBuffers 00122 * @param outBuffers 00123 */ 00124 void calibrate(vector<Buffer *> &inBuffers, vector<Buffer *> &outBuffers) { 00125 Buffer *inBuffer = inBuffers[0]; 00126 Buffer *flatFieldBuffer = inBuffers[1]; 00127 Buffer *solarRemoveBuffer = NULL; // this is optional 00128 00129 if(inBuffers.size() > 2) { 00130 inBuffer = inBuffers[0]; 00131 solarRemoveBuffer = inBuffers[1]; 00132 flatFieldBuffer = inBuffers[2]; 00133 } 00134 00135 Buffer *outBuffer = outBuffers[0]; 00136 00137 for(int i = 0; i < inBuffer->size(); i++) { 00138 (*outBuffer)[i] = (*inBuffer)[i]; 00139 00140 if(IsSpecial((*outBuffer)[i])) continue; 00141 00142 map< pair<int, int>, double>::iterator darkCorrection = 00143 sampleBasedDarkCorrections.find(pair<int, int>(i + 1, inBuffer->Band())); 00144 00145 if(darkCorrection != sampleBasedDarkCorrections.end()) { 00146 (*outBuffer)[i] -= darkCorrection->second; 00147 } 00148 00149 darkCorrection = lineBasedDarkCorrections.find(pair<int, int>(inBuffer->Line(), inBuffer->Band())); 00150 00151 if(darkCorrection != lineBasedDarkCorrections.end()) { 00152 if(!IsSpecial(darkCorrection->second)) 00153 (*outBuffer)[i] -= darkCorrection->second; 00154 else 00155 (*outBuffer)[i] = Null; 00156 } 00157 00158 if(!IsSpecial((*flatFieldBuffer)[i]) && !IsSpecial((*outBuffer)[i])) { 00159 (*outBuffer)[i] /= (*flatFieldBuffer)[i]; 00160 } 00161 00162 if(inBuffer->Band() <= (int)specificEnergyCorrections.size() && !IsSpecial((*outBuffer)[i])) { 00163 (*outBuffer)[i] *= specificEnergyCorrections[inBuffer->Band()-1]; 00164 } 00165 00166 if(iof && solarRemoveBuffer && !IsSpecial((*outBuffer)[i])) { 00167 (*outBuffer)[i] = (*outBuffer)[i] / ((*solarRemoveBuffer)[i] / solarRemoveCoefficient) * Isis::PI; 00168 } 00169 } 00170 } 00171 00172 /** 00173 * This calculates the values necessary to convert from 00174 * specific energy to I/F. A cube is used as part of the 00175 * equation (which probably* just contains a vector of values) 00176 * so p->SetInputCube(...) will be called with the appropriate 00177 * filename. 00178 * 00179 * @param icube 00180 * @param p 00181 */ 00182 void calculateSolarRemove(Cube *icube, ProcessByLine *p) { 00183 UserInterface &ui = Application::GetUserInterface(); 00184 if(ui.GetString("UNITS") != "IOF") return; 00185 00186 Camera *cam = NULL; 00187 00188 try { 00189 cam = icube->camera(); 00190 } 00191 catch(IException &e) { 00192 QString msg = "Unable to create a camera model from [" + 00193 icube->fileName() + "]. Please run " 00194 "spiceinit on this file"; 00195 throw IException(e, IException::Unknown, msg, _FILEINFO_); 00196 } 00197 00198 00199 solarRemoveCoefficient = -1; 00200 00201 // try center first 00202 if(cam->SetImage(icube->sampleCount() / 2, icube->lineCount() / 2)) { 00203 solarRemoveCoefficient = cam->SolarDistance() * cam->SolarDistance(); 00204 } 00205 00206 // try 4 corners 00207 if(solarRemoveCoefficient < 0 && cam->SetImage(1.0, 1.0)) { 00208 solarRemoveCoefficient = cam->SolarDistance() * cam->SolarDistance(); 00209 } 00210 00211 if(solarRemoveCoefficient < 0 && cam->SetImage(icube->sampleCount(), 1.0)) { 00212 solarRemoveCoefficient = cam->SolarDistance() * cam->SolarDistance(); 00213 } 00214 00215 if(solarRemoveCoefficient < 0 && cam->SetImage(icube->sampleCount(), 00216 icube->lineCount())) { 00217 solarRemoveCoefficient = cam->SolarDistance() * cam->SolarDistance(); 00218 } 00219 00220 if(solarRemoveCoefficient < 0 && cam->SetImage(1.0, icube->lineCount())) { 00221 solarRemoveCoefficient = cam->SolarDistance() * cam->SolarDistance(); 00222 } 00223 00224 // try center of 4 edges 00225 if(solarRemoveCoefficient < 0 && cam->SetImage(icube->sampleCount() / 2, 1.0)) { 00226 solarRemoveCoefficient = cam->SolarDistance() * cam->SolarDistance(); 00227 } 00228 00229 if(solarRemoveCoefficient < 0 && cam->SetImage(icube->sampleCount(), 00230 icube->lineCount() / 2)) { 00231 solarRemoveCoefficient = cam->SolarDistance() * cam->SolarDistance(); 00232 } 00233 00234 if(solarRemoveCoefficient < 0 && cam->SetImage(icube->sampleCount() / 2, 00235 icube->lineCount())) { 00236 solarRemoveCoefficient = cam->SolarDistance() * cam->SolarDistance(); 00237 } 00238 00239 if(solarRemoveCoefficient < 0 && cam->SetImage(1.0, icube->lineCount() / 2)) { 00240 solarRemoveCoefficient = cam->SolarDistance() * cam->SolarDistance(); 00241 } 00242 00243 // Default to original vimscal's solar distance if we can't find a target 00244 if(solarRemoveCoefficient < 0) { 00245 solarRemoveCoefficient = 81.595089; 00246 /* 00247 QString msg = "Unable to project image at four corners, center of edges or "; 00248 msg += "at center. The solar distance can not be calculated, try using"; 00249 msg += " [UNITS=SPECENERGY] on ["; 00250 msg += icube->FileName() + "]"; 00251 throw iException::Message(iException::Camera, msg, _FILEINFO_); 00252 */ 00253 } 00254 00255 bool vis = (icube->label()-> 00256 FindGroup("Instrument", Pvl::Traverse)["Channel"][0] != "IR"); 00257 00258 QString attributes; 00259 00260 // vis is bands 1-96, ir is bands 97-352 in this calibration file 00261 if(vis) { 00262 attributes = "+1-96"; 00263 } 00264 else { 00265 attributes = "+97-352"; 00266 } 00267 00268 CubeAttributeInput iatt(attributes); 00269 00270 FileName solarFileName("$cassini/calibration/vims/solar_v????.cub"); 00271 solarFileName = solarFileName.highestVersion(); 00272 00273 p->SetInputCube(createCroppedFile(icube, solarFileName.expanded()), iatt); 00274 } 00275 00276 00277 /** 00278 * This calculates the coefficients for specific energy corrections 00279 */ 00280 void calculateSpecificEnergy(Cube *icube) { 00281 PvlGroup &inst = icube->label()->FindGroup("Instrument", Pvl::Traverse); 00282 bool vis = (inst["Channel"][0] != "IR"); 00283 00284 double coefficient = 1.0; 00285 00286 if(inst["GainMode"][0] == "HIGH") { 00287 coefficient /= 2; 00288 } 00289 00290 if(vis && inst["SamplingMode"][0] == "HI-RES") { 00291 coefficient *= 3; 00292 } 00293 00294 if(vis) { 00295 coefficient /= toDouble(inst["ExposureDuration"][1]) / 1000.0; 00296 } 00297 else { 00298 coefficient /= (toDouble(inst["ExposureDuration"][0])) / 1000.0 - 0.004; 00299 } 00300 00301 QString specEnergyFile = "$cassini/calibration/vims/"; 00302 00303 if(vis) { 00304 specEnergyFile += "vis_perf_v????.cub"; 00305 } 00306 else { 00307 specEnergyFile += "ir_perf_v????.cub"; 00308 } 00309 00310 QString waveCalFile = "$cassini/calibration/vims/wavecal_v????.cub"; 00311 00312 FileName specEnergyFileName(specEnergyFile); 00313 specEnergyFileName = specEnergyFileName.highestVersion(); 00314 00315 FileName waveCalFileName(waveCalFile); 00316 waveCalFileName = waveCalFileName.highestVersion(); 00317 00318 Cube specEnergyCube; 00319 specEnergyCube.open(specEnergyFileName.expanded()); 00320 00321 Cube waveCalCube; 00322 waveCalCube.open(waveCalFileName.expanded()); 00323 00324 LineManager specEnergyMgr(specEnergyCube); 00325 LineManager waveCalMgr(waveCalCube); 00326 00327 for(int i = 0; i < icube->bandCount(); i++) { 00328 Statistics specEnergyStats; 00329 Statistics waveCalStats; 00330 00331 if(vis) { 00332 specEnergyMgr.SetLine(1, i + 1); 00333 waveCalMgr.SetLine(1, i + 1); 00334 } 00335 else { 00336 specEnergyMgr.SetLine(1, i + 1); 00337 // ir starts at band 97 00338 waveCalMgr.SetLine(1, i + 96 + 1); 00339 } 00340 00341 specEnergyCube.read(specEnergyMgr); 00342 waveCalCube.read(waveCalMgr); 00343 00344 specEnergyStats.AddData(specEnergyMgr.DoubleBuffer(), specEnergyMgr.size()); 00345 waveCalStats.AddData(waveCalMgr.DoubleBuffer(), waveCalMgr.size()); 00346 00347 double bandCoefficient = coefficient * specEnergyStats.Average() * waveCalStats.Average(); 00348 00349 specificEnergyCorrections.push_back(bandCoefficient); 00350 } 00351 } 00352 00353 /** 00354 * This decides if we have a VIS or IR dark current correction and calls the 00355 * appropriate method. 00356 * 00357 * @param currCube 00358 */ 00359 void calculateDarkCurrent(Cube *icube) { 00360 PvlGroup &inst = icube->label()->FindGroup("Instrument", Pvl::Traverse); 00361 bool vis = (inst["Channel"][0] != "IR"); 00362 00363 calibInfo += PvlKeyword("Vis", ((vis) ? "true" : "false")); 00364 00365 if(vis) { 00366 calculateVisDarkCurrent(icube); 00367 } 00368 else { 00369 calculateIrDarkCurrent(icube); 00370 } 00371 } 00372 00373 /** 00374 * This populates darkCorrections with the result of the equation: 00375 * dark = a + x * b 00376 * for each line,band. a, b are from the "vis_*_dark_model.tab" files 00377 * and x is the ExposureDuration. 00378 * 00379 * @param icube 00380 */ 00381 void calculateVisDarkCurrent(Cube *icube) { 00382 PvlGroup &inst = icube->label()->FindGroup("Instrument", Pvl::Traverse); 00383 00384 // This is the dark current corrections for VIS 00385 bool hires = ((inst["SamplingMode"][0] == "HIGH") || (inst["SamplingMode"][0] == "HI-RES")); 00386 QString calFile = "$cassini/calibration/vims/vis_"; 00387 00388 if(hires) { 00389 calFile += "hires"; 00390 } 00391 else { 00392 calFile += "lowres"; 00393 } 00394 00395 calFile += "_dark_model_v????.tab"; 00396 00397 FileName calFileName(calFile); 00398 calFileName = calFileName.highestVersion(); 00399 00400 calibInfo += PvlKeyword("DarkCurrentFile", calFileName.originalPath() + "/" + calFileName.name()); 00401 00402 calFile = calFileName.expanded(); 00403 00404 EndianSwapper swapper("LSB"); 00405 00406 FILE *calFilePtr = fopen(calFile.toAscii().data(), "r"); 00407 00408 double visExposure = toDouble(inst["ExposureDuration"][1]); 00409 00410 int sampleOffset, lineOffset; 00411 GetOffsets(*icube->label(), sampleOffset, lineOffset); 00412 00413 /** 00414 * Reading in one parameter at a time: 00415 * parameter 1 = constant coefficient 00416 * parameter 2 = exposure coefficient 00417 * param1 + param2*exposure = dark correction 00418 * 00419 * Do byte swapping where necessary. 00420 */ 00421 for(int parameter = 1; parameter <= 2; parameter ++) { 00422 for(int band = 1; band <= 96; band++) { 00423 for(int sample = 1; sample <= 64; sample++) { 00424 float calData; 00425 00426 if(fread(&calData, sizeof(calData), 1, calFilePtr) != 1) { 00427 // error! 00428 QString msg = "Error reading file [" + calFile + "]"; 00429 throw IException(IException::Io, msg, _FILEINFO_); 00430 } 00431 00432 int associatedSample = sample - sampleOffset + 1; 00433 00434 calData = swapper.Float(&calData); 00435 pair<int, int> index = pair<int, int>(associatedSample, band); 00436 00437 map< pair<int, int>, double>::iterator pos = sampleBasedDarkCorrections.find(index); 00438 if(pos == sampleBasedDarkCorrections.end()) { 00439 sampleBasedDarkCorrections.insert(pair< pair<int, int>, double>(index, calData)); 00440 } 00441 else { 00442 (*pos).second = (*pos).second + visExposure * calData; 00443 } 00444 } 00445 } 00446 } 00447 00448 fclose(calFilePtr); 00449 00450 // If spectral summing is on, go in sets of 8 and set darks to the average 00451 /* 00452 PvlGroup &archive = icube->Label()->FindGroup("Archive", Pvl::Traverse); 00453 if(archive["SpectralSummingFlag"][0] == "ON") { 00454 for(int band = 1; band <= 96; band += 8) { 00455 for(int sample = 1; sample <= 64; sample++) { 00456 Statistics stats; 00457 00458 // we're calculating an average of 8 of these values through the bands 00459 for(int avgIndex = 0; avgIndex < 8; avgIndex ++) { 00460 // this wont go out of bounds as long as we have 8 as the increment 00461 pair<int,int> index = pair<int,int>(sample, band+avgIndex); 00462 stats.AddData(sampleBasedDarkCorrections.find(index)->second); 00463 } 00464 00465 // now set the values to the average 00466 for(int setIndex = 0; setIndex < 8; setIndex ++) { 00467 pair<int,int> index = pair<int,int>(sample, band+setIndex); 00468 if(!setIndex) printf("Changing %.4f to %.4f\n", sampleBasedDarkCorrections.find(index)->second, stats.Average()); 00469 sampleBasedDarkCorrections.find(index)->second = stats.Average(); 00470 } 00471 } 00472 } 00473 }*/ 00474 } 00475 00476 /** 00477 * This calculates the dark current corrections for IR. If 00478 * IRDARKAVG is false, then it translates the sideplane data 00479 * into the lineBasedDarkCorrections map directly and does nothing further 00480 * with the data. Otherwise, this will apply a least squares linear 00481 * fit (the original script did chi-squared, but this is okay) for 00482 * each band and uses the points on the line instead of the sideplane 00483 * data directly. 00484 * 00485 * @param icube 00486 */ 00487 void calculateIrDarkCurrent(Cube *icube) { 00488 UserInterface &ui = Application::GetUserInterface(); 00489 00490 bool found = false; 00491 00492 // verify if IR we have sideplane data 00493 for(int obj = 0; !found && obj < icube->label()->Objects(); obj++) { 00494 PvlObject &object = icube->label()->Object(obj); 00495 00496 if(object.Name() != "Table") continue; 00497 00498 if(object.HasKeyword("Name") && object["Name"][0] == "SideplaneIr") found = true; 00499 } 00500 00501 if(!found) { 00502 calibInfo += PvlKeyword("SideplaneCorrection", "None"); 00503 return; 00504 } 00505 00506 Table sideplane("SideplaneIr", ui.GetFileName("FROM")); 00507 00508 // If spectal summing is on OR compressor_id isnt N/A then 00509 // just return. 00510 PvlGroup &archive = icube->label()->FindGroup("Archive", Pvl::Traverse); 00511 00512 // If dark subtracted (compressorid is valid) and cant do linear 00513 // correction (spectral editing flag on) then do not do dark 00514 if(archive["CompressorId"][0] != "N/A" && 00515 archive["SpectralEditingFlag"][0] == "ON") { 00516 calibInfo += PvlKeyword("SideplaneCorrection", "None"); 00517 return; 00518 } 00519 00520 // If subtracted (compressor id is valid) and dont do linear then return 00521 if(archive["CompressorId"][0] != "N/A" && ui.GetBoolean("IRORIGDARK") == true) { 00522 calibInfo += PvlKeyword("SideplaneCorrection", "None"); 00523 return; 00524 } 00525 00526 if(archive["SpectralSummingFlag"][0] == "ON") return; 00527 00528 // Insert the sideplane data into our lineBasedDarkCorrections map (line,band to correction) 00529 for(int line = 1; line <= icube->lineCount(); line++) { 00530 for(int band = 1; band <= icube->bandCount(); band++) { 00531 pair<int, int> index = pair<int, int>(line, band); 00532 int value = (int)sideplane[(line-1)*icube->bandCount() + (band-1)][2]; 00533 00534 if(value != 57344) 00535 lineBasedDarkCorrections.insert(pair< pair<int, int>, double>(index, value)); 00536 else 00537 lineBasedDarkCorrections.insert(pair< pair<int, int>, double>(index, Null)); 00538 } 00539 } 00540 00541 if(ui.GetBoolean("IRORIGDARK") == true) { 00542 calibInfo += PvlKeyword("SideplaneCorrection", "Sideplane"); 00543 return; 00544 } 00545 00546 // do linear fits 00547 for(int band = 1; band <= icube->bandCount(); band++) { 00548 PolynomialUnivariate basis(1); 00549 LeastSquares lsq(basis); 00550 00551 for(int line = 1; line <= icube->lineCount(); line++) { 00552 pair<int, int> index = pair<int, int>(line, band); 00553 map< pair<int, int>, double>::iterator val = lineBasedDarkCorrections.find(index); 00554 00555 if(val != lineBasedDarkCorrections.end()) { 00556 vector<double> input; 00557 input.push_back(line); 00558 double expected = val->second; 00559 00560 if(!IsSpecial(expected)) 00561 lsq.AddKnown(input, expected); 00562 } 00563 } 00564 00565 if(lsq.Rows() == 0) return; 00566 lsq.Solve(); 00567 00568 double coefficients[2] = { 00569 basis.Coefficient(0), 00570 basis.Coefficient(1) 00571 }; 00572 00573 for(int line = 1; line <= icube->lineCount(); line++) { 00574 pair<int, int> index = pair<int, int>(line, band); 00575 00576 map< pair<int, int>, double>::iterator val = lineBasedDarkCorrections.find(index); 00577 if(val != lineBasedDarkCorrections.end()) { 00578 double currentDark = val->second; 00579 00580 if(!IsSpecial(currentDark)) { 00581 double newDark = coefficients[0] + line * coefficients[1]; 00582 00583 // initial dark applied by compressor 00584 if(archive["CompressorId"][0] != "N/A") { 00585 // input is in (dn-dark) units 00586 // (dn-dark) - (fit-dark) = dn-fit 00587 newDark -= currentDark; 00588 } 00589 00590 val->second = newDark; 00591 } 00592 } 00593 } 00594 } 00595 00596 if(archive["CompressorId"][0] != "N/A") { 00597 calibInfo += PvlKeyword("SideplaneCorrection", "Fit Delta"); 00598 } 00599 else { 00600 calibInfo += PvlKeyword("SideplaneCorrection", "Fit"); 00601 } 00602 } 00603 00604 /** 00605 * This calls p->SetInputCube with the appropriate flat file needed for 00606 * icube. 00607 * 00608 * @param icube 00609 * @param p 00610 */ 00611 void chooseFlatFile(Cube *icube, ProcessByLine *p) { 00612 PvlGroup &inst = icube->label()->FindGroup("Instrument", Pvl::Traverse); 00613 bool vis = (inst["Channel"][0] != "IR"); 00614 bool hires = ((inst["SamplingMode"][0] == "HIGH") || (inst["SamplingMode"][0] == "HI-RES")); 00615 00616 QString calFile = "$cassini/calibration/vims/flatfield/"; 00617 00618 if(vis) { 00619 calFile += "vis_"; 00620 } 00621 else { 00622 calFile += "ir_"; 00623 } 00624 00625 if(hires) { 00626 calFile += "hires_flatfield_v????.cub"; 00627 } 00628 else { 00629 calFile += "flatfield_v????.cub"; 00630 } 00631 00632 FileName calibrationFileName(calFile); 00633 calibrationFileName = calibrationFileName.highestVersion(); 00634 00635 calibInfo += PvlKeyword("FlatFile", calibrationFileName.originalPath() + "/" + calibrationFileName.name()); 00636 00637 CubeAttributeInput iatt; 00638 p->SetInputCube(createCroppedFile(icube, calibrationFileName.expanded(), true), iatt); 00639 } 00640 00641 /** 00642 * This makes our calibration files match the input cube described 00643 * by the swath keywords. 00644 * 00645 * @param icube 00646 * @param cubeFileName 00647 * 00648 * @return QString 00649 */ 00650 QString createCroppedFile(Cube *icube, QString cubeFileName, bool flatFile) { 00651 int sampOffset = 1; 00652 int lineOffset = 1; 00653 00654 if(flatFile) { 00655 GetOffsets(*icube->label(), sampOffset, lineOffset); 00656 } 00657 00658 00659 QString appArgs = "from=" + cubeFileName + " "; 00660 appArgs += "sample=" + toString(sampOffset) + " "; 00661 appArgs += "line=" + toString(lineOffset) + " "; 00662 appArgs += "nsamples=" + toString(icube->sampleCount()) + " "; 00663 appArgs += "nlines=" + toString(icube->lineCount()) + " "; 00664 00665 FileName tempFile("$TEMPORARY/tmp_" + FileName(cubeFileName).baseName() + 00666 "_" + FileName(icube->fileName()).name()); 00667 00668 appArgs += "to=" + tempFile.expanded(); 00669 00670 ProgramLauncher::RunIsisProgram("crop", appArgs); 00671 tempFiles.push_back(tempFile.expanded()); 00672 return tempFile.expanded(); 00673 } 00674 00675 void GetOffsets(const Pvl &lab, int &finalSampOffset, int &finalLineOffset) { 00676 const PvlGroup &inst = lab.FindGroup("Instrument", Pvl::Traverse); 00677 00678 // Get sample/line offsets 00679 int sampOffset = inst ["XOffset"]; 00680 int lineOffset = inst ["ZOffset"]; 00681 00682 // Get swath width/length which will be image size unless occultation image 00683 int swathWidth = inst ["SwathWidth"]; 00684 int swathLength = inst ["SwathLength"]; 00685 00686 bool vis = (inst["Channel"][0] != "IR"); 00687 finalSampOffset = sampOffset; 00688 finalLineOffset = lineOffset; 00689 00690 QString samplingMode = QString(inst["SamplingMode"]).toUpper(); 00691 if(vis) { 00692 if(samplingMode == "NORMAL") { 00693 finalSampOffset = sampOffset - 1; 00694 finalLineOffset = lineOffset - 1; 00695 } 00696 else if(samplingMode == "HI-RES") { 00697 finalSampOffset = (3 * ((sampOffset - 1) + swathWidth / 2)) - swathWidth / 2; 00698 finalLineOffset = (3 * (lineOffset + swathLength / 2)) - swathLength / 2; 00699 } 00700 else { 00701 QString msg = "Unsupported sampling mode [" + samplingMode + "]"; 00702 throw IException(IException::Io, msg, _FILEINFO_); 00703 } 00704 } 00705 else { 00706 if(samplingMode == "NORMAL") { 00707 finalSampOffset = sampOffset - 1; 00708 finalLineOffset = lineOffset - 1; 00709 } 00710 else if(samplingMode == "HI-RES") { 00711 finalSampOffset = 2 * ((sampOffset - 1) + ((swathWidth - 1) / 4)); 00712 finalLineOffset = lineOffset - 1; 00713 } 00714 else if(samplingMode == "NYQUIST") { 00715 QString msg = "Cannot process NYQUIST (undersampled) mode "; 00716 throw IException(IException::Unknown, msg, _FILEINFO_); 00717 } 00718 else { 00719 QString msg = "Unsupported sampling mode [" + samplingMode + "]"; 00720 throw IException(IException::Unknown, msg, _FILEINFO_); 00721 } 00722 } 00723 00724 finalSampOffset ++; 00725 finalLineOffset ++; 00726 }