Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

patch pseudo metrology for GUIDE3 and GUIDE7 into fp-metrology.csv #108

Merged
merged 3 commits into from
Jul 29, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion bin/write_focal_plane_metrology
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import numpy as np
import yaml
from desimeter.log import get_logger
from pkg_resources import resource_filename
from astropy.table import Table
from astropy.table import Table, vstack
from desimeter.transform.ptl2fp import apply_ptl2fp

parser = argparse.ArgumentParser(formatter_class=argparse.ArgumentDefaultsHelpFormatter,
Expand Down Expand Up @@ -75,6 +75,12 @@ for i in range(patch["X_FP"].size) :
log.info("Replacing LOCATION={} PINHOLE_ID={}".format(patch["LOCATION"][i],patch["PINHOLE_ID"][i]))
spots[:][j] = patch[:][i]

log.info("applying GUIDE3/GUIDE7 patch")
filename = resource_filename('desimeter',"data/fp-metrology-gfa_patch.csv")
log.info(" from {}".format(filename))
gfa_patch = Table.read(filename, format="csv")
spots = vstack([spots, gfa_patch])


spots.write(args.outfile,format='csv',overwrite=True)

Expand Down
265 changes: 265 additions & 0 deletions bin/write_guide3_guide7_patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,265 @@
#!/usr/bin/env python

from astropy.table import Table
from astropy.io import ascii
from pkg_resources import resource_filename
from desimeter.transform.ptl2fp import fp2ptl, ptl2fp
import numpy as np

pinhole_ids = [1, 2, 3, 4]

def _get_pinhole_gfa_coords(pinhole_id):
"""
get x_gfa, y_gfa pinhole coordinates at which to evaluate planar model

Args:
pinhole_id : int, should be one of (1, 2, 3, 4)

Returns:
coords : tuple, (x_gfa, y_gfa) pixel coordinates
"""

assert(pinhole_id in pinhole_ids)

szx = 2048
szy = 1032

xy_gfa_dict = {1 : (0.0, 0.0),
2 : (szx-1.0, 0.0),
3 : (szx-1.0, szy-1.0),
4 : (0.0, szy-1.0)}

coords = xy_gfa_dict[pinhole_id]

return coords

def _get_plane_coeff(petal_loc, coord='X'):
"""
get coefficients of planar surface mapping from x_gfa, y_gfa to x_fp, y_fp

Args:
petal_loc : guide camera petal location in focal plane (0,2,3,5,7,8)
coord : string, should be either 'X' (for X_FP), or 'Y' (for Y_FP)

Returns:
coeff : list of three coefficients specifying planar model
"""

assert(petal_loc in [0, 2, 3, 5, 7, 8])
assert(coord in ['X', 'Y'])

coeff_x_fp = {0: [91.8290008897, 0.0142564754, -0.0046540723],
2: [405.7272754413, 0.0000436514, -0.0149327409],
3: [348.8824487879, -0.0088595464, -0.0120471442],
5: [-91.8627781345, -0.0142609354, 0.0046420089],
7: [-405.7801509760, -0.0000106187, 0.0149351226],
8: [-349.3793836387, 0.0087573071, 0.0121231345]}

coeff_y_fp = {0: [-396.9957752088, 0.0046691204, 0.0141891317],
2: [-35.2976124185, 0.0150007008, 0.0000343108],
3: [210.2297400065, 0.0121055754, -0.0088252019],
5: [396.8617645949, -0.0046561284, -0.0141934371],
7: [35.4811212256, -0.0150023601, -0.0000019735],
8: [-209.8801602520, -0.0121796381, 0.0087240329]}

coeff = coeff_x_fp[petal_loc] if coord == 'X' else coeff_y_fp[petal_loc]

return coeff

def _get_pinhole_xy_fp(petal_loc, pinhole_id):
"""
get pinhole focal plane coordinates according to planar models

Args:
petal_loc : int, one of (0,2,3,5,7,8)
pinhole_id : int, one of (1,2,3,4)

Returns:
fp_coords : tuple, (X_FP, Y_FP)
"""

x_gfa, y_gfa = _get_pinhole_gfa_coords(pinhole_id)

fp_coords = []
for coord in ['X', 'Y']:
coeff = _get_plane_coeff(petal_loc, coord=coord)
coord = coeff[0] + coeff[1]*x_gfa + coeff[2]*y_gfa
fp_coords.append(coord)

return tuple(fp_coords)

def get_ptl_avg(pinhole_id, coord='Z'):
"""
Get petal coordinate by averaging across petals with real metrology

Args:
pinhole_id : int, one of (1,2,3,4)
coord : string, one of 'X', 'Y', 'Z'

Returns:
ptl : float, average petal coordinate for this pinhole_id
"""

assert((coord == 'X') or (coord == 'Y') or (coord == 'Z'))

fname = resource_filename('desimeter',"data/fp-metrology.csv")

tab = ascii.read(fname, format='csv')

tab = tab[(tab['PINHOLE_ID'] == pinhole_id) & (tab['DEVICE_TYPE'] == 'GFA')]

assert(len(tab) == 8)

ptl = np.mean(tab[coord + '_PTL'])

return ptl

def get_fp_avg_guess(petal_loc, pinhole_id):
"""
Retrieve a guess for a pinhole's focal plane coords

Args:
petal_loc: int
pinhole_id: int, one of (1,2,3,4)

Returns:
xyz_fp: tuple
"""
assert(pinhole_id in pinhole_ids)

coords = ['X', 'Y', 'Z']

xyz_ptl = [get_ptl_avg(pinhole_id, coord=coord) for coord in coords]

x_fp, y_fp, _ = ptl2fp(petal_loc, xyz_ptl[0], xyz_ptl[1])

xyz_fp = x_fp[0], y_fp[0], xyz_ptl[2]

return xyz_fp

def _ccd_to_fs_offs(xfp, yfp, zfp):
""" partial copy of fit_gfa2fp """

x01 = np.array( [ xfp[1]-xfp[0], yfp[1]-yfp[0], zfp[1]-zfp[0] ] )
x01 /= np.sqrt(np.sum(x01**2))
x12 = np.array( [ xfp[2]-xfp[1], yfp[2]-yfp[1], zfp[2]-zfp[1] ] )
x12 /= np.sqrt(np.sum(x12**2))
norm_vector= np.cross(x01,x12)

delta_z = 2.23 # mm
delta_x = delta_z*norm_vector[0]/norm_vector[2]
delta_y = delta_z*norm_vector[1]/norm_vector[2]

return delta_x, delta_y

def _derive_ccd_fp_coords(petal_loc=3):

# get initial guess for X_FP, Y_FP, Z_FP of corners by
# averaging the petals with realmetrology

x_fp_guess = []
y_fp_guess = []
z_fp_guess = []

for pinhole_id in pinhole_ids:
xyz_guess = get_fp_avg_guess(petal_loc, pinhole_id)
x_fp_guess.append(xyz_guess[0])
y_fp_guess.append(xyz_guess[1])
z_fp_guess.append(xyz_guess[2])

x_fp_guess = np.array(x_fp_guess)
y_fp_guess = np.array(y_fp_guess)
z_fp_guess = np.array(z_fp_guess)

# evaluate the polynomial at the corner GFA pixel coordinates to
# get FP coords at the focal surface

x_fp_planar = np.array([_get_pinhole_xy_fp(petal_loc, pinhole_id)[0] for pinhole_id in pinhole_ids])
y_fp_planar = np.array([_get_pinhole_xy_fp(petal_loc, pinhole_id)[1] for pinhole_id in pinhole_ids])

n_iter = 10
for i in range(n_iter):
# use the guessed coordinates to derive offsets
delta_x, delta_y = _ccd_to_fs_offs(x_fp_guess, y_fp_guess, z_fp_guess)

# the offsets should be SUBTRACTED from the focal surface FP coords
x_fp_physical = x_fp_planar - delta_x
y_fp_physical = y_fp_planar - delta_y

x_fp_guess = x_fp_physical
y_fp_guess = y_fp_physical

return x_fp_physical, y_fp_physical

def _get_petal_id(petal_loc):
"""convert from petal_loc to petal_id"""

petal_loc2id = {0: 1,
1: 5,
2: 6,
3: 3,
4: 8,
5: 10,
6: 11,
7: 2,
8: 7,
9: 9}

return petal_loc2id[petal_loc]

def _get_gfa_device(petal_loc):
"""convert from petal_loc to GFA device number"""

petal2device = {0: 10,
1: 5,
2: 6,
3: 2,
4: 7,
5: 8,
6: 13,
7: 1,
8: 4,
9: 3}

return petal2device[petal_loc]


results = []
for petal_loc in [3, 7]:
x_fp, y_fp = _derive_ccd_fp_coords(petal_loc=petal_loc)

x_ptl, y_ptl, _ = fp2ptl(petal_loc, x_fp, y_fp)
for pinhole_id in pinhole_ids:
z_ptl = get_ptl_avg(pinhole_id, coord='Z')

petal_id = _get_petal_id(petal_loc)
result = (petal_id, petal_loc, pinhole_id,
x_fp[pinhole_id-1], y_fp[pinhole_id-1],
x_ptl[pinhole_id-1], y_ptl[pinhole_id-1],
z_ptl)

results.append(result)

t = Table()
t['PETAL_ID'] = [r[0] for r in results]
t['PETAL_LOC'] = [r[1] for r in results]
t['DEVICE_LOC'] = ''
t['DEVICE_TYPE'] = 'GFA'
t['PINHOLE_ID'] = [r[2] for r in results]
t['X_PTL'] = [r[5] for r in results]
t['Y_PTL'] = [r[6] for r in results]
t['Z_PTL'] = [r[7] for r in results]
t['X_MNT'] = ''
t['Y_MNT'] = ''
t['Z_MNT'] = ''
t['PTL_SOURCE'] = 'Calculated'
t['PROJ_DISTANCE'] = ''
t['PROVENANCE'] = 'DESI-5784'
t['NOTES'] = [('GFA ' + str(_get_gfa_device(r[1])).zfill(2)) for r in results]
t['X_FP'] = [r[3] for r in results]
t['Y_FP'] = [r[4] for r in results]
t['Z_FP'] = t['Z_PTL'] # this is true in existing fp-metrology.csv file
t['LOCATION'] = ''

outname = resource_filename('desimeter',"data/fp-metrology-gfa_patch.csv")
ascii.write(t, outname, format='csv', fast_writer=False, overwrite=True)
9 changes: 9 additions & 0 deletions py/desimeter/data/fp-metrology-gfa_patch.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
PETAL_ID,PETAL_LOC,DEVICE_LOC,DEVICE_TYPE,PINHOLE_ID,X_PTL,Y_PTL,Z_PTL,X_MNT,Y_MNT,Z_MNT,PTL_SOURCE,PROJ_DISTANCE,PROVENANCE,NOTES,X_FP,Y_FP,Z_FP,LOCATION
3,3,,GFA,1,348.76444805487927,210.07005017983633,-20.952542536599914,,,,Calculated,,DESI-5784,GFA 02,348.70679491687133,210.11786897613584,-20.952542536599914,
3,3,,GFA,2,330.6341880103817,234.8539908374583,-20.767164722593968,,,,Calculated,,DESI-5784,GFA 02,330.57130343607133,234.89798181993584,-20.767164722593968,
3,3,,GFA,3,318.2116618820145,225.75782984628623,-19.332358573025797,,,,Calculated,,DESI-5784,GFA 02,318.1506977658713,225.79919866103583,-19.332358573025797,
3,3,,GFA,4,336.34192192651204,200.9738891886643,-19.51773638703174,,,,Calculated,,DESI-5784,GFA 02,336.2861892466713,201.01908581723583,-19.51773638703174,
2,7,,GFA,1,349.04407428852346,209.67266701045628,-20.952542536599914,,,,Calculated,,DESI-5784,GFA 01,-405.57235990722916,35.467512906826826,-20.952542536599914,
2,7,,GFA,2,331.0072885205292,234.52761740955359,-20.767164722593968,,,,Calculated,,DESI-5784,GFA 01,-405.59409638612914,4.7576817821268245,-20.767164722593968,
2,7,,GFA,3,318.55006408375885,225.47668385675718,-19.332358573025797,,,,Calculated,,DESI-5784,GFA 01,-390.19598498552915,4.755647103626824,-19.332358573025797,
2,7,,GFA,4,336.58684985175313,200.62173345765987,-19.51773638703174,,,,Calculated,,DESI-5784,GFA 01,-390.17424850662917,35.46547822832682,-19.51773638703174,
8 changes: 8 additions & 0 deletions py/desimeter/data/fp-metrology.csv
Original file line number Diff line number Diff line change
Expand Up @@ -5586,3 +5586,11 @@ PETAL_ID,PETAL_LOC,DEVICE_LOC,DEVICE_TYPE,PINHOLE_ID,X_PTL,Y_PTL,Z_PTL,X_MNT,Y_M
11,6,,GIF-T,0,356.9507287827308,202.45975508907802,-19.379952041040358,,,,Calculated,,DESI-4886,Transformed from GFA Metrology,-302.9746945891407,276.83750986418437,-19.379952041040358,
8,4,321,FIF,5,0.0,0.0,0.0,0.0,0.0,0.0,interp,0.0,none,none,194.68450753637484,248.41179725484267,0.0,4321
11,6,541,GIF,3,295.6316672,207.6472784,-14.7505573,0.0,0.0,0.0,interp,0.0,none,0.0,-289.7276321654746,217.54445741827737,-14.7505573,6541
3,3,,GFA,1,348.76444805487927,210.07005017983633,-20.952542536599914,,,,Calculated,,DESI-5784,GFA 02,348.70679491687133,210.11786897613584,-20.952542536599914,
3,3,,GFA,2,330.6341880103817,234.8539908374583,-20.767164722593968,,,,Calculated,,DESI-5784,GFA 02,330.57130343607133,234.89798181993584,-20.767164722593968,
3,3,,GFA,3,318.2116618820145,225.75782984628623,-19.332358573025797,,,,Calculated,,DESI-5784,GFA 02,318.1506977658713,225.79919866103583,-19.332358573025797,
3,3,,GFA,4,336.34192192651204,200.9738891886643,-19.51773638703174,,,,Calculated,,DESI-5784,GFA 02,336.2861892466713,201.01908581723583,-19.51773638703174,
2,7,,GFA,1,349.04407428852346,209.67266701045628,-20.952542536599914,,,,Calculated,,DESI-5784,GFA 01,-405.57235990722916,35.467512906826826,-20.952542536599914,
2,7,,GFA,2,331.0072885205292,234.52761740955359,-20.767164722593968,,,,Calculated,,DESI-5784,GFA 01,-405.59409638612914,4.7576817821268245,-20.767164722593968,
2,7,,GFA,3,318.55006408375885,225.47668385675718,-19.332358573025797,,,,Calculated,,DESI-5784,GFA 01,-390.19598498552915,4.755647103626824,-19.332358573025797,
2,7,,GFA,4,336.58684985175313,200.62173345765987,-19.51773638703174,,,,Calculated,,DESI-5784,GFA 01,-390.17424850662917,35.46547822832682,-19.51773638703174,