Isis 3 Programmer Reference
KernelDb.cpp
1
7/* SPDX-License-Identifier: CC0-1.0 */
8
9#include "KernelDb.h"
10
11#include <iomanip>
12#include <queue>
13
14#include "CameraFactory.h"
15#include "FileName.h"
16#include "IException.h"
17#include "IString.h"
18#include "iTime.h"
19#include "Kernel.h"
20#include "Preference.h"
21#include "Preference.h"
22#include "PvlGroup.h"
23#include "PvlKeyword.h"
24#include "PvlObject.h"
25
26using namespace std;
27namespace Isis {
48 KernelDb::KernelDb(const unsigned int allowedKernelTypes) {
49 m_filename = "None";
50 m_allowedKernelTypes = allowedKernelTypes;
51 m_kernelDbFiles.clear();
52 }
53
54
76 KernelDb::KernelDb(const QString &dbName, const unsigned int allowedKernelTypes) :
77 m_kernelData(dbName) {
78 m_filename = dbName;
79 m_allowedKernelTypes = allowedKernelTypes;
80 m_kernelDbFiles.clear();
81 }
82
83
105 KernelDb::KernelDb(std::istream &dbStream, const unsigned int allowedKernelTypes) {
106 dbStream >> m_kernelData;
107 m_filename = "internal stream";
108 m_allowedKernelTypes = allowedKernelTypes;
109 m_kernelDbFiles.clear();
110 }
111
117
135 return findLast("LeapSecond", lab);
136 }
137
138
156 return findLast("TargetAttitudeShape", lab);
157 }
158
159
177 return findLast("TargetPosition", lab);
178 }
179
180
197 QList< std::priority_queue<Kernel> > KernelDb::spacecraftPointing(Pvl &lab) {
198 return findAll("SpacecraftPointing", lab);
199 }
200
201
218 return findLast("SpacecraftClock", lab);
219 }
220
221
239 return findLast("SpacecraftPosition", lab);
240 }
241
242
260 return findLast("Instrument", lab);
261 }
262
263
281 return findLast("Frame", lab);
282 }
283
301 return findLast("InstrumentAddendum", lab);
302 }
303
304
322 return findLast("Dem", lab);
323 }
324
338 Kernel KernelDb::findLast(const QString &entry, Pvl &lab) {
339
340 QList< priority_queue<Kernel> > queues = findAll(entry, lab);
341 Kernel lastKernel;
342
343 if (queues.size() > 0 && queues.at(0).size() > 0) {
344 lastKernel = queues.at(0).top();
345 }
346
347 return lastKernel;
348 }
349
365 QList< std::priority_queue<Kernel> > KernelDb::findAll(const QString &entry,
366 Pvl &lab) {
367
368 QList< priority_queue<Kernel> > queues;
369 PvlObject &cube = lab.findObject("IsisCube");
370 int cameraVersion = -1;
371
372 try {
373 cameraVersion = CameraFactory::CameraVersion(lab);
374 }
375 catch (IException &) {
376 }
377
378 // Make sure the entry has been loaded into memory
379 if (!m_kernelData.hasObject(entry)) {
380 priority_queue<Kernel> emptyKernelQueue;
381 emptyKernelQueue.push(Kernel());
382 queues.push_back(emptyKernelQueue);
383 return queues;
384 }
385
386 // Get the start and end time for the cube
387 iTime start;
388 iTime end;
389
390 if (cube.hasGroup("Instrument")) {
391 start = (QString) cube.findGroup("Instrument")["StartTime"];
392
393 if (cube.findGroup("Instrument").hasKeyword("StopTime")) {
394 end = ((QString) cube.findGroup("Instrument")["StopTime"]);
395 }
396 else {
397 end = ((QString) cube.findGroup("Instrument")["StartTime"]);
398 }
399 }
400
401 // Loop through the objects to look for all matches to the entry value
402 for (int i = 0; i < m_kernelData.objects(); i++) {
403 if (m_kernelData.object(i).isNamed(entry)) {
404 priority_queue<Kernel> filesFound;
405 PvlObject &obj = m_kernelData.object(i);
406
407 for (int groupIndex = obj.groups() - 1; groupIndex >= 0; groupIndex--) {
408 // Get the group and start testing the cases in the keywords
409 // to see if they all match this cube
410 PvlGroup &grp = obj.group(groupIndex);
411
412 // If the group name isn't selection, skip it.
413 if (!grp.isNamed("Selection")) continue;
414
415 QString type = "";
416
417 // Make sure the type is allowed
418 if (grp.hasKeyword("Type")) {
419 type = (QString) grp["Type"];
420 if (!(Kernel::typeEnum(type) & m_allowedKernelTypes)) {
421 // will return 1 for each bit that has 1 in both type and allowed and
422 // return 0 for all other bits
423 //
424 // so, if Type = 0010 and allowed = 1010, then this bitwise operator
425 // (type & allowed) returns 0010 and is true.
426 // That is, this type is allowed.
427 continue;
428 }
429 }
430
431
432 bool startMatches = matches(lab, grp, start, cameraVersion);
433 bool endMatches = matches(lab, grp, end, cameraVersion);
434
435 if (startMatches && endMatches) {
436 // Simple case - the selection simply matches
437 filesFound.push(Kernel(Kernel::typeEnum(type), files(grp)));
438 QStringList kernelfiles = files(grp);
439 }
440 else if (startMatches) {
441 // Well, the selection start matched but not the end.
442 // Let's look for a second selection to handle overlap areas.
443 for (int endTimeIndex = obj.groups() - 1;
444 endTimeIndex >= 0;
445 endTimeIndex--) {
446
447 PvlGroup &endTimeGrp = obj.group(endTimeIndex);
448
449 // The second selection must:
450 // Not be the current selection
451 // Be a selection
452 // Be of the same quality
453 // Match the end time
454 //
455 // *If start time is also matched, do not merge and simply take the
456 // secondary match
457 if (endTimeIndex == groupIndex) continue;
458 if (!endTimeGrp.isNamed("Selection")) continue;
459 if (grp.hasKeyword("Type") != endTimeGrp.hasKeyword("Type")) continue;
460 if (grp.hasKeyword("Type") &&
461 grp["Type"] != endTimeGrp["Type"]) continue;
462 if (!matches(lab, endTimeGrp, end, cameraVersion)) continue;
463
464 // Better match is true if we find a full overlap
465 bool betterMatch = false;
466
467 // True if we have matching time ranges = we want to merge
468 bool endTimesMatch = true;
469
470 // Check for matching time ranges
471 for (int keyIndex = 0;
472 !betterMatch && keyIndex < grp.keywords();
473 keyIndex++) {
474 PvlKeyword &key = grp[keyIndex];
475
476 if (!key.isNamed("Time")) continue;
477
478 iTime timeRangeStart((QString)key[0]);
479 iTime timeRangeEnd((QString)key[1]);
480
481 bool thisEndMatches = matches(lab, endTimeGrp,
482 timeRangeEnd, cameraVersion);
483 endTimesMatch = endTimesMatch && thisEndMatches;
484
485 if (matches(lab, endTimeGrp, start, cameraVersion)
486 && matches(lab, endTimeGrp, end, cameraVersion)) {
487 // If we run into a continuous kernel, we want to take that in all
488 // cases.
489 betterMatch = true;
490 }
491 }
492
493 // No exact match but time ranges overlap, merge the selections
494 if (!betterMatch && endTimesMatch) {
495 QStringList startMatchFiles = files(grp);
496 QStringList endMatchFiles = files(endTimeGrp);
497
498 while (endMatchFiles.size()) {
499 startMatchFiles.push_back(endMatchFiles[endMatchFiles.size() - 1]);
500 endMatchFiles.pop_back();
501 }
502
503 filesFound.push(
504 Kernel(Kernel::typeEnum(type), startMatchFiles));
505 }
506 // Found an exact match, use it
507 else if (betterMatch) {
508 filesFound.push(Kernel(Kernel::typeEnum(type), files(endTimeGrp)));
509 QStringList kernelfiles = files(endTimeGrp);
510 }
511 }
512 }
513 }
514
515 queues.push_back(filesFound);
516 }
517 }
518
519 if (queues.size() == 0) {
520 priority_queue<Kernel> emptyKernelQueue;
521 emptyKernelQueue.push(Kernel());
522 queues.push_back(emptyKernelQueue);
523 }
524
525 return queues;
526 }
527
571 bool KernelDb::matches(const Pvl &lab, PvlGroup &grp,
572 iTime timeToMatch, int cameraVersion) {
573 // These are the conditions that make this test pass:
574 // 1) No time OR At least one matching time
575 // 2) All keyword matches are true OR No keyword matches present
576 //
577 // In order to accomplish this, matchTime is initialized to true and remains
578 // as such if and only if there are no time conditionals. If Time keywords
579 // exist, one of them has to set matchTime to true. The matchKeywords is
580 // true until a mismatch is found.
581 const PvlObject &cube = lab.findObject("IsisCube");
582 bool matchTime = !grp.hasKeyword("Time");
583 bool matchKeywords = true;
584 double startOffset = 0;
585 double endOffset = 0;
586 QString instrument = "";
587
588 if (grp.hasKeyword("StartOffset")){
589 startOffset = (double) grp["StartOffset"] + 0.001;
590 }
591 if (grp.hasKeyword("EndOffset")){
592 endOffset = (double) grp["EndOffset"] + 0.001;
593 }
594 if (grp.hasKeyword("Instrument")){
595 instrument = (QString) grp["Instrument"];
596 }
597
598 // First, the time search. Loop through the keywords, if the name isn't
599 // Time then skip it. If it is, then get the start/end times and keep
600 // looking until one is found.
601 for (int keyword = 0; keyword < grp.keywords(); keyword++) {
602 PvlKeyword key = grp[keyword];
603
604 if (key.isNamed("Time")) {
605
606 // Pull the selections start and end time out
607 iTime kernelStart = (QString) key[0];
608 iTime kernelEnd = (QString) key[1];
609
610 // If the kernel times inside of the requested times we
611 // set the matchTime to be true.
612 if ((kernelStart - startOffset <= timeToMatch) && (kernelEnd + endOffset >= timeToMatch)) {
613 matchTime = true;
614 }
615 // If the kernel segment has an instrument specification that doesn't match
616 // the instrument id in the label then the timing is always invalid
617 if (!instrument.isEmpty()) {
618 const PvlGroup &inst = lab.findGroup("Instrument", Pvl::Traverse);
619 QString instId = (QString) inst.findKeyword("InstrumentId");
620 if (instId.compare(instrument) != 0) {
621 matchTime = false;
622 }
623 }
624 }
625
626 else if (key.isNamed("Match")) {
627 try {
628 QString matchGroup = key[0];
629 QString matchKey = key[1];
630 QString matchValue = key[2];
631
632 QString cubeValue = cube.findGroup(matchGroup)[matchKey];
633 cubeValue = cubeValue.simplified().trimmed().toUpper();
634 matchValue = matchValue.simplified().trimmed().toUpper();
635
636 // If QStrings are not the same, match automatically fails
637 if (cubeValue.compare(matchValue) != 0) {
638 matchKeywords = false;
639 }
640 }
641 catch (IException &e) {
642 // This error is thrown if the group or keyword do not exist in 'lab'
643 matchKeywords = false;
644 }
645 }
646 else if (key.isNamed("CameraVersion")) {
647 try {
648 for (int camVersionKeyIndex = 0;
649 camVersionKeyIndex < key.size();
650 camVersionKeyIndex++) {
651
652 bool versionMatch = false;
653 IString val = key[camVersionKeyIndex];
654 IString commaTok;
655
656 while ((commaTok = val.Token(",")).ToQt().length() > 0) {
657 if (commaTok.find('-') != string::npos) {
658 QString dashTok;
659 int start = commaTok.Token("-").ToInteger();
660 int end = commaTok.Token("-").ToInteger();
661 int direction;
662 direction = (start <= end) ? 1 : -1;
663 // Save the entire range of bands
664 for (int version = start;
665 version != end + direction;
666 version += direction) {
667 if (version == cameraVersion) {
668 versionMatch = true;
669 }
670 }
671 }
672 // This token is a single band specification
673 else {
674 if (commaTok.ToInteger() == cameraVersion) {
675 versionMatch = true;
676 }
677 }
678 }
679
680 if (!versionMatch) {
681 matchKeywords = false;
682 }
683 }
684 }
685 catch (IException &) {
686 matchKeywords = false;
687 }
688 }
689 }
690
691 return matchKeywords && matchTime;
692 }
693
731 void KernelDb::loadSystemDb(const QString &mission, const Pvl &lab) {
732
733 // Get the base DataDirectory
734 PvlGroup &dataDir = Preference::Preferences().findGroup("DataDirectory");
735 QString baseDir = dataDir["Base"];
736
737 // Get the mission DataDirectory
738 QString missionDir = dataDir[mission];
739
740 // Load the leapsecond DB
741 loadKernelDbFiles(dataDir, baseDir + "/kernels/lsk", lab);
742 // Load the target attitude shape DB
743 // Try to get mission specific pck data, if that
744 // fails, fallback to the base pck data
745 try {
746 loadKernelDbFiles(dataDir, missionDir + "/kernels/pck", lab);
747 }
748 catch (IException &e) {
749 loadKernelDbFiles(dataDir, baseDir + "/kernels/pck", lab);
750 }
751 // Load the target position DB
752 FileName tpDbPath(missionDir + "/kernels/tspk");
753 if (tpDbPath.fileExists()) {
754 loadKernelDbFiles(dataDir, missionDir + "/kernels/tspk", lab);
755 }
756 else {
757 loadKernelDbFiles(dataDir, baseDir + "/kernels/spk", lab);
758 }
759 // Load the DEM DB
760 loadKernelDbFiles(dataDir, baseDir + "/dems", lab);
761 // Load the mission specific spacecraft pointing DB
762 loadKernelDbFiles(dataDir, missionDir + "/kernels/ck", lab);
763 // Load the mission specific frame DB
764 loadKernelDbFiles(dataDir, missionDir + "/kernels/fk", lab);
765 // Load the mission specific instrument DB
766 loadKernelDbFiles(dataDir, missionDir + "/kernels/ik", lab);
767 // Load the mission specific spacecraft clock DB
768 loadKernelDbFiles(dataDir, missionDir + "/kernels/sclk", lab);
769 // Load the mission specific spacecraft position DB
770 loadKernelDbFiles(dataDir, missionDir + "/kernels/spk", lab);
771 // Load the mission specific instrument addendum DB
772 loadKernelDbFiles(dataDir, missionDir + "/kernels/iak", lab);
774 }
775
805 QString directory, const Pvl &lab) {
806 // get most recent version of config file
807 FileName configFile = directory + "/kernels.????.conf";
808 bool noConfigFile = false;
809 // if there is no config file, default to the most recent kernel db file
810 try {
811 configFile = configFile.highestVersion();
812 }
813 catch (IException &e) {
814 noConfigFile = true;
815 }
816 if (noConfigFile) {
817 FileName kernelDb(directory + "/kernels.????.db");
818 m_kernelDbFiles.append(kernelDb.highestVersion());
819 }
820 else { // else, read in the appropriate database files from the config file
821 PvlObject inst = Pvl(configFile.expanded()).findObject("Instrument");
822 bool foundMatch = false;
823 // loop through each group until we find a match
824 for (int groupIndex = 0; groupIndex < inst.groups(); groupIndex++) {
825 if (!foundMatch) {
826 PvlGroup &grp = inst.group(groupIndex);
827 // Only add files in Selection groups with matching intrument id
828 if (grp.isNamed("Selection")
829 && KernelDb::matches(lab, grp, iTime(), 1)) {
830 foundMatch = true;
831 // add each File keywords in the matching group to the list
832 for (int keyIndex = 0; keyIndex < grp.keywords(); keyIndex++) {
833 PvlKeyword keyword = grp[keyIndex];
834 if (keyword.isNamed("File")) {
835 QString dir = dataDir[keyword[0]];
836 FileName kernelDb( dir + "/" + keyword[1]);
837 m_kernelDbFiles.append(kernelDb.highestVersion());
838 }
839 }
840 }
841 }
842 }
843 }
844 return;
845 }
846
847
866 // read each of the database files appended to the list into m_kernelData
867 foreach (FileName kernelDbFile, m_kernelDbFiles) {
868 try {
869 m_kernelData.read(kernelDbFile.expanded());
870 }
871 catch (IException &e) {
872 QString msg = "Unable to read kernel database file ["
873 + kernelDbFile.expanded() + "].";
874 throw IException(e, IException::Unknown, msg, _FILEINFO_);
875 }
876 }
877 }
878
886 QList<FileName> KernelDb::kernelDbFiles() {
887 return m_kernelDbFiles;
888 }
889
890
902
903 for (int i = 0; i < grp.keywords(); i++) {
904 PvlKeyword kfile = grp[i];
905 if (kfile.name() != "File") continue;
906
907 // Two values in the "File" keyword from the DB,
908 // indicates an ISIS preference in the DataDirectory section
909 // and a filename
910 if (kfile.size() == 2) {
911 QString pref = kfile[0];
912 QString version = kfile[1];
913 FileName filename("$" + pref + "/" + version);
914 if (filename.isVersioned())
915 filename = filename.highestVersion();
916 files.push_back(filename.originalPath() + "/" + filename.name());
917 }
918 // One value in "File" indicates a full file spec
919 else if (kfile.size() == 1) {
920 FileName filename(kfile[0]);
921 if (filename.isVersioned())
922 filename = filename.highestVersion();
923 files.push_back(filename.originalPath() + "/" + filename.name());
924 }
925 else {
926 QString msg = "Invalid File keyword value in [Group = ";
927 msg += grp.name() + "] in database file [";
928 msg += m_filename + "]";
929 throw IException(IException::Unknown, msg, _FILEINFO_);
930 }
931 }
932
933 return files;
934 }
935} //end namespace isis
static int CameraVersion(Cube &cube)
This looks up the current camera model version from the cube.
File name manipulation and expansion.
Definition FileName.h:100
QString name() const
Returns the name of the file excluding the path and the attributes in the file name.
Definition FileName.cpp:162
FileName highestVersion() const
Searches the directory specified in the file name for the highest version of the file name.
Definition FileName.cpp:313
QString originalPath() const
Returns the path of the original file name.
Definition FileName.cpp:84
bool isVersioned() const
Checks to see if a file name is versioned by date or numerically.
Definition FileName.cpp:281
Isis exception class.
Definition IException.h:91
@ Unknown
A type of error that cannot be classified as any of the other error types.
Definition IException.h:118
Adds specific functionality to C++ strings.
Definition IString.h:165
int ToInteger() const
Returns the object string as an integer.
Definition IString.cpp:718
IString Token(const IString &separator)
Returns the first token in the IString.
Definition IString.cpp:897
Kernel instrumentAddendum(Pvl &lab)
This method finds the highest version of all Instrument Addendum kernels (iak) identified by the data...
Definition KernelDb.cpp:300
QStringList files(PvlGroup &grp)
This method retrieves the values of all of the "File" keywords in the given PvlGroup.
Definition KernelDb.cpp:900
Kernel spacecraftClock(Pvl &lab)
This method finds the highest version of all Spacecraft Clock kernels (sclk) identified by the databa...
Definition KernelDb.cpp:217
Kernel targetAttitudeShape(Pvl &lab)
This method finds the highest version of all Target Attitude Shape kernels (pck) identified by the da...
Definition KernelDb.cpp:155
void loadKernelDbFiles(PvlGroup &dataDir, QString directory, const Pvl &lab)
This method is called by loadSystemDb() to create a list of all appropriate kernel database files to ...
Definition KernelDb.cpp:804
QList< FileName > m_kernelDbFiles
List of the kernel database file names that were read in when the loadSystemDb() method is called.
Definition KernelDb.h:145
Kernel instrument(Pvl &lab)
This method finds the last Instrument kernel found that matches the (ik) criteria in the database and...
Definition KernelDb.cpp:259
~KernelDb()
Destructs KernelDb object.
Definition KernelDb.cpp:115
void loadSystemDb(const QString &mission, const Pvl &lab)
Loads the appropriate kernel database files with the defined BASE and MISSION info for each type of k...
Definition KernelDb.cpp:731
static bool matches(const Pvl &lab, PvlGroup &kernelDbGrp, iTime timeToMatch, int cameraVersion)
This static method determines whether the given cube label matches the given criteria.
Definition KernelDb.cpp:571
Kernel targetPosition(Pvl &lab)
This method finds the highest version of all Target Position kernels (tspk) identified by the databas...
Definition KernelDb.cpp:176
Kernel findLast(const QString &entry, Pvl &lab)
Finds the highest priority Kernel object for the given entry based on the allowed Kernel types.
Definition KernelDb.cpp:338
Pvl m_kernelData
Pvl containing the information in the kernel database(s) that is read in from the constructor and whe...
Definition KernelDb.h:156
QList< std::priority_queue< Kernel > > findAll(const QString &entry, Pvl &lab)
Finds all of the Kernel objects for the given entry value based on the allowed Kernel types.
Definition KernelDb.cpp:365
QString m_filename
The name of the kernel database file.
Definition KernelDb.h:143
Kernel spacecraftPosition(Pvl &lab)
This method finds the highest version of all Spacecraft Position kernels (spk) identified by the data...
Definition KernelDb.cpp:238
unsigned int m_allowedKernelTypes
This integer value represents which Kernel::Types are allowed.
Definition KernelDb.h:148
Kernel frame(Pvl &lab)
This method finds the highest version of all Frame kernels (fk) identified by the database and the al...
Definition KernelDb.cpp:280
QList< std::priority_queue< Kernel > > spacecraftPointing(Pvl &lab)
This method finds a list of the highest versions of all Spacecraft Pointing kernels (ck) identified b...
Definition KernelDb.cpp:197
QList< FileName > kernelDbFiles()
Accessor method to retrieve the list of kernel database files that were read in when loadSystemDb() i...
Definition KernelDb.cpp:886
Kernel dem(Pvl &lab)
This method finds the highest version of all Digital Terrain Models (DEMs) found that match the crite...
Definition KernelDb.cpp:321
Kernel leapSecond(Pvl &lab)
This method finds the top priority of all Leap Second kernels (lsk) identified by the database and th...
Definition KernelDb.cpp:134
void readKernelDbFiles()
This method is called by loadSystemDb() to read kernel database file list compiled by loadKernelDbFil...
Definition KernelDb.cpp:865
KernelDb(const unsigned int allowedKernelTypes)
Constructs a new KernelDb object with a given integer value representing the Kernel::Type enumeration...
Definition KernelDb.cpp:48
This class stores Kernel information, including Type and kernel file names.
Definition Kernel.h:36
static Type typeEnum(const QString &type)
Converts the given string to a character as follows.
Definition Kernel.cpp:57
bool isNamed(const QString &match) const
Returns whether the given string is equal to the container name or not.
PvlKeyword & findKeyword(const QString &name)
Find a keyword with a specified name.
Contains multiple PvlContainers.
Definition PvlGroup.h:41
Container for cube-like labels.
Definition Pvl.h:119
void read(const QString &file)
Loads PVL information from a stream.
Definition Pvl.cpp:90
A single keyword-value pair.
Definition PvlKeyword.h:87
int size() const
Returns the number of values stored in this keyword.
Definition PvlKeyword.h:133
bool isNamed(QString name) const
Determines whether two PvlKeywords have the same name or not.
Definition PvlKeyword.h:115
Contains Pvl Groups and Pvl Objects.
Definition PvlObject.h:61
bool hasObject(const QString &name) const
Returns a boolean value based on whether the object exists in the current PvlObject or not.
Definition PvlObject.h:325
PvlObjectIterator findObject(const QString &name, PvlObjectIterator beg, PvlObjectIterator end)
Find the index of object with a specified name, between two indexes.
Definition PvlObject.h:276
int objects() const
Returns the number of objects.
Definition PvlObject.h:221
PvlObject & object(const int index)
Return the object at the specified index.
bool hasGroup(const QString &name) const
Returns a boolean value based on whether the object has the specified group or not.
Definition PvlObject.h:212
@ Traverse
Search child objects.
Definition PvlObject.h:158
PvlGroupIterator findGroup(const QString &name, PvlGroupIterator beg, PvlGroupIterator end)
Find a group with the specified name, within these indexes.
Definition PvlObject.h:129
Parse and return pieces of a time string.
Definition iTime.h:65
This is free and unencumbered software released into the public domain.
Definition Apollo.h:16
Namespace for the standard library.