Beispiel #1
0
def get_alms_iso(events, l_max):
    cplx_alms = np.zeros(Alm.getsize(l_max), dtype=complex)
    for l in xrange(l_max + 1):
        for m in xrange(l + 1):
            cplx_alms[Alm.getidx(l_max, l, m)] = np.mean(
                cplxYlm(l, m, events["theta"], events["phi"]))
    return cplx_alms
Beispiel #2
0
def cplx2real_alms(cplx_alms):
    """
	convert healpy's complex alms to denton's real alms
	"""
    l_max = Alm.getlmax(len(cplx_alms))
    real_alms = np.zeros((l_max + 1)**2)

    for i in xrange(len(cplx_alms)):
        l, m = Alm.getlm(l_max, i)
        if m == 0:
            real_alms[lm2i(l, m)] = cplx_alms[i].real
        else:
            real_alms[lm2i(l, m)] = np.sqrt(2) * cplx_alms[i].real
            real_alms[lm2i(l, -m)] = -(-1)**m * np.sqrt(2) * cplx_alms[i].imag
    return real_alms
Beispiel #3
0
def real2cplx_alms(real_alms):
    """
	convert denton's real alms to healpy's complex alms
	"""
    l_max = np.sqrt(len(real_alms)) - 1
    assert l_max == int(l_max)
    l_max = int(l_max)

    cplx_alms = np.zeros(Alm.getsize(l_max), dtype=complex)
    for i in xrange(len(real_alms)):
        l, m = i2lm(i)
        if m == 0:
            cplx_alms[Alm.getidx(l_max, l, m)] = real_alms[i]
        if m < 0:
            cplx_alms[Alm.getidx(
                l_max, l, abs(m))] += -(-1)**m * 1j * real_alms[i] / np.sqrt(2)
        if m > 0:
            cplx_alms[Alm.getidx(l_max, l, m)] += real_alms[i] / np.sqrt(2)
    return cplx_alms
Beispiel #4
0
def get_alms_exposure(events, l_max, ff):
    # this is the prefered way
    # 1702.07209 eq 8
    # same as Sommers
    omegas = CR.omega(events["dec"], ff)

    # check field names in events
    phi_field = "phi"
    if phi_field not in events.dtype.names:
        names = list(events.dtype.names)
        idx = names.index("RA")
        names[idx] = phi_field
        events.dtype.names = names

    exposure_alms = np.zeros(Alm.getsize(l_max), dtype=complex)
    for l in xrange(l_max + 1):
        for m in xrange(l + 1):
            cplx_alms = cplxYlm(l, m, CR.dec2theta(events["dec"]),
                                events["phi"]) / omegas
            exposure_alms[Alm.getidx(l_max, l, m)] = np.sum(cplx_alms)
    return exposure_alms / (exposure_alms[0] * np.sqrt(4 * np.pi)
                            )  # normalize the alms so that a00 = 1/sqrt(4pi)
Beispiel #5
0
def swhtWorker(idx, lProc, lMax, kRVec, kZeroBool, inputDropped, phi, theta, preFac, results, uvw):
	"""SWHT implementatino for full sky images.
	
	Based on the methodology described by Carrozi 2015
	
	
	Args:
	    idx (int): Multiprocessing ID
	    lProc (int or list-like): l Values to process (list or upto l)
	    lMax (int): Maximum overall l value (for MP reference)
	    kRVec (np.ndarray): Product of k . r for reference
	    kZeroBool (np.ndarray): Locations of r = 0 to fix issues
	    inputDropped (np.ndarray): Input correlations, named as we tend to drop the lower triangle for SWHT observations
	    phi (np.ndarray): Element of UVW plane in psh. coords
	    theta (np.ndarray): Element of UVW plane in psh. coords
	    preFac (float): Constant for output
	    results (np.ndarray): Reference expected output map shape
	    uvw (np.ndarray): Reference for shapes, can be removed if a better reference is found.
	
	Returns:
	    idx, outputHealPyMap: Multiprocessing ID, resulting healpy map
	
	"""
	
	# Multiprocessing gives a list, single process gives an int.
	if isinstance(lProc, int):
		iterL = range(lProc)
	else:
		iterL = lProc

	for counter, l in enumerate(iterL):
		print("Processing l value {0} ({1}/{2}) on Chunk {3}.".format(l, counter + 1, len(iterL), idx + 1))
		j_l = scipy.special.spherical_jn(l, kRVec) # (rLen,)
		j_l[kZeroBool] = 0. # nan otherwise
		
		lRev = (4 * np.pi * (-1j)**l) # (1,)
		visBessel = inputDropped.flatten() * np.repeat(j_l, uvw.shape[0], axis = 0) 

		# Healpy dumps m < 0, so don't both calculating them.
		for m in range(l + 1):
			y_lm_star = np.conj(scipy.special.sph_harm(m, l, phi.T.flatten(), theta.T.flatten()))# (timeSamples * nants ** 2)
			resultsIndex = almMap.getidx(lMax - 1, l, m)
			results[resultsIndex] = preFac * np.sum(visBessel * y_lm_star) / lRev

	print("Chunk {0} work completed for l values {1}".format(idx + 1, iterL))

	return idx, results
