def fake_focalplane():
    """Create a set of fake detectors.

    This generates 7 pixels (14 dets) in a hexagon layout at the boresight
    and with a made up polarization orientation.

    Args:
        None

    Returns:
        (dict):  dictionary of detectors and their properties.

    """
    zaxis = np.array([0, 0, 1.0])
    samplerate = 20.0
    epsilon = 0.0
    net = 1.0
    fmin = 0.0
    alpha = 1.0
    fknee = 0.05
    fwhm = 30.0
    
    npix = 7
    ndet = 2 * npix
    
    pol_A = hex_pol_angles_qu(npix)
    pol_B = hex_pol_angles_qu(npix, offset=90.0)
    
    dets_A = hex_layout(npix, 3.0, "", "", pol_A)
    dets_B = hex_layout(npix, 3.0, "", "", pol_B)
    
    dets = dict()
    for p in range(npix):
        pstr = "{:01d}".format(p)
        for d, layout in zip(["A", "B"], [dets_A, dets_B]):
            props = dict()
            props["quat"] = layout[pstr]["quat"]
            props["epsilon"] = epsilon
            props["rate"] = samplerate
            props["alpha"] = alpha
            props["NET"] = net
            props["fmin"] = fmin
            props["fknee"] = fknee
            props["fwhm_arcmin"] = fwhm
            dname = "{}{}".format(pstr, d)
            dets[dname] = props
    return dets
Ejemplo n.º 2
0
def fake_focalplane():
    """
    Make a fake focalplane geometry.

    This function returns a fake hexagonal focalplane with 19 pixels
    and 2 detectors at each position.  The spacing is set to fill the
    field of view.
    """
    npix = 19
    # 5' beam
    fwhm = 5.0 / 60.0
    # 5 degree FOV...
    fov = 5.0
    # ...converted to size of hexagon
    angwidth = fov * np.cos(30.0 * np.pi / 180.0)
    
    # Alternating polarization orientations
    Apol = tt.hex_pol_angles_qu(npix, offset=0.0)
    Bpol = tt.hex_pol_angles_qu(npix, offset=90.0)
    
    # Build a simple hexagon layout
    Adets = tt.hex_layout(npix, 100.0, angwidth, fwhm, "fake_", "A", Apol)
    Bdets = tt.hex_layout(npix, 100.0, angwidth, fwhm, "fake_", "B", Bpol)
    
    # Combine into a single dictionary
    dets = Adets.copy()
    dets.update(Bdets)

    # Give each detector the same fake noise properties
    for indx, d in enumerate(sorted(dets.keys())):
        # 50mHz knee frequency
        dets[d]["fknee"] = 0.050
        # High pass "plateau" to avoid blow-up at very low f
        dets[d]["fmin"] = 1.0e-5
        # Exponent
        dets[d]["alpha"] = 1.0
        # Sensitivity
        dets[d]["NET"] = 20.0e-6
        # Unique index for reproducibility of simulations
        dets[d]["index"] = indx

    return dets
