;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; function btcgeneral_getspice_presetstruct, swver ;;; strtype = size('',/type) lngtype = size(0L,/type) dbltype = size(0d0,/type) ;;; rtnstr = { btcgeneral_dumy: 0L $ @btcgeneral_getspice_struct__include.pro } tags = tag_names(rtnstr) ntm1 = n_elements(tags)-1L ;;; for i=1L,ntm1 do begin ;;; N.B. Skip first tag (btcgeneral_dumy) case tags[i] of 'STAT': rtnstr.(i).val = 'BAD' ;;; Assume failure 'KWVER': ;;; don't change keyword version: in *raw.tsv & *__include.pro 'SWVER': rtnstr.(i).val = swver else: begin case size(rtnstr.(i).val,/type) of strtype: rtnstr.(i).val = 'UNK' lngtype: rtnstr.(i).val = -999L dbltype: rtnstr.(i).val = -999d0 else: endcase end endcase endfor ;;; return,rtnstr end ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; unload all (default), or types of, kernels ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; pro btcgeneral_getspice_unloadkernels, spicelist $ , argktypes=argktypes $ , forceTextUnload=forceTextUnload $ , mylog=mylog $ , debug=debug common btcg_TKsLeftLoaded_cmn, slTksLeftLoaded ;;; Maintain state btw calls dodebug = keyword_set(debug) dolog = keyword_set(mylog) or dodebug doftu = keyword_set(forceTextUnload) noftu = doftu ? 0b : 1b ;;; if n_elements(argktypes) eq 0 then ktypes = ['ALL'] $ else ktypes = [strupcase(strtrim(argktypes,2))] ;;; ;;; SLPFS: Spice List File PathS ;;; if n_elements(spicelist) gt 0L then slfps = spicelist.kernelfilepath ;;; if dolog then help,doftu,noftu,argktypes,slfps ;;; for i=0L, n_elements(ktypes)-1L do begin ;;; case ktypes[i] of 'SPK:': ktype = 'SPK' 'CK:': ktype = 'CK' 'ORIBPCK:': ktype = 'PCK' 'EK:': ktype = 'EK' 'TK:': ktype = 'TEXT' 'META:': ktype = 'META' 'ALL': ktype = 'ALL' else: ktype = ktypes[i] endcase ;;; Clear the kernel pool if both ktype is ALL and forceTextUnload is set if doftu then begin if ktype eq 'ALL' then cspice_clpool if (ktype eq 'ALL' or ktype eq 'TEXT') $ and n_elements(slTksLeftLoaded) gt 0L then begin ptr_free, ptr_new( slTksLeftLoaded, /no_copy) endif endif ;;; cspice_ktotal, ktype, count if dolog then help, count nLeftLoaded = 0L while count gt nLeftLoaded do begin ft='' cspice_kdata, nLeftLoaded, ktype, fp, ft, source, handle, found if dolog then help,fp,ft,found if found then begin fn = strmid( fp, strpos(fp,'/',/reverse_search)+1L) doUnload = 1b ;;; Assume kernel will be unloaded ;;; Unload if forceTextUnload is set or kernel is not TEXT ;;; - i.e. leave TEXT kernels loaded if forceTextUnload is not set ;;; - purpose is speed enhancement: minimize unloading and ;;; and reloading TEXT kernels doUnload = doftu or ft ne 'TEXT' if n_elements(slfps) gt 0 then begin iw = where( fp eq slfps, iwcount) ;;; Look for kernel in spicelist if iwcount gt 0L then begin sl = spicelist[iw] ;;; - save current loaded state of kernel if it will not be unloaded spicelist[iw].kernelloaded = 0b spicelist[iw].textKernelLeftLoaded = $ doUnload ? 0b : (sl.kernelloaded or sl.textKernelLeftLoaded) endif endif ;;; else ...: Kernel loaded but not in spicelist: default unload if ft eq 'TEXT' and dolog then help,doftu,doUnload ;;; Actually unload the kernel if desired if doUnload then begin cspice_unload, fp if dolog then print, 'Unloaded kernel ' + fp endif else begin if dolog then print, 'Left loaded kernel ' + fp nLeftLoaded = nLeftLoaded + 1 newsi = { btcg_spicelist $ , 'TK:' $ , fp $ , fn $ , 0b $ , 0d0 $ , 0d0 $ , 0b $ , 1b $ } if n_elements(slTksLeftLoaded) gt 0L then begin slTksLeftLoaded = [slTksLeftloaded, newsi ] endif else begin slTksLeftLoaded = [ newsi ] endelse endelse endif ;;; found if dolog then help,nleftloaded,ktype ;;; Get new number of loaded kernels cspice_ktotal, ktype, count endwhile return endfor ;;; end ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Load one type of kernel from spicelist ;;; - return index into spicelist of all kernels of this type that are ;;; loaded at the end of this routine ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; function btcgeneral_getspice_loadkernels, spicelist, argktype $ , argbasetime, argtimetolerance $ , mylog=mylog $ , debug=debug common btcg_TKsLeftLoaded_cmn, slTksLeftLoaded ;;; Maintain state btw calls dodebug = keyword_set(debug) dolog = keyword_set(mylog) or dodebug ;;; iw = where(spicelist.kerneltype eq argktype, iwcount) ;;; if iwcount lt 1L then return, [-1L] ;;; reload = 0b ;;; No need to reload already-loaded kernels yet ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Special case for argktype == 'TK:' ;;; - skip reload if all text kernels were actually left loaded by last ;;; btcgeneral_getspice_unloadkernels call ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; nTksLL = n_elements(slTksLeftLoaded) kernelsLeftLoaded = 0b if argktype eq 'TK:' and nTksLL gt 0L then begin ;;; - check if the input TK list is the same length as the LeftLoaded list kernelsLeftLoaded = iwcount eq nTksLL ;;; - check if the input TK list names are the same as the LeftLoaded list if kernelsLeftLoaded then begin iwiw = where( spicelist[iw].kernelFilename $ ne slTksLeftLoaded.kernelFilename $ , iwiwct) kernelsLeftLoaded = iwiwct eq 0L endif if kernelsLeftLoaded then begin spicelist[iw].kernelloaded[iw] = 1b spicelist[iw].textKernelLeftLoaded[iw] = 0b ptr_free,ptr_new(slTksLeftLoaded,/no_copy) ;;; delete common variable iwcount = 0L ;;; Bypass default load loop below endif else begin ;;; This next call will ;;; - unload all TK (TEXT) kernels, whether left loaded or not ;;; - reset .kernelloaded and .textKernelLeftLoaded members ;;; - delete slTksLeftLoaded common variable btcgeneral_getspice_unloadkernels, spicelist $ , argktypes=argktype $ , /forceTextUnload $ , mylog=mylog $ , debug=debug endelse nTksLL = n_elements(slTksLeftLoaded) endif ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Default loop to load kernels from spicelist of type argktype ;;; N.B. Loop is bypassed if iwcount set to zero above for i=0L,iwcount-1 do begin iwi = iw[i] spiceitem = spicelist[iwi] ;;; Look for the same TK in slTksLeftLoaded ;;; wasLeftLoaded = 0b ;;; Assume was not LeftLoaded if nTksLL gt 0L and spiceitem.kerneltype eq 'TK:' then begin iwTLL = where(spiceitem.kernelfilename eq slTksLeftLoaded.kernelfilename $ , iwTLLCt) if iwTLLCt gt 0L then begin spiceitem = slTksLeftLoaded[iwTLL[0]] wasLeftLoaded = 1b endif endif ;;; Find out if this kernel should be, or remains, loaded ;;; if not spiceitem.testsegment then begin ;;; unconditional load doload = 1b ;;; endif else begin ;;; conditional load doload = 0b ;;; - assume no load ;;; if n_elements(argbasetime) eq 1 then begin ;;; Need base time to load basetime = argbasetime ;;; if n_elements(argtimetolerance) eq 1 then begin ;;; Don't need tolerance timetol = argtimetolerance endif else begin timetol = 0d0 endelse ;;; doload = (basetime ge (spiceitem.segmentstart-timetol)) $ and (basetime le (spiceitem.segmentend+timetol)) if dolog then help,argtimetolerance $ ,doload,basetime,spiceitem.segmentstart,spiceitem.segmentend,timetol endif endelse ;;; ;;; if kernel should not be loaded ;;; - unload it if it is currently loaded ;;; - replace its spicelist index in iw with -1L ;;; N. B. check of .textKernelLeftLoaded is probably unnecessary as ;;; TKs are not time dependent in the current scheme ;;; if not doload then begin if spiceitem.kernelloaded or spiceitem.textKernelLeftLoaded then begin cspice_unload, spiceitem.kernelfilepath if dolog then begin sTmp = wasLeftLoaded and spiceitem.textKernelLeftLoaded ? 'Left-Loaded ' $ : '' print, 'Unloading ' + sTmp + 'kernel ' + spiceitem.kernelfilename endif if wasLeftLoaded and spiceitem.textKernelLeftLoaded then begin slTksLeftLoaded[iwTLL[0]].kernellloaded = 0b slTksLeftLoaded[iwTLL[0]].textKernelLeftLoaded = 0b endif spicelist[iwi].kernelloaded = 0b spicelist[iwi].textKernelLeftLoaded = 0b endif iw[i] = -1L continue endif ;;; ;;; to here, the kernel should be loaded (or re-loaded) ;;; if (not (spiceitem.kernelloaded or spiceItem.textKernelLeftLoaded)) $ or reload then begin fp = spiceitem.kernelfilepath ;;; Unload TK before re-loading if (spiceitem.kernelloaded or spiceItem.textKernelLeftLoaded) $ and spiceitem.kernelType eq 'TK:' then $ cspice_unload, fp cspice_furnsh, fp reload = 1b ;;; will need to reload later kernels also if dolog then print, 'Loading kernel ' + spiceitem.kernelfilename ;;; endif if wasLeftLoaded and spiceitem.textKernelLeftLoaded then begin slTksLeftLoaded[iwTLL[0]].kernelLoaded = 1b slTksLeftLoaded[iwTLL[0]].textKernelLeftLoaded = 0b endif spicelist[iwi].kernelloaded = 1b ;;; Moved outside previous if-endif spicelist[iwi].textKernelLeftLoaded = 0b ;;; endfor ;;; Reset Left-Loaded kernels common variable ;;; if nTksLL gt 0L then begin iwLL = where( slTksLeftLoaded.textKernelLeftLoaded, iwLLct) if iwLLct eq 0 then begin ptr_free, ptr_new(slTksLeftLoaded, /no_copy) endif else if iwLLct lt nTksLl then begin slTksLeftLoaded = slTksLeftLoaded[iwLL] endif endif iwiw = where( iw gt -1L, iwiwcount) if iwiwcount eq 0L then return, [-1L] iwnet = iw[iwiw] if dolog then begin print, 'Currently loaded ' + argktype + ' kernels:' print, spicelist[iwnet].kerneltype + spicelist[iwnet].kernelfilename,f='(a)' if kernelsLeftLoaded then $ print, 'N.B. These TKs were Left Loaded from a previous Unload' print, iwnet endif return, iwnet end ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; pro btcgeneral_dbgmsg, varname, val, found, argfunc print help,val func = (n_elements(argfunc) eq 0) ? 'G*POOL' : argfunc print, func + ': ' + string(varname) $ + ' => ' + strjoin(strtrim(val[*],2),',') $ + '; ' + (found ? "SUCCESS" : "FAILED") return end ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; pro btcgeneral_getspice_sxform, frfrm, tofrm, ck_mid_et $ , xforminstr2j2k $ , cktimeoffsets=arg_cktimeoffsets $ , ckitermax=arg_ckitermax $ , mylog=mylog $ , debug=debug dodebug = keyword_set(debug) dolog = keyword_set(mylog) or dodebug if dolog then begin print,'In BTCGENERAL_GETSPICE_SXFORM; OFFSETS=' print, f='(2x,a)' $ , n_elements(arg_cktimeoffsets) lt 1L ? '' $ : strtrim( double(arg_cktimeoffsets[*]), 2) endif ;;; Look for the attitude at the input time ck_mid_et0 = ck_mid_et ;;; save the input time ;;;;;;;;;; SINGLE RUN CATCH ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; er = 0L catch,er if er eq 0L then begin cspice_sxform, frfrm, tofrm, ck_mid_et, xforminstr2j2k if dolog then btcgeneral_dbgmsg, ck_mid_et-ck_mid_et0, xforminstr2j2k, 1b, 'SXFORM:A' return ;;; success at input time endif msg = !error_state.msg ;;; failure at the input time, save message ... ;;;;;;;;;; SINGLE RUN CATCH ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; catch,/cancel iOffset=0 ;;; ... try the offsets nOffsets = n_elements(arg_cktimeoffsets) ;;;;;;;;;; MULTIPLE RUN CATCHES: look for valid offset ;;;;;;;;;;;;;; er = 0L catch,er if er ne 0L or iOffset ge nOffsets then begin iOffset = iOffset + 1L if iOffset ge nOffsets then begin ;;; SXFORM failed at all offsets catch,/cancel message,msg endif endif ck_mid_et_max = ck_mid_et0 + double(arg_cktimeoffsets[iOffset]) cspice_sxform, frfrm, tofrm, ck_mid_et_max, xforminstr2j2k if dolog then btcgeneral_dbgmsg, ck_mid_et_max-ck_mid_et0, xforminstr2j2k, 1b, 'SXFORM:B' ;;;;;;;;;; MULTIPLE RUN CATCHES: look for valid offset ;;;;;;;;;;;;;; catch,/cancel ck_mid_et_mid = ck_mid_et_max ck_mid_et = ck_mid_et_max ck_mid_et00 = ck_mid_et0 if n_elements(arg_ckitermax) lt 1L then begin iSteps = 16L endif else begin iSteps = long(arg_ckitermax[0]) endelse ;;;;;;;;;; MULTIPLE RUN CATCHES: binary search for minimum valid offset er = 0L catch,er while iSteps gt 0L do begin iSteps = iSteps - 1L if dolog then help,iSteps,ck_mid_et-ck_mid_et00,ck_mid_et0-ck_mid_et00 if er ne 0L then begin ck_mid_et0 = ck_mid_et_mid ;;; SXFORM FAILURE, increase offset er = 0L ;;; Reset error endif ck_mid_et_mid = (ck_mid_et + ck_mid_et0) / 2d0 cspice_sxform, frfrm, tofrm, ck_mid_et_mid, xforminstr2j2k if dolog then btcgeneral_dbgmsg, ck_mid_et_mid-ck_mid_et00, xforminstr2j2k, 1b, 'SXFORM:C' ck_mid_et = ck_mid_et_mid ;;; SXFORM SUCCESS, decrease offset endwhile ;;;;;;;;;; MULTIPLE RUN CATCHES: binary search for minimum valid offset catch,/cancel cspice_sxform, frfrm, tofrm, ck_mid_et, xforminstr2j2k if dolog then btcgeneral_dbgmsg, ck_mid_et-ck_mid_et00, xforminstr2j2k, 1b, 'SXFORM:D' return end ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; pro btcgeneral_getspice_spkgeo, tmptargid, mid_et, frame, spkid, tmpstate, ltime savestate = tmpstate catcherr = 0L catch,catcherr if catcherr ne 0L then begin catch,/cancel tmpstate = savestate ltime = -1e32 return endif cspice_spkgeo, tmptargid, mid_et, frame, spkid, tmpstate, ltime catch,/cancel return end ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; STRING: SPICELISTFILE: SPICE kernel files to load; see _readspicelistfile ;;; STRING: QUAL: Quality of kernels ;;; - NOM (nominal or predicted) or REC (reconstructed) ;;; STRING: ARGINSTRUMENT: Instrument of observation ;;; - SPICE kernel pool FRAME of this name must exist ;;; - e.g. DI Flyby HRI VIS => DIF_HRI_VIS => FRAME_DIF_HRI_VIS ;;; STRING[]: TARGETS: Possible targets of observation ;;; - SPICE name e.g. DI HRI VIS => FRAME_DIF_HRI_VIS SPICE variable ;;; STRING: ARG_PARTITION_SCLKCH: Base time of obs as SCLK string, w/partition ;;; DOUBLE: ARG_ET: Base time of obs as s past J2000 ;;; - ARG_ET used if ARG_PARTITION_SLCKCH not specified ;;; DOUBLE: ARG_DELTICKS: delta from base to mid exposure time, SCLK ticks ;;; DOUBLE: ARG_DELET: delta from base time to mid exposure time, s ;;; - ARG_DELET used if ARG_DELTICKS not specified ;;; KEYWORD: /noMsgNoFrameConnect: inhibit message,/continue if CSPICE_SXFORM ;;; throws a NOFRAMECONNECT error ;;; KEYWORD: /DEBUG: Log progress if KEYWORD_SET(DEBUG) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; function btcgeneral_getspice, spicelistfile $ , qual $ , arginstrument $ , targets $ , arg_partition_sclkch=arg_partition_sclkch $ , arg_et=arg_et $ , arg_delticks=arg_delticks $ , arg_delet=arg_delet $ , spicelist=spicelist $ , cktimeoffsets=arg_cktimeoffsets $ , ckitermax=arg_ckitermax $ , noMsgNoFrameConnect=noMsgNoFrameConnect $ , nocatch=nocatch $ , badSclk0=badSclk0 $ , mylog=mylog $ , debug=debug ;;; dodebug = keyword_set(debug) dolog = keyword_set(mylog) or dodebug ;;; rtnstr = btcgeneral_getspice_presetstruct('BTCGENERAL_GETSPICE 2011-05-09') ;;; rtnstr.qual.val = strupcase(qual) ;;; errstat = 0L if not keyword_set(nocatch) then catch, errstat if errstat ne 0 then begin catch,/cancel errMsg = compress_errmsg( !error_state.msg) rgx = 'CSPICE_SXFORM: *SPICE[(]NOFRAMECONNECT[)]: *' irgx = stregex(errMsg, rgx) if not keyword_set(noMsgNoFrameConnect) or iRgx lt 0 then begin if iRgx eq 0 then errMsg = stregex(errMsg, rgx, /extract) + '...' message,/continue, errMsg + '; QUAL="' + qual + '"' endif return, rtnstr endif if dodebug then catch,/cancel ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Start SPICE toolkit calls ;;; - unload all kernels ;;; - read list of SPICE files into structure SPICELIST ;;; - load all TEXT kernels (leapsecond, SCLK, frame & instrument kernels) ;;; btcgeneral_getspice_unloadkernels, mylog=mylog, debug=debug ;;; if spicelistfile eq '/dev/null' then return, rtnstr if spicelistfile eq '' then return, rtnstr ;;; spicelist = btcgeneral_readspicelist( spicelistfile, mylog=mylog, debug=debug) ;;; iwtkloaded = btcgeneral_getspice_loadkernels(spicelist, 'TK:' $ , mylog=mylog, debug=debug) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Check and load mission sub-phases into common area from kernel pool rtn = btcgeneral_missionphases(/checkandload) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Get frame from arginstrument ;;; - ***N.B. ASSUMES FRAME ID AND INSTRUMENT ID ARE THE SAME! ;;; framenm = 'FRAME_' + arginstrument cspice_gipool, framenm, 0L, 1L, frameid, found if dolog then btcgeneral_dbgmsg, framenm, frameid, found ;;; frameid = frameid[0] ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; rtnstr.insid.val = frameid rtnstr.insnm.val = strupcase(arginstrument) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; frameidch = strtrim(frameid,2) ;;; inspfx = 'INS' + frameidch varname = inspfx + '_PLATFORM_ID' cspice_gipool, varname, 0L, 1L, platformid, found if dolog then btcgeneral_dbgmsg, varname, platformid, found ;;; platformid = platformid[0] platformidch = strtrim(platformid,2) ;;; varname = 'CK_' + platformidch + '_SCLK' cspice_gipool, varname, 0L, 1L, sclkid, found if dolog then btcgeneral_dbgmsg, varname, sclkid, found ;;; sclkid = sclkid[0] sclkidch = strtrim(sclkid,2) ;;; varname = inspfx + '_IFOV' cspice_gdpool, varname, 0L, 1L, ifov, found if dolog then btcgeneral_dbgmsg, varname, sclkid, found ;;; if found then ifov = ifov[0] else ifov = 0d0 ;;; cspice_bodc2n, sclkid, sclknm, found if dolog then btcgeneral_dbgmsg, sclkid, sclknm, found, 'BODC2N' ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; rtnstr.slkid.val = sclkid rtnstr.slknm.val = sclknm rtnstr.pxlsz.val = ifov ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; varname = 'CK_' + platformidch + '_SPK' cspice_gipool, varname, 0L, 1L, spkid, found if dolog then btcgeneral_dbgmsg, varname, spkid, found ;;; spkid = spkid[0] spkidch = strtrim(spkid,2) ;;; cspice_bodc2n, spkid, spknm, found if dolog then btcgeneral_dbgmsg, spkid, spknm, found, 'BODC2N' ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; rtnstr.spkid.val = spkid rtnstr.spknm.val = spknm ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Determine mid-exposure time from BASE + DELTA ;;; 1) get base time from ARG_PARTITION_SCLKCH or ARG_ET ;;; 2) get delta time from ARG_DELTICKS or ARG_DELET ;;; ;;; - BASE time ;;; - ET ;;; - SCLK string ;;; - SCLK ticks (DOUBLE) ;;; if n_elements(arg_partition_sclkch) eq 1 then begin base_sclkch = arg_partition_sclkch ;;; cspice_scs2e, sclkid, base_sclkch, base_et if dolog then btcgeneral_dbgmsg, base_sclkch, base_et, 1b, 'SCS2E' ;;; endif else begin base_et = arg_et ;;; cspice_sce2s, sclkid, base_et, base_sclkch if dolog then btcgeneral_dbgmsg, base_et, base_sclkch, 1b, 'SCE2S' endelse ;;; cspice_scencd, sclkid, base_sclkch, base_sclkticks if dolog then btcgeneral_dbgmsg, base_et, base_sclkch, 1b, 'SCENCD' ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; rtnstr.sct0.val = base_et rtnstr.slk0.val = base_sclkch rtnstr.slk0d.val = base_sclkticks if n_elements(badSclk0) eq 1L then rtnstr.bads0.val = badSclk0[0] ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; ;;; 2) DELTA time ;;; - SCLK TICKS + DELTA TICKS ;;; OR ;;; - ET + DELTA ET ;;; if n_elements(arg_delticks) eq 1 then begin mid_sclkticks = base_sclkticks + arg_delticks if arg_delticks lt 0.0 then begin start_sclkticks = base_sclkticks + 2*(arg_delticks) end_sclkticks = base_sclkticks endif else begin start_sclkticks = base_sclkticks end_sclkticks = base_sclkticks + 2*(arg_delticks) endelse ;;; cspice_scdecd, sclkid, start_sclkticks, start_sclkch if dolog then btcgeneral_dbgmsg, start_sclkticks, start_sclkch, 1b, 'SCDECD' ;;; cspice_scs2e, sclkid, start_sclkch, start_et if dolog then btcgeneral_dbgmsg, start_sclkch, start_et, 1b, 'SCS2E' ;;; cspice_scdecd, sclkid, end_sclkticks, end_sclkch if dolog then btcgeneral_dbgmsg, end_sclkticks, end_sclkch, 1b, 'SCDECD' cspice_scdecd, sclkid, mid_sclkticks, mid_sclkch if dolog then btcgeneral_dbgmsg, mid_sclkticks, mid_sclkch, 1b, 'SCDECD' ;;; cspice_scs2e, sclkid, mid_sclkch, mid_et if dolog then btcgeneral_dbgmsg, mid_sclkch, mid_et, 1b, 'SCS2E' ;;; endif else begin mid_et = base_et + arg_delet if arg_delet lt 0.0 then begin start_et = base_et + 2*arg_delet end_et = base_et endif else begin start_et = base_et end_et = base_et + 2*arg_delet endelse cspice_sce2s, sclkid, start_et, start_sclkch if dolog then btcgeneral_dbgmsg, start_et, start_sclkch, 1b, 'SCE2S' ;;; cspice_scencd, sclkid, start_sclkch, start_sclkticks if dolog then btcgeneral_dbgmsg, start_sclkch, start_sclkticks, 1b, 'SCENCD' cspice_sce2s, sclkid, end_et, end_sclkch if dolog then btcgeneral_dbgmsg, end_et, end_sclkch, 1b, 'SCE2S' ;;; cspice_scencd, sclkid, end_sclkch, end_sclkticks if dolog then btcgeneral_dbgmsg, end_sclkch, end_sclkticks, 1b, 'SCENCD' cspice_sce2s, sclkid, mid_et, mid_sclkch if dolog then btcgeneral_dbgmsg, mid_et, mid_sclkch, 1b, 'SCE2S' ;;; cspice_scencd, sclkid, mid_sclkch, mid_sclkticks if dolog then btcgeneral_dbgmsg, mid_et, mid_sclkch, 1b, 'SCENCD' endelse ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; cspice_et2utc, mid_et, 'D', 3, utcscch if dolog then btcgeneral_dbgmsg, mid_et, strtrim(utcscch,2), 1b, 'ET2UTC' ;;; cspice_et2utc, mid_et, 'C', 3, calscch if dolog then btcgeneral_dbgmsg, mid_et, strtrim(calscch,2), 1b, 'ET2UTC' ;;; cspice_et2utc, mid_et, 'J', 8, jdscch if dolog then btcgeneral_dbgmsg, mid_et, strtrim(jdscch,2), 1b, 'ET2UTC' ;;; cspice_et2utc, mid_et, 'ISOD', 3, isodscch if dolog then btcgeneral_dbgmsg, mid_et, strtrim(isodscch,2), 1b, 'ET2UTC' ;;; cspice_et2utc, mid_et, 'ISOC', 3, isocscch if dolog then btcgeneral_dbgmsg, mid_et, strtrim(isocscch,2), 1b, 'ET2UTC' ;;; ;;; break up Julian Day string into whole days and fractional days ;;; jdscstruct = btcgeneral_getspice_parsejulianday( jdscch) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; rtnstr.dsct0.val = mid_et - base_et rtnstr.dslk0.val = mid_sclkticks - base_sclkticks rtnstr.partn.val = strmid(mid_sclkch,0,strpos(mid_sclkch,'/')) rtnstr.sclk.val = mid_sclkch rtnstr.sclkd.val = mid_sclkticks rtnstr.utcsc.val = utcscch rtnstr.calsc.val = calscch rtnstr.jdsc.val = jdscch rtnstr.isdsc.val = isodscch rtnstr.iscsc.val = isocscch rtnstr.tdbsc.val = mid_et rtnstr.jd0.val = jdscstruct.jdfix rtnstr.jsc.val = jdscstruct.jdfrac rtnstr.sslk.val = start_sclkch rtnstr.eslk.val = end_sclkch ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Get instrument frame definition ;;; - get boresight from instrument kernel variable INS-framennn_BORESIGHT ;;; - break into right-hand system components: Image Right, Bore, Image Up ;;; - get boresight in instrument frame ;;; - find closest frame axis to boresight, call this nearboreaxis ;;; - if nearboreaxis is not frame +/-X ;;; - make right-hand system with +X toward Right in horizontal plane ;;; - if nearboreaxis is frame +/-X ;;; - make right-hand system with +Z toward Right in horizontal plane ;;; - this should put +/-Y toward Up and in Bore-Up plane ;;; ;;; - Orthogonal cases in the dreaded ASCII 2D graphics ;;; - view is from behind, up and right of instrument ;;; - boresight is going into page/screen ;;; ;;; -Y = image up +Y = image up ;;; ^ ^ ;;; | +Z = bore | -Z = bore ;;; | /| | /| ;;; | / | / ;;; |/ |/ ;;; o---->+X = image right o---->+X = image right ;;; ;;; +Z = image up -Z = image up ;;; ^ ^ ;;; | +Y = bore | -Y = bore ;;; | /| | /| ;;; | / | / ;;; |/ |/ ;;; o---->+X = image right o---->+X = image right ;;; ;;; +Y = image up -Y = image up ;;; ^ ^ ;;; | +X = bore | -X = bore ;;; | /| | /| ;;; | / | / ;;; |/ |/ ;;; o---->+Z = image right o---->+Z = image right ;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; - boresight ;;; inspfx = 'INS' + frameidch varname = inspfx + '_BORESIGHT' cspice_gdpool, varname, 0L, 3L, scborexyzsc, found if dolog then btcgeneral_dbgmsg, varname, scborexyzsc, found ;;; cspice_vhat, scborexyzsc, scborexyzsc ;;; ensure unit vector ;;; cspice_ident, mtxident ;;; Identity matrix xaxis = mtxident[*,0] yaxis = mtxident[*,1] zaxis = mtxident[*,2] xaxisneg = -mtxident[*,0] yaxisneg = -mtxident[*,1] zaxisneg = -mtxident[*,2] ;;; ;;; - Find minimum boresight separation from frame axes ;;; - 0,1: +X, -X ;;; - 2,3: +Y, -Y ;;; - 4,5: +Z, -Z ;;; boresep = min( [ cspice_vsep(scborexyzsc,xaxis) $ , cspice_vsep(scborexyzsc,xaxisneg) $ , cspice_vsep(scborexyzsc,yaxis) $ , cspice_vsep(scborexyzsc,yaxisneg) $ , cspice_vsep(scborexyzsc,zaxis) $ , cspice_vsep(scborexyzsc,zaxisneg) $ ], iwmin) ;;; ;;; - Right-ish vector (X or Z) cross Boresight => "Up" ;;; if iwmin gt 1 then begin ;;; nearboreaxis is not +/-X, put +X to right ;;; cspice_vperp, xaxis, scborexyzsc, scrightxyzsc ;;; endif else begin ;;; nearboreaxis is +/-X, put +Z right, +/-Y up ;;; cspice_vperp, zaxis, scborexyzsc, scrightxyzsc ;;; endelse ;;; ;;; - ensure Right is a unit vector ;;; - Right cross Boresight => Up ;;; cspice_vhat, scrightxyzsc, scrightxyzsc cspice_vcrss, scrightxyzsc, scborexyzsc, scupxyzsc ;;; if dolog then begin btcgeneral_dbgmsg, 'UP,UPlen-1', [scupxyzsc,cspice_vnorm(scupxyzsc)-1d0], 1b, 'INSTRUMENT' btcgeneral_dbgmsg, 'RIGHT,RIGHTlen-1', [scrightxyzsc,cspice_vnorm(scrightxyzsc)-1d0], 1b, 'INSTRUMENT' endif ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Get boundaries and maximum separation of FOV boundaries from boresight ;;; cspice_getfov, frameid, 20L, shape, frame2, bsight, bounds count = (n_elements(bounds) / 3L) fovsiz = make_array( count+1, value=-1d0) for i=0L,count-1L do fovsiz[i] = cspice_vsep( bsight, bounds[*,i]) maxfovsiz = max( fovsiz) ;;; if dolog then begin btcgeneral_dbgmsg, frameidch + ' SHAPE:', shape, 1b, 'GETFOV' btcgeneral_dbgmsg, frameidch + ' FRAME:', frame2, 1b, 'GETFOV' btcgeneral_dbgmsg, frameidch + ' BORE:', bsight, 1b, 'GETFOV' btcgeneral_dbgmsg, frameidch + ' SIZE:', fovsiz, 1b, 'VSEP' endif ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Load CK-kernels to get S/C orientation ;;; iwckloaded = btcgeneral_getspice_loadkernels( $ spicelist, 'CK:', mid_sclkticks, 0d0 $ , mylog=mylog, debug=debug) ;;; ck_mid_et = mid_et if n_elements(arg_cktimeoffsets) eq 0L then begin cspice_sxform, arginstrument, 'J2000', mid_et, xforminstr2j2k if dolog then btcgeneral_dbgmsg, mid_et, xforminstr2j2k, 1b, 'SXFORM' endif else begin btcgeneral_getspice_sxform, arginstrument, 'J2000', ck_mid_et $ , xforminstr2j2k $ , cktimeoffsets=arg_cktimeoffsets $ , ckitermax=arg_ckitermax $ , mylog=mylog $ , debug=debug endelse ;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Extract rotation & angular velocity from state transformation matrix ;;; - in J2000 coordinates ;;; - mtxinst2j2k is rotation from instrument frame to J2000 frame ;;; - instr_avinst is angular velocity, relative to instrument ;;; - rotate instr_avinst to J2000 via mtxinst2j2k ;;; cspice_xf2rav, xforminstr2j2k, mtxinst2j2k, instr_avinst cspice_mxv, mtxinst2j2k, instr_avinst, instr_avj2k ;;; cspice_m2q, mtxinst2j2k, quatinst2j2k if dolog then btcgeneral_dbgmsg, 'MTX', quatinst2j2k, 1b, 'M2Q' ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; rtnstr.scqdt.val = ck_mid_et - mid_et rtnstr.scqa.val = quatinst2j2k[0] rtnstr.scqx.val = quatinst2j2k[1] rtnstr.scqy.val = quatinst2j2k[2] rtnstr.scqz.val = quatinst2j2k[3] rtnstr.scvqx.val = instr_avj2k[0] rtnstr.scvqy.val = instr_avj2k[1] rtnstr.scvqz.val = instr_avj2k[2] ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Rotate boresight into J2k frame ;;; cspice_mxv, mtxinst2j2k, scborexyzsc, scborexyzj2k if dolog then btcgeneral_dbgmsg, varname, scborexyzj2k, 1b, 'MXV' ;;; cspice_recrad, scborexyzj2k, scboreradiusj2k, scboreraj2k, scboredecj2k ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; rtnstr.scra.val = scboreraj2k * 180d0 / !dpi rtnstr.scdec.val = scboredecj2k * 180d0 / !dpi ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; btcgeneral_getspice_unloadkernels, spicelist, argktypes='CK:' $ , mylog=mylog, debug=debug ;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Load SP-Kernels to get initial geometry w/o light-time correction ;;; to calculate approximate light-time correction ;;; iwspkloaded = btcgeneral_getspice_loadkernels( $ spicelist, 'SPK:', mid_et, 0d0 $ , mylog=mylog $ , debug=debug) ;;; ;;; Make separation and target time arrays for each target ;;; - add targets "sun" and "earth" ;;; alltargets = [targets, 'sun', 'earth'] ;;; ntargets = n_elements(targets) targetseps = make_array( ntargets, val=10d0) ;;; set > PI i.e. max sep targetltimes = make_array( ntargets+2L, val=-1d0) targetids = make_array( ntargets+2L, value=0L) ;;; for i=0L, ntargets+1L do begin ;;; cspice_bodn2c, alltargets[i], tmptargid, found if not found then continue targetids[i] = tmptargid if dolog then btcgeneral_dbgmsg, alltargets[i], tmptargid, found, 'BODN2C' ;;; ltime = -1d32 tmpstate = [ -scborexyzj2k,0,0,0] btcgeneral_getspice_spkgeo, tmptargid, mid_et, 'J2000', spkid, tmpstate, ltime if ltime lt -1d30 then continue if dolog then btcgeneral_dbgmsg, alltargets[i], tmpstate, 1b, 'SPKGEO' ;;; if ltime gt cspice_spd() then ltime = 0d0 ;;; targetltimes[i] = ltime ;;; if i lt ntargets then begin tmpsep = cspice_vsep( scborexyzj2k, tmpstate[0:2]) if dolog then btcgeneral_dbgmsg, 'scborexyzj2k', tmpsep, 1b, 'VSEP' ;;; Add in radius of body for close encounters varname = 'BODY' + strtrim(tmptargid,2) + '_RADII' cspice_gdpool, varname, 0L, 99L, radii, found if dolog then btcgeneral_dbgmsg, varname, radii, found, 'GDPOOL' reducesep = found $ ? asin( (max([radii]) / cspice_vnorm(tmpstate[0:2])) < 1d0) $ : 0d0 ;;; targetseps[i] = tmpsep - reducesep endif endfor ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Determine target as closest body to boresight within ;;; PI/2 & (20 * maxfovsiz) ;;; - if no targets meet the criterion ;;; - use S/C as target and prefix it with 'UNKNOWN/USING ' in structure ;;; iw = where( targetseps lt min([20d0*maxfovsiz, cspice_halfpi()]), count) if dodebug then count=1L if count eq 0L then begin targetid = spkid targetnmpfx = 'UNKNOWN/USING ' targetnm = spknm endif else begin minsep = min( targetseps, iwmin) targetid = targetids[iwmin[0]] targetnmpfx = '' targetnm = strupcase(targets[iwmin[0]]) endelse ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; rtnstr.trgid.val = targetid rtnstr.trgnm.val = targetnmpfx + targetnm ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Reload SP-Kernels with max([targetltimes,0d0]) tolerance ;;; iwspkloaded = btcgeneral_getspice_loadkernels( $ spicelist, 'SPK:', mid_et, max([targetltimes,0d0]) $ , mylog=mylog $ , debug=debug) ;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Get states ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; 1) Target to S/C ;;; if spkid eq targetid then begin sc2targj2k = make_array(6,val=0d0) mid_etattarg = mid_et cspice_xpose, mtxinst2j2k, mtxj2k2targ ;;; transpose instrument matrix endif else begin cspice_spkez, targetid, mid_et, 'J2000', 'LT+S' $ , spkid, sc2targj2k, targ2scltime mid_etattarg = mid_et - targ2scltime cspice_tipbod, 'J2000', targetid, mid_etattarg, mtxj2k2targ endelse ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Clever code to get inverse of state tranformation matrix, and then ;;; use it to calculate target vector in FOV sc2targfov = transpose(shift(xforminstr2j2k,3,3)) ## sc2targj2k ;;; targ2scj2k = -sc2targj2k jdtargstruct = btcgeneral_getspice_parsejulianday(mid_etattarg) ;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; 2) Target to Sun ;;; cspice_spkezr, 'sun', mid_etattarg, 'J2000', 'LT+S' $ , targetnm, targ2sunj2k, targ2sunltime ;;; mid_etatsun = mid_etattarg - targ2sunltime jdsunstruct = btcgeneral_getspice_parsejulianday(mid_etatsun) ;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; 3) Earth-based observer ('EO') to Target ;;; - ABCORR = 'XLT+S'=>Transmission light time: Earth is actual observer ;;; cspice_spkezr, 'earth', mid_etattarg, 'J2000', 'XLT+S' $ , targetnm, targ2eoj2k, targ2eoltime ;;; eo2targj2k = - targ2eoj2k mid_etateo = mid_etattarg + targ2eoltime jdeostruct = btcgeneral_getspice_parsejulianday(mid_etateo) ;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; 4) S/C to Earth ;;; - ABCORR = 'XLT+S'=>Transmission light time: Earth is actual observer ;;; cspice_spkezr, 'earth', mid_et, 'J2000', 'XLT+S' $ , spknm, sc2earthj2k, sc2earthltime ;;; mid_etatearth = mid_et + sc2earthltime jdearthstruct = btcgeneral_getspice_parsejulianday(mid_etatearth) ;;;calculate the UTC time at earth cspice_et2utc, mid_etatearth, 'ISOC', 3, mid_earth_utc rtnstr.iscea.val = mid_earth_utc ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; rtnstr.scx.val = targ2scj2k[0] rtnstr.scy.val = targ2scj2k[1] rtnstr.scz.val = targ2scj2k[2] rtnstr.scvx.val = targ2scj2k[3] rtnstr.scvy.val = targ2scj2k[4] rtnstr.scvz.val = targ2scj2k[5] rtnstr.scrng.val = cspice_vnorm(targ2scj2k[0:2]) rtnstr.jtarg.val = jdtargstruct.jddbl - rtnstr.jd0.val ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; rtnstr.sox.val = targ2sunj2k[0] rtnstr.soy.val = targ2sunj2k[1] rtnstr.soz.val = targ2sunj2k[2] rtnstr.sovx.val = targ2sunj2k[3] rtnstr.sovy.val = targ2sunj2k[4] rtnstr.sovz.val = targ2sunj2k[5] rtnstr.sorng.val = cspice_vnorm(targ2sunj2k[0:2]) rtnstr.jsun.val = jdsunstruct.jddbl - rtnstr.jd0.val ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; rtnstr.eox.val = eo2targj2k[0] rtnstr.eoy.val = eo2targj2k[1] rtnstr.eoz.val = eo2targj2k[2] rtnstr.eovx.val = eo2targj2k[3] rtnstr.eovy.val = eo2targj2k[4] rtnstr.eovz.val = eo2targj2k[5] rtnstr.eorng.val = cspice_vnorm(eo2targj2k[0:2]) rtnstr.jeo.val = jdeostruct.jddbl - rtnstr.jd0.val ;;; ;;; RA & DEC ;;; if rtnstr.eorng.val gt 0d0 then begin cspice_recrad, eo2targj2k[0:2], eo2t2k_r, eo2tj2k_ra, eo2tj2k_dec rtnstr.eora.val = eo2tj2k_ra * 180d0 / !dpi rtnstr.eodec.val = eo2tj2k_dec * 180d0 / !dpi endif else begin rtnstr.eora.val = 0d0 rtnstr.eodec.val = 0d0 endelse ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; rtnstr.ex.val = sc2earthj2k[0] rtnstr.ey.val = sc2earthj2k[1] rtnstr.ez.val = sc2earthj2k[2] rtnstr.evx.val = sc2earthj2k[3] rtnstr.evy.val = sc2earthj2k[4] rtnstr.evz.val = sc2earthj2k[5] rtnstr.erng.val = cspice_vnorm(sc2earthj2k[0:2]) rtnstr.je.val = jdearthstruct.jddbl - rtnstr.jd0.val ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Get EMEJ2k & ECLIPTICJ2k North azimuths in FOV ;;; ;;; rotate Ecliptic North into J2000 ;;; cspice_sxform,'ECLIPJ2000', 'J2000', mid_et, eclip2j2k cspice_mxv, eclip2j2k[0:2,0:2], zaxis, eclipnorth_j2k ;;; ;;; rotate from J2000 to S/C: ;;; cspice_mtxv, mtxinst2j2k, zaxis, j2knorth_sc cspice_mtxv, mtxinst2j2k, eclipnorth_j2k, eclipnorth_sc ;;; ;;; get clockwise from up, using recrad ;;; ;;; BTC 2005-04-27 Swapped scupxyzsc & scrightxyzsc in the ;;; following formulae: ;;; UPsc.J2kNorth=X & RIGHTsc.J2kNorth=Y gives CW from UP ;;; (old way, RIGHTsc...=X & UPsc...=Y gives CW from RIGHT) ;;; cspice_recrad, [ cspice_vdot(scupxyzsc,j2knorth_sc) $ , cspice_vdot(scrightxyzsc,j2knorth_sc) $ , 0d0], tmpr, j2knoraz, tmpdec ;;; cspice_recrad, [ cspice_vdot(scupxyzsc,eclipnorth_sc) $ , cspice_vdot(scrightxyzsc,eclipnorth_sc) $ , 0d0], tmpr, eclipnoraz, tmpdec ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; rtnstr.emen.val = j2knoraz * 180d0 / !dpi rtnstr.ecln.val = eclipnoraz * 180d0 / !dpi ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Get Solar elongation & clock angle (azimuth, CW from up) in ;;; instrument frame ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; cspice_mtxv, mtxinst2j2k, sc2targj2k[0:2] + targ2sunj2k[0:2], sc2suninst cspice_recrad, [ cspice_vdot(scupxyzsc,sc2suninst) $ , cspice_vdot(scrightxyzsc,sc2suninst) $ , cspice_vdot(scborexyzsc,sc2suninst) $ ], tmpr, solarclock_instr, solardec_instr rtnstr.solcl.val = solarclock_instr * 180d0 / !dpi rtnstr.solel.val = 90d0 - (solardec_instr * 180d0 / !dpi) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Get Body / Instrument / Sun values ;;; - S/C Lat, WLon ;;; - Solar Lat, WLon ;;; - Earth observer Lat, WLon ;;; - Range along boresight ;;; - Noraz: body north in FOV and in instrument frame ;;; - Body center offset from boresight (Right & Down, also XYZ) ;;; ;;; Suffix "_bf" => Target Body Fixed ;;; cspice_mxv, mtxj2k2targ, targ2scj2k[0:2], v3t2sc_bf ;;; S/C cspice_mxv, mtxj2k2targ, targ2sunj2k[0:2], v3t2sun_bf ;;; Sun cspice_mxv, mtxj2k2targ, targ2eoj2k[0:2], v3t2eo_bf ;;; Earth observer ;;; cspice_recrad, v3t2sc_bf, r_sc, elon_sc, lat_sc ;;; switch to west lon later cspice_recrad, v3t2sun_bf, r_sun, elon_sun, lat_sun cspice_recrad, v3t2eo_bf, r_eo, elon_eo, lat_eo ;;; cspice_mtxv, mtxinst2j2k, sc2targj2k[0:2], sc2targ_sc ;;; rotate targ V to SC ;;; rangb = cspice_vdot(sc2targ_sc,scborexyzsc) ;;; Range along bore to CA to Body ;;; offb_sc = sc2targ_sc - (rangb*scborexyzsc) ;;; Targ pos offset from boresight ;;; offbr = cspice_vdot(offb_sc, scrightxyzsc) ;;; Body ctr offset right wrt bore offbd = cspice_vdot(offb_sc, -scupxyzsc) ;;; Body ctr offset down wrt bore fovvr = cspice_vdot(sc2targfov[3:5], scrightxyzsc) ;;; Vel right wrt bore fovvd = cspice_vdot(sc2targfov[3:5], -scupxyzsc) ;;; Vel down wrt bore ;;; cspice_mtxv, mtxj2k2targ, zaxis, bodyNorthJ2k ;;; rotate body N to J2k cspice_mtxv, mtxinst2j2k, bodyNorthJ2k, bodyNorth_sc ;;; ... then to instr frm ;;; ;;; Target Body North Azimuth, CW from up: ;;; cspice_recrad, [ cspice_vdot(scupxyzsc,bodyNorth_sc) $ , cspice_vdot(scrightxyzsc,bodyNorth_sc) $ , 0d0], tmpr, bodynoraz, tmpdec ;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; rtnstr.sclat.val = lat_sc * cspice_dpr() rtnstr.sclon.val = 360d0 - (elon_sc * cspice_dpr()) ;;; West Longitude rtnstr.solat.val = lat_sun * cspice_dpr() rtnstr.solon.val = 360d0 - (elon_sun * cspice_dpr()) rtnstr.eolat.val = lat_eo * cspice_dpr() rtnstr.eolon.val = 360d0 - (elon_eo * cspice_dpr()) ;;; rtnstr.rangb.val = rangb ;;; km rtnstr.noraz.val = bodynoraz * cspice_dpr() ;;; if rangb gt 0d0 then begin rtnstr.offbr.val = 1d6 * offbr / rangb ;;; microRadians rtnstr.offbd.val = 1d6 * offbd / rangb ;;; microRadians rtnstr.fovvr.val = 1d6 * fovvr / rangb ;;; microRadians/s rtnstr.fovvd.val = 1d6 * fovvd / rangb ;;; microRadians/s endif else begin rtnstr.offbr.val = 0d0 ;;; microRadians rtnstr.offbd.val = 0d0 ;;; microRadians rtnstr.fovvr.val = 0d0 ;;; microRadians/s rtnstr.fovvd.val = 0d0 ;;; microRadians/s endelse ;;; rtnstr.nrthx.val = bodyNorth_sc[0] rtnstr.nrthy.val = bodyNorth_sc[1] rtnstr.nrthz.val = bodyNorth_sc[2] ;;; rtnstr.offbx.val = offb_sc[0] ;;; km rtnstr.offby.val = offb_sc[1] ;;; km rtnstr.offbz.val = offb_sc[2] ;;; km ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Loaded kernels ;;; - store "TYPE:PATH" values in rtnstr.k0000.val delimited by "*" ;;; iwksloaded = [iwtkloaded, iwckloaded, iwspkloaded] iw = where( iwksloaded gt -1L) iwksloaded = iwksloaded[iw] ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; rtnstr.k0000.val = strjoin(spicelist[iwksloaded].kerneltype + spicelist[iwksloaded].kernelfilename, '*') ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; rtnstr.stat.val = ck_mid_et eq mid_et ? 'OK' : 'POOR: Tquat ne Tmid_obs' return, rtnstr end