Ejemplo n.º 1
0
def get_disk(mask, pos_src, out_edge, in_edge, tol=1):
    '''
    Return unmasked pixel indices of disks centred at a source.
    For usage purpose the input includes two disks.
    Input: mask: mask healpix map;
           pos_src: position of source (with shape=3);
           out_edge: outer disk centred at each source(in arcmin);
           in_edge: inner disk centred at each source(in arcmin);
           tol: tolerance between 0 and 1 indicating a threshold of fraction of
                unmasked pixels in a disk
    Output: pixel indices of both disks.
    '''

    Ns = hp.npix2nside(mask.size)

    list_out = hp.query_disc(Ns, pos_src, np.radians(out_edge / 60.))
    npix_out = len(list_out)

    list_out_unmasked = list_out[mask[list_out] > 0]

    if (list_out_unmasked.size < tol * npix_out):

        return [0, 0]
    lon, lat = hp.vec2dir(pos_src, lonlat=True)
    list_in = hp.query_disc(Ns, pos_src, np.radians(in_edge / 60.))
    list_in_unmasked = list_in[mask[list_in] > 0]
    return list_out_unmasked, list_in_unmasked
Ejemplo n.º 2
0
    def get_disk(self, src_ind, out_edge, in_edge, tol=1):

        '''
        Return unmasked pixel indices of disks centred at a source.
        For usage purpose the input includes two disks.
        Input: src_ind: index of source;
               out_edge: outer disk centred at each source(in arcmin);
               in_edge: inner disk centred at each source(in arcmin);
               tol: tolerance between 0 and 1 indicating a threshold of 
               fraction of unmasked pixels in a disk
        Output: pixel indices of both disks.
        '''
        mask = self.mask
        Ns = self.Nside
        pos_src = self.pos_src_all[src_ind]

        list_out = hp.query_disc(Ns, pos_src, np.radians(out_edge / 60.))
        npix_out = len(list_out)

        list_out_unmasked = list_out[mask[list_out] > 0]

        if(list_out_unmasked.size < tol * npix_out):
            return [0, 0]
        lon, lat = hp.vec2dir(pos_src, lonlat=True)
        list_in = hp.query_disc(Ns, pos_src, np.radians(in_edge / 60.))
        list_in_unmasked = list_in[mask[list_in] > 0]
        return list_out_unmasked, list_in_unmasked
Ejemplo n.º 3
0
 def generate_point_set(self) -> Tuple[np.ndarray, np.ndarray]:
     rng = np.random.default_rng(self.seed)
     lon = 360 * rng.random(size=self.resolution) - 180
     uniform = rng.random(size=self.resolution)
     lat = np.arcsin(2 * uniform - 1) * 180 / np.pi
     vec = hp.dir2vec(theta=lon, phi=lat, lonlat=True)
     dir = hp.vec2dir(vec, lonlat=self.lonlat)
     return vec, dir
Ejemplo n.º 4
0
 def generate_point_set(self) -> Tuple[np.ndarray, np.ndarray]:
     step = np.arange(self.resolution)
     phi = step * self.golden_angle
     phi = Angle(phi * u.rad).wrap_at(2 * np.pi * u.rad)
     theta = np.arccos(1 - (2 * step / self.resolution))
     vec = hp.dir2vec(theta=theta, phi=phi, lonlat=False)
     dir = hp.vec2dir(vec, lonlat=self.lonlat)
     return vec, dir
Ejemplo n.º 5
0
def get_tiling(lon0, lat0, dlon, dlat):
    rot = hp.rotator.Rotator(rot=(0., -lat0, -lon0), eulertype='Y',
                             deg=True).mat
    x = hp.dir2vec(dlon, dlat, lonlat=True)
    if hasattr(dlon, '__len__') and (len(x.shape) == 1):
        x.shape = (3, 1)
    y = np.einsum('ij,jn', rot, x)
    lonlat = hp.vec2dir(y, lonlat=True)
    return lonlat
