def predict(self, hillas_dict, inst, pointing_alt, pointing_az): ''' The function you want to call for the reconstruction of the event. It takes care of setting up the event and consecutively calls the functions for the direction and core position reconstruction. Shower parameters not reconstructed by this class are set to np.nan Parameters ----------- hillas_dict: dict dictionary with telescope IDs as key and HillasParametersContainer instances as values inst : ctapipe.io.InstrumentContainer instrumental description pointing_alt: dict[astropy.coordinates.Angle] dict mapping telescope ids to pointing altitude pointing_az: dict[astropy.coordinates.Angle] dict mapping telescope ids to pointing azimuth Raises ------ TooFewTelescopesException if len(hillas_dict) < 2 ''' # filter warnings for missing obs time. this is needed because MC data has no obs time warnings.filterwarnings(action='ignore', category=MissingFrameAttributeWarning) # stereoscopy needs at least two telescopes if len(hillas_dict) < 2: raise TooFewTelescopesException( "need at least two telescopes, have {}" .format(len(hillas_dict))) self.initialize_hillas_planes( hillas_dict, inst.subarray, pointing_alt, pointing_az ) # algebraic direction estimate direction, err_est_dir = self.estimate_direction() alt = u.Quantity(list(pointing_alt.values())) az = u.Quantity(list(pointing_az.values())) if np.any(alt != alt[0]) or np.any(az != az[0]): warnings.warn('Divergent pointing not supported') telescope_pointing = SkyCoord(alt=alt[0], az=az[0], frame=AltAz()) # core position estimate using a geometric approach core_pos = self.estimate_core_position(hillas_dict, telescope_pointing) # container class for reconstructed showers result = ReconstructedShowerContainer() _, lat, lon = cartesian_to_spherical(*direction) # estimate max height of shower h_max = self.estimate_h_max() # astropy's coordinates system rotates counter-clockwise. # Apparently we assume it to be clockwise. result.alt, result.az = lat, -lon result.core_x = core_pos[0] result.core_y = core_pos[1] result.core_uncert = np.nan result.tel_ids = [h for h in hillas_dict.keys()] result.average_intensity = np.mean([h.intensity for h in hillas_dict.values()]) result.is_valid = True result.alt_uncert = err_est_dir result.az_uncert = np.nan result.h_max = h_max result.h_max_uncert = np.nan result.goodness_of_fit = np.nan return result
def transform(self, matrix): """ Transform the cartesian coordinates using a 3x3 matrix. This returns a new representation and does not modify the original one. Parameters ---------- matrix : `~numpy.ndarray` A 3x3 transformation matrix, such as a rotation matrix. Examples -------- We can start off by creating a cartesian representation object: >>> from astropy import units as u >>> from astropy.coordinates import CartesianRepresentation >>> rep = CartesianRepresentation([1, 2] * u.pc, ... [2, 3] * u.pc, ... [3, 4] * u.pc) We now create a rotation matrix around the z axis: >>> from astropy.coordinates.matrix_utilities import rotation_matrix >>> rotation = rotation_matrix(30 * u.deg, axis='z') Finally, we can apply this transformation: >>> rep_new = rep.transform(rotation) >>> rep_new.xyz # doctest: +FLOAT_CMP <Quantity [[ 1.8660254 , 3.23205081], [ 1.23205081, 1.59807621], [ 3. , 4. ]] pc> """ # Avoid doing gratuitous np.array for things that look like arrays. try: matrix_shape = matrix.shape except AttributeError: matrix = np.array(matrix) matrix_shape = matrix.shape if matrix_shape[-2:] != (3, 3): raise ValueError("tried to do matrix multiplication with an array " "that doesn't end in 3x3") # TODO: since this is likely to be a widely used function in coordinate # transforms, it should be optimized (for example in Cython). # Get xyz once since it's an expensive operation oldxyz = self.xyz # Note that neither dot nor einsum handles Quantity properly, so we use # the arrays and put the unit back in the end. if self.isscalar and not matrix_shape[:-2]: # a fast path for scalar coordinates. newxyz = matrix.dot(oldxyz.value) else: # Matrix multiply all pmat items and coordinates, broadcasting the # remaining dimensions. newxyz = np.einsum('...ij,j...->i...', matrix, oldxyz.value) newxyz = u.Quantity(newxyz, oldxyz.unit, copy=False) return self.__class__(*newxyz, copy=False)
def __init__(self, fit=None, h5file=None, redshift=None, lumdist=None, cosmo_type='WMAP9'): """ Parameters ---------- fit : mbb_fitter Fit object h5file : string Name of HDF5 file to load from previously saved fit. You can't provide this in combination with any of the other variables. redshift : float Redshift of source. Necessary if you plan to compute dustmass, L_IR, or L_AGN lumdist : float or astropy.units.Quantity Luminosity distance to object, in Mpc if units not specified. cosmo_type : string Name of cosmology to use if needed. The pre-loaded cosmologies from astropy.cosmology are supported (e.g., 'WMAP9', 'Planck13'). This is used if lumdist is not provided """ # Make sure user isn't trying to specify too much if not h5file is None: if not fit is None: raise Exception("It doesn't make sense to provide h5file" " and a fit to process") if not redshift is None: raise Exception("It doesn't make sense to provide h5file" " and the redshift") if not lumdist is None: raise Exception("It doesn't make sense to provide h5file" " and the lumdist") self._fitset = False self._has_lir = False self._lir_min = None self._lir_max = None self._has_dustmass = False self._kappa = None self._kappa_wave = None self._has_peaklambda = False if not h5file is None: self.readFromHDF5(h5file) else: if redshift is None: self._z = None else: self._z = float(redshift) if lumdist is None: self._has_lumdist = False else: self._has_lumdist = True if isinstance(lumdist, u.Quantity): self._lumdist = lumdist.to(u.Mpc) else: self._lumdist = u.Quantity(float(lumdist), u.Mpc) if cosmo_type is None: raise ValueError("Cosmology type must not be none -- " "maybe you should just use the default") self._cosmo_type = cosmo_type if not fit is None: self.process_fit(fit)
from datetime import timedelta import pytest import astropy.units as u from astropy.time import Time, TimeDelta from astropy.utils.exceptions import ErfaWarning import sunpy.time from sunpy.time import is_time_equal tbegin_str = '2012/1/1' tfin_str = '2012/1/2' dt = u.Quantity(24 * 60 * 60, 's') start = sunpy.time.parse_time(tbegin_str) end = sunpy.time.parse_time(tfin_str) delta = end - start @pytest.mark.parametrize("inputs", [(tbegin_str, tfin_str), (tbegin_str, dt), (tbegin_str, TimeDelta(1 * u.day)), (tbegin_str, timedelta(days=1))]) def test_timerange_inputs(inputs): timerange = sunpy.time.TimeRange(*inputs) assert isinstance(timerange, sunpy.time.TimeRange) assert timerange.start == start assert timerange.end == end assert timerange.dt == delta
def test_minutes(timerange_a): assert timerange_a.minutes == u.Quantity(24 * 60, 'min')
pictureDir = Dir + 'picture/' scriptDir = Dir + 'script/' image_12CO10 = 'NGC5258_12CO10_combine_smooth_masked' image_13CO10 = 'NGC5258_13CO10_12m_smooth_masked' image_ratio = imageDir + 'NGC5258_1213_ratio_pbcor' ############################################################ # basic information galaxy = 'NGC5258' rationame = '12CO/13CO 1-0' ratiolabel = '1213' freq12 = 112 freq13 = 107 center = SkyCoord(dec=0.8319 * u.degree, ra=204.9908 * u.degree, frame='icrs') size = u.Quantity((54, 42), u.arcsec) stat12 = {} stat13 = {} stat = {} apertures = {} regions = ['center', 'ring around center', 'northarm', 'southarm'] values = ['flux', 'uncertainty'] ratio = ['ratio', 'uncertainty'] type = ['sky', 'pix'] stat12 = dict.fromkeys(regions, {}) stat13 = dict.fromkeys(regions, {}) apertures = apertures.fromkeys(regions, {}) stat = dict.fromkeys(regions, {}) for region in regions: stat12[region] = dict.fromkeys(values)
def blackbody_nu(in_x, temperature): """Calculate blackbody flux per steradian, :math:`B_{\\nu}(T)`. .. note:: Use `numpy.errstate` to suppress Numpy warnings, if desired. .. warning:: Output values might contain ``nan`` and ``inf``. Parameters ---------- in_x : number, array-like, or `~astropy.units.Quantity` Frequency, wavelength, or wave number. If not a Quantity, it is assumed to be in Hz. temperature : number, array-like, or `~astropy.units.Quantity` Blackbody temperature. If not a Quantity, it is assumed to be in Kelvin. Returns ------- flux : `~astropy.units.Quantity` Blackbody monochromatic flux in :math:`erg \\; cm^{-2} s^{-1} Hz^{-1} sr^{-1}`. Raises ------ ValueError Invalid temperature. ZeroDivisionError Wavelength is zero (when converting to frequency). """ # Convert to units for calculations, also force double precision with u.add_enabled_equivalencies(u.spectral() + u.temperature()): freq = u.Quantity(in_x, u.Hz, dtype=np.float64) temp = u.Quantity(temperature, u.K, dtype=np.float64) # Check if input values are physically possible if np.any(temp < 0): raise ValueError(f'Temperature should be positive: {temp}') if not np.all(np.isfinite(freq)) or np.any(freq <= 0): warnings.warn('Input contains invalid wavelength/frequency value(s)', AstropyUserWarning) log_boltz = const.h * freq / (const.k_B * temp) boltzm1 = np.expm1(log_boltz) if _has_buggy_expm1: # Replace incorrect nan results with infs--any result of 'nan' is # incorrect unless the input (in log_boltz) happened to be nan to begin # with. (As noted in #4393 ideally this would be replaced by a version # of expm1 that doesn't have this bug, rather than fixing incorrect # results after the fact...) boltzm1_nans = np.isnan(boltzm1) if np.any(boltzm1_nans): if boltzm1.isscalar and not np.isnan(log_boltz): boltzm1 = np.inf else: boltzm1[np.where(~np.isnan(log_boltz) & boltzm1_nans)] = np.inf # Calculate blackbody flux bb_nu = (2.0 * const.h * freq**3 / (const.c**2 * boltzm1)) flux = bb_nu.to(FNU, u.spectral_density(freq)) return flux / u.sr # Add per steradian to output flux unit
param3 = uvp.UVParameter(name="p3", value=np.array([0, 1])) assert param1 != param3 def test_array_equality_nans(): """Test array equality with nans present.""" param1 = uvp.UVParameter(name="p1", value=np.array([0, 1, np.nan])) param2 = uvp.UVParameter(name="p2", value=np.array([0, 1, np.nan])) assert param1 == param2 @pytest.mark.parametrize("atol", [0.001, 1 * units.mm]) @pytest.mark.parametrize( "vals", ( units.Quantity([0 * units.cm, 100 * units.cm, 3000 * units.mm]), units.Quantity([0.09 * units.cm, 100.09 * units.cm, 2999.1 * units.mm ]), np.array([0, 1000, 3000]) * units.mm, ), ) def test_quantity_equality(atol, vals): """Test equality for different quantity values.""" param1 = uvp.UVParameter(name="p1", value=np.array([0, 1, 3]) * units.m, tols=atol) param2 = uvp.UVParameter(name="p2", value=vals, tols=atol) assert param1 == param2 def test_quantity_equality_error():
vmag = -99. bmag = -99. vmage = -99. bmage = -99. jmags = -99. hmags = -99. kmags = -99. jmagse = -99. hmagse = -99. kmagse = -99. ra = -99. dec = -99. print('querying Gaia ...') try: width = u.Quantity(0.01, u.deg) height = u.Quantity(0.01, u.deg) gaiaq = Gaia.query_object_async(coordinate=coord[0], width=width, height=height) plx = gaiaq['parallax'][0] + 0.05 plxe = gaiaq['parallax_error'][0] bpmags = gaiaq['phot_bp_mean_mag'][0] bpmagse = 0.01 rpmags = gaiaq['phot_rp_mean_mag'][0] rpmagse = 0.01 print('done') except: gaiaq = 0 print('failed')
from astropy.units.quantity import QuantityInfoBase from astropy.utils.exceptions import AstropyUserWarning from .angles import Longitude, Latitude from .representation import CartesianRepresentation, CartesianDifferential from .errors import UnknownSiteException from astropy.utils import data from astropy import _erfa as erfa __all__ = ['EarthLocation'] GeodeticLocation = collections.namedtuple('GeodeticLocation', ['lon', 'lat', 'height']) # Available ellipsoids (defined in erfam.h, with numbers exposed in erfa). ELLIPSOIDS = ('WGS84', 'GRS80', 'WGS72') OMEGA_EARTH = u.Quantity(7.292115855306589e-5, 1./u.s) """ Rotational velocity of Earth. In UT1 seconds, this would be 2 pi / (24 * 3600), but we need the value in SI seconds. See Explanatory Supplement to the Astronomical Almanac, ed. P. Kenneth Seidelmann (1992), University Science Books. """ def _check_ellipsoid(ellipsoid=None, default='WGS84'): if ellipsoid is None: ellipsoid = default if ellipsoid not in ELLIPSOIDS: raise ValueError('Ellipsoid {} not among known ones ({})' .format(ellipsoid, ELLIPSOIDS)) return ellipsoid
def is_quantity(instance): try: _ = u.Quantity(instance) return True except ValueError: return False
from .. import config # factor 2.3545 converts from FWHM to sigma perpplanescatter = 1.5 / 2.3545 * u.arcsec # 2 * 0.68 converts HPD to sigma inplanescatter = 7. / (2 * 0.68) * u.arcsec focallength = 12000. spogeom = load_table('spos', 'petallayout') spogeom['r_mid'] = (spogeom['outer_radius'] + spogeom['inner_radius']) / 2 spo_pos4d = [] # Convert angle to quantity here to make sure that unit is taken into account for row, ang in zip(spogeom, u.Quantity(spogeom['clocking_angle']).to(u.rad).value): spo_pos4d.append(compose([0, # focallength, # - spogeom[i]['d_from_12m'] row['r_mid'] * np.sin(ang), row['r_mid'] * np.cos(ang)], euler2mat(-ang, 0., 0.), # In detail this should be (primary_length + gap + secondary_length) / 2 # but the gap is somewhat complicated and this is only used # for display, we'll ignore that for now. [row['primary_length'], row['azwidth'] / 2., (row['outer_radius'] - row['inner_radius']) / 2.])) spo_pos4d = [np.dot(xyz2zxy, s) for s in spo_pos4d] reflectivity = load_table2d(os.path.join(config['data']['caldb_inputdata'], 'spos', 'coated_reflectivity.csv'))
def exposure(geom_true): m = Map.from_geom(geom_true) m.quantity = np.ones(geom_true.data_shape) * u.Quantity("100 m2 s") m.data[1] *= 10 return m
def __init__(self, rad, psf_value, interp_kwargs=None): self.rad = Angle(rad).to("rad") self.psf_value = u.Quantity(psf_value).to("sr^-1") self._interp_kwargs = interp_kwargs or {}
def function(self, lamb, Av=1.0, Rv=3.1, Alambda=True, **kwargs): """ Cardelli89 extinction Law Parameters ---------- lamb: float or ndarray(dtype=float) wavelength [in Angstroms] at which to evaluate the law. Av: float desired A(V) (default: 1.0) Rv: float desired R(V) (default: 3.1) Alambda: bool if set returns +2.5*1./log(10.)*tau, tau otherwise Returns ------- r: float or ndarray(dtype=float) attenuation as a function of wavelength depending on Alambda option +2.5*1./log(10.)*tau, or tau """ # ensure the units are in angstrom _lamb = units.Quantity(lamb, units.angstrom).value if isinstance(_lamb, float) or isinstance(_lamb, np.float_): _lamb = np.asarray([lamb]) else: _lamb = lamb[:] # convert to wavenumbers x = 1.0e4 / _lamb # check that the wavenumbers are within the defined range _test_valid_x_range(x, self.x_range, self.name) # init variables a = np.zeros(np.size(x)) b = np.zeros(np.size(x)) # Infrared (Eq 2a,2b) ind = np.where((x >= 0.3) & (x < 1.1)) a[ind] = 0.574 * x[ind]**1.61 b[ind] = -0.527 * x[ind]**1.61 # Optical & Near IR # Eq 3a, 3b ind = np.where((x >= 1.1) & (x < 3.3)) y = x[ind] - 1.82 a[ind] = (1.0 + 0.17699 * y - 0.50447 * y**2 - 0.02427 * y**3 + 0.72085 * y**4 + 0.01979 * y**5 - 0.77530 * y**6 + 0.32999 * y**7) b[ind] = (1.41338 * y + 2.28305 * y**2 + 1.07233 * y**3 - 5.38434 * y**4 - 0.62251 * y**5 + 5.30260 * y**6 - 2.09002 * y**7) # UV # Eq 4a, 4b ind = np.where((x >= 3.3) & (x <= 8.0)) a[ind] = 1.752 - 0.316 * x[ind] - 0.104 / ((x[ind] - 4.67)**2 + 0.341) b[ind] = -3.090 + 1.825 * x[ind] + 1.206 / ((x[ind] - 4.62)**2 + 0.263) ind = np.where((x >= 5.9) & (x <= 8.0)) y = x[ind] - 5.9 Fa = -0.04473 * y**2 - 0.009779 * y**3 Fb = 0.21300 * y**2 + 0.120700 * y**3 a[ind] = a[ind] + Fa b[ind] = b[ind] + Fb # Far UV # Eq 5a, 5b ind = np.where((x > 8.0) & (x <= 10.0)) # Fa = Fb = 0 y = x[ind] - 8.0 a[ind] = -1.073 - 0.628 * y + 0.137 * y**2 - 0.070 * y**3 b[ind] = 13.670 + 4.257 * y - 0.420 * y**2 + 0.374 * y**3 # Case of -values x out of range [0.289,10.0] ind = np.where((x > 10.0) | (x < 0.3)) a[ind] = 0.0 b[ind] = 0.0 # Return Extinction vector # Eq 1 if Alambda: return (a + b / Rv) * Av else: # return( 1./(2.5 * 1. / np.log(10.)) * ( a + b / Rv ) * Av) return 0.4 * np.log(10.0) * (a + b / Rv) * Av
def __init__(self, maps, temperature: u.K, responses, **kwargs): self.temperature = temperature wvl = u.Quantity([m.meta['wavelnth']*u.Unit(m.meta['waveunit']) for m in maps]) self.maps = [maps[i] for i in np.argsort(wvl)] self.response = [responses[i] for i in np.argsort(wvl)] self.wavelength = np.sort(wvl)
def __init__( self, geometry, image=None, ax=None, title="Camera", norm="lin", cmap="hot", allow_pick=False, autoupdate=True, autoscale=True, antialiased=True, ): self.axes = ax if ax is not None else plt.gca() self.geom = geometry self.pixels = None self.colorbar = None self.autoupdate = autoupdate self.autoscale = autoscale self._active_pixel = None self._active_pixel_label = None # initialize the plot and generate the pixels as a # RegularPolyCollection patches = [] if not hasattr(self.geom, "mask"): self.geom.mask = np.ones_like(self.geom.pix_x.value, dtype=bool) for xx, yy, aa in zip( u.Quantity(self.geom.pix_x[self.geom.mask]).value, u.Quantity(self.geom.pix_y[self.geom.mask]).value, u.Quantity(np.array(self.geom.pix_area)[self.geom.mask]).value): if self.geom.pix_type.startswith("hex"): rr = sqrt(aa * 2 / 3 / sqrt(3)) poly = RegularPolygon( (xx, yy), 6, radius=rr, orientation=self.geom.pix_rotation.rad, fill=True, ) else: rr = sqrt(aa) poly = Rectangle( (xx-rr/2., yy-rr/2.), width=rr, height=rr, angle=self.geom.pix_rotation.deg, fill=True, ) patches.append(poly) self.pixels = PatchCollection(patches, cmap=cmap, linewidth=0) self.axes.add_collection(self.pixels) self.pixel_highlighting = copy.copy(self.pixels) self.pixel_highlighting.set_facecolor('none') self.pixel_highlighting.set_linewidth(0) self.axes.add_collection(self.pixel_highlighting) # Set up some nice plot defaults self.axes.set_aspect('equal', 'datalim') self.axes.set_title(title) self.axes.set_xlabel("X position ({})".format(self.geom.pix_x.unit)) self.axes.set_ylabel("Y position ({})".format(self.geom.pix_y.unit)) self.axes.autoscale_view() # set up a patch to display when a pixel is clicked (and # pixel_picker is enabled): self._active_pixel = copy.copy(patches[0]) self._active_pixel.set_facecolor('r') self._active_pixel.set_alpha(0.5) self._active_pixel.set_linewidth(2.0) self._active_pixel.set_visible(False) self.axes.add_patch(self._active_pixel) self._active_pixel_label = self.axes.text(self._active_pixel.xy[0], self._active_pixel.xy[1], "0", horizontalalignment='center', verticalalignment='center') self._active_pixel_label.set_visible(False) # enable ability to click on pixel and do something (can be # enabled on-the-fly later as well: if allow_pick: self.enable_pixel_picker() if image is not None: self.image = image else: self.image = np.zeros_like(self.geom.pix_id, dtype=np.float) self.norm = norm
def test_angle_to_quantity(): with pytest.warns(IllegalSecondWarning): a = Angle('00:00:60', u.deg) q = u.Quantity(a) assert isinstance(q, u.Quantity) assert q.unit is u.deg
def test_spectraldensity4(): """PHOTLAM and PHOTNU conversions.""" flam = u.erg / (u.cm ** 2 * u.s * u.AA) fnu = u.erg / (u.cm ** 2 * u.s * u.Hz) photlam = u.photon / (u.cm ** 2 * u.s * u.AA) photnu = u.photon / (u.cm ** 2 * u.s * u.Hz) wave = u.Quantity([4956.8, 4959.55, 4962.3], u.AA) flux_photlam = [9.7654e-3, 1.003896e-2, 9.78473e-3] flux_photnu = [8.00335589e-14, 8.23668949e-14, 8.03700310e-14] flux_flam = [3.9135e-14, 4.0209e-14, 3.9169e-14] flux_fnu = [3.20735792e-25, 3.29903646e-25, 3.21727226e-25] flux_jy = [3.20735792e-2, 3.29903646e-2, 3.21727226e-2] flux_stmag = [12.41858665, 12.38919182, 12.41764379] flux_abmag = [12.63463143, 12.60403221, 12.63128047] # PHOTLAM <--> FLAM assert_allclose(photlam.to( flam, flux_photlam, u.spectral_density(wave)), flux_flam, rtol=1e-6) assert_allclose(flam.to( photlam, flux_flam, u.spectral_density(wave)), flux_photlam, rtol=1e-6) # PHOTLAM <--> FNU assert_allclose(photlam.to( fnu, flux_photlam, u.spectral_density(wave)), flux_fnu, rtol=1e-6) assert_allclose(fnu.to( photlam, flux_fnu, u.spectral_density(wave)), flux_photlam, rtol=1e-6) # PHOTLAM <--> Jy assert_allclose(photlam.to( u.Jy, flux_photlam, u.spectral_density(wave)), flux_jy, rtol=1e-6) assert_allclose(u.Jy.to( photlam, flux_jy, u.spectral_density(wave)), flux_photlam, rtol=1e-6) # PHOTLAM <--> PHOTNU assert_allclose(photlam.to( photnu, flux_photlam, u.spectral_density(wave)), flux_photnu, rtol=1e-6) assert_allclose(photnu.to( photlam, flux_photnu, u.spectral_density(wave)), flux_photlam, rtol=1e-6) # PHOTNU <--> FNU assert_allclose(photnu.to( fnu, flux_photnu, u.spectral_density(wave)), flux_fnu, rtol=1e-6) assert_allclose(fnu.to( photnu, flux_fnu, u.spectral_density(wave)), flux_photnu, rtol=1e-6) # PHOTNU <--> FLAM assert_allclose(photnu.to( flam, flux_photnu, u.spectral_density(wave)), flux_flam, rtol=1e-6) assert_allclose(flam.to( photnu, flux_flam, u.spectral_density(wave)), flux_photnu, rtol=1e-6) # PHOTLAM <--> STMAG assert_allclose(photlam.to( u.STmag, flux_photlam, u.spectral_density(wave)), flux_stmag, rtol=1e-6) assert_allclose(u.STmag.to( photlam, flux_stmag, u.spectral_density(wave)), flux_photlam, rtol=1e-6) # PHOTLAM <--> ABMAG assert_allclose(photlam.to( u.ABmag, flux_photlam, u.spectral_density(wave)), flux_abmag, rtol=1e-6) assert_allclose(u.ABmag.to( photlam, flux_abmag, u.spectral_density(wave)), flux_photlam, rtol=1e-6)
def make_rprof(regions, ploteach=False): names = [r.attr[1]['text'] for r in regions] center_positions = coordinates.SkyCoord([r.coord_list for r in regions], unit=(u.deg, u.deg), frame='fk5') size = u.Quantity([1.25, 1.25], u.arcsec) if ploteach: nplots = len(names) for ii in range(nplots): pl.figure(ii).clf() pl.figure(nplots + ii).clf() pl.figure(nplots * 2 + ii).clf() linestyles = { name: itertools.cycle(['-'] + ['--'] + [':'] + ['-.']) for name in names } for fn in ffiles: fh = fits.open(paths.dpath("12m/continuum/" + fn)) mywcs = wcs.WCS(fh[0].header) if 'BMAJ' not in fh[0].header: #print("File {0} does not have BMAJ".format(fn)) continue try: beam = radio_beam.Beam.from_fits_header(fh[0].header) except KeyError: #print("File {0} doesn't have beam info in the header".format(fn)) continue pixscale = (mywcs.pixel_scale_matrix.diagonal()**2).sum()**0.5 ppbeam = (beam.sr / (pixscale**2 * u.deg**2)).decompose().value / u.beam #print("fn {0} ppbeam={1:0.2f}".format(fn, ppbeam)) for ii, (name, position) in enumerate(zip(names, center_positions)): cutout = Cutout2D(fh[0].data, position, size, wcs=mywcs) nr, bins, rprof = azimuthalAverage(cutout.data, binsize=1.0, return_nr=True) linestyle = next(linestyles[name]) pl.figure(ii) pl.title(name) pl.plot(bins * pixscale * 3600., rprof / ppbeam, label=fn.split(".")[0], linestyle=linestyle) pl.ylabel("Azimuthally Averaged Flux (Jy)") pl.xlabel("Radius [arcsec]") cumul_rprof = np.nan_to_num(rprof * nr / ppbeam).cumsum() pl.figure(nplots + ii) pl.title(name) pl.plot(bins * pixscale * 3600., cumul_rprof, label=fn.split(".")[0], linestyle=linestyle) pl.ylabel("Cumulative Flux (Jy)") pl.xlabel("Radius [arcsec]") if ii == 0: ax = pl.gca() ax2 = ax.twiny() ax3 = ax.twinx() def tick_function(old_x): newx = (old_x * u.arcsec * masscalc.distance).to( u.pc, u.dimensionless_angles()).value return ["%.1f" % z for z in newx] new_tick_locations = [0.005, 0.01, 0.015, 0.02, 0.025 ] * u.pc new_tick_locs_as = (new_tick_locations / masscalc.distance).to( u.arcsec, u.dimensionless_angles()) ax2.set_xlim(ax.get_xlim()) ax2.set_xticks(new_tick_locs_as.value) ax2.set_xticklabels(tick_function(new_tick_locs_as.value)) ax2.set_xlabel(r"Radius (pc)") ax3.set_ylim(ax.get_ylim()) yticks_mass = np.arange(0, 6000, 1000) yticks_Jy = yticks_mass / masscalc.mass_conversion_factor( ).value ax3.set_yticks(yticks_Jy) ax3.set_yticklabels(yticks_mass) ax3.set_ylabel("Cumulative Mass (M$_\\odot$, $T=20$ K)") pl.figure(nplots * 2 + ii) pl.title(name) pl.plot(((bins * pixscale * u.deg) * masscalc.distance).to( u.pc, u.dimensionless_angles()), cumul_rprof * masscalc.mass_conversion_factor(), label=fn.split(".")[0], linestyle=linestyle) pl.ylabel("Cumulative Mass (M$_\\odot$, $T=20$ K)") pl.xlabel("Radius (pc)") for ii in range(nplots): for xtra in (0, nplots * 2): ax = pl.figure(ii + xtra).gca() box = ax.get_position() ax.set_position([box.x0, box.y0, box.width * 0.6, box.height]) # Put a legend to the right of the current axis ax.legend(loc='center left', bbox_to_anchor=(1, 0.5)) else: nplots = 0 pl.matplotlib.rc_file('pubfiguresrc') for jj in range(nplots * 3 + 1, nplots * 3 + 11): pl.figure(jj).clf() # $ find ~/work/w51/alma/FITS/ -samefile ~/work/w51/alma/FITS/W51_te_continuum_best.fits # /Users/adam/work/w51/alma/FITS//12m/continuum/selfcal_allspw_selfcal_3_mfs_deeper.image.pbcor.fits # /Users/adam/work/w51/alma/FITS//W51_te_continuum_best.fits fn = "selfcal_allspw_selfcal_3_mfs_deeper.image.pbcor.fits" fh = fits.open(paths.dpath("12m/continuum/" + fn)) mywcs = wcs.WCS(fh[0].header) beam = radio_beam.Beam.from_fits_header(fh[0].header) pixscale = (mywcs.pixel_scale_matrix.diagonal()**2).sum()**0.5 ppbeam = (beam.sr / (pixscale**2 * u.deg**2)).decompose().value / u.beam for ii, (name, position) in enumerate(zip(names, center_positions)): cutout = Cutout2D(fh[0].data, position, size, wcs=mywcs) nr, bins, rprof = azimuthalAverage(cutout.data, binsize=1.0, return_nr=True) pl.figure(nplots * 3 + 1) #pl.title(fn.replace(".image.pbcor.fits","")) pl.plot(bins * pixscale * 3600., rprof / ppbeam, label=name) pl.ylabel("Azimuthally Averaged Flux (Jy)") pl.xlabel("Radius [arcsec]") if len(names) < 5: pl.legend(loc='best') elif ii == len(names) - 1: ax = pl.gca() box = ax.get_position() ax.set_position([box.x0, box.y0, box.width * 0.6, box.height]) # Put a legend to the right of the current axis ax.legend(loc='center left', bbox_to_anchor=(1, 0.5)) cumul_rprof = np.nan_to_num(rprof * nr / ppbeam).cumsum() pl.figure(nplots * 3 + 2) #pl.title(fn.replace(".image.pbcor.fits","")) pl.plot(bins * pixscale * 3600., cumul_rprof, label=name) pl.ylabel("Cumulative Flux (Jy)") pl.xlabel("Radius [arcsec]") if len(names) < 5: pl.legend(loc='best') elif ii == len(names) - 1: ax = pl.gca() box = ax.get_position() ax.set_position([box.x0, box.y0, box.width * 0.6, box.height]) # Put a legend to the right of the current axis ax.legend(loc='center left', bbox_to_anchor=(1, 0.5)) if ii == len(names) - 1: ax = pl.gca() ax2 = ax.twiny() ax3 = ax.twinx() def tick_function(old_x): newx = (old_x * u.arcsec * masscalc.distance).to( u.au, u.dimensionless_angles()).value return ["%.1f" % z for z in newx] new_tick_locations = np.arange(0, 8000, 1000) * u.au new_tick_locs_as = (new_tick_locations / masscalc.distance).to( u.arcsec, u.dimensionless_angles()) ax2.set_xlim(ax.get_xlim()) ax2.set_xticks(new_tick_locs_as.value) ax2.set_xticklabels(tick_function(new_tick_locs_as.value)) ax2.set_xlabel(r"Radius [au]") ax3.set_ylim(ax.get_ylim()) yticks_mass = np.arange(0, 6000, 1000) yticks_Jy = yticks_mass / masscalc.mass_conversion_factor( TK=40).value ax3.set_yticks(yticks_Jy) ax3.set_yticklabels(yticks_mass) ax3.set_ylabel("Cumulative Mass (M$_\\odot$, $T=40$ K)") radii = ((bins * pixscale * u.deg) * masscalc.distance).to( u.pc, u.dimensionless_angles()) mass_40k_profile = (cumul_rprof * masscalc.mass_conversion_factor(TK=40) / u.beam).to(u.M_sun) pl.figure(nplots * 3 + 3) #pl.title(fn.replace(".image.pbcor.fits","")) pl.plot(radii, mass_40k_profile, label=name) pl.ylabel("Cumulative Mass (M$_\\odot$, $T=40$ K)") pl.xlabel("Radius (pc)") if len(names) < 5: pl.legend(loc='best') elif ii == len(names) - 1: ax = pl.gca() box = ax.get_position() ax.set_position([box.x0, box.y0, box.width * 0.6, box.height]) # Put a legend to the right of the current axis ax.legend(loc='center left', bbox_to_anchor=(1, 0.5)) density_40k_profile = (mass_40k_profile / (4 / 3. * np.pi * radii**3) / (2.8 * u.Da)).to(u.cm**-3) #print(density_40k_profile) #print(radii) pl.figure(nplots * 3 + 4) #pl.title(fn.replace(".image.pbcor.fits","")) pl.semilogy(radii, density_40k_profile, label=name) pl.ylabel("Cumulative Density [n(H$_2$), $T=40$ K]") pl.xlabel("Radius (pc)") if len(names) < 5: pl.legend(loc='best') elif ii == len(names) - 1: ax = pl.gca() box = ax.get_position() ax.set_position([box.x0, box.y0, box.width * 0.6, box.height]) # Put a legend to the right of the current axis ax.legend(loc='center left', bbox_to_anchor=(1, 0.5)) angular_radii = bins * pixscale * 3600. azimuthal_average_flux = rprof / ppbeam azimuthal_average_mass = azimuthal_average_flux * masscalc.mass_conversion_factor( TK=40) / u.beam bindiff_as = np.diff(bins).mean() * pixscale * 3600. bindiff_cm = bindiff_as * masscalc.distance / 206265. bins_cm = (angular_radii * masscalc.distance / 206265.).to(u.cm) sqdiffbins_cm = u.Quantity([bins_cm[0].to(u.cm).value**2] + (bins_cm.to(u.cm)[1:]**2 - bins_cm.to(u.cm)[:-1]**2).value.tolist(), u.cm**2) cudiffbins_cm = u.Quantity([bins_cm[0].to(u.cm).value**3] + (bins_cm.to(u.cm)[1:]**3 - bins_cm.to(u.cm)[:-1]**3).value.tolist(), u.cm**3) sqdiffbins_pix = [bins[0]**2] + (bins[1:]**2 - bins[:-1]**2).tolist() azimuthal_average_density = (azimuthal_average_mass * sqdiffbins_pix / (2.8 * u.Da) / (4 / 3. * np.pi * (cudiffbins_cm))).to( u.cm**-3) pl.figure(nplots * 3 + 5) pl.semilogy(angular_radii, azimuthal_average_density, label=name) pl.ylabel("Azimuthally Averaged Density [cm$^{-3}$]") pl.xlabel("Radius [arcsec]") if len(names) < 5: pl.legend(loc='best') elif ii == len(names) - 1: ax = pl.gca() box = ax.get_position() ax.set_position([box.x0, box.y0, box.width * 0.6, box.height]) # Put a legend to the right of the current axis ax.legend(loc='center left', bbox_to_anchor=(1, 0.5)) if ii == len(names) - 1: ax = pl.gca() ax.set_ylim(1e7, 5e10) ax2 = ax.twiny() #ax3 = ax.twinx() def tick_function(old_x): newx = (old_x * u.arcsec * masscalc.distance).to( u.au, u.dimensionless_angles()).value return ["%.1f" % z for z in newx] new_tick_locations = np.arange(0, 8000, 1000) * u.au new_tick_locs_as = (new_tick_locations / masscalc.distance).to( u.arcsec, u.dimensionless_angles()) ax2.set_xlim(ax.get_xlim()) ax2.set_xticks(new_tick_locs_as.value) ax2.set_xticklabels(tick_function(new_tick_locs_as.value)) ax2.set_xlabel(r"Radius [au]") #ax3.set_ylim(ax.get_ylim()) #yticks_mass = np.arange(0,6000,1000) #yticks_Jy = yticks_mass/masscalc.mass_conversion_factor(TK=40).value #ax3.set_yticks(yticks_Jy) #ax3.set_yticklabels(yticks_mass) #ax3.set_ylabel("Cumulative Mass (M$_\\odot$, $T=40$ K)") c_s_40k = ((constants.k_B * 40 * u.K / (2.4 * u.Da))**0.5).to(u.km / u.s) azimuthal_average_MJ_40k = ( np.pi / 6. * c_s_40k**3 / (constants.G**1.5 * (2.8 * u.Da * azimuthal_average_density)**0.5)).to(u.M_sun) pl.figure(nplots * 3 + 6) pl.semilogy(angular_radii, azimuthal_average_MJ_40k, label=name) pl.ylabel("Azimuthally Averaged $M_J$ at $T=40$K") pl.xlabel("Radius [arcsec]") if len(names) < 5: pl.legend(loc='best') elif ii == len(names) - 1: ax = pl.gca() box = ax.get_position() ax.set_position([box.x0, box.y0, box.width * 0.6, box.height]) # Put a legend to the right of the current axis ax.legend(loc='center left', bbox_to_anchor=(1, 0.5)) if ii == len(names) - 1: ax = pl.gca() #ax.set_ylim(1e7, 5e10) ax2 = ax.twiny() #ax3 = ax.twinx() def tick_function(old_x): newx = (old_x * u.arcsec * masscalc.distance).to( u.au, u.dimensionless_angles()).value return ["%.1f" % z for z in newx] new_tick_locations = np.arange(0, 8000, 1000) * u.au new_tick_locs_as = (new_tick_locations / masscalc.distance).to( u.arcsec, u.dimensionless_angles()) ax2.set_xlim(ax.get_xlim()) ax2.set_xticks(new_tick_locs_as.value) ax2.set_xticklabels(tick_function(new_tick_locs_as.value)) ax2.set_xlabel(r"Radius [au]") source = 'e2' if name == 'e2e' else name temperature_map_fn = paths.dpath( '12m/moments/CH3OH_{0}_cutout_temperaturemap.fits'.format(source)) temperature_map_fh = fits.open(temperature_map_fn) # this whole section is copied from overlay_contours_on_ch3oh ch3ohN_hdul = fits.open( paths.dpath( '12m/moments/CH3OH_{0}_cutout_columnmap.fits'.format(source))) ch3ohT_hdul = fits.open( paths.dpath( '12m/moments/CH3OH_{0}_cutout_temperaturemap.fits'.format( source))) bigwcs = wcs.WCS(ch3ohT_hdul[0].header) bigpixscale = (bigwcs.pixel_scale_matrix.diagonal()** 2).sum()**0.5 * u.deg ch3ohN = ch3ohN_hdul[0].data ch3ohT = ch3ohT_hdul[0].data dust_brightness, wts = reproject.reproject_interp( fits.open(paths.dpath('W51_te_continuum_best.fits')), ch3ohN_hdul[0].header) bm = radio_beam.Beam.from_fits_header( paths.dpath("W51_te_continuum_best.fits")) yy, xx = np.indices(ch3ohN.shape) if source == 'north': center = [84., 38.] else: center = [ch3ohN.shape[0] / 2., ch3ohN.shape[1] / 2.] yyc = (yy - center[0]) xxc = (xx - center[1]) rr = (yyc**2 + xxc**2)**0.5 rr_as = (rr * bigpixscale).to(u.arcsec) theta = np.arctan2(yyc, xxc) * u.rad dust_column = dust_emissivity.dust.colofsnu(225 * u.GHz, dust_brightness * u.Jy, beamomega=bm, temperature=ch3ohT * u.K) ch3oh_abundance = ch3ohN / dust_column.value mask = (ch3oh_abundance > 1e-10) & (ch3oh_abundance < 1e-5) if source == 'e2': mask = mask & (((theta > 15 * u.deg) & (theta < 345 * u.deg)) | (theta < -15 * u.deg)) mask = mask & np.isfinite(ch3oh_abundance) # exclude high-abundance, low-column regions: likely to be div-by-zero zones mask = mask & (~((ch3ohN < 1e18) & (ch3oh_abundance > 5e-6))) mask = mask & (~((dust_brightness < 1e-2) & (ch3ohT > 500) & (ch3oh_abundance > 1e-6))) #mask = mask & (~((ch3ohT > 250) & # (ch3ohN < 1e18) & # (rr_as>1.5*u.arcsec)) # )# these are low-column, temwcs = wcs.WCS(temperature_map_fh[0].header) temcutout = Cutout2D(temperature_map_fh[0].data, position, size, wcs=temwcs) maskcutout = Cutout2D(mask.astype('float'), position, size, wcs=bigwcs) tem_nr, tem_bins, tem_rprof = azimuthalAverage( temcutout.data, weights=(maskcutout.data > 0).astype('float'), binsize=1.0, return_nr=True, interpnan=True, ) mass_profile = (cumul_rprof * masscalc.mass_conversion_factor(TK=tem_rprof) / u.beam).to(u.M_sun) density_profile = (mass_profile / (4 / 3. * np.pi * radii**3) / (2.8 * u.Da)).to(u.cm**-3) c_s = ((constants.k_B * tem_rprof * u.K / (2.4 * u.Da))**0.5).to(u.km / u.s) azimuthal_average_MJ = ( np.pi / 6. * c_s**3 / (constants.G**1.5 * (2.8 * u.Da * azimuthal_average_density)**0.5)).to(u.M_sun) pl.figure(nplots * 3 + 7) pl.plot(angular_radii, azimuthal_average_MJ, label=name) pl.ylabel( "Azimuthally Averaged $M_J$ at $T(\\mathrm{CH}_3\\mathrm{OH})$") pl.xlabel("Radius [arcsec]") if len(names) < 5: pl.legend(loc='best') elif ii == len(names) - 1: ax = pl.gca() box = ax.get_position() ax.set_position([box.x0, box.y0, box.width * 0.6, box.height]) # Put a legend to the right of the current axis ax.legend(loc='center left', bbox_to_anchor=(1, 0.5)) if ii == len(names) - 1: ax = pl.gca() #ax.set_ylim(1e7, 5e10) ax2 = ax.twiny() #ax3 = ax.twinx() def tick_function(old_x): newx = (old_x * u.arcsec * masscalc.distance).to( u.au, u.dimensionless_angles()).value return ["%.1f" % z for z in newx] new_tick_locations = np.arange(0, 8000, 1000) * u.au new_tick_locs_as = (new_tick_locations / masscalc.distance).to( u.arcsec, u.dimensionless_angles()) ax2.set_xlim(ax.get_xlim()) ax2.set_xticks(new_tick_locs_as.value) ax2.set_xticklabels(tick_function(new_tick_locs_as.value)) ax2.set_xlabel(r"Radius [au]") pl.figure(nplots * 3 + 8) #pl.title(fn.replace(".image.pbcor.fits","")) pl.plot(bins * pixscale * 3600., mass_profile, label=name) pl.ylabel("Cumulative Mass at T(CH$_3$OH)") pl.xlabel("Radius [arcsec]") if len(names) < 5: pl.legend(loc='best') elif ii == len(names) - 1: ax = pl.gca() box = ax.get_position() ax.set_position([box.x0, box.y0, box.width * 0.6, box.height]) # Put a legend to the right of the current axis ax.legend(loc='center left', bbox_to_anchor=(1, 0.5)) if ii == len(names) - 1: ax = pl.gca() ax2 = ax.twiny() def tick_function(old_x): newx = (old_x * u.arcsec * masscalc.distance).to( u.au, u.dimensionless_angles()).value return ["%.1f" % z for z in newx] new_tick_locations = np.arange(0, 8000, 1000) * u.au new_tick_locs_as = (new_tick_locations / masscalc.distance).to( u.arcsec, u.dimensionless_angles()) ax2.set_xlim(ax.get_xlim()) ax2.set_xticks(new_tick_locs_as.value) ax2.set_xticklabels(tick_function(new_tick_locs_as.value)) ax2.set_xlabel(r"Radius [au]") pl.figure(nplots * 3 + 9) #pl.title(fn.replace(".image.pbcor.fits","")) pl.plot(bins * pixscale * 3600., tem_rprof, label=name) pl.legend(loc='best') pl.ylabel("CH$_3$OH temperature") pl.xlabel("Radius (as)") azimuthal_average_RJ = ( c_s**1 / (constants.G**0.5 * (2.8 * u.Da * azimuthal_average_density)**0.5)).to(u.au) pl.figure(nplots * 3 + 10) pl.plot(angular_radii, azimuthal_average_RJ, label=name) pl.plot([ 0, (7000 * u.au / masscalc.distance).to( u.arcsec, u.dimensionless_angles()).value ], [0, 7000], 'k--', alpha=0.5) pl.ylabel( "Azimuthally Averaged $R_J$ at $T(\\mathrm{CH}_3\\mathrm{OH})$ [au]" ) pl.xlabel("Radius [arcsec]") pl.ylim(0, 3000) if len(names) < 5: pl.legend(loc='best') elif ii == len(names) - 1: ax = pl.gca() box = ax.get_position() ax.set_position([box.x0, box.y0, box.width * 0.6, box.height]) # Put a legend to the right of the current axis ax.legend(loc='center left', bbox_to_anchor=(1, 0.5)) if ii == len(names) - 1: ax = pl.gca() #ax.set_ylim(1e7, 5e10) ax2 = ax.twiny() #ax3 = ax.twinx() def tick_function(old_x): newx = (old_x * u.arcsec * masscalc.distance).to( u.au, u.dimensionless_angles()).value return ["%.1f" % z for z in newx] new_tick_locations = np.arange(0, 8000, 1000) * u.au new_tick_locs_as = (new_tick_locations / masscalc.distance).to( u.arcsec, u.dimensionless_angles()) ax2.set_xlim(ax.get_xlim()) ax2.set_xticks(new_tick_locs_as.value) ax2.set_xticklabels(tick_function(new_tick_locs_as.value)) ax2.set_xlabel(r"Radius [au]")
import astropy.units as u from astropy.time import Time from ... import exceptions as sbe from .. import orbit as sbo from ..orbit import Orbit try: import pyoorb # noqa except ImportError: pyoorb = None # CERES and CERES2 retrieved from Horizons on 24 Sep 2021 CERES = { 'targetname': '1 Ceres (A801 AA)', 'H': u.Quantity(3.53, 'mag'), 'G': 0.12, 'e': 0.07842518340409492, 'q': u.Quantity(2.548847914875325, 'au'), 'incl': u.Quantity(10.58812123343471, 'deg'), 'Omega': u.Quantity(80.26788752671405, 'deg'), 'w': u.Quantity(73.70547052298863, 'deg'), 'n': u.Quantity(0.21428120879034, 'deg / d'), 'M': u.Quantity(266.0066794881785, 'deg'), 'nu': u.Quantity(257.137950098325, 'deg'), 'a': u.Quantity(2.765752567209041, 'AU'), 'Q': u.Quantity(2.982657219542757, 'AU'), 'P': u.Quantity(1680.035323826441, 'd'), 'epoch': Time(2459482.454237461, scale='tdb', format='jd'), 'Tp': Time(2459921.098955971, scale='tdb', format='jd'), 'orbtype': 'KEP',
def vgal_to_hel(coordinate, vxyz, vcirc=VCIRC, vlsr=VLSR, galactocentric_frame=None): r""" Convert a Galactocentric, cartesian velocity to a Heliocentric velocity in spherical coordinates (e.g., proper motion and radial velocity). The frame of the input coordinate determines the output frame of the proper motions. For example, if the input coordinate is in the ICRS frame, the proper motions returned will be :math:`(\mu_\alpha\cos\delta,\mu_delta)`. This function also handles array inputs (see examples below). Examples -------- >>> import astropy.units as u >>> import astropy.coordinates as coord >>> c = coord.Galactocentric(x=15.*u.kpc, y=13.*u.kpc, z=2.*u.kpc) >>> vxyz = [-115., 100., 95.]*u.km/u.s >>> icrs = c.transform_to(coord.ICRS) >>> vgal_to_hel(icrs, vxyz) (<Quantity -0.876885123328934 mas / yr>, <Quantity 0.024501209459030334 mas / yr>, <Quantity -163.24449462243052 km / s>) >>> c = coord.Galactocentric([[15.,11.],[13,21.],[2.,-7]]*u.kpc) >>> vxyz = [[-115.,11.], [100.,-21.], [95.,103]]*u.km/u.s >>> icrs = c.transform_to(coord.ICRS) >>> vgal_to_hel(icrs, vxyz) (<Quantity [-0.87688512,-0.91157482] mas / yr>, <Quantity [ 0.02450121,-0.86124895] mas / yr>, <Quantity [-163.24449462,-198.31241148] km / s>) Parameters ---------- coordinate : :class:`~astropy.coordinates.SkyCoord`, :class:`~astropy.coordinates.BaseCoordinateFrame` This is most commonly a :class:`~astropy.coordinates.SkyCoord` object, but alternatively, it can be any coordinate frame object that is transformable to the Galactocentric frame. vxyz : :class:`~astropy.units.Quantity`, iterable Cartesian velocity components :math:`(v_x,v_y,v_z)`. This should either be a single :class:`~astropy.units.Quantity` object with shape (3,N), or an iterable object with 3 :class:`~astropy.units.Quantity` objects as elements. vcirc : :class:`~astropy.units.Quantity` (optional) Circular velocity of the Sun. vlsr : :class:`~astropy.units.Quantity` (optional) Velocity of the Sun relative to the local standard of rest (LSR). galactocentric_frame : :class:`~astropy.coordinates.Galactocentric` (optional) An instantiated :class:`~astropy.coordinates.Galactocentric` frame object with custom parameters for the Galactocentric coordinates. For example, if you want to set your own position of the Galactic center, you can pass in a frame with custom `galcen_ra` and `galcen_dec`. Returns ------- pmv : tuple A tuple containing the proper motions (in Galactic coordinates) and radial velocity, all as :class:`~astropy.units.Quantity` objects. """ if galactocentric_frame is None: galactocentric_frame = coord.Galactocentric # so I don't accidentally modify in place vxyz = vxyz.copy() # make sure this is a coordinate and get the frame for later use c = coord.SkyCoord(coordinate) coord_frame = c.frame R = _icrs_gctc_velocity_matrix(galactocentric_frame) # remove circular and LSR velocities vxyz[1] = vxyz[1] - vcirc for i in range(3): vxyz[i] = vxyz[i] - vlsr[i] orig_shape = vxyz.shape v_icrs = np.linalg.inv(R).dot( vxyz.reshape(vxyz.shape[0], np.prod(vxyz.shape[1:]))).reshape(orig_shape) # get cartesian galactocentric x_icrs = c.icrs.cartesian.xyz d = np.sqrt(np.sum(x_icrs**2, axis=0)) dxy = np.sqrt(x_icrs[0]**2 + x_icrs[1]**2) vr = np.sum(x_icrs * v_icrs, axis=0) / d with u.set_enabled_equivalencies(u.dimensionless_angles()): mua = ((x_icrs[0] * v_icrs[1] - v_icrs[0] * x_icrs[1]) / dxy**2).to( u.mas / u.yr) mua_cosd = (mua * dxy / d).to(u.mas / u.yr) mud = (-(x_icrs[2] * (x_icrs[0] * v_icrs[0] + x_icrs[1] * v_icrs[1]) - dxy**2 * v_icrs[2]) / d**2 / dxy).to(u.mas / u.yr) pm_radec = (mua_cosd, mud) if coord_frame.name == 'icrs': pm = u.Quantity(map(np.atleast_1d, pm_radec)) elif coord_frame.name == 'galactic': # transform to ICRS proper motions pm = pm_icrs_to_gal(c, pm_radec) else: raise NotImplementedError("Proper motions in the {} system are not " "currently supported.".format( coord_frame.name)) if c.isscalar: vr = vr.reshape(()) pm = (pm[0].reshape(()), pm[1].reshape(())) return tuple(pm) + (vr, )
def test_days(timerange_a): assert timerange_a.days == u.Quantity(1, 'd')
def vhel_to_gal(coordinate, pm, rv, vcirc=VCIRC, vlsr=VLSR, galactocentric_frame=None): r""" Convert a Heliocentric velocity in spherical coordinates (e.g., proper motion and radial velocity) in the ICRS or Galactic frame to a Galactocentric, cartesian velocity. The frame of the input coordinate determines how to interpret the given proper motions. For example, if the input coordinate is in the ICRS frame, the proper motions are assumed to be :math:`(\mu_\alpha\cos\delta,\mu_\delta)`. This function also handles array inputs (see examples below). Examples -------- >>> import astropy.units as u >>> import astropy.coordinates as coord >>> c = coord.SkyCoord(ra=196.5*u.degree, dec=-10.33*u.deg, distance=16.2*u.kpc) >>> pm = [-1.53, 3.5]*u.mas/u.yr >>> rv = 161.4*u.km/u.s >>> vhel_to_gal(c, pm=pm, rv=rv) <Quantity [-137.29984564, 262.64052249, 305.50786499] km / s> >>> c = coord.SkyCoord(ra=[196.5,51.3]*u.degree, dec=[-10.33,2.1]*u.deg, distance=[16.2,11.]*u.kpc) >>> pm = [[-1.53,4.5], [3.5,10.9]]*u.mas/u.yr >>> rv = [161.4,-210.2]*u.km/u.s >>> vhel_to_gal(c, pm=pm, rv=rv) <Quantity [[-137.29984564,-212.10415701], [ 262.64052249, 496.85687803], [ 305.50786499, 554.16562628]] km / s> Parameters ---------- coordinate : :class:`~astropy.coordinates.SkyCoord`, :class:`~astropy.coordinates.BaseCoordinateFrame` This is most commonly a :class:`~astropy.coordinates.SkyCoord` object, but alternatively, it can be any coordinate frame object that is transformable to the Galactocentric frame. pm : :class:`~astropy.units.Quantity` or iterable of :class:`~astropy.units.Quantity` objects Proper motion in the same frame as the coordinate. For example, if your input coordinate is in :class:`~astropy.coordinates.ICRS`, then the proper motion is assumed to be in this frame as well. The order of elements should always be proper motion in (longitude, latitude), and should have shape (2,N). The longitude component is assumed to have the cosine of the latitude already multiplied in, so that in ICRS, for example, this would be :math:`\mu_\alpha\cos\delta`. rv : :class:`~astropy.units.Quantity` Barycentric radial velocity. Should have shape (1,N) or (N,). vcirc : :class:`~astropy.units.Quantity` (optional) Circular velocity of the Sun. vlsr : :class:`~astropy.units.Quantity` (optional) Velocity of the Sun relative to the local standard of rest (LSR). galactocentric_frame : :class:`~astropy.coordinates.Galactocentric` (optional) An instantiated :class:`~astropy.coordinates.Galactocentric` frame object with custom parameters for the Galactocentric coordinates. For example, if you want to set your own position of the Galactic center, you can pass in a frame with custom `galcen_ra` and `galcen_dec`. Returns ------- vxyz : :class:`~astropy.units.Quantity` (optional) Cartesian velocity components (U,V,W). A :class:`~astropy.units.Quantity` object with shape (3,N). """ if galactocentric_frame is None: galactocentric_frame = coord.Galactocentric # make sure this is a coordinate and get the frame for later use c = coord.SkyCoord(coordinate) coord_frame = c.frame if coord_frame.name == 'icrs': pm_radec = u.Quantity(map(np.atleast_1d, pm)) elif coord_frame.name == 'galactic': # transform to ICRS proper motions pm_radec = pm_gal_to_icrs(c, pm) else: raise NotImplementedError("Proper motions in the {} system are not " "currently supported.".format( coord_frame.name)) # proper motion components: longitude, latitude mura_cosdec, mudec = pm_radec # Adrian, you're fired a, d, D = c.icrs.ra, c.icrs.dec, c.distance with u.set_enabled_equivalencies(u.dimensionless_angles()): v_icrs = [ rv * np.cos(a) * np.cos(d) - D * np.sin(a) * mura_cosdec - D * np.cos(a) * np.sin(d) * mudec, rv * np.sin(a) * np.cos(d) + D * np.cos(a) * mura_cosdec - D * np.sin(a) * np.sin(d) * mudec, rv * np.sin(d) + D * np.cos(d) * mudec ] v_icrs = np.array([v.to(u.km / u.s).value for v in v_icrs]) * u.km / u.s R = _icrs_gctc_velocity_matrix(galactocentric_frame) orig_shape = v_icrs.shape v_gc = R.dot(v_icrs.reshape(v_icrs.shape[0], np.prod(v_icrs.shape[1:]))).reshape(orig_shape) # remove circular and LSR velocities v_gc[1] = v_gc[1] + vcirc for i in range(3): v_gc[i] = v_gc[i] + vlsr[i] if c.isscalar: return v_gc.reshape((3, )) else: return v_gc
def test_hours(timerange_a): assert timerange_a.hours == u.Quantity(24, 'hour')
def function(self, lamb, Av=1, Rv=3.1, Alambda=True, **kwargs): """ Fitzpatrick99 extinction Law Parameters ---------- lamb: float or ndarray(dtype=float) wavelength [in Angstroms] at which to evaluate the law. Av: float desired A(V) (default 1.0) Rv: float desired R(V) (default 3.1) Alambda: bool if set returns +2.5*1./log(10.)*tau, tau otherwise Returns ------- r: float or ndarray(dtype=float) attenuation as a function of wavelength depending on Alambda option +2.5*1./log(10.)*tau, or tau """ # ensure the units are in angstrom _lamb = units.Quantity(lamb, units.angstrom).value if isinstance(_lamb, float) or isinstance(_lamb, np.float_): _lamb = np.asarray([lamb]) else: _lamb = lamb[:] # convert to wavenumbers x = 1.0e4 / _lamb # check that the wavenumbers are within the defined range _test_valid_x_range(x, self.x_range, self.name) # initialize values c2 = -0.824 + 4.717 / Rv c1 = 2.030 - 3.007 * c2 c3 = 3.23 c4 = 0.41 x0 = 4.596 gamma = 0.99 k = np.zeros(np.size(x)) # compute the UV portion of A(lambda)/E(B-V) xcutuv = 10000.0 / 2700.0 xspluv = 10000.0 / np.array([2700.0, 2600.0]) ind = np.where(x >= xcutuv) if np.size(ind) > 0: k[ind] = (c1 + (c2 * x[ind]) + c3 * ((x[ind])**2) / (((x[ind])**2 - (x0**2))**2 + (gamma**2) * ((x[ind])**2))) yspluv = (c1 + (c2 * xspluv) + c3 * ((xspluv)**2) / (((xspluv)**2 - (x0**2))**2 + (gamma**2) * ((xspluv)**2))) # FUV portion fuvind = np.where(x >= 5.9) k[fuvind] += c4 * (0.5392 * ((x[fuvind] - 5.9)**2) + 0.05644 * ((x[fuvind] - 5.9)**3)) k[ind] += Rv yspluv += Rv # Optical/NIR portion ind = np.where(x < xcutuv) if np.size(ind) > 0: xsplopir = np.zeros(7) xsplopir[0] = 0.0 xsplopir[1:7] = 10000.0 / np.array( [26500.0, 12200.0, 6000.0, 5470.0, 4670.0, 4110.0]) ysplopir = np.zeros(7) ysplopir[0:3] = np.array([0.0, 0.26469, 0.82925]) * Rv / 3.1 ysplopir[3:7] = np.array([ np.poly1d([2.13572e-04, 1.00270, -4.22809e-01])(Rv), np.poly1d([-7.35778e-05, 1.00216, -5.13540e-02])(Rv), np.poly1d([-3.32598e-05, 1.00184, 7.00127e-01])(Rv), np.poly1d([ 1.19456, 1.01707, -5.46959e-03, 7.97809e-04, -4.45636e-05 ][::-1])(Rv), ]) tck = interpolate.splrep(np.hstack([xsplopir, xspluv]), np.hstack([ysplopir, yspluv]), k=3) k[ind] = interpolate.splev(x[ind], tck) # convert from A(lambda)/E(B-V) to A(lambda)/A(V) k /= Rv # setup the output if Alambda: return k * Av else: return k * Av * (np.log(10.0) * 0.4)
def readFromHDF5(self, filename): """ Restores from an HDF 5 file""" import h5py f = h5py.File(filename, 'r') if "z" in f.attrs: self._z = f.attrs["z"] else: self._z = None self._noalpha = f.attrs["Noalpha"] self._opthin = f.attrs["Opthin"] self._nwalkers = f.attrs["Nwalkers"] self._wavenorm = f.attrs["Wavenorm"] self._lowlim = f.attrs["Lowlim"] self._has_uplim = f.attrs["HasUplim"] self._uplim = f.attrs["Uplim"] self._has_gprior = f.attrs["HasGaussianPrior"] self._gprior_mean = f.attrs["GaussianPriorMean"] self._gprior_sigma = f.attrs["GaussianPriorSigma"] self._gprior_ivar = f.attrs["GaussianPriorIVar"] self._response_integrate = f.attrs["ResponseIntegrate"] self._fixed = f.attrs["Fixed"] self._ndata = f.attrs["Ndata"] if self._response_integrate: if not "Responses" in f: errmsg = "Didn't find expected responses in {:s}" raise ValueError(errmsg.format(filename)) self._responsewheel = response_set() self._responsewheel.readFromHDF5(f["Responses"]) gd = f["Data"] self._data_wave = gd["Wave"][...] self._data_flux = gd["FluxDensity"][...] self._data_flux_unc = gd["FluxDensityUnc"][...] if "Covmatrix" in gd: self._has_covmatrix = True self._covmatrix = gd["Covmatrix"][...] self._invcovmatrix = gd["InvCovmatrix"][...] else: self._has_covmatrix = False if hasattr(self, "_covmatrix"): del self._covmatrix if hasattr(self, "_invcovmatrix"): del self._invcovmatrix gc = f["Chain"] self.par_central_values = gc["ParamCentralValues"][...] self.chain = gc["Chain"][...] self.lnprobability = gc["LogLike"][...] self._best_fit = (gc["BestFitParams"][...], gc["BestFitLogLike"][()], gc["BestFitIndex"][()]) ga = f["Ancillary"] if "cosmo_type" in ga.attrs: self._cosmo_type = ga.attrs["cosmo_type"] if "lumdist" in ga.attrs: self._has_lumdist = True self._lumdist = u.Quantity(ga.attrs["lumdist"], u.Mpc) else: self._has_lumdist = False if "Lir" in ga: self._lir_min = ga.attrs["LirMin"] self._lir_max = ga.attrs["LirMax"] self.lir = ga["Lir"][...] self._has_lir = True else: self._has_lir = False self._lir_min = None self._lir_max = None if hasattr(self, 'lir'): del self.lir if "Dustmass" in ga: self._kappa = ga.attrs["Kappa"] self._kappa_wave = ga.attrs["KappaWave"] self.dustmass = ga["Dustmass"][...] self._has_dustmass = True else: self._has_dustmass = False self._kappa = None self._kappa_wave = None if hasattr(self, 'dustmass'): del self.dustmass if "PeakLambda" in ga: self._has_peaklambda = True self.peaklambda = ga["PeakLambda"][...] else: self._has_peaklambda = False if hasattr(self, 'peaklambda'): del self.peaklambda self._fitset = True f.close()
def function(self, lamb, Av=1, Rv=2.74, Alambda=True, **kwargs): """ Gordon03_SMCBar extinction law Parameters ---------- lamb: float or ndarray(dtype=float) wavelength [in Angstroms] at which to evaluate the law. Av: float desired A(V) (default 1.0) Rv: float desired R(V) (default 2.74) Alambda: bool if set returns +2.5*1./log(10.)*tau, tau otherwise Returns ------- r: float or ndarray(dtype=float) attenuation as a function of wavelength depending on Alambda option +2.5*1./log(10.)*tau, or tau """ # ensure the units are in angstrom _lamb = units.Quantity(lamb, units.angstrom).value if isinstance(_lamb, float) or isinstance(_lamb, np.float_): _lamb = np.asarray([lamb]) else: _lamb = lamb[:] # convert to wavenumbers x = 1.0e4 / _lamb # check that the wavenumbers are within the defined range _test_valid_x_range(x, self.x_range, self.name) # set Rv explicitly to the fixed value Rv = self.Rv c1 = -4.959 / Rv c2 = 2.264 / Rv c3 = 0.389 / Rv c4 = 0.461 / Rv x0 = 4.6 gamma = 1.0 k = np.zeros(np.size(x)) # UV part xcutuv = 10000.0 / 2700.0 xspluv = 10000.0 / np.array([2700.0, 2600.0]) ind = np.where(x >= xcutuv) if np.size(ind) > 0: k[ind] = (1.0 + c1 + (c2 * x[ind]) + c3 * ((x[ind])**2) / (((x[ind])**2 - (x0**2))**2 + (gamma**2) * ((x[ind])**2))) yspluv = (1.0 + c1 + (c2 * xspluv) + c3 * ((xspluv)**2) / (((xspluv)**2 - (x0**2))**2 + (gamma**2) * ((xspluv)**2))) # FUV portion ind = np.where(x >= 5.9) if np.size(ind) > 0: k[ind] += c4 * (0.5392 * ((x[ind] - 5.9)**2) + 0.05644 * ((x[ind] - 5.9)**3)) # Opt/NIR part ind = np.where(x < xcutuv) if np.size(ind) > 0: xsplopir = np.zeros(9) xsplopir[0] = 0.0 xsplopir[1:10] = 1.0 / np.array( [2.198, 1.65, 1.25, 0.81, 0.65, 0.55, 0.44, 0.37]) # Values directly from Gordon et al. (2003) # ysplopir = np.array([0.0,0.016,0.169,0.131,0.567,0.801, # 1.00,1.374,1.672]) # K & J values adjusted to provide a smooth, # non-negative cubic spline interpolation ysplopir = np.array( [0.0, 0.11, 0.169, 0.25, 0.567, 0.801, 1.00, 1.374, 1.672]) tck = interpolate.splrep(np.hstack([xsplopir, xspluv]), np.hstack([ysplopir, yspluv]), k=3) k[ind] = interpolate.splev(x[ind], tck) if Alambda: return k * Av else: return k * Av * (np.log(10.0) * 0.4)
############################################################################## # It's sometimes useful to specify the solar motion using the `proper motion # of Sgr A* <https://arxiv.org/abs/astro-ph/0408107>`_ instead of Cartesian # velocity components. With an assumed distance, we can convert proper motion # components to Cartesian velocity components using `astropy.units`: galcen_distance = 8 * u.kpc pm_gal_sgrA = [-6.379, -0.202] * u.mas / u.yr # from Reid & Brunthaler 2004 vy, vz = -(galcen_distance * pm_gal_sgrA).to(u.km / u.s, u.dimensionless_angles()) ############################################################################## # We still have to assume a line-of-sight velocity for the Galactic center, # which we will again take to be 11 km/s: vx = 11.1 * u.km / u.s v_sun2 = u.Quantity([vx, vy, vz]) # List of Quantity -> a single Quantity gc_frame2 = coord.Galactocentric(galcen_distance=galcen_distance, galcen_v_sun=v_sun2, z_sun=0 * u.pc) gc3 = c1.transform_to(gc_frame2) print(gc3.v_x, gc3.v_y, gc3.v_z) ############################################################################## # The transformations also work in the opposite direction. This can be useful # for transforming simulated or theoretical data to observable quantities. As # an example, we'll generate 4 theoretical circular orbits at different # Galactocentric radii with the same circular velocity, and transform them to # Heliocentric coordinates: ring_distances = np.arange(10, 25 + 1, 5) * u.kpc
# Licensed under a 3-clause BSD style license - see LICENSE.rst import pytest import astropy.units as u from ...utils.testing import assert_quantity_allclose from ...spectrum import create_crab_spectral_model CRAB_SPECTRA = [ dict( name="meyer", dnde=u.Quantity(5.572437502365652e-12, "cm-2 s-1 TeV-1"), flux=u.Quantity(2.0744425607240974e-11, "cm-2 s-1"), index=2.631535530090332, ), dict( name="hegra", dnde=u.Quantity(4.60349681e-12, "cm-2 s-1 TeV-1"), flux=u.Quantity(1.74688947e-11, "cm-2 s-1"), index=2.62000000, ), dict( name="hess_pl", dnde=u.Quantity(5.57327158e-12, "cm-2 s-1 TeV-1"), flux=u.Quantity(2.11653715e-11, "cm-2 s-1"), index=2.63000000, ), dict( name="hess_ecpl", dnde=u.Quantity(6.23714253e-12, "cm-2 s-1 TeV-1"), flux=u.Quantity(2.267957713046026e-11, "cm-2 s-1"), index=2.529860258102417, ),