Isis 3 Programmer Reference
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.
double exposureTime() const
Return the exposure time.
int Records() const
Returns the number of records.
Definition: Table.cpp:224
void SetFocalLength()
Reads the focal length from the instrument kernel.
Definition: Camera.cpp:1430
double startTime() const
Return start time for the entire cube.
void MinimizeCache(DownsizeStatus status)
Set the downsize status to minimize cache.
double lineEndTime(const double midExpTime) const
Return the end time for a given line exposure time.
double scanLineTime() const
Return the line scan rate.
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.
bool hasArticulationKernel(Pvl &label) const
determine if the CK articulation kernels are present/given
Parse and return pieces of a time string.
Definition: iTime.h:78
Table getPointingTable(const QString &channelId, const int zeroFrame)
Compute the pointing table for each line.
QStringList getKernelList(const QString &ktype="") const
Provide a list of all the kernels found.
Definition: Kernels.cpp:689
SpiceInt getInteger(const QString &key, int index=0)
This returns a value from the NAIF text pool.
Definition: Spice.cpp:949
QString m_instrumentNameLong
Full instrument name.
Definition: Camera.h:507
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.
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:1437
Namespace for the standard library.
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
Search child objects.
Definition: PvlObject.h:170
double lineStartTime(const double midExpTime) const
Return the start time for a given line exposure time.
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:162
double m_opticalAngle
Optical angle in degrees.
std::vector< ScanMirrorInfo > m_mirrorData
vector of mirror info for each line
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 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:508
Contains multiple PvlContainers.
Definition: PvlGroup.h:57
virtual int CkReferenceId() const
CK Reference ID - J2000.
SpiceInt naifIkCode() const
This returns the NAIF IK code to use when reading from instrument kernels.
Definition: Spice.cpp:893
virtual int CkFrameId() const
CK Frame ID - Instrument Code from spacit run on CK.
int pixelSumming() const
Return the pixel summing rate.
#define _FILEINFO_
Macro for the filename and line number.
Definition: IException.h:40
QString scrub(const QString &text) const
Scrubs a string coming out of the housekeeping table.
A type of error that could only have occurred due to a mistake on the user&#39;s part (e...
Definition: IException.h:142
A single keyword-value pair.
Definition: PvlKeyword.h:98
double m_scanRate
Line scan rate.
iTime getClockTime(QString clockValue, int sclkCode=-1, bool clockTicks=false)
This converts the spacecraft clock ticks value (clockValue) to an iTime.
Definition: Spice.cpp:977
Do not downsize the cache.
int hkLineCount() const
Returns number of housekeeping records found in the cube Table.
Distort/undistort focal plane coordinates.
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:2848
SMatrix getStateRotation(const QString &frame1, const QString &frame2, const double &et) const
Compute the state rotation at a given time for given frames.
Convert between undistorted focal plane and ra/dec coordinates.
void LoadCache()
This loads the spice cache big enough for this image.
Definition: Camera.cpp:2432
QString m_spacecraftNameLong
Full spacecraft name.
Definition: Camera.h:509
double m_mirrorCos
Raw mirror cosine value.
Pvl * label() const
Returns a pointer to the IsisLabel object associated with the cube.
Definition: Cube.cpp:1346
Class for storing Table blobs information.
Definition: Table.h:77
LineScanCameraDetectorMap * DetectorMap()
Returns a pointer to the LineScanCameraDetectorMap object.
void AddData(const double x, const double y)
Add a datapoint to the set.
int Lines() const
Returns the number of lines in the image.
Definition: Camera.cpp:2798
QString fileName() const
Returns the filename used to initialise the Pvl object.
Definition: PvlContainer.h:246
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:107
Namespace for ISIS/Bullet specific routines.
Definition: Apollo.h:31
int Fields() const
Returns the number of fields that are currently in the record.
Definition: TableRecord.cpp:94
SpiceRotation * instrumentRotation() const
Accessor method for the instrument rotation.
Definition: Spice.cpp:1489
QString m_spacecraftNameShort
Shortened spacecraft name.
Definition: Camera.h:510
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
std::vector< LineRateChange > m_lineRates
vector of timing info for each line
SpiceInt naifSpkCode() const
This returns the NAIF SPK code to use when reading from SPK kernels.
Definition: Spice.cpp:875
double endTime() const
Return end time for the entire cube.
char m_slitMode
Slit mode of the instrument.
virtual int SpkReferenceId() const
SPK Reference ID - J2000.
double Et() const
Returns the ephemeris time (TDB) representation of the time as a double.
Definition: iTime.h:139
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:963
void addValue(QString value, QString unit="")
Adds a value with units.
Definition: PvlKeyword.cpp:268
IO Handler for Isis Cubes.
Definition: Cube.h:170