IIINSTRUMENT Pipeline Reference Manual 4.6.1
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 /* Assume the new detector unless we discover otherwise */
300 int is_aqu = TRUE;
301
302
303 visir_img_phot_config.exptime = -1.0;
304 visir_img_phot_config.pscale = -1.0;
305 visir_img_phot_config.star_name[0] = (char)0;
306 visir_img_phot_config.filter[0] = (char)0;
307 visir_img_phot_config.bg_sigma = -1.0;
308 visir_img_phot_config.flux_snr = -1.0;
309 visir_img_phot_config.flux_snr_noise = -1.0;
310 visir_img_phot_config.flux_snr_radius[0] = -1;
311 visir_img_phot_config.flux_snr_radius[1] = -1;
312 visir_img_phot_config.flux_snr_radius[2] = -1;
313 visir_img_phot_config.flux_snr_radius[3] = -1;
314 visir_img_phot_config.flux_tot = -1.0;
315 visir_img_phot_config.nelec = -1.0;
316 visir_img_phot_config.nphot = -1.0;
317 visir_img_phot_config.beamshape =
318 (beamshape_t){.fwhm_x = -1., .fwhm_y = -1.,
319 .peak = -1., .peak_err = 0.,
320 .major = -1., .major_err = 0.,
321 .minor = -1., .minor_err = 0.,
322 .angle = -1., .angle_err = 0.};
323 visir_img_phot_config.fwhm_x_pos1 = -1.0;
324 visir_img_phot_config.fwhm_y_pos1 = -1.0;
325 visir_img_phot_config.fwhm_x_pos2 = -1.0;
326 visir_img_phot_config.fwhm_y_pos2 = -1.0;
327 visir_img_phot_config.fwhm_x_neg1 = -1.0;
328 visir_img_phot_config.fwhm_y_neg1 = -1.0;
329 visir_img_phot_config.fwhm_x_neg2 = -1.0;
330 visir_img_phot_config.fwhm_y_neg2 = -1.0;
331 visir_img_phot_config.sensitivity = -1.0;
332 visir_img_phot_config.area_sensit = -1.0;
333 visir_img_phot_config.conversion = -1.0;
334 visir_img_phot_config.strehl = -1.0;
335 visir_img_phot_config.strehl_err = -1.0;
336
337 /* Retrieve input parameters */
338 combine_string = visir_parameterlist_get_string(parlist, RECIPE_STRING,
339 VISIR_PARAM_COMBINE);
340
341 bug_if (combine_string == NULL);
342
343 if (combine_string[0] == 'u')
344 combine_mode = CPL_GEOM_UNION;
345 else if (combine_string[0] == 'f')
346 combine_mode = CPL_GEOM_FIRST;
347 else if (combine_string[0] == 'i')
348 combine_mode = CPL_GEOM_INTERSECT;
349 else
350 skip_if(1);
351
352
353 visir_img_phot_config.jy_val =
354 visir_parameterlist_get_double(parlist, RECIPE_STRING, VISIR_PARAM_JYVAL);
355 skip_if (0);
356
357 /* Identify the RAW and CALIB frames in the input frameset */
358 skip_if (visir_dfs_set_groups(framelist));
359
360 /* Objects observation */
361 allframes = irplib_framelist_cast(framelist);
362 skip_if(allframes == NULL);
363 {
364 rawframes = irplib_framelist_extract(allframes, VISIR_IMG_PHOT_RAW);
365 if (rawframes == NULL) {
366 cpl_errorstate_set(cleanstate);
367 rawframes = irplib_framelist_extract(allframes,
368 VISIR_IMG_CAL_PHOT_PP);
369 skip_if (rawframes == NULL);
370 const char * fn =
371 irplib_frameset_find_file(framelist, VISIR_UTIL_QC_PROCATG);
372 if(fn == NULL) {
373 cpl_msg_error(cpl_func, "The input files has no header tagged "
374 "%s", VISIR_UTIL_QC_PROCATG);
375 visir_error_set(CPL_ERROR_DATA_NOT_FOUND);
376 skip_if(1);
377 }
378 ppqc = cpl_propertylist_load(fn, 0);
379 one_beam = CPL_TRUE;
380 }
381 }
382
383 skip_if (rawframes == NULL);
384
385 irplib_framelist_empty(allframes);
386
387 skip_if(irplib_framelist_load_propertylist(rawframes, 0, 0, keys_regexp,
388 CPL_FALSE));
389 qclist = cpl_propertylist_duplicate(irplib_framelist_get_propertylist(rawframes, 0));
390 if (ppqc)
391 skip_if(propagate_qc_header(qclist, ppqc));
392
393 skip_if(irplib_framelist_load_propertylist_all(rawframes, 0, "^("
394 RECIPE_KEYS_REGEXP_ALL
395 "|"VISIR_PFITS_REGEXP_DIT
396 ")$", CPL_FALSE));
397
398 skip_if(visir_dfs_check_framelist_tag(rawframes));
399
400 if (cpl_propertylist_has(irplib_framelist_get_propertylist(rawframes, 0),
401 VISIR_PFITS_DOUBLE_SEQ1_DIT))
402 dit_key = VISIR_PFITS_DOUBLE_SEQ1_DIT;
403 skip_if(0);
404
405 /* Check if this is the old detector */
406 if (ppqc && cpl_propertylist_has(ppqc, VISIR_PFITS_DOUBLE_PIXSPACE)) {
407 double pixspace = cpl_propertylist_get_double(ppqc, VISIR_PFITS_DOUBLE_PIXSPACE);
408 if (pixspace > 3e-5) {
409 is_aqu = FALSE;
410 }
411 }
412
413 /* Get the radii parameter */
414 sval = visir_parameterlist_get_string(parlist, RECIPE_STRING, VISIR_PARAM_RADII);
415 skip_if (sval == NULL);
416
417 if (!strcmp(sval, "default")) {
418 /* If it's the default value then set it depending on the detector */
419 if (is_aqu) {
420 /* Aquarius detector is larger */
421 visir_img_phot_config.r0_max = 40;
422 visir_img_phot_config.r1 = 40;
423 visir_img_phot_config.r2 = 50;
424 } else {
425 /* DRS detector is smaller */
426 visir_img_phot_config.r0_max = 20;
427 visir_img_phot_config.r1 = 20;
428 visir_img_phot_config.r2 = 30;
429 }
430 cpl_msg_warning(cpl_func, "Set --radii=%d-%d-%d",
431 visir_img_phot_config.r0_max,
432 visir_img_phot_config.r1,
433 visir_img_phot_config.r2);
434 } else {
435 /* Check if the supplied --radii parameter is valid or not */
436 if (sscanf(sval, "%d%*c%d%*c%d",
437 &visir_img_phot_config.r0_max,
438 &visir_img_phot_config.r1,
439 &visir_img_phot_config.r2) != 3) {
440 cpl_msg_error(cpl_func, "Could not parse --radii=%s", sval);
441 skip_if(1);
442 }
443 }
444
445 /* Standard star catalog */
446 star_cat = irplib_frameset_find_file(framelist, VISIR_CALIB_STDSTAR_IMG);
447 if (star_cat == NULL) {
448 cpl_msg_error(cpl_func, "The input files has no star catalog tagged "
449 "%s", VISIR_CALIB_STDSTAR_IMG);
450 visir_error_set(CPL_ERROR_DATA_NOT_FOUND);
451 skip_if(1);
452 }
453
454 /* Bad pixels calibration file */
455 badpix = irplib_frameset_find_file(framelist, VISIR_CALIB_BPM);
456
457 /* Flatfield calibration file */
458 flat = irplib_frameset_find_file(framelist, VISIR_CALIB_FLAT);
459
460
461 /* DIT must be present every where */
462 skip_if(irplib_framelist_contains(rawframes, dit_key,
463 CPL_TYPE_DOUBLE, CPL_FALSE, 0.0));
464 if(irplib_framelist_contains(rawframes, dit_key,
465 CPL_TYPE_DOUBLE, CPL_TRUE, 1e-5)) {
466 /* Allow 0.1 ms difference - or warn */
467 /* FIXME: The recipe does not properly handle non-uniform DITSs */
468 visir_error_reset("DIT differs by more than %g", 1e-5);
469 }
470
471 /* FIXME: Verify the angular distance */
472 skip_if(irplib_framelist_contains(rawframes, VISIR_PFITS_DOUBLE_RA,
473 CPL_TYPE_DOUBLE, CPL_FALSE, 0.0));
474
475 /* FIXME: Allow 1 degree difference */
476 skip_if(irplib_framelist_contains(rawframes, VISIR_PFITS_DOUBLE_DEC,
477 CPL_TYPE_DOUBLE, CPL_TRUE, 1.0));
478
479 skip_if(irplib_framelist_contains(rawframes, VISIR_PFITS_INT_CHOP_NCYCLES,
480 CPL_TYPE_INT, CPL_TRUE, 0.0));
481
482 skip_if(irplib_framelist_contains(rawframes, VISIR_PFITS_INT_NDIT,
483 CPL_TYPE_INT, CPL_TRUE, 0.0));
484
485 skip_if(irplib_framelist_contains(rawframes, VISIR_PFITS_STRING_STARNAME,
486 CPL_TYPE_STRING, CPL_TRUE, 0.0));
487
488 skip_if(irplib_framelist_contains(rawframes, VISIR_PFITS_STRING_INSMODE,
489 CPL_TYPE_STRING, CPL_TRUE, 0.0));
490
491 if (strncmp("IMG", visir_pfits_get_insmode(
492 irplib_framelist_get_propertylist_const(rawframes, 0)),
493 6) == 0) {
494 skip_if(irplib_framelist_contains(rawframes, VISIR_PFITS_STRING_FILTER1,
495 CPL_TYPE_STRING, CPL_TRUE, 0.0));
496 } else {
497 skip_if(irplib_framelist_contains(rawframes, VISIR_PFITS_STRING_FILTER2,
498 CPL_TYPE_STRING, CPL_TRUE, 0.0));
499 }
500
501 skip_if(irplib_framelist_contains(rawframes, VISIR_PFITS_STRING_PIXSCALE,
502 CPL_TYPE_STRING, CPL_TRUE, 0.0));
503
504
505 {
506 const char * prew =
507 irplib_frameset_find_file(framelist, "WEIGHT_MAP");
508 if (prew) {
509 cpl_msg_info(cpl_func, "Loading weight map %s", prew);
510 weights = cpl_image_load(prew, CPL_TYPE_UNSPECIFIED, 0, 0);
511 }
512 }
513
514 {
515 const char * prec =
516 irplib_frameset_find_file(framelist, "CONTRIBUTION_MAP");
517 if (prec) {
518 cpl_msg_info(cpl_func, "Loading contribution map %s", prec);
519 contrib = cpl_image_load(prec, CPL_TYPE_INT, 0, 0);
520 }
521 }
522
523 skip_if(0);
524 /* Combine the frames */
525 cpl_msg_info(cpl_func, "Combining the images");
526 {
527 const char * pre =
528 irplib_frameset_find_file(framelist, VISIR_IMG_CAL_PHOT_PP);
529 if (pre) {
530 combined = cpl_calloc(2, sizeof(combined[0]));
531 combined[0] = cpl_image_load(pre, CPL_TYPE_UNSPECIFIED, 0, 0);
532 combined[1] = contrib ? cpl_image_duplicate(contrib) : NULL;
533 if (combined[0] == NULL) {
534 cpl_msg_error(cpl_func, "Could not load the input frames");
535 skip_if(1);
536 }
537 if (weights) {
538 cpl_mask * m = cpl_mask_threshold_image_create(weights, -1,
539 FLT_EPSILON);
540 cpl_image_reject_from_mask(combined[0], m);
541 cpl_mask_delete(m);
542 }
543 }
544 else {
545 combined = visir_img_recombine(RECIPE_STRING, parlist, rawframes,
546 badpix, flat, combine_mode,
547 &drop_wcs, CPL_FALSE, 0.0, 0);
548 if (combined == NULL) {
549 cpl_msg_error(cpl_func, "Could not combine the input frames");
550 skip_if(1);
551 }
552 beam1 = visir_img_collapse_beam(qclist, combined[0], parlist, RECIPE_STRING,
553 VISIR_CHOPNOD_AUTO,
554 irplib_framelist_get_propertylist_const
555 (rawframes, 0));
556 if (beam1 == NULL)
557 irplib_error_recover(cleanstate, "Could not collapse the "
558 "beams of the combined image");
559
560 /* Compute the background values of the HCYCLE frames
561 * done by repack in preprocessed mode */
562 skip_if(visir_qc_append_background(qclist, rawframes, 0, 0));
563 }
564 }
565
566 /* Compute here the sensitivity */
567 cpl_msg_info(cpl_func, "Computing the sensitivity");
568 if (visir_img_phot_sensit(combined[0], weights, contrib, rawframes,
569 star_cat, one_beam, ppqc)) {
570 cpl_msg_error(cpl_func, "Could not compute sensitivity: '%s' in %s",
571 cpl_error_get_message(), cpl_error_get_where());
572 skip_if(1);
573 }
574
575 skip_if (visir_img_phot_qc(qclist, drop_wcs, rawframes));
576 irplib_framelist_empty(rawframes);
577
578 /* Save the combined image and contribution map */
579 if (beam1 == NULL) {
580 cpl_msg_info(cpl_func, "Saving the combined image with its contribution "
581 "map");
582 skip_if (visir_img_phot_save(framelist, parlist, qclist, combined[0],
583 combined[1], NULL, NULL, weights));
584 } else {
585 cpl_msg_info(cpl_func, "Saving the combined and the beam-combined "
586 "images with their contribution maps");
587 skip_if (visir_img_phot_save(framelist, parlist, qclist, combined[0],
588 combined[1], beam1[0], beam1[1], weights));
589 }
590
591 end_skip;
592
593 cpl_propertylist_delete(qclist);
594 irplib_framelist_delete(allframes);
595 irplib_framelist_delete(rawframes);
596 cpl_propertylist_delete(ppqc);
597 cpl_image_delete(weights);
598 cpl_image_delete(contrib);
599
600 if (combined) {
601 cpl_image_delete(combined[0]);
602 cpl_image_delete(combined[1]);
603 cpl_free(combined);
604 }
605
606 if (beam1) {
607 cpl_image_delete(beam1[0]);
608 cpl_image_delete(beam1[1]);
609 cpl_free(beam1);
610 }
611
612 return cpl_error_get_code();
613
614}
615
616/*----------------------------------------------------------------------------*/
641/*----------------------------------------------------------------------------*/
642static int visir_img_phot_sensit(const cpl_image * combined,
643 const cpl_image * weights,
644 const cpl_image * contrib,
645 const irplib_framelist * rawframes,
646 const char * star_cat,
647 cpl_boolean one_beam,
648 cpl_propertylist * ppqc)
649{
650 cpl_errorstate cleanstate = cpl_errorstate_get();
651 const cpl_propertylist * plist = NULL;
652 double ra, dec;
653 const char * sval;
654 double f2;
655
656
657 skip_if (0);
658
659 plist = irplib_framelist_get_propertylist_const(rawframes, 0);
660 skip_if (0);
661
662 /* Get the total exposure time */
663 {
664 double exptime;
665
666 if (ppqc) /* FIXME: use effective exptime? */
667 exptime = cpl_propertylist_get_double(ppqc, "ESO QC EXPTIME TOTAL");
668 else {
669 const int nnod = irplib_framelist_get_size(rawframes);
670 exptime = visir_utils_get_exptime(nnod, plist);
671 }
672 visir_img_phot_config.exptime = exptime;
673
674 if (exptime <= 0 || cpl_error_get_code()) {
675 cpl_msg_error(cpl_func, "Illegal exposure time: %g", exptime);
676 skip_if(1);
677 }
678 }
679
680 /* Copy the standard star name */
681 skip_if ((sval = visir_pfits_get_starname(plist)) == NULL);
682 (void) strncpy(visir_img_phot_config.star_name, sval, fits_strlen);
683
684 /* Copy the filter name */
685 skip_if ((sval = visir_pfits_get_filter(plist)) == NULL);
686 (void)strncpy(visir_img_phot_config.filter, sval, fits_strlen);
687
688 /* Get RA / DEC */
689 ra = visir_pfits_get_ra(plist);
690 skip_if (0);
691 dec = visir_pfits_get_dec(plist);
692 skip_if (0);
693
694 /* Get the pixel scale */
695 visir_img_phot_config.pscale = visir_pfits_get_pixscale(plist);
696
697 /* Get the JY value from the catalog if not user provided */
698 if (visir_img_phot_config.jy_val < -998) {
699 visir_img_phot_config.jy_val =
700 visir_img_phot_jy_from_cat(star_cat, visir_img_phot_config.filter,
701 ra,dec, visir_img_phot_config.star_name);
702 skip_if (visir_img_phot_config.jy_val < -998);
703 }
704
705 /* Display the result */
706 cpl_msg_info(cpl_func, "Star %s with filter %s : %g Jy",
707 visir_img_phot_config.star_name,
708 visir_img_phot_config.filter,
709 visir_img_phot_config.jy_val);
710
711 /* Compute the background signa */
712 visir_img_phot_config.bg_sigma = visir_img_phot_sigma_clip(combined);
713 skip_if (0);
714
715 /* Get the flux and flux noise and fwhm */
716 cpl_msg_info(cpl_func, "Compute the star flux");
717 sval = visir_pfits_get_chopnod_dir(plist);
718#if 1
719 if (one_beam) {
720 skip_if (visir_img_phot_flux_one(combined, weights, contrib, plist));
721 }
722 else if (sval != NULL && !strcmp(sval, "PERPENDICULAR")) {
723 /* 4 sources */
724 skip_if (visir_img_phot_flux_four(combined));
725 } else if (sval != NULL && !strcmp(sval, "PARALLEL")) {
726 /* 3 sources */
727 skip_if (visir_img_phot_flux_three(combined));
728 } else {
729 if (sval == NULL) {
730 visir_error_reset("Could not get FITS key");
731 } else {
732 cpl_msg_warning(cpl_func, "Unknown chopping direction: %s", sval);
733 }
734 cpl_msg_warning(cpl_func, "Proceeding as if FITS card %s had value %s",
735 "ESO SEQ CHOPNOD DIR", "PERPENDICULAR");
736 if (visir_img_phot_flux_four(combined)) {
737 visir_error_reset("Proceeding as if FITS card %s had value %s",
738 "ESO SEQ CHOPNOD DIR", "PARALLEL");
739 skip_if (visir_img_phot_flux_three(combined));
740 }
741 }
742#else
743 if (sval == NULL) {
744 visir_error_reset("Could not get chopping direction");
745 if (visir_img_phot_flux_three(combined)) {
746 cpl_msg_error(cpl_func, "Could not compute the flux");
747 skip_if(1);
748 }
749 } else if (!strcmp(sval, "PARALLEL")) {
750 /* 3 sources */
751 if (visir_img_phot_flux_three(combined)) {
752 cpl_msg_error(cpl_func, "Could not compute the flux");
753 skip_if(1);
754 }
755 } else {
756 /* Default is 4 sources */
757 if (strcmp(sval, "PERPENDICULAR"))
758 cpl_msg_warning(cpl_func, "Unknown chopping direction: %s", sval);
759 if (visir_img_phot_flux_four(combined)) {
760 cpl_msg_error(cpl_func, "Could not compute the flux");
761 skip_if(1);
762 }
763 }
764#endif
765
766
767 /* compute number of photons and electrons for the efficiency */
768 {
769 double fluxSI = visir_img_phot_config.jy_val * 1e-26;
770 double dit = visir_pfits_get_dit(plist);;
771 /* area of telescope [m^2] */
772 double area = (8.2/2.) * (8.2/2.) * CPL_MATH_PI;
773 const char * filter = visir_pfits_get_filter(plist);
774 double wl;
775 /* filter bandwidth delta lambda [m] */
776 double bandwidth;
777 double gain = 20.;
778
779 if (ppqc && cpl_propertylist_has(ppqc, "ESO DET CHIP1 GAIN"))
780 gain = cpl_propertylist_get_double(ppqc, "ESO DET CHIP1 GAIN");
781 else if (ppqc && cpl_propertylist_has(ppqc, "ESO DET CHIP GAIN"))
782 gain = cpl_propertylist_get_double(ppqc, "ESO DET CHIP GAIN");
783 else
784 cpl_msg_warning(cpl_func, "ESO DET CHIP1 GAIN not found, "
785 "assuming %g", gain);
786
787 if (filter && !visir_get_filter_infos(filter, &wl, &bandwidth)) {
788 /* filter bandwidth deltanue [Hz] */
789 double bwh, ptot, ephot;
790 wl *= 1e-6; /* [micron] -> [m] */
791 bandwidth *= 1e-6; /* [micron] -> [m] */
792
793 bwh = CPL_PHYS_C / (wl * wl) * bandwidth;
794 /* total power [W] */
795 ptot = fluxSI * area * bwh;
796 /* photon energy [Ws] */
797 ephot = CPL_PHYS_H * CPL_PHYS_C / wl;
798
799 visir_img_phot_config.nelec = visir_img_phot_config.flux_tot * gain;
800 visir_img_phot_config.nphot = ptot / ephot * dit;
801 }
802 else
803 cpl_msg_warning(cpl_func, "Unknown filter: %s", filter);
804 }
805
806 /* Compute the sensitivity and the conversion factor */
807
808 skip_if ( visir_img_phot_config.flux_snr == 0 );
809 skip_if ( visir_img_phot_config.flux_snr_noise == 0 );
810 skip_if ( visir_img_phot_config.jy_val == 0 );
811
812 f2 = visir_img_phot_config.flux_snr / visir_img_phot_config.flux_snr_noise;
813 f2 *= sqrt(3600/visir_img_phot_config.exptime);
814 visir_img_phot_config.sensitivity = visir_img_phot_config.jy_val*1000*10/f2;
815 /* compute conversion, accounting for double signal in parallel mode */
816 visir_img_phot_config.conversion = visir_img_phot_config.flux_tot /
817 visir_img_phot_config.jy_val /
818 (ppqc ? visir_pfits_get_img_weight(ppqc) : 1.);
819
820 /* sensitivity using the noise under 1as circle */
821 visir_img_phot_config.area_sensit =
822 visir_img_phot_config.sensitivity *
823 sqrt((1. / SQR(visir_img_phot_config.pscale)) /
824 SQR(visir_img_phot_config.flux_snr_radius[0]));
825
826 end_skip;
827
828 cpl_msg_info(cpl_func, "Sensitivity : %g", visir_img_phot_config.sensitivity);
829 cpl_msg_info(cpl_func, "Conversion : %g", visir_img_phot_config.conversion);
830 cpl_msg_info(cpl_func, "Strehl : %g", visir_img_phot_config.strehl);
831 cpl_msg_info(cpl_func, "Strehl error: %g", visir_img_phot_config.strehl_err);
832 cpl_msg_info(cpl_func, "Exposure : %g s", visir_img_phot_config.exptime);
833
834 return cpl_error_get_code();
835}
836
837/*----------------------------------------------------------------------------*/
847/*----------------------------------------------------------------------------*/
848static double visir_img_phot_jy_from_cat(
849 const char * star_cat,
850 const char * filter,
851 double ra,
852 double dec,
853 const char * star_name)
854{
855 cpl_table * tab = NULL;
856 cpl_vector * v_ra = NULL;
857 cpl_vector * v_dec = NULL;
858 const char * stdstar;
859 char * label = NULL;
860 int nb_stars;
861 const double max_radius = VISIR_STAR_MAX_RADIUS;
862 double value = -999;
863 double jy;
864 double dist;
865 int min_dist_ind;
866
867
868 skip_if( 0 );
869 skip_if( star_cat == NULL );
870 skip_if( star_name == NULL );
871 skip_if( filter == NULL );
872
873 label = visir_img_phot_filter2label(filter);
874 skip_if(label == NULL);
875
876 /* Open the star catalog */
877 if ((tab = cpl_table_load(star_cat, 1, 1)) == NULL) {
878 cpl_error_set_message(cpl_func, cpl_error_get_code(),
879 "Could not load the star catalog: %s",
880 star_cat);
881 skip_if(1);
882 }
883
884 /* Check that the filter is in the table */
885 if (!cpl_table_has_column(tab, label)) {
886 cpl_error_set_message(cpl_func, CPL_ERROR_DATA_NOT_FOUND,
887 "Catalog %s has no column for filter: %s",
888 star_cat, filter);
889 skip_if(1);
890 }
891
892 if (!cpl_table_has_column(tab, "STARS")) {
893 cpl_error_set_message(cpl_func, CPL_ERROR_BAD_FILE_FORMAT,
894 "Catalog %s does not have a column labeled %s",
895 star_cat, "STARS");
896 skip_if(1);
897 }
898
899 nb_stars = cpl_table_get_nrow(tab);
900 skip_if (nb_stars < 1);
901
902 /* Get the RA and DEC columns */
903 v_ra = cpl_vector_wrap(nb_stars, cpl_table_get_data_double(tab, "RA"));
904 skip_if( v_ra == NULL);
905
906 v_dec = cpl_vector_wrap(nb_stars, cpl_table_get_data_double(tab, "DEC"));
907 skip_if( v_dec == NULL);
908
909 min_dist_ind = visir_star_find(v_ra, v_dec, ra, dec, max_radius, &dist);
910
911 if (min_dist_ind < 0) {
912 cpl_error_set_message(cpl_func, cpl_error_get_code(),
913 "Observation target '%s' was not found among "
914 "the %d entries in the standard star catalog %s",
915 star_name, nb_stars, star_cat);
916 skip_if(1);
917 }
918
919 stdstar = cpl_table_get_string(tab, "STARS", min_dist_ind);
920 skip_if ( stdstar == NULL );
921
922 int null;
923 jy = cpl_table_get(tab, label, min_dist_ind, &null);
924 skip_if( 0 );
925
926 if (null || isnan(jy)) {
927 cpl_error_set_message(cpl_func, CPL_ERROR_DATA_NOT_FOUND,
928 "Catalog does not contain a value for %s in "
929 "filter %s", star_name, filter);
930 skip_if(1);
931 }
932
933 value = jy;
934
935 if (strcmp(stdstar, star_name) != 0 && dist > 0.0) {
936 /* The names do not match, nor does the location (exactly) */
937 cpl_msg_warning(cpl_func, "The standard star '%s' at (RA,DEC)=(%g,%g) "
938 "in the FITS header is closest to the catalog star "
939 "'%s' at (RA,DEC)=(%g,%g) at distance %g degrees",
940 star_name, ra, dec, stdstar,
941 cpl_vector_get(v_ra, min_dist_ind),
942 cpl_vector_get(v_dec, min_dist_ind), dist);
943 } else if (dist > 0.0) {
944 /* The names match, but the location does not (exactly) */
945 cpl_msg_warning(cpl_func, "The location of the standard star '%s' in "
946 "the FITS header (RA,DEC)=(%g,%g) and the catalog "
947 "(RA,DEC)=(%g,%g) differ by %g degrees", stdstar, ra,
948 dec, cpl_vector_get(v_ra, min_dist_ind),
949 cpl_vector_get(v_dec, min_dist_ind), dist);
950 } else if (strcmp(stdstar, star_name) != 0) {
951 /* The names do not match, but the location does */
952 cpl_msg_warning(cpl_func, "The name of the standard star at (RA,DEC)="
953 "(%g,%g) in the FITS header '%s' and the catalog '%s' "
954 "are different", ra, dec, star_name, stdstar);
955 } else {
956 cpl_msg_info(cpl_func, "Standard star is '%s' at (RA, DEC)=(%g,%g)",
957 stdstar, ra, dec);
958
959 if (cpl_msg_get_level() <= CPL_MSG_DEBUG)
960 cpl_table_dump(tab, min_dist_ind, 1, stdout);
961 }
962
963 cpl_msg_info(cpl_func, "The standard star '%s' has %g Jy through filter %s",
964 stdstar, value, filter);
965
966 end_skip;
967
968 cpl_free(label);
969 cpl_table_delete(tab);
970 cpl_vector_unwrap(v_ra);
971 cpl_vector_unwrap(v_dec);
972
973 return value;
974}
975
976/*----------------------------------------------------------------------------*/
985/*----------------------------------------------------------------------------*/
986static int visir_img_phot_flux_three(const cpl_image * combined)
987{
988 cpl_errorstate cleanstate = cpl_errorstate_get();
989 cpl_image * min_combined = NULL;
990 cpl_apertures * appos = NULL;
991 cpl_apertures * apneg = NULL;
992 cpl_vector * sigmas = NULL;
993 double psigmas[] = {5, 2, 1, 0.5};
994 double x[3];
995 double y[3];
996 double flux_snr[3];
997 double flux_snr_noise[3];
998 int flux_snr_radius[3];
999 double flux_tot[3];
1000 beamshape_t beamshapes[3];
1001 double dist1, dist2;
1002 int ngood_fwhm;
1003 double lam, dlam;
1004 double star_bg,star_peak,star_flux,psf_peak,psf_flux,bg_noise;
1005 double eccmin = DBL_MAX;
1006 const int nsigmas = sizeof(psigmas)/sizeof(double);
1007 int isigma;
1008#ifdef VISIR_IMG_PHOT_USE_ECCENT_THREE
1009 int ipos, ineg1, ineg2;
1010#endif
1011 int iappos, iapneg2[2];
1012 int i;
1013
1014
1015 if (cpl_error_get_code()) return cpl_error_get_code();
1016
1017 cpl_ensure_code(combined != NULL, CPL_ERROR_NULL_INPUT);
1018
1019 cpl_msg_info(cpl_func, "Detecting the 3-source star using %d sigma-levels "
1020 "ranging from %g down to %g", nsigmas, psigmas[0],
1021 psigmas[nsigmas-1]);
1022
1023 sigmas = cpl_vector_new(1);
1024 min_combined = cpl_image_multiply_scalar_create(combined, -1.0);
1025 bug_if(0);
1026 for (isigma = 0; isigma < nsigmas; isigma++) {
1027
1028 /* FIXME: Why ?! */
1029 irplib_error_recover(cleanstate, "Resetting error (why?)");
1030
1031 bug_if(cpl_vector_set(sigmas, 0, psigmas[isigma]));
1032
1033 /* Detect where the POSITIVE star is */
1034 cpl_apertures_delete(appos);
1035 appos = cpl_apertures_extract(combined, sigmas, NULL);
1036 if (appos == NULL) {
1037 cpl_msg_warning(cpl_func, "Found no positive star at sigma=%g",
1038 psigmas[isigma]);
1039 continue;
1040 }
1041
1042 /* Detect where the NEGATIVE stars are */
1043 cpl_apertures_delete(apneg);
1044 apneg = cpl_apertures_extract(min_combined, sigmas, NULL);
1045 if (apneg == NULL) {
1046 cpl_msg_warning(cpl_func, "Found no negative stars at sigma=%g",
1047 psigmas[isigma]);
1048 continue;
1049 }
1050 if (cpl_apertures_get_size(apneg) < 2) {
1051 cpl_msg_warning(cpl_func, "Found just 1 negative star at sigma=%g, "
1052 "need two", psigmas[isigma]);
1053 continue;
1054 }
1055
1056 cpl_msg_info(cpl_func, "Found positive and negative stars at sigma=%g",
1057 psigmas[isigma]);
1058 break;
1059 }
1060
1061 skip_if(appos == NULL);
1062 skip_if(apneg == NULL);
1063 skip_if (cpl_apertures_get_size(apneg) < 2);
1064
1065 if (cpl_msg_get_level() == CPL_MSG_DEBUG) {
1066 cpl_apertures_dump(appos, stdout);
1067 cpl_apertures_dump(apneg, stdout);
1068 }
1069
1070#ifndef VISIR_IMG_PHOT_USE_ECCENT_THREE
1071 bug_if(irplib_apertures_find_max_flux(appos, &iappos, 1));
1072 bug_if(irplib_apertures_find_max_flux(apneg, iapneg2, 2));
1073#else
1074 if (cpl_apertures_get_size(appos) > 1 || cpl_apertures_get_size(apneg) > 2)
1075 cpl_msg_info(cpl_func, "Selecting from %d positive and %d negative "
1076 "stars 3 stars on a vertical line",
1077 cpl_apertures_get_size(appos),
1078 cpl_apertures_get_size(apneg));
1079
1080 for (ipos = 1; ipos <= cpl_apertures_get_size(appos); ipos++) {
1081 for (ineg1 = 2; ineg1 <= cpl_apertures_get_size(apneg); ineg1++) {
1082 for (ineg2 = 1; ineg2 < ineg1; ineg2++) {
1083 const double ecc = visir_img_phot_eccent_three(appos, ipos,
1084 apneg,
1085 ineg1, ineg2);
1086 if (ecc < eccmin) {
1087 if (eccmin < DBL_MAX)
1088 cpl_msg_debug(cpl_func, "Found star positions with "
1089 "reduced mis-alignment [pixel]: "
1090 "%g < %g", ecc, eccmin);
1091 eccmin = ecc;
1092 iappos = ipos;
1093 iapneg2[0] = ineg1;
1094 iapneg2[1] = ineg2;
1095 }
1096 }
1097 }
1098 }
1099
1100 /* Star 1 should have largest flux */
1101 if (cpl_apertures_get_flux(apneg, iapneg2[0]) <
1102 cpl_apertures_get_flux(apneg, iapneg2[1])) {
1103 const int tmp = iapneg2[0];
1104 iapneg2[0] = iapneg2[1];
1105 iapneg2[1] = tmp;
1106 }
1107
1108#endif
1109
1110 x[0] = cpl_apertures_get_centroid_x(appos, iappos);
1111 y[0] = cpl_apertures_get_centroid_y(appos, iappos);
1112
1113 x[1] = cpl_apertures_get_centroid_x(apneg, iapneg2[0]);
1114 y[1] = cpl_apertures_get_centroid_y(apneg, iapneg2[0]);
1115 x[2] = cpl_apertures_get_centroid_x(apneg, iapneg2[1]);
1116 y[2] = cpl_apertures_get_centroid_y(apneg, iapneg2[1]);
1117
1118 cpl_apertures_delete(appos);
1119 cpl_apertures_delete(apneg);
1120 appos = NULL;
1121 apneg = NULL;
1122
1123 cpl_msg_info(cpl_func, "Positive star at position %g %g", x[0], y[0]);
1124 cpl_msg_info(cpl_func, "Negative star 1 at position %g %g", x[1], y[1]);
1125 cpl_msg_info(cpl_func, "Negative star 2 at position %g %g", x[2], y[2]);
1126
1127 dist1 = sqrt((x[1]-x[0])*(x[1]-x[0])+(y[1]-y[0])*(y[1]-y[0]));
1128 dist2 = sqrt((x[2]-x[0])*(x[2]-x[0])+(y[2]-y[0])*(y[2]-y[0]));
1129 cpl_msg_info(cpl_func, "Star 1 Pos/Neg Distance: %g", dist1);
1130 cpl_msg_info(cpl_func, "Star 2 Pos/Neg Distance: %g", dist2);
1131
1132
1133 if (eccmin < DBL_MAX) {
1134 cpl_msg_info(cpl_func, "The deviation from a vertical line by "
1135 "the three stars [pixel]: %g", eccmin);
1136 if (eccmin > VISIR_IMG_PHOT_POS_WARN) {
1137 if (eccmin > VISIR_IMG_PHOT_POS_ERROR) {
1138 cpl_msg_error(cpl_func, "The deviation from a vertical line"
1139 " by the three stars exceed %g, the detected "
1140 "objects are wrong", VISIR_IMG_PHOT_POS_ERROR);
1141 skip_if(1);
1142 }
1143 cpl_msg_warning(cpl_func, "The deviation from a vertical line "
1144 "by the three stars exceed %g, the detected "
1145 "objects may be wrong", VISIR_IMG_PHOT_POS_WARN);
1146 }
1147 }
1148
1149 /* FIXME: Pick other object instead, and lower sigma if needed */
1150 if ((int)x[0]-IRPLIB_STREHL_BORDER <= 0 ||
1151 (int)y[0]-IRPLIB_STREHL_BORDER <= 0 ||
1152 (int)x[0]+IRPLIB_STREHL_BORDER > cpl_image_get_size_x(combined) ||
1153 (int)y[0]+IRPLIB_STREHL_BORDER > cpl_image_get_size_y(combined)) {
1154 cpl_msg_error(cpl_func, "Positive star at (%g,%g) is less than %d "
1155 "pixels from the image border", x[0], y[0],
1156 1+IRPLIB_STREHL_BORDER);
1157 skip_if(1);
1158 }
1159
1160 /* FIXME: Useful ? */
1161 /* Verify the stars positions */
1162 if (fabs(dist1-dist2) > VISIR_IMG_PHOT_POS_UNCERTAINTY) {
1163 cpl_msg_error(cpl_func, "Too large Pos/Neg Distance between the two "
1164 "stars: %g > %g", fabs(dist1-dist2),
1165 VISIR_IMG_PHOT_POS_UNCERTAINTY);
1166 skip_if(1);
1167 }
1168
1169 /* Photometry on positive stars */
1170 skip_if (visir_img_phot_flux(combined, NULL, NULL,
1171 x[0], y[0],
1172 visir_img_phot_config.r0_max,
1173 visir_img_phot_config.r1,
1174 visir_img_phot_config.r2,
1175 &(flux_snr[0]),
1176 &(flux_snr_noise[0]),
1177 &(flux_snr_radius[0]),
1178 &(flux_tot[0]),
1179 &(beamshapes[0])));
1180
1181 /* Photometry on negative stars */
1182 for (i=1 ; i<3 ; i++)
1183 skip_if (visir_img_phot_flux(min_combined, NULL, NULL,
1184 x[i], y[i],
1185 visir_img_phot_config.r0_max,
1186 visir_img_phot_config.r1,
1187 visir_img_phot_config.r2,
1188 &(flux_snr[i]),
1189 &(flux_snr_noise[i]),
1190 &(flux_snr_radius[i]),
1191 &(flux_tot[i]),
1192 &(beamshapes[i])));
1193
1194 cpl_image_delete(min_combined);
1195 min_combined = NULL;
1196
1197 /* Compute the results */
1198 /* Flux */
1199 visir_img_phot_config.flux_snr = 0.0;
1200 for (i=0 ; i<3 ; i++) visir_img_phot_config.flux_snr += flux_snr[i];
1201
1202 /* Flux noise */
1203 visir_img_phot_config.flux_snr_noise = 0.0;
1204 for (i=0 ; i<3 ; i++) visir_img_phot_config.flux_snr_noise +=
1205 flux_snr_noise[i]*flux_snr_noise[i];
1206 visir_img_phot_config.flux_snr_noise =
1207 sqrt(visir_img_phot_config.flux_snr_noise);
1208
1209 for (i=0 ; i<3 ; i++)
1210 visir_img_phot_config.flux_snr_radius[i] = flux_snr_radius[i];
1211
1212 /* Total flux */
1213 visir_img_phot_config.flux_tot = 0.0;
1214 for (i=0 ; i<3 ; i++) visir_img_phot_config.flux_tot += flux_tot[i];
1215
1216 /* FWHM */
1217 ngood_fwhm = 0;
1218 visir_img_phot_config.beamshape.fwhm_x = 0.0;
1219 for (i=0 ; i<3 ; i++) {
1220 if (beamshapes[i].fwhm_x > 0.0) {
1221 visir_img_phot_config.beamshape.fwhm_x += beamshapes[i].fwhm_x;
1222 ngood_fwhm ++;
1223 }
1224 }
1225 if (ngood_fwhm > 0) visir_img_phot_config.beamshape.fwhm_x /= ngood_fwhm;
1226 else visir_img_phot_config.beamshape.fwhm_x = -1.0;
1227 ngood_fwhm = 0;
1228 visir_img_phot_config.beamshape.fwhm_y = 0.0;
1229 for (i=0 ; i<3 ; i++) {
1230 if (beamshapes[i].fwhm_y > 0.0) {
1231 visir_img_phot_config.beamshape.fwhm_y += beamshapes[i].fwhm_y;
1232 ngood_fwhm ++;
1233 }
1234 }
1235 if (ngood_fwhm > 0) visir_img_phot_config.beamshape.fwhm_y /= ngood_fwhm;
1236 else visir_img_phot_config.beamshape.fwhm_y = -1.0;
1237 visir_img_phot_config.fwhm_x_pos1 = beamshapes[0].fwhm_x;
1238 visir_img_phot_config.fwhm_y_pos1 = beamshapes[0].fwhm_y;
1239 visir_img_phot_config.fwhm_x_neg1 = beamshapes[1].fwhm_x;
1240 visir_img_phot_config.fwhm_y_neg1 = beamshapes[1].fwhm_y;
1241 visir_img_phot_config.fwhm_x_neg2 = beamshapes[2].fwhm_x;
1242 visir_img_phot_config.fwhm_y_neg2 = beamshapes[2].fwhm_y;
1243
1244 /* Get lam and dlam from the filter name for the Strehl computation */
1245 if (visir_get_filter_infos(visir_img_phot_config.filter, &lam, &dlam)) {
1246 cpl_msg_error(cpl_func, "Could not get info for filter: %s",
1247 visir_img_phot_config.filter);
1248 skip_if(1);
1249 }
1250
1251 /* Strehl computation */
1252 cpl_errorstate errstate = cpl_errorstate_get();
1253 if (irplib_strehl_compute(combined, STREHL_M1, STREHL_M2, lam, dlam,
1254 visir_img_phot_config.pscale,
1255 STREHL_BOX_SIZE, x[0], y[0], STREHL_STAR_RADIUS,
1256 STREHL_BG_R1, STREHL_BG_R2, -1, -1,
1257 &(visir_img_phot_config.strehl),
1258 &(visir_img_phot_config.strehl_err),
1259 &star_bg, &star_peak, &star_flux, &psf_peak, &psf_flux,
1260 &bg_noise)) {
1261 cpl_msg_error(cpl_func, "Could not compute the strehl: '%s' in %s",
1262 cpl_error_get_message(), cpl_error_get_where());
1263 cpl_errorstate_set(errstate);
1264 }
1265
1266
1267 end_skip;
1268
1269 cpl_apertures_delete(appos);
1270 cpl_apertures_delete(apneg);
1271 cpl_vector_delete(sigmas);
1272 cpl_image_delete(min_combined);
1273
1274 return cpl_error_get_code();
1275}
1276
1277static int visir_img_phot_flux_one(const cpl_image * combined,
1278 const cpl_image * weights,
1279 const cpl_image * contrib,
1280 const cpl_propertylist * plist)
1281{
1282 double x;
1283 double y;
1284 double flux_snr;
1285 double flux_snr_noise;
1286 int flux_snr_radius;
1287 double flux_tot;
1288 beamshape_t beamshape;
1289 double lam, dlam;
1290 double star_bg,star_peak,star_flux,psf_peak,psf_flux,bg_noise;
1291
1292 if (cpl_error_get_code()) return cpl_error_get_code();
1293
1294 cpl_ensure_code(combined != NULL, CPL_ERROR_NULL_INPUT);
1295
1296 x = cpl_propertylist_get_double(plist, "CRPIX1");
1297 y = cpl_propertylist_get_double(plist, "CRPIX2");
1298 {
1299 /* CRPIX can be a few pixels off center due to slicing of
1300 * the images around the beam done in detect_shift
1301 * only the int cast is used later, so pixel precision of
1302 * maxpos is ok */
1303 cpl_size yp, xp;
1304 cpl_image_get_maxpos_window(combined,
1305 CX_MAX(1, x - 5), CX_MAX(1, y - 5),
1306 CX_MIN(cpl_image_get_size_x(combined), x + 5),
1307 CX_MIN(cpl_image_get_size_y(combined), y + 5), &xp, &yp);
1308 x = xp;
1309 y = yp;
1310 }
1311
1312 cpl_msg_info(cpl_func, "Positive star 1 at position %g %g", x, y);
1313
1314 if ((int)x-IRPLIB_STREHL_BORDER <= 0 ||
1315 (int)y-IRPLIB_STREHL_BORDER <= 0) {
1316 cpl_msg_error(cpl_func, "Positive star 1 at (%g,%g) is less than %d "
1317 "pixels from the image border", x, y,
1318 1+IRPLIB_STREHL_BORDER);
1319 skip_if(1);
1320 }
1321
1322 /* Photometry on positive stars */
1323 skip_if (visir_img_phot_flux(combined, weights, contrib,
1324 x, y,
1325 visir_img_phot_config.r0_max,
1326 visir_img_phot_config.r1,
1327 visir_img_phot_config.r2,
1328 &(flux_snr),
1329 &(flux_snr_noise),
1330 &(flux_snr_radius),
1331 &(flux_tot),
1332 &(beamshape)));
1333
1334
1335 /* Compute the results */
1336 /* Flux */
1337 visir_img_phot_config.flux_snr = flux_snr;
1338
1339 /* Flux noise */
1340 visir_img_phot_config.flux_snr_noise = flux_snr_noise;
1341
1342 visir_img_phot_config.flux_snr_radius[0] = flux_snr_radius;
1343
1344 /* Total flux */
1345 visir_img_phot_config.flux_tot = flux_tot;
1346
1347 /* FWHM */
1348 visir_img_phot_config.beamshape = beamshape;
1349 visir_img_phot_config.fwhm_x_pos1 = beamshape.fwhm_x;
1350 visir_img_phot_config.fwhm_y_pos1 = beamshape.fwhm_y;
1351
1352 /* Get lam and dlam from the filter name for the Strehl computation */
1353 if (visir_get_filter_infos(visir_img_phot_config.filter, &lam, &dlam)) {
1354 cpl_msg_error(cpl_func, "Central wavelength and width is missing for "
1355 "filter: %s", visir_img_phot_config.filter);
1356 skip_if(1);
1357 }
1358
1359 /* Strehl computation */
1360 cpl_errorstate errstate = cpl_errorstate_get();
1361 if (irplib_strehl_compute(combined, STREHL_M1, STREHL_M2, lam, dlam,
1362 visir_img_phot_config.pscale,
1363 STREHL_BOX_SIZE, x, y, STREHL_STAR_RADIUS,
1364 STREHL_BG_R1, STREHL_BG_R2, -1, -1,
1365 &(visir_img_phot_config.strehl),
1366 &(visir_img_phot_config.strehl_err),
1367 &star_bg, &star_peak, &star_flux, &psf_peak, &psf_flux,
1368 &bg_noise)) {
1369 cpl_msg_error(cpl_func, "Could not compute the strehl: '%s' in %s",
1370 cpl_error_get_message(), cpl_error_get_where());
1371 cpl_errorstate_set(errstate);
1372 }
1373
1374
1375 end_skip;
1376
1377 return cpl_error_get_code();
1378
1379}
1380
1381/*----------------------------------------------------------------------------*/
1390/*----------------------------------------------------------------------------*/
1391static int visir_img_phot_flux_four(const cpl_image * combined)
1392{
1393 cpl_errorstate cleanstate = cpl_errorstate_get();
1394 cpl_image * min_combined = NULL;
1395 cpl_apertures * appos = NULL;
1396 cpl_apertures * apneg = NULL;
1397 cpl_vector * sigmas = NULL;
1398 double psigmas[] = {5, 2, 1, 0.5};
1399 double x[4];
1400 double y[4];
1401 double flux_snr[4];
1402 double flux_snr_noise[4];
1403 int flux_snr_radius[4];
1404 double flux_tot[4];
1405 beamshape_t beamshapes[4];
1406 double dist1, dist2;
1407 int ngood_fwhm;
1408 double lam, dlam;
1409 double star_bg,star_peak,star_flux,psf_peak,psf_flux,bg_noise;
1410 double eccmin = DBL_MAX;
1411 const int nsigmas = sizeof(psigmas)/sizeof(double);
1412 int isigma;
1413 int ipos1, ipos2, ineg1, ineg2;
1414 int i;
1415 int iappos2[] = {0, 0}; /* Avoid (false) uninit warning */
1416 int iapneg2[] = {0, 0}; /* Avoid (false) uninit warning */
1417
1418
1419 if (cpl_error_get_code()) return cpl_error_get_code();
1420
1421 cpl_ensure_code(combined != NULL, CPL_ERROR_NULL_INPUT);
1422
1423 cpl_msg_info(cpl_func, "Detecting the 4-source star using %d sigma-levels "
1424 "ranging from %g down to %g", nsigmas, psigmas[0],
1425 psigmas[nsigmas-1]);
1426
1427 sigmas = cpl_vector_new(1);
1428 min_combined = cpl_image_multiply_scalar_create(combined, -1.0);
1429 bug_if(0);
1430 for (isigma = 0; isigma < nsigmas; isigma++) {
1431
1432 /* FIXME: Why ?! */
1433 irplib_error_recover(cleanstate, "Resetting error (why?)");
1434
1435 bug_if(cpl_vector_set(sigmas, 0, psigmas[isigma]));
1436
1437 /* Detect where the POSITIVE stars are */
1438 cpl_apertures_delete(appos);
1439 appos = cpl_apertures_extract(combined, sigmas, NULL);
1440 if (appos == NULL) {
1441 cpl_msg_warning(cpl_func, "Found no positive stars at sigma=%g",
1442 psigmas[isigma]);
1443 continue;
1444 }
1445 if (cpl_apertures_get_size(appos) < 2) {
1446 cpl_msg_warning(cpl_func, "Found just 1 positive star at sigma=%g, "
1447 "need two", psigmas[isigma]);
1448 continue;
1449 }
1450
1451 /* Detect where the NEGATIVE stars are */
1452 cpl_apertures_delete(apneg);
1453 apneg = cpl_apertures_extract(min_combined, sigmas, NULL);
1454 if (apneg == NULL) {
1455 cpl_msg_warning(cpl_func, "Found no negative stars at sigma=%g",
1456 psigmas[isigma]);
1457 continue;
1458 }
1459 if (cpl_apertures_get_size(apneg) < 2) {
1460 cpl_msg_warning(cpl_func, "Found just 1 negative star at sigma=%g, "
1461 "need two", psigmas[isigma]);
1462 continue;
1463 }
1464
1465 cpl_msg_info(cpl_func, "Found positive and negative stars at sigma=%g",
1466 psigmas[isigma]);
1467 break;
1468 }
1469
1470 skip_if(appos == NULL);
1471 skip_if(apneg == NULL);
1472 skip_if (cpl_apertures_get_size(appos) < 2);
1473 skip_if (cpl_apertures_get_size(apneg) < 2);
1474
1475 if (cpl_msg_get_level() == CPL_MSG_DEBUG) {
1476 cpl_apertures_dump(appos, stdout);
1477 cpl_apertures_dump(apneg, stdout);
1478 }
1479
1480 if (cpl_apertures_get_size(appos) > 2 || cpl_apertures_get_size(apneg) > 2)
1481 cpl_msg_info(cpl_func, "Selecting from %d positive and %d negative "
1482 "stars two pairs that outline a square",
1483 (int)cpl_apertures_get_size(appos),
1484 (int)cpl_apertures_get_size(apneg));
1485
1486 for (ipos1 = 2; ipos1 <= cpl_apertures_get_size(appos); ipos1++) {
1487 for (ipos2 = 1; ipos2 < ipos1; ipos2++) {
1488 for (ineg1 = 2; ineg1 <= cpl_apertures_get_size(apneg); ineg1++) {
1489 for (ineg2 = 1; ineg2 < ineg1; ineg2++) {
1490 const double ecc = visir_img_phot_eccent_four(appos, ipos1,
1491 ipos2, apneg,
1492 ineg1, ineg2);
1493
1494 if (ecc < eccmin) {
1495 if (eccmin < DBL_MAX)
1496 cpl_msg_debug(cpl_func, "Found star positions with "
1497 "reduced non-square-ness [pixel]: "
1498 "%g < %g", ecc, eccmin);
1499 eccmin = ecc;
1500 iappos2[0] = ipos1;
1501 iappos2[1] = ipos2;
1502 iapneg2[0] = ineg1;
1503 iapneg2[1] = ineg2;
1504 }
1505 }
1506 }
1507 }
1508 }
1509
1510 /* Star 1 should have largest flux */
1511 if (cpl_apertures_get_flux(appos, iappos2[0]) <
1512 cpl_apertures_get_flux(appos, iappos2[1])) {
1513 const int tmp = iappos2[0];
1514 iappos2[0] = iappos2[1];
1515 iappos2[1] = tmp;
1516 }
1517 if (cpl_apertures_get_flux(apneg, iapneg2[0]) <
1518 cpl_apertures_get_flux(apneg, iapneg2[1])) {
1519 const int tmp = iapneg2[0];
1520 iapneg2[0] = iapneg2[1];
1521 iapneg2[1] = tmp;
1522 }
1523
1524
1525 x[0] = cpl_apertures_get_centroid_x(appos, iappos2[0]);
1526 y[0] = cpl_apertures_get_centroid_y(appos, iappos2[0]);
1527 x[1] = cpl_apertures_get_centroid_x(appos, iappos2[1]);
1528 y[1] = cpl_apertures_get_centroid_y(appos, iappos2[1]);
1529
1530 x[2] = cpl_apertures_get_centroid_x(apneg, iapneg2[0]);
1531 y[2] = cpl_apertures_get_centroid_y(apneg, iapneg2[0]);
1532 x[3] = cpl_apertures_get_centroid_x(apneg, iapneg2[1]);
1533 y[3] = cpl_apertures_get_centroid_y(apneg, iapneg2[1]);
1534
1535 cpl_apertures_delete(appos);
1536 cpl_apertures_delete(apneg);
1537 appos = NULL;
1538 apneg = NULL;
1539
1540 cpl_msg_info(cpl_func, "Positive star 1 at position %g %g", x[0], y[0]);
1541 cpl_msg_info(cpl_func, "Positive star 2 at position %g %g", x[1], y[1]);
1542
1543 cpl_msg_info(cpl_func, "Negative star 1 at position %g %g", x[2], y[2]);
1544 cpl_msg_info(cpl_func, "Negative star 2 at position %g %g", x[3], y[3]);
1545
1546 /* FIXME: Useful ? - change to 1D-distances - and move into sigma loop */
1547 dist1 = sqrt((x[2]-x[0])*(x[2]-x[0])+(y[2]-y[0])*(y[2]-y[0]));
1548 dist2 = sqrt((x[3]-x[1])*(x[3]-x[1])+(y[3]-y[1])*(y[3]-y[1]));
1549 cpl_msg_info(cpl_func, "Star 1 Pos/Neg Distance: %g", dist1);
1550 cpl_msg_info(cpl_func, "Star 2 Pos/Neg Distance: %g", dist2);
1551
1552 if (eccmin < DBL_MAX) {
1553 cpl_msg_info(cpl_func, "The deviation from a horizontal square by "
1554 "the two star pairs [pixel]: %g", eccmin);
1555 if (eccmin > VISIR_IMG_PHOT_POS_WARN) {
1556 if (eccmin > VISIR_IMG_PHOT_POS_ERROR) {
1557 cpl_msg_error(cpl_func, "The deviation from a horizontal square"
1558 " by the two star pairs exceed %g, the detected "
1559 "objects are wrong", VISIR_IMG_PHOT_POS_ERROR);
1560 skip_if(1);
1561 }
1562 cpl_msg_warning(cpl_func, "The deviation from a horizontal square "
1563 "by the two star pairs exceed %g, the detected "
1564 "objects may be wrong", VISIR_IMG_PHOT_POS_WARN);
1565 }
1566 }
1567
1568 if ((int)x[0]-IRPLIB_STREHL_BORDER <= 0 ||
1569 (int)y[0]-IRPLIB_STREHL_BORDER <= 0 ||
1570 (int)x[0]+IRPLIB_STREHL_BORDER > cpl_image_get_size_x(combined) ||
1571 (int)y[0]+IRPLIB_STREHL_BORDER > cpl_image_get_size_y(combined)) {
1572 cpl_msg_error(cpl_func, "Positive star 1 at (%g,%g) is less than %d "
1573 "pixels from the image border", x[0], y[0],
1574 1+IRPLIB_STREHL_BORDER);
1575 skip_if(1);
1576 }
1577
1578 /* Verify the stars positions */
1579 if (fabs(dist1-dist2) > VISIR_IMG_PHOT_POS_UNCERTAINTY) {
1580 cpl_msg_error(cpl_func, "Too large Pos/Neg Distance between the two "
1581 "stars: %g > %g", fabs(dist1-dist2),
1582 VISIR_IMG_PHOT_POS_UNCERTAINTY);
1583 skip_if(1);
1584 }
1585
1586 /* Photometry on positive stars */
1587 for (i=0 ; i<2 ; i++)
1588 skip_if (visir_img_phot_flux(combined, NULL, NULL,
1589 x[i], y[i],
1590 visir_img_phot_config.r0_max,
1591 visir_img_phot_config.r1,
1592 visir_img_phot_config.r2,
1593 &(flux_snr[i]),
1594 &(flux_snr_noise[i]),
1595 &(flux_snr_radius[i]),
1596 &(flux_tot[i]),
1597 &(beamshapes[i])));
1598
1599 /* Photometry on negative stars */
1600 for (i=2 ; i<4 ; i++)
1601 skip_if (visir_img_phot_flux(min_combined, NULL, NULL,
1602 x[i], y[i],
1603 visir_img_phot_config.r0_max,
1604 visir_img_phot_config.r1,
1605 visir_img_phot_config.r2,
1606 &(flux_snr[i]),
1607 &(flux_snr_noise[i]),
1608 &(flux_snr_radius[i]),
1609 &(flux_tot[i]),
1610 &(beamshapes[i])));
1611
1612 cpl_image_delete(min_combined);
1613 min_combined = NULL;
1614
1615 /* Compute the results */
1616 /* Flux */
1617 visir_img_phot_config.flux_snr = 0.0;
1618 for (i=0 ; i<4 ; i++) visir_img_phot_config.flux_snr += flux_snr[i];
1619
1620 /* Flux noise */
1621 visir_img_phot_config.flux_snr_noise = 0.0;
1622 for (i=0 ; i<4 ; i++) visir_img_phot_config.flux_snr_noise +=
1623 flux_snr_noise[i]*flux_snr_noise[i];
1624 visir_img_phot_config.flux_snr_noise =
1625 sqrt(visir_img_phot_config.flux_snr_noise);
1626
1627 for (i=0 ; i<4 ; i++)
1628 visir_img_phot_config.flux_snr_radius[i] = flux_snr_radius[i];
1629
1630 /* Total flux */
1631 visir_img_phot_config.flux_tot = 0.0;
1632 for (i=0 ; i<4 ; i++) visir_img_phot_config.flux_tot += flux_tot[i];
1633
1634 /* FWHM */
1635 ngood_fwhm = 0;
1636 visir_img_phot_config.beamshape.fwhm_x = 0.0;
1637 for (i=0 ; i<4 ; i++) {
1638 if (beamshapes[i].fwhm_x > 0.0) {
1639 visir_img_phot_config.beamshape.fwhm_x += beamshapes[i].fwhm_x;
1640 ngood_fwhm ++;
1641 }
1642 }
1643 if (ngood_fwhm > 0) visir_img_phot_config.beamshape.fwhm_x /= ngood_fwhm;
1644 else visir_img_phot_config.beamshape.fwhm_x = -1.0;
1645 ngood_fwhm = 0;
1646 visir_img_phot_config.beamshape.fwhm_y = 0.0;
1647 for (i=0 ; i<4 ; i++) {
1648 if (beamshapes[i].fwhm_y > 0.0) {
1649 visir_img_phot_config.beamshape.fwhm_y += beamshapes[i].fwhm_y;
1650 ngood_fwhm ++;
1651 }
1652 }
1653 if (ngood_fwhm > 0) visir_img_phot_config.beamshape.fwhm_y /= ngood_fwhm;
1654 else visir_img_phot_config.beamshape.fwhm_y = -1.0;
1655 visir_img_phot_config.fwhm_x_pos1 = beamshapes[0].fwhm_x;
1656 visir_img_phot_config.fwhm_y_pos1 = beamshapes[0].fwhm_y;
1657 visir_img_phot_config.fwhm_x_pos2 = beamshapes[1].fwhm_x;
1658 visir_img_phot_config.fwhm_y_pos2 = beamshapes[1].fwhm_y;
1659 visir_img_phot_config.fwhm_x_neg1 = beamshapes[2].fwhm_x;
1660 visir_img_phot_config.fwhm_y_neg1 = beamshapes[2].fwhm_y;
1661 visir_img_phot_config.fwhm_x_neg2 = beamshapes[3].fwhm_x;
1662 visir_img_phot_config.fwhm_y_neg2 = beamshapes[3].fwhm_y;
1663
1664 /* Get lam and dlam from the filter name for the Strehl computation */
1665 if (visir_get_filter_infos(visir_img_phot_config.filter, &lam, &dlam)) {
1666 cpl_msg_error(cpl_func, "Central wavelength and width is missing for "
1667 "filter: %s", visir_img_phot_config.filter);
1668 skip_if(1);
1669 }
1670
1671 /* Strehl computation */
1672 cpl_errorstate errstate = cpl_errorstate_get();
1673 if (irplib_strehl_compute(combined, STREHL_M1, STREHL_M2, lam, dlam,
1674 visir_img_phot_config.pscale,
1675 STREHL_BOX_SIZE, x[0], y[0], STREHL_STAR_RADIUS,
1676 STREHL_BG_R1, STREHL_BG_R2, -1, -1,
1677 &(visir_img_phot_config.strehl),
1678 &(visir_img_phot_config.strehl_err),
1679 &star_bg, &star_peak, &star_flux, &psf_peak, &psf_flux,
1680 &bg_noise)) {
1681 cpl_msg_error(cpl_func, "Could not compute the strehl: '%s' in %s",
1682 cpl_error_get_message(), cpl_error_get_where());
1683 cpl_errorstate_set(errstate);
1684 }
1685
1686
1687 end_skip;
1688
1689 cpl_apertures_delete(appos);
1690 cpl_apertures_delete(apneg);
1691 cpl_vector_delete(sigmas);
1692 cpl_image_delete(min_combined);
1693
1694 return cpl_error_get_code();
1695
1696}
1697
1698
1699/*----------------------------------------------------------------------------*/
1715/*----------------------------------------------------------------------------*/
1716static double visir_img_phot_eccent_four(const cpl_apertures * appos,
1717 int ipos1, int ipos2,
1718 const cpl_apertures * apneg,
1719 int ineg1, int ineg2)
1720{
1721
1722 /* NB: Lower left pixel is (1, 1) */
1723
1724 /* The two positive points */
1725 const double xp1 = cpl_apertures_get_centroid_x(appos, ipos1);
1726 const double xp2 = cpl_apertures_get_centroid_x(appos, ipos2);
1727 const double yp1 = cpl_apertures_get_centroid_y(appos, ipos1);
1728 const double yp2 = cpl_apertures_get_centroid_y(appos, ipos2);
1729
1730 /* The leftmost positive point */
1731 const double xpl = xp1 < xp2 ? xp1 : xp2;
1732 const double ypl = xp1 < xp2 ? yp1 : yp2;
1733
1734 /* The rightmost positive point */
1735 const double xpr = xp1 < xp2 ? xp2 : xp1;
1736 const double ypr = xp1 < xp2 ? yp2 : yp1;
1737
1738 /* The two negative points */
1739 const double xn1 = cpl_apertures_get_centroid_x(apneg, ineg1);
1740 const double yn1 = cpl_apertures_get_centroid_y(apneg, ineg1);
1741 const double xn2 = cpl_apertures_get_centroid_x(apneg, ineg2);
1742 const double yn2 = cpl_apertures_get_centroid_y(apneg, ineg2);
1743
1744 /* The leftmost negative point */
1745 const double xln = xn1 < xn2 ? xn1 : xn2;
1746 const double yln = xn1 < xn2 ? yn1 : yn2;
1747
1748 /* The rightmost engative point */
1749 const double xrn = xn1 < xn2 ? xn2 : xn1;
1750 const double yrn = xn1 < xn2 ? yn2 : yn1;
1751
1752 const double lx1 = xrn - xpl; /* The length of the top x-side */
1753 const double lx2 = xpr - xln; /* The length of the bottom x-side */
1754 const double ly1 = ypl - yln; /* The length of the left y-side */
1755 const double ly2 = yrn - ypr; /* The length of the right y-side */
1756
1757 const double lmean = 0.25 * ( lx1 + lx2 + ly1 + ly2);
1758
1759 const double dx1 = lx1 - lmean;
1760 const double dx2 = lx2 - lmean;
1761 const double dy1 = ly1 - lmean;
1762 const double dy2 = ly2 - lmean;
1763
1764 const double ey1 = yrn - ypl; /* The displacement in the top x-side */
1765 const double ey2 = ypr - yln; /* The displacement in the bottom x-side */
1766 const double ex1 = xpl - xln; /* The displacement in the left y-side */
1767 const double ex2 = xpr - xrn; /* The displacement in the right y-side */
1768
1769 const double result = sqrt(dx1 * dx1 + dx2 * dx2 + dy1 * dy1 + dy2 * dy2 +
1770 ex1 * ex1 + ex2 * ex2 + ey1 * ey1 + ey2 * ey2);
1771
1772
1773 bug_if(0);
1774
1775 bug_if(appos == apneg);
1776 bug_if(ipos1 == ipos2);
1777 bug_if(ineg1 == ineg2);
1778
1779 end_skip;
1780
1781 return result;
1782
1783
1784}
1785
1786#ifdef VISIR_IMG_PHOT_USE_ECCENT_THREE
1787/*----------------------------------------------------------------------------*/
1802/*----------------------------------------------------------------------------*/
1803static double visir_img_phot_eccent_three(const cpl_apertures * appos,
1804 int ipos,
1805 const cpl_apertures * apneg,
1806 int ineg1, int ineg2)
1807{
1808
1809 /* NB: Lower left pixel is (1, 1) */
1810
1811 /* The positive point */
1812 const double xp = cpl_apertures_get_centroid_x(appos, ipos);
1813 const double yp = cpl_apertures_get_centroid_y(appos, ipos);
1814
1815 /* The two negative points */
1816 const double xn1 = cpl_apertures_get_centroid_x(apneg, ineg1);
1817 const double yn1 = cpl_apertures_get_centroid_y(apneg, ineg1);
1818 const double xn2 = cpl_apertures_get_centroid_x(apneg, ineg2);
1819 const double yn2 = cpl_apertures_get_centroid_y(apneg, ineg2);
1820
1821 /* The bottom negative point */
1822 const double xnb = xn1 < xn2 ? xn1 : xn2;
1823 const double ynb = xn1 < xn2 ? yn1 : yn2;
1824
1825 /* The top engative point */
1826 const double xnt = xn1 < xn2 ? xn2 : xn1;
1827 const double ynt = xn1 < xn2 ? yn2 : yn1;
1828
1829 const double l1 = ynt - yp; /* The length of the top line */
1830 const double l2 = yp - ynb; /* The length of the bottom line */
1831 const double ln = ynt - ynb; /* The length of the top to bottom line */
1832
1833 const double lmean = 0.25 * ( l1 + l2 + ln);
1834
1835 const double d1 = l1 - lmean;
1836 const double d2 = l2 - lmean;
1837 const double dn = 0.5 * ln - lmean;
1838
1839 const double e1 = xp - xnt; /* The displacement in the top line */
1840 const double e2 = xp - xnb; /* The displacement in the bottom line */
1841
1842 const double result = sqrt(d1 * d1 + d2 * d2 + dn * dn + e1 * e1 + e2 * e2);
1843
1844
1845 bug_if(0);
1846
1847 bug_if(appos == apneg);
1848 bug_if(ineg1 == ineg2);
1849
1850 end_skip;
1851
1852 return result;
1853
1854
1855}
1856
1857#endif
1858
1859/*----------------------------------------------------------------------------*/
1881/*----------------------------------------------------------------------------*/
1882static int visir_img_phot_flux(
1883 const cpl_image * combined,
1884 const cpl_image * weights_,
1885 const cpl_image * contrib,
1886 double x_pos,
1887 double y_pos,
1888 int r0_max,
1889 int r1,
1890 int r2,
1891 double * flux_snr,
1892 double * flux_snr_noise,
1893 int * flux_snr_radius,
1894 double * flux_tot,
1895 beamshape_t * beamshape)
1896{
1897 cpl_apertures * apert = NULL;
1898 cpl_image * labels;
1899 cpl_image * bg_subtracted = NULL;
1900 cpl_vector * r0 = NULL;
1901 cpl_vector * fl = NULL;
1902 cpl_vector * fl_noise = NULL;
1903 cpl_vector * snr = NULL;
1904 double bg;
1905 double max_val = 0.0; /* Avoid (false) uninit warning */
1906 int max_ind = 0; /* Avoid (false) uninit warning */
1907 int i;
1908 cpl_size nx, ny;
1909 int max_contrib = 1;
1910 cpl_image * weights = weights_ == NULL ?
1911 NULL : cpl_image_duplicate(weights_);
1912
1913
1914 if (cpl_error_get_code()) return cpl_error_get_code();
1915
1916 cpl_ensure_code(combined != NULL, CPL_ERROR_NULL_INPUT);
1917 cpl_ensure_code(r0_max > 0, CPL_ERROR_ILLEGAL_INPUT);
1918
1919 nx = cpl_image_get_size_x(combined);
1920 ny = cpl_image_get_size_y(combined);
1921
1922 if (weights) {
1923 cpl_ensure_code(nx == cpl_image_get_size_x(weights) &&
1924 ny == cpl_image_get_size_y(weights),
1925 CPL_ERROR_ILLEGAL_INPUT);
1926 }
1927
1928 if (contrib) {
1929 cpl_ensure_code(nx == cpl_image_get_size_x(contrib) &&
1930 ny == cpl_image_get_size_y(contrib),
1931 CPL_ERROR_ILLEGAL_INPUT);
1932 max_contrib = cpl_image_get_max(contrib);
1933 cpl_ensure_code(max_contrib >= 1, CPL_ERROR_ILLEGAL_INPUT);
1934 }
1935
1936 /* Create the label image defining the background ring */
1937 if ((labels = visir_create_ring_intimage(nx, ny,
1938 (int)x_pos, (int)y_pos, r1, r2)) == NULL) {
1939 cpl_msg_error(cpl_func, "Could not create a ring image");
1940 skip_if(1);
1941 }
1942 /* Compute the background */
1943 apert = cpl_apertures_new_from_image(combined, labels);
1944 cpl_image_delete(labels);
1945 labels = NULL;
1946 bg = cpl_apertures_get_median(apert, 1);
1947 cpl_apertures_delete(apert);
1948 apert = NULL;
1949 cpl_msg_info(cpl_func, "Background : %g", bg);
1950
1951 /* Create the label image defining the total star disk */
1952 if ((labels = visir_create_disk_intimage(nx, ny,
1953 (int)x_pos, (int)y_pos, r0_max)) == NULL) {
1954 cpl_msg_error(cpl_func, "Could not create a disk image");
1955 skip_if(1);
1956 }
1957
1958 /* Compute the total flux and the associated error */
1959
1960 bg_subtracted = cpl_image_subtract_scalar_create(combined, bg);
1961
1962 /* due to bad pixels rescale the sum to equal contribution */
1963 if (contrib) {
1964 cpl_image * scale = cpl_image_cast(contrib, CPL_TYPE_DOUBLE);
1965 cpl_image_power(scale, -1);
1966 cpl_image_multiply_scalar(scale, max_contrib);
1967 cpl_image_multiply(bg_subtracted, scale);
1968 if (weights)
1969 cpl_image_multiply(weights, scale);
1970 cpl_image_delete(scale);
1971 }
1972
1973 apert = cpl_apertures_new_from_image(bg_subtracted, labels);
1974 cpl_image_delete(labels);
1975 labels = NULL;
1976 *flux_tot = cpl_apertures_get_flux(apert, 1);
1977 cpl_apertures_delete(apert);
1978 apert = NULL;
1979 cpl_msg_info(cpl_func, "Star total flux (error): %g", *flux_tot);
1980
1981 /* Create and fill r0 */
1982 r0 = cpl_vector_new(r0_max);
1983 for (i=0 ; i<r0_max ; i++) cpl_vector_set(r0, i, i+1);
1984
1985 /* Create fl, fl_noise */
1986 fl = cpl_vector_new(r0_max);
1987 fl_noise = cpl_vector_new(r0_max);
1988
1989 /* For each radius, compute fl and fl_noise */
1990 for (i=0 ; i<r0_max ; i++) {
1991 float fl_val = 0.f, fl_noise_val = 0.f;
1992 /* Create the label image defining the current star disk */
1993 if ((labels = visir_create_disk_intimage(nx, ny,
1994 (int)x_pos, (int)y_pos, (int)cpl_vector_get(r0, i))) == NULL) {
1995 cpl_msg_error(cpl_func, "Could not create a disk image: %d", i);
1996 break;
1997 }
1998
1999 if (weights) {
2000 double sum = 0, esum = 0;
2001 int d;
2002 for (int ix = 1; ix < 1 + nx; ix++) {
2003 for (int iy = 1; iy < 1 + ny; iy++) {
2004 if (!cpl_image_get(labels, ix, iy, &d) || d)
2005 continue;
2006
2007 sum += cpl_image_get(bg_subtracted, ix, iy, &d);
2008 /* assume gaussian error propagation, e = sqrt(1/w)
2009 * => e = sqrt(sum_i(1/w_i)) */
2010 esum += (1. / cpl_image_get(weights, ix, iy, &d));
2011 }
2012 }
2013 fl_val = sum;
2014 fl_noise_val = sqrt(esum);
2015 }
2016 else {
2017 cpl_apertures * pert =
2018 cpl_apertures_new_from_image(bg_subtracted, labels);
2019 /* FIXME: pert == NULL ? */
2020 fl_val = cpl_apertures_get_flux(pert, 1);
2021 fl_noise_val = visir_img_phot_config.bg_sigma *
2022 sqrt((double)cpl_apertures_get_npix(pert, 1));
2023 cpl_apertures_delete(pert);
2024 }
2025
2026 /* Compute the statistics on the zone defined by the labels */
2027 cpl_image_delete(labels);
2028 labels = NULL;
2029 cpl_vector_set(fl, i, fl_val);
2030 cpl_vector_set(fl_noise, i, fl_noise_val);
2031 }
2032 skip_if( 0 );
2033
2034 /* Compute the flux (and error) for the best signal to noise */
2035 snr = cpl_vector_duplicate(fl);
2036 cpl_vector_divide(snr, fl_noise);
2037 for (i=0 ; i<r0_max ; i++) {
2038 if (i == 0 || max_val < cpl_vector_get(snr, i)) {
2039 max_val = cpl_vector_get(snr, i);
2040 max_ind = i;
2041 }
2042 }
2043 *flux_snr = cpl_vector_get(fl, max_ind);
2044 *flux_snr_noise = cpl_vector_get(fl_noise, max_ind);
2045 *flux_snr_radius = (int)cpl_vector_get(r0, max_ind);
2046 cpl_msg_info(cpl_func, "Best SNR star flux : %g (%g) for radius %d <= %d "
2047 " [pixel]", *flux_snr, *flux_snr_noise,
2048 (int)cpl_vector_get(r0, max_ind),
2049 (int)cpl_vector_get(r0, r0_max-1));
2050
2051 if (cpl_msg_get_level() <= CPL_MSG_DEBUG) {
2052 cpl_matrix * mdump = cpl_matrix_new(1+r0_max, 3);
2053 for (i = 0; i < r0_max; i++) {
2054 cpl_matrix_set(mdump, i+1, 0, cpl_vector_get(fl, i));
2055 cpl_matrix_set(mdump, i+1, 1, cpl_vector_get(fl_noise, i));
2056 cpl_matrix_set(mdump, i+1, 2, cpl_vector_get(snr, i));
2057 }
2058 cpl_msg_debug(cpl_func, "Flux, flux-noise and S/N for radii out to %d",
2059 (int)cpl_vector_get(r0, r0_max-1));
2060
2061 cpl_matrix_dump(mdump, stdout);
2062 cpl_matrix_delete(mdump);
2063 }
2064
2065 *beamshape = (beamshape_t){.fwhm_x = -1., .fwhm_y = -1.,
2066 .peak = -1., .peak_err = 0.,
2067 .major = -1., .major_err = 0.,
2068 .minor = -1., .minor_err = 0.,
2069 .angle = -1., .angle_err = 0.};
2070
2071 /* Compute the FWHM */
2072 skip_if (cpl_image_get_fwhm(bg_subtracted, (int)x_pos, (int)y_pos, &beamshape->fwhm_x,
2073 &beamshape->fwhm_y));
2074
2075 skip_if ( beamshape->fwhm_x <= 0.0 );
2076 skip_if ( beamshape->fwhm_y <= 0.0 );
2077
2078 cpl_errorstate cleanstate = cpl_errorstate_get();
2079
2080 if (fit_2d_gauss(bg_subtracted, weights, (cpl_size)x_pos, (cpl_size)y_pos,
2081 beamshape->fwhm_x, beamshape->fwhm_y,
2082 &beamshape->peak, &beamshape->peak_err,
2083 &beamshape->major, &beamshape->major_err,
2084 &beamshape->minor, &beamshape->minor_err,
2085 &beamshape->angle, &beamshape->angle_err) == CPL_ERROR_NONE) {
2086 cpl_msg_info(cpl_func, "Peak: %g +- %g, FWHM : %g +- %g major ; %g +- %g minor, "
2087 "angle %g +- %g", beamshape->peak, beamshape->peak_err,
2088 beamshape->major, beamshape->major_err,
2089 beamshape->minor, beamshape->minor_err, beamshape->angle *
2090 CPL_MATH_DEG_RAD, beamshape->angle_err *
2091 CPL_MATH_DEG_RAD);
2092 }
2093 else {
2094 cpl_msg_warning(cpl_func, "2D gauss fit failed, approximate FWHM : %g"
2095 "in x ; %g in y ", beamshape->fwhm_x, beamshape->fwhm_y);
2096 cpl_errorstate_set(cleanstate);
2097 }
2098
2099 end_skip;
2100
2101 cpl_apertures_delete(apert);
2102 cpl_image_delete(labels);
2103 cpl_image_delete(bg_subtracted);
2104 cpl_image_delete(weights);
2105
2106 cpl_vector_delete(r0);
2107 cpl_vector_delete(fl);
2108 cpl_vector_delete(snr);
2109 cpl_vector_delete(fl_noise);
2110
2111 return cpl_error_get_code();
2112}
2113
2114
2115/*----------------------------------------------------------------------------*/
2126/*----------------------------------------------------------------------------*/
2127static cpl_error_code visir_get_filter_infos(
2128 const char * f,
2129 double * pcwlen,
2130 double * pdwlen)
2131{
2132
2133 double cwlen = -1;
2134 double dwlen = -1;
2135
2136 cpl_ensure_code(f, CPL_ERROR_NULL_INPUT);
2137 cpl_ensure_code(pcwlen, CPL_ERROR_NULL_INPUT);
2138 cpl_ensure_code(pdwlen, CPL_ERROR_NULL_INPUT);
2139
2140 skip_if (!strcmp(f, "MV"));
2141
2142 if (!strcmp(f, "N-BAND") || !strcmp(f, "N_BAND"))
2143 { cwlen = 10.56; dwlen = 5.37;}
2144 else if (!strcmp(f, "SIC")) { cwlen = 11.848;dwlen = 2.34;}
2145 else if (!strcmp(f, "PAH1_1")) { cwlen = 8.19;dwlen = 0.15;}
2146 else if (!strcmp(f, "PAH1")) { cwlen = 8.586;dwlen = 0.421;}
2147 else if (!strcmp(f, "ARIII")) { cwlen = 8.992;dwlen = 0.138;}
2148 else if (!strcmp(f, "SIV_1")) { cwlen = 10.02;dwlen = 0.18;}
2149 else if (!strcmp(f, "SIV")) { cwlen = 10.485;dwlen = 0.159;}
2150 else if (!strcmp(f, "PAH2_1")) { cwlen = 10.76;dwlen = 0.69;}
2151 else if (!strcmp(f, "SIV_2")) { cwlen = 11.1;dwlen = 0.19;}
2152 else if (!strcmp(f, "PAH2")) { cwlen = 11.254;dwlen = 0.594;}
2153 else if (!strcmp(f, "PAH2_2")) { cwlen = 12.13;dwlen = 0.37;}
2154 else if (!strcmp(f, "NEII_1")) { cwlen = 12.51;dwlen = 0.18;}
2155 else if (!strcmp(f, "NEII")) { cwlen = 12.805;dwlen = 0.21;}
2156 else if (!strcmp(f, "NEII_2")) { cwlen = 13.036;dwlen = 0.219;}
2157 else if (!strcmp(f, "Q0")) { cwlen = 16.554;dwlen = 0.398;}
2158 else if (!strcmp(f, "QH2")) { cwlen = 17.11;dwlen = 0.398;}
2159 else if (!strcmp(f, "Q1")) { cwlen = 17.653;dwlen = 0.83;}
2160 else if (!strcmp(f, "Q2")) { cwlen = 18.718;dwlen = 0.878;}
2161 else if (!strcmp(f, "Q3")) { cwlen = 19.5;dwlen = 0.4;}
2162 else if (!strcmp(f, "Q4")) { cwlen = 20.5;dwlen = 1.0;}
2163 else if (!strcmp(f, "Q7")) { cwlen = 23.1;dwlen = 0.8;}
2164 else if (!strcmp(f, "Q8")) { cwlen = 24.5;dwlen = 0.8;}
2165 /* TODO missing bandwidth for coro filters not determined yet */
2166 else if (!strcmp(f, "10_5_4QP")) { cwlen = 10.5;dwlen =0.1;}
2167 else if (!strcmp(f, "11_3_4QP")) { cwlen = 11.3;dwlen =0.1;}
2168 else if (!strcmp(f, "12_4_AGP")) { cwlen = 12.4;dwlen =0.1;}
2169 else if (!strcmp(f, "N-SW-spec") || !strcmp(f, "N_SW_spec"))
2170 { cwlen = 8.85; dwlen = 2.7;}
2171 else if (!strcmp(f, "H2S4-spec") || !strcmp(f, "H2S4_spec"))
2172 { cwlen = 8.12; dwlen = 0.3;}
2173 else if (!strcmp(f, "ARIII-spec") || !strcmp(f, "ARIII_spec"))
2174 { cwlen = 8.44; dwlen = 0.78;}
2175 else if (!strcmp(f, "NEII_2-spec") || !strcmp(f, "NEII_2_spec"))
2176 { cwlen = 12.805; dwlen = 0.2;}
2177 else if (!strcmp(f, "H2S3-spec") || !strcmp(f, "H2S3_spec"))
2178 { cwlen = 9.62; dwlen = 0.2;}
2179 else if (!strcmp(f, "H2S1-spec") || !strcmp(f, "H2S1_spec"))
2180 { cwlen = 17.0;dwlen = 0.4;}
2181 else if (!strcmp(f, "M-BAND") || !strcmp(f, "M_BAND"))
2182 { cwlen = 4.82;dwlen = 0.35;}
2183
2184 /* The width of each new, below filter is the Full Width at Half Maximum */
2185
2186 else if (!strcmp(f, "J7.9") || !strcmp(f, "J7_9"))
2187 { cwlen = (7.483 + 8.035)/2.0;
2188 dwlen = 8.035 - 7.483;}
2189 else if (!strcmp(f, "J8.9") || !strcmp(f, "J8_9"))
2190 { cwlen = (8.338 + 9.068)/2.0;
2191 dwlen = 9.068 - 8.338;}
2192 else if (!strcmp(f, "J9.8") || !strcmp(f, "J9_8"))
2193 { cwlen = (9.123 + 10.059)/2.0;
2194 dwlen = 10.059 - 9.123;}
2195 else if (!strcmp(f, "J12.2") || !strcmp(f, "J12_2"))
2196 { cwlen = (11.700 + 12.216)/2.0;
2197 dwlen = 12.216 - 11.700;}
2198 else if (!strcmp(f, "B8.7") || !strcmp(f, "B8_7"))
2199 { cwlen = (8.436 + 9.410)/2.0;
2200 dwlen = 9.410 - 8.436;}
2201 else if (!strcmp(f, "B9.7") || !strcmp(f, "B9_7"))
2202 { cwlen = (9.402 + 10.242)/2.0;
2203 dwlen = 10.242 - 9.402;}
2204 else if (!strcmp(f, "B10.7") || !strcmp(f, "B10_7"))
2205 { cwlen = (9.970 + 11.338)/2.0;
2206 dwlen = 11.338 - 9.970;}
2207 else if (!strcmp(f, "B11.7") || !strcmp(f, "B11_7"))
2208 { cwlen = (11.098 + 11.950)/2.0;
2209 dwlen = 11.950 - 11.098;}
2210 else if (!strcmp(f, "B12.4") || !strcmp(f, "B12_4"))
2211 { cwlen = (11.971 + 12.961)/2.0;
2212 dwlen = 12.961 - 11.971;}
2213 else if (!strcmp(f, "L-BAND") || !strcmp(f, "L_BAND"))
2214 { cwlen = 3.7702; //(3.4195 + 4.0610)/2.0;
2215 dwlen = 4.0610 - 3.4195;}
2216
2217 *pcwlen = cwlen;
2218 *pdwlen = dwlen;
2219
2220 cpl_ensure_code(cwlen > 0, CPL_ERROR_DATA_NOT_FOUND);
2221 cpl_ensure_code(dwlen > 0, CPL_ERROR_DATA_NOT_FOUND);
2222
2223 end_skip;
2224
2225 return cpl_error_get_code();
2226}
2227
2228/*----------------------------------------------------------------------------*/
2236/*----------------------------------------------------------------------------*/
2237static cpl_error_code visir_img_phot_qc(cpl_propertylist * qclist,
2238 cpl_boolean drop_wcs,
2239 const irplib_framelist * rawframes)
2240{
2241
2242 const cpl_propertylist * reflist
2243 = irplib_framelist_get_propertylist_const(rawframes, 0);
2244
2245
2246 /* QC.EXPTIME */
2247 bug_if (cpl_propertylist_append_double(qclist, "ESO QC EXPTIME",
2248 visir_img_phot_config.exptime));
2249 /* QC.JYVAL */
2250 bug_if (cpl_propertylist_append_double(qclist, "ESO QC JYVAL",
2251 visir_img_phot_config.jy_val));
2252 /* QC.STARNAME */
2253 bug_if (cpl_propertylist_append_string(qclist, "ESO QC STARNAME",
2254 visir_img_phot_config.star_name));
2255 /* QC.FILTER */
2256 bug_if (cpl_propertylist_append_string(qclist, "ESO QC FILTER",
2257 visir_img_phot_config.filter));
2258
2259 /* QC.NELEC */
2260 bug_if (cpl_propertylist_append_double(qclist, "ESO QC NELEC",
2261 visir_img_phot_config.nelec));
2262 /* QC.NPHOT */
2263 bug_if (cpl_propertylist_append_double(qclist, "ESO QC NPHOT",
2264 visir_img_phot_config.nphot));
2265 /* QC.BACKGD.SIGMA */
2266 bug_if (cpl_propertylist_append_double(qclist, "ESO QC BACKGD SIGMA",
2267 visir_img_phot_config.bg_sigma));
2268 /* QC.FLUXTOT */
2269 bug_if (cpl_propertylist_append_double(qclist, "ESO QC FLUXTOT",
2270 visir_img_phot_config.flux_tot));
2271 /* QC.FLUXSNR */
2272 bug_if (cpl_propertylist_append_double(qclist, "ESO QC FLUXSNR",
2273 visir_img_phot_config.flux_snr));
2274 /* QC.FLUXSNR.NOISE */
2275 bug_if (cpl_propertylist_append_double(qclist, "ESO QC FLUXSNR NOISE",
2276 visir_img_phot_config.flux_snr_noise));
2277 /* QC.FLUXSNR.RADIUS */
2278 for (int i = 0; i < 4; i++) {
2279 const int r = visir_img_phot_config.flux_snr_radius[i];
2280 char buffer[100];
2281 sprintf(buffer, "ESO QC FLUXSNR RADIUS%d", i + 1);
2282 bug_if (cpl_propertylist_append_int(qclist, buffer, r));
2283 }
2284 /* QC.FWHMX */
2285 bug_if (cpl_propertylist_append_double(qclist, "ESO QC FWHMX",
2286 visir_img_phot_config.beamshape.fwhm_x));
2287 /* QC.FWHMY */
2288 bug_if (cpl_propertylist_append_double(qclist, "ESO QC FWHMY",
2289 visir_img_phot_config.beamshape.fwhm_y));
2290 bug_if (cpl_propertylist_append_double(qclist, "ESO QC GAUSSFIT FWHM_MAX",
2291 visir_img_phot_config.beamshape.major));
2292 cpl_propertylist_set_comment(qclist, "ESO QC GAUSSFIT FWHM_MAX",
2293 "major axis [pix]");
2294 bug_if (cpl_propertylist_append_double(qclist, "ESO QC GAUSSFIT FWHM_MAX_ERR",
2295 visir_img_phot_config.beamshape.major_err));
2296 bug_if (cpl_propertylist_append_double(qclist, "ESO QC GAUSSFIT FWHM_MIN",
2297 visir_img_phot_config.beamshape.minor));
2298 cpl_propertylist_set_comment(qclist, "ESO QC GAUSSFIT FWHM_MIN",
2299 "minor axis [pix]");
2300 bug_if (cpl_propertylist_append_double(qclist, "ESO QC GAUSSFIT FWHM_MIN_ERR",
2301 visir_img_phot_config.beamshape.minor_err));
2302 bug_if (cpl_propertylist_append_double(qclist, "ESO QC GAUSSFIT ANGLE",
2303 visir_img_phot_config.beamshape.angle * CPL_MATH_DEG_RAD));
2304 cpl_propertylist_set_comment(qclist, "ESO QC GAUSSFIT ANGLE",
2305 "[deg]");
2306 bug_if (cpl_propertylist_append_double(qclist, "ESO QC GAUSSFIT ANGLE_ERR",
2307 visir_img_phot_config.beamshape.angle_err * CPL_MATH_DEG_RAD));
2308 bug_if (cpl_propertylist_append_double(qclist, "ESO QC GAUSSFIT PEAK",
2309 visir_img_phot_config.beamshape.peak));
2310 bug_if (cpl_propertylist_append_double(qclist, "ESO QC GAUSSFIT PEAK_ERR",
2311 visir_img_phot_config.beamshape.peak_err));
2312 /* QC.FWHMX.POS1 */
2313 bug_if (cpl_propertylist_append_double(qclist, "ESO QC FWHMX POS1",
2314 visir_img_phot_config.fwhm_x_pos1));
2315 /* QC.FWHMY.POS1 */
2316 bug_if (cpl_propertylist_append_double(qclist, "ESO QC FWHMY POS1",
2317 visir_img_phot_config.fwhm_y_pos1));
2318 /* QC.FWHMX.POS2 */
2319 bug_if (cpl_propertylist_append_double(qclist, "ESO QC FWHMX POS2",
2320 visir_img_phot_config.fwhm_x_pos2));
2321 /* QC.FWHMY.POS2 */
2322 bug_if (cpl_propertylist_append_double(qclist, "ESO QC FWHMY POS2",
2323 visir_img_phot_config.fwhm_y_pos2));
2324 /* QC.FWHMX.NEG1 */
2325 bug_if (cpl_propertylist_append_double(qclist, "ESO QC FWHMX NEG1",
2326 visir_img_phot_config.fwhm_x_neg1));
2327 /* QC.FWHMY.NEG1 */
2328 bug_if (cpl_propertylist_append_double(qclist, "ESO QC FWHMY NEG1",
2329 visir_img_phot_config.fwhm_y_neg1));
2330 /* QC.FWHMX.NEG2 */
2331 bug_if (cpl_propertylist_append_double(qclist, "ESO QC FWHMX NEG2",
2332 visir_img_phot_config.fwhm_x_neg2));
2333 /* QC.FWHMY.NEG2 */
2334 bug_if (cpl_propertylist_append_double(qclist, "ESO QC FWHMY NEG2",
2335 visir_img_phot_config.fwhm_y_neg2));
2336 /* QC.SENSIT */
2337 bug_if (cpl_propertylist_append_double(qclist, "ESO QC SENSIT",
2338 visir_img_phot_config.sensitivity));
2339 /* QC.AREASENSIT */
2340 bug_if (cpl_propertylist_append_double(qclist, "ESO QC AREA SENSIT",
2341 visir_img_phot_config.area_sensit));
2342 cpl_propertylist_set_comment(qclist, "ESO QC AREA SENSIT",
2343 "scaled to noise of 1 arcsecond");
2344 /* QC.CONVER */
2345 bug_if (cpl_propertylist_append_double(qclist, "ESO QC CONVER",
2346 visir_img_phot_config.conversion));
2347 /* QC.STREHL */
2348 bug_if (cpl_propertylist_append_double(qclist, "ESO QC STREHL",
2349 visir_img_phot_config.strehl));
2350 /* QC.STREHL.ERROR */
2351 bug_if (cpl_propertylist_append_double(qclist, "ESO QC STREHL ERROR",
2352 visir_img_phot_config.strehl_err));
2353
2354 /* QC.CAPA */
2355 skip_if (visir_qc_append_capa(qclist, rawframes));
2356
2357 if (drop_wcs) {
2358 cpl_propertylist * pcopy = cpl_propertylist_new();
2359 const cpl_error_code error
2360 = cpl_propertylist_copy_property_regexp(pcopy, reflist, "^("
2361 IRPLIB_PFITS_WCS_REGEXP
2362 ")$", 0);
2363 if (!error && cpl_propertylist_get_size(pcopy) > 0) {
2364 cpl_msg_warning(cpl_func, "Combined image will have no WCS "
2365 "coordinates");
2366 }
2367 cpl_propertylist_delete(pcopy);
2368 bug_if(0);
2369
2370 bug_if(cpl_propertylist_copy_property_regexp(qclist, reflist, "^("
2371 VISIR_PFITS_IMG_PHOT_COPY
2372 ")$", 0));
2373 } else {
2374 bug_if(cpl_propertylist_copy_property_regexp(qclist, reflist, "^("
2375 VISIR_PFITS_IMG_PHOT_COPY
2376 "|" IRPLIB_PFITS_WCS_REGEXP
2377 ")$", 0));
2378 }
2379
2380 bug_if (irplib_pfits_set_airmass(qclist, rawframes));
2381
2382 end_skip;
2383
2384 return cpl_error_get_code();
2385
2386}
2387
2388/*----------------------------------------------------------------------------*/
2400/*----------------------------------------------------------------------------*/
2401static cpl_error_code visir_img_phot_save(cpl_frameset * self,
2402 const cpl_parameterlist * parlist,
2403 const cpl_propertylist * qclist,
2404 const cpl_image * combined,
2405 const cpl_image * contrib,
2406 const cpl_image * beam1,
2407 const cpl_image * beam1i,
2408 const cpl_image * weights)
2409{
2410
2411 cpl_propertylist * xtlist = cpl_propertylist_new();
2412 const char * procatg = VISIR_IMG_PHOT_COMBINED_PROCATG;
2413
2414 bug_if (0);
2415
2416 if (weights) {
2417 const char * s = cpl_propertylist_get_string(qclist, "ESO QC BEAMID");
2418 bug_if(s == NULL);
2419
2420 if (strcmp(s, "COMBINED") == 0)
2421 procatg = VISIR_IMG_PHOT_COMBINED_PROCATG;
2422 else
2423 procatg = VISIR_IMG_PHOT_ONEBEAM_PROCATG;
2424 }
2425
2426 /* SAVE THE COMBINED IMAGE */
2427 skip_if (irplib_dfs_save_image(self, parlist, self, combined,
2428 CPL_BPP_IEEE_FLOAT, RECIPE_SAVE_STRING,
2429 procatg, qclist, NULL, visir_pipe_id,
2430 RECIPE_SAVE_STRING CPL_DFS_FITS));
2431
2432 if (!weights) {
2433 /* THE CONTRIBUTION MAP */
2434 bug_if(cpl_propertylist_append_string(xtlist, "EXTNAME",
2435 "Contribution Map"));
2436 skip_if (cpl_image_save(contrib, RECIPE_SAVE_STRING CPL_DFS_FITS,
2437 CPL_BPP_16_UNSIGNED, xtlist, CPL_IO_EXTEND));
2438 }
2439
2440 if (beam1 != NULL) {
2441 bug_if(weights);
2442 /* THE BEAM COLLAPSED IMAGE */
2443 skip_if (irplib_dfs_save_image(self, parlist, self, beam1,
2444 CPL_BPP_IEEE_FLOAT, RECIPE_SAVE_STRING,
2445 VISIR_IMG_PHOT_ONEBEAM_PROCATG, qclist,
2446 NULL, visir_pipe_id,
2447 RECIPE_SAVE_STRING "_onebeam" CPL_DFS_FITS));
2448
2449 /* THE BEAM COLLAPSED CONTRIBUTION MAP */
2450 skip_if (cpl_image_save(beam1i, RECIPE_SAVE_STRING "_onebeam" CPL_DFS_FITS,
2451 CPL_BPP_8_UNSIGNED, xtlist, CPL_IO_EXTEND));
2452 }
2453
2454 end_skip;
2455
2456 cpl_propertylist_delete(xtlist);
2457
2458 return cpl_error_get_code();
2459
2460}
2461
2462/*----------------------------------------------------------------------------*/
2472/*----------------------------------------------------------------------------*/
2473static char * visir_img_phot_filter2label(const char * self)
2474{
2475
2476 char * label = NULL;
2477 char * p;
2478
2479 bug_if(self == NULL);
2480
2481 label = cpl_strdup(self);
2482
2483 for (p = label; *p != (char)0; p++) {
2484 if (*p == '.' || *p == '-') *p = '_';
2485 }
2486
2487 end_skip;
2488
2489 return label;
2490
2491}
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:613
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