Пример #1
0
def offset_beam_ghost(az_off=0,
                      el_off=0,
                      polang=0,
                      lmax=100,
                      fwhm=200,
                      hwp_freq=25.,
                      pol_only=True):
    '''
    Script that scans LCDM realization of sky with a detector
    on the boresight that has no main beam but a full-amplitude
    ghost at the specified offset eam. The signal is then binned
    using the boresight pointing and compared to a map made by
    a symmetric Gaussian beam that has been rotated away from
    the boresight. Results should agree.

    Keyword arguments
    ---------

    az_off : float,
        Azimuthal location of detector relative to boresight
        (default : 0.)
    el_off : float,
        Elevation location of detector relative to boresight
        (default : 0.)
    polang : float,
        Detector polarization angle in degrees (defined for
        unrotated detector as offset from meridian)
        (default : 0)
    lmax : int,
        Maximum multipole number, (default : 200)
    fwhm : float,
        The beam FWHM used in this analysis in arcmin
        (default : 100)
    hwp_freq : float,
        HWP spin frequency (continuous mode) (default : 25.)
    pol_only : bool,
        Set unpolarized sky signal to zero (default : True)
    '''

    # Load up alm and blm
    ell, cls = get_cls()
    np.random.seed(30)
    alm = hp.synalm(cls, lmax=lmax, new=True, verbose=True)  # uK

    if pol_only:
        alm = (alm[0] * 0., alm[1], alm[2])

    # init scan strategy and instrument
    mlen = 240  # mission length
    ss = ScanStrategy(
        mlen,  # mission duration in sec.
        sample_rate=1,  # sample rate in Hz
        location='spole')  # South pole instrument

    # create single detector on boresight
    ss.create_focal_plane(nrow=1,
                          ncol=1,
                          fov=0,
                          no_pairs=True,
                          polang=polang,
                          lmax=lmax,
                          fwhm=fwhm,
                          scatter=True)

    try:
        beam = ss.beams[0][0]

        # set main beam to zero
        beam.amplitude = 0.

        # create Gaussian beam (would be done by code anyway otherwise)
        beam.gen_gaussian_blm()

        #explicitely set offset to zero
        beam.az = 0.
        beam.el = 0.
        beam.polang = 0.

        # create full-amplitude ghost
        beam.create_ghost(az=az_off, el=el_off, polang=polang, amplitude=1.)
        ghost = beam.ghosts[0]
        ghost.gen_gaussian_blm()

    except IndexError as e:
        if ss.mpi_rank != 0:
            pass
        else:
            raise e

    # Start instrument rotated (just to make things complicated)
    rot_period = ss.mlen
    ss.set_instr_rot(period=rot_period, start_ang=45)

    # Set HWP rotation
    ss.set_hwp_mod(mode='stepped',
                   freq=1 / 20.,
                   start_ang=45,
                   angles=[34, 12, 67])

    # calculate tod in one go (beam is symmetric so mmax=2 suffices)
    ss.partition_mission()
    ss.scan_instrument_mpi(alm,
                           binning=False,
                           nside_spin=512,
                           max_spin=2,
                           verbose=2)

    # Store the tod and pixel indices made with ghost
    try:
        tod_ghost = ss.tod.copy()
        pix_ghost = ss.pix.copy()
    except AttributeError as e:
        if ss.mpi_rank != 0:
            pass
        else:
            raise e

    # now repeat with asymmetric beam and no detector offset
    # set offsets to zero such that tods are generated using
    # only the boresight pointing.
    try:
        beam = ss.beams[0][0]
        beam.amplitude = 1.
        beam.gen_gaussian_blm()

        # Convert beam spin modes to E and B modes and rotate them
        blm = beam.blm
        blmI = blm[0].copy()
        blmE, blmB = tools.spin2eb(blm[1], blm[2])

        # Rotate blm to match centroid.
        # Note that rotate_alm uses the ZYZ euler convention.
        # Note that we include polang here as first rotation.
        q_off = ss.det_offset(az_off, el_off, polang)
        ra, dec, pa = ss.quat2radecpa(q_off)

        # convert between healpy and math angle conventions
        phi = np.radians(ra)
        theta = np.radians(90 - dec)
        psi = np.radians(-pa)

        # rotate blm
        hp.rotate_alm([blmI, blmE, blmB],
                      psi,
                      theta,
                      phi,
                      lmax=lmax,
                      mmax=lmax)

        # convert beam coeff. back to spin representation.
        blmm2, blmp2 = tools.eb2spin(blmE, blmB)
        beam.blm = (blmI, blmm2, blmp2)

        # kill ghost
        ghost.dead = True
        # spinmaps will still be created, so make as painless as possible
        ghost.lmax = 1
        ghost.mmax = 0

    except IndexError as e:
        if ss.mpi_rank != 0:
            pass
        else:
            raise e

    # reset instr. rot and hwp modulation
    ss.reset_instr_rot()
    ss.reset_hwp_mod()

    ss.scan_instrument_mpi(alm,
                           binning=False,
                           nside_spin=512,
                           verbose=2,
                           max_spin=lmax)  # now we use all spin modes

    # Figure comparing the raw detector timelines for the two versions
    # For subpixel offsets, the bottom plot shows you that sudden shifts
    # in the differenced tods are due to the pointing for the symmetric
    # case hitting a different pixel than the boresight pointing.
    if ss.mpi_rank == 0:
        plt.figure()
        gs = gridspec.GridSpec(5, 9)
        ax1 = plt.subplot(gs[:2, :6])
        ax2 = plt.subplot(gs[2:4, :6])
        ax3 = plt.subplot(gs[-1, :6])
        ax4 = plt.subplot(gs[:, 6:])

        samples = np.arange(tod_ghost.size)
        ax1.plot(samples, ss.tod, label='Asymmetric Gaussian', linewidth=0.7)
        ax1.plot(samples, tod_ghost, label='Ghost', linewidth=0.7, alpha=0.5)
        ax1.legend()

        ax1.tick_params(labelbottom='off')
        sigdiff = ss.tod - tod_ghost
        ax2.plot(samples, sigdiff, ls='None', marker='.', markersize=2.)
        ax2.tick_params(labelbottom='off')
        ax3.plot(samples, (pix_ghost - ss.pix).astype(bool).astype(int),
                 ls='None',
                 marker='.',
                 markersize=2.)
        ax1.set_ylabel(r'Signal [$\mu K_{\mathrm{CMB}}$]')
        ax2.set_ylabel(r'asym-sym. [$\mu K_{\mathrm{CMB}}$]')
        ax3.set_xlabel('Sample number')
        ax3.set_ylabel('different pixel?')
        ax3.set_ylim([-0.25, 1.25])
        ax3.set_yticks([0, 1])

        ax4.hist(sigdiff, 128, label='Difference')
        ax4.set_xlabel(r'Difference [$\mu K_{\mathrm{CMB}}$]')
        ax4.tick_params(labelleft='off')

        plt.savefig('../scratch/img/tods_ghost.png')
        plt.close()
