1 | #!/bin/env python |
---|
2 | # coding: utf-8 |
---|
3 | # Un programme pour exploiter les données des mires |
---|
4 | # -- Frédéric Meynadier |
---|
5 | |
---|
6 | import string |
---|
7 | from numpy import * |
---|
8 | |
---|
9 | from functions import * |
---|
10 | |
---|
11 | from datetime import * |
---|
12 | |
---|
13 | |
---|
14 | from optparse import OptionParser |
---|
15 | parser = OptionParser() |
---|
16 | parser.add_option("-c","--catalog",dest="catalogfile", |
---|
17 | help="Name of the catalog file") |
---|
18 | parser.add_option("-r","--reference",dest="reference", |
---|
19 | help="Name of the file with reference coordinates") |
---|
20 | parser.add_option("-o","--outputfits",dest="outputfits", |
---|
21 | default="output.fits", |
---|
22 | help="Name of the output fits file") |
---|
23 | parser.add_option("-m","--measurement",dest="measurement", |
---|
24 | default="output.mes", |
---|
25 | help="Name of the output measurement file") |
---|
26 | parser.add_option("--ring",dest="ring", |
---|
27 | default="output.ring", |
---|
28 | help="Name of the output measurement file") |
---|
29 | parser.add_option("-s","--square",dest="square", |
---|
30 | default="output.square", |
---|
31 | help="Name of the output measurement file") |
---|
32 | parser.add_option("-t","--timing",dest="timing", |
---|
33 | help="Name of the input timing file") |
---|
34 | |
---|
35 | |
---|
36 | (options, args) = parser.parse_args () |
---|
37 | |
---|
38 | # Recherche de la date dans un fichier des timings |
---|
39 | # (généré par recup_date, soit : |
---|
40 | # ls -l $1| awk '{print$8 "\t" $7 "\t" $6}' | sort -k2 | sed -e 's/*//' |
---|
41 | # où $1 est le répertoire contenant les .dat non modifiés.) |
---|
42 | # format attendu : nom_fichier phase_cycle date_isoformat |
---|
43 | |
---|
44 | for line in file(options.timing): |
---|
45 | line_s = string.split(line) |
---|
46 | if (len(line_s) > 2): |
---|
47 | nom = line_s[0] [:-4] |
---|
48 | if (nom == options.catalogfile[:-6]): |
---|
49 | dt = datetime.strptime(line_s[2], |
---|
50 | "%Y-%m-%dT%H:%M:%S") |
---|
51 | phase = float(line_s[1]) |
---|
52 | |
---|
53 | # Donner les coordonnées approximatives des 4 repÚres |
---|
54 | |
---|
55 | rep = zeros((4,2)) |
---|
56 | i = 0 |
---|
57 | for line in open(options.reference): |
---|
58 | if ((line[0] != "#") and (line != '\n')): |
---|
59 | spl = string.split(line) |
---|
60 | rep[i][0] = float(spl[0]) |
---|
61 | rep[i][1] = float(spl[1]) |
---|
62 | i+=1 |
---|
63 | |
---|
64 | # Lecture du fichier catalogue |
---|
65 | fields = ["FLUX_MAX", |
---|
66 | "X_IMAGE", |
---|
67 | "Y_IMAGE", |
---|
68 | "THETA_IMAGE", |
---|
69 | "ELONGATION", |
---|
70 | "ELLIPTICITY", |
---|
71 | "FWHM_IMAGE", |
---|
72 | "ERRX2_IMAGE", |
---|
73 | "ERRY2_IMAGE"] |
---|
74 | |
---|
75 | catalog = [] |
---|
76 | for line in open(options.catalogfile): |
---|
77 | if ((line[0] != "#") and (line != '\n')): |
---|
78 | tmp = {} |
---|
79 | spl = string.split(line) |
---|
80 | for i in range(len(fields)): |
---|
81 | tmp[fields[i]] = float(spl[i]) |
---|
82 | tmp['MEAN_DIST_TO_NGBRS']=0 |
---|
83 | catalog.append(tmp) |
---|
84 | |
---|
85 | |
---|
86 | mode_degrade = 0 |
---|
87 | # Recherche de la position des repÚres selon catalogue - attention aux doublons |
---|
88 | real_rep = zeros((4,2)) |
---|
89 | for i in range(4): |
---|
90 | detections = 0 |
---|
91 | for source in catalog: |
---|
92 | pos_source = array([source['X_IMAGE'],source['Y_IMAGE']]) |
---|
93 | max_dist = 5 # pixels |
---|
94 | if ((modulus(rep[i,:] - pos_source)) < max_dist): |
---|
95 | max_dist = modulus(rep[i,:] - pos_source) |
---|
96 | detections +=1 |
---|
97 | real_rep[i,:] = pos_source |
---|
98 | if (detections > 1): |
---|
99 | print "Attention ! ambiguïté pour repÚre ",i,\ |
---|
100 | ", nb de détections :",detections |
---|
101 | |
---|
102 | if (detections ==0): |
---|
103 | print "Erreur ! Pas de détection pour repÚre ",i |
---|
104 | real_rep[i,:]=rep[i,:] |
---|
105 | mode_degrade = 1 |
---|
106 | |
---|
107 | if (mode_degrade==1): |
---|
108 | print "Passage en mode dégradé, sorties réduites" |
---|
109 | |
---|
110 | # Détermination du centre : barycentre des 4 repÚres |
---|
111 | center = array([sum(real_rep[:,0])/4,sum(real_rep[:,1])/4]) |
---|
112 | |
---|
113 | # Vecteurs unitaires de référence |
---|
114 | vec_i = ((real_rep[0,:] - real_rep[1,:])/20 \ |
---|
115 | + (real_rep[3,:] - real_rep[2,:])/20) / 2 |
---|
116 | vec_j = ((real_rep[1,:] - real_rep[2,:])/20 \ |
---|
117 | + (real_rep[0,:] - real_rep[3,:])/20) / 2 |
---|
118 | |
---|
119 | # Détection des noeuds de grille les plus proches de chaque source |
---|
120 | vec_i_2 = dot(vec_i,vec_i) |
---|
121 | vec_j_2 = dot(vec_j,vec_j) |
---|
122 | for source in catalog: |
---|
123 | pos_source = array([source['X_IMAGE'],source['Y_IMAGE']])-center |
---|
124 | # dans le référentiel grille (en projetant sur les vecteurs unitaires) : |
---|
125 | pos_source_grid = array([dot(pos_source,vec_i)/vec_i_2, |
---|
126 | dot(pos_source,vec_j)/vec_j_2]) |
---|
127 | # on arrondit au noeud le plus proche |
---|
128 | knot = pos_source_grid.round() |
---|
129 | # et on calcule la distance entre les deux |
---|
130 | r = modulus(pos_source_grid - knot) |
---|
131 | # enregistrement des résultats |
---|
132 | source['I_GRID'] = knot[0] |
---|
133 | source['J_GRID'] = knot[1] |
---|
134 | source['KNOT_DIST'] = r |
---|
135 | #if (modulus(knot) <1): |
---|
136 | # print source['I_GRID'], source['J_GRID'], source['KNOT_DIST'], pos_source_grid, pos_source,source['X_IMAGE'], source['Y_IMAGE'] |
---|
137 | |
---|
138 | # Chasse aux doublons |
---|
139 | # tableau 81*81 contenant : |
---|
140 | # champ 0 : nb de sources rattachée au noeud |
---|
141 | # champ 1 : distance actuelle entre le noeud et la source |
---|
142 | # champ 2 : index courant de la source dans catalog |
---|
143 | # champ 3 : distance moyenne aux voisins (calculé plus tard) |
---|
144 | lookup_sources = zeros((81,81,4)) |
---|
145 | for si in range(len(catalog)): |
---|
146 | source = catalog[si] |
---|
147 | i = source['I_GRID']+40 |
---|
148 | j = source['J_GRID']+40 |
---|
149 | if ((lookup_sources[i,j,0] < 1) |
---|
150 | or (lookup_sources[i,j,1] > source['KNOT_DIST'])): |
---|
151 | lookup_sources[i,j,2] = si |
---|
152 | lookup_sources[i,j,1] = source['KNOT_DIST'] |
---|
153 | lookup_sources[i,j,0] += 1 |
---|
154 | |
---|
155 | # On élimine le noeud (1,1), trop prÚs du "P" |
---|
156 | lookup_sources[41,41,0] = 0 |
---|
157 | |
---|
158 | # Calcul de la distance moyenne entre noeuds voisins |
---|
159 | |
---|
160 | fen = 2 |
---|
161 | |
---|
162 | shift_list = [] |
---|
163 | |
---|
164 | for i in range(-fen,fen+1): |
---|
165 | for j in range(-fen,fen+1): |
---|
166 | if (i!=0 or j!=0): |
---|
167 | shift_list.append([i,j]) |
---|
168 | |
---|
169 | for i in range(fen,81-fen): |
---|
170 | for j in range(fen,81-fen): |
---|
171 | if (lookup_sources[i,j,0] > 0): |
---|
172 | knot_idx = int(lookup_sources[i,j,2]) |
---|
173 | catalog[knot_idx]['MEAN_DIST_TO_NGBRS'] = 0 |
---|
174 | nb_voisin = 0 |
---|
175 | distance = 0 |
---|
176 | weights = 0 |
---|
177 | pos_source = array([catalog[knot_idx]['X_IMAGE'], |
---|
178 | catalog[knot_idx]['Y_IMAGE']]) |
---|
179 | for shifts in shift_list : |
---|
180 | i_voisin = i + shifts[0] |
---|
181 | j_voisin = j + shifts[1] |
---|
182 | if (lookup_sources[i_voisin,j_voisin,0] > 0): |
---|
183 | neigh_idx = int(lookup_sources[i_voisin,j_voisin,2]) |
---|
184 | nb_voisin +=1 |
---|
185 | pos_voisin = array([catalog[neigh_idx]['X_IMAGE'], |
---|
186 | catalog[neigh_idx]['Y_IMAGE']]) |
---|
187 | distance += modulus(pos_source-pos_voisin) |
---|
188 | weights += modulus(shifts) |
---|
189 | if (nb_voisin > 0): |
---|
190 | catalog[knot_idx]['MEAN_DIST_TO_NGBRS'] = float(distance)/weights |
---|
191 | lookup_sources[i,j,3] = (float(distance)/weights) |
---|
192 | |
---|
193 | cleaned_catalog = [] |
---|
194 | for i in range(81): |
---|
195 | for j in range(81): |
---|
196 | if (lookup_sources[i,j,0] > 0): |
---|
197 | cleaned_catalog.append(catalog[int(lookup_sources[i,j,2])]) |
---|
198 | |
---|
199 | # Sortie du catalogue nettoyé des doublons |
---|
200 | |
---|
201 | of = open('clean.cat','w') |
---|
202 | |
---|
203 | fields = ["FLUX_MAX", |
---|
204 | "X_IMAGE", |
---|
205 | "Y_IMAGE", |
---|
206 | "THETA_IMAGE", |
---|
207 | "ELONGATION", |
---|
208 | "ELLIPTICITY", |
---|
209 | "FWHM_IMAGE", |
---|
210 | "ERRX2_IMAGE", |
---|
211 | "ERRY2_IMAGE", |
---|
212 | "I_GRID", |
---|
213 | "J_GRID", |
---|
214 | "KNOT_DIST", |
---|
215 | "MEAN_DIST_TO_NGBRS"] |
---|
216 | |
---|
217 | fmts = ["%10.3f ", |
---|
218 | "%8.3f ", |
---|
219 | "%8.3f ", |
---|
220 | "%8.3f ", |
---|
221 | "%8.3f ", |
---|
222 | "%8.3f ", |
---|
223 | "%8.3f ", |
---|
224 | "%8.5f ", |
---|
225 | "%8.5f ", |
---|
226 | "%5d ", |
---|
227 | "%5d ", |
---|
228 | "%5.3f ", |
---|
229 | "%8.3f"] |
---|
230 | |
---|
231 | for source in cleaned_catalog: |
---|
232 | outs = "" |
---|
233 | for i in range(len(fields)): |
---|
234 | outs += fmts[i] % source[fields[i]] |
---|
235 | outs += "\n" |
---|
236 | of.write(outs) |
---|
237 | |
---|
238 | of.close() |
---|
239 | |
---|
240 | # Génération d'un fichier fits contenant les résultats |
---|
241 | |
---|
242 | |
---|
243 | import pyfits |
---|
244 | |
---|
245 | #a = zeros((2048,2048)) |
---|
246 | # |
---|
247 | # patches width in pixel: |
---|
248 | ## width = int(modulus(vec_i)) |
---|
249 | |
---|
250 | ## for i in range(len(cleaned_catalog)): |
---|
251 | ## print i |
---|
252 | ## source = cleaned_catalog[i] |
---|
253 | ## pos_source = array([int(source['X_IMAGE']),int(source['Y_IMAGE'])]) |
---|
254 | ## pos_mean_dist = source['MEAN_DIST_TO_NGBRS'] |
---|
255 | ## for rel_x in range(-width,width): |
---|
256 | ## for rel_y in range(-width,width): |
---|
257 | ## rel_vec = array([rel_x,rel_y]) |
---|
258 | ## # Forme du patch : carré |
---|
259 | ## if ( (dot(rel_vec,vec_i) < vec_i_2/2) and |
---|
260 | ## (dot(rel_vec,vec_j) < vec_j_2/2)): |
---|
261 | ## (x,y) = pos_source+rel_vec |
---|
262 | ## if ( x>0 and x<2048 and y>0 and y<2048): |
---|
263 | ## a[x,y] = pos_mean_dist |
---|
264 | |
---|
265 | |
---|
266 | |
---|
267 | a = lookup_sources[:,:,3] |
---|
268 | |
---|
269 | for i in range(81): |
---|
270 | for j in range(81): |
---|
271 | if (a[i,j] > 0): |
---|
272 | a[i,j] = 60.0/a[i,j] |
---|
273 | else : |
---|
274 | a[i,j] = 1.06 |
---|
275 | |
---|
276 | # Interpolation de la case du "P" |
---|
277 | |
---|
278 | a[41,41] = (a[42,41] + a[40,41] + a[41,42] + a[41,40]) /4. |
---|
279 | |
---|
280 | hdu = pyfits.PrimaryHDU(a) |
---|
281 | hdulist = pyfits.HDUList([hdu]) |
---|
282 | |
---|
283 | hdu.writeto(options.outputfits,clobber=True) |
---|
284 | |
---|
285 | |
---|
286 | # Facteur d'échelle moyen |
---|
287 | |
---|
288 | tmp = [] |
---|
289 | for i in range(81): |
---|
290 | for j in range(81): |
---|
291 | if (lookup_sources[i,j,0] == 1): |
---|
292 | tmp.append(lookup_sources[i,j,3]) |
---|
293 | |
---|
294 | |
---|
295 | meas = open(options.measurement,'w') |
---|
296 | |
---|
297 | meas.write("# Moyenne des mesures / Module vec_i / Module vec_j / deltaT (min) / date\n") |
---|
298 | # transfo pixels / arcminutes -> mas / pixel |
---|
299 | moyenne_mesures = 60 * (1. / (sum(tmp)/len(tmp))) |
---|
300 | module_veci = 60 * (1. / modulus(vec_i)) |
---|
301 | module_vecj = 60 * (1. / modulus(vec_j)) |
---|
302 | |
---|
303 | outs = "%10.7f %10.7f %10.7f %7.3f %s\n" % (moyenne_mesures, |
---|
304 | module_veci, |
---|
305 | module_vecj, |
---|
306 | phase, |
---|
307 | dt.isoformat()) |
---|
308 | meas.write(outs) |
---|
309 | |
---|
310 | meas.close() |
---|
311 | |
---|
312 | ## Facteur d'échelle par rapport au centre du champ sur une couronne |
---|
313 | ## représentative du diamÚtre solaire |
---|
314 | |
---|
315 | # Quel noeud est (à peu prÚs) au centre ? |
---|
316 | |
---|
317 | |
---|
318 | dist_mini = 2048 |
---|
319 | i_centre = 0 |
---|
320 | for i in range(len(cleaned_catalog)): |
---|
321 | source = cleaned_catalog[i] |
---|
322 | dist = modulus([source["X_IMAGE"] - 1024, source["Y_IMAGE"] - 1024]) |
---|
323 | if (dist < dist_mini): |
---|
324 | dist_mini = dist |
---|
325 | i_centre = i |
---|
326 | |
---|
327 | #print "Source au centre : ",cleaned_catalog[i_centre] |
---|
328 | |
---|
329 | # On parcourt une couronne de noeuds et on calcule le facteur d'échelle pour chacun |
---|
330 | |
---|
331 | rmin = 14 # en inter-noeud |
---|
332 | rmax = 18 # en inter-noeud |
---|
333 | |
---|
334 | source_centrale = cleaned_catalog[i_centre] |
---|
335 | |
---|
336 | couronne=[] |
---|
337 | |
---|
338 | for source in cleaned_catalog: |
---|
339 | tmp = {} |
---|
340 | dist_knots = modulus([source["I_GRID"] - source_centrale["I_GRID"], |
---|
341 | source["J_GRID"] - source_centrale["J_GRID"]]) |
---|
342 | x_rel = source["X_IMAGE"] - source_centrale["X_IMAGE"] |
---|
343 | y_rel = source["Y_IMAGE"] - source_centrale["Y_IMAGE"] |
---|
344 | dist_pix = modulus([x_rel,y_rel]) |
---|
345 | if ((dist_knots >= rmin) and (dist_knots <= rmax)): |
---|
346 | tmp['ScFact'] = dist_knots * 60. / dist_pix # arcsec / pix |
---|
347 | tmp['r'] = dist_pix |
---|
348 | tmp['theta'] = math.atan(y_rel/x_rel) |
---|
349 | if (x_rel < 0): |
---|
350 | tmp['theta']+=math.pi |
---|
351 | if (tmp['theta'] < 0): |
---|
352 | tmp['theta'] += 2*math.pi |
---|
353 | if (tmp['theta'] >= 2*math.pi): |
---|
354 | tmp['theta'] -= 2*math.pi |
---|
355 | couronne.append(tmp) |
---|
356 | |
---|
357 | output_couronne = file(options.ring,'w') |
---|
358 | |
---|
359 | outs = "# phase: %f date: %s\n" % (phase, |
---|
360 | dt.isoformat()) |
---|
361 | output_couronne.write(outs) |
---|
362 | |
---|
363 | for source in couronne: |
---|
364 | outs = "%f %f %10.7f\n" % (source['r'], |
---|
365 | math.degrees(source['theta']), |
---|
366 | source['ScFact']) |
---|
367 | output_couronne.write(outs) |
---|
368 | |
---|
369 | |
---|
370 | |
---|
371 | output_couronne.close() |
---|
372 | |
---|
373 | # On parcourt un carré de surface équivalente à la couronne définie ci dessus |
---|
374 | # Le facteur d'échelle est calculé par rapport au point opposé du carré |
---|
375 | # soit un cÎté de 28 noeuds |
---|
376 | |
---|
377 | |
---|
378 | # Le centre a été trouvé pour la couronne |
---|
379 | i_cen = cleaned_catalog[i_centre]["I_GRID"] |
---|
380 | j_cen = cleaned_catalog[i_centre]["J_GRID"] |
---|
381 | |
---|
382 | # On se refait un "lookup" simplifié |
---|
383 | |
---|
384 | synthese = zeros((81,81,2)) |
---|
385 | |
---|
386 | for source in cleaned_catalog: |
---|
387 | synthese[source['I_GRID'],source['J_GRID'],0] = source['X_IMAGE'] |
---|
388 | synthese[source['I_GRID'],source['J_GRID'],1] = source['Y_IMAGE'] |
---|
389 | |
---|
390 | valeurs = [] |
---|
391 | for i in range(-14,15): |
---|
392 | vecteur = synthese[i_cen+14,j_cen+i,:] - synthese[i_cen-14,j_cen+i,:] |
---|
393 | valeurs.append(modulus(vecteur)) |
---|
394 | |
---|
395 | valeurs_orth = [] |
---|
396 | for i in range(-14,15): |
---|
397 | vecteur = synthese[i_cen+i,j_cen+14,:] - synthese[i_cen+i,j_cen-14,:] |
---|
398 | valeurs_orth.append(modulus(vecteur)) |
---|
399 | |
---|
400 | for i in range(len(valeurs)): |
---|
401 | if valeurs[i] > 0: |
---|
402 | valeurs[i] = 28*60./valeurs[i] |
---|
403 | |
---|
404 | for i in range(len(valeurs_orth)): |
---|
405 | if valeurs_orth[i] > 0: |
---|
406 | valeurs_orth[i] = 28*60./valeurs_orth[i] |
---|
407 | |
---|
408 | |
---|
409 | # on vire les valeurs aberrantes |
---|
410 | def f(x): |
---|
411 | return ((x < 1.07) and (x > 1.05)) |
---|
412 | |
---|
413 | valeurs = filter(f, valeurs) |
---|
414 | valeurs_orth = filter(f, valeurs_orth) |
---|
415 | |
---|
416 | output_square = open(options.square,'w') |
---|
417 | outs = "# moyennes: %f / %f phase: %f date: %s\n" % (mean(valeurs), |
---|
418 | mean(valeurs_orth), |
---|
419 | phase, |
---|
420 | dt.isoformat()) |
---|
421 | output_square.write(outs) |
---|
422 | |
---|
423 | for valeur in valeurs: |
---|
424 | outs = "%f\n" % (valeur) |
---|
425 | output_square.write(outs) |
---|
426 | |
---|
427 | output_square.write('orth \n') |
---|
428 | |
---|
429 | for valeur in valeurs_orth: |
---|
430 | outs = "%f\n" % (valeur) |
---|
431 | output_square.write(outs) |
---|
432 | |
---|
433 | output_square.close() |
---|
434 | |
---|