Source code for desispec.focus

"""
desispec.focus
==============

Utility functions for spectrographs focus.
"""

import numpy as np
from desiutil.log import get_logger


RPIXSCALE=2048.


[docs]def piston_and_tilt_to_gauge_offsets(camera_spectro,focus_plane_coefficients) : """ Computes gauge offsets to apply for a given best focus plane as a function of xccd and yccd Args: camera_spectro: str, camera identifier starting with b, r or z for NIR focus_plane_coefficients: array with 3 values (c0,c1,c2), defining the best focus plane offsets: c0+c1*(xccd/2048-1)+c2*(yccd/2048-1) in microns Returns: dictionnary of offsets to apply, in mm, for the "TOP","LEFT" and "RIGHT" gauge """ c=camera_spectro[0].upper() if c=="B" : camera="BLUE" elif c=="R" : camera="RED" elif c=="Z" : camera="NIR" else : raise ValueError("unexpected camera = '{}' (expect r4,b2,z7 ...,)".format(camera_spectro)) log=get_logger() # from outil_tilt.ppt , email from Sandrine on 2020/11/12 x_plate_gauge={} y_plate_gauge={} x_plate_gauge["TOP"]=328/2*np.sin(9*np.pi/180) y_plate_gauge["TOP"]=328/2*np.cos(9*np.pi/180) x_plate_gauge["LEFT"]=-328/2*np.cos(39*np.pi/180) y_plate_gauge["LEFT"]=-328/2*np.sin(39*np.pi/180) x_plate_gauge["RIGHT"]=328/2*np.cos(39*np.pi/180) y_plate_gauge["RIGHT"]=-328/2*np.sin(39*np.pi/180) log.debug("X_PLATE_GAUGE={}".format(x_plate_gauge)) log.debug("Y_PLATE_GAUGE={}".format(y_plate_gauge)) x_pix_gauge={} y_pix_gauge={} for k in ["TOP","LEFT","RIGHT"] : x_pix_gauge[k] = -y_plate_gauge[k]/0.015+2048 if camera.upper() == "BLUE" or camera.upper() == "NIR" : y_pix_gauge[k] = -x_plate_gauge[k]/0.015+2048 elif camera.upper() == "RED" : y_pix_gauge[k] = x_plate_gauge[k]/0.015+2048 else : raise ValueError("don't know camera "+camera) log.debug("X_PIX_GAUGE={}".format(x_pix_gauge)) log.debug("Y_PIX_GAUGE={}".format(y_pix_gauge)) best_focus_gauge_offset = {} for k in ["TOP","LEFT","RIGHT"] : best_focus_gauge_offset[k] = focus_plane_coefficients[0]/1000. + focus_plane_coefficients[1]*(x_pix_gauge[k]/RPIXSCALE-1)/1000.+ focus_plane_coefficients[2]*(y_pix_gauge[k]/RPIXSCALE-1)/1000. log.debug("Best focus gauge offsets = {} mm".format(best_focus_gauge_offset)) return best_focus_gauge_offset
[docs]def test_gauge_offsets() : """ Test function """ # copied from DESI-5084 https://desi.lbl.gov/DocDB/cgi-bin/private/RetrieveFile?docid=5084;filename=DESI_doc_5084_Spectrographs_Tests_Summary_Mayall.xlsx;version=1 # BLUE RED NIR # piston (mm) tilt/X(deg) tilt/Y(deg) piston (mm) tilt/X(deg) tilt/Y(deg) piston (mm) tilt/X(deg) tilt/Y(deg) plane={} plane["SM1"]=[0.076,-0.00722,-0.00722,0.055,-0.01690,0.0252,0.050,-0.01765,0.01377] plane["SM2"]=[0.022,0.0214,0.02661,0.043,0.00854,0.02465,0.042,0.02101,0.00988] plane["SM3"]=[-0.012,0.01487,-0.00906,0.031,0.02189,0.0084,0.034,0.00855,0.0172] plane["SM4"]=[0.082,0.00588,0.0442,0.101,0.01326,0.02309,0.099,0.02772,0.03108] plane["SM5"]=[0.043,0.01552,-0.00571,0.048,0.00313,-0.00067,0.049,0.01882,0.01281] plane["SM6"]=[0.078,-0.0076,0.0023,0.053,0.01989,-0.00802,0.051,0.02632,0.01648] #final @WL final @Mayall #Nir Red Blue Nir Red Blue #Top Left Right Top Left Right Top Left Right Top Left Right Top Left Right Top Left Right gauges={} gauges["SM1"]=[62.988,61.988,62.688,61.190,61.354,61.815,61.650,63.358,61.814,63.037,62.037,62.737,61.302,61.337,61.881,61.722,63.430,61.886] gauges["SM2"]=[62.380,62.214,62.231,60.307,60.707,61.032,62.050,61.967,62.205,62.369,62.313,62.270,60.334,60.708,61.142,61.998,62.085,62.205] gauges["SM3"]=[62.413,62.159,62.476,61.355,60.867,60.420,62.574,62.847,61.843,62.418,62.244,62.487,61.319,60.927,60.508,62.557,62.830,61.827] gauges["SM4"]=[61.681,62.534,62.490,60.633,61.312,61.062,62.696,62.667,62.506,61.694,62.759,62.576,60.707,61.385,61.238,62.747,62.864,62.506] gauges["SM5"]=[62.368,62.647,62.363,61.014,60.984,60.956,62.066,62.911,62.263,62.358,62.758,62.417,61.062,61.032,61.004,62.062,62.963,62.341] gauges["SM6"]=[61.971,62.483,62.674,60.959,61.504,60.886,62.200,62.959,62.082,61.942,62.620,62.738,60.954,61.613,60.959,62.274,63.033,62.156] for cam in ["r"] : for spec in ["SM1","SM2","SM3","SM4","SM5","SM6"] : if cam == "b" : i=0 elif cam == "r" : i=3 elif cam == "z" : i=6 else : raise ValueError("cam={} ???".format(cam)) pixelsize_um = 15. tilt_deg_to_pixel_coeff = np.pi/180. * pixelsize_um * RPIXSCALE focus_plane_coefficients = [ 1000 * plane[spec][i] , tilt_deg_to_pixel_coeff * plane[spec][i+1], tilt_deg_to_pixel_coeff * plane[spec][i+2] ] # um,um/pix log.debug("focus_plane_coefficients = {}".format(focus_plane_coefficients)) if cam == "b" : i=6 elif cam == "r" : i=3 elif cam == "z" : i=0 else : raise ValueError("cam={} ???".format(cam)) # top left right winlight_gauges = np.array([gauges[spec][i+0],gauges[spec][i+1],gauges[spec][i+2]]) mayall_gauges = np.array([gauges[spec][i+0+9],gauges[spec][i+1+9],gauges[spec][i+2+9]]) log.debug("winlight_gauges = {}".format(winlight_gauges)) log.debug("mayall_gauges = {}".format(mayall_gauges)) reported_gauge_offsets = mayall_gauges - winlight_gauges res = piston_and_tilt_to_gauge_offsets(cam,focus_plane_coefficients) my_gauge_offsets = np.array([res[key] for key in ["TOP","LEFT","RIGHT"]]) delta_gauge = my_gauge_offsets - reported_gauge_offsets log.info("cam={} spec={} delta gauge (this code - DESI-5084) = {} mm".format(cam,spec,delta_gauge))