USGS

Isis 3.0 Object Programmers' Reference

Home

MdisCamera.cpp
Go to the documentation of this file.
1 
23 #include <cmath>
24 
25 #include <QVariant>
26 
27 #include "MdisCamera.h"
29 
30 #include "CameraDetectorMap.h"
31 #include "CameraDistortionMap.h"
32 #include "CameraFocalPlaneMap.h"
33 #include "CameraGroundMap.h"
34 #include "CameraSkyMap.h"
35 #include "IException.h"
36 #include "IString.h"
37 #include "iTime.h"
38 #include "NaifStatus.h"
39 
40 using namespace std;
41 
42 namespace Isis {
63  MdisCamera::MdisCamera(Cube &cube) : FramingCamera(cube) {
65  // Set up detector constants
66  const int MdisWac(-236800);
67  // const int MdisNac(-236820);
68 
69  Pvl &lab = *cube.label();
70  PvlGroup &inst = lab.findGroup("Instrument", Pvl::Traverse);
71 
72  // Clarification on MDIS subframe image mode provides us the ability to
73  // support this mode now. The entire MDIS frame is geometrically valid
74  // but only portions of the full frame actually contain image data. The
75  // portions outside subframes should be NULL and not interfere in
76  // downstream processing, such as mosaics.
77 #if defined(MDIS_SUBFRAMES_UNSUPPORTED)
78  int subFrameMode = inst["SubFrameMode"];
79  if(subFrameMode != 0) {
80  string msg = "Subframe imaging mode is not supported!";
81  throw iException::Message(iException::User, msg, _FILEINFO_);
82  }
83 #endif
84 
85  // According to the MDIS team, this is nothing to be concerned with and
86  // should be treated as other normal observations. So the test to
87  // disallow it has been effectively removed 2007-09-05 (KJB).
88 #if defined(MDIS_JAILBARS_UNSUPPORTED)
89  int jailBars = inst["JailBars"];
90  if(jailBars != 0) {
91  string msg = "Jail bar observations are not currently supported!";
92  throw iException::Message(iException::Programmer, msg, _FILEINFO_);
93  }
94 #endif
95 
96  // Determine filter number. Only conditional code required for
97  // NAC and WAC support!
98  int filterNumber(0); // Default appropriate for MDIS-NAC
99  if(naifIkCode() == MdisWac) {
100  PvlGroup &bandBin = lab.findGroup("BandBin", Pvl::Traverse);
101  filterNumber = bandBin["Number"];
102  }
103 
104  // Set up instrument and filter code strings
105  QString ikCode = toString(naifIkCode());
106  int fnCode(naifIkCode() - filterNumber);
107  QString filterCode = toString(fnCode);
108  QString ikernKey;
109 
110  // Fetch the frame translations from the instrument kernels
111  ikernKey = "INS" + ikCode + "_REFERENCE_FRAME";
112  QString baseFrame = getString(ikernKey);
113 
114  ikernKey = "INS" + filterCode + "_FRAME";
115  QString ikFrame = getString(ikernKey);
116 
117  // Set up the camera info from ik/iak kernels
118 
119  // Turns out (2008-01-17) the WAC has different focal lengths for
120  // each filter. Added to the instrument kernel (IAK) on this date.
121  // Add temperature dependant focal length
122  SetFocalLength(computeFocalLength(filterCode, lab));
123 
124  SetPixelPitch();
125 
126  // Removed by Jeff Anderson. The refactor of the SPICE class
127  // uses frames always so this is no longer needed
128  // LoadFrameMounting(baseFrame, ikFrame, false);
129 
130  // Get the start time from labels as the starting image time plus half
131  // the exposure duration (in <MS>) to get pointing attitude.
132  // !!NOTE: The ephemeris time MUST be set prior to creating the
133  // cache (CreateCache) because the kernels are all unloaded
134  // after the cache is done and this operation will fail!!
135  QString stime = inst["SpacecraftClockCount"];
136  double exposureDuration = ((double) inst["ExposureDuration"]) / 1000.0;// divide by 1000 to convert to seconds
137 
138  iTime etStart = getClockTime(stime);
139 
140  // Setup camera detector map
141  CameraDetectorMap *detMap = new CameraDetectorMap(this);
142 
143  // Setup focal plane map, and detector origin for the instrument that
144  // may have a filter (WAC only!).
145  CameraFocalPlaneMap *focalMap = new CameraFocalPlaneMap(this, fnCode);
146 
147  // Retrieve boresight location from instrument kernel (IK) (addendum?)
148  ikernKey = "INS" + ikCode + "_BORESIGHT_SAMPLE";
149  double sampleBoreSight = getDouble(ikernKey);
150 
151  ikernKey = "INS" + ikCode + "_BORESIGHT_LINE";
152  double lineBoreSight = getDouble(ikernKey);
153 
154  // Apply the boresight
155  focalMap->SetDetectorOrigin(sampleBoreSight, lineBoreSight);
156 
157  // Determine summing. MDIS has two sources of summing or binning.
158  // One is performed in the FPU and the in the MP, post-observation,
159  // on-board after coming out of the FPGAs, where the FPU binning is
160  // performed. The FPU binning was programmed incorrectly and the
161  // actual pixels from the detector are peculiar. Hence, I have
162  // designed this camera model such that the offsets can be managed
163  // external to the code. See the MDIS instrument kernel addendum
164  // in $ISIS3DATA/messenger/kernels/iak/mdisAddendum???.ti for the
165  // offsets for *each* detector. Note that an offset is only applied
166  // when FPU binning is performed.
167  int fpuBinMode = inst["FpuBinningMode"];
168  int pixelBinMode = inst["PixelBinningMode"];
169 
170  int summing = ((pixelBinMode == 0) ? 1 : pixelBinMode);
171  // FPU binning was performed, retrieve the FPU binning offsets and
172  // apply them to the focal plane mapping.
173  if(fpuBinMode == 1) {
174 #if defined(USE_FPU_BINNING_OFFSETS)
175  ikernKey = "INS" + ikCode + "_FPUBIN_START_SAMPLE";
176  double fpuStartingSample = getDouble(ikernKey);
177  detMap->SetStartingDetectorSample(fpuStartingSample);
178 
179  ikernKey = "INS" + ikCode + "_FPUBIN_START_LINE";
180  double fpuStartingLine = getDouble(ikernKey);
181  detMap->SetStartingDetectorLine(fpuStartingLine);
182 #endif
183  summing *= 2;
184  }
185 
186  // Set summing/binning modes as an accumulation of FPU and MP binning.
187  detMap->SetDetectorLineSumming(summing);
188  detMap->SetDetectorSampleSumming(summing);
189 
190  // Setup distortion map. As of 2007/12/06, we now have an actual model.
191  // Note that this model supports distinct distortion for each WAC filter.
192  // See $ISIS3DATA/messenger/kernels/iak/mdisAddendumXXX.ti or possibly
193  // $ISIS3DATA/messenger/kernels/ik/msgr_mdis_vXXX.ti for the *_OD_K
194  // parameters.
195  // NAC has a new implementation of its distortion contributed by
196  // Scott Turner and Lillian Nguyen at JHUAPL.
197  // (2010/10/06) The WAC now uses the same disortion model implementation.
198  // Valid Taylor Series parameters are in versions msgr_mdis_v120.ti IK
199  // and above. Note fnCode works for NAC as well as long as
200  // filterNumber stays at 0 for the NAC only!
201  try {
202  TaylorCameraDistortionMap *distortionMap = new TaylorCameraDistortionMap(this);
203  distortionMap->SetDistortion(fnCode);
204  }
205  catch(IException &ie) {
206  string msg = "New MDIS NAC/WAC distortion models will invalidate previous "
207  "SPICE - you may need to rerun spiceinit to get new kernels";
208  throw IException(ie, IException::User, msg, _FILEINFO_);
209  }
210 
211  // Setup the ground and sky map
212  new CameraGroundMap(this);
213  new CameraSkyMap(this);
214 
215  // Create a cache and grab spice info since it does not change for
216  // a framing camera (fixed spacecraft position and pointing) after,
217  // of course applying the gimble offset which is handled in the SPICE
218  // kernels (thank you!). Note this was done automagically in the
219  // SetEpheremisTime call above. IMPORTANT that it be done prior to
220  // creating the cache since all kernels are unloaded, essentially
221  // clearing the pool and whacking the frames definitions, required to
222  iTime centerTime = etStart + (exposureDuration / 2.0);
223  setTime(centerTime);
224  LoadCache();
226  }
227 
228 
250  pair <iTime, iTime> MdisCamera::ShutterOpenCloseTimes(double time,
251  double exposureDuration) {
252  return FramingCamera::ShutterOpenCloseTimes(time, exposureDuration);
253  }
254 
284  double MdisCamera::computeFocalLength(const QString &filterCode,
285  Pvl &label) {
286 
287  double focalLength(0.0);
288  QString tdflKey("TempDependentFocalLength");
289 
290  // Determine if the desired value is already computed. We are interested
291  // in the temperature dependent value firstly. Backward compatibility is
292  // considered below.
293  QVariant my_tdfl = readStoredValue(tdflKey, SpiceStringType, 0);
294  if (my_tdfl.isValid()) {
295  focalLength = IString(my_tdfl.toString()).ToDouble();
296  }
297  else {
298  // Hasn't been computed yet (in spiceinit now - maybe) or the proper
299  // IK containing polynomial parameters is not in use.
300 
301  // Original Code ensures backward compatibility
302  focalLength = getDouble("INS" + filterCode + "_FOCAL_LENGTH");
303 
304  // Check for disabling of temperature dependent focal length
305  bool tdfl_disabled(false);
306 #ifndef DISABLE_TDFL_DISABLING
307  try {
308  IString tdfl_state = getString("DISABLE_MDIS_TD_FOCAL_LENGTH");
309  tdfl_disabled = ( "TRUE" == tdfl_state.UpCase() );
310  }
311  catch (IException &ie) {
312  tdfl_disabled = false;
313  }
314 #endif
315 
316  // Attempt to retrieve parameters necessary for temperature-dependent focal
317  // length and computed it
318  if ( !tdfl_disabled ) {
319  // Wrap a try clause all around this so that if it fails, will return
320  // default
321  try {
322  PvlGroup &inst = label.findGroup("Instrument", Pvl::Traverse);
323  double fpTemp = inst["FocalPlaneTemperature"];
324  double fl(0.0);
325  QString fptCoeffs = "INS" + filterCode + "_FL_TEMP_COEFFS";
326  // Compute 5th order polynomial
327  for (int i = 0 ; i < 6 ; i++) {
328  fl += getDouble(fptCoeffs, i) * pow(fpTemp, (double) i);
329  }
330 
331  // Store computed focal length
332  focalLength = fl;
333  storeValue(tdflKey, 0, SpiceStringType, QVariant(focalLength));
334  }
335  catch (IException &ie) {
336  // Noop when supporting old IKs
338  "Failed to compute temperature-dependent focal length",
339  _FILEINFO_);
340  }
341  }
342  }
343  return (focalLength);
344  }
345 }
346 
356  return new Isis::MdisCamera(cube);
357 }