ERIS Pipeline Reference Manual 1.9.3
eris_nix_scired.c
1/* $Id: eris_nix_scired.c,v 1.9 2013-03-26 17:00:44 jtaylor Exp $
2 *
3 * This file is part of the ERIS Pipeline
4 * Copyright (C) 2002,2003 European Southern Observatory
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21/*
22 * $Author: jtaylor $
23 * $Date: 2013-03-26 17:00:44 $
24 * $Revision: 1.9 $
25 * $Name: not supported by cvs2svn $
26 */
27
28#ifdef HAVE_CONFIG_H
29#include <config.h>
30#endif
31
32/*-----------------------------------------------------------------------------
33 Includes
34 -----------------------------------------------------------------------------*/
35#include <casu_utils.h>
36#include <casu_stats.h>
37#include <casu_mods.h>
38#include <eris_nix_scired.h>
39#include <eris_nix_dfs.h>
40#include <eris_nix_utils.h>
41#include <eris_nix_catalogue.h>
42#include <eris_nix_gain_linearity.h>
43#include <eris_nix_master_dark.h>
44#include <eris_nix_master_bpm.h>
45#include <eris_nix_master_flat.h>
46#include <eris_nix_casu_match.h>
47#include <eris_nix_casu_utils.h>
48#include <eris_nix_match.h>
49#include <eris_utils.h>
50#include <string.h>
51#include <libgen.h>
52#include <math.h>
53/*----------------------------------------------------------------------------*/
59/*----------------------------------------------------------------------------*/
60
64/* science parameter setting functions (to allow to share params between wrapper
65 * recipe eris_nix_img_scired and the others eris_nix_cal_det, eris_nix_skysub
66 * eris_nix_cal_wcs, eris_nix_cal_phot, eris_nix_img_hdrl_stack
67 * */
68
69cpl_error_code eris_nix_pixel_coord_diagnostic_param_set(
70 const char* context,
71 cpl_parameterlist* parlist) {
72 /* coords of pixel to be used for diagnostics during reduction */
73
74 cpl_parameter* p;
75 char* param_name = NULL;
76
77 param_name = cpl_sprintf("%s.x_probe", context);
78 p = cpl_parameter_new_value(param_name, CPL_TYPE_INT,
79 "x coord of diagnostic pixel", context, -1);
80 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "x-probe");
81 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
82 cpl_parameterlist_append(parlist, p);
83 cpl_free(param_name);
84
85 param_name = cpl_sprintf("%s.y_probe", context);
86 p = cpl_parameter_new_value(param_name, CPL_TYPE_INT,
87 "y coord of diagnostic pixel", context, -1);
88 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "y-probe");
89 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
90 cpl_free(param_name);
91
92 cpl_parameterlist_append(parlist, p);
93 return cpl_error_get_code();
94}
95
96cpl_error_code eris_nix_skysub_param_set(const char* context,
97 cpl_parameterlist* parlist) {
98
99 /* skysub recipe-specific parameters */
100 cpl_parameter* p;
101 char* param_name = NULL;
102
103 param_name = cpl_sprintf("%s.sky-source", context);
104 p = cpl_parameter_new_enum(param_name, CPL_TYPE_STRING,
105 "data to be used for calculation of sky "
106 "background", context,
107 "auto", 3, "auto", "target", "offset");
108 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "sky-source");
109 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
110 cpl_parameterlist_append(parlist, p);
111 cpl_free(param_name);
112
113 param_name = cpl_sprintf("%s.sky-selector", context);
114 p = cpl_parameter_new_enum(param_name, CPL_TYPE_STRING,
115 "method for selecting sky frames",
116 context, "bracket", 1, "bracket");
117 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "sky-selector");
118 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
119 cpl_parameterlist_append(parlist, p);
120 cpl_free(param_name);
121
122 param_name = cpl_sprintf("%s.sky-method", context);
123 p = cpl_parameter_new_enum(param_name, CPL_TYPE_STRING,
124 "method for combining sky frames",
125 context, "median-median", 2,
126 "collapse-median", "median-median");
127 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "sky-method");
128 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
129 cpl_parameterlist_append(parlist, p);
130 cpl_free(param_name);
131
132 param_name = cpl_sprintf("%s.sky-bracket-time", context);
133 p = cpl_parameter_new_range(param_name, CPL_TYPE_DOUBLE,
134 "2 * max.time between target and sky measurement",
135 context, 1800.0, 60.0, 18000.0);
136 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "sky-bracket-time");
137 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
138 cpl_parameterlist_append(parlist, p);
139 cpl_free(param_name);
140
141 param_name = cpl_sprintf("%s.debug-data", context);
142 p = cpl_parameter_new_value(param_name,
143 CPL_TYPE_BOOL, "true to save interim results",
144 context, CPL_FALSE);
145 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "debug-data");
146 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
147 cpl_parameterlist_append(parlist, p);
148 cpl_free(param_name);
149
150 return cpl_error_get_code();
151}
152
153/* defaults skysub:
154 * 20, 3.0, CPL_TRUE, 5.0, CPL_TRUE, 64, 2.0, 3.0,
155 * ERIS_NIX_SATURATION_DEFAULT, HDRL_CATALOGUE_ALL
156 * default photom:
157 * 4, 2.5, CPL_TRUE, 5.0, CPL_TRUE, 64, 2.0, 3.0,
158 ERIS_NIX_SATURATION_DEFAULT, HDRL_CATALOGUE_ALL);
159
160 default hdrl_stack:
161 4, 2.5, CPL_TRUE, 5.0, CPL_TRUE, 64, 2.0, 3.0,
162 ERIS_NIX_SATURATION_DEFAULT, HDRL_CATALOGUE_ALL);
163
164 ==> obj_min_pixels, obj_threshold may have recipe dependent values
165 */
166cpl_error_code
167eris_nix_catalogue_param_set(const char* context,
168 cpl_parameterlist* parlist,
169 int obj_min_pixels, double obj_threshold, cpl_boolean obj_deblending,
170 double obj_core_radius, cpl_boolean bkg_estimate, int bkg_mesh_size,
171 double bkg_smooth_fwhm, double det_eff_gain, double det_saturation,
172 hdrl_catalogue_options resulttype)
173{
174
175 /* generate the general parameter list for the catalogue */
176 cpl_parameter * p = NULL;
177 hdrl_parameter * catalogue_defaults = NULL;
178 cpl_parameterlist * catalogue_parlist = NULL;
179
180 catalogue_defaults = hdrl_catalogue_parameter_create(obj_min_pixels,
181 obj_threshold, obj_deblending, obj_core_radius, bkg_estimate,
182 bkg_mesh_size, bkg_smooth_fwhm, det_eff_gain, det_saturation,
183 resulttype);
184 catalogue_parlist = hdrl_catalogue_parameter_create_parlist(context,
185 "catalogue", catalogue_defaults);
186
187 /* add the subset of parameters to be used */
188 for (p = cpl_parameterlist_get_first(catalogue_parlist);
189 p != NULL;
190 p = cpl_parameterlist_get_next(catalogue_parlist)) {
191
192 const char * pname = cpl_parameter_get_name(p);
193 if (strstr(pname, "min-pixels") ||
194 strstr(pname, "threshold") ||
195 strstr(pname, "mesh-size") ||
196 strstr(pname, "threshold") ||
197 strstr(pname, "smooth-gauss-fwhm")) {
198 cpl_parameter * duplicate = cpl_parameter_duplicate(p);
199 cpl_parameterlist_append(parlist, duplicate);
200 }
201 }
202
203 /* ..add ao-params which specifies how to set params depending on AO */
204
205 char * pname = cpl_sprintf("%s.catalogue.ao-params", context);
206 p = cpl_parameter_new_enum(pname,
207 CPL_TYPE_STRING,
208 "Default catalogue.core-radius and "
209 "catalogue.mesh-size depending on "
210 "AOMODE, or not",
211 context,
212 "auto", 2, "auto", "user");
213 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "catalogue.ao-params");
214 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
215 cpl_parameterlist_append(parlist, p);
216 cpl_free(pname);
217
218 hdrl_parameter_delete(catalogue_defaults);
219 cpl_parameterlist_delete(catalogue_parlist);
220 return cpl_error_get_code();
221}
222
223cpl_error_code
224eris_nix_astrometric_param_set(const char* context,
225 cpl_parameterlist* parlist)
226{
227
228 cpl_parameter* p;
229 char* param_name = NULL;
230
231 /* Flag to decide how we get the astrometric standard star information.
232 If "none", then use the local catalogues specified in the sof. If not,
233 then use one of the selection of catalogues available from CDS -
234 only gaia has sufficient accuracy */
235
236 param_name = cpl_sprintf("%s.cdssearch_astrom", context);
237 p = cpl_parameter_new_enum(param_name,
238 CPL_TYPE_STRING,
239 "CDS astrometric catalogue",
240 context,
241 "none", 3, "none", "2mass", "gaiadr3");
242 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "cdssearch-astrom");
243 cpl_parameterlist_append(parlist, p);
244 cpl_free(param_name);
245
246 param_name = cpl_sprintf("%s.debug-data", context);
247 p = cpl_parameter_new_value(param_name,
248 CPL_TYPE_BOOL, "true to save interim results",
249 context, CPL_FALSE);
250 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "debug-data");
251 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
252 cpl_parameterlist_append(parlist, p);
253 cpl_free(param_name);
254
255 return cpl_error_get_code();
256
257}
258
259cpl_error_code
260eris_nix_photom_param_set(const char* context,
261 cpl_parameterlist* parlist)
262{
263 cpl_parameter* p;
264 char* param_name = NULL;
265
266 /* Flag to decide how we get the photometric standard star information. */
267 param_name = cpl_sprintf("%s.cdssearch_photom", context);
268 p = cpl_parameter_new_enum(param_name,
269 CPL_TYPE_STRING,
270 "CDS photometric catalogue",
271 context,
272 "2MASS", 1, "2MASS");
273 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "cdssearch_photom");
274 cpl_parameterlist_append(parlist, p);
275 cpl_free(param_name);
276
277 param_name = cpl_sprintf("%s.pixel_radius", context);
278 p = cpl_parameter_new_value(param_name,
279 CPL_TYPE_DOUBLE,
280 "Max. distance between object and catalogue "
281 "entry for association (pixels)",
282 context, 5.0);
283 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "pixel-radius");
284 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
285 cpl_parameterlist_append(parlist, p);
286 cpl_free(param_name);
287
288 param_name = cpl_sprintf("%s.minphotom", context);
289 p = cpl_parameter_new_range(param_name,
290 CPL_TYPE_INT,
291 "Min number of matched stars for photometric "
292 "calibration", context, 1, 1, 100000);
293 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "minphotom");
294 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
295 cpl_parameterlist_append(parlist, p);
296 cpl_free(param_name);
297
298 param_name = cpl_sprintf("%s.magerrcut", context);
299 p = cpl_parameter_new_value(param_name,
300 CPL_TYPE_DOUBLE,
301 "Matched stars with magnitude error above "
302 "this cutoff will not be used.",
303 context, 0.5);
304 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "magerrcut");
305 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
306 cpl_parameterlist_append(parlist, p);
307 cpl_free(param_name);
308
309 param_name = cpl_sprintf("%s.debug-data", context);
310 p = cpl_parameter_new_value(param_name,
311 CPL_TYPE_BOOL, "true to save interim results",
312 context, CPL_FALSE);
313 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "debug-data");
314 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
315 cpl_parameterlist_append(parlist, p);
316 cpl_free(param_name);
317
318 return cpl_error_get_code();
319
320}
321
322
323cpl_error_code eris_nix_hdrl_stack_param_set(const char* context,
324 cpl_parameterlist* parlist) {
325 cpl_parameter* p;
326 char* param_name = NULL;
327
328 /* Interpolation method */
329 param_name = cpl_sprintf("%s.interpolation_method", context);
330 p = cpl_parameter_new_enum(param_name,
331 CPL_TYPE_STRING, "The interpolation method",
332 context, "lanczos", 6, "nearest",
333 "linear", "quadratic", "renka", "drizzle",
334 "lanczos");
335 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
336 "interpolation-method");
337 cpl_parameterlist_append(parlist, p);
338 cpl_free(param_name);
339
340
341 /* Loop distance */
342 param_name = cpl_sprintf("%s.loop_distance", context);
343 p = cpl_parameter_new_value(param_name, CPL_TYPE_INT,
344 "maximum pixel offset taken into account",
345 context, 1);
346 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "loop-distance");
347 cpl_parameterlist_append(parlist, p);
348 cpl_free(param_name);
349
350 /* Kernel size */
351 param_name = cpl_sprintf("%s.kernel_size", context);
352 p = cpl_parameter_new_value(param_name, CPL_TYPE_INT,
353 "(Lanczos method) size of kernel in pixels",
354 context, 2);
355 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "kernel-size");
356 cpl_parameterlist_append(parlist, p);
357 cpl_free(param_name);
358
359 /* Critical radius */
360 param_name = cpl_sprintf("%s.critical_radius", context);
361 p = cpl_parameter_new_value(param_name, CPL_TYPE_DOUBLE,
362 "(Renka method) distance beyond which weights "
363 "set to 0",
364 context, 5.0);
365 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "critical-radius");
366 cpl_parameterlist_append(parlist, p);
367 cpl_free(param_name);
368
369 /* Drizzle frac parameters */
370 param_name = cpl_sprintf("%s.pix_frac_x", context);
371 p = cpl_parameter_new_value(param_name, CPL_TYPE_DOUBLE,
372 "(Drizzle method) percentage of flux "
373 "to drizzle from original to target pixel",
374 context, 50.0);
375 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "pix-frac-x");
376 cpl_parameterlist_append(parlist, p);
377 cpl_free(param_name);
378
379 param_name = cpl_sprintf("%s.pix_frac_y", context);
380 p = cpl_parameter_new_value(param_name, CPL_TYPE_DOUBLE,
381 "(Drizzle method) percentage of flux "
382 "to drizzle from original to target pixel",
383 context, 50.0);
384 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "pix-frac-y");
385 cpl_parameterlist_append(parlist, p);
386 cpl_free(param_name);
387
388 /* catalogue parameters should be added separately if needed */
389
390 return cpl_error_get_code();
391}
392/*----------------------------------------------------------------------------*/
402/*----------------------------------------------------------------------------*/
403
404static cpl_error_code eris_nix_cal_det_save(
405 located_image * limage,
406 const char * procatg,
407 cpl_frameset * frameset,
408 const cpl_parameterlist * parlist,
409 const cpl_frameset * calib_frames,
410 const char* recipe_name) {
411
412 /* check input */
413
414 if (cpl_error_get_code() != CPL_ERROR_NONE) return cpl_error_get_code();
415 cpl_ensure_code(limage, CPL_ERROR_NONE);
416 cpl_ensure_code(procatg, CPL_ERROR_NULL_INPUT);
417 cpl_ensure_code(frameset, CPL_ERROR_NULL_INPUT);
418 cpl_ensure_code(calib_frames, CPL_ERROR_NULL_INPUT);
419
420 /* construct the provenance frameset for this frame - the frames
421 actually used */
422
423 cpl_frameset * provenance = cpl_frameset_new();
424 cpl_frameset_insert(provenance, cpl_frame_duplicate(limage->frame));
425
426 /* applist, keywords to add to headers */
427
428 cpl_propertylist * applist = cpl_propertylist_new();
429 cpl_propertylist_update_string(applist, CPL_DFS_PRO_CATG, procatg);
430 cpl_propertylist_copy_property(applist, limage->plist, "BUNIT");
431 cpl_propertylist_update_int(applist, "NCOMBINE", 1);
432 double dit = enu_get_dit(limage->plist);
433 int ndit = cpl_propertylist_get_int(limage->plist, "ESO DET NDIT");
434 cpl_propertylist_update_double(applist, "TEXPTIME", ndit * dit);
435 /* update EXPTIME as well because it has a different defn in product
436 compared to raw file - see jira PIPE-10669 for discussion. */
437 cpl_propertylist_update_double(applist, "EXPTIME", ndit * dit);
438 double mjd_obs = cpl_propertylist_get_double(limage->plist, "MJD-OBS");
439 double mjd_end = mjd_obs + (ndit * dit) / (3600.0 * 24.0);
440 cpl_propertylist_update_double(applist, "MJD-END", mjd_end);
441 if(cpl_propertylist_has(limage->plist, "PSF_FWHM")) {
442 cpl_propertylist_copy_property(applist, limage->plist, "PSF_FWHM");
443 }
444 cpl_propertylist_copy_property(applist, limage->plist,
445 "ESO DETMON SATURATION");
446 cpl_propertylist_copy_property(applist, limage->plist,
447 "ESO DARK GAIN");
448 cpl_propertylist_update_string(applist, "PRODCATG", "ANCILLARY.IMAGE");
449
450 /* set RA, DEC from WCS rather than let dfs copy it from another
451 frame. This only in case of input data in 'single' format, that means NAXIS=2 */
452
453 int naxis = cpl_propertylist_get_int(limage->plist,"NAXIS");
454 if(naxis == 2)
455 {
456 cpl_wcs * wcs = cpl_wcs_new_from_propertylist(limage->plist);
457 double ra = 0.0;
458 double dec = 0.0;
459 enu_get_ra_dec(wcs, &ra, &dec);
460
461 cpl_propertylist_update_double(applist, "RA", ra);
462 cpl_propertylist_update_double(applist, "DEC", dec);
463
464 cpl_wcs_delete(wcs);
465 }
466
467 /* generate name of output file, write file */
468
469 char * out_fname = enu_repreface(cpl_frame_get_filename(limage->frame),
470 "cal_det");
471
472 /* save the result */
473
474 enu_dfs_save_limage(frameset,
475 parlist,
476 provenance,
477 CPL_TRUE,
478 limage,
479 recipe_name,
480 limage->frame,
481 applist,
482 PACKAGE "/" PACKAGE_VERSION,
483 out_fname);
484
485 cpl_free(out_fname);
486 cpl_frameset_delete(provenance);
487 cpl_propertylist_delete(applist);
488 return cpl_error_get_code();
489}
490
491
492static char*
493eris_nix_update_pupil_pro_catg(const char* pro_catg, located_image * limage)
494{
495 char* new_pro_catg=NULL;
496 char* suffix=NULL;
497 const char* nxpw = NULL;
498 if(cpl_propertylist_has(limage->plist, "ESO INS2 NXPW NAME")) {
499 nxpw = cpl_propertylist_get_string(limage->plist, "ESO INS2 NXPW NAME");
500 }
501
502 if(strcmp(nxpw, "Open1") == 0){
503 suffix = cpl_sprintf("OPEN");
504 } else if (strcmp(nxpw, "JHK-pupil") == 0){
505 suffix = cpl_sprintf("JHK");
506 } else if (strcmp(nxpw, "Crosshairs") == 0){
507 suffix = cpl_sprintf("CROSS");
508 } else if (strcmp(nxpw, "APP") == 0){
509 suffix = cpl_sprintf("APP");
510 } else if (strcmp(nxpw, "LM-pupil") == 0){
511 suffix = cpl_sprintf("LM");
512 } else if (strcmp(nxpw, "Lyot") == 0){
513 suffix = cpl_sprintf("LYOT");
514 } else if (strcmp(nxpw, "Lyot-ND") == 0){
515 suffix = cpl_sprintf("LYOTND");
516 } else if (strstr(nxpw, "SAM")){
517 suffix = cpl_sprintf("SAM");
518 } else if (strstr(nxpw, "Spider")){
519 suffix = cpl_sprintf("SPIDER");
520 } else {
521 cpl_msg_warning(cpl_func,"%s",nxpw);
522 suffix = cpl_sprintf("NOT_SUPPORTED");
523 }
524
525 //AMO: check the following if check: result is the same
526 if(strcmp(nxpw, "Open1") == 0 || strcmp(nxpw, "ND") == 0) {
527 new_pro_catg = cpl_sprintf("%s_%s", pro_catg, suffix);
528 } else {
529 new_pro_catg = cpl_sprintf("%s_%s", pro_catg, suffix);
530 }
531
532 cpl_free(suffix);
533 return new_pro_catg;
534}
535
536/*----------------------------------------------------------------------------*/
549/*----------------------------------------------------------------------------*/
550
551
552cpl_error_code eris_nix_scired_cal_det(cpl_frameset * frameset,
553 const cpl_parameterlist * parlist,
554 const char* recipe_name,
555 const char* context) {
556
557 cpl_frameset * base_frames = NULL;
558 gain_linearity * gain_lin = NULL;
559 located_image * limage = NULL;
560 master_bpm * master_bpm_used = NULL;
561 master_bpm * master_bpm_lamp = NULL;
562 master_bpm * master_bpm_sky = NULL;
563 master_dark * master_drk = NULL;
564 master_flat * master_flat_hifreq = NULL;
565 master_flat * master_flat_lofreq = NULL;
566 const cpl_parameter * p = NULL;
567 char * param_name = NULL;
568 cpl_table * refine_wcs = NULL;
569 cpl_image * copyconf = NULL;
570
571 enu_check_error_code("%s():%d: An error is already set: %s",
572 cpl_func, __LINE__, cpl_error_get_where());
573
574 /* Check input parameters */
575
576 cpl_ensure_code(frameset, CPL_ERROR_NULL_INPUT);
577 cpl_ensure_code(parlist, CPL_ERROR_NULL_INPUT);
578
579 /* Set the msg verbosity level from environment variable CPL_MSG_LEVEL */
580 /* check for invalid input */
581 if(eris_files_dont_exist(frameset) != CPL_ERROR_NONE) {
582 return CPL_ERROR_BAD_FILE_FORMAT;
583 }
584
585 cpl_msg_set_level_from_env();
586
587 /* check required input tags are present */
588 const int nfile_tags = 4;
589 const char* required_tags[4] = {ERIS_NIX_NL_BPM_PRO_CATG,
590 ERIS_NIX_COEFFS_CUBE_PRO_CATG,
591 ERIS_NIX_GAIN_PRO_CATG,
592// opt ERIS_NIX_MASTER_BPM_LAMP_PRO_CATG,
593 ERIS_NIX_MASTER_DARK_IMG_PRO_CATG
594// opt ERIS_NIX_MASTER_FLAT_LAMP_HIFREQ_PRO_CATG,
595// opt ERIS_NIX_MASTER_FLAT_LAMP_LOFREQ_PRO_CATG, // opt
596// opt ERIS_NIX_MASTER_FLAT_TWILIGHT_LOFREQ_PRO_CATG, //opt
597// opt ERIS_NIX_RAW_OBJECT_JITTER_DO_CATG,
598// opt ERIS_NIX_WCS_REFINE_PRO_CATG
599 };
600
601 cpl_ensure_code(CPL_ERROR_NONE ==
602 eris_dfs_check_input_tags(frameset, required_tags, nfile_tags, 1),
603 CPL_ERROR_ILLEGAL_INPUT);
604
605 /* Read parameters */
606
607 param_name = cpl_sprintf("%s.fill-rejected", context);
608 p = cpl_parameterlist_find_const(parlist, param_name);
609 const char * fill_rejected = cpl_parameter_get_string(p);
610 cpl_free(param_name);
611
612 param_name = cpl_sprintf("%s.fill-value", context);
613 p = cpl_parameterlist_find_const(parlist, param_name);
614 const double fill_value = cpl_parameter_get_double(p);
615 cpl_free(param_name);
616
617 param_name = cpl_sprintf("%s.cd_matrix_modify", context);
618 p = cpl_parameterlist_find_const(parlist, param_name);
619 const int cd_matrix_modify = cpl_parameter_get_bool(p);
620 cpl_free(param_name);
621
622 param_name = cpl_sprintf("%s.x_probe", context);
623 p = cpl_parameterlist_find_const(parlist, param_name);
624 cpl_size x_probe = (cpl_size) cpl_parameter_get_int(p);
625 cpl_free(param_name);
626
627 param_name = cpl_sprintf("%s.y_probe", context);
628 p = cpl_parameterlist_find_const(parlist, param_name);
629 cpl_size y_probe = (cpl_size) cpl_parameter_get_int(p);
630 cpl_free(param_name);
631
632 param_name = cpl_sprintf("%s.collapse_cube", context);
633 p = cpl_parameterlist_find_const(parlist, param_name);
634 cpl_size collapse_cube = (cpl_size) cpl_parameter_get_int(p);
635 cpl_free(param_name);
636
637 enu_check_error_code("Could not retrieve input parameters");
638
639 /* Identify the RAW and CALIB frames in the input frameset */
640
641 eris_nix_dfs_set_groups(frameset);
642 enu_check_error_code("Could not identify RAW and CALIB frames");
643
644 base_frames = cpl_frameset_new();
645
646 /* read the gain and linearity information. This is required
647 as the linearization process changes the data units to
648 electrons/sec which is assumed later for the photometric
649 calibration*/
650
651 int required = CPL_TRUE;
652 gain_lin = engl_gain_linearity_load_from_frameset(frameset,
653 ERIS_NIX_GAIN_PRO_CATG, ERIS_NIX_COEFFS_CUBE_PRO_CATG,
654 ERIS_NIX_NL_BPM_PRO_CATG, required, base_frames);
655 enu_check_error_code("failed to read gain/linearity information from SoF");
656
657 /* read the master_dark */
658
659 master_drk = en_master_dark_load_from_frameset(frameset,
660 ERIS_NIX_MASTER_DARK_IMG_PRO_CATG, base_frames);
661 enu_check_error_code("failed to read master dark from SoF");
662
663 /* read the master_bpm
664 ..there is a choice between sky bpm/flatfield or lamp bpm/flatfield
665 ..detect that choice here by the bpm used */
666
667 master_bpm_lamp = en_master_bpm_load_from_frameset(frameset,
668 ERIS_NIX_MASTER_BPM_LAMP_PRO_CATG,
669 base_frames, CPL_FALSE);
670 if (!master_bpm_lamp) {
671 master_bpm_sky = en_master_bpm_load_from_frameset(frameset,
672 ERIS_NIX_MASTER_BPM_SKY_PRO_CATG, base_frames,
673 CPL_FALSE);
674
675 }
676 enu_check_error_code("failed to read master BPM from SoF");
677 enu_check(master_bpm_lamp || master_bpm_sky, CPL_ERROR_ILLEGAL_INPUT,
678 "SoF contains neither lamp nor sky BPM");
679 enu_check(!(master_bpm_lamp && master_bpm_sky), CPL_ERROR_ILLEGAL_INPUT,
680 "SoF contains both lamp and sky BPM");
681 if (master_bpm_lamp) {
682 cpl_msg_info(cpl_func, "lamp bpm read");
683 master_bpm_used = master_bpm_lamp;
684 }
685 if (master_bpm_sky) {
686 cpl_msg_info(cpl_func, "sky bpm read");
687 master_bpm_used = master_bpm_sky;
688 }
689
690 /* read the high-freq flatfield (optional) */
691
692 if (master_bpm_lamp) {
693 master_flat_hifreq = en_master_flat_load_from_frameset(frameset,
694 ERIS_NIX_MASTER_FLAT_LAMP_HIFREQ_PRO_CATG,
695 base_frames, CPL_FALSE);
696 if (master_flat_hifreq) {
697 cpl_msg_info(cpl_func, "lamp hifreq flat read");
698 }
699 } else {
700 master_flat_hifreq = en_master_flat_load_from_frameset(frameset,
701 ERIS_NIX_MASTER_FLAT_SKY_HIFREQ_PRO_CATG,
702 base_frames, CPL_FALSE);
703 if (master_flat_hifreq) {
704 cpl_msg_info(cpl_func, "sky hifreq flat read");
705 }
706 }
707
708 if (master_bpm_lamp) {
709 /* read the low-freq flatfield (twilight preferred, optional) */
710
711 master_flat_lofreq = en_master_flat_load_from_frameset(frameset,
712 ERIS_NIX_MASTER_FLAT_TWILIGHT_LOFREQ_PRO_CATG,
713 base_frames, CPL_FALSE);
714 if(master_flat_lofreq) {
715 cpl_msg_info(cpl_func, "twilight lofreq flat read");
716 } else {
717 master_flat_lofreq = en_master_flat_load_from_frameset(frameset,
718 ERIS_NIX_MASTER_FLAT_LAMP_LOFREQ_PRO_CATG,
719 base_frames, CPL_FALSE);
720 if(master_flat_lofreq) {
721 cpl_msg_info(cpl_func, "lamp lofreq flat read");
722 }
723 }
724 }
725 if (master_bpm_sky) {
726 master_flat_lofreq = en_master_flat_load_from_frameset(frameset,
727 ERIS_NIX_MASTER_FLAT_SKY_LOFREQ_PRO_CATG,
728 base_frames, CPL_FALSE);
729 if(master_flat_lofreq) {
730 cpl_msg_info(cpl_func, "sky lofreq flat read");
731 }
732 }
733
734 /* load wcs refinement table if required */
735
736 if (cd_matrix_modify) {
737 const cpl_frame * target_frame = cpl_frameset_find_const(
738 frameset,
739 ERIS_NIX_WCS_REFINE_PRO_CATG);
740 enu_check(target_frame != NULL, CPL_ERROR_DATA_NOT_FOUND,
741 "SoF has no file tagged %s", ERIS_NIX_WCS_REFINE_PRO_CATG);
742
743 refine_wcs = cpl_table_load(cpl_frame_get_filename(target_frame),
744 1, CPL_TRUE);
745 if (refine_wcs) {
746 cpl_msg_info(cpl_func, "wcs refinement table read:");
747 cpl_table_dump(refine_wcs, 0, 100, NULL);
748 }
749 }
750
751 const char * datatags[] = {
752 ERIS_NIX_RAW_OBJECT_JITTER_DO_CATG,
753 ERIS_NIX_RAW_SKY_JITTER_DO_CATG,
754 ERIS_NIX_RAW_STD_JITTER_DO_CATG,
755 ERIS_NIX_RAW_OBJECT_LSS_JITTER_DO_CATG,
756 ERIS_NIX_RAW_SKY_LSS_JITTER_DO_CATG,
757 ERIS_NIX_RAW_STD_LSS_JITTER_DO_CATG,
758 ERIS_NIX_RAW_STD_APP_DO_CATG,
759 ERIS_NIX_RAW_STD_FPC_DO_CATG,
760 ERIS_NIX_RAW_STD_SAM_DO_CATG,
761 ERIS_NIX_RAW_OBJECT_APP_DO_CATG,
762 ERIS_NIX_RAW_OBJECT_FPC_DO_CATG,
763 ERIS_NIX_RAW_OBJECT_SAM_DO_CATG,
764 ERIS_NIX_RAW_SKY_FPC_DO_CATG,
765 ERIS_NIX_RAW_SKY_APP_DO_CATG,
766 ERIS_NIX_RAW_PUPIL_LAMP_DO_CATG,
767 ERIS_NIX_RAW_PUPIL_SKY_DO_CATG,
768 ERIS_NIX_RAW_PUPIL_BKG_DO_CATG,
769 ERIS_NIX_RAW_PUPIL_DARK_DO_CATG
770 };
771 cpl_size ntags = sizeof(datatags) / sizeof(const char *);
772 const char * protags[] = {
773 ERIS_NIX_CAL_DET_OBJECT_JITTER_PRO_CATG,
774 ERIS_NIX_CAL_DET_SKY_JITTER_PRO_CATG,
775 ERIS_NIX_CAL_DET_STD_JITTER_PRO_CATG,
776 ERIS_NIX_CAL_DET_OBJECT_LSS_JITTER_PRO_CATG,
777 ERIS_NIX_CAL_DET_SKY_LSS_JITTER_PRO_CATG,
778 ERIS_NIX_CAL_DET_STD_LSS_JITTER_PRO_CATG,
779 ERIS_NIX_CAL_DET_STD_APP_PRO_CATG,
780 ERIS_NIX_CAL_DET_STD_FPC_PRO_CATG,
781 ERIS_NIX_CAL_DET_STD_SAM_PRO_CATG,
782 ERIS_NIX_CAL_DET_OBJECT_APP_PRO_CATG,
783 ERIS_NIX_CAL_DET_OBJECT_FPC_PRO_CATG,
784 ERIS_NIX_CAL_DET_OBJECT_SAM_PRO_CATG,
785 ERIS_NIX_CAL_DET_SKY_APP_PRO_CATG,
786 ERIS_NIX_CAL_DET_SKY_FPC_PRO_CATG,
787 ERIS_NIX_CAL_DET_PUPIL_LAMP_PRO_CATG,
788 ERIS_NIX_CAL_DET_PUPIL_SKY_PRO_CATG,
789 ERIS_NIX_CAL_DET_PUPIL_BKG_PRO_CATG,
790 ERIS_NIX_CAL_DET_PUPIL_DARK_PRO_CATG
791 };
792 cpl_size nprotags = sizeof(protags) / sizeof(const char *);
793 cpl_msg_debug(cpl_func,"ntags: %lld nprotags: %lld",ntags,nprotags);
794 enu_check(ntags == nprotags, CPL_ERROR_UNSPECIFIED, "programming error");
795
796 /* Loop through the possible data tags */
797
798 for (cpl_size itag = 0; itag < ntags; itag++) {
799
800 /* handle each frame individually. Ones taken in cube mode can
801 be large, and there is no need to read them together */
802
803 cpl_frameset_iterator * frameset_iter = cpl_frameset_iterator_new(frameset);
804 for (cpl_size iframe = 0; iframe < cpl_frameset_get_size(frameset);
805 iframe++) {
806
807 cpl_frame * frame = cpl_frameset_iterator_get(frameset_iter);
808 if (!strcmp(datatags[itag], cpl_frame_get_tag(frame))) {
809 cpl_msg_info(cpl_func, "processing %s", cpl_frame_get_filename(frame));
810
811 limage = enu_load_limage_from_frame(frame, &copyconf, collapse_cube);
812 enu_check_error_code("failed to read data to calibrate");
813 if (limage && limage->confidence) {
814 cpl_image_delete(copyconf);
815 copyconf = cpl_image_duplicate(limage->confidence);
816 }
817
818 /* check that the jitter has reasonable WCS keywords
819 (i.e. non-zero) - early commissioning data suffered from this */
820
821 //AMO: TODO is the following check really needed?
822 if(strcmp(cpl_frame_get_tag(frame), "PUPIL_LAMP") ){
823 //enu_check_wcs(limage);
824 }
825
826 /* Do 'detector calibration': dark subtraction, linearize,
827 calculate error plane, flatfield, associate with bpm */
828
829 int remove_read_offsets = CPL_TRUE;
830 int flag_mask = 0;
831 flag_mask = ~flag_mask;
832
833 enu_basic_calibrate(limage,
834 remove_read_offsets,
835 refine_wcs,
836 master_drk,
837 gain_lin,
838 master_flat_hifreq,
839 master_flat_lofreq,
840 master_bpm_used,
841 flag_mask,
842 fill_rejected,
843 fill_value,
844 x_probe,
845 y_probe);
846 enu_check_error_code("error performing detector calibration of frames");
847
848 /* handle pupil data */
849 char* pro_catg = NULL;
850
851 if(strstr(protags[itag],"PUPIL")) {
852 pro_catg = eris_nix_update_pupil_pro_catg(protags[itag],limage);
853 } else {
854 pro_catg = cpl_sprintf("%s",protags[itag]);
855 }
856
857 /* save the calibrated image to FITS */
858 eris_nix_cal_det_save(limage,
859 pro_catg,
860 frameset,
861 parlist,
862 base_frames,
863 recipe_name);
864
865 enu_check_error_code("error saving frame");
866
868 limage = NULL;
869 if(pro_catg) {
870 cpl_free(pro_catg);
871 }
872 }
873 cpl_frameset_iterator_advance(frameset_iter, 1);
874 }
875 cpl_frameset_iterator_delete(frameset_iter);
876 }
877
878cleanup:
879 cpl_image_delete(copyconf);
880 cpl_frameset_delete(base_frames);
881 engl_gain_linearity_delete(gain_lin);
883 en_master_bpm_delete(master_bpm_lamp);
884 en_master_bpm_delete(master_bpm_sky);
885 en_master_dark_delete(master_drk);
886 en_master_flat_delete(master_flat_hifreq);
887 en_master_flat_delete(master_flat_lofreq);
888 cpl_table_delete(refine_wcs);
889
890 return cpl_error_get_code();
891}
892
893/*----------------------------------------------------------------------------*/
910/*----------------------------------------------------------------------------*/
911
912static cpl_error_code eris_nix_img_sky_objmask(
913 const char* recipe_name,
914 const char* context,
915 const located_imagelist * jitters,
916 const char * sky_selector,
917 const double sky_time_range,
918 const char * sky_method,
919 const int debug_data,
920 const char * debug_preface,
921 cpl_frameset * frameset,
922 const cpl_parameterlist * parlist,
923 const cpl_frameset * used_frameset,
924 const cpl_size x_probe,
925 const cpl_size y_probe,
926 located_imagelist ** objmask_jitters) {
927
928 if (cpl_error_get_code() != CPL_ERROR_NONE) return cpl_error_get_code();
929
930 located_imagelist * jitters1 = NULL;
931 located_imagelist * jitters2 = NULL;
932 const cpl_parameter * p = NULL;
933 char* param_name = NULL;
934
935 /* We only need a subset of catalogue parameters but they are not defined
936 outside of hdrl - so re-read them here */
937
938 param_name = cpl_sprintf("%s.catalogue.obj.min-pixels", context);
939 p = cpl_parameterlist_find_const(parlist, param_name);
940 int obj_min_pixels = cpl_parameter_get_int(p);
941 cpl_free(param_name);
942
943 param_name = cpl_sprintf("%s.catalogue.obj.threshold", context);
944 p = cpl_parameterlist_find_const(parlist, param_name);
945 double obj_threshold = cpl_parameter_get_double(p);
946 cpl_free(param_name);
947
948 /* use AOMODE to decide if set catalogue.core-radius and mesh-size to
949 defaults or read them from parameters */
950
951 double obj_core_radius = -1.0;
952 int bkg_mesh_size = -1;
954 parlist,
955 jitters->limages[0]->plist,
956 &obj_core_radius,
957 &bkg_mesh_size);
958
959 param_name = cpl_sprintf("%s.catalogue.bkg.smooth-gauss-fwhm", context);
960 p = cpl_parameterlist_find_const(parlist, param_name);
961 double bkg_smooth_fwhm = cpl_parameter_get_double(p);
962 cpl_free(param_name);
963
964 /* Estimate and subtract the sky background with no objmasks */
965
966 jitters1 = enu_located_imagelist_duplicate(jitters);
967 cpl_msg_info(cpl_func, "Estimating sky background with no source blanking ...");
968 enu_sky_subtract_limlist(sky_method, sky_selector, sky_time_range,
969 jitters1, x_probe, y_probe, jitters1);
970 enu_check_error_code("error in sky_objmask: sky estimation");
971
972 /* derive object masks for each image */
973
974 enu_opm_limlist(obj_min_pixels, obj_threshold, bkg_mesh_size,
975 bkg_smooth_fwhm, jitters1);
976 enu_check_error_code("error in sky_objmask: deriving object mask");
977
978 /* in debug mode, save the sky-subtracted images */
979
980 char * preface = cpl_sprintf("%s_%s", debug_preface, "sky1");
981 enu_debug_limlist_save(debug_data, jitters1, preface, recipe_name,
982 frameset, parlist, used_frameset);
983 cpl_free(preface);
984 enu_check_error_code("error in sky_objmask: saving debug data");
985
986 /* Return a copy the raw jitter data with objmasks attached */
987
988 jitters2 = enu_located_imagelist_duplicate(jitters);
989 for (cpl_size j = 0; j < jitters2->size; j++) {
990 jitters2->limages[j]->object_mask = cpl_mask_duplicate(jitters1->
991 limages[j]->object_mask);
992 }
993
994 cleanup:
995
997 if (cpl_error_get_code() == CPL_ERROR_NONE) {
998 *objmask_jitters = jitters2;
999 } else {
1001 }
1002
1003 return cpl_error_get_code();
1004}
1005
1006/*----------------------------------------------------------------------------*/
1020/*----------------------------------------------------------------------------*/
1021
1022
1023cpl_error_code eris_nix_scired_skysub(cpl_frameset * frameset,
1024 const cpl_parameterlist * parlist,
1025 const char* recipe_name,
1026 const char* context) {
1027
1028 located_imagelist * object_jitters = NULL;
1029 located_imagelist * objmask_jitters = NULL;
1030 located_imagelist * objmask_sky_jitters = NULL;
1031 const char * out_tag = NULL;
1032 const cpl_parameter * p = NULL;
1033 located_imagelist * result_jitters = NULL;
1034 located_imagelist * skysub_jitters = NULL;
1035 located_imagelist * sky_jitters = NULL;
1036 located_imagelist * std_jitters = NULL;
1037 located_imagelist * target_jitters = NULL;
1038 cpl_frameset * used_frameset = NULL;
1039 char * param_name = NULL;
1040
1041 enu_check_error_code("%s():%d: An error is already set: %s",
1042 cpl_func, __LINE__, cpl_error_get_where());
1043
1044 /* Check input parameters */
1045
1046 cpl_ensure_code(frameset, CPL_ERROR_NULL_INPUT);
1047 cpl_ensure_code(parlist, CPL_ERROR_NULL_INPUT);
1048
1049 /* Set the msg verbosity level from environment variable CPL_MSG_LEVEL
1050 - not working, so set manually for now */
1051
1052 cpl_msg_set_level_from_env();
1053 cpl_msg_severity severity = cpl_msg_get_level();
1054 cpl_msg_info(cpl_func, "level %d", (int) severity);
1055
1056 /* check for invalid input */
1057 if(eris_files_dont_exist(frameset) != CPL_ERROR_NONE) {
1058 return CPL_ERROR_BAD_FILE_FORMAT;
1059 }
1060
1061 /* Retrieve input parameters */
1062 param_name = cpl_sprintf("%s.sky-source", context);
1063 p = cpl_parameterlist_find_const(parlist, param_name);
1064 const char * sky_source = cpl_parameter_get_string(p);
1065 cpl_free(param_name);
1066
1067 param_name = cpl_sprintf("%s.sky-selector", context);
1068 p = cpl_parameterlist_find_const(parlist, param_name);
1069 const char * sky_selector = cpl_parameter_get_string(p);
1070 cpl_free(param_name);
1071
1072 param_name = cpl_sprintf("%s.sky-method", context);
1073 p = cpl_parameterlist_find_const(parlist, param_name);
1074 const char * sky_method = cpl_parameter_get_string(p);
1075 cpl_free(param_name);
1076
1077 param_name = cpl_sprintf("%s.sky-bracket-time", context);
1078 p = cpl_parameterlist_find_const(parlist, param_name);
1079 const double sky_time_range = cpl_parameter_get_double(p);
1080 cpl_free(param_name);
1081
1082 param_name = cpl_sprintf("%s.debug-data", context);
1083 p = cpl_parameterlist_find_const(parlist, param_name);
1084 const int debug_data = cpl_parameter_get_bool(p);
1085 cpl_free(param_name);
1086
1087 param_name = cpl_sprintf("%s.x_probe", context);
1088 p = cpl_parameterlist_find_const(parlist, param_name);
1089 cpl_size x_probe = (cpl_size) cpl_parameter_get_int(p);
1090 cpl_free(param_name);
1091
1092 param_name = cpl_sprintf("%s.y_probe", context);
1093 p = cpl_parameterlist_find_const(parlist, param_name);
1094 cpl_size y_probe = (cpl_size) cpl_parameter_get_int(p);
1095 cpl_free(param_name);
1096
1097 enu_check_error_code("Could not retrieve input parameters");
1098
1099 /* Identify the RAW and CALIB frames in the input frameset */
1100
1101 eris_nix_dfs_set_groups(frameset);
1102 enu_check_error_code("Could not identify RAW and CALIB frames");
1103
1104 used_frameset = cpl_frameset_new();
1105
1106 /* Read in CAL_DET_OBJECT_JITTER data, CAL_DET_SKY_JITTER, or
1107 CAL_DET_STD_JITTER frames if present */
1108
1109 object_jitters = enu_limlist_load_from_frameset(frameset,
1110 ERIS_NIX_CAL_DET_OBJECT_JITTER_PRO_CATG, used_frameset);
1111 enu_check_error_code("Could not load "
1112 ERIS_NIX_CAL_DET_OBJECT_JITTER_PRO_CATG" frames");
1113 sky_jitters = enu_limlist_load_from_frameset(frameset,
1114 ERIS_NIX_CAL_DET_SKY_JITTER_PRO_CATG, used_frameset);
1115 enu_check_error_code("Could not load "
1116 ERIS_NIX_CAL_DET_SKY_JITTER_PRO_CATG" frames");
1117 std_jitters = enu_limlist_load_from_frameset(frameset,
1118 ERIS_NIX_CAL_DET_STD_JITTER_PRO_CATG, used_frameset);
1119 enu_check_error_code("Could not load "
1120 ERIS_NIX_CAL_DET_STD_JITTER_PRO_CATG" frames");
1121
1122 cpl_msg_info(cpl_func, "%d "
1123 ERIS_NIX_CAL_DET_OBJECT_JITTER_PRO_CATG" frames read",
1124 (int) object_jitters->size);
1125 cpl_msg_info(cpl_func, "%d "
1126 ERIS_NIX_CAL_DET_SKY_JITTER_PRO_CATG" frames read",
1127 (int) sky_jitters->size);
1128 cpl_msg_info(cpl_func, "%d "
1129 ERIS_NIX_CAL_DET_STD_JITTER_PRO_CATG" frames read",
1130 (int) std_jitters->size);
1131
1132 /* check that the SOF collection makes sense */
1133 if (object_jitters->size > 0 || std_jitters->size) {
1134 if(!strcmp(sky_source,"auto")) {
1135 /* OK */
1136 } else {
1137 if (sky_jitters->size > 0 || !strcmp(sky_source,"target")) {
1138 /* OK */
1139 } else {
1140 cpl_msg_error(cpl_func,"sky_source: %s, but missing input sky frames. Exit!", sky_source);
1141 return CPL_ERROR_DATA_NOT_FOUND;
1142 }
1143 }
1144 } else {
1145 cpl_msg_error(cpl_func,"Missing input object frames. Exit!");
1146 return CPL_ERROR_DATA_NOT_FOUND;
1147 }
1148
1149 enu_check(!(object_jitters->size == 0 && std_jitters->size == 0),
1150 CPL_ERROR_DATA_NOT_FOUND, "SoF contains no "
1151 ERIS_NIX_CAL_DET_OBJECT_JITTER_PRO_CATG" or "
1152 ERIS_NIX_CAL_DET_STD_JITTER_PRO_CATG" frames");
1153 enu_check(!(object_jitters->size > 0 && std_jitters->size > 0),
1154 CPL_ERROR_ILLEGAL_INPUT, "SoF contains both "
1155 ERIS_NIX_CAL_DET_OBJECT_JITTER_PRO_CATG" and "
1156 ERIS_NIX_CAL_DET_STD_JITTER_PRO_CATG" frames");
1157 enu_check(!(!strcmp(sky_source,"offset") && sky_jitters->size==0),
1158 CPL_ERROR_INCOMPATIBLE_INPUT,
1159 "offset sky position requested but no"
1160 ERIS_NIX_CAL_DET_SKY_JITTER_PRO_CATG" in sof");
1161
1162 /* is target an object or std? */
1163
1164 if (object_jitters->size > 0) {
1165 target_jitters = object_jitters;
1166 out_tag = ERIS_NIX_SKYSUB_OBJECT_JITTER_PRO_CATG;
1167 enu_located_imagelist_delete(std_jitters);
1168 std_jitters = NULL;
1169 } else if (std_jitters->size > 0) {
1170 target_jitters = std_jitters;
1171 out_tag = ERIS_NIX_SKYSUB_STD_JITTER_PRO_CATG;
1172 enu_located_imagelist_delete(object_jitters);
1173 object_jitters = NULL;
1174 }
1175
1176 for (cpl_size j=0; j<target_jitters->size; j++) {
1177 double temp = cpl_propertylist_get_double(target_jitters->limages[j]->plist, "RA");
1178 const char * nm = cpl_frame_get_filename(target_jitters->limages[j]->frame);
1179 cpl_msg_info(cpl_func, "%s %f %s", nm, temp, cpl_error_get_message());
1180 }
1181
1182 /* do right thing when sky-source=="auto", namely use offset
1183 sky data if available */
1184
1185 if (!strcmp(sky_source, "auto")) {
1186 if (sky_jitters->size > 0) {
1187 sky_source = "offset";
1188 } else {
1189 sky_source = "target";
1190 }
1191 cpl_msg_info(cpl_func, "sky-source=='auto', resetting to '%s'",
1192 sky_source);
1193 }
1194
1195 if (!strcmp(sky_source, "offset")) {
1196 if (sky_jitters->size > 1) {
1197
1198 /* Calculate object masks for the 'offset' jitter images */
1199
1200 eris_nix_img_sky_objmask(recipe_name, context, sky_jitters,
1201 sky_selector, sky_time_range,
1202 sky_method,
1203 debug_data, "offset",
1204 frameset, parlist, used_frameset,
1205 x_probe, y_probe,
1206 &objmask_sky_jitters);
1207
1208 /* Use the masked images to estimate the sky background and
1209 subtract it */
1210
1211 cpl_msg_info(cpl_func,
1212 "Estimating sky background with source blanking ...");
1213 enu_sky_subtract_limlist(sky_method, sky_selector,
1214 sky_time_range, objmask_sky_jitters,
1215 x_probe, y_probe,
1216 target_jitters);
1217 enu_check_error_code("error in sky background subtraction");
1218
1219 char * preface = cpl_sprintf("%s_%s", "offset", "sky2");
1220 enu_debug_limlist_save(debug_data, target_jitters, preface,
1221 recipe_name, frameset, parlist,
1222 used_frameset);
1223 cpl_free(preface);
1224 result_jitters = target_jitters;
1225
1226 } else {
1227
1228 /* There is only one sky image. Can't think of ways to improve
1229 it so just use the direct image as the sky background and
1230 subtract it */
1231
1232 cpl_msg_info(cpl_func,
1233 "Using sky-offset image as background ...");
1234 enu_sky_subtract_limlist(sky_method, sky_selector,
1235 sky_time_range, sky_jitters,
1236 x_probe, y_probe,
1237 target_jitters);
1238 enu_check_error_code("error in sky background subtraction");
1239
1240 char * preface = cpl_sprintf("%s_%s", "offset", "sky2");
1241 enu_debug_limlist_save(debug_data, target_jitters, preface,
1242 recipe_name, frameset, parlist,
1243 used_frameset);
1244 cpl_free(preface);
1245 result_jitters = target_jitters;
1246 }
1247
1248 } else if (!strcmp(sky_source, "target")) {
1249
1250 /* Calculate object masks for the target jitter images
1251 and attach them the data */
1252
1253 eris_nix_img_sky_objmask(recipe_name, context, target_jitters,
1254 sky_selector, sky_time_range,
1255 sky_method,
1256 debug_data, "target",
1257 frameset, parlist, used_frameset,
1258 x_probe, y_probe,
1259 &objmask_jitters);
1260
1261 /* Use the masked images to estimate the sky background and
1262 subtract it */
1263
1264 cpl_msg_info(cpl_func, "Estimating sky background with source blanking ...");
1265 enu_sky_subtract_limlist(sky_method, sky_selector, sky_time_range,
1266 objmask_jitters, x_probe, y_probe,
1267 objmask_jitters);
1268 enu_check_error_code("error in sky background subtraction");
1269
1270 char * preface = cpl_sprintf("%s_%s", "target", "sky2");
1271 enu_debug_limlist_save(debug_data, objmask_jitters, preface,
1272 recipe_name, frameset, parlist,
1273 used_frameset);
1274 cpl_free(preface);
1275 result_jitters = objmask_jitters;
1276 }
1277
1278 enu_check_error_code("failed to remove sky background");
1279
1280 /* save the sky-subtracted jitter images to FITS files */
1281
1282 for (cpl_size i = 0; i < result_jitters->size; i++) {
1283
1284 /* add necessary things to output header. RA and DEC are needed as
1285 would otherwise be overwritten by DFS */
1286 cpl_propertylist * applist = cpl_propertylist_new();
1287 cpl_propertylist_update_string(applist, CPL_DFS_PRO_CATG, out_tag);
1288 cpl_propertylist_update_string(applist, "PRODCATG",
1289 "ANCILLARY.IMAGE");
1290 cpl_propertylist_copy_property_regexp(applist,
1291 result_jitters->limages[i]->plist,
1292 "RA|DEC",
1293 CPL_FALSE);
1294
1295 /* set RA, DEC from WCS rather than let dfs copy it from ano†her
1296 frame */
1297
1298 {
1299 cpl_wcs * wcs = cpl_wcs_new_from_propertylist(
1300 result_jitters->limages[i]->plist);
1301 double ra = 0.0;
1302 double dec = 0.0;
1303 enu_get_ra_dec(wcs, &ra, &dec);
1304
1305 cpl_propertylist_update_double(applist, "RA", ra);
1306 cpl_propertylist_update_double(applist, "DEC", dec);
1307
1308 cpl_wcs_delete(wcs);
1309 }
1310
1311 /* Generate output file name and write the file */
1312
1313 char * out_fname = enu_repreface(cpl_frame_get_filename(
1314 result_jitters->limages[i]->
1315 frame),
1316 "skysub");
1317
1318 enu_dfs_save_limage(frameset,
1319 parlist,
1320 used_frameset,
1321 CPL_TRUE,
1322 result_jitters->limages[i],
1323 recipe_name,
1324 result_jitters->limages[i]->frame,
1325 applist,
1326 PACKAGE "/" PACKAGE_VERSION,
1327 out_fname);
1328
1329 cpl_free(out_fname);
1330 cpl_propertylist_delete(applist);
1331 }
1332
1333 cleanup:
1334 enu_located_imagelist_delete(object_jitters);
1335 enu_located_imagelist_delete(objmask_jitters);
1336 enu_located_imagelist_delete(skysub_jitters);
1337 enu_located_imagelist_delete(sky_jitters);
1338 enu_located_imagelist_delete(std_jitters);
1339 cpl_frameset_delete(used_frameset);
1340
1341 return (int) cpl_error_get_code();
1342}
1343
1344static cpl_error_code
1345eris_nix_scired_get_split_param_int(const cpl_parameterlist * parlist,
1346 const char* context, const char* pname, const int min_x, const int min_y,
1347 const int max_x, const int max_y,
1348 cpl_size* txmin, cpl_size* tymin, cpl_size* txmax, cpl_size* tymax)
1349{
1350
1351 const cpl_parameter* par = NULL;
1352 char* param_name;
1353
1354
1355 const char* pname_string_value;
1356 param_name = cpl_sprintf("%s.%s", context, pname);
1357 par = cpl_parameterlist_find_const(parlist, param_name);
1358 pname_string_value = cpl_parameter_get_string(par);
1359 cpl_free(param_name);
1360
1361 int nFields;
1362 unsigned int end;
1363 *txmin = 0;
1364 *tymin = 0;
1365 *txmax = 0;
1366 *tymax = 0;
1367 cpl_msg_warning(cpl_func,"param value: %s", pname_string_value);
1368 nFields = sscanf(pname_string_value, "%lld,%lld,%lld,%lld%n", txmin, tymin, txmax, tymax, &end);
1369 cpl_msg_warning(cpl_func,"nFields:%d", nFields);
1370 cpl_msg_warning(cpl_func,"end:%d", end);
1371 if (nFields != 4 || end != strlen(pname_string_value)) {
1372 cpl_msg_error(cpl_func, "The %s parameter must be "
1373 "a list of four integers separated by a comma", pname);
1374 printf("Error reading sky-box-center string\n");
1375 }
1376
1377 if (*txmin < min_x) {
1378 cpl_msg_warning(cpl_func,"%s_x: %lld set it to 1",pname, *txmin);
1379 *txmin = 1;
1380 }
1381 if (*tymin < min_y) {
1382 cpl_msg_warning(cpl_func,"%s_y: %lld set it to 1",pname, *tymin);
1383 *tymin = 1;
1384 }
1385 if (*txmax > max_x) {
1386 cpl_msg_warning(cpl_func,"%s_x: %lld set it to 1",pname, *txmax);
1387 *txmax = 1;
1388 }
1389 if (*tymax > max_y) {
1390 cpl_msg_warning(cpl_func,"%s_y: %lld set it to 1", pname, *tymax);
1391 *tymax = 1;
1392 }
1393
1394 cpl_msg_debug(cpl_func,"%s_x: %lld, %s_y: %lld, %s_x: %lld, %s_y: %lld",
1395 pname, *txmin, pname, *tymin, pname, *txmax, pname, *tymax);
1396
1397 eris_check_error_code("eris_nix_scired_get_split_param_int");
1398 return cpl_error_get_code();
1399}
1400
1401/*----------------------------------------------------------------------------*/
1411/*----------------------------------------------------------------------------*/
1412
1413static cpl_error_code eris_nix_calculate_overlaps(
1414 const located_imagelist * jitters,
1415 cpl_matrix ** overlaps) {
1416
1417 /* Make table of jitter offsets relative to reference jitter, calculate
1418 the overlap of each jitter with the reference */
1419
1420 double pixsize = fabs(cpl_propertylist_get_double(jitters->limages[0]->
1421 plist, "CD1_1") * 3600.0);
1422
1423 cpl_size nrow = cpl_matrix_get_nrow(*overlaps);
1424
1425 for (cpl_size row=0; row < nrow; row++) {
1426 double ra_centre = cpl_propertylist_get_double(
1427 jitters->limages[row]->plist,
1428 "CRVAL1");
1429 double dec_centre = cpl_propertylist_get_double(
1430 jitters->limages[row]->plist,
1431 "CRVAL2");
1432
1433 for (cpl_size col = 0; col <= row; col++) {
1434 double ra = cpl_propertylist_get_double(
1435 jitters->limages[col]->plist,
1436 "CRVAL1");
1437 double dec = cpl_propertylist_get_double(
1438 jitters->limages[col]->plist,
1439 "CRVAL2");
1440 /* size of window if used */
1441 cpl_size nx = 2048;
1442 if (cpl_propertylist_has(jitters->limages[col]->plist,
1443 "ESO DET SEQ1 WIN NX")) {
1444 nx = cpl_propertylist_get_int(
1445 jitters->limages[col]->plist,
1446 "ESO DET SEQ1 WIN NX");
1447 }
1448 cpl_size ny = 2048;
1449 if (cpl_propertylist_has(jitters->limages[col]->plist,
1450 "ESO DET SEQ1 WIN NY")) {
1451 ny = cpl_propertylist_get_int(
1452 jitters->limages[col]->plist,
1453 "ESO DET SEQ1 WIN NY");
1454 }
1455// cpl_msg_info(cpl_func, "window %d %d %s", (int)nx, (int)ny,
1456// cpl_error_get_message());
1457
1458 /* calculate overlap with jitter index, -1 for no overlap */
1459
1460 double ra_size = nx * pixsize;
1461 double ra_shift = fabs(ra - ra_centre) * 3600.0;
1462 double ra_overlap = (ra_size - ra_shift) / ra_size;
1463
1464 double dec_size = ny * pixsize;
1465 double dec_shift = fabs(dec - dec_centre) * 3600.0;
1466 double dec_overlap = (dec_size - dec_shift) / dec_size;
1467
1468 double overlap = -1.0;
1469 if (ra_overlap > 0.0 && dec_overlap > 0.0) {
1470 overlap = ra_overlap * dec_overlap;
1471 }
1472
1473 cpl_matrix_set(*overlaps, row, col, overlap);
1474 cpl_matrix_set(*overlaps, col, row, overlap);
1475 }
1476 }
1477
1478 return cpl_error_get_code();
1479}
1480
1481
1482/*----------------------------------------------------------------------------*/
1494/*----------------------------------------------------------------------------*/
1495
1496static cpl_error_code eris_nix_report_table(
1497 const cpl_size ref,
1498 const located_imagelist * jitters,
1499 cpl_table ** report) {
1500
1501 /* Make table of jitter offsets relative to reference jitter, calculate
1502 the overlap of each jitter with the reference */
1503
1504 cpl_table_new_column(*report, "Index", CPL_TYPE_INT);
1505 cpl_table_new_column(*report, "RA offset", CPL_TYPE_DOUBLE);
1506 cpl_table_new_column(*report, "Dec offset", CPL_TYPE_DOUBLE);
1507 cpl_table_new_column(*report, "Reference", CPL_TYPE_INT);
1508 cpl_table_new_column(*report, "Overlap", CPL_TYPE_DOUBLE);
1509 cpl_table_new_column(*report, "WCS_METHOD", CPL_TYPE_STRING);
1510 cpl_table_new_column(*report, "Catalogue/File", CPL_TYPE_STRING);
1511 cpl_table_new_column(*report, "# matches", CPL_TYPE_INT);
1512
1513 double ra_centre = cpl_propertylist_get_double(
1514 jitters->limages[ref]->plist,
1515 "CRVAL1");
1516 double dec_centre = cpl_propertylist_get_double(
1517 jitters->limages[ref]->plist,
1518 "CRVAL2");
1519
1520 for (cpl_size i = 0; i < jitters->size; i++) {
1521 double ra = cpl_propertylist_get_double(jitters->limages[i]->plist,
1522 "CRVAL1");
1523 double dec = cpl_propertylist_get_double(jitters->limages[i]->plist,
1524 "CRVAL2");
1525 cpl_table_set_int(*report, "Index", i, (int) i);
1526 cpl_table_set_double(*report, "RA offset", i,
1527 (ra - ra_centre) * 3600.0);
1528 cpl_table_set_double(*report, "Dec offset", i,
1529 (dec - dec_centre) * 3600.0);
1530 }
1531
1532 return cpl_error_get_code();
1533}
1534
1535/*----------------------------------------------------------------------------*/
1554/*----------------------------------------------------------------------------*/
1555
1556static cpl_error_code eris_nix_match_and_correct(
1557 located_image * limage,
1558 const char * wcs_method,
1559 cpl_table * reference,
1560 const cpl_propertylist * ref_qclist,
1561 const char * reference_name,
1562 const double match_radius,
1563 cpl_size * nmatches,
1564 cpl_frameset * frameset,
1565 const cpl_parameterlist * parlist,
1566 const char * recipe_name,
1567 hdrl_parameter * cat_params) {
1568
1569 cpl_table * matched_stds = NULL;
1570
1571 if (cpl_error_get_code() != CPL_ERROR_NONE) return cpl_error_get_code();
1572
1573 /* beware situation where no sources were found in the image */
1574
1575 if (limage->objects && limage->objects->catalogue) {
1576 cpl_matrix * ignore = NULL;
1577 enu_correct_wcs(reference,
1578 wcs_method,
1579 reference_name,
1580 limage,
1581 match_radius,
1582 &matched_stds,
1583 &ignore);
1584 cpl_matrix_delete(ignore);
1585 enu_check_error_code("error correcting jitter wcs");
1586
1587 /* measure of how good was the match */
1588
1589 if (matched_stds) {
1590 *nmatches = cpl_table_get_nrow(matched_stds);
1591 } else {
1592 *nmatches = 0;
1593 }
1594
1595 /* save the reference catalogue */
1596
1597 enu_calc_pixel_coords(reference, limage->plist);
1598 enu_dfs_save_catalogue(frameset,
1599 limage->frame,
1600 parlist,
1601 reference,
1602 ref_qclist,
1603 "reference jitter",
1604 recipe_name,
1605 PACKAGE "/" PACKAGE_VERSION,
1606 "refcat.cal_wcs",
1607 ERIS_NIX_CAL_WCS_REF_CATALOGUE_PRO_CATG);
1608
1609 /* save the matched standards catalogue */
1610
1611 enu_dfs_save_catalogue(frameset,
1612 limage->frame,
1613 parlist,
1614 matched_stds,
1615 NULL,
1616 "matched standards",
1617 recipe_name,
1618 PACKAGE "/" PACKAGE_VERSION,
1619 "matchcat.cal_wcs",
1620 ERIS_NIX_CAL_WCS_MATCH_CATALOGUE_PRO_CATG);
1621
1622 /* save the image catalogue, recalculated for new wcs */
1623
1624 cpl_wcs * iwcs = cpl_wcs_new_from_propertylist(limage->plist);
1625 hdrl_catalogue_result_delete(limage->objects);
1626 limage->objects = enu_catalogue_compute(limage->himage,
1627 limage->confidence,
1628 iwcs,
1629 cat_params);
1630 cpl_wcs_delete(iwcs);
1631
1632 enu_dfs_save_catalogue(frameset,
1633 limage->frame,
1634 parlist,
1635 limage->objects->catalogue,
1636 limage->objects->qclist,
1637 cpl_frame_get_filename(limage->frame),
1638 recipe_name,
1639 PACKAGE "/" PACKAGE_VERSION,
1640 "cat.cal_wcs",
1641 ERIS_NIX_CAL_WCS_CATALOGUE_PRO_CATG);
1642
1643 } else {
1644 cpl_msg_info(cpl_func, "cannot match jitters %s",
1645 cpl_error_get_message());
1646 }
1647
1648 cleanup:
1649 cpl_table_delete(matched_stds);
1650 return cpl_error_get_code();
1651}
1652
1653/*----------------------------------------------------------------------------*/
1666/*----------------------------------------------------------------------------*/
1667
1668cpl_error_code eris_nix_scired_cal_wcs(cpl_frameset * frameset,
1669 const cpl_parameterlist * parlist,
1670 const char* recipe_name,
1671 const char* context) {
1672
1673 cpl_table * astrom_refcat = NULL;
1674 hdrl_parameter * cat_params = NULL;
1675 const char * cdssearch_astrom = NULL;
1676 cpl_table * ref_jitter_match = NULL;
1677 located_imagelist * jitters = NULL;
1678 cpl_matrix * jitter_overlaps = NULL;
1679 char * jitter_ref_name = NULL;
1680 cpl_table * matched_stds = NULL;
1681 int minstds = 1;
1682 located_imagelist * object_jitters = NULL;
1683 const char * out_tag = NULL;
1684 const cpl_parameter * p = NULL;
1685 cpl_vector * plan_ref = NULL;
1686 cpl_vector * plan_cal = NULL;
1687 cpl_table * report = NULL;
1688 cpl_matrix * jitter_ref_shift = NULL;
1689 located_imagelist * std_jitters = NULL;
1690 cpl_frameset * used = NULL;
1691 cpl_table * wcs_match_list = NULL;
1692 char * param_name = NULL;
1693
1694 enu_check_error_code("%s():%d: An error is already set: %s",
1695 cpl_func, __LINE__, cpl_error_get_where());
1696
1697 /* Check input parameters */
1698
1699 cpl_ensure_code(frameset, CPL_ERROR_NULL_INPUT);
1700 cpl_ensure_code(parlist, CPL_ERROR_NULL_INPUT);
1701
1702 /* Set the msg verbosity level from environment variable CPL_MSG_LEVEL
1703 - not working, so set manually for now */
1704
1705 cpl_msg_set_level_from_env();
1706 cpl_msg_severity severity = cpl_msg_get_level();
1707 cpl_msg_info(cpl_func, "level %d", (int) severity);
1708
1709 /* check for invalid input */
1710 if(eris_files_dont_exist(frameset) != CPL_ERROR_NONE) {
1711 return CPL_ERROR_BAD_FILE_FORMAT;
1712 }
1713
1714 /* Retrieve general input parameters */
1715
1716 param_name = cpl_sprintf("%s.cdssearch_astrom", context);
1717 p = cpl_parameterlist_find_const(parlist, param_name);
1718 cdssearch_astrom = cpl_parameter_get_string(p);
1719 cpl_free(param_name);
1720
1721 param_name = cpl_sprintf("%s.debug-data", context);
1722 p = cpl_parameterlist_find_const(parlist, param_name);
1723// const int debug = cpl_parameter_get_bool(p);
1724 cpl_free(param_name);
1725
1726 enu_check_error_code("Error retrieving input parameters");
1727
1728 /* check required input tags are present */
1729// const int ntags = 1;
1730// const char* required_tags[1] = {
1731// ERIS_NIX_WCS_MATCHED_CATALOGUE_PRO_CATG // opt
1732// };
1733
1734 // ERIS_NIX_SKYSUB_OBJECT_JITTER_PRO_CATG, or ERIS_NIX_SKYSUB_STD_JITTER_PRO_CATG
1735// cpl_ensure_code(CPL_ERROR_NONE ==
1736// eris_dfs_check_input_tags(frameset, required_tags, ntags, 1),
1737// CPL_ERROR_ILLEGAL_INPUT);
1738
1739 /* Identify the RAW and CALIB frames in the input frameset */
1740
1741 eris_nix_dfs_set_groups(frameset);
1742 enu_check_error_code("Could not identify RAW and CALIB frames");
1743
1744 used = cpl_frameset_new();
1745
1746 /* Read input data */
1747
1748 object_jitters = enu_limlist_load_from_frameset(frameset,
1749 ERIS_NIX_SKYSUB_OBJECT_JITTER_PRO_CATG, used);
1750 std_jitters = enu_limlist_load_from_frameset(frameset,
1751 ERIS_NIX_SKYSUB_STD_JITTER_PRO_CATG, used);
1752 enu_check_error_code("Could not load data frames");
1753
1754 cpl_msg_info(cpl_func, "%d %s frames read", (int) object_jitters->size,
1755 ERIS_NIX_SKYSUB_OBJECT_JITTER_PRO_CATG);
1756 cpl_msg_info(cpl_func, "%d %s frames read", (int) std_jitters->size,
1757 ERIS_NIX_SKYSUB_STD_JITTER_PRO_CATG);
1758
1759 /* check that the data files in the SoF are as expected */
1760
1761 enu_check(object_jitters->size > 0 || std_jitters->size > 0,
1762 CPL_ERROR_DATA_NOT_FOUND, "no input frames found");
1763 enu_check(!(object_jitters->size > 0 && std_jitters->size > 0),
1764 CPL_ERROR_ILLEGAL_INPUT, "SoF contains both "
1765 ERIS_NIX_SKYSUB_OBJECT_JITTER_PRO_CATG" and "
1766 ERIS_NIX_SKYSUB_STD_JITTER_PRO_CATG" frames");
1767
1768 /* is target an object or std? */
1769
1770 if (object_jitters->size > 0) {
1771 jitters = object_jitters;
1772 out_tag = ERIS_NIX_CAL_WCS_OBJECT_JITTER_PRO_CATG;
1773 enu_located_imagelist_delete(std_jitters);
1774 std_jitters = NULL;
1775 } else if (std_jitters->size > 0) {
1776 jitters = std_jitters;
1777 out_tag = ERIS_NIX_CAL_WCS_STD_JITTER_PRO_CATG;
1778 enu_located_imagelist_delete(object_jitters);
1779 object_jitters = NULL;
1780 }
1781
1782 /* Now that we have access to the data, setup the parameters for
1783 cataloguing - some elements can be overridden by contents
1784 of data files */
1785
1786 param_name = cpl_sprintf("%s.catalogue.det.effective-gain", context);
1787 p = cpl_parameterlist_find_const(parlist, param_name);
1788 double gain = cpl_parameter_get_double(p);
1789 cpl_free(param_name);
1790
1791 if (cpl_propertylist_has(jitters->limages[0]->plist, "ESO DARK GAIN")) {
1792 gain = cpl_propertylist_get_double(jitters->limages[0]->plist,
1793 "ESO DARK GAIN");
1794 cpl_msg_info(cpl_func, "catalogue params - reading detector gain "
1795 "from first jitter %4.1f", gain);
1796 }
1797 param_name = cpl_sprintf("%s.catalogue.det.saturation", context);
1798 p = cpl_parameterlist_find_const(parlist, param_name);
1799 double saturation = cpl_parameter_get_double(p);
1800 cpl_free(param_name);
1801
1802 if (cpl_propertylist_has(jitters->limages[0]->plist,
1803 "ESO DETMON SATURATION")) {
1804 saturation = cpl_propertylist_get_double(jitters->limages[0]->plist,
1805 "ESO DETMON SATURATION");
1806 cpl_msg_info(cpl_func, "catalogue params - reading detector "
1807 "saturation level from first jitter %6.1f", saturation);
1808 }
1809
1810 param_name = cpl_sprintf("%s.catalogue.obj.min-pixels", context);
1811 p = cpl_parameterlist_find_const(parlist, param_name);
1812 int minpixels = cpl_parameter_get_int(p);
1813 cpl_free(param_name);
1814
1815 param_name = cpl_sprintf("%s.catalogue.obj.threshold", context);
1816 p = cpl_parameterlist_find_const(parlist, param_name);
1817 double threshold = cpl_parameter_get_double(p);
1818 cpl_free(param_name);
1819
1820 param_name = cpl_sprintf("%s.catalogue.obj.deblending", context);
1821 p = cpl_parameterlist_find_const(parlist, param_name);
1822 cpl_boolean deblending = cpl_parameter_get_bool(p);
1823 cpl_free(param_name);
1824
1825 /* use AOMODE to decide if set catalogue.core-radius and mesh-size to
1826 defaults or read them from parameters */
1827
1828 double core_radius = -1.0;
1829 int mesh_size = -1;
1831 parlist,
1832 jitters->limages[0]->plist,
1833 &core_radius,
1834 &mesh_size);
1835
1836 param_name = cpl_sprintf("%s.catalogue.bkg.estimate", context);
1837 p = cpl_parameterlist_find_const(parlist, param_name);
1838 cpl_boolean estimate = cpl_parameter_get_bool(p);
1839 cpl_free(param_name);
1840
1841 param_name = cpl_sprintf("%s.catalogue.bkg.smooth-gauss-fwhm", context);
1842 p = cpl_parameterlist_find_const(parlist, param_name);
1843 double smooth_gauss_fwhm = cpl_parameter_get_double(p);
1844 cpl_free(param_name);
1845
1846 cat_params = hdrl_catalogue_parameter_create(minpixels,
1847 threshold,
1848 deblending,
1849 core_radius,
1850 estimate,
1851 mesh_size,
1852 smooth_gauss_fwhm,
1853 gain,
1854 saturation,
1855 HDRL_CATALOGUE_ALL);
1856
1857 enu_check_error_code("Error setting catalogue params");
1858
1859 /* set initial description for wcs calibration: raw telescope pointing */
1860
1861 for (cpl_size i=0; i < jitters->size; i++) {
1862 cpl_propertylist_update_string(jitters->limages[i]->plist,
1863 "ESO WCS_METHOD",
1864 ERIS_NIX_WCS_TEL_POINTING);
1865 cpl_propertylist_update_string(jitters->limages[i]->plist,
1866 "WCS_CAT", "none");
1867 }
1868
1869 /* estimate the centre of the jitter pattern */
1870
1871 float diff[1000];
1872 for (cpl_size i = 0; i < jitters->size; i++) {
1873 diff[i] = cpl_propertylist_get_double(jitters->limages[i]->plist,
1874 "CRVAL1");
1875 }
1876 float ra_centre = casu_med(diff, NULL, jitters->size);
1877 for (cpl_size i = 0; i < jitters->size; i++) {
1878 diff[i] = cpl_propertylist_get_double(jitters->limages[i]->plist,
1879 "CRVAL2");
1880 }
1881 float dec_centre = casu_med(diff, NULL, jitters->size);
1882 cpl_msg_info(cpl_func, "Jitter pattern centre at RA=%10.7f Dec=%10.7f",
1883 ra_centre, dec_centre);
1884
1885 /* find the 'reference' jitter, the one nearest the centre of the
1886 pattern */
1887
1888 cpl_size jitter_ref = -1;
1889 double minr2 = 1.0e6;
1890 for (cpl_size i = 0; i < jitters->size; i++) {
1891 double ra = cpl_propertylist_get_double(jitters->limages[i]->plist,
1892 "CRVAL1");
1893 double dec = cpl_propertylist_get_double(jitters->limages[i]->plist,
1894 "CRVAL2");
1895 double r2 = pow(ra - ra_centre, 2) + pow(dec - dec_centre, 2);
1896 if (r2 < minr2) {
1897 jitter_ref = i;
1898 minr2 = r2;
1899 }
1900 }
1901 cpl_msg_info(cpl_func, "Nearest jitter to centre is %d", (int) jitter_ref);
1902 char * refname = cpl_strdup(cpl_frame_get_filename(jitters->
1903 limages[jitter_ref]->frame));
1904 cpl_msg_info(cpl_func, "..filename %s", basename(refname));
1905 cpl_free(refname);
1906
1907 /* AMo: TODO creates a mask to trim pixels at image edge. Maybe we can also remove
1908 entries from catalog without using a mask */
1909
1910 cpl_size sx = hdrl_image_get_size_x(jitters->limages[jitter_ref]->himage);
1911 cpl_size sy = hdrl_image_get_size_y(jitters->limages[jitter_ref]->himage);
1912 cpl_size txmin = 0;
1913 cpl_size tymin = 0;
1914 cpl_size txmax = 0;
1915 cpl_size tymax = 0;
1916 eris_nix_scired_get_split_param_int(parlist, context, "edges-trim", 1, 1,
1917 sx, sy, &txmin, &tymin, &txmax, &tymax);
1918
1919 cpl_msg_info(cpl_func,"trim edge params: %lld %lld %lld %lld", txmin, tymin, txmax, tymax);
1920 cpl_image* image_edge = cpl_image_new(sx, sy, CPL_TYPE_INT);
1921 if(txmin > 1) {
1922 cpl_image_fill_window(image_edge,1, 1, txmin, sy, 1);
1923 }
1924
1925 if(txmax > 1) {
1926 cpl_image_fill_window(image_edge,sx - txmax, 1, sx, sy, 1);
1927 }
1928
1929 if(tymin > 1) {
1930 cpl_image_fill_window(image_edge,1, 1, sx, tymin, 1);
1931 }
1932
1933 if(tymax > 1) {
1934 cpl_image_fill_window(image_edge,1, sy - tymax, sx, sy, 1);
1935 }
1936 cpl_mask* mask_edge = cpl_mask_threshold_image_create(image_edge,0.9, 1.1);
1937 cpl_image_delete(image_edge);
1938 cpl_mask_save(mask_edge, "mask_edge.fits", NULL, CPL_IO_DEFAULT);
1939 //cpl_mask* hmask = hdrl_image_get_mask(jitters->limages[jitter_ref]->himage);
1940 //cpl_mask_or(hmask, mask_edge);
1941 hdrl_image_reject_from_mask(jitters->limages[jitter_ref]->himage, mask_edge);
1942 cpl_mask_delete(mask_edge);
1943 /* AMo: END coded added to trim edges of any input image (to prevent outliers to affect WCS sol) */
1944
1945 /* Make table of jitter offsets relative to reference jitter, calculate
1946 the overlap of each jitter with the reference */
1947
1948 jitter_overlaps = cpl_matrix_new(jitters->size, jitters->size);
1949 eris_nix_calculate_overlaps(jitters, &jitter_overlaps);
1950 cpl_msg_info(cpl_func, " ");
1951 cpl_msg_info(cpl_func, "Jitter overlaps matrix:");
1952 cpl_matrix_dump(jitter_overlaps, NULL);
1953
1954 /* Make calibration plan, that is the list of (reference, jitter) pairs */
1955
1956 cpl_vector * matched = cpl_vector_new(jitters->size);
1957 plan_ref = cpl_vector_new(jitters->size);
1958 plan_cal = cpl_vector_new(jitters->size);
1959 for (cpl_size j=0; j<cpl_vector_get_size(matched); j++) {
1960 cpl_vector_set(matched, j, 0.0);
1961 cpl_vector_set(plan_ref, j, -1.0);
1962 cpl_vector_set(plan_cal, j, -1.0);
1963 }
1964
1965 /* ..reference jitter agains Gaia first */
1966 cpl_vector_set(matched, jitter_ref, 1.0);
1967 cpl_msg_info(cpl_func, " ");
1968 cpl_msg_info(cpl_func, "WCS calibration plan:");
1969 cpl_msg_info(cpl_func, "ref Gaia calibrates %d", (int)jitter_ref);
1970
1971 /* ..then subsequent jitters, based on the size of the overlap
1972 between them */
1973
1974 int matching = CPL_TRUE;
1975 cpl_size iplan = 0;
1976 while (matching) {
1977 cpl_size row_next = -1;
1978 cpl_size col_next = -1;
1979 cpl_matrix * overlaps_copy = cpl_matrix_duplicate(jitter_overlaps);
1980
1981 /* highlight calibrated columns and uncalibrated rows */
1982
1983 for (cpl_size col=0; col<jitters->size; col++) {
1984 if (cpl_vector_get(matched, col) < 1.0) {
1985 for (cpl_size row=0; row<jitters->size; row++) {
1986 cpl_matrix_set(overlaps_copy, row, col, -1.0);
1987 }
1988 }
1989 }
1990 for (cpl_size row=0; row<jitters->size; row++) {
1991 if (cpl_vector_get(matched, row) > 0.0) {
1992 for (cpl_size col=0; col<jitters->size; col++) {
1993 cpl_matrix_set(overlaps_copy, row, col, -1.0);
1994 }
1995 }
1996 }
1997
1998 /* look for max overlap remaining - the col will be the
1999 ref jitter and the row the jitter to calibrate */
2000
2001 if (cpl_matrix_get_max(overlaps_copy) > 0.0) {
2002 cpl_matrix_get_maxpos(overlaps_copy, &row_next, &col_next);
2003 double overlap_next = cpl_matrix_get(overlaps_copy, row_next,
2004 col_next);
2005 cpl_msg_info(cpl_func, "ref %d -> %d overlap %4.2f", (int)col_next,
2006 (int)row_next, overlap_next);
2007 cpl_vector_set(matched, row_next, 1.0);
2008
2009 cpl_vector_set(plan_ref, iplan, col_next);
2010 cpl_vector_set(plan_cal, iplan, row_next);
2011 iplan++;
2012 } else {
2013 matching = CPL_FALSE;
2014 }
2015 cpl_matrix_delete(overlaps_copy);
2016 }
2017 cpl_vector_delete(matched);
2018
2019 /* build the calibration 'report' table which will hold information
2020 on the calibration plan and results */
2021
2022 report = cpl_table_new(jitters->size);
2023 eris_nix_report_table(jitter_ref, jitters, &report);
2024
2025 /* Starting WCS calibration ...
2026
2027 First, is there a file with a list of positions to calibrate
2028 the reference jitter? */
2029
2030 cpl_frame * wcs_matched_frame = cpl_frameset_find (frameset,
2031 ERIS_NIX_WCS_MATCHED_CATALOGUE_PRO_CATG);
2032 const char * wcs_match_list_name = NULL;
2033 if (wcs_matched_frame) {
2034 wcs_match_list_name = cpl_frame_get_filename (wcs_matched_frame);
2035
2036 /* There is, read it */
2037
2038 cpl_msg_info(cpl_func, "found manual matching list %s",
2039 wcs_match_list_name);
2040 wcs_match_list = cpl_table_load(wcs_match_list_name, 1, 0);
2041 enu_check_error_code("failed to read match list");
2042
2043 /* Select the table row that matches the reference jitter */
2044
2045 const char * ref_jitter_name = cpl_frame_get_filename(
2046 jitters->limages[jitter_ref]->frame);
2047 cpl_msg_info(cpl_func, "..reference jitter %s", ref_jitter_name);
2048 cpl_table_unselect_all(wcs_match_list);
2049 for (cpl_size row = 0; row < cpl_table_get_nrow(wcs_match_list);
2050 row++) {
2051 if (strstr(ref_jitter_name, cpl_table_get_string(wcs_match_list,
2052 "Filename", row))) {
2053 cpl_table_select_row(wcs_match_list, row);
2054 ref_jitter_match = cpl_table_extract_selected(wcs_match_list);
2055 cpl_msg_info(cpl_func, "..found entry for reference jitter");
2056 break;
2057 }
2058 }
2059
2060 if (!ref_jitter_match) {
2061 cpl_msg_info(cpl_func, "..reference jitter not found in manual "
2062 "matching file");
2063 } else {
2064 cpl_msg_info(cpl_func, "..calculating WCS correction for "
2065 "reference jitter");
2066
2067 /* Using the existing wcs info, calculate the predicted x and y
2068 positions for the given celestial point in the reference
2069 jitter */
2070
2071 cpl_table_new_column(ref_jitter_match, "xpredict", CPL_TYPE_FLOAT);
2072 cpl_table_new_column(ref_jitter_match, "ypredict", CPL_TYPE_FLOAT);
2073 double * ra = cpl_table_get_data_double(ref_jitter_match, "RA");
2074 double * dec = cpl_table_get_data_double(ref_jitter_match, "DEC");
2075 cpl_matrix * celestial = cpl_matrix_new(1, 2);
2076 cpl_matrix_set(celestial, 0, 0, ra[0]);
2077 cpl_matrix_set(celestial, 0, 1, dec[0]);
2078 cpl_wcs * iwcs = cpl_wcs_new_from_propertylist(
2079 jitters->limages[jitter_ref]->plist);
2080 cpl_matrix * predicted = NULL;
2081 cpl_array * status = NULL;
2082 cpl_wcs_convert(iwcs, celestial, &predicted, &status,
2083 CPL_WCS_WORLD2PHYS);
2084 cpl_wcs_delete(iwcs);
2085
2086 /* subtract the predicted positions from the measured in jitter 1,
2087 giving the observed coarse shift in x, y. This will be an
2088 estimate of the telescope pointing error for the first jitter;
2089 the relative error of subsequent jitters will be much smaller */
2090
2091 double * x_coordinate = cpl_table_get_data_double(ref_jitter_match,
2092 "X_coordinate");
2093 double * y_coordinate = cpl_table_get_data_double(ref_jitter_match,
2094 "Y_coordinate");
2095 cpl_matrix * xy = cpl_matrix_new(1, 2);
2096 cpl_matrix_set(xy, 0, 0, x_coordinate[0]);
2097 cpl_matrix_set(xy, 0, 1, y_coordinate[0]);
2098 cpl_matrix_subtract(xy, predicted);
2099 jitter_ref_shift = xy;
2100 cpl_msg_info(cpl_func, "..reference jitter shift is");
2101 cpl_matrix_dump(jitter_ref_shift, NULL);
2102
2103 cpl_msg_info(cpl_func, "..applying WCS correction to reference "
2104 "jitter");
2105
2106 double crpix1 = cpl_propertylist_get_double(
2107 jitters->limages[jitter_ref]->plist, "CRPIX1");
2108 cpl_propertylist_update_double(jitters->limages[jitter_ref]->plist,
2109 "CRPIX1", crpix1 +
2110 cpl_matrix_get(jitter_ref_shift, 0, 0));
2111 double crpix2 = cpl_propertylist_get_double(
2112 jitters->limages[jitter_ref]->plist, "CRPIX2");
2113 cpl_propertylist_update_double(jitters->limages[jitter_ref]->plist,
2114 "CRPIX2", crpix2 +
2115 cpl_matrix_get(jitter_ref_shift, 0, 1));
2116
2117 /* store correction method */
2118
2119 cpl_propertylist_update_string(jitters->limages[jitter_ref]->plist,
2120 "ESO WCS_METHOD",
2121 ERIS_NIX_WCS_CATALOGUE_MATCH);
2122 cpl_propertylist_update_string(jitters->limages[jitter_ref]->plist,
2123 "WCS_CAT",
2124 cpl_table_get_string(ref_jitter_match,
2125 "Catalogue", 0));
2126 enu_check_error_code("failure to set corrected wcs");
2127
2128 /* save the reference catalogue */
2129
2130 enu_calc_pixel_coords(ref_jitter_match,
2131 jitters->limages[jitter_ref]->plist);
2132 enu_dfs_save_catalogue(frameset,
2133 jitters->limages[jitter_ref]->frame,
2134 parlist,
2135 ref_jitter_match,
2136 NULL,
2137 cpl_table_get_string(ref_jitter_match,
2138 "Catalogue", 0),
2139 recipe_name,
2140 PACKAGE "/" PACKAGE_VERSION,
2141 "refcat.cal_wcs",
2142 ERIS_NIX_CAL_WCS_REF_CATALOGUE_PRO_CATG);
2143
2144 /* save the matched standards catalogue - same as reference
2145 cat but done for consistency with other jitters */
2146
2147 enu_dfs_save_catalogue(frameset,
2148 jitters->limages[jitter_ref]->frame,
2149 parlist,
2150 ref_jitter_match,
2151 NULL,
2152 cpl_table_get_string(ref_jitter_match,
2153 "Catalogue", 0),
2154 recipe_name,
2155 PACKAGE "/" PACKAGE_VERSION,
2156 "matchcat.cal_wcs",
2157 ERIS_NIX_CAL_WCS_MATCH_CATALOGUE_PRO_CATG);
2158
2159 /* save the image catalogue, calculated for new wcs */
2160
2161 cpl_wcs * wcs = cpl_wcs_new_from_propertylist(
2162 jitters->limages[jitter_ref]->plist);
2163 cpl_msg_info(cpl_func, "cataloguing reference jitter");
2164 jitters->limages[jitter_ref]->objects = enu_catalogue_compute(
2165 jitters->limages[jitter_ref]->himage,
2166 jitters->limages[jitter_ref]->confidence,
2167 wcs,
2168 cat_params);
2169 cpl_wcs_delete(wcs);
2170 enu_dfs_save_catalogue(frameset,
2171 jitters->limages[jitter_ref]->frame,
2172 parlist,
2173 jitters->limages[jitter_ref]->objects->catalogue,
2174 jitters->limages[jitter_ref]->objects->qclist,
2175 cpl_frame_get_filename(jitters->
2176 limages[jitter_ref]->
2177 frame),
2178 recipe_name,
2179 PACKAGE "/" PACKAGE_VERSION,
2180 "cat.cal_wcs",
2181 ERIS_NIX_CAL_WCS_CATALOGUE_PRO_CATG);
2182 }
2183 cpl_msg_info(cpl_func, "..");
2184 }
2185
2186 if (jitter_ref_shift == NULL) {
2187
2188 /* If that didn't work, try matching sources in jitter_ref with
2189 the astrometric catalogue specified */
2190
2191 if (strcmp(cdssearch_astrom, "none")) {
2192
2193 cpl_msg_info(cpl_func, " ");
2194 cpl_msg_info(cpl_func, "Try to match sources in reference jitter "
2195 "with %s", cdssearch_astrom);
2196
2197 /* Read the astrom catalogue for the image area of the reference
2198 jitter from CDS */
2199
2200 /* use casu_getstds to do the read as it forms the table in the way
2201 expected by other casu routines */
2202
2203 astrom_refcat = NULL;
2204 int casu_status = CASU_OK;
2205 char * catname = cpl_strdup(cdssearch_astrom);
2206 int cdschoice = casu_get_cdschoice(cdssearch_astrom);
2207 casu_getstds(jitters->limages[jitter_ref]->plist,
2208 CPL_FALSE, NULL, catname, cdschoice, NULL,
2209 &astrom_refcat, NULL, &casu_status);
2210
2211 if (astrom_refcat) {
2212
2213 /* Some standards were found, are there enough? */
2214
2215 cpl_size nstds = cpl_table_get_nrow(astrom_refcat);
2216 enu_check(nstds >= minstds, CPL_ERROR_INCOMPATIBLE_INPUT,
2217 "nstds = %d, need at least %d", (int)nstds, minstds);
2218
2219 /* getstds returns a "Dec" column whereas the rest of the code
2220 expects "DEC". Fix this. */
2221
2222 if (cpl_table_has_column(astrom_refcat, "Dec") &&
2223 !cpl_table_has_column(astrom_refcat, "DEC")) {
2224 cpl_table_duplicate_column(astrom_refcat, "DEC",
2225 astrom_refcat, "Dec");
2226 cpl_table_erase_column(astrom_refcat, "Dec");
2227 }
2228
2229 cpl_msg_info(cpl_func, "cataloguing reference jitter %d",
2230 (int) jitter_ref);
2231 cpl_wcs * iwcs = cpl_wcs_new_from_propertylist
2232 (jitters->limages[jitter_ref]->plist);
2233 jitters->limages[jitter_ref]->objects = enu_catalogue_compute(
2234 jitters->limages[jitter_ref]->himage,
2235 jitters->limages[jitter_ref]->confidence,
2236 iwcs,
2237 cat_params);
2238 cpl_wcs_delete(iwcs);
2239
2240 /* catalogue standards can move so make match_rad fairly loose */
2241 double match_rad = 10.0;
2242 cpl_size nmatches = 0;
2243 eris_nix_match_and_correct(jitters->limages[jitter_ref],
2244 ERIS_NIX_WCS_CATALOGUE_MATCH,
2245 astrom_refcat,
2246 NULL,
2247 cdssearch_astrom,
2248 match_rad,
2249 &nmatches,
2250 frameset,
2251 parlist,
2252 recipe_name,
2253 cat_params);
2254
2255 cpl_table_set_int(report, "Reference", jitter_ref, -1);
2256 cpl_table_set_double(report, "Overlap", jitter_ref,
2257 cpl_matrix_get(jitter_overlaps,
2258 jitter_ref, jitter_ref));
2259 cpl_table_set_string(report, "WCS_METHOD", jitter_ref,
2260 ERIS_NIX_WCS_CATALOGUE_MATCH);
2261 cpl_table_set_string(report, "Catalogue/File", jitter_ref,
2262 catname);
2263 cpl_table_set_int(report, "# matches", jitter_ref, nmatches);
2264 }
2265 cpl_msg_info(cpl_func, "..");
2266 enu_check_error_code("error correcting wcs of reference jitter");
2267 cpl_free(catname);
2268 }
2269 }
2270
2271 /* correction of other jitters - work through the calibration 'plan' calculated
2272 earlier and 'match and correct' the reference/jitter pairs.
2273 The first reference will be the reference jitter, which anchors the
2274 whole thing. */
2275
2276 enu_catalogue_limlist(jitters, cat_params);
2277
2278 if (!(jitters->limages[jitter_ref]->objects)) {
2279 cpl_msg_warning(cpl_func, "Unable to absolute correct jitters "
2280 "because no sources found in reference jitter");
2281 }
2282
2283 for (cpl_size i = 0; i < jitters->size; i++) {
2284 cpl_size jref = cpl_vector_get(plan_ref, i);
2285 cpl_size jcal = cpl_vector_get(plan_cal, i);
2286
2287 if (jref >= 0 && jitters->limages[jref]->objects != NULL) {
2288 cpl_msg_info(cpl_func, " ");
2289 cpl_msg_info(cpl_func, "using jitter %d to correct %d",
2290 (int)jref, (int)jcal);
2291
2292 /* basename does mysterious things sometimes (in this case
2293 result is changed by subsequent calls in the loop), take
2294 a copy of its result to freeze it */
2295
2296 char * fname = cpl_strdup(cpl_frame_get_filename(
2297 jitters->limages[jref]->frame));
2298 char * jref_name = cpl_strdup(basename(fname));
2299 cpl_free(fname);
2300
2301 /* objects do not move between jitters so match_rad can be
2302 relatively tight */
2303 double match_rad = 2.0;
2304 cpl_size nmatches = 0;
2305 eris_nix_match_and_correct(jitters->limages[jcal],
2306 ERIS_NIX_WCS_JITTER_RELATIVE,
2307 jitters->limages[jref]->
2308 objects->catalogue,
2309 jitters->limages[jref]->
2310 objects->qclist,
2311 jref_name,
2312 match_rad,
2313 &nmatches,
2314 frameset,
2315 parlist,
2316 recipe_name,
2317 cat_params);
2318
2319
2320 cpl_table_set_int(report, "Reference", jcal, jref);
2321 cpl_table_set_double(report, "Overlap", jcal,
2322 cpl_matrix_get(jitter_overlaps, jref, jcal));
2323 cpl_table_set_string(report, "WCS_METHOD", jcal,
2324 ERIS_NIX_WCS_JITTER_RELATIVE);
2325 cpl_table_set_string(report, "Catalogue/File", jcal, jref_name);
2326 cpl_table_set_int(report, "# matches", jcal, nmatches);
2327 cpl_free(jref_name);
2328 }
2329 }
2330 cpl_msg_info(cpl_func, "..");
2331
2332 /* save the wcs-corrected jitter images to FITS files */
2333
2334 for (cpl_size i = 0; i < jitters->size; i++) {
2335
2336 /* Generate output file name, provenance frameset */
2337
2338 char * out_fname = enu_repreface(cpl_frame_get_filename(jitters->
2339 limages[i]->frame),
2340 "cal_wcs");
2341
2342 cpl_propertylist * applist = cpl_propertylist_new();
2343 cpl_propertylist_update_string(applist, CPL_DFS_PRO_CATG, out_tag);
2344 cpl_propertylist_update_string(applist, "PRODCATG", "ANCILLARY.IMAGE");
2345 cpl_propertylist_copy_property(applist, jitters->limages[i]->plist,
2346 "ESO WCS_METHOD");
2347 cpl_propertylist_copy_property(applist, jitters->limages[i]->plist,
2348 "WCS_CAT");
2349
2350 /* set RA, DEC from WCS rather than let dfs copy it from some random
2351 frame */
2352
2353 {
2354 cpl_wcs * wcs = cpl_wcs_new_from_propertylist(
2355 jitters->limages[i]->plist);
2356 double ra = 0.0;
2357 double dec = 0.0;
2358 enu_get_ra_dec(wcs, &ra, &dec);
2359
2360 cpl_propertylist_update_double(applist, "RA", ra);
2361 cpl_propertylist_update_double(applist, "DEC", dec);
2362
2363 cpl_wcs_delete(wcs);
2364 }
2365
2366 /* provenance is the frame itself plus the frame it's referenced to */
2367 cpl_frameset * provenance = cpl_frameset_new();
2368 cpl_frameset_insert(provenance, cpl_frame_duplicate(
2369 jitters->limages[i]->frame));
2370 if (i != jitter_ref) {
2371 cpl_frameset_insert(provenance, cpl_frame_duplicate(
2372 jitters->limages[jitter_ref]->frame));
2373 }
2374 enu_dfs_save_limage(frameset,
2375 parlist,
2376 provenance,
2377 CPL_TRUE,
2378 jitters->limages[i],
2379 recipe_name,
2380 jitters->limages[i]->frame,
2381 applist,
2382 PACKAGE "/" PACKAGE_VERSION,
2383 out_fname);
2384
2385 cpl_free(out_fname);
2386 cpl_frameset_delete(provenance);
2387 cpl_propertylist_delete(applist);
2388 }
2389
2390 cpl_table_dump(report, 0, 100, NULL);
2391
2392 char * in_fname = cpl_strdup(cpl_frame_get_filename(jitters->limages[0]->
2393 frame));
2394 char * out_fname = cpl_sprintf("cal_wcs_report.%s", basename(in_fname));
2395
2396 cpl_propertylist * report_plist = cpl_propertylist_new();
2397 cpl_propertylist_update_string(report_plist, CPL_DFS_PRO_CATG,
2398 ERIS_NIX_CAL_WCS_REPORT_PRO_CATG);
2399 cpl_table_save (report, report_plist, NULL, out_fname, CPL_IO_CREATE);
2400 cpl_propertylist_delete(report_plist);
2401 cpl_free(in_fname);
2402 cpl_free(out_fname);
2403
2404cleanup:
2405 cpl_table_delete(astrom_refcat);
2406 hdrl_parameter_delete(cat_params);
2407 cpl_table_delete(ref_jitter_match);
2408 cpl_free(jitter_ref_name);
2409 cpl_matrix_delete(jitter_ref_shift);
2410 cpl_matrix_delete(jitter_overlaps);
2411 cpl_table_delete(matched_stds);
2412 cpl_vector_delete(plan_ref);
2413 cpl_vector_delete(plan_cal);
2414 enu_located_imagelist_delete(object_jitters);
2415 cpl_table_delete(report);
2416 enu_located_imagelist_delete(std_jitters);
2417 cpl_frameset_delete(used);
2418 cpl_table_delete(wcs_match_list);
2419
2420 return (int) cpl_error_get_code();
2421}
2422
2423
2424/*----------------------------------------------------------------------------*/
2429/*----------------------------------------------------------------------------*/
2430
2431static cpl_error_code cal_phot_cast_columns_to_float(cpl_table * table) {
2432
2433 if (cpl_error_get_code() != CPL_ERROR_NONE) return cpl_error_get_code();
2434
2435 /* let NULL table drop through */
2436
2437 if (table == NULL) return CPL_ERROR_NONE;
2438
2439 cpl_array * colnames = cpl_table_get_column_names(table);
2440 for (cpl_size icol=0; icol < cpl_array_get_size(colnames); icol++) {
2441 const char * colname = cpl_array_get_string(colnames, icol);
2442 if (cpl_table_get_column_type(table, colname) == CPL_TYPE_DOUBLE ||
2443 cpl_table_get_column_type(table, colname) == CPL_TYPE_LONG_LONG) {
2444 cpl_table_cast_column(table, colname, colname, CPL_TYPE_FLOAT);
2445 }
2446 }
2447 cpl_array_delete(colnames);
2448
2449 return cpl_error_get_code();
2450}
2451
2452
2453/*----------------------------------------------------------------------------*/
2464/*----------------------------------------------------------------------------*/
2465
2466static cpl_error_code eris_nix_img_cal_phot_save(
2467 located_image * limage,
2468 const char * tag,
2469 cpl_frameset * frameset,
2470 const cpl_parameterlist * parlist,
2471 const char * recipe_name) {
2472
2473 if (cpl_error_get_code() != CPL_ERROR_NONE) return cpl_error_get_code();
2474
2475 /* calculate magnitude limit using HDRL */
2476 /* ..set mode calculation following HDRL docs example */
2477
2478 /* try to get actual fwhm from catalogue, failing that use the PSF
2479 currently in the header */
2480
2481 double cd1_1 = cpl_propertylist_get_double(limage->plist, "CD1_1");
2482 double cd2_1 = cpl_propertylist_get_double(limage->plist, "CD2_1");
2483 double pixsize = sqrt(pow(cd1_1, 2) + pow(cd2_1, 2)) * 3600.0;
2484
2485 double fwhm_pix = -1.0;
2486 if (limage->objects &&
2487 limage->objects->qclist &&
2488 cpl_propertylist_has(limage->objects->qclist, "ESO QC IMAGE_SIZE")) {
2489
2490 fwhm_pix = cpl_propertylist_get_double(limage->objects->qclist,
2491 "ESO QC IMAGE_SIZE");
2492 }
2493
2494 if (fwhm_pix != -1.0) {
2495 cpl_propertylist_update_double(limage->plist, "PSF_FWHM",
2496 fwhm_pix * pixsize);
2497 cpl_propertylist_set_comment(limage->plist, "PSF_FWHM",
2498 "Average FWHM of stellar objects[arcsec]");
2499 } else {
2500 double fwhm = cpl_propertylist_get_double(limage->plist, "PSF_FWHM");
2501 fwhm_pix = fwhm / pixsize;
2502 }
2503
2504 double photzp = cpl_propertylist_get_double(limage->plist, "PHOTZP");
2505 double abmaglim = -1.0;
2506 if(!isfinite(photzp)) {
2507 photzp = -999;
2508 }
2509 enu_calc_maglim(limage, photzp, fwhm_pix, &abmaglim);
2510
2511 /* update DFS keywords affected by this recipe */
2512
2513 cpl_propertylist * applist = cpl_propertylist_new();
2514
2515 cpl_propertylist_copy_property(applist, limage->plist, "FLUXCAL");
2516
2517 if(!isfinite(cpl_propertylist_get_double(limage->plist,"ESO QC MAGZPT"))) {
2518 cpl_propertylist_update_double(applist, "ESO QC MAGZPT", -999);
2519 cpl_propertylist_update_double(limage->plist, "ESO QC MAGZPT", -999);
2520 } else {
2521 cpl_propertylist_copy_property(applist, limage->plist, "ESO QC MAGZPT");
2522 }
2523
2524 if(!isfinite(cpl_propertylist_get_double(limage->plist,"ESO QC MAGZERR"))) {
2525 cpl_propertylist_update_double(applist, "ESO QC MAGZERR", -999);
2526 cpl_propertylist_update_double(limage->plist, "ESO QC MAGZERR", -999);
2527 } else {
2528 cpl_propertylist_copy_property(applist, limage->plist, "ESO QC MAGZERR");
2529 }
2530
2531
2532 cpl_propertylist_update_double(applist, "ABMAGLIM", abmaglim);
2533 cpl_propertylist_set_comment(applist, "ABMAGLIM", "5-sigma "
2534 "limiting AB magnitude");
2535
2536 /* ABMAGSAT is calculated by casu_photcal_extinct assumimg satlev=65000,
2537 when it should be ESO.DETMON.SATURATION / ESO.DET.SEQ1.DIT.
2538 Modify the value accordingly */
2539 double saturation = cpl_propertylist_get_double(limage->plist,
2540 "ESO DETMON SATURATION");
2541 double dit = enu_get_dit(limage->plist);
2542 double satlev = saturation / dit;
2543 double abmagsat = cpl_propertylist_get_double(limage->plist, "ABMAGSAT");
2544 abmagsat = abmagsat + 2.5 * log10(65000 / satlev);
2545 cpl_propertylist_copy_property(applist, limage->plist, "ABMAGSAT");
2546
2547 if(!isfinite(cpl_propertylist_get_double(limage->plist,"ABMAGSAT"))) {
2548 cpl_propertylist_update_double(applist, "ABMAGSAT", -999);
2549 cpl_propertylist_update_double(limage->plist, "ABMAGSAT", -999);
2550 } else {
2551 cpl_propertylist_update_double(applist, "ABMAGSAT", abmagsat);
2552 }
2553
2554 if(!isfinite(cpl_propertylist_get_double(limage->plist,"PHOTZP"))) {
2555 cpl_propertylist_append_double(applist, "PHOTZP", -999);
2556 cpl_propertylist_set_double(limage->plist, "PHOTZP", -999);
2557 } else {
2558 cpl_propertylist_copy_property(applist, limage->plist, "PHOTZP");
2559 }
2560
2561 if(!isfinite(cpl_propertylist_get_double(limage->plist,"PHOTZPER"))) {
2562 cpl_propertylist_append_double(applist, "PHOTZPER", -999);
2563 cpl_propertylist_set_double(limage->plist, "PHOTZPER", -999);
2564 } else {
2565 cpl_propertylist_copy_property(applist, limage->plist, "PHOTZPER");
2566 }
2567 cpl_propertylist_copy_property(applist, limage->plist, "ZPMETHOD");
2568 if (cpl_propertylist_has(limage->plist, "ZP_CAT")) {
2569 cpl_propertylist_copy_property(applist, limage->plist, "ZP_CAT");
2570 }
2571 cpl_propertylist_copy_property(applist, limage->plist, "ESO DRS EXTCOEF");
2572
2573 /* set PRO.CATG */
2574
2575 cpl_propertylist_update_string(applist, CPL_DFS_PRO_CATG, tag);
2576 cpl_propertylist_update_string(applist, "PRODCATG", "ANCILLARY.IMAGE");
2577
2578 /* set RA, DEC from WCS rather than let dfs copy it from one of the
2579 frames */
2580
2581 {
2582 cpl_wcs * wcs = cpl_wcs_new_from_propertylist(limage->plist);
2583 double ra = 0.0;
2584 double dec = 0.0;
2585 enu_get_ra_dec(wcs, &ra, &dec);
2586
2587 cpl_propertylist_update_double(applist, "RA", ra);
2588 cpl_propertylist_update_double(applist, "DEC", dec);
2589
2590 cpl_wcs_delete(wcs);
2591 }
2592
2593 /* provenance frameset, files that contributed to this reduction */
2594
2595 cpl_frameset * provenance = cpl_frameset_new();
2596 cpl_frameset_insert(provenance, cpl_frame_duplicate(limage->frame));
2597
2598 /* Generate output file name, write the file. */
2599
2600 char * out_fname = enu_repreface(cpl_frame_get_filename(limage->frame),
2601 "cal_phot");
2602
2603 enu_dfs_save_limage(frameset,
2604 parlist,
2605 provenance,
2606 CPL_TRUE,
2607 limage,
2608 recipe_name,
2609 limage->frame,
2610 applist,
2611 PACKAGE "/" PACKAGE_VERSION,
2612 out_fname);
2613
2614 cpl_free(out_fname);
2615 cpl_frameset_delete(provenance);
2616 cpl_propertylist_delete(applist);
2617
2618 return cpl_error_get_code();
2619}
2620
2621
2622/*----------------------------------------------------------------------------*/
2629/*----------------------------------------------------------------------------*/
2630
2631static cpl_error_code eris_nix_img_cal_phot_default(
2632 cpl_frameset * frameset,
2633 located_image * jitter) {
2634
2635 cpl_table * phot_data = NULL;
2636 cpl_table * selected = NULL;
2637
2638 /* Read in the data file with default photometric values */
2639
2640 cpl_frame * phot_data_frame = cpl_frameset_find (frameset,
2641 ERIS_NIX_PHOT_DATA_PRO_CATG);
2642 const char * phot_data_file = cpl_frame_get_filename (phot_data_frame);
2643 enu_check_error_code("Failed to read NIX photometry file name");
2644
2645 cpl_msg_info(cpl_func, "..transferring default photometric calibration "
2646 "from %s", phot_data_file);
2647
2648 /* Read in the instrument photometry table, with info on conversion
2649 between standard and instrument filters */
2650
2651 const char * pcat = "2MASS";
2652 cpl_size phot_ext = cpl_fits_find_extension(phot_data_file, pcat);
2653 enu_check(phot_ext > 0, CPL_ERROR_INCOMPATIBLE_INPUT,
2654 "photometry information for '%s' not found in %s",
2655 pcat, phot_data_file);
2656
2657 phot_data = cpl_table_load(phot_data_file, phot_ext, 0);
2658
2659 /* get the filter used for the observation and the relevant line of
2660 the phot_data table */
2661
2662 const char * filter = enu_get_filter(jitter->plist);
2663 enu_check(filter != NULL, CPL_ERROR_INCOMPATIBLE_INPUT,
2664 "Failure to find filter name");
2665
2666 /* comparison is treated as a regular expression */
2667 char * comparison = cpl_sprintf("^%s$", filter);
2668 cpl_size nsel = cpl_table_and_selected_string(phot_data, "filter_name",
2669 CPL_EQUAL_TO, comparison);
2670 cpl_free(comparison);
2671 if (nsel == 1) {
2672 cpl_msg_info(cpl_func, "Filter %s located in %s", filter,
2673 phot_data_file);
2674 selected = cpl_table_extract_selected(phot_data);
2675 cpl_table_dump(selected, 0, 1, NULL);
2676 cpl_table_delete(phot_data);
2677 phot_data = selected;
2678 } else {
2679 cpl_error_set_message(cpl_func, CPL_ERROR_INCOMPATIBLE_INPUT,
2680 "No entry for filter %s in %s", filter,
2681 phot_data_file);
2682 }
2683 enu_check_error_code("Failure to read photometry data for filter %s",
2684 filter);
2685
2686 int ignore = 0;
2687 double default_zp = cpl_table_get_double(phot_data, "default_zp", 0,
2688 &ignore);
2689 double default_zp_err = cpl_table_get_double(phot_data,
2690 "default_zp_err", 0,
2691 &ignore);
2692 double extcoef = cpl_table_get_double(phot_data, "atm_extcoef", 0,
2693 &ignore);
2694
2695 /* Set default zeropoint in the jitter image */
2696
2697 /* PHOTZP absorbs the exposure time and extinction for the jitter
2698 so this correction can be applied directly to the image data.
2699 Because data are in adu/s the exposure time for this calculation
2700 is 1.0 */
2701
2702 double airmass = enu_get_airmass(jitter->plist);
2703 const double extinct = extcoef * (airmass - 1.0);
2704 const double exptime = 1.0;
2705 cpl_msg_info(cpl_func, "default %f %f %f", default_zp, exptime, extinct);
2706 const double photzp = default_zp + 2.5*log10(exptime) - extinct;
2707
2708 /* Set ZPMETHOD to reflect the calibration method used */
2709
2710 const char * zp_method = "DEFAULT";
2711 const char * zp_method_comment = "ZP taken from filter default value";
2712 const char * magzpt_comment = "[mag] photometric zeropoint";
2713 const char * magzerr_comment = "[mag] photometric zeropoint error";
2714 const char * photzp_comment = "[mag] photometric zeropoint";
2715 const char * photzper_comment = "[mag] uncertainty on PHOTZP";
2716 const char * extcoef_comment = "[mag] Assumed extinction coefficient";
2717
2718 /* write the calibration keywords to the jitter header */
2719
2720 cpl_propertylist_update_string(jitter->plist, "FLUXCAL", "ABSOLUTE");
2721 cpl_propertylist_set_comment(jitter->plist, "FLUXCAL",
2722 "quality of flux calibration");
2723 cpl_propertylist_update_double(jitter->plist, "ESO QC MAGZPT",
2724 default_zp);
2725 cpl_propertylist_set_comment(jitter->plist, "ESO QC MAGZPT",
2726 magzpt_comment);
2727 cpl_propertylist_update_double(jitter->plist, "ESO QC MAGZERR",
2728 default_zp_err);
2729 cpl_propertylist_set_comment(jitter->plist, "ESO QC MAGZERR",
2730 magzerr_comment);
2731 cpl_propertylist_update_double(jitter->plist, "PHOTZP", photzp);
2732 cpl_propertylist_set_comment(jitter->plist, "PHOTZP", photzp_comment);
2733 cpl_propertylist_update_double(jitter->plist, "PHOTZPER", default_zp_err);
2734 cpl_propertylist_set_comment(jitter->plist, "PHOTZPER", photzper_comment);
2735 cpl_propertylist_update_string(jitter->plist, "ZPMETHOD", zp_method);
2736 cpl_propertylist_set_comment(jitter->plist, "ZPMETHOD",
2737 zp_method_comment);
2738 cpl_propertylist_update_double(jitter->plist, "ESO DRS EXTCOEF", extcoef);
2739 cpl_propertylist_set_comment(jitter->plist, "ESO DRS EXTCOEF",
2740 extcoef_comment);
2741
2742 /* and to the catalogue header */
2743
2744 if (jitter->objects && jitter->objects->qclist) {
2745 cpl_propertylist_update_double(jitter->objects->qclist,
2746 "ESO QC MAGZPT", default_zp);
2747 cpl_propertylist_set_comment(jitter->objects->qclist,
2748 "ESO QC MAGZPT", magzpt_comment);
2749 cpl_propertylist_update_double(jitter->objects->qclist,
2750 "ESO QC MAGZERR", default_zp_err);
2751 cpl_propertylist_set_comment(jitter->objects->qclist,
2752 "ESO QC MAGZERR", magzerr_comment);
2753 cpl_propertylist_update_double(jitter->objects->qclist, "PHOTZP",
2754 photzp);
2755 cpl_propertylist_set_comment(jitter->objects->qclist, "PHOTZP",
2756 photzp_comment);
2757 cpl_propertylist_update_string(jitter->objects->qclist,
2758 "ZPMETHOD", zp_method);
2759 cpl_propertylist_set_comment(jitter->objects->qclist,
2760 "ZPMETHOD", zp_method_comment);
2761 cpl_propertylist_update_double(jitter->plist, "ESO DRS EXTCOEF",
2762 extcoef);
2763 cpl_propertylist_set_comment(jitter->plist, "ESO DRS EXTCOEF",
2764 extcoef_comment);
2765 }
2766
2767cleanup:
2768
2769 cpl_table_delete(phot_data);
2770 return cpl_error_get_code();
2771}
2772
2773
2774/*----------------------------------------------------------------------------*/
2783/*----------------------------------------------------------------------------*/
2784
2785static cpl_error_code eris_nix_img_cal_phot_external(
2786 cpl_frameset * frameset,
2787 const cpl_parameterlist * parlist,
2788 located_imagelist * standards,
2789 located_imagelist * jitters,
2790 const char * out_catg,
2791 const char * recipe_name) {
2792
2793 cpl_msg_info(cpl_func, "..transferring photometric calibration from %s",
2794 cpl_frame_get_filename(standards->limages[0]->frame));
2795
2796 /* get the filter used for the observation, check that it is the same
2797 as in the calibrated image */
2798
2799 const char * filter = enu_get_filter(jitters->limages[0]->plist);
2800 const char * std_filter = cpl_propertylist_get_string(
2801 standards->limages[0]->plist,
2802 "FILTER");
2803 enu_check(!strcmp(filter, std_filter), CPL_ERROR_INCOMPATIBLE_INPUT,
2804 "Standard field filter (%s) does not match "
2805 "target (%s)", std_filter, filter);
2806
2807 /* Read the photometric calibration of the standard image.
2808 MAGZPT is for the image normalised by EXPTIME and at zenith */
2809
2810 const double magzpt = cpl_propertylist_get_double(
2811 standards->limages[0]->plist, "ESO QC MAGZPT");
2812 const char * magzpt_comment = cpl_propertylist_get_comment(
2813 standards->limages[0]->plist,
2814 "ESO QC MAGZPT");
2815 const double magzerr = cpl_propertylist_get_double(
2816 standards->limages[0]->plist, "ESO QC MAGZERR");
2817 const char * magzerr_comment = cpl_propertylist_get_comment(
2818 standards->limages[0]->plist,
2819 "ESO QC MAGZERR");
2820 const char * photzp_comment = cpl_propertylist_get_comment(
2821 standards->limages[0]->plist, "PHOTZP");
2822
2823 /* read the atmospheric extinction assumed for the standard field
2824 and the zeropoint at zenith */
2825
2826 const double extcoef = cpl_propertylist_get_double(
2827 standards->limages[0]->plist,
2828 "ESO DRS EXTCOEF");
2829 const char * extcoef_comment = "[mag] Assumed extinction coefficient";
2830/*
2831 const char * extcoef_comment = cpl_propertylist_get_comment(
2832 standards->limages[0]->plist, "EXTCOEF");
2833*/
2834
2835 /* save the photometric calibrated jitter images to FITS files */
2836
2837 for (cpl_size j = 0; j < jitters->size; j++) {
2838
2839 /* PHOTZP absorbs the exposure time and extinction for the jitter
2840 so this correction can be applied directly to the image data.
2841 NIX data are in DN/sec so here exposure time = 1 */
2842
2843 const double airmass = enu_get_airmass(jitters->limages[j]->plist);
2844 const double extinct = extcoef * (airmass - 1.0);
2845 const double exptime = 1.0;
2846 const double photzp = magzpt + 2.5*log10(exptime) - extinct;
2847
2848 /* write the calibration keywords to the jitter header */
2849
2850 cpl_propertylist_update_string(jitters->limages[j]->plist,
2851 "FLUXCAL", "ABSOLUTE");
2852 cpl_propertylist_set_comment(jitters->limages[j]->plist, "FLUXCAL",
2853 "quality of flux calibration");
2854 cpl_propertylist_update_double(jitters->limages[j]->plist,
2855 "ESO QC MAGZPT", magzpt);
2856 cpl_propertylist_set_comment(jitters->limages[j]->plist,
2857 "ESO QC MAGZPT", magzpt_comment);
2858 cpl_propertylist_update_double(jitters->limages[j]->plist,
2859 "ESO QC MAGZERR", magzerr);
2860 cpl_propertylist_set_comment(jitters->limages[j]->plist,
2861 "ESO QC MAGZERR", magzerr_comment);
2862 cpl_propertylist_update_double(jitters->limages[j]->plist,
2863 "PHOTZP", photzp);
2864 cpl_propertylist_set_comment(jitters->limages[j]->plist,
2865 "PHOTZP", photzp_comment);
2866 cpl_propertylist_update_double(jitters->limages[j]->plist,
2867 "ESO DRS EXTCOEF", extcoef);
2868 cpl_propertylist_set_comment(jitters->limages[j]->plist,
2869 "ESO DRS EXTCOEF", extcoef_comment);
2870
2871 /* and to the catalogue header, if present */
2872
2873 if (jitters->limages[j]->objects) {
2874 cpl_propertylist_update_double(jitters->limages[j]->objects->qclist,
2875 "ESO QC MAGZPT", magzpt);
2876 cpl_propertylist_set_comment(jitters->limages[j]->objects->qclist,
2877 "ESO QC MAGZPT", magzpt_comment);
2878 cpl_propertylist_update_double(jitters->limages[j]->objects->qclist,
2879 "ESO QC MAGZERR", magzerr);
2880 cpl_propertylist_set_comment(jitters->limages[j]->objects->qclist,
2881 "ESO QC MAGZERR", magzerr_comment);
2882 cpl_propertylist_update_double(jitters->limages[j]->objects->qclist,
2883 "PHOTZP", photzp);
2884 cpl_propertylist_set_comment(jitters->limages[j]->objects->qclist,
2885 "PHOTZP", photzp_comment);
2886 cpl_propertylist_update_double(jitters->limages[j]->objects->qclist,
2887 "ESO DRS EXTCOEF", extcoef);
2888 cpl_propertylist_set_comment(jitters->limages[j]->objects->qclist,
2889 "ESO DRS EXTCOEF", extcoef_comment);
2890 }
2891
2892 /* Set ZPMETHOD to reflect the calibration method used */
2893
2894 const char * zp_method = "separate_STD_star";
2895 const char * zp_method_comment =
2896 "photometric cal method: "
2897 "separate_STD_star = transfer from other image, "
2898 "science_field_standards = using stds in field, "
2899 "default = default value from phot data file";
2900 cpl_propertylist_update_string(jitters->limages[j]->plist,
2901 "ZPMETHOD", zp_method);
2902 cpl_propertylist_set_comment(jitters->limages[j]->plist,
2903 "ZPMETHOD", zp_method_comment);
2904 if (jitters->limages[j]->objects) {
2905 cpl_propertylist_update_string(jitters->limages[j]->objects->qclist,
2906 "ZPMETHOD", zp_method);
2907 cpl_propertylist_set_comment(jitters->limages[j]->objects->qclist,
2908 "ZPMETHOD", zp_method_comment);
2909 }
2910
2911 /* save the result */
2912
2913 eris_nix_img_cal_phot_save(jitters->limages[j],
2914 out_catg,
2915 frameset,
2916 parlist,
2917 recipe_name);
2918 enu_check_error_code("failure writing result");
2919 }
2920
2921cleanup:
2922
2923 return cpl_error_get_code();
2924}
2925
2926
2927/*----------------------------------------------------------------------------*/
2936/*----------------------------------------------------------------------------*/
2937
2938static cpl_error_code eris_nix_img_cal_phot_internal(
2939 cpl_frameset * frameset,
2940 const cpl_parameterlist * parlist,
2941 located_imagelist * jitters,
2942 const char * out_catg,
2943 const char * recipe_name,
2944 const char* context) {
2945
2946 int casu_status = CASU_OK;
2947 hdrl_parameter * cat_params = NULL;
2948 casu_fits ** in_image_data = NULL;
2949 casu_fits ** in_image_conf = NULL;
2950 casu_fits ** in_image_var = NULL;
2951 casu_tfits ** in_cats = NULL;
2952 casu_tfits ** in_mstds = NULL;
2953 const cpl_parameter * p = NULL;
2954 cpl_table * phot_data = NULL;
2955 cpl_table ** phot_refcat = NULL;
2956 char * param_name = NULL;
2957
2958 cpl_msg_info(cpl_func, "Calibrating using standard stars in field");
2959
2960 /* Retrieve input parameters */
2961
2962 param_name = cpl_sprintf("%s.cdssearch_photom", context);
2963 p = cpl_parameterlist_find_const(parlist, param_name);
2964 const char * cdssearch_photom = cpl_parameter_get_string(p);
2965 cpl_msg_info(cpl_func,"cdssearch_photom: %s",cdssearch_photom);
2966 cpl_free(param_name);
2967
2968 param_name = cpl_sprintf("%s.pixel_radius", context);
2969 p = cpl_parameterlist_find_const(parlist, param_name);
2970 const double pixel_radius = cpl_parameter_get_double(p);
2971 cpl_free(param_name);
2972
2973 param_name = cpl_sprintf("%s.minphotom", context);
2974 p = cpl_parameterlist_find_const(parlist, param_name);
2975 const int minphotom = cpl_parameter_get_int(p);
2976 cpl_free(param_name);
2977
2978 param_name = cpl_sprintf("%s.magerrcut", context);
2979 p = cpl_parameterlist_find_const(parlist, param_name);
2980 const double magerrcut = cpl_parameter_get_double(p);
2981 cpl_free(param_name);
2982
2983 /* some elements of catalogue parameters, gain and saturation,
2984 can be overridden by contents of data files. This is done in a
2985 roundabout way because you can't simply access fields in the
2986 catalogue parameter structure from outside HDRL */
2987
2988 param_name = cpl_sprintf("%s.catalogue.det.effective-gain", context);
2989 p = cpl_parameterlist_find_const(parlist, param_name);
2990 double gain = cpl_parameter_get_double(p);
2991 cpl_free(param_name);
2992
2993 if (cpl_propertylist_has(jitters->limages[0]->plist, "ESO DARK GAIN")) {
2994 cpl_msg_info(cpl_func, "reading detector gain from first jitter");
2995 gain = cpl_propertylist_get_double(jitters->limages[0]->plist,
2996 "ESO DARK GAIN");
2997 }
2998
2999 param_name = cpl_sprintf("%s.catalogue.det.saturation", context);
3000 p = cpl_parameterlist_find_const(parlist, param_name);
3001 double saturation = cpl_parameter_get_double(p);
3002 cpl_free(param_name);
3003
3004 /* saturation in adu/s is DETMON_saturation/dit */
3005 if (cpl_propertylist_has(jitters->limages[0]->plist,
3006 "ESO DETMON SATURATION")) {
3007 cpl_msg_info(cpl_func,
3008 "reading detector saturation level from first jitter");
3009 double saturation_adu = cpl_propertylist_get_double(
3010 jitters->limages[0]->plist,
3011 "ESO DETMON SATURATION");
3012 double dit = enu_get_dit(jitters->limages[0]->plist);
3013 saturation = saturation_adu / dit;
3014 cpl_msg_info(cpl_func,
3015 "saturation(adu)=%5.3e dit=%5.3e saturation(adu/s)=%5.3e",
3016 saturation_adu, dit, saturation);
3017
3018 }
3019
3020 param_name = cpl_sprintf("%s.catalogue.obj.min-pixels", context);
3021 p = cpl_parameterlist_find_const(parlist, param_name);
3022 int minpixels = cpl_parameter_get_int(p);
3023 cpl_free(param_name);
3024
3025 param_name = cpl_sprintf("%s.catalogue.obj.threshold", context);
3026 p = cpl_parameterlist_find_const(parlist, param_name);
3027 double threshold = cpl_parameter_get_double(p);
3028 cpl_free(param_name);
3029
3030 param_name = cpl_sprintf("%s.catalogue.obj.deblending", context);
3031 p = cpl_parameterlist_find_const(parlist, param_name);
3032 cpl_boolean deblending = cpl_parameter_get_bool(p);
3033 cpl_free(param_name);
3034
3035 /* use AOMODE to decide if set catalogue.core-radius and mesh-size to
3036 defaults or read them from parameters */
3037
3038 double core_radius = -1.0;
3039 int mesh_size = -1;
3041 parlist,
3042 jitters->limages[0]->plist,
3043 &core_radius,
3044 &mesh_size);
3045
3046 param_name = cpl_sprintf("%s.catalogue.bkg.estimate", context);
3047 p = cpl_parameterlist_find_const(parlist, param_name);
3048 cpl_boolean estimate = cpl_parameter_get_bool(p);
3049 cpl_free(param_name);
3050
3051 param_name = cpl_sprintf("%s.catalogue.bkg.smooth-gauss-fwhm",
3052 context);
3053 p = cpl_parameterlist_find_const(parlist, param_name);
3054 double smooth_gauss_fwhm = cpl_parameter_get_double(p);
3055 cpl_free(param_name);
3056
3057 cat_params = hdrl_catalogue_parameter_create(minpixels,
3058 threshold,
3059 deblending,
3060 core_radius,
3061 estimate,
3062 mesh_size,
3063 smooth_gauss_fwhm,
3064 gain,
3065 saturation,
3066 HDRL_CATALOGUE_ALL);
3067
3068 cpl_msg_info(cpl_func, "gain=%4.2f saturation=%6.2f", gain, saturation);
3069
3070 enu_check_error_code("Could not retrieve input parameters");
3071 enu_check(strcmp(cdssearch_photom, "none"), CPL_ERROR_ILLEGAL_INPUT,
3072 "photometric catalogue not specified");
3073
3074 /* Read in the data file with default photometric values */
3075
3076 cpl_frame * phot_data_frame = cpl_frameset_find (frameset,
3077 ERIS_NIX_PHOT_DATA_PRO_CATG);
3078 const char * phot_data_file = cpl_frame_get_filename (phot_data_frame);
3079 enu_check_error_code("Failed to read NIX photometry file name");
3080
3081 cpl_msg_info(cpl_func, "..reading instrument photometric properties "
3082 "from %s", phot_data_file);
3083 cpl_size phot_ext = cpl_fits_find_extension(phot_data_file,
3084 cdssearch_photom);
3085 enu_check(phot_ext > 0, CPL_ERROR_INCOMPATIBLE_INPUT,
3086 "photometry information for '%s' not found in %s",
3087 cdssearch_photom, phot_data_file);
3088 phot_data = cpl_table_load(phot_data_file, phot_ext, 0);
3089
3090 /* cast any double columns to float to suit casu */
3091
3092 cal_phot_cast_columns_to_float(phot_data);
3093
3094 /* get the filter used for the observation and the relevant line of
3095 the phot_data table */
3096
3097 const char * filter = enu_get_filter(jitters->limages[0]->plist);
3098 enu_check_error_code("Failed to read filter name from file");
3099
3100 /* comparison is treated as a regular expression */
3101 char * comparison = cpl_sprintf("^%s$", filter);
3102 cpl_size nsel = cpl_table_and_selected_string(phot_data, "filter_name",
3103 CPL_EQUAL_TO, comparison);
3104 cpl_free(comparison);
3105 if (nsel == 1) {
3106 cpl_msg_info(cpl_func, "Filter %s located in %s", filter,
3107 phot_data_file);
3108 cpl_table * selected = cpl_table_extract_selected(phot_data);
3109 cpl_table_dump(selected, 0, 10, NULL);
3110 cpl_table_delete(selected);
3111 cpl_table_select_all(phot_data);
3112 } else {
3113 cpl_error_set_message(cpl_func, CPL_ERROR_INCOMPATIBLE_INPUT,
3114 "No entry for filter %s in %s", filter,
3115 phot_data_file);
3116 }
3117 enu_check_error_code("Failure to read photometry data for filter %s",
3118 filter);
3119
3120 /* generate object catalogues for each image */
3121
3122 enu_catalogue_limlist(jitters, cat_params);
3123
3124 /* copy a few things to FITS places that casu_photcal_extinct expects */
3125
3126 for (cpl_size j = 0; j < jitters->size; j++) {
3127 /* tell the CASU routine via CEXPTIME that the exposure time to
3128 use in magnitude calculations is 1 sec. This is because the
3129 linearization process outputs results in DM/sec */
3130 cpl_propertylist_update_double(jitters->limages[j]->plist,
3131 "CEXPTIME", 1.0);
3132
3133 if (jitters->limages[j]->objects) {
3134 cpl_propertylist * phu = jitters->limages[j]->plist;
3135 cpl_propertylist * ehu = jitters->limages[j]->objects->qclist;
3136
3137 /* exptime for photcal_extinct is 1 sec, as the images are in
3138 DN/sec. Store this in temporary keyword that photcal_extinct
3139 can access */
3140
3141 /* pixel scale, arcsec/pix */
3142 double cd1_1 = cpl_propertylist_get_double(phu, "CD1_1");
3143 double cd2_1 = cpl_propertylist_get_double(phu, "CD2_1");
3144 double pixsize = sqrt(cd1_1 * cd1_1 + cd2_1 * cd2_1) * 3600.0;
3145 cpl_propertylist_update_float(phu, "ESO QC WCS_SCALE",
3146 (float) pixsize);
3147
3148 /* sky noise */
3149 double val = cpl_propertylist_get_double(ehu, "ESO QC SKY_NOISE");
3150 cpl_propertylist_update_float(ehu, "ESO DRS SKYNOISE", (float) val);
3151
3152 /* mean sky */
3153 val = cpl_propertylist_get_double(ehu, "ESO QC MEAN_SKY");
3154 /* set skylevel to a very small number. Should be 0 as sky has been
3155 subtracted but its log is taken in casu_photcal_extinct. */
3156 cpl_propertylist_update_double(ehu, "ESO DRS SKYLEVEL",
3157 max(val, 0.01));
3158
3159 /* ESO QC IMAGE_SIZE claims to be the average fwhm
3160 of stellar objects in pixels */
3161
3162 double fwhm_pix = cpl_propertylist_get_double(
3163 ehu, "ESO QC IMAGE_SIZE");
3164
3165 /* casu_photcal_extinct expects PSF_FWHM in arcsec, if known */
3166 if (fwhm_pix > 0) {
3167 double fwhm = fwhm_pix * pixsize;
3168 cpl_propertylist_update_double(ehu, "PSF_FWHM", (float)fwhm);
3169 cpl_propertylist_set_comment(ehu, "PSF_FWHM", "[arcsec] Average "
3170 "FWHM of stellar objects");
3171 }
3172
3173 /* also cast any double table columns to float to suit casu */
3174 if (jitters->limages[j]->objects->catalogue) {
3175 cal_phot_cast_columns_to_float(jitters->limages[j]->objects->
3176 catalogue);
3177 }
3178 }
3179 }
3180
3181 /* Convert jitter data to casu_tfits */
3182
3183 encu_limlist_to_casu_fits(jitters, &in_image_data, &in_image_conf,
3184 &in_image_var);
3185
3186 /* Initialise in_cats and in_mstds to values that will be safely
3187 deleted if something goes wrong */
3188
3189 in_cats = cpl_malloc(jitters->size * sizeof(casu_tfits *));
3190 in_mstds = cpl_malloc(jitters->size * sizeof(casu_tfits *));
3191 phot_refcat = cpl_malloc(jitters->size * sizeof(cpl_table *));
3192
3193 for (cpl_size j = 0; j < jitters->size; j++) {
3194 in_mstds[j] = cpl_malloc(sizeof(casu_tfits));
3195 in_mstds[j]->table = NULL;
3196 in_mstds[j]->phu = NULL;
3197 in_mstds[j]->ehu = NULL;
3198 in_mstds[j]->fname = NULL;
3199 in_mstds[j]->extname = NULL;
3200 in_mstds[j]->fullname = NULL;
3201 in_mstds[j]->nexten = -1;
3202 in_mstds[j]->status = CASU_OK;
3203
3204 in_cats[j] = cpl_malloc(sizeof(casu_tfits));
3205 in_cats[j]->table = NULL;
3206 in_cats[j]->phu = NULL;
3207 in_cats[j]->ehu = NULL;
3208 in_cats[j]->fname = NULL;
3209 in_cats[j]->extname = NULL;
3210 in_cats[j]->fullname = NULL;
3211 in_cats[j]->nexten = -1;
3212 in_cats[j]->status = CASU_OK;
3213
3214 phot_refcat[j] = NULL;
3215 }
3216
3217 /* Now populate in_mstds and in_cats with values to be used by
3218 casu_photcal_extinct */
3219
3220 for (cpl_size j = 0; j < jitters->size; j++) {
3221 cpl_msg_info(cpl_func, "processing jitter %d", (int)j);
3222
3223 /* be wary of empty (NULL) catalogues */
3224
3225 if (jitters->limages[j]->objects) {
3226 in_cats[j]->table = cpl_table_duplicate(jitters->limages[j]->
3227 objects->catalogue);
3228 in_cats[j]->phu = cpl_propertylist_duplicate(jitters->limages[j]->
3229 plist);
3230 in_cats[j]->ehu = cpl_propertylist_duplicate(jitters->limages[j]->
3231 objects->qclist);
3232 in_cats[j]->fname = cpl_strdup(cpl_frame_get_filename(
3233 jitters->limages[j]->frame));
3234
3235 /* use casu_getstds to read in photom reference catalogue entries
3236 for the area covered by the jitter, the routine also adds
3237 some columns used by casu_photcal_extinct*/
3238
3239 /* check not in error state before entry. If error set then
3240 casu_getstds will fail, ptentially with a confusing error
3241 message */
3242
3243 enu_check_error_code("error before calling casu_getstds");
3244 phot_refcat[j] = NULL;
3245 casu_status = CASU_OK;
3246 casu_getstds(jitters->limages[j]->plist, CPL_FALSE,
3247 NULL,
3248 (char*) "2MASS",
3249 1, NULL, &phot_refcat[j], NULL,
3250 &casu_status);
3251 //cpl_msg_info(cpl_func, "casu %d", (int)casu_status);
3252 if (phot_refcat[j] == NULL) {
3253 cpl_msg_info(cpl_func, "...no phot standards found");
3254 } else {
3255 en_catalogue_name_conformance(phot_refcat[j]);
3256 cpl_size nstds = cpl_table_get_nrow(phot_refcat[j]);
3257 cpl_msg_info(cpl_func, "...%d phot standards read", (int)nstds);
3258
3259 /* populate in_mstds by associating image catalogue objects with
3260 those in the reference catalog, again beware NULL catalogues
3261 (from detecting no sources in the image) */
3262
3263 const int strict = 0;
3264 enm_associate_std(jitters->limages[j]->objects->catalogue,
3265 phot_refcat[j], pixel_radius, strict,
3266 &(in_mstds[j]->table));
3267 enu_check_error_code("Failure trying to match standards: %s",
3268 cpl_error_get_message());
3269
3270 /* cast any double columns to float to suit casu */
3271
3272 cal_phot_cast_columns_to_float(in_mstds[j]->table);
3273 in_mstds[j]->phu = cpl_propertylist_new();
3274 in_mstds[j]->ehu = cpl_propertylist_new();
3275 enu_check(casu_status == CASU_OK, CPL_ERROR_ILLEGAL_INPUT,
3276 "casu_matchstds failure status : %d", casu_status);
3277 }
3278
3279 } else {
3280
3281 /* No objects found hence no object catalogue. Add some dummy
3282 propertylists to keep casu_photcal_extinct happy - it will
3283 write to them */
3284
3285 cpl_msg_info(cpl_func, ".no objects detected in field");
3286 in_cats[j]->phu = cpl_propertylist_new();
3287 in_cats[j]->ehu = cpl_propertylist_new();
3288 }
3289
3290 /* If for some reason there are no matched standards then point
3291 to an empty table rather than NULL. casu_photcal_extinct can
3292 handle the former but not the latter
3293
3294 Also, add some empty propertylists for casu_photcal_extinct
3295 to write results into, otherwise it will fail */
3296
3297 if (in_mstds[j]->table == NULL) {
3298 in_mstds[j]->table = cpl_table_new(0);
3299 in_mstds[j]->phu = cpl_propertylist_new();
3300 in_mstds[j]->ehu = cpl_propertylist_new();
3301 }
3302 }
3303
3304 /* Now do the photometric calibration */
3305
3306 cpl_msg_info(cpl_func, "performing photometric calibration");
3307 casu_status = CASU_OK;
3308 char * filter_copy = cpl_strdup(filter);
3309 casu_photcal_extinct(in_image_data,
3310 in_mstds,
3311 in_cats,
3312 jitters->size,
3313 filter_copy,
3314 phot_data,
3315 minphotom,
3316 NULL, NULL,
3317 "CEXPTIME",
3318 "ESO TEL AIRM START",
3319 magerrcut,
3320 &casu_status);
3321 cpl_free(filter_copy);
3322 enu_check_error_code("Failure in casu_photcal_extinct: %s",
3323 cpl_error_get_message());
3324
3325 /* assess the calibration and save the photometric calibrated jitter
3326 images to FITS files */
3327
3328 for (cpl_size j = 0; j < jitters->size; j++) {
3329
3330 const char * fluxcal = cpl_propertylist_get_string(
3331 in_image_data[j]->phu,
3332 "FLUXCAL");
3333
3334 if (!strcmp(fluxcal, "UNCALIBRATED")) {
3335
3336 /* did the casu flux calibration succeed? An outright failure
3337 will have casu_photcal_extinct set FLUXCAL to
3338 'UNCALIBRATED'. In this case set the default result */
3339
3340 cpl_msg_warning(cpl_func, "casu_photcal_extinct has returned "
3341 "a bad result, applying default");
3342 eris_nix_img_cal_phot_default(frameset, jitters->limages[j]);
3343
3344 } else {
3345
3346 /* otherwise set the result returned by casu_photcal_extinct */
3347
3348 /* ..for in_image_data the phu and ehu are both copies of
3349 the original limage->plist. ehu is the one updated by
3350 casu_photcal_extinct - now copy it back to get the updates.
3351 *except for FLUXCAL which is set in phu*/
3352
3353 cpl_propertylist_delete(jitters->limages[j]->plist);
3354 jitters->limages[j]->plist = cpl_propertylist_duplicate(
3355 in_image_data[j]->ehu);
3356 cpl_propertylist_set_string(jitters->limages[j]->plist, "FLUXCAL",
3357 fluxcal);
3358
3359 /* add the photometric system */
3360
3361 cpl_propertylist_update_string(jitters->limages[j]->plist,
3362 "PHOTSYS", "VEGA");
3363
3364 /* Set ZPMETHOD to reflect the calibration method used
3365 If casu_photcal_extinct has left keyword ZPFUDGED==True
3366 then the calibration failed and the routine itself
3367 set zp/zp error to default values from file */
3368
3369 const int zpfudged = cpl_propertylist_get_bool(
3370 jitters->limages[j]->plist, "ZPFUDGED");
3371
3372 const char * zp_method = NULL;
3373 const char * zp_comment = NULL;
3374 if (zpfudged) {
3375 zp_method = "DEFAULT";
3376 zp_comment = "ZP taken from filter default value";
3377 } else {
3378 zp_method = "2MASS";
3379 zp_comment = "ZP computed from 2MASS sources in the field";
3380 }
3381 cpl_propertylist_update_string(jitters->limages[j]->plist,
3382 "ZPMETHOD", zp_method);
3383 cpl_propertylist_set_comment(jitters->limages[j]->plist,
3384 "ZPMETHOD", zp_comment);
3385 cpl_msg_info(cpl_func, "set ZPMETHOD %s", zp_method);
3386
3387 if (!strcmp(zp_method, "2MASS")) {
3388 cpl_propertylist_update_string(jitters->limages[j]->plist,
3389 "ZP_CAT", cdssearch_photom);
3390 }
3391
3392 /* copy updated plist to image catalogue */
3393
3394 if (jitters->limages[j]->objects &&
3395 jitters->limages[j]->objects->qclist) {
3396 cpl_propertylist_delete(jitters->limages[j]->objects->qclist);
3397 jitters->limages[j]->objects->qclist =
3398 cpl_propertylist_duplicate(
3399 in_cats[j]->ehu);
3400 cpl_propertylist_update_string(
3401 jitters->limages[j]->objects->qclist,
3402 "ZPMETHOD", zp_method);
3403 cpl_propertylist_update_string(
3404 jitters->limages[j]->objects->qclist,
3405 "PHOTSYS", "VEGA");
3406 }
3407
3408 /* if they exist and contain any rows, copy matched stds catalogues
3409 and associated qclist to limage */
3410
3411 if (in_mstds[j] &&
3412 in_mstds[j]->table &&
3413 cpl_table_get_nrow(in_mstds[j]->table) > 0) {
3414 jitters->limages[j]->matchstd_phot = cpl_calloc(
3415 sizeof(hdrl_catalogue_result), 1);
3416 jitters->limages[j]->matchstd_phot->catalogue =
3417 cpl_table_duplicate(in_mstds[j]->table);
3418 jitters->limages[j]->matchstd_phot->qclist =
3419 cpl_propertylist_duplicate(
3420 in_mstds[j]->ehu);
3421 cpl_propertylist_update_string(jitters->limages[j]->
3422 matchstd_phot->qclist,
3423 "ZPMETHOD",
3424 zp_method);
3425 if (!strcmp(zp_method, "science_field_standards")) {
3426 cpl_propertylist_update_string(jitters->limages[j]->
3427 matchstd_phot->qclist, "ZP_CAT",
3428 cdssearch_photom);
3429 }
3430 }
3431 }
3432
3433 /* Save the result */
3434
3435 eris_nix_img_cal_phot_save(jitters->limages[j],
3436 out_catg,
3437 frameset,
3438 parlist,
3439 recipe_name);
3440 enu_check_error_code("failure writing result");
3441
3442 /* save the reference catalogue */
3443
3444 if (phot_refcat[j]) {
3445 enu_dfs_save_catalogue(frameset,
3446 jitters->limages[j]->frame,
3447 parlist,
3448 phot_refcat[j],
3449 NULL,
3450 cdssearch_photom,
3451 recipe_name,
3452 PACKAGE "/" PACKAGE_VERSION,
3453 "refcat.cal_phot",
3454 ERIS_NIX_CAL_PHOT_REF_CATALOGUE_PRO_CATG);
3455 }
3456
3457 /* save the matched standards catalogue */
3458
3459 if (jitters->limages[j]->matchstd_phot &&
3460 jitters->limages[j]->matchstd_phot->catalogue) {
3461
3462 enu_dfs_save_catalogue(frameset,
3463 jitters->limages[j]->frame,
3464 parlist,
3465 jitters->limages[j]->matchstd_phot->catalogue,
3466 jitters->limages[j]->matchstd_phot->qclist,
3467 "2MASS",
3468 recipe_name,
3469 PACKAGE "/" PACKAGE_VERSION,
3470 "matchcat.cal_phot",
3471 ERIS_NIX_CAL_PHOT_MATCH_CATALOGUE_PRO_CATG);
3472 }
3473
3474 /* save the catalogue of sources in the image itself */
3475
3476 if (jitters->limages[j]->objects &&
3477 jitters->limages[j]->objects->catalogue) {
3478
3479 enu_dfs_save_catalogue(frameset,
3480 jitters->limages[j]->frame,
3481 parlist,
3482 jitters->limages[j]->objects->catalogue,
3483 jitters->limages[j]->objects->qclist,
3484 cpl_frame_get_filename(jitters->
3485 limages[j]->
3486 frame),
3487 recipe_name,
3488 PACKAGE "/" PACKAGE_VERSION,
3489 "cat.cal_phot",
3490 ERIS_NIX_CAL_PHOT_CATALOGUE_PRO_CATG);
3491 }
3492 }
3493
3494cleanup:
3495 hdrl_parameter_delete(cat_params);
3496 if (jitters) {
3497 if (in_image_data) {
3498 for (cpl_size j = 0; j < jitters->size; j++) {
3499 if (in_image_data[j]) casu_fits_unwrap(in_image_data[j]);
3500 }
3501 cpl_free(in_image_data);
3502 }
3503 if (in_image_var) {
3504 for (cpl_size j = 0; j < jitters->size; j++) {
3505 if (in_image_var[j]) casu_fits_unwrap(in_image_var[j]);
3506 }
3507 cpl_free(in_image_var);
3508 }
3509 if (in_image_conf) {
3510 for (cpl_size j = 0; j < jitters->size; j++) {
3511 if (in_image_conf[j]) casu_fits_unwrap(in_image_conf[j]);
3512 }
3513 cpl_free(in_image_conf);
3514 }
3515 casu_tfits_delete_list(in_cats, (int)jitters->size);
3516 casu_tfits_delete_list(in_mstds, jitters->size);
3517 if (phot_refcat != NULL) {
3518 for (cpl_size j = 0; j < jitters->size; j++) {
3519 cpl_table_delete(phot_refcat[j]);
3520 }
3521 }
3522 }
3523 cpl_table_delete(phot_data);
3524 cpl_free(phot_refcat);
3525 eris_check_error_code("eris_nix_img_cal_phot_internal");
3526 return cpl_error_get_code();
3527}
3528
3529
3530/*----------------------------------------------------------------------------*/
3542/*----------------------------------------------------------------------------*/
3543cpl_error_code eris_nix_scired_cal_phot(cpl_frameset * frameset,
3544 const cpl_parameterlist * parlist,
3545 const char * recipe_name,
3546 const char* context) {
3547
3548 located_imagelist * jitters = NULL;
3549 located_imagelist * object_jitters = NULL;
3550 located_imagelist * standards = NULL;
3551 located_imagelist * std_jitters = NULL;
3552 cpl_frameset * used = NULL;
3553
3554 enu_check_error_code("%s():%d: An error is already set: %s",
3555 cpl_func, __LINE__, cpl_error_get_where());
3556
3557 cpl_ensure_code(frameset, CPL_ERROR_NULL_INPUT);
3558 cpl_ensure_code(parlist, CPL_ERROR_NULL_INPUT);
3559
3560 /* Set the msg verbosity level from environment variable CPL_MSG_LEVEL
3561 - not working, so set manually for now */
3562
3563 cpl_msg_set_level_from_env();
3564 cpl_msg_severity severity = cpl_msg_get_level();
3565 cpl_msg_info(cpl_func, "level %d", (int) severity);
3566
3567 /* check for invalid input */
3568 if(eris_files_dont_exist(frameset) != CPL_ERROR_NONE) {
3569 return CPL_ERROR_BAD_FILE_FORMAT;
3570 }
3571 /* check required input tags are present */
3572 const int ntags = 1;
3573 const char* required_tags[1] = {
3574 ERIS_NIX_PHOT_DATA_PRO_CATG
3575 };
3576
3577 // ERIS_NIX_SKYSUB_OBJECT_JITTER_PRO_CATG, or ERIS_NIX_SKYSUB_STD_JITTER_PRO_CATG
3578 cpl_ensure_code(CPL_ERROR_NONE ==
3579 eris_dfs_check_input_tags(frameset, required_tags, ntags, 1),
3580 CPL_ERROR_ILLEGAL_INPUT);
3581
3582 const int ntags_opt = 3;
3583 const char* optional_tags[3] = {
3584 ERIS_NIX_CAL_WCS_MATCH_CATALOGUE_PRO_CATG, // opt
3585 ERIS_NIX_CAL_WCS_REF_CATALOGUE_PRO_CATG, // opt
3586 ERIS_NIX_CAL_WCS_CATALOGUE_PRO_CATG //opt
3587 };
3588
3589 // ERIS_NIX_SKYSUB_OBJECT_JITTER_PRO_CATG, or ERIS_NIX_SKYSUB_STD_JITTER_PRO_CATG
3590 cpl_ensure_code(CPL_ERROR_NONE ==
3591 eris_dfs_check_input_tags(frameset, optional_tags, ntags_opt, 0),
3592 CPL_ERROR_ILLEGAL_INPUT);
3593
3594 /* Some initialization */
3595
3596 used = cpl_frameset_new();
3597
3598 /* Identify the RAW and CALIB frames in the input frameset */
3599
3600 eris_nix_dfs_set_groups(frameset);
3601 enu_check_error_code("Could not identify RAW and CALIB frames");
3602
3603 /* Read in images to be calibrated */
3604
3605 object_jitters = enu_limlist_load_from_frameset(frameset,
3606 ERIS_NIX_CAL_WCS_OBJECT_JITTER_PRO_CATG, used);
3607 enu_check_error_code("Failed to read object jitter data");
3608 std_jitters = enu_limlist_load_from_frameset(frameset,
3609 ERIS_NIX_CAL_WCS_STD_JITTER_PRO_CATG, used);
3610 enu_check_error_code("Failed to read STD jitter data");
3611
3612 cpl_msg_info(cpl_func, "%d %s frames read", (int) object_jitters->size,
3613 ERIS_NIX_CAL_WCS_OBJECT_JITTER_PRO_CATG);
3614 cpl_msg_info(cpl_func, "%d %s frames read", (int) std_jitters->size,
3615 ERIS_NIX_CAL_WCS_STD_JITTER_PRO_CATG);
3616
3617 /* check that the data files in the SoF are as expected */
3618
3619 enu_check(object_jitters->size > 0 || std_jitters->size > 0,
3620 CPL_ERROR_DATA_NOT_FOUND, "no input frames found");
3621 enu_check(!(object_jitters->size > 0 && std_jitters->size > 0),
3622 CPL_ERROR_ILLEGAL_INPUT, "SoF contains both "
3623 ERIS_NIX_CAL_WCS_OBJECT_JITTER_PRO_CATG" and "
3624 ERIS_NIX_CAL_WCS_STD_JITTER_PRO_CATG" frames");
3625
3626 /* set the catg of the output data */
3627
3628 const char * out_catg = NULL;
3629 if (object_jitters->size > 0) {
3630 jitters = object_jitters;
3631 out_catg = ERIS_NIX_CAL_PHOT_OBJECT_JITTER_PRO_CATG;
3632 enu_located_imagelist_delete(std_jitters);
3633 std_jitters = NULL;
3634 } else {
3635 jitters = std_jitters;
3636 out_catg = ERIS_NIX_CAL_PHOT_STD_JITTER_PRO_CATG;
3637 enu_located_imagelist_delete(object_jitters);
3638 object_jitters = NULL;
3639 }
3640
3641 /* The calibration method depends on whether a photometrically calibrated
3642 frame is present in the SoF. If so, then transfer its calibration.
3643 If not, try to calibrate the frames using their own measured
3644 standards. */
3645
3646 standards = enu_limlist_load_from_frameset(frameset,
3647 ERIS_NIX_IMG_STD_COMBINED_PRO_CATG, used);
3648 enu_check_error_code("Failed to read external standard");
3649 if (standards->size > 0) {
3650 cpl_msg_info(cpl_func, "%d "
3651 ERIS_NIX_IMG_STD_COMBINED_PRO_CATG" frames read",
3652 (int) standards->size);
3653 }
3654
3655 if (standards->size == 0) {
3656
3657 /* Not transferring calibration from another frame.
3658 Is the wcs astrometry calibration absolute? */
3659
3660 int absolute_wcs = CPL_FALSE;
3661
3662 for (cpl_size j = 0; j < jitters->size; j++) {
3663
3664 const char * wcs_method;
3665 if (cpl_propertylist_has(jitters->limages[j]->plist,"ESO WCS_METHOD")) {
3666 wcs_method = cpl_propertylist_get_string(
3667 jitters->limages[j]->plist,
3668 "ESO WCS_METHOD");
3669 } else {
3670 /* old version may have stored the WCS method without prefix. Thus allow also this option */
3671 wcs_method = cpl_propertylist_get_string(
3672 jitters->limages[j]->plist,
3673 "WCS_METHOD");
3674 }
3675
3676 cpl_msg_info(cpl_func,"jitter %d wcs_method: %s", (int)j, wcs_method);
3677 if (!strcmp(wcs_method, ERIS_NIX_WCS_CATALOGUE_MATCH)) {
3678 absolute_wcs = CPL_TRUE;
3679 }
3680 }
3681 enu_check_error_code("failed to determine type of wcs calibration");
3682
3683 if (absolute_wcs) {
3684
3685 /* Calibrate using standards measured in field */
3686
3687 eris_nix_img_cal_phot_internal(frameset,
3688 parlist,
3689 jitters,
3690 out_catg,
3691 recipe_name, context);
3692 enu_check_error_code("error attempting internal photometric "
3693 "calibration");
3694 } else {
3695
3696 for (cpl_size j = 0; j < jitters->size; j++) {
3697
3698 /* Set zeropoint to default value for filter */
3699
3700 cpl_msg_info(cpl_func, "..astrometry calibration is not absolute");
3701 eris_nix_img_cal_phot_default(frameset,
3702 jitters->limages[j]);
3703 enu_check_error_code("error setting default photometric "
3704 "calibration");
3705
3706 /* and write the result */
3707
3708 eris_nix_img_cal_phot_save(jitters->limages[j],
3709 out_catg,
3710 frameset,
3711 parlist,
3712 recipe_name);
3713 enu_check_error_code("failure writing result");
3714 }
3715 }
3716
3717 } else if (standards->size == 1){
3718
3719 /* Transfer calibration from the external image */
3720
3721 eris_nix_img_cal_phot_external(frameset,
3722 parlist,
3723 standards,
3724 jitters,
3725 out_catg,
3726 recipe_name);
3727 enu_check_error_code("error attempting external photometric "
3728 "calibration");
3729 } else {
3730 cpl_error_set_message(cpl_func, CPL_ERROR_INCOMPATIBLE_INPUT,
3731 "only one "
3732 ERIS_NIX_IMG_STD_COMBINED_PRO_CATG
3733 " file is allowed, found %d",
3734 (int) standards->size);
3735 }
3736
3737cleanup:
3738 enu_located_imagelist_delete(object_jitters);
3739 enu_located_imagelist_delete(std_jitters);
3741 cpl_frameset_delete(used);
3742
3743 return (int) cpl_error_get_code();
3744}
3745
3746
3747/*----------------------------------------------------------------------------*/
3762/*----------------------------------------------------------------------------*/
3763cpl_error_code eris_nix_scired_hdrl_stack(cpl_frameset * frameset,
3764 const cpl_parameterlist * parlist,
3765 const char* recipe_name,
3766 const char* context) {
3767
3768 cpl_propertylist * applist = NULL;
3769 cpl_property * bunit = NULL;
3770 hdrl_parameter * cat_params = NULL;
3771 cpl_property * fluxcal_0 = NULL;
3772 const char * funcid = "eris_nix_img_hdrl_stack";
3773 cpl_frame * inherit = NULL;
3774 located_imagelist * jitters = NULL;
3775 cpl_property * jitter_psf_fwhm = NULL;
3776 hdrl_parameter * method = NULL;
3777 located_imagelist * object_jitters = NULL;
3778 cpl_vector * obsid = NULL;
3779 hdrl_parameter * outgrid = NULL;
3780 char * photsys_0 = NULL;
3781 char * proto_copy = NULL;
3782 cpl_frameset * provenance = NULL;
3783 cpl_table * restable = NULL;
3784 hdrl_resample_result * result = NULL;
3785 cpl_image * stack_conf = NULL;
3786 cpl_propertylist * stack_header = NULL;
3787 hdrl_image * stack_himage = NULL;
3788 located_image * stacked = NULL;
3789 located_imagelist * std_jitters = NULL;
3790 cpl_propertylist * tablelist = NULL;
3791 cpl_wcs * template_wcs = NULL;
3792 cpl_frameset * used = NULL;
3793 cpl_property * zp_method_0 = NULL;
3794 const cpl_parameter * p = NULL;
3795 char * param_name = NULL;
3796
3797 enu_check_error_code("%s():%d: An error is already set: %s",
3798 cpl_func, __LINE__, cpl_error_get_where());
3799
3800 /* Check input parameters */
3801
3802 cpl_ensure_code(frameset, CPL_ERROR_NULL_INPUT);
3803 cpl_ensure_code(parlist, CPL_ERROR_NULL_INPUT);
3804
3805 cpl_msg_set_level_from_env();
3806
3807 /* check for invalid input */
3808 if(eris_files_dont_exist(frameset) != CPL_ERROR_NONE) {
3809 return CPL_ERROR_BAD_FILE_FORMAT;
3810 }
3811 /* Retrieve input parameters */
3812
3813 /* .. the resampling method and parameters */
3814 param_name = cpl_sprintf("%s.interpolation_method", context);
3815 p = cpl_parameterlist_find_const(parlist, param_name);
3816 const char * interpolation_method = cpl_parameter_get_string(p);
3817 cpl_free(param_name);
3818
3819 param_name = cpl_sprintf("%s.loop_distance", context);
3820 p = cpl_parameterlist_find_const(parlist, param_name);
3821 const int loop_distance = cpl_parameter_get_int(p);
3822 cpl_free(param_name);
3823
3824 /* don't weight by image errors */
3825 const cpl_boolean use_errorweights = CPL_FALSE;
3826
3827 param_name = cpl_sprintf("%s.kernel_size", context);
3828 p = cpl_parameterlist_find_const(parlist, param_name);
3829 const int kernel_size = cpl_parameter_get_int(p);
3830 cpl_free(param_name);
3831
3832 param_name = cpl_sprintf("%s.critical_radius", context);
3833 p = cpl_parameterlist_find_const(parlist, param_name);
3834 const double critical_radius = cpl_parameter_get_double(p);
3835 cpl_free(param_name);
3836
3837 param_name = cpl_sprintf("%s.pix_frac_x", context);
3838 p = cpl_parameterlist_find_const(parlist, param_name);
3839 const double pix_frac_x = cpl_parameter_get_double(p);
3840 cpl_free(param_name);
3841
3842 param_name = cpl_sprintf("%s.pix_frac_y", context);
3843 p = cpl_parameterlist_find_const(parlist, param_name);
3844 const double pix_frac_y = cpl_parameter_get_double(p);
3845 cpl_free(param_name);
3846
3847 const double pix_frac_lambda = 100.0;
3848
3849 enu_check_error_code("Could not retrieve input parameters");
3850
3851
3852 if (!strcmp(interpolation_method, "nearest")) {
3854 } else if (!strcmp(interpolation_method, "linear")) {
3855 method = hdrl_resample_parameter_create_linear(loop_distance,
3856 use_errorweights);
3857 } else if (!strcmp(interpolation_method, "quadratic")) {
3858 method = hdrl_resample_parameter_create_quadratic(loop_distance,
3859 use_errorweights);
3860 } else if (!strcmp(interpolation_method, "renka")) {
3861 method = hdrl_resample_parameter_create_renka(loop_distance,
3862 use_errorweights,
3863 critical_radius);
3864 } else if (!strcmp(interpolation_method, "drizzle")) {
3865 method = hdrl_resample_parameter_create_drizzle(loop_distance,
3866 use_errorweights,
3867 pix_frac_x,
3868 pix_frac_y,
3869 pix_frac_lambda);
3870 } else if (!strcmp(interpolation_method, "lanczos")) {
3871 method = hdrl_resample_parameter_create_lanczos(loop_distance,
3872 use_errorweights,
3873 kernel_size);
3874 } else {
3875 cpl_error_set_message(cpl_func, CPL_ERROR_ILLEGAL_INPUT,
3876 "bad interpolation method: %s",
3877 interpolation_method);
3878 }
3879 enu_check_error_code("Error constructing interpolation method");
3880
3881 /* Identify the RAW and CALIB frames in the input frameset */
3882
3883 eris_nix_dfs_set_groups(frameset);
3884 enu_check_error_code("Could not identify RAW and CALIB frames");
3885
3886 /* read the input frameset */
3887
3888 used = cpl_frameset_new();
3889 object_jitters = enu_limlist_load_from_frameset(frameset,
3890 ERIS_NIX_CAL_PHOT_OBJECT_JITTER_PRO_CATG, used);
3891 enu_check_error_code("Could not read %s frames",
3892 ERIS_NIX_CAL_PHOT_OBJECT_JITTER_PRO_CATG);
3893 cpl_msg_info(funcid, "%d %s frames read", (int) object_jitters->size,
3894 ERIS_NIX_CAL_PHOT_OBJECT_JITTER_PRO_CATG);
3895 std_jitters = enu_limlist_load_from_frameset(frameset,
3896 ERIS_NIX_CAL_PHOT_STD_JITTER_PRO_CATG, used);
3897 enu_check_error_code("Could not read %s frames",
3898 ERIS_NIX_CAL_PHOT_STD_JITTER_PRO_CATG);
3899 cpl_msg_info(funcid, "%d %s frames read", (int) std_jitters->size,
3900 ERIS_NIX_CAL_PHOT_STD_JITTER_PRO_CATG);
3901
3902 /* is this a target object or standard? */
3903
3904 enu_check(!(object_jitters->size > 0 && std_jitters->size > 0),
3905 CPL_ERROR_ILLEGAL_INPUT,
3906 "SoF cannot contain data for both target and standard");
3907 enu_check(!(object_jitters->size == 0 && std_jitters->size == 0),
3908 CPL_ERROR_DATA_NOT_FOUND,
3909 "SoF contains no data");
3910 const char * out_catg = NULL;
3911 if(object_jitters->size > 0) {
3912 jitters = object_jitters;
3913 out_catg = ERIS_NIX_IMG_OBS_COMBINED_PRO_CATG;
3914 enu_located_imagelist_delete(std_jitters);
3915 std_jitters = NULL;
3916 } else {
3917 jitters = std_jitters;
3918 out_catg = ERIS_NIX_IMG_STD_COMBINED_PRO_CATG;
3919 enu_located_imagelist_delete(object_jitters);
3920 object_jitters = NULL;
3921 }
3922
3923
3924
3925 /* estimate the centre of the jitter pattern */
3926
3927 float diff[1000];
3928 for (cpl_size i = 0; i < jitters->size; i++) {
3929 diff[i] = cpl_propertylist_get_double(jitters->limages[i]->plist,
3930 "CRVAL1");
3931 }
3932 float ra_centre = casu_med(diff, NULL, jitters->size);
3933 for (cpl_size i = 0; i < jitters->size; i++) {
3934 diff[i] = cpl_propertylist_get_double(jitters->limages[i]->plist,
3935 "CRVAL2");
3936 }
3937 float dec_centre = casu_med(diff, NULL, jitters->size);
3938 cpl_msg_info(cpl_func, "Jitter pattern centre at RA=%10.7f Dec=%10.7f",
3939 ra_centre, dec_centre);
3940
3941
3942
3943 cpl_size jitter_ref = -1;
3944 double minr2 = 1.0e6;
3945 for (cpl_size i = 0; i < jitters->size; i++) {
3946 double ra = cpl_propertylist_get_double(jitters->limages[i]->plist,
3947 "CRVAL1");
3948 double dec = cpl_propertylist_get_double(jitters->limages[i]->plist,
3949 "CRVAL2");
3950 double r2 = pow(ra - ra_centre, 2) + pow(dec - dec_centre, 2);
3951 if (r2 < minr2) {
3952 jitter_ref = i;
3953 minr2 = r2;
3954 }
3955 }
3956 cpl_msg_info(cpl_func, "Nearest jitter to centre is %d", (int) jitter_ref);
3957 char * refname = cpl_strdup(cpl_frame_get_filename(jitters->
3958 limages[jitter_ref]->frame));
3959 cpl_msg_info(cpl_func, "..filename %s", basename(refname));
3960 cpl_free(refname);
3961
3962 /* AMo: TODO creates a mask to trim pixels at image edge. Maybe we can also remove
3963 entries from catalog without using a mask */
3964
3965 cpl_size sx = hdrl_image_get_size_x(jitters->limages[jitter_ref]->himage);
3966 cpl_size sy = hdrl_image_get_size_y(jitters->limages[jitter_ref]->himage);
3967 cpl_size txmin = 0;
3968 cpl_size tymin = 0;
3969 cpl_size txmax = 0;
3970 cpl_size tymax = 0;
3971 eris_nix_scired_get_split_param_int(parlist, context, "edges-trim", 1, 1,
3972 sx, sy, &txmin, &tymin, &txmax, &tymax);
3973
3974 cpl_msg_info(cpl_func,"trim edge params: %lld %lld %lld %lld", txmin, tymin, txmax, tymax);
3975 cpl_image* image_edge = cpl_image_new(sx, sy, CPL_TYPE_INT);
3976 if(txmin > 1 && txmin < sx/2) {
3977 cpl_image_fill_window(image_edge,1, 1, txmin, sy, 1);
3978 }
3979
3980 if(txmax > 1 && txmax < sx/2) {
3981 cpl_image_fill_window(image_edge,sx - txmax, 1, sx, sy, 1);
3982 }
3983
3984 if(tymin > 1 && tymin < sy/2) {
3985 cpl_image_fill_window(image_edge,1, 1, sx, tymin, 1);
3986 }
3987
3988 if(tymax > 1 && tymax < sy/2) {
3989 cpl_image_fill_window(image_edge,1, sy - tymax, sx, sy, 1);
3990 }
3991 cpl_mask* mask_edge = cpl_mask_threshold_image_create(image_edge,0.9, 1.1);
3992 cpl_image_delete(image_edge);
3993 cpl_mask_save(mask_edge, "mask_edge.fits", NULL, CPL_IO_DEFAULT);
3994 //cpl_mask* hmask = hdrl_image_get_mask(jitters->limages[jitter_ref]->himage);
3995 //cpl_mask_or(hmask, mask_edge);
3996 for(cpl_size k = 0; k < jitters->size; k++) {
3997 hdrl_image_reject_from_mask(jitters->limages[k]->himage, mask_edge);
3998 cpl_image_reject_from_mask(jitters->limages[k]->confidence, mask_edge);
3999 }
4000
4001
4002
4003
4004 cpl_mask_delete(mask_edge);
4005 /* AMo: END coded added to trim edges of any input image (to prevent outliers to affect WCS sol) */
4006
4007
4008
4009
4010
4011 /* get some info from jitters that we will need after they have been
4012 deleted */
4013
4014 cpl_size njitters = jitters->size;
4015 const char * proto = cpl_frame_get_filename((jitters->limages[0])->
4016 frame);
4017 proto_copy = cpl_strdup(proto);
4018
4019 inherit = cpl_frame_duplicate(jitters->limages[0]->frame);
4020
4021 /* Loop through the jitter images and populate the resampling table */
4022
4023 obsid = cpl_vector_new(jitters->size);
4024 cpl_vector_fill(obsid, -1.0);
4025 int ncombine = 0;
4026 double total_exptime = 0.0;
4027 double mjd_start = 1000000.0;
4028 double mjd_end = 0.0;
4029
4030 /* take pixel scale and wcs from first jitter file */
4031
4032 double cd1_1 = cpl_propertylist_get_double(jitters->limages[0]->plist,
4033 "CD1_1");
4034 double cd2_1 = cpl_propertylist_get_double(jitters->limages[0]->plist,
4035 "CD2_1");
4036 double pixsize = sqrt(cd1_1 * cd1_1 + cd2_1 * cd2_1) * 3600.0;
4037 cpl_msg_info(cpl_func, "pixel scale: %6.4f arcsec", pixsize);
4038 template_wcs = cpl_wcs_new_from_propertylist(jitters->limages[0]->plist);
4039 enu_check_error_code("error set after loading template wcs");
4040
4041 /* some elements of catalogue parameters can be overridden by contents
4042 of data files. This is done in a roundabout way because you can't
4043 simply access fields in the catalogue parameter structure from
4044 outside HDRL */
4045
4046 param_name = cpl_sprintf("%s.catalogue.det.effective-gain", context);
4047 p = cpl_parameterlist_find_const(parlist, param_name);
4048 double gain = cpl_parameter_get_double(p);
4049 cpl_free(param_name);
4050
4051 if (cpl_propertylist_has(jitters->limages[0]->plist, "ESO DARK GAIN")) {
4052 cpl_msg_info(cpl_func, "reading detector gain from first jitter");
4053 gain = cpl_propertylist_get_double(jitters->limages[0]->plist,
4054 "ESO DARK GAIN");
4055 }
4056
4057 param_name = cpl_sprintf("%s.catalogue.det.saturation", context);
4058 p = cpl_parameterlist_find_const(parlist, param_name);
4059 double saturation = cpl_parameter_get_double(p);
4060 cpl_free(param_name);
4061
4062 /* saturation in adu/s is DETMON_saturation/dit */
4063 if (cpl_propertylist_has(jitters->limages[0]->plist,
4064 "ESO DETMON SATURATION")) {
4065 cpl_msg_info(cpl_func,
4066 "reading detector saturation level from first jitter");
4067 double saturation_adu = cpl_propertylist_get_double(
4068 jitters->limages[0]->plist,
4069 "ESO DETMON SATURATION");
4070 double dit = enu_get_dit(jitters->limages[0]->plist);
4071 saturation = saturation_adu / dit;
4072 cpl_msg_info(cpl_func,
4073 "saturation(adu)=%5.3e dit=%5.3e saturation(adu/s)=%5.3e",
4074 saturation_adu, dit, saturation);
4075
4076 }
4077
4078 param_name = cpl_sprintf("%s.catalogue.obj.min-pixels", context);
4079 p = cpl_parameterlist_find_const(parlist, param_name);
4080 int minpixels = cpl_parameter_get_int(p);
4081 cpl_free(param_name);
4082
4083 param_name = cpl_sprintf("%s.catalogue.obj.threshold", context);
4084 p = cpl_parameterlist_find_const(parlist, param_name);
4085 double threshold = cpl_parameter_get_double(p);
4086 cpl_free(param_name);
4087
4088 param_name = cpl_sprintf("%s.catalogue.obj.deblending", context);
4089 p = cpl_parameterlist_find_const(parlist, param_name);
4090 cpl_boolean deblending = cpl_parameter_get_bool(p);
4091 cpl_free(param_name);
4092
4093 /* use AOMODE to decide if set catalogue.core-radius and mesh-size to
4094 defaults or read them from parameters */
4095
4096 double core_radius = -1.0;
4097 int mesh_size = -1;
4099 parlist,
4100 jitters->limages[0]->plist,
4101 &core_radius,
4102 &mesh_size);
4103
4104 param_name = cpl_sprintf("%s.catalogue.bkg.estimate", context);
4105 p = cpl_parameterlist_find_const(parlist, param_name);
4106 cpl_boolean estimate = cpl_parameter_get_bool(p);
4107 cpl_free(param_name);
4108
4109 param_name = cpl_sprintf("%s.catalogue.bkg.smooth-gauss-fwhm",
4110 context);
4111 p = cpl_parameterlist_find_const(parlist, param_name);
4112 double smooth_gauss_fwhm = cpl_parameter_get_double(p);
4113 cpl_free(param_name);
4114
4115 cat_params = hdrl_catalogue_parameter_create(minpixels,
4116 threshold,
4117 deblending,
4118 core_radius,
4119 estimate,
4120 mesh_size,
4121 smooth_gauss_fwhm,
4122 gain,
4123 saturation,
4124 HDRL_CATALOGUE_ALL);
4125 enu_check_error_code("error set after setting catalogue params");
4126
4127 cpl_msg_info(cpl_func, "gain=%4.2f saturation=%6.2f", gain, saturation);
4128
4129 provenance = cpl_frameset_new();
4130
4131 cpl_msg_info(cpl_func, "assembling information on combined exposures");
4132
4133 for (cpl_size j = 0; j < jitters->size; j++) {
4134
4135 /* add the frame to the provenance of images contributing
4136 to the result */
4137
4138 cpl_frameset_insert(provenance, cpl_frame_duplicate(
4139 jitters->limages[j]->frame));
4140
4141 /* calculate some other things needed by the DFS to describe
4142 what has gone into the measurement */
4143
4144 if (!bunit) {
4145 bunit = cpl_property_duplicate(cpl_propertylist_get_property(
4146 jitters->limages[j]->plist,
4147 "BUNIT"));
4148 }
4149
4150 if (!jitter_psf_fwhm) {
4151 jitter_psf_fwhm = cpl_property_duplicate(
4152 cpl_propertylist_get_property(
4153 jitters->limages[j]->plist,
4154 "PSF_FWHM"));
4155 }
4156
4157 /* .. number of measurements combined */
4158
4159 ncombine++;
4160
4161 /* .. total integration time */
4162
4163 double dit = enu_get_dit(jitters->limages[j]->plist);
4164 double exptime = dit * cpl_propertylist_get_int(
4165 jitters->limages[j]->plist, "ESO DET NDIT");
4166 total_exptime += exptime;
4167
4168 /* .. MJD of start and end of measurements used */
4169
4170 double jitter_start = cpl_propertylist_get_double(
4171 jitters->limages[j]->plist, "MJD-OBS");
4172 if (jitter_start < mjd_start) {
4173 mjd_start = jitter_start;
4174 }
4175 double jitter_end = cpl_propertylist_get_double(
4176 jitters->limages[j]->plist, "MJD-END");
4177 if (jitter_end > mjd_end) {
4178 mjd_end = jitter_end;
4179 }
4180 cpl_msg_info(cpl_func, "..combined mjd start: %15.8f end: %15.8f",
4181 mjd_start, mjd_end);
4182
4183 /* .. the OBS_IDs of the component measurements, no duplicates */
4184
4185 int obs_id = cpl_propertylist_get_int(jitters->limages[j]->plist,
4186 "ESO OBS ID");
4187 for (cpl_size jj = 0; jj < cpl_vector_get_size(obsid); jj++) {
4188 if ((int) cpl_vector_get(obsid, jj) == obs_id) {
4189 break;
4190 } else if (cpl_vector_get(obsid, jj) < 0.0) {
4191 cpl_vector_set(obsid, jj, obs_id);
4192 break;
4193 }
4194 }
4195 }
4196
4197 /* set the output grid */
4198
4199 outgrid = hdrl_resample_parameter_create_outgrid2D(pixsize / 3600.0,
4200 pixsize / 3600.0);
4201
4202 double photzp_0 = 0.0;
4203 double photzper_0 = 0.0;
4204 double extcoef_0 = 0.0;
4205
4206 cpl_msg_info(cpl_func, "stacking image data");
4207 {
4208
4209 for (cpl_size j = 0; j < jitters->size; j++) {
4210 cpl_msg_info(cpl_func, "ingesting jitter %d", (int)j);
4211
4212 /* get calibration info */
4213
4214 const cpl_property * fluxcal_j = cpl_propertylist_get_property(
4215 jitters->limages[j]->plist, "FLUXCAL");
4216 const char * photsys_j = cpl_propertylist_get_string(
4217 jitters->limages[j]->plist, "PHOTSYS");
4218 const cpl_property * zp_method_j = cpl_propertylist_get_property(
4219 jitters->limages[j]->plist,
4220 "ZPMETHOD");
4221 double photzp_j = cpl_propertylist_get_double(
4222 jitters->limages[j]->plist, "PHOTZP");
4223 double photzper_j = cpl_propertylist_get_double(
4224 jitters->limages[j]->plist, "PHOTZPER");
4225 double extcoef_j = cpl_propertylist_get_double(
4226 jitters->limages[j]->plist,
4227 "ESO DRS EXTCOEF");
4228
4229 cpl_msg_info(cpl_func, "..fluxcal: %s",
4230 cpl_property_get_string(fluxcal_j));
4231 cpl_msg_info(cpl_func, "..photsys: %s", photsys_j);
4232 cpl_msg_info(cpl_func, "..extcoef: %f", extcoef_j);
4233 cpl_msg_info(cpl_func, "..zp_method: %s",
4234 cpl_property_get_string(zp_method_j));
4235 cpl_msg_info(cpl_func, "..photzp: %f photzper: %f", photzp_j,
4236 photzper_j);
4237
4238 if (j == 0) {
4239 photzp_0 = photzp_j;
4240 photzper_0 = photzper_j;
4241 fluxcal_0 = cpl_property_duplicate(fluxcal_j);
4242 photsys_0 = cpl_strdup(photsys_j);
4243 zp_method_0 = cpl_property_duplicate(zp_method_j);
4244 extcoef_0 = extcoef_j;
4245 } else {
4246
4247 if (!strcmp(cpl_property_get_string(fluxcal_j), "CALIBRATED")) {
4248 cpl_msg_warning(cpl_func, "jitter is not calbrated");
4249 }
4250 if (strcmp(photsys_j, "VEGA")) {
4251 cpl_msg_warning(cpl_func, "PHOTSYS is not recognized");
4252 }
4253 if (extcoef_j != extcoef_0) {
4254 cpl_msg_warning(cpl_func,
4255 "..inconsistent extcoef: %d %5.3e %5.3e",
4256 (int) j, extcoef_0, extcoef_j);
4257 }
4258
4259 /* other checks? */
4260 }
4261
4262 /* factor to multiply jitter j to get on same intensity scale as
4263 jitter 0 */
4264
4265 double factor = pow(10.0, (photzp_0 - photzp_j) / 2.5);
4266 cpl_msg_info(cpl_func, "..scaling jitter %d by %5.3e", (int)j,
4267 factor);
4268 hdrl_image_mul_scalar(jitters->limages[j]->himage,
4269 (hdrl_value){factor, 0.0});
4270
4271 /* The following commented-out code snippet would be useful if
4272 we wanted to weight according to the confidence array. In
4273 this case use_errorweights would be set TRUE in resampling
4274 'method' so that 'an additional weight defined as 1/variance'
4275 would be applied. To use confidence rather than pixel
4276 variance the 'resampling variance' should be 1/confidence,
4277 and the 'resampling error' the sqrt of that.
4278
4279 Not being done now because I don't think it's currently
4280 possible to resample the image errors weighted by
4281 the confidence. */
4282/*
4283 cpl_image * inverse_conf = cpl_image_duplicate(
4284 jitters->limages[j]->confidence);
4285 double * ic_data = cpl_image_get_data_double(inverse_conf);
4286 const cpl_size nx = cpl_image_get_size_x(inverse_conf);
4287 const cpl_size ny = cpl_image_get_size_y(inverse_conf);
4288 for (cpl_size i=0; i<nx*ny; i++) {
4289*/
4290 /* assume case of 0 confidence pixel is also 'bad' in image */
4291/*
4292 if (ic_data[i] > 0.0) {
4293 ic_data[i] = sqrt(1.0 / ic_data[i]);
4294 }
4295 }
4296*/
4297
4298 /* add the jitter to the resampling table */
4299
4300 cpl_wcs * wcs = cpl_wcs_new_from_propertylist(
4301 jitters->limages[j]->plist);
4302 cpl_table * jitter_table = hdrl_resample_image_to_table(
4303 jitters->limages[j]->himage,
4304 wcs);
4305 cpl_wcs_delete(wcs);
4306
4307 if (restable == NULL) {
4308 restable = jitter_table;
4309 } else {
4310 cpl_size nrow = cpl_table_get_nrow(restable);
4311 cpl_table_insert(restable, jitter_table, nrow+1);
4312 cpl_table_delete(jitter_table);
4313 }
4314 }
4315
4316 enu_check_error_code("error set after loading jitters");
4317
4318 /* delete the jitters to free up memory */
4319
4320 enu_located_imagelist_delete(jitters); jitters = NULL;
4321 object_jitters = std_jitters = NULL;
4322
4323 /* Stack the jitter image data */
4324
4325 cpl_msg_info(cpl_func, "calling hdrl_resample_compute");
4326 result = hdrl_resample_compute(restable, method, outgrid,
4327 template_wcs);
4328
4329 /* release the resampling table as no longer needed */
4330
4331 cpl_table_delete(restable); restable = NULL;
4332 enu_check_error_code("error set computing resample_compute");
4333
4334 /* keep the resampled image and header for later but delete the
4335 rest of the result */
4336
4337 stack_himage = hdrl_image_duplicate(
4339 result->himlist, 0));
4340 stack_header = cpl_propertylist_duplicate(result->header);
4341 hdrl_resample_result_delete(result); result = NULL;
4342 }
4343
4344 cpl_msg_info(cpl_func, "stacking the confidence");
4345
4346 {
4347 /* reload jitter data, with fewer checks this time*/
4348
4349 cpl_frameset * ignore = cpl_frameset_new();
4350 object_jitters = enu_limlist_load_from_frameset(frameset,
4351 ERIS_NIX_CAL_PHOT_OBJECT_JITTER_PRO_CATG,
4352 ignore);
4353 std_jitters = enu_limlist_load_from_frameset(frameset,
4354 ERIS_NIX_CAL_PHOT_STD_JITTER_PRO_CATG,
4355 ignore);
4356 if(object_jitters->size > 0) {
4357 jitters = object_jitters;
4358 enu_located_imagelist_delete(std_jitters); std_jitters = NULL;
4359 } else {
4360 jitters = std_jitters;
4361 enu_located_imagelist_delete(object_jitters); object_jitters = NULL;
4362 }
4363
4364 /* build the data table */
4365
4366 for (cpl_size j = 0; j < jitters->size; j++) {
4367 cpl_msg_info(cpl_func, "ingesting jitter %d", (int)j);
4368
4369 double photzp_j = cpl_propertylist_get_double(
4370 jitters->limages[j]->plist, "PHOTZP");
4371
4372 double factor = pow(10.0, (photzp_0 - photzp_j) / 2.5);
4373 cpl_msg_info(cpl_func, "..scaling by %5.3e", factor);
4374 hdrl_image_mul_scalar(jitters->limages[j]->himage,
4375 (hdrl_value){factor, 0.0});
4376
4377 /* To resample the confidence we replace the data error
4378 plane with numbers derived from the confidence. Confidence
4379 is 1 / variance so we want error = sqrt(1 / confidence) */
4380
4381 cpl_image * inverse_conf = cpl_image_duplicate(
4382 jitters->limages[j]->confidence);
4383 double * ic_data = cpl_image_get_data_double(inverse_conf);
4384 const cpl_size nx = cpl_image_get_size_x(inverse_conf);
4385 const cpl_size ny = cpl_image_get_size_y(inverse_conf);
4386 for (cpl_size i=0; i<nx*ny; i++) {
4387 if (ic_data[i] > 0.0) {
4388 ic_data[i] = sqrt(1.0 / ic_data[i]);
4389 }
4390 }
4391
4392 hdrl_image * jitter_error = hdrl_image_create(hdrl_image_get_image(
4393 jitters->limages[j]->himage),
4394 inverse_conf);
4395 cpl_wcs * wcs = cpl_wcs_new_from_propertylist(
4396 jitters->limages[j]->plist);
4397 cpl_table * jitter_table = hdrl_resample_image_to_table(
4398 jitter_error,
4399 wcs);
4400 cpl_wcs_delete(wcs);
4401 cpl_image_delete(inverse_conf);
4402 hdrl_image_delete(jitter_error);
4403
4404 if (restable == NULL) {
4405 restable = jitter_table;
4406 } else {
4407 cpl_size nrow = cpl_table_get_nrow(restable);
4408 cpl_table_insert(restable, jitter_table, nrow+1);
4409 cpl_table_delete(jitter_table);
4410 }
4411 }
4412
4413 enu_located_imagelist_delete(jitters); jitters = NULL;
4414 object_jitters = std_jitters = NULL;
4415 enu_check_error_code("error set after loading error image of jitters");
4416
4417 cpl_msg_info(cpl_func, "calling hdrl_resample_compute");
4418 result = hdrl_resample_compute(restable, method, outgrid, template_wcs);
4419 cpl_table_delete(restable); restable = NULL;
4420 enu_check_error_code("error after resample_compute of image confidence");
4421
4422 /* Calculate the confidence from the result errors. Raw confidence is
4423 1 / variance or result_error / result_error^3 */
4424
4425 stack_conf = cpl_image_duplicate(
4428 result->himlist, 0)));
4429 cpl_image * sc_copy = cpl_image_duplicate(stack_conf);
4430 cpl_image_divide(stack_conf, sc_copy);
4431 cpl_image_divide(stack_conf, sc_copy);
4432 cpl_image_divide(stack_conf, sc_copy);
4433 cpl_image_delete(sc_copy);
4434
4435 enu_normalise_confidence(stack_conf);
4436
4437 hdrl_resample_result_delete(result); result = NULL;
4438 }
4439
4440 /* assemble result. hdrl_create makes copies, located_image_new takes
4441 ownership, hence the different memory management */
4442
4443 stacked = enu_located_image_new(stack_himage,
4444 NULL,
4445 stack_conf,
4446 NULL,
4447 NULL,
4448 stack_header,
4449 NULL,
4450 NULL,
4451 NULL,
4452 NULL,
4453 NULL);
4454 enu_check_error_code("error set after image stacking");
4455
4456 /* generate a source catalogue for the stacked result */
4457
4458 cpl_wcs * result_wcs = cpl_wcs_new_from_propertylist(stacked->plist);
4459 stacked->objects = enu_catalogue_compute(stacked->himage,
4460 stacked->confidence,
4461 result_wcs,
4462 cat_params);
4463 cpl_wcs_delete(result_wcs);
4464 enu_check_error_code("error in target reduction: catalogue");
4465
4466 /* add result properties in applist */
4467
4468 applist = cpl_propertylist_new();
4469
4470 /* update PRO.CATG and stack info */
4471
4472 cpl_propertylist_update_string(applist, CPL_DFS_PRO_CATG, out_catg);
4473 cpl_propertylist_update_string(applist, "PRODCATG", "SCIENCE.IMAGE");
4474 cpl_propertylist_update_string(applist, "BUNIT", cpl_property_get_string(bunit));
4475 cpl_propertylist_set_comment(applist, "BUNIT", cpl_property_get_comment(bunit));
4476 cpl_propertylist_update_int(applist, "NCOMBINE", ncombine);
4477 cpl_propertylist_update_double(applist, "TEXPTIME", total_exptime);
4478 cpl_propertylist_update_double(applist, "EXPTIME", total_exptime);
4479 cpl_propertylist_update_double(applist, "MJD-OBS", mjd_start);
4480 cpl_propertylist_update_double(applist, "MJD-END", mjd_end);
4481 for (cpl_size j = 0; j < njitters; ++j) {
4482 if (cpl_vector_get(obsid, j) > 0.0) {
4483 char * pname = cpl_sprintf("OBID%.0i", (int)(j+1));
4484 cpl_propertylist_update_int(applist, pname,
4485 (int)cpl_vector_get(obsid, j));
4486 cpl_free(pname);
4487 }
4488 }
4489
4490 /* write PHOTZP info */
4491
4492 cpl_propertylist_update_string(applist, "PHOTSYS", photsys_0);
4493 cpl_propertylist_update_double(applist, "PHOTZP", photzp_0);
4494 cpl_propertylist_set_comment(applist, "PHOTZP",
4495 "MAG=-2.5*log(data)+PHOTZP+APCOR");
4496 cpl_propertylist_update_string(applist, "FLUXCAL",
4497 cpl_property_get_string(fluxcal_0));
4498 cpl_propertylist_set_comment(applist, "FLUXCAL",
4499 cpl_property_get_comment(fluxcal_0));
4500 cpl_propertylist_update_double(applist, "PHOTZPER", photzper_0);
4501 cpl_propertylist_update_string(applist, "ZPMETHOD",
4502 cpl_property_get_string(zp_method_0));
4503 cpl_propertylist_set_comment(applist, "ZPMETHOD",
4504 cpl_property_get_comment(zp_method_0));
4505 cpl_propertylist_update_double(applist, "ESO DRS EXTCOEF", extcoef_0);
4506 cpl_propertylist_set_comment(applist, "ESO DRS EXTCOEF",
4507 "[mag] Assumed extinction coefficient");
4508
4509 /* try to get actual fwhm from catalogue, failing that use the PSF
4510 from the first stacked image */
4511
4512 double fwhm_pix = -1.0;
4513 if (stacked->objects &&
4514 stacked->objects->qclist &&
4515 cpl_propertylist_has(stacked->objects->qclist, "ESO QC IMAGE_SIZE")) {
4516
4517 fwhm_pix = cpl_propertylist_get_double(stacked->objects->qclist,
4518 "ESO QC IMAGE_SIZE");
4519 }
4520
4521 if (fwhm_pix != -1.0) {
4522 cpl_propertylist_update_double(applist, "PSF_FWHM",
4523 fwhm_pix * pixsize);
4524 cpl_propertylist_set_comment(applist, "PSF_FWHM",
4525 "Average FWHM of stellar objects[arcsec]");
4526 } else {
4527 cpl_propertylist_update_double(applist, "PSF_FWHM",
4528 cpl_property_get_double(jitter_psf_fwhm));
4529 cpl_propertylist_set_comment(applist, "PSF_FWHM",
4530 cpl_property_get_comment(jitter_psf_fwhm));
4531 fwhm_pix = cpl_property_get_double(jitter_psf_fwhm) / pixsize;
4532 }
4533
4534 double abmaglim = -1.0;
4535 enu_calc_maglim(stacked, photzp_0, fwhm_pix, &abmaglim);
4536 cpl_propertylist_update_double(applist, "ABMAGLIM", abmaglim);
4537 cpl_propertylist_set_comment(applist, "ABMAGLIM", "5-sigma "
4538 "limiting AB magnitude");
4539
4540 /* ABMAGSAT. Data calibrated as photons/s so exptime=1 for calculation.
4541 Formula copied from CASU casu_calculate_abmag_sat */
4542
4543 double mean_sky = 0.0;
4544 if (cpl_propertylist_has(stacked->objects->qclist, "ESO QC MEAN_SKY")) {
4545 mean_sky = cpl_propertylist_get_double(stacked->objects->qclist,
4546 "ESO QC MEAN_SKY");
4547 } else {
4548 cpl_msg_warning(cpl_func, "ESO QC MEAN_SKY not found, mean "
4549 "sky assumed 0");
4550 }
4551 double exptime = 1.0;
4552 double abmagsat = -1.0;
4553 if ((CPL_MATH_PI_4 * CPL_MATH_LN2 * (saturation - mean_sky) *
4554 pow(fwhm_pix, 2.0) / exptime) > 0.0) {
4555 abmagsat = photzp_0 - 2.5 * log10(CPL_MATH_PI_4 * CPL_MATH_LN2 *
4556 (saturation - mean_sky) * pow(fwhm_pix, 2.0) / exptime);
4557 }
4558 cpl_msg_debug(cpl_func, "abmagsat stack %5.3e %5.3e %5.3e %5.3e %5.3e",
4559 photzp_0, saturation, mean_sky, fwhm_pix, exptime);
4560 cpl_propertylist_update_double(applist, "ABMAGSAT", abmagsat);
4561 cpl_propertylist_set_comment(applist, "ABMAGSAT", "Saturation "
4562 "limit for point sources (AB mag)");
4563
4564 /* set RA, DEC from WCS rather than let dfs copy it from one of the
4565 frames */
4566
4567 {
4568 cpl_wcs * stack_wcs = cpl_wcs_new_from_propertylist(stacked->plist);
4569 double ra = 0.0;
4570 double dec = 0.0;
4571 enu_get_ra_dec(stack_wcs, &ra, &dec);
4572
4573 cpl_propertylist_update_double(applist, "RA", ra);
4574 cpl_propertylist_update_double(applist, "DEC", dec);
4575
4576 cpl_wcs_delete(stack_wcs);
4577 }
4578 enu_check_error_code("error set after setting header keywords");
4579
4580 /* generate name of file with stacked image */
4581
4582 char * stack_fname = enu_repreface(proto_copy, "stack");
4583
4584 enu_dfs_save_limage(frameset,
4585 parlist,
4586 used,
4587 CPL_FALSE,
4588 stacked,
4589 recipe_name,
4590 inherit,
4591 applist,
4592 PACKAGE "/" PACKAGE_VERSION,
4593 stack_fname);
4594
4595 /* save the catalogue */
4596
4597 cpl_frame * stack_frame = cpl_frame_new();
4598 cpl_frame_set_filename(stack_frame, stack_fname);
4599 cpl_frame_set_tag(stack_frame, ERIS_NIX_IMG_CATALOGUE_PRO_CATG);
4600 cpl_frame_set_type(stack_frame, CPL_FRAME_TYPE_ANY);
4601 cpl_frame_set_group(stack_frame, CPL_FRAME_GROUP_PRODUCT);
4602 cpl_frame_set_level(stack_frame, CPL_FRAME_LEVEL_FINAL);
4603 cpl_frameset_insert(used, stack_frame);
4604 cpl_free(stack_fname);
4605
4606 //cpl_table_dump(stacked->objects->catalogue, 1, 10, NULL);
4607
4608 /* ..the header for the table extension */
4609 tablelist = cpl_propertylist_duplicate(stacked->objects->qclist);
4610 cpl_propertylist_copy_property_regexp(tablelist,
4611 applist,
4612 "ABMAGLIM|ABMAGSAT|PSF_FWHM|PHOTSYS|"
4613 "RA|DEC",
4614 CPL_FALSE);
4615 enu_dfs_save_catalogue(frameset,
4616 stack_frame,
4617 parlist,
4618 stacked->objects->catalogue,
4619 tablelist,
4620 "image source catalogue",
4621 recipe_name,
4622 PACKAGE "/" PACKAGE_VERSION,
4623 "cat.stack",
4624 ERIS_NIX_IMG_CATALOGUE_PRO_CATG);
4625
4626 /* useful for outputting stack result with catalogue for debugging
4627 BUT CATALOGUE OUTPUT TBD IN enu_dfs_save_limage */
4628 if (CPL_FALSE) {
4629 cpl_propertylist_update_string(applist, "PRODCATG", "ANCILLARY.IMAGE");
4630 enu_dfs_save_limage(frameset,
4631 parlist,
4632 provenance,
4633 CPL_FALSE,
4634 stacked,
4635 recipe_name,
4636 inherit,
4637 applist,
4638 PACKAGE "/" PACKAGE_VERSION,
4639 "stack_cat_debug.fits");
4640 }
4641
4642cleanup:
4643 cpl_propertylist_delete(applist);
4644 cpl_property_delete(bunit);
4645 hdrl_parameter_delete(cat_params);
4646 cpl_property_delete(fluxcal_0);
4647 cpl_frame_delete(inherit);
4648 cpl_property_delete(jitter_psf_fwhm);
4649 hdrl_parameter_delete(method);
4650 enu_located_imagelist_delete(object_jitters);
4651 cpl_vector_delete(obsid);
4652 hdrl_parameter_delete(outgrid);
4653 cpl_free(photsys_0);
4654 cpl_free(proto_copy);
4655 cpl_frameset_delete(provenance);
4656 cpl_table_delete(restable);
4658 enu_located_image_delete(stacked);
4659 enu_located_imagelist_delete(std_jitters);
4660 cpl_propertylist_delete(tablelist);
4661 cpl_wcs_delete(template_wcs);
4662 cpl_frameset_delete(used);
4663 cpl_property_delete(zp_method_0);
4664
4665 return (int)cpl_error_get_code();
4666}
4667
4668
4669
cpl_error_code encu_limlist_to_casu_fits(located_imagelist *limlist, casu_fits ***indata, casu_fits ***inconf, casu_fits ***invar)
Translate a located_imagelist to arrays of casu_fits structs.
cpl_error_code enu_dfs_save_limage(cpl_frameset *allframes, const cpl_parameterlist *parlist, const cpl_frameset *provenance, const cpl_boolean prov_raw, const located_image *limage, const char *recipe, const cpl_frame *inherit, cpl_propertylist *applist, const char *pipe_id, const char *filename)
Save a located image structure to a MEF.
Definition: eris_nix_dfs.c:909
cpl_error_code eris_nix_dfs_set_groups(cpl_frameset *set)
Set the group as RAW or CALIB in a frameset.
Definition: eris_nix_dfs.c:58
cpl_error_code enu_dfs_save_catalogue(cpl_frameset *frameset, cpl_frame *image, const cpl_parameterlist *parlist, const cpl_table *catalogue, const cpl_propertylist *tablelist, const char *cat_name, const char *recipe, const char *pipe_id, const char *preface, const char *procat)
Save a catalogue as DFS product.
Definition: eris_nix_dfs.c:274
void en_master_bpm_delete(master_bpm *target)
Delete a 'master_bpm' struct.
master_dark * en_master_dark_load_from_frameset(const cpl_frameset *frameset, const char *tag, cpl_frameset *used)
Load a 'master_dark' struct from a frameset.
void en_master_dark_delete(master_dark *target)
Delete a 'master_dark' struct.
cpl_error_code enm_associate_std(cpl_table *objtab, cpl_table *stdtab, const float assoc, const int strict_classification, cpl_table **associated_std)
Associate image catalogue objects with standards.
cpl_error_code eris_nix_scired_hdrl_stack(cpl_frameset *frameset, const cpl_parameterlist *parlist, const char *recipe_name, const char *context)
This rebin and stack a set of calibrated ERIS/NIX jitter frames.
cpl_error_code eris_nix_scired_cal_phot(cpl_frameset *frameset, const cpl_parameterlist *parlist, const char *recipe_name, const char *context)
This recipe calibrates the photometry of ERIS/NIX frames.
cpl_error_code eris_nix_scired_cal_det(cpl_frameset *frameset, const cpl_parameterlist *parlist, const char *recipe_name, const char *context)
This function removes the detector signature from science frames.
cpl_error_code eris_nix_scired_skysub(cpl_frameset *frameset, const cpl_parameterlist *parlist, const char *recipe_name, const char *context)
This recipe estimates and subtracts the sky background from a set of science frames.
cpl_error_code eris_nix_scired_cal_wcs(cpl_frameset *frameset, const cpl_parameterlist *parlist, const char *recipe_name, const char *context)
This recipe calibrates the astrometry of ERIS/NIX frames.
void enu_located_imagelist_delete(located_imagelist *limlist)
Delete a located_imagelist and its contents.
located_image * enu_load_limage_from_frame(const cpl_frame *frame, cpl_image **pcopyconf, const cpl_boolean collapse_cube)
Load components of a located_image from a frame.
located_imagelist * enu_located_imagelist_duplicate(const located_imagelist *limlist)
Make a deep copy of a located_imagelist and its contents.
cpl_error_code enu_calc_maglim(const located_image *limage, const double photzp, const double fwhm_pix, double *abmaglim)
Calculate magnitude limit of image.
cpl_error_code enu_get_ra_dec(const cpl_wcs *wcs, double *ra, double *dec)
Get RA and Dec at centre of image with given wcs.
cpl_error_code enu_basic_calibrate(located_image *limage, const int read_offsets, const cpl_table *refine_wcs, const master_dark *mdark, const gain_linearity *gain_lin, const master_flat *flatfield_1, const master_flat *flatfield_2, const master_bpm *mbad_pix_map, const int flag_mask, const char *fill_rejected, const double fill_value, const cpl_size x_probe, const cpl_size y_probe)
Do basic calibration of located_image (single or cube)
cpl_error_code enu_catalogue_limlist(located_imagelist *limlist, hdrl_parameter *params)
Calculate object catalogues for a list of images.
cpl_error_code enu_sky_subtract_limlist(const char *method, const char *select_method, const double timerange, const located_imagelist *sky_data, const cpl_size x_probe, const cpl_size y_probe, located_imagelist *target_data)
Estimate and subtract sky backgrounds for a list of target images.
cpl_error_code enu_debug_limlist_save(const int debug, const located_imagelist *limlist, const char *nameroot, const char *recipename, cpl_frameset *frameset, const cpl_parameterlist *parlist, const cpl_frameset *used)
Save a list of intermediate image results for use in debugging.
located_image * enu_located_image_new(hdrl_image *himage, hdrl_imagelist *himagelist, cpl_image *confidence, hdrl_image *bkg, cpl_image *bkg_confidence, cpl_propertylist *plist, hdrl_catalogue_result *objects, cpl_mask *object_mask, hdrl_catalogue_result *wcs, hdrl_catalogue_result *photom, cpl_frame *frame)
Create a located_image structure and initialise the contents.
double enu_get_airmass(const cpl_propertylist *plist)
Get the mean airmass of an observation.
cpl_error_code enu_calc_pixel_coords(cpl_table *catalogue, const cpl_propertylist *wcs_plist)
Calculate predicted positions of catalogue objects for given wcs.
located_imagelist * enu_limlist_load_from_frameset(cpl_frameset *frameset, const char *tag, cpl_frameset *used)
Load tagged data from a frameset into a located_imagelist.
void enu_located_image_delete(located_image *limage)
Delete a located_image and its contents.
cpl_error_code enu_normalise_confidence(cpl_image *confidence)
Normalise confidence array so that mean of good pixels is 100.
cpl_error_code enu_correct_wcs(const cpl_table *refcat, const char *wcs_method, const char *catalogue, located_image *limage, const double match_rad, cpl_table **matched_stds, cpl_matrix **xy_shift)
Correct the wcs of an image.
char * enu_repreface(const char *filename, const char *preface)
Preface a raw filename with a string.
const char * enu_get_filter(const cpl_propertylist *plist)
Get the filter used in an observation.
cpl_error_code enu_get_rcore_and_mesh_size(const char *context, const cpl_parameterlist *parlist, const cpl_propertylist *plist, double *obj_core_radius, int *bkg_mesh_size)
Get catalogue core-radius and mesh-size appropriate to AO mode.
hdrl_catalogue_result * enu_catalogue_compute(const hdrl_image *himage, const cpl_image *confidence, const cpl_wcs *wcs, hdrl_parameter *params)
Wrapper for hdrl_catalogue_compute.
cpl_error_code enu_opm_limlist(const int obj_min_pixels, const double obj_threshold, const int bkg_mesh_size, const double bkg_smooth_fwhm, located_imagelist *limlist)
Calculate object masks for images in a located_imagelist.
double enu_get_dit(const cpl_propertylist *plist)
Get the DIT of an integration.
cpl_error_code eris_files_dont_exist(cpl_frameset *frameset)
Check if all SOF files exist.
Definition: eris_utils.c:867
cpl_error_code eris_check_error_code(const char *func_id)
handle CPL errors
Definition: eris_utils.c:56
void hdrl_catalogue_result_delete(hdrl_catalogue_result *result)
delete hdrl parameter result object
hdrl_parameter * hdrl_catalogue_parameter_create(int obj_min_pixels, double obj_threshold, cpl_boolean obj_deblending, double obj_core_radius, cpl_boolean bkg_estimate, int bkg_mesh_size, double bkg_smooth_fwhm, double det_eff_gain, double det_saturation, hdrl_catalogue_options resulttype)
Creates catalogue Parameters object.
cpl_parameterlist * hdrl_catalogue_parameter_create_parlist(const char *base_context, const char *prefix, hdrl_parameter *defaults)
Create parameter list for the catalogue computation.
cpl_error_code hdrl_image_reject_from_mask(hdrl_image *self, const cpl_mask *map)
set bpm of hdrl_image
Definition: hdrl_image.c:407
cpl_error_code hdrl_image_mul_scalar(hdrl_image *self, hdrl_value value)
Elementwise multiplication of an image with a scalar.
hdrl_image * hdrl_image_duplicate(const hdrl_image *himg)
copy hdrl_image
Definition: hdrl_image.c:391
cpl_image * hdrl_image_get_error(hdrl_image *himg)
get error as cpl image
Definition: hdrl_image.c:131
cpl_size hdrl_image_get_size_y(const hdrl_image *self)
return size of Y dimension of image
Definition: hdrl_image.c:540
cpl_size hdrl_image_get_size_x(const hdrl_image *self)
return size of X dimension of image
Definition: hdrl_image.c:525
hdrl_image * hdrl_image_create(const cpl_image *image, const cpl_image *error)
create a new hdrl_image from to existing images by copying them
Definition: hdrl_image.c:295
cpl_image * hdrl_image_get_image(hdrl_image *himg)
get data as cpl image
Definition: hdrl_image.c:105
void hdrl_image_delete(hdrl_image *himg)
delete hdrl_image
Definition: hdrl_image.c:379
hdrl_image * hdrl_imagelist_get(const hdrl_imagelist *himlist, cpl_size inum)
Get an image from a list of images.
void hdrl_parameter_delete(hdrl_parameter *obj)
shallow delete of a parameter
hdrl_parameter * hdrl_resample_parameter_create_nearest(void)
Creates a resample nearest neighbor hdrl parameter object. The algorithm does not use any weighting f...
hdrl_parameter * hdrl_resample_parameter_create_renka(const int loop_distance, cpl_boolean use_errorweights, const double critical_radius)
Creates a resample renka hdrl parameter object. The algorithm uses a modified Shepard-like distance w...
hdrl_parameter * hdrl_resample_parameter_create_lanczos(const int loop_distance, cpl_boolean use_errorweights, const int kernel_size)
Creates a resample Lanczos hdrl parameter object. The algorithm uses a restricted SINC distance weigh...
hdrl_parameter * hdrl_resample_parameter_create_drizzle(const int loop_distance, cpl_boolean use_errorweights, const double pix_frac_x, const double pix_frac_y, const double pix_frac_lambda)
Creates a resample drizzle hdrl parameter object. The algorithm uses a drizzle-like distance weightin...
hdrl_parameter * hdrl_resample_parameter_create_quadratic(const int loop_distance, cpl_boolean use_errorweights)
Creates a resample quadratic hdrl parameter object. The algorithm uses a quadratic inverse distance w...
hdrl_parameter * hdrl_resample_parameter_create_linear(const int loop_distance, cpl_boolean use_errorweights)
Creates a resample linear hdrl parameter object. The algorithm uses a linear inverse distance weighti...
hdrl_parameter * hdrl_resample_parameter_create_outgrid2D(const double delta_ra, const double delta_dec)
Creates a resample_outgrid hdrl parameter object for a 2 dimensional interpolation,...
hdrl_resample_result * hdrl_resample_compute(const cpl_table *ResTable, hdrl_parameter *method, hdrl_parameter *outputgrid, const cpl_wcs *wcs)
High level resampling function.
void hdrl_resample_result_delete(hdrl_resample_result *aCube)
Deallocates the memory associated to a hdrl_resample_result object.
cpl_table * hdrl_resample_image_to_table(const hdrl_image *hima, const cpl_wcs *wcs)
Convert a hdrl image into a cpl table that can be given as input to hdrl_resample_compute()