Exemple #1
0
    def test_science(self):
        set_matplotlib_pdf_backend()
        import matplotlib.pyplot as plt
        test_dir = test_subdir_create("qa_test_science")
        log_file = os.path.join(test_dir, "log.txt")

        np.random.seed(123456789)
        input_mtl = os.path.join(test_dir, "mtl.fits")
        # For this test, we will use just 2 science target classes, in order to verify
        # we get approximately the correct distribution
        sdist = [(3000, 1, 0.25, "QSO"), (2000, 1, 0.75, "ELG")]
        nscience = sim_targets(input_mtl,
                               TARGET_TYPE_SCIENCE,
                               0,
                               density=self.density_science,
                               science_frac=sdist)

        log_msg = "Simulated {} science targets\n".format(nscience)

        tgs = Targets()
        load_target_file(tgs, input_mtl)

        # Read hardware properties
        fp, exclude, state = sim_focalplane(rundate=test_assign_date)
        hw = load_hardware(focalplane=(fp, exclude, state))
        tfile = os.path.join(test_dir, "footprint.fits")
        sim_tiles(tfile)
        tiles = load_tiles(tiles_file=tfile)

        # Precompute target positions
        tile_targetids, tile_x, tile_y = targets_in_tiles(hw, tgs, tiles)
        # Compute the targets available to each fiber for each tile.
        tgsavail = TargetsAvailable(hw, tiles, tile_targetids, tile_x, tile_y)

        # Compute the fibers on all tiles available for each target
        favail = LocationsAvailable(tgsavail)

        # Pass empty map of STUCK positioners that land on good sky
        stucksky = {}

        # Create assignment object
        asgn = Assignment(tgs, tgsavail, favail, stucksky)

        # First-pass assignment of science targets
        asgn.assign_unused(TARGET_TYPE_SCIENCE)

        # Redistribute
        asgn.redistribute_science()

        write_assignment_fits(tiles, asgn, out_dir=test_dir, all_targets=True)

        tile_ids = list(tiles.id)

        merge_results([input_mtl],
                      list(),
                      tile_ids,
                      result_dir=test_dir,
                      copy_fba=False)

        # FIXME:  In order to use the qa_targets function, we need to know the
        # starting requested number of observations (NUMOBS_INIT).  Then we can use
        # that value for each target and compare to the number actually assigned.
        # However, the NUMOBS_INIT column was removed from the merged TARGET table.
        # If we are ever able to reach consensus on restoring that column, then we
        # can re-enable these tests below.
        #
        # qa_targets(
        #     hw,
        #     tiles,
        #     result_dir=test_dir,
        #     result_prefix="fiberassign-"
        # )
        #
        # # Load the target catalog so that we have access to the target properties
        #
        # fd = fitsio.FITS(input_mtl, "r")
        # scidata = np.array(np.sort(fd[1].read(), order="TARGETID"))
        # fd.close()
        # del fd
        #
        # # How many possible positioner assignments did we have?
        # nassign = 5000 * len(tile_ids)
        #
        # possible = dict()
        # achieved = dict()
        #
        # namepat = re.compile(r".*/qa_target_count_(.*)_init-(.*)\.fits")
        # for qafile in glob.glob("{}/qa_target_count_*.fits".format(test_dir)):
        #     namemat = namepat.match(qafile)
        #     name = namemat.group(1)
        #     obs = int(namemat.group(2))
        #     if obs == 0:
        #         continue
        #     fd = fitsio.FITS(qafile, "r")
        #     fdata = fd["COUNTS"].read()
        #     # Sort by target ID so we can select easily
        #     fdata = np.sort(fdata, order="TARGETID")
        #     tgid = np.array(fdata["TARGETID"])
        #     counts = np.array(fdata["NUMOBS_DONE"])
        #     avail = np.array(fdata["NUMOBS_AVAIL"])
        #     del fdata
        #     fd.close()
        #
        #     # Select target properties.  BOTH TARGET LISTS MUST BE SORTED.
        #     rows = np.where(np.isin(scidata["TARGETID"], tgid, assume_unique=True))[0]
        #
        #     ra = np.array(scidata["RA"][rows])
        #     dec = np.array(scidata["DEC"][rows])
        #     dtarget = np.array(scidata["DESI_TARGET"][rows])
        #     init = np.array(scidata["NUMOBS_INIT"][rows])
        #
        #     requested = obs * np.ones_like(avail)
        #
        #     under = np.where(avail < requested)[0]
        #     over = np.where(avail > requested)[0]
        #
        #     limavail = np.array(avail)
        #     limavail[over] = obs
        #
        #     deficit = np.zeros(len(limavail), dtype=np.int)
        #
        #     deficit[:] = limavail - counts
        #     deficit[avail == 0] = 0
        #
        #     possible[name] = np.sum(limavail)
        #     achieved[name] = np.sum(counts)
        #
        #     log_msg += "{}-{}:\n".format(name, obs)
        #
        #     pindx = np.where(deficit > 0)[0]
        #     poor_tgid = tgid[pindx]
        #     poor_dtarget = dtarget[pindx]
        #     log_msg += "  Deficit > 0: {}\n".format(len(poor_tgid))
        #     poor_ra = ra[pindx]
        #     poor_dec = dec[pindx]
        #     poor_deficit = deficit[pindx]
        #
        #     # Plot Target availability
        #     # Commented out by default, since in the case of high target density
        #     # needed for maximizing assignments, there are far more targets than
        #     # the number of available fiber placements.
        #
        #     # marksize = 4 * np.ones_like(deficit)
        #     #
        #     # fig = plt.figure(figsize=(12, 12))
        #     # ax = fig.add_subplot(1, 1, 1)
        #     # ax.scatter(ra, dec, s=2, c="black", marker="o")
        #     # for pt, pr, pd, pdef in zip(poor_tgid, poor_ra, poor_dec, poor_deficit):
        #     #     ploc = plt.Circle(
        #     #         (pr, pd), radius=(0.05*pdef), fc="none", ec="red"
        #     #     )
        #     #     ax.add_artist(ploc)
        #     # ax.set_xlabel("RA", fontsize="large")
        #     # ax.set_ylabel("DEC", fontsize="large")
        #     # ax.set_title(
        #     #     "Target \"{}\": (min(avail, requested) - counts) > 0".format(
        #     #         name, obs
        #     #     )
        #     # )
        #     # #ax.legend(handles=lg, framealpha=1.0, loc="upper right")
        #     # plt.savefig(os.path.join(test_dir, "{}-{}_deficit.pdf".format(name, obs)), dpi=300, format="pdf")
        #
        # log_msg += \
        #     "Assigned {} tiles for total of {} possible target observations\n".format(
        #         len(tile_ids), nassign
        #     )
        # ach = 0
        # for nm in possible.keys():
        #     ach += achieved[nm]
        #     log_msg += \
        #         "  type {} had {} possible target obs and achieved {}\n".format(
        #             nm, possible[nm], achieved[nm]
        #         )
        # frac = 100.0 * ach / nassign
        # log_msg += \
        #     "  {} / {} = {:0.2f}% of fibers were assigned\n".format(
        #         ach, nassign, frac
        #     )
        # for nm in possible.keys():
        #     log_msg += \
        #         "  type {} had {:0.2f}% of achieved observations\n".format(
        #             nm, achieved[nm] / ach
        #         )
        # with open(log_file, "w") as f:
        #     f.write(log_msg)
        #
        # self.assertGreaterEqual(frac,  99.0)

        # Test if qa-fiberassign script runs without crashing
        script = os.path.join(self.binDir, "qa-fiberassign")
        if os.path.exists(script):
            fafiles = glob.glob(f"{test_dir}/fiberassign-*.fits")
            cmd = "{} --targets {}".format(script, " ".join(fafiles))
            err = subprocess.call(cmd.split())
            self.assertEqual(err, 0, f"FAILED ({err}): {cmd}")
        else:
            print(f"ERROR: didn't find {script}")
    def test_full(self):
        test_dir = test_subdir_create("assign_test_full")
        np.random.seed(123456789)
        input_mtl = os.path.join(test_dir, "mtl.fits")
        input_std = os.path.join(test_dir, "standards.fits")
        input_sky = os.path.join(test_dir, "sky.fits")
        nscience = sim_targets(input_mtl, TARGET_TYPE_SCIENCE, 0)
        nstd = sim_targets(input_std, TARGET_TYPE_STANDARD, nscience)
        nsky = sim_targets(input_sky, TARGET_TYPE_SKY, (nscience + nstd))

        tgs = Targets()
        load_target_file(tgs, input_mtl)
        load_target_file(tgs, input_std)
        load_target_file(tgs, input_sky)

        # Create a hierarchical triangle mesh lookup of the targets positions
        tree = TargetTree(tgs, 0.01)

        # Read hardware properties
        fstatus = os.path.join(test_dir, "fiberstatus.ecsv")
        sim_status(fstatus)
        hw = load_hardware(status_file=fstatus)
        tfile = os.path.join(test_dir, "footprint.fits")
        sim_tiles(tfile)
        tiles = load_tiles(tiles_file=tfile)

        # Compute the targets available to each fiber for each tile.
        tgsavail = TargetsAvailable(hw, tgs, tiles, tree)

        # Free the tree
        del tree

        # Compute the fibers on all tiles available for each target
        favail = FibersAvailable(tgsavail)

        # Create assignment object
        asgn = Assignment(tgs, tgsavail, favail)

        # First-pass assignment of science targets
        asgn.assign_unused(TARGET_TYPE_SCIENCE)

        # Redistribute science targets
        asgn.redistribute_science()

        # Assign standards, 10 per petal
        asgn.assign_unused(TARGET_TYPE_STANDARD, 10)
        asgn.assign_force(TARGET_TYPE_STANDARD, 10)

        # Assign sky to unused fibers, up to 40 per petal
        asgn.assign_unused(TARGET_TYPE_SKY, 40)
        asgn.assign_force(TARGET_TYPE_SKY, 40)

        # If there are any unassigned fibers, try to place them somewhere.
        asgn.assign_unused(TARGET_TYPE_SCIENCE)
        asgn.assign_unused(TARGET_TYPE_SKY)

        write_assignment_fits(tiles, asgn, out_dir=test_dir, all_targets=True)

        plot_tiles(hw,
                   tiles,
                   result_dir=test_dir,
                   plot_dir=test_dir,
                   petals=[0],
                   serial=True)

        qa_tiles(hw, tiles, result_dir=test_dir)

        qadata = None
        with open(os.path.join(test_dir, "qa.json"), "r") as f:
            qadata = json.load(f)

        for tile, props in qadata.items():
            self.assertEqual(4495, props["assign_science"])
            self.assertEqual(100, props["assign_std"])
            self.assertEqual(400, props["assign_sky"])

        plot_qa(qadata,
                os.path.join(test_dir, "qa"),
                outformat="pdf",
                labels=True)

        return
