// Main moccal routine void IsisMain() { // We will be processing by line ProcessByLine p; // Setup the input and make sure it is a ctx file UserInterface &ui = Application::GetUserInterface(); Isis::Pvl lab(ui.GetFileName("FROM")); Isis::PvlGroup &inst = lab.findGroup("Instrument", Pvl::Traverse); QString instId = inst["InstrumentId"]; if(instId != "CTX") { QString msg = "This is not a CTX image. Ctxcal requires a CTX image."; throw IException(IException::User, msg, _FILEINFO_); } Cube *icube = p.SetInputCube("FROM", OneBand); Cube flatFile; if(ui.WasEntered("FLATFILE")) { flatFile.open(ui.GetFileName("FLATFILE")); } else { FileName flat = FileName("$mro/calibration/ctxFlat_????.cub").highestVersion(); flatFile.open(flat.expanded()); } flat = new Brick(5000, 1, 1, flatFile.pixelType()); flat->SetBasePosition(1, 1, 1); flatFile.read(*flat); // If it is already calibrated then complain if(icube->hasGroup("Radiometry")) { QString msg = "The CTX image [" + icube->fileName() + "] has already " "been radiometrically calibrated"; throw IException(IException::User, msg, _FILEINFO_); } // Get label parameters we will need for calibration equation iTime startTime((QString) inst["StartTime"]); double etStart = startTime.Et(); // Read exposure and convert to milliseconds exposure = inst["LineExposureDuration"]; //exposure *= 1000.; sum = inst["SpatialSumming"]; // If firstSamp > 0, adjust by 38 to account for prefix pixels. firstSamp = inst["SampleFirstPixel"]; if(firstSamp > 0) firstSamp -= 38; // Read dark current info, if no dc exit? Table dcTable("Ctx Prefix Dark Pixels"); icube->read(dcTable); // TODO:: make sure dc records match cube nlines. // If summing mode = 1 , average odd & even dc pixels separately for // a & b channels. // If summing mode != 1, average all dc pixels and use for both for(int rec = 0; rec < dcTable.Records(); rec++) { vector<int> darks = dcTable[rec]["DarkPixels"]; bool aChannel = true; double dcASum = 0.; double dcBSum = 0.; int dcACount = 0; int dcBCount = 0; double dcSum = 0; int dcCount = 0; for(int i = 0; i < (int)darks.size(); i++) { if(sum == 1) { if(aChannel == true) { dcASum += (double)darks.at(i); dcACount++; } else { dcBSum += (double)darks.at(i); dcBCount++; } aChannel = !aChannel; } else if(sum > 1) { dcSum += (double)darks.at(i); dcCount ++; } } if(sum == 1) { dcA.push_back(dcASum / (double)dcACount); dcB.push_back(dcBSum / (double)dcBCount); } else { dc.push_back(dcSum / (double)dcCount); } } // See if the user wants counts/ms or i/f // iof = conversion factor from counts/ms to i/f bool convertIOF = ui.GetBoolean("IOF"); if(convertIOF) { // Get the distance between Mars and the Sun at the given time in // Astronomical Units (AU) QString bspKernel = p.MissionData("base", "/kernels/spk/de???.bsp", true); furnsh_c(bspKernel.toAscii().data()); QString pckKernel = p.MissionData("base", "/kernels/pck/pck?????.tpc", true); furnsh_c(pckKernel.toAscii().data()); double sunpos[6], lt; spkezr_c("sun", etStart, "iau_mars", "LT+S", "mars", sunpos, <); double dist1 = vnorm_c(sunpos); unload_c(bspKernel.toAscii().data()); unload_c(pckKernel.toAscii().data()); double dist = 2.07E8; double w0 = 3660.5; double w1 = w0 * ((dist * dist) / (dist1 * dist1)); if(exposure *w1 == 0.0) { QString msg = icube->fileName() + ": exposure or w1 has value of 0.0 "; throw IException(IException::User, msg, _FILEINFO_); } iof = 1.0 / (exposure * w1); } else { iof = 1.0; } // Setup the output cube Cube *ocube = p.SetOutputCube("TO"); // Add the radiometry group PvlGroup calgrp("Radiometry"); calgrp += PvlKeyword("FlatFile", flatFile.fileName()); calgrp += PvlKeyword("iof", toString(iof)); ocube->putGroup(calgrp); // Start the line-by-line calibration sequence p.StartProcess(Calibrate); p.EndProcess(); }
// Main moccal routine void IsisMain() { // We will be processing by line ProcessByLine p; // Setup the input and make sure it is a moc file UserInterface &ui = Application::GetUserInterface(); Cube *icube = p.SetInputCube("FROM", OneBand); gbl::moc = new MocLabels(ui.GetFileName("FROM")); // If it is already calibrated then complain if(icube->hasGroup("Radiometry")) { QString msg = "The MOC image [" + icube->fileName() + "] has already " "been radiometrically calibrated"; throw IException(IException::User, msg, _FILEINFO_); } // Get label parameters we will need for calibration equation gbl::a = gbl::moc->Gain(); gbl::off = gbl::moc->Offset(); gbl::ex = gbl::moc->ExposureDuration(); // Get the starting, ending, and activation et's. For now, the // activation et is set to the largest double precision value. If // The narrow angle B detectors ever get activated then the value // will need to be changed to the appropriate et iTime startTime(gbl::moc->StartTime()); double etStart = startTime.Et(); double etNABActivation = DBL_MAX; // Open the calibration kernel that contains constants for each camera // and internalize it in a pvl object QString calKernelFile; if(ui.WasEntered("CALKERNEL")) { calKernelFile = ui.GetFileName("CALKERNEL"); } else { calKernelFile = p.MissionData("mgs", "/calibration/moccal.ker.???", true); } Pvl calKernel(calKernelFile); // Point to the right group of camera parameters QString camera; if(gbl::moc->WideAngleRed()) { camera = "WideAngleRed"; } else if(gbl::moc->WideAngleBlue()) { camera = "WideAngleBlue"; } else if(etStart > etNABActivation) { camera = "NarrowAngleB"; } else { camera = "NarrowAngleA"; } PvlGroup &calCamera = calKernel.findGroup(camera); // Get the camera specific calibration parameters from the kernel file // and load detector coefficients (gain/offsets at each pixel) gbl::z = calCamera["Z"]; gbl::dc = calCamera["DC"]; gbl::g = calCamera["G"]; gbl::w0 = calCamera["W0"]; QString coefFile = calCamera["CoefFile"]; gbl::LoadCoefficients(coefFile, icube->sampleCount()); #if 0 // Override with these with any user selected parameters if(ui.WasEntered("Z")) gbl::z = ui.GetDouble("Z"); if(ui.WasEntered("DC")) gbl::dc = ui.GetDouble("DC"); if(ui.WasEntered("G")) gbl::g = ui.GetDouble("G"); if(ui.WasEntered("W0")) gbl::w0 = ui.GetDouble("W0"); #endif gbl::nullWago = ui.GetBoolean("NULLWAGO"); // Get the distance between Mars and the Sun at the given time in // Astronomical Units (AU) QString bspKernel = p.MissionData("base", "/kernels/spk/de???.bsp", true); furnsh_c(bspKernel.toAscii().data()); QString pckKernel = p.MissionData("base", "/kernels/pck/pck?????.tpc", true); furnsh_c(pckKernel.toAscii().data()); double sunpos[6], lt; spkezr_c("sun", etStart, "iau_mars", "LT+S", "mars", sunpos, <); double dist = vnorm_c(sunpos); double kmPerAU = 1.4959787066E8; double sunAU = dist / kmPerAU; unload_c(bspKernel.toAscii().data()); unload_c(pckKernel.toAscii().data()); // See if the user wants counts/ms or i/f but if w0 is 0 then // we must go to counts/ms // iof = conversion factor from counts/ms to i/f bool convertIOF = ui.GetBoolean("IOF") && (gbl::w0 > 0.0); if(convertIOF) { gbl::iof = sunAU * sunAU / gbl::w0; } else { gbl::iof = 1.0; } // Setup the output cube Cube *ocube = p.SetOutputCube("TO"); // Add the radiometry group PvlGroup calgrp("Radiometry"); calgrp += PvlKeyword("CalibrationKernel", calKernelFile); calgrp += PvlKeyword("CoefficientFile", coefFile); calgrp += PvlKeyword("a", toString(gbl::a)); calgrp["a"].addComment("Radiometric equation in moccal"); calgrp["a"].addComment("r = (pixel - z + off) / a - g / ex - dc"); calgrp += PvlKeyword("off", toString(gbl::off)); calgrp += PvlKeyword("ex", toString(gbl::ex)); calgrp += PvlKeyword("z", toString(gbl::z)); calgrp += PvlKeyword("dc", toString(gbl::dc)); calgrp += PvlKeyword("g", toString(gbl::g)); calgrp += PvlKeyword("w0", toString(gbl::w0)); calgrp["w0"].addComment("Reflectance = r * iof, where iof = (s * s) / w0"); calgrp += PvlKeyword("s", toString(sunAU)); calgrp += PvlKeyword("iof", toString(gbl::iof)); ocube->putGroup(calgrp); // Start the line-by-line calibration sequence p.StartProcess(gbl::Calibrate); p.EndProcess(); // Now go fix errors around the wago changes gbl::FixWagoLines(ui.GetFileName("TO")); // Cleanup gbl::pixelGain.clear(); gbl::pixelOffset.clear(); gbl::inLineAvg.clear(); gbl::outLineAvg.clear(); }