Example #1
0
def sky_coords(cluster):
    """Get the sky coordinates of every star in the cluster

    Parameters
    ----------
    cluster : class
        StarCluster

    Returns
    -------
    ra,dec,d0,pmra,pmdec,vr0 : float
      on-sky positions and velocities of cluster stars
      
    History
    -------
    2018 - Written - Webb (UofT)
    """
    origin0 = cluster.origin

    if origin0 != "galaxy":
        cluster.to_galaxy()

    x0, y0, z0 = bovy_coords.galcenrect_to_XYZ(cluster.x,
                                               cluster.y,
                                               cluster.z,
                                               Xsun=8.0,
                                               Zsun=0.025).T
    vx0, vy0, vz0 = bovy_coords.galcenrect_to_vxvyvz(
        cluster.vx,
        cluster.vy,
        cluster.vz,
        Xsun=8.0,
        Zsun=0.025,
        vsun=[-11.1, 244.0, 7.25],
    ).T

    l0, b0, d0 = bovy_coords.XYZ_to_lbd(x0, y0, z0, degree=True).T
    ra, dec = bovy_coords.lb_to_radec(l0, b0, degree=True).T

    vr0, pmll0, pmbb0 = bovy_coords.vxvyvz_to_vrpmllpmbb(vx0,
                                                         vy0,
                                                         vz0,
                                                         l0,
                                                         b0,
                                                         d0,
                                                         degree=True).T
    pmra, pmdec = bovy_coords.pmllpmbb_to_pmrapmdec(pmll0,
                                                    pmbb0,
                                                    l0,
                                                    b0,
                                                    degree=True).T

    if origin0 == "centre":
        cluster.to_centre()
    elif origin0 == "cluster":
        cluster.to_cluster()

    return ra, dec, d0, pmra, pmdec, vr0
def convertHelioCentricToRADEC(xyzuvw_hc, kpc=False):
    """
    Generate astrometry values from cartesian coordinates centred on sun

    Parameters
    ----------
    xyzuvw_hc : [6] array
        [kpc, kpc, kpc, km/s, km/s, km/s]

    Returns
    -------
    astrometry : [6] array
        [RA, DEC, pi, pm_ra, pm_dec, vr]
    """
    #    if not kpc:
    #        xyzuvw_hc = xyzuvw_hc.copy()
    #        xyzuvw_hc[:3] /= 1e3
    logging.debug("Positions is: {}".format(xyzuvw_hc[:3]))
    logging.debug("Velocity is: {}".format(xyzuvw_hc[3:]))
    lbdist = convertHelioCentricTolbdist(xyzuvw_hc)
    radec = bovy_coords.lb_to_radec(lbdist[0], lbdist[1], degree=True)
    vrpmllpmbb = bovy_coords.vxvyvz_to_vrpmllpmbb(xyzuvw_hc[3],
                                                  xyzuvw_hc[4],
                                                  xyzuvw_hc[5],
                                                  lbdist[0],
                                                  lbdist[1],
                                                  lbdist[2],
                                                  degree=True)
    pmrapmdec = bovy_coords.pmllpmbb_to_pmrapmdec(vrpmllpmbb[1],
                                                  vrpmllpmbb[2],
                                                  lbdist[0],
                                                  lbdist[1],
                                                  degree=True)
    return [
        radec[0], radec[1], 1.0 / lbdist[2], pmrapmdec[0], pmrapmdec[1],
        vrpmllpmbb[0]
    ]
Example #3
0
def example_integrate_orbit():
    # Use 'MWPotential2014' as an example
    my_potential = MWPotential2014

    # integration time in units of (_R0/_V0)
    time_start = 0.
    time_end = 100.
    my_time_step = numpy.linspace(time_start, time_end, 1001)

    # read 6D astrometric data
    # (0) [mas] parallax
    # (1) [deg] ell
    # (2) [deg] b
    # (3) [km/s] heliocentric line-of-sight velocity
    # (4) [mas/yr] proper motion along ell direction (mu_ellstar = mu_ell * cos(b))
    # (5) [mas/yr] proper motion along b direction (mu_b)

    my_filename = 'parallax_ell_b_heliocentricLineOfSightVelocity_properMotionEllStar_properMotionB.txt'
    my_file = open(my_filename, 'r')
    my_data = numpy.loadtxt(my_file, comments='#')

    my_parallax_mas = my_data[:, 0]
    my_ell_deg = my_data[:, 1]
    my_b_deg = my_data[:, 2]
    my_hlosv_kms = my_data[:, 3]
    my_muellstar_masyr = my_data[:, 4]
    my_mub_masyr = my_data[:, 5]

    # count sample size
    my_sample_size = len(my_ell_deg)

    for i in range(my_sample_size):
        print('star ID=%d' % (i))

        # convert parallax to distance
        distance_kpc = 1. / my_parallax_mas[i]

        # convert (ell, b) to (RA, DEC)
        RA_deg, DEC_deg = bovy_coords.lb_to_radec(my_ell_deg[i],
                                                  my_b_deg[i],
                                                  degree=True,
                                                  epoch=_my_epoch)

        # heliocentric line-of-sight velocity
        hlosv_kms = my_hlosv_kms[i]

        # convert (mu_ellstar, mu_b) to (mu_RAstar, mu_DEC)
        muRAstar_masyr, muDEC_masyr = bovy_coords.pmllpmbb_to_pmrapmdec(
            my_muellstar_masyr[i],
            my_mub_masyr[i],
            my_ell_deg[i],
            my_b_deg[i],
            degree=True,
            epoch=_my_epoch)

        # create orbit instance
        obs_6D = Orbit(vxvv=[
            RA_deg, DEC_deg, distance_kpc, muRAstar_masyr, muDEC_masyr,
            hlosv_kms
        ],
                       radec=True,
                       ro=_R0,
                       vo=_V0,
                       zo=0.,
                       solarmotion=[_Usun, _Vsun, _Wsun])

        # integrate orbit in my_potential
        obs_6D.integrate(my_time_step, my_potential)

        # file on which we write 6D data at each time step
        outfile_i = open("t_x_y_z_vx_vy_vz_R__orbitID%03d.txt" % (i), 'w')

        # For illustrative purpose, I use an explicit expression to access 6D data at each time.
        for j in range(len(my_time_step)):
            # Here I assume that
            # (a) Galactic Center is located at (x,y)=(0,0) kpc
            # (b) Sun is located at (x,y)=(-8,0) kpc
            # (c) Nearby disc stars with circular orbits move towards (vx,vy)=(0,220) km/s
            # This is why I add a minus sign (-) to x and vx.
            x = -obs_6D.x(my_time_step[j])
            y = obs_6D.y(my_time_step[j])
            z = obs_6D.z(my_time_step[j])
            vx = -obs_6D.vx(my_time_step[j])
            vy = obs_6D.vy(my_time_step[j])
            vz = obs_6D.vz(my_time_step[j])
            R = obs_6D.R(my_time_step[j])
            printline = '%lf %lf %lf %lf %lf %lf %lf %lf\n' % (
                my_time_step[j], x, y, z, vx, vy, vz, R)
            outfile_i.write(printline)

        # close file
        outfile_i.close()

    return None
