def test_from_altaz_parameters(ts): usno = Topos('38.9215 N', '77.0669 W', elevation_m=92.0) t = ts.tt(jd=api.T0) p = usno.at(t) a = api.Angle(degrees=10.0) d = api.Distance(au=0.234) with assert_raises(ValueError, 'the alt= parameter with an Angle'): p.from_altaz(alt='Bad value', alt_degrees=0, az_degrees=0) with assert_raises(ValueError, 'the az= parameter with an Angle'): p.from_altaz(az='Bad value', alt_degrees=0, az_degrees=0) p.from_altaz(alt=a, alt_degrees='bad', az_degrees=0) p.from_altaz(az=a, alt_degrees=0, az_degrees='bad') assert str(p.from_altaz(alt=a, az=a).distance()) == '0.1 au' assert str(p.from_altaz(alt=a, az=a, distance=d).distance()) == '0.234 au'
def horz2eq(az, ZA, gps): """ Convert from horizontal (az, ZA) to equatorial (RA, dec)" Returns RA, dec, Inputs: time - GPS time """ t = su.time2tai(gps) observer = su.S_MWAPOS.at(t) # logger.info('Calculating az, ZA at time %s', t.utc_iso()) coords = observer.from_altaz(alt_degrees=(90 - ZA), az_degrees=az, distance=si.Distance(au=9e90)) ra_a, dec_a, _ = coords.radec() return {'RA': ra_a._degrees, 'dec': dec_a.degrees}
def make_primarybeammap(datetimestring, delays, frequency, center=False, sunline=True, low=1, high=2000, plothourangle=True, extension='png', figsize=8, title=None, directory=None, tle=None, duration=300, moon=False, jupiter=False, verbose=False): """ filename=make_primarybeammap(datetimestring, delays, frequency, center=False, sunline=True, low=1, high=2000, plothourangle=True, extension='png', figsize=8, title=None, directory=None, tle=None, duration=300, moon=False, jupiter=False, verbose=False) if center==True, will center the image on the LST otherwise will have a fixed range (RA=-12 to 12) can adjust the grayscale limits if plothourangle==True, will also plot x-axis for hour angle """ su.init_data() # protect against log errors if (low <= 0): low = 1 if not os.path.exists(config.RADIO_IMAGE_FILE): logger.error("Could not find 408 MHz image: %s\n" % (config.RADIO_IMAGE_FILE)) return None try: if (verbose): print("Loading 408 MHz map from %s..." % config.RADIO_IMAGE_FILE) f = pyfits.open(config.RADIO_IMAGE_FILE) except Exception as e: logger.error("Error opening 408 MHz image: %s\nError: %s\n" % (config.RADIO_IMAGE_FILE, e)) return None skymap = f[0].data[0] # x=skymap[:,0].reshape(-1,1) # x=skymap[:,0:10] # skymap=numpy.concatenate((skymap,x),axis=1) tlelines = [] satellite_label = '' if tle is not None: try: tlefile = open(tle) tlelines = tlefile.readlines() tlefile.close() except Exception as e: logger.error('Could not open TLE file %s: %s' % (tle, e)) ra = (f[0].header.get('CRVAL1') + (numpy.arange(1, skymap.shape[1] + 1) - f[0].header.get('CRPIX1')) * f[0].header.get('CDELT1')) / 15.0 dec = (f[0].header.get('CRVAL2') + (numpy.arange(1, skymap.shape[0] + 1) - f[0].header.get('CRPIX2')) * f[0].header.get('CDELT2')) # parse the datetimestring try: yr = int(datetimestring[:4]) mn = int(datetimestring[4:6]) dy = int(datetimestring[6:8]) hour = int(datetimestring[8:10]) minute = int(datetimestring[10:12]) second = int(datetimestring[12:14]) except ValueError: logger.error('Could not parse datetimestring %s\n' % datetimestring) return None s_obstime = su.TIMESCALE.utc(year=yr, month=mn, day=dy, hour=hour, minute=minute, second=second) observer = su.S_MWAPOS.at(s_obstime) # determine the LST LST_hours = s_obstime.gmst + (su.MWA_TOPO.longitude.degrees / 15) if LST_hours > 24.0: LST_hours -= 24.0 if (verbose): print("For %s UT, LST=%6.4f" % (s_obstime.utc_iso()[:-1], LST_hours)) # this will be the center of the image RA0 = 0 if (center): RA0 = LST_hours * 15 else: if (6 < LST_hours < 18): RA0 = 180 # use LST to get Az,Alt grid for image RA, Dec = numpy.meshgrid(ra * 15, dec) UTs = '%02d:%02d:%02d' % (hour, minute, second) a_obstime = Time('%d-%d-%d %s' % (yr, mn, dy, UTs), scale='utc') coords = SkyCoord(ra=RA, dec=Dec, equinox='J2000', unit=(astropy.units.deg, astropy.units.deg)) coords.location = config.MWAPOS coords.obstime = a_obstime coords_prec = coords.transform_to('altaz') Az, Alt = coords_prec.az.deg, coords_prec.alt.deg # get the horizon line Az_Horz = numpy.arange(360.0) Alt_Horz = numpy.zeros(Az_Horz.shape) hequatorial = observer.from_altaz(alt_degrees=Alt_Horz, az_degrees=Az_Horz, distance=si.Distance(au=9e90)) RA_H_a, Dec_H_a, _ = hequatorial.radec() RA_Horz, Dec_Horz = RA_H_a._degrees, Dec_H_a.degrees RA_Horz[numpy.where(RA_Horz > 180 + RA0)] -= 360 RA_Horz[numpy.where(RA_Horz < -180 + RA0)] += 360 maskedskymap = numpy.where(Alt > 0, skymap, numpy.nan) # figure out where the Sun will be RAsun, Decsun, Azsun, Altsun = sunposition(s_obstime) if (RAsun > 180 + RA0): RAsun -= 360 if (RAsun < -180 + RA0): RAsun += 360 RAsuns, Decsuns = sunpositions() RAsuns = numpy.array(RAsuns) Decsuns = numpy.array(Decsuns) HAsuns = -RAsuns + LST_hours * 15 RAsuns = numpy.where(RAsuns > 180 + RA0, RAsuns - 360, RAsuns) RAsuns = numpy.where(RAsuns < -180 + RA0, RAsuns + 360, RAsuns) ra_sat = [] dec_sat = [] time_sat = [] if tlelines is not None and len(tlelines) >= 3: satellite_label = tlelines[0].replace('_', r'\_').replace('\n', '') satellite = si.EarthSatellite(tlelines[1], tlelines[2], name=tlelines[0], ts=su.TIMESCALE) ra_sat, dec_sat, time_sat, sublong_sat, sublat_sat = satellite_positions( satellite, a_obstime.gps, range(0, duration, 1), RA0=RA0) # do the plotting # this sets up the figure with the right aspect ratio fig = pylab.figure(figsize=(figsize, 0.5 * figsize), dpi=120) ax1 = fig.add_subplot(1, 1, 1) # this is the Haslam map, plotted as a log-scale # it is slightly transparent since this does below the horizon too ax1.imshow(numpy.log10(skymap), cmap=pylab.cm.get_cmap('gray_r'), aspect='auto', vmin=math.log10(low), vmax=math.log10(high), origin='lower', extent=(ra[0], ra[-1], dec[0], dec[-1]), alpha=0.9) ax1.imshow(numpy.log10(maskedskymap), cmap=pylab.cm.get_cmap('gray_r'), aspect='auto', vmin=0, vmax=math.log10(2000), origin='lower', extent=(ra[0], ra[-1], dec[0], dec[-1])) # this is the Haslam map but only above the horizon ax1.imshow(numpy.log10(skymap), cmap=pylab.cm.get_cmap('gray_r'), aspect='auto', vmin=math.log10(low), vmax=math.log10(high), origin='lower', extent=(ra[0] + 24, ra[-1] + 24, dec[0], dec[-1]), alpha=0.9) ax1.imshow(numpy.log10(maskedskymap), cmap=pylab.cm.get_cmap('gray_r'), aspect='auto', vmin=math.log10(low), vmax=math.log10(high), origin='lower', extent=(ra[0] + 24, ra[-1] + 24, dec[0], dec[-1])) contourcolors = ['r', 'c', 'y', 'm', 'w', 'g', 'b'] if (isinstance(frequency, float) or isinstance(frequency, int)): if (verbose): print("Creating primary beam response for frequency %.2f MHz..." % (frequency)) print("Beamformer delays are %s" % delays) r = return_beam(Alt, Az, delays, frequency) if (r is None): return None Z2 = numpy.where(r >= min(contourlevels), r, 0) if (verbose): i = numpy.nonzero(Z2 == Z2.max()) ramax = RA[i][0] if (ramax < 0): ramax += 360 print("Sensitivity is max at (RA,Dec)=(%.5f,%.5f)" % (ramax, Dec[i][0])) # put on contours for the beam ax1.contour(RA / 15.0, Dec, Z2, contourlevels, colors='r') ax1.contour(RA / 15.0 - 24, Dec, Z2, contourlevels, colors='r') ax1.contour(RA / 15.0 + 24, Dec, Z2, contourlevels, colors='r') else: icolor = 0 for f in frequency: color = contourcolors[icolor] if (verbose): print( "Creating primary beam response for frequency %.2f MHz..." % (f)) print("Beamformer delays are %s" % delays) r = return_beam(Alt, Az, delays, f) if r is None: return None Z2 = numpy.where(r >= min(contourlevels), r, 0) if (verbose): i = numpy.nonzero(Z2 == Z2.max()) ramax = RA[i][0] if (ramax < 0): ramax += 360 print("Sensitivity is max at (RA,Dec)=(%.5f,%.5f)" % (ramax, Dec[i][0])) # put on contours for the beam ax1.contour(RA / 15.0, Dec, Z2, contourlevels, colors=color) ax1.contour(RA / 15.0 - 24, Dec, Z2, contourlevels, colors=color) ax1.contour(RA / 15.0 + 24, Dec, Z2, contourlevels, colors=color) icolor += 1 if (icolor >= len(contourcolors)): icolor = 0 # plot the horizon line RA_Horz, Dec_Horz = list(zip(*sorted(zip(RA_Horz, Dec_Horz)))) ax1.plot(numpy.array(RA_Horz) / 15.0, numpy.array(Dec_Horz), 'k') x1 = 12 + RA0 / 15 x2 = -12 + RA0 / 15 ax1.set_xlim(left=x1, right=x2) ax1.set_ylim(bottom=-90, top=90) ax1.set_xticks(numpy.arange(-12 + int(RA0 / 15), 15 + int(RA0 / 15), 3)) ll = [] for x in numpy.arange(-12 + int(RA0 / 15), 15 + int(RA0 / 15), 3): if (0 <= x < 24): ll.append('%d' % x) elif (x >= 24): ll.append('%d' % (x - 24)) else: ll.append('%d' % (x + 24)) ax1.set_xticklabels(ll) ax1.set_yticks(numpy.arange(-90, 105, 15)) ax1.set_xlabel('Right Ascension (hours)') ax1.set_ylabel('Declination (degrees)') # plot the Sun ax1.plot(RAsun / 15.0, Decsun, 'yo', markersize=10) RAsuns, Decsuns = list(zip(*sorted(zip(RAsuns, Decsuns)))) if (sunline): ax1.plot(numpy.array(RAsuns) / 15.0, numpy.array(Decsuns), 'y-') if moon: RAmoon, Decmoon, Azmoon, Altmoon = moonposition(s_obstime) if (RAmoon > 180 + RA0): RAmoon -= 360 if (RAmoon < -180 + RA0): RAmoon += 360 ax1.plot(RAmoon / 15.0, Decmoon, 'ko', markersize=10) print(RAmoon, Decmoon) if jupiter: RAjupiter, Decjupiter, Azjupiter, Altjupiter = jupiterposition( s_obstime) if (RAjupiter > 180 + RA0): RAjupiter -= 360 if (RAjupiter < -180 + RA0): RAjupiter += 360 ax1.plot(RAjupiter / 15.0, Decjupiter, 'bo', markersize=8) print(RAjupiter, Decjupiter) if len(ra_sat) > 0: coords = SkyCoord(ra=ra_sat, dec=dec_sat, equinox='J2000', unit=(astropy.units.deg, astropy.units.deg)) coords.location = config.MWAPOS coords.obstime = a_obstime coords_prec = coords.transform_to('altaz') Azsat, Altsat = coords_prec.az.deg, coords_prec.alt.deg rsat = return_beam(Altsat, Azsat, delays, frequency) ax1.plot(numpy.array(ra_sat) / 15.0, numpy.array(dec_sat), 'c-') ax1.scatter( numpy.array(ra_sat) / 15.0, numpy.array(dec_sat), # c=numpy.arange(len(ra_sat))/(1.0*len(ra_sat)), # cmap=pylab.cm.hsv, c=1 - rsat, cmap=pylab.cm.get_cmap('Blues'), alpha=0.5, edgecolors='none') ax1.text(ra_sat[0] / 15.0, dec_sat[0], time_sat[0].strftime('%H:%M:%S'), fontsize=8, horizontalalignment='left', color='c') ax1.text(ra_sat[-1] / 15.0, dec_sat[-1], time_sat[-1].strftime('%H:%M:%S'), fontsize=8, horizontalalignment='left', color='c') # add text for sources for source in sources: r = Angle(sources[source][1], unit=astropy.units.hour).hour d = Angle(sources[source][2], unit=astropy.units.deg).deg horizontalalignment = 'left' x = r - 0.2 if (len(sources[source]) >= 6 and sources[source][5] == 'c'): horizontalalignment = 'center' x = r if (len(sources[source]) >= 6 and sources[source][5] == 'r'): horizontalalignment = 'right' x = r + 0.1 if (x > 12 + RA0 / 15): x -= 24 if (x < -12 + RA0 / 15): x += 24 fontsize = defaultsize if (len(sources[source]) >= 5): fontsize = sources[source][4] color = defaultcolor if (len(sources[source]) >= 4): color = sources[source][3] ax1.text(x, d, sources[source][0], horizontalalignment=horizontalalignment, fontsize=fontsize, color=color, verticalalignment='center') if (isinstance(frequency, int) or isinstance(frequency, float)): textlabel = '%04d-%02d-%02d %02d:%02d:%02d %.2f MHz' % ( yr, mn, dy, hour, minute, second, frequency) else: fstring = "[" + ','.join(["%.2f" % f for f in frequency]) + "]" textlabel = '%04d-%02d-%02d %02d:%02d:%02d %s MHz' % ( yr, mn, dy, hour, minute, second, fstring) icolor = 0 for i in range(len(frequency)): color = contourcolors[icolor] ax1.text(x1 - 1, 70 - 10 * i, '%.2f MHz' % frequency[i], fontsize=12, color=color, horizontalalignment='left') icolor += 1 if (icolor >= len(contourcolors)): icolor = 0 if title is not None: title = title.replace('_', r'\_') textlabel = title + ' ' + textlabel if (plothourangle): ax2 = ax1.twiny() p = ax2.plot(HAsuns / 15, Decsuns, 'y-') p[0].set_visible(False) ax1.set_ylim(bottom=-90, top=90) ax2.set_ylim(bottom=-90, top=90) ax1.set_yticks(numpy.arange(-90, 105, 15)) # x1b=x1-LST_hours # x2b=x2-LST_hours x1b = -x1 + LST_hours # x2b = -x2 + LST_hours while (x1b < 0): x1b += 24 while (x1b > 24): x1b -= 24 x2b = x1b - 24 ax2.set_xlim(left=x2b, right=x1b) ax2.set_xlabel('Hour Angle (hours)') ax1.text(x1 - 1, 80, textlabel, fontsize=14, horizontalalignment='left') if len(satellite_label) > 0: ax1.text(x1 - 1, 70, satellite_label, fontsize=14, horizontalalignment='left', color='c') else: ax1.set_title(textlabel) # print ax1.get_xlim() # try: # print ax2.get_xlim() # except: # pass if (isinstance(frequency, int) or isinstance(frequency, float)): filename = '%s_%.2fMHz.%s' % (datetimestring, frequency, extension) else: filename = '%s_%.2fMHz.%s' % (datetimestring, frequency[0], extension) if directory is not None: filename = directory + '/' + filename try: pylab.savefig(filename) except RuntimeError as err: logger.error('Error saving figure: %s\n' % err) return None return filename
def get_best_gridpoints(gps_start, obs_source_ra_deg, obs_source_dec_deg, avoid_source_ra_deg, avoid_source_dec_deg, model="analytic", min_gain=None, max_beam_distance_deg=360, channel=145, verb_level=1, logger=LOGGER, duration=3600, step=120, min_elevation=30.00): su.init_data() frequency = channel * 1.28 if model not in ['analytic', 'advanced', 'full_EE', 'full_EE_AAVS05']: logger.error("Model %s not found\n" % model) gp_numbers = list(mwa_sweet_spots.all_grid_points.keys()) gp_numbers.sort() gp_azes = numpy.array([mwa_sweet_spots.all_grid_points[i][1] for i in gp_numbers]) gp_alts = numpy.array([mwa_sweet_spots.all_grid_points[i][2] for i in gp_numbers]) gp_delays = [mwa_sweet_spots.all_grid_points[i][4] for i in gp_numbers] obs_source = si.Star(ra=si.Angle(degrees=obs_source_ra_deg), dec=si.Angle(degrees=obs_source_dec_deg)) avoid_source = si.Star(ra=si.Angle(degrees=avoid_source_ra_deg), dec=si.Angle(degrees=avoid_source_dec_deg)) freq = frequency * 1e6 tracklist = [] # List of (starttime, duration, az, el) tuples for starttime in range(int(gps_start), int(gps_start + duration), int(step)): t = su.time2tai(starttime) observer = su.S_MWAPOS.at(t) obs_source_apparent = observer.observe(obs_source).apparent() obs_source_alt, obs_source_az, _ = obs_source_apparent.altaz() if obs_source_alt.degrees < min_elevation: logger.debug("Source at %.2f [deg] below minimum elevation = %.2f [deg] at this time, skip this timestep." % (obs_source_alt.degrees, min_elevation)) continue # Source below pointing horizon at this time, skip this timestep. if min_gain is None: current_min_gain = 0.5 if obs_source_alt.degrees < 50: current_min_gain = 0.1 else: current_min_gain = min_gain avoid_source_apparent = observer.observe(avoid_source).apparent() avoid_source_alt, avoid_source_az, _ = avoid_source_apparent.altaz() if avoid_source_alt.degrees < 0.0: tracklist.append((starttime, step, obs_source_az.degrees, obs_source_alt.degrees)) logger.debug("Avoided source below TRUE horizon, just use actual target az/alt for this timestep.") continue # Avoided source below TRUE horizon, just use actual target az/alt for this timestep. dist_deg = obs_source_apparent.separation_from(avoid_source_apparent).degrees logger.debug("Observed source at (az,alt) = (%.4f,%.4f) [deg]" % (obs_source_az.degrees, obs_source_alt.degrees)) logger.debug("Avoided source at (az,alt) = (%.4f,%.4f) [deg]" % (avoid_source_az.degrees, avoid_source_alt.degrees)) logger.debug("Anglular distance = %.2f [deg]" % (dist_deg)) logger.debug("Gps time = %d" % su.tai2gps(t)) gp_positions = observer.from_altaz(alt_degrees=gp_alts, az_degrees=gp_azes, distance=si.Distance(au=9e90)) dist_obs_degs = obs_source_apparent.separation_from(gp_positions).degrees dist_avoid_degs = avoid_source_apparent.separation_from(gp_positions).degrees # select gridpoints within given angular distance : best_gridpoint = None r_max = -1000 best_gain_obs = 0 best_gain_avoid = 0 skipped_too_far = 0 skipped_gain_too_low = 0 for i in range(len(gp_numbers)): gpnum = gp_numbers[i] dist_obs = dist_obs_degs[i] dist_avoid = dist_avoid_degs[i] if verb_level > 1: outstring = "\n\t\ttesting gridpoint %d, dist_obs_deg = %.2f [deg], dist_avoid_deg = %.2f [deg]" logger.debug(outstring % (gpnum, dist_obs, dist_avoid)) # if dist_obs_deg < options.max_beam_distance_deg and dist_avoid_deg < options.max_beam_distance_deg : if dist_obs < max_beam_distance_deg: beam_obs = primarybeammap_tant.get_beam_power(gp_delays[i], freq, model=model, pointing_az_deg=obs_source_az.degrees, pointing_za_deg=90 - obs_source_alt.degrees, zenithnorm=True) beam_avoid = primarybeammap_tant.get_beam_power(gp_delays[i], freq, model=model, pointing_az_deg=avoid_source_az.degrees, pointing_za_deg=90 - avoid_source_alt.degrees, zenithnorm=True) gain_XX_obs = beam_obs['XX'] gain_XX_avoid = beam_avoid['XX'] r = gain_XX_obs / gain_XX_avoid if r > 1.00 and gain_XX_obs > current_min_gain: outstring = "\t\tSelected gridpoint = %d at (az,elev) = (%.4f,%.4f) [deg] at (distances %.4f and %.4f deg) " outstring += "-> gain_obs=%.4f and gain_avoid=%.4f -> gain_obs/gain_avoid = %.4f" logger.debug(outstring % (gpnum, gp_azes[i], gp_alts[i], dist_obs, dist_avoid, gain_XX_obs, gain_XX_avoid, r)) if r > r_max: best_gridpoint = i r_max = r best_gain_obs = gain_XX_obs best_gain_avoid = gain_XX_avoid else: skipped_gain_too_low = skipped_gain_too_low + 1 if verb_level > 1: outstring = "\t\tSKIPPED gridpoint = %d at (az,elev) = (%.4f,%.4f) [deg] at (distances %.4f and %.4f deg) " outstring += "-> gain_obs=%.4f (vs. min_gain=%.2f) and gain_avoid=%.4f -> gain_obs/gain_avoid = %.4f" logger.debug(outstring % (gpnum, gp_azes[i], gp_alts[i], dist_obs, dist_avoid, gain_XX_obs, current_min_gain, gain_XX_avoid, r)) else: skipped_too_far = skipped_too_far + 1 if verb_level > 1: outstring = "\t\t\tskipped as dist_obs_deg = %.2f [deg] and dist_avoid_deg = %.2f [deg] , one > " outstring += "max_beam_distance_deg = %.2f [deg]" logger.debug(outstring % (dist_obs, dist_avoid, max_beam_distance_deg)) logger.debug("Number of gridpoints skipped due to gain lower than minimum (=%.2f) = %d" % (current_min_gain, skipped_gain_too_low)) outstring = "Number of gridpoints skipped due to being further than limit ( max_beam_distance_deg = %.2f [deg] ) = %d" logger.debug(outstring % (max_beam_distance_deg, skipped_too_far)) if best_gridpoint is not None: outstring = "Best gridpoint %d at (az,alt)=(%.4f,%.4f) [deg] at %s UTC to observe has ratio = %.2f = %.8f / %.8f\n" logger.info(outstring % (gp_numbers[best_gridpoint], gp_azes[best_gridpoint], gp_alts[best_gridpoint], t.utc_iso(), r_max, best_gain_obs, best_gain_avoid)) tracklist.append((starttime, step, gp_azes[best_gridpoint], gp_alts[best_gridpoint])) return tracklist
outfile.write(command % {'creator': creator, 'otime': start_time.gps, 'channel': options.channel, 'inttime': inttime_str, 'freqres': options.freqres, 'project': options.project}) outfile.write("\n") for entry in tracklist: otime, step, az, alt = entry t = su.time2tai(otime) observer = su.S_MWAPOS.at(t) pos = observer.from_altaz(alt_degrees=alt, az_degrees=az, distance=si.Distance(au=9e90)) ra_a, dec_a, _ = pos.radec() if options.radec: command = "single_observation.py --creator=%(creator)s --starttime=%(otime)s --stoptime=++%(step)s --freq=%(channel)d,24 " command += "--obsname=%(obj)s_%(channel)d --inttime=%(inttime)s --freqres=%(freqres)d --useazel --usegrid= " command += "--ra=%(ra).4f --dec=%(dec).4f --project=%(project)s\n" else: command = "single_observation.py --creator=%(creator)s --starttime=%(otime)s --stoptime=++%(step)s --freq=%(channel)d,24 " command += "--obsname=%(obj)s_%(channel)d --inttime=%(inttime)s --freqres=%(freqres)d --useazel --usegrid= " command += "--azimuth=%(az).4f --elevation=%(alt).4f --project=%(project)s\n" outfile.write(command % {'creator': creator, 'otime': otime, 'step': step, 'channel': options.channel,