1 | #!/usr/bin/env python |
---|
2 | """ This script is to calculate the HPFs fiber and CFB positions on HET telescope. |
---|
3 | If something is not clear, feel free to drop me an email - Joe Ninan, indiajoe@gmail.com """ |
---|
4 | |
---|
5 | from __future__ import division |
---|
6 | import sys |
---|
7 | import argparse |
---|
8 | import numpy as np |
---|
9 | from scipy.optimize import leastsq |
---|
10 | import matplotlib.pyplot as plt |
---|
11 | from collections import OrderedDict |
---|
12 | ########################################################################## |
---|
13 | # Library of functions we will use later in this calculation. |
---|
14 | ###################################################### |
---|
15 | ### Calculation of general purpose transformation matrix |
---|
16 | #### These are constrained transformation matrix where scaling in x and y is same. |
---|
17 | |
---|
18 | def ScaleMatrix(Scale): |
---|
19 | ScaleMatrix = np.matrix([[Scale,0,0], |
---|
20 | [0,Scale,0], |
---|
21 | [0,0,1]]) |
---|
22 | return ScaleMatrix |
---|
23 | |
---|
24 | def TranslateMatrix(TranX,TranY): |
---|
25 | TranslateMatrix = np.matrix([[1,0,TranX], |
---|
26 | [0,1,TranY], |
---|
27 | [0,0,1]]) |
---|
28 | return TranslateMatrix |
---|
29 | |
---|
30 | def RotMatrix(theta): |
---|
31 | RotMatrix = np.matrix([[np.cos(theta),-np.sin(theta),0], |
---|
32 | [np.sin(theta),np.cos(theta),0], |
---|
33 | [0,0,1]]) |
---|
34 | return RotMatrix |
---|
35 | |
---|
36 | def ReflectYMatrix(): |
---|
37 | ReflectYMatrix = np.matrix([[1,0,0], |
---|
38 | [0,-1,0], |
---|
39 | [0,0,1]]) |
---|
40 | return ReflectYMatrix |
---|
41 | |
---|
42 | def ReflectXMatrix(): |
---|
43 | ReflectXMatrix = np.matrix([[-1,0,0], |
---|
44 | [0,1,0], |
---|
45 | [0,0,1]]) |
---|
46 | return ReflectXMatrix |
---|
47 | |
---|
48 | ################################### |
---|
49 | # Error functions to fit the pramaeters of transformation matrix |
---|
50 | |
---|
51 | # Function to fit the Translate*Rotate*Scale transformation |
---|
52 | def error_funcTRS(p,OldCoords,NewCoords): |
---|
53 | """ Error function to fit the coordinate where parameters are p=[Scale,theta,TranX,TranY] |
---|
54 | which will transform OldCoords to NewCoords |
---|
55 | Fitted transformation is TRS: Translate*Rotate*Scale """ |
---|
56 | RS = np.matmul(RotMatrix(p[1]),ScaleMatrix(p[0])) |
---|
57 | TRS = np.matmul(TranslateMatrix(p[2],p[3]),RS) |
---|
58 | TransformCoords = np.matmul(TRS,OldCoords) |
---|
59 | return np.array(TransformCoords.flatten() - NewCoords.flatten())[0] |
---|
60 | |
---|
61 | # Function to fit the Translate*Rotate*Scale*ParityFlipY transformation |
---|
62 | # Not used for naything now. Just here for completeness |
---|
63 | def error_funcTRSP(p,OldCoords,NewCoords): |
---|
64 | """ Error function to fit the coordinate where parameters are p=[Scale,theta,TranX,TranY] |
---|
65 | which will transform OldCoords to NewCoords |
---|
66 | Fitted transformation is TRSP: Translate*Rotate*Scale*ParityFlipY""" |
---|
67 | SP = np.matmul(ScaleMatrix(p[0]),ReflectYMatrix()) |
---|
68 | RSP = np.matmul(RotMatrix(p[1]),SP) |
---|
69 | TRSP = np.matmul(TranslateMatrix(p[2],p[3]),RSP) |
---|
70 | TransformCoords = np.matmul(TRSP,OldCoords) |
---|
71 | return np.array(TransformCoords.flatten() - NewCoords.flatten())[0] |
---|
72 | |
---|
73 | ############################################################################# |
---|
74 | |
---|
75 | |
---|
76 | # There are three Scenarios of calculation |
---|
77 | |
---|
78 | #HPF fiber head fiber positions in telecentric lens images measured at PSU lab. |
---|
79 | CentroidCoords = OrderedDict() |
---|
80 | CentroidCoords['cCFB'] = (641.7590850208674, 378.2411130588114) |
---|
81 | CentroidCoords['sCFB'] = (373.99530838383396, 644.5011001356886) |
---|
82 | CentroidCoords['oct1'] = (241.7727067933783, 715.9757709056951) |
---|
83 | CentroidCoords['oct2'] = (298.5672272093679, 773.1045874545131) |
---|
84 | CentroidCoords['oct3'] = (717.8617085355628, 248.97764755048598) |
---|
85 | CentroidCoords['oct4'] = (774.8631863343908, 305.7149638147935) |
---|
86 | CentroidCoords['cir1'] = (222.25408901265263, 333.5099840115954) |
---|
87 | CentroidCoords['cir2'] = (273.45298734501097, 270.7847529387491) |
---|
88 | CentroidCoords['cir3'] = (336.04330942778, 222.2177477751225) |
---|
89 | CentroidCoords['cir4'] = (680.1842052725259, 800.6668579582121) |
---|
90 | CentroidCoords['cir5'] = (744.1546788398894, 752.2047326301424) |
---|
91 | CentroidCoords['cir6'] = (793.7851982362772, 688.9766017329656) |
---|
92 | |
---|
93 | def Calculate_all_coordinates_from_scratch(DictOfCoords,MakePlot=False): |
---|
94 | """ |
---|
95 | Scenrio 1 |
---|
96 | Calculates all the coordinates from scratch using new measured positions |
---|
97 | ## Scenario 1: Everything from scratch ############################################ |
---|
98 | |
---|
99 | # When: This is when you suspect the HPF's fiber puck inserted in the HET's focal plane has moved with respect to BIB, LRS2 etc.. |
---|
100 | |
---|
101 | # Things to do: |
---|
102 | # 1. Measure the cCFB and sCFB positions in in ACAM |
---|
103 | # 2. Calculate all of the HPF fiber positions in the fplane.txt file |
---|
104 | # 3. Calculate the offsets in X & Y coordinates for moving from cCFB to science fibers. |
---|
105 | # 4. Calculate the ACAM pixel coordinates for all the fibers. |
---|
106 | |
---|
107 | ### Step 1: Measure the cCFB and sCFB positions in ACAM |
---|
108 | |
---|
109 | # 1. Use the previous estimate of the ACAM coordaintes to bring the star inside cCFB |
---|
110 | # 2. Guide the telescope using a guide probe and offset it to bring the star to the center of cCFB. (You cannot guide on cCFB unless the orientation is constrained later) |
---|
111 | # 3. Once the star is at the center of cCFB of HPF_ACQM, and guiding smoothly on the guide probe. Insert the ACAM and wait for it to stabilise before taking exposure. |
---|
112 | # 4. Take a few exposures, and then retract the ACAM. Make sure star is still at the center of cCFB |
---|
113 | # 5. Repeate the procedure of inserting the ACAM, taking images, retreive,reinsert.. |
---|
114 | # 6. Average the centriods to get a good accurate ACAM pixel position of cCFB. |
---|
115 | # 7. Do the same for sCFB and get its pixel coordinates on ACAM. |
---|
116 | |
---|
117 | ### Step 2: Calculate all of the HPF fiber positions in the fplane.txt file |
---|
118 | # 1. Get the latest ACAM pixel positions of BIB, LRS2R, and LRS2B from https://het.as.utexas.edu:8001/trac/WFUCommissioning/wiki/NightOperations/Commissioning/Results |
---|
119 | # 2. Get the fplane.tx coordinates of BIB, LRS2R, and LRS2B from fplane.txt file |
---|
120 | # 3. Fits a linear transformation matrix to transform ACAM pixel coordinates to fplane.txt coordinates |
---|
121 | |
---|
122 | """ |
---|
123 | try: |
---|
124 | coordsOfACAMcCFB = DictOfCoords['ACAMcCFB'] |
---|
125 | coordsOfACAMsCFB = DictOfCoords['ACAMsCFB'] |
---|
126 | coordsOfBIB = DictOfCoords['BIB'] |
---|
127 | coordsOfLRS2R = DictOfCoords['LRS2R'] |
---|
128 | coordsOfLRS2B = DictOfCoords['LRS2B'] |
---|
129 | fplaneBIB = DictOfCoords['fplaneBIB'] |
---|
130 | fplaneLRS2R = DictOfCoords['fplaneLRS2R'] |
---|
131 | fplaneLRS2B = DictOfCoords['fplaneLRS2B'] |
---|
132 | except KeyError as e: |
---|
133 | print('ERROR: Missing coordinate in input') |
---|
134 | print(e) |
---|
135 | raise |
---|
136 | |
---|
137 | |
---|
138 | ##### First doing the calculation for ACAM coordinates |
---|
139 | |
---|
140 | # Telcentric lens image pixel coordinates of central CFB and side CFB as a matrix for transformation |
---|
141 | PixelCoords = np.matrix([[CentroidCoords['cCFB'][0],CentroidCoords['sCFB'][0]], |
---|
142 | [CentroidCoords['cCFB'][1],CentroidCoords['sCFB'][1]], |
---|
143 | [1,1]]) |
---|
144 | |
---|
145 | #New ACAM image coordinate measurements of (Central CFB & Side CFB) |
---|
146 | # All other coordinates on ACAM is going to depend on this. So make sure you have best measurment possible. |
---|
147 | ACAMcoords = np.matrix([[coordsOfACAMcCFB[0],coordsOfACAMsCFB[0]], |
---|
148 | [coordsOfACAMcCFB[1],coordsOfACAMsCFB[1]], |
---|
149 | [1,1]]) |
---|
150 | |
---|
151 | # Do a least square solution of the TRS transformation from Telecentric image pixel coordinates to ACAM coordinates |
---|
152 | p0 = [0.1,1,1,1] |
---|
153 | pTRS,iter = leastsq(error_funcTRS,p0,args=(PixelCoords,ACAMcoords)) |
---|
154 | print('TRS transformation solution from Telecentric pixels to ACAM') |
---|
155 | print('Scale = {0},theta ={1},TranX ={2},TranY={3}'.format(*pTRS)) |
---|
156 | |
---|
157 | RS = np.matmul(RotMatrix(pTRS[1]),ScaleMatrix(pTRS[0])) |
---|
158 | TRS = np.matmul(TranslateMatrix(pTRS[2],pTRS[3]),RS) |
---|
159 | print('Matrix of transformation : {0}'.format(TRS)) |
---|
160 | |
---|
161 | # We chose TRS instead of TRSP since TRS matches the BIB and IMHP orientaiton |
---|
162 | print('*'*20) |
---|
163 | print('New ACAM positions of two CFBs and all HPF fibers') |
---|
164 | print('*'*20) |
---|
165 | |
---|
166 | ACAMCoordTRS = OrderedDict() |
---|
167 | for fiber in CentroidCoords: |
---|
168 | ACAMCoordTRS[fiber] = np.matmul(TRS,np.matrix([[CentroidCoords[fiber][0]],[CentroidCoords[fiber][1]],[1]])) |
---|
169 | print('{0} : {1:.1f} {2:.1f}'.format(fiber,ACAMCoordTRS[fiber][0,0],ACAMCoordTRS[fiber][1,0])) |
---|
170 | if MakePlot: |
---|
171 | plt.plot(ACAMCoordTRS[fiber][0,0],ACAMCoordTRS[fiber][1,0],'o') |
---|
172 | plt.text(ACAMCoordTRS[fiber][0,0],ACAMCoordTRS[fiber][1,0],fiber+ ' ({0:.1f},{1:.1f})'.format(ACAMCoordTRS[fiber][0,0],ACAMCoordTRS[fiber][1,0])) |
---|
173 | print('*'*20) |
---|
174 | if MakePlot: |
---|
175 | plt.xlabel('X (pixel)') |
---|
176 | plt.ylabel('Y (pixel)') |
---|
177 | plt.title('ACAM pixels') |
---|
178 | plt.show() |
---|
179 | |
---|
180 | |
---|
181 | |
---|
182 | ### ACAM to fplane.txt transformation |
---|
183 | # We shall use BIB, LRS2R, LRS2B to fit the transform. |
---|
184 | |
---|
185 | # New ACAM measurement of BIB, LRS2R, LRS2B |
---|
186 | ACAMbilrlbCoords = np.matrix([[coordsOfBIB[0],coordsOfLRS2R[0],coordsOfLRS2B[0]], |
---|
187 | [coordsOfBIB[1],coordsOfLRS2R[1],coordsOfLRS2B[1]], |
---|
188 | [1,1,1]]) |
---|
189 | |
---|
190 | # Latest fplane.txt coordinates of BIB, LRS2R, LRS2B |
---|
191 | SkybilrlbCoords = np.matrix([[fplaneBIB[0],fplaneLRS2R[0],fplaneLRS2B[0]], |
---|
192 | [fplaneBIB[1],fplaneLRS2R[1],fplaneLRS2B[1]], |
---|
193 | [1,1,1]]) |
---|
194 | |
---|
195 | # Do a least square solution of the TRS transformation from ACAM coordinates to fplane coordinates |
---|
196 | p0 = [0.1,1,1,1] |
---|
197 | pTRS,iter = leastsq(error_funcTRS,p0,args=(ACAMbilrlbCoords,SkybilrlbCoords)) |
---|
198 | print('TRS transformation solution from ACAM coordinates to fplane coordinates') |
---|
199 | print('Scale = {0},theta ={1},TranX ={2},TranY={3}'.format(*pTRS)) |
---|
200 | |
---|
201 | RS = np.matmul(RotMatrix(pTRS[1]),ScaleMatrix(pTRS[0])) |
---|
202 | TRS = np.matmul(TranslateMatrix(pTRS[2],pTRS[3]),RS) |
---|
203 | print('Matrix of transformation : {0}'.format(TRS)) |
---|
204 | |
---|
205 | # Transformation of all the coordinates to fplane.txt Sky coords from ACAM pixels |
---|
206 | print('Sanity Check of calculating the BIB, LRS2R, LRS2B coorindates in fplane') |
---|
207 | print('TRS: BIB, LRS2R, LRS2B in fplane:', np.matmul(TRS, ACAMbilrlbCoords)) |
---|
208 | print('Sanity Check of calculating the cCFB, sCFB coorindates in fplane') |
---|
209 | print('TRS: cCFB, sCFB in fplane:', np.matmul(TRS, ACAMcoords)) |
---|
210 | ############################################### |
---|
211 | # Transformation of all the fiber coordinates |
---|
212 | print('*'*20) |
---|
213 | print('New fplane.txt positions of two CFBs and all HPF fibers') |
---|
214 | print('*'*20) |
---|
215 | SkyCoordTRS = OrderedDict() |
---|
216 | for fiber in ACAMCoordTRS: |
---|
217 | SkyCoordTRS[fiber] = np.matmul(TRS,np.matrix([[ACAMCoordTRS[fiber][0,0]],[ACAMCoordTRS[fiber][1,0]],[1]])) |
---|
218 | print('{0} : {1:.1f} {2:.1f}'.format(fiber,SkyCoordTRS[fiber][0,0],SkyCoordTRS[fiber][1,0])) |
---|
219 | if MakePlot: |
---|
220 | plt.plot(SkyCoordTRS[fiber][0,0],SkyCoordTRS[fiber][1,0],'o') |
---|
221 | plt.text(SkyCoordTRS[fiber][0,0],SkyCoordTRS[fiber][1,0],fiber+ ' ({0:.1f},{1:.1f})'.format(SkyCoordTRS[fiber][0,0],SkyCoordTRS[fiber][1,0])) |
---|
222 | print('*'*20) |
---|
223 | if MakePlot: |
---|
224 | plt.title('fplane.txt') |
---|
225 | plt.xlabel('X (arcsec)') |
---|
226 | plt.ylabel('Y (arcsec)') |
---|
227 | plt.show() |
---|
228 | print('New guider fiducial offset command to go from cCFB to HR Sci fiber is') |
---|
229 | print("""syscmd -T 'Guider1_offset_fiducial(dx_asec={0:.1f},dy_asec={1:.1f},compensate="true")'""".format(SkyCoordTRS['cCFB'][0,0]-SkyCoordTRS['oct3'][0,0], |
---|
230 | SkyCoordTRS['cCFB'][1,0]-SkyCoordTRS['oct3'][1,0])) |
---|
231 | |
---|
232 | return ACAMCoordTRS, SkyCoordTRS |
---|
233 | |
---|
234 | |
---|
235 | |
---|
236 | ### Second Scenario is when there is only an over all shift of the entire focal plane array on ACAM. |
---|
237 | # No shifts of the HPF fiber itself with respect to LRS2 or BIB. |
---|
238 | |
---|
239 | def Calculate_new_ACAMcoordinates_from_old(DictOfOldAndNew,DictOfOldPositions,MakePlot=False): |
---|
240 | """ |
---|
241 | ## Scenario 2: Update the ACAM coordinates after an IHMP take down and IFU install |
---|
242 | # When: This is when there is only an overall shift to correct after IHMP take down and IFU re-install |
---|
243 | |
---|
244 | # Things to do: |
---|
245 | # 1. Get the old ACAM pixels positions of BIB, LRS2R, and LRS2B |
---|
246 | # 2. Get the latest ACAM pixel positions of BIB, LRS2R, and LRS2B from https://het.as.utexas.edu:8001/trac/WFUCommissioning/wiki/NightOperations/Commissioning/Results |
---|
247 | # 3. Fit a linear transformation from the old pixel coordinates to new pixel coordinates |
---|
248 | # 4. Apply the transformation to old HPF acam pixel positions to obtain new pixel coordinates |
---|
249 | |
---|
250 | """ |
---|
251 | try: |
---|
252 | oldBIB = DictOfOldAndNew['oldBIB'] |
---|
253 | oldLRS2R = DictOfOldAndNew['oldLRS2R'] |
---|
254 | oldLRS2B = DictOfOldAndNew['oldLRS2B'] |
---|
255 | newBIB = DictOfOldAndNew['newBIB'] |
---|
256 | newLRS2R = DictOfOldAndNew['newLRS2R'] |
---|
257 | newLRS2B = DictOfOldAndNew['newLRS2B'] |
---|
258 | except KeyError as e: |
---|
259 | print('ERROR: Missing coordinate in input') |
---|
260 | print(e) |
---|
261 | raise |
---|
262 | |
---|
263 | |
---|
264 | # Step 1: |
---|
265 | # Old BIB, LRS2R, LRS2B pixel coordinates in ACAM |
---|
266 | OldACAM_b_lr_lb_Coords = np.matrix([[oldBIB[0], oldLRS2R[0], oldLRS2B[0]], |
---|
267 | [oldBIB[1], oldLRS2R[1], oldLRS2B[1]], |
---|
268 | [1, 1, 1]]) |
---|
269 | |
---|
270 | |
---|
271 | # Step 2: |
---|
272 | # New BIB, LRS2R, LRS2B pixel coordinates in ACAM |
---|
273 | NewACAM_b_lr_lb_Coords = np.matrix([[newBIB[0], newLRS2R[0], newLRS2B[0]], |
---|
274 | [newBIB[1], newLRS2R[1], newLRS2B[1]], |
---|
275 | [1, 1, 1]]) |
---|
276 | |
---|
277 | |
---|
278 | # Step 3: |
---|
279 | # Fit TRS linear transformtion |
---|
280 | p0 = [1,0,0,0] |
---|
281 | pTRS,iter = leastsq(error_funcTRS,p0,args=(OldACAM_b_lr_lb_Coords,NewACAM_b_lr_lb_Coords)) |
---|
282 | print('Scale = {0},theta ={1},TranX ={2},TranY={3}'.format(*pTRS)) |
---|
283 | |
---|
284 | print('Transformation matrix') |
---|
285 | RS = np.matmul(RotMatrix(pTRS[1]),ScaleMatrix(pTRS[0])) |
---|
286 | TRS = np.matmul(TranslateMatrix(pTRS[2],pTRS[3]),RS) |
---|
287 | print(TRS) |
---|
288 | print('Residue/Error in the fitted transform (PredictedNewCoords - NewCoords). This is a consistence and sanity check') |
---|
289 | print(np.matmul(TRS,OldACAM_b_lr_lb_Coords)-NewACAM_b_lr_lb_Coords) |
---|
290 | |
---|
291 | # Step 4 |
---|
292 | # Apply the transformation to old coordinates to obtain new ACAM coordinates |
---|
293 | print('*'*20) |
---|
294 | print('New ACAM positions of old ACAM coordinates') |
---|
295 | print('*'*20) |
---|
296 | NewACAMCoordTRS = OrderedDict() |
---|
297 | for fiber in DictOfOldPositions: |
---|
298 | NewACAMCoordTRS[fiber] = np.matmul(TRS,np.matrix([[DictOfOldPositions[fiber][0]],[DictOfOldPositions[fiber][1]],[1]])) |
---|
299 | print('{0} : {1:.1f} {2:.1f}'.format(fiber,NewACAMCoordTRS[fiber][0,0],NewACAMCoordTRS[fiber][1,0])) |
---|
300 | if MakePlot: |
---|
301 | plt.plot(NewACAMCoordTRS[fiber][0,0],NewACAMCoordTRS[fiber][1,0],'o') |
---|
302 | plt.text(NewACAMCoordTRS[fiber][0,0],NewACAMCoordTRS[fiber][1,0],fiber+ ' ({0:.1f},{1:.1f})'.format(NewACAMCoordTRS[fiber][0,0],NewACAMCoordTRS[fiber][1,0])) |
---|
303 | print('*'*20) |
---|
304 | if MakePlot: |
---|
305 | plt.title('New ACAM coords') |
---|
306 | plt.xlabel('X (pixels)') |
---|
307 | plt.ylabel('Y (pixels)') |
---|
308 | plt.show() |
---|
309 | |
---|
310 | return NewACAMCoordTRS |
---|
311 | |
---|
312 | #################### Third Scenrario |
---|
313 | # fplane positions of the Central CFB and Side CFB are calculated using simultanious measurments with VIRUS |
---|
314 | # We need to transform HPF fibers also to the fplane coordinates using the Lab measurment |
---|
315 | |
---|
316 | def Calculate_all_fplanecoordinates_from_CFBs(DictOfCFBCoords,MakePlot=False): |
---|
317 | """ |
---|
318 | Scenrio 3 |
---|
319 | Calculates all the coordinates from scratch using new measured positions of central and side CFBs |
---|
320 | ## Scenario 3: Fibers based on cCFB and sCFB positions ############################################ |
---|
321 | |
---|
322 | # When: This is when you have new measurmenets of the HPF's cetranl as sied CFBs in the HET's focal plane or ACAM |
---|
323 | |
---|
324 | # Things to do: |
---|
325 | # 1. Measure the cCFB and sCFB positions in fplane positions using VIRUS unit or in ACAM |
---|
326 | # 2. Calculate all of the HPF fiber positions in the fplane.txt file |
---|
327 | # 3. Calculate the offsets in X & Y coordinates for moving from cCFB to science fibers. |
---|
328 | |
---|
329 | ### Step 1: Measure the cCFB and sCFB positions in fplane |
---|
330 | ### Step 2: Calculate all of the HPF fiber positions in the fplane.txt file |
---|
331 | # Fits a linear transformation matrix to transform PSU lab measurments coordinates to fplane.txt coordinates |
---|
332 | |
---|
333 | """ |
---|
334 | try: |
---|
335 | coordsOfcCFB = DictOfCFBCoords['cCFB'] |
---|
336 | coordsOfsCFB = DictOfCFBCoords['sCFB'] |
---|
337 | except KeyError as e: |
---|
338 | print('ERROR: Missing coordinate in input') |
---|
339 | print(e) |
---|
340 | raise |
---|
341 | |
---|
342 | |
---|
343 | ##### First doing the calculation for fplane coordinates |
---|
344 | |
---|
345 | # PSU Telcentric lens image pixel coordinates of central CFB and side CFB as a matrix for transformation |
---|
346 | PixelCoords = np.matrix([[CentroidCoords['cCFB'][0],CentroidCoords['sCFB'][0]], |
---|
347 | [CentroidCoords['cCFB'][1],CentroidCoords['sCFB'][1]], |
---|
348 | [1,1]]) |
---|
349 | |
---|
350 | # New fplane/ACAM coordinate measurements of (Central CFB & Side CFB) |
---|
351 | # All other coordinates on ACAM is going to depend on this. So make sure you have best measurment possible. |
---|
352 | fplanecoords = np.matrix([[coordsOfcCFB[0],coordsOfsCFB[0]], |
---|
353 | [coordsOfcCFB[1],coordsOfsCFB[1]], |
---|
354 | [1,1]]) |
---|
355 | |
---|
356 | # Do a least square solution of the TRS transformation from Telecentric image pixel coordinates to fplane/ACAM coordinates |
---|
357 | p0 = [0.1,1,1,1] |
---|
358 | pTRS,iter = leastsq(error_funcTRS,p0,args=(PixelCoords,fplanecoords)) |
---|
359 | print('TRS transformation solution from Telecentric pixels to fplane') |
---|
360 | print('Scale = {0},theta ={1},TranX ={2},TranY={3}'.format(*pTRS)) |
---|
361 | |
---|
362 | RS = np.matmul(RotMatrix(pTRS[1]),ScaleMatrix(pTRS[0])) |
---|
363 | TRS = np.matmul(TranslateMatrix(pTRS[2],pTRS[3]),RS) |
---|
364 | print('Matrix of transformation : {0}'.format(TRS)) |
---|
365 | |
---|
366 | # We chose TRS instead of TRSP since TRS matches the fplane orientaiton to PSU telecentric coordinates |
---|
367 | print('*'*20) |
---|
368 | print('New fplane positions of two CFBs and all HPF fibers') |
---|
369 | print('*'*20) |
---|
370 | |
---|
371 | fplaneCoordTRS = OrderedDict() |
---|
372 | for fiber in CentroidCoords: |
---|
373 | fplaneCoordTRS[fiber] = np.matmul(TRS,np.matrix([[CentroidCoords[fiber][0]],[CentroidCoords[fiber][1]],[1]])) |
---|
374 | print('{0} : {1:.1f} {2:.1f}'.format(fiber,fplaneCoordTRS[fiber][0,0],fplaneCoordTRS[fiber][1,0])) |
---|
375 | if MakePlot: |
---|
376 | plt.plot(fplaneCoordTRS[fiber][0,0],fplaneCoordTRS[fiber][1,0],'o') |
---|
377 | plt.text(fplaneCoordTRS[fiber][0,0],fplaneCoordTRS[fiber][1,0],fiber+ ' ({0:.1f},{1:.1f})'.format(fplaneCoordTRS[fiber][0,0],fplaneCoordTRS[fiber][1,0])) |
---|
378 | print('*'*20) |
---|
379 | if MakePlot: |
---|
380 | plt.title('fplane.txt') |
---|
381 | plt.xlabel('X (arcsec)') |
---|
382 | plt.ylabel('Y (arcsec)') |
---|
383 | plt.show() |
---|
384 | |
---|
385 | |
---|
386 | print('New guider fiducial offset command to go from cCFB to HR Sci fiber is') |
---|
387 | print("""syscmd -T 'Guider1_offset_fiducial(dx_asec={0:.1f},dy_asec={1:.1f},compensate="true")'""".format(fplaneCoordTRS['cCFB'][0,0]-fplaneCoordTRS['oct3'][0,0], |
---|
388 | fplaneCoordTRS['cCFB'][1,0]-fplaneCoordTRS['oct3'][1,0])) |
---|
389 | |
---|
390 | return fplaneCoordTRS |
---|
391 | |
---|
392 | |
---|
393 | |
---|
394 | ##################################################################################################### |
---|
395 | def LoadInputCoordsFile(inpfilename): |
---|
396 | """ Loads and returns the coordinates in the input file as a dictionary. |
---|
397 | All blank lines and comments starting with # are ignored. |
---|
398 | Inlines comments startting with # are ignored. |
---|
399 | Valid line format is as follows |
---|
400 | FiberName = Xcoord , Ycoords # Any optional inline comment which will be ignored |
---|
401 | """ |
---|
402 | CoordsDic = OrderedDict() |
---|
403 | with open(inpfilename,'r') as inpfile: |
---|
404 | for line in inpfile: |
---|
405 | line = line.rstrip() |
---|
406 | if (len(line) < 1) or (line[0] =='#'): # Ignore blank lines and comment lines starting with # |
---|
407 | continue |
---|
408 | line = line.split('#')[0] # Ignore inline comments after # |
---|
409 | name = line.split('=')[0].strip() |
---|
410 | value = tuple(float(c.strip()) for c in line.split('=')[1].strip().split(',')) |
---|
411 | CoordsDic[name]=value |
---|
412 | return CoordsDic |
---|
413 | |
---|
414 | def parse_args(): |
---|
415 | """ Parses the command line input arguments""" |
---|
416 | parser = argparse.ArgumentParser(description="Script to calculate the HPFs fiber and CFB positions on HET telescope.") |
---|
417 | parser.add_argument('--ShowPlots', action='store_true', help='Show Plots') |
---|
418 | subparsers = parser.add_subparsers(help='Choose one of the subcommands below and add -h flag for more help') |
---|
419 | |
---|
420 | parser_a = subparsers.add_parser('fromscratch', help='Calculate both ACAM positions as well as fplane positions using cCFB and sCFB') |
---|
421 | parser_a.add_argument('MeasuredCoordsFile', type=str, |
---|
422 | help="Input Coords file containing the New ACAM image coordinate measurements of (Central CFB & Side CFB), BIB, LRS2R, LRS2B, and Latest fplane.txt coordinates of BIB, LRS2R, LRS2B. See the example file for the keywords and format to use.") |
---|
423 | parser_a.set_defaults(command='fromscratch') |
---|
424 | |
---|
425 | parser_b = subparsers.add_parser('old2newacam', help='Calculate new ACAM positions based on old ACAM positions') |
---|
426 | parser_b.add_argument('OldAndNewCoordsFile', type=str, |
---|
427 | help="Input Coords file containing the Old BIB, LRS2R, LRS2B pixel coordinates in ACAM as well as new BIB, LRS2R, LRS2B pixel coordinates in ACAM. See the example file for the keywords and format to use.") |
---|
428 | parser_b.add_argument('OldCoordsToRecalculate', type=str, |
---|
429 | help="Input Coords file containing the Old pixel coordinates of HPF fibers in ACAM which needs to be recalculated. See the example file for the format to use.") |
---|
430 | parser_b.set_defaults(command='old2newacam') |
---|
431 | |
---|
432 | parser_c = subparsers.add_parser('newfplane', help='Calculate new fplane positions based on new fplane position measurement of cCFB and sCFB') |
---|
433 | parser_c.add_argument('MeasuredCFBfplaneCoordsFile', type=str, |
---|
434 | help="Input Coords file containing the new fplane coordinate measurements of Central CFB (cCFB) & Side CFB (cCFB). See the example file for the keywords and format to use.") |
---|
435 | parser_c.set_defaults(command='newfplane') |
---|
436 | |
---|
437 | args = parser.parse_args() |
---|
438 | return args |
---|
439 | |
---|
440 | |
---|
441 | def main(): |
---|
442 | """ Standalone Script to calculate new HPF fiber positions on HET focal plan or ACAM""" |
---|
443 | # Parse input arguments |
---|
444 | args = parse_args() |
---|
445 | if args.command == 'fromscratch': |
---|
446 | DictOfCoords = LoadInputCoordsFile(args.MeasuredCoordsFile) |
---|
447 | _ = Calculate_all_coordinates_from_scratch(DictOfCoords,MakePlot=args.ShowPlots) |
---|
448 | |
---|
449 | elif args.command == 'old2newacam': |
---|
450 | DictOfOldAndNew = LoadInputCoordsFile(args.OldAndNewCoordsFile) |
---|
451 | DictOfOldPositions = LoadInputCoordsFile(args.OldCoordsToRecalculate) |
---|
452 | _ = Calculate_new_ACAMcoordinates_from_old(DictOfOldAndNew,DictOfOldPositions,MakePlot=args.ShowPlots) |
---|
453 | |
---|
454 | elif args.command == 'newfplane': |
---|
455 | DictOfCFBCoords = LoadInputCoordsFile(args.MeasuredCFBfplaneCoordsFile) |
---|
456 | _ = Calculate_all_fplanecoordinates_from_CFBs(DictOfCFBCoords,MakePlot=args.ShowPlots) |
---|
457 | |
---|
458 | print('-'*20) |
---|
459 | |
---|
460 | |
---|
461 | if __name__ == '__main__': |
---|
462 | main() |
---|