def test_comet(): text = (b' CJ95O010 1997 03 29.6333 0.916241 0.994928 130.6448' b' 283.3593 88.9908 20200224 -2.0 4.0 C/1995 O1 (Hale-Bopp)' b' MPC106342\n') ts = load.timescale() t = ts.utc(2020, 5, 31) eph = load('de421.bsp') e = eph['earth'].at(t) for loader in mpc.load_comets_dataframe, mpc.load_comets_dataframe_slow: df = loader(BytesIO(text)) row = df.iloc[0] k = mpc.comet_orbit(row, ts, GM_SUN) p = e.observe(eph['sun'] + k) ra, dec, distance = p.radec() # The file authorities/mpc-hale-bopp in the repository is the # source of these angles. TODO: can we tighten this bound and # drive it to fractions of an arcsecond? ra_want = Angle(hours=(23, 59, 16.6)) dec_want = Angle(degrees=(-84, 46, 58)) assert abs(ra_want.arcseconds() - ra.arcseconds()) < 2.0 assert abs(dec_want.arcseconds() - dec.arcseconds()) < 0.2 assert abs(distance.au - 43.266) < 0.0005 assert k.target == 'C/1995 O1 (Hale-Bopp)'
def comet_info(comet_id): """View a comet info.""" comet = _find_comet(comet_id) if comet is None: abort(404) form = CometFindChartForm() ts = load.timescale(builtin=True) eph = load('de421.bsp') sun, earth = eph['sun'], eph['earth'] c = sun + mpc.comet_orbit(comet, ts, GM_SUN) if not form.date_from.data or not form.date_to.data: today = datetime.today() form.date_from.data = today form.date_to.data = today + timedelta(days=7) if (form.date_from.data is None) or (form.date_to.data is None) or form.date_from.data >= form.date_to.data: t = ts.now() comet_ra_ang, comet_dec_ang, distance = earth.at(t).observe(c).radec() trajectory_b64 = None else: d1 = date(form.date_from.data.year, form.date_from.data.month, form.date_from.data.day) d2 = date(form.date_to.data.year, form.date_to.data.month, form.date_to.data.day) t = ts.now() comet_ra_ang, comet_dec_ang, distance = earth.at(t).observe(c).radec() if d1 != d2: time_delta = d2 - d1 if time_delta.days > 365: d2 = d1 + timedelta(days=365) dt = get_trajectory_time_delta(d1, d2) trajectory = [] while d1 <= d2: t = ts.utc(d1.year, d1.month, d1.day) ra, dec, distance = earth.at(t).observe(c).radec() trajectory.append((ra.radians, dec.radians, d1.strftime('%d.%m.'))) d1 += dt t = ts.utc(d1.year, d1.month, d1.day) trajectory_json = json.dumps(trajectory) trajectory_b64 = base64.b64encode(trajectory_json.encode('utf-8')) else: trajectory_b64 = None comet_ra = comet_ra_ang.radians comet_dec = comet_dec_ang.radians if not common_ra_dec_fsz_from_request(form): form.ra.data = comet_ra form.dec.data = comet_dec chart_control = common_prepare_chart_data(form) return render_template('main/solarsystem/comet_info.html', fchart_form=form, type='info', comet=comet, comet_ra=comet_ra, comet_dec=comet_dec, chart_control=chart_control, trajectory=trajectory_b64)
def comet(self, designation: str) -> CelestialObject: """Look up a comet by its designation, e.g. 1P/Halley""" # NB: mpc.comet_orbit returns an orbit centered on the Sun, so we need to offset it! row = self._comets.loc[designation] return makeObject( type=ObjectType.COMET, name=designation[designation.find("/") + 1:], position=self.sun.position + mpc.comet_orbit(row, self.timescale, GM_SUN), dataFrame=row, )
def get_mpc_positions(designation): row = comets.loc[designation] coords = list() comet = planets['sun'] + mpc.comet_orbit(row, ts, GM_SUN) now = ts.now() x, y, z = comet.at( ts.utc(now.utc.year, now.utc.month, range(now.utc.day - 30, now.utc.day + 30))).ecliptic_xyz().km for xc, yc, zc in zip(x, y, z): coords.append([xc, yc, zc]) return f2i(coords)
def calc_comet(comet_df, obstime, earthcoords, numdays=0, alt_table=False): # Generating a position. cometvec = sun + mpc.comet_orbit(comet_df, ts, GM_SUN) cometpos = earth.at(obstime).observe(cometvec) ra, dec, distance = cometpos.radec() print("RA", ra, " DEC", dec, " Distance", distance) if earthcoords: if len(earthcoords) > 2: elev = earthcoords[2] else: elev = 0 obstopos = Topos(latitude_degrees=earthcoords[0], longitude_degrees=earthcoords[1], elevation_m=elev) print("\nObserver at", obstopos.latitude, "N ", obstopos.longitude, "E ", "Elevation", obstopos.elevation.m, "m") obsvec = earth + obstopos alt, az, distance = \ obsvec.at(obstime).observe(cometvec).apparent().altaz() print("Altitude", alt, " Azumuth", az, distance) alm_twilights = almanac.dark_twilight_day(eph, obstopos) # dawn, dusk = find_twilights(obstime, alm_twilights) # print(WHICH_TWILIGHT, ": Dawn", svt2str(dawn), "Dusk", svt2str(dusk)) if numdays: print("\nRises and sets over", numdays, "days:") datetime1 = obstime.utc_datetime() - timedelta(hours=2) t0 = ts.utc(datetime1) t1 = ts.utc(datetime1 + timedelta(days=numdays)) alm = almanac.risings_and_settings(eph, cometvec, obstopos) t, y = almanac.find_discrete(t0, t1, alm) print_rises_sets(obsvec, cometvec, alm, t0, t1) if alt_table: print() oneday = timedelta(days=1) while True: print_alt_table(obstime, cometvec, obsvec, alm_twilights) numdays -= 1 if numdays <= 0: break # Add a day: there doesn't seem to be a way to do this # while staying within skyview's Time object. obstime = ts.utc(obstime.utc_datetime() + oneday)
def get_comet(name, timestamp): # https://rhodesmill.org/skyfield/example-plots.html#drawing-a-finder-chart-for-comet-neowise # https://astroquery.readthedocs.io/en/latest/mpc/mpc.html # name = "C/2020 F3 (NEOWISE)" # https://www.minorplanetcenter.net/iau/info/CometOrbitFormat.html with load.open(mpc.COMET_URL) as f: comets = mpc.load_comets_dataframe(f) comets = (comets.sort_values('reference') .groupby('designation', as_index=False).last() .set_index('designation', drop=False)) row = comets.loc[name] print(row) ts = load.timescale() eph = load('de421.bsp') sun, earth = eph['sun'], eph['earth'] comet = sun + mpc.comet_orbit(row, ts, GM_SUN) t = ts.utc(timestamp.year, timestamp.month, timestamp.day, timestamp.hour, timestamp.minute) ra, dec, distance = earth.at(t).observe(comet).radec() result = {} result['name'] = name result['designation'] = row['designation'] result['timestamp'] = str(timestamp) result['ra'] = str(ra) result['dec'] = str(dec) result['ra_decimal'] = str(ra.hours * 15) result['dec_decimal'] = str(dec.degrees) result['distance'] = str(distance) result['magnitude_g'] = row['magnitude_g'] result['magnitude_k'] = row['magnitude_k'] result['visual_magnitude'] = row['magnitude_k'] result['row'] = row return result,comet
def test_comet_with_eccentricity_of_exactly_one(): ts = load.timescale() t = ts.utc(2020, 8, 13) planets = load('de421.bsp') earth, sun = planets['earth'], planets['sun'] data = (b' CK15A020 2015 08 1.8353 5.341055 1.000000 208.8369 ' b'258.5042 109.1696 10.5 4.0 C/2015 A2 (PANSTARRS)' b' MPC 93587') with BytesIO(data) as f: df = mpc.load_comets_dataframe(f) df = df[df['designation'] == 'C/2015 A2 (PANSTARRS)'] comet = mpc.comet_orbit(df.iloc[0], ts, GM_SUN) ra, dec, distance = earth.at(t).observe(sun + comet).radec() # These are exactly the RA and declination from the Minor Planet # Center for this comet! (The RA seconds returned by Skyfield # actually say "46.45s", which would round up to 46.5, but what's a # tenth of an arcsecond among friends?) assert str(ra).startswith('18h 46m 46.4') assert str(dec).startswith("-72deg 05' 33.")
def _create_comet_brighness_file(all_comets, fname): global creation_running ts = load.timescale(builtin=True) eph = load('de421.bsp') sun, earth = eph['sun'], eph['earth'] mags = [] t = ts.now() with open(fname, 'w') as f: for index, row in all_comets.iterrows(): m = 22.0 try: comet = sun + mpc.comet_orbit(row, ts, GM_SUN) dist_earth = earth.at(t).observe(comet).distance().au dist_sun = sun.at(t).observe(comet).distance().au if dist_earth < 10.0: m = row['magnitude_g'] + 5.0*np.log10(dist_earth) + 2.5*row['magnitude_k']*np.log10(dist_sun) print('Comet: {} de={} ds={} m={} g={}'.format(row['designation'], dist_earth, dist_sun, m, row['magnitude_k']), flush=True) except Exception: pass f.write(row['comet_id'] + ' ' + str(m) + '\n') mags.append(m) all_comets['mag'] = mags creation_running = False
t = t_comet[len(t_comet) // 2] # middle date # An ephemeris from the JPL provides Sun and Earth positions. eph = load('de421.bsp') sun = eph['sun'] earth = eph['earth'] # The Minor Planet Center data file provides the comet orbit. with load.open(mpc.COMET_URL) as f: comets = mpc.load_comets_dataframe(f) comets = comets.set_index('designation', drop=False) row = comets.loc['C/2020 F3 (NEOWISE)'] comet = sun + mpc.comet_orbit(row, ts, GM_SUN) # The Hipparcos mission provides our star catalog. with load.open(hipparcos.URL) as f: stars = hipparcos.load_dataframe(f) # And the constellation outlines come from Stellarium. We make a list # of the stars at which each edge stars, and the star at which each edge # ends. url = ('https://raw.githubusercontent.com/Stellarium/stellarium/master' '/skycultures/western_SnT/constellationship.fab') with load.open(url) as f: constellations = stellarium.parse_constellations(f)
ts = load.timescale() ephem = load('de421.bsp') cet = timezone('CET') sun, moon, earth = ephem['sun'], ephem['moon'], ephem['earth'] amsterdam = Topos('52.3679 N', '4.8984 E') amstercentric = earth + amsterdam t0 = ts.now() t1 = ts.tt_jd(t0.tt + 1) nu = t0.utc_datetime().astimezone(cet).time().strftime('%H:%M') mindist=1.5 from skyfield.constants import GM_SUN_Pitjeva_2005_km3_s2 as GM_SUN with load.open(mpc.COMET_URL,reload=True) as f: comets = mpc.load_comets_dataframe(f) print('Found ',len(comets), ' comets') comets = (comets.sort_values('reference') .groupby('designation', as_index=False).last() .set_index('designation', drop=False)) f = open('cometlist.txt', 'w') for (c, cometdata) in comets.iterrows(): comet = sun + mpc.comet_orbit(cometdata, ts, GM_SUN) ra, dec, distance = sun.at(t0).observe(comet).radec() print(c,' is at ',distance.au,'au') if (distance.au < mindist): f.write(c+"\n") f.close()
def comet_visibility(start_dt, comet_name, lat, lng, tzname='UTC', minutes_coarse=60, minutes_fine=1, days=1, min_comet_alt=0, max_sun_alt=-12): ''' find periods where the comet is above the specified horizon and the Sun is sufficiently below the horizon :param start_dt: timezone aware datetime to begin search :param comet_name: string containing the comet name, must match up with the MPC database :param lat: string with a float followed by N or S (e.g. 35.22 N), no negative numbers :param lng: string with a float followed by E or W (e.g. 78.01 W), no negative numbers :param tzname: string containing the timzone name :param days: integer with the length of the search window in days :param min_comet_alt: minimum altitude the comet is visible, defaults to 0 but could be set to match treeline :param max_sun_alt: maximum Sun altitide, defaults to -12 (nautical twilight) which works for low altitude comets less than magnitude 2 subtract 1-1.5 for that maximum altitude for every additional increase of 1 in magnitude. :return: a dataframe containing each minute during the specified time period the comet is observable ''' rediskey = f"cv:{start_dt.isoformat()}:{days}:{lat}:{lng}".replace( ' ', "_") start_utc = start_dt.astimezone(UTC) - datetime.timedelta(hours=4) try: cached_dict = pickle.loads(rconn.get(rediskey)) print("from cv cache") return cached_dict except Exception as e: pass try: localtz = start_dt.tzinfo except: localtz = 'UTC' # get comet ephemris and observer's location in space comet = sun + mpc.comet_orbit(comets.loc[comet_name], ts, GM_SUN) obs = earth + Topos(lat, lng) # course grained look at visiblity, use Sun at horizon to ensure we dont miss any opporunities times_coarse = ts.utc(start_utc.year, start_utc.month, start_utc.day, start_utc.hour, range(0, 60 * 24 * days, minutes_coarse)) _, instances = run_calculations(comet, 0, 0, obs, minutes_coarse, times_coarse) # rerun observations with a finer grain (defaults to 1 minute intervals) and passed Sun altitude instances_fine = [] for instance in instances: new_start = instance['begin']['time'] window = range( new_start.minute - minutes_coarse, round(instance['duration'].total_seconds() / 60) + minutes_coarse) times_fine = ts.utc(new_start.year, new_start.month, new_start.day, new_start.hour, window) _, local_instances_fine = run_calculations(comet, max_sun_alt, min_comet_alt, obs, minutes_fine, times_fine) instances_fine += local_instances_fine daily_instances = dict() for instance in instances_fine: for x in ['begin', 'end']: instance[x]['tz'] = localtz instance[x]['time_local'] = instance[x]['time'].astimezone(localtz) datestr = instance['begin']['time_local'].strftime('%a %b %-d') if datestr not in daily_instances.keys(): daily_instances[datestr] = [] daily_instances[datestr].append(instance) pickled_object = pickle.dumps(daily_instances) rconn.set(rediskey, pickled_object) # rconn.lset("rediskey", daily_instances) return (daily_instances)
def get_mpc_current_position(designation): row = comets.loc[designation] coords = list() comet = planets['sun'] + mpc.comet_orbit(row, ts, GM_SUN) x, y, z = comet.at(ts.now()).ecliptic_xyz().km return [x, y, z]
def create_starmap(command, observation_id): # The comet is plotted on several dates `t_comet`. But the stars only # need to be drawn once, so we take the middle comet date as the single # time `t` we use for everything else. ts = load.timescale() t_comet = ts.utc(2020, 8, range(1, 10)) t = t_comet[len(t_comet) // 2] # middle date # An ephemeris from the JPL provides Sun and Earth positions. eph = load('de421.bsp') sun = eph['sun'] earth = eph['earth'] # The Minor Planet Center data file provides the comet orbit. with load.open(mpc.COMET_URL) as f: comets = mpc.load_comets_dataframe(f) comets = (comets.sort_values('reference') .groupby('designation', as_index=False).last() .set_index('designation', drop=False)) row = comets.loc['C/2020 F3 (NEOWISE)'] comet = sun + mpc.comet_orbit(row, ts, GM_SUN) # The Hipparcos mission provides our star catalog. # with load.open(hipparcos.URL) as f: with load.open(settings.MY_HIPPARCOS_URL) as f: stars = hipparcos.load_dataframe(f) # And the constellation outlines come from Stellarium. We make a list # of the stars at which each edge stars, and the star at which each edge # ends. url = ('https://raw.githubusercontent.com/Stellarium/stellarium/master' '/skycultures/western_SnT/constellationship.fab') with load.open(url) as f: constellations = stellarium.parse_constellations(f) edges = [edge for name, edges in constellations for edge in edges] edges_star1 = [star1 for star1, star2 in edges] edges_star2 = [star2 for star1, star2 in edges] # We will center the chart on the comet's middle position. center = earth.at(t).observe(comet) projection = build_stereographic_projection(center) field_of_view_degrees = 30.0 limiting_magnitude = 8.0 # Now that we have constructed our projection, compute the x and y # coordinates that each star and the comet will have on the plot. star_positions = earth.at(t).observe(Star.from_dataframe(stars)) stars['x'], stars['y'] = projection(star_positions) comet_x, comet_y = projection(earth.at(t_comet).observe(comet)) # Create a True/False mask marking the stars bright enough to be # included in our plot. And go ahead and compute how large their # markers will be on the plot. bright_stars = (stars.magnitude <= limiting_magnitude) magnitude = stars['magnitude'][bright_stars] marker_size = (0.5 + limiting_magnitude - magnitude) ** 2.0 # The constellation lines will each begin at the x,y of one star and end # at the x,y of another. We have to "rollaxis" the resulting coordinate # array into the shape that matplotlib expects. xy1 = stars[['x', 'y']].loc[edges_star1].values xy2 = stars[['x', 'y']].loc[edges_star2].values lines_xy = np.rollaxis(np.array([xy1, xy2]), 1) # Time to build the figure! fig, ax = plt.subplots(figsize=[9, 9]) # Draw the constellation lines. ax.add_collection(LineCollection(lines_xy, colors='#00f2')) # Draw the stars. ax.scatter(stars['x'][bright_stars], stars['y'][bright_stars], s=marker_size, color='k') # Draw the comet positions, and label them with dates. comet_color = '#f00' offset = 0.002 ax.plot(comet_x, comet_y, '+', c=comet_color, zorder=3) for xi, yi, tstr in zip(comet_x, comet_y, t_comet.utc_strftime('%m/%d')): tstr = tstr.lstrip('0') text = ax.text(xi + offset, yi - offset, tstr, color=comet_color, ha='left', va='top', fontsize=9, weight='bold', zorder=-1) text.set_alpha(0.5) # Finally, title the plot and set some final parameters. angle = np.pi - field_of_view_degrees / 360.0 * np.pi limit = np.sin(angle) / (1.0 - np.cos(angle)) ax.set_xlim(-limit, limit) ax.set_ylim(-limit, limit) ax.xaxis.set_visible(False) ax.yaxis.set_visible(False) ax.set_aspect(1.0) ax.set_title('Comet NEOWISE {} through {}'.format( t_comet[0].utc_strftime('%Y %B %d'), t_comet[-1].utc_strftime('%Y %B %d'), )) # Save. filename = 'starmap.png' path = os.path.join(settings.MEDIA_ROOT, filename) fig.savefig(path, bbox_inches='tight') image_url = os.path.join(settings.MEDIA_URL, filename) return image_url