def __init__(self, *args, **kwargs): """ Takes a set of input observations and fits the orbital elements. These can then be used to compute the position and error ellipse for the object on an arbitrary date. Requires: observatories.dat and binEphem.423. keyword arguments: obsfile -- file containing observation data, either in MPC format or as JD HH:MM:SS.SS +DD:MM:SS.SS ERROR OBSCODE or as YYYY MM DD.DDDDD HH:MM:SS.SS +DD:MM:SS.SS ERROR OBSCODE where the error is the astrometric error on each measurement in arcsec (default 0.2) and OBSCODE is the observatory code in observatories.dat The number of digits in each field is unrestricted, but ra and dec must not contain spaces. The following options should be used only if obsfile is None. Then they must all be used. If obsfile is supplied then these arguments are ignored. dates -- list of observation dates, either in JD or YYYY MM DD.DDDDD format ra -- list of RA in HH:MM:SS.SS format. dec -- list of DEC in +DD:MM:SS.SS format obscode -- list of observatory codes err -- measurement error in arcsec Methods: get_elements() -- returns aei orbital elements and their errors get_elements_abg() -- returns abg orbital elements and their errors barycentric_distance() -- barycentric distance and error perihelion() -- perihelion and error aphelion() -- aphelion and error cov_pq() -- covariance matrix for perihelion, aphelion plotEllipse() -- generates an error ellipse for a given covariance matrix predict_pos() -- predicted ra, dec, and error ellipse on a given date ellipticalBody() -- returns an EllipticalBody object with these orbital parameters, suitable for use by pyEphem """ if 'file' in kwargs.keys(): # observations supplied in a file obsfile = kwargs['file'] with open(obsfile, 'r') as fobs: self.nobs = 0 # determine the number of observations for line in fobs: if line[0] != '#': self.nobs += 1 fobs.seek(0) # rewind to the beginning self.obsarray = orbfit.OBSERVATION_ARRAY( self.nobs) # create empty array of observations iobs = 0 for line in fobs: if line[0] != '#': thisobs = orbfit.OBSERVATION() orbfit.scan_observation(line, thisobs) orbfit.add_to_obsarray(self.obsarray, iobs, thisobs) iobs += 1 if 'err' in kwargs.keys( ): # change: obserr need not be constant obserr = kwargs['err'] elif len(args): # observations supplied in a Catalog object self.nobs = len(args[0]) self.obsarray = orbfit.OBSERVATION_ARRAY(self.nobs) for iobs, pt in enumerate(args[0]): thisobs = orbfit.OBSERVATION() if pt.err is None: pt.err = 0.15 # This is to avoid silent crash. if pt.obscode is None: pt.obscode = 807 # Ditto. obsline = str(ephem.julian_date(pt.date)) + ' ' + str( pt.ra) + ' ' + str(pt.dec) + ' ' + str(pt.err) + ' ' + str( pt.obscode) orbfit.scan_observation(obsline, thisobs) orbfit.add_to_obsarray(self.obsarray, iobs, thisobs) else: # observations specified in input lists required_keys = ['dates', 'ra', 'dec', 'obscode'] for k in required_keys: if k not in kwargs.keys(): raise KeyError('keyword ' + k + ' is missing') obsdate = kwargs['dates'] ra = kwargs['ra'] dec = kwargs['dec'] obscode = kwargs['obscode'] self.nobs = len(obsdate) if 'err' in kwargs.keys(): # change: obserr need not be constant obserr = kwargs['err'] if not np.iterable(obserr): obserr = [obserr for i in range(self.nobs)] else: obserr = [0.15 for i in range(self.nobs) ] # obervation astrometric error defaults to 0.15" assert self.nobs == len(ra) and self.nobs == len( dec) and self.nobs == len(obscode) and self.nobs == len(obserr) self.obsarray = orbfit.OBSERVATION_ARRAY( self.nobs) # create empty array of observations for iobs in range(self.nobs): # fill the OBSERVATION_ARRAY thisobs = orbfit.OBSERVATION() obsline = str(ephem.julian_date(obsdate[iobs])) + ' ' + str( ra[iobs]) + ' ' + str(dec[iobs]) + ' ' + str( obserr[iobs]) + ' ' + str(obscode[iobs]) orbfit.scan_observation(obsline, thisobs) orbfit.add_to_obsarray(self.obsarray, iobs, thisobs) # At this point we have filled obsarray with the observations. Now fit the orbit. # orbfit.set_ephem_file('/Users/gerdes/TNO/pyOrbfit/binEphem.430') # pick up the correct ephemeris and observatories file. # orbfit.set_observatory_file('/Users/gerdes/TNO/pyOrbfit/observatories.dat') # Will need to handle pathnames more elegantly. self.orbit_abg = orbfit.PBASIS() self.orbit_xyz = orbfit.XVBASIS() self.orbit_aei = orbfit.ORBIT() self.cov_abg = orbfit.dmatrix( 1, 6, 1, 6 ) # need to make this one globally visible since it's needed by predict_pos() cov_xyz = orbfit.dmatrix(1, 6, 1, 6) cov_aei = orbfit.dmatrix(1, 6, 1, 6) derivs = orbfit.dmatrix(1, 6, 1, 6) # fittype is 6 if normal fit, 5 if energy constraint was used. self.fittype, self.chisq, self.ndof = orbfit.fit_observations( self.obsarray, self.nobs, self.orbit_abg, self.cov_abg, None) # abg orbit elements # Transform the orbit basis and get the deriv. matrix orbfit.pbasis_to_bary(self.orbit_abg, self.orbit_xyz, derivs) orbfit.orbitElements(self.orbit_xyz, self.orbit_aei) # aei orbit elements # self.orbit_xyz.jd0 = orbfit.cvar.jd0 # time zeropoint # covariance matrices orbfit.covar_map(self.cov_abg, derivs, cov_xyz, 6, 6) # map the covariance matrix to xyz basis orbfit.aei_derivs( self.orbit_xyz, derivs) # Get partial derivative matrix from xyz to aei orbfit.covar_map(cov_xyz, derivs, cov_aei, 6, 6) # map covariance matrix from xyz to aei # This is a hack to create matrices python can actually use. We have trouble wrapping double pointers. c = orbfit.doubleArray(36) orbfit.flatten_cov(self.cov_abg, 6, c) self.covar_abg = np.array([c[i] for i in range(36) ]).reshape(6, 6) # a bona-fide numpy array. c = orbfit.doubleArray( 36) # It's necessary to reallocate the space in memory orbfit.flatten_cov(cov_xyz, 6, c) self.covar_xyz = np.array([c[i] for i in range(36)]).reshape(6, 6) c = orbfit.doubleArray(36) orbfit.flatten_cov(cov_aei, 6, c) self.covar_aei = np.array([c[i] for i in range(36)]).reshape(6, 6) self.elements, self.elements_errs = self.get_elements() self.jd0 = orbfit.cvar.jd0 self.lat0 = orbfit.cvar.lat0 self.lon0 = orbfit.cvar.lon0 self.xBary = orbfit.cvar.xBary self.yBary = orbfit.cvar.yBary self.zBary = orbfit.cvar.zBary
def __init__(self, *args, **kwargs): """ Takes a set of input observations and fits the orbital elements. These can then be used to compute the position and error ellipse for the object on an arbitrary date. Requires: observatories.dat and binEphem.423. keyword arguments: obsfile -- file containing observation data, either in MPC format or as JD HH:MM:SS.SS +DD:MM:SS.SS ERROR OBSCODE or as YYYY MM DD.DDDDD HH:MM:SS.SS +DD:MM:SS.SS ERROR OBSCODE where the error is the astrometric error on each measurement in arcsec (default 0.2) and OBSCODE is the observatory code in observatories.dat The number of digits in each field is unrestricted, but ra and dec must not contain spaces. The following options should be used only if obsfile is None. Then they must all be used. If obsfile is supplied then these arguments are ignored. dates -- list of observation dates, either in JD or YYYY MM DD.DDDDD format ra -- list of RA in HH:MM:SS.SS format. dec -- list of DEC in +DD:MM:SS.SS format obscode -- list of observatory codes err -- measurement error in arcsec Methods: get_elements() -- returns aei orbital elements and their errors get_elements_abg() -- returns abg orbital elements and their errors barycentric_distance() -- barycentric distance and error perihelion() -- perihelion and error aphelion() -- aphelion and error cov_pq() -- covariance matrix for perihelion, aphelion plotEllipse() -- generates an error ellipse for a given covariance matrix predict_pos() -- predicted ra, dec, and error ellipse on a given date ellipticalBody() -- returns an EllipticalBody object with these orbital parameters, suitable for use by pyEphem """ if "file" in kwargs.keys(): # observations supplied in a file obsfile = kwargs["file"] with open(obsfile, "r") as fobs: self.nobs = 0 # determine the number of observations for line in fobs: if line[0] != "#": self.nobs += 1 fobs.seek(0) # rewind to the beginning self.obsarray = orbfit.OBSERVATION_ARRAY(self.nobs) # create empty array of observations iobs = 0 for line in fobs: if line[0] != "#": thisobs = orbfit.OBSERVATION() orbfit.scan_observation(line, thisobs) orbfit.add_to_obsarray(self.obsarray, iobs, thisobs) iobs += 1 elif len(args): # observations supplied in a Catalog object self.nobs = len(args[0]) self.obsarray = orbfit.OBSERVATION_ARRAY(self.nobs) for iobs, pt in enumerate(args[0]): thisobs = orbfit.OBSERVATION() if pt.err is None: pt.err = 0.15 # This is to avoid silent crash. if pt.obscode is None: pt.obscode = 807 # Ditto. obsline = ( str(ephem.julian_date(pt.date)) + " " + str(pt.ra) + " " + str(pt.dec) + " " + str(pt.err) + " " + str(pt.obscode) ) orbfit.scan_observation(obsline, thisobs) orbfit.add_to_obsarray(self.obsarray, iobs, thisobs) else: # observations specified in input lists required_keys = ["dates", "ra", "dec", "obscode"] for k in required_keys: if k not in kwargs.keys(): raise KeyError("keyword " + k + " is missing") obsdate = kwargs["dates"] ra = kwargs["ra"] dec = kwargs["dec"] obscode = kwargs["obscode"] self.nobs = len(obsdate) if "err" in kwargs.keys(): # change: obserr need not be constant obserr = kwargs["err"] if not np.iterable(obserr): obserr = [obserr for i in range(self.nobs)] else: obserr = [0.15 for i in range(self.nobs)] # obervation astrometric error defaults to 0.15" assert ( self.nobs == len(ra) and self.nobs == len(dec) and self.nobs == len(obscode) and self.nobs == len(obserr) ) self.obsarray = orbfit.OBSERVATION_ARRAY(self.nobs) # create empty array of observations for iobs in range(self.nobs): # fill the OBSERVATION_ARRAY thisobs = orbfit.OBSERVATION() obsline = ( str(ephem.julian_date(obsdate[iobs])) + " " + str(ra[iobs]) + " " + str(dec[iobs]) + " " + str(obserr[iobs]) + " " + str(obscode[iobs]) ) orbfit.scan_observation(obsline, thisobs) orbfit.add_to_obsarray(self.obsarray, iobs, thisobs) # At this point we have filled obsarray with the observations. Now fit the orbit. # orbfit.set_ephem_file('/Users/gerdes/TNO/pyOrbfit/binEphem.430') # pick up the correct ephemeris and observatories file. # orbfit.set_observatory_file('/Users/gerdes/TNO/pyOrbfit/observatories.dat') # Will need to handle pathnames more elegantly. self.orbit_abg = orbfit.PBASIS() self.orbit_xyz = orbfit.XVBASIS() self.orbit_aei = orbfit.ORBIT() self.cov_abg = orbfit.dmatrix( 1, 6, 1, 6 ) # need to make this one globally visible since it's needed by predict_pos() cov_xyz = orbfit.dmatrix(1, 6, 1, 6) cov_aei = orbfit.dmatrix(1, 6, 1, 6) derivs = orbfit.dmatrix(1, 6, 1, 6) # fittype is 6 if normal fit, 5 if energy constraint was used. self.fittype, self.chisq, self.ndof = orbfit.fit_observations( self.obsarray, self.nobs, self.orbit_abg, self.cov_abg, None ) # abg orbit elements # Transform the orbit basis and get the deriv. matrix orbfit.pbasis_to_bary(self.orbit_abg, self.orbit_xyz, derivs) orbfit.orbitElements(self.orbit_xyz, self.orbit_aei) # aei orbit elements # self.orbit_xyz.jd0 = orbfit.cvar.jd0 # time zeropoint # covariance matrices orbfit.covar_map(self.cov_abg, derivs, cov_xyz, 6, 6) # map the covariance matrix to xyz basis orbfit.aei_derivs(self.orbit_xyz, derivs) # Get partial derivative matrix from xyz to aei orbfit.covar_map(cov_xyz, derivs, cov_aei, 6, 6) # map covariance matrix from xyz to aei # This is a hack to create matrices python can actually use. We have trouble wrapping double pointers. c = orbfit.doubleArray(36) orbfit.flatten_cov(self.cov_abg, 6, c) self.covar_abg = np.array([c[i] for i in range(36)]).reshape(6, 6) # a bona-fide numpy array. c = orbfit.doubleArray(36) # It's necessary to reallocate the space in memory orbfit.flatten_cov(cov_xyz, 6, c) self.covar_xyz = np.array([c[i] for i in range(36)]).reshape(6, 6) c = orbfit.doubleArray(36) orbfit.flatten_cov(cov_aei, 6, c) self.covar_aei = np.array([c[i] for i in range(36)]).reshape(6, 6) self.elements, self.elements_errs = self.get_elements() self.jd0 = orbfit.cvar.jd0 self.lat0 = orbfit.cvar.lat0 self.lon0 = orbfit.cvar.lon0 self.xBary = orbfit.cvar.xBary self.yBary = orbfit.cvar.yBary self.zBary = orbfit.cvar.zBary
def orbfit_abg(abgfile): with open(abgfile) as f: lines = [line for line in f if line[0] != '#'] elem_abg = [float(e) for e in lines[0].split()] cov_arr = np.array([[float(de) for de in lines[i].split()] for i in range(1, 7)], dtype=np.float64) last = lines[7].split() lat0 = float(last[0]) lon0 = float(last[1]) xBary = float(last[2]) yBary = float(last[3]) zBary = float(last[4]) jd0 = float(last[5]) abginfo = { 'elem': elem_abg, 'cov': cov_arr, 'lat0': lat0, 'lon0': lon0, 'xBary': xBary, 'yBary': yBary, 'zBary': zBary, 'jd0': jd0 } jd0 = abginfo['jd0'] # zeropoint of time scale # Create space for various useful matrices cov_abg = orbfit.dmatrix(1, 6, 1, 6) p_in = orbfit.PBASIS() orbit_xyz = orbfit.XVBASIS() orbit_aei = orbfit.ORBIT() p_in.a = abginfo['elem'][0] p_in.adot = abginfo['elem'][1] p_in.b = abginfo['elem'][2] p_in.bdot = abginfo['elem'][3] p_in.g = abginfo['elem'][4] p_in.gdot = abginfo['elem'][5] # Here follows kludginess to put the covariance matrix into C double pointers c = orbfit.doubleArray(36) cc = abginfo['cov'].reshape(36, order='F') for i in range(len(cc)): c[i] = cc[i] orbfit.unflatten_cov(c, 6, cov_abg) abginfo['pbasis'] = p_in abginfo['cov_abg'] = cov_abg cov_xyz = orbfit.dmatrix(1, 6, 1, 6) cov_aei = orbfit.dmatrix(1, 6, 1, 6) derivs = orbfit.dmatrix(1, 6, 1, 6) # Transform the orbit basis and get the deriv. matrix orbfit.cvar.jd0 = abginfo['jd0'] orbfit.cvar.xBary = abginfo['xBary'] orbfit.cvar.yBary = abginfo['yBary'] orbfit.cvar.zBary = abginfo['zBary'] orbfit.cvar.lon0 = abginfo['lon0'] * np.pi / 180 orbfit.cvar.lat0 = abginfo['lat0'] * np.pi / 180 #CHANGE HERE orbfit.pbasis_to_bary(p_in, orbit_xyz, derivs) orbfit.orbitElements(orbit_xyz, orbit_aei) # aei orbit elements abginfo['orbit_aei'] = orbit_aei abginfo['cov_aei'] = cov_aei abginfo['elems_aei'] = { 'a': orbit_aei.a, 'e': orbit_aei.e, 'i': orbit_aei.i, 'lan': orbit_aei.lan, 'aop': orbit_aei.aop, 'top': orbit_aei.T } return abginfo
def orbfit_abg(abgfile): with open(abgfile) as f: lines = [line for line in f if line[0] != "#"] elem_abg = [float(e) for e in lines[0].split()] cov_arr = np.array([[float(de) for de in lines[i].split()] for i in range(1, 7)], dtype=np.float64) last = lines[7].split() lat0 = float(last[0]) lon0 = float(last[1]) xBary = float(last[2]) yBary = float(last[3]) zBary = float(last[4]) jd0 = float(last[5]) abginfo = { "elem": elem_abg, "cov": cov_arr, "lat0": lat0, "lon0": lon0, "xBary": xBary, "yBary": yBary, "zBary": zBary, "jd0": jd0, } jd0 = abginfo["jd0"] # zeropoint of time scale # Create space for various useful matrices cov_abg = orbfit.dmatrix(1, 6, 1, 6) p_in = orbfit.PBASIS() orbit_xyz = orbfit.XVBASIS() orbit_aei = orbfit.ORBIT() p_in.a = abginfo["elem"][0] p_in.adot = abginfo["elem"][1] p_in.b = abginfo["elem"][2] p_in.bdot = abginfo["elem"][3] p_in.g = abginfo["elem"][4] p_in.gdot = abginfo["elem"][5] # Here follows kludginess to put the covariance matrix into C double pointers c = orbfit.doubleArray(36) cc = abginfo["cov"].reshape(36, order="F") for i in range(len(cc)): c[i] = cc[i] orbfit.unflatten_cov(c, 6, cov_abg) abginfo["pbasis"] = p_in abginfo["cov_abg"] = cov_abg cov_xyz = orbfit.dmatrix(1, 6, 1, 6) cov_aei = orbfit.dmatrix(1, 6, 1, 6) derivs = orbfit.dmatrix(1, 6, 1, 6) # Transform the orbit basis and get the deriv. matrix orbfit.cvar.jd0 = abginfo["jd0"] orbfit.cvar.xBary = abginfo["xBary"] orbfit.cvar.yBary = abginfo["yBary"] orbfit.cvar.zBary = abginfo["zBary"] orbfit.cvar.lon0 = abginfo["lon0"] * np.pi / 180 orbfit.cvar.lat0 = abginfo["lat0"] * np.pi / 180 orbfit.pbasis_to_bary(p_in, orbit_xyz, derivs) orbfit.orbitElements(orbit_xyz, orbit_aei) # aei orbit elements abginfo["orbit_aei"] = orbit_aei abginfo["cov_aei"] = cov_aei abginfo["elems_aei"] = { "a": orbit_aei.a, "e": orbit_aei.e, "i": orbit_aei.i, "lan": orbit_aei.lan, "aop": orbit_aei.aop, "top": orbit_aei.T, } return abginfo