Ejemplo n.º 3
0
def main():

    parser = argparse.ArgumentParser(
        description="Simulate fake hexagonal focalplane.",
        fromfile_prefix_chars='@')

    parser.add_argument("--minpix",
                        required=False,
                        type=int,
                        default=100,
                        help="minimum number of pixels to use")

    parser.add_argument("--out",
                        required=False,
                        default="fp_fake",
                        help="Root name of output pickle file")

    parser.add_argument("--fwhm",
                        required=False,
                        type=float,
                        default=5.0,
                        help="beam FWHM in arcmin")

    parser.add_argument("--fwhm_sigma",
                        required=False,
                        type=float,
                        default=0,
                        help="Relative beam FWHM distribution width")

    parser.add_argument("--fov",
                        required=False,
                        type=float,
                        default=5.0,
                        help="Field of View in degrees")

    parser.add_argument("--psd_fknee",
                        required=False,
                        type=float,
                        default=0.05,
                        help="Detector noise model f_knee in Hz")

    parser.add_argument("--psd_NET",
                        required=False,
                        type=float,
                        default=60.0e-6,
                        help="Detector noise model NET in K*sqrt(sec)")

    parser.add_argument("--psd_alpha",
                        required=False,
                        type=float,
                        default=1.0,
                        help="Detector noise model slope")

    parser.add_argument("--psd_fmin",
                        required=False,
                        type=float,
                        default=1.0e-5,
                        help="Detector noise model f_min in Hz")

    parser.add_argument("--bandcenter_ghz",
                        required=False,
                        type=float,
                        help="Band center frequency [GHz]")

    parser.add_argument("--bandcenter_sigma",
                        required=False,
                        type=float,
                        default=0,
                        help="Relative band center distribution width")

    parser.add_argument("--bandwidth_ghz",
                        required=False,
                        type=float,
                        help="Bandwidth [GHz]")

    parser.add_argument("--bandwidth_sigma",
                        required=False,
                        type=float,
                        default=0,
                        help="Relative bandwidth distribution width")

    parser.add_argument("--random_seed",
                        required=False,
                        type=np.int,
                        default=123456,
                        help="Random number generator seed for randomized "
                        "detector parameters")

    args = timing.add_arguments_and_parse(parser, timing.FILE(noquotes=True))

    # Guard against being called with multiple processes
    if MPI.COMM_WORLD.rank == 0:
        # Make one big hexagon layout at the center of the focalplane.
        # Compute the number of pixels that is at least the number requested.

        test = args.minpix - 1
        nrings = 0
        while (test - 6 * nrings) > 0:
            test -= 6 * nrings
            nrings += 1

        npix = 1
        for r in range(1, nrings + 1):
            npix += 6 * r

        print("using {} pixels ({} detectors)".format(npix, npix * 2))

        # Translate the field-of-view into distance between flag sides
        angwidth = args.fov * np.cos(30 * degree)

        Apol = tt.hex_pol_angles_qu(npix, offset=0.0)
        Bpol = tt.hex_pol_angles_qu(npix, offset=90.0)

        Adets = tt.hex_layout(npix, angwidth, "fake_", "A", Apol)
        Bdets = tt.hex_layout(npix, angwidth, "fake_", "B", Bpol)

        dets = Adets.copy()
        dets.update(Bdets)

        np.random.seed(args.random_seed)

        for indx, d in enumerate(sorted(dets.keys())):
            dets[d]["fknee"] = args.psd_fknee
            dets[d]["fmin"] = args.psd_fmin
            dets[d]["alpha"] = args.psd_alpha
            dets[d]["NET"] = args.psd_NET
            # This is in degrees, but the input is in arcmin.
            dets[d]["fwhm_deg"] = (args.fwhm / 60.0)  \
                * (1 + np.random.randn()*args.fwhm_sigma)
            # This is a fixed value, in arcmin.
            dets[d]["fwhm"] = args.fwhm
            if args.bandcenter_ghz:
                dets[d]["bandcenter_ghz"] \
                    = args.bandcenter_ghz * (1+np.random.randn()*args.bandcenter_sigma)
            if args.bandwidth_ghz:
                dets[d]["bandwidth_ghz"] \
                    = args.bandwidth_ghz * (1+np.random.randn()*args.bandwidth_sigma)
            dets[d]["index"] = indx

        outfile = "{}_{}".format(args.out, npix)
        qdets = {x: y["quat"] for x, y in dets.items()}
        beams = {x: (60.0 * y["fwhm_deg"]) for x, y in dets.items()}
        tt.plot_focalplane(qdets,
                           args.fov,
                           args.fov,
                           "{}.png".format(outfile),
                           fwhm=beams)

        with open("{}.pkl".format(outfile), "wb") as p:
            pickle.dump(dets, p)

    return
