Isis 3 Programmer Reference
MocLabels.cpp
1 #include "MocLabels.h"
2 
3 #include <cmath>
4 #include <cfloat>
5 #include <iostream>
6 #include <vector>
7 #include <fstream>
8 
9 #include "Cube.h"
10 #include "IException.h"
11 #include "IString.h"
12 #include "iTime.h"
13 #include "mocxtrack.h"
14 #include "TextFile.h"
15 #include "AlphaCube.h"
16 
17 using namespace std;
18 namespace Isis {
22  MocLabels::MocLabels(const QString &file) {
23  Cube cube(file, "r");
24  Init(cube);
25  }
26 
30  MocLabels::MocLabels(Cube &cube) {
31  Init(cube);
32  }
33 
38  void MocLabels::Init(Cube &cube) {
39  // Initialize gain tables
40  InitGainMaps();
41 
42  try {
43  ReadLabels(cube);
44  ValidateLabels();
45  Compute();
46  }
47  catch(IException &e) {
48  string msg = "Labels do not appear contain a valid MOC instrument";
49  throw IException(IException::Unknown, msg, _FILEINFO_);
50  }
51  }
56  void MocLabels::ReadLabels(Cube &cube) {
57  // Get stuff out of the instrument group
58  Pvl &lab = *cube.label();
59  PvlGroup &inst = lab.findGroup("Instrument", Pvl::Traverse);
60  p_instrumentId = (QString) inst["InstrumentId"];
61  p_startingSample = inst["FirstLineSample"];
62  p_crosstrackSumming = inst["CrosstrackSumming"];
63  p_downtrackSumming = inst["DowntrackSumming"];
64  p_exposureDuration = inst["LineExposureDuration"];
65  p_focalPlaneTemp = inst["FocalPlaneTemperature"];
66  p_clockCount = (QString) inst["SpacecraftClockCount"];
67  p_orbitNumber = 0;
68  if(inst.hasKeyword("OrbitNumber")) {
69  p_orbitNumber = inst["OrbitNumber"];
70  }
71  p_gainModeId = (QString) inst["GainModeId"];
72  p_offsetModeId = inst["OffsetModeId"];
73  p_startTime = (QString) inst["StartTime"];
74 
75  // Get stuff out of the archive group
76  p_dataQuality = "Unknown";
77  PvlGroup &arch = lab.findGroup("Archive", Pvl::Traverse);
78  if(arch.hasKeyword("DataQualityDesc")) {
79  p_dataQuality = (QString) arch["DataQualityDesc"];
80  }
81 
82  // Get Stuff out of the band bind group
83  PvlGroup &bandBin = lab.findGroup("BandBin", Pvl::Traverse);
84  p_filter = (QString) bandBin["FilterName"];
85 
86  // Get the number of samples in the initial cube as it may have been
87  // cropped or projected
88  AlphaCube a(cube);
89  p_ns = a.AlphaSamples();
90  p_nl = a.AlphaLines();
91 
92  // Get the two kernels for time computations
93  PvlGroup &kerns = lab.findGroup("Kernels", Pvl::Traverse);
94  p_lsk = FileName(kerns["LeapSecond"][0]);
95  p_sclk = FileName(kerns["SpacecraftClock"][0]);
96  }
97 
101  void MocLabels::ValidateLabels() {
102  // Validate the camera type
103  p_mocNA = false;
104  p_mocRedWA = false;
105  p_mocBlueWA = false;
106 
107  if(p_instrumentId == "MOC-NA") p_mocNA = true;
108  if(p_instrumentId == "MOC-WA") {
109  if(p_filter == "RED") p_mocRedWA = true;
110  if(p_filter == "BLUE") p_mocBlueWA = true;
111  }
112 
113  if(!p_mocNA && !p_mocRedWA && !p_mocBlueWA) {
114  QString msg = "InstrumentID [" + p_instrumentId + "] and/or FilterName ["
115  + p_filter + "] are inappropriate for the MOC camera";
116  throw IException(IException::Unknown, msg, _FILEINFO_);
117  }
118 
119  // Validate summing modes for narrow angle camera
120  if(p_mocNA) {
121  if((p_crosstrackSumming < 1) || (p_crosstrackSumming > 8)) {
122  string msg = "MOC-NA keyword [CrosstrackSumming] must be between ";
123  msg += "1 and 8, but is [" + IString(p_crosstrackSumming) + "]";
124  throw IException(IException::Unknown, msg, _FILEINFO_);
125  }
126 
127  if((p_downtrackSumming < 1) || (p_downtrackSumming > 8)) {
128  string msg = "MOC-NA keyword [DowntrackSumming] must be between ";
129  msg += "1 and 8, but is [" + IString(p_downtrackSumming) + "]";
130  throw IException(IException::Unknown, msg, _FILEINFO_);
131  }
132  }
133 
134  // Validate summing modes for the wide angle camera
135  if((p_mocRedWA) || (p_mocBlueWA)) {
136  if((p_crosstrackSumming < 1) || (p_crosstrackSumming > 127)) {
137  string msg = "MOC-WA keyword [CrosstrackSumming] must be between ";
138  msg += "1 and 127, but is [" + IString(p_crosstrackSumming) + "]";
139  throw IException(IException::Unknown, msg, _FILEINFO_);
140  }
141 
142  if((p_downtrackSumming < 1) || (p_downtrackSumming > 127)) {
143  string msg = "MOC-WA keyword [DowntrackSumming] must be between ";
144  msg += "1 and 127, but is [" + IString(p_downtrackSumming) + "]";
145  throw IException(IException::Unknown, msg, _FILEINFO_);
146  }
147  }
148  }
152  void MocLabels::Compute() {
153  // Compute line rate in seconds
154  p_trueLineRate = p_exposureDuration * (double) p_downtrackSumming;
155  p_trueLineRate /= 1000.0;
156 
157  // Fix the exposure duration for NA images
158  if(NarrowAngle() && (p_downtrackSumming != 1)) {
159  p_exposureDuration *= p_downtrackSumming;
160  }
161 
162  // Lookup the gain using the gain mode in the gain maps
163  map<QString, double>::iterator p;
164  if(NarrowAngle()) {
165  p = p_gainMapNA.find(p_gainModeId);
166  if(p == p_gainMapNA.end()) {
167  QString msg = "Invalid value for PVL keyword GainModeId [" +
168  p_gainModeId + "]";
169  throw IException(IException::Unknown, msg, _FILEINFO_);
170  }
171  }
172  else {
173  p = p_gainMapWA.find(p_gainModeId);
174  if(p == p_gainMapWA.end()) {
175  QString msg = "Invalid value for PVL keyword GainModeId [" +
176  p_gainModeId + "]";
177  throw IException(IException::Unknown, msg, _FILEINFO_);
178  }
179  }
180  p_gain = p->second;
181 
182  // Compute the offset using the offset mode id
183  p_offset = p_offsetModeId * 5.0;
184 
185  // Ok the gain computation for narrow angle changed from
186  // pre-mapping to mapping phase. Fix it up if necessary
187  // (when the Downtrack summing is not 1)
188  if(NarrowAngle() && (p_downtrackSumming != 1)) {
189  iTime currentTime(p_startTime);
190  iTime mappingPhaseBeginTime("1999-04-03T01:00:40.441");
191  if(currentTime < mappingPhaseBeginTime) {
192  double newGain = p_gain / (double) p_downtrackSumming;
193  double mindiff = DBL_MAX;
194  map<QString, double>::iterator p;
195  QString index = "";
196  p = p_gainMapNA.begin();
197  while(p != p_gainMapNA.end()) {
198  double diff = abs(newGain - p->second);
199  if(diff < mindiff) {
200  index = p->first;
201  mindiff = diff;
202  }
203 
204  p ++;
205  }
206 
207  p = p_gainMapNA.find(index);
208  if(p == p_gainMapNA.end()) {
209  string msg = "Could not find new gain for pre-mapping narrow angle image";
210  throw IException(IException::Unknown, msg, _FILEINFO_);
211  }
212  p_gain = p->second;
213  }
214  }
215 
216  // Initialize the maps from sample coordinate to detector coordinates
217  InitDetectorMaps();
218 
219  // Temporarily load some naif kernels
220  QString lsk = p_lsk.expanded();
221  QString sclk = p_sclk.expanded();
222  furnsh_c(lsk.toLatin1().data());
223  furnsh_c(sclk.toLatin1().data());
224 
225  // Compute the starting ephemeris time
226  scs2e_c(-94, p_clockCount.toLatin1().data(), &p_etStart);
227  p_etEnd = EphemerisTime((double)p_nl);
228 
229  // Unload the naif kernels
230  unload_c(lsk.toLatin1().data());
231  unload_c(sclk.toLatin1().data());
232  }
233 
238  void MocLabels::InitGainMaps() {
239  p_gainMapNA["F2"] = 1.0;
240  p_gainMapNA["D2"] = 1.456;
241  p_gainMapNA["B2"] = 2.076;
242  p_gainMapNA["92"] = 2.935;
243  p_gainMapNA["72"] = 4.150;
244  p_gainMapNA["52"] = 5.866;
245  p_gainMapNA["32"] = 8.292;
246  p_gainMapNA["12"] = 11.73;
247  p_gainMapNA["EA"] = 7.968;
248  p_gainMapNA["CA"] = 11.673;
249  p_gainMapNA["AA"] = 16.542;
250  p_gainMapNA["8A"] = 23.386;
251  p_gainMapNA["6A"] = 33.067;
252  p_gainMapNA["4A"] = 46.740;
253  p_gainMapNA["2A"] = 66.071;
254  p_gainMapNA["0A"] = 93.465;
255 
256  p_gainMapWA["9A"] = 1.0;
257  p_gainMapWA["8A"] = 1.412;
258  p_gainMapWA["7A"] = 2.002;
259  p_gainMapWA["6A"] = 2.832;
260  p_gainMapWA["5A"] = 4.006;
261  p_gainMapWA["4A"] = 5.666;
262  p_gainMapWA["3A"] = 8.014;
263  p_gainMapWA["2A"] = 11.34;
264  p_gainMapWA["1A"] = 16.03;
265  p_gainMapWA["0A"] = 22.67;
266  p_gainMapWA["96"] = 16.030;
267  p_gainMapWA["86"] = 22.634;
268  p_gainMapWA["76"] = 32.092;
269  p_gainMapWA["66"] = 45.397;
270  p_gainMapWA["56"] = 64.216;
271  p_gainMapWA["46"] = 90.826;
272  p_gainMapWA["36"] = 128.464;
273  p_gainMapWA["26"] = 181.780;
274  p_gainMapWA["16"] = 256.961;
275  p_gainMapWA["06"] = 363.400;
276  };
277 
283  int MocLabels::StartDetector(int sample) const {
284  if((sample < 1) || (sample > p_ns)) {
285  string msg = "Out of array bounds in MocLabels::StartDetector";
286  throw IException(IException::Unknown, msg, _FILEINFO_);
287  }
288  return p_startDetector[sample-1];
289  }
295  int MocLabels::EndDetector(int sample) const {
296  if((sample < 1) || (sample > p_ns)) {
297  string msg = "Out of array bounds in MocLabels::EndDetector";
298  throw IException(IException::Unknown, msg, _FILEINFO_);
299  }
300  return p_endDetector[sample-1];
301  }
307  double MocLabels::Sample(int detector) const {
308  if((detector < 0) || (detector >= Detectors())) {
309  string msg = "Out of array bounds in MocLabels::Sample";
310  throw IException(IException::Unknown, msg, _FILEINFO_);
311  }
312  return p_sample[detector];
313  }
317  void MocLabels::InitDetectorMaps() {
318  // Create sample to detector maps
319  if(p_crosstrackSumming == 13) {
320  for(int i = 0; i < p_ns; i++) {
321  p_startDetector[i] = mode13_table[i].starting_pixel +
322  p_startingSample - 1;
323  p_endDetector[i] = mode13_table[i].ending_pixel +
324  p_startingSample - 1;
325  }
326  }
327  else if(p_crosstrackSumming == 27) {
328  for(int i = 0; i < p_ns; i++) {
329  p_startDetector[i] = mode27_table[i].starting_pixel +
330  p_startingSample - 1;
331  p_endDetector[i] = mode27_table[i].ending_pixel +
332  p_startingSample - 1;
333  }
334  }
335  else {
336  int detector = (p_startingSample - 1);
337  for(int i = 0; i < p_ns; i++) {
338  p_startDetector[i] = detector;
339  detector += p_crosstrackSumming - 1;
340  p_endDetector[i] = detector;
341  detector++;
342  }
343  }
344 
345  // Now create a detector to sample map
346  // Start by setting each position to a invalid sample
347  for(int det = 0; det < Detectors(); det++) {
348  p_sample[det] = -1.0;
349  }
350 
351  for(int samp = 1; samp <= p_ns; samp++) {
352  int sd = p_startDetector[samp-1];
353  int ed = p_endDetector[samp-1];
354 
355  double m = ((samp + 0.5) - (samp - 0.5)) / ((ed + 0.5) - (sd - 0.5));
356  for(int det = sd; det <= ed; det++) {
357  p_sample[det] = m * (det - (sd - 0.5)) + (samp - 0.5);
358  }
359  }
360  }
366  double MocLabels::EphemerisTime(double line) const {
367  return p_etStart + (line - 0.5) * p_trueLineRate;
368  }
374  // return gain at a line
375  double MocLabels::Gain(int line) {
376  if(NarrowAngle()) return p_gain;
377 
378  InitWago();
379 
380  double etLine = EphemerisTime((double)line);
381  for(int i = (int)p_wagos.size() - 1; i >= 0; i--) {
382  if(etLine >= p_wagos[i].et) {
383  return p_wagos[i].gain;
384  }
385  }
386 
387  return p_gain;
388  }
394  double MocLabels::Offset(int line) {
395  if(NarrowAngle()) return p_offset;
396  InitWago();
397 
398  double etLine = EphemerisTime((double)line);
399  for(int i = (int)p_wagos.size() - 1; i >= 0; i--) {
400  if(etLine >= p_wagos[i].et) {
401  return p_wagos[i].offset;
402  }
403  }
404  return p_offset;
405  }
415  void MocLabels::InitWago() {
416  // Only do this once
417  static bool firstTime = true;
418  if(!firstTime) return;
419  firstTime = false;
420 
421  // Load naif kernels
422  QString lskKern = p_lsk.expanded();
423  QString sclkKern = p_sclk.expanded();
424  furnsh_c(lskKern.toLatin1().data());
425  furnsh_c(sclkKern.toLatin1().data());
426 
427  //Set up file for reading
428  FileName wagoFile("$mgs/calibration/MGSC_????_wago.tab");
429  wagoFile = wagoFile.highestVersion();
430  QString nameOfFile = wagoFile.expanded();
431  ifstream temp(nameOfFile.toLatin1().data());
432  vector<int> wholeFile;
433 
434  // Read file into a vector of bytes, ignoring EOL chars
435  while(temp.good()) {
436  int nextByte = temp.get();
437  if(nextByte != 10 && nextByte != 13) {
438  wholeFile.push_back(nextByte);
439  }
440  }
441  temp.close();
442 
443  //Set up to binary search for the desired time
444  int low = 1;
445  int high = wholeFile.size() / 35;
446  int middle;
447  IString line, filter, sclk, offsetId;
448  QString gainId;
449  WAGO wago;
450 
451  //Binary search. This determines the middle of the current range and
452  //moves through the file until it reaches that line, at which point it
453  //analyzes to see if the time is within the set limits.
454  while(low <= high) {
455  middle = (low + high) / 2;
456  int SclkStart = middle * 35 + 8;
457  int SclkEnd = SclkStart + 15;
458  string currentSclk;
459 
460  //Build sclk string and convert to an actual time
461  for(int i = SclkStart; i < SclkEnd; i++) {
462  currentSclk += (char)wholeFile[i];
463  }
464  sclk = currentSclk;
465  sclk.Remove("\"");
466  sclk.Trim(" ");
467  double et;
468  scs2e_c(-94, currentSclk.c_str(), &et);
469 
470  //Compare time against given parameters, if it fits, process
471  if(et < p_etEnd && et > p_etStart) {
472  int linenum = middle;
473  int top = middle;
474  int bottom = middle;
475 
476  //First, find the highest line that will meet requirements
477  while(et >= p_etStart) {
478  linenum--;
479  int lineStart = (linenum * 35);
480  int lineEnd = lineStart + 35;
481 
482  string currentLine = "";
483  for(int i = lineStart; i < lineEnd; i++) {
484  currentLine += (char)wholeFile[i];
485  }
486  line = currentLine;
487 
488  currentSclk = "";
489  for(int i = 8; i < 23; ++i) {
490  currentSclk += currentLine[i];
491  }
492  sclk = currentSclk;
493  sclk.Trim(" ");
494  scs2e_c(-94, currentSclk.c_str(), &et);
495 
496  bottom = linenum;
497  }
498  //Next, find the lowest line to meet requirements
499  while(et <= p_etEnd) {
500  linenum++;
501  int lineStart = (linenum * 35);
502  int lineEnd = lineStart + 35;
503 
504  string currentLine = "";
505  for(int i = lineStart; i < lineEnd; i++) {
506  currentLine += (char)wholeFile[i];
507  }
508  line = currentLine;
509 
510  currentSclk = "";
511  for(int i = 8; i < 23; ++i) {
512  currentSclk += currentLine[i];
513  }
514  sclk = currentSclk;
515  sclk.Trim(" ");
516  scs2e_c(-94, currentSclk.c_str(), &et);
517  top = linenum;
518  }
519  //Now, go from the upper limit to the lower limit, and grab all lines
520  //that meet requirements
521  for(int i = bottom; i <= top; ++i) {
522  int lineStart = (i * 35);
523  int lineEnd = lineStart + 35;
524  string currentLine = "";
525  for(int j = lineStart; j < lineEnd; j++) {
526  currentLine += (char)wholeFile[j];
527  }
528  line = currentLine;
529 
530  // Get the filter color (red or blue)
531  filter = line.Token(",");
532  filter.Remove("\"");
533  filter.Trim(" ");
534 
535  // If it's not the filter we want then skip to loop end
536  if((filter == "RED") && (WideAngleBlue())) continue;
537  if((filter == "BLUE") && (WideAngleRed())) continue;
538 
539  // Get the sclk and convert to et
540  sclk = line.Token(",");
541  sclk.Remove("\"");
542  sclk.Trim(" ");
543 
544  scs2e_c(-94, sclk.c_str(), &et);
545 
546  // Get the gain mode id
547  gainId = line.Token(",").ToQt().remove("\"").trimmed();
548 
549  // Get the offset mode id
550  offsetId = line;
551  offsetId.Remove("\"");
552  offsetId.ConvertWhiteSpace();
553  offsetId.Trim(" ");
554 
555  // Compute the gain
556  map<QString, double>::iterator p;
557  p = p_gainMapWA.find(gainId);
558  if(p == p_gainMapWA.end()) {
559  // Unload the naif kernels
560  unload_c(lskKern.toLatin1().data());
561  unload_c(sclkKern.toLatin1().data());
562 
563  QString msg = "Invalid GainModeId [" + gainId + "] in wago table";
564  throw IException(IException::Unknown, msg, _FILEINFO_);
565  }
566  double gain = p->second;
567 
568  // Compute the offset
569  double offset = offsetId.ToDouble() * 5.0;
570 
571  // Push everything onto a stack
572  wago.et = et;
573  wago.gain = gain;
574  wago.offset = offset;
575  p_wagos.push_back(wago);
576 
577  }
578 
579  low = high++;
580  }
581  //If we're too high, search beginning of array
582  else if(et < p_etStart) {
583  low = middle + 1;
584  }
585  //If we're too low, search end of array
586  else {
587  high = middle - 1;
588  }
589  }
590 
591  // Ok sort and unique the wago list by time
592  sort(p_wagos.begin(), p_wagos.end());
593  unique(p_wagos.begin(), p_wagos.end());
594 
595  // Unload the naif kernels
596  unload_c(lskKern.toLatin1().data());
597  unload_c(sclkKern.toLatin1().data());
598  }
599 }
600 
bool hasKeyword(const QString &name) const
Check to see if a keyword exists.
PvlGroupIterator findGroup(const QString &name, PvlGroupIterator beg, PvlGroupIterator end)
Find a group with the specified name, within these indexes.
Definition: PvlObject.h:141
File name manipulation and expansion.
Definition: FileName.h:116
Parse and return pieces of a time string.
Definition: iTime.h:78
double ToDouble() const
Returns the floating point value the IString represents.
Definition: IString.cpp:814
int AlphaLines() const
Returns the number of lines in the alpha cube.
Definition: AlphaCube.h:83
Namespace for the standard library.
int AlphaSamples() const
Returns the number of samples in the alpha cube.
Definition: AlphaCube.h:93
This class is used to rewrite the "alpha" keywords out of the AlphaCube group or Instrument group...
Definition: AlphaCube.h:62
IString Token(const IString &separator)
Returns the first token in the IString.
Definition: IString.cpp:912
Contains multiple PvlContainers.
Definition: PvlGroup.h:57
#define _FILEINFO_
Macro for the filename and line number.
Definition: IException.h:40
QString ToQt() const
Retuns the object string as a QString.
Definition: IString.cpp:884
IString Remove(const std::string &del)
Remove all instances of any character in the string from the IString.
Definition: IString.cpp:1281
Container for cube-like labels.
Definition: Pvl.h:135
Pvl * label() const
Returns a pointer to the IsisLabel object associated with the cube.
Definition: Cube.cpp:1346
Isis exception class.
Definition: IException.h:107
Adds specific functionality to C++ strings.
Definition: IString.h:181
Namespace for ISIS/Bullet specific routines.
Definition: Apollo.h:31
IString ConvertWhiteSpace()
Returns the string with all "new lines", "carriage returns", "tabs", "form feeds", "vertical tabs" and "back spaces" converted to single spaces.
Definition: IString.cpp:1253
IString Trim(const std::string &chars)
Removes characters from the beginning and end of the IString.
Definition: IString.cpp:540
IO Handler for Isis Cubes.
Definition: Cube.h:170