Example #4
0
def findfriends(targname,radial_velocity,velocity_limit=5.0,search_radius=25.0,rvcut=5.0,radec=[None,None],output_directory = None,showplots=False,verbose=False,DoGALEX=True,DoWISE=True,DoROSAT=True):
    
    radvel= radial_velocity * u.kilometer / u.second
    
    if output_directory == None:
        outdir = './' + targname.replace(" ", "") + '_friends/'
    else: 
        outdir = output_directory
    if os.path.isdir(outdir) == True:
        print('Output directory ' + outdir +' Already Exists!!')
        print('Either Move it, Delete it, or input a different [output_directory] Please!')
        return
    os.mkdir(outdir)
    
    if velocity_limit < 0.00001 : 
        print('input velocity_limit is too small, try something else')
        print('velocity_limit: ' + str(velocity_limit))
    if search_radius < 0.0000001:
        print('input search_radius is too small, try something else')
        print('search_radius: ' + str(search_radius))
     
    # Search parameters
    vlim=velocity_limit * u.kilometer / u.second
    searchradpc=search_radius * u.parsec

    if (radec[0] != None) & (radec[1] != None):
        usera,usedec = radec[0],radec[1]
    else:  ##use the target name to get simbad ra and dec.
        print('Asking Simbad for RA and DEC')
        result_table = Simbad.query_object(targname)
        usera,usedec = result_table['RA'][0],result_table['DEC'][0]
    
    if verbose == True:
        print('Target name: ',targname)
        print('Coordinates: ' + str(usera) +' '+str(usedec))
        print()

    c = SkyCoord( ra=usera , dec=usedec , unit=(u.hourangle, u.deg) , frame='icrs')
    if verbose == True: print(c)

    # Find precise coordinates and distance from Gaia, define search radius and parallax cutoff
    print('Asking Gaia for precise coordinates')
    sqltext = "SELECT * FROM gaiaedr3.gaia_source WHERE CONTAINS( \
               POINT('ICRS',gaiaedr3.gaia_source.ra,gaiaedr3.gaia_source.dec), \
               CIRCLE('ICRS'," + str(c.ra.value) +","+ str(c.dec.value) +","+ str(6.0/3600.0) +"))=1;"
    job = Gaia.launch_job_async(sqltext , dump_to_file=False)
    Pgaia = job.get_results()
    if verbose == True:
        print(sqltext)
        print()
        print(Pgaia['source_id','ra','dec','phot_g_mean_mag','parallax','ruwe'].pprint_all())
        print()

    minpos = Pgaia['phot_g_mean_mag'].tolist().index(min(Pgaia['phot_g_mean_mag']))
    Pcoord = SkyCoord( ra=Pgaia['ra'][minpos]*u.deg , dec=Pgaia['dec'][minpos]*u.deg , \
                      distance=(1000.0/Pgaia['parallax'][minpos])*u.parsec , frame='icrs' , \
                      radial_velocity=radvel , \
                      pm_ra_cosdec=Pgaia['pmra'][minpos]*u.mas/u.year , pm_dec=Pgaia['pmdec'][minpos]*u.mas/u.year )

    searchraddeg = np.arcsin(searchradpc/Pcoord.distance).to(u.deg)
    minpar = (1000.0 * u.parsec) / (Pcoord.distance + searchradpc) * u.mas
    if verbose == True:
        print(Pcoord)
        print()
        print('Search radius in deg: ',searchraddeg)
        print('Minimum parallax: ',minpar)


    # Query Gaia with search radius and parallax cut
    # Note, a cut on parallax_error was added because searches at low galactic latitude 
    # return an overwhelming number of noisy sources that scatter into the search volume - ALK 20210325
    print('Querying Gaia for neighbors')

    Pllbb     = bc.radec_to_lb(Pcoord.ra.value , Pcoord.dec.value , degree=True)
    if ( np.abs(Pllbb[1]) > 10.0): plxcut = max( 0.5 , (1000.0/Pcoord.distance.value/10.0) )
    else: plxcut = 0.5
    print('Parallax cut: ',plxcut)

    if (searchradpc < Pcoord.distance):
        sqltext = "SELECT * FROM gaiaedr3.gaia_source WHERE CONTAINS( \
            POINT('ICRS',gaiaedr3.gaia_source.ra,gaiaedr3.gaia_source.dec), \
            CIRCLE('ICRS'," + str(Pcoord.ra.value) +","+ str(Pcoord.dec.value) +","+ str(searchraddeg.value) +"))\
            =1 AND parallax>" + str(minpar.value) + " AND parallax_error<" + str(plxcut) + ";"
    if (searchradpc >= Pcoord.distance):
        sqltext = "SELECT * FROM gaiaedr3.gaia_source WHERE parallax>" + str(minpar.value) + " AND parallax_error<" + str(plxcut) + ";"
        print('Note, using all-sky search')
    if verbose == True:
        print(sqltext)
        print()

    job = Gaia.launch_job_async(sqltext , dump_to_file=False)
    r = job.get_results()
   
    if verbose == True: print('Number of records: ',len(r['ra']))


    # Construct coordinates array for all stars returned in cone search

    gaiacoord = SkyCoord( ra=r['ra'] , dec=r['dec'] , distance=(1000.0/r['parallax'])*u.parsec , \
                         frame='icrs' , \
                         pm_ra_cosdec=r['pmra'] , pm_dec=r['pmdec'] )

    sep = gaiacoord.separation(Pcoord)
    sep3d = gaiacoord.separation_3d(Pcoord)

    if verbose == True:
        print('Printing angular separations in degrees as sanity check')
        print(sep.degree)



    Pllbb     = bc.radec_to_lb(Pcoord.ra.value , Pcoord.dec.value , degree=True)
    Ppmllpmbb = bc.pmrapmdec_to_pmllpmbb( Pcoord.pm_ra_cosdec.value , Pcoord.pm_dec.value , \
                                         Pcoord.ra.value , Pcoord.dec.value , degree=True )
    Pvxvyvz   = bc.vrpmllpmbb_to_vxvyvz(Pcoord.radial_velocity.value , Ppmllpmbb[0] , Ppmllpmbb[1] , \
                                   Pllbb[0] , Pllbb[1] , Pcoord.distance.value/1000.0 , XYZ=False , degree=True)

    if verbose == True:
        print('Science Target Name: ',targname)
        print('Science Target RA/DEC: ',Pcoord.ra.value,Pcoord.dec.value)
        print('Science Target Galactic Coordinates: ',Pllbb)
        print('Science Target UVW: ',Pvxvyvz)
        print()

    Gllbb = bc.radec_to_lb(gaiacoord.ra.value , gaiacoord.dec.value , degree=True)
    Gxyz = bc.lbd_to_XYZ( Gllbb[:,0] , Gllbb[:,1] , gaiacoord.distance/1000.0 , degree=True)
    Gvrpmllpmbb = bc.vxvyvz_to_vrpmllpmbb( \
                    Pvxvyvz[0]*np.ones(len(Gxyz[:,0])) , Pvxvyvz[1]*np.ones(len(Gxyz[:,1])) , Pvxvyvz[2]*np.ones(len(Gxyz[:,2])) , \
                    Gxyz[:,0] , Gxyz[:,1] , Gxyz[:,2] , XYZ=True)
    Gpmrapmdec = bc.pmllpmbb_to_pmrapmdec( Gvrpmllpmbb[:,1] , Gvrpmllpmbb[:,2] , Gllbb[:,0] , Gllbb[:,1] , degree=True)

    # Code in case I want to do chi^2 cuts someday
    Gvtanerr = 1.0 * np.ones(len(Gxyz[:,0]))
    Gpmerr = Gvtanerr * 206265000.0 * 3.154e7 / (gaiacoord.distance.value * 3.086e13)


    Gchi2 = ( (Gpmrapmdec[:,0]-gaiacoord.pm_ra_cosdec.value)**2 + (Gpmrapmdec[:,1]-gaiacoord.pm_dec.value)**2 )**0.5
    Gchi2 = Gchi2 / Gpmerr
    if verbose == True:
        print('Predicted PMs if comoving:')
        print(Gpmrapmdec , "\n")
        print('Actual PMRAs from Gaia:')
        print(gaiacoord.pm_ra_cosdec.value , "\n")
        print('Actual PMDECs from Gaia:')
        print(gaiacoord.pm_dec.value , "\n")
        print('Predicted PM errors:')
        print(Gpmerr , "\n")
        print('Chi^2 values:')
        print(Gchi2)


    # Query external list(s) of RVs

    zz = np.where( (sep3d.value < searchradpc.value) & (Gchi2 < vlim.value) )
    yy = zz[0][np.argsort(sep3d[zz])]
    
    RV    = np.empty(np.array(r['ra']).size)
    RVerr = np.empty(np.array(r['ra']).size)
    RVsrc = np.array([ '                             None' for x in range(np.array(r['ra']).size) ])
    RV[:]    = np.nan
    RVerr[:] = np.nan

    print('Populating RV table')
    for x in range(0 , np.array(yy).size):
        if np.isnan(r['dr2_radial_velocity'][yy[x]]) == False:        # First copy over DR2 RVs
            RV[yy[x]]    = r['dr2_radial_velocity'][yy[x]]
            RVerr[yy[x]] = r['dr2_radial_velocity_error'][yy[x]]
            RVsrc[yy[x]] = 'Gaia DR2'
    if os.path.isfile('LocalRV.csv'):
        with open('LocalRV.csv') as csvfile:                          # Now check for a local RV that would supercede
            readCSV = csv.reader(csvfile, delimiter=',')
            for row in readCSV:
                ww = np.where(r['designation'] == row[0])[0]
                if (np.array(ww).size == 1):
                    RV[ww]    = row[2]
                    RVerr[ww] = row[3]
                    RVsrc[ww] = row[4]
                    if verbose == True: 
                        print('Using stored RV: ',row)
                        print(r['ra','dec','phot_g_mean_mag'][ww])
                        print(RV[ww])
                        print(RVerr[ww])
                        print(RVsrc[ww])



    # Create Gaia CMD plot

    mamajek  = np.loadtxt(datapath+'/sptGBpRp.txt')
    pleiades = np.loadtxt(datapath+'/PleGBpRp.txt')
    tuchor   = np.loadtxt(datapath+'/TucGBpRp.txt')
    usco     = np.loadtxt(datapath+'/UScGBpRp.txt')
    chai     = np.loadtxt(datapath+'/ChaGBpRp.txt')

    zz = np.where( (sep3d.value < searchradpc.value) & (Gchi2 < vlim.value) & (np.isnan(r['bp_rp']) == False) ) # Note, this causes an error because NaNs
    yy = zz[0][np.argsort(sep3d[zz])]
    zz2= np.where( (sep3d.value < searchradpc.value) & (Gchi2 < vlim.value) & (sep.degree > 0.00001) & \
                 (r['phot_bp_rp_excess_factor'] < (1.3 + 0.06*r['bp_rp']**2)) & \
                 (np.isnan(r['bp_rp']) == False) )                                                              # Note, this causes an error because NaNs
    yy2= zz2[0][np.argsort((-Gchi2)[zz2])]


    figname=outdir + targname.replace(" ", "") + "cmd.png"
    if verbose == True: print(figname)

    fig,ax1 = plt.subplots(figsize=(12,8))

    ax1.axis([ math.floor(min(r['bp_rp'][zz])) , \
               math.ceil(max(r['bp_rp'][zz])), \
               math.ceil(max((r['phot_g_mean_mag'][zz] - (5.0*np.log10(gaiacoord.distance[zz].value)-5.0))))+1, \
               math.floor(min((r['phot_g_mean_mag'][zz] - (5.0*np.log10(gaiacoord.distance[zz].value)-5.0))))-1 ] )
    ax1.set_xlabel(r'$B_p-R_p$ (mag)' , fontsize=16)
    ax1.set_ylabel(r'$M_G$ (mag)' , fontsize=16)
    ax1.tick_params(axis='both',which='major',labelsize=12)

    ax2 = ax1.twiny()
    ax2.set_xlim(ax1.get_xlim())
    spttickvals = np.array([ -0.037 , 0.377 , 0.782 , 0.980 , 1.84 , 2.50 , 3.36 , 4.75 ])
    sptticklabs = np.array([ 'A0' , 'F0' , 'G0' , 'K0' , 'M0' , 'M3' , 'M5' , 'M7' ])
    xx = np.where( (spttickvals >= math.floor(min(r['bp_rp'][zz]))) & (spttickvals <= math.ceil(max(r['bp_rp'][zz]))) )[0]
    ax2.set_xticks(spttickvals[xx])
    ax2.set_xticklabels( sptticklabs[xx] )
    ax2.set_xlabel('SpT' , fontsize=16, labelpad=15)
    ax2.tick_params(axis='both',which='major',labelsize=12)

    ax1.plot(    chai[:,1] ,     chai[:,0]  , zorder=1 , label='Cha-I (0-5 Myr)')
    ax1.plot(    usco[:,1] ,     usco[:,0]  , zorder=2 , label='USco (11 Myr)')
    ax1.plot(  tuchor[:,1] ,   tuchor[:,0]  , zorder=3 , label='Tuc-Hor (40 Myr)')
    ax1.plot(pleiades[:,1] , pleiades[:,0]  , zorder=4 , label='Pleiades (125 Myr)')
    ax1.plot( mamajek[:,2] ,  mamajek[:,1]  , zorder=5 , label='Mamajek MS')

    for x in range(0 , np.array(yy2).size):
        msize  = (17-12.0*(sep3d[yy2[x]].value/searchradpc.value))**2
        mcolor = Gchi2[yy2[x]]
        medge  = 'black'
        mzorder= 7
        if (r['ruwe'][yy2[x]] < 1.2):
            mshape='o'
        if (r['ruwe'][yy2[x]] >= 1.2):
            mshape='s'
        if (np.isnan(rvcut) == False): 
            if (np.isnan(RV[yy2[x]])==False) & (np.abs(RV[yy2[x]]-Gvrpmllpmbb[yy2[x],0]) > rvcut):
                mshape='+'
                mcolor='black'
                mzorder=6
            if (np.isnan(RV[yy2[x]])==False) & (np.abs(RV[yy2[x]]-Gvrpmllpmbb[yy2[x],0]) <= rvcut):
                medge='blue'

        ccc = ax1.scatter(r['bp_rp'][yy2[x]] , (r['phot_g_mean_mag'][yy2[x]] - (5.0*np.log10(gaiacoord.distance[yy2[x]].value)-5.0)) , \
                s=msize , c=mcolor , marker=mshape , edgecolors=medge , zorder=mzorder , \
                vmin=0.0 , vmax=vlim.value , cmap='cubehelix' , label='_nolabel' )

    temp1 = ax1.scatter([] , [] , c='white' , edgecolors='black', marker='o' , s=12**2 , label = 'RUWE < 1.2')
    temp2 = ax1.scatter([] , [] , c='white' , edgecolors='black', marker='s' , s=12**2 , label = 'RUWE >= 1.2')
    temp3 = ax1.scatter([] , [] , c='white' , edgecolors='blue' , marker='o' , s=12**2 , label = 'RV Comoving')
    temp4 = ax1.scatter([] , [] , c='black' , marker='+' , s=12**2 , label = 'RV Outlier')

    ax1.plot(r['bp_rp'][yy[0]] , (r['phot_g_mean_mag'][yy[0]] - (5.0*np.log10(gaiacoord.distance[yy[0]].value)-5.0)) , \
             'rx' , markersize=18 , mew=3 , markeredgecolor='red' , zorder=10 , label=targname)

    ax1.arrow( 1.3 , 2.5 , 0.374, 0.743 , length_includes_head=True , head_width=0.07 , head_length = 0.10 )
    ax1.text(  1.4 , 2.3, r'$A_V=1$' , fontsize=12)



    ax1.legend(fontsize=11)
    cb = plt.colorbar(ccc , ax=ax1)
    cb.set_label(label='Velocity Difference (km/s)',fontsize=14)
    plt.savefig(figname , bbox_inches='tight', pad_inches=0.2 , dpi=200)
    if showplots == True: plt.show()
    plt.close('all')


    # Create PM plot


    zz2= np.where( (sep3d.value < searchradpc.value) & (Gchi2 < vlim.value) & (sep.degree > 0.00001) )
    yy2= zz2[0][np.argsort((-Gchi2)[zz2])]
    zz3= np.where( (sep3d.value < searchradpc.value) & (sep.degree > 0.00001) )

    figname=outdir + targname.replace(" ", "") + "pmd.png"

    fig,ax1 = plt.subplots(figsize=(12,8))

    ax1.axis([ (max(r['pmra'][zz2]) + 0.05*np.ptp(r['pmra'][zz2]) ) , \
           (min(r['pmra'][zz2]) - 0.05*np.ptp(r['pmra'][zz2]) ) , \
           (min(r['pmdec'][zz2])- 0.05*np.ptp(r['pmra'][zz2]) ) , \
           (max(r['pmdec'][zz2])+ 0.05*np.ptp(r['pmra'][zz2]) ) ] )
    ax1.tick_params(axis='both',which='major',labelsize=16)

    if  ((max(r['pmra'][zz2]) + 0.05*np.ptp(r['pmra'][zz2])) > 0.0) & \
            ((min(r['pmra'][zz2]) - 0.05*np.ptp(r['pmra'][zz2])) < 0.0) & \
            ((min(r['pmdec'][zz2])- 0.05*np.ptp(r['pmra'][zz2])) < 0.0) & \
            ((max(r['pmdec'][zz2])+ 0.05*np.ptp(r['pmra'][zz2])) > 0.0):
        ax1.plot( [0.0,0.0] , [-1000.0,1000.0] , 'k--' , linewidth=1 )
        ax1.plot( [-1000.0,1000.0] , [0.0,0.0] , 'k--' , linewidth=1 )

    ax1.errorbar( (r['pmra'][yy2]) , (r['pmdec'][yy2]) , \
            yerr=(r['pmdec_error'][yy2]) , xerr=(r['pmra_error'][yy2]) , fmt='none' , ecolor='k' )

    ax1.scatter( (r['pmra'][zz3]) , (r['pmdec'][zz3]) , \
              s=(0.5)**2 , marker='o' , c='black' , zorder=2 , label='Field' )

    for x in range(0 , np.array(yy2).size):
        msize  = (17-12.0*(sep3d[yy2[x]].value/searchradpc.value))**2
        mcolor = Gchi2[yy2[x]]
        medge  = 'black'
        mzorder= 7
        if (r['ruwe'][yy2[x]] < 1.2):
            mshape='o'
        if (r['ruwe'][yy2[x]] >= 1.2):
            mshape='s'
        if (np.isnan(rvcut) == False): 
            if (np.isnan(RV[yy2[x]])==False) & (np.abs(RV[yy2[x]]-Gvrpmllpmbb[yy2[x],0]) > rvcut):
                mshape='+'
                mcolor='black'
                mzorder=6
            if (np.isnan(RV[yy2[x]])==False) & (np.abs(RV[yy2[x]]-Gvrpmllpmbb[yy2[x],0]) <= rvcut):
                medge='blue'
        ccc = ax1.scatter(r['pmra'][yy2[x]] , r['pmdec'][yy2[x]] , \
                s=msize , c=mcolor , marker=mshape , edgecolors=medge , zorder=mzorder , \
                vmin=0.0 , vmax=vlim.value , cmap='cubehelix' , label='_nolabel' )

    temp1 = ax1.scatter([] , [] , c='white' , edgecolors='black', marker='o' , s=12**2 , label = 'RUWE < 1.2')
    temp2 = ax1.scatter([] , [] , c='white' , edgecolors='black', marker='s' , s=12**2 , label = 'RUWE >= 1.2')
    temp3 = ax1.scatter([] , [] , c='white' , edgecolors='blue' , marker='o' , s=12**2 , label = 'RV Comoving')
    temp4 = ax1.scatter([] , [] , c='black' , marker='+' , s=12**2 , label = 'RV Outlier')

    ax1.plot( Pgaia['pmra'][minpos] , Pgaia['pmdec'][minpos] , \
         'rx' , markersize=18 , mew=3 , markeredgecolor='red' , zorder=3 , label=targname)

    ax1.set_xlabel(r'$\mu_{RA}$ (mas/yr)' , fontsize=22 , labelpad=10)
    ax1.set_ylabel(r'$\mu_{DEC}$ (mas/yr)' , fontsize=22 , labelpad=10)
    ax1.legend(fontsize=12)

    cb = plt.colorbar(ccc , ax=ax1)
    cb.set_label(label='Tangential Velocity Difference (km/s)',fontsize=18 , labelpad=10)
    plt.savefig(figname , bbox_inches='tight', pad_inches=0.2 , dpi=200)
    if showplots == True: plt.show()
    plt.close('all')


    # Create RV plot

    zz2= np.where( (sep3d.value < searchradpc.value) & (Gchi2 < vlim.value) & (sep.degree > 0.00001) & \
             (np.isnan(RV) == False) )
    yy2= zz2[0][np.argsort((-Gchi2)[zz2])]

    zz3= np.where( (sep3d.value < searchradpc.value) & (Gchi2 < vlim.value) & (sep.degree > 0.00001) & \
             (np.isnan(RV) == False) & (np.isnan(r['phot_g_mean_mag']) == False) & \
             (np.abs(RV-Gvrpmllpmbb[:,0]) < 20.0) ) # Just to set Y axis

    fig,ax1 = plt.subplots(figsize=(12,8))
    ax1.axis([ -20.0 , +20.0, \
           max( np.append( np.array(r['phot_g_mean_mag'][zz3] - (5.0*np.log10(gaiacoord.distance[zz3].value)-5.0)) ,  0.0 )) + 0.3 , \
           min( np.append( np.array(r['phot_g_mean_mag'][zz3] - (5.0*np.log10(gaiacoord.distance[zz3].value)-5.0)) , 15.0 )) - 0.3   ])
    ax1.tick_params(axis='both',which='major',labelsize=16)

    ax1.plot( [0.0,0.0] , [-20.0,25.0] , 'k--' , linewidth=1 )

    ax1.errorbar( (RV[yy2]-Gvrpmllpmbb[yy2,0]) , \
           (r['phot_g_mean_mag'][yy2] - (5.0*np.log10(gaiacoord.distance[yy2].value)-5.0)) , \
            yerr=None,xerr=(RVerr[yy2]) , fmt='none' , ecolor='k' )

    for x in range(0 , np.array(yy2).size):
        msize  = (17-12.0*(sep3d[yy2[x]].value/searchradpc.value))**2
        mcolor = Gchi2[yy2[x]]
        medge  = 'black'
        mzorder= 2
        if (r['ruwe'][yy2[x]] < 1.2):
            mshape='o'
        if (r['ruwe'][yy2[x]] >= 1.2):
            mshape='s'
        ccc = ax1.scatter( (RV[yy2[x]]-Gvrpmllpmbb[yy2[x],0]) , \
                (r['phot_g_mean_mag'][yy2[x]] - (5.0*np.log10(gaiacoord.distance[yy2[x]].value)-5.0)) , \
                s=msize , c=mcolor , marker=mshape , edgecolors=medge , zorder=mzorder , \
                vmin=0.0 , vmax=vlim.value , cmap='cubehelix' , label='_nolabel' )

    temp1 = ax1.scatter([] , [] , c='white' , edgecolors='black', marker='o' , s=12**2 , label = 'RUWE < 1.2')
    temp2 = ax1.scatter([] , [] , c='white' , edgecolors='black', marker='s' , s=12**2 , label = 'RUWE >= 1.2')
    temp3 = ax1.scatter([] , [] , c='white' , edgecolors='blue' , marker='o' , s=12**2 , label = 'RV Comoving')

    if ( (Pgaia['phot_g_mean_mag'][minpos] - (5.0*np.log10(Pcoord.distance.value)-5.0)) < \
                                     (max( np.append( np.array(r['phot_g_mean_mag'][zz3] - (5.0*np.log10(gaiacoord.distance[zz3].value)-5.0)) , 0.0 )) + 0.3) ):
        ax1.plot( [0.0] , (Pgaia['phot_g_mean_mag'][minpos] - (5.0*np.log10(Pcoord.distance.value)-5.0)) , \
                  'rx' , markersize=18 , mew=3 , markeredgecolor='red' , zorder=3 , label=targname)


    ax1.set_ylabel(r'$M_G$ (mag)' , fontsize=22 , labelpad=10)
    ax1.set_xlabel(r'$v_{r,obs}-v_{r,pred}$ (km/s)' , fontsize=22 , labelpad=10)
    ax1.legend(fontsize=12)

    cb = plt.colorbar(ccc , ax=ax1)
    cb.set_label(label='Tangential Velocity Difference (km/s)',fontsize=18 , labelpad=10)

    figname=outdir + targname.replace(" ", "") + "drv.png"
    plt.savefig(figname , bbox_inches='tight', pad_inches=0.2 , dpi=200)
    if showplots == True: plt.show()
    plt.close('all')



    
    # Create XYZ plot

    Pxyz = bc.lbd_to_XYZ( Pllbb[0] , Pllbb[1] , Pcoord.distance.value/1000.0 , degree=True)

    fig,axs = plt.subplots(2,2)
    fig.set_figheight(16)
    fig.set_figwidth(16)
    fig.subplots_adjust(hspace=0.03,wspace=0.03)

    zz2= np.where( (sep3d.value < searchradpc.value) & (Gchi2 < vlim.value) & (sep.degree > 0.00001) )
    yy2= zz2[0][np.argsort((-Gchi2)[zz2])]

    for x in range(0 , np.array(yy2).size):
        msize  = (17-12.0*(sep3d[yy2[x]].value/searchradpc.value))**2
        mcolor = Gchi2[yy2[x]]
        medge  = 'black'
        mzorder= 3
        if (r['ruwe'][yy2[x]] < 1.2):
            mshape='o'
        if (r['ruwe'][yy2[x]] >= 1.2):
            mshape='s'
        if (np.isnan(rvcut) == False): 
            if (np.isnan(RV[yy2[x]])==False) & (np.abs(RV[yy2[x]]-Gvrpmllpmbb[yy2[x],0]) > rvcut):
                mshape='+'
                mcolor='black'
                mzorder=2
            if (np.isnan(RV[yy2[x]])==False) & (np.abs(RV[yy2[x]]-Gvrpmllpmbb[yy2[x],0]) <= rvcut):
                medge='blue'
        ccc = axs[0,0].scatter( 1000.0*Gxyz[yy2[x],0] , 1000.0*Gxyz[yy2[x],1] , \
                s=msize , c=mcolor , marker=mshape , edgecolors=medge , zorder=mzorder , \
                vmin=0.0 , vmax=vlim.value , cmap='cubehelix' , label='_nolabel' )
        ccc = axs[0,1].scatter( 1000.0*Gxyz[yy2[x],2] , 1000.0*Gxyz[yy2[x],1] , \
                s=msize , c=mcolor , marker=mshape , edgecolors=medge , zorder=mzorder , \
                vmin=0.0 , vmax=vlim.value , cmap='cubehelix' , label='_nolabel' )
        ccc = axs[1,0].scatter( 1000.0*Gxyz[yy2[x],0] , 1000.0*Gxyz[yy2[x],2] , \
                s=msize , c=mcolor , marker=mshape , edgecolors=medge , zorder=mzorder , \
                vmin=0.0 , vmax=vlim.value , cmap='cubehelix' , label='_nolabel' )

    temp1 = axs[0,0].scatter([] , [] , c='white' , edgecolors='black', marker='o' , s=12**2 , label = 'RUWE < 1.2')
    temp2 = axs[0,0].scatter([] , [] , c='white' , edgecolors='black', marker='s' , s=12**2 , label = 'RUWE >= 1.2')
    temp3 = axs[0,0].scatter([] , [] , c='white' , edgecolors='blue' , marker='o' , s=12**2 , label = 'RV Comoving')
    temp4 = axs[0,0].scatter([] , [] , c='black' , marker='+' , s=12**2 , label = 'RV Outlier')

    axs[0,0].plot( 1000.0*Pxyz[0] , 1000.0*Pxyz[1] , 'rx' , markersize=18 , mew=3 , markeredgecolor='red')
    axs[0,1].plot( 1000.0*Pxyz[2] , 1000.0*Pxyz[1] , 'rx' , markersize=18 , mew=3 , markeredgecolor='red')
    axs[1,0].plot( 1000.0*Pxyz[0] , 1000.0*Pxyz[2] , 'rx' , markersize=18 , mew=3 , markeredgecolor='red' , zorder=1 , label = targname)

    axs[0,0].set_xlim( [1000.0*Pxyz[0]-(search_radius+1.0) , 1000.0*Pxyz[0]+(search_radius+1.0)] )
    axs[0,0].set_ylim( [1000.0*Pxyz[1]-(search_radius+1.0) , 1000.0*Pxyz[1]+(search_radius+1.0)] )
    axs[0,1].set_xlim( [1000.0*Pxyz[2]-(search_radius+1.0) , 1000.0*Pxyz[2]+(search_radius+1.0)] )
    axs[0,1].set_ylim( [1000.0*Pxyz[1]-(search_radius+1.0) , 1000.0*Pxyz[1]+(search_radius+1.0)] )
    axs[1,0].set_xlim( [1000.0*Pxyz[0]-(search_radius+1.0) , 1000.0*Pxyz[0]+(search_radius+1.0)] )
    axs[1,0].set_ylim( [1000.0*Pxyz[2]-(search_radius+1.0) , 1000.0*Pxyz[2]+(search_radius+1.0)] )
    
    axs[0,0].set_xlabel(r'$X$ (pc)',fontsize=20,labelpad=10)
    axs[0,0].set_ylabel(r'$Y$ (pc)',fontsize=20,labelpad=10)

    axs[1,0].set_xlabel(r'$X$ (pc)',fontsize=20,labelpad=10)
    axs[1,0].set_ylabel(r'$Z$ (pc)',fontsize=20,labelpad=10)

    axs[0,1].set_xlabel(r'$Z$ (pc)',fontsize=20,labelpad=10)
    axs[0,1].set_ylabel(r'$Y$ (pc)',fontsize=20,labelpad=10)

    axs[0,0].xaxis.set_ticks_position('top')
    axs[0,1].xaxis.set_ticks_position('top')
    axs[0,1].yaxis.set_ticks_position('right')

    axs[0,0].xaxis.set_label_position('top')
    axs[0,1].xaxis.set_label_position('top')
    axs[0,1].yaxis.set_label_position('right')

    for aa in [0,1]:
        for bb in [0,1]:
            axs[aa,bb].tick_params(top=True,bottom=True,left=True,right=True,direction='in',labelsize=18)

    fig.delaxes(axs[1][1])
    strsize = 26
    if (len(targname) > 12.0): strsize = np.floor(24 / (len(targname)/14.5))
    fig.legend( bbox_to_anchor=(0.92,0.37) , prop={'size':strsize})

    cbaxes = fig.add_axes([0.55,0.14,0.02,0.34])
    cb = plt.colorbar( ccc , cax=cbaxes )
    cb.set_label( label='Velocity Difference (km/s)' , fontsize=24 , labelpad=20 )
    cb.ax.tick_params(labelsize=18)

    figname=outdir + targname.replace(" ", "") + "xyz.png"
    plt.savefig(figname , bbox_inches='tight', pad_inches=0.2 , dpi=200)

    if showplots == True: plt.show()
    plt.close('all')



    # Create sky map
    # Hacked from cartopy.mpl.gridliner
    _DEGREE_SYMBOL = u'\u00B0'
    def _east_west_formatted(longitude, num_format='g'):
        fmt_string = u'{longitude:{num_format}}{degree}'
        return fmt_string.format(longitude=(longitude if (longitude >= 0) else (longitude + 360)) , \
                                            num_format=num_format,degree=_DEGREE_SYMBOL)
    def _north_south_formatted(latitude, num_format='g'):
        fmt_string = u'{latitude:{num_format}}{degree}'
        return fmt_string.format(latitude=latitude, num_format=num_format,degree=_DEGREE_SYMBOL)
    LONGITUDE_FORMATTER = mticker.FuncFormatter(lambda v, pos:
                                                _east_west_formatted(v))
    LATITUDE_FORMATTER = mticker.FuncFormatter(lambda v, pos:
                                               _north_south_formatted(v))

    zz = np.where( (sep3d.value < searchradpc.value) & (Gchi2 < vlim.value) & (sep.degree > 0.00001) )
    yy = zz[0][np.argsort((-Gchi2)[zz])]

    searchcircle = Pcoord.directional_offset_by( (np.arange(0,360)*u.degree) , searchraddeg*np.ones(360))
    circleRA = searchcircle.ra.value
    circleDE = searchcircle.dec.value
    ww = np.where(circleRA > 180.0)
    circleRA[ww] = circleRA[ww] - 360.0

    RAlist = gaiacoord.ra[yy].value
    DElist = gaiacoord.dec[yy].value
    ww = np.where( RAlist > 180.0 )
    RAlist[ww] = RAlist[ww] - 360.0

    polelat = ((Pcoord.dec.value+90) if (Pcoord.dec.value<0) else (90-Pcoord.dec.value))
    polelong= (Pcoord.ra.value if (Pcoord.dec.value<0.0) else (Pcoord.ra.value+180.0))
    polelong= (polelong if polelong < 180 else polelong - 360.0)

    if verbose == True:
        print('Alignment variables: ',polelat,polelong,Pcoord.ra.value)
        print(Pcoord.dec.value+searchraddeg.value)
    rotated_pole = ccrs.RotatedPole( \
        pole_latitude=polelat , \
        pole_longitude=polelong , \
        central_rotated_longitude=90.0 )#\
    #    (Pcoord.ra.value if (Pcoord.dec.value > 0.0) else (Pcoord.ra.value+180.0)) )

    fig = plt.figure(figsize=(8,8))
    ax = fig.add_subplot(1, 1, 1, projection=rotated_pole)

    ax.gridlines(draw_labels=True,x_inline=True,y_inline=True, \
                 xformatter=LONGITUDE_FORMATTER,yformatter=LATITUDE_FORMATTER)
    ax.plot( circleRA , circleDE , c="gray" , ls="--" , transform=ccrs.Geodetic())
    
    figname=outdir + targname.replace(" ", "") + "sky.png"

    base=plt.cm.get_cmap('cubehelix')

    for x in range(0 , np.array(yy).size):
        msize  = (17-12.0*(sep3d[yy[x]].value/searchradpc.value))
        mcolor = base(Gchi2[yy[x]]/vlim.value)
        medge  = 'black'
        mzorder= 3
        if (r['ruwe'][yy[x]] < 1.2):
            mshape='o'
        if (r['ruwe'][yy[x]] >= 1.2):
            mshape='s'
        if (np.isnan(rvcut) == False): 
            if (np.isnan(RV[yy[x]])==False) & (np.abs(RV[yy[x]]-Gvrpmllpmbb[yy[x],0]) > rvcut):
                mshape='+'
                mcolor='black'
                mzorder=2
            if (np.isnan(RV[yy[x]])==False) & (np.abs(RV[yy[x]]-Gvrpmllpmbb[yy[x],0]) <= rvcut):
                medge='blue'
        ccc = ax.plot( RAlist[x] , DElist[x] , marker=mshape ,  \
                markeredgecolor=medge , ms = msize , mfc = mcolor , transform=ccrs.Geodetic() )
        
    ax.plot( (Pcoord.ra.value-360.0) , Pcoord.dec.value , \
            'rx' , markersize=18 , mew=3 , transform=ccrs.Geodetic())

    plt.savefig(figname , bbox_inches='tight', pad_inches=0.2 , dpi=200)
    
    if showplots == True: plt.show()
    plt.close('all')

    ## Query GALEX and 2MASS data

    zz = np.where( (sep3d.value < searchradpc.value) & (Gchi2 < vlim.value) )
    yy = zz[0][np.argsort((-Gchi2)[zz])]
    
    NUVmag = np.empty(np.array(r['ra']).size)
    NUVerr = np.empty(np.array(r['ra']).size)
    NUVmag[:] = np.nan
    NUVerr[:] = np.nan

    print('Searching on neighbors in GALEX')
    ##suppress the stupid noresultswarning from the catalogs package
    warnings.filterwarnings("ignore",category=NoResultsWarning)

    for x in range(0 , np.array(yy).size):
        querystring=((str(gaiacoord.ra[yy[x]].value) if (gaiacoord.ra[yy[x]].value > 0) \
                      else str(gaiacoord.ra[yy[x]].value+360.0)) + " " + str(gaiacoord.dec[yy[x]].value))
        print('GALEX query ',x,' of ',np.array(yy).size, end='\r')
        if verbose == True: print('GALEX query ',x,' of ',np.array(yy).size)
        if verbose == True: print(querystring)
        if (DoGALEX == True): 
            galex = Catalogs.query_object(querystring , catalog="Galex" , radius=0.0028 , TIMEOUT=600)
            if ((np.where(galex['nuv_magerr'] > 0.0)[0]).size > 0):
                ww = np.where( (galex['nuv_magerr'] == min(galex['nuv_magerr'][np.where(galex['nuv_magerr'] > 0.0)])))
                NUVmag[yy[x]] = galex['nuv_mag'][ww][0]
                NUVerr[yy[x]] = galex['nuv_magerr'][ww][0]
                if verbose == True: print(galex['distance_arcmin','ra','nuv_mag','nuv_magerr'][ww])

        
    Jmag = np.empty(np.array(r['ra']).size)
    Jerr = np.empty(np.array(r['ra']).size)
    Jmag[:] = np.nan
    Jerr[:] = np.nan

    print('Searching on neighbors in 2MASS')

    for x in range(0 , np.array(yy).size):
        if ( np.isnan(NUVmag[yy[x]]) == False ):
            querycoord = SkyCoord((str(gaiacoord.ra[yy[x]].value) if (gaiacoord.ra[yy[x]].value > 0) else \
                     str(gaiacoord.ra[yy[x]].value+360.0)) , str(gaiacoord.dec[yy[x]].value) , \
                     unit=(u.deg,u.deg) , frame='icrs')
            print('2MASS query ',x,' of ',np.array(yy).size, end='\r')
            if verbose == True: print('2MASS query ',x,' of ',np.array(yy).size)
            if verbose == True: print(querycoord)
            tmass = []
            if (DoGALEX == True): 
                tmass = Irsa.query_region(querycoord , catalog='fp_psc' , radius='0d0m10s' )
                if ((np.where(tmass['j_m'] > -10.0)[0]).size > 0):
                    ww = np.where( (tmass['j_m'] == min(tmass['j_m'][np.where(tmass['j_m'] > 0.0)])))
                    Jmag[yy[x]] = tmass['j_m'][ww][0]
                    Jerr[yy[x]] = tmass['j_cmsig'][ww][0]
                    if verbose == True: print(tmass['j_m','j_cmsig'][ww])
        


    # Create GALEX plots
    mamajek = np.loadtxt(datapath+'/sptGBpRp.txt')
    f = interp1d( mamajek[:,2] , mamajek[:,0] , kind='cubic')

    zz2 = np.where( (sep3d.value < searchradpc.value) & (Gchi2 < vlim.value) )
    yy2 = zz[0][np.argsort(sep3d[zz])]
    zz = np.where( (sep3d.value < searchradpc.value) & (Gchi2 < vlim.value) & (sep.degree > 0.00001) )
    yy = zz[0][np.argsort((-Gchi2)[zz])]

    fnuvj = (3631.0 * 10**6 * 10**(-0.4 * NUVmag)) / (1594.0 * 10**6 * 10**(-0.4 * Jmag))
    spt = f(r['bp_rp'].filled(np.nan))
    sptstring = ["nan" for x in range(np.array(r['bp_rp']).size)]
    for x in range(0 , np.array(zz2).size):
        if (round(spt[yy2[x]],1) >= 17.0) and (round(spt[yy2[x]],1) < 27.0):
            sptstring[yy2[x]] = 'M' + ('% 3.1f' % (round(spt[yy2[x]],1)-17.0)).strip()
        if (round(spt[yy2[x]],1) >= 16.0) and (round(spt[yy2[x]],1) < 17.0):
            sptstring[yy2[x]] = 'K' + ('% 3.1f' % (round(spt[yy2[x]],1)-9.0)).strip()
        if (round(spt[yy2[x]],1) >= 10.0) and (round(spt[yy2[x]],1) < 16.0):
            sptstring[yy2[x]] = 'K' + ('% 3.1f' % (round(spt[yy2[x]],1)-10.0)).strip()
        if (round(spt[yy2[x]],1) >= 0.0) and (round(spt[yy2[x]],1) < 10.0):
            sptstring[yy2[x]] = 'G' + ('% 3.1f' % (round(spt[yy2[x]],1)-0.0)).strip()
        if (round(spt[yy2[x]],1) >= -10.0) and (round(spt[yy2[x]],1) < 0.0):
            sptstring[yy2[x]] = 'F' + ('% 3.1f' % (round(spt[yy2[x]],1)+10.0)).strip()
        if (round(spt[yy2[x]],1) >= -20.0) and (round(spt[yy2[x]],1) < -10.0):
            sptstring[yy2[x]] = 'A' + ('% 3.1f' % (round(spt[yy2[x]],1)+20.0)).strip()       
        if (round(spt[yy2[x]],1) >= -30.0) and (round(spt[yy2[x]],1) < -20.0):
            sptstring[yy2[x]] = 'B' + ('% 3.1f' % (round(spt[yy2[x]],1)+30.0)).strip()  
    


    figname=outdir + targname.replace(" ", "") + "galex.png"
    if verbose == True: print(figname)
    ##Muck with the axis to get two x axes

    fig,ax1 = plt.subplots(figsize=(12,8))
    ax1.set_yscale('log')
    ax1.axis([5.0 , 24.0 , 0.000004 , 0.02])
    ax2 = ax1.twiny()
    ax2.set_xlim(ax1.get_xlim())
    ax1.set_xticks(np.array([5.0 , 10.0 , 15.0 , 17.0 , 22.0 , 24.0]))
    ax1.set_xticklabels(['G5','K0','K5','M0','M5','M7'])
    ax1.set_xlabel('SpT' , fontsize=20, labelpad=15)
    ax1.tick_params(axis='both',which='major',labelsize=16)
    ax2.set_xticks(np.array([5.0 , 10.0 , 15.0 , 17.0 , 22.0 , 24.0]))
    ax2.set_xticklabels(['0.85','0.98','1.45','1.84','3.36','4.75'])
    ax2.set_xlabel(r'$B_p-R_p$ (mag)' , fontsize=20, labelpad=15)
    ax2.tick_params(axis='both',which='major',labelsize=16)
    ax1.set_ylabel(r'$F_{NUV}/F_{J}$' , fontsize=22, labelpad=0)

    ##Hyades
    hyades = readsav(datapath +'/HYsaved.sav')
    hyadesfnuvj = (3631.0 * 10**6 * 10**(-0.4 * hyades['clnuv'])) / (1594.0 * 10**6 * 10**(-0.4 * hyades['clJ']))
    ax1.plot(hyades['clspt'] , hyadesfnuvj , 'x' , markersize=4 , mew=1 , markeredgecolor='black' , zorder=1 , label='Hyades' )

    for x in range(0 , np.array(yy).size):
        msize  = (17-12.0*(sep3d[yy[x]].value/searchradpc.value))**2
        mcolor = Gchi2[yy[x]]
        medge  = 'black'
        mzorder= 3
        if (r['ruwe'][yy[x]] < 1.2):
            mshape='o'
        if (r['ruwe'][yy[x]] >= 1.2):
            mshape='s'
        if (np.isnan(rvcut) == False): 
            if (np.isnan(RV[yy[x]])==False) & (np.abs(RV[yy[x]]-Gvrpmllpmbb[yy[x],0]) > rvcut):
                mshape='+'
                mcolor='black'
                mzorder=2
            if (np.isnan(RV[yy[x]])==False) & (np.abs(RV[yy[x]]-Gvrpmllpmbb[yy[x],0]) <= rvcut):
                medge='blue'
        ccc = ax1.scatter( spt[yy[x]] , fnuvj[yy[x]] , \
                s=msize , c=mcolor , marker=mshape , edgecolors=medge , zorder=mzorder , \
                vmin=0.0 , vmax=vlim.value , cmap='cubehelix' , label='_nolabel' )

    temp1 = ax1.scatter([] , [] , c='white' , edgecolors='black', marker='o' , s=12**2 , label = 'RUWE < 1.2')
    temp2 = ax1.scatter([] , [] , c='white' , edgecolors='black', marker='s' , s=12**2 , label = 'RUWE >= 1.2')
    temp3 = ax1.scatter([] , [] , c='white' , edgecolors='blue' , marker='o' , s=12**2 , label = 'RV Comoving')
    temp4 = ax1.scatter([] , [] , c='black' , marker='+' , s=12**2 , label = 'RV Outlier')



    # Plot science target
    if (spt[yy[0]] > 5): ax1.plot(spt[yy[0]] , fnuvj[yy[0]] , 'rx' , markersize=18 , mew=3 , markeredgecolor='red' , zorder=3 , label=targname )

    ax1.legend(fontsize=16 , loc='lower left')
    cb = fig.colorbar(ccc , ax=ax1)
    cb.set_label(label='Velocity Offset (km/s)',fontsize=13)
    if (DoGALEX == True): plt.savefig(figname , bbox_inches='tight', pad_inches=0.2 , dpi=200)
    if showplots == True: plt.show()
    plt.close('all')
    
    
    # Query CatWISE for W1+W2 and AllWISE for W3+W4

    zz = np.where( (sep3d.value < searchradpc.value) & (Gchi2 < vlim.value) )
    yy = zz[0][np.argsort((-Gchi2)[zz])]

    WISEmag = np.empty([np.array(r['ra']).size,4])
    WISEerr = np.empty([np.array(r['ra']).size,4])
    WISEmag[:] = np.nan
    WISEerr[:] = np.nan

    print('Searching on neighbors in WISE')
    ##there's an annoying nan warning here, hide it for now as it's not a problem
    warnings.filterwarnings("ignore",category=UserWarning)

    for x in range(0 , np.array(yy).size):
        querycoord = SkyCoord((str(gaiacoord.ra[yy[x]].value) if (gaiacoord.ra[yy[x]].value > 0) else \
                     str(gaiacoord.ra[yy[x]].value+360.0)) , str(gaiacoord.dec[yy[x]].value) , \
                     unit=(u.deg,u.deg) , frame='icrs')
        print('WISE query ',x,' of ',np.array(yy).size, end='\r')
        if verbose == True: print('WISE query ',x,' of ',np.array(yy).size)
        if verbose == True: print(querycoord)
    
        wisecat = []
        if (DoWISE == True): 
            wisecat = Irsa.query_region(querycoord,catalog='catwise_2020' , radius='0d0m10s')
            if ((np.where(wisecat['w1mpro'] > -10.0)[0]).size > 0):
                ww = np.where( (wisecat['w1mpro'] == min( wisecat['w1mpro'][np.where(wisecat['w1mpro'] > -10.0)]) ))
                WISEmag[yy[x],0] = wisecat['w1mpro'][ww][0]
                WISEerr[yy[x],0] = wisecat['w1sigmpro'][ww][0]
            if ((np.where(wisecat['w2mpro'] > -10.0)[0]).size > 0):
                ww = np.where( (wisecat['w2mpro'] == min( wisecat['w2mpro'][np.where(wisecat['w2mpro'] > -10.0)]) ))
                WISEmag[yy[x],1] = wisecat['w2mpro'][ww][0]
                WISEerr[yy[x],1] = wisecat['w2sigmpro'][ww][0]
 
        if (DoWISE == True): 
            wisecat = Irsa.query_region(querycoord,catalog='allwise_p3as_psd' , radius='0d0m10s')
            if ((np.where(wisecat['w1mpro'] > -10.0)[0]).size > 0):
                ww = np.where( (wisecat['w1mpro'] == min( wisecat['w1mpro'][np.where(wisecat['w1mpro'] > -10.0)]) ))
                if (np.isnan(WISEmag[yy[x],0]) == True) | (wisecat['w1mpro'][ww][0] < 11.0):				# Note, only if CatWISE absent/saturated
                    WISEmag[yy[x],0] = wisecat['w1mpro'][ww][0]
                    WISEerr[yy[x],0] = wisecat['w1sigmpro'][ww][0]
            if ((np.where(wisecat['w2mpro'] > -10.0)[0]).size > 0):
                ww = np.where( (wisecat['w2mpro'] == min( wisecat['w2mpro'][np.where(wisecat['w2mpro'] > -10.0)]) ))
                if (np.isnan(WISEmag[yy[x],1]) == True) | (wisecat['w2mpro'][ww][0] < 11.0):				# Note, only if CatWISE absent/saturated
                    WISEmag[yy[x],1] = wisecat['w2mpro'][ww][0]
                    WISEerr[yy[x],1] = wisecat['w2sigmpro'][ww][0]
            if ((np.where(wisecat['w3mpro'] > -10.0)[0]).size > 0):
                ww = np.where( (wisecat['w3mpro'] == min( wisecat['w3mpro'][np.where(wisecat['w3mpro'] > -10.0)]) ))
                WISEmag[yy[x],2] = wisecat['w3mpro'][ww][0]
                WISEerr[yy[x],2] = wisecat['w3sigmpro'][ww][0]
            if ((np.where(wisecat['w4mpro'] > -10.0)[0]).size > 0):
                ww = np.where( (wisecat['w4mpro'] == min( wisecat['w4mpro'][np.where(wisecat['w4mpro'] > -10.0)]) ))
                WISEmag[yy[x],3] = wisecat['w4mpro'][ww][0]
                WISEerr[yy[x],3] = wisecat['w4sigmpro'][ww][0]
        
        if verbose == True: print(yy[x],WISEmag[yy[x],:],WISEerr[yy[x],:])

    # Create WISE plots

    W13 = WISEmag[:,0]-WISEmag[:,2]
    W13err = ( WISEerr[:,0]**2 + WISEerr[:,2]**2 )**0.5

    zz = np.argwhere( np.isnan(W13err) )
    W13[zz] = np.nan
    W13err[zz] = np.nan

    zz = np.where( (W13err > 0.15) )
    W13[zz] = np.nan
    W13err[zz] = np.nan
    warnings.filterwarnings("default",category=UserWarning)




    zz2 = np.where( (sep3d.value < searchradpc.value) & (Gchi2 < vlim.value))
    yy2 = zz[0][np.argsort(sep3d[zz])]
    zz = np.where( (sep3d.value < searchradpc.value) & (Gchi2 < vlim.value) & (sep.degree > 0.00001) )
    yy = zz[0][np.argsort((-Gchi2)[zz])]

    figname=outdir + targname.replace(" ", "") + "wise.png"
    if verbose == True: print(figname)
    plt.figure(figsize=(12,8))

    if (verbose == True) & ((np.where(np.isfinite(W13+W13err))[0]).size > 0): print('Max y value: ' , (max((W13+W13err)[np.isfinite(W13+W13err)])+0.1) )
    plt.axis([ 5.0 , 24.0 , \
              max( [(min(np.append((W13-W13err)[ np.isfinite(W13-W13err) ],-0.1))-0.1) , -0.3]) , \
              max( [(max(np.append((W13+W13err)[ np.isfinite(W13+W13err) ],+0.0))+0.2) , +0.6]) ])

    ax1 = plt.gca()
    ax2 = ax1.twiny()
    ax2.set_xlim(5.0,24.0)

    ax1.set_xticks(np.array([5.0 , 10.0 , 15.0 , 17.0 , 22.0 , 24.0]))
    ax1.set_xticklabels(['G5','K0','K5','M0','M5','M7'])
    ax1.set_xlabel('SpT' , fontsize=20, labelpad=15)
    ax1.tick_params(axis='both',which='major',labelsize=16)

    ax2.set_xticks(np.array([5.0 , 10.0 , 15.0 , 17.0 , 22.0 , 24.0]))
    ax2.set_xticklabels(['0.85','0.98','1.45','1.84','3.36','4.75'])
    ax2.set_xlabel(r'$B_p-R_p$ (mag)' , fontsize=20, labelpad=15)
    ax2.tick_params(axis='both',which='major',labelsize=16)

    ax1.set_ylabel(r'$W1-W3$ (mag)' , fontsize=22, labelpad=0)

    # Plot field sequence from Tuc-Hor (Kraus et al. 2014)
    fldspt = [ 5 , 7 , 10 , 12 , 15 , 17 , 20 , 22 , 24 ]
    fldW13 = [ 0 , 0 ,  0 , .02, .06, .12, .27, .40, .60]
    plt.plot(fldspt , fldW13  , zorder=0 , label='Photosphere')

    # Plot neighbors
    ax1.errorbar( spt[yy] , W13[yy] , yerr=W13err[yy] , fmt='none' , ecolor='k')


    for x in range(0 , np.array(yy).size):
        msize  = (17-12.0*(sep3d[yy[x]].value/searchradpc.value))**2
        mcolor = Gchi2[yy[x]]
        medge  = 'black'
        mzorder= 3
        if (r['ruwe'][yy[x]] < 1.2):
            mshape='o'
        if (r['ruwe'][yy[x]] >= 1.2):
            mshape='s'
        if (np.isnan(rvcut) == False): 
            if (np.isnan(RV[yy[x]])==False) & (np.abs(RV[yy[x]]-Gvrpmllpmbb[yy[x],0]) > rvcut):
                mshape='+'
                mcolor='black'
                mzorder=2
            if (np.isnan(RV[yy[x]])==False) & (np.abs(RV[yy[x]]-Gvrpmllpmbb[yy[x],0]) <= rvcut):
                medge='blue'
        ccc = ax1.scatter( spt[yy[x]] , W13[yy[x]] , \
                s=msize , c=mcolor , marker=mshape , edgecolors=medge , zorder=mzorder , \
                vmin=0.0 , vmax=vlim.value , cmap='cubehelix' , label='_nolabel' )

    temp1 = ax1.scatter([] , [] , c='white' , edgecolors='black', marker='o' , s=12**2 , label = 'RUWE < 1.2')
    temp2 = ax1.scatter([] , [] , c='white' , edgecolors='black', marker='s' , s=12**2 , label = 'RUWE >= 1.2')
    temp3 = ax1.scatter([] , [] , c='white' , edgecolors='blue' , marker='o' , s=12**2 , label = 'RV Comoving')
    temp4 = ax1.scatter([] , [] , c='black' , marker='+' , s=12**2 , label = 'RV Outlier')


    # Plot science target
    if (spt[yy2[0]] > 5):
        plt.plot(spt[yy2[0]] , W13[yy2[0]] , 'rx' , markersize=18 , mew=3 , markeredgecolor='red' , zorder=3 , label=targname )

    plt.legend(fontsize=16 , loc='upper left')
    cb = plt.colorbar(ccc , ax=ax1)
    cb.set_label(label='Velocity Offset (km/s)',fontsize=14)
    if (DoWISE == True): plt.savefig(figname , bbox_inches='tight', pad_inches=0.2 , dpi=200)
    if showplots == True: plt.show()
    plt.close('all')

    # Cross-reference with ROSAT

    v = Vizier(columns=["**", "+_R"] , catalog='J/A+A/588/A103/cat2rxs' )

    zz = np.where( (sep3d.value < searchradpc.value) & (Gchi2 < vlim.value) )
    yy = zz[0][np.argsort(sep3d[zz])]

    ROSATflux = np.empty([np.array(r['ra']).size])
    ROSATflux[:] = np.nan

    print('Searching on neighbors in ROSAT')
    for x in range(0 , np.array(yy).size):
        querycoord = SkyCoord((str(gaiacoord.ra[yy[x]].value) if (gaiacoord.ra[yy[x]].value > 0) else \
                     str(gaiacoord.ra[yy[x]].value+360.0)) , str(gaiacoord.dec[yy[x]].value) , \
                     unit=(u.deg,u.deg) , frame='icrs')
        print('ROSAT query ',x,' of ',np.array(yy).size, end='\r')
        if verbose == True: print('ROSAT query ',x,' of ',np.array(yy).size)
        if verbose == True: print(querycoord)
        if (DoROSAT == True): 
            rosatcat = v.query_region(querycoord , radius='0d1m0s' )
            if (len(rosatcat) > 0):
                rosatcat = rosatcat['J/A+A/588/A103/cat2rxs']
                if verbose == True: print(rosatcat)
                if ((np.where(rosatcat['CRate'] > -999)[0]).size > 0):
                    ww = np.where( (rosatcat['CRate'] == max(rosatcat['CRate'][np.where(rosatcat['CRate'] > -999)])))
                    ROSATflux[yy[x]] = rosatcat['CRate'][ww][0]
                if verbose == True: print(x,yy[x],ROSATflux[yy[x]])


    # Create output table with results
    print('Creating Output Tables with Results')
    if verbose == True: 
        print('Reminder, there were this many input entries: ',len(Gxyz[:,0]))
        print('The search radius in velocity space is: ',vlim)
        print()

    zz = np.where( (sep3d.value < searchradpc.value) & (Gchi2 < vlim.value) )
    sortlist = np.argsort(sep3d[zz])
    yy = zz[0][sortlist]

    fmt1 = "%11.7f %11.7f %6.3f %6.3f %11.3f %8.4f %8.4f %8.2f %8.2f %8.2f %8.3f %4s %8.6f %6.2f %7.3f %7.3f %35s"
    fmt2 = "%11.7f %11.7f %6.3f %6.3f %11.3f %8.4f %8.4f %8.2f %8.2f %8.2f %8.3f %4s %8.6f %6.2f %7.3f %7.3f %35s"
    filename=outdir + targname.replace(" ", "") + ".txt"
    
    warnings.filterwarnings("ignore",category=UserWarning)
    if verbose == True: 
        print('Also creating SIMBAD query table')
        print(filename)
        print('RA            DEC        Gmag   Bp-Rp  Voff(km/s) Sep(deg)   3D(pc) Vr(pred)  Vr(obs)    Vrerr Plx(mas)  SpT    FnuvJ  W1-W3    RUWE  XCrate RVsrc')
    with open(filename,'w') as file1:
        file1.write('RA            DEC        Gmag   Bp-Rp  Voff(km/s) Sep(deg)   3D(pc) Vr(pred)  Vr(obs)    Vrerr Plx(mas)  SpT    FnuvJ  W1-W3    RUWE  XCrate RVsrc \n')
    for x in range(0 , np.array(zz).size):
            if verbose == True:
                print(fmt1 % (gaiacoord.ra[yy[x]].value,gaiacoord.dec[yy[x]].value, \
                  r['phot_g_mean_mag'][yy[x]], r['bp_rp'][yy[x]] , \
                  Gchi2[yy[x]] , sep[yy[x]].value , sep3d[yy[x]].value , \
                  Gvrpmllpmbb[yy[x],0] , RV[yy[x]] , RVerr[yy[x]] , \
                  r['parallax'][yy[x]], \
                  sptstring[yy[x]] , fnuvj[yy[x]] , W13[yy[x]] , r['ruwe'][yy[x]] , ROSATflux[yy[x]] , RVsrc[yy[x]]) )
            with open(filename,'a') as file1:
                  file1.write(fmt2 % (gaiacoord.ra[yy[x]].value,gaiacoord.dec[yy[x]].value, \
                      r['phot_g_mean_mag'][yy[x]], r['bp_rp'][yy[x]] , \
                      Gchi2[yy[x]],sep[yy[x]].value,sep3d[yy[x]].value , \
                      Gvrpmllpmbb[yy[x],0] , RV[yy[x]] , RVerr[yy[x]] , \
                      r['parallax'][yy[x]], \
                      sptstring[yy[x]] , fnuvj[yy[x]] , W13[yy[x]] , r['ruwe'][yy[x]] , ROSATflux[yy[x]] , RVsrc[yy[x]]) )
                  file1.write("\n")

    filename=outdir + targname.replace(" ", "") + ".csv"
    with open(filename,mode='w') as result_file:
        wr = csv.writer(result_file)
        wr.writerow(['RA','DEC','Gmag','Bp-Rp','Voff(km/s)','Sep(deg)','3D(pc)','Vr(pred)','Vr(obs)','Vrerr','Plx(mas)','SpT','FnuvJ','W1-W3','RUWE','XCrate','RVsrc'])
        for x in range(0 , np.array(zz).size):
            wr.writerow(( "{0:.7f}".format(gaiacoord.ra[yy[x]].value) , "{0:.7f}".format(gaiacoord.dec[yy[x]].value) , \
                      "{0:.3f}".format(r['phot_g_mean_mag'][yy[x]]), "{0:.3f}".format(r['bp_rp'][yy[x]]) , \
                      "{0:.3f}".format(Gchi2[yy[x]]) , "{0:.4f}".format(sep[yy[x]].value) , "{0:.4f}".format(sep3d[yy[x]].value) , \
                      "{0:.2f}".format(Gvrpmllpmbb[yy[x],0]) , "{0:.2f}".format(RV[yy[x]]) , "{0:.2f}".format(RVerr[yy[x]]) , \
                      "{0:.3f}".format(r['parallax'][yy[x]]), \
                      sptstring[yy[x]] , "{0:.6f}".format(fnuvj[yy[x]]) , "{0:.2f}".format(W13[yy[x]]) , \
                      "{0:.3f}".format(r['ruwe'][yy[x]]) , "{0:.3f}".format(ROSATflux[yy[x]]) , RVsrc[yy[x]].strip()) )

    if verbose == True: print('All output can be found in ' + outdir)



    return outdir
