def transform_to_galactic(icrs_coords): """ For the input astrometry plus radial velocity in the ICRS system calculate the barycentric Galactic coordinates as well as Galactocentric coordinates. Parameters ---------- icrs_coords: astropy.coordinates.ICRS ICRS instance constructed from the 5-parameter Gaia DR2 astrometry and the radial velocity. Returns ------- Galactic and Galactocentric objects containing the astrometry in Galactic coordinates, the galactocentric Cartesian coordinates, and the galactocentric cylindrical coordinates. """ galactic_coords = icrs_coords.transform_to(Galactic()) sun_motion = CartesianDifferential(_Usun, _vc + _Vsun, _Wsun) galactocentric_cartesian = icrs_coords.transform_to( Galactocentric(galcen_distance=_Rsun, z_sun=_zsun, galcen_v_sun=sun_motion)) galactocentric_cartesian.set_representation_cls(base='cartesian') galactocentric_cylindrical = icrs_coords.transform_to( Galactocentric(galcen_distance=_Rsun, z_sun=_zsun, galcen_v_sun=sun_motion)) galactocentric_cylindrical.set_representation_cls(base='cylindrical') return galactic_coords, galactocentric_cartesian, galactocentric_cylindrical
def freqs_to_vel(center_freq, fs, lcoord, bcoord): # Convert from earth reference frame to solar reference frame using # https://docs.astropy.org/en/stable/coordinates/velocities.html#radial-velocity-corrections # Then convert from solar reference frame to Galactic Standard of Rest using # https://docs.astropy.org/en/stable/generated/examples/coordinates/rv-to-gsr.html pos_gal = SkyCoord(l=lcoord * u.degree, b=bcoord * u.degree, frame='galactic') v_to_bary = pos_gal.radial_velocity_correction( kind='barycentric', obstime=get_time(), location=radome_observer.location) # Calculate the sun's velocity projected in the observing direction. v_sun = Galactocentric().galcen_v_sun.to_cartesian() cart_data = pos_gal.data.to_cartesian() unit_vector = cart_data / cart_data.norm() v_proj = v_sun.dot(unit_vector) def freq_to_vel(f): f = f * u.MHz v_local = f.to(u.km / u.s, u.doppler_radio(center_freq * u.MHz)) v_bary = v_local + v_to_bary + v_local * v_to_bary / c # v_bary is now barycentric; now we need to remove the solar system motion as well return (v_bary + v_proj) / (u.km / u.s) return [freq_to_vel(f) for f in fs]
def test_galactocentric_defaults(reset_galactocentric_defaults): from astropy.coordinates import (Galactocentric, galactocentric_frame_defaults, BaseCoordinateFrame, CartesianDifferential) with galactocentric_frame_defaults.set('pre-v4.0'): galcen_pre40 = Galactocentric() with galactocentric_frame_defaults.set('v4.0'): galcen_40 = Galactocentric() with galactocentric_frame_defaults.set('latest'): galcen_latest = Galactocentric() # parameters that changed assert not u.allclose(galcen_pre40.galcen_distance, galcen_40.galcen_distance) assert not u.allclose(galcen_pre40.z_sun, galcen_40.z_sun) for k in galcen_40.get_frame_attr_names(): if isinstance(getattr(galcen_40, k), BaseCoordinateFrame): continue # skip coordinate comparison... elif isinstance(getattr(galcen_40, k), CartesianDifferential): assert u.allclose(getattr(galcen_40, k).d_xyz, getattr(galcen_latest, k).d_xyz) else: assert getattr(galcen_40, k) == getattr(galcen_latest, k)
def freqs_to_vel(center_freq, fs, sc): """Convert frequency to radial Doppler velocity. Accounts for movement of the earth relative to the sun and the sun relative to galactic center. Args: center_freq: frequency at zero velocity fs: Quantity object representing frequencies sc: SkyCoord object representing one or many coordinates (must have obstime and location set) """ # Convert from earth reference frame to solar reference frame using # https://docs.astropy.org/en/stable/coordinates/velocities.html#radial-velocity-corrections # Then convert from solar reference frame to Galactic Standard of Rest using # https://docs.astropy.org/en/stable/generated/examples/coordinates/rv-to-gsr.html pos_gal = sc.galactic v_to_bary = pos_gal.radial_velocity_correction(kind='barycentric') # Calculate the sun's velocity projected in the observing direction. v_sun = Galactocentric().galcen_v_sun.to_cartesian() cart_data = pos_gal.data.to_cartesian() unit_vector = cart_data / cart_data.norm() v_proj = v_sun.dot(unit_vector) doppler_shift = u.doppler_radio(center_freq) v_local = fs.to(u.km/u.s, doppler_shift) v_bary = v_local + v_to_bary + v_local * v_to_bary / c # v_bary is now barycentric; now we need to remove the solar system motion as well return (v_bary + v_proj)
def test_galactocentric_references(reset_galactocentric_defaults): # references in the "scientific paper"-sense from astropy.coordinates import (Galactocentric, galactocentric_frame_defaults) with galactocentric_frame_defaults.set('pre-v4.0'): galcen_pre40 = Galactocentric() for k in galcen_pre40.get_frame_attr_names(): if k == 'roll': # no reference for this parameter continue assert k in galcen_pre40.frame_attribute_references with galactocentric_frame_defaults.set('v4.0'): galcen_40 = Galactocentric() for k in galcen_40.get_frame_attr_names(): if k == 'roll': # no reference for this parameter continue assert k in galcen_40.frame_attribute_references with galactocentric_frame_defaults.set('v4.0'): galcen_custom = Galactocentric(z_sun=15*u.pc) for k in galcen_custom.get_frame_attr_names(): if k == 'roll': # no reference for this parameter continue if k == 'z_sun': assert k not in galcen_custom.frame_attribute_references else: assert k in galcen_custom.frame_attribute_references
def gen_act_cat(gaiadata, fout, nsamples=1024, seed=162, R0=8.175, sigmaR0=0.013, z0=20.8, sigmaz0=0.3, min_parallax=1e-3*u.mas): # generate the central galactocentric coordinate sytem galcen = Galactocentric(galcen_distance=R0*u.kpc, z_sun=z0*u.pc) # generate samples of the GC system # R0samples = np.random.normal(0, sigmaR0, nsamples) # z0samples = np.random.normal(0, sigmaz0, nsamples) # generate Monte Carlo samples of the observed coordinates g_samples = gaiadata.get_error_samples(size=nsamples, rnd=np.random.RandomState(seed=seed)) g_galcen = gaiadata.skycoord.transform_to(galcen) # converting samples to galcen, some parallaxes will be negative due to sampling # even though the input catalog must have only positive parallaxes dist = g_samples.get_distance(min_parallax=min_parallax) c = g_samples.get_skycoord(distance=dist) g_samples_galcen = c.transform_to(galcen) samples_posvel = convert_posvel_to_agama(g_samples_galcen) samples_posvel_reshaped = np.reshape(samples_posvel, (len(gaiadata)*nsamples, 6)) actions, angles, freqs = af(samples_posvel_reshaped, angles=True) actions[:,[1, 2]] = actions[:,[2, 1]] angles[:,[1, 2]] = angles[:,[2, 1]] freqs[:,[1, 2]] = freqs[:,[2, 1]] actions = np.reshape(actions, (nsamples, len(gaiadata), 3)) angles = np.reshape(angles, (nsamples, len(gaiadata), 3)) freqs = np.reshape(freqs, (nsamples, len(gaiadata), 3)) actions = np.swapaxes(actions, 0, 1) angles = np.swapaxes(angles, 0, 1) freqs = np.swapaxes(freqs, 0, 1) samples_posvel = np.swapaxes(samples_posvel, 0, 1) posvel_central = convert_posvel_to_agama(g_galcen) actions_c, angles_c, freqs_c = af(posvel_central, angles=True) actions_c[:,[1, 2]] = actions_c[:,[2, 1]] angles_c[:,[1, 2]] = angles_c[:,[2, 1]] freqs_c[:,[1, 2]] = freqs_c[:,[2, 1]] with h.File(fout, 'w') as f: f.create_dataset('actions', data=actions) f.create_dataset('angles', data=angles) f.create_dataset('freqs', data=freqs) f.create_dataset('posvel', data=samples_posvel) f.create_dataset('actions_central', data=actions_c) f.create_dataset('angles_central', data=angles_c) f.create_dataset('freqs_central', data=freqs_c) f.create_dataset('source_id', data=gaiadata.source_id, dtype='i8') return None
def test_galactocentric_default_warning(reset_galactocentric_defaults): from astropy.coordinates import (Galactocentric, galactocentric_frame_defaults) # Make sure a warning is thrown if the frame is created with no args with pytest.warns(AstropyDeprecationWarning, match=r"In v4\.1 and later versions"): Galactocentric() # Throw a warning even if only a subset of args are specified with pytest.warns(AstropyDeprecationWarning, match=r"In v4\.1 and later versions"): Galactocentric(galcen_distance=8.2*u.kpc) # No warning if using the latest parameter set: with galactocentric_frame_defaults.set('latest'): Galactocentric()
def backwards(self, l_deg, b_deg, d_kpc): with galactocentric_frame_defaults.set('pre-v4.0'): gal = Galactic(l=l_deg * u.deg, b=b_deg * u.deg, distance=d_kpc * u.kpc).transform_to( Galactocentric()) return gal.x.to(u.kpc).value, gal.y.to(u.kpc).value, gal.z.to( u.kpc).value
def test_m33galactocentric(): """Try to reproduce the transformation of M33 velocity from heliocentric to galactocentric in vdm12""" kms = u.km / u.s c0 = SkyCoord( x=0. * u.kpc, y=0. * u.kpc, z=0. * u.kpc, v_x=0. * kms, v_y=0. * kms, v_z=0. * kms, gal_distance=794. * u.kpc, # galvel_heliocentric=CartesianDifferential([133.6, -47.0, -180.] * kms)) # galvel_heliocentric=CartesianDifferential([98.2, -7.2, -180.] * kms)) # galvel_heliocentric=CartesianDifferential([17.7, -53.1, -180.] * kms)) no rot corr galvel_heliocentric=CartesianDifferential([87.3, 28.2, -180.] * kms), frame=M33Frame) # test - closer to M31 props # c0 = M33Frame(x=0.*u.kpc, y=0.*u.kpc, z=0.*u.kpc, v_x=0.*kms, v_y=0.*kms, v_z=0.*kms, # # gal_coord = ICRS(ra=10.68470833 * u.degree, dec=41.26875 * u.degree), # gal_distance=794.*u.kpc, # # galvel_heliocentric=CartesianDifferential([125.2, -73.8, -301.] * kms)) # # galvel_heliocentric=CartesianDifferential([125.2, -73.8, -180.] * kms)) # # galvel_heliocentric = CartesianDifferential([125.2, -53.1, -180.] * kms)) # # galvel_heliocentric=CartesianDifferential([17.7, -53.1, -180.] * kms)) # galvel_heliocentric=CartesianDifferential([87.3, 28.2, -180.] * kms)) print(c0) c_i = c0.transform_to(ICRS) print('proper motion:') print(c_i.proper_motion) print('radial velocity:') print(c_i.radial_velocity) gcframe = Galactocentric(galcen_distance=8.29 * u.kpc, galcen_v_sun=(11.1, 239. + 12.24, 7.25) * kms, z_sun=0. * u.kpc, roll=0. * u.deg) c = c0.transform_to(gcframe) answer = c.velocity.to_cartesian().xyz.value # print(c) # print(c.velocity) # print(type(c.velocity)) # import pdb; pdb.set_trace() # return # print(np.array(c.velocity)) vdm12 = np.array([43.1, 101.3, 138.8]) print('velocity:') print(answer) print(answer - vdm12) # also do position answer = c.cartesian.xyz.value vdm12 = np.array([-476.1, 491.1, -412.9]) print('position:') print(answer) print(answer - vdm12)
def test_galactocentric_default_warning(reset_galactocentric_defaults): from astropy.coordinates import (Galactocentric, galactocentric_frame_defaults) # Note: this is necessary because the doctests may alter the state of the # class globally and simultaneously when the tests are run in parallel # reset_galactocentric_defaults() # Make sure a warning is thrown if the frame is created with no args with pytest.warns(AstropyDeprecationWarning, match=r"In v4\.1 and later versions"): Galactocentric() # Throw a warning even if only a subset of args are specified with pytest.warns(AstropyDeprecationWarning, match=r"In v4\.1 and later versions"): Galactocentric(galcen_distance=8.2 * u.kpc) # No warning if using the latest parameter set: with galactocentric_frame_defaults.set('latest'): Galactocentric()
def test_m31galactocentric(): """Try to reproduce the transformation of M31 velocity from heliocentric to galactocentric in vdm12""" kms = u.km / u.s # Set point at M31 pos/vel. Can either pass all parameters to SkyCoord... # c0 = SkyCoord(x=0.*u.kpc, y=0.*u.kpc, z=0.*u.kpc, v_x=0.*kms, v_y=0.*kms, v_z=0.*kms, # gal_distance=770.*u.kpc, # galvel_heliocentric=CartesianDifferential([125.2, -73.8, -301.] * kms), # frame=M31Frame) # or initialize M31 frame separately and then use it as frame m31frame = M31Frame(gal_distance=770. * u.kpc, galvel_heliocentric=CartesianDifferential( [125.2, -73.8, -301.] * kms)) c0 = SkyCoord(x=0. * u.kpc, y=0. * u.kpc, z=0. * u.kpc, v_x=0. * kms, v_y=0. * kms, v_z=0. * kms, frame=m31frame) print(c0) c_i = c0.transform_to(ICRS) print('proper motion:') print(c_i.proper_motion) gcframe = Galactocentric(galcen_distance=8.29 * u.kpc, galcen_v_sun=(11.1, 239. + 12.24, 7.25) * kms, z_sun=0. * u.kpc, roll=0. * u.deg) c = c0.transform_to(gcframe) answer = c.velocity.to_cartesian().xyz.value # print(c) # print(c.velocity) # print(type(c.velocity)) # import pdb; pdb.set_trace() # return # print(np.array(c.velocity)) vdm12 = np.array([66.1, -76.3, 45.1]) print('velocity:') print(answer) print('difference from answer in paper:') print(answer - vdm12) # also do position answer = c.cartesian.xyz.value vdm12 = np.array([-378.9, 612.7, -283.1]) print('position:') print(answer) print('difference from answer in paper:') print(answer - vdm12)
def test_xyz_to_lbr(): x,y,z = pygedm.convert_lbr_to_xyz(0, 0, 0, method='ymw16') assert x == 0 assert y == 8300 * u.pc assert z == 6 * u.pc x,y,z = pygedm.convert_lbr_to_xyz(0, 0, 0, method='ne2001') assert x == 0 assert y == 8500 * u.pc assert z == 0 # Who even knows where the centre of the Galaxy is? # https://docs.astropy.org/en/stable/api/astropy.coordinates.galactocentric_frame_defaults.html from astropy.coordinates import galactocentric_frame_defaults _ = galactocentric_frame_defaults.set('v4.0') x,y,z = pygedm.convert_lbr_to_xyz(0, 0, 0, method='astropy') assert np.isclose(x.to('pc').value, -1 * Galactocentric().galcen_distance.to('pc').value) assert y == 0 assert np.isclose(z.to('pc').value, Galactocentric().z_sun.to('pc').value) x,y,z = pygedm.convert_lbr_to_xyz(Angle(0, unit='degree'), Angle(0, unit='rad'), 0 * u.pc, method='ymw16') assert x == 0 assert y == 8300 * u.pc assert z == 6 * u.pc
def test_m31galactocentric2(): """Try to reproduce the transformation of M31 velocity from heliocentric to galactocentric in vdm19""" kms = u.km / u.s # Set point at M31 pos/vel. Can either pass all parameters to SkyCoord... # c0 = SkyCoord(x=0.*u.kpc, y=0.*u.kpc, z=0.*u.kpc, v_x=0.*kms, v_y=0.*kms, v_z=0.*kms, # gal_distance=770.*u.kpc, # galvel_heliocentric=CartesianDifferential([125.2, -73.8, -301.] * kms), # frame=M31Frame) # or initialize M31 frame separately and then use it as frame m31frame = M31Frame(gal_distance=770. * u.kpc, galvel_heliocentric=CartesianDifferential( [178.9, -138.8, -301.] * kms)) c0 = SkyCoord(x=0. * u.kpc, y=0. * u.kpc, z=0. * u.kpc, v_x=0. * kms, v_y=0. * kms, v_z=0. * kms, frame=m31frame) print(c0) c_i = c0.transform_to(ICRS) print('proper motion:') print(c_i.proper_motion) gcframe = Galactocentric(galcen_distance=8.29 * u.kpc, galcen_v_sun=(11.1, 239. + 12.24, 7.25) * kms, z_sun=0. * u.kpc, roll=0. * u.deg) # think this is vdM12b as used in vdM19 c = c0.transform_to(gcframe) answer = c.velocity.to_cartesian().xyz.value vdm19 = np.array([34., -123., -19.]) print('velocity:') print(answer) print('difference from answer in paper:') print(answer - vdm19)
from pyia import GaiaData import astropy.units as u from astropy.coordinates import Galactocentric from astropy.table import Table Rcut = 250 * u.pc zcut = 2 * u.kpc gmag_max = 6.5 gmag_min = 3.2 bprp_min = 0.5 bprp_max = 1.2 R0 = 8.175 * u.kpc z0 = 20.8 * u.pc galcen = Galactocentric(galcen_distance=R0, z_sun=z0) g = GaiaData('gdr2_radv_actions_noerrors.fits') coord = g.skycoord.transform_to(galcen) R = np.sqrt(np.square(coord.x + R0) + np.square(coord.y)) z = np.abs(coord.z) bool1 = R < Rcut bool2 = z < zcut xybool = np.logical_and(bool1, bool2) gapp = g.phot_g_mean_mag.value dist = g.distance.to_value(u.pc)
def create_pulsars(self): """ Create the pulsar parameter files based on the supplied distributions. """ # pulsar parameter/injection file directory self.pulsardir = os.path.join(self.basedir, "pulsars") self.makedirs(self.pulsardir) self.pulsars = {} self.priors = {} for i in range(self.npulsars): # generate fake pulsar parameters if self.posdist is not None: skyloc = self.posdist.sample() if self._posdist_type in ["galactocentric", "galactic"]: # transform coordinates if required gpos = ( Galactocentric( x=skyloc["x"] * u.kpc, y=skyloc["y"] * u.kpc, z=skyloc["z"] * u.kpc, ) if self._posdist_type == "galactocentric" else Galactic( l=skyloc["l"] * u.rad, # noqa: E741 b=skyloc["b"] * u.rad, distance=skyloc["dist"] * u.kpc, )) eqpos = gpos.transform_to(ICRS) skyloc["ra"] = eqpos.ra.rad skyloc["dec"] = eqpos.dec.rad skyloc["dist"] = eqpos.distance.value if self.fdist is not None: freq = self.fdist.sample() # generate orientation parameters orientation = self.oridist.sample() if self.parfiles is None: pulsar = PulsarParametersPy() pulsar["RAJ"] = skyloc["ra"] pulsar["DECJ"] = skyloc["dec"] pulsar["DIST"] = (skyloc["dist"] * u.kpc).to("m").value # set pulsar name from sky position rastr = "".join( pulsar.convert_to_tempo_units( "RAJ", pulsar["RAJ"]).split(":")[:2]) decstr = "".join( pulsar.convert_to_tempo_units( "DECJ", pulsar["DECJ"]).split(":")[:2]) decstr = decstr if decstr[0] == "-" else ("+" + decstr) pname = "J{}{}".format(rastr, decstr) pnameorig = str(pname) # copy of original name counter = 1 while pname in self.pulsars: anum = int_to_alpha(counter) pname = pnameorig + anum counter += 1 pulsar["PSRJ"] = pname pulsar["F"] = [freq] for param in ["psi", "iota", "phi0"]: pulsar[param.upper()] = orientation[param] # output file name pfile = os.path.join(self.pulsardir, "{}.par".format(pname)) injfile = pfile self.priors[pname] = self.prior else: pfile = list(self.parfiles.values())[i] pulsar = PulsarParametersPy(pfile) pname = list(self.parfiles.keys())[i] injfile = os.path.join(self.pulsardir, "{}.par".format(pname)) if pulsar["DIST"] is None or (self.overwrite and "dist" in skyloc): # add distance if not present in parameter file pulsar["DIST"] = (skyloc["dist"] * u.kpc).to("m").value for param in ["psi", "iota", "phi0"]: # add orientation values if not present in parameter file if pulsar[param.upper()] is None or (self.overwrite and param in orientation): pulsar[param.upper()] = orientation[param] if isinstance(self.prior, dict) and pname in self.prior: # there are individual pulsar priors self.priors[pname] = self.prior[pname] else: self.priors[pname] = self.prior # check whether to add distance uncertainties to priors if self.distance_err is not None: dist = None if isinstance(self.distance_err, float): # set truncated Gaussian prior dist = bilby.core.prior.TruncatedGaussian( pulsar["DIST"], self.distance_err * pulsar["DIST"], 0.0, np.inf, name="dist", ) elif pname in self.distance_err: if isinstance(self.distance_err[pname], float): dist = bilby.core.prior.TruncatedGaussian( pulsar["DIST"], self.distance_err[pname] * pulsar["DIST"], 0.0, np.inf, name="dist", ) elif isinstance(self.distance_err[pname], bilby.core.prior.Prior): dist = self.distance_err[pname] if dist is not None and "dist" not in self.priors[pname]: # only add distance if not already specified self.priors[pname]["dist"] = dist # set amplitude value amp = self.ampdist.sample() if self.ampdist is not None else None if self.ampdist.name == "q22" and (pulsar["Q22"] is None or self.overwrite): pulsar["Q22"] = amp elif self.ampdist.name == "h0" and (pulsar["H0"] is None or self.overwrite): pulsar["H0"] = amp elif (self.ampdist.name.lower() in [ "epsilon", "ell", "ellipticity" ]) and (pulsar["Q22"] is None or self.overwrite): # convert ellipticity to Q22 using fiducial moment of inertia pulsar["Q22"] = ellipticity_to_q22(amp) with open(injfile, "w") as fp: fp.write(str(pulsar)) self.pulsars[pname] = {} self.pulsars[pname]["file"] = pfile self.pulsars[pname]["injection_file"] = injfile self.pulsars[pname]["parameters"] = pulsar
""" import numpy as np from numpy import array as nparr import astropy.units as u import astropy.constants as const from astropy.coordinates import Galactocentric import astropy.coordinates as coord _ = coord.galactocentric_frame_defaults.set('v4.0') from astropy.coordinates import SkyCoord VERBOSE = 1 if VERBOSE: print(Galactocentric()) def append_physicalpositions(df, reference_df): """ Given a pandas dataframe `df` with [ra, dec, parallax, pmra, pmdec], and a reference dataframe `reference_df` with [ra, dec, parallax, pmra, pmdec, (dr2_)radial_velocity], calculate the XYZ coordinates, the "delta_pmra_prime_km_s" and "delta_pmdec_prime_km_s" coordinates (tangential velocity with respect to reference_df), the "delta_r_pc" (3d separation) and "delta_mu_km_s" (2d tangential velocity separation) coordinates, and append them to the dataframe. Returns: new DataFrame with ['x_pc', 'y_pc', 'z_pc', 'delta_r_pc', 'delta_mu_km_s', 'delta_pmra_km_s' ,'delta_pmdec_km_s'] appended.
def forwards(self, x_kpc, y_kpc, z_kpc): with galactocentric_frame_defaults.set('pre-v4.0'): gal = Galactocentric(x=x_kpc * u.kpc, y=y_kpc * u.kpc, z=z_kpc * u.kpc).transform_to(Galactic) return gal.l.degree, gal.b.degree, gal.distance.to(u.kpc).value
def convert_lbr_to_xyz(gl, gb, dist, method='ymw16'): """ Convert Galactic (l,b,r) coords to Galactocentric (x,y,z) coords Args: gl (float, Angle, or Quantity): Galatic longitude in degrees (or astropy Angle) gb (float, Angle, or Quantity): Galactic latitude in degrees (or astropy Angle) dist (float or Quantity): Distance in pc method (str): one of 'ymw16', 'ne2001', or 'astropy' Returns: xyz (tuple): Galactocentric X, Y, Z coordinates Notes: For transform, the Sun is located at (x=0, y=R_sun, z=z_sun) YMW16 uses R_sun of 8300 pc and z_sun of 6.0 pc NE2001 uses R_sun of 8500 pc and z_sun of 0.0 pc Both of these do a basic spherical to cartesian conversion. astropy does a much more complicated conversion, see https://astropy.readthedocs.io/en/latest/coordinates/galactocentric.html This is the 'proper' coordinate system, but note that it is NOT COMPATIBLE WITH NE2001 OR YMW16! (!SEE EXAMPLE OUTPUT BELOW!) Example output:: pygedm.convert_lbr_to_xyz(0, 0, 0, method='ymw16') (<Quantity 0. pc>, <Quantity 8300. pc>, <Quantity 6. pc>) pygedm.convert_lbr_to_xyz(0, 0, 0, method='ne2001') (<Quantity 0. pc>, <Quantity 8500. pc>, <Quantity 0. pc>) pygedm.convert_lbr_to_xyz(0, 0, 0, method='astropy') (<Quantity -8499.95711754 pc>, <Quantity 0. pc>, <Quantity 27. pc>) """ gl, gb = _gl_gb_convert(gl, gb, 'deg') gl = np.deg2rad(gl) gb = np.deg2rad(gb) dist = _unit_convert(dist, 'pc') # Unit conversion and strip quantity dist = dist * u.pc # Make sure distance is in units of pc if method == 'astropy': lbr = SkyCoord(gl, gb, distance=dist, frame='galactic', unit=('rad', 'rad', 'pc')) xyz = lbr.transform_to(Galactocentric()) return xyz.x, xyz.y, xyz.z elif method.lower() == 'ymw16': Rsun = 8300 * u.pc Zsun = 6.0 * u.pc x = dist * np.sin(gl) * np.cos(gb) y = Rsun - dist * np.cos(gl) * np.cos(gb) z = Zsun + dist * np.sin(gb) return x, y, z elif method.lower() == 'ne2001': Rsun = 8500 * u.pc x = dist * np.sin(gl) * np.cos(gb) y = Rsun - dist * np.cos(gl) * np.cos(gb) z = dist * np.sin(gb) return x, y, z else: raise RuntimeError("method must be astropy, ne2001, or ymw16")
def forward(self, x_kpc, y_kpc, z_kpc): gal = Galactocentric(x=x_kpc * u.kpc, y=y_kpc * u.kpc, z=z_kpc * u.kpc).transform_to(Galactic) return gal.l.degree, gal.b.degree, gal.distance.to(u.kpc).value
def stars(in_file, plots_flag): # Create structured datatype correspond to given format # and load data file in_type = np.dtype([('ra' , 'f'), ('dec' , 'f'), ('d' , 'f'), ('vlos' , 'f'), ('pmra' , 'f'), ('pmdec', 'f')]) data = np.loadtxt(in_file,dtype=in_type,skiprows=1) # astropy.SkyCoords doesn't support automatically converting the velocity components # so we need to transform the data manually icrs = ICRS(ra=data['ra'] * u.degree, dec=data['dec'] * u.degree, distance=data['d'] * u.kpc, pm_ra_cosdec=(data['pmra'] * u.mas / u.yr), #* np.cos(data['dec'] * u.degree)), pm_dec=data['pmdec'] * u.mas / u.yr, radial_velocity=data['vlos'] * u.km / u.s) # Cartesian galactocentric coordinates v_sun = CartesianDifferential(11.1, 12.248 + 238, 7.25, unit=u.km / u.s) gal_cen = icrs.transform_to(Galactocentric(galcen_v_sun=v_sun, galcen_distance=8.0 * u.kpc, z_sun=0 * u.kpc)) # Output the 6D Cartesian coordinates out_file = '6d.txt' out_data = np.column_stack((gal_cen.x, gal_cen.y, gal_cen.z, gal_cen.v_x, gal_cen.v_y, gal_cen.v_z)) cols = ('x[kpc]', 'y[kpc]', 'z[kpc]', 'v_x[km/s]', 'v_y[km/s]', 'v_z[km/s]') np.savetxt(out_file, out_data, fmt='%9.4f', header=' '.join(cols)) print('6D coordinates written to {}'.format(out_file)) # r = distance # theta = latitude # phi = azimuth/longitude # NB This is opposite to how spherical coordinates are normally defined! # Spherical galactocentric coordinates gal_cen_sph = gal_cen.copy() gal_cen_sph.representation = 'spherical' # Calculate spherical velocity components and make units sensible vr = (gal_cen_sph.d_distance .to(u.km/u.s)) vtheta = ((gal_cen_sph.d_lat * gal_cen_sph.distance) .to(u.rad * u.km/u.s) / u.rad) vphi = ((gal_cen_sph.d_lon * gal_cen_sph.distance * np.cos(gal_cen_sph.lat)) .to(u.rad * u.km/u.s) / u.rad) # Calculate standard deviations (sigma) for three velocity components vr_dev = np.std(vr) vtheta_dev = np.std(vtheta) vphi_dev = np.std(vphi) # Calculate the velocity anisotropy parameter beta v_anis = vel_anisotropy(vr, vtheta, vphi) # Calculate the rotation velocity # Assumed that this is the expectation value of vphi v_rot = np.mean(vphi) # Report the results print('Velocity dispersion and anisotropy results:') print(""" sigma_r = {} sigma_theta = {} sigma_phi = {} v_rot = {} beta = {}""".format(vr_dev, vtheta_dev, vphi_dev, v_rot, v_anis)) # Spit out some plots if the command line flag was given if plots_flag: #from matplotlib import rc #rc('text', usetex=True) # plot positions fig = plt.figure() ax = plt.gca() ax.set_title('XY positions scatterplot') ax.set_aspect('equal') ax.set_xlabel('x [kpc]') ax.set_ylabel('y [kpc]') plt.scatter(gal_cen.x, gal_cen.y, s=2) # radius histogram hist_fig = plt.figure() ax = plt.gca() ax.set_title('Histogram of radial distances') ax.set_xlabel('Radial distance [kpc]') ax.set_ylabel('Count') plt.hist(gal_cen_sph.distance, bins='auto') # xyz histogram xyz_hist_fig = plt.figure() ax = plt.gca() ax.set_title('Histogram of Cartesian position components') ax.set_xlabel('Position [kpc]') ax.set_ylabel('Count') plt.hist(np.array(gal_cen.x), bins=50, alpha=0.4, label='x') plt.hist(np.array(gal_cen.y), bins=50, alpha=0.4, label='y') plt.hist(np.array(gal_cen.z), bins=50, alpha=0.4, label='z') plt.legend() # velocities vel_fig = plt.figure() ax = plt.gca() ax.set_title('Histogram of spherical velocity components') ax.set_xlabel('Velocity [km/s]') ax.set_ylabel('Count') plt.hist(np.array(vr), bins=50, range=(-500, 500),alpha=0.4,label='vr') plt.hist(np.array(vtheta), bins=50, range=(-500, 500), alpha=0.4,label='vtheta') plt.hist(np.array(vphi), bins=50, range=(-500, 500),alpha=0.4,label='vphi') #plt.hist(np.array(vtheta), bins=50, alpha=0.4,label='vtheta') #plt.hist(np.array(vphi), bins=50, alpha=0.4,label='vphi') plt.legend() cart_vel_fig = plt.figure() ax = plt.gca() ax.set_title('Histogram of Cartesian velocity components') ax.set_xlabel('Velocity [km/s]') ax.set_ylabel('Count') plt.hist(np.array(gal_cen.v_x), bins=50, range=(-500, 500),alpha=0.4,label='vx') plt.hist(np.array(gal_cen.v_y), bins=50, range=(-500, 500), alpha=0.4,label='vy') plt.hist(np.array(gal_cen.v_z), bins=50, range=(-500, 500),alpha=0.4,label='vz') #plt.hist(np.array(vtheta), bins=50, alpha=0.4,label='vtheta') #plt.hist(np.array(vphi), bins=50, alpha=0.4,label='vphi') plt.legend() print("Plots have been opened. Close them all to terminate the program.") plt.show()