Пример #2
0
def offset_beam_interp(az_off=0, el_off=0, polang=0, lmax=100,
                fwhm=200, hwp_freq=25., pol_only=True):
    '''
    Script that scans LCDM realization of sky with a symmetric
    Gaussian beam that has been rotated away from the boresight.
    This means that the beam is highly asymmetric. Scanning using
    interpolation.

    Keyword arguments
    -----------------
    az_off : float,
        Azimuthal location of detector relative to boresight
        (default : 0.)
    el_off : float,
        Elevation location of detector relative to boresight
        (default : 0.)
    polang : float,
        Detector polarization angle in degrees (defined for
        unrotated detector as offset from meridian)
        (default : 0)
    lmax : int,
        Maximum multipole number, (default : 200)
    fwhm : float,
        The beam FWHM used in this analysis [arcmin]
        (default : 100)
    hwp_freq : float,
        HWP spin frequency (continuous mode) (default : 25.)
    pol_only : bool,
        Set unpolarized sky signal to zero (default : True)
    '''

    # Load up alm and blm
    ell, cls = get_cls()
    np.random.seed(30)
    alm = hp.synalm(cls, lmax=lmax, new=True, verbose=True) # uK

    if pol_only:
        alm = (alm[0]*0., alm[1], alm[2])

    # init scan strategy and instrument
    mlen = 240 # mission length
    ss = ScanStrategy(mlen, # mission duration in sec.
                      sample_rate=1, # sample rate in Hz
                      location='spole') # South pole instrument

    # create single detector
    ss.create_focal_plane(nrow=1, ncol=1, fov=0, no_pairs=True,
                          polang=polang, lmax=lmax, fwhm=fwhm,
                          scatter=True)

    # move detector away from boresight
    try:
        ss.beams[0][0].az = az_off
        ss.beams[0][0].el = el_off
    except IndexError as e:
        if ss.mpi_rank != 0:
            pass
        else:
            raise e

    # Start instrument rotated (just to make things complicated)
    rot_period =  ss.mlen
    ss.set_instr_rot(period=rot_period, start_ang=45)

    # Set HWP rotation
    ss.set_hwp_mod(mode='stepped', freq=1/20., start_ang=45,
                   angles=[34, 12, 67])

    # calculate tod in one go (beam is symmetric so mmax=2 suffices)
    ss.partition_mission()
    ss.scan_instrument_mpi(alm, binning=False, nside_spin=512,
                           max_spin=2, interp=True)

    # Store the tod made with symmetric beam
    try:
        tod_sym = ss.tod.copy()
    except AttributeError as e:
        if ss.mpi_rank != 0:
            pass
        else:
            raise e
    
    # now repeat with asymmetric beam and no detector offset
    # set offsets to zero such that tods are generated using
    # only the boresight pointing.
    try:
        ss.beams[0][0].az = 0
        ss.beams[0][0].el = 0
        ss.beams[0][0].polang = 0

        # Convert beam spin modes to E and B modes and rotate them
        # create blm again, scan_instrument_mpi detetes blms when done
        ss.beams[0][0].gen_gaussian_blm()
        blm = ss.beams[0][0].blm
        blmI = blm[0].copy()
        blmE, blmB = tools.spin2eb(blm[1], blm[2])

        # Rotate blm to match centroid.
        # Note that rotate_alm uses the ZYZ euler convention.
        # Note that we include polang here as first rotation.
        q_off = ss.det_offset(az_off, el_off, polang)
        ra, dec, pa = ss.quat2radecpa(q_off)

        # convert between healpy and math angle conventions
        phi = np.radians(ra)
        theta = np.radians(90 - dec)
        psi = np.radians(-pa)

        # rotate blm
        hp.rotate_alm([blmI, blmE, blmB], psi, theta, phi, lmax=lmax, mmax=lmax)

        # convert beam coeff. back to spin representation.
        blmm2, blmp2 = tools.eb2spin(blmE, blmB)
        ss.beams[0][0].blm = (blmI, blmm2, blmp2)

    except IndexError as e:
        if ss.mpi_rank != 0:
            pass
        else:
            raise e

    ss.reset_instr_rot()
    ss.reset_hwp_mod()
    
    # Now we use all spin modes.
    ss.scan_instrument_mpi(alm, binning=False, nside_spin=512,
                           max_spin=lmax, interp=True) 

    if ss.mpi_rank == 0:
        plt.figure()
        gs = gridspec.GridSpec(5, 9)
        ax1 = plt.subplot(gs[:2, :6])
        ax2 = plt.subplot(gs[2:4, :6])
        ax4 = plt.subplot(gs[:, 6:])

        samples = np.arange(tod_sym.size)
        ax1.plot(samples, ss.tod, label='Asymmetric Gaussian', linewidth=0.7)
        ax1.plot(samples, tod_sym, label='Symmetric Gaussian', linewidth=0.7,
                 alpha=0.5)
        ax1.legend()

        ax1.tick_params(labelbottom='off')
        sigdiff = ss.tod - tod_sym
        ax2.plot(samples, sigdiff,ls='None', marker='.', markersize=2.)
        ax2.tick_params(labelbottom='off')
        ax1.set_ylabel(r'Signal [$\mu K_{\mathrm{CMB}}$]')
        ax2.set_ylabel(r'asym-sym. [$\mu K_{\mathrm{CMB}}$]')
        ax2.set_xlabel('Sample number')

        ax4.hist(sigdiff, 128, label='Difference')
        ax4.set_xlabel(r'Difference [$\mu K_{\mathrm{CMB}}$]')
        ax4.tick_params(labelleft='off')

        plt.savefig('../scratch/img/tods_interp.png', dpi=250)
        plt.close()