Example #5
0
    def propagate_initial(self,
                          potential,
                          index,
                          dt=0.01 * u.Myr,
                          size=100,
                          deltav=5. * u.km / u.s,
                          deltat=0.5 * u.Myr):
        '''
            Propagates the index-th star and _size_ more stars with random spread in
            initial velocity and flight time dictated by deltav, deltat.

            This overwrites the original catalogue!

            Parameters
            ----------
                index : int
                    Index of the star to propagate this in.
                size : int

                dv, dt : Quantity
                    Spread in initial velocity and
                See self.propagate() for the other parameters.

        '''
        from galpy.orbit import Orbit
        from galpy.util.bovy_coords import pmllpmbb_to_pmrapmdec, lb_to_radec, vrpmllpmbb_to_vxvyvz, lbd_to_XYZ

        self.r0, self.theta0, self.phi0, self.v0, self.phiv0, self.thetav0, self.tflight, self.tage, self.m = np.ones(size)*self.r0[index], np.ones(size)*self.theta0[index], \
                                        np.ones(size)*self.phi0[index], np.ones(size)*self.v0[index], np.ones(size)*self.phiv0[index], np.ones(size)*self.thetav0[index], \
                                        np.ones(size)*self.tflight[index], np.ones(size)*self.tage[index], np.ones(size)*self.m[index]

        self.v0 = self.v0 + np.random.normal(size=size) * deltav
        self.tflight = self.tflight + np.random.normal(size=size) * deltat
        self.size = size

        # Integration time step
        self.dt = dt
        nsteps = np.ceil((self.tflight / self.dt).to('1').value)
        nsteps[nsteps < 100] = 100

        # Initialize position in cylindrical coords
        rho = self.r0 * np.sin(self.theta0)
        z = self.r0 * np.cos(self.theta0)
        phi = self.phi0

        #... and velocity
        vR = self.v0 * np.sin(self.thetav0) * np.cos(self.phiv0)
        vT = self.v0 * np.sin(self.thetav0) * np.sin(self.phiv0)
        vz = self.v0 * np.cos(self.thetav0)

        # Initialize empty arrays to save orbit data and integration steps
        self.pmll, self.pmbb, self.ll, self.bb, self.vlos, self.dist, self.energy_var = \
                                                                            (np.zeros(self.size) for i in xrange(7))
        self.orbits = [None] * self.size

        #Integration loop for the self.size orbits
        for i in xrange(self.size):
            ts = np.linspace(0, 1, nsteps[i]) * self.tflight[i]

            self.orbits[i] = Orbit(
                vxvv=[rho[i], vR[i], vT[i], z[i], vz[i], phi[i]],
                solarmotion=self.solarmotion)
            self.orbits[i].integrate(ts, potential, method='dopr54_c')

            # Export the final position
            self.dist[i], self.ll[i], self.bb[i], self.pmll[i], self.pmbb[i], self.vlos[i] = \
                                                self.orbits[i].dist(self.tflight[i], use_physical=True), \
                                                self.orbits[i].ll(self.tflight[i], use_physical=True), \
                                                self.orbits[i].bb(self.tflight[i], use_physical=True), \
                                                self.orbits[i].pmll(self.tflight[i], use_physical=True) , \
                                                self.orbits[i].pmbb(self.tflight[i], use_physical=True)  , \
                                                self.orbits[i].vlos(self.tflight[i], use_physical=True)

        # Radial velocity and distance + distance modulus
        self.vlos, self.dist = self.vlos * u.km / u.s, self.dist * u.kpc

        # Sky coordinates and proper motion
        data = pmllpmbb_to_pmrapmdec(
            self.pmll, self.pmbb, self.ll, self.bb,
            degree=True) * u.mas / u.year
        self.pmra, self.pmdec = data[:, 0], data[:, 1]
        data = lb_to_radec(self.ll, self.bb, degree=True) * u.deg
        self.ra, self.dec = data[:, 0], data[:, 1]

        # Done propagating
        self.cattype = 1
