# Path: py/fiberassign/utils.py
# def option_list(opts):
# def assert_isoformat_utc(time_str):
# def get_date_cutoff(datetype, cutoff_case):
# def get_svn_version(svn_dir):
# def get_last_line(fn):
# def read_ecsv_keys(fn):
# 
# Path: py/fiberassign/hardware.py
# def radec2xy(hw, tile_ra, tile_dec, tile_obstime, tile_obstheta, tile_obsha,
#              ra, dec, use_cs5, threads=0):
#     '''
#     For the tile pointed at (tilera, tiledec), project the (ra, dec)
#     value into X/Y mm.
# 
#     Args:
#       hw: Hardware object
#       tile_ra (float): Tile RA
#       tile_dec (float): Tile Dec
#       tile_obstime (string): Tile observation time, YYYY-MM-DDTHH:MM:SS / Astropy "isot" format.
#       tile_obstheta (float): Tile "fieldrot" rotation angle.
#       tile_obsha (float): Tile designed Hour Angle, in degrees.
#       ra (numpy array): RA to project, in degrees
#       dec (numpy array): Dec to project, in degrees
#       use_CS5 (bool):  If True, return CS5 coordinates, else curved.
#       threads=0 (int): currently unused; for backward compatibility.
# 
#     Returns:
#       x, y: numpy arrays: the (X, Y) projected locations.
#     '''
#     #xy = hw.radec2xy_multi(
#     #    tile_ra, tile_dec, tile_obstheta, ra, dec, use_cs5, threads=0
#     #)
#     #x = np.array([x for x,y in xy])
#     #y = np.array([y for x,y in xy])
#     from astropy.time import Time
#     from desimeter.fiberassign import fiberassign_radec2xy_cs5, fiberassign_radec2xy_flat
#     # Note that MJD is only used for precession, so no need for
#     # high precision.
#     t = Time(tile_obstime, format='isot')
#     mjd = t.mjd
# 
#     # Don't pass adc[12]: Let desimeter use its pm-alike routines
#     if use_cs5:
#         x, y = fiberassign_radec2xy_cs5(ra, dec, tile_ra, tile_dec, mjd,
#                                         tile_obsha, tile_obstheta)
#     else:
#         x, y = fiberassign_radec2xy_flat(ra, dec, tile_ra, tile_dec, mjd,
#                                          tile_obsha, tile_obstheta)
#     return x,y
# 
# def cs52xy(x, y):
#     '''
#     Converts from CS5 coordinates (mm) into curved focal-plane X,Y coordinates in mm.
# 
#     Args:
#     cs5x (numpy array): CS5 X coord (mm)
#     cs5y (numpy array): CS5 Y coord (mm)
# 
#     Returns:
#     x (numpy array): X coord (mm)
#     y (numpy array): Y coord (mm)
#     '''
#     # There's a change in terminology between the focal-plane team and
#     # the outside world here...
#     from desimeter.transform.pos2ptl import ptl2flat
#     return ptl2flat(x, y)


import numpy as np
import fitsio
from desitarget.targetmask import desi_mask, mws_mask
from desitarget.cmx.cmx_targetmask import cmx_mask
from desitarget.sv1.sv1_targetmask import desi_mask as sv1_mask
from desitarget.sv1.sv1_targetmask import scnd_mask as sv1_scnd_mask
from desitarget.sv2.sv2_targetmask import desi_mask as sv2_mask
from desitarget.sv3.sv3_targetmask import desi_mask as sv3_mask
from desitarget.targets import main_cmx_or_sv
from .utils import Logger, Timer
from .hardware import radec2xy, cs52xy
from ._internal import (TARGET_TYPE_SCIENCE, TARGET_TYPE_SKY,
                        TARGET_TYPE_STANDARD, TARGET_TYPE_SAFE,
                        TARGET_TYPE_SUPPSKY,
                        Target, Targets, TargetsAvailable,
                        LocationsAvailable)
from fiberassign.utils import assert_isoformat_utc, get_date_cutoff
from datetime import datetime
from astropy.time import Time
    from scipy.spatial import KDTree
    tile_y = {}
    tile_xy_cs5 = {}

    target_ids = tgs.ids()
    target_ra, target_dec, target_obscond = tagalong.get_for_ids(
        target_ids, ['RA', 'DEC', 'OBSCOND'])

    kd = _radec2kd(target_ra, target_dec)

    for (tile_id, tile_ra, tile_dec, tile_obscond, tile_ha, tile_obstheta,
         tile_obstime) in zip(
            tiles.id, tiles.ra, tiles.dec, tiles.obscond, tiles.obshourang,
            tiles.obstheta, tiles.obstime):

        print('Tile', tile_id, 'at RA,Dec', tile_ra, tile_dec, 'obscond:', tile_obscond, 'HA', tile_ha, 'obstime', tile_obstime)

        inds = _kd_query_radec(kd, tile_ra, tile_dec, hw.focalplane_radius_deg)
        match = np.flatnonzero(target_obscond[inds] & tile_obscond)
        inds = inds[match]
        del match
        ras  = target_ra [inds]
        decs = target_dec[inds]
        tids = target_ids[inds]
        del inds
        print('Found', len(tids), 'targets near tile and matching obscond')

        x, y = radec2xy(hw, tile_ra, tile_dec, tile_obstime, tile_obstheta,
                        tile_ha, ras, decs, True)
        # Save CS5 mapping
        tile_xy_cs5[tile_id] = dict((tid,(xi,yi)) for tid,xi,yi in zip(tids, x, y))

