def light_travel_time_to_detector(self, det): """Return the light travel time from this detector Parameters ---------- detector: Detector The other detector to determine the light travel time to. Returns ------- time: float The light travel time in seconds """ return lal.LightTravelTime(self.frDetector, det.frDetector) * 1e-9
def MaxTimeDelayLine(ifos, ra, dec, gpstime=None, n=3): """ Return the n-point SkyPositionTable describing the line perpendicular to the line of constant time delay through the given ra and dec for the 2-tuple ifos. """ # construct sky point p = SkyPosition() p.longitude = ra p.latitude = dec p.system = 'equatorial' # remove duplicate site references ifos = parse_sites(ifos) assert len(ifos) == 2, "More than two sites in given list of detectors" # get light travel time ltt = lal.LightTravelTime(ifos[0], ifos[1]) # get number of points dt = ltt / n return TwoSiteSkyGrid(ifos, gpstime, dt=dt, point=p, sky='full')
def ThreeSiteSkyGrid(ifos, gpstime, dt=0.0005, tiling='square', sky='half'): """ Generates a SkyPositionTable for a three-site all-sky grid, covering either a hemisphere (sky='half') or full sphere (sky='full'), using either 'square' or 'hexagonal tiling. """ # remove duplicate site references pop = [] for i, ifo in enumerate(ifos): if i == 0: continue site = ifo[0] if site in [x[0] for x in ifos[0:i]]: sys.stderr.write("Duplicate site reference, ignoring %s.\n" % ifo) pop.append(i) for p in pop[::-1]: ifos.pop(p) assert len(ifos) == 3 detectors = [] T = [] baseline = [] # load detectors for i, ifo in enumerate(ifos): detectors.append(cached_detector.get(prefix_to_name[ifo])) # get light travel time and baseline for other detectors to first if i >= 1: T.append(lal.LightTravelTime(detectors[0], detectors[i])) baseline.append(detectors[i].location - detectors[0].location) baseline[i - 1] /= np.linalg.norm(baseline[i - 1]) # get angle between baselines angle = np.arccos(np.dot(baseline[0], baseline[1])) # # construct tiling vectors # tiling = tiling.lower() t = np.zeros(len(baseline)) tdgrid = [] # square grid dx = np.array([1, 0]) dy = np.array([0, 1]) nx = int(np.floor(T[0] / dt)) ny = int(np.floor(T[1] / dt)) # hexagonal grid if tiling == 'square': dm = dx dn = dy nm = nx nn = ny x = np.linspace(-nx, nx, 2 * nx + 1) y = np.linspace(-ny, ny, 2 * ny + 1) grid = np.array([[i, j] for i in x for j in y]) # hexagonal grid elif re.match('hex', tiling): dm = (2 * dx + dy) dn = (-dx + dy) dx = dm - dn # tile grid so that origin gets tiled grid = [] orig = np.array([0, 0]) # find bottom left point on grid while orig[1] >= -ny: orig -= dn # loop over y for y in xrange(-ny, ny + 1): orig[0] = orig[0] % dx[0] # work out minimal x value minx = -nx while minx % 3 != orig[0]: minx += 1 # tile x x = np.arange(minx, nx + 1, dx[0]) # append to grid grid.extend([[i, y] for i in x]) orig += dn orig[0] = orig[0] % dx[0] grid = np.asarray(grid) # # Following Rabaste, Chassande-Motin, Piran (2009), construct an ellipse # of physical values in 2D time-delay space for 3 detectors # # # (theta, phi) coordinate system is as follows: # detector 1 is origin # z-axis joins positively to detector 2 # x-axis is orthogonal to z-axis in plane joining D1, D2, and D3 # y-axis forms a right-handed coordinate system # # so need to rotate from Rabaste network coordinates into # earth-fixed coordinates at the end # set z-axis in Rabaste frame zaxis = baseline[0] # work out y-axis in Rabaste frame yaxis = np.cross(zaxis, baseline[1]) yaxis /= np.linalg.norm(yaxis) # work out x-axis in Rabaste frame xaxis = np.cross(yaxis, zaxis) xaxis /= np.linalg.norm(xaxis) # work out lines of nodes north = np.array([0, 0, 1]) lineofnodes = np.cross(baseline[0], north) lineofnodes /= np.linalg.norm(lineofnodes) # work out Euler angles alpha = np.arccos(np.dot(xaxis, lineofnodes)) beta = np.arccos(np.dot(baseline[0], north)) gamma = np.arccos(np.dot(lineofnodes, [1, 0, 0])) # construct rotation R = _rotation_euler(alpha, beta, gamma) # # construct sky position table # l = SkyPositionTable() # loop over time-delay between D1 and D2 k = 0 for i in grid: t = dt * i # construct coefficients of elliptical equation in quadratic form A = -T[1] / T[0] * t[0] * np.cos(angle) B = T[1]**2 * ((t[0] / T[0])**2 - np.sin(angle)**2) # test condition for inside ellipse and place point condition = t[1]**2 + 2 * A * t[1] + B if condition <= 0: ntheta = np.arccos(-t[0] / T[0]) nphi = np.arccos(-(T[0]*t[1]-T[1]*t[0]*np.cos(angle))/\ (T[1]*np.sqrt(T[0]**2-t[0]**2)*np.sin(angle))) p = SkyPosition() p.system = 'geographic' p.longitude = nphi p.latitude = lal.PI_2 - ntheta p.probability = None p.solid_angle = None p.normalize() p = p.rotate(R) p = GeographicToEquatorial(p, lal.LIGOTimeGPS(gpstime)) l.append(p) if sky == 'full': p2 = SkyPosition() p2.longitude = p.longitude p2.latitude = p.latitude + lal.PI p2.system = 'equatorial' p2.normalize() l.append(p2) return l
def TwoSiteSkyGrid(ifos, gpstime, dt=0.0005, sky='half', point=None): """ Generates a SkyPositionTable for a two-site all-sky grid, covering either a hemisphere (sky='half') or full sphere (sky='full'). The grid can be forced to pass through the given SkyPosition point if required. """ # remove duplicate site references ifos = parse_sites(ifos) assert len(ifos) == 2, "More than two sites in given list of detectors" # get detectors detectors = [cached_detector.get(prefix_to_name[ifo])\ for ifo in ifos] # get light travel time ltt = lal.LightTravelTime(detectors[0], detectors[1]) # get number of points max = int(np.floor(ltt / dt)) # get baseline baseline = detectors[1].location - detectors[0].location baseline /= np.linalg.norm(baseline) # # construct rotation # # xaxis points overhead of detector 1 or given point # zaxis is baseline, or something else if point: xaxis = SphericalToCartesian(point) xaxis /= np.linalg.norm(xaxis) zaxis = np.cross(xaxis, baseline) zaxis /= np.linalg.norm(zaxis) else: xaxis = detectors[0].location xaxis /= np.linalg.norm(xaxis) zaxis = baseline yaxis = np.cross(zaxis, xaxis) yaxis /= np.linalg.norm(yaxis) yaxis = np.cross(xaxis, zaxis) yaxis /= np.linalg.norm(yaxis) # construct Euler rotation lineofnodes = np.cross([0, 0, 1], zaxis) lineofnodes /= np.linalg.norm(lineofnodes) # work out Euler angles alpha = np.arccos(np.dot([1, 0, 0], lineofnodes)) beta = np.arccos(np.dot([0, 0, 1], zaxis)) gamma = np.arccos(np.dot(lineofnodes, xaxis)) # get rotation R = _rotation_euler(alpha, beta, gamma) # construct sky table l = SkyPositionTable() if sky == 'half': longs = [0] elif sky == 'full': longs = [0, lal.PI] else: raise AttributeError("Sky type \"%s\" not recognised, please use " "'half' or 'full'" % sky) for long in longs: for i in xrange(-max, max + 1): # get time-delay t = i * dt # if time-delay greater that light travel time, skip if abs(t) >= ltt: continue # construct object e = SkyPosition() e.system = 'geographic' # project time-delay onto prime meridian e.longitude = long e.latitude = lal.PI_2 - np.arccos(-t / ltt) e.probability = None e.solid_angle = None e.normalize() e = e.rotate(R) e = GeographicToEquatorial(e, lal.LIGOTimeGPS(gpstime)) if e not in l: l.append(e) return l
def SkyPatch(ifos, ra, dec, radius, gpstime, dt=0.0005, sigma=1.65,\ grid='circular'): """ Returns a SkyPositionTable of circular rings emanating from a given central ra and dec. out to the maximal radius. """ # form centre point p = SkyPosition() p.longitude = ra p.latitude = dec # get detectors ifos.sort() detectors = [] for ifo in ifos: if ifo not in prefix_to_name.keys(): raise ValueError("Interferometer '%s' not recognised." % ifo) detectors.append(cached_detector.get(\ prefix_to_name[ifo])) alpha = 0 for i in xrange(len(ifos)): for j in xrange(i + 1, len(ifos)): # get opening angle baseline = lal.ArrivalTimeDiff(detectors[i].location,\ detectors[j].location,\ ra, dec, lal.LIGOTimeGPS(gpstime)) ltt = float( lal.LIGOTimeGPS( 0, lal.LightTravelTime(detectors[i], detectors[j]))) angle = np.arccos(baseline / ltt) # get window lmin = angle - radius lmax = angle + radius if lmin < lal.PI_2 and lmax > lal.PI_2: l = lal.PI_2 elif np.fabs(lal.PI_2-lmin) <\ np.fabs(lal.PI_2-lmax): l = lmin else: l = lmax # get alpha dalpha = ltt * np.sin(l) if dalpha > alpha: alpha = dalpha # get angular resolution angRes = 2 * dt / alpha # generate grid if grid.lower() == 'circular': grid = CircularGrid(angRes, radius) else: raise RuntimeError("Must use grid='circular', others not coded yet") # # Need to rotate grid onto (ra, dec) # # calculate opening angle from north pole north = [0, 0, 1] angle = np.arccos(np.dot(north, SphericalToCartesian(p))) #angle = north.opening_angle(p) # get rotation axis axis = np.cross(north, SphericalToCartesian(p)) axis = axis / np.linalg.norm(axis) # rotate grid R = _rotation(axis, angle) grid = grid.rotate(R) # # calculate probability density function # # assume Fisher distribution in angle from centre kappa = (0.66 * radius / sigma)**(-2) # compute probability for p in grid: overlap = np.cos(p.opening_angle(grid[0])) p.probability = np.exp(kappa * (overlap - 1)) probs = [p.probability for p in grid] for p in grid: p.probability = p.probability / max(probs) return grid
def test_light_time(self): for d1 in self.d: for d2 in self.d: t1 = lal.LightTravelTime(d1.lal(), d2.lal()) * 1e-9 t2 = d1.light_travel_time_to_detector(d2) self.assertAlmostEqual(t1, t2, 7)