Example #6
0
    def propagate(self, potential, dt=0.01 * u.Myr, threshold=None):
        '''
            Propagates the sample in the Galaxy, changes cattype from 0 to 1.

            Parameters
            ----------
                potential : galpy potential instance
                    Potential instance of the galpy library used to integrate the orbits
                dt : Quantity
                    Integration timestep. Defaults to 0.01 Myr
                threshold : float
                    Maximum relative energy difference between the initial energy and the energy at any point needed
                    to consider an integration step an energy outliar. E.g. for threshold=0.01, any excess or
                    deficit of 1% (or more) of the initial energy is enough to be registered as outliar.
                    A table E_data.fits is created in the working directory containing for every orbit the percentage
                    of outliar points (pol)

        '''
        from galpy.orbit import Orbit
        from galpy.util.bovy_coords import pmllpmbb_to_pmrapmdec, lb_to_radec, vrpmllpmbb_to_vxvyvz, lbd_to_XYZ

        if (self.cattype > 0):
            raise RuntimeError('This sample is already propagated!')

        if (threshold is None):
            check = False
        else:
            check = True

        # Integration time step
        self.dt = dt
        nsteps = np.ceil((self.tflight / self.dt).to('1').value)
        nsteps[nsteps < 100] = 100

        # Initialize position in cylindrical coords
        rho = self.r0 * np.sin(self.theta0)
        z = self.r0 * np.cos(self.theta0)
        phi = self.phi0

        #... and velocity
        vR = self.v0 * np.sin(self.thetav0) * np.cos(self.phiv0)
        vT = self.v0 * np.sin(self.thetav0) * np.sin(self.phiv0)
        vz = self.v0 * np.cos(self.thetav0)

        # Initialize empty arrays to save orbit data and integration steps
        self.pmll, self.pmbb, self.ll, self.bb, self.vlos, self.dist, self.energy_var = \
                                                                            (np.zeros(self.size) for i in xrange(7))
        self.orbits = [None] * self.size

        #Integration loop for the self.size orbits
        for i in xrange(self.size):
            ts = np.linspace(0, 1, nsteps[i]) * self.tflight[i]

            self.orbits[i] = Orbit(
                vxvv=[rho[i], vR[i], vT[i], z[i], vz[i], phi[i]],
                solarmotion=self.solarmotion)
            self.orbits[i].integrate(ts, potential, method='dopr54_c')

            # Export the final position
            self.dist[i], self.ll[i], self.bb[i], self.pmll[i], self.pmbb[i], self.vlos[i] = \
                                                self.orbits[i].dist(self.tflight[i], use_physical=True), \
                                                self.orbits[i].ll(self.tflight[i], use_physical=True), \
                                                self.orbits[i].bb(self.tflight[i], use_physical=True), \
                                                self.orbits[i].pmll(self.tflight[i], use_physical=True) , \
                                                self.orbits[i].pmbb(self.tflight[i], use_physical=True)  , \
                                                self.orbits[i].vlos(self.tflight[i], use_physical=True)

            # Energy check
            if (check):
                energy_array = self.orbits[i].E(ts)
                idx_energy = np.absolute(energy_array / energy_array[0] -
                                         1) > threshold
                self.energy_var[i] = float(
                    idx_energy.sum()) / nsteps[i]  # percentage of outliars

        # Radial velocity and distance + distance modulus
        self.vlos, self.dist = self.vlos * u.km / u.s, self.dist * u.kpc

        # Sky coordinates and proper motion
        data = pmllpmbb_to_pmrapmdec(
            self.pmll, self.pmbb, self.ll, self.bb,
            degree=True) * u.mas / u.year
        self.pmra, self.pmdec = data[:, 0], data[:, 1]
        data = lb_to_radec(self.ll, self.bb, degree=True) * u.deg
        self.ra, self.dec = data[:, 0], data[:, 1]

        # Done propagating
        self.cattype = 1

        # Save the energy check information
        if (check):
            from astropy.table import Table
            e_data = Table([self.m, self.tflight, self.energy_var],
                           names=['m', 'tflight', 'pol'])
            e_data.write('E_data.fits', overwrite=True)