# Path: py/fiberassign/utils.py
# def option_list(opts):
# def assert_isoformat_utc(time_str):
# def get_date_cutoff(datetype, cutoff_case):
# def get_svn_version(svn_dir):
# def get_last_line(fn):
# def read_ecsv_keys(fn):
# 
# Path: py/fiberassign/hardware.py
# def radec2xy(hw, tile_ra, tile_dec, tile_obstime, tile_obstheta, tile_obsha,
#              ra, dec, use_cs5, threads=0):
#     '''
#     For the tile pointed at (tilera, tiledec), project the (ra, dec)
#     value into X/Y mm.
# 
#     Args:
#       hw: Hardware object
#       tile_ra (float): Tile RA
#       tile_dec (float): Tile Dec
#       tile_obstime (string): Tile observation time, YYYY-MM-DDTHH:MM:SS / Astropy "isot" format.
#       tile_obstheta (float): Tile "fieldrot" rotation angle.
#       tile_obsha (float): Tile designed Hour Angle, in degrees.
#       ra (numpy array): RA to project, in degrees
#       dec (numpy array): Dec to project, in degrees
#       use_CS5 (bool):  If True, return CS5 coordinates, else curved.
#       threads=0 (int): currently unused; for backward compatibility.
# 
#     Returns:
#       x, y: numpy arrays: the (X, Y) projected locations.
#     '''
#     #xy = hw.radec2xy_multi(
#     #    tile_ra, tile_dec, tile_obstheta, ra, dec, use_cs5, threads=0
#     #)
#     #x = np.array([x for x,y in xy])
#     #y = np.array([y for x,y in xy])
#     from astropy.time import Time
#     from desimeter.fiberassign import fiberassign_radec2xy_cs5, fiberassign_radec2xy_flat
#     # Note that MJD is only used for precession, so no need for
#     # high precision.
#     t = Time(tile_obstime, format='isot')
#     mjd = t.mjd
# 
#     # Don't pass adc[12]: Let desimeter use its pm-alike routines
#     if use_cs5:
#         x, y = fiberassign_radec2xy_cs5(ra, dec, tile_ra, tile_dec, mjd,
#                                         tile_obsha, tile_obstheta)
#     else:
#         x, y = fiberassign_radec2xy_flat(ra, dec, tile_ra, tile_dec, mjd,
#                                          tile_obsha, tile_obstheta)
#     return x,y
# 
# def cs52xy(x, y):
#     '''
#     Converts from CS5 coordinates (mm) into curved focal-plane X,Y coordinates in mm.
# 
#     Args:
#     cs5x (numpy array): CS5 X coord (mm)
#     cs5y (numpy array): CS5 Y coord (mm)
# 
#     Returns:
#     x (numpy array): X coord (mm)
#     y (numpy array): Y coord (mm)
#     '''
#     # There's a change in terminology between the focal-plane team and
#     # the outside world here...
#     from desimeter.transform.pos2ptl import ptl2flat
#     return ptl2flat(x, y)


# Path: py/fiberassign/targets.py
import numpy as np
import fitsio
from desitarget.targetmask import desi_mask, mws_mask
from desitarget.cmx.cmx_targetmask import cmx_mask
from desitarget.sv1.sv1_targetmask import desi_mask as sv1_mask
from desitarget.sv1.sv1_targetmask import scnd_mask as sv1_scnd_mask
from desitarget.sv2.sv2_targetmask import desi_mask as sv2_mask
from desitarget.sv3.sv3_targetmask import desi_mask as sv3_mask
from desitarget.targets import main_cmx_or_sv
from .utils import Logger, Timer
from .hardware import radec2xy, cs52xy
from ._internal import (TARGET_TYPE_SCIENCE, TARGET_TYPE_SKY,
                        TARGET_TYPE_STANDARD, TARGET_TYPE_SAFE,
                        TARGET_TYPE_SUPPSKY,
                        Target, Targets, TargetsAvailable,
                        LocationsAvailable)
from fiberassign.utils import assert_isoformat_utc, get_date_cutoff
from datetime import datetime
from astropy.time import Time
    from scipy.spatial import KDTree

    tile_y = {}
    tile_xy_cs5 = {}

    target_ids = tgs.ids()
    target_ra, target_dec, target_obscond = tagalong.get_for_ids(
        target_ids, ['RA', 'DEC', 'OBSCOND'])

    kd = _radec2kd(target_ra, target_dec)

    for (tile_id, tile_ra, tile_dec, tile_obscond, tile_ha, tile_obstheta,
         tile_obstime) in zip(
            tiles.id, tiles.ra, tiles.dec, tiles.obscond, tiles.obshourang,
            tiles.obstheta, tiles.obstime):

        print('Tile', tile_id, 'at RA,Dec', tile_ra, tile_dec, 'obscond:', tile_obscond, 'HA', tile_ha, 'obstime', tile_obstime)

        inds = _kd_query_radec(kd, tile_ra, tile_dec, hw.focalplane_radius_deg)
        match = np.flatnonzero(target_obscond[inds] & tile_obscond)
        inds = inds[match]
        del match
        ras  = target_ra [inds]
        decs = target_dec[inds]
        tids = target_ids[inds]
        del inds
        print('Found', len(tids), 'targets near tile and matching obscond')

        x, y = radec2xy(hw, tile_ra, tile_dec, tile_obstime, tile_obstheta,
                        tile_ha, ras, decs, True)
        # Save CS5 mapping
        tile_xy_cs5[tile_id] = dict((tid,(xi,yi)) for tid,xi,yi in zip(tids, x, y))

        x, y = cs52xy(x, y)