def _make_new_meta_kernel(kernels, local_kernel_dir, new_pathname): path_values = spice.gcpool("PATH_VALUES", 0, 256) path_symbols = spice.gcpool("PATH_SYMBOLS", 0, 256) kernels_to_load = spice.gcpool("KERNELS_TO_LOAD", 0, 1024) s = "KPL/MK\n" s += "\\begindata\n" # PATH_VALUES s += " PATH_VALUES = (\n" path_base = Path(local_kernel_dir) for path_value in path_values: s += " '" + str(path_base / path_value) + "'\n" s += " )\n" # PATH_SYMBOLS s += " PATH_SYMBOLS = (\n" for path_symbol in path_symbols: s += " '" + path_symbol + "'\n" s += " )\n" # KERNELS_TO_LOAD s += " KERNELS_TO_LOAD = (\n" for kernel in kernels_to_load: s += " '" + kernel + "'\n" s += " )\n" with open(new_pathname, "w") as f: f.write(s)
def test_topo_frame_setup(): # Check that the frame setup puts all the correct values in the kernel pool. latitude, longitude = 30, 25 name, idnum, frame_dict, latlon = spice_utils.topo_frame_def( latitude, longitude) frame_strs = ["{}={}".format(k, v) for (k, v) in frame_dict.items()] spice.lmpool(frame_strs) for k, v in frame_dict.items(): N, typecode = spice.dtpool(k) if typecode == 'N': res = spice.gdpool(k, 0, 100) if len(res) == 1: res = [int(res[0])] if N > 1: v = [float(it) for it in v.split(' ')] res = res.tolist() else: res = res[0] v = int(v) assert v == res else: res = spice.gcpool(k, 0, 100)[0] v = v.replace('\'', '') assert v == res
def get_orientation_matrix(obsinfo, target, object_id): iau_frame = f"IAU_{target}" frcode = spice.namfrm(iau_frame) if frcode == 0: frame_name = f"FRAME_{object_id}_NAME" _n, iau_frame = spice.gcpool(frame_name, 0, 1) frcode = spice.namfrm(iau_frame) mtx = spice.pxform(iau_frame, obsinfo.fov.frame, obsinfo.et) # rot = get_boresight_rotation_matrix(obsinfo['boresight']) # return spice.mxm(rot, mtx) return mtx
def _meta_kernel_to_urls(meta_kernel, url, local_kernel_dir, remote_root): spice.ldpool(meta_kernel) path_values = spice.gcpool("PATH_VALUES", 0, 256) path_symbols = spice.gcpool("PATH_SYMBOLS", 0, 256) kernels_to_load = spice.gcpool("KERNELS_TO_LOAD", 0, 1024) symbols = {} for path_value, path_symbol in zip(path_values, path_symbols): symbols[f"${path_symbol}"] = path_value url_base = urllib.parse.urljoin(url, remote_root) path_base = Path(local_kernel_dir) kernel_urls = [] for kernel in kernels_to_load: for key in symbols: if key in kernel: kernel = kernel.replace(key, symbols[key]) remote_url = urllib.parse.urljoin(url_base, kernel) local_path = str(path_base / kernel) kernel_urls.append((remote_url, local_path)) return kernel_urls
def correct_lt_to_surface(self): """ Returns if light time correction should be made to the surface instead of to the center of the body. This is defined by a keyword in ISIS IAKs. If the keyword is not defined in any loaded kernels then False is returned. Expects ikid to be defined. This should be an integer containing the Naif Id code of the instrument. """ try: surface_correct = spice.gcpool( 'INS{}_LT_SURFACE_CORRECT'.format(self.ikid), 0, 1)[0] return surface_correct.upper() == "TRUE" except: return False
def swap_observer_target(self): """ Returns if the observer and target should be swapped when determining the sensor state relative to the target. This is defined by a keyword in ISIS IAKs. If the keyword is not defined in any loaded kernels then False is returned. Expects ikid to be defined. This should be an integer containing the Naif Id code of the instrument. """ try: swap = spice.gcpool('INS{}_SWAP_OBSERVER_TARGET'.format(self.ikid), 0, 1)[0] return swap.upper() == "TRUE" except: return False
def _spice_setup(latitude, longitude): if not isinstance(latitude, (int, float)): latitude = latitude[0] if not isinstance(longitude, (int, float)): longitude = longitude[0] loadnew = True frameloaded = check_is_loaded('*LUNAR-TOPO*') if frameloaded: latlon = spice.gcpool('TOPO_LAT_LON', 0, 8) loadnew = not latlon == ["{:.4f}".format(l) for l in [latitude, longitude]] if loadnew: station_name, idnum, frame_specs, latlon = topo_frame_def(latitude, longitude, moon=True) spice.pcpool('TOPO_LAT_LON', latlon) frame_strs = ["{}={}".format(k, v) for (k, v) in frame_specs.items()] spice.lmpool(frame_strs)
def light_time_correction(self): """ Returns the type of light time correciton and abberation correction to use in NAIF calls. Expects ikid to be defined. This must be the integer Naif id code of the instrument. This searches for the value of the NAIF keyword INS<ikid>_LIGHTTIME_CORRECTION. If the keyword is not defined, then this defaults to light time correction and abberation correction (LT+S). Returns ------- : str The light time and abberation correction string for use in NAIF calls. See https://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/req/abcorr.html for the different options available. """ try: return spice.gcpool('INS{}_LIGHTTIME_CORRECTION'.format(self.ikid), 0, 1)[0] except: return 'LT+S'
self.lineTerm)) ######################################################################## if "__main__" == __name__: # FURNSH the docstring above as a text kernel, # plus any other files on the command line, # and put values into kernel pool for arg in sys.argv: spice.furnsh(arg) # Get pairs of ET endpoints from kernel pool pts = list(spice.gdpool('PAIR_TIMES', 0, 100)) nPETs = len(pts) # Set or clear debug flag try: doDebug = True if spice.gcpool("DEBUG", 0, 1, 999)[0] else False except: doDebug = False # Allocate cell of SpiceDoubles pws = stypes.SPICEDOUBLE_CELL(nPETs) # Add ET endpoints to cell pts.reverse() while pts: spice.appndd(pts.pop(), pws) # Convert those pairs of ET endpoints into confinement window pws = spice.wnvald(nPETs, nPETs, pws) assert (spice.wncard(pws) << 1) == nPETs pts = list(spice.gdpool('PAIR_TIMES', 0, 100)) # Get the filename of, and read, the input XFR file filename = spice.gcpool("XPC_KERNEL", 0, 1, 999)[0] assert filename
def create_ck(kernels, frames_to_convert, fks, stop_ets, output_ck): """ Create CK from FKs and times at which the FKs end being valid """ ### FURNSH any kernels for kernel in kernels: sp.furnsh(kernel) ### Set last ET to None so it will be initialized in loop's first pass last_et = None ### Do not overwrite existing output CK assert (not sp.exists(output_ck) ) or dict()['Cannot overwrite existing CK[{}]'.format(output_ck)] ### Initialize CK handle to None ck_handle = None ### Loop over CKs while fks: ### Get FK and corresponding stop ET fk = fks.pop() stop_et = stop_ets.pop() ### Loop over reference frames (reffrms) for reffrm in frames_to_convert: ### Get reffrm ID, SCLK ID; N.B. latter comes from new FK reffrm_id = sp.gipool('FRAME_{}'.format(reffrm.upper()), 0, 1)[0] sclk_id = sp.gipool('CK_{}_{}'.format(reffrm_id, 'SCLK'), 0, 1)[0] ### Set start DP-SCLK of window for this old FK (outer loop) ### - Set to zero for first window ### - Covnert ET to DP-SCLK for subsequent windows if last_et is None: begtim = 0.0 else: begtim = sp.sce2t(sclk_id, last_et) ### Load old FK, get RELATIVE frame name, get time-invariant ### matrix, and unload old FK sp.furnsh(fk) relative_reffrm = sp.gcpool( 'TKFRAME_{}_{}'.format(reffrm_id, 'RELATIVE'), 0, 1, 99)[0] mtx = sp.pxform(relative_reffrm, reffrm, 0.0) sp.unload(fk) ### Covnert matrix to quaternion quat = sp.m2q(mtx) ### Calculate tick rate: seconds per tick rate = (sp.sct2e(sclk_id, 1e3) - sp.sct2e(sclk_id, 0.)) / 1e3 if doVerbose: ### if VERBOSE environment variable is present, log information print(( relative_reffrm, reffrm, fk, last_et, stop_et, '{:010.3f}'.format(1. / rate), quat, )) ### Set stop DP-SCLK of window if stop_et < -1e30: ### Use end of encoded DP_SCLK for final window endtim = sp.gdpool('SCLK_PARTITION_END_{}'.format(-sclk_id), 0, 999)[-1] else: ### Else convert stop ET to DP-SCLK endtim = sp.sce2t(sclk_id, stop_et) if doDebug: ### Debug output pprint.pprint( dict(fk=fk, reffrm=reffrm, reffrm_id=reffrm_id, relative_reffrm=relative_reffrm, rate=rate, begtim=begtim, endtim=endtim, diff=endtim - begtim, mtx=mtx, quat=quat)) ### Open CK, once if ck_handle is None: ck_handle = sp.ckopn(output_ck, 'ORX FK REPLACEMENT', 0) ### Write Type 2 CK segment with one record; angular velocity = 0 sp.ckw02(ck_handle, begtim, endtim, reffrm_id, relative_reffrm, '{}[{}]'.format(os.path.basename(fk), reffrm)[:40], 1, [begtim], [endtim], [quat], [[0., 0., 0.]], [rate]) ### Save stop ET for start ET of next pass last_et = stop_et ### Close CK if not (ck_handle is None): sp.ckcls(ck_handle)
def main(argv_arg=sys.argv[1:]): """ Process oommand-line arguments into input to create_ck and test_ck methods """ ### Process arguments ### Create set of non-kernel options non_kernel_opts = set('--test --create'.split()) ### All arguments which are not in that set are SPICE kernels kernels = [arg for arg in argv_arg if not (arg in non_kernel_opts)] ### - Use this script as the lone SPICE kernel if none provided if not kernels: kernels = [__file__[-4:-1] == '.py' and __file__[:-1] or __file__] ### - FURNSH those kernels for kernel in kernels: sp.furnsh(kernel) ### Get frames to convert from FK to CK form frames_to_convert = sp.gcpool('FRAMES_TO_CONVERT', 0, 999, 99) assert frames_to_convert ### Get FK paths; use STPOOL in case paths are long fks = list() item = 0 while True: ### - Use '+' for continuation ### - Read paths until exception; assume that indicates the end try: fks.append(sp.stpool('FKS', item, '+', 2048)[0]) except: if doDebug: tb.print_exc() sys.stderr.write('\nN.B. Expected error; continuing ...\n\n') break item += 1 ### Throw exception if no FKs were provided assert fks ### Get stop times for each FK, cast to list so .pop() is available stop_ets = list(sp.gdpool('STOP_ETS', 0, 999)) ### Ensure there is a stop time for each FK assert len(fks) == len(stop_ets) ### Reverse order of FKs so .pop() will get items in order fks.reverse() stop_ets.reverse() ### Get output CK path output_ck = sp.stpool('OUTPUT_CK', 0, '+', 2048)[0] ### Unload all kernels sp.kclear() if '--create' in argv_arg: ### Call method to create CK; pass copies of fks and stop_ets create_ck(kernels, frames_to_convert, fks[:], stop_ets[:], output_ck) if '--test' in argv_arg: ### Call test method; pass copies of fks and stop_ets test_ck(kernels, frames_to_convert, fks[:], stop_ets[:], output_ck)
def test_ck(kernels, frames_to_convert, fks, stop_ets, output_ck): """ Text CK against FKs at times at which the FKs are valid """ ### Load base kernels (LSK, new FK, SCLK) for kernel in kernels + [output_ck]: sp.furnsh(kernel) ### Set last ET to None so it will be initialized in loop's first pass last_et = None ### Create dict of info; keys will be new FK filenames dt = dict() while fks: ### Pop FK and stop ET off of lists fk = fks.pop() stop_et = stop_ets.pop() ### Create dict for this FK dt[fk] = dict() ### Loop over refernce frames for reffrm in frames_to_convert: ### Get reffrm ID, SCLK ID; N.B. latter comes from new FK reffrm_id = sp.gipool('FRAME_{}'.format(reffrm.upper()), 0, 1)[0] sclk_id = sp.gipool('CK_{}_{}'.format(reffrm_id, 'SCLK'), 0, 1)[0] ### Set start DP-SCLK of window for this old FK (outer loop) ### - Set to zero for first window ### - Covnert ET to DP-SCLK for subsequent windows if last_et is None: et_lo = sp.sct2e(sclk_id, 0.) else: et_lo = last_et ### Load old FK, get RELATIVE frame name, get time-invariant ### matrix, and unload old FK sp.furnsh(fk) relative_reffrm = sp.gcpool( 'TKFRAME_{}_{}'.format(reffrm_id, 'RELATIVE'), 0, 1, 99)[0] sp.unload(fk) ### Get ETs at which to do the tests: ### - 10s after start of window ### - 10s before end of window, or 1e6s after start if last window if stop_et < -1e30: et_test_lo = et_lo + 10. et_test_hi = et_lo + 1e6 else: et_delta = min([10., (stop_et - et_lo) / 3.]) et_test_lo = et_lo + et_delta et_test_hi = stop_et - et_delta ### Save the relative reffrm, the reffrm, the window, and an empty ### dict for this reffrm under this FK dt[fk][reffrm] = (relative_reffrm, et_test_lo, et_test_hi, dict()) ### For next pass last_et = stop_et ### Clear all kernels, and test sp.kclear() assert 0 == sp.ktotal('all') ### Load base kernels including new FK and new CK for kernel in kernels + [output_ck]: sp.furnsh(kernel) ### Loop over old FKs, reffrms, and ETs for fk in dt: for reffrm in dt[fk]: ### Retrieve relative reffrm, ETs and quat dict relative_reffrm, et_test_lo, et_test_hi, dtquat = dt[fk][reffrm] for et in ( et_test_lo, et_test_hi, ): ### Lookup CK-based matrix, convrt to and save quat at each ET dtquat[et] = sp.m2q(sp.pxform(relative_reffrm, reffrm, et)) ### Loop over the old FKs again for fk in dt: ### Clear all kernels, and test sp.kclear() assert 0 == sp.ktotal('all') ### Load only the old FK sp.furnsh(fk) ### Loop over reffrms, and ETs for reffrm in dt[fk]: relative_reffrm, et_test_lo, et_test_hi, dtquat = dt[fk][reffrm] for et in ( et_test_lo, et_test_hi, ): ### Calculate norm of difference of CK-based and FK-based quats quat_error = round( sp.vnorm(dtquat[et] - sp.m2q(sp.pxform(relative_reffrm, reffrm, et))), 16) ### Output that norm as an error for each case, which norm ### should be zero print( dict(fk=fk, quat_error=quat_error, relative_reffrm=relative_reffrm, reffrm=reffrm, et='{:015.4f}'.format(et)))
### SPICE names of Clock, minute hand, hour hand sClock, sMinute, sHour = sNames = "CLOCK MINUTE HOUR".split() ### SPICE works in seconds; get seconds per minute, per hour, per day spm = sp.convrt(1.0, 'minutes', 'seconds') sph = sp.convrt(1.0, 'hours', 'seconds') hpd = sp.convrt(1.0, 'days', 'hours') spd = sp.spd() ### Other constants: 2*PI; degrees/radian twopi = sp.twopi() dpr = sp.dpr() ### Get start time (TDB) and SPK filename from kernel pool et0 = sp.gdpool('ET0', 0, 1)[0] fnClockSpk = sp.gcpool('CLOCKSPK', 0, 1, 99)[0] ### Make clock SPK if it does not exist if not os.path.exists(fnClockSpk): ### Orbital period formula: ### ### T = 2 PI (a*3 / mu))**(1/2) ### ### where ### ### T = orbital period ### a = length of semi-major axis ### mu = GM, standard gravitational parameter ### => G is the gravitational constant ### => M is the mass of the more massive body (CLOCK, here)
def gen_frame_dict(mk, report=False): # # Frame names are as follows: # r'FRAME_-?[0-9]*_NAME' # frame_dict = {} spiceypy.furnsh(mk) start = 1 n_items = 9999 template = 'FRAME_*_NAME' try: cvals = spiceypy.gnpool(template, start, n_items) if report: print(f'Number of reference frames defined: {len(cvals)}') except SpiceyError: print('No frames definitions present') return # # Okay, now we know something about the kernel pool # variables of interest to us. Let's find out more... # for cval in cvals: # # We check the type of variable: # C (character) or N (numeric), of each pool # variable name in the cvals array. It has to # be a character # start = 0 n_items = 20 [dim, type] = spiceypy.dtpool(cval) if type == 'C': cvars = spiceypy.gcpool(cval, start, n_items) # # The variable (list) should be unique # if len(cvars) > 1: spiceypy.kclear() raise Exception(f'Variable {cval} is incorrect') # # We build the frames dictionary # frmclass = spiceypy.gipool(cval.replace('NAME', 'CLASS'), start, n_items) frmid = spiceypy.gipool(cval.replace('NAME', 'CLASS_ID'), start, n_items) frmcentr = spiceypy.gipool(cval.replace('NAME', 'CENTER'), start, n_items) if frmclass[0] == 4: try: varname = cval.replace('FRAME','TKFRAME').replace('NAME', 'RELATIVE') frmrelat = spiceypy.gcpool(varname, start, n_items) except: frmrelat = ['ERROR'] else: frmrelat = ['N/A'] frame_dict[cvars[0]] = { 'name': cvars[0], 'class':frmclass[0], 'id': frmid[0], 'center': frmcentr[0], 'relative': frmrelat[0] } if report: print(f' CLASS: {frmclass[0]} NAME: {cvars[0]} ') else: spiceypy.kclear() raise Exception(f'Variable {cval} is incorrect') spiceypy.kclear() return frame_dict