Provide addendum-only TGO CaSSIS constants in the driver so isd_generate produces a complete ISD#732
Conversation
The CaSSIS focal length, ITRANSS/ITRANSL, distortion model, and light-time flags are defined only in the ISIS addendum kernel, so on the NaifSpice path they were read as null or False and isd_generate produced an incomplete or geometrically wrong ISD. Return them from the driver, following the Cassini precedent. The resulting CSM camera matches the ISIS camera to a few thousandths of a pixel. Done with Claude, an AI assistant. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
| instrument id | ||
| """ | ||
| id_lookup = { | ||
| 'CaSSIS': 'TGO_CASSIS', |
There was a problem hiding this comment.
I don't think this driver was fleshed out very well for use with USGSCSM when originally created. I think we want to expand the lookup table to handle:
TGO_CASSIS -143400
TGO_CASSIS_PAN -143421
TGO_CASSIS_RED -143422
TGO_CASSIS_NIR -143423
TGO_CASSIS_BLU -143424
We likely want to expand the dictionary to include the filter from the label. Basically make the look up key:
key = super().instrument_id + "_" + self.label["IsisCube"]["Instrument"]["Filter"]
Then update the look up table with:
'CaSSIS_RED': 'TGO_CASSIS_RED',
'CaSSIS_NIR': 'TGO_CASSIS_NIR',
...
There was a problem hiding this comment.
ISIS keys the CaSSIS camera on the base frame -143400 for every filter, not the per-filter codes. Spice::init prefers NaifFrameCode over NaifIkCode, and TgoCassisCamera reads the boresight, focal-plane map, and distortion from that code. Verified on real PAN and NIR cubes, both carry NaifFrameCode -143400. So the single lookup entry matches ISIS, and keying on the filter would diverge from it. The driver now reads the values from the furnished addendum for that code.
| return -143420 | ||
|
|
||
| @property | ||
| def focal_length(self): |
There was a problem hiding this comment.
Similarly above, all of these added properties have the potential to be different in the IAK based on the NAIF ID. As of the latest addendum (007) they are all the same
There was a problem hiding this comment.
Agreed they are equal at 007. And since ISIS uses only the base -143400 values regardless (NaifFrameCode overrides the per-filter NaifIkCode), the per-code differences never reach the camera. The driver now reads these from the furnished addendum instead of hardcoding, so a newer addendum is picked up automatically.
| line (INS-143400_BORESIGHT_LINE = 1024.5) is addendum-only, so hardcoded. | ||
| """ | ||
| return 1024.5 - 0.5 |
There was a problem hiding this comment.
Per the IAK, if we handle each filter as ISIS does this will be different based on the filter:
INS-143400_BORESIGHT_LINE = 1024.5
INS-143421_BORESIGHT_LINE = 493.5
INS-143422_BORESIGHT_LINE = 839.5
INS-143423_BORESIGHT_LINE = 1175.5
INS-143424_BORESIGHT_LINE = 1516.5
There was a problem hiding this comment.
The camera uses INS-143400_BORESIGHT_LINE = 1024.5 for all filters, because TgoCassisCamera builds on naifIkCode() = -143400 (NaifFrameCode wins over NaifIkCode). A PAN cube reprojects ISIS vs CSM to about 7e-4 px median with 1024.5, which the per-filter 493.5 would not. This is now read from the addendum rather than hardcoded.
| return [0.0, 100.0, 0.0] | ||
|
|
||
| @property | ||
| def usgscsm_distortion_model(self): |
There was a problem hiding this comment.
Looking at the distortion in USGSCSM, we are using:
static const double cassisFocalBound = 0.5 * 0.01 * 2048.0 + 0.2;
For both width and height of the detector to check that we are within the image. ISIS applies a slightly different check and uses the FILTER_LINES and FILTER_SAMPLES from here based on the NAIF ID:
INS-143421_FILTER_LINES = 280
INS-143421_FILTER_SAMPLES = 2048
INS-143422_FILTER_LINES = 256
INS-143422_FILTER_SAMPLES = 2048
INS-143423_FILTER_LINES = 256
INS-143423_FILTER_SAMPLES = 2048
INS-143424_FILTER_LINES = 256
INS-143424_FILTER_SAMPLES = 2048
It would be best if these values were baked into the distortion array's of the ISD and accessed within USGSCSM
There was a problem hiding this comment.
For the -143400 code the camera uses, INS-143400_FILTER_SAMPLES and FILTER_LINES are both 2048, so the USGSCSM bound 0.50.012048+0.2 already matches ISIS. The per-filter 256/280 belong to the -14342x codes, which ISIS does not use to build this camera: TgoCassisCamera keys the distortion map on naifIkCode() = -143400. The bound only differs outside the CCD where the model is identity either way, so no ISD or USGSCSM change is needed here, because all logic is already as in ISIS.
Instead of hardcoding the addendum-only CaSSIS values, furnish the ISIS addendum from the data area, auto-detecting the latest version, and read the focal length, distortion, boresight, focal-plane transforms, and light-time flags from the SPICE pool. Fall back to the latest known constants only when the addendum cannot be furnished. Add tests that furnish a faux addendum and assert the driver returns its value, proving the read path. The ISIS and CSM cameras still agree to the same tolerance, verified with cam_test. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017UAsYR1UURD4nMBE4afn7G
|
Update: rather than hardcoding the addendum values, the driver now furnishes the ISIS addendum from the data area, auto-detecting the latest version, and reads the focal length, distortion, boresight, focal-plane transforms, and light-time flags from the SPICE pool, falling back to the latest known constants only when the addendum is not furnished. This lets the values track the addendum and its version rather than a frozen copy. A new unite test was added that furnishes a faux addendum with a distinctive focal length and asserts the driver returns it, proving the read path, and another asserts the fallback when no addendum is furnished. The ASP cam_test tool shows the ISIS and CSM cameras still agree to the same tolerance as before this change, about 7e-4 px median and 0.013 px max, so this robustness fix does not change the result. |
The TGO CaSSIS driver builds its ISD from the mission metakernel on the NaifSpice path, which is what isd_generate uses. Several CaSSIS instrument constants live only in the ISIS addendum kernel (tgoCassisAddendum), not in any NAIF instrument kernel, so on the NaifSpice path they were read as null or False and the ISD was incomplete or geometrically wrong. Following the Cassini driver precedent, the driver now returns these addendum-only values:
With these, isd_generate produces a complete CSM camera whose geometry matches the ISIS camera.
Validation: the ale test suite passes, with a new test asserting the CaSSIS focal length on the NaifSpice path. The camera was also checked with the Ames Stereo Pipeline cam_test tool, comparing the ISIS camera from a spiceinit'd cube against the CSM camera from the isd_generate ISD. They agree to a camera center difference of 1.7e-9 m, a look direction difference of 3.7e-15, and a pixel difference of 0.0007 px median and 0.013 px max over the frame.
A reviewer can reproduce that with cam_test on the sample cube cas_cal_sc_20210725T202818-20210725T202822-16378-10-PAN-838849161-0-0__4_0.cub (observation MY36_016378_162_1, Jezero, 2021-07-25), which we can provide on request. It needs a USGSCSM build with CaSSIS distortion support, already merged in USGSCSM, and spiceinit to succeed on the cube. On recent CaSSIS observations spiceinit currently fails with "No instrument position available" because the shipped TGO SPK database omits the reconstructed spacecraft positions, tracked in DOI-USGS/ISIS3#6094.
This work was done with Claude, an AI assistant.
Licensing