Ejemplo n.º 4
0
def fake_focalplane(
    samplerate: float = 20.,
    epsilon: float = 0.,
    net: float = 1.,
    fmin: float = 0.,
    alpha: float = 1.,
    fknee: float = 0.05,
    fwhm: float = 30.,
    npix: int = 7,
    fov: float = 3.,
) -> Dict[str, Union[float, np.ndarray]]:
    """Create a set of fake detectors.

    This generates 7 pixels (14 dets) in a hexagon layout at the boresight
    and with a made up polarization orientation.

    This function is copied from TOAST workshop with the following license:

    BSD 2-Clause License

    Copyright (c) 2019, hpc4cmb
    All rights reserved.

    Redistribution and use in source and binary forms, with or without
    modification, are permitted provided that the following conditions are met:

    1. Redistributions of source code must retain the above copyright notice, this
    list of conditions and the following disclaimer.

    2. Redistributions in binary form must reproduce the above copyright notice,
    this list of conditions and the following disclaimer in the documentation
    and/or other materials provided with the distribution.

    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
    AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
    DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
    FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
    DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
    SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
    CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
    OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    """
    pol_A = hex_pol_angles_qu(npix)
    pol_B = hex_pol_angles_qu(npix, offset=90.0)

    dets_A = hex_layout(npix, fov, "", "", pol_A)
    dets_B = hex_layout(npix, fov, "", "", pol_B)

    dets = {}
    for p in range(npix):
        pstr = "{:01d}".format(p)
        for d, layout in zip(["A", "B"], [dets_A, dets_B]):
            props = dict()
            props["quat"] = layout[pstr]["quat"]
            props["epsilon"] = epsilon
            props["rate"] = samplerate
            props["alpha"] = alpha
            props["NET"] = net
            props["fmin"] = fmin
            props["fknee"] = fknee
            props["fwhm_arcmin"] = fwhm
            dname = "{}{}".format(pstr, d)
            dets[dname] = props
    return dets
Ejemplo n.º 5
0
#!/usr/bin/env python3

from toast.mpi import MPI

from toast.tod.sim_tod import TODSatellite

from toast.tod import hex_layout, hex_pol_angles_qu

# Create a simple hex focalplane.  This number of detectors might be typical
# for the number per process in a full-machine run.
npix = 37
pol = hex_pol_angles_qu(npix)
fp = hex_layout(npix, 1.0, "det", "", pol)
print(fp, flush=True)

# Write this out to a simple text format
with open("focalplane.txt", "w") as f:
    for det, props in fp.items():
        q = props["quat"]
        f.write("{} {:0.15e} {:0.15e} {:0.15e} {:0.15e}\n".format(
            det, q[0], q[1], q[2], q[3]))

# Use a typical sample rate and simulate data for one observation.  We can
# then repeat this for a typical number of observations to get the right
# data volume.
rate = 100.0
samples = 180000

