|
| 1 | +#!/usr/bin/env python |
| 2 | + |
| 3 | +""" |
| 4 | +need to set: |
| 5 | +export DESI_TARGET=/global/cfs/cdirs/desi/users/raichoor/fiberassign-designs/fiberassign-pm-lowdec/v0/target |
| 6 | +export DESI_SURVEYOPS=/global/cfs/cdirs/desi/users/raichoor/fiberassign-designs/fiberassign-pm-lowdec/v0/surveyops |
| 7 | +so that the desisurveyops and fiberassign routines find the required products |
| 8 | +""" |
| 9 | + |
| 10 | +import os |
| 11 | +import fitsio |
| 12 | +import numpy as np |
| 13 | +from astropy.io import fits |
| 14 | +from astropy.table import Table, vstack |
| 15 | +from desiutil.log import get_logger |
| 16 | +from desiutil.redirect import stdouterr_redirected |
| 17 | +from desisurveyops.fba_tertiary_design_io import ( |
| 18 | + assert_environ_settings, |
| 19 | + get_fn, |
| 20 | + read_yaml, |
| 21 | + assert_tertiary_settings, |
| 22 | + get_tile_centers_grid, |
| 23 | + create_tiles_table, |
| 24 | + creates_priority_table, |
| 25 | + get_main_primary_priorities, |
| 26 | + get_main_primary_targets, |
| 27 | + get_main_primary_targets_names, |
| 28 | + finalize_target_table, |
| 29 | + assert_files, |
| 30 | + create_targets_assign, |
| 31 | + plot_targets_assign, |
| 32 | +) |
| 33 | +from desitarget.io import read_targets_in_tiles |
| 34 | +from desitarget.targetmask import mws_mask |
| 35 | +from argparse import ArgumentParser |
| 36 | + |
| 37 | +# AR message to ensure that some key settings in the environment are correctly set |
| 38 | +# AR put it at the very top, so that it appears first, and is not redirected |
| 39 | +# AR (=burried) in the log file |
| 40 | +assert_environ_settings() |
| 41 | + |
| 42 | +log = get_logger() |
| 43 | + |
| 44 | + |
| 45 | +def parse(): |
| 46 | + parser = ArgumentParser() |
| 47 | + parser.add_argument( |
| 48 | + "--yamlfn", |
| 49 | + help="path to the tertiary-config-PROGNUMPAD.yaml file", |
| 50 | + type=str, |
| 51 | + default=None, |
| 52 | + ) |
| 53 | + parser.add_argument( |
| 54 | + "--steps", |
| 55 | + help="comma-separated list of steps to execute (default='tiles,priorities,targets,run,diagnosis')", |
| 56 | + type=str, |
| 57 | + default="tiles,priorities,targets,run,diagnosis", |
| 58 | + ) |
| 59 | + parser.add_argument( |
| 60 | + "--dry_run", |
| 61 | + action="store_true", |
| 62 | + help="for the 'run' step, only print the commands on the prompt", |
| 63 | + ) |
| 64 | + parser.add_argument( |
| 65 | + "--log-stdout", |
| 66 | + "--log_stdout", |
| 67 | + action="store_true", |
| 68 | + help="log to stdout instead of redirecting to a file", |
| 69 | + ) |
| 70 | + args = parser.parse_args() |
| 71 | + for kwargs in args._get_kwargs(): |
| 72 | + log.info("{} = {}".format(kwargs[0], kwargs[1])) |
| 73 | + return args |
| 74 | + |
| 75 | +# AR 2x8 tiles |
| 76 | +# see minutes from 2025-02-10 surveyops telecon |
| 77 | +def create_tiles(tileid_start, ntile, obsconds, outfn): |
| 78 | + ras = [70., 85., 100., 150., 165., 180., 195., 210.] |
| 79 | + decs = [-31., -36.] |
| 80 | + tileras, tiledecs = [], [] |
| 81 | + for ra in ras: |
| 82 | + for dec in decs: |
| 83 | + tileras.append(ra) |
| 84 | + tiledecs.append(dec) |
| 85 | + tileras, tiledecs = np.array(tileras), np.array(tiledecs) |
| 86 | + tileids = np.arange(tileid_start, tileid_start + ntile, dtype=int) |
| 87 | + assert tileras.size == ntile |
| 88 | + assert tiledecs.size == ntile |
| 89 | + d = create_tiles_table(tileids, tileras, tiledecs, obsconds) |
| 90 | + d.write(outfn) |
| 91 | + |
| 92 | + |
| 93 | +# AR usual priority scheme (+1 when observed) |
| 94 | +def create_priorities(yamlfn, outfn): |
| 95 | + d = creates_priority_table(yamlfn) |
| 96 | + # AR print |
| 97 | + d.pprint_all() |
| 98 | + for sample in np.unique(d["TERTIARY_TARGET"]): |
| 99 | + sel = d["TERTIARY_TARGET"] == sample |
| 100 | + log.info("priorites for {}: {}".format(sample, d["PRIORITY"][sel].tolist())) |
| 101 | + d.write(outfn) |
| 102 | + |
| 103 | + |
| 104 | +# AR a bit "unusual" approach, as we create here the input targs catalog |
| 105 | +# AR (whereas usually it is provided beforehand) |
| 106 | +# AR the reason is because we retrieve the targets with get_main_primary_targets()... |
| 107 | +# AR the lines of code to retrieve the targets etc are the same than in bin/desi_fba_calibration_inputs |
| 108 | +# AR except we query for 1 DESI radius (and not 3 degrees) |
| 109 | +def create_targets(yamlfn, outfn): |
| 110 | + |
| 111 | + # AR input cat |
| 112 | + mydict = read_yaml(yamlfn)["settings"] |
| 113 | + prognum, targdir, program = mydict["prognum"], mydict["targdir"], mydict["obsconds"] |
| 114 | + mydict = read_yaml(yamlfn)["samples"] |
| 115 | + samples = np.array(list(mydict.keys())) |
| 116 | + initprios = np.array([mydict[sample]["PRIORITY_INIT"] for sample in samples]) |
| 117 | + fns = np.unique([mydict[sample]["FN"] for sample in samples]) |
| 118 | + assert fns.size == 1 |
| 119 | + fn = fns[0] |
| 120 | + checkers = np.unique([mydict[sample]["CHECKER"] for sample in samples]) |
| 121 | + assert checkers.size == 1 |
| 122 | + checker = checkers[0] |
| 123 | + |
| 124 | + # AR parse the custom DESI_TARGET folder |
| 125 | + # AR we use here program=backup |
| 126 | + # AR =(in the yaml file, program=bright, because TOO_BACKUP_HIP does not exist in desitarget...) |
| 127 | + # AR we keep std - there will be 100 duplicates with what fiberassign will pick up - ok |
| 128 | + log.info("DESI_TARGET = {}".format(os.getenv("DESI_TARGET"))) |
| 129 | + t = Table.read(os.path.join(targdir, "tertiary-tiles-{:04d}.ecsv".format(prognum))) |
| 130 | + d = get_main_primary_targets("BACKUP", t["RA"], t["DEC"], dtver="2.2.0", remove_stds=False) |
| 131 | + # AR write, for posterity.. |
| 132 | + d.write(os.path.join(targdir, "inputcats", fn)) |
| 133 | + |
| 134 | + d["TERTIARY_TARGET"] = get_main_primary_targets_names( |
| 135 | + d, |
| 136 | + program, |
| 137 | + tertiary_targets=samples, |
| 138 | + initprios=initprios, |
| 139 | + keep_calib_or_nonstds=True, |
| 140 | + ) |
| 141 | + # AR verify that all rows got assigned a TERTIARY_TARGET |
| 142 | + assert (d["TERTIARY_TARGET"].astype(str) == "-").sum() == 0 |
| 143 | + |
| 144 | + # AR columns we keep |
| 145 | + keys = ["TERTIARY_TARGET", "RA", "DEC", "PMRA", "PMDEC", "REF_EPOCH", "SUBPRIORITY"] |
| 146 | + |
| 147 | + # AR rename with ORIG_ prefix some columns to keep the original information |
| 148 | + # AR + keep then |
| 149 | + for key in [ |
| 150 | + "TARGETID", |
| 151 | + "DESI_TARGET", |
| 152 | + "BGS_TARGET", |
| 153 | + "MWS_TARGET", |
| 154 | + "SCND_TARGET", |
| 155 | + "PRIORITY_INIT", |
| 156 | + ]: |
| 157 | + d[key].name = "ORIG_{}".format(key) |
| 158 | + keys.append("ORIG_{}".format(key)) |
| 159 | + |
| 160 | + # AR cut on columns |
| 161 | + d = d[keys] |
| 162 | + |
| 163 | + # AR do all the proper formatting things |
| 164 | + d = finalize_target_table(d, yamlfn) |
| 165 | + |
| 166 | + # AR write |
| 167 | + d.write(outfn) |
| 168 | + |
| 169 | + |
| 170 | +def main(): |
| 171 | + |
| 172 | + # AR read + assert settings |
| 173 | + mydict = read_yaml(args.yamlfn)["settings"] |
| 174 | + assert_tertiary_settings(mydict) |
| 175 | + prognum, targdir = mydict["prognum"], mydict["targdir"] |
| 176 | + |
| 177 | + # AR set random seed (for SUBPRIORITY reproducibility) |
| 178 | + np.random.seed(mydict["np_rand_seed"]) |
| 179 | + |
| 180 | + # AR tiles file |
| 181 | + if "tiles" in args.steps.split(","): |
| 182 | + tilesfn = get_fn(prognum, "tiles", targdir) |
| 183 | + log.info("run create_tiles() to generate {}".format(tilesfn)) |
| 184 | + create_tiles( |
| 185 | + mydict["tileid_start"], mydict["ntile"], mydict["obsconds"], tilesfn |
| 186 | + ) |
| 187 | + |
| 188 | + # AR priorities file |
| 189 | + if "priorities" in args.steps.split(","): |
| 190 | + priofn = get_fn(prognum, "priorities", targdir) |
| 191 | + log.info("run create_priorities() to generate {}".format(priofn)) |
| 192 | + create_priorities(args.yamlfn, priofn) |
| 193 | + |
| 194 | + # AR targets file |
| 195 | + if "targets" in args.steps.split(","): |
| 196 | + targfn = get_fn(prognum, "targets", targdir) |
| 197 | + log.info("run create_targets() to generate {}".format(targfn)) |
| 198 | + create_targets(args.yamlfn, targfn) |
| 199 | + |
| 200 | + # AR sanity checks + run |
| 201 | + if "run" in args.steps.split(","): |
| 202 | + assert_files(prognum, targdir) |
| 203 | + cmd = "desi_fba_tertiary_wrapper --prognum {} --targdir {} --rundate {} --std_dtver {}".format( |
| 204 | + prognum, targdir, mydict["rundate"], mydict["std_dtver"] |
| 205 | + ) |
| 206 | + if args.dry_run: |
| 207 | + cmd = "{} --dry_run".format(cmd) |
| 208 | + cmd = "{} --custom_too_development".format(cmd) |
| 209 | + log.info(cmd) |
| 210 | + os.system(cmd) |
| 211 | + |
| 212 | + # AR diagnosis |
| 213 | + if "diagnosis" in args.steps.split(","): |
| 214 | + create_targets_assign(prognum, targdir) |
| 215 | + plot_targets_assign(prognum, targdir) |
| 216 | + |
| 217 | + |
| 218 | +if __name__ == "__main__": |
| 219 | + |
| 220 | + args = parse() |
| 221 | + |
| 222 | + if args.log_stdout: |
| 223 | + main() |
| 224 | + else: |
| 225 | + _ = read_yaml(args.yamlfn)["settings"] |
| 226 | + logfn = get_fn(_["prognum"], "log", _["targdir"]) |
| 227 | + with stdouterr_redirected(to=logfn): |
| 228 | + main() |
0 commit comments