def Period(current,start_time): start=Time(start_time,format='mjd',scale='utc').mjd current=start+(float(current)/(60*60*24)) eph1957 = ELL1Ephemeris('psrj1959.par') jpleph = JPLEphemeris(de405) mjd = Time(current, format='mjd', scale='utc', lon=(74*u.deg+02*u.arcmin+59.07*u.arcsec).to(u.deg).value, lat=(19*u.deg+05*u.arcmin+47.46*u.arcsec).to(u.deg).value) time=mjd.tdb.mjd #start time in mjd time_jd=mjd.tdb.jd #start time in jd f_p=eph1957.evaluate('F',time,t0par='PEPOCH')#pulse frequency f_dot=eph1957.evaluate('FDOT',time,t0par='PEPOCH') P_0=1./f_p #pulse period P_1000=1000*P_0 #scale up to get output every 1000 periods # orbital delay and velocity (lt-s and v/c) d_orb = eph1957.orbital_delay(time) v_orb = eph1957.radial_velocity(time) # direction to target dir_1957 = eph1957.pos(time) # Delay from and velocity of centre of earth to SSB (lt-s and v/c) posvel_earth = jpleph.compute('earth', time_jd) pos_earth = posvel_earth[:3]/c.to(u.km/u.s).value vel_earth = posvel_earth[3:]/c.to(u.km/u.day).value d_earth = np.sum(pos_earth*dir_1957, axis=0) v_earth = np.sum(vel_earth*dir_1957, axis=0) #GMRT from tempo2-2013.3.1/T2runtime/observatory/observatories.dat xyz_gmrt = (1656318.94, 5797865.99, 2073213.72) # Rough delay from observatory to center of earth # mean sidereal time (checked it is close to rf_ephem.utc_to_last) lmst = (observability.time2gmst(mjd)/24. + mjd.lon/360.)*2.*np.pi coslmst, sinlmst = np.cos(lmst), np.sin(lmst) # rotate observatory vector xy = np.sqrt(xyz_gmrt[0]**2+xyz_gmrt[1]**2) pos_gmrt = np.array([xy*coslmst, xy*sinlmst, xyz_gmrt[2]*np.ones_like(lmst)])/c.si.value vel_gmrt = np.array([-xy*sinlmst, xy*coslmst, np.zeros_like(lmst)] )*2.*np.pi*366.25/365.25/c.to(u.m/u.day).value # take inner product with direction to pulsar d_topo = np.sum(pos_gmrt*dir_1957, axis=0) v_topo = np.sum(vel_gmrt*dir_1957, axis=0) #total relative velocity total_rv = - v_topo - v_earth + v_orb L=(1./(1+total_rv))#multiplying factor to find doppler frequency f_dp=f_p*L #doppler shifted frequency P_dp=1./f_dp #doppler shifted period total_delay = d_topo + d_earth + d_orb period=P_dp return period
def wave_to_vel(restWave, wave, flux, fluxError=None, delta=False): if delta is True: vel = (wave / restWave) * c.to('km/s').value else: vel = ((wave - restWave) / restWave) * c.to('km/s').value flux = flux * (restWave / c.to('km/s').value) if fluxError is not None: fluxError = fluxError * (restWave / c.to('km/s').value) return vel, flux, fluxError else: return vel, flux
def vel_to_wave(restWave, vel, flux, fluxError=None, delta=False): if delta is True: wave = (vel / c.to('km/s').value) * restWave else: wave = (vel / c.to('km/s').value) * restWave + restWave flux = flux / (restWave / c.to('km/s').value) if fluxError is not None: fluxError = fluxError / (restWave / c.to('km/s').value) return vel, flux, fluxError else: return wave, flux
def light_travel_time(self): """ The time in seconds it takes for light to travel from the body to the observer. """ return (self.distance_observer_to_body().to(u.m) / c.to(u.m / u.s)).to( u.s)
def mag2flux(self, spec_in=None): """ Convert magnitudes to flux units. This is important for dealing with standards and files from IRAF, which are stored in AB mag units. To be clear, this converts to "PHOTFLAM" units in IRAF-speak. Assumes the common flux zeropoint used in IRAF. Parameters ---------- spec_in: a Spectrum1D object, optional An input spectrum with wavelength of the data points in Angstroms as the ``spectral_axis`` and magnitudes of the data as the ``flux``. Returns ------- spec_out: specutils.Spectrum1D Containing both ``flux`` and ``spectral_axis`` data in which the ``flux`` has been properly converted from mag->flux. """ if spec_in is None: spec_in = self.object_spectrum lamb = spec_in.spectral_axis mag = spec_in.flux flux = (10.0**((mag + self.zeropt) / (-2.5))) * (cc.to('AA/s').value / lamb**2.0) flux = flux * u.erg / u.s / u.angstrom / (u.cm * u.cm) spec_out = Spectrum1D(spectral_axis=lamb, flux=flux) return spec_out
def scale_dependence_modification(cosmo, redshift): r"""Return the scale-dependence modification kernel :math:`A(k,z)` for a given cosmological model. Parameters ---------- cosmo : :class:`nbodykit.cosmology.cosmology.Cosmology` Cosmological model. redshift : float Redshift at which quantities are evaluated. Returns ------- callable Scale-dependence modification kernel as a function of wavenumber (in :math:`h`/Mpc). """ SPHERICAL_COLLAPSE_CRITICAL_OVERDENSITY = 1.686 SPEED_OF_LIGHT_IN_KM_PER_S = c.to('km/s').value GROWTH_FACTOR_NORMALISATION = 1.3 num_factors = GROWTH_FACTOR_NORMALISATION \ * 3 * cosmo.Omega0_m * SPHERICAL_COLLAPSE_CRITICAL_OVERDENSITY \ * (cosmo.H0 / SPEED_OF_LIGHT_IN_KM_PER_S) ** 2 transfer_func = cosmology.power.transfers.CLASS(cosmo, redshift=redshift) return lambda k: num_factors / (k**2 * transfer_func(k))
def solve_v(self): """ Solve for the velocity of the line given the expected wavelength. The result is returned in km s-1. """ line_center = self.Params[self.current_component]['Peak'] * self.wavelength.unit return c.to(u.km / u.second) * (line_center - self.wavelength) / self.wavelength
def ABVega(self): """ Compute AB-Vega conversion """ from astropy.constants import c import astropy.units as u try: import grizli.utils_c interp = grizli.utils_c.interp.interp_conserve_c except ImportError: interp = utils.interp_conserve # Union of throughput and Vega spectrum arrays full_x = np.hstack([self.wave, VEGA['WAVELENGTH']]) full_x = full_x[np.argsort(full_x)] # Vega spectrum, units of f-lambda flux density, cgs # Interpolate to wavelength grid, no extrapolation vega_full = interp(full_x, VEGA['WAVELENGTH'], VEGA['FLUX'], left=0, right=0) thru_full = interp(full_x, self.wave, self.throughput, left=0, right=0) # AB = 0, same units absp = 3631 * 1e-23 * c.to(u.m / u.s).value * 1.e10 / full_x**2 # Integrate over the bandpass, flam dlam num = np.trapz(vega_full * thru_full, full_x) den = np.trapz(absp * thru_full, full_x) return -2.5 * np.log10(num / den)
def ra_dec_z(x, v, cosmo=None): """ Calculate ra, dec, and redshift for a mock assuming an observer placed at (0,0,0). Parameters ---------- x: array_like Npts x 3 numpy array containing 3-d positions in Mpc/h units v: array_like Npts x 3 numpy array containing 3-d velocities of shape (N,3) in km/s cosmo: astropy.cosmology object, optional default is FlatLambdaCDM(H0=0.7, Om0=0.3) Returns ------- ra: np.array right accession in radians dec: np.array declination in radians z: np.array redshift """ #calculate the observed redshift if cosmo == None: cosmo = cosmology.FlatLambdaCDM(H0=0.7, Om0=0.3) c_km_s = c.to('km/s').value #remove h scaling from position so we can use the cosmo object x = x / cosmo.h #compute comoving distance from observer r = np.sqrt(x[:, 0]**2 + x[:, 1]**2 + x[:, 2]**2) #compute radial velocity ct = x[:, 2] / r st = np.sqrt(1.0 - ct**2) cp = x[:, 0] / np.sqrt(x[:, 0]**2 + x[:, 1]**2) sp = x[:, 1] / np.sqrt(x[:, 0]**2 + x[:, 1]**2) vr = v[:, 0] * st * cp + v[:, 1] * st * sp + v[:, 2] * ct #compute cosmological redshift and add contribution from perculiar velocity yy = np.arange(0, 1.0, 0.001) xx = cosmo.comoving_distance(yy).value f = interp1d(xx, yy, kind='cubic') z_cos = f(r) redshift = z_cos + (vr / c_km_s) * (1.0 + z_cos) #calculate spherical coordinates theta = np.arccos(x[:, 2] / r) phi = np.arccos(cp) #atan(y/x) #convert spherical coordinates into ra,dec ra = phi dec = (np.pi / 2.0) - theta return ra, dec, redshift
def ra_dec_z(x, v, cosmo=None): """ Calculate ra, dec, and redshift for a mock assuming an observer placed at (0,0,0). Parameters ---------- x: array_like Npts x 3 numpy array containing 3-d positions in Mpc/h units v: array_like Npts x 3 numpy array containing 3-d velocities of shape (N,3) in km/s cosmo: astropy.cosmology object, optional default is FlatLambdaCDM(H0=0.7, Om0=0.3) Returns ------- ra: np.array right accession in radians dec: np.array declination in radians z: np.array redshift """ # calculate the observed redshift if cosmo == None: cosmo = cosmology.FlatLambdaCDM(H0=0.7, Om0=0.3) c_km_s = c.to("km/s").value # remove h scaling from position so we can use the cosmo object x = x / cosmo.h # compute comoving distance from observer r = np.sqrt(x[:, 0] ** 2 + x[:, 1] ** 2 + x[:, 2] ** 2) # compute radial velocity ct = x[:, 2] / r st = np.sqrt(1.0 - ct ** 2) cp = x[:, 0] / np.sqrt(x[:, 0] ** 2 + x[:, 1] ** 2) sp = x[:, 1] / np.sqrt(x[:, 0] ** 2 + x[:, 1] ** 2) vr = v[:, 0] * st * cp + v[:, 1] * st * sp + v[:, 2] * ct # compute cosmological redshift and add contribution from perculiar velocity yy = np.arange(0, 1.0, 0.001) xx = cosmo.comoving_distance(yy).value f = interp1d(xx, yy, kind="cubic") z_cos = f(r) redshift = z_cos + (vr / c_km_s) * (1.0 + z_cos) # calculate spherical coordinates theta = np.arccos(x[:, 2] / r) phi = np.arccos(cp) # atan(y/x) # convert spherical coordinates into ra,dec ra = phi dec = (np.pi / 2.0) - theta return ra, dec, redshift
def get_corrected_rv(self, obs): """Compute a corrected radial velocity for the given observation""" # Compute the raw offset: difference between Halpha centroid and true # wavelength value x0 = obs.measurements[0].x0 * u.angstrom raw_offset = (x0 - self.Halpha) # precision estimate from line centroid error precision = (obs.measurements[0].x0_error * u.angstrom) / self.Halpha * c.to(u.km / u.s) # For each sky line (that passes certain quality checks), compute the # offset between the predicted wavelength and measured centroid # TODO: generalize these quality cuts - see also above in # _compute_offset_corrections sky_offsets = np.full(3, np.nan) * u.angstrom for j, meas in enumerate(obs.measurements[1:]): sky_offset = meas.x0 * u.angstrom - meas.info.wavelength if (meas.amp > 16 and meas.std_G < 2 and meas.std_G > 0.3 and np.abs(sky_offset) < 3.3 * u.angstrom): # MAGIC NUMBER: quality cuts sky_offsets[j] = sky_offset # final sky offset to apply flag = 0 sky_offset = np.nanmean(sky_offsets) if np.isnan(sky_offset.value): logger.debug("not correcting with sky line for {0}".format(obs)) sky_offset = 0 * u.angstrom flag = 1 # apply global sky offset correction - see _compute_offset_corrections() sky_offset -= self._night_polys[obs.night](obs.utc_hour) * u.angstrom # compute radial velocity and correct for sky line rv = (raw_offset - sky_offset) / self.Halpha * c.to(u.km / u.s) # correct for offset of median of ∆RV distribution from targets with # prior/known RV's rv -= self._night_final_offsets[obs.night] # rv error err = np.sqrt(self._abs_err**2 + precision**2) return rv, err, flag
def mag2flux(mag, wave): """Convert flux from AB mag to erg.s-1.cm-2.A-1 wave is the wavelength in A """ cs = c.to('Angstrom/s').value # speed of light in A/s return 10 ** (-0.4 * (mag + 48.60)) * cs / wave ** 2
def LOS_velocity(wv,data,hw=0.01,band=False): """ Calculte the Line-of-Sight velocity of given data. Parameters ---------- wv : ~numpy.ndarray A Calibrated wavelength. data : ~numpy.ndarray n (n>=2) dimensional spectral profile data, the last dimension component must be the spectral component, and the size is equal to the size of wv. hw : float A half width of the horizontal line segment. band : str A string of the wavelength band. It must be the 4 characters in Angstrom unit. ex) '6562', '8542' Returns ------- losv : ~numpy.ndarray n-1 (n>=2) dimensional Line-of_sight velocity value, where n is the dimension of the given data. Example ------- >>> from fisspy.doppler import LOS_velocity >>> mask = np.abs(wv) < 1 >>> losv = LOS_velocity(wv[mask],data[:,:,mask],hw=0.03,band='6562') """ if not band : raise ValueError("Please insert the parameter band (str)") wc, intc = lambdameter(wv,data,hw,wvinput=True) if band == '6562' : return wc*c.to('km/s').value/6562.817 elif band == '8542' : return wc*c.to('km/s').value/8542.09 elif band == '5890' : return wc*c.to('km/s').value/5890.9399 elif band == '5434' : return wc*c.to('km/s').value/5434.3398 else: raise ValueError("Value of band must be one among" "'6562', '8542', '5890', '5434'")
def LOS_velocity(wv, data, hw=0.01, band=False): """ Calculte the Line-of-Sight velocity of given data. Parameters ---------- wv : 1d ndarray A Calibrated wavelength. data : nd ndarray n (n>=2) dimensional spectral profile data, the last dimension component must be the spectral component, and the size is equal to the size of wv. hw : float A half width of the horizontal line segment. band : str A string of the wavelength band. It must be the 4 characters in Angstrom unit. ex) '6562', '8542' Returns ------- losv : nd ndarray n-1 (n>=2) dimensional Line-of_sight velocity value, where n is the dimension of the given data. Example ------- >>> from fisspy.doppler import LOS_velocity >>> mask = np.abs(wv) < 1 >>> losv = LOS_velocity(wv[mask],data[:,:,mask],hw=0.03,band='6562') """ if not band: raise ValueError("Please insert the parameter band (str)") wc, intc = lambdameter(wv, data, hw, wvinput=True) if band == '6562': return wc * c.to('km/s').value / 6562.817 elif band == '8542': return wc * c.to('km/s').value / 8542.09 elif band == '5890': return wc * c.to('km/s').value / 5890.9399 elif band == '5434': return wc * c.to('km/s').value / 5434.3398 else: raise ValueError("Value of band must be one among" "'6562', '8542', '5890', '5434'")
def v_to_z(v): ''' Convert km/s to redshift assuming all are using special relativity @param v: velocity in km/s @return Redshift of object with speed in km/s ''' ckms = c.to('km/s').value return np.sqrt((1 + v / ckms) / (1 - v / ckms)) - 1
def z_to_v(z): ''' Convert redshift to km/s assuming shift is due to velocity using special relativity @param z: Redshift @return speed in km/s assuming shift is due to motion using special relativity ''' ckms = c.to('km/s').value return (ckms * ((z + 1)**2 - 1) / ((z + 1)**2 + 1))
def compute_photon_rate(mag, tic_params, emulate_signal=False): """Compute the number of photons/s/cm^2/angstrom for an object of magnitude <mag> in a specific passband. The result is returned as a `~astropy.units.Quantity` object or None if this can't be calculated. If [emulate_signal] is set to True, then it will use a lower precision value of h (Planck's constant) to emulate the IAC's SIGNAL code (http://catserver.ing.iac.es/signal/) In order to work, this routine need a dictionary, <tic_params>, for the telecope, instrument, camera parameters. For this routine, the needed entries are: 'flux_mag0' : the flux in Janskys of a mag=0 object in this band (u.Jy) 'wavelength' : the central wavelength of the band involved (normally u.nm, although astropy.units wavelength should work) """ if emulate_signal: # Equivalent original code below # 6.6 magic no. is the mantissa part of Planck's constant(rounded). Most of the # exponent part (10^-34) is cancelled by Jansky->erg conversion (10^-23) and # erg->Watts (10^-7) # m_0 = tic_params['flux_mag0'] * 10000.0/6.6/tic_params['wavelength'] # Need new version of h at same low precision as SIGNAL's original code hc = (6.6e-27 * h.cgs.unit) * c.to(u.angstrom / u.s) # Photon energy in ergs/photon photon_energy = (hc / tic_params['wavelength'].to(u.angstrom)) / u.photon # Convert flux in Janskys (=10^-23 ergs s^-1 cm^-2 Hz^-1) to an energy density per second energy_density = tic_params['flux_mag0'].to( u.erg / (u.s * u.cm**2 * u.Hz)) * tic_params['wavelength'].to( u.Hz, equivalencies=u.spectral()) # Divide by the energy-per-photon at this wavelength and the wavelength to give us # photons per second per cm**2 per Angstrom, matching the astropy version below m_0 = energy_density / photon_energy / tic_params['wavelength'].to( u.AA) else: m_0 = tic_params['flux_mag0'].to(u.photon / u.cm**2 / u.s / u.angstrom, equivalencies=u.spectral_density( tic_params['wavelength'])) rate = None try: rate = m_0 * 10.0**(-0.4 * mag) except u.UnitTypeError: # astropy.units Quantity, take value rate = m_0 * 10.0**(-0.4 * mag.value) except TypeError: pass return rate
def dv2df(f0, dv): """ Convert a velocity delta to a frequency delta given a central frequency. :param f0: Rest frequency. :type f0: float :param dv: Velocity delta in m/s. :type dv: float :returns: For the given velocity delta the equivalent frequency delta. :rtype: float """ return dv * f0 / c.to('m/s').value
def flux2mag(flux, err_flux, wave): """Convert flux from erg.s-1.cm-2.A-1 to AB mag. wave is the wavelength in A """ if flux > 0: cs = c.to('Angstrom/s').value # speed of light in A/s mag = -48.60 - 2.5 * np.log10(wave ** 2 * flux / cs) err_mag = np.abs(2.5 * err_flux / (flux * np.log(10))) return (mag, err_mag) else: return (99, np.inf)
def df2dv(f0, df): """ Convert a frequency delta to a velocity delta given a central frequency. :param f0: Rest frequency. :type f0: float :param df: Frequency delta. :type df: float :returns: The equivalent velocity delta for the given frequency delta. :rtype: float in :math:`\mbox{m s}^{-1}` """ return c.to('m/s').value * (df / f0)
def _update_parameter_names(self): """ Update the model parameter names based on the current metadata. """ # Profile parameter names. func, parameter_names = self._profiles[self.metadata["profile"]] parameter_names = list(parameter_names) # Continuum coefficients. parameter_names += ["c{0}".format(i) \ for i in range(self.metadata["continuum_order"] + 1)] # Update the bounds. bounds = {} if self.metadata["profile"] == "gaussian": bounds.update({ "sigma": (-0.5, 0.5), "amplitude": (0, 1), }) elif self.metadata["profile"] == "voigt": bounds["fwhm"] = (-0.5, 0.5) if self.metadata["wavelength_tolerance"] is not None \ or self.metadata["velocity_tolerance"] is not None: # Convert velocity tolerance into wavelength. wavelength = self.transitions["wavelength"] try: wavelength = wavelength[0] except IndexError: None vt = abs(self.metadata.get("velocity_tolerance", None) or np.inf) wt = abs(self.metadata.get("wavelength_tolerance", None) or np.inf) bound = np.nanmin( [wt, wavelength * vt / speed_of_light.to("km/s").value]) bounds["mean"] = (wavelength - bound, wavelength + bound) else: # TODO: Allow the wavelength to be fixed. raise NotImplementedError("wavelength cannot be fixed yet; " "set a small tolerance on wavelength") self._parameter_names = parameter_names self._parameter_bounds = bounds return True
def freq2vel(f0, f): """ Convert a frequency axis to a velocity axis given a central frequency. Uses the radio definition of velocity. :param f0: Rest frequency for the conversion. (Hz) :type f0: float :param f: Frequencies to be converted to velocity. (Hz) :type f: numpy array :returns: f converted to velocity given a rest frequency :math:`f_{0}`. :rtype: numpy array """ return c.to('m/s').value * (1. - f / f0)
def lambdaMeter(self, hw= 0.03, sp= 5e3, wvRange= False, wvinput= True, shift2velocity= False): """ """ lineShift, intensity = lambdameter(self.wv, self.frame, ref_spectrum= self.refProfile, wvRange= wvRange, hw= hw, wvinput= wvinput) if shift2velocity: LOSvelocity = lineShift * c.to('km/s').value/self.centralWavelength return LOSvelocity, intensity else: return lineShift, intensity
def jy2Tsr(f, bm=1.0, mK=False): """Return [K sr] / [Jy] vs. frequency (in Hz) Arguments: f = frequencies (Hz) bm = Reference solid angle in steradians (Defaults to 1) mK = Return in mK sr instead of K sr """ c_cmps = c.to("cm/s").value # cm/s k_boltz = 1.380658e-16 # erg/K lam = c_cmps / f # cm fac = 1.0 if mK: fac = 1e3 return 1e-23 * lam**2 / (2 * k_boltz * bm) * fac
def vel2freq(f0, vel): """ Convert a velocity axis to a frequency axis given a central frequency. Uses the radio definition, :math:`\\nu=f_{0}(1-v/c)`. :param f0: Rest frequency in Hz. :type f0: float :param vel: Velocity to convert in m/s. :type vel: float or array :returns: The frequency which is equivalent to vel. :rtype: float or array """ return f0 * (1. - vel / c.to('m/s').value)
def compare_z(z1, z2, dv): """Return true if the difference between z1 and z2 is within dv at the mean redshift. Otherwise return False. dv has to be much smaller and speed of light as the function does not account for relativity.""" z1 = np.array(z1) z2 = np.array(z2) dv = np.array(dv) dz = np.fabs(z1 - z2) z = np.mean([z1, z2]) if dz / (1. + z) < dv / C.to('km/s').value: return True else: return False
def add_6df(simplifiedmastercat, sixdf, tol=1*u.arcmin): """ Adds entries in the catalog for the 6dF survey, or updates v when missing """ from astropy import table from astropy.coordinates import SkyCoord from astropy.constants import c ckps = c.to(u.km/u.s).value catcoo = SkyCoord(simplifiedmastercat['RA'].view(np.ndarray)*u.deg, simplifiedmastercat['Dec'].view(np.ndarray)*u.deg) sixdfcoo = SkyCoord(sixdf['obsra'].view(np.ndarray)*u.deg, sixdf['obsdec'].view(np.ndarray)*u.deg) idx, dd, d3d = sixdfcoo.match_to_catalog_sky(catcoo) msk = dd < tol sixdfnomatch = sixdf[~msk] t = table.Table() t.add_column(table.MaskedColumn(name='RA', data=sixdfnomatch['obsra'])) t.add_column(table.MaskedColumn(name='Dec', data=sixdfnomatch['obsdec'])) t.add_column(table.MaskedColumn(name='PGC#', data=-np.ones(len(sixdfnomatch), dtype=int), mask=np.ones(len(sixdfnomatch), dtype=bool))) t.add_column(table.MaskedColumn(name='NSAID', data=-np.ones(len(sixdfnomatch), dtype=int), mask=np.ones(len(sixdfnomatch), dtype=bool))) t.add_column(table.MaskedColumn(name='othername', data=sixdfnomatch['targetname'])) t.add_column(table.MaskedColumn(name='vhelio', data=sixdfnomatch['z_helio']*ckps)) #t.add_column(table.MaskedColumn(name='vhelio_err', data=sixdfnomatch['zfinalerr']*ckps)) t.add_column(table.MaskedColumn(name='distance', data=WMAP9.luminosity_distance(sixdfnomatch['z_helio']).value)) #fill in anything else needed with -999 and masked for nm in simplifiedmastercat.colnames: if nm not in t.colnames: t.add_column(table.MaskedColumn(name=nm, data=-999*np.ones(len(sixdfnomatch), dtype=int), mask=np.ones(len(sixdfnomatch), dtype=bool))) t = table.vstack([simplifiedmastercat, t], join_type='exact') #now update anything that *did* match but doesn't have another velocity tcoo = SkyCoord(t['RA'].view(np.ndarray)*u.deg, t['Dec'].view(np.ndarray)*u.deg) idx, dd, d3d = sixdfcoo.match_to_catalog_sky(tcoo) msk = dd < tol catmatch = t[idx[msk]] sixdfmatch = sixdf[msk] msk2 = t['vhelio'][idx[msk]].mask t['vhelio'][idx[msk&msk2]] = sixdf['z_helio'][msk2]*ckps return t
def distant_observer_redshift(x, v, period=None, cosmo=None): """ Calculate observed redshifts using the distant observer approximation. The cosmological redshift is estimated as: z_cosmo = z*H0/c where z is the 'z' position, H0 is the Hubble constant at z=0, and c is the speed of light. Note that this is an approximation Parameters ---------- x: array_like Npts x 3 numpy array containing 3-d positions in Mpc/h units v: array_like Npts x 3 numpy array containing 3-d velocities of shape (N,3) in km/s period: array_like, optional periodic boundary conditions of simulation box Returns ------- redshift: np.array 'observed' redshift. """ c_km_s = c.to('km/s').value #get the peculiar velocity component along the line of sight direction (z direction) v_los = v[:, 2] #compute cosmological redshift (h=1, note that positions are in Mpc/h) z_cos = x[:, 2] * 100.0 / c_km_s #redshift is combination of cosmological and peculiar velocities z = z_cos + (v_los / c_km_s) * (1.0 + z_cos) #reflect galaxies around PBC if period is not None: z_cos_max = period[2] * 100.00 / c_km_s #maximum cosmological redshift flip = (z > z_cos_max) z[flip] = z[flip] - z_cos_max flip = (z < 0.0) z[flip] = z[flip] + z_cos_max return z
def distant_observer_redshift(x, v, period=None, cosmo=None): """ Calculate observed redshifts using the distant observer approximation. The cosmological redshift is estimated as: z_cosmo = z*H0/c where z is the 'z' position, H0 is the Hubble constant at z=0, and c is the speed of light. Note that this is an approximation Parameters ---------- x: array_like Npts x 3 numpy array containing 3-d positions in Mpc/h units v: array_like Npts x 3 numpy array containing 3-d velocities of shape (N,3) in km/s period: array_like, optional periodic boundary conditions of simulation box Returns ------- redshift: np.array 'observed' redshift. """ c_km_s = c.to("km/s").value # get the peculiar velocity component along the line of sight direction (z direction) v_los = v[:, 2] # compute cosmological redshift (h=1, note that positions are in Mpc/h) z_cos = x[:, 2] * 100.0 / c_km_s # redshift is combination of cosmological and peculiar velocities z = z_cos + (v_los / c_km_s) * (1.0 + z_cos) # reflect galaxies around PBC if period is not None: z_cos_max = period[2] * 100.00 / c_km_s # maximum cosmological redshift flip = z > z_cos_max z[flip] = z[flip] - z_cos_max flip = z < 0.0 z[flip] = z[flip] + z_cos_max return z
def test_distant_observer(): """ test distant observer function """ redshifts = distant_observer_redshift(x,v) assert len(redshifts)==N, "redshift array is not the correct size" redshifts = distant_observer_redshift(x,v,period=period) from astropy.constants import c c_km_s = c.to('km/s').value z_cos_max = period[2]*100.00/c_km_s assert len(redshifts)==N, "redshift array is not the correct size" assert np.max(redshifts)<=z_cos_max, "PBC is not handeled correctly for redshifts"
def romer_delay(xyzEarth, xyzObj): """ Calculate Rømer delay (classical light travel time correction) in units of days Notes: ------ https://en.wikipedia.org/wiki/Ole_R%C3%B8mer https://en.wikipedia.org/wiki/R%C3%B8mer%27s_determination_of_the_speed_of_light """ # ephemeris units is in km / s . convert to m / (julian) day convf = c.to('km/day').value delay = (xyzEarth * xyzObj).sum(1) / convf return delay
def main(): tmpname = 'data/templates/F0_+0.5_Dwarf.fits' model = Model(tmpname) # ftargetname = 'data/spec-4961-55719-0378.fits' ftargetname = '/home/zzx/workspace/data/xiamen/P200-Hale_spec/blue/reduce_second/specdir/fawftbblue0073.fits' # new_wo, new_fo, new_eo = specio.read_sdss(ftargetname, lw=3660, rw=10170) new_wo, new_fo, new_eo = specio.read_iraf(ftargetname) unit = func.get_unit(new_fo) new_fo = new_fo / unit new_eo = new_eo / unit # new_wo, new_fo, new_eo = specio.read_iraf(targetname) result = fit(model, new_wo, new_fo, new_eo, show=True, isprint=True) residual = model.residual out_parms = result.params # spec_fit = model.get_spectrum(out_parms, new_wo) scalepar = model.get_scale_par(out_parms) parshift = model.get_shift_par(out_parms) print(parshift[1]) velocity = str(parshift[1] * c.to('km/s')) print('shift = ' + velocity) myscale = model.get_scale(new_wo, scalepar) plt.figure() plt.plot(new_wo, myscale) plt.show() emcee_params = result.params.copy() # emcee_params.add('__lnsigma', value=np.log(0.1), min=np.log(1.0e-20), # max=np.log(1.0e20)) result_emcee = minimize(residual, params=emcee_params, args=(new_wo, new_fo, new_eo), method='emcee', nan_policy='omit', steps=1000) report_fit(result_emcee) plt.plot(new_wo, new_fo) # plt.plot(new_wo, spec_fit) spec_emcee = model.get_spectrum(result_emcee.params, new_wo) plt.plot(new_wo, spec_emcee) corner.corner(result_emcee.flatchain, labels=result_emcee.var_names, truths=list(result_emcee.params.valuesdict().values())) plt.show()
def BpC_flux(self, spectrum=None, parameters=None): """ Analytic model of the high-order Balmer lines, making up the Pseudo continuum near 3666 A. Line profiles are Gaussians (for now). The line ratios are fixed to Storey &^ Hummer 1995, case B, n_e = 10^10 cm^-3. This component has 3 parameters: parameter1 : The flux normalization near the Balmer Edge lambda = 3666 A, F(3666) parameter4 : A shift of the line centroids parameter5 : The width of the Gaussians parameter6 : The log of the electron density note that all constants, and the units, are absorbed in the parameter F(3656 A). priors: p1 : Flat, between 0 and the observed flux F(3656). p4 : Determined from Hbeta, if applicable. p5 : Determined from Hbeta, if applicable. p6 : Flat between 2 and 14. note that all constants, and the units, are absorbed in the parameter F(3656 A). """ normalization = parameters[self.parameter_index("bc_norm")] Te = parameters[self.parameter_index("bc_Te")] tauBE = parameters[self.parameter_index("bc_tauBE")] loffset = parameters[self.parameter_index("bc_loffset")] lwidth = parameters[self.parameter_index("bc_lwidth")] logNe = parameters[self.parameter_index("bc_logNe")] # lscale = parameters[self.parameter_index("lscale")] c_kms = c.to("km/s") edge_wl = balmer_edge * (1 - loffset / c_kms.value) n_e = 10.**logNe bpc_flux = self.makelines(spectrum.wavelengths, Te, n_e, loffset / c_kms.value, lwidth / c_kms.value) norm_index = find_nearest_index(spectrum.wavelengths, edge_wl) fnorm = bpc_flux[norm_index] bpc_flux[spectrum.wavelengths <= spectrum.wavelengths[norm_index]] = 0 bpc_flux *= normalization / fnorm # bpc_flux *= lscale return bpc_flux
def test_distant_observer(): """ test distant observer function """ redshifts = distant_observer_redshift(x, v) assert len(redshifts) == N, "redshift array is not the correct size" redshifts = distant_observer_redshift(x, v, period=period) from astropy.constants import c c_km_s = c.to('km/s').value z_cos_max = period[2] * 100.00 / c_km_s assert len(redshifts) == N, "redshift array is not the correct size" assert np.max( redshifts) <= z_cos_max, "PBC is not handeled correctly for redshifts"
def ComovingDistance(self, ze): # Function that returns the Comoving Radial Distance to an object at a given redshift # Distance to a galaxy that is moving with the Hubble Flow (expanding universe) at a given redshift # Input: Redshift emitted (ze) # Output: DC in Mpc # define an array with redshifts, spaced in intervals of 0.001 # Note that if you want redshifts smaller than 0.001 you'll need to refine this zrange = np.arange(0, ze, 1e-3) # 1/H(zrange)*speed of light # Speed of light is loaded in modules from astropy, but in units of m/s --> need in km/s # FILL THIS IN y = 1 / self.HubbleParameter(zrange) * c.to(u.km / u.s) # Integrate y numerically over zrange and return in units of Mpc # FILL THIS IN return simps(y, zrange) * u.Mpc
def test_distant_observer(): N=100 x = np.random.random((N,3)) v = np.random.random((N,3))*0.1 period = np.array([1,1,1]) redshifts = distant_observer_redshift(x,v) assert len(redshifts)==N, "redshift array is not the correct size" redshifts = distant_observer_redshift(x,v,period=period) from astropy.constants import c c_km_s = c.to('km/s').value z_cos_max = period[2]*100.00/c_km_s assert len(redshifts)==N, "redshift array is not the correct size" assert np.max(redshifts)<=z_cos_max, "PBC is not handeled correctly for redshifts"
def set_transition(self, i, j, fr=-1, ang=0): """ Sets parameters of transition to read """ from astropy.constants import c cc = c.to('Angstrom / s') self.d.i = i - 1 self.d.j = j - 1 self.d.isline = self.atom.ilin[self.d.i, self.d.j] != 0 self.d.iscont = self.atom.icon[self.d.i, self.d.j] != 0 if self.d.isline: self.d.kr = self.atom.ilin[self.d.i, self.d.j] - 1 self.d.nnu = self.line[self.d.kr].nnu self.d.nu = np.copy(self.line[self.d.kr].nu) * u.Hz self.d.l = (cc / self.d.nu).to('Angstrom') self.d.dl = (cc * (1.0 / self.d.nu - 1.0 / self.line[self.d.kr].nu0)).to('Angstrom') self.d.ired = self.line[self.d.kr].ired elif self.d.iscont: self.d.kr = self.atom.icon[self.d.i, self.d.j] - 1 self.d.nnu = self.cont[self.d.kr].nnu self.d.nu = np.copy(self.cont[self.d.kr].nu) * u.Hz self.d.l = (cc / self.d.nu).to('Angstrom') self.d.dl = None self.d.ired = self.cont[self.d.kr].ired else: raise RuntimeError('upper and lower level %i, %i are not connected' ' with a radiative transition.' % (i, j)) if fr == -1: self.d.ff = -1 else: self.d.ff = self.d.ired + fr self.d.ang = ang if self.printinfo: print('transition parameters are set to:') print(' i =', self.d.i) print(' j =', self.d.j) print(' kr =', self.d.kr) print(' ff =', self.d.ff) print(' ang =', self.d.ang)
def manually_tweak_simplified_catalog(simplifiedcat): """ This just updates a few entries in the catalog that seem to be missing velocities for unclear reasons. No longer needed with `add_6df`: they are present. """ from astropy.coordinates import SkyCoord from astropy.constants import c infolines = """ 46.480833 54.266111 2051.8 No velocity in NED PGC 011632 46.704583 54.588333 2859.3 No velocity in NED 50.288333 66.921667 2637.1 Velocity in NED, but no LEDA entry 99.794583 -1.5075000 2887.9 No velocity in NED 102.57375 -2.8605556 2699.9 No velocity in NED 102.93875 -3.6077778 2867.4 No velocity in NED 114.40708 -26.746667 2964.5 Velocity in NED, LEDA source, but not HyperLeda 116.32750 -32.516667 2162.0 Velocity in NED, LEDA source, but not HyperLeda 123.74833 -30.866667 1761.0 Velocity in NED, PGC 023091 (note in NED re; position error?) """.split('\n')[1:-1] ras = [] decs = [] vels = [] for l in infolines: ls = l.split() ras.append(float(ls[0])) decs.append(float(ls[1])) vels.append(float(ls[2])) updatecoos = SkyCoord(ras*u.deg, decs*u.deg) catcoos = SkyCoord(simplifiedcat['RA'].view(np.ndarray)*u.deg, simplifiedcat['Dec'].view(np.ndarray)*u.deg) idx, dd, d3d = updatecoos.match_to_catalog_sky(catcoos) simplifiedcat = simplifiedcat.copy() simplifiedcat['vhelio'][idx] = vels = np.array(vels) simplifiedcat['distance'][idx] = WMAP9.luminosity_distance( vels / c.to(u.km / u.s).value).to(u.Mpc).value return simplifiedcat
def manually_tweak_simplified_catalog(simplifiedcat): """ This just updates a few entries in the catalog that seem to be missing velocities for unclear reasons. No longer needed with `add_6df`: they are present. """ from astropy.coordinates import SkyCoord from astropy.constants import c infolines = """ 46.480833 54.266111 2051.8 No velocity in NED PGC 011632 46.704583 54.588333 2859.3 No velocity in NED 50.288333 66.921667 2637.1 Velocity in NED, but no LEDA entry 99.794583 -1.5075000 2887.9 No velocity in NED 102.57375 -2.8605556 2699.9 No velocity in NED 102.93875 -3.6077778 2867.4 No velocity in NED 114.40708 -26.746667 2964.5 Velocity in NED, LEDA source, but not HyperLeda 116.32750 -32.516667 2162.0 Velocity in NED, LEDA source, but not HyperLeda 123.74833 -30.866667 1761.0 Velocity in NED, PGC 023091 (note in NED re; position error?) """.split('\n')[1:-1] ras = [] decs = [] vels = [] for l in infolines: ls = l.split() ras.append(float(ls[0])) decs.append(float(ls[1])) vels.append(float(ls[2])) updatecoos = SkyCoord(ras * u.deg, decs * u.deg) catcoos = SkyCoord(simplifiedcat['RA'].view(np.ndarray) * u.deg, simplifiedcat['Dec'].view(np.ndarray) * u.deg) idx, dd, d3d = updatecoos.match_to_catalog_sky(catcoos) simplifiedcat = simplifiedcat.copy() simplifiedcat['vhelio'][idx] = vels = np.array(vels) simplifiedcat['distance'][idx] = WMAP9.luminosity_distance( vels / c.to(u.km / u.s).value).to(u.Mpc).value return simplifiedcat
def test_distant_observer(): N = 100 x = np.random.random((N, 3)) v = np.random.random((N, 3)) * 0.1 period = np.array([1, 1, 1]) redshifts = distant_observer_redshift(x, v) assert len(redshifts) == N, "redshift array is not the correct size" redshifts = distant_observer_redshift(x, v, period=period) from astropy.constants import c c_km_s = c.to('km/s').value z_cos_max = period[2] * 100.00 / c_km_s assert len(redshifts) == N, "redshift array is not the correct size" assert np.max( redshifts) <= z_cos_max, "PBC is not handeled correctly for redshifts"
def HorizonDistance(self, zo): # Compute the proper distance to the horizon at a given redshift # DC(zo,ze)/(1+zo) # input: Redshift of the observer # Returns the proper distance (Mpc) # define an array with redshifts, spaced in intervals of 0.001 # Note that if you want redshifts smaller than 0.001 you'll need to refine this zrange = np.arange(zo, 5000, 1e-3) # 1/H(zrange)*speed of light # Speed of light is loaded in modules from astropy, but in units of m/s --> need in km/s # FILL THIS IN y = c.to(u.km / u.s) * (1.0 / self.HubbleParameter(zrange)) # Integrate y numerically over zrange and return in units of Mpc # FILL THIS IN Comoving = simps(y, zrange) * u.Mpc # Proper distance Comoving/(1+z) return Comoving / (1 + zo)
def calc_mag_ab(targetSN, w1, w2): """Calculates the AB magnitudes of the bins""" for field, sn in zip(fields, targetSN): os.chdir(os.path.join(data_dir, "combined_{0}".format(field))) fits = "binned_sn{0}_res2.95.fits".format(sn) data = pf.getdata(fits, 0) w = wavelength_array(fits, axis=1, extension=0) * u.angstrom idx = np.where(((w >= w1 * u.angstrom) & (w < w2 * u.angstrom))) data = data[:,idx] w = w[idx] bins = wavelength_array(fits, axis=2, extension=0) lines = [] for i, bin in enumerate(bins): f_lambda = data[i] * np.power(10., -20) * u.erg / u.s / u.cm / u.cm / u.angstrom f_lambda = f_lambda.to("erg * s**-1 * cm**-3") f_nu = f_lambda * w.to("cm") * w.to("cm") / c.to("cm * Hz") m_ab = -2.5 * np.log10(np.median(f_nu.to("Jy")/ (3631 * u.Jy))) mv = m_ab - 3 id = "{0}_bin{1:04d}".format(field, bin) line = "{0:20s}{1:10.4f}{2:10.4f}".format(id, m_ab, mv) lines.append(line) with open("magab_w{0}_{1}.dat".format(w1, w2), "w") as f: f.write("\n".join(lines))
from astropy.constants import c from astropy.units import km, s from astropy.io import ascii from matplotlib.transforms import blended_transform_factory from collections import defaultdict from math import ceil import numpy as np import sys import os c_kms = c.to(km / s).value # speed of light in km/s atom = AtomDat() # atomic data # Panel label inset format: bbox = dict(facecolor='w', edgecolor='None') def make_velocity_scale(vmin, vmax, observed_wavelength, wavelength): """ Makes a velocity scale for a spectrum, with the zero velocity defined by the observed wavelength of some spectral feature. Parameters ---------- vmin, vmax : float Minimum and maximum velocity for the scale.
spectral_gaps = [] else: # this is for the casual user lsf='COS_LP1' # not being used, is it? instr=['COS','COS'] lsfranges=np.array([[1130,1450],[1450,1800]]) gratings=['G130M','G160M'] cen_wave=['1291','1611'] slits=['NA','NA'] lps=['2','2'] spectral_gaps = [[0,1162.5], [1198,1201.5], [1213.3, 1217.93], [1299.3,1321.6],[1596,1612.8],[1782,2000]] # fundamental constants echarge = 4.803204505713468e-10 m_e = 9.10938291e-28 c = C.to('cm/s').value c2 = 29979245800.0 # store LSFs and FGs lsfs=[] fgs=[] wavegroups=[] wgidxs=[] uqwgidxs=[] outputdir = './' VPparoutfile = outputdir + field + '_VP.dat' VPmodeloutfile = outputdir + field + 'VPmodel.fits' contoutfile = outputdir + 'continua.dat' largeVPparfile = outputdir + '_VP_log.dat'
def distant_observer_redshift(x, v, period=None, cosmo=None): """ Calculate observed redshifts, :math:`z_{\\rm obs}`, assuming the distant observer approximation. The line-of-sight (LOS) is assumed to be the z-direction. Parameters ---------- x: array_like Npts x 3 array containing 3-d positions in Mpc/h units v: array_like Npts x 3 array containing 3-d velocity components of galaxies in km/s period : array_like, optional Length-3 array defining axis-aligned periodic boundary conditions. If only one number, Lbox, is specified, period is assumed to be [Lbox]*3. Returns ------- redshift : np.array array of "observed" redshifts. Notes ----- This function convolves the peculiar velocities of galaxies with the comological redshift. The cosmological redshift is estimated as: .. math:: z_{\\rm cosmo} = z \\times H_0/c where :math:`z` is the z-position of the galaxy, :math:`H_0` is the Hubble constant at z=0, and :math:`c` is the speed of light. The observed redshift is: .. math:: z_{\\rm obs} = z_{\\rm cosmo}+(v_{\\rm LOS}/c) \\times (1.0+z_{\\rm cosmo}) where :math:`v_{\\rm LOS}` is the LOS component of the peculiar velocoty of the galaxy. When ``period`` is not None, and a galaxy's observed redshift, :math:`z_{\\rm obs}`, exceeds the cosmological redshift of period[2], :math:`z_{\\rm cosmo, max}`: .. math:: z_{\\rm cosmo, max} = \\text{period[2]}\\times H_0/c or is less than 0.0, the observed redshift is shifted to lay within the periodic boundaries such that :math:`z^{\\prime}_{\\rm obs} = {z}_{\\rm obs} - z_{\\rm cosmo, max}` or :math:`z^{\\prime}_{\\rm obs} = {z}_{\\rm obs} + z_{\\rm cosmo, max}`, respectively. Examples -------- For demonstration purposes we create a randomly distributed set of points within a periodic unit cube. >>> Npts = 1000 >>> Lbox = 1.0 >>> period = np.array([Lbox,Lbox,Lbox]) >>> x = np.random.random(Npts) >>> y = np.random.random(Npts) >>> z = np.random.random(Npts) We transform our *x, y, z* points into the array shape used by the pair-counter by taking the transpose of the result of `numpy.vstack`. This boilerplate transformation is used throughout the `~halotools.mock_observables` sub-package: >>> coords = np.vstack((x,y,z)).T We do the same thing to assign random peculiar velocities: >>> vx,vy,vz = (np.random.random(Npts),np.random.random(Npts),np.random.random(Npts)) >>> vels = np.vstack((vx,vy,vz)).T >>> redshifts = distant_observer_redshift(coords, vels) """ c_km_s = c.to('km/s').value #get the peculiar velocity component along the line of sight direction (z direction) v_los = v[:,2] #compute cosmological redshift (h=1, note that positions are in Mpc/h) z_cos = x[:,2]*100.0/c_km_s #redshift is combination of cosmological and peculiar velocities z = z_cos+(v_los/c_km_s)*(1.0+z_cos) #reflect galaxies around PBC if period is not None: z_cos_max = period[2]*100.00/c_km_s #maximum cosmological redshift flip = (z > z_cos_max) z[flip] = z[flip] - z_cos_max flip = (z < 0.0) z[flip] = z[flip] + z_cos_max return z
def ra_dec_z(x, v, cosmo=None): """ Calculate the ra, dec, and redshift assuming an observer placed at (0,0,0). Parameters ---------- x: array_like Npts x 3 numpy array containing 3-d positions in Mpc/h v: array_like Npts x 3 numpy array containing 3-d velocities in km/s cosmo : object, optional Instance of an Astropy `~astropy.cosmology` object. The default is FlatLambdaCDM(H0=0.7, Om0=0.3) Returns ------- ra : np.array right accession in radians dec : np.array declination in radians redshift : np.array "observed" redshift Examples -------- For demonstration purposes we create a randomly distributed set of points within a periodic unit cube. >>> Npts = 1000 >>> Lbox = 1.0 >>> period = np.array([Lbox,Lbox,Lbox]) >>> x = np.random.random(Npts) >>> y = np.random.random(Npts) >>> z = np.random.random(Npts) We transform our *x, y, z* points into the array shape used by the pair-counter by taking the transpose of the result of `numpy.vstack`. This boilerplate transformation is used throughout the `~halotools.mock_observables` sub-package: >>> coords = np.vstack((x,y,z)).T We do the same thing to assign random peculiar velocities: >>> vx,vy,vz = (np.random.random(Npts),np.random.random(Npts),np.random.random(Npts)) >>> vels = np.vstack((vx,vy,vz)).T >>> from astropy.cosmology import WMAP9 as cosmo >>> ra, dec, redshift = ra_dec_z(coords, vels, cosmo = cosmo) """ #calculate the observed redshift if cosmo==None: cosmo = cosmology.FlatLambdaCDM(H0=0.7, Om0=0.3) c_km_s = c.to('km/s').value #remove h scaling from position so we can use the cosmo object x = x/cosmo.h #compute comoving distance from observer r = np.sqrt(x[:,0]**2+x[:,1]**2+x[:,2]**2) #compute radial velocity ct = x[:,2]/r st = np.sqrt(1.0 - ct**2) cp = x[:,0]/np.sqrt(x[:,0]**2 + x[:,1]**2) sp = x[:,1]/np.sqrt(x[:,0]**2 + x[:,1]**2) vr = v[:,0]*st*cp + v[:,1]*st*sp + v[:,2]*ct #compute cosmological redshift and add contribution from perculiar velocity yy = np.arange(0,1.0,0.001) xx = cosmo.comoving_distance(yy).value f = interp1d(xx, yy, kind='cubic') z_cos = f(r) redshift = z_cos+(vr/c_km_s)*(1.0+z_cos) #calculate spherical coordinates theta = np.arccos(x[:,2]/r) phi = np.arccos(cp) #atan(y/x) #convert spherical coordinates into ra,dec ra = phi dec = (np.pi/2.0) - theta return ra, dec, redshift
def __init__(self, splot, obs=None, ion=None, function='Voigt', **kwargs): """ Build widget elements based on a spectrum plotted in `splot` (type SPlot). `splot` may also be a Spectrum object (for which a SPlot will be created). Make initial guesses at parameters, build widgets, render the figure. """ try: options = Options( kwargs, { 'kind' : 'cubic' , # given to interp1d for continuum 'bandwidth' : 0.1*u.nm, # user should provide this! 'linecolor' : 'k' # color passed to plt.plot() for lines }) kind = options('kind') bandwidth = options('bandwidth') linecolor = options('linecolor') except OptionsError as err: print(' --> OptionsError:', err) raise ProfileError('Unrecognized option given to FittingGUI.__init__()!') if function not in ['Voigt', 'Lorentzian', 'Gaussian']: raise ProfileError('The only currently implemented functions ' 'for fitting profiles are `Voigt`, `Lorentzian` and `Gaussian`!') # grab and/or create the SPlot if isinstance(splot, Spectrum): splot = SPlot(splot, marker='k-', label='spectrum') elif not isinstance(splot, SPlot): raise ProfileError('FittingGUI() expects the `splot` argument to ' 'either be a Spectrum or a SPlot!') # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # if the profile `function` is `Voigt` and we have necessary parameters, # show a preview for `b` and `N` and `v`. self.any_line_parameters = True if obs or ion else False self.has_line_parameters = True if obs and ion else False if self.any_line_parameters and not self.has_line_parameters: raise ProfileError('From FittingGUI.__init__(), if the absoption line ' 'parameters `obs` or `ion` are provided, both must be given!') if self.has_line_parameters: if function != 'Voigt': raise ProfileError('From FittingGUI.__init__(), in order to compute the ' 'broadening from the instrument profile of the `obs`ervatory and the ' 'column density for the `ion`, it is expected that we try to fit a `Voigt` ' 'profile `function`!') if not isinstance(obs, Observatory): raise ProfileError('From FittingGUI.__init__(), if `obs` is provided it should ' 'be of type Observatory!') if not hasattr(obs, 'resolution'): raise ProfileError('From FittingGUI.__init__(), if an observatory `obs` is ' 'provided, it needs to have a member `resolution`!') if not hasattr(ion, 'wavelength') or not hasattr(ion.wavelength, 'unit'): raise ProfileError('From FittingGUI.__init__(), the provided `ion` either ' 'did not have a `wavelength` attribute or it has one without units!') if not hasattr(ion, 'fvalue'): raise ProfileError('From FittingGUI.__init__(), the provide `ion` does not ' 'have an `fvalue` (oscillator strength) attribute!') if hasattr(ion.fvalue, 'unit') and ion.fvalue.unit != u.dimensionless_unscaled: raise ProfileError('From FittingGUI.__init__(), the osciallator strength, ' '`fvalue` for an ion must be a dimensionless Quantity!') if not hasattr(ion, 'A') or not ion.A: raise ProfileError('From FittingGUI.__init__(), the provided `ion` does not ' 'have an `A` (transition probability) attribute!') if hasattr(ion.A, 'unit') and ion.A.unit != u.Unit('s-1'): raise ProfileError('From FittingGUI.__init__(), the transition probability, ' '`A`, from the `ion` must be in units of `s-1` if units are present!') # the instrument broadening is from R = lambda / delta_lambda # FWHM = 2 sqrt( 2 log 2) sigma for the Gaussian instrument profile self.R = obs.resolution self.sigma_instrument = (ion.wavelength / self.R) / (2 * np.sqrt(2 * np.log(2))) self.sigma_instrument_squared = self.sigma_instrument.value ** 2 # save parameters for later self.wavelength = ion.wavelength self.fvalue = ion.fvalue self.A = ion.A # the FWHM of the intrinsic line profile (Lorentzian) is proportional to the # transition probability (Einstein coeff.) `A`... # convert from km s-1 to wavelength units self.gamma = (ion.wavelength * (ion.wavelength * ion.A / (2 * np.pi)).to(u.km / u.s) / c.si).to(ion.wavelength.unit).value # the leading constant in the computation of `N` (per Angstrom per cm-2) # self.leading_constant = (m_e.si * c.si / (np.sqrt(np.pi) * e.si**2 * ion.fvalue * # ion.wavelength.to(u.Angstrom))).value self.leading_constant = 1 / (ion.fvalue * ion.wavelength.to(u.AA)**2 * np.pi * e.emu**2 / (m_e.si * c.to(u.km/u.s)**2)).value # setting `function` to `ModifiedVoigt` only makes a change in how the `Voigt` # profile is evaluated by using `self.gamma` instead of self.Params[...]['Gamma'] function = 'ModifiedVoigt' # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - print('\n We need to extract the lines from the continuum before we ' 'begin the fitting process.') # extract the line, continuum, rms from the spectrum self.line, self.continuum = Extract(splot, bandwidth=bandwidth, kind=kind) self.rms = self.continuum.rms print('\n Now select the peaks of each line to be fit.') print(' Initial guesses will be made for each line markered.') input(' Press <Return> after making your selections ... ') # grab all the selected points global selected points = np.array([ [ entry.value for entry in selected['wave'] ], [ entry.value for entry in selected['data'] ] ]) # point pairs in ascending order by wavelength points = points[:, points[0].argsort()] # domain size of the line and the number of components self.domainsize = self.line.wave.value[-1] - self.line.wave.value[0] self.numlines = np.shape(points)[1] - 4 if self.numlines < 1: raise ProfileError('FittingGUI() expects at least one line to ' 'be selected for fitting!') # final spectral line profile is convolution of the LSP and the # line profile function. Gaussian on Gaussian, Gaussian on Lorentzian, # etc ... Set the functional form given requested profile function self.Evaluate = self.SetFunction(function) # initial guesses for parameters given the line locations, # containing `L1`, `L2`, etc ... the values of which are themselves # dictionaries of parameters (e.g., `FWHM`, `Depth`, etc...) whose values # are the initial guesses for those parameters given the location of # it`s peak and the number of peaks within the `line`s domain. self.Params = { 'L' + str(line + 1) : self.Parameterize(function, loc) for line, loc in enumerate(points[:, 2:-2].T) } # grab the actual Figure object and it's axis to keep references self.splot = splot self.fig = splot.fig self.ax = splot.ax # refresh image, but keep any changes in axis limits splot.xlim( *splot.ax.get_xlim() ) splot.ylim( *splot.ax.get_ylim() ) splot.draw() # bring up plot to make room for sliders plt.subplots_adjust(bottom = 0.30) # resample continuum onto line domain self.continuum = self.continuum.copy() self.continuum.resample(self.line) # common domain for plotting, strip units, wavelengths from continuum self.x = self.continuum.wave.value self.continuum = self.continuum.data.value # copy of continuum allows for adjustments self.y = self.continuum.copy() # save the mid-level of the continuum to avoid over-calculation self.continuum_level = self.continuum.mean() # add plots of each line, keep dictionary of handles self.Component = { line : plt.plot(self.x, self.y - self.Evaluate(self.x, **parameters), linecolor+'--')[0] for line, parameters in self.Params.items() } # add plot of the continuum self.Continuum, = plt.plot(self.x, self.y, 'r-', lw=2) # add plot of superposition of each component self.Combination, = plt.plot(self.x, self.y - self.SuperPosition(), 'g-') # fix the limits on plot xmin, xmax = splot.ax.get_xlim() ymin, ymax = splot.ax.get_ylim() plt.axis([xmin, xmax, ymin, ymax]) # color scheme for sliders theme = { 'light': {'bg': 'white', 'fg': 'blue'}, 'dark' : {'bg': 'black', 'fg': 'red'} } # axes for parameter sliders self.Axis = { # key : axis xpos , ypos + dy , xsize, ysize line : plt.axes([0.10, 0.05 + (k+1) * 0.03, 0.65, 0.02], axisbg = 'black') for k, line in enumerate( self.Params['L1'].keys() ) } # add an axis to make adjustments to the continuum self.Axis['Continuum'] = plt.axes([0.10, 0.05, 0.65, 0.02], axisbg='black') # create the sliders for the parameters self.Slider = { # Slider `key` and widget param : widgets.Slider( self.Axis[param], # which axis to put slider on param, # name of parameter (and the slider) self.Minimum(param), # set the minimum of the slider self.Maximum(param), # set the maximum of the slider valinit = self.Params['L1'][param], # initial value facecolor = 'c' ) # create a slider for each parameter for param in self.Params['L1'].keys() } # create the slider for the continuum (10% adjustments) self.Slider['Continuum'] = widgets.Slider(self.Axis['Continuum'], 'Continuum', 0.90 * self.continuum_level, 1.10 * self.continuum_level, valinit = self.continuum_level, facecolor = 'c') # connect sliders to update function for slider in self.Slider.values(): slider.on_changed(self.Update) # create axis for radio buttons self.RadioAxis = plt.axes([0.85, 0.01, 0.1, 0.2], axisbg = 'black', frameon = False) # create the radio button widget self.Radio = widgets.RadioButtons(self.RadioAxis, tuple(['L' + str(i+1) for i in range(self.numlines)]), active = 0, activecolor = 'c') # connect the radio button to it's update function self.Radio.on_clicked(self.ToggleComponent) # set current component as the first line self.current_component = 'L1' # make currently selected line bold self.Component['L1'].set_linewidth(2) # variable allows for the radio buttons to not screw-up the sliders/graphs # when switching between lines self.stall = False # add the initial text for `N` and `b` if applicable. # text is along 20% below the y-axis if self.has_line_parameters: # self.b, self.N, self.v = self.solve_b(), self.solve_N(), self.solve_v() self.preview = self.ax.text(xmin, ymin - 0.1 * (ymax - ymin), 'v: {:>10.4f} km s-1 b: {:>10.4f} km s-1' ' W: {:>10.4f}\nN: {:>10.4e} cm-2 tau_0: {:>10.4f}'.format( self.solve_v().value, self.solve_b().value, self.solve_W(), self.solve_N().value, self.solve_tau0()), va = 'top') # display the text self.fig.canvas.draw_idle()
from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg from matplotlib.transforms import blended_transform_factory from astropy.table import Table from astropy.constants import c from astropy.units import km, s from astropy.io import ascii from math import ceil import numpy as np import sys import os c_kms = c.to(km / s).value atom = AtomDat() # Panel label inset format: bbox = dict(facecolor='w', edgecolor='None') info = """ The following keypress options are available: space Set the zero velocity at the position of the cursor and re-draw. b Print a VPFIT fitting region based on two cursor positions (requires pressing 'b' twice, once at each extrema). l Print a VPFIT line entry at the position of the cursor, guessing the column density (assumes b = 20 km/s). z Move the plot to a new redshift. S Save the figure.
mjd = Time(mjd, format='mjd', scale='utc', lon=(74*u.deg+02*u.arcmin+59.07*u.arcsec).to(u.deg).value, lat=(19*u.deg+05*u.arcmin+47.46*u.arcsec).to(u.deg).value) q+=steps # orbital delay and velocity (lt-s and v/c) d_orb = eph1957.orbital_delay(mjd.tdb.mjd) v_orb = eph1957.radial_velocity(mjd.tdb.mjd) # direction to target dir_1957 = eph1957.pos(mjd.tdb.mjd) # Delay from and velocity of centre of earth to SSB (lt-s and v/c) posvel_earth = jpleph.compute('earth', mjd.tdb.jd) pos_earth = posvel_earth[:3]/c.to(u.km/u.s).value vel_earth = posvel_earth[3:]/c.to(u.km/u.day).value d_earth = np.sum(pos_earth*dir_1957, axis=0) v_earth = np.sum(vel_earth*dir_1957, axis=0) #GMRT from tempo2-2013.3.1/T2runtime/observatory/observatories.dat xyz_gmrt = (1656318.94, 5797865.99, 2073213.72) # Rough delay from observatory to center of earth # mean sidereal time (checked it is close to rf_ephem.utc_to_last) lmst = (observability.time2gmst(mjd)/24. + mjd.lon/360.)*2.*np.pi coslmst, sinlmst = np.cos(lmst), np.sin(lmst) # rotate observatory vector xy = np.sqrt(xyz_gmrt[0]**2+xyz_gmrt[1]**2) pos_gmrt = np.array([xy*coslmst, xy*sinlmst, xyz_gmrt[2]*np.ones_like(lmst)])/c.si.value
def plotEnergySolution(file_name, res_id=None, pixel=[], axis=None): ''' Plot the phase to energy solution for a pixel from the wavlength calibration solution file 'file_name'. Provide either the pixel location pixel=(row, column) or the res_id for the resonator. Args: file_name: the wavecal solution file including the path (string) res_id: the resonator ID for the plotted pixel. Can use pixel keyword-arg instead. (integer) pixel: the pixel row and column for the plotted pixel. Can use res_id keyword-arg instead. (length 2 list of integers) axis: matplotlib axis object on which to display the plot. If no axis is provided a new figure will be made. ''' # load file_name wave_cal = tb.open_file(file_name, mode='r') wavelengths = wave_cal.root.header.wavelengths.read()[0] info = wave_cal.root.header.info.read() model_name = info['model_name'][0].decode('utf-8') calsoln = wave_cal.root.wavecal.calsoln.read() debug = wave_cal.root.debug.debug_info.read() beamImage = wave_cal.root.header.beamMap.read() # parse inputs if len(pixel) != 2 and res_id is None: wave_cal.close() raise ValueError('please supply resonator location or res_id') if len(pixel) == 2 and res_id is None: row = pixel[0] column = pixel[1] res_id = beamImage[row][column] index = np.where(res_id == np.array(calsoln['resid'])) elif res_id is not None: index = np.where(res_id == np.array(calsoln['resid'])) if len(index[0]) != 1: wave_cal.close() raise ValueError("res_id must exist and be unique") row = calsoln['pixel_row'][index][0] column = calsoln['pixel_col'][index][0] # load data if len(calsoln['polyfit'][index]) == 0: print('pixel has no data') return poly = calsoln['polyfit'][index][0] flag = calsoln['wave_flag'][index][0] centers = [] errors = [] energies = [] for ind, wavelength in enumerate(wavelengths): hist_fit = debug['hist_fit' + str(ind)][index][0] hist_cov = debug['hist_cov' + str(ind)][index][0] hist_flag = debug['hist_flag'][index, ind][0] if hist_flag == 0: if model_name == 'gaussian_and_exp': energies.append(h.to('eV s').value * c.to('nm/s').value / np.array(wavelength)) centers.append(hist_fit[3]) errors.append(np.sqrt(hist_cov.reshape((5, 5))[3, 3])) else: raise ValueError("{0} is not a valid fit model name" .format(model_name)) wave_cal.close() energies = np.array(energies) centers = np.array(centers) errors = np.array(errors) if len(energies) == 0: print('pixel has no data') return R0 = calsoln['R'][index] R0[R0 == -1] = np.nan with warnings.catch_warnings(): # rows with all nan values will give an unnecessary RuntimeWarning warnings.simplefilter("ignore", category=RuntimeWarning) R = np.nanmedian(R0) # plot data show = False if axis is None: fig, axis = plt.subplots() show = True axis.set_xlabel('phase [deg]') axis.set_ylabel('energy [eV]') axis.errorbar(centers, energies, xerr=errors, linestyle='--', marker='o', markersize=5, markeredgecolor='black', markeredgewidth=0.5, ecolor='black', capsize=3, elinewidth=0.5) ylim = [0.95 * min(energies), max(energies) * 1.05] axis.set_ylim(ylim) xlim = [1.05 * min(centers - errors), 0.92 * max(centers + errors)] axis.set_xlim(xlim) if poly[0] != -1: xx = np.arange(-180, 0, 0.1) axis.plot(xx, np.polyval(poly, xx), color='orange') xmax = xlim[1] ymax = ylim[1] dx = xlim[1] - xlim[0] dy = ylim[1] - ylim[0] flag_dict = pipelineFlags.waveCal axis.text(xmax - 0.05 * dx, ymax - 0.05 * dy, '{0} : ({1}, {2})'.format(res_id, row, column), ha='right', va='top') if poly[0] == -1: axis.text(xmax - 0.05 * dx, ymax - 0.1 * dy, flag_dict[flag], color='red', ha='right', va='top') else: if flag == 9: axis.text(xmax - 0.05 * dx, ymax - 0.1 * dy, flag_dict[flag], color='red', ha='right', va='top') else: axis.text(xmax - 0.05 * dx, ymax - 0.1 * dy, flag_dict[flag], ha='right', va='top') axis.text(xmax - 0.05 * dx, ymax - 0.15 * dy, "Median R = {0}".format(round(R, 2)), ha='right', va='top') if show: plt.show(block=False) else: return axis
from joebvp import utils as jbu import os from linetools.spectra.io import readspec import numpy as np from astropy.constants import c from matplotlib.figure import Figure from matplotlib.backends.backend_qt5agg import ( FigureCanvasQTAgg as FigureCanvas, NavigationToolbar2QT as NavigationToolbar) modpath=os.path.abspath(os.path.dirname(__file__)) print os.path.abspath(os.path.dirname(__file__)) Ui_MainWindow, QMainWindow = loadUiType(modpath+'/mainvpwindow.ui') c= c.to('km/s').value class LineParTableModel(QAbstractTableModel): def __init__(self,fitpars,fiterrors,parinfo,linecmts=None,parent=None): QAbstractTableModel.__init__(self,parent) self.fitpars=fitpars self.fiterrors=fiterrors self.parinfo=parinfo self.linecmts=linecmts self.headers=['Wavelength','Species','z','N','sig(N)','b','sig(b)','v','sig(v)','rely','comment'] def rowCount(self,parent): return len(self.fitpars[0]) def columnCount(self, parent): return 11
import logging import sys from datetime import datetime from typing import Dict, List, Any, Union import astropy.units as u import matplotlib.pyplot as plt import numpy as np from astropy.constants import c from mpl_toolkits.axes_grid1 import host_subplot from utils.parse import parse_paramfile from utils.rv_utils import RV, JulianDate, prepare_mass_params, generate_companion_label from utils.rv_utils import strtimes2jd, join_times, check_core_parameters c_km_s = c.to(u.kilometer / u.second) # Speed of light in km/s def parse_args(args): # type: List[str] -> argparse.Namespace """RV Argparse parser.""" parser = argparse.ArgumentParser(description='Radial velocity plotting') parser.add_argument('params', help='RV parameters filename', type=str) parser.add_argument('-d', '--date', default=None, help='Reference date in format YYYY-MM-DD [HH:MM:SS]. Default=None uses time of now.') # parser.add_argument('-r', '--rv_diff', help='RV difference threshold to find') parser.add_argument('-o', '--obs_times', help='Times of previous observations YYYY-MM-DD format', nargs='+', default=None) parser.add_argument('-l', '--obs_list', help='File with list of obs times.', type=str, default=None) # parser.add_argument('-f', '--files', help='Params and obs-times are file' # ' names to open', action='store_true')
rv=[] #empty array to hold relative velocities of the system time_elapsed=[] time_orig=start real_time=[] while time_orig<finish: time=time_orig print "Time left: {0}\n".format(finish-time) f_p=eph1957.evaluate('F',time,t0par='PEPOCH')#pulse frequency P_0=1./f_p #pulse period # direction to target dir_1957 = eph1957.pos(time) # Delay from and velocity of centre of earth to SSB (lt-s and v/c) posvel_earth = jpleph.compute('earth', time_jd) pos_earth = posvel_earth[:3]/c.to(u.km/u.s).value vel_earth = posvel_earth[3:]/c.to(u.km/u.day).value d_earth = np.sum(pos_earth*dir_1957, axis=0) v_earth = np.sum(vel_earth*dir_1957, axis=0) time+=d_earth/(3600*24) time_jd+=d_earth/(3600*24) mjd = Time(time, format='mjd', scale='utc', lon=(74*u.deg+02*u.arcmin+59.07*u.arcsec).to(u.deg).value, lat=(19*u.deg+05*u.arcmin+47.46*u.arcsec).to(u.deg).value) #GMRT from tempo2-2013.3.1/T2runtime/observatory/observatories.dat xyz_gmrt = (1656318.94, 5797865.99, 2073213.72) # Rough delay from observatory to center of earth
from scipy.interpolate import interp1d import numpy as np import os __all__ = ['read_x1d', 'read_lsf', 'limiting_equivalent_width', 'significance_level'] datapath = os.path.split(os.path.abspath(__file__))[0] + '/' dw_orig = dict(G130M=0.00997, G160M=0.01223, G140L=0.083, G185M=0.034, G225M=0.034, G285M=0.04, G230L=0.39) c_kms = c.to(km / s) # Cache for the LSF values: cache_lsf = {} def read_x1d(filename): """ Reads an x1d format spectrum from CalCOS. Parameters ---------- filename : str x1d filename. Returns -------
quality = [] for comp_name in comps.keys(): name += [comp_name] ion += [comp_name.split('_')[1]] comment += [comps[comp_name]['Comment']] wrest += [comps[comp_name]['wrest']] zfit_aux = comps[comp_name]['zfit'] zfit += [zfit_aux] # component redshift from fit zcmp_aux = comps[comp_name]['zcomp'] zcmp += [zcmp_aux] # middle of component vlim vlim_zcmp = np.array((comps[comp_name]['vlim'])) # w/r zcmp vmin_zcmp += [vlim_zcmp[0]] vmax_zcmp += [vlim_zcmp[1]] zlim_zcmp = zcmp_aux + vlim_zcmp * (1 + zcmp_aux) / c.to('km/s').value # w/r zcmp vlim_zfit = (zlim_zcmp - zfit_aux) * c.to('km/s').value / (1 + zfit_aux) # w/r zfit vmin_zfit += [vlim_zfit[0]] vmax_zfit += [vlim_zfit[1]] # quantities that are independent of redshift logn += [comps[comp_name]['Nfit']] b += [comps[comp_name]['bfit']] quality += [comps[comp_name]['Quality']] # Create table comp_table = Table() comp_table.add_column(Column(name='name', data=name)) comp_table.add_column(Column(name='ion', data=ion)) comp_table.add_column(Column(name='comment', data=comment)) comp_table.add_column(Column(name='zcmp', data=zcmp))
# mjd = Time('2013-05-16 23:45:00', scale='utc').mjd+np.linspace(0.,finish, steps) # mjd = Time(mjd, format='mjd', scale='utc', # lon=(74*u.deg+02*u.arcmin+59.07*u.arcsec).to(u.deg).value, # lat=(19*u.deg+05*u.arcmin+47.46*u.arcsec).to(u.deg).value) # time+=steps # orbital delay and velocity (lt-s and v/c) d_orb = eph1957.orbital_delay(mjd.tdb.mjd) v_orb = eph1957.radial_velocity(mjd.tdb.mjd) # direction to target dir_1957 = eph1957.pos(mjd.tdb.mjd) # Delay from and velocity of centre of earth to SSB (lt-s and v/c) posvel_earth = jpleph.compute("earth", mjd.tdb.jd) pos_earth = posvel_earth[:3] / c.to(u.km / u.s).value vel_earth = posvel_earth[3:] / c.to(u.km / u.day).value d_earth = np.sum(pos_earth * dir_1957, axis=0) v_earth = np.sum(vel_earth * dir_1957, axis=0) # GMRT from tempo2-2013.3.1/T2runtime/observatory/observatories.dat xyz_gmrt = (1656318.94, 5797865.99, 2073213.72) # Rough delay from observatory to center of earth # mean sidereal time (checked it is close to rf_ephem.utc_to_last) lmst = (observability.time2gmst(mjd) / 24.0 + mjd.lon / 360.0) * 2.0 * np.pi coslmst, sinlmst = np.cos(lmst), np.sin(lmst) # rotate observatory vector xy = np.sqrt(xyz_gmrt[0] ** 2 + xyz_gmrt[1] ** 2) pos_gmrt = np.array([xy * coslmst, xy * sinlmst, xyz_gmrt[2] * np.ones_like(lmst)]) / c.si.value vel_gmrt = (
def CartesianToSky(pos, cosmo, velocity=None, observer=[0,0,0], zmax=100., frame='icrs'): r""" Convert Cartesian position coordinates to RA/Dec and redshift, using the specified cosmology to convert radial distances from the origin into redshift. If velocity is supplied, the returned redshift accounts for the additional peculiar velocity shift. Users should ensure that ``zmax`` is larger than the largest possible redshift being considered to avoid an interpolation exception. .. note:: Cartesian coordinates should be in units of Mpc/h and velocity should be in units of km/s. Parameters ---------- pos : dask array a N x 3 array holding the Cartesian position coordinates in Mpc/h cosmo : :class:`~nbodykit.cosmology.cosmology.Cosmology` the cosmology used to meausre the comoving distance from ``redshift`` velocity : array_like a N x 3 array holding velocity in km/s observer : array_like, optional a length 3 array holding the observer location zmax : float, optional the maximum possible redshift, should be set to a reasonably large value to avoid interpolation failure going from comoving distance to redshift frame : string ('icrs' or 'galactic') speciefies which frame the Cartesian coordinates is. Useful if you know the simulation (usually cartesian) is in galactic units but you want to convert to the icrs (ra, dec) usually used in surveys. Returns ------- ra, dec, z : dask array the right ascension (in degrees), declination (in degrees), and redshift coordinates. RA will be in the range [0,360] and DEC in the range [-90, 90] Notes ----- If velocity is provided, redshift-space distortions are added to the real-space redshift :math:`z_\mathrm{real}`, via: .. math:: z_\mathrm{redshift} = ( v_\mathrm{pec} / c ) (1 + z_\mathrm{reals}) Raises ------ TypeError If the input columns are not dask arrays """ from astropy.constants import c from scipy.interpolate import interp1d if not isinstance(pos, da.Array): pos = da.from_array(pos, chunks=100000) pos = pos - observer # RA,dec coordinates (in degrees) ra, dec = CartesianToEquatorial(pos, frame=frame) # the distance from the origin r = da.linalg.norm(pos, axis=-1) def z_from_comoving_distance(x): zgrid = numpy.logspace(-8, numpy.log10(zmax), 1024) zgrid = numpy.concatenate([[0.], zgrid]) rgrid = cosmo.comoving_distance(zgrid) return interp1d(rgrid, zgrid)(x) # invert distance - redshift relation z = r.map_blocks(z_from_comoving_distance) # add in velocity offsets? if velocity is not None: vpec = (pos * velocity).sum(axis=-1) / r z += vpec / c.to('km/s').value * (1 + z) return da.stack((ra, dec, z), axis=0)
import astropy.units as apu from astropy.constants import h, c, u import numpy as np one_arcsec = 1.0/3600.0 erg_per_eV = apu.eV.to("erg") erg_per_keV = erg_per_eV * 1.0e3 keV_per_erg = 1.0 / erg_per_keV eV_per_erg = 1.0 / erg_per_eV hc = (h*c).to("keV*angstrom").value clight = c.to("cm/s").value ckms = c.to_value("km/s") sigma_to_fwhm = 2.*np.sqrt(2.*np.log(2.)) sqrt2pi = np.sqrt(2.*np.pi) m_u = u.to("g").value elem_names = ["", "H", "He", "Li", "Be", "B", "C", "N", "O", "F", "Ne", "Na", "Mg", "Al", "Si", "P", "S", "Cl", "Ar", "K", "Ca", "Sc", "Ti", "V", "Cr", "Mn", "Fe", "Co", "Ni", "Cu", "Zn"] cosmic_elem = [1, 2, 3, 4, 5, 9, 11, 15, 17, 19, 21, 22, 23, 24, 25, 27, 29, 30] metal_elem = [6, 7, 8, 10, 12, 13, 14, 16, 18, 20, 26, 28] atomic_weights = np.array([0.0, 1.00794, 4.00262, 6.941, 9.012182, 10.811, 12.0107, 14.0067, 15.9994, 18.9984, 20.1797,
def HelioCorrect( obs, *spectra, **kwargs ): """ Perform heliocentric velocity corrects on `spectra` based on `obs`ervatory information (longitude, latitude, altitude) and the member attributes, ra (right ascension), dec (declination), and jd (julian date) from the `spectra`. """ try: # define function parameters options = Options( kwargs, { 'verbose': False # display messages, progress }) # assign parameters verbose = options('verbose') # check `obs` type if not issubclass( type(obs), Observatory): raise VelocityError('HelioCorrect() expects its first argument to ' 'be derived from the Observatory class.') elif ( not hasattr(obs, 'latitude') or not hasattr(obs,'longitude') or not hasattr(obs, 'altitude') ): raise VelocityError('HelioCorrect expects `obs`ervatory to have ' 'all three: latitude, longitude, and altitude attributes.') # check `spectra` arguments for a, spectrum in enumerate(spectra): if type(spectrum) is not Spectrum: raise VelocityError('HelioCorrect() expects all `spectrum` ' 'arguments to be of type Spectrum.') if not spectrum.ra or not spectrum.dec or not spectrum.jd: raise VelocityError('Spectrum {} lacks one or all of `ra`, ' '`dec`, and `jd`; from HelioCorrect().'.format(a)) if not hasattr(spectrum.ra, 'unit'): raise VelocityError('From HelioCorrect(), in spectrum {}, ' '`ra` doesn`t have units!'.format(a)) if not hasattr(spectrum.dec, 'unit'): raise VelocityError('From HelioCorrect(), in spectrum {}, ' '`dec` doesn`t have units!'.format(a)) if not hasattr(spectrum.jd, 'unit'): raise VelocityError('From HelioCorrect(), in spectrum {}, ' '`jd` doesn`t have units!'.format(a)) if verbose: display = Monitor() print(' Running HelioCorrect on {} spectra ...' .format(len(spectra))) for a, spectrum in enumerate(spectra): # heliocentric velocity correction in km s^-1, # the `astrolibpy...helcorr` function doesn't work with units, # so I convert to appropriate units and strip them. hcorr = helcorr( obs.longitude.to(u.degree).value, obs.latitude.to(u.degree).value, obs.altitude.to(u.meter).value, spectrum.ra.to(u.hourangle).value, spectrum.dec.to(u.degree).value, spectrum.jd.to(u.day).value )[1] * u.km / u.second # apply correction to wave vector, # del[Lambda] / Lambda = del[V] / c spectrum.wave -= spectrum.wave * hcorr / c.to(u.km / u.second) # show progress if desired if verbose: display.progress(a, len(spectra)) # finalize progress bar (erase) if verbose: display.complete() except OptionsError as err: print(' --> OptionsError:', err) raise VelocityError('Failed to perform HelioCorrect() task.') except DisplayError as err: print(' --> DisplayError:', err) raise VelocityError('Exception from Display.Monitor in HelioCorrect().')