Example #7
0
def to_radec(cluster, do_order=False, do_key_params=False, ro=8.0, vo=220.0):
    """Convert to on-sky position, proper motion, and radial velocity of cluster
    
    Parameters
    ----------
    cluster : class
        StarCluster
    do_order : bool
        sort star by radius after coordinate change (default: False)
    do_key_params : bool
        call key_params to calculate key parameters after unit change (default: False)
    ro : float
        galpy radius scaling parameter
    vo : float
        galpy velocity scaling parameter

    Returns
    -------
    None

    History:
    -------
   2018 - Written - Webb (UofT)
    """
    if len(cluster.ra) == len(cluster.x):
        cluster.x = copy(cluster.ra)
        cluster.y = copy(cluster.dec)
        cluster.z = copy(cluster.dist)
        cluster.vx = copy(cluster.pmra)
        cluster.vy = copy(cluster.pmdec)
        cluster.vz = copy(cluster.vlos)

        cluster.units = "radec"
        cluster.origin = "sky"

    else:

        units0, origin0 = cluster.units, cluster.origin

        cluster.to_galaxy()
        cluster.to_kpckms()

        x0, y0, z0 = bovy_coords.galcenrect_to_XYZ(cluster.x,
                                                   cluster.y,
                                                   cluster.z,
                                                   Xsun=8.0,
                                                   Zsun=0.025).T

        cluster.dist = np.sqrt(x0**2.0 + y0**2.0 + z0**2.0)

        vx0, vy0, vz0 = bovy_coords.galcenrect_to_vxvyvz(
            cluster.vx,
            cluster.vy,
            cluster.vz,
            Xsun=8.0,
            Zsun=0.025,
            vsun=[-11.1, 244.0, 7.25],
        ).T

        cluster.vlos = (vx0 * x0 + vy0 * y0 +
                        vz0 * z0) / np.sqrt(x0**2.0 + y0**2.0 + z0**2.0)

        l0, b0, cluster.dist = bovy_coords.XYZ_to_lbd(x0, y0, z0,
                                                      degree=True).T
        cluster.ra, cluster.dec = bovy_coords.lb_to_radec(l0, b0,
                                                          degree=True).T

        vr0, pmll0, pmbb0 = bovy_coords.vxvyvz_to_vrpmllpmbb(vx0,
                                                             vy0,
                                                             vz0,
                                                             l0,
                                                             b0,
                                                             cluster.dist,
                                                             degree=True).T
        cluster.pmra, cluster.pmdec = bovy_coords.pmllpmbb_to_pmrapmdec(
            pmll0, pmbb0, l0, b0, degree=True).T

        x0, y0, z0 = bovy_coords.galcenrect_to_XYZ(cluster.xgc,
                                                   cluster.ygc,
                                                   cluster.zgc,
                                                   Xsun=8.0,
                                                   Zsun=0.025)
        vx0, vy0, vz0 = bovy_coords.galcenrect_to_vxvyvz(
            cluster.vxgc,
            cluster.vygc,
            cluster.vzgc,
            Xsun=8.0,
            Zsun=0.025,
            vsun=[-11.1, 244.0, 7.25],
        )

        cluster.vlos_gc = (vx0 * x0 + vy0 * y0 +
                           vz0 * z0) / np.sqrt(x0**2.0 + y0**2.0 + z0**2.0)

        l0, b0, cluster.dist_gc = bovy_coords.XYZ_to_lbd(x0,
                                                         y0,
                                                         z0,
                                                         degree=True)
        cluster.ra_gc, cluster.dec_gc = bovy_coords.lb_to_radec(l0,
                                                                b0,
                                                                degree=True)

        vr0, pmll0, pmbb0 = bovy_coords.vxvyvz_to_vrpmllpmbb(vx0,
                                                             vy0,
                                                             vz0,
                                                             l0,
                                                             b0,
                                                             cluster.dist_gc,
                                                             degree=True)
        cluster.pmra_gc, cluster.pmdec_gc = bovy_coords.pmllpmbb_to_pmrapmdec(
            pmll0, pmbb0, l0, b0, degree=True)

        cluster.x = copy(cluster.ra)
        cluster.y = copy(cluster.dec)
        cluster.z = copy(cluster.dist)
        cluster.vx = copy(cluster.pmra)
        cluster.vy = copy(cluster.pmdec)
        cluster.vz = copy(cluster.vlos)

        cluster.xgc = copy(cluster.ra_gc)
        cluster.ygc = copy(cluster.dec_gc)
        cluster.zgc = copy(cluster.dist_gc)
        cluster.vxgc = copy(cluster.pmra_gc)
        cluster.vygc = copy(cluster.pmdec_gc)
        cluster.vzgc = copy(cluster.vlos_gc)

        cluster.units = "radec"
        cluster.origin = "sky"

    cluster.rv3d()

    if do_key_params:
        cluster.key_params(do_order=do_order)