Ejemplo n.º 6
0
def get_tiling(lon0, lat0, dlon, dlat):
    rot = hp.rotator.Rotator(rot=(0., -lat0, -lon0),
                             eulertype='Y',
                             deg=True).mat
    x = hp.dir2vec(dlon, dlat, lonlat=True)
    if hasattr(dlon, '__len__') and (len(x.shape) == 1):
        x.shape = (3,1)
    y = np.einsum('ij,jn', rot, x)
    lonlat = hp.vec2dir(y, lonlat=True)
    return lonlat
Ejemplo n.º 7
0
def coord_trans(pos_in, coord_in, coord_out, lonlat=False):
    r = hp.rotator.Rotator(coord=[coord_in, coord_out])
    pos_out = r(pos_in.T).T

    if lonlat:
        if pos_out.shape[1] == 2:
            return pos_out
        elif pos_out.shape[1] == 3:
            return hp.vec2dir(pos_out.T, lonlat=True).T
    else:
        return pos_out
Ejemplo n.º 8
0
def get_2d_profile(skymap,
                   mask,
                   pos_src,
                   xbins,
                   ybins,
                   out_edge,
                   in_edge,
                   tol=1):
    '''
    Calculate the 2d signal profile(map) of a single source

    Input: skymap: healpix skymap;
           mask: mask healpix map;
           pos_src: position of the source (with size=3);
           xbins: array, bins in x direction specified by the user.
           ybins: array, bins in y direction specified by the user.
           out_edge: outer disk of the ring to calculate background(in arcmin);
           in_edge: inner disk of the ring to calculate background(in arcmin);
           tol: tolerance between 0 and 1 indicating a threshold of fraction of
                unmasked pixels in a disk
    Output: 2d signal profile(map) of a single source
    '''

    list_out_unmasked, list_in_unmasked = get_disk(mask, pos_src, out_edge,
                                                   in_edge, tol)
    bkg = get_bkg(skymap, mask, list_out_unmasked, list_in_unmasked)

    xybin = np.transpose(
        [np.tile(xbins, len(ybins)),
         np.repeat(ybins, len(xbins))])
    Ns = hp.npix2nside(mask.size)
    nbins = xbins.size
    x, y = xybin.T
    lon, lat = hp.vec2dir(pos_src, lonlat=True)

    lat_pix = y / 60. + lat  # in degrees
    lon_pix = x / 60. / np.cos(np.radians(lat)) + lon
    try:
        x_pix, y_pix, z_pix = hp.ang2vec(lon_pix, lat_pix, lonlat=True).T
    except ValueError, e:
        print(e)
        return np.zeros((nbins, nbins))