Exemple #3
0
    def test_full(self):
        test_dir = test_subdir_create("assign_test_full")
        np.random.seed(123456789)
        input_mtl = os.path.join(test_dir, "mtl.fits")
        input_std = os.path.join(test_dir, "standards.fits")
        input_sky = os.path.join(test_dir, "sky.fits")
        input_suppsky = os.path.join(test_dir, "suppsky.fits")
        tgoff = 0
        nscience = sim_targets(input_mtl,
                               TARGET_TYPE_SCIENCE,
                               tgoff,
                               density=self.density_science)
        tgoff += nscience
        nstd = sim_targets(input_std,
                           TARGET_TYPE_STANDARD,
                           tgoff,
                           density=self.density_standards)
        tgoff += nstd
        nsky = sim_targets(input_sky,
                           TARGET_TYPE_SKY,
                           tgoff,
                           density=self.density_sky)
        tgoff += nsky
        nsuppsky = sim_targets(input_suppsky,
                               TARGET_TYPE_SUPPSKY,
                               tgoff,
                               density=self.density_suppsky)

        tgs = Targets()
        load_target_file(tgs, input_mtl)
        load_target_file(tgs, input_std)
        load_target_file(tgs, input_sky)
        load_target_file(tgs, input_suppsky)

        # Create a hierarchical triangle mesh lookup of the targets positions
        tree = TargetTree(tgs, 0.01)

        # Read hardware properties
        fp, exclude, state = sim_focalplane(rundate=test_assign_date)
        hw = load_hardware(focalplane=(fp, exclude, state))
        tfile = os.path.join(test_dir, "footprint.fits")
        sim_tiles(tfile)
        tiles = load_tiles(tiles_file=tfile)

        # Compute the targets available to each fiber for each tile.
        tgsavail = TargetsAvailable(hw, tgs, tiles, tree)

        # Free the tree
        del tree

        # Compute the fibers on all tiles available for each target
        favail = LocationsAvailable(tgsavail)

        # Create assignment object
        asgn = Assignment(tgs, tgsavail, favail)

        # First-pass assignment of science targets
        asgn.assign_unused(TARGET_TYPE_SCIENCE)

        # Redistribute science targets
        asgn.redistribute_science()

        # Assign standards, 10 per petal
        asgn.assign_unused(TARGET_TYPE_STANDARD, 10)
        asgn.assign_force(TARGET_TYPE_STANDARD, 10)

        # Assign sky to unused fibers, up to 40 per petal
        asgn.assign_unused(TARGET_TYPE_SKY, 40)
        asgn.assign_force(TARGET_TYPE_SKY, 40)

        # Use supplemental sky to meet our requirements
        asgn.assign_unused(TARGET_TYPE_SUPPSKY, 40)
        asgn.assign_force(TARGET_TYPE_SUPPSKY, 40)

        # If there are any unassigned fibers, try to place them somewhere.
        asgn.assign_unused(TARGET_TYPE_SCIENCE)
        asgn.assign_unused(TARGET_TYPE_SKY)
        asgn.assign_unused(TARGET_TYPE_SUPPSKY)

        write_assignment_fits(tiles, asgn, out_dir=test_dir, all_targets=True)

        plotpetals = [0]
        #plotpetals = None
        plot_tiles(hw,
                   tiles,
                   result_dir=test_dir,
                   plot_dir=test_dir,
                   result_prefix="fba-",
                   real_shapes=True,
                   petals=plotpetals,
                   serial=True)

        qa_tiles(hw, tiles, result_dir=test_dir)

        qadata = None
        with open(os.path.join(test_dir, "qa.json"), "r") as f:
            qadata = json.load(f)

        for tile, props in qadata.items():
            self.assertTrue(props["assign_science"] >= 4485)
            self.assertEqual(100, props["assign_std"])
            self.assertTrue(
                (props["assign_sky"] + props["assign_suppsky"]) >= 400)

        plot_qa(qadata,
                os.path.join(test_dir, "qa"),
                outformat="pdf",
                labels=True)
        return