tod = TODSatellite(MPI.COMM_WORLD,
                   fp,
                   samples,
Ejemplo n.º 6
0
npix = 1
for r in range(1, nrings + 1):
    npix += 6 * r

print("using {} pixels ({} detectors)".format(npix, npix * 2))

fwhm = args.fwhm / 60.0
width = 100.0
# Translate the field-of-view into distance between flag sides
angwidth = args.fov * np.cos(30 * degree)

Apol = tt.hex_pol_angles_qu(npix, offset=0.0)
Bpol = tt.hex_pol_angles_qu(npix, offset=90.0)

Adets = tt.hex_layout(npix, width, angwidth, fwhm, "fake_", "A", Apol)
Bdets = tt.hex_layout(npix, width, angwidth, fwhm, "fake_", "B", Bpol)

dets = Adets.copy()
dets.update(Bdets)

np.random.seed(args.random_seed)

for indx, d in enumerate(sorted(dets.keys())):
    dets[d]["fknee"] = args.psd_fknee
    dets[d]["fmin"] = args.psd_fmin
    dets[d]["alpha"] = args.psd_alpha
    dets[d]["NET"] = args.psd_NET
    dets[d]["fwhm_deg"] = fwhm \
                          * (1 + np.random.randn()*args.fwhm_sigma)
    dets[d]["fwhm"] = dets[d]["fwhm_deg"]  # Support legacy code
Ejemplo n.º 7
0
def main():

    parser = argparse.ArgumentParser(
        description="Simulate fake hexagonal focalplane.",
        fromfile_prefix_chars='@')

    parser.add_argument( "--minpix", required=False, type=int, default=100,
        help="minimum number of pixels to use" )

    parser.add_argument( "--out", required=False, default="fp_fake",
        help="Root name of output pickle file" )

    parser.add_argument( "--fwhm", required=False, type=float, default=5.0,
        help="beam FWHM in arcmin" )

    parser.add_argument( "--fwhm_sigma", required=False, type=float, default=0,
        help="Relative beam FWHM distribution width" )

    parser.add_argument( "--fov", required=False, type=float, default=5.0,
        help="Field of View in degrees" )

    parser.add_argument( "--psd_fknee", required=False, type=float,
        default=0.05, help="Detector noise model f_knee in Hz" )

    parser.add_argument( "--psd_NET", required=False, type=float,
        default=60.0e-6, help="Detector noise model NET in K*sqrt(sec)" )

    parser.add_argument( "--psd_alpha", required=False, type=float,
        default=1.0, help="Detector noise model slope" )

    parser.add_argument( "--psd_fmin", required=False, type=float,
        default=1.0e-5, help="Detector noise model f_min in Hz" )

    parser.add_argument( "--bandcenter_ghz", required=False, type=float,
        help="Band center frequency [GHz]" )

    parser.add_argument( "--bandcenter_sigma", required=False, type=float,
        default=0, help="Relative band center distribution width" )

    parser.add_argument( "--bandwidth_ghz", required=False, type=float,
        help="Bandwidth [GHz]" )

    parser.add_argument( "--bandwidth_sigma", required=False, type=float,
        default=0, help="Relative bandwidth distribution width" )

    parser.add_argument( "--random_seed", required=False, type=np.int,
        default=123456, help="Random number generator seed for randomized "
        "detector parameters" )

    args = timing.add_arguments_and_parse(parser, timing.FILE(noquotes=True))

    # Guard against being called with multiple processes
    if MPI.COMM_WORLD.rank == 0:
        # Make one big hexagon layout at the center of the focalplane.
        # Compute the number of pixels that is at least the number requested.

        test = args.minpix - 1
        nrings = 0
        while (test - 6 * nrings) > 0:
            test -= 6 * nrings
            nrings += 1

        npix = 1
        for r in range(1, nrings+1):
            npix += 6 * r

        print("using {} pixels ({} detectors)".format(npix, npix*2))

        # Translate the field-of-view into distance between flag sides
        angwidth = args.fov * np.cos(30 * degree)

        Apol = tt.hex_pol_angles_qu(npix, offset=0.0)
        Bpol = tt.hex_pol_angles_qu(npix, offset=90.0)

        Adets = tt.hex_layout(npix, angwidth, "fake_", "A", Apol)
        Bdets = tt.hex_layout(npix, angwidth, "fake_", "B", Bpol)

        dets = Adets.copy()
        dets.update(Bdets)

        np.random.seed(args.random_seed)

        for indx, d in enumerate(sorted(dets.keys())):
            dets[d]["fknee"] = args.psd_fknee
            dets[d]["fmin"] = args.psd_fmin
            dets[d]["alpha"] = args.psd_alpha
            dets[d]["NET"] = args.psd_NET
            # This is in degrees, but the input is in arcmin.
            dets[d]["fwhm_deg"] = (args.fwhm / 60.0)  \
                * (1 + np.random.randn()*args.fwhm_sigma)
            # This is a fixed value, in arcmin.
            dets[d]["fwhm"] = args.fwhm
            if args.bandcenter_ghz:
                dets[d]["bandcenter_ghz"] \
                    = args.bandcenter_ghz * (1+np.random.randn()*args.bandcenter_sigma)
            if args.bandwidth_ghz:
                dets[d]["bandwidth_ghz"] \
                    = args.bandwidth_ghz * (1+np.random.randn()*args.bandwidth_sigma)
            dets[d]["index"] = indx

        outfile = "{}_{}".format(args.out, npix)
        qdets = { x : y["quat"] for x, y in dets.items() }
        beams = { x : (60.0*y["fwhm_deg"]) for x, y in dets.items() }
        tt.plot_focalplane(qdets, args.fov, args.fov, "{}.png".format(outfile),
            fwhm=beams)

        with open("{}.pkl".format(outfile), "wb") as p:
            pickle.dump(dets, p)

    return