Ejemplo n.º 9
0
def main():
    parser = argparse.ArgumentParser(
        description="This program measures the median offset of subset of "
        "detectors from boresight.",
        usage="get_wafer_offset [options] (use --help for details)")

    group = parser.add_mutually_exclusive_group(required=True)
    group.add_argument(
        "--tube_slots",
        help="Comma-separated list of optics tube slots: c1 (UHF), i5 (UHF), "
        " i6 (MF), i1 (MF), i3 (MF), i4 (MF), o6 (LF).  ")
    group.add_argument("--wafer_slots",
                       help="Comma-separated list of optics tube slots. ")
    parser.add_argument("--reverse",
                        action="store_true",
                        help="Reverse offsets")
    # LAT specific params
    parser.add_argument(
        "--corotate-lat",
        required=False,
        action="store_true",
        help="Rotate LAT receiver to maintain focalplane orientation",
        dest="corotate_lat",
    )
    parser.add_argument(
        "--no-corotate-lat",
        required=False,
        action="store_false",
        help="Do not Rotate LAT receiver to maintain focalplane orientation",
        dest="corotate_lat",
    )
    parser.set_defaults(corotate_lat=True)
    parser.add_argument(
        "--elevation-deg",
        required=False,
        type=np.float,
        help="Observing elevation",
    )

    args = parser.parse_args()

    hw = hardware.get_example()

    # Which telescope?

    if args.wafer_slots is not None:
        wafer_slots = args.wafer_slots.split(",")
        wafer_map = hw.wafer_map()
        tube_slots = [wafer_map["tube_slots"][ws] for ws in wafer_slots]
    else:
        tube_slots = args.tube_slots.split(",")

    telescope = None
    for tube_slot in tube_slots:
        for telescope_name, telescope_data in hw.data["telescopes"].items():
            if tube_slot in telescope_data["tube_slots"]:
                if telescope is None:
                    telescope = telescope_name
                elif telescope != telescope.name:
                    raise RuntimeError(
                        f"Tubes '{tube_slots}' span more than one telescope")
        if telescope is None:
            raise RuntimeError(
                f"Failed to match tube_slot = '{tube_slot}' with a telescope")

    # Which detectors?

    hw.data["detectors"] = hardware.sim_telescope_detectors(hw, telescope)

    match = {}
    tube_slots = None
    if args.wafer_slots is not None:
        match["wafer_slot"] = args.wafer_slots.split(",")
    elif args.tube_slots is not None:
        tube_slots = args.tube_slots.split(",")

    hw = hw.select(tube_slots=tube_slots, match=match)
    ndet = len(hw.data["detectors"])

    # print(f"tube_slots = {tube_slots}, match = {match} leaves {ndet} detectors")

    # Optional corotator rotation

    if telescope == "LAT":
        if args.corotate_lat:
            rot = qa.rotation(ZAXIS, np.radians(LAT_COROTATOR_OFFSET_DEG))
        else:
            if args.elevation_deg is None:
                raise RuntimeError(
                    "You must set the observing elevation when not co-rotating."
                )
            rot = qa.rotation(
                ZAXIS,
                np.radians(args.elevation_deg - 60 + LAT_COROTATOR_OFFSET_DEG))
    else:
        if args.elevation_deg is not None:
            raise RuntimeError("Observing elevation does not matter for SAT")
        rot = None

    # Average detector offset

    vec_mean = np.zeros(3)
    for det_name, det_data in hw.data["detectors"].items():
        quat = det_data["quat"]
        if rot is not None:
            quat = qa.mult(rot, quat)
        vec = qa.rotate(quat, ZAXIS)
        vec_mean += vec
    vec_mean /= ndet

    # Radius

    all_dist = []
    for det_name, det_data in hw.data["detectors"].items():
        quat = det_data["quat"]
        if rot is not None:
            quat = qa.mult(rot, quat)
        vec = qa.rotate(quat, ZAXIS)
        all_dist.append(np.degrees(np.arccos(np.dot(vec_mean, vec))))
    dist_max = np.amax(all_dist)

    # Wafers

    if args.tube_slots is None:
        wafer_slots = set(wafer_slots)
    else:
        wafer_slots = set()
        for tube_slot in tube_slots:
            wafer_slots.update(hw.data["tube_slots"][tube_slot]["wafer_slots"])
    waferstring = ""
    for wafer_slot in sorted(wafer_slots):
        waferstring += f" {wafer_slot}"

    # Translate into Az/El offsets at el=0

    rot = hp.Rotator(rot=[0, 90, 0])
    vec_mean = rot(vec_mean)
    az_offset, el_offset = hp.vec2dir(vec_mean, lonlat=True)

    el_offset *= -1
    if args.reverse:
        az_offset *= -1
        el_offset *= -1

    print(f"{az_offset:.3f} {el_offset:.3f} {dist_max:.3f}" + waferstring)

    return
Ejemplo n.º 10
0
nband = len(bands)
site = "chile"
nside = 4096
lmax = 2 * nside
flavor = "noise_atmo_7splits" # cmb_r0  cmb_tensor_only_r3e-3  foregrounds  noise_atmo_7splits
#flavor = "noise" # cmb_r0  cmb_tensor_only_r3e-3  foregrounds  noise_atmo_7splits

split = 1
nsplits = 1

# Mock the ACT processing mask.  This is 525 sq.deg (0.0127 fsky)

