Isis 3.0 Programmer Reference
Home
DawnVirCamera.cpp
1  #include "DawnVirCamera.h"
2 
3 #include <cctype>
4 #include <iostream>
5 #include <iomanip>
6 #include <sstream>
7 #include <algorithm>
8 
9 #include <QRegExp>
10 #include <QString>
11 
12 #include <tnt/tnt_array2d_utils.h>
13 
14 #include "Camera.h"
15 #include "CameraFocalPlaneMap.h"
16 #include "IException.h"
17 #include "IString.h"
18 #include "iTime.h"
19 #include "Kernels.h"
22 #include "LineScanCameraSkyMap.h"
23 #include "NaifStatus.h"
24 #include "NumericalApproximation.h"
25 
26 // #define DUMP_INFO 1
27 
28 using namespace std;
29 namespace Isis {
30  // constructors
37  DawnVirCamera::DawnVirCamera(Cube &cube) : LineScanCamera(cube) {
38 
39  m_instrumentNameLong = "Visual and Infrared Spectrometer";
40  m_instrumentNameShort = "VIR";
41  m_spacecraftNameLong = "Dawn";
42  m_spacecraftNameShort = "Dawn";
43 
44  // cout << "Testing DawnVirCamera...\n";
45 
46  Pvl &lab = *cube.label();
47  PvlGroup &archive = lab.findGroup("Archive", Isis::Pvl::Traverse);
48  int procLevel = archive["ProcessingLevelId"];
49  m_is1BCalibrated = (procLevel > 2) ? true : false;
50 
51  // Get the start time from labels
52  PvlGroup &inst = lab.findGroup("Instrument", Isis::Pvl::Traverse);
53  QString channelId = inst["ChannelId"];
54 
55  QString instMode = inst["InstrumentModeId"];
56  m_slitMode = instMode[14].toLatin1(); // "F" for full slit, Q for quarter slit
57 
58  // Check for presence of articulation kernel
59  bool hasArtCK = hasArticulationKernel(lab);
60 
61  // Set proper end frame
62  int virFrame(0);
63  if (channelId == "VIS") {
64  // Frame DAWN_VIR_VIS : DAWN_VIR_VIS_ZERO
65  virFrame = (hasArtCK) ? -203211 : -203221;
66  }
67  else { // (channelId == "IR)
68  // Frame DAWN_VIR_IR : DAWN_VIR_IR_ZERO
69  virFrame = (hasArtCK) ? -203213 : -203223;
70  }
71 
72  instrumentRotation()->SetFrame(virFrame);
73 
74  // We do not want to downsize the cache
76 
77  // Set up the camera info from ik/iak kernels
79  SetPixelPitch();
80 
81  // Get other info from labels
82  PvlKeyword &frameParam = inst["FrameParameter"];
83  m_exposureTime = toDouble(frameParam[0]);
84  m_summing = toDouble(frameParam[1]);
85  m_scanRate = toDouble(frameParam[2]);
86 
87  // Setup detector map
88  // Get the line scan rates/times
92 
93  // Setup focal plane map
94  new CameraFocalPlaneMap(this, naifIkCode());
95 
96  // Retrieve boresight location from instrument kernel (IK) (addendum?)
97  QString ikernKey = "INS" + toString(naifIkCode()) + "_BORESIGHT_SAMPLE";
98  double sampleBoreSight = getDouble(ikernKey);
99 
100  ikernKey = "INS" + toString(naifIkCode()) + "_BORESIGHT_LINE";
101  double lineBoreSight = getDouble(ikernKey);
102 
103  FocalPlaneMap()->SetDetectorOrigin(sampleBoreSight, lineBoreSight);
104 
105  // Setup distortion map
106  new CameraDistortionMap(this);
107 
108  // Setup the ground and sky map
109  new LineScanCameraGroundMap(this);
110  new LineScanCameraSkyMap(this);
111 
112  // Set initial start time always (label start time is inaccurate)
113  setTime(iTime(startTime())); // Isis3nightly
114 // SetEphemerisTime(startTime()); // Isis3.2.1
115 
116  // Now check to determine if we have a cache already. If we have a cache
117  // table, we are beyond spiceinit and have already computed the proper
118  // point table from the housekeeping data or articulation kernel.
119  if (!instrumentRotation()->IsCached() && !hasArtCK) {
120 
121  // Create new table here prior to creating normal caches
122  Table quats = getPointingTable(channelId, virFrame);
123 
124  // Create all system tables - all kernels closed after this
125  LoadCache();
126  instrumentRotation()->LoadCache(quats);
127  }
128  else {
129  LoadCache();
130  }
131 
132 #if defined(DUMP_INFO)
133  Table cache = instrumentRotation()->Cache("Loaded");
134  cout << "Total Records: " << cache.Records() << "\n";
135 
136  for (int i = 0 ; i < cache.Records() ; i++) {
137  TableRecord rec = cache[i];
138  string separator("");
139  for (int f = 0 ; f < rec.Fields() ; f++) {
140  cout << separator << (double) rec[f];
141  separator = ", ";
142  }
143  cout << "\n";
144  }
145 #endif
146  }
147 
152  }
153 
160  return (-203000);
161  }
162 
163 
170  return (1);
171  }
172 
173 
180  return (1);
181  }
182 
183 
197  QString DawnVirCamera::scrub(const QString &text) const {
198  QString ostr;
199  for (int i = 0 ; i < text.size() ; i++) {
200  if ((text[i] > ' ') && (text[i] <= 'z')) ostr += text[i];
201  }
202  return (ostr);
203  }
204 
205 
212  return (m_summing);
213  }
214 
215 
222  return (m_exposureTime);
223  }
224 
225 
232  return (m_scanRate);
233  }
234 
235 
241  double DawnVirCamera::lineStartTime(const double midExpTime) const {
242  return (midExpTime-(exposureTime()/2.0));
243  }
244 
245 
251  double DawnVirCamera::lineEndTime(const double midExpTime) const {
252  return (midExpTime+(exposureTime()/2.0));
253  }
254 
255 
261  double DawnVirCamera::startTime() const {
262  return (lineStartTime(m_mirrorData[0].m_scanLineEt));
263  }
264 
265 
271  double DawnVirCamera::endTime() const {
272  return (lineEndTime(m_mirrorData[hkLineCount()-1].m_scanLineEt));
273  }
274 
275 
282  return (m_mirrorData.size());
283  }
284 
285 
300  void DawnVirCamera::readHouseKeeping(const QString &filename,
301  double lineRate) {
302  // Open the ISIS table object
303  Table hktable("VIRHouseKeeping", filename);
304 
305  m_lineRates.clear();
306  int lineno(1);
307  NumericalApproximation angFit;
308  for (int i = 0; i < hktable.Records(); i++) {
309  TableRecord &trec = hktable[i];
310  QString scet = scrub(trec["ScetTimeClock"]);
311  QString shutterMode = scrub(trec["ShutterStatus"]);
312 
313  // Compute the optical mirror angle
314  double mirrorSin = trec["MirrorSin"];
315  double mirrorCos = trec["MirrorCos"];
316  double scanElecDeg = atan(mirrorSin/mirrorCos) * dpr_c();
317  double optAng = ((scanElecDeg - 3.7996979) * 0.25/0.257812);
318  optAng /= 1000.0;
319 
320 
321  ScanMirrorInfo smInfo;
322  double lineMidTime;
323  // scs2e_c(naifSpkCode(), scet.c_str(), &lineMidTime);
324  lineMidTime = getClockTime(scet, naifSpkCode()).Et();
325  bool isDark = shutterMode.toLower() == "closed";
326 
327  // Add fit data for all open angles
328  if ( ! isDark ) { angFit.AddData(lineno, optAng); }
329 
330 #if defined(DUMP_INFO)
331  cout << "Line(" << ((isDark) ? "C): " : "O): ") << i
332  << ", OptAng(D): " << setprecision(12) << optAng * dpr_c()
333  << ", MidExpTime(ET): " << lineMidTime
334  << "\n";
335 #endif
336 
337  // Store line,
338  smInfo.m_lineNum = lineno;
339  smInfo.m_scanLineEt = lineMidTime;
340  smInfo.m_mirrorSin = mirrorSin;
341  smInfo.m_mirrorCos = mirrorCos;
342  smInfo.m_opticalAngle = optAng;
343  smInfo.m_isDarkCurrent = isDark;
344 
345  if ((!m_is1BCalibrated) || (!(m_is1BCalibrated && isDark))) {
346  m_lineRates.push_back(LineRateChange(lineno,
347  lineStartTime(lineMidTime),
348  exposureTime()));
349  m_mirrorData.push_back(smInfo);
350  lineno++;
351  }
352  }
353 
354  // Adjust the last time
355  LineRateChange lastR = m_lineRates.back();
356 
357  // Normally the line rate changes would store the line scan rate instead of exposure time.
358  // Storing the exposure time instead allows for better time calculations within a line.
359  // In order for the VariableLineScanCameraDetectorMap to work correctly with this change,
360  // every line in the cube must have a LineRateChange object. This is because determining
361  // the start time for one line based on another line requires the line scan rate. Having
362  // a LineRateChange for every line means never needing to calculate the start time for a line
363  // because the start time is stored in that line's LineRateChange. So, the detector map only
364  // calculates times within a given line.
365  // See VariableLineScanCameraDetectorMap::exposureDuration() for a description of the
366  // difference between exposure time and line scan rate.
367 
368  m_lineRates.back() = LineRateChange(lastR.GetStartLine(),
369  lastR.GetStartEt(),
370  exposureTime());
371 
372  // Run through replacing all closed optical angles with fitted data.
373  // These are mostly first/last lines so must set proper extrapolation
374  // option.
375  for (unsigned int a = 0 ; a < m_mirrorData.size() ; a++) {
376  if (m_mirrorData[a].m_isDarkCurrent) {
377  m_mirrorData[a].m_opticalAngle = angFit.Evaluate(a+1,
379  }
380  }
381 
382  // Gut check on housekeeping contents and cube lines
383  if ((int) m_lineRates.size() != Lines()) {
384  ostringstream mess;
385  mess << "Number housekeeping lines determined (" << m_lineRates.size()
386  << ") is not equal to image lines(" << Lines() << ")";
387  throw IException(IException::Programmer, mess.str(), _FILEINFO_);
388  }
389  }
390 
391 
402  Table DawnVirCamera::getPointingTable(const QString &virChannel,
403  const int zeroFrame) {
404 
405  // Create Spice Pointing table
406  TableField q0("J2000Q0", TableField::Double);
407  TableField q1("J2000Q1", TableField::Double);
408  TableField q2("J2000Q2", TableField::Double);
409  TableField q3("J2000Q3", TableField::Double);
410  TableField av1("AV1", TableField::Double);
411  TableField av2("AV2", TableField::Double);
412  TableField av3("AV3", TableField::Double);
414 
415  TableRecord record;
416  record += q0;
417  record += q1;
418  record += q2;
419  record += q3;
420  record += av1;
421  record += av2;
422  record += av3;
423  record += t;
424 
425  // Get pointing table
426  Table quats("SpiceRotation", record);
427  int nfields = record.Fields();
428 
429  QString virId = "DAWN_VIR_" + virChannel;
430  QString virZero = virId + "_ZERO";
431 
432  // Allocate output arrays
433  int nvals = nfields - 1;
434  int nlines = m_lineRates.size();
435 
436  SpiceDouble eulang[6] = { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 };
437  SpiceDouble xform[6][6], xform2[6][6];
438  SpiceDouble m[3][3];
439  SpiceDouble q_av[7], *av(&q_av[4]);
440 
441  for (int i = 0 ; i < nlines ; i++) {
442  int index = min(i, nlines-1);
443  double etTime = m_mirrorData[index].m_scanLineEt; // mid exposure ET
444  double optAng = m_mirrorData[index].m_opticalAngle;
445  try {
446  // J2000 -> DAWN_VIR_{channel}_ZERO
447  SMatrix state = getStateRotation("J2000", virZero, etTime);
448 
449  // Set rotation of optical scan mirror (in radians)
450  eulang[1] = -optAng;
451  eul2xf_c(eulang, 1, 2, 3, xform);
452  mxmg_c(xform, &state[0][0], 6, 6, 6, xform2);
453 
454  // Transform to output format
455  xf2rav_c(xform2, m, av); // Transfers AV to output q_av via pointer
456  m2q_c(m, q_av); // Transfers quaternion
457 
458  // Now populate the table record with the line pointing
459  for (int k = 0 ; k < nvals ; k++) {
460  record[k] = q_av[k];
461  }
462 
463  // Add time to record; record to table
464  record[nvals] = etTime;
465  quats += record;
466  }
467  catch (IException &ie) {
468  ostringstream mess;
469  mess << "Failed to get point state for line " << i+1;
470  throw IException(ie, IException::User, mess.str(), _FILEINFO_);
471  }
472  }
473 
474  // Add some necessary keywords
475  quats.Label() += PvlKeyword("CkTableStartTime", toString(startTime()));
476  quats.Label() += PvlKeyword("CkTableEndTime", toString(endTime()));
477  quats.Label() += PvlKeyword("CkTableOriginalSize", toString(quats.Records()));
478 
479  // Create the time dependant frames keyword
480  int virZeroId = getInteger("FRAME_" + virZero);
481  PvlKeyword tdf("TimeDependentFrames", toString(virZeroId)); // DAWN_VIR_{ID}_ZERO
482  tdf.addValue("-203200"); // DAWN_VIR
483  tdf.addValue("-203000"); // DAWN_SPACECRAFT
484  tdf.addValue("1"); // J2000
485  quats.Label() += tdf;
486 
487  // Create constant rotation frames
488  PvlKeyword cf("ConstantFrames", toString(virZeroId));
489  cf.addValue(toString(virZeroId));
490  quats.Label() += cf;
491 
492  SpiceDouble identity[3][3];
493  ident_c(identity);
494 
495  // Store DAWN_VIR_{ID}_ZERO -> DAWN_VIR_{ID}_ZERO identity rotation
496  PvlKeyword crot("ConstantRotation");
497  for (int i = 0 ; i < 3 ; i++) {
498  for (int j = 0 ; j < 3 ; j++) {
499  crot.addValue(toString(identity[i][j]));
500  }
501  }
502 
503  quats.Label() += crot;
504 
505  return (quats);
506  }
507 
508 
526  const QString &frame2,
527  const double &etTime)
528  const {
529  SMatrix state(6,6);
531  try {
532  // Get pointing w/AVs
533  sxform_c(frame1.toLatin1().data(), frame2.toLatin1().data(), etTime,
534  (SpiceDouble (*)[6]) state[0]);
536  }
537  catch (IException &) {
538  try {
539  SMatrix rot(3,3);
540  pxform_c(frame1.toLatin1().data(), frame2.toLatin1().data(), etTime,
541  (SpiceDouble (*)[3]) rot[0]);
543  SpiceDouble av[3] = {0.0, 0.0, 0.0 };
544  rav2xf_c((SpiceDouble (*)[3]) rot[0], av,
545  (SpiceDouble (*)[6]) state[0]);
546  }
547  catch (IException &ie2) {
548  ostringstream mess;
549  mess << "Could not get state rotation for Frame1 (" << frame1
550  << ") to Frame2 (" << frame2 << ") at time " << etTime;
551  throw IException(ie2, IException::User, mess.str(), _FILEINFO_);
552  }
553  }
554  return (state);
555  }
556 
557 
573  Kernels kerns(label);
574  QStringList cks = kerns.getKernelList("CK");
575  QRegExp virCk("*dawn_vir_?????????_?.bc");
576  virCk.setPatternSyntax(QRegExp::Wildcard);
577  for (int i = 0 ; i < cks.size() ; i++) {
578  if ( virCk.exactMatch(cks[i]) ) return (true);
579  }
580  return (false);
581  }
582 
583 }
584 
588 extern "C" Isis::Camera *DawnVirCameraPlugin(Isis::Cube &cube) {
589  return new Isis::DawnVirCamera(cube);
590 }
Table Cache(const QString &tableName)
Return a table with J2000 to reference rotations.
void SetFocalLength()
Reads the focal length from the instrument kernel.
Definition: Camera.cpp:1485
int Records() const
Returns the number of records.
Definition: Table.cpp:224
void MinimizeCache(DownsizeStatus status)
Set the downsize status to minimize cache.
PvlGroupIterator findGroup(const QString &name, PvlGroupIterator beg, PvlGroupIterator end)
Find a group with the specified name, within these indexes.
Definition: PvlObject.h:141
double m_mirrorSin
Raw mirror sine value.
double endTime() const
Return end time for the entire cube.
Parse and return pieces of a time string.
Definition: iTime.h:74
Table getPointingTable(const QString &channelId, const int zeroFrame)
Compute the pointing table for each line.
SpiceInt getInteger(const QString &key, int index=0)
This returns a value from the NAIF text pool.
Definition: Spice.cpp:944
SpiceRotation * instrumentRotation() const
Accessor method for the instrument rotation.
Definition: Spice.cpp:1476
double lineStartTime(const double midExpTime) const
Return the start time for a given line exposure time.
QString m_instrumentNameLong
Full instrument name.
Definition: Camera.h:494
void SetDetectorSampleSumming(const double summing)
Set sample summing mode.
void LoadCache(double startTime, double endTime, int size)
Cache J2000 rotation quaternion over a time range.
Pvl * label() const
Returns a pointer to the IsisLabel object associated with the cube.
Definition: Cube.cpp:1298
double m_scanLineEt
Center of line time in ET.
bool m_isDarkCurrent
If the line is dark current data.
void SetPixelPitch()
Reads the Pixel Pitch from the instrument kernel.
Definition: Camera.cpp:1492
TNT::Array2D< SpiceDouble > SMatrix
2-D buffer
Definition: DawnVirCamera.h:70
Generic class for Line Scan Cameras.
Determine SPICE kernels defined in an ISIS file.
Definition: Kernels.h:111
Camera model for both Danw VIR VIS and IR instruments.
Definition: DawnVirCamera.h:68
QString fileName() const
Returns the filename used to initialise the Pvl object.
Definition: PvlContainer.h:247
Search child objects.
Definition: PvlObject.h:170
double scanLineTime() const
Return the line scan rate.
virtual int CkFrameId() const
CK Frame ID - Instrument Code from spacit run on CK.
NumericalApproximation provides various numerical analysis methods of interpolation, extrapolation and approximation of a tabulated set of x, y data.
QString toString(bool boolToConvert)
Global function to convert a boolean to a string.
Definition: IString.cpp:226
Evaluate() returns the y-value of the nearest endpoint if a is outside of the domain.
void SetDetectorOrigin(const double sample, const double line)
Set the detector origin.
~DawnVirCamera()
Destructor.
double toDouble(const QString &string)
Global function to convert from a string to a double.
Definition: IString.cpp:164
This error is for when a programmer made an API call that was illegal.
Definition: IException.h:154
double m_opticalAngle
Optical angle in degrees.
std::vector< ScanMirrorInfo > m_mirrorData
vector of mirror info for each line
double Et() const
Returns the ephemeris time (TDB) representation of the time as a double.
Definition: iTime.h:135
SpiceInt naifSpkCode() const
This returns the NAIF SPK code to use when reading from SPK kernels.
Definition: Spice.cpp:870
Convert between undistorted focal plane and ground coordinates.
Container class for storing timing information for a section of an image.
int m_lineNum
The line the info is for.
void SetFrame(int frameCode)
Change the frame to the given frame code.
bool m_is1BCalibrated
is determined by Archive/ProcessingLevelId
double lineEndTime(const double midExpTime) const
Return the end time for a given line exposure time.
double Evaluate(const double a, const ExtrapType &etype=ThrowError)
Calculates interpolated or extrapolated value of tabulated data set for given domain value...
Convert between distorted focal plane and detector coordinates.
int m_summing
Summing/binnning mode.
QString m_instrumentNameShort
Shortened instrument name.
Definition: Camera.h:495
int Fields() const
Returns the number of fields that are currently in the record.
Definition: TableRecord.cpp:94
virtual int SpkReferenceId() const
SPK Reference ID - J2000.
Contains multiple PvlContainers.
Definition: PvlGroup.h:57
#define _FILEINFO_
Macro for the filename and line number.
Definition: IException.h:38
A type of error that could only have occurred due to a mistake on the user&#39;s part (e...
Definition: IException.h:134
A single keyword-value pair.
Definition: PvlKeyword.h:98
double m_scanRate
Line scan rate.
Do not downsize the cache.
Distort/undistort focal plane coordinates.
QStringList getKernelList(const QString &ktype="") const
Provide a list of all the kernels found.
Definition: Kernels.cpp:689
void setTime(const iTime &time)
By setting the time you essential set the position of the spacecraft and body as indicated in the cla...
Definition: Sensor.cpp:112
Convert between parent image coordinates and detector coordinates.
Container for cube-like labels.
Definition: Pvl.h:135
The values in the field are 8 byte doubles.
Definition: TableField.h:70
CameraFocalPlaneMap * FocalPlaneMap()
Returns a pointer to the CameraFocalPlaneMap object.
Definition: Camera.cpp:2896
Convert between undistorted focal plane and ra/dec coordinates.
void LoadCache()
This loads the spice cache big enough for this image.
Definition: Camera.cpp:2489
SMatrix getStateRotation(const QString &frame1, const QString &frame2, const double &et) const
Compute the state rotation at a given time for given frames.
QString m_spacecraftNameLong
Full spacecraft name.
Definition: Camera.h:496
double startTime() const
Return start time for the entire cube.
double m_mirrorCos
Raw mirror cosine value.
Class for storing Table blobs information.
Definition: Table.h:74
LineScanCameraDetectorMap * DetectorMap()
Returns a pointer to the LineScanCameraDetectorMap object.
QString scrub(const QString &text) const
Scrubs a string coming out of the housekeeping table.
void AddData(const double x, const double y)
Add a datapoint to the set.
static void CheckErrors(bool resetNaif=true)
This method looks for any naif errors that might have occurred.
Definition: NaifStatus.cpp:43
Isis exception class.
Definition: IException.h:99
SpiceInt naifIkCode() const
This returns the NAIF IK code to use when reading from instrument kernels.
Definition: Spice.cpp:888
iTime getClockTime(QString clockValue, int sclkCode=-1)
This converts the spacecraft clock ticks value (clockValue) to an iTime.
Definition: Spice.cpp:969
QString m_spacecraftNameShort
Shortened spacecraft name.
Definition: Camera.h:497
Class for storing an Isis::Table&#39;s field information.
Definition: TableField.h:63
double m_exposureTime
Line exposure time.
PvlObject & Label()
Accessor method that returns a PvlObject containing the Blob label.
Definition: Blob.cpp:167
double exposureTime() const
Return the exposure time.
std::vector< LineRateChange > m_lineRates
vector of timing info for each line
virtual int CkReferenceId() const
CK Reference ID - J2000.
char m_slitMode
Slit mode of the instrument.
bool hasArticulationKernel(Pvl &label) const
determine if the CK articulation kernels are present/given
int pixelSumming() const
Return the pixel summing rate.
int Lines() const
Returns the number of lines in the image.
Definition: Camera.cpp:2846
int hkLineCount() const
Returns number of housekeeping records found in the cube Table.
void readHouseKeeping(const QString &filename, double lineRate)
Read the VIR houskeeping table from cube.
SpiceDouble getDouble(const QString &key, int index=0)
This returns a value from the NAIF text pool.
Definition: Spice.cpp:958
void addValue(QString value, QString unit="")
Adds a value with units.
Definition: PvlKeyword.cpp:268
IO Handler for Isis Cubes.
Definition: Cube.h:158