Exemple #4
0
    def test_science(self):
        set_matplotlib_pdf_backend()
        import matplotlib.pyplot as plt
        test_dir = test_subdir_create("qa_test_science")
        log_file = os.path.join(test_dir, "log.txt")

        np.random.seed(123456789)
        input_mtl = os.path.join(test_dir, "mtl.fits")
        # For this test, we will use just 2 science target classes, in order to verify
        # we get approximately the correct distribution
        sdist = [(3000, 1, 0.25, "QSO"), (2000, 1, 0.75, "ELG")]
        nscience = sim_targets(input_mtl,
                               TARGET_TYPE_SCIENCE,
                               0,
                               density=self.density_science,
                               science_frac=sdist)

        log_msg = "Simulated {} science targets\n".format(nscience)

        tgs = Targets()
        load_target_file(tgs, input_mtl)

        # Create a hierarchical triangle mesh lookup of the targets positions
        tree = TargetTree(tgs, 0.01)

        # Read hardware properties
        fp, exclude, state = sim_focalplane(rundate=test_assign_date)
        hw = load_hardware(focalplane=(fp, exclude, state))
        tfile = os.path.join(test_dir, "footprint.fits")
        sim_tiles(tfile)
        tiles = load_tiles(tiles_file=tfile)

        # Compute the targets available to each fiber for each tile.
        tgsavail = TargetsAvailable(hw, tgs, tiles, tree)

        # Free the tree
        del tree

        # Compute the fibers on all tiles available for each target
        favail = LocationsAvailable(tgsavail)

        # Create assignment object
        asgn = Assignment(tgs, tgsavail, favail)

        # First-pass assignment of science targets
        asgn.assign_unused(TARGET_TYPE_SCIENCE)

        # Redistribute
        asgn.redistribute_science()

        write_assignment_fits(tiles, asgn, out_dir=test_dir, all_targets=True)

        tile_ids = list(tiles.id)

        merge_results([input_mtl],
                      list(),
                      tile_ids,
                      result_dir=test_dir,
                      copy_fba=False)

        # if "TRAVIS" not in os.environ:
        #     plot_tiles(
        #         hw,
        #         tiles,
        #         result_dir=test_dir,
        #         plot_dir=test_dir,
        #         real_shapes=True,
        #         serial=True
        #     )

        qa_targets(hw,
                   tiles,
                   result_dir=test_dir,
                   result_prefix="fiberassign-")

        # Load the target catalog so that we have access to the target properties

        fd = fitsio.FITS(input_mtl, "r")
        scidata = np.array(np.sort(fd[1].read(), order="TARGETID"))
        fd.close()
        del fd

        # How many possible positioner assignments did we have?
        nassign = 5000 * len(tile_ids)

        possible = dict()
        achieved = dict()

        namepat = re.compile(r".*/qa_target_count_(.*)_init-(.*)\.fits")
        for qafile in glob.glob("{}/qa_target_count_*.fits".format(test_dir)):
            namemat = namepat.match(qafile)
            name = namemat.group(1)
            obs = int(namemat.group(2))
            if obs == 0:
                continue
            fd = fitsio.FITS(qafile, "r")
            fdata = fd["COUNTS"].read()
            # Sort by target ID so we can select easily
            fdata = np.sort(fdata, order="TARGETID")
            tgid = np.array(fdata["TARGETID"])
            counts = np.array(fdata["NUMOBS_DONE"])
            avail = np.array(fdata["NUMOBS_AVAIL"])
            del fdata
            fd.close()

            # Select target properties.  BOTH TARGET LISTS MUST BE SORTED.
            rows = np.where(
                np.isin(scidata["TARGETID"], tgid, assume_unique=True))[0]

            ra = np.array(scidata["RA"][rows])
            dec = np.array(scidata["DEC"][rows])
            dtarget = np.array(scidata["DESI_TARGET"][rows])
            init = np.array(scidata["NUMOBS_MORE"][rows])

            requested = obs * np.ones_like(avail)

            under = np.where(avail < requested)[0]
            over = np.where(avail > requested)[0]

            limavail = np.array(avail)
            limavail[over] = obs

            deficit = np.zeros(len(limavail), dtype=np.int)

            deficit[:] = limavail - counts
            deficit[avail == 0] = 0

            possible[name] = np.sum(limavail)
            achieved[name] = np.sum(counts)

            log_msg += "{}-{}:\n".format(name, obs)

            pindx = np.where(deficit > 0)[0]
            poor_tgid = tgid[pindx]
            poor_dtarget = dtarget[pindx]
            log_msg += "  Deficit > 0: {}\n".format(len(poor_tgid))
            poor_ra = ra[pindx]
            poor_dec = dec[pindx]
            poor_deficit = deficit[pindx]

            # Plot Target availability
            # Commented out by default, since in the case of high target density
            # needed for maximizing assignments, there are far more targets than
            # the number of available fiber placements.

            # marksize = 4 * np.ones_like(deficit)
            #
            # fig = plt.figure(figsize=(12, 12))
            # ax = fig.add_subplot(1, 1, 1)
            # ax.scatter(ra, dec, s=2, c="black", marker="o")
            # for pt, pr, pd, pdef in zip(poor_tgid, poor_ra, poor_dec, poor_deficit):
            #     ploc = plt.Circle(
            #         (pr, pd), radius=(0.05*pdef), fc="none", ec="red"
            #     )
            #     ax.add_artist(ploc)
            # ax.set_xlabel("RA", fontsize="large")
            # ax.set_ylabel("DEC", fontsize="large")
            # ax.set_title(
            #     "Target \"{}\": (min(avail, requested) - counts) > 0".format(
            #         name, obs
            #     )
            # )
            # #ax.legend(handles=lg, framealpha=1.0, loc="upper right")
            # plt.savefig(os.path.join(test_dir, "{}-{}_deficit.pdf".format(name, obs)), dpi=300, format="pdf")

        log_msg += \
            "Assigned {} tiles for total of {} possible target observations\n".format(
                len(tile_ids), nassign
            )
        ach = 0
        for nm in possible.keys():
            ach += achieved[nm]
            log_msg += \
                "  type {} had {} possible target obs and achieved {}\n".format(
                    nm, possible[nm], achieved[nm]
                )
        frac = 100.0 * ach / nassign
        log_msg += \
            "  {} / {} = {:0.2f}% of fibers were assigned\n".format(
                ach, nassign, frac
            )
        for nm in possible.keys():
            log_msg += \
                "  type {} had {:0.2f}% of achieved observations\n".format(
                    nm, achieved[nm] / ach
                )
        with open(log_file, "w") as f:
            f.write(log_msg)

        self.assertGreaterEqual(frac, 99.0)

        #- Test if qa-fiberassign script runs without crashing
        bindir = os.path.join(os.path.dirname(fiberassign.__file__), '..',
                              '..', 'bin')
        script = os.path.join(os.path.abspath(bindir), 'qa-fiberassign')
        if os.path.exists(script):
            fafiles = glob.glob(f"{test_dir}/fiberassign-*.fits")
            cmd = "{} --targets {}".format(script, " ".join(fafiles))
            err = subprocess.call(cmd.split())
            self.assertEqual(err, 0, f"FAILED ({err}): {cmd}")
        else:
            print(f"ERROR: didn't find {script}")
Exemple #5
0
favail = FibersAvailable(tgsavail)

# Create assignment object
asgn = Assignment(tgs, tgsavail, favail)

# --------------------------------------------------------------------------------------------------
# FIBER ASSIGNMENT PROCESS
#
# Fiber assignment process is carried out here. Results are stored in the Assignment type object.
# --------------------------------------------------------------------------------------------------

# First-pass assignment of science targets
asgn.assign_unused(TARGET_TYPE_SCIENCE)

# Redistribute science targets across available petals
asgn.redistribute_science()

# Assign standards, 10 per petal
asgn.assign_unused(TARGET_TYPE_STANDARD, 10)
asgn.assign_force(TARGET_TYPE_STANDARD, 10)

# Assign sky, up to 40 per petal
asgn.assign_unused(TARGET_TYPE_SKY, 40)
asgn.assign_force(TARGET_TYPE_SKY, 40)

# If there are any unassigned fibers, try to place them somewhere.
asgn.assign_unused(TARGET_TYPE_SCIENCE)
asgn.assign_unused(TARGET_TYPE_SKY)

# --------------------------------------------------------------------------------------------------
# EXTRACTING THE ASSIGNED TARGET IDS