npix = 12 * nside ** 2
pix = np.arange(npix)
vec = hp.pix2vec(nside, pix)
lon, lat = hp.vec2dir(vec, lonlat=True)
mask = np.logical_and(lon > -4, lon < 40) * np.logical_and(lat > -8, lat < 4)

# Deep56 is 565 sq.deg (0.0137 fsky) of which 340 sq.deg (0.00824 fsky) is usable for power spectrum estimation
# ell pa1(150GHz) pa2(150GHz) pa3(150GHz) pa3(98GHz) pa3(98x150GHz)
act_tt = np.genfromtxt("deep56_TT_Nl_out_210317.txt", skip_header=1).T
act_ee = np.genfromtxt("deep56_EE_Nl_out_210317.txt", skip_header=1).T


def map2cl(m, hits):
    """
    good = hits > 0
    ngood = np.sum(good)
    sorted_hits = np.sort(hits[good])
    
    hit_lim = sorted_hits[np.int(ngood * .01)]
Ejemplo n.º 11
0
 def generate_point_set(self) -> Tuple[np.ndarray, np.ndarray]:
     vec = np.stack(hp.pix2vec(self.nside, np.arange(self.resolution)), axis=0)
     dir = hp.vec2dir(vec, lonlat=self.lonlat)
     return vec, dir
Ejemplo n.º 12
0
     len(xyz1), 1) * 20e-3 + pert_p_norm * GZK_dist_scale
 # END OF PERTURBED VECTOR
 # SAME CUTS ALSO APPLIED TO PERTURBED VECTOR
 xyz = xyz1 / xyz1l2norm.reshape(len(xyz1),
                                 1) * 20e-3 + pxpypz_norm * GZK_dist_scale
 l2norm = np.sqrt((xyz * xyz).sum(axis=1))
 xyz_norm = xyz / l2norm.reshape(len(xyz), 1)
 lon = np.zeros(len(xyz))
 lat = np.zeros(len(xyz))
 # PERTURBED
 pert_l2norm = np.sqrt((pert_xyz * pert_xyz).sum(axis=1))
 pert_xyz_norm = pert_xyz / pert_l2norm.reshape(len(pert_xyz), 1)
 p_lon = np.zeros(len(pert_xyz))
 p_lat = np.zeros(len(pert_xyz))
 for i in range(len(xyz)):
     lon[i], lat[i] = hp.vec2dir(xyz[i], lonlat=True)
     p_lon[i], p_lat[i] = hp.vec2dir(pert_xyz[i], lonlat=True)
 # Test for nans (might be a result of run stoppage)
 tmp = np.isnan(lat)
 if len(lat[tmp]) > 0:
     num_nans = len(lat[tmp])
     print("found %i nans in lat array. Exlcuding." % num_nans)
     lon = lon[~tmp]
     lat = lat[~tmp]
     xyz = xyz[~tmp]
     xyz_norm = xyz_norm[~tmp]
     pxpypz_norm = pxpypz_norm[~tmp]
     E1 = E1[~tmp]
     p_lon = p_lon[~tmp]
     p_lat = p_lat[~tmp]
 # Wrap coords to [0,360] if necessary
Ejemplo n.º 13
0
    def exec(self, data):
        """Apply the 2D polynomial filter to the signal.

        Args:
            data (toast.Data): The distributed data.

        """
        norder = self._order + 1
        nmode = self._nmode
        world_comm = data.comm.comm_world
        if world_comm is None:
            world_rank = 0
        else:
            world_rank = world_comm.rank

        for obs in data.obs:
            t0 = time()
            t_template = 0
            t_get_norm = 0
            t_apply_norm = 0
            t_solve = 0
            t_clean = 0

            tod = obs["tod"]
            times = tod.local_times()
            # communicator for processes with the same sample range
            comm = tod.grid_comm_col
            if comm is None:
                comm_rank = 0
                comm_size = 1
            else:
                comm_rank = comm.rank
                comm_size = comm.size
            detectors = tod.detectors
            ndet = len(detectors)
            detector_index = {}
            pat = re.compile(self._pattern)

            ndet = 0
            for det in detectors:
                if pat.match(det) is None:
                    continue
                detector_index[det] = ndet
                ndet += 1
            # Number of detectors may limit the number of modes we can constrain
            nmode = min(self._nmode, ndet)

            focalplane = obs["focalplane"]

            detector_templates = np.zeros([ndet, nmode])
            mode = 0
            xorders = np.zeros(nmode)
            yorders = np.zeros(nmode)
            for order in range(norder):
                for yorder in range(order + 1):
                    xorder = order - yorder
                    xorders[mode] = xorder
                    yorders[mode] = yorder
                    mode += 1
                    if mode == nmode:
                        break
                if mode == nmode:
                    break

            yrot = qa.rotation(YAXIS, np.pi / 2)
            for det in tod.local_dets:
                if det not in detector_index:
                    continue
                idet = detector_index[det]
                det_quat = focalplane[det]["quat"]
                vec = qa.rotate(det_quat, ZAXIS)
                theta, phi = hp.vec2dir(qa.rotate(yrot, vec))
                theta -= np.pi / 2
                detector_templates[idet] = theta ** xorders * phi ** yorders

            if self._intervals in obs:
                intervals = obs[self._intervals]
            else:
                intervals = None
            local_intervals = tod.local_intervals(intervals)
            if len(local_intervals) == 0:
                # No intervals to filter
                continue
            common_ref = tod.local_common_flags(self._common_flag_name)

            # Iterate over each interval

            for ival in local_intervals:
                istart = ival.first
                while istart < ival.last + 1:
                    istop = min(istart + self._buffer_length, ival.last + 1)
                    ind = slice(istart, istop)
                    nsample = istop - istart

                    templates = np.zeros([ndet, nmode])
                    masks = np.zeros([ndet, nsample], dtype=np.bool)
                    proj = np.zeros([nmode, nsample])
                    norms = np.zeros(nmode)

                    t1 = time()

                    for det in tod.local_dets:
                        if det not in detector_index:
                            continue
                        idet = detector_index[det]

                        ref = tod.local_signal(det, self._name)[ind]
                        flag_ref = tod.local_flags(det, self._flag_name)[ind]

                        flg = common_ref[ind] & self._common_flag_mask
                        flg |= flag_ref & self._flag_mask
                        mask = flg == 0

                        # We might want to remove the interval mean if the
                        # data were not already 1D-filtered
                        # ref -= np.mean(ref[mask])

                        template = detector_templates[idet]
                        templates[idet] = template
                        masks[idet] = mask
                        proj += np.outer(template, ref * mask)
                        norms += template ** 2

                        del ref
                        del flag_ref

                    t_template += time() - t1

                    t1 = time()
                    if comm is not None:
                        comm.Barrier()
                        comm.Allreduce(MPI.IN_PLACE, templates, op=MPI.SUM)
                        comm.Allreduce(MPI.IN_PLACE, masks, op=MPI.LOR)
                        comm.Allreduce(MPI.IN_PLACE, proj, op=MPI.SUM)
                        comm.Allreduce(MPI.IN_PLACE, norms, op=MPI.SUM)

                    good = norms != 0
                    norms[good] = norms[good] ** -0.5
                    t_get_norm += time() - t1

                    t1 = time()
                    templates = templates.T.copy()  # nmode x ndet
                    for mode, norm in enumerate(norms):
                        if norm:
                            templates[mode] *= norm
                            proj[mode] *= norm
                    t_apply_norm += time() - t1

                    t1 = time()
                    proj = proj.T.copy()  # nsample x nmode
                    coeff = np.zeros([nsample, nmode])
                    masks = np.transpose(masks)  # nsample x ndet
                    for isample in range(nsample):
                        if isample % comm_size != comm_rank:
                            continue
                        mask = masks[isample]
                        templatesT = mask * templates  # nmode * ndet
                        invcov = np.dot(templatesT, templates.T)
                        try:
                            cov = np.linalg.inv(invcov)
                            coeff[isample] = np.dot(cov, proj[isample])
                        except np.linalg.LinAlgError:
                            coeff[isample] = 0
                    if comm is not None:
                        comm.Allreduce(MPI.IN_PLACE, coeff, op=MPI.SUM)
                    t_solve += time() - t1

                    t1 = time()

                    for isample in range(nsample):
                        if np.all(coeff[isample] == 0):
                            common_ref[istart + isample] |= self._poly_flag_mask

                    templates = templates.T.copy()  # ndet x nmode x nsample
                    coeff = coeff.T.copy()  # nmode x nsample

                    for det in tod.local_dets:
                        if det not in detector_index:
                            continue
                        idet = detector_index[det]
                        ref = tod.local_signal(det, self._name)[ind]
                        for mode in range(nmode):
                            ref -= coeff[mode] * templates[idet, mode]

                    t_clean += time() - t1

                    del templates
                    istart = istop

            del common_ref

            if world_rank == 0 or (comm_rank == 0 and self._verbose > 1):
                print(
                    "Time per observation: {:.1f} s\n"
                    "   templates : {:6.1f} s\n"
                    "    get_norm : {:6.1f} s\n"
                    "  apply_norm : {:6.1f} s\n"
                    "       solve : {:6.1f} s\n"
                    "       clean : {:6.1f} s".format(
                        time() - t0,
                        t_template,
                        t_get_norm,
                        t_apply_norm,
                        t_solve,
                        t_clean,
                    ),
                    flush=True,
                )

        return
Ejemplo n.º 14
0
    def translate(self, quats, timestamps, psi_pol=None):
        """
        Translate the input quaternions into planet-centric coordinates
        and convert the offsets to arc minutes.  The quaternions ARE
        EXPECTED to be in galactic coordinates although adding a
        rotation would be straightforward.

        The output coordinate system is Pxx, unless either
        a) quats do not include the psi_pol rotation or
        b) psi_pol is provided in radians. translate() will then remove
            the psi_pol rotation from the quaternions
        """
        if timestamps[0] > self.time[-1] or timestamps[-1] < self.time[0]:
            raise Exception(
                'There is no overlap in the stored and provided time stamps.')

        if psi_pol is not None:
            pol_quat = qa.rotation(zaxis, -psi_pol)
            zquat = qa.mult(pol_quat, self.zquat)
        else:
            zquat = self.zquat

        my_quats = qa.mult(quats, zquat)  # From X-axis to detector position

        # Transform the planet positions into quaternions

        tol = 3600.

        ind = np.logical_and(self.time >= timestamps[0] - tol,
                             self.time <= timestamps[-1] + tol)
        nind = np.sum(ind)

        planettime = self.time[ind]
        planetglon = self.glon[ind]
        planetglat = self.glat[ind]
        planetquat = np.zeros([nind, 4])

        # ZYZ rotation to put the X-axis to the planet position

        phi = planetglon * degree
        theta = -planetglat * degree
        psi = 0

        planetquat[:, 3] = np.cos(.5 * theta) * np.cos(.5 * (phi + psi))
        planetquat[:, 0] = -np.sin(.5 * theta) * np.sin(.5 * (phi - psi))
        planetquat[:, 1] = np.sin(.5 * theta) * np.cos(.5 * (phi - psi))
        planetquat[:, 2] = np.cos(.5 * theta) * np.sin(.5 * (phi + psi))

        targetquats = qa.slerp(timestamps, planettime, planetquat)

        planetvec = qa.rotate(targetquats, xaxis)

        # Rotate the planet into Dxx frame (detector on X-axis)

        planetvec = qa.rotate(qa.inv(my_quats), planetvec)

        # The detector position relative to the planet is the inverse
        # of the planet coordinates in Dxx

        lon, lat = hp.vec2dir(planetvec.T, lonlat=True)

        az, el = -np.array([lon, lat]) * 60  # To arc minutes
        return az, el
            # In[10]:

            #rotmat = np.hstack([ vec_north[:,0][:,np.newaxis], np.cross(vec[:,0], vec_north[:,0])[:,np.newaxis], vec[:,0][:,np.newaxis]])


            # In[11]:

            vec_north.T[:,0][:,np.newaxis]


            # Need to prepend a column of zeros to `vec`, because I need to have an input with a dimension equal to 4 to declare the signature

            # In[12]:

            lon, lat= hp.vec2dir(vec[:,0], vec[:,1], vec[:,2], lonlat=True)


            # In[13]:

            q = np.empty([len(vec), 4], dtype=np.float)


            # In[14]:

            n = len(vec)
            for i in range(n):
                rotmat = np.hstack([ vec_north[i,:][:,np.newaxis],
                                     np.cross(vec[i,:], vec_north[i,:])[:,np.newaxis],
                                     vec[i,:][:,np.newaxis]
                                ])
Ejemplo n.º 16
0
def main():
    parser = argparse.ArgumentParser(
        description="This program measures the median offset of subset of "
        "detectors from boresight.",
        usage="get_wafer_offset [options] (use --help for details)")

    group = parser.add_mutually_exclusive_group(required=True)
    group.add_argument(
        "--tube_slots",
        help="Comma-separated list of optics tube slots: c1 (UHF), i5 (UHF), "
        " i6 (MF), i1 (MF), i3 (MF), i4 (MF), o6 (LF).  ")
    group.add_argument("--wafer_slots",
                       help="Comma-separated list of optics tube slots. ")
    parser.add_argument("--reverse",
                        action="store_true",
                        help="Reverse offsets")

    args = parser.parse_args()

    hw = hardware.get_example()

    # Which telescope?

    if args.wafer_slots is not None:
        wafer_slots = args.wafer_slots.split(",")
        wafer_map = hw.wafer_map()
        tube_slots = [wafer_map["tube_slots"][ws] for ws in wafer_slots]
    else:
        tube_slots = args.tube_slots.split(",")

    telescope = None
    for tube_slot in tube_slots:
        for telescope_name, telescope_data in hw.data["telescopes"].items():
            if tube_slot in telescope_data["tube_slots"]:
                if telescope is None:
                    telescope = telescope_name
                elif telescope != telescope.name:
                    raise RuntimeError(
                        f"Tubes '{tube_slots}' span more than one telescope")
        if telescope is None:
            raise RuntimeError(
                f"Failed to match tube_slot = '{tube_slot}' with a telescope")

    # Which detectors?

    hw.data["detectors"] = hardware.sim_telescope_detectors(hw, telescope)

    match = {}
    tube_slots = None
    if args.wafer_slots is not None:
        match["wafer_slot"] = args.wafer_slots.split(",")
    elif args.tube_slots is not None:
        tube_slots = args.tube_slots.split(",")

    hw = hw.select(tube_slots=tube_slots, match=match)
    ndet = len(hw.data["detectors"])

    # print(f"tube_slots = {tube_slots}, match = {match} leaves {ndet} detectors")

    # Average detector offset

    vec_mean = np.zeros(3)
    zaxis = np.array([0, 0, 1])
    for det_name, det_data in hw.data["detectors"].items():
        quat = det_data["quat"]
        vec = qa.rotate(quat, zaxis)
        vec_mean += vec
    vec_mean /= ndet

    # Radius

    all_dist = []
    for det_name, det_data in hw.data["detectors"].items():
        quat = det_data["quat"]
        vec = qa.rotate(quat, zaxis)
        all_dist.append(np.degrees(np.arccos(np.dot(vec_mean, vec))))
    dist_max = np.amax(all_dist)

    # Translate into Az/El offsets at el=0

    rot = hp.Rotator(rot=[0, 90, 0])
    vec_mean = rot(vec_mean)
    az_offset, el_offset = hp.vec2dir(vec_mean, lonlat=True)

    el_offset *= -1
    if args.reverse:
        az_offset *= -1
        el_offset *= -1

    print(f"{az_offset:.3f} {el_offset:.3f} {dist_max:.3f}")

    return
Ejemplo n.º 17
0
 def lonlat(self, value):
     self._lonlat = value
     self.dir = hp.vec2dir(self.vec, lonlat=value)