IIINSTRUMENT Pipeline Reference Manual 4.4.3
visir_img_phot.c
1/*
2 * This file is part of the VISIR Pipeline
3 * Copyright (C) 2002,2003,2013,2014 European Southern Observatory
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02111-1307 USA
18 */
19
20#ifdef HAVE_CONFIG_H
21#include <config.h>
22#endif
23
24
25/*-----------------------------------------------------------------------------
26 Includes
27 -----------------------------------------------------------------------------*/
28
29#include "visir_recipe.h"
30#include "visir_pfits.h"
31#include "irplib_strehl.h"
32#include "irplib_framelist.h"
33
34#include <string.h>
35#include <float.h>
36
37#define SQR(a) ((a) * (a))
38
39/*-----------------------------------------------------------------------------
40 Define
41 -----------------------------------------------------------------------------*/
42
43#define VISIR_IMG_PHOT_POS_WARN 10.0
44#define VISIR_IMG_PHOT_POS_ERROR 25.0
45#define VISIR_IMG_PHOT_POS_UNCERTAINTY 10.0
46#define STREHL_M1 8.0
47#define STREHL_M2 1.1
48#define STREHL_BOX_SIZE 64
49#define STREHL_STAR_RADIUS 2.0
50#define STREHL_BG_R1 2.0
51#define STREHL_BG_R2 3.0
52
53#define RECIPE_STRING "visir_old_img_phot"
54/* still used by chain recipe internally, so keep name for output */
55#define RECIPE_SAVE_STRING "visir_img_phot"
56
57
58/* FITS keys to be loaded for all raw files */
59#define RECIPE_KEYS_REGEXP_ALL \
60 VISIR_PFITS_REGEXP_IMG_RECOMBINE \
61 "|" VISIR_PFITS_REGEXP_IMG_SENSIT
62
63/* FITS keys to be loaded for first raw file */
64#define RECIPE_KEYS_REGEXP \
65 RECIPE_KEYS_REGEXP_ALL \
66 "|" VISIR_PFITS_IMG_PHOT_COPY \
67 "|" VISIR_PFITS_REGEXP_IMG_PHOT_PAF
68
69/* FITS keys to be loaded for first raw file, in case WCS is used */
70#define RECIPE_KEYS_REGEXP_WCS \
71 RECIPE_KEYS_REGEXP \
72 "|" IRPLIB_PFITS_WCS_REGEXP
73
74
75/*-----------------------------------------------------------------------------
76 Private Functions prototypes
77 -----------------------------------------------------------------------------*/
78
79typedef struct beamshape_ {
80 /* simple fwhm in x and y from cpl, very inaccurate */
81 double fwhm_x, fwhm_y;
82 /* fwhm from gauss fit */
83 double peak, peak_err;
84 double major, major_err;
85 double minor, minor_err;
86 double angle, angle_err;
87} beamshape_t;
88
89
90static double visir_img_phot_eccent_four(const cpl_apertures *, int, int,
91 const cpl_apertures *, int, int);
92
93static int visir_img_phot_flux_one(const cpl_image *, const cpl_image *,
94 const cpl_image *, const cpl_propertylist *);
95#ifdef VISIR_IMG_PHOT_USE_ECCENT_THREE
96static double visir_img_phot_eccent_three(const cpl_apertures *, int,
97 const cpl_apertures *, int, int);
98#endif
99
100static double visir_img_phot_jy_from_cat(const char *, const char *, double,
101 double, const char *);
102static int visir_img_phot_sensit(const cpl_image *, const cpl_image *,
103 const cpl_image *, const irplib_framelist *,
104 const char *, cpl_boolean, cpl_propertylist *);
105static int visir_img_phot_flux_three(const cpl_image *);
106static int visir_img_phot_flux_four(const cpl_image *);
107static int visir_img_phot_flux(const cpl_image *, const cpl_image *,
108 const cpl_image *, double,
109 double, int, int, int, double *,
110 double *, int *, double *, beamshape_t *);
111
112static cpl_error_code visir_get_filter_infos(const char *, double *, double *);
113
114static cpl_error_code visir_img_phot_qc(cpl_propertylist *,
115 cpl_boolean,
116 const irplib_framelist *);
117
118static cpl_error_code visir_img_phot_save(cpl_frameset *,
119 const cpl_parameterlist *,
120 const cpl_propertylist *,
121 const cpl_image *,
122 const cpl_image *,
123 const cpl_image *,
124 const cpl_image *,
125 const cpl_image *);
126
127static char * visir_img_phot_filter2label(const char *);
128
129#ifdef VISIR_CHAIN
130#define cpl_plugin_get_info visir_old_img_phot_get_info
131#endif
132VISIR_RECIPE_DEFINE(visir_old_img_phot,
133 VISIR_PARAM_RADII | VISIR_PARAM_JYVAL |
134 VISIR_PARAM_REFINE | VISIR_PARAM_XCORR |
135 VISIR_PARAM_OFFSETS | VISIR_PARAM_OBJECTS |
136 VISIR_PARAM_NODPOS | VISIR_PARAM_AUTOBPM |
137 VISIR_PARAM_GLITCH | VISIR_PARAM_PURGE |
138 VISIR_PARAM_UNION | VISIR_PARAM_REJECT |
139 VISIR_PARAM_COMBINE | VISIR_PARAM_ECCMAX |
140 VISIR_PARAM_STRIPITE | VISIR_PARAM_STRIPMOR |
141 VISIR_PARAM_PLOT,
142 "Old DRS detector: Sensitivity computation",
143 "This recipe computes the conversion factor and the "
144 "sentitivity of a\n"
145 "standard star. It requires a standard star catalog.\n"
146 "The files listed in the Set Of Frames (sof-file) "
147 "must be tagged:\n"
148 "VISIR-std-star-observation.fits " VISIR_IMG_PHOT_RAW
149 "\n"
150 "VISIR-Imaging-Standard-Star-Catalog.fits "
151 VISIR_IMA_STD_CAT_PROCATG "\n"
152 "\n"
153 "The primary product will have a FITS card\n"
154 "'HIERARCH " CPL_DFS_PRO_CATG "' with a string value of\n"
155 "'" VISIR_IMG_PHOT_COMBINED_PROCATG "'\n"
156 " and the corresponding beam-collapsed product will "
157 "have a FITS card\n"
158 "'HIERARCH " CPL_DFS_PRO_CATG "' with a value of\n"
159 VISIR_IMG_PHOT_ONEBEAM_PROCATG
160 "\n"
161 MAN_VISIR_CALIB_BPM_IMG);
162
163/*-----------------------------------------------------------------------------
164 Static variables
165 -----------------------------------------------------------------------------*/
166
167static const int fits_strlen = IRPLIB_FITS_STRLEN;
168
169static struct {
170 /* Inputs */
171 double jy_val;
172 int r0_max;
173 int r1;
174 int r2;
175
176 /* Outputs */
177 double exptime;
178 double pscale;
179 char star_name[IRPLIB_FITS_STRLEN+1];
180 char filter[IRPLIB_FITS_STRLEN+1];
181 double bg_sigma;
182 double flux_snr;
183 double flux_snr_noise;
184 int flux_snr_radius[4];
185 double flux_tot;
186 double nelec;
187 double nphot;
188 beamshape_t beamshape;
189 double fwhm_x_pos1;
190 double fwhm_y_pos1;
191 double fwhm_x_pos2;
192 double fwhm_y_pos2;
193 double fwhm_x_neg1;
194 double fwhm_y_neg1;
195 double fwhm_x_neg2;
196 double fwhm_y_neg2;
197 double sensitivity;
198 double area_sensit;
199 double conversion;
200 double strehl;
201 double strehl_err;
202} visir_img_phot_config;
203
204
205/*----------------------------------------------------------------------------*/
209/*----------------------------------------------------------------------------*/
210
211/*-----------------------------------------------------------------------------
212 Functions code
213 -----------------------------------------------------------------------------*/
214
215
216static cpl_error_code
217propagate_qc_header(cpl_propertylist * qclist, const cpl_propertylist * ppqc)
218{
219 double d;
220 int i;
221 const char * s;
222
223 s = cpl_propertylist_get_string(ppqc, "BUNIT");
224 cpl_propertylist_append_string(qclist, "BUNIT", s);
225
226 s = cpl_propertylist_get_string(ppqc, "ESO DRS CATG");
227 cpl_propertylist_append_string(qclist, "ESO DRS CATG", s);
228
229 d = cpl_propertylist_get_double(ppqc, "ESO QC BACKGD MEAN");
230 cpl_propertylist_append_double(qclist, "ESO QC BACKGD MEAN", d);
231
232 d = cpl_propertylist_get_double(ppqc, "ESO QC EXPTIME EFFECTIVE");
233 cpl_propertylist_append_double(qclist, "ESO QC EXPTIME EFFECTIVE", d);
234
235 if (cpl_propertylist_has(ppqc, "ESO QC EXECTIME")) {
236 d = cpl_propertylist_get_double(ppqc, "ESO QC EXECTIME");
237 cpl_propertylist_append_double(qclist, "ESO QC EXECTIME", d);
238 }
239
240 i = cpl_propertylist_get_int(ppqc, "ESO QC NIMAGES TOTAL");
241 cpl_propertylist_append_int(qclist, "ESO QC NIMAGES TOTAL", i);
242
243 i = cpl_propertylist_get_int(ppqc, "ESO QC NIMAGES EFFECTIVE");
244 cpl_propertylist_append_int(qclist, "ESO QC NIMAGES EFFECTIVE", i);
245
246 s = cpl_propertylist_get_string(ppqc, "ESO QC BEAMID");
247 cpl_propertylist_append_string(qclist, "ESO QC BEAMID", s);
248
249 error_if(strcmp(s, "UNDEFINED") == 0, CPL_ERROR_ILLEGAL_INPUT,
250 "Object detection was not successful, "
251 "please provide visir_util_detect_position with the object "
252 "positions to allow photometry");
253 if (strcmp(s, "COMBINED") != 0) {
254 d = cpl_propertylist_get_double(ppqc, "ESO QC BEAMX");
255 cpl_propertylist_append_double(qclist, "ESO QC BEAMX", d);
256
257 d = cpl_propertylist_get_double(ppqc, "ESO QC BEAMY");
258 cpl_propertylist_append_double(qclist, "ESO QC BEAMY", d);
259 }
260
261 end_skip;
262
263 return cpl_error_get_code();
264}
265
266
267/*----------------------------------------------------------------------------*/
274/*----------------------------------------------------------------------------*/
275static int visir_old_img_phot(cpl_frameset * framelist,
276 const cpl_parameterlist * parlist)
277{
278 cpl_errorstate cleanstate = cpl_errorstate_get();
279 irplib_framelist * allframes = NULL;
280 irplib_framelist * rawframes = NULL;
281 cpl_propertylist * ppqc = NULL;
282 cpl_propertylist * qclist = NULL;
283 const char * badpix;
284 const char * star_cat;
285 const char * flat;
286 cpl_image * weights = NULL;
287 cpl_image * contrib = NULL;
288 cpl_image ** combined = NULL;
289 cpl_image ** beam1 = NULL;
290 const char * sval;
291 cpl_boolean drop_wcs = CPL_FALSE;
292 const char * keys_regexp = "^(" RECIPE_KEYS_REGEXP_WCS
293 "|"VISIR_PFITS_REGEXP_DIT
294 "|ESO OBS.*)$";
295 const char * combine_string;
296 cpl_geom_combine combine_mode;
297 cpl_boolean one_beam = CPL_FALSE;
298 const char * dit_key = VISIR_PFITS_DOUBLE_DIT;
299
300
301
302 visir_img_phot_config.exptime = -1.0;
303 visir_img_phot_config.pscale = -1.0;
304 visir_img_phot_config.star_name[0] = (char)0;
305 visir_img_phot_config.filter[0] = (char)0;
306 visir_img_phot_config.bg_sigma = -1.0;
307 visir_img_phot_config.flux_snr = -1.0;
308 visir_img_phot_config.flux_snr_noise = -1.0;
309 visir_img_phot_config.flux_snr_radius[0] = -1;
310 visir_img_phot_config.flux_snr_radius[1] = -1;
311 visir_img_phot_config.flux_snr_radius[2] = -1;
312 visir_img_phot_config.flux_snr_radius[3] = -1;
313 visir_img_phot_config.flux_tot = -1.0;
314 visir_img_phot_config.nelec = -1.0;
315 visir_img_phot_config.nphot = -1.0;
316 visir_img_phot_config.beamshape =
317 (beamshape_t){.fwhm_x = -1., .fwhm_y = -1.,
318 .peak = -1., .peak_err = 0.,
319 .major = -1., .major_err = 0.,
320 .minor = -1., .minor_err = 0.,
321 .angle = -1., .angle_err = 0.};
322 visir_img_phot_config.fwhm_x_pos1 = -1.0;
323 visir_img_phot_config.fwhm_y_pos1 = -1.0;
324 visir_img_phot_config.fwhm_x_pos2 = -1.0;
325 visir_img_phot_config.fwhm_y_pos2 = -1.0;
326 visir_img_phot_config.fwhm_x_neg1 = -1.0;
327 visir_img_phot_config.fwhm_y_neg1 = -1.0;
328 visir_img_phot_config.fwhm_x_neg2 = -1.0;
329 visir_img_phot_config.fwhm_y_neg2 = -1.0;
330 visir_img_phot_config.sensitivity = -1.0;
331 visir_img_phot_config.area_sensit = -1.0;
332 visir_img_phot_config.conversion = -1.0;
333 visir_img_phot_config.strehl = -1.0;
334 visir_img_phot_config.strehl_err = -1.0;
335
336 /* Retrieve input parameters */
337 combine_string = visir_parameterlist_get_string(parlist, RECIPE_STRING,
338 VISIR_PARAM_COMBINE);
339
340 bug_if (combine_string == NULL);
341
342 if (combine_string[0] == 'u')
343 combine_mode = CPL_GEOM_UNION;
344 else if (combine_string[0] == 'f')
345 combine_mode = CPL_GEOM_FIRST;
346 else if (combine_string[0] == 'i')
347 combine_mode = CPL_GEOM_INTERSECT;
348 else
349 skip_if(1);
350
351
352 visir_img_phot_config.jy_val =
353 visir_parameterlist_get_double(parlist, RECIPE_STRING, VISIR_PARAM_JYVAL);
354 skip_if (0);
355
356 sval = visir_parameterlist_get_string(parlist, RECIPE_STRING, VISIR_PARAM_RADII);
357 skip_if (sval == NULL);
358
359 skip_if (sscanf(sval, "%d%*c%d%*c%d",
360 &visir_img_phot_config.r0_max,
361 &visir_img_phot_config.r1,
362 &visir_img_phot_config.r2) != 3);
363
364 /* Identify the RAW and CALIB frames in the input frameset */
365 skip_if (visir_dfs_set_groups(framelist));
366
367 /* Objects observation */
368 allframes = irplib_framelist_cast(framelist);
369 skip_if(allframes == NULL);
370 {
371 rawframes = irplib_framelist_extract(allframes, VISIR_IMG_PHOT_RAW);
372 if (rawframes == NULL) {
373 cpl_errorstate_set(cleanstate);
374 rawframes = irplib_framelist_extract(allframes,
375 VISIR_IMG_CAL_PHOT_PP);
376 skip_if (rawframes == NULL);
377 const char * fn =
378 irplib_frameset_find_file(framelist, VISIR_UTIL_QC_PROCATG);
379 if(fn == NULL) {
380 cpl_msg_error(cpl_func, "The input files has no header tagged "
381 "%s", VISIR_UTIL_QC_PROCATG);
382 visir_error_set(CPL_ERROR_DATA_NOT_FOUND);
383 skip_if(1);
384 }
385 ppqc = cpl_propertylist_load(fn, 0);
386 one_beam = CPL_TRUE;
387 }
388 }
389
390 skip_if (rawframes == NULL);
391
392 irplib_framelist_empty(allframes);
393
394 skip_if(irplib_framelist_load_propertylist(rawframes, 0, 0, keys_regexp,
395 CPL_FALSE));
396 qclist = cpl_propertylist_duplicate(irplib_framelist_get_propertylist(rawframes, 0));
397 if (ppqc)
398 skip_if(propagate_qc_header(qclist, ppqc));
399
400 skip_if(irplib_framelist_load_propertylist_all(rawframes, 0, "^("
401 RECIPE_KEYS_REGEXP_ALL
402 "|"VISIR_PFITS_REGEXP_DIT
403 ")$", CPL_FALSE));
404
405 skip_if(visir_dfs_check_framelist_tag(rawframes));
406
407 if (cpl_propertylist_has(irplib_framelist_get_propertylist(rawframes, 0),
408 VISIR_PFITS_DOUBLE_SEQ1_DIT))
409 dit_key = VISIR_PFITS_DOUBLE_SEQ1_DIT;
410 skip_if(0);
411
412 /* Standard star catalog */
413 star_cat = irplib_frameset_find_file(framelist, VISIR_CALIB_STDSTAR_IMG);
414 if (star_cat == NULL) {
415 cpl_msg_error(cpl_func, "The input files has no star catalog tagged "
416 "%s", VISIR_CALIB_STDSTAR_IMG);
417 visir_error_set(CPL_ERROR_DATA_NOT_FOUND);
418 skip_if(1);
419 }
420
421 /* Bad pixels calibration file */
422 badpix = irplib_frameset_find_file(framelist, VISIR_CALIB_BPM);
423
424 /* Flatfield calibration file */
425 flat = irplib_frameset_find_file(framelist, VISIR_CALIB_FLAT);
426
427
428 /* DIT must be present every where */
429 skip_if(irplib_framelist_contains(rawframes, dit_key,
430 CPL_TYPE_DOUBLE, CPL_FALSE, 0.0));
431 if(irplib_framelist_contains(rawframes, dit_key,
432 CPL_TYPE_DOUBLE, CPL_TRUE, 1e-5)) {
433 /* Allow 0.1 ms difference - or warn */
434 /* FIXME: The recipe does not properly handle non-uniform DITSs */
435 visir_error_reset("DIT differs by more than %g", 1e-5);
436 }
437
438 /* FIXME: Verify the angular distance */
439 skip_if(irplib_framelist_contains(rawframes, VISIR_PFITS_DOUBLE_RA,
440 CPL_TYPE_DOUBLE, CPL_FALSE, 0.0));
441
442 /* FIXME: Allow 1 degree difference */
443 skip_if(irplib_framelist_contains(rawframes, VISIR_PFITS_DOUBLE_DEC,
444 CPL_TYPE_DOUBLE, CPL_TRUE, 1.0));
445
446 skip_if(irplib_framelist_contains(rawframes, VISIR_PFITS_INT_CHOP_NCYCLES,
447 CPL_TYPE_INT, CPL_TRUE, 0.0));
448
449 skip_if(irplib_framelist_contains(rawframes, VISIR_PFITS_INT_NDIT,
450 CPL_TYPE_INT, CPL_TRUE, 0.0));
451
452 skip_if(irplib_framelist_contains(rawframes, VISIR_PFITS_STRING_STARNAME,
453 CPL_TYPE_STRING, CPL_TRUE, 0.0));
454
455 skip_if(irplib_framelist_contains(rawframes, VISIR_PFITS_STRING_INSMODE,
456 CPL_TYPE_STRING, CPL_TRUE, 0.0));
457
458 if (strncmp("IMG", visir_pfits_get_insmode(
459 irplib_framelist_get_propertylist_const(rawframes, 0)),
460 6) == 0) {
461 skip_if(irplib_framelist_contains(rawframes, VISIR_PFITS_STRING_FILTER1,
462 CPL_TYPE_STRING, CPL_TRUE, 0.0));
463 } else {
464 skip_if(irplib_framelist_contains(rawframes, VISIR_PFITS_STRING_FILTER2,
465 CPL_TYPE_STRING, CPL_TRUE, 0.0));
466 }
467
468 skip_if(irplib_framelist_contains(rawframes, VISIR_PFITS_STRING_PIXSCALE,
469 CPL_TYPE_STRING, CPL_TRUE, 0.0));
470
471
472 {
473 const char * prew =
474 irplib_frameset_find_file(framelist, "WEIGHT_MAP");
475 if (prew) {
476 cpl_msg_info(cpl_func, "Loading weight map %s", prew);
477 weights = cpl_image_load(prew, CPL_TYPE_UNSPECIFIED, 0, 0);
478 }
479 }
480
481 {
482 const char * prec =
483 irplib_frameset_find_file(framelist, "CONTRIBUTION_MAP");
484 if (prec) {
485 cpl_msg_info(cpl_func, "Loading contribution map %s", prec);
486 contrib = cpl_image_load(prec, CPL_TYPE_INT, 0, 0);
487 }
488 }
489
490 skip_if(0);
491 /* Combine the frames */
492 cpl_msg_info(cpl_func, "Combining the images");
493 {
494 const char * pre =
495 irplib_frameset_find_file(framelist, VISIR_IMG_CAL_PHOT_PP);
496 if (pre) {
497 combined = cpl_calloc(2, sizeof(combined[0]));
498 combined[0] = cpl_image_load(pre, CPL_TYPE_UNSPECIFIED, 0, 0);
499 combined[1] = contrib ? cpl_image_duplicate(contrib) : NULL;
500 if (combined[0] == NULL) {
501 cpl_msg_error(cpl_func, "Could not load the input frames");
502 skip_if(1);
503 }
504 if (weights) {
505 cpl_mask * m = cpl_mask_threshold_image_create(weights, -1,
506 FLT_EPSILON);
507 cpl_image_reject_from_mask(combined[0], m);
508 cpl_mask_delete(m);
509 }
510 }
511 else {
512 combined = visir_img_recombine(RECIPE_STRING, parlist, rawframes,
513 badpix, flat, combine_mode,
514 &drop_wcs, CPL_FALSE, 0.0, 0);
515 if (combined == NULL) {
516 cpl_msg_error(cpl_func, "Could not combine the input frames");
517 skip_if(1);
518 }
519 beam1 = visir_img_collapse_beam(qclist, combined[0], parlist, RECIPE_STRING,
520 VISIR_CHOPNOD_AUTO,
521 irplib_framelist_get_propertylist_const
522 (rawframes, 0));
523 if (beam1 == NULL)
524 irplib_error_recover(cleanstate, "Could not collapse the "
525 "beams of the combined image");
526
527 /* Compute the background values of the HCYCLE frames
528 * done by repack in preprocessed mode */
529 skip_if(visir_qc_append_background(qclist, rawframes, 0, 0));
530 }
531 }
532
533 /* Compute here the sensitivity */
534 cpl_msg_info(cpl_func, "Computing the sensitivity");
535 if (visir_img_phot_sensit(combined[0], weights, contrib, rawframes,
536 star_cat, one_beam, ppqc)) {
537 cpl_msg_error(cpl_func, "Could not compute sensitivity: '%s' in %s",
538 cpl_error_get_message(), cpl_error_get_where());
539 skip_if(1);
540 }
541
542 skip_if (visir_img_phot_qc(qclist, drop_wcs, rawframes));
543 irplib_framelist_empty(rawframes);
544
545 /* Save the combined image and contribution map */
546 if (beam1 == NULL) {
547 cpl_msg_info(cpl_func, "Saving the combined image with its contribution "
548 "map");
549 skip_if (visir_img_phot_save(framelist, parlist, qclist, combined[0],
550 combined[1], NULL, NULL, weights));
551 } else {
552 cpl_msg_info(cpl_func, "Saving the combined and the beam-combined "
553 "images with their contribution maps");
554 skip_if (visir_img_phot_save(framelist, parlist, qclist, combined[0],
555 combined[1], beam1[0], beam1[1], weights));
556 }
557
558 end_skip;
559
560 cpl_propertylist_delete(qclist);
561 irplib_framelist_delete(allframes);
562 irplib_framelist_delete(rawframes);
563 cpl_propertylist_delete(ppqc);
564 cpl_image_delete(weights);
565 cpl_image_delete(contrib);
566
567 if (combined) {
568 cpl_image_delete(combined[0]);
569 cpl_image_delete(combined[1]);
570 cpl_free(combined);
571 }
572
573 if (beam1) {
574 cpl_image_delete(beam1[0]);
575 cpl_image_delete(beam1[1]);
576 cpl_free(beam1);
577 }
578
579 return cpl_error_get_code();
580
581}
582
583/*----------------------------------------------------------------------------*/
608/*----------------------------------------------------------------------------*/
609static int visir_img_phot_sensit(const cpl_image * combined,
610 const cpl_image * weights,
611 const cpl_image * contrib,
612 const irplib_framelist * rawframes,
613 const char * star_cat,
614 cpl_boolean one_beam,
615 cpl_propertylist * ppqc)
616{
617 cpl_errorstate cleanstate = cpl_errorstate_get();
618 const cpl_propertylist * plist = NULL;
619 double ra, dec;
620 const char * sval;
621 double f2;
622
623
624 skip_if (0);
625
626 plist = irplib_framelist_get_propertylist_const(rawframes, 0);
627 skip_if (0);
628
629 /* Get the total exposure time */
630 {
631 double exptime;
632
633 if (ppqc) /* FIXME: use effective exptime? */
634 exptime = cpl_propertylist_get_double(ppqc, "ESO QC EXPTIME TOTAL");
635 else {
636 const int nnod = irplib_framelist_get_size(rawframes);
637 exptime = visir_utils_get_exptime(nnod, plist);
638 }
639 visir_img_phot_config.exptime = exptime;
640
641 if (exptime <= 0 || cpl_error_get_code()) {
642 cpl_msg_error(cpl_func, "Illegal exposure time: %g", exptime);
643 skip_if(1);
644 }
645 }
646
647 /* Copy the standard star name */
648 skip_if ((sval = visir_pfits_get_starname(plist)) == NULL);
649 (void) strncpy(visir_img_phot_config.star_name, sval, fits_strlen);
650
651 /* Copy the filter name */
652 skip_if ((sval = visir_pfits_get_filter(plist)) == NULL);
653 (void)strncpy(visir_img_phot_config.filter, sval, fits_strlen);
654
655 /* Get RA / DEC */
656 ra = visir_pfits_get_ra(plist);
657 skip_if (0);
658 dec = visir_pfits_get_dec(plist);
659 skip_if (0);
660
661 /* Get the pixel scale */
662 visir_img_phot_config.pscale = visir_pfits_get_pixscale(plist);
663
664 /* Get the JY value from the catalog if not user provided */
665 if (visir_img_phot_config.jy_val < -998) {
666 visir_img_phot_config.jy_val =
667 visir_img_phot_jy_from_cat(star_cat, visir_img_phot_config.filter,
668 ra,dec, visir_img_phot_config.star_name);
669 skip_if (visir_img_phot_config.jy_val < -998);
670 }
671
672 /* Display the result */
673 cpl_msg_info(cpl_func, "Star %s with filter %s : %g Jy",
674 visir_img_phot_config.star_name,
675 visir_img_phot_config.filter,
676 visir_img_phot_config.jy_val);
677
678 /* Compute the background signa */
679 visir_img_phot_config.bg_sigma = visir_img_phot_sigma_clip(combined);
680 skip_if (0);
681
682 /* Get the flux and flux noise and fwhm */
683 cpl_msg_info(cpl_func, "Compute the star flux");
684 sval = visir_pfits_get_chopnod_dir(plist);
685#if 1
686 if (one_beam) {
687 skip_if (visir_img_phot_flux_one(combined, weights, contrib, plist));
688 }
689 else if (sval != NULL && !strcmp(sval, "PERPENDICULAR")) {
690 /* 4 sources */
691 skip_if (visir_img_phot_flux_four(combined));
692 } else if (sval != NULL && !strcmp(sval, "PARALLEL")) {
693 /* 3 sources */
694 skip_if (visir_img_phot_flux_three(combined));
695 } else {
696 if (sval == NULL) {
697 visir_error_reset("Could not get FITS key");
698 } else {
699 cpl_msg_warning(cpl_func, "Unknown chopping direction: %s", sval);
700 }
701 cpl_msg_warning(cpl_func, "Proceeding as if FITS card %s had value %s",
702 "ESO SEQ CHOPNOD DIR", "PERPENDICULAR");
703 if (visir_img_phot_flux_four(combined)) {
704 visir_error_reset("Proceeding as if FITS card %s had value %s",
705 "ESO SEQ CHOPNOD DIR", "PARALLEL");
706 skip_if (visir_img_phot_flux_three(combined));
707 }
708 }
709#else
710 if (sval == NULL) {
711 visir_error_reset("Could not get chopping direction");
712 if (visir_img_phot_flux_three(combined)) {
713 cpl_msg_error(cpl_func, "Could not compute the flux");
714 skip_if(1);
715 }
716 } else if (!strcmp(sval, "PARALLEL")) {
717 /* 3 sources */
718 if (visir_img_phot_flux_three(combined)) {
719 cpl_msg_error(cpl_func, "Could not compute the flux");
720 skip_if(1);
721 }
722 } else {
723 /* Default is 4 sources */
724 if (strcmp(sval, "PERPENDICULAR"))
725 cpl_msg_warning(cpl_func, "Unknown chopping direction: %s", sval);
726 if (visir_img_phot_flux_four(combined)) {
727 cpl_msg_error(cpl_func, "Could not compute the flux");
728 skip_if(1);
729 }
730 }
731#endif
732
733
734 /* compute number of photons and electrons for the efficiency */
735 {
736 double fluxSI = visir_img_phot_config.jy_val * 1e-26;
737 double dit = visir_pfits_get_dit(plist);;
738 /* area of telescope [m^2] */
739 double area = (8.2/2.) * (8.2/2.) * CPL_MATH_PI;
740 const char * filter = visir_pfits_get_filter(plist);
741 double wl;
742 /* filter bandwidth delta lambda [m] */
743 double bandwidth;
744 double gain = 20.;
745
746 if (ppqc && cpl_propertylist_has(ppqc, "ESO DET CHIP1 GAIN"))
747 gain = cpl_propertylist_get_double(ppqc, "ESO DET CHIP1 GAIN");
748 else if (ppqc && cpl_propertylist_has(ppqc, "ESO DET CHIP GAIN"))
749 gain = cpl_propertylist_get_double(ppqc, "ESO DET CHIP GAIN");
750 else
751 cpl_msg_warning(cpl_func, "ESO DET CHIP1 GAIN not found, "
752 "assuming %g", gain);
753
754 if (filter && !visir_get_filter_infos(filter, &wl, &bandwidth)) {
755 /* filter bandwidth deltanue [Hz] */
756 double bwh, ptot, ephot;
757 wl *= 1e-6; /* [micron] -> [m] */
758 bandwidth *= 1e-6; /* [micron] -> [m] */
759
760 bwh = CPL_PHYS_C / (wl * wl) * bandwidth;
761 /* total power [W] */
762 ptot = fluxSI * area * bwh;
763 /* photon energy [Ws] */
764 ephot = CPL_PHYS_H * CPL_PHYS_C / wl;
765
766 visir_img_phot_config.nelec = visir_img_phot_config.flux_tot * gain;
767 visir_img_phot_config.nphot = ptot / ephot * dit;
768 }
769 else
770 cpl_msg_warning(cpl_func, "Unknown filter: %s", filter);
771 }
772
773 /* Compute the sensitivity and the conversion factor */
774
775 skip_if ( visir_img_phot_config.flux_snr == 0 );
776 skip_if ( visir_img_phot_config.flux_snr_noise == 0 );
777 skip_if ( visir_img_phot_config.jy_val == 0 );
778
779 f2 = visir_img_phot_config.flux_snr / visir_img_phot_config.flux_snr_noise;
780 f2 *= sqrt(3600/visir_img_phot_config.exptime);
781 visir_img_phot_config.sensitivity = visir_img_phot_config.jy_val*1000*10/f2;
782 /* compute conversion, accounting for double signal in parallel mode */
783 visir_img_phot_config.conversion = visir_img_phot_config.flux_tot /
784 visir_img_phot_config.jy_val /
785 (ppqc ? visir_pfits_get_img_weight(ppqc) : 1.);
786
787 /* sensitivity using the noise under 1as circle */
788 visir_img_phot_config.area_sensit =
789 visir_img_phot_config.sensitivity *
790 sqrt((1. / SQR(visir_img_phot_config.pscale)) /
791 SQR(visir_img_phot_config.flux_snr_radius[0]));
792
793 end_skip;
794
795 cpl_msg_info(cpl_func, "Sensitivity : %g", visir_img_phot_config.sensitivity);
796 cpl_msg_info(cpl_func, "Conversion : %g", visir_img_phot_config.conversion);
797 cpl_msg_info(cpl_func, "Strehl : %g", visir_img_phot_config.strehl);
798 cpl_msg_info(cpl_func, "Strehl error: %g", visir_img_phot_config.strehl_err);
799 cpl_msg_info(cpl_func, "Exposure : %g s", visir_img_phot_config.exptime);
800
801 return cpl_error_get_code();
802}
803
804/*----------------------------------------------------------------------------*/
814/*----------------------------------------------------------------------------*/
815static double visir_img_phot_jy_from_cat(
816 const char * star_cat,
817 const char * filter,
818 double ra,
819 double dec,
820 const char * star_name)
821{
822 cpl_table * tab = NULL;
823 cpl_vector * v_ra = NULL;
824 cpl_vector * v_dec = NULL;
825 const char * stdstar;
826 char * label = NULL;
827 int nb_stars;
828 const double max_radius = VISIR_STAR_MAX_RADIUS;
829 double value = -999;
830 double jy;
831 double dist;
832 int min_dist_ind;
833
834
835 skip_if( 0 );
836 skip_if( star_cat == NULL );
837 skip_if( star_name == NULL );
838 skip_if( filter == NULL );
839
840 label = visir_img_phot_filter2label(filter);
841 skip_if(label == NULL);
842
843 /* Open the star catalog */
844 if ((tab = cpl_table_load(star_cat, 1, 1)) == NULL) {
845 cpl_error_set_message(cpl_func, cpl_error_get_code(),
846 "Could not load the star catalog: %s",
847 star_cat);
848 skip_if(1);
849 }
850
851 /* Check that the filter is in the table */
852 if (!cpl_table_has_column(tab, label)) {
853 cpl_error_set_message(cpl_func, CPL_ERROR_DATA_NOT_FOUND,
854 "Catalog %s has no column for filter: %s",
855 star_cat, filter);
856 skip_if(1);
857 }
858
859 if (!cpl_table_has_column(tab, "STARS")) {
860 cpl_error_set_message(cpl_func, CPL_ERROR_BAD_FILE_FORMAT,
861 "Catalog %s does not have a column labeled %s",
862 star_cat, "STARS");
863 skip_if(1);
864 }
865
866 nb_stars = cpl_table_get_nrow(tab);
867 skip_if (nb_stars < 1);
868
869 /* Get the RA and DEC columns */
870 v_ra = cpl_vector_wrap(nb_stars, cpl_table_get_data_double(tab, "RA"));
871 skip_if( v_ra == NULL);
872
873 v_dec = cpl_vector_wrap(nb_stars, cpl_table_get_data_double(tab, "DEC"));
874 skip_if( v_dec == NULL);
875
876 min_dist_ind = visir_star_find(v_ra, v_dec, ra, dec, max_radius, &dist);
877
878 if (min_dist_ind < 0) {
879 cpl_error_set_message(cpl_func, cpl_error_get_code(),
880 "Observation target '%s' was not found among "
881 "the %d entries in the standard star catalog %s",
882 star_name, nb_stars, star_cat);
883 skip_if(1);
884 }
885
886 stdstar = cpl_table_get_string(tab, "STARS", min_dist_ind);
887 skip_if ( stdstar == NULL );
888
889 int null;
890 jy = cpl_table_get(tab, label, min_dist_ind, &null);
891 skip_if( 0 );
892
893 if (null || isnan(jy)) {
894 cpl_error_set_message(cpl_func, CPL_ERROR_DATA_NOT_FOUND,
895 "Catalog does not contain a value for %s in "
896 "filter %s", star_name, filter);
897 skip_if(1);
898 }
899
900 value = jy;
901
902 if (strcmp(stdstar, star_name) != 0 && dist > 0.0) {
903 /* The names do not match, nor does the location (exactly) */
904 cpl_msg_warning(cpl_func, "The standard star '%s' at (RA,DEC)=(%g,%g) "
905 "in the FITS header is closest to the catalog star "
906 "'%s' at (RA,DEC)=(%g,%g) at distance %g degrees",
907 star_name, ra, dec, stdstar,
908 cpl_vector_get(v_ra, min_dist_ind),
909 cpl_vector_get(v_dec, min_dist_ind), dist);
910 } else if (dist > 0.0) {
911 /* The names match, but the location does not (exactly) */
912 cpl_msg_warning(cpl_func, "The location of the standard star '%s' in "
913 "the FITS header (RA,DEC)=(%g,%g) and the catalog "
914 "(RA,DEC)=(%g,%g) differ by %g degrees", stdstar, ra,
915 dec, cpl_vector_get(v_ra, min_dist_ind),
916 cpl_vector_get(v_dec, min_dist_ind), dist);
917 } else if (strcmp(stdstar, star_name) != 0) {
918 /* The names do not match, but the location does */
919 cpl_msg_warning(cpl_func, "The name of the standard star at (RA,DEC)="
920 "(%g,%g) in the FITS header '%s' and the catalog '%s' "
921 "are different", ra, dec, star_name, stdstar);
922 } else {
923 cpl_msg_info(cpl_func, "Standard star is '%s' at (RA, DEC)=(%g,%g)",
924 stdstar, ra, dec);
925
926 if (cpl_msg_get_level() <= CPL_MSG_DEBUG)
927 cpl_table_dump(tab, min_dist_ind, 1, stdout);
928 }
929
930 cpl_msg_info(cpl_func, "The standard star '%s' has %g Jy through filter %s",
931 stdstar, value, filter);
932
933 end_skip;
934
935 cpl_free(label);
936 cpl_table_delete(tab);
937 cpl_vector_unwrap(v_ra);
938 cpl_vector_unwrap(v_dec);
939
940 return value;
941}
942
943/*----------------------------------------------------------------------------*/
952/*----------------------------------------------------------------------------*/
953static int visir_img_phot_flux_three(const cpl_image * combined)
954{
955 cpl_errorstate cleanstate = cpl_errorstate_get();
956 cpl_image * min_combined = NULL;
957 cpl_apertures * appos = NULL;
958 cpl_apertures * apneg = NULL;
959 cpl_vector * sigmas = NULL;
960 double psigmas[] = {5, 2, 1, 0.5};
961 double x[3];
962 double y[3];
963 double flux_snr[3];
964 double flux_snr_noise[3];
965 int flux_snr_radius[3];
966 double flux_tot[3];
967 beamshape_t beamshapes[3];
968 double dist1, dist2;
969 int ngood_fwhm;
970 double lam, dlam;
971 double star_bg,star_peak,star_flux,psf_peak,psf_flux,bg_noise;
972 double eccmin = DBL_MAX;
973 const int nsigmas = sizeof(psigmas)/sizeof(double);
974 int isigma;
975#ifdef VISIR_IMG_PHOT_USE_ECCENT_THREE
976 int ipos, ineg1, ineg2;
977#endif
978 int iappos, iapneg2[2];
979 int i;
980
981
982 if (cpl_error_get_code()) return cpl_error_get_code();
983
984 cpl_ensure_code(combined != NULL, CPL_ERROR_NULL_INPUT);
985
986 cpl_msg_info(cpl_func, "Detecting the 3-source star using %d sigma-levels "
987 "ranging from %g down to %g", nsigmas, psigmas[0],
988 psigmas[nsigmas-1]);
989
990 sigmas = cpl_vector_new(1);
991 min_combined = cpl_image_multiply_scalar_create(combined, -1.0);
992 bug_if(0);
993 for (isigma = 0; isigma < nsigmas; isigma++) {
994
995 /* FIXME: Why ?! */
996 irplib_error_recover(cleanstate, "Resetting error (why?)");
997
998 bug_if(cpl_vector_set(sigmas, 0, psigmas[isigma]));
999
1000 /* Detect where the POSITIVE star is */
1001 cpl_apertures_delete(appos);
1002 appos = cpl_apertures_extract(combined, sigmas, NULL);
1003 if (appos == NULL) {
1004 cpl_msg_warning(cpl_func, "Found no positive star at sigma=%g",
1005 psigmas[isigma]);
1006 continue;
1007 }
1008
1009 /* Detect where the NEGATIVE stars are */
1010 cpl_apertures_delete(apneg);
1011 apneg = cpl_apertures_extract(min_combined, sigmas, NULL);
1012 if (apneg == NULL) {
1013 cpl_msg_warning(cpl_func, "Found no negative stars at sigma=%g",
1014 psigmas[isigma]);
1015 continue;
1016 }
1017 if (cpl_apertures_get_size(apneg) < 2) {
1018 cpl_msg_warning(cpl_func, "Found just 1 negative star at sigma=%g, "
1019 "need two", psigmas[isigma]);
1020 continue;
1021 }
1022
1023 cpl_msg_info(cpl_func, "Found positive and negative stars at sigma=%g",
1024 psigmas[isigma]);
1025 break;
1026 }
1027
1028 skip_if(appos == NULL);
1029 skip_if(apneg == NULL);
1030 skip_if (cpl_apertures_get_size(apneg) < 2);
1031
1032 if (cpl_msg_get_level() == CPL_MSG_DEBUG) {
1033 cpl_apertures_dump(appos, stdout);
1034 cpl_apertures_dump(apneg, stdout);
1035 }
1036
1037#ifndef VISIR_IMG_PHOT_USE_ECCENT_THREE
1038 bug_if(irplib_apertures_find_max_flux(appos, &iappos, 1));
1039 bug_if(irplib_apertures_find_max_flux(apneg, iapneg2, 2));
1040#else
1041 if (cpl_apertures_get_size(appos) > 1 || cpl_apertures_get_size(apneg) > 2)
1042 cpl_msg_info(cpl_func, "Selecting from %d positive and %d negative "
1043 "stars 3 stars on a vertical line",
1044 cpl_apertures_get_size(appos),
1045 cpl_apertures_get_size(apneg));
1046
1047 for (ipos = 1; ipos <= cpl_apertures_get_size(appos); ipos++) {
1048 for (ineg1 = 2; ineg1 <= cpl_apertures_get_size(apneg); ineg1++) {
1049 for (ineg2 = 1; ineg2 < ineg1; ineg2++) {
1050 const double ecc = visir_img_phot_eccent_three(appos, ipos,
1051 apneg,
1052 ineg1, ineg2);
1053 if (ecc < eccmin) {
1054 if (eccmin < DBL_MAX)
1055 cpl_msg_debug(cpl_func, "Found star positions with "
1056 "reduced mis-alignment [pixel]: "
1057 "%g < %g", ecc, eccmin);
1058 eccmin = ecc;
1059 iappos = ipos;
1060 iapneg2[0] = ineg1;
1061 iapneg2[1] = ineg2;
1062 }
1063 }
1064 }
1065 }
1066
1067 /* Star 1 should have largest flux */
1068 if (cpl_apertures_get_flux(apneg, iapneg2[0]) <
1069 cpl_apertures_get_flux(apneg, iapneg2[1])) {
1070 const int tmp = iapneg2[0];
1071 iapneg2[0] = iapneg2[1];
1072 iapneg2[1] = tmp;
1073 }
1074
1075#endif
1076
1077 x[0] = cpl_apertures_get_centroid_x(appos, iappos);
1078 y[0] = cpl_apertures_get_centroid_y(appos, iappos);
1079
1080 x[1] = cpl_apertures_get_centroid_x(apneg, iapneg2[0]);
1081 y[1] = cpl_apertures_get_centroid_y(apneg, iapneg2[0]);
1082 x[2] = cpl_apertures_get_centroid_x(apneg, iapneg2[1]);
1083 y[2] = cpl_apertures_get_centroid_y(apneg, iapneg2[1]);
1084
1085 cpl_apertures_delete(appos);
1086 cpl_apertures_delete(apneg);
1087 appos = NULL;
1088 apneg = NULL;
1089
1090 cpl_msg_info(cpl_func, "Positive star at position %g %g", x[0], y[0]);
1091 cpl_msg_info(cpl_func, "Negative star 1 at position %g %g", x[1], y[1]);
1092 cpl_msg_info(cpl_func, "Negative star 2 at position %g %g", x[2], y[2]);
1093
1094 dist1 = sqrt((x[1]-x[0])*(x[1]-x[0])+(y[1]-y[0])*(y[1]-y[0]));
1095 dist2 = sqrt((x[2]-x[0])*(x[2]-x[0])+(y[2]-y[0])*(y[2]-y[0]));
1096 cpl_msg_info(cpl_func, "Star 1 Pos/Neg Distance: %g", dist1);
1097 cpl_msg_info(cpl_func, "Star 2 Pos/Neg Distance: %g", dist2);
1098
1099
1100 if (eccmin < DBL_MAX) {
1101 cpl_msg_info(cpl_func, "The deviation from a vertical line by "
1102 "the three stars [pixel]: %g", eccmin);
1103 if (eccmin > VISIR_IMG_PHOT_POS_WARN) {
1104 if (eccmin > VISIR_IMG_PHOT_POS_ERROR) {
1105 cpl_msg_error(cpl_func, "The deviation from a vertical line"
1106 " by the three stars exceed %g, the detected "
1107 "objects are wrong", VISIR_IMG_PHOT_POS_ERROR);
1108 skip_if(1);
1109 }
1110 cpl_msg_warning(cpl_func, "The deviation from a vertical line "
1111 "by the three stars exceed %g, the detected "
1112 "objects may be wrong", VISIR_IMG_PHOT_POS_WARN);
1113 }
1114 }
1115
1116 /* FIXME: Pick other object instead, and lower sigma if needed */
1117 if ((int)x[0]-IRPLIB_STREHL_BORDER <= 0 ||
1118 (int)y[0]-IRPLIB_STREHL_BORDER <= 0 ||
1119 (int)x[0]+IRPLIB_STREHL_BORDER > cpl_image_get_size_x(combined) ||
1120 (int)y[0]+IRPLIB_STREHL_BORDER > cpl_image_get_size_y(combined)) {
1121 cpl_msg_error(cpl_func, "Positive star at (%g,%g) is less than %d "
1122 "pixels from the image border", x[0], y[0],
1123 1+IRPLIB_STREHL_BORDER);
1124 skip_if(1);
1125 }
1126
1127 /* FIXME: Useful ? */
1128 /* Verify the stars positions */
1129 if (fabs(dist1-dist2) > VISIR_IMG_PHOT_POS_UNCERTAINTY) {
1130 cpl_msg_error(cpl_func, "Too large Pos/Neg Distance between the two "
1131 "stars: %g > %g", fabs(dist1-dist2),
1132 VISIR_IMG_PHOT_POS_UNCERTAINTY);
1133 skip_if(1);
1134 }
1135
1136 /* Photometry on positive stars */
1137 skip_if (visir_img_phot_flux(combined, NULL, NULL,
1138 x[0], y[0],
1139 visir_img_phot_config.r0_max,
1140 visir_img_phot_config.r1,
1141 visir_img_phot_config.r2,
1142 &(flux_snr[0]),
1143 &(flux_snr_noise[0]),
1144 &(flux_snr_radius[0]),
1145 &(flux_tot[0]),
1146 &(beamshapes[0])));
1147
1148 /* Photometry on negative stars */
1149 for (i=1 ; i<3 ; i++)
1150 skip_if (visir_img_phot_flux(min_combined, NULL, NULL,
1151 x[i], y[i],
1152 visir_img_phot_config.r0_max,
1153 visir_img_phot_config.r1,
1154 visir_img_phot_config.r2,
1155 &(flux_snr[i]),
1156 &(flux_snr_noise[i]),
1157 &(flux_snr_radius[i]),
1158 &(flux_tot[i]),
1159 &(beamshapes[i])));
1160
1161 cpl_image_delete(min_combined);
1162 min_combined = NULL;
1163
1164 /* Compute the results */
1165 /* Flux */
1166 visir_img_phot_config.flux_snr = 0.0;
1167 for (i=0 ; i<3 ; i++) visir_img_phot_config.flux_snr += flux_snr[i];
1168
1169 /* Flux noise */
1170 visir_img_phot_config.flux_snr_noise = 0.0;
1171 for (i=0 ; i<3 ; i++) visir_img_phot_config.flux_snr_noise +=
1172 flux_snr_noise[i]*flux_snr_noise[i];
1173 visir_img_phot_config.flux_snr_noise =
1174 sqrt(visir_img_phot_config.flux_snr_noise);
1175
1176 for (i=0 ; i<3 ; i++)
1177 visir_img_phot_config.flux_snr_radius[i] = flux_snr_radius[i];
1178
1179 /* Total flux */
1180 visir_img_phot_config.flux_tot = 0.0;
1181 for (i=0 ; i<3 ; i++) visir_img_phot_config.flux_tot += flux_tot[i];
1182
1183 /* FWHM */
1184 ngood_fwhm = 0;
1185 visir_img_phot_config.beamshape.fwhm_x = 0.0;
1186 for (i=0 ; i<3 ; i++) {
1187 if (beamshapes[i].fwhm_x > 0.0) {
1188 visir_img_phot_config.beamshape.fwhm_x += beamshapes[i].fwhm_x;
1189 ngood_fwhm ++;
1190 }
1191 }
1192 if (ngood_fwhm > 0) visir_img_phot_config.beamshape.fwhm_x /= ngood_fwhm;
1193 else visir_img_phot_config.beamshape.fwhm_x = -1.0;
1194 ngood_fwhm = 0;
1195 visir_img_phot_config.beamshape.fwhm_y = 0.0;
1196 for (i=0 ; i<3 ; i++) {
1197 if (beamshapes[i].fwhm_y > 0.0) {
1198 visir_img_phot_config.beamshape.fwhm_y += beamshapes[i].fwhm_y;
1199 ngood_fwhm ++;
1200 }
1201 }
1202 if (ngood_fwhm > 0) visir_img_phot_config.beamshape.fwhm_y /= ngood_fwhm;
1203 else visir_img_phot_config.beamshape.fwhm_y = -1.0;
1204 visir_img_phot_config.fwhm_x_pos1 = beamshapes[0].fwhm_x;
1205 visir_img_phot_config.fwhm_y_pos1 = beamshapes[0].fwhm_y;
1206 visir_img_phot_config.fwhm_x_neg1 = beamshapes[1].fwhm_x;
1207 visir_img_phot_config.fwhm_y_neg1 = beamshapes[1].fwhm_y;
1208 visir_img_phot_config.fwhm_x_neg2 = beamshapes[2].fwhm_x;
1209 visir_img_phot_config.fwhm_y_neg2 = beamshapes[2].fwhm_y;
1210
1211 /* Get lam and dlam from the filter name for the Strehl computation */
1212 if (visir_get_filter_infos(visir_img_phot_config.filter, &lam, &dlam)) {
1213 cpl_msg_error(cpl_func, "Could not get info for filter: %s",
1214 visir_img_phot_config.filter);
1215 skip_if(1);
1216 }
1217
1218 /* Strehl computation */
1219 cpl_errorstate errstate = cpl_errorstate_get();
1220 if (irplib_strehl_compute(combined, STREHL_M1, STREHL_M2, lam, dlam,
1221 visir_img_phot_config.pscale,
1222 STREHL_BOX_SIZE, x[0], y[0], STREHL_STAR_RADIUS,
1223 STREHL_BG_R1, STREHL_BG_R2, -1, -1,
1224 &(visir_img_phot_config.strehl),
1225 &(visir_img_phot_config.strehl_err),
1226 &star_bg, &star_peak, &star_flux, &psf_peak, &psf_flux,
1227 &bg_noise)) {
1228 cpl_msg_error(cpl_func, "Could not compute the strehl: '%s' in %s",
1229 cpl_error_get_message(), cpl_error_get_where());
1230 cpl_errorstate_set(errstate);
1231 }
1232
1233
1234 end_skip;
1235
1236 cpl_apertures_delete(appos);
1237 cpl_apertures_delete(apneg);
1238 cpl_vector_delete(sigmas);
1239 cpl_image_delete(min_combined);
1240
1241 return cpl_error_get_code();
1242}
1243
1244static int visir_img_phot_flux_one(const cpl_image * combined,
1245 const cpl_image * weights,
1246 const cpl_image * contrib,
1247 const cpl_propertylist * plist)
1248{
1249 double x;
1250 double y;
1251 double flux_snr;
1252 double flux_snr_noise;
1253 int flux_snr_radius;
1254 double flux_tot;
1255 beamshape_t beamshape;
1256 double lam, dlam;
1257 double star_bg,star_peak,star_flux,psf_peak,psf_flux,bg_noise;
1258
1259 if (cpl_error_get_code()) return cpl_error_get_code();
1260
1261 cpl_ensure_code(combined != NULL, CPL_ERROR_NULL_INPUT);
1262
1263 x = cpl_propertylist_get_double(plist, "CRPIX1");
1264 y = cpl_propertylist_get_double(plist, "CRPIX2");
1265 {
1266 /* CRPIX can be a few pixels off center due to slicing of
1267 * the images around the beam done in detect_shift
1268 * only the int cast is used later, so pixel precision of
1269 * maxpos is ok */
1270 cpl_size yp, xp;
1271 cpl_image_get_maxpos_window(combined,
1272 CX_MAX(1, x - 5), CX_MAX(1, y - 5),
1273 CX_MIN(cpl_image_get_size_x(combined), x + 5),
1274 CX_MIN(cpl_image_get_size_y(combined), y + 5), &xp, &yp);
1275 x = xp;
1276 y = yp;
1277 }
1278
1279 cpl_msg_info(cpl_func, "Positive star 1 at position %g %g", x, y);
1280
1281 if ((int)x-IRPLIB_STREHL_BORDER <= 0 ||
1282 (int)y-IRPLIB_STREHL_BORDER <= 0) {
1283 cpl_msg_error(cpl_func, "Positive star 1 at (%g,%g) is less than %d "
1284 "pixels from the image border", x, y,
1285 1+IRPLIB_STREHL_BORDER);
1286 skip_if(1);
1287 }
1288
1289 /* Photometry on positive stars */
1290 skip_if (visir_img_phot_flux(combined, weights, contrib,
1291 x, y,
1292 visir_img_phot_config.r0_max,
1293 visir_img_phot_config.r1,
1294 visir_img_phot_config.r2,
1295 &(flux_snr),
1296 &(flux_snr_noise),
1297 &(flux_snr_radius),
1298 &(flux_tot),
1299 &(beamshape)));
1300
1301
1302 /* Compute the results */
1303 /* Flux */
1304 visir_img_phot_config.flux_snr = flux_snr;
1305
1306 /* Flux noise */
1307 visir_img_phot_config.flux_snr_noise = flux_snr_noise;
1308
1309 visir_img_phot_config.flux_snr_radius[0] = flux_snr_radius;
1310
1311 /* Total flux */
1312 visir_img_phot_config.flux_tot = flux_tot;
1313
1314 /* FWHM */
1315 visir_img_phot_config.beamshape = beamshape;
1316 visir_img_phot_config.fwhm_x_pos1 = beamshape.fwhm_x;
1317 visir_img_phot_config.fwhm_y_pos1 = beamshape.fwhm_y;
1318
1319 /* Get lam and dlam from the filter name for the Strehl computation */
1320 if (visir_get_filter_infos(visir_img_phot_config.filter, &lam, &dlam)) {
1321 cpl_msg_error(cpl_func, "Central wavelength and width is missing for "
1322 "filter: %s", visir_img_phot_config.filter);
1323 skip_if(1);
1324 }
1325
1326 /* Strehl computation */
1327 cpl_errorstate errstate = cpl_errorstate_get();
1328 if (irplib_strehl_compute(combined, STREHL_M1, STREHL_M2, lam, dlam,
1329 visir_img_phot_config.pscale,
1330 STREHL_BOX_SIZE, x, y, STREHL_STAR_RADIUS,
1331 STREHL_BG_R1, STREHL_BG_R2, -1, -1,
1332 &(visir_img_phot_config.strehl),
1333 &(visir_img_phot_config.strehl_err),
1334 &star_bg, &star_peak, &star_flux, &psf_peak, &psf_flux,
1335 &bg_noise)) {
1336 cpl_msg_error(cpl_func, "Could not compute the strehl: '%s' in %s",
1337 cpl_error_get_message(), cpl_error_get_where());
1338 cpl_errorstate_set(errstate);
1339 }
1340
1341
1342 end_skip;
1343
1344 return cpl_error_get_code();
1345
1346}
1347
1348/*----------------------------------------------------------------------------*/
1357/*----------------------------------------------------------------------------*/
1358static int visir_img_phot_flux_four(const cpl_image * combined)
1359{
1360 cpl_errorstate cleanstate = cpl_errorstate_get();
1361 cpl_image * min_combined = NULL;
1362 cpl_apertures * appos = NULL;
1363 cpl_apertures * apneg = NULL;
1364 cpl_vector * sigmas = NULL;
1365 double psigmas[] = {5, 2, 1, 0.5};
1366 double x[4];
1367 double y[4];
1368 double flux_snr[4];
1369 double flux_snr_noise[4];
1370 int flux_snr_radius[4];
1371 double flux_tot[4];
1372 beamshape_t beamshapes[4];
1373 double dist1, dist2;
1374 int ngood_fwhm;
1375 double lam, dlam;
1376 double star_bg,star_peak,star_flux,psf_peak,psf_flux,bg_noise;
1377 double eccmin = DBL_MAX;
1378 const int nsigmas = sizeof(psigmas)/sizeof(double);
1379 int isigma;
1380 int ipos1, ipos2, ineg1, ineg2;
1381 int i;
1382 int iappos2[] = {0, 0}; /* Avoid (false) uninit warning */
1383 int iapneg2[] = {0, 0}; /* Avoid (false) uninit warning */
1384
1385
1386 if (cpl_error_get_code()) return cpl_error_get_code();
1387
1388 cpl_ensure_code(combined != NULL, CPL_ERROR_NULL_INPUT);
1389
1390 cpl_msg_info(cpl_func, "Detecting the 4-source star using %d sigma-levels "
1391 "ranging from %g down to %g", nsigmas, psigmas[0],
1392 psigmas[nsigmas-1]);
1393
1394 sigmas = cpl_vector_new(1);
1395 min_combined = cpl_image_multiply_scalar_create(combined, -1.0);
1396 bug_if(0);
1397 for (isigma = 0; isigma < nsigmas; isigma++) {
1398
1399 /* FIXME: Why ?! */
1400 irplib_error_recover(cleanstate, "Resetting error (why?)");
1401
1402 bug_if(cpl_vector_set(sigmas, 0, psigmas[isigma]));
1403
1404 /* Detect where the POSITIVE stars are */
1405 cpl_apertures_delete(appos);
1406 appos = cpl_apertures_extract(combined, sigmas, NULL);
1407 if (appos == NULL) {
1408 cpl_msg_warning(cpl_func, "Found no positive stars at sigma=%g",
1409 psigmas[isigma]);
1410 continue;
1411 }
1412 if (cpl_apertures_get_size(appos) < 2) {
1413 cpl_msg_warning(cpl_func, "Found just 1 positive star at sigma=%g, "
1414 "need two", psigmas[isigma]);
1415 continue;
1416 }
1417
1418 /* Detect where the NEGATIVE stars are */
1419 cpl_apertures_delete(apneg);
1420 apneg = cpl_apertures_extract(min_combined, sigmas, NULL);
1421 if (apneg == NULL) {
1422 cpl_msg_warning(cpl_func, "Found no negative stars at sigma=%g",
1423 psigmas[isigma]);
1424 continue;
1425 }
1426 if (cpl_apertures_get_size(apneg) < 2) {
1427 cpl_msg_warning(cpl_func, "Found just 1 negative star at sigma=%g, "
1428 "need two", psigmas[isigma]);
1429 continue;
1430 }
1431
1432 cpl_msg_info(cpl_func, "Found positive and negative stars at sigma=%g",
1433 psigmas[isigma]);
1434 break;
1435 }
1436
1437 skip_if(appos == NULL);
1438 skip_if(apneg == NULL);
1439 skip_if (cpl_apertures_get_size(appos) < 2);
1440 skip_if (cpl_apertures_get_size(apneg) < 2);
1441
1442 if (cpl_msg_get_level() == CPL_MSG_DEBUG) {
1443 cpl_apertures_dump(appos, stdout);
1444 cpl_apertures_dump(apneg, stdout);
1445 }
1446
1447 if (cpl_apertures_get_size(appos) > 2 || cpl_apertures_get_size(apneg) > 2)
1448 cpl_msg_info(cpl_func, "Selecting from %d positive and %d negative "
1449 "stars two pairs that outline a square",
1450 (int)cpl_apertures_get_size(appos),
1451 (int)cpl_apertures_get_size(apneg));
1452
1453 for (ipos1 = 2; ipos1 <= cpl_apertures_get_size(appos); ipos1++) {
1454 for (ipos2 = 1; ipos2 < ipos1; ipos2++) {
1455 for (ineg1 = 2; ineg1 <= cpl_apertures_get_size(apneg); ineg1++) {
1456 for (ineg2 = 1; ineg2 < ineg1; ineg2++) {
1457 const double ecc = visir_img_phot_eccent_four(appos, ipos1,
1458 ipos2, apneg,
1459 ineg1, ineg2);
1460
1461 if (ecc < eccmin) {
1462 if (eccmin < DBL_MAX)
1463 cpl_msg_debug(cpl_func, "Found star positions with "
1464 "reduced non-square-ness [pixel]: "
1465 "%g < %g", ecc, eccmin);
1466 eccmin = ecc;
1467 iappos2[0] = ipos1;
1468 iappos2[1] = ipos2;
1469 iapneg2[0] = ineg1;
1470 iapneg2[1] = ineg2;
1471 }
1472 }
1473 }
1474 }
1475 }
1476
1477 /* Star 1 should have largest flux */
1478 if (cpl_apertures_get_flux(appos, iappos2[0]) <
1479 cpl_apertures_get_flux(appos, iappos2[1])) {
1480 const int tmp = iappos2[0];
1481 iappos2[0] = iappos2[1];
1482 iappos2[1] = tmp;
1483 }
1484 if (cpl_apertures_get_flux(apneg, iapneg2[0]) <
1485 cpl_apertures_get_flux(apneg, iapneg2[1])) {
1486 const int tmp = iapneg2[0];
1487 iapneg2[0] = iapneg2[1];
1488 iapneg2[1] = tmp;
1489 }
1490
1491
1492 x[0] = cpl_apertures_get_centroid_x(appos, iappos2[0]);
1493 y[0] = cpl_apertures_get_centroid_y(appos, iappos2[0]);
1494 x[1] = cpl_apertures_get_centroid_x(appos, iappos2[1]);
1495 y[1] = cpl_apertures_get_centroid_y(appos, iappos2[1]);
1496
1497 x[2] = cpl_apertures_get_centroid_x(apneg, iapneg2[0]);
1498 y[2] = cpl_apertures_get_centroid_y(apneg, iapneg2[0]);
1499 x[3] = cpl_apertures_get_centroid_x(apneg, iapneg2[1]);
1500 y[3] = cpl_apertures_get_centroid_y(apneg, iapneg2[1]);
1501
1502 cpl_apertures_delete(appos);
1503 cpl_apertures_delete(apneg);
1504 appos = NULL;
1505 apneg = NULL;
1506
1507 cpl_msg_info(cpl_func, "Positive star 1 at position %g %g", x[0], y[0]);
1508 cpl_msg_info(cpl_func, "Positive star 2 at position %g %g", x[1], y[1]);
1509
1510 cpl_msg_info(cpl_func, "Negative star 1 at position %g %g", x[2], y[2]);
1511 cpl_msg_info(cpl_func, "Negative star 2 at position %g %g", x[3], y[3]);
1512
1513 /* FIXME: Useful ? - change to 1D-distances - and move into sigma loop */
1514 dist1 = sqrt((x[2]-x[0])*(x[2]-x[0])+(y[2]-y[0])*(y[2]-y[0]));
1515 dist2 = sqrt((x[3]-x[1])*(x[3]-x[1])+(y[3]-y[1])*(y[3]-y[1]));
1516 cpl_msg_info(cpl_func, "Star 1 Pos/Neg Distance: %g", dist1);
1517 cpl_msg_info(cpl_func, "Star 2 Pos/Neg Distance: %g", dist2);
1518
1519 if (eccmin < DBL_MAX) {
1520 cpl_msg_info(cpl_func, "The deviation from a horizontal square by "
1521 "the two star pairs [pixel]: %g", eccmin);
1522 if (eccmin > VISIR_IMG_PHOT_POS_WARN) {
1523 if (eccmin > VISIR_IMG_PHOT_POS_ERROR) {
1524 cpl_msg_error(cpl_func, "The deviation from a horizontal square"
1525 " by the two star pairs exceed %g, the detected "
1526 "objects are wrong", VISIR_IMG_PHOT_POS_ERROR);
1527 skip_if(1);
1528 }
1529 cpl_msg_warning(cpl_func, "The deviation from a horizontal square "
1530 "by the two star pairs exceed %g, the detected "
1531 "objects may be wrong", VISIR_IMG_PHOT_POS_WARN);
1532 }
1533 }
1534
1535 if ((int)x[0]-IRPLIB_STREHL_BORDER <= 0 ||
1536 (int)y[0]-IRPLIB_STREHL_BORDER <= 0 ||
1537 (int)x[0]+IRPLIB_STREHL_BORDER > cpl_image_get_size_x(combined) ||
1538 (int)y[0]+IRPLIB_STREHL_BORDER > cpl_image_get_size_y(combined)) {
1539 cpl_msg_error(cpl_func, "Positive star 1 at (%g,%g) is less than %d "
1540 "pixels from the image border", x[0], y[0],
1541 1+IRPLIB_STREHL_BORDER);
1542 skip_if(1);
1543 }
1544
1545 /* Verify the stars positions */
1546 if (fabs(dist1-dist2) > VISIR_IMG_PHOT_POS_UNCERTAINTY) {
1547 cpl_msg_error(cpl_func, "Too large Pos/Neg Distance between the two "
1548 "stars: %g > %g", fabs(dist1-dist2),
1549 VISIR_IMG_PHOT_POS_UNCERTAINTY);
1550 skip_if(1);
1551 }
1552
1553 /* Photometry on positive stars */
1554 for (i=0 ; i<2 ; i++)
1555 skip_if (visir_img_phot_flux(combined, NULL, NULL,
1556 x[i], y[i],
1557 visir_img_phot_config.r0_max,
1558 visir_img_phot_config.r1,
1559 visir_img_phot_config.r2,
1560 &(flux_snr[i]),
1561 &(flux_snr_noise[i]),
1562 &(flux_snr_radius[i]),
1563 &(flux_tot[i]),
1564 &(beamshapes[i])));
1565
1566 /* Photometry on negative stars */
1567 for (i=2 ; i<4 ; i++)
1568 skip_if (visir_img_phot_flux(min_combined, NULL, NULL,
1569 x[i], y[i],
1570 visir_img_phot_config.r0_max,
1571 visir_img_phot_config.r1,
1572 visir_img_phot_config.r2,
1573 &(flux_snr[i]),
1574 &(flux_snr_noise[i]),
1575 &(flux_snr_radius[i]),
1576 &(flux_tot[i]),
1577 &(beamshapes[i])));
1578
1579 cpl_image_delete(min_combined);
1580 min_combined = NULL;
1581
1582 /* Compute the results */
1583 /* Flux */
1584 visir_img_phot_config.flux_snr = 0.0;
1585 for (i=0 ; i<4 ; i++) visir_img_phot_config.flux_snr += flux_snr[i];
1586
1587 /* Flux noise */
1588 visir_img_phot_config.flux_snr_noise = 0.0;
1589 for (i=0 ; i<4 ; i++) visir_img_phot_config.flux_snr_noise +=
1590 flux_snr_noise[i]*flux_snr_noise[i];
1591 visir_img_phot_config.flux_snr_noise =
1592 sqrt(visir_img_phot_config.flux_snr_noise);
1593
1594 for (i=0 ; i<4 ; i++)
1595 visir_img_phot_config.flux_snr_radius[i] = flux_snr_radius[i];
1596
1597 /* Total flux */
1598 visir_img_phot_config.flux_tot = 0.0;
1599 for (i=0 ; i<4 ; i++) visir_img_phot_config.flux_tot += flux_tot[i];
1600
1601 /* FWHM */
1602 ngood_fwhm = 0;
1603 visir_img_phot_config.beamshape.fwhm_x = 0.0;
1604 for (i=0 ; i<4 ; i++) {
1605 if (beamshapes[i].fwhm_x > 0.0) {
1606 visir_img_phot_config.beamshape.fwhm_x += beamshapes[i].fwhm_x;
1607 ngood_fwhm ++;
1608 }
1609 }
1610 if (ngood_fwhm > 0) visir_img_phot_config.beamshape.fwhm_x /= ngood_fwhm;
1611 else visir_img_phot_config.beamshape.fwhm_x = -1.0;
1612 ngood_fwhm = 0;
1613 visir_img_phot_config.beamshape.fwhm_y = 0.0;
1614 for (i=0 ; i<4 ; i++) {
1615 if (beamshapes[i].fwhm_y > 0.0) {
1616 visir_img_phot_config.beamshape.fwhm_y += beamshapes[i].fwhm_y;
1617 ngood_fwhm ++;
1618 }
1619 }
1620 if (ngood_fwhm > 0) visir_img_phot_config.beamshape.fwhm_y /= ngood_fwhm;
1621 else visir_img_phot_config.beamshape.fwhm_y = -1.0;
1622 visir_img_phot_config.fwhm_x_pos1 = beamshapes[0].fwhm_x;
1623 visir_img_phot_config.fwhm_y_pos1 = beamshapes[0].fwhm_y;
1624 visir_img_phot_config.fwhm_x_pos2 = beamshapes[1].fwhm_x;
1625 visir_img_phot_config.fwhm_y_pos2 = beamshapes[1].fwhm_y;
1626 visir_img_phot_config.fwhm_x_neg1 = beamshapes[2].fwhm_x;
1627 visir_img_phot_config.fwhm_y_neg1 = beamshapes[2].fwhm_y;
1628 visir_img_phot_config.fwhm_x_neg2 = beamshapes[3].fwhm_x;
1629 visir_img_phot_config.fwhm_y_neg2 = beamshapes[3].fwhm_y;
1630
1631 /* Get lam and dlam from the filter name for the Strehl computation */
1632 if (visir_get_filter_infos(visir_img_phot_config.filter, &lam, &dlam)) {
1633 cpl_msg_error(cpl_func, "Central wavelength and width is missing for "
1634 "filter: %s", visir_img_phot_config.filter);
1635 skip_if(1);
1636 }
1637
1638 /* Strehl computation */
1639 cpl_errorstate errstate = cpl_errorstate_get();
1640 if (irplib_strehl_compute(combined, STREHL_M1, STREHL_M2, lam, dlam,
1641 visir_img_phot_config.pscale,
1642 STREHL_BOX_SIZE, x[0], y[0], STREHL_STAR_RADIUS,
1643 STREHL_BG_R1, STREHL_BG_R2, -1, -1,
1644 &(visir_img_phot_config.strehl),
1645 &(visir_img_phot_config.strehl_err),
1646 &star_bg, &star_peak, &star_flux, &psf_peak, &psf_flux,
1647 &bg_noise)) {
1648 cpl_msg_error(cpl_func, "Could not compute the strehl: '%s' in %s",
1649 cpl_error_get_message(), cpl_error_get_where());
1650 cpl_errorstate_set(errstate);
1651 }
1652
1653
1654 end_skip;
1655
1656 cpl_apertures_delete(appos);
1657 cpl_apertures_delete(apneg);
1658 cpl_vector_delete(sigmas);
1659 cpl_image_delete(min_combined);
1660
1661 return cpl_error_get_code();
1662
1663}
1664
1665
1666/*----------------------------------------------------------------------------*/
1682/*----------------------------------------------------------------------------*/
1683static double visir_img_phot_eccent_four(const cpl_apertures * appos,
1684 int ipos1, int ipos2,
1685 const cpl_apertures * apneg,
1686 int ineg1, int ineg2)
1687{
1688
1689 /* NB: Lower left pixel is (1, 1) */
1690
1691 /* The two positive points */
1692 const double xp1 = cpl_apertures_get_centroid_x(appos, ipos1);
1693 const double xp2 = cpl_apertures_get_centroid_x(appos, ipos2);
1694 const double yp1 = cpl_apertures_get_centroid_y(appos, ipos1);
1695 const double yp2 = cpl_apertures_get_centroid_y(appos, ipos2);
1696
1697 /* The leftmost positive point */
1698 const double xpl = xp1 < xp2 ? xp1 : xp2;
1699 const double ypl = xp1 < xp2 ? yp1 : yp2;
1700
1701 /* The rightmost positive point */
1702 const double xpr = xp1 < xp2 ? xp2 : xp1;
1703 const double ypr = xp1 < xp2 ? yp2 : yp1;
1704
1705 /* The two negative points */
1706 const double xn1 = cpl_apertures_get_centroid_x(apneg, ineg1);
1707 const double yn1 = cpl_apertures_get_centroid_y(apneg, ineg1);
1708 const double xn2 = cpl_apertures_get_centroid_x(apneg, ineg2);
1709 const double yn2 = cpl_apertures_get_centroid_y(apneg, ineg2);
1710
1711 /* The leftmost negative point */
1712 const double xln = xn1 < xn2 ? xn1 : xn2;
1713 const double yln = xn1 < xn2 ? yn1 : yn2;
1714
1715 /* The rightmost engative point */
1716 const double xrn = xn1 < xn2 ? xn2 : xn1;
1717 const double yrn = xn1 < xn2 ? yn2 : yn1;
1718
1719 const double lx1 = xrn - xpl; /* The length of the top x-side */
1720 const double lx2 = xpr - xln; /* The length of the bottom x-side */
1721 const double ly1 = ypl - yln; /* The length of the left y-side */
1722 const double ly2 = yrn - ypr; /* The length of the right y-side */
1723
1724 const double lmean = 0.25 * ( lx1 + lx2 + ly1 + ly2);
1725
1726 const double dx1 = lx1 - lmean;
1727 const double dx2 = lx2 - lmean;
1728 const double dy1 = ly1 - lmean;
1729 const double dy2 = ly2 - lmean;
1730
1731 const double ey1 = yrn - ypl; /* The displacement in the top x-side */
1732 const double ey2 = ypr - yln; /* The displacement in the bottom x-side */
1733 const double ex1 = xpl - xln; /* The displacement in the left y-side */
1734 const double ex2 = xpr - xrn; /* The displacement in the right y-side */
1735
1736 const double result = sqrt(dx1 * dx1 + dx2 * dx2 + dy1 * dy1 + dy2 * dy2 +
1737 ex1 * ex1 + ex2 * ex2 + ey1 * ey1 + ey2 * ey2);
1738
1739
1740 bug_if(0);
1741
1742 bug_if(appos == apneg);
1743 bug_if(ipos1 == ipos2);
1744 bug_if(ineg1 == ineg2);
1745
1746 end_skip;
1747
1748 return result;
1749
1750
1751}
1752
1753#ifdef VISIR_IMG_PHOT_USE_ECCENT_THREE
1754/*----------------------------------------------------------------------------*/
1769/*----------------------------------------------------------------------------*/
1770static double visir_img_phot_eccent_three(const cpl_apertures * appos,
1771 int ipos,
1772 const cpl_apertures * apneg,
1773 int ineg1, int ineg2)
1774{
1775
1776 /* NB: Lower left pixel is (1, 1) */
1777
1778 /* The positive point */
1779 const double xp = cpl_apertures_get_centroid_x(appos, ipos);
1780 const double yp = cpl_apertures_get_centroid_y(appos, ipos);
1781
1782 /* The two negative points */
1783 const double xn1 = cpl_apertures_get_centroid_x(apneg, ineg1);
1784 const double yn1 = cpl_apertures_get_centroid_y(apneg, ineg1);
1785 const double xn2 = cpl_apertures_get_centroid_x(apneg, ineg2);
1786 const double yn2 = cpl_apertures_get_centroid_y(apneg, ineg2);
1787
1788 /* The bottom negative point */
1789 const double xnb = xn1 < xn2 ? xn1 : xn2;
1790 const double ynb = xn1 < xn2 ? yn1 : yn2;
1791
1792 /* The top engative point */
1793 const double xnt = xn1 < xn2 ? xn2 : xn1;
1794 const double ynt = xn1 < xn2 ? yn2 : yn1;
1795
1796 const double l1 = ynt - yp; /* The length of the top line */
1797 const double l2 = yp - ynb; /* The length of the bottom line */
1798 const double ln = ynt - ynb; /* The length of the top to bottom line */
1799
1800 const double lmean = 0.25 * ( l1 + l2 + ln);
1801
1802 const double d1 = l1 - lmean;
1803 const double d2 = l2 - lmean;
1804 const double dn = 0.5 * ln - lmean;
1805
1806 const double e1 = xp - xnt; /* The displacement in the top line */
1807 const double e2 = xp - xnb; /* The displacement in the bottom line */
1808
1809 const double result = sqrt(d1 * d1 + d2 * d2 + dn * dn + e1 * e1 + e2 * e2);
1810
1811
1812 bug_if(0);
1813
1814 bug_if(appos == apneg);
1815 bug_if(ineg1 == ineg2);
1816
1817 end_skip;
1818
1819 return result;
1820
1821
1822}
1823
1824#endif
1825
1826/*----------------------------------------------------------------------------*/
1848/*----------------------------------------------------------------------------*/
1849static int visir_img_phot_flux(
1850 const cpl_image * combined,
1851 const cpl_image * weights_,
1852 const cpl_image * contrib,
1853 double x_pos,
1854 double y_pos,
1855 int r0_max,
1856 int r1,
1857 int r2,
1858 double * flux_snr,
1859 double * flux_snr_noise,
1860 int * flux_snr_radius,
1861 double * flux_tot,
1862 beamshape_t * beamshape)
1863{
1864 cpl_apertures * apert = NULL;
1865 cpl_image * labels;
1866 cpl_image * bg_subtracted = NULL;
1867 cpl_vector * r0 = NULL;
1868 cpl_vector * fl = NULL;
1869 cpl_vector * fl_noise = NULL;
1870 cpl_vector * snr = NULL;
1871 double bg;
1872 double max_val = 0.0; /* Avoid (false) uninit warning */
1873 int max_ind = 0; /* Avoid (false) uninit warning */
1874 int i;
1875 cpl_size nx, ny;
1876 int max_contrib = 1;
1877 cpl_image * weights = weights_ == NULL ?
1878 NULL : cpl_image_duplicate(weights_);
1879
1880
1881 if (cpl_error_get_code()) return cpl_error_get_code();
1882
1883 cpl_ensure_code(combined != NULL, CPL_ERROR_NULL_INPUT);
1884 cpl_ensure_code(r0_max > 0, CPL_ERROR_ILLEGAL_INPUT);
1885
1886 nx = cpl_image_get_size_x(combined);
1887 ny = cpl_image_get_size_y(combined);
1888
1889 if (weights) {
1890 cpl_ensure_code(nx == cpl_image_get_size_x(weights) &&
1891 ny == cpl_image_get_size_y(weights),
1892 CPL_ERROR_ILLEGAL_INPUT);
1893 }
1894
1895 if (contrib) {
1896 cpl_ensure_code(nx == cpl_image_get_size_x(contrib) &&
1897 ny == cpl_image_get_size_y(contrib),
1898 CPL_ERROR_ILLEGAL_INPUT);
1899 max_contrib = cpl_image_get_max(contrib);
1900 cpl_ensure_code(max_contrib >= 1, CPL_ERROR_ILLEGAL_INPUT);
1901 }
1902
1903 /* Create the label image defining the background ring */
1904 if ((labels = visir_create_ring_intimage(nx, ny,
1905 (int)x_pos, (int)y_pos, r1, r2)) == NULL) {
1906 cpl_msg_error(cpl_func, "Could not create a ring image");
1907 skip_if(1);
1908 }
1909 /* Compute the background */
1910 apert = cpl_apertures_new_from_image(combined, labels);
1911 cpl_image_delete(labels);
1912 labels = NULL;
1913 bg = cpl_apertures_get_median(apert, 1);
1914 cpl_apertures_delete(apert);
1915 apert = NULL;
1916 cpl_msg_info(cpl_func, "Background : %g", bg);
1917
1918 /* Create the label image defining the total star disk */
1919 if ((labels = visir_create_disk_intimage(nx, ny,
1920 (int)x_pos, (int)y_pos, r0_max)) == NULL) {
1921 cpl_msg_error(cpl_func, "Could not create a disk image");
1922 skip_if(1);
1923 }
1924
1925 /* Compute the total flux and the associated error */
1926
1927 bg_subtracted = cpl_image_subtract_scalar_create(combined, bg);
1928
1929 /* due to bad pixels rescale the sum to equal contribution */
1930 if (contrib) {
1931 cpl_image * scale = cpl_image_cast(contrib, CPL_TYPE_DOUBLE);
1932 cpl_image_power(scale, -1);
1933 cpl_image_multiply_scalar(scale, max_contrib);
1934 cpl_image_multiply(bg_subtracted, scale);
1935 if (weights)
1936 cpl_image_multiply(weights, scale);
1937 cpl_image_delete(scale);
1938 }
1939
1940 apert = cpl_apertures_new_from_image(bg_subtracted, labels);
1941 cpl_image_delete(labels);
1942 labels = NULL;
1943 *flux_tot = cpl_apertures_get_flux(apert, 1);
1944 cpl_apertures_delete(apert);
1945 apert = NULL;
1946 cpl_msg_info(cpl_func, "Star total flux (error): %g", *flux_tot);
1947
1948 /* Create and fill r0 */
1949 r0 = cpl_vector_new(r0_max);
1950 for (i=0 ; i<r0_max ; i++) cpl_vector_set(r0, i, i+1);
1951
1952 /* Create fl, fl_noise */
1953 fl = cpl_vector_new(r0_max);
1954 fl_noise = cpl_vector_new(r0_max);
1955
1956 /* For each radius, compute fl and fl_noise */
1957 for (i=0 ; i<r0_max ; i++) {
1958 float fl_val = 0.f, fl_noise_val = 0.f;
1959 /* Create the label image defining the current star disk */
1960 if ((labels = visir_create_disk_intimage(nx, ny,
1961 (int)x_pos, (int)y_pos, (int)cpl_vector_get(r0, i))) == NULL) {
1962 cpl_msg_error(cpl_func, "Could not create a disk image: %d", i);
1963 break;
1964 }
1965
1966 if (weights) {
1967 double sum = 0, esum = 0;
1968 int d;
1969 for (int ix = 1; ix < 1 + nx; ix++) {
1970 for (int iy = 1; iy < 1 + ny; iy++) {
1971 if (!cpl_image_get(labels, ix, iy, &d) || d)
1972 continue;
1973
1974 sum += cpl_image_get(bg_subtracted, ix, iy, &d);
1975 /* assume gaussian error propagation, e = sqrt(1/w)
1976 * => e = sqrt(sum_i(1/w_i)) */
1977 esum += (1. / cpl_image_get(weights, ix, iy, &d));
1978 }
1979 }
1980 fl_val = sum;
1981 fl_noise_val = sqrt(esum);
1982 }
1983 else {
1984 cpl_apertures * pert =
1985 cpl_apertures_new_from_image(bg_subtracted, labels);
1986 /* FIXME: pert == NULL ? */
1987 fl_val = cpl_apertures_get_flux(pert, 1);
1988 fl_noise_val = visir_img_phot_config.bg_sigma *
1989 sqrt((double)cpl_apertures_get_npix(pert, 1));
1990 cpl_apertures_delete(pert);
1991 }
1992
1993 /* Compute the statistics on the zone defined by the labels */
1994 cpl_image_delete(labels);
1995 labels = NULL;
1996 cpl_vector_set(fl, i, fl_val);
1997 cpl_vector_set(fl_noise, i, fl_noise_val);
1998 }
1999 skip_if( 0 );
2000
2001 /* Compute the flux (and error) for the best signal to noise */
2002 snr = cpl_vector_duplicate(fl);
2003 cpl_vector_divide(snr, fl_noise);
2004 for (i=0 ; i<r0_max ; i++) {
2005 if (i == 0 || max_val < cpl_vector_get(snr, i)) {
2006 max_val = cpl_vector_get(snr, i);
2007 max_ind = i;
2008 }
2009 }
2010 *flux_snr = cpl_vector_get(fl, max_ind);
2011 *flux_snr_noise = cpl_vector_get(fl_noise, max_ind);
2012 *flux_snr_radius = (int)cpl_vector_get(r0, max_ind);
2013 cpl_msg_info(cpl_func, "Best SNR star flux : %g (%g) for radius %d <= %d "
2014 " [pixel]", *flux_snr, *flux_snr_noise,
2015 (int)cpl_vector_get(r0, max_ind),
2016 (int)cpl_vector_get(r0, r0_max-1));
2017
2018 if (cpl_msg_get_level() <= CPL_MSG_DEBUG) {
2019 cpl_matrix * mdump = cpl_matrix_new(1+r0_max, 3);
2020 for (i = 0; i < r0_max; i++) {
2021 cpl_matrix_set(mdump, i+1, 0, cpl_vector_get(fl, i));
2022 cpl_matrix_set(mdump, i+1, 1, cpl_vector_get(fl_noise, i));
2023 cpl_matrix_set(mdump, i+1, 2, cpl_vector_get(snr, i));
2024 }
2025 cpl_msg_debug(cpl_func, "Flux, flux-noise and S/N for radii out to %d",
2026 (int)cpl_vector_get(r0, r0_max-1));
2027
2028 cpl_matrix_dump(mdump, stdout);
2029 cpl_matrix_delete(mdump);
2030 }
2031
2032 *beamshape = (beamshape_t){.fwhm_x = -1., .fwhm_y = -1.,
2033 .peak = -1., .peak_err = 0.,
2034 .major = -1., .major_err = 0.,
2035 .minor = -1., .minor_err = 0.,
2036 .angle = -1., .angle_err = 0.};
2037
2038 /* Compute the FWHM */
2039 skip_if (cpl_image_get_fwhm(bg_subtracted, (int)x_pos, (int)y_pos, &beamshape->fwhm_x,
2040 &beamshape->fwhm_y));
2041
2042 skip_if ( beamshape->fwhm_x <= 0.0 );
2043 skip_if ( beamshape->fwhm_y <= 0.0 );
2044
2045 cpl_errorstate cleanstate = cpl_errorstate_get();
2046
2047 if (fit_2d_gauss(bg_subtracted, weights, (cpl_size)x_pos, (cpl_size)y_pos,
2048 beamshape->fwhm_x, beamshape->fwhm_y,
2049 &beamshape->peak, &beamshape->peak_err,
2050 &beamshape->major, &beamshape->major_err,
2051 &beamshape->minor, &beamshape->minor_err,
2052 &beamshape->angle, &beamshape->angle_err) == CPL_ERROR_NONE) {
2053 cpl_msg_info(cpl_func, "Peak: %g +- %g, FWHM : %g +- %g major ; %g +- %g minor, "
2054 "angle %g +- %g", beamshape->peak, beamshape->peak_err,
2055 beamshape->major, beamshape->major_err,
2056 beamshape->minor, beamshape->minor_err, beamshape->angle *
2057 CPL_MATH_DEG_RAD, beamshape->angle_err *
2058 CPL_MATH_DEG_RAD);
2059 }
2060 else {
2061 cpl_msg_warning(cpl_func, "2D gauss fit failed, approximate FWHM : %g"
2062 "in x ; %g in y ", beamshape->fwhm_x, beamshape->fwhm_y);
2063 cpl_errorstate_set(cleanstate);
2064 }
2065
2066 end_skip;
2067
2068 cpl_apertures_delete(apert);
2069 cpl_image_delete(labels);
2070 cpl_image_delete(bg_subtracted);
2071 cpl_image_delete(weights);
2072
2073 cpl_vector_delete(r0);
2074 cpl_vector_delete(fl);
2075 cpl_vector_delete(snr);
2076 cpl_vector_delete(fl_noise);
2077
2078 return cpl_error_get_code();
2079}
2080
2081
2082/*----------------------------------------------------------------------------*/
2093/*----------------------------------------------------------------------------*/
2094static cpl_error_code visir_get_filter_infos(
2095 const char * f,
2096 double * pcwlen,
2097 double * pdwlen)
2098{
2099
2100 double cwlen = -1;
2101 double dwlen = -1;
2102
2103 cpl_ensure_code(f, CPL_ERROR_NULL_INPUT);
2104 cpl_ensure_code(pcwlen, CPL_ERROR_NULL_INPUT);
2105 cpl_ensure_code(pdwlen, CPL_ERROR_NULL_INPUT);
2106
2107 skip_if (!strcmp(f, "MV"));
2108
2109 if (!strcmp(f, "N-BAND") || !strcmp(f, "N_BAND"))
2110 { cwlen = 10.56; dwlen = 5.37;}
2111 else if (!strcmp(f, "SIC")) { cwlen = 11.848;dwlen = 2.34;}
2112 else if (!strcmp(f, "PAH1_1")) { cwlen = 8.19;dwlen = 0.15;}
2113 else if (!strcmp(f, "PAH1")) { cwlen = 8.586;dwlen = 0.421;}
2114 else if (!strcmp(f, "ARIII")) { cwlen = 8.992;dwlen = 0.138;}
2115 else if (!strcmp(f, "SIV_1")) { cwlen = 10.02;dwlen = 0.18;}
2116 else if (!strcmp(f, "SIV")) { cwlen = 10.485;dwlen = 0.159;}
2117 else if (!strcmp(f, "PAH2_1")) { cwlen = 10.76;dwlen = 0.69;}
2118 else if (!strcmp(f, "SIV_2")) { cwlen = 11.1;dwlen = 0.19;}
2119 else if (!strcmp(f, "PAH2")) { cwlen = 11.254;dwlen = 0.594;}
2120 else if (!strcmp(f, "PAH2_2")) { cwlen = 12.13;dwlen = 0.37;}
2121 else if (!strcmp(f, "NEII_1")) { cwlen = 12.51;dwlen = 0.18;}
2122 else if (!strcmp(f, "NEII")) { cwlen = 12.805;dwlen = 0.21;}
2123 else if (!strcmp(f, "NEII_2")) { cwlen = 13.036;dwlen = 0.219;}
2124 else if (!strcmp(f, "Q0")) { cwlen = 16.554;dwlen = 0.398;}
2125 else if (!strcmp(f, "QH2")) { cwlen = 17.11;dwlen = 0.398;}
2126 else if (!strcmp(f, "Q1")) { cwlen = 17.653;dwlen = 0.83;}
2127 else if (!strcmp(f, "Q2")) { cwlen = 18.718;dwlen = 0.878;}
2128 else if (!strcmp(f, "Q3")) { cwlen = 19.5;dwlen = 0.4;}
2129 else if (!strcmp(f, "Q4")) { cwlen = 20.5;dwlen = 1.0;}
2130 else if (!strcmp(f, "Q7")) { cwlen = 23.1;dwlen = 0.8;}
2131 else if (!strcmp(f, "Q8")) { cwlen = 24.5;dwlen = 0.8;}
2132 /* TODO missing bandwidth for coro filters not determined yet */
2133 else if (!strcmp(f, "10_5_4QP")) { cwlen = 10.5;dwlen =0.1;}
2134 else if (!strcmp(f, "11_3_4QP")) { cwlen = 11.3;dwlen =0.1;}
2135 else if (!strcmp(f, "12_4_AGP")) { cwlen = 12.4;dwlen =0.1;}
2136 else if (!strcmp(f, "N-SW-spec") || !strcmp(f, "N_SW_spec"))
2137 { cwlen = 8.85; dwlen = 2.7;}
2138 else if (!strcmp(f, "H2S4-spec") || !strcmp(f, "H2S4_spec"))
2139 { cwlen = 8.12; dwlen = 0.3;}
2140 else if (!strcmp(f, "ARIII-spec") || !strcmp(f, "ARIII_spec"))
2141 { cwlen = 8.44; dwlen = 0.78;}
2142 else if (!strcmp(f, "NEII_2-spec") || !strcmp(f, "NEII_2_spec"))
2143 { cwlen = 12.805; dwlen = 0.2;}
2144 else if (!strcmp(f, "H2S3-spec") || !strcmp(f, "H2S3_spec"))
2145 { cwlen = 9.62; dwlen = 0.2;}
2146 else if (!strcmp(f, "H2S1-spec") || !strcmp(f, "H2S1_spec"))
2147 { cwlen = 17.0;dwlen = 0.4;}
2148 else if (!strcmp(f, "M-BAND") || !strcmp(f, "M_BAND"))
2149 { cwlen = 4.82;dwlen = 0.35;}
2150
2151 /* The width of each new, below filter is the Full Width at Half Maximum */
2152
2153 else if (!strcmp(f, "J7.9") || !strcmp(f, "J7_9"))
2154 { cwlen = (7.483 + 8.035)/2.0;
2155 dwlen = 8.035 - 7.483;}
2156 else if (!strcmp(f, "J8.9") || !strcmp(f, "J8_9"))
2157 { cwlen = (8.338 + 9.068)/2.0;
2158 dwlen = 9.068 - 8.338;}
2159 else if (!strcmp(f, "J9.8") || !strcmp(f, "J9_8"))
2160 { cwlen = (9.123 + 10.059)/2.0;
2161 dwlen = 10.059 - 9.123;}
2162 else if (!strcmp(f, "J12.2") || !strcmp(f, "J12_2"))
2163 { cwlen = (11.700 + 12.216)/2.0;
2164 dwlen = 12.216 - 11.700;}
2165 else if (!strcmp(f, "B8.7") || !strcmp(f, "B8_7"))
2166 { cwlen = (8.436 + 9.410)/2.0;
2167 dwlen = 9.410 - 8.436;}
2168 else if (!strcmp(f, "B9.7") || !strcmp(f, "B9_7"))
2169 { cwlen = (9.402 + 10.242)/2.0;
2170 dwlen = 10.242 - 9.402;}
2171 else if (!strcmp(f, "B10.7") || !strcmp(f, "B10_7"))
2172 { cwlen = (9.970 + 11.338)/2.0;
2173 dwlen = 11.338 - 9.970;}
2174 else if (!strcmp(f, "B11.7") || !strcmp(f, "B11_7"))
2175 { cwlen = (11.098 + 11.950)/2.0;
2176 dwlen = 11.950 - 11.098;}
2177 else if (!strcmp(f, "B12.4") || !strcmp(f, "B12_4"))
2178 { cwlen = (11.971 + 12.961)/2.0;
2179 dwlen = 12.961 - 11.971;}
2180 else if (!strcmp(f, "L-BAND") || !strcmp(f, "L_BAND"))
2181 { cwlen = 3.7702; //(3.4195 + 4.0610)/2.0;
2182 dwlen = 4.0610 - 3.4195;}
2183
2184 *pcwlen = cwlen;
2185 *pdwlen = dwlen;
2186
2187 cpl_ensure_code(cwlen > 0, CPL_ERROR_DATA_NOT_FOUND);
2188 cpl_ensure_code(dwlen > 0, CPL_ERROR_DATA_NOT_FOUND);
2189
2190 end_skip;
2191
2192 return cpl_error_get_code();
2193}
2194
2195/*----------------------------------------------------------------------------*/
2203/*----------------------------------------------------------------------------*/
2204static cpl_error_code visir_img_phot_qc(cpl_propertylist * qclist,
2205 cpl_boolean drop_wcs,
2206 const irplib_framelist * rawframes)
2207{
2208
2209 const cpl_propertylist * reflist
2210 = irplib_framelist_get_propertylist_const(rawframes, 0);
2211
2212
2213 /* QC.EXPTIME */
2214 bug_if (cpl_propertylist_append_double(qclist, "ESO QC EXPTIME",
2215 visir_img_phot_config.exptime));
2216 /* QC.JYVAL */
2217 bug_if (cpl_propertylist_append_double(qclist, "ESO QC JYVAL",
2218 visir_img_phot_config.jy_val));
2219 /* QC.STARNAME */
2220 bug_if (cpl_propertylist_append_string(qclist, "ESO QC STARNAME",
2221 visir_img_phot_config.star_name));
2222 /* QC.FILTER */
2223 bug_if (cpl_propertylist_append_string(qclist, "ESO QC FILTER",
2224 visir_img_phot_config.filter));
2225
2226 /* QC.NELEC */
2227 bug_if (cpl_propertylist_append_double(qclist, "ESO QC NELEC",
2228 visir_img_phot_config.nelec));
2229 /* QC.NPHOT */
2230 bug_if (cpl_propertylist_append_double(qclist, "ESO QC NPHOT",
2231 visir_img_phot_config.nphot));
2232 /* QC.BACKGD.SIGMA */
2233 bug_if (cpl_propertylist_append_double(qclist, "ESO QC BACKGD SIGMA",
2234 visir_img_phot_config.bg_sigma));
2235 /* QC.FLUXTOT */
2236 bug_if (cpl_propertylist_append_double(qclist, "ESO QC FLUXTOT",
2237 visir_img_phot_config.flux_tot));
2238 /* QC.FLUXSNR */
2239 bug_if (cpl_propertylist_append_double(qclist, "ESO QC FLUXSNR",
2240 visir_img_phot_config.flux_snr));
2241 /* QC.FLUXSNR.NOISE */
2242 bug_if (cpl_propertylist_append_double(qclist, "ESO QC FLUXSNR NOISE",
2243 visir_img_phot_config.flux_snr_noise));
2244 /* QC.FLUXSNR.RADIUS */
2245 for (int i = 0; i < 4; i++) {
2246 const int r = visir_img_phot_config.flux_snr_radius[i];
2247 char buffer[100];
2248 sprintf(buffer, "ESO QC FLUXSNR RADIUS%d", i + 1);
2249 bug_if (cpl_propertylist_append_int(qclist, buffer, r));
2250 }
2251 /* QC.FWHMX */
2252 bug_if (cpl_propertylist_append_double(qclist, "ESO QC FWHMX",
2253 visir_img_phot_config.beamshape.fwhm_x));
2254 /* QC.FWHMY */
2255 bug_if (cpl_propertylist_append_double(qclist, "ESO QC FWHMY",
2256 visir_img_phot_config.beamshape.fwhm_y));
2257 bug_if (cpl_propertylist_append_double(qclist, "ESO QC GAUSSFIT FWHM_MAX",
2258 visir_img_phot_config.beamshape.major));
2259 cpl_propertylist_set_comment(qclist, "ESO QC GAUSSFIT FWHM_MAX",
2260 "major axis [pix]");
2261 bug_if (cpl_propertylist_append_double(qclist, "ESO QC GAUSSFIT FWHM_MAX_ERR",
2262 visir_img_phot_config.beamshape.major_err));
2263 bug_if (cpl_propertylist_append_double(qclist, "ESO QC GAUSSFIT FWHM_MIN",
2264 visir_img_phot_config.beamshape.minor));
2265 cpl_propertylist_set_comment(qclist, "ESO QC GAUSSFIT FWHM_MIN",
2266 "minor axis [pix]");
2267 bug_if (cpl_propertylist_append_double(qclist, "ESO QC GAUSSFIT FWHM_MIN_ERR",
2268 visir_img_phot_config.beamshape.minor_err));
2269 bug_if (cpl_propertylist_append_double(qclist, "ESO QC GAUSSFIT ANGLE",
2270 visir_img_phot_config.beamshape.angle * CPL_MATH_DEG_RAD));
2271 cpl_propertylist_set_comment(qclist, "ESO QC GAUSSFIT ANGLE",
2272 "[deg]");
2273 bug_if (cpl_propertylist_append_double(qclist, "ESO QC GAUSSFIT ANGLE_ERR",
2274 visir_img_phot_config.beamshape.angle_err * CPL_MATH_DEG_RAD));
2275 bug_if (cpl_propertylist_append_double(qclist, "ESO QC GAUSSFIT PEAK",
2276 visir_img_phot_config.beamshape.peak));
2277 bug_if (cpl_propertylist_append_double(qclist, "ESO QC GAUSSFIT PEAK_ERR",
2278 visir_img_phot_config.beamshape.peak_err));
2279 /* QC.FWHMX.POS1 */
2280 bug_if (cpl_propertylist_append_double(qclist, "ESO QC FWHMX POS1",
2281 visir_img_phot_config.fwhm_x_pos1));
2282 /* QC.FWHMY.POS1 */
2283 bug_if (cpl_propertylist_append_double(qclist, "ESO QC FWHMY POS1",
2284 visir_img_phot_config.fwhm_y_pos1));
2285 /* QC.FWHMX.POS2 */
2286 bug_if (cpl_propertylist_append_double(qclist, "ESO QC FWHMX POS2",
2287 visir_img_phot_config.fwhm_x_pos2));
2288 /* QC.FWHMY.POS2 */
2289 bug_if (cpl_propertylist_append_double(qclist, "ESO QC FWHMY POS2",
2290 visir_img_phot_config.fwhm_y_pos2));
2291 /* QC.FWHMX.NEG1 */
2292 bug_if (cpl_propertylist_append_double(qclist, "ESO QC FWHMX NEG1",
2293 visir_img_phot_config.fwhm_x_neg1));
2294 /* QC.FWHMY.NEG1 */
2295 bug_if (cpl_propertylist_append_double(qclist, "ESO QC FWHMY NEG1",
2296 visir_img_phot_config.fwhm_y_neg1));
2297 /* QC.FWHMX.NEG2 */
2298 bug_if (cpl_propertylist_append_double(qclist, "ESO QC FWHMX NEG2",
2299 visir_img_phot_config.fwhm_x_neg2));
2300 /* QC.FWHMY.NEG2 */
2301 bug_if (cpl_propertylist_append_double(qclist, "ESO QC FWHMY NEG2",
2302 visir_img_phot_config.fwhm_y_neg2));
2303 /* QC.SENSIT */
2304 bug_if (cpl_propertylist_append_double(qclist, "ESO QC SENSIT",
2305 visir_img_phot_config.sensitivity));
2306 /* QC.AREASENSIT */
2307 bug_if (cpl_propertylist_append_double(qclist, "ESO QC AREA SENSIT",
2308 visir_img_phot_config.area_sensit));
2309 cpl_propertylist_set_comment(qclist, "ESO QC AREA SENSIT",
2310 "scaled to noise of 1 arcsecond");
2311 /* QC.CONVER */
2312 bug_if (cpl_propertylist_append_double(qclist, "ESO QC CONVER",
2313 visir_img_phot_config.conversion));
2314 /* QC.STREHL */
2315 bug_if (cpl_propertylist_append_double(qclist, "ESO QC STREHL",
2316 visir_img_phot_config.strehl));
2317 /* QC.STREHL.ERROR */
2318 bug_if (cpl_propertylist_append_double(qclist, "ESO QC STREHL ERROR",
2319 visir_img_phot_config.strehl_err));
2320
2321 /* QC.CAPA */
2322 skip_if (visir_qc_append_capa(qclist, rawframes));
2323
2324 if (drop_wcs) {
2325 cpl_propertylist * pcopy = cpl_propertylist_new();
2326 const cpl_error_code error
2327 = cpl_propertylist_copy_property_regexp(pcopy, reflist, "^("
2328 IRPLIB_PFITS_WCS_REGEXP
2329 ")$", 0);
2330 if (!error && cpl_propertylist_get_size(pcopy) > 0) {
2331 cpl_msg_warning(cpl_func, "Combined image will have no WCS "
2332 "coordinates");
2333 }
2334 cpl_propertylist_delete(pcopy);
2335 bug_if(0);
2336
2337 bug_if(cpl_propertylist_copy_property_regexp(qclist, reflist, "^("
2338 VISIR_PFITS_IMG_PHOT_COPY
2339 ")$", 0));
2340 } else {
2341 bug_if(cpl_propertylist_copy_property_regexp(qclist, reflist, "^("
2342 VISIR_PFITS_IMG_PHOT_COPY
2343 "|" IRPLIB_PFITS_WCS_REGEXP
2344 ")$", 0));
2345 }
2346
2347 bug_if (irplib_pfits_set_airmass(qclist, rawframes));
2348
2349 end_skip;
2350
2351 return cpl_error_get_code();
2352
2353}
2354
2355/*----------------------------------------------------------------------------*/
2367/*----------------------------------------------------------------------------*/
2368static cpl_error_code visir_img_phot_save(cpl_frameset * self,
2369 const cpl_parameterlist * parlist,
2370 const cpl_propertylist * qclist,
2371 const cpl_image * combined,
2372 const cpl_image * contrib,
2373 const cpl_image * beam1,
2374 const cpl_image * beam1i,
2375 const cpl_image * weights)
2376{
2377
2378 cpl_propertylist * xtlist = cpl_propertylist_new();
2379 const char * procatg = VISIR_IMG_PHOT_COMBINED_PROCATG;
2380
2381 bug_if (0);
2382
2383 if (weights) {
2384 const char * s = cpl_propertylist_get_string(qclist, "ESO QC BEAMID");
2385 bug_if(s == NULL);
2386
2387 if (strcmp(s, "COMBINED") == 0)
2388 procatg = VISIR_IMG_PHOT_COMBINED_PROCATG;
2389 else
2390 procatg = VISIR_IMG_PHOT_ONEBEAM_PROCATG;
2391 }
2392
2393 /* SAVE THE COMBINED IMAGE */
2394 skip_if (irplib_dfs_save_image(self, parlist, self, combined,
2395 CPL_BPP_IEEE_FLOAT, RECIPE_SAVE_STRING,
2396 procatg, qclist, NULL, visir_pipe_id,
2397 RECIPE_SAVE_STRING CPL_DFS_FITS));
2398
2399 if (!weights) {
2400 /* THE CONTRIBUTION MAP */
2401 bug_if(cpl_propertylist_append_string(xtlist, "EXTNAME",
2402 "Contribution Map"));
2403 skip_if (cpl_image_save(contrib, RECIPE_SAVE_STRING CPL_DFS_FITS,
2404 CPL_BPP_16_UNSIGNED, xtlist, CPL_IO_EXTEND));
2405 }
2406
2407 if (beam1 != NULL) {
2408 bug_if(weights);
2409 /* THE BEAM COLLAPSED IMAGE */
2410 skip_if (irplib_dfs_save_image(self, parlist, self, beam1,
2411 CPL_BPP_IEEE_FLOAT, RECIPE_SAVE_STRING,
2412 VISIR_IMG_PHOT_ONEBEAM_PROCATG, qclist,
2413 NULL, visir_pipe_id,
2414 RECIPE_SAVE_STRING "_onebeam" CPL_DFS_FITS));
2415
2416 /* THE BEAM COLLAPSED CONTRIBUTION MAP */
2417 skip_if (cpl_image_save(beam1i, RECIPE_SAVE_STRING "_onebeam" CPL_DFS_FITS,
2418 CPL_BPP_8_UNSIGNED, xtlist, CPL_IO_EXTEND));
2419 }
2420
2421 end_skip;
2422
2423 cpl_propertylist_delete(xtlist);
2424
2425 return cpl_error_get_code();
2426
2427}
2428
2429/*----------------------------------------------------------------------------*/
2439/*----------------------------------------------------------------------------*/
2440static char * visir_img_phot_filter2label(const char * self)
2441{
2442
2443 char * label = NULL;
2444 char * p;
2445
2446 bug_if(self == NULL);
2447
2448 label = cpl_strdup(self);
2449
2450 for (p = label; *p != (char)0; p++) {
2451 if (*p == '.' || *p == '-') *p = '_';
2452 }
2453
2454 end_skip;
2455
2456 return label;
2457
2458}
cpl_error_code irplib_pfits_set_airmass(cpl_propertylist *self, const irplib_framelist *rawframes)
Update/Set the AIRMASS property.
Definition: irplib_pfits.c:338
cpl_error_code visir_dfs_check_framelist_tag(const irplib_framelist *self)
Check the tags in a frameset (group raw only)
Definition: visir_dfs.c:234
int visir_dfs_set_groups(cpl_frameset *set)
Set the group as RAW or CALIB in a frameset.
Definition: visir_dfs.c:72
cpl_image ** visir_img_collapse_beam(cpl_propertylist *qclist, const cpl_image *self, const cpl_parameterlist *parlist, const char *recipename, visir_chopnod_mode mode, const cpl_propertylist *plist)
Collapse the 3/4 beams of a combined image.
Definition: visir_inputs.c:626
cpl_image ** visir_img_recombine(const char *recipename, const cpl_parameterlist *parlist, const irplib_framelist *rawframes, const char *badpix, const char *flat, cpl_geom_combine combine_mode, cpl_boolean *pdid_resize, cpl_boolean do_spc_fix, double wlen, visir_spc_resol resol)
The VISIR imaging combination using cross correlation.
const char * visir_parameterlist_get_string(const cpl_parameterlist *self, const char *recipe, visir_parameter bitmask)
Retrieve the value of a VISIR string parameter.
double visir_parameterlist_get_double(const cpl_parameterlist *self, const char *recipe, visir_parameter bitmask)
Retrieve the value of a VISIR parameter of type double.
double visir_pfits_get_dit(const cpl_propertylist *self)
The DIT.
Definition: visir_pfits.c:325
double visir_pfits_get_ra(const cpl_propertylist *self)
The RA.
Definition: visir_pfits.c:742
double visir_pfits_get_img_weight(const cpl_propertylist *self)
The relative weight of the image compared to the other images.
Definition: visir_pfits.c:913
double visir_pfits_get_dec(const cpl_propertylist *self)
The DEC.
Definition: visir_pfits.c:313
double visir_pfits_get_pixscale(const cpl_propertylist *self)
The pixel scale.
Definition: visir_pfits.c:711
const char * visir_pfits_get_starname(const cpl_propertylist *self)
The std star name.
Definition: visir_pfits.c:808
const char * visir_pfits_get_insmode(const cpl_propertylist *self)
The mode.
Definition: visir_pfits.c:474
const char * visir_pfits_get_filter(const cpl_propertylist *self)
The filter.
Definition: visir_pfits.c:365
const char * visir_pfits_get_chopnod_dir(const cpl_propertylist *self)
The chopping direction.
Definition: visir_pfits.c:139