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