def main(args: Optional[list] = None, opts: Optional[Namespace] = None):
    """Fit MWPotential2014 Script Function.

    Parameters
    ----------
    args : list, optional
        an optional single argument that holds the sys.argv list,
        except for the script name (e.g., argv[1:])
    opts : Namespace, optional
        pre-constructed results of parsed args
        if not None, used ONLY if args is None

    """
    if opts is not None and args is None:
        pass
    else:
        if opts is not None:
            warnings.warn("Not using `opts` because `args` are given")
        parser = make_parser()
        opts = parser.parse_args(args)

    fpath = opts.fpath + "/" if not opts.fpath.endswith("/") else opts.fpath
    opath = opts.opath + "/" if not opts.opath.endswith("/") else opts.opath

    # plot chains
    print("Plotting Chains")
    fig = mcmc_util.plot_chains(opath)
    fig.savefig(fpath + "chains.pdf")
    plt.close(fig)

    print("Need to continue chains:", end=" ")
    for i in range(32):
        ngood = mcmc_util.determine_nburn(
            filename=opath + f"mwpot14-fitsigma-{i:02}.dat", return_nsamples=True,
        )
        if ngood < 4000:
            print(f"{i:02} (N={ngood})", end=", ")

    ###############################################################
    # RESULTING PDFS

    data, _, weights, _ = read_mcmc(nburn=None, skip=1, evi_func=lambda x: 1.0)

    plot_corner(data, weights=weights)
    plt.savefig("figures/PDFs/corner.pdf")
    plt.close()

    # --------------

    savefilename = "output/pal5_forces_mcmc.pkl"
    if not os.path.exists(savefilename):
        data_wf, index_wf, weights_wf, evi_wf = read_mcmc(
            nburn=None, addforces=True, skip=1, evi_func=lambda x: 1.0
        )
        save_pickles(savefilename, data_wf, index_wf, weights_wf, evi_wf)
    else:
        with open(savefilename, "rb") as savefile:
            data_wf = pickle.load(savefile)
            index_wf = pickle.load(savefile)
            weights_wf = pickle.load(savefile)
            evi_wf = pickle.load(savefile)

    # --------------
    plot_corner(data_wf, weights=weights_wf, addvcprior=False)
    plt.savefig("figures/PDFs/corner_wf.pdf")
    plt.close()

    # --------------
    # Which potential is preferred?
    data_noforce, potindx, weights, evidences = read_mcmc(evi_func=evi_harmonic)

    fig = plt.figure(figsize=(6, 4))
    bovy_plot.bovy_plot(
        potindx,
        np.log(evidences),
        "o",
        xrange=[-1, 34],
        yrange=[-35, -22],
        xlabel=r"$\mathrm{Potential\ index}$",
        ylabel=r"$\ln\ \mathrm{evidence}$",
    )
    data_noforce, potindx, weights, evidences = read_mcmc(evi_func=evi_laplace)
    bovy_plot.bovy_plot(potindx, np.log(evidences) - 30.0, "d", overplot=True)
    data_noforce, potindx, weights, evidences = read_mcmc(
        evi_func=lambda x: np.exp(np.amax(x[:, -1]))
    )
    bovy_plot.bovy_plot(potindx, np.log(evidences) - 8.0, "s", overplot=True)
    data_noforce, potindx, weights, evidences = read_mcmc(
        evi_func=lambda x: np.exp(-25.0)
        if (np.log(evi_harmonic(x)) > -25.0)
        else np.exp(-50.0)
    )
    bovy_plot.bovy_plot(potindx, np.log(evidences), "o", overplot=True)
    plt.savefig("figures/PDFs/preferred_pot.pdf")
    plt.close()

    ###############################################################
    # Look at the results for individual potentials

    # --------------
    # The flattening $c$
    npot = 32
    nwalkers = 12

    plt.figure(figsize=(16, 6))
    cmap = cm.plasma
    maxl = np.zeros((npot, 2))
    for en, ii in enumerate(range(npot)):
        data_ip, _, weights_ip, evi_ip = read_mcmc(singlepot=ii, evi_func=evi_harmonic)
        try:
            maxl[en, 0] = np.amax(data_ip[:, -1])
            maxl[en, 1] = np.log(evi_ip[0])
        except ValueError:
            maxl[en] = -10000000.0
        plt.subplot(2, 4, en // 4 + 1)
        bovy_plot.bovy_hist(
            data_ip[:, 0],
            range=[0.5, 2.0],
            bins=26,
            histtype="step",
            color=cmap((en % 4) / 3.0),
            normed=True,
            xlabel=r"$c$",
            lw=1.5,
            overplot=True,
        )
        if en % 4 == 0:
            bovy_plot.bovy_text(
                r"$\mathrm{Potential\ %i\ to\ % i}$" % (en, en + 3),
                size=17.0,
                top_left=True,
            )
    plt.tight_layout()
    plt.savefig("figures/flattening_c.pdf")
    plt.close()

    ###############################################################
    # What is the effective prior in $(F_R,F_Z)$?

    frfzprior_savefilename = "frfzprior.pkl"
    if not os.path.exists(frfzprior_savefilename):
        # Compute for each potential separately
        nvoc = 10000
        ro = 8.0
        npot = 32
        fs = np.zeros((2, nvoc, npot))
        for en, ii in tqdm(enumerate(range(npot))):
            fn = f"output/fitsigma/mwpot14-fitsigma-{i:02}.dat"
            # Read the potential parameters
            with open(fn, "r") as savefile:
                line1 = savefile.readline()
            potparams = [float(s) for s in (line1.split(":")[1].split(","))]
            for jj in range(nvoc):
                c = np.random.uniform() * 1.5 + 0.5
                tvo = np.random.uniform() * 50.0 + 200.0
                pot = mw_pot.setup_potential(potparams, c, False, False, REFR0, tvo)
                fs[:, jj, ii] = np.array(pal5_util.force_pal5(pot, 23.46, REFR0, tvo))[
                    :2
                ]
        save_pickles(frfzprior_savefilename, fs)
    else:
        with open(frfzprior_savefilename, "rb") as savefile:
            fs = pickle.load(savefile)

    # --------------
    plt.figure(figsize=(6, 6))
    bovy_plot.scatterplot(
        fs[0].flatten(),
        fs[1].flatten(),
        "k,",
        xrange=[-1.75, -0.25],
        yrange=[-2.5, -1.2],
        xlabel=r"$F_R(\mathrm{Pal\ 5})$",
        ylabel=r"$F_Z(\mathrm{Pal\ 5})$",
        onedhists=True,
    )
    bovy_plot.scatterplot(
        data_wf[:, 7],
        data_wf[:, 8],
        weights=weights_wf,
        bins=26,
        xrange=[-1.75, -0.25],
        yrange=[-2.5, -1.2],
        justcontours=True,
        cntrcolors="w",
        overplot=True,
        onedhists=True,
    )
    plt.axvline(-0.81, color=sns.color_palette()[0])
    plt.axhline(-1.85, color=sns.color_palette()[0])
    plt.savefig("figures/effective_force_prior.pdf")
    plt.close()

    # --------------
    # The ratio of the posterior and the prior

    bovy_plot.bovy_print(
        axes_labelsize=17.0,
        text_fontsize=12.0,
        xtick_labelsize=14.0,
        ytick_labelsize=14.0,
    )
    plt.figure(figsize=(12.5, 4))

    def axes_white():
        for k, spine in plt.gca().spines.items():  # ax.spines is a dictionary
            spine.set_color("w")
        plt.gca().tick_params(axis="x", which="both", colors="w")
        plt.gca().tick_params(axis="y", which="both", colors="w")
        [t.set_color("k") for t in plt.gca().xaxis.get_ticklabels()]
        [t.set_color("k") for t in plt.gca().yaxis.get_ticklabels()]
        return None

    bins = 32
    trange = [[-1.75, -0.25], [-2.5, -1.2]]
    tw = copy.deepcopy(weights_wf)
    tw[index_wf == 14] = 0.0  # Didn't converge properly
    H_prior, xedges, yedges = np.histogram2d(
        fs[0].flatten(), fs[1].flatten(), bins=bins, range=trange, normed=True
    )
    H_post, xedges, yedges = np.histogram2d(
        data_wf[:, 7], data_wf[:, 8], weights=tw, bins=bins, range=trange, normed=True,
    )
    H_like = H_post / H_prior
    H_like[H_prior == 0.0] = 0.0
    plt.subplot(1, 3, 1)
    bovy_plot.bovy_dens2d(
        H_prior.T,
        origin="lower",
        cmap="viridis",
        interpolation="nearest",
        xrange=[xedges[0], xedges[-1]],
        yrange=[yedges[0], yedges[-1]],
        xlabel=r"$F_R(\mathrm{Pal\ 5})\,(\mathrm{km\,s}^{-1}\,\mathrm{Myr}^{-1})$",
        ylabel=r"$F_Z(\mathrm{Pal\ 5})\,(\mathrm{km\,s}^{-1}\,\mathrm{Myr}^{-1})$",
        gcf=True,
    )
    bovy_plot.bovy_text(r"$\mathbf{Prior}$", top_left=True, size=19.0, color="w")
    axes_white()
    plt.subplot(1, 3, 2)
    bovy_plot.bovy_dens2d(
        H_post.T,
        origin="lower",
        cmap="viridis",
        interpolation="nearest",
        xrange=[xedges[0], xedges[-1]],
        yrange=[yedges[0], yedges[-1]],
        xlabel=r"$F_R(\mathrm{Pal\ 5})\,(\mathrm{km\,s}^{-1}\,\mathrm{Myr}^{-1})$",
        gcf=True,
    )
    bovy_plot.bovy_text(r"$\mathbf{Posterior}$", top_left=True, size=19.0, color="w")
    axes_white()
    plt.subplot(1, 3, 3)
    bovy_plot.bovy_dens2d(
        H_like.T,
        origin="lower",
        cmap="viridis",
        interpolation="nearest",
        vmin=0.1,
        vmax=4.0,
        xrange=[xedges[0], xedges[-1]],
        yrange=[yedges[0], yedges[-1]],
        xlabel=r"$F_R(\mathrm{Pal\ 5})\,(\mathrm{km\,s}^{-1}\,\mathrm{Myr}^{-1})$",
        gcf=True,
    )
    bovy_plot.bovy_text(r"$\mathbf{Likelihood}$", top_left=True, size=19.0, color="w")
    axes_white()

    def qline(FR, q=0.95):
        return 2.0 * FR / q ** 2.0

    q = 0.94
    plt.plot([-1.25, -0.2], [qline(-1.25, q=q), qline(-0.2, q=q)], "w--")
    bovy_plot.bovy_text(-1.7, -2.2, r"$q_\Phi = 0.94$", size=16.0, color="w")
    plt.plot((-1.25, -1.02), (-2.19, qline(-1.02, q=q)), "w-", lw=0.8)

    plt.tight_layout()
    plt.savefig(
        "figures/pal5post.pdf", bbox_inches="tight",
    )
    plt.close()

    # --------------
    # Projection onto the direction perpendicular to constant $q = 0.94$:
    frs = np.tile(0.5 * (xedges[:-1] + xedges[1:]), (len(yedges) - 1, 1)).T
    fzs = np.tile(0.5 * (yedges[:-1] + yedges[1:]), (len(xedges) - 1, 1))
    plt.figure(figsize=(6, 4))
    txlabel = r"$F_\perp$"
    dum = bovy_plot.bovy_hist(
        (-2.0 * (frs + 0.8) + 0.94 ** 2.0 * (fzs + 1.82)).flatten(),
        weights=H_prior.flatten(),
        bins=21,
        histtype="step",
        lw=2.0,
        xrange=[-1.5, 1.5],
        xlabel=txlabel,
        normed=True,
    )
    dum = bovy_plot.bovy_hist(
        (-2.0 * (frs + 0.8) + 0.94 ** 2.0 * (fzs + 1.82)).flatten(),
        weights=H_post.flatten(),
        bins=21,
        histtype="step",
        lw=2.0,
        overplot=True,
        xrange=[-1.5, 1.5],
        normed=True,
    )
    dum = bovy_plot.bovy_hist(
        (-2.0 * (frs + 0.8) + 0.94 ** 2.0 * (fzs + 1.82)).flatten(),
        weights=H_like.flatten(),
        bins=21,
        histtype="step",
        lw=2.0,
        overplot=True,
        xrange=[-1.5, 1.5],
        normed=True,
    )
    plt.savefig("figures/PDFs/projection_perp_to_q0p94.pdf")
    plt.close()

    mq = (
        np.sum(
            (-2.0 * (frs + 0.8) + 0.94 ** 2.0 * (fzs + 1.82)).flatten()
            * H_like.flatten()
        )
    ) / np.sum(H_like.flatten())

    print(
        mq,
        np.sqrt(
            (
                np.sum(
                    ((-2.0 * (frs + 0.8) + 0.94 ** 2.0 * (fzs + 1.82)).flatten() - mq)
                    ** 2.0
                    * H_like.flatten()
                )
            )
            / np.sum(H_like.flatten())
        ),
    )

    # --------------
    # Projection onto the direction parallel to constant $q = 0.94$:
    frs = np.tile(0.5 * (xedges[:-1] + xedges[1:]), (len(yedges) - 1, 1)).T
    fzs = np.tile(0.5 * (yedges[:-1] + yedges[1:]), (len(xedges) - 1, 1))
    plt.figure(figsize=(6, 4))
    txlabel = r"$F_\parallel$"
    dum = bovy_plot.bovy_hist(
        (0.94 ** 2.0 * (frs + 0.8) + 2.0 * (fzs + 1.82)).flatten(),
        weights=H_prior.flatten(),
        bins=21,
        histtype="step",
        lw=2.0,
        xrange=[-2.5, 2.5],
        xlabel=txlabel,
        normed=True,
    )
    dum = bovy_plot.bovy_hist(
        (0.94 ** 2.0 * (frs + 0.8) + 2.0 * (fzs + 1.82)).flatten(),
        weights=H_post.flatten(),
        bins=21,
        histtype="step",
        lw=2.0,
        overplot=True,
        xrange=[-2.5, 2.5],
        normed=True,
    )
    dum = bovy_plot.bovy_hist(
        (0.94 ** 2.0 * (frs + 0.8) + 2.0 * (fzs + 1.82)).flatten(),
        weights=H_like.flatten(),
        bins=21,
        histtype="step",
        lw=2.0,
        overplot=True,
        xrange=[-2.5, 2.5],
        normed=True,
    )
    plt.savefig("figures/PDFs/projection_prll_to_q0p94.pdf")
    plt.close()
    mq = (
        np.sum(
            (0.94 ** 2.0 * (frs + 0.8) + 2.0 * (fzs + 1.82)).flatten()
            * H_like.flatten()
        )
    ) / np.sum(H_like.flatten())
    print(
        mq,
        np.sqrt(
            (
                np.sum(
                    ((0.94 ** 2.0 * (frs + 0.8) + 2.0 * (fzs + 1.82)).flatten() - mq)
                    ** 2.0
                    * H_like.flatten()
                )
            )
            / np.sum(H_like.flatten())
        ),
    )

    # --------------
    # Thus, there is only a weak constraint on $F_\parallel$.

    nrow = int(np.ceil(npot / 4.0))
    plt.figure(figsize=(16, nrow * 4))
    for en, ii in enumerate(range(npot)):
        plt.subplot(nrow, 4, en + 1)
        if ii % 4 == 0:
            tylabel = r"$F_Z(\mathrm{Pal\ 5})$"
        else:
            tylabel = None
        if ii // 4 == nrow - 1:
            txlabel = r"$F_R(\mathrm{Pal\ 5})$"
        else:
            txlabel = None
        bovy_plot.scatterplot(
            fs[0][:, en],
            fs[1][:, en],
            "k,",
            xrange=[-1.75, -0.25],
            yrange=[-2.5, -1.0],
            xlabel=txlabel,
            ylabel=tylabel,
            gcf=True,
        )
        bovy_plot.scatterplot(
            data_wf[:, 7],
            data_wf[:, 8],
            weights=weights_wf,
            bins=26,
            xrange=[-1.75, -0.25],
            yrange=[-2.5, -1.0],
            justcontours=True,
            cntrcolors="w",
            overplot=True,
        )
        bovy_plot.scatterplot(
            data_wf[index_wf == ii, 7],
            data_wf[index_wf == ii, 8],
            weights=weights_wf[index_wf == ii],
            bins=26,
            xrange=[-1.75, -0.25],
            yrange=[-2.5, -1.0],
            justcontours=True,
            # cntrcolors=sns.color_palette()[2],
            overplot=True,
        )
        plt.axvline(-0.80, color=sns.color_palette()[0])
        plt.axhline(-1.83, color=sns.color_palette()[0])
        bovy_plot.bovy_text(r"$\mathrm{Potential}\ %i$" % ii, size=17.0, top_left=True)
    plt.savefig("figures/PDFs/constain_F_prll.pdf")
    plt.close()

    # --------------
    # Let's plot four representative ones for the paper:

    bovy_plot.bovy_print(
        axes_labelsize=17.0,
        text_fontsize=12.0,
        xtick_labelsize=14.0,
        ytick_labelsize=14.0,
    )
    nullfmt = NullFormatter()
    nrow = 1

    plt.figure(figsize=(15, nrow * 4))
    for en, ii in enumerate([0, 15, 24, 25]):
        plt.subplot(nrow, 4, en + 1)
        if en % 4 == 0:
            tylabel = (
                r"$F_Z(\mathrm{Pal\ 5})\,(\mathrm{km\,s}^{-1}\,\mathrm{Myr}^{-1})$"
            )
        else:
            tylabel = None
        if en // 4 == nrow - 1:
            txlabel = (
                r"$F_R(\mathrm{Pal\ 5})\,(\mathrm{km\,s}^{-1}\,\mathrm{Myr}^{-1})$"
            )
        else:
            txlabel = None
        bovy_plot.scatterplot(
            fs[0][:, ii],
            fs[1][:, ii],
            "k,",
            bins=31,
            xrange=[-1.75, -0.25],
            yrange=[-2.5, -1.0],
            xlabel=txlabel,
            ylabel=tylabel,
            gcf=True,
        )
        bovy_plot.scatterplot(
            data_wf[:, 7],
            data_wf[:, 8],
            weights=weights_wf,
            bins=21,
            xrange=[-1.75, -0.25],
            yrange=[-2.5, -1.0],
            justcontours=True,
            cntrcolors=sns.color_palette("colorblind")[2],
            cntrls="--",
            cntrlw=2.0,
            overplot=True,
        )
        bovy_plot.scatterplot(
            data_wf[index_wf == ii, 7],
            data_wf[index_wf == ii, 8],
            weights=weights_wf[index_wf == ii],
            bins=21,
            xrange=[-1.75, -0.25],
            yrange=[-2.5, -1.0],
            justcontours=True,
            cntrcolors=sns.color_palette("colorblind")[0],
            cntrlw=2.5,
            overplot=True,
        )
        if en > 0:
            plt.gca().yaxis.set_major_formatter(nullfmt)

    plt.tight_layout()
    plt.savefig(
        "figures/pal5post_examples.pdf", bbox_inches="tight",
    )
    plt.close()

    ###############################################################
    # What about $q_\Phi$?

    bins = 47
    plt.figure(figsize=(6, 4))
    dum = bovy_plot.bovy_hist(
        np.sqrt(2.0 * fs[0].flatten() / fs[1].flatten()),
        histtype="step",
        lw=2.0,
        bins=bins,
        xlabel=r"$q_\mathrm{\Phi}$",
        xrange=[0.7, 1.25],
        normed=True,
    )
    dum = bovy_plot.bovy_hist(
        np.sqrt(16.8 / 8.4 * data_wf[:, -2] / data_wf[:, -1]),
        weights=weights_wf,
        histtype="step",
        lw=2.0,
        bins=bins,
        overplot=True,
        xrange=[0.7, 1.25],
        normed=True,
    )
    mq = np.sum(
        np.sqrt(16.8 / 8.4 * data_wf[:, -2] / data_wf[:, -1]) * weights_wf
    ) / np.sum(weights_wf)
    sq = np.sqrt(
        np.sum(
            (np.sqrt(16.8 / 8.4 * data_wf[:, -2] / data_wf[:, -1]) - mq) ** 2.0
            * weights_wf
        )
        / np.sum(weights_wf)
    )
    print("From posterior samples: q = %.3f +/- %.3f" % (mq, sq))
    Hq_post, xedges = np.histogram(
        np.sqrt(16.8 / 8.4 * data_wf[:, -2] / data_wf[:, -1]),
        weights=weights_wf,
        bins=bins,
        range=[0.7, 1.25],
        normed=True,
    )
    Hq_prior, xedges = np.histogram(
        np.sqrt(2.0 * fs[0].flatten() / fs[1].flatten()),
        bins=bins,
        range=[0.7, 1.25],
        normed=True,
    )
    qs = 0.5 * (xedges[:-1] + xedges[1:])
    Hq_like = Hq_post / Hq_prior
    Hq_like[Hq_post == 0.0] = 0.0
    mq = np.sum(qs * Hq_like) / np.sum(Hq_like)
    sq = np.sqrt(np.sum((qs - mq) ** 2.0 * Hq_like) / np.sum(Hq_like))
    print("From likelihood of samples: q = %.3f +/- %.3f" % (mq, sq))

    plt.savefig("figures/q_phi.pdf")
    plt.close()

    # It appears that $q_\Phi$ is the quantity that is the most strongly constrained by the Pal 5 data.

    ###############################################################
    # A sampling of tracks from the MCMC

    savefilename = "mwpot14-pal5-mcmcTracks.pkl"
    pmdecpar = 2.257 / 2.296
    pmdecperp = -2.296 / 2.257
    if os.path.exists(savefilename):
        with open(savefilename, "rb") as savefile:
            pal5_track_samples = pickle.load(savefile)
            forces = pickle.load(savefile)
            all_potparams = pickle.load(savefile)
            all_params = pickle.load(savefile)
    else:
        np.random.seed(1)
        ntracks = 21
        multi = 8
        pal5_track_samples = np.zeros((ntracks, 2, 6, pal5varyc[0].shape[1]))
        forces = np.zeros((ntracks, 2))
        all_potparams = np.zeros((ntracks, 5))
        all_params = np.zeros((ntracks, 7))
        for ii in range(ntracks):
            # Pick a random potential from among the set, but leave 14 out
            pindx = 14
            while pindx == 14:
                pindx = np.random.permutation(32)[0]
            # Load this potential
            fn = f"output/fitsigma/mwpot14-fitsigma-{pindx:02}.dat"
            with open(fn, "r") as savefile:
                line1 = savefile.readline()
            potparams = [float(s) for s in (line1.split(":")[1].split(","))]
            all_potparams[ii] = potparams
            # Now pick a random sample from this MCMC chain
            tnburn = mcmc_util.determine_nburn(fn)
            tdata = np.loadtxt(fn, comments="#", delimiter=",")
            tdata = tdata[tnburn::]
            tdata = tdata[np.random.permutation(len(tdata))[0]]
            all_params[ii] = tdata
            tvo = tdata[1] * REFV0
            pot = mw_pot.setup_potential(potparams, tdata[0], False, False, REFR0, tvo)
            forces[ii, :] = pal5_util.force_pal5(pot, 23.46, REFR0, tvo)[:2]
            # Now compute the stream model for this setup
            dist = tdata[2] * 22.0
            pmra = -2.296 + tdata[3] + tdata[4]
            pmdecpar = 2.257 / 2.296
            pmdecperp = -2.296 / 2.257
            pmdec = -2.257 + tdata[3] * pmdecpar + tdata[4] * pmdecperp
            vlos = -58.7
            sigv = 0.4 * np.exp(tdata[5])
            prog = Orbit(
                [229.018, -0.124, dist, pmra, pmdec, vlos],
                radec=True,
                ro=REFR0,
                vo=tvo,
                solarmotion=[-11.1, 24.0, 7.25],
            )
            tsdf_trailing, tsdf_leading = pal5_util.setup_sdf(
                pot,
                prog,
                sigv,
                10.0,
                REFR0,
                tvo,
                multi=multi,
                nTrackChunks=8,
                trailing_only=False,
                verbose=True,
                useTM=False,
            )
            # Compute the track
            for jj, sdf in enumerate([tsdf_trailing, tsdf_leading]):
                trackRADec = bovy_coords.lb_to_radec(
                    sdf._interpolatedObsTrackLB[:, 0],
                    sdf._interpolatedObsTrackLB[:, 1],
                    degree=True,
                )
                trackpmRADec = bovy_coords.pmllpmbb_to_pmrapmdec(
                    sdf._interpolatedObsTrackLB[:, 4],
                    sdf._interpolatedObsTrackLB[:, 5],
                    sdf._interpolatedObsTrackLB[:, 0],
                    sdf._interpolatedObsTrackLB[:, 1],
                    degree=True,
                )
                # Store the track
                pal5_track_samples[ii, jj, 0] = trackRADec[:, 0]
                pal5_track_samples[ii, jj, 1] = trackRADec[:, 1]
                pal5_track_samples[ii, jj, 2] = sdf._interpolatedObsTrackLB[:, 2]
                pal5_track_samples[ii, jj, 3] = sdf._interpolatedObsTrackLB[:, 3]
                pal5_track_samples[ii, jj, 4] = trackpmRADec[:, 0]
                pal5_track_samples[ii, jj, 5] = trackpmRADec[:, 1]
        save_pickles(
            savefilename, pal5_track_samples, forces, all_potparams, all_params
        )

    # --------------
    bovy_plot.bovy_print(
        axes_labelsize=17.0,
        text_fontsize=12.0,
        xtick_labelsize=14.0,
        ytick_labelsize=14.0,
    )
    plt.figure(figsize=(12, 8))
    gs = gridspec.GridSpec(2, 2, wspace=0.225, hspace=0.1, right=0.94)
    ntracks = pal5_track_samples.shape[0]
    cmap = cm.plasma
    alpha = 0.7
    for ii in range(ntracks):
        tc = cmap((forces[ii, 1] + 2.5) / 1.0)
        for jj in range(2):
            # RA, Dec
            plt.subplot(gs[0])
            plt.plot(
                pal5_track_samples[ii, jj, 0],
                pal5_track_samples[ii, jj, 1],
                "-",
                color=tc,
                alpha=alpha,
            )
            # RA, Vlos
            plt.subplot(gs[1])
            plt.plot(
                pal5_track_samples[ii, jj, 0],
                pal5_track_samples[ii, jj, 3],
                "-",
                color=tc,
                alpha=alpha,
            )
            # RA, Dist
            plt.subplot(gs[2])
            plt.plot(
                pal5_track_samples[ii, jj, 0],
                pal5_track_samples[ii, jj, 2] - all_params[ii, 2] * 22.0,
                "-",
                color=tc,
                alpha=alpha,
            )
            # RA, pm_parallel
            plt.subplot(gs[3])
            plt.plot(
                pal5_track_samples[ii, jj, 0, : 500 + 500 * (1 - jj)],
                np.sqrt(1.0 + (2.257 / 2.296) ** 2.0)
                * (
                    (pal5_track_samples[ii, jj, 4, : 500 + 500 * (1 - jj)] + 2.296)
                    * pmdecperp
                    - (pal5_track_samples[ii, jj, 5, : 500 + 500 * (1 - jj)] + 2.257)
                )
                / (pmdecpar - pmdecperp),
                "-",
                color=tc,
                alpha=alpha,
            )
    plot_data_add_labels(
        p1=(gs[0],), p2=(gs[1],), noxlabel_dec=True, noxlabel_vlos=True
    )
    plt.subplot(gs[2])
    plt.xlim(250.0, 221.0)
    plt.ylim(-3.0, 1.5)
    bovy_plot._add_ticks()
    plt.xlabel(r"$\mathrm{RA}\,(\mathrm{degree})$")
    plt.ylabel(r"$\Delta\mathrm{Distance}\,(\mathrm{kpc})$")
    plt.subplot(gs[3])
    plt.xlim(250.0, 221.0)
    plt.ylim(-0.5, 0.5)
    bovy_plot._add_ticks()
    plt.xlabel(r"$\mathrm{RA}\,(\mathrm{degree})$")
    plt.ylabel(r"$\Delta\mu_\parallel\,(\mathrm{mas\,yr}^{-1})$")
    # Colorbar
    gs2 = gridspec.GridSpec(2, 1, wspace=0.0, left=0.95, right=0.975)
    plt.subplot(gs2[:, -1])
    sm = plt.cm.ScalarMappable(cmap=cmap, norm=plt.Normalize(vmin=-2.5, vmax=-1.5))
    sm._A = []
    CB1 = plt.colorbar(sm, orientation="vertical", cax=plt.gca())
    CB1.set_label(
        r"$F_Z(\mathrm{Pal\ 5})\,(\mathrm{km\,s}^{-1}\,\mathrm{Myr}^{-1})$",
        fontsize=18.0,
    )
    plt.savefig(
        "figures/pal5tracksamples.pdf", bbox_inches="tight",
    )
    plt.close()

    ###############################################################
    # What about Kuepper et al. (2015)?

    # Can we recover the Kuepper et al. (2015) result as prior + $q_\Phi =
    # 0.94 \pm 0.05$ + $V_c(R_0)$ between 200 and 280 km/s? For simplicity
    # we will not vary $R_0$, which should not have a big impact.

    s = sample_kuepper_flattening_post(50000, 0.94, 0.05)
    plot_kuepper_samples(s)
    plt.savefig("figures/kuepper_samples.pdf")
    plt.close()

    # The constraint on the potential flattening gets you far, but there
    # is more going on (the constraint on the halo mass and scale
    # parameter appear to come completely from the $V_c(R_0)$ constraint).
    # Let's add the weak constraint on the sum of the forces, scaled to
    # Kuepper et al.'s best-fit acceleration (which is higher than ours):

    s = sample_kuepper_flatteningforce_post(50000, 0.94, 0.05, -0.83, 0.36)
    plot_kuepper_samples(s)
    plt.savefig("figures/kuepper_samples_flatF.pdf")
    plt.close()

    # This gets a tight relation between $M_\mathrm{halo}$ and the scale
    # parameter of the halo, but does not lead to a constraint on either
    # independently; the halo potential flattening constraint is that of
    # Kuepper et al. Based on this, it appears that the information that
    # ties down $M_\mathrm{halo}$ comes from the overdensities, which may
    # be spurious (Thomas et al. 2016) and whose use in dynamical modeling
    # is dubious anyway.

    # What is Kuepper et al.'s prior on $a_{\mathrm{Pal\ 5}}$?

    apal5s = []
    ns = 100000
    for ii in range(ns):
        Mh = np.random.uniform() * (10.0 - 0.001) + 0.001
        a = np.random.uniform() * (100.0 - 0.1) + 0.1
        q = np.random.uniform() * (1.8 - 0.2) + 0.2
        pot = setup_potential_kuepper(Mh, a)
        FR, FZ = force_pal5_kuepper(pot, q)
        apal5s.append(np.sqrt(FR ** 2.0 + FZ ** 2.0))
    apal5s = np.array(apal5s)

    plt.figure(figsize=(6, 4))
    dum = bovy_plot.bovy_hist(
        apal5s, range=[0.0, 10.0], lw=2.0, bins=51, histtype="step", normed=True,
    )
    plt.savefig("figures/kuepper_samples_prior.pdf")
    plt.close()