def transform_basis(nside, jones, z0_cza, R_z0): """ At zenith in the local frame the 'x' feed is aligned with 'theta' and the 'y' feed is aligned with 'phi' """ npix = hp.nside2npix(nside) hpxidx = np.arange(npix) cza, ra = hp.pix2ang(nside, hpxidx) # Rb is the rotation relating the E-field basis coordinate frame to the local horizontal zenith. # (specific to this instrument response simulation data) Rb = np.array([[0, 0, -1], [0, -1, 0], [-1, 0, 0]]) fR = np.einsum('ab,bc->ac', Rb, R_z0) # matrix product of two rotations tb, pb = irf.rotate_sphr_coords(fR, cza, ra) cza_v = irf.t_hat_cart(cza, ra) ra_v = irf.p_hat_cart(cza, ra) tb_v = irf.t_hat_cart(tb, pb) fRcza_v = np.einsum('ab...,b...->a...', fR, cza_v) fRra_v = np.einsum('ab...,b...->a...', fR, ra_v) cosX = np.einsum('a...,a...', fRcza_v, tb_v) sinX = np.einsum('a...,a...', fRra_v, tb_v) basis_rot = np.array([[cosX, sinX], [-sinX, cosX]]) basis_rot = np.transpose(basis_rot, (2, 0, 1)) return irnf.M(jones, basis_rot)
def transform_basis(nside, jones, z0_cza, R_z0): npix = hp.nside2npix(nside) hpxidx = np.arange(npix) cza, ra = hp.pix2ang(nside, hpxidx) fR = R_z0 tb, pb = irf.rotate_sphr_coords(fR, cza, ra) cza_v = irf.t_hat_cart(cza, ra) ra_v = irf.p_hat_cart(cza, ra) tb_v = irf.t_hat_cart(tb, pb) fRcza_v = np.einsum('ab...,b...->a...', fR, cza_v) fRra_v = np.einsum('ab...,b...->a...', fR, ra_v) cosX = np.einsum('a...,a...', fRcza_v, tb_v) sinX = np.einsum('a...,a...', fRra_v, tb_v) basis_rot = np.array([[cosX, -sinX],[sinX, cosX]]) basis_rot = np.transpose(basis_rot,(2,0,1)) # return np.einsum('...ab,...bc->...ac', jones, basis_rot) return irnf.M(jones, basis_rot)
def transform_basis(nside, jones, z0_cza, R_z0): npix = hp.nside2npix(nside) hpxidx = np.arange(npix) cza, ra = hp.pix2ang(nside, hpxidx) fR = R_z0 tb, pb = irf.rotate_sphr_coords(fR, cza, ra) cza_v = irf.t_hat_cart(cza, ra) ra_v = irf.p_hat_cart(cza, ra) tb_v = irf.t_hat_cart(tb, pb) fRcza_v = np.einsum('ab...,b...->a...', fR, cza_v) fRra_v = np.einsum('ab...,b...->a...', fR, ra_v) cosX = np.einsum('a...,a...', fRcza_v, tb_v) sinX = np.einsum('a...,a...', fRra_v, tb_v) basis_rot = np.array([[cosX, -sinX], [sinX, cosX]]) basis_rot = np.transpose(basis_rot, (2, 0, 1)) # return np.einsum('...ab,...bc->...ac', jones, basis_rot) return irnf.M(jones, basis_rot)
def horizon_mask(jones, z0_cza): npix = jones.shape[0] nside = hp.npix2nside(npix) hpxidx = np.arange(npix) cza, ra = hp.pix2ang(nside, hpxidx) if z0_cza == 0.: tb, pb = cza, ra else: z0 = irf.r_hat_cart(z0_cza, 0.) RotAxis = np.cross(z0, np.array([0,0,1.])) RotAxis /= np.sqrt(np.dot(RotAxis,RotAxis)) RotAngle = np.arccos(np.dot(z0, [0,0,1.])) R_z0 = irf.rotation_matrix(RotAxis, RotAngle) tb, pb = irf.rotate_sphr_coords(R_z0, cza, ra) hm = np.zeros((npix,2,2)) hm[np.where(tb < np.pi/2.)] = 1. return hm
def horizon_mask(jones, z0_cza): npix = jones.shape[0] nside = hp.npix2nside(npix) hpxidx = np.arange(npix) cza, ra = hp.pix2ang(nside, hpxidx) if z0_cza == 0.: tb, pb = cza, ra else: z0 = irf.r_hat_cart(z0_cza, 0.) RotAxis = np.cross(z0, np.array([0, 0, 1.])) RotAxis /= np.sqrt(np.dot(RotAxis, RotAxis)) RotAngle = np.arccos(np.dot(z0, [0, 0, 1.])) R_z0 = irf.rotation_matrix(RotAxis, RotAngle) tb, pb = irf.rotate_sphr_coords(R_z0, cza, ra) hm = np.zeros((npix, 2, 2)) hm[np.where(tb < np.pi / 2.)] = 1. return hm
def transform_basis(nside, jones, z0_cza, R_z0): """ At zenith in the local frame the 'x' feed is aligned with 'theta' and the 'y' feed is aligned with 'phi' """ npix = hp.nside2npix(nside) hpxidx = np.arange(npix) cza, ra = hp.pix2ang(nside, hpxidx) # Rb is the rotation relating the E-field basis coordinate frame to the local horizontal zenith. # (specific to this instrument response simulation data) Rb = np.array([ [0,0,-1], [0,-1,0], [-1,0,0] ]) fR = np.einsum('ab,bc->ac', Rb, R_z0) # matrix product of two rotations tb, pb = irf.rotate_sphr_coords(fR, cza, ra) cza_v = irf.t_hat_cart(cza, ra) ra_v = irf.p_hat_cart(cza, ra) tb_v = irf.t_hat_cart(tb, pb) fRcza_v = np.einsum('ab...,b...->a...', fR, cza_v) fRra_v = np.einsum('ab...,b...->a...', fR, ra_v) cosX = np.einsum('a...,a...', fRcza_v, tb_v) sinX = np.einsum('a...,a...', fRra_v, tb_v) basis_rot = np.array([[cosX, sinX],[-sinX, cosX]]) basis_rot = np.transpose(basis_rot,(2,0,1)) return irnf.M(jones, basis_rot)
def instrument_setup(z0_cza, freqs): """ This is the CST simulation using the efield basis of z' = -x, y' = -y, x' = -z frequencies are every 10MHz, from 100-200 Each file contains 8 columns which are ordered as: (Re(xt),Re(xp),Re(yt),Re(yp),Im(xt),Im(xp),Im(yt),Im(yp)). Each column is a healpix map with resolution nside = 2**8 """ nu0 = str(int(p.nu_axis[0] / 1e6)) nuf = str(int(p.nu_axis[-1] / 1e6)) band_str = nu0 + "-" + nuf # restore_name = p.interp_type + "_" + "band_" + band_str + "mhz_nfreq" + str(p.nfreq)+ "_nside" + str(p.nside) + ".npy" # # if os.path.exists('jones_save/' + restore_name) == True: # return np.load('jones_save/' + restore_name) # local_jones0_file = 'local_jones0/nside' + str( p.nside) + '_band' + band_str + '_Jdata.npy' if os.path.exists(local_jones0_file) == True: return np.load(local_jones0_file) fbase = '/data4/paper/zionos/HERA_jones_data/HERA_Jones_healpix_' # fbase = '/home/zmart/radcos/polskysim/IonRIME/HERA_jones_data/HERA_Jones_healpix_' nside_in = 2**8 fnames = [fbase + str(int(f / 1e6)) + 'MHz.txt' for f in freqs] nfreq_nodes = len(freqs) npix = hp.nside2npix(nside_in) hpxidx = np.arange(npix) cza, ra = hp.pix2ang(nside_in, hpxidx) z0 = irf.r_hat_cart(z0_cza, 0.) RotAxis = np.cross(z0, np.array([0, 0, 1.])) RotAxis /= np.sqrt(np.dot(RotAxis, RotAxis)) RotAngle = np.arccos(np.dot(z0, [0, 0, 1.])) R_z0 = irf.rotation_matrix(RotAxis, RotAngle) t0, p0 = irf.rotate_sphr_coords(R_z0, cza, ra) hm = np.zeros(npix) hm[np.where(cza < (np.pi / 2. + np.pi / 20.) )] = 1 # Horizon mask; is 0 below the local horizon. # added some padding. Idea being to allow for some interpolation near the horizon. Questionable. npix_out = hp.nside2npix(p.nside) Jdata = np.zeros((nfreq_nodes, npix_out, 2, 2), dtype='complex128') for i, f in enumerate(fnames): J_f = np.loadtxt(f) # J_f.shape = (npix_in, 8) J_f = J_f * np.tile(hm, 8).reshape(8, npix).transpose( 1, 0) # Apply horizon mask # Could future "rotation" of these zeroed-maps have small errors at the # edges of the horizon? due to the way healpy interpolates. # Unlikely to be important. # Comment update: Yep, it turns out this happens, BUT it is approximately # power-preserving. The pixels at the edges of the rotated mask are not # identically 1, but the sum over the mask is maintained to about a part # in 1e-5 # Perform a scalar rotation of each component so that the instrument's boresight # is pointed toward (z0_cza, 0), the location of the instrument on the # earth in the Current-Epoch-RA/Dec coordinate frame. J_f = irf.rotate_jones(J_f, R_z0, multiway=False) if p.nside != nside_in: # Change the map resolution as needed. #d = lambda m: hp.ud_grade(m, nside=p.nside, power=-2.) # I think these two ended up being (roughly) the same? # The apparent normalization problem was really becuase of an freq. interpolation problem. # irf.harmonic_ud_grade is probably better for increasing resolution, but hp.ud_grade is # faster because it's just averaging/tiling instead of doing SHT's d = lambda m: irf.harmonic_ud_grade(m, nside_in, p.nside) J_f = (np.asarray(map(d, J_f.T))).T # The inner transpose is so that correct dimension is map()'ed over, # and then the outer transpose returns the array to its original shape. J_f = irf.inverse_flatten_jones( J_f) # Change shape to (nfreq,npix,2,2), complex-valued J_f = transform_basis( p.nside, J_f, z0_cza, R_z0 ) # right-multiply by the basis transformation matrix from RA/CZA to the Local CST basis. # Note that CZA = pi/2 - Dec! So this is not quite the RA/Dec basis. But the difference # in the Stoke parameters between the two is only U -> -U Jdata[i, :, :, :] = J_f print i # If the model at the current nside hasn't been generated before, save it for future reuse. if os.path.exists(local_jones0_file) == False: np.save(local_jones0_file, Jdata) return Jdata
def make_jones(freq): if freq in range(90, 221): pass else: raise ValueError('Frequency is not available.') nside = 512 # make this as large as possible to minimize singularity effects at zenith ## nside 512 seems to work well enough using the "neighbours of neighbours" patch ## of the zenith singularity in the ra/cza basis. npix = hp.nside2npix(nside) hpxidx = np.arange(npix) t, p = hp.pix2ang(nside, hpxidx) g1 = ecomp(csvname(freq, 'G', 'X'), csvname(freq, 'P', 'X')) g2 = ecomp(csvname(freq, 'G', 'Y'), csvname(freq, 'P', 'Y')) I = (abs(g1)**2. + abs(g2)**2.) norm = np.sqrt(np.amax(I, axis=0)) # g1 /= norm # g2 /= norm rhm = irf.rotate_healpix_map Rb = np.array([[0, 0, -1], [0, -1, 0], [-1, 0, 0]]) Et_b = udgrade(g1.real, nside) + 1j * udgrade(g1.imag, nside) Ep_b = udgrade(g2.real, nside) + 1j * udgrade(g2.imag, nside) tb, pb = irf.rotate_sphr_coords(Rb, t, p) tb_v = irf.t_hat_cart(tb, pb) pb_v = irf.p_hat_cart(tb, pb) t_v = irf.t_hat_cart(t, p) p_v = irf.p_hat_cart(t, p) Rb_tb_v = np.einsum('ab...,b...->a...', Rb, tb_v) Rb_pb_v = np.einsum('ab...,b...->a...', Rb, pb_v) cosX = np.einsum('a...,a...', Rb_tb_v, t_v) sinX = np.einsum('a...,a...', Rb_pb_v, t_v) Et = Et_b * cosX + Ep_b * sinX Ep = -Et_b * sinX + Ep_b * cosX Ext = Et Exp = Ep ## This assumes that Et and Ep are the components of a dipole oriented ## along the X axis, and we want to obtain the components of the same ## dipole if it was oriented along Y. ## In the current basis, this is done by a scalar rotation of the theta and phi ## components by 90 degrees about the Z axis. Eyt = arm(Et.real) + 1j * arm(Et.imag) Eyp = arm(Ep.real) + 1j * arm(Ep.imag) jones_c = np.array([[Ext, Exp], [Eyt, Eyp]]).transpose(2, 0, 1) # jones_a = np.array([[rhm(Ext,Rb), rhm(Exp,Rb)],[rhm(Eyt,Rb),rhm(Eyp,Rb)]]).transpose(2,0,1) # # basis_rot = np.array([[cosX,-sinX],[sinX,cosX]]).transpose(2,0,1) # # jones_b = np.einsum('...ab,...bc->...ac', jones_a, basis_rot) # # Ext_b, Exp_b, Eyt_b, Eyp_b = [rhm(jones_b[:,i,j],Rb) for i in range(2) for j in range(2)] # # jones_c = np.array([[Ext_b,Exp_b],[Eyt_b,Eyp_b]]).transpose(2,0,1) return jones_c
def instrument_setup(z0_cza, freqs): """ This is the CST simulation using the efield basis of z' = -x, y' = -y, x' = -z frequencies are every 10MHz, from 100-200 Each file contains 8 columns which are ordered as: (Re(xt),Re(xp),Re(yt),Re(yp),Im(xt),Im(xp),Im(yt),Im(yp)). Each column is a healpix map with resolution nside = 2**8 """ nu0 = str(int(p.nu_axis[0] / 1e6)) nuf = str(int(p.nu_axis[-1] / 1e6)) band_str = nu0 + "-" + nuf # restore_name = p.interp_type + "_" + "band_" + band_str + "mhz_nfreq" + str(p.nfreq)+ "_nside" + str(p.nside) + ".npy" # # if os.path.exists('jones_save/' + restore_name) == True: # return np.load('jones_save/' + restore_name) # local_jones0_file = 'local_jones0/nside' + str(p.nside) + '_band' + band_str + '_Jdata.npy' if os.path.exists(local_jones0_file) == True: return np.load(local_jones0_file) fbase = '/data4/paper/zionos/HERA_jones_data/HERA_Jones_healpix_' # fbase = '/home/zmart/radcos/polskysim/IonRIME/HERA_jones_data/HERA_Jones_healpix_' nside_in = 2**8 fnames = [fbase + str(int(f / 1e6)) + 'MHz.txt' for f in freqs] nfreq_nodes = len(freqs) npix = hp.nside2npix(nside_in) hpxidx = np.arange(npix) cza, ra = hp.pix2ang(nside_in, hpxidx) z0 = irf.r_hat_cart(z0_cza, 0.) RotAxis = np.cross(z0, np.array([0,0,1.])) RotAxis /= np.sqrt(np.dot(RotAxis,RotAxis)) RotAngle = np.arccos(np.dot(z0, [0,0,1.])) R_z0 = irf.rotation_matrix(RotAxis, RotAngle) t0, p0 = irf.rotate_sphr_coords(R_z0, cza, ra) hm = np.zeros(npix) hm[np.where(cza < (np.pi / 2. + np.pi / 20.))] = 1 # Horizon mask; is 0 below the local horizon. # added some padding. Idea being to allow for some interpolation near the horizon. Questionable. npix_out = hp.nside2npix(p.nside) Jdata = np.zeros((nfreq_nodes,npix_out,2,2),dtype='complex128') for i,f in enumerate(fnames): J_f = np.loadtxt(f) # J_f.shape = (npix_in, 8) J_f = J_f * np.tile(hm, 8).reshape(8, npix).transpose(1,0) # Apply horizon mask # Could future "rotation" of these zeroed-maps have small errors at the # edges of the horizon? due to the way healpy interpolates. # Unlikely to be important. # Comment update: Yep, it turns out this happens, BUT it is approximately # power-preserving. The pixels at the edges of the rotated mask are not # identically 1, but the sum over the mask is maintained to about a part # in 1e-5 # Perform a scalar rotation of each component so that the instrument's boresight # is pointed toward (z0_cza, 0), the location of the instrument on the # earth in the Current-Epoch-RA/Dec coordinate frame. J_f = irf.rotate_jones(J_f, R_z0, multiway=False) if p.nside != nside_in: # Change the map resolution as needed. #d = lambda m: hp.ud_grade(m, nside=p.nside, power=-2.) # I think these two ended up being (roughly) the same? # The apparent normalization problem was really becuase of an freq. interpolation problem. # irf.harmonic_ud_grade is probably better for increasing resolution, but hp.ud_grade is # faster because it's just averaging/tiling instead of doing SHT's d = lambda m: irf.harmonic_ud_grade(m, nside_in, p.nside) J_f = (np.asarray(map(d, J_f.T))).T # The inner transpose is so that correct dimension is map()'ed over, # and then the outer transpose returns the array to its original shape. J_f = irf.inverse_flatten_jones(J_f) # Change shape to (nfreq,npix,2,2), complex-valued J_f = transform_basis(p.nside, J_f, z0_cza, R_z0) # right-multiply by the basis transformation matrix from RA/CZA to the Local CST basis. # Note that CZA = pi/2 - Dec! So this is not quite the RA/Dec basis. But the difference # in the Stoke parameters between the two is only U -> -U Jdata[i,:,:,:] = J_f print i # If the model at the current nside hasn't been generated before, save it for future reuse. if os.path.exists(local_jones0_file) == False: np.save(local_jones0_file, Jdata) return Jdata
def make_jones(freq): if freq in range(90,221): pass else: raise ValueError('Frequency is not available.') nside = 512 # make this as large as possible to minimize singularity effects at zenith ## nside 512 seems to work well enough using the "neighbours of neighbours" patch ## of the zenith singularity in the ra/cza basis. npix = hp.nside2npix(nside) hpxidx = np.arange(npix) t,p = hp.pix2ang(nside,hpxidx) g1 = ecomp(csvname(freq,'G','X'),csvname(freq,'P','X')) g2 = ecomp(csvname(freq,'G','Y'),csvname(freq,'P','Y')) I = (abs(g1)**2. + abs(g2)**2.) norm = np.sqrt(np.amax(I, axis=0)) g1 /= norm g2 /= norm rhm = irf.rotate_healpix_map Rb = np.array([ [0,0,-1], [0,-1,0], [-1,0,0] ]) Et_b = udgrade(g1.real, nside) + 1j * udgrade(g1.imag, nside) Ep_b = udgrade(g2.real, nside) + 1j * udgrade(g2.imag, nside) tb,pb = irf.rotate_sphr_coords(Rb, t, p) tb_v = irf.t_hat_cart(tb,pb) pb_v = irf.p_hat_cart(tb,pb) t_v = irf.t_hat_cart(t,p) p_v = irf.p_hat_cart(t,p) Rb_tb_v = np.einsum('ab...,b...->a...', Rb, tb_v) Rb_pb_v = np.einsum('ab...,b...->a...', Rb, pb_v) cosX = np.einsum('a...,a...', Rb_tb_v,t_v) sinX = np.einsum('a...,a...', Rb_pb_v,t_v) Et = Et_b * cosX + Ep_b * sinX Ep = -Et_b * sinX + Ep_b * cosX Ext = Et Exp = Ep ## This assumes that Et and Ep are the components of a dipole oriented ## along the X axis, and we want to obtain the components of the same ## dipole if it was oriented along Y. ## In the current basis, this is done by a scalar rotation of the theta and phi ## components by 90 degrees about the Z axis. Eyt = arm(Et.real) + 1j*arm(Et.imag) Eyp = arm(Ep.real) + 1j*arm(Ep.imag) jones_c = np.array([[Ext,Exp],[Eyt,Eyp]]).transpose(2,0,1) # jones_a = np.array([[rhm(Ext,Rb), rhm(Exp,Rb)],[rhm(Eyt,Rb),rhm(Eyp,Rb)]]).transpose(2,0,1) # # basis_rot = np.array([[cosX,-sinX],[sinX,cosX]]).transpose(2,0,1) # # jones_b = np.einsum('...ab,...bc->...ac', jones_a, basis_rot) # # Ext_b, Exp_b, Eyt_b, Eyp_b = [rhm(jones_b[:,i,j],Rb) for i in range(2) for j in range(2)] # # jones_c = np.array([[Ext_b,Exp_b],[Eyt_b,Eyp_b]]).transpose(2,0,1) return jones_c