def predict_pos(self, date, obscode=807): """ Computes ra, dec, and error ellipse at the date(s) and observatory specified. Date is an ephem.date object. Returns a corresponding dictionary with keywords 'ra' -- ra in ICRS coords, returned as an ephem.Angle object 'dec' -- dec in ICRS coords, ditto 'err' -- error ellipse (see below) 'elong' -- solar elongation in degrees 'opp' -- opposition angle in degrees where the error ellipse, indexed by 'err', is itself a dictionary with keywords: 'a' -- semimajor axis in arcsec 'b' -- semiminor axis in arcsec 'PA' -- position angle in degrees, north through east """ p_in = self.orbit_abg jd0 = orbfit.cvar.jd0 # zeropoint of time scale # Create space for various useful matrices sigxy = orbfit.dmatrix(1, 2, 1, 2) derivs = orbfit.dmatrix(1, 2, 1, 2) covecl = orbfit.dmatrix(1, 2, 1, 2) coveq = orbfit.dmatrix(1, 2, 1, 2) # Fill the OBSERVATION structure futobs = orbfit.OBSERVATION() futobs.obscode = obscode futobs.obstime = (ephem.julian_date(date) - jd0) * orbfit.DAY futobs.xe = -999 # force evaluation of earth3D dx = orbfit.dvector(1, 6) dy = orbfit.dvector(1, 6) # Sometimes hangs in next line... why? thetax, thetay = orbfit.kbo2d(p_in, futobs, dx, dy) # Predicted position, in abg basis: orbfit.predict_posn(p_in, self.cov_abg, futobs, sigxy) solar_elongation = orbfit.elongation( futobs) / orbfit.DTOR # solar elongation in degrees opposition_angle = orbfit.opposition_angle( futobs) / orbfit.DTOR # opposition angle in degrees lat_ec, lon_ec = orbfit.proj_to_ec( futobs.thetax, futobs.thetay, orbfit.cvar.lat0, orbfit.cvar.lon0, derivs) # project to ecliptic coords orbfit.covar_map(sigxy, derivs, covecl, 2, 2) # map the covariance ra_eq, dec_eq = orbfit.ec_to_eq( lat_ec, lon_ec, derivs) # transform to ICRS to compute ra, dec if ra_eq < 0: ra_eq += 2 * np.pi # convert angle to (0,2pi) range orbfit.covar_map(covecl, derivs, coveq, 2, 2) # map the covariance # Compute ICRS error ellipse c = orbfit.doubleArray(4) # stoopid workaround for double pointers... orbfit.flatten_cov(coveq, 2, c) covar_eq = np.array([c[i] for i in range(4)]).reshape(2, 2) xx = covar_eq[0][0] * np.cos(dec_eq)**2 xy = covar_eq[0][1] * np.cos(dec_eq) yy = covar_eq[1][1] pos_angle = 0.5 * np.arctan2(2. * xy, (xx - yy)) * 180. / np.pi pos_angle = 90 - pos_angle # convert to astronomy convention of measuring position angle North through East bovasqrd = (xx + yy - np.sqrt((xx - yy)**2 + (2 * xy)**2)) / (xx + yy + np.sqrt((xx - yy)**2 + (2 * xy)**2)) det = xx * yy - xy * xy a = (det / bovasqrd)**( 1 / 4 ) / orbfit.ARCSEC # semimajor, minor axes of error ellipse, in arcsec b = (det * bovasqrd)**(1 / 4) / orbfit.ARCSEC err_ellipse = dict(a=a, b=b, PA=pos_angle) # store as a dictionary pos = dict(ra=ephem.hours(ra_eq), dec=ephem.degrees(dec_eq), err=err_ellipse, elong=solar_elongation, opp=opposition_angle) return pos
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 predict_from_abg(abginfo, date, obscode=807): p_in = abginfo['pbasis'] cov_abg = abginfo['cov_abg'] 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 sigxy = orbfit.dmatrix(1, 2, 1, 2) derivs = orbfit.dmatrix(1, 2, 1, 2) covecl = orbfit.dmatrix(1, 2, 1, 2) coveq = orbfit.dmatrix(1, 2, 1, 2) # Fill the OBSERVATION structure futobs = orbfit.OBSERVATION() futobs.obscode = obscode futobs.obstime = (ephem.julian_date(date) - orbfit.cvar.jd0) * orbfit.DAY futobs.xe = -999 # force evaluation of earth3D dx = orbfit.dvector(1, 6) dy = orbfit.dvector(1, 6) thetax, thetay = orbfit.kbo2d(p_in, futobs, dx, dy) # Predicted position, in abg basis: orbfit.predict_posn(p_in, cov_abg, futobs, sigxy) solar_elongation = orbfit.elongation( futobs) / orbfit.DTOR # solar elongation in degrees opposition_angle = orbfit.opposition_angle( futobs) / orbfit.DTOR # opposition angle in degrees lat_ec, lon_ec = orbfit.proj_to_ec(futobs.thetax, futobs.thetay, orbfit.cvar.lat0, orbfit.cvar.lon0, derivs) # project to ecliptic coords orbfit.covar_map(sigxy, derivs, covecl, 2, 2) # map the covariance ra_eq, dec_eq = orbfit.ec_to_eq( lat_ec, lon_ec, derivs) # transform to ICRS to compute ra, dec eq = ephem.Equatorial(ephem.Ecliptic(lat_ec, lon_ec)) ra_eq2 = eq.ra * 180 / np.pi dec_eq2 = eq.dec * 180 / np.pi if ra_eq < 0: ra_eq += 2 * np.pi # convert angle to (0,2pi) range # print ra_eq*180/np.pi, dec_eq*180/np.pi, ra_eq2, dec_eq2, ra_eq*180/np.pi-ra_eq2, dec_eq*180/np.pi-dec_eq2 orbfit.covar_map(covecl, derivs, coveq, 2, 2) # map the covariance # print ephem.hours(ra_eq), ephem.degrees(dec_eq) # Compute ICRS error ellipse c2d = orbfit.doubleArray(4) # stoopid workaround for double pointers... orbfit.flatten_cov(coveq, 2, c2d) covar_eq = np.array([c2d[i] for i in range(4)]).reshape(2, 2) xx = covar_eq[0][0] * np.cos(dec_eq)**2 xy = covar_eq[0][1] * np.cos(dec_eq) yy = covar_eq[1][1] pos_angle = 0.5 * np.arctan2(2. * xy, (xx - yy)) * 180. / np.pi pos_angle = 90 - pos_angle # convert to astronomy convention of measuring position angle North through East bovasqrd = (xx + yy - np.sqrt((xx - yy)**2 + (2 * xy)**2)) / (xx + yy + np.sqrt((xx - yy)**2 + (2 * xy)**2)) det = xx * yy - xy * xy a = (det / bovasqrd)**( 1 / 4) / orbfit.ARCSEC # semimajor, minor axes of error ellipse, in arcsec b = (det * bovasqrd)**(1 / 4) / orbfit.ARCSEC err_ellipse = dict(a=a, b=b, PA=pos_angle) # store as a dictionary pos = dict(ra=ephem.hours(ra_eq), dec=ephem.degrees(dec_eq), err=err_ellipse, elong=solar_elongation, opp=opposition_angle) return pos
def predict_pos(self, date, obscode=807): """ Computes ra, dec, and error ellipse at the date(s) and observatory specified. Date is an ephem.date object. Returns a corresponding dictionary with keywords 'ra' -- ra in ICRS coords, returned as an ephem.Angle object 'dec' -- dec in ICRS coords, ditto 'err' -- error ellipse (see below) 'elong' -- solar elongation in degrees 'opp' -- opposition angle in degrees where the error ellipse, indexed by 'err', is itself a dictionary with keywords: 'a' -- semimajor axis in arcsec 'b' -- semiminor axis in arcsec 'PA' -- position angle in degrees, north through east """ p_in = self.orbit_abg jd0 = orbfit.cvar.jd0 # zeropoint of time scale # Create space for various useful matrices sigxy = orbfit.dmatrix(1, 2, 1, 2) derivs = orbfit.dmatrix(1, 2, 1, 2) covecl = orbfit.dmatrix(1, 2, 1, 2) coveq = orbfit.dmatrix(1, 2, 1, 2) # Fill the OBSERVATION structure futobs = orbfit.OBSERVATION() futobs.obscode = obscode futobs.obstime = (ephem.julian_date(date) - jd0) * orbfit.DAY futobs.xe = -999 # force evaluation of earth3D dx = orbfit.dvector(1, 6) dy = orbfit.dvector(1, 6) thetax, thetay = orbfit.kbo2d(p_in, futobs, dx, dy) # Predicted position, in abg basis: orbfit.predict_posn(p_in, self.cov_abg, futobs, sigxy) solar_elongation = orbfit.elongation(futobs) / orbfit.DTOR # solar elongation in degrees opposition_angle = orbfit.opposition_angle(futobs) / orbfit.DTOR # opposition angle in degrees lat_ec, lon_ec = orbfit.proj_to_ec( futobs.thetax, futobs.thetay, orbfit.cvar.lat0, orbfit.cvar.lon0, derivs ) # project to ecliptic coords orbfit.covar_map(sigxy, derivs, covecl, 2, 2) # map the covariance ra_eq, dec_eq = orbfit.ec_to_eq(lat_ec, lon_ec, derivs) # transform to ICRS to compute ra, dec if ra_eq < 0: ra_eq += 2 * np.pi # convert angle to (0,2pi) range orbfit.covar_map(covecl, derivs, coveq, 2, 2) # map the covariance # Compute ICRS error ellipse c = orbfit.doubleArray(4) # stoopid workaround for double pointers... orbfit.flatten_cov(coveq, 2, c) covar_eq = np.array([c[i] for i in range(4)]).reshape(2, 2) xx = covar_eq[0][0] * np.cos(dec_eq) ** 2 xy = covar_eq[0][1] * np.cos(dec_eq) yy = covar_eq[1][1] pos_angle = 0.5 * np.arctan2(2.0 * xy, (xx - yy)) * 180.0 / np.pi pos_angle = 90 - pos_angle # convert to astronomy convention of measuring position angle North through East bovasqrd = (xx + yy - np.sqrt((xx - yy) ** 2 + (2 * xy) ** 2)) / ( xx + yy + np.sqrt((xx - yy) ** 2 + (2 * xy) ** 2) ) det = xx * yy - xy * xy a = (det / bovasqrd) ** (1 / 4) / orbfit.ARCSEC # semimajor, minor axes of error ellipse, in arcsec b = (det * bovasqrd) ** (1 / 4) / orbfit.ARCSEC err_ellipse = dict(a=a, b=b, PA=pos_angle) # store as a dictionary pos = dict( ra=ephem.hours(ra_eq), dec=ephem.degrees(dec_eq), err=err_ellipse, elong=solar_elongation, opp=opposition_angle, ) return pos
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 predict_from_abg(abginfo, date, obscode=807): p_in = abginfo["pbasis"] cov_abg = abginfo["cov_abg"] 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 sigxy = orbfit.dmatrix(1, 2, 1, 2) derivs = orbfit.dmatrix(1, 2, 1, 2) covecl = orbfit.dmatrix(1, 2, 1, 2) coveq = orbfit.dmatrix(1, 2, 1, 2) # Fill the OBSERVATION structure futobs = orbfit.OBSERVATION() futobs.obscode = obscode futobs.obstime = (ephem.julian_date(date) - orbfit.cvar.jd0) * orbfit.DAY futobs.xe = -999 # force evaluation of earth3D dx = orbfit.dvector(1, 6) dy = orbfit.dvector(1, 6) thetax, thetay = orbfit.kbo2d(p_in, futobs, dx, dy) # Predicted position, in abg basis: orbfit.predict_posn(p_in, cov_abg, futobs, sigxy) solar_elongation = orbfit.elongation(futobs) / orbfit.DTOR # solar elongation in degrees opposition_angle = orbfit.opposition_angle(futobs) / orbfit.DTOR # opposition angle in degrees lat_ec, lon_ec = orbfit.proj_to_ec( futobs.thetax, futobs.thetay, orbfit.cvar.lat0, orbfit.cvar.lon0, derivs ) # project to ecliptic coords orbfit.covar_map(sigxy, derivs, covecl, 2, 2) # map the covariance ra_eq, dec_eq = orbfit.ec_to_eq(lat_ec, lon_ec, derivs) # transform to ICRS to compute ra, dec eq = ephem.Equatorial(ephem.Ecliptic(lat_ec, lon_ec)) ra_eq2 = eq.ra * 180 / np.pi dec_eq2 = eq.dec * 180 / np.pi if ra_eq < 0: ra_eq += 2 * np.pi # convert angle to (0,2pi) range # print ra_eq*180/np.pi, dec_eq*180/np.pi, ra_eq2, dec_eq2, ra_eq*180/np.pi-ra_eq2, dec_eq*180/np.pi-dec_eq2 orbfit.covar_map(covecl, derivs, coveq, 2, 2) # map the covariance # print ephem.hours(ra_eq), ephem.degrees(dec_eq) # Compute ICRS error ellipse c2d = orbfit.doubleArray(4) # stoopid workaround for double pointers... orbfit.flatten_cov(coveq, 2, c2d) covar_eq = np.array([c2d[i] for i in range(4)]).reshape(2, 2) xx = covar_eq[0][0] * np.cos(dec_eq) ** 2 xy = covar_eq[0][1] * np.cos(dec_eq) yy = covar_eq[1][1] pos_angle = 0.5 * np.arctan2(2.0 * xy, (xx - yy)) * 180.0 / np.pi pos_angle = 90 - pos_angle # convert to astronomy convention of measuring position angle North through East bovasqrd = (xx + yy - np.sqrt((xx - yy) ** 2 + (2 * xy) ** 2)) / (xx + yy + np.sqrt((xx - yy) ** 2 + (2 * xy) ** 2)) det = xx * yy - xy * xy a = (det / bovasqrd) ** (1 / 4) / orbfit.ARCSEC # semimajor, minor axes of error ellipse, in arcsec b = (det * bovasqrd) ** (1 / 4) / orbfit.ARCSEC err_ellipse = dict(a=a, b=b, PA=pos_angle) # store as a dictionary pos = dict( ra=ephem.hours(ra_eq), dec=ephem.degrees(dec_eq), err=err_ellipse, elong=solar_elongation, opp=opposition_angle ) return pos