Beispiel #6
0
def fname2real_alms(fname, l_max):
    the_map = np.genfromtxt(fname)
    the_map = hp.pixelfunc.ud_grade(the_map, 128, pess=True, power=1.)
    the_map /= the_map.sum()
    the_map = hp.smoothing(the_map, sigma=np.deg2rad(2), verbose=False)
    the_map -= 1. * np.min(the_map)
    the_map /= the_map.sum()

    #	the_map[hp.pixelfunc.ang2pix(128, np.pi/2 - 0.222, 3.26)] += 0.1 # virgo cluster in equatorial coordinates
    #	the_map[hp.pixelfunc.ang2pix(128, 1.23, 5.4)] += 0.1 # cen a in galactic coordinates

    cplx_alms = hp.sphtfunc.map2alm(the_map, l_max)

    cplx_alms /= cplx_alms[Alm.getidx(l_max, 0, 0)]
    cplx_alms /= np.sqrt(4 * np.pi)

    #	hp.visufunc.mollview(hp.sphtfunc.alm2map(cplx_alms, 128))
    #	plt.show()

    real_alms = cplx2real_alms(cplx_alms)
    return real_alms
Beispiel #7
0
def swhtProcessCorrelations(corrDict, options, processDict, xyz, stationLocation, metaDataArr, frequency, labelOptions):
	"""Handler for converting an observation to a full sky map through the spherical wave harmonic transform.
	
	Args:
	    corrDict (dict): Dictionary of elements in the format 'CORRELATION': (nAnts x nAnts x nSamples array of correlations)
	    options (dict): Standard options dictionary
	    processDict (dict): Dictionary of correlation times ('XX', 'XY'...) and values of whether or not to process them
	    xyz (np.ndarray): Antenna locations nAnts x 3
	    stationLocation (list): Station location in (lon (deg), lat (deg) and elevation (meters))
	    metaDataArr (list): List of dictionaries formatted as strings from the input dataset attributes
	    frequency (float): Observing frequency (in Hz)
	    labelOptions (list): List of useful values for plotting
	
	Returns:
	    dict: Dictionary of processed outputs ('XX', 'I',....)
	"""

	# Borrowed from Griffith's method as an optomisisation, cuts processed values by a factor of 2.
	# Should look into implementing in the FT method? After all, we can recreate the lost correlations
	#	by getting their complex conjugate.
	xyz = xyz - xyz.transpose(1,0,2)
	xyzTriu = np.triu_indices(xyz.shape[0])
	xyz = xyz[xyzTriu]

	# Extract the integration midpoints from the metadata array.
	dateArr = [dateTime.split("'integrationMidpoint': '")[1].split("', ")[0] for dateTime in metaDataArr]

	# We need to use two sets of locations: The true location for the zenith ponting and an arbitrary lon/lat for the uvw plane.
	trueTelescopeLoc = astropy.coordinates.EarthLocation( lat = stationLocation[1] * u.deg, lon = stationLocation[0] * u.deg, height = stationLocation[2] * u.m )
	telescopeLoc = astropy.coordinates.EarthLocation(lat = 0 * u.deg, lon = -90 * u.deg, height = 0 * u.m) # Not sure why, used by Griffin as a baseline for calculations and it works.
	
	# Initialise the UVW array
	uvw = np.zeros([0] + list(xyz.shape))

	zenithArr = []
	timeArr = []
	for timestamp in dateArr:
		# Get two sets of times: One for getting the zenith, the other for plotting the observation title times in local time
		obsTime = astropy.time.Time(timestamp, scale = 'utc', location = telescopeLoc)
		utcObsTime = astropy.time.Time(timestamp, scale = 'utc')


		altAz = astropy.coordinates.AltAz(az = 0. * u.deg, alt = 90. * u.deg, location = trueTelescopeLoc, obstime = utcObsTime)
		zenith = altAz.transform_to(astropy.coordinates.Galactic)
		sidAngle = float(obsTime.sidereal_time('mean').radian)

		zenithArr.append(zenith)
		timeArr.append(obsTime)

		# Rotate the baselines to generate a uvw-like plane (still needs to be divded by wavelength)
		sinSA = np.sin(sidAngle)
		cosSA = np.cos(sidAngle)
		rotationMatrix = np.array([[sinSA, cosSA, 0.],
						[-1. * cosSA, sinSA, 0.],
						[0., 0., 1.]])

		uvw = np.concatenate([uvw, np.dot(rotationMatrix, xyz.T).T[np.newaxis]], axis = 0)
		print('UVW Successfully generated for timestamp {0} with zenith at {1:.2f}, {2:.2f} (GAL)'.format(timestamp[:-5], zenith.l.deg, zenith.b.deg))

	# Convert the UVW coordinates to r, theta, phi (referred to as rtp) for spherical coordinates
	r, theta, phi = cartToSpherical(uvw)
	r = r[0] # All samples have the same r values

	# Generate the k-vector to normalise the r elements
	k_0 = 2. * np.pi * frequency / scipy.constants.c
	preFac = 2. * (k_0 ** 2) / np.pi
	kRVec = k_0 * r

	# Get the maximum l value from the options dictionary and prepare the result arrays
	lMax = options['imagingOptions']['swhtlMax']
	arraySize = almMap.getsize(lMax - 1)
	results = np.zeros(arraySize, dtype = complex)
	maskVar = np.ones(healpy.nside2npix(max(64, 2 * lMax)), dtype=np.bool)

	# Account for autocorrelations (remove excess np.nans from results as r = 0 causes issues to say the least)
	kZeroBool = kRVec == 0.

	# Generate the mask based on the pointings: pixels are masked if they are never within 90 degrees of a zenith pointing
	if options['imagingOptions']['maskOutput']:
		pixelTheta, pixelPhi = healpy.pix2ang(max(64, 2 * lMax), np.arange(healpy.nside2npix(max(64, 2 * lMax))), lonlat = True)
	
		# F**k everyhting about this coordinate system...
		# For further context: standard latitutde and longitude, healpy and galactic coordinates all have different
		# 	ways of wrapping angles. I created functions to map between the different coordinate systems
		pixelTheta = usefulFunctions.lonToHealpyLon(pixelTheta, rads = False)
	
	
		galCoordLon = np.array([skyCoord.l.deg for skyCoord in zenithArr])
		galCoordLat = np.array([skyCoord.b.deg for skyCoord in zenithArr])

		# Convert to radians for easier angular maths
		galCoordSampled = np.deg2rad(np.vstack([galCoordLon, galCoordLat])[:, np.newaxis])
		pixelCoord = np.deg2rad(np.vstack([pixelTheta, pixelPhi])[..., np.newaxis])
		
		# Check where the angular difference is less than 70 (ie., 35 degrees in any direction., save as used for all sky maps)
		# Not sure about where the factor of 2 is coming from, but I can visually confirm that this works.
		deltaLoc = greatCircleAngularDiff(galCoordSampled, pixelCoord)
		maskVar = np.logical_not(np.any(np.rad2deg(deltaLoc) < 35, axis = 1))


	procDict = {}
	# Create a rotate to convert from arbitrary healpy logic to cartesian-galactic coordinates
	galRotator = healpy.rotator.Rotator(coord = ['C','G'])
	for key, value in processDict.items():
		# processDict is a dictionary of keys/values of correlations and whether or not they are needed for the output images
		# So if we were imaging the Stokes I, we would have {'XX': True, 'YY': True, 'XY': False,...}, making it easy to only processed
		# 	the required correlations.
		if value:
			# Drop the autocorrelations; we have to remove the r = 0 elements to get rid of inf/nans
			corrDict[key][np.eye(corrDict[key].shape[0], dtype = bool)] = 0.
			inputDropped = corrDict[key][xyzTriu]

			# Multithreaded, might not be more efficient if I implement Schaeffer 2015
			if options['multiprocessing']:
				processCount = int(mp.cpu_count()-1)
				mpPool = mp.Pool(processes = processCount)

				fragments = [np.arange(lMax)[i::processCount] for i in range(processCount)]
				callBacks = [mpPool.apply_async(swhtWorker.swhtWorker, args = ([idx, fragmentChunk, lMax, kRVec, kZeroBool, inputDropped, phi, theta, preFac, results, uvw])) for idx, fragmentChunk in enumerate(fragments)]

				mpPool.close()
				mpPool.join()

				for asyncResult in callBacks:
					idx, resultsVar = asyncResult.get()
					results[resultsVar != 0.] = resultsVar[resultsVar != 0.]

				allSkyImageAlm = results

			else:
				allSkyImageAlm = swhtWorker.swhtWorker(0, lMax, lMax, kRVec, kZeroBool, inputDropped, phi, theta, preFac, results, uvw)[1]

			# Convert the results to a healpy map
			procDict['{0}-alm'.format(key)] = allSkyImageAlm
			hpMap = healpy.alm2map(allSkyImageAlm, max(64, 2 * lMax)).astype(complex)

			# Clone + generate imaginary map as well (as healpy seems to hate imaginary values results)
			# Not sure if this is the right way to go about doing things, but it seems to function at least.
			# Can't find a Stokes-V map of the sky to compare.
			clone = allSkyImageAlm.copy()
			clone.real = clone.imag
			clone.imag = np.zeros_like(allSkyImageAlm)
			hpMap.imag = healpy.alm2map(clone, max(64, 2 * lMax))

			# Rotate to the right coordinate system
			hpMap = galRotator.rotate_map(hpMap)

			# Store the results]
			print("{0} Polarisation Processed.".format(key))
			procDict[key] = hpMap

	# Process each of the requested outputs
	for method in options['imagingOptions']['correlationTypes']:
		if len(method) == 2:
			allSkyImage = procDict[method].real
			allSkySave = procDict[method]
		elif 'I' is method:
			allSkySave = (procDict['XX'] + procDict['YY'])
			allSkyImage = allSkySave.real
		elif 'Q' is method:
			allSkySave = (procDict['XX'] - procDict['YY'])
			allSkyImage = allSkySave.real
		elif 'U' is method:
			allSkySave = (procDict['XY'] + procDict['YX'])
			allSkyImage = allSkySave.real
		elif 'V' is method:
			# Healpy doesn't like dealing with imaginary values, take the 'V' output with a mountain of salt.
			allSkySave  = (procDict['YX'] - procDict['XY'])
			allSkyImage = allSkySave.imag
		else:
			print('How did we get this far with a broken method \'{0}\'? Processing the first value in procDict so it hasn\'t gone to waste...'.format(method))
			allSkyImage = procDict.values()[0]
			method = procDict.keys()[0]

		# Mask off values if needed. 
		# For note, doing it before this point breaks stuff as the masked arrays fail to mask on simple maths (values on the other of 1e40 anyone?)
		allSkyImage = healpy.ma(allSkyImage)
		allSkySave = healpy.ma(allSkySave)

		allSkyImage.mask = maskVar
		allSkySave.mask = maskVar

		# Don't save the result out of we are doing a pure-correlation map
		procDict[method] = allSkySave

		if options['plottingOptions']['plotImages']:
			swhtPlot(allSkyImage, options, labelOptions + [method, 0], healpy.newvisufunc.mollview, [timeArr, trueTelescopeLoc], zenithArr, metaDataArr)

	# Save a copy of the mask encase it gets mangled again.
	procDict['mask'] = maskVar

	return procDict
Beispiel #8
0
def get_alms_iso_exact(l_max):
    assert l_max == int(l_max)
    return np.zeros(Alm.getsize(l_max), dtype=complex)
Beispiel #9
0
 def lmax(self, l):
     self._almsize = Alm.getsize(l - 1)
     self._hpsize = max(128, 2 * l)  #max(64, 2 * l)
     self._max = l
     return