ERIS Pipeline Reference Manual 1.8.10
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 enu_calc_maglim(limage, photzp, fwhm_pix, &abmaglim);
2548
2549 /* update DFS keywords affected by this recipe */
2550
2551 cpl_propertylist * applist = cpl_propertylist_new();
2552
2553 cpl_propertylist_copy_property(applist, limage->plist, "FLUXCAL");
2554 cpl_propertylist_copy_property(applist, limage->plist, "ESO QC MAGZPT");
2555 cpl_propertylist_copy_property(applist, limage->plist, "ESO QC MAGZERR");
2556 cpl_propertylist_update_double(applist, "ABMAGLIM", abmaglim);
2557 cpl_propertylist_set_comment(applist, "ABMAGLIM", "5-sigma "
2558 "limiting AB magnitude");
2559
2560 /* ABMAGSAT is calculated by casu_photcal_extinct assumimg satlev=65000,
2561 when it should be ESO.DETMON.SATURATION / ESO.DET.SEQ1.DIT.
2562 Modify the value accordingly */
2563 double saturation = cpl_propertylist_get_double(limage->plist,
2564 "ESO DETMON SATURATION");
2565 double dit = enu_get_dit(limage->plist);
2566 double satlev = saturation / dit;
2567 double abmagsat = cpl_propertylist_get_double(limage->plist, "ABMAGSAT");
2568 abmagsat = abmagsat + 2.5 * log10(65000 / satlev);
2569 cpl_propertylist_copy_property(applist, limage->plist, "ABMAGSAT");
2570 cpl_propertylist_update_double(applist, "ABMAGSAT", abmagsat);
2571 cpl_propertylist_copy_property(applist, limage->plist, "PHOTZP");
2572 cpl_propertylist_copy_property(applist, limage->plist, "PHOTZPER");
2573 cpl_propertylist_copy_property(applist, limage->plist, "ZPMETHOD");
2574 if (cpl_propertylist_has(limage->plist, "ZP_CAT")) {
2575 cpl_propertylist_copy_property(applist, limage->plist, "ZP_CAT");
2576 }
2577 cpl_propertylist_copy_property(applist, limage->plist, "ESO DRS EXTCOEF");
2578
2579 /* set PRO.CATG */
2580
2581 cpl_propertylist_update_string(applist, CPL_DFS_PRO_CATG, tag);
2582 cpl_propertylist_update_string(applist, "PRODCATG", "ANCILLARY.IMAGE");
2583
2584 /* set RA, DEC from WCS rather than let dfs copy it from one of the
2585 frames */
2586
2587 {
2588 cpl_wcs * wcs = cpl_wcs_new_from_propertylist(limage->plist);
2589 double ra = 0.0;
2590 double dec = 0.0;
2591 enu_get_ra_dec(wcs, &ra, &dec);
2592
2593 cpl_propertylist_update_double(applist, "RA", ra);
2594 cpl_propertylist_update_double(applist, "DEC", dec);
2595
2596 cpl_wcs_delete(wcs);
2597 }
2598
2599 /* provenance frameset, files that contributed to this reduction */
2600
2601 cpl_frameset * provenance = cpl_frameset_new();
2602 cpl_frameset_insert(provenance, cpl_frame_duplicate(limage->frame));
2603
2604 /* Generate output file name, write the file. */
2605
2606 char * out_fname = enu_repreface(cpl_frame_get_filename(limage->frame),
2607 "cal_phot");
2608
2609 enu_dfs_save_limage(frameset,
2610 parlist,
2611 provenance,
2612 CPL_TRUE,
2613 limage,
2614 recipe_name,
2615 limage->frame,
2616 applist,
2617 PACKAGE "/" PACKAGE_VERSION,
2618 out_fname);
2619
2620 cpl_free(out_fname);
2621 cpl_frameset_delete(provenance);
2622 cpl_propertylist_delete(applist);
2623
2624 return cpl_error_get_code();
2625}
2626
2627
2628/*----------------------------------------------------------------------------*/
2635/*----------------------------------------------------------------------------*/
2636
2637static cpl_error_code eris_nix_img_cal_phot_default(
2638 cpl_frameset * frameset,
2639 located_image * jitter) {
2640
2641 cpl_table * phot_data = NULL;
2642 cpl_table * selected = NULL;
2643
2644 /* Read in the data file with default photometric values */
2645
2646 cpl_frame * phot_data_frame = cpl_frameset_find (frameset,
2647 ERIS_NIX_PHOT_DATA_PRO_CATG);
2648 const char * phot_data_file = cpl_frame_get_filename (phot_data_frame);
2649 enu_check_error_code("Failed to read NIX photometry file name");
2650
2651 cpl_msg_info(cpl_func, "..transferring default photometric calibration "
2652 "from %s", phot_data_file);
2653
2654 /* Read in the instrument photometry table, with info on conversion
2655 between standard and instrument filters */
2656
2657 const char * pcat = "2MASS";
2658 cpl_size phot_ext = cpl_fits_find_extension(phot_data_file, pcat);
2659 enu_check(phot_ext > 0, CPL_ERROR_INCOMPATIBLE_INPUT,
2660 "photometry information for '%s' not found in %s",
2661 pcat, phot_data_file);
2662
2663 phot_data = cpl_table_load(phot_data_file, phot_ext, 0);
2664
2665 /* get the filter used for the observation and the relevant line of
2666 the phot_data table */
2667
2668 const char * filter = enu_get_filter(jitter->plist);
2669 enu_check(filter != NULL, CPL_ERROR_INCOMPATIBLE_INPUT,
2670 "Failure to find filter name");
2671
2672 /* comparison is treated as a regular expression */
2673 char * comparison = cpl_sprintf("^%s$", filter);
2674 cpl_size nsel = cpl_table_and_selected_string(phot_data, "filter_name",
2675 CPL_EQUAL_TO, comparison);
2676 cpl_free(comparison);
2677 if (nsel == 1) {
2678 cpl_msg_info(cpl_func, "Filter %s located in %s", filter,
2679 phot_data_file);
2680 selected = cpl_table_extract_selected(phot_data);
2681 cpl_table_dump(selected, 0, 1, NULL);
2682 cpl_table_delete(phot_data);
2683 phot_data = selected;
2684 } else {
2685 cpl_error_set_message(cpl_func, CPL_ERROR_INCOMPATIBLE_INPUT,
2686 "No entry for filter %s in %s", filter,
2687 phot_data_file);
2688 }
2689 enu_check_error_code("Failure to read photometry data for filter %s",
2690 filter);
2691
2692 int ignore = 0;
2693 double default_zp = cpl_table_get_double(phot_data, "default_zp", 0,
2694 &ignore);
2695 double default_zp_err = cpl_table_get_double(phot_data,
2696 "default_zp_err", 0,
2697 &ignore);
2698 double extcoef = cpl_table_get_double(phot_data, "atm_extcoef", 0,
2699 &ignore);
2700
2701 /* Set default zeropoint in the jitter image */
2702
2703 /* PHOTZP absorbs the exposure time and extinction for the jitter
2704 so this correction can be applied directly to the image data.
2705 Because data are in adu/s the exposure time for this calculation
2706 is 1.0 */
2707
2708 double airmass = enu_get_airmass(jitter->plist);
2709 const double extinct = extcoef * (airmass - 1.0);
2710 const double exptime = 1.0;
2711 cpl_msg_info(cpl_func, "default %f %f %f", default_zp, exptime, extinct);
2712 const double photzp = default_zp + 2.5*log10(exptime) - extinct;
2713
2714 /* Set ZPMETHOD to reflect the calibration method used */
2715
2716 const char * zp_method = "DEFAULT";
2717 const char * zp_method_comment = "ZP taken from filter default value";
2718 const char * magzpt_comment = "[mag] photometric zeropoint";
2719 const char * magzerr_comment = "[mag] photometric zeropoint error";
2720 const char * photzp_comment = "[mag] photometric zeropoint";
2721 const char * photzper_comment = "[mag] uncertainty on PHOTZP";
2722 const char * extcoef_comment = "[mag] Assumed extinction coefficient";
2723
2724 /* write the calibration keywords to the jitter header */
2725
2726 cpl_propertylist_update_string(jitter->plist, "FLUXCAL", "ABSOLUTE");
2727 cpl_propertylist_set_comment(jitter->plist, "FLUXCAL",
2728 "quality of flux calibration");
2729 cpl_propertylist_update_double(jitter->plist, "ESO QC MAGZPT",
2730 default_zp);
2731 cpl_propertylist_set_comment(jitter->plist, "ESO QC MAGZPT",
2732 magzpt_comment);
2733 cpl_propertylist_update_double(jitter->plist, "ESO QC MAGZERR",
2734 default_zp_err);
2735 cpl_propertylist_set_comment(jitter->plist, "ESO QC MAGZERR",
2736 magzerr_comment);
2737 cpl_propertylist_update_double(jitter->plist, "PHOTZP", photzp);
2738 cpl_propertylist_set_comment(jitter->plist, "PHOTZP", photzp_comment);
2739 cpl_propertylist_update_double(jitter->plist, "PHOTZPER", default_zp_err);
2740 cpl_propertylist_set_comment(jitter->plist, "PHOTZPER", photzper_comment);
2741 cpl_propertylist_update_string(jitter->plist, "ZPMETHOD", zp_method);
2742 cpl_propertylist_set_comment(jitter->plist, "ZPMETHOD",
2743 zp_method_comment);
2744 cpl_propertylist_update_double(jitter->plist, "ESO DRS EXTCOEF", extcoef);
2745 cpl_propertylist_set_comment(jitter->plist, "ESO DRS EXTCOEF",
2746 extcoef_comment);
2747
2748 /* and to the catalogue header */
2749
2750 if (jitter->objects && jitter->objects->qclist) {
2751 cpl_propertylist_update_double(jitter->objects->qclist,
2752 "ESO QC MAGZPT", default_zp);
2753 cpl_propertylist_set_comment(jitter->objects->qclist,
2754 "ESO QC MAGZPT", magzpt_comment);
2755 cpl_propertylist_update_double(jitter->objects->qclist,
2756 "ESO QC MAGZERR", default_zp_err);
2757 cpl_propertylist_set_comment(jitter->objects->qclist,
2758 "ESO QC MAGZERR", magzerr_comment);
2759 cpl_propertylist_update_double(jitter->objects->qclist, "PHOTZP",
2760 photzp);
2761 cpl_propertylist_set_comment(jitter->objects->qclist, "PHOTZP",
2762 photzp_comment);
2763 cpl_propertylist_update_string(jitter->objects->qclist,
2764 "ZPMETHOD", zp_method);
2765 cpl_propertylist_set_comment(jitter->objects->qclist,
2766 "ZPMETHOD", zp_method_comment);
2767 cpl_propertylist_update_double(jitter->plist, "ESO DRS EXTCOEF",
2768 extcoef);
2769 cpl_propertylist_set_comment(jitter->plist, "ESO DRS EXTCOEF",
2770 extcoef_comment);
2771 }
2772
2773cleanup:
2774
2775 cpl_table_delete(phot_data);
2776 return cpl_error_get_code();
2777}
2778
2779
2780/*----------------------------------------------------------------------------*/
2789/*----------------------------------------------------------------------------*/
2790
2791static cpl_error_code eris_nix_img_cal_phot_external(
2792 cpl_frameset * frameset,
2793 const cpl_parameterlist * parlist,
2794 located_imagelist * standards,
2795 located_imagelist * jitters,
2796 const char * out_catg,
2797 const char * recipe_name) {
2798
2799 cpl_msg_info(cpl_func, "..transferring photometric calibration from %s",
2800 cpl_frame_get_filename(standards->limages[0]->frame));
2801
2802 /* get the filter used for the observation, check that it is the same
2803 as in the calibrated image */
2804
2805 const char * filter = enu_get_filter(jitters->limages[0]->plist);
2806 const char * std_filter = cpl_propertylist_get_string(
2807 standards->limages[0]->plist,
2808 "FILTER");
2809 enu_check(!strcmp(filter, std_filter), CPL_ERROR_INCOMPATIBLE_INPUT,
2810 "Standard field filter (%s) does not match "
2811 "target (%s)", std_filter, filter);
2812
2813 /* Read the photometric calibration of the standard image.
2814 MAGZPT is for the image normalised by EXPTIME and at zenith */
2815
2816 const double magzpt = cpl_propertylist_get_double(
2817 standards->limages[0]->plist, "ESO QC MAGZPT");
2818 const char * magzpt_comment = cpl_propertylist_get_comment(
2819 standards->limages[0]->plist,
2820 "ESO QC MAGZPT");
2821 const double magzerr = cpl_propertylist_get_double(
2822 standards->limages[0]->plist, "ESO QC MAGZERR");
2823 const char * magzerr_comment = cpl_propertylist_get_comment(
2824 standards->limages[0]->plist,
2825 "ESO QC MAGZERR");
2826 const char * photzp_comment = cpl_propertylist_get_comment(
2827 standards->limages[0]->plist, "PHOTZP");
2828
2829 /* read the atmospheric extinction assumed for the standard field
2830 and the zeropoint at zenith */
2831
2832 const double extcoef = cpl_propertylist_get_double(
2833 standards->limages[0]->plist,
2834 "ESO DRS EXTCOEF");
2835 const char * extcoef_comment = "[mag] Assumed extinction coefficient";
2836/*
2837 const char * extcoef_comment = cpl_propertylist_get_comment(
2838 standards->limages[0]->plist, "EXTCOEF");
2839*/
2840
2841 /* save the photometric calibrated jitter images to FITS files */
2842
2843 for (cpl_size j = 0; j < jitters->size; j++) {
2844
2845 /* PHOTZP absorbs the exposure time and extinction for the jitter
2846 so this correction can be applied directly to the image data.
2847 NIX data are in DN/sec so here exposure time = 1 */
2848
2849 const double airmass = enu_get_airmass(jitters->limages[j]->plist);
2850 const double extinct = extcoef * (airmass - 1.0);
2851 const double exptime = 1.0;
2852 const double photzp = magzpt + 2.5*log10(exptime) - extinct;
2853
2854 /* write the calibration keywords to the jitter header */
2855
2856 cpl_propertylist_update_string(jitters->limages[j]->plist,
2857 "FLUXCAL", "ABSOLUTE");
2858 cpl_propertylist_set_comment(jitters->limages[j]->plist, "FLUXCAL",
2859 "quality of flux calibration");
2860 cpl_propertylist_update_double(jitters->limages[j]->plist,
2861 "ESO QC MAGZPT", magzpt);
2862 cpl_propertylist_set_comment(jitters->limages[j]->plist,
2863 "ESO QC MAGZPT", magzpt_comment);
2864 cpl_propertylist_update_double(jitters->limages[j]->plist,
2865 "ESO QC MAGZERR", magzerr);
2866 cpl_propertylist_set_comment(jitters->limages[j]->plist,
2867 "ESO QC MAGZERR", magzerr_comment);
2868 cpl_propertylist_update_double(jitters->limages[j]->plist,
2869 "PHOTZP", photzp);
2870 cpl_propertylist_set_comment(jitters->limages[j]->plist,
2871 "PHOTZP", photzp_comment);
2872 cpl_propertylist_update_double(jitters->limages[j]->plist,
2873 "ESO DRS EXTCOEF", extcoef);
2874 cpl_propertylist_set_comment(jitters->limages[j]->plist,
2875 "ESO DRS EXTCOEF", extcoef_comment);
2876
2877 /* and to the catalogue header, if present */
2878
2879 if (jitters->limages[j]->objects) {
2880 cpl_propertylist_update_double(jitters->limages[j]->objects->qclist,
2881 "ESO QC MAGZPT", magzpt);
2882 cpl_propertylist_set_comment(jitters->limages[j]->objects->qclist,
2883 "ESO QC MAGZPT", magzpt_comment);
2884 cpl_propertylist_update_double(jitters->limages[j]->objects->qclist,
2885 "ESO QC MAGZERR", magzerr);
2886 cpl_propertylist_set_comment(jitters->limages[j]->objects->qclist,
2887 "ESO QC MAGZERR", magzerr_comment);
2888 cpl_propertylist_update_double(jitters->limages[j]->objects->qclist,
2889 "PHOTZP", photzp);
2890 cpl_propertylist_set_comment(jitters->limages[j]->objects->qclist,
2891 "PHOTZP", photzp_comment);
2892 cpl_propertylist_update_double(jitters->limages[j]->objects->qclist,
2893 "ESO DRS EXTCOEF", extcoef);
2894 cpl_propertylist_set_comment(jitters->limages[j]->objects->qclist,
2895 "ESO DRS EXTCOEF", extcoef_comment);
2896 }
2897
2898 /* Set ZPMETHOD to reflect the calibration method used */
2899
2900 const char * zp_method = "separate_STD_star";
2901 const char * zp_method_comment =
2902 "photometric cal method: "
2903 "separate_STD_star = transfer from other image, "
2904 "science_field_standards = using stds in field, "
2905 "default = default value from phot data file";
2906 cpl_propertylist_update_string(jitters->limages[j]->plist,
2907 "ZPMETHOD", zp_method);
2908 cpl_propertylist_set_comment(jitters->limages[j]->plist,
2909 "ZPMETHOD", zp_method_comment);
2910 if (jitters->limages[j]->objects) {
2911 cpl_propertylist_update_string(jitters->limages[j]->objects->qclist,
2912 "ZPMETHOD", zp_method);
2913 cpl_propertylist_set_comment(jitters->limages[j]->objects->qclist,
2914 "ZPMETHOD", zp_method_comment);
2915 }
2916
2917 /* save the result */
2918
2919 eris_nix_img_cal_phot_save(jitters->limages[j],
2920 out_catg,
2921 frameset,
2922 parlist,
2923 recipe_name);
2924 enu_check_error_code("failure writing result");
2925 }
2926
2927cleanup:
2928
2929 return cpl_error_get_code();
2930}
2931
2932
2933/*----------------------------------------------------------------------------*/
2942/*----------------------------------------------------------------------------*/
2943
2944static cpl_error_code eris_nix_img_cal_phot_internal(
2945 cpl_frameset * frameset,
2946 const cpl_parameterlist * parlist,
2947 located_imagelist * jitters,
2948 const char * out_catg,
2949 const char * recipe_name,
2950 const char* context) {
2951
2952 int casu_status = CASU_OK;
2953 hdrl_parameter * cat_params = NULL;
2954 casu_fits ** in_image_data = NULL;
2955 casu_fits ** in_image_conf = NULL;
2956 casu_fits ** in_image_var = NULL;
2957 casu_tfits ** in_cats = NULL;
2958 casu_tfits ** in_mstds = NULL;
2959 const cpl_parameter * p = NULL;
2960 cpl_table * phot_data = NULL;
2961 cpl_table ** phot_refcat = NULL;
2962 char * param_name = NULL;
2963
2964 cpl_msg_info(cpl_func, "Calibrating using standard stars in field");
2965
2966 /* Retrieve input parameters */
2967
2968 param_name = cpl_sprintf("%s.cdssearch_photom", context);
2969 p = cpl_parameterlist_find_const(parlist, param_name);
2970 const char * cdssearch_photom = cpl_parameter_get_string(p);
2971 cpl_msg_info(cpl_func,"cdssearch_photom: %s",cdssearch_photom);
2972 cpl_free(param_name);
2973
2974 param_name = cpl_sprintf("%s.pixel_radius", context);
2975 p = cpl_parameterlist_find_const(parlist, param_name);
2976 const double pixel_radius = cpl_parameter_get_double(p);
2977 cpl_free(param_name);
2978
2979 param_name = cpl_sprintf("%s.minphotom", context);
2980 p = cpl_parameterlist_find_const(parlist, param_name);
2981 const int minphotom = cpl_parameter_get_int(p);
2982 cpl_free(param_name);
2983
2984 param_name = cpl_sprintf("%s.magerrcut", context);
2985 p = cpl_parameterlist_find_const(parlist, param_name);
2986 const double magerrcut = cpl_parameter_get_double(p);
2987 cpl_free(param_name);
2988
2989 /* some elements of catalogue parameters, gain and saturation,
2990 can be overridden by contents of data files. This is done in a
2991 roundabout way because you can't simply access fields in the
2992 catalogue parameter structure from outside HDRL */
2993
2994 param_name = cpl_sprintf("%s.catalogue.det.effective-gain", context);
2995 p = cpl_parameterlist_find_const(parlist, param_name);
2996 double gain = cpl_parameter_get_double(p);
2997 cpl_free(param_name);
2998
2999 if (cpl_propertylist_has(jitters->limages[0]->plist, "ESO DARK GAIN")) {
3000 cpl_msg_info(cpl_func, "reading detector gain from first jitter");
3001 gain = cpl_propertylist_get_double(jitters->limages[0]->plist,
3002 "ESO DARK GAIN");
3003 }
3004
3005 param_name = cpl_sprintf("%s.catalogue.det.saturation", context);
3006 p = cpl_parameterlist_find_const(parlist, param_name);
3007 double saturation = cpl_parameter_get_double(p);
3008 cpl_free(param_name);
3009
3010 /* saturation in adu/s is DETMON_saturation/dit */
3011 if (cpl_propertylist_has(jitters->limages[0]->plist,
3012 "ESO DETMON SATURATION")) {
3013 cpl_msg_info(cpl_func,
3014 "reading detector saturation level from first jitter");
3015 double saturation_adu = cpl_propertylist_get_double(
3016 jitters->limages[0]->plist,
3017 "ESO DETMON SATURATION");
3018 double dit = enu_get_dit(jitters->limages[0]->plist);
3019 saturation = saturation_adu / dit;
3020 cpl_msg_info(cpl_func,
3021 "saturation(adu)=%5.3e dit=%5.3e saturation(adu/s)=%5.3e",
3022 saturation_adu, dit, saturation);
3023
3024 }
3025
3026 param_name = cpl_sprintf("%s.catalogue.obj.min-pixels", context);
3027 p = cpl_parameterlist_find_const(parlist, param_name);
3028 int minpixels = cpl_parameter_get_int(p);
3029 cpl_free(param_name);
3030
3031 param_name = cpl_sprintf("%s.catalogue.obj.threshold", context);
3032 p = cpl_parameterlist_find_const(parlist, param_name);
3033 double threshold = cpl_parameter_get_double(p);
3034 cpl_free(param_name);
3035
3036 param_name = cpl_sprintf("%s.catalogue.obj.deblending", context);
3037 p = cpl_parameterlist_find_const(parlist, param_name);
3038 cpl_boolean deblending = cpl_parameter_get_bool(p);
3039 cpl_free(param_name);
3040
3041 /* use AOMODE to decide if set catalogue.core-radius and mesh-size to
3042 defaults or read them from parameters */
3043
3044 double core_radius = -1.0;
3045 int mesh_size = -1;
3047 parlist,
3048 jitters->limages[0]->plist,
3049 &core_radius,
3050 &mesh_size);
3051
3052 param_name = cpl_sprintf("%s.catalogue.bkg.estimate", context);
3053 p = cpl_parameterlist_find_const(parlist, param_name);
3054 cpl_boolean estimate = cpl_parameter_get_bool(p);
3055 cpl_free(param_name);
3056
3057 param_name = cpl_sprintf("%s.catalogue.bkg.smooth-gauss-fwhm",
3058 context);
3059 p = cpl_parameterlist_find_const(parlist, param_name);
3060 double smooth_gauss_fwhm = cpl_parameter_get_double(p);
3061 cpl_free(param_name);
3062
3063 cat_params = hdrl_catalogue_parameter_create(minpixels,
3064 threshold,
3065 deblending,
3066 core_radius,
3067 estimate,
3068 mesh_size,
3069 smooth_gauss_fwhm,
3070 gain,
3071 saturation,
3072 HDRL_CATALOGUE_ALL);
3073
3074 cpl_msg_info(cpl_func, "gain=%4.2f saturation=%6.2f", gain, saturation);
3075
3076 enu_check_error_code("Could not retrieve input parameters");
3077 enu_check(strcmp(cdssearch_photom, "none"), CPL_ERROR_ILLEGAL_INPUT,
3078 "photometric catalogue not specified");
3079
3080 /* Read in the data file with default photometric values */
3081
3082 cpl_frame * phot_data_frame = cpl_frameset_find (frameset,
3083 ERIS_NIX_PHOT_DATA_PRO_CATG);
3084 const char * phot_data_file = cpl_frame_get_filename (phot_data_frame);
3085 enu_check_error_code("Failed to read NIX photometry file name");
3086
3087 cpl_msg_info(cpl_func, "..reading instrument photometric properties "
3088 "from %s", phot_data_file);
3089 cpl_size phot_ext = cpl_fits_find_extension(phot_data_file,
3090 cdssearch_photom);
3091 enu_check(phot_ext > 0, CPL_ERROR_INCOMPATIBLE_INPUT,
3092 "photometry information for '%s' not found in %s",
3093 cdssearch_photom, phot_data_file);
3094 phot_data = cpl_table_load(phot_data_file, phot_ext, 0);
3095
3096 /* cast any double columns to float to suit casu */
3097
3098 cal_phot_cast_columns_to_float(phot_data);
3099
3100 /* get the filter used for the observation and the relevant line of
3101 the phot_data table */
3102
3103 const char * filter = enu_get_filter(jitters->limages[0]->plist);
3104 enu_check_error_code("Failed to read filter name from file");
3105
3106 /* comparison is treated as a regular expression */
3107 char * comparison = cpl_sprintf("^%s$", filter);
3108 cpl_size nsel = cpl_table_and_selected_string(phot_data, "filter_name",
3109 CPL_EQUAL_TO, comparison);
3110 cpl_free(comparison);
3111 if (nsel == 1) {
3112 cpl_msg_info(cpl_func, "Filter %s located in %s", filter,
3113 phot_data_file);
3114 cpl_table * selected = cpl_table_extract_selected(phot_data);
3115 cpl_table_dump(selected, 0, 10, NULL);
3116 cpl_table_delete(selected);
3117 cpl_table_select_all(phot_data);
3118 } else {
3119 cpl_error_set_message(cpl_func, CPL_ERROR_INCOMPATIBLE_INPUT,
3120 "No entry for filter %s in %s", filter,
3121 phot_data_file);
3122 }
3123 enu_check_error_code("Failure to read photometry data for filter %s",
3124 filter);
3125
3126 /* generate object catalogues for each image */
3127
3128 enu_catalogue_limlist(jitters, cat_params);
3129
3130 /* copy a few things to FITS places that casu_photcal_extinct expects */
3131
3132 for (cpl_size j = 0; j < jitters->size; j++) {
3133 /* tell the CASU routine via CEXPTIME that the exposure time to
3134 use in magnitude calculations is 1 sec. This is because the
3135 linearization process outputs results in DM/sec */
3136 cpl_propertylist_update_double(jitters->limages[j]->plist,
3137 "CEXPTIME", 1.0);
3138
3139 if (jitters->limages[j]->objects) {
3140 cpl_propertylist * phu = jitters->limages[j]->plist;
3141 cpl_propertylist * ehu = jitters->limages[j]->objects->qclist;
3142
3143 /* exptime for photcal_extinct is 1 sec, as the images are in
3144 DN/sec. Store this in temporary keyword that photcal_extinct
3145 can access */
3146
3147 /* pixel scale, arcsec/pix */
3148 double cd1_1 = cpl_propertylist_get_double(phu, "CD1_1");
3149 double cd2_1 = cpl_propertylist_get_double(phu, "CD2_1");
3150 double pixsize = sqrt(cd1_1 * cd1_1 + cd2_1 * cd2_1) * 3600.0;
3151 cpl_propertylist_update_float(phu, "ESO QC WCS_SCALE",
3152 (float) pixsize);
3153
3154 /* sky noise */
3155 double val = cpl_propertylist_get_double(ehu, "ESO QC SKY_NOISE");
3156 cpl_propertylist_update_float(ehu, "ESO DRS SKYNOISE", (float) val);
3157
3158 /* mean sky */
3159 val = cpl_propertylist_get_double(ehu, "ESO QC MEAN_SKY");
3160 /* set skylevel to a very small number. Should be 0 as sky has been
3161 subtracted but its log is taken in casu_photcal_extinct. */
3162 cpl_propertylist_update_double(ehu, "ESO DRS SKYLEVEL",
3163 max(val, 0.01));
3164
3165 /* ESO QC IMAGE_SIZE claims to be the average fwhm
3166 of stellar objects in pixels */
3167
3168 double fwhm_pix = cpl_propertylist_get_double(
3169 ehu, "ESO QC IMAGE_SIZE");
3170
3171 /* casu_photcal_extinct expects PSF_FWHM in arcsec, if known */
3172 if (fwhm_pix > 0) {
3173 double fwhm = fwhm_pix * pixsize;
3174 cpl_propertylist_update_double(ehu, "PSF_FWHM", (float)fwhm);
3175 cpl_propertylist_set_comment(ehu, "PSF_FWHM", "[arcsec] Average "
3176 "FWHM of stellar objects");
3177 }
3178
3179 /* also cast any double table columns to float to suit casu */
3180 if (jitters->limages[j]->objects->catalogue) {
3181 cal_phot_cast_columns_to_float(jitters->limages[j]->objects->
3182 catalogue);
3183 }
3184 }
3185 }
3186
3187 /* Convert jitter data to casu_tfits */
3188
3189 encu_limlist_to_casu_fits(jitters, &in_image_data, &in_image_conf,
3190 &in_image_var);
3191
3192 /* Initialise in_cats and in_mstds to values that will be safely
3193 deleted if something goes wrong */
3194
3195 in_cats = cpl_malloc(jitters->size * sizeof(casu_tfits *));
3196 in_mstds = cpl_malloc(jitters->size * sizeof(casu_tfits *));
3197 phot_refcat = cpl_malloc(jitters->size * sizeof(cpl_table *));
3198
3199 for (cpl_size j = 0; j < jitters->size; j++) {
3200 in_mstds[j] = cpl_malloc(sizeof(casu_tfits));
3201 in_mstds[j]->table = NULL;
3202 in_mstds[j]->phu = NULL;
3203 in_mstds[j]->ehu = NULL;
3204 in_mstds[j]->fname = NULL;
3205 in_mstds[j]->extname = NULL;
3206 in_mstds[j]->fullname = NULL;
3207 in_mstds[j]->nexten = -1;
3208 in_mstds[j]->status = CASU_OK;
3209
3210 in_cats[j] = cpl_malloc(sizeof(casu_tfits));
3211 in_cats[j]->table = NULL;
3212 in_cats[j]->phu = NULL;
3213 in_cats[j]->ehu = NULL;
3214 in_cats[j]->fname = NULL;
3215 in_cats[j]->extname = NULL;
3216 in_cats[j]->fullname = NULL;
3217 in_cats[j]->nexten = -1;
3218 in_cats[j]->status = CASU_OK;
3219
3220 phot_refcat[j] = NULL;
3221 }
3222
3223 /* Now populate in_mstds and in_cats with values to be used by
3224 casu_photcal_extinct */
3225
3226 for (cpl_size j = 0; j < jitters->size; j++) {
3227 cpl_msg_info(cpl_func, "processing jitter %d", (int)j);
3228
3229 /* be wary of empty (NULL) catalogues */
3230
3231 if (jitters->limages[j]->objects) {
3232 in_cats[j]->table = cpl_table_duplicate(jitters->limages[j]->
3233 objects->catalogue);
3234 in_cats[j]->phu = cpl_propertylist_duplicate(jitters->limages[j]->
3235 plist);
3236 in_cats[j]->ehu = cpl_propertylist_duplicate(jitters->limages[j]->
3237 objects->qclist);
3238 in_cats[j]->fname = cpl_strdup(cpl_frame_get_filename(
3239 jitters->limages[j]->frame));
3240
3241 /* use casu_getstds to read in photom reference catalogue entries
3242 for the area covered by the jitter, the routine also adds
3243 some columns used by casu_photcal_extinct*/
3244
3245 /* check not in error state before entry. If error set then
3246 casu_getstds will fail, ptentially with a confusing error
3247 message */
3248
3249 enu_check_error_code("error before calling casu_getstds");
3250 phot_refcat[j] = NULL;
3251 casu_status = CASU_OK;
3252 casu_getstds(jitters->limages[j]->plist, CPL_FALSE,
3253 NULL,
3254 (char*) "2MASS",
3255 1, NULL, &phot_refcat[j], NULL,
3256 &casu_status);
3257 //cpl_msg_info(cpl_func, "casu %d", (int)casu_status);
3258 if (phot_refcat[j] == NULL) {
3259 cpl_msg_info(cpl_func, "...no phot standards found");
3260 } else {
3261 en_catalogue_name_conformance(phot_refcat[j]);
3262 cpl_size nstds = cpl_table_get_nrow(phot_refcat[j]);
3263 cpl_msg_info(cpl_func, "...%d phot standards read", (int)nstds);
3264
3265 /* populate in_mstds by associating image catalogue objects with
3266 those in the reference catalog, again beware NULL catalogues
3267 (from detecting no sources in the image) */
3268
3269 const int strict = 0;
3270 enm_associate_std(jitters->limages[j]->objects->catalogue,
3271 phot_refcat[j], pixel_radius, strict,
3272 &(in_mstds[j]->table));
3273 enu_check_error_code("Failure trying to match standards: %s",
3274 cpl_error_get_message());
3275
3276 /* cast any double columns to float to suit casu */
3277
3278 cal_phot_cast_columns_to_float(in_mstds[j]->table);
3279 in_mstds[j]->phu = cpl_propertylist_new();
3280 in_mstds[j]->ehu = cpl_propertylist_new();
3281 enu_check(casu_status == CASU_OK, CPL_ERROR_ILLEGAL_INPUT,
3282 "casu_matchstds failure status : %d", casu_status);
3283 }
3284
3285 } else {
3286
3287 /* No objects found hence no object catalogue. Add some dummy
3288 propertylists to keep casu_photcal_extinct happy - it will
3289 write to them */
3290
3291 cpl_msg_info(cpl_func, ".no objects detected in field");
3292 in_cats[j]->phu = cpl_propertylist_new();
3293 in_cats[j]->ehu = cpl_propertylist_new();
3294 }
3295
3296 /* If for some reason there are no matched standards then point
3297 to an empty table rather than NULL. casu_photcal_extinct can
3298 handle the former but not the latter
3299
3300 Also, add some empty propertylists for casu_photcal_extinct
3301 to write results into, otherwise it will fail */
3302
3303 if (in_mstds[j]->table == NULL) {
3304 in_mstds[j]->table = cpl_table_new(0);
3305 in_mstds[j]->phu = cpl_propertylist_new();
3306 in_mstds[j]->ehu = cpl_propertylist_new();
3307 }
3308 }
3309
3310 /* Now do the photometric calibration */
3311
3312 cpl_msg_info(cpl_func, "performing photometric calibration");
3313 casu_status = CASU_OK;
3314 char * filter_copy = cpl_strdup(filter);
3315 casu_photcal_extinct(in_image_data,
3316 in_mstds,
3317 in_cats,
3318 jitters->size,
3319 filter_copy,
3320 phot_data,
3321 minphotom,
3322 NULL, NULL,
3323 "CEXPTIME",
3324 "ESO TEL AIRM START",
3325 magerrcut,
3326 &casu_status);
3327 cpl_free(filter_copy);
3328 enu_check_error_code("Failure in casu_photcal_extinct: %s",
3329 cpl_error_get_message());
3330
3331 /* assess the calibration and save the photometric calibrated jitter
3332 images to FITS files */
3333
3334 for (cpl_size j = 0; j < jitters->size; j++) {
3335
3336 const char * fluxcal = cpl_propertylist_get_string(
3337 in_image_data[j]->phu,
3338 "FLUXCAL");
3339
3340 if (!strcmp(fluxcal, "UNCALIBRATED")) {
3341
3342 /* did the casu flux calibration succeed? An outright failure
3343 will have casu_photcal_extinct set FLUXCAL to
3344 'UNCALIBRATED'. In this case set the default result */
3345
3346 cpl_msg_warning(cpl_func, "casu_photcal_extinct has returned "
3347 "a bad result, applying default");
3348 eris_nix_img_cal_phot_default(frameset, jitters->limages[j]);
3349
3350 } else {
3351
3352 /* otherwise set the result returned by casu_photcal_extinct */
3353
3354 /* ..for in_image_data the phu and ehu are both copies of
3355 the original limage->plist. ehu is the one updated by
3356 casu_photcal_extinct - now copy it back to get the updates.
3357 *except for FLUXCAL which is set in phu*/
3358
3359 cpl_propertylist_delete(jitters->limages[j]->plist);
3360 jitters->limages[j]->plist = cpl_propertylist_duplicate(
3361 in_image_data[j]->ehu);
3362 cpl_propertylist_set_string(jitters->limages[j]->plist, "FLUXCAL",
3363 fluxcal);
3364
3365 /* add the photometric system */
3366
3367 cpl_propertylist_update_string(jitters->limages[j]->plist,
3368 "PHOTSYS", "VEGA");
3369
3370 /* Set ZPMETHOD to reflect the calibration method used
3371 If casu_photcal_extinct has left keyword ZPFUDGED==True
3372 then the calibration failed and the routine itself
3373 set zp/zp error to default values from file */
3374
3375 const int zpfudged = cpl_propertylist_get_bool(
3376 jitters->limages[j]->plist, "ZPFUDGED");
3377
3378 const char * zp_method = NULL;
3379 const char * zp_comment = NULL;
3380 if (zpfudged) {
3381 zp_method = "DEFAULT";
3382 zp_comment = "ZP taken from filter default value";
3383 } else {
3384 zp_method = "2MASS";
3385 zp_comment = "ZP computed from 2MASS sources in the field";
3386 }
3387 cpl_propertylist_update_string(jitters->limages[j]->plist,
3388 "ZPMETHOD", zp_method);
3389 cpl_propertylist_set_comment(jitters->limages[j]->plist,
3390 "ZPMETHOD", zp_comment);
3391 cpl_msg_info(cpl_func, "set ZPMETHOD %s", zp_method);
3392
3393 if (!strcmp(zp_method, "2MASS")) {
3394 cpl_propertylist_update_string(jitters->limages[j]->plist,
3395 "ZP_CAT", cdssearch_photom);
3396 }
3397
3398 /* copy updated plist to image catalogue */
3399
3400 if (jitters->limages[j]->objects &&
3401 jitters->limages[j]->objects->qclist) {
3402 cpl_propertylist_delete(jitters->limages[j]->objects->qclist);
3403 jitters->limages[j]->objects->qclist =
3404 cpl_propertylist_duplicate(
3405 in_cats[j]->ehu);
3406 cpl_propertylist_update_string(
3407 jitters->limages[j]->objects->qclist,
3408 "ZPMETHOD", zp_method);
3409 cpl_propertylist_update_string(
3410 jitters->limages[j]->objects->qclist,
3411 "PHOTSYS", "VEGA");
3412 }
3413
3414 /* if they exist and contain any rows, copy matched stds catalogues
3415 and associated qclist to limage */
3416
3417 if (in_mstds[j] &&
3418 in_mstds[j]->table &&
3419 cpl_table_get_nrow(in_mstds[j]->table) > 0) {
3420 jitters->limages[j]->matchstd_phot = cpl_calloc(
3421 sizeof(hdrl_catalogue_result), 1);
3422 jitters->limages[j]->matchstd_phot->catalogue =
3423 cpl_table_duplicate(in_mstds[j]->table);
3424 jitters->limages[j]->matchstd_phot->qclist =
3425 cpl_propertylist_duplicate(
3426 in_mstds[j]->ehu);
3427 cpl_propertylist_update_string(jitters->limages[j]->
3428 matchstd_phot->qclist,
3429 "ZPMETHOD",
3430 zp_method);
3431 if (!strcmp(zp_method, "science_field_standards")) {
3432 cpl_propertylist_update_string(jitters->limages[j]->
3433 matchstd_phot->qclist, "ZP_CAT",
3434 cdssearch_photom);
3435 }
3436 }
3437 }
3438
3439 /* Save the result */
3440
3441 eris_nix_img_cal_phot_save(jitters->limages[j],
3442 out_catg,
3443 frameset,
3444 parlist,
3445 recipe_name);
3446 enu_check_error_code("failure writing result");
3447
3448 /* save the reference catalogue */
3449
3450 if (phot_refcat[j]) {
3451 enu_dfs_save_catalogue(frameset,
3452 jitters->limages[j]->frame,
3453 parlist,
3454 phot_refcat[j],
3455 NULL,
3456 cdssearch_photom,
3457 recipe_name,
3458 PACKAGE "/" PACKAGE_VERSION,
3459 "refcat.cal_phot",
3460 ERIS_NIX_CAL_PHOT_REF_CATALOGUE_PRO_CATG);
3461 }
3462
3463 /* save the matched standards catalogue */
3464
3465 if (jitters->limages[j]->matchstd_phot &&
3466 jitters->limages[j]->matchstd_phot->catalogue) {
3467
3468 enu_dfs_save_catalogue(frameset,
3469 jitters->limages[j]->frame,
3470 parlist,
3471 jitters->limages[j]->matchstd_phot->catalogue,
3472 jitters->limages[j]->matchstd_phot->qclist,
3473 "2MASS",
3474 recipe_name,
3475 PACKAGE "/" PACKAGE_VERSION,
3476 "matchcat.cal_phot",
3477 ERIS_NIX_CAL_PHOT_MATCH_CATALOGUE_PRO_CATG);
3478 }
3479
3480 /* save the catalogue of sources in the image itself */
3481
3482 if (jitters->limages[j]->objects &&
3483 jitters->limages[j]->objects->catalogue) {
3484
3485 enu_dfs_save_catalogue(frameset,
3486 jitters->limages[j]->frame,
3487 parlist,
3488 jitters->limages[j]->objects->catalogue,
3489 jitters->limages[j]->objects->qclist,
3490 cpl_frame_get_filename(jitters->
3491 limages[j]->
3492 frame),
3493 recipe_name,
3494 PACKAGE "/" PACKAGE_VERSION,
3495 "cat.cal_phot",
3496 ERIS_NIX_CAL_PHOT_CATALOGUE_PRO_CATG);
3497 }
3498 }
3499
3500cleanup:
3501 hdrl_parameter_delete(cat_params);
3502 if (jitters) {
3503 if (in_image_data) {
3504 for (cpl_size j = 0; j < jitters->size; j++) {
3505 if (in_image_data[j]) casu_fits_unwrap(in_image_data[j]);
3506 }
3507 cpl_free(in_image_data);
3508 }
3509 if (in_image_var) {
3510 for (cpl_size j = 0; j < jitters->size; j++) {
3511 if (in_image_var[j]) casu_fits_unwrap(in_image_var[j]);
3512 }
3513 cpl_free(in_image_var);
3514 }
3515 if (in_image_conf) {
3516 for (cpl_size j = 0; j < jitters->size; j++) {
3517 if (in_image_conf[j]) casu_fits_unwrap(in_image_conf[j]);
3518 }
3519 cpl_free(in_image_conf);
3520 }
3521 casu_tfits_delete_list(in_cats, (int)jitters->size);
3522 casu_tfits_delete_list(in_mstds, jitters->size);
3523 if (phot_refcat != NULL) {
3524 for (cpl_size j = 0; j < jitters->size; j++) {
3525 cpl_table_delete(phot_refcat[j]);
3526 }
3527 }
3528 }
3529 cpl_table_delete(phot_data);
3530 cpl_free(phot_refcat);
3531 eris_check_error_code("eris_nix_img_cal_phot_internal");
3532 return cpl_error_get_code();
3533}
3534
3535
3536/*----------------------------------------------------------------------------*/
3548/*----------------------------------------------------------------------------*/
3549cpl_error_code eris_nix_scired_cal_phot(cpl_frameset * frameset,
3550 const cpl_parameterlist * parlist,
3551 const char * recipe_name,
3552 const char* context) {
3553
3554 located_imagelist * jitters = NULL;
3555 located_imagelist * object_jitters = NULL;
3556 located_imagelist * standards = NULL;
3557 located_imagelist * std_jitters = NULL;
3558 cpl_frameset * used = NULL;
3559
3560 enu_check_error_code("%s():%d: An error is already set: %s",
3561 cpl_func, __LINE__, cpl_error_get_where());
3562
3563 cpl_ensure_code(frameset, CPL_ERROR_NULL_INPUT);
3564 cpl_ensure_code(parlist, CPL_ERROR_NULL_INPUT);
3565
3566 /* Set the msg verbosity level from environment variable CPL_MSG_LEVEL
3567 - not working, so set manually for now */
3568
3569 cpl_msg_set_level_from_env();
3570 cpl_msg_severity severity = cpl_msg_get_level();
3571 cpl_msg_info(cpl_func, "level %d", (int) severity);
3572
3573 /* check for invalid input */
3574 if(eris_files_dont_exist(frameset) != CPL_ERROR_NONE) {
3575 return CPL_ERROR_BAD_FILE_FORMAT;
3576 }
3577 /* check required input tags are present */
3578 const int ntags = 1;
3579 const char* required_tags[1] = {
3580 ERIS_NIX_PHOT_DATA_PRO_CATG
3581 };
3582
3583 // ERIS_NIX_SKYSUB_OBJECT_JITTER_PRO_CATG, or ERIS_NIX_SKYSUB_STD_JITTER_PRO_CATG
3584 cpl_ensure_code(CPL_ERROR_NONE ==
3585 eris_dfs_check_input_tags(frameset, required_tags, ntags, 1),
3586 CPL_ERROR_ILLEGAL_INPUT);
3587
3588 const int ntags_opt = 3;
3589 const char* optional_tags[3] = {
3590 ERIS_NIX_CAL_WCS_MATCH_CATALOGUE_PRO_CATG, // opt
3591 ERIS_NIX_CAL_WCS_REF_CATALOGUE_PRO_CATG, // opt
3592 ERIS_NIX_CAL_WCS_CATALOGUE_PRO_CATG //opt
3593 };
3594
3595 // ERIS_NIX_SKYSUB_OBJECT_JITTER_PRO_CATG, or ERIS_NIX_SKYSUB_STD_JITTER_PRO_CATG
3596 cpl_ensure_code(CPL_ERROR_NONE ==
3597 eris_dfs_check_input_tags(frameset, optional_tags, ntags_opt, 0),
3598 CPL_ERROR_ILLEGAL_INPUT);
3599
3600 /* Some initialization */
3601
3602 used = cpl_frameset_new();
3603
3604 /* Identify the RAW and CALIB frames in the input frameset */
3605
3606 eris_nix_dfs_set_groups(frameset);
3607 enu_check_error_code("Could not identify RAW and CALIB frames");
3608
3609 /* Read in images to be calibrated */
3610
3611 object_jitters = enu_limlist_load_from_frameset(frameset,
3612 ERIS_NIX_CAL_WCS_OBJECT_JITTER_PRO_CATG, used);
3613 enu_check_error_code("Failed to read object jitter data");
3614 std_jitters = enu_limlist_load_from_frameset(frameset,
3615 ERIS_NIX_CAL_WCS_STD_JITTER_PRO_CATG, used);
3616 enu_check_error_code("Failed to read STD jitter data");
3617
3618 cpl_msg_info(cpl_func, "%d %s frames read", (int) object_jitters->size,
3619 ERIS_NIX_CAL_WCS_OBJECT_JITTER_PRO_CATG);
3620 cpl_msg_info(cpl_func, "%d %s frames read", (int) std_jitters->size,
3621 ERIS_NIX_CAL_WCS_STD_JITTER_PRO_CATG);
3622
3623 /* check that the data files in the SoF are as expected */
3624
3625 enu_check(object_jitters->size > 0 || std_jitters->size > 0,
3626 CPL_ERROR_DATA_NOT_FOUND, "no input frames found");
3627 enu_check(!(object_jitters->size > 0 && std_jitters->size > 0),
3628 CPL_ERROR_ILLEGAL_INPUT, "SoF contains both "
3629 ERIS_NIX_CAL_WCS_OBJECT_JITTER_PRO_CATG" and "
3630 ERIS_NIX_CAL_WCS_STD_JITTER_PRO_CATG" frames");
3631
3632 /* set the catg of the output data */
3633
3634 const char * out_catg = NULL;
3635 if (object_jitters->size > 0) {
3636 jitters = object_jitters;
3637 out_catg = ERIS_NIX_CAL_PHOT_OBJECT_JITTER_PRO_CATG;
3638 enu_located_imagelist_delete(std_jitters);
3639 std_jitters = NULL;
3640 } else {
3641 jitters = std_jitters;
3642 out_catg = ERIS_NIX_CAL_PHOT_STD_JITTER_PRO_CATG;
3643 enu_located_imagelist_delete(object_jitters);
3644 object_jitters = NULL;
3645 }
3646
3647 /* The calibration method depends on whether a photometrically calibrated
3648 frame is present in the SoF. If so, then transfer its calibration.
3649 If not, try to calibrate the frames using their own measured
3650 standards. */
3651
3652 standards = enu_limlist_load_from_frameset(frameset,
3653 ERIS_NIX_IMG_STD_COMBINED_PRO_CATG, used);
3654 enu_check_error_code("Failed to read external standard");
3655 if (standards->size > 0) {
3656 cpl_msg_info(cpl_func, "%d "
3657 ERIS_NIX_IMG_STD_COMBINED_PRO_CATG" frames read",
3658 (int) standards->size);
3659 }
3660
3661 if (standards->size == 0) {
3662
3663 /* Not transferring calibration from another frame.
3664 Is the wcs astrometry calibration absolute? */
3665
3666 int absolute_wcs = CPL_FALSE;
3667
3668 for (cpl_size j = 0; j < jitters->size; j++) {
3669
3670 const char * wcs_method;
3671 if (cpl_propertylist_has(jitters->limages[j]->plist,"ESO WCS_METHOD")) {
3672 wcs_method = cpl_propertylist_get_string(
3673 jitters->limages[j]->plist,
3674 "ESO WCS_METHOD");
3675 } else {
3676 /* old version may have stored the WCS method without prefix. Thus allow also this option */
3677 wcs_method = cpl_propertylist_get_string(
3678 jitters->limages[j]->plist,
3679 "WCS_METHOD");
3680 }
3681
3682 cpl_msg_info(cpl_func,"jitter %d wcs_method: %s", (int)j, wcs_method);
3683 if (!strcmp(wcs_method, ERIS_NIX_WCS_CATALOGUE_MATCH)) {
3684 absolute_wcs = CPL_TRUE;
3685 }
3686 }
3687 enu_check_error_code("failed to determine type of wcs calibration");
3688
3689 if (absolute_wcs) {
3690
3691 /* Calibrate using standards measured in field */
3692
3693 eris_nix_img_cal_phot_internal(frameset,
3694 parlist,
3695 jitters,
3696 out_catg,
3697 recipe_name, context);
3698 enu_check_error_code("error attempting internal photometric "
3699 "calibration");
3700 } else {
3701
3702 for (cpl_size j = 0; j < jitters->size; j++) {
3703
3704 /* Set zeropoint to default value for filter */
3705
3706 cpl_msg_info(cpl_func, "..astrometry calibration is not absolute");
3707 eris_nix_img_cal_phot_default(frameset,
3708 jitters->limages[j]);
3709 enu_check_error_code("error setting default photometric "
3710 "calibration");
3711
3712 /* and write the result */
3713
3714 eris_nix_img_cal_phot_save(jitters->limages[j],
3715 out_catg,
3716 frameset,
3717 parlist,
3718 recipe_name);
3719 enu_check_error_code("failure writing result");
3720 }
3721 }
3722
3723 } else if (standards->size == 1){
3724
3725 /* Transfer calibration from the external image */
3726
3727 eris_nix_img_cal_phot_external(frameset,
3728 parlist,
3729 standards,
3730 jitters,
3731 out_catg,
3732 recipe_name);
3733 enu_check_error_code("error attempting external photometric "
3734 "calibration");
3735 } else {
3736 cpl_error_set_message(cpl_func, CPL_ERROR_INCOMPATIBLE_INPUT,
3737 "only one "
3738 ERIS_NIX_IMG_STD_COMBINED_PRO_CATG
3739 " file is allowed, found %d",
3740 (int) standards->size);
3741 }
3742
3743cleanup:
3744 enu_located_imagelist_delete(object_jitters);
3745 enu_located_imagelist_delete(std_jitters);
3747 cpl_frameset_delete(used);
3748
3749 return (int) cpl_error_get_code();
3750}
3751
3752
3753/*----------------------------------------------------------------------------*/
3768/*----------------------------------------------------------------------------*/
3769cpl_error_code eris_nix_scired_hdrl_stack(cpl_frameset * frameset,
3770 const cpl_parameterlist * parlist,
3771 const char* recipe_name,
3772 const char* context) {
3773
3774 cpl_propertylist * applist = NULL;
3775 cpl_property * bunit = NULL;
3776 hdrl_parameter * cat_params = NULL;
3777 cpl_property * fluxcal_0 = NULL;
3778 const char * funcid = "eris_nix_img_hdrl_stack";
3779 cpl_frame * inherit = NULL;
3780 located_imagelist * jitters = NULL;
3781 cpl_property * jitter_psf_fwhm = NULL;
3782 hdrl_parameter * method = NULL;
3783 located_imagelist * object_jitters = NULL;
3784 cpl_vector * obsid = NULL;
3785 hdrl_parameter * outgrid = NULL;
3786 char * photsys_0 = NULL;
3787 char * proto_copy = NULL;
3788 cpl_frameset * provenance = NULL;
3789 cpl_table * restable = NULL;
3790 hdrl_resample_result * result = NULL;
3791 cpl_image * stack_conf = NULL;
3792 cpl_propertylist * stack_header = NULL;
3793 hdrl_image * stack_himage = NULL;
3794 located_image * stacked = NULL;
3795 located_imagelist * std_jitters = NULL;
3796 cpl_propertylist * tablelist = NULL;
3797 cpl_wcs * template_wcs = NULL;
3798 cpl_frameset * used = NULL;
3799 cpl_property * zp_method_0 = NULL;
3800 const cpl_parameter * p = NULL;
3801 char * param_name = NULL;
3802
3803 enu_check_error_code("%s():%d: An error is already set: %s",
3804 cpl_func, __LINE__, cpl_error_get_where());
3805
3806 /* Check input parameters */
3807
3808 cpl_ensure_code(frameset, CPL_ERROR_NULL_INPUT);
3809 cpl_ensure_code(parlist, CPL_ERROR_NULL_INPUT);
3810
3811 cpl_msg_set_level_from_env();
3812
3813 /* check for invalid input */
3814 if(eris_files_dont_exist(frameset) != CPL_ERROR_NONE) {
3815 return CPL_ERROR_BAD_FILE_FORMAT;
3816 }
3817 /* Retrieve input parameters */
3818
3819 /* .. the resampling method and parameters */
3820 param_name = cpl_sprintf("%s.interpolation_method", context);
3821 p = cpl_parameterlist_find_const(parlist, param_name);
3822 const char * interpolation_method = cpl_parameter_get_string(p);
3823 cpl_free(param_name);
3824
3825 param_name = cpl_sprintf("%s.loop_distance", context);
3826 p = cpl_parameterlist_find_const(parlist, param_name);
3827 const int loop_distance = cpl_parameter_get_int(p);
3828 cpl_free(param_name);
3829
3830 /* don't weight by image errors */
3831 const cpl_boolean use_errorweights = CPL_FALSE;
3832
3833 param_name = cpl_sprintf("%s.kernel_size", context);
3834 p = cpl_parameterlist_find_const(parlist, param_name);
3835 const int kernel_size = cpl_parameter_get_int(p);
3836 cpl_free(param_name);
3837
3838 param_name = cpl_sprintf("%s.critical_radius", context);
3839 p = cpl_parameterlist_find_const(parlist, param_name);
3840 const double critical_radius = cpl_parameter_get_double(p);
3841 cpl_free(param_name);
3842
3843 param_name = cpl_sprintf("%s.pix_frac_x", context);
3844 p = cpl_parameterlist_find_const(parlist, param_name);
3845 const double pix_frac_x = cpl_parameter_get_double(p);
3846 cpl_free(param_name);
3847
3848 param_name = cpl_sprintf("%s.pix_frac_y", context);
3849 p = cpl_parameterlist_find_const(parlist, param_name);
3850 const double pix_frac_y = cpl_parameter_get_double(p);
3851 cpl_free(param_name);
3852
3853 const double pix_frac_lambda = 100.0;
3854
3855 enu_check_error_code("Could not retrieve input parameters");
3856
3857
3858 if (!strcmp(interpolation_method, "nearest")) {
3860 } else if (!strcmp(interpolation_method, "linear")) {
3861 method = hdrl_resample_parameter_create_linear(loop_distance,
3862 use_errorweights);
3863 } else if (!strcmp(interpolation_method, "quadratic")) {
3864 method = hdrl_resample_parameter_create_quadratic(loop_distance,
3865 use_errorweights);
3866 } else if (!strcmp(interpolation_method, "renka")) {
3867 method = hdrl_resample_parameter_create_renka(loop_distance,
3868 use_errorweights,
3869 critical_radius);
3870 } else if (!strcmp(interpolation_method, "drizzle")) {
3871 method = hdrl_resample_parameter_create_drizzle(loop_distance,
3872 use_errorweights,
3873 pix_frac_x,
3874 pix_frac_y,
3875 pix_frac_lambda);
3876 } else if (!strcmp(interpolation_method, "lanczos")) {
3877 method = hdrl_resample_parameter_create_lanczos(loop_distance,
3878 use_errorweights,
3879 kernel_size);
3880 } else {
3881 cpl_error_set_message(cpl_func, CPL_ERROR_ILLEGAL_INPUT,
3882 "bad interpolation method: %s",
3883 interpolation_method);
3884 }
3885 enu_check_error_code("Error constructing interpolation method");
3886
3887 /* Identify the RAW and CALIB frames in the input frameset */
3888
3889 eris_nix_dfs_set_groups(frameset);
3890 enu_check_error_code("Could not identify RAW and CALIB frames");
3891
3892 /* read the input frameset */
3893
3894 used = cpl_frameset_new();
3895 object_jitters = enu_limlist_load_from_frameset(frameset,
3896 ERIS_NIX_CAL_PHOT_OBJECT_JITTER_PRO_CATG, used);
3897 enu_check_error_code("Could not read %s frames",
3898 ERIS_NIX_CAL_PHOT_OBJECT_JITTER_PRO_CATG);
3899 cpl_msg_info(funcid, "%d %s frames read", (int) object_jitters->size,
3900 ERIS_NIX_CAL_PHOT_OBJECT_JITTER_PRO_CATG);
3901 std_jitters = enu_limlist_load_from_frameset(frameset,
3902 ERIS_NIX_CAL_PHOT_STD_JITTER_PRO_CATG, used);
3903 enu_check_error_code("Could not read %s frames",
3904 ERIS_NIX_CAL_PHOT_STD_JITTER_PRO_CATG);
3905 cpl_msg_info(funcid, "%d %s frames read", (int) std_jitters->size,
3906 ERIS_NIX_CAL_PHOT_STD_JITTER_PRO_CATG);
3907
3908 /* is this a target object or standard? */
3909
3910 enu_check(!(object_jitters->size > 0 && std_jitters->size > 0),
3911 CPL_ERROR_ILLEGAL_INPUT,
3912 "SoF cannot contain data for both target and standard");
3913 enu_check(!(object_jitters->size == 0 && std_jitters->size == 0),
3914 CPL_ERROR_DATA_NOT_FOUND,
3915 "SoF contains no data");
3916 const char * out_catg = NULL;
3917 if(object_jitters->size > 0) {
3918 jitters = object_jitters;
3919 out_catg = ERIS_NIX_IMG_OBS_COMBINED_PRO_CATG;
3920 enu_located_imagelist_delete(std_jitters);
3921 std_jitters = NULL;
3922 } else {
3923 jitters = std_jitters;
3924 out_catg = ERIS_NIX_IMG_STD_COMBINED_PRO_CATG;
3925 enu_located_imagelist_delete(object_jitters);
3926 object_jitters = NULL;
3927 }
3928
3929 /* get some info from jitters that we will need after they have been
3930 deleted */
3931
3932 cpl_size njitters = jitters->size;
3933 const char * proto = cpl_frame_get_filename((jitters->limages[0])->
3934 frame);
3935 proto_copy = cpl_strdup(proto);
3936
3937 inherit = cpl_frame_duplicate(jitters->limages[0]->frame);
3938
3939 /* Loop through the jitter images and populate the resampling table */
3940
3941 obsid = cpl_vector_new(jitters->size);
3942 cpl_vector_fill(obsid, -1.0);
3943 int ncombine = 0;
3944 double total_exptime = 0.0;
3945 double mjd_start = 1000000.0;
3946 double mjd_end = 0.0;
3947
3948 /* take pixel scale and wcs from first jitter file */
3949
3950 double cd1_1 = cpl_propertylist_get_double(jitters->limages[0]->plist,
3951 "CD1_1");
3952 double cd2_1 = cpl_propertylist_get_double(jitters->limages[0]->plist,
3953 "CD2_1");
3954 double pixsize = sqrt(cd1_1 * cd1_1 + cd2_1 * cd2_1) * 3600.0;
3955 cpl_msg_info(cpl_func, "pixel scale: %6.4f arcsec", pixsize);
3956 template_wcs = cpl_wcs_new_from_propertylist(jitters->limages[0]->plist);
3957 enu_check_error_code("error set after loading template wcs");
3958
3959 /* some elements of catalogue parameters can be overridden by contents
3960 of data files. This is done in a roundabout way because you can't
3961 simply access fields in the catalogue parameter structure from
3962 outside HDRL */
3963
3964 param_name = cpl_sprintf("%s.catalogue.det.effective-gain", context);
3965 p = cpl_parameterlist_find_const(parlist, param_name);
3966 double gain = cpl_parameter_get_double(p);
3967 cpl_free(param_name);
3968
3969 if (cpl_propertylist_has(jitters->limages[0]->plist, "ESO DARK GAIN")) {
3970 cpl_msg_info(cpl_func, "reading detector gain from first jitter");
3971 gain = cpl_propertylist_get_double(jitters->limages[0]->plist,
3972 "ESO DARK GAIN");
3973 }
3974
3975 param_name = cpl_sprintf("%s.catalogue.det.saturation", context);
3976 p = cpl_parameterlist_find_const(parlist, param_name);
3977 double saturation = cpl_parameter_get_double(p);
3978 cpl_free(param_name);
3979
3980 /* saturation in adu/s is DETMON_saturation/dit */
3981 if (cpl_propertylist_has(jitters->limages[0]->plist,
3982 "ESO DETMON SATURATION")) {
3983 cpl_msg_info(cpl_func,
3984 "reading detector saturation level from first jitter");
3985 double saturation_adu = cpl_propertylist_get_double(
3986 jitters->limages[0]->plist,
3987 "ESO DETMON SATURATION");
3988 double dit = enu_get_dit(jitters->limages[0]->plist);
3989 saturation = saturation_adu / dit;
3990 cpl_msg_info(cpl_func,
3991 "saturation(adu)=%5.3e dit=%5.3e saturation(adu/s)=%5.3e",
3992 saturation_adu, dit, saturation);
3993
3994 }
3995
3996 param_name = cpl_sprintf("%s.catalogue.obj.min-pixels", context);
3997 p = cpl_parameterlist_find_const(parlist, param_name);
3998 int minpixels = cpl_parameter_get_int(p);
3999 cpl_free(param_name);
4000
4001 param_name = cpl_sprintf("%s.catalogue.obj.threshold", context);
4002 p = cpl_parameterlist_find_const(parlist, param_name);
4003 double threshold = cpl_parameter_get_double(p);
4004 cpl_free(param_name);
4005
4006 param_name = cpl_sprintf("%s.catalogue.obj.deblending", context);
4007 p = cpl_parameterlist_find_const(parlist, param_name);
4008 cpl_boolean deblending = cpl_parameter_get_bool(p);
4009 cpl_free(param_name);
4010
4011 /* use AOMODE to decide if set catalogue.core-radius and mesh-size to
4012 defaults or read them from parameters */
4013
4014 double core_radius = -1.0;
4015 int mesh_size = -1;
4017 parlist,
4018 jitters->limages[0]->plist,
4019 &core_radius,
4020 &mesh_size);
4021
4022 param_name = cpl_sprintf("%s.catalogue.bkg.estimate", context);
4023 p = cpl_parameterlist_find_const(parlist, param_name);
4024 cpl_boolean estimate = cpl_parameter_get_bool(p);
4025 cpl_free(param_name);
4026
4027 param_name = cpl_sprintf("%s.catalogue.bkg.smooth-gauss-fwhm",
4028 context);
4029 p = cpl_parameterlist_find_const(parlist, param_name);
4030 double smooth_gauss_fwhm = cpl_parameter_get_double(p);
4031 cpl_free(param_name);
4032
4033 cat_params = hdrl_catalogue_parameter_create(minpixels,
4034 threshold,
4035 deblending,
4036 core_radius,
4037 estimate,
4038 mesh_size,
4039 smooth_gauss_fwhm,
4040 gain,
4041 saturation,
4042 HDRL_CATALOGUE_ALL);
4043 enu_check_error_code("error set after setting catalogue params");
4044
4045 cpl_msg_info(cpl_func, "gain=%4.2f saturation=%6.2f", gain, saturation);
4046
4047 provenance = cpl_frameset_new();
4048
4049 cpl_msg_info(cpl_func, "assembling information on combined exposures");
4050
4051 for (cpl_size j = 0; j < jitters->size; j++) {
4052
4053 /* add the frame to the provenance of images contributing
4054 to the result */
4055
4056 cpl_frameset_insert(provenance, cpl_frame_duplicate(
4057 jitters->limages[j]->frame));
4058
4059 /* calculate some other things needed by the DFS to describe
4060 what has gone into the measurement */
4061
4062 if (!bunit) {
4063 bunit = cpl_property_duplicate(cpl_propertylist_get_property(
4064 jitters->limages[j]->plist,
4065 "BUNIT"));
4066 }
4067
4068 if (!jitter_psf_fwhm) {
4069 jitter_psf_fwhm = cpl_property_duplicate(
4070 cpl_propertylist_get_property(
4071 jitters->limages[j]->plist,
4072 "PSF_FWHM"));
4073 }
4074
4075 /* .. number of measurements combined */
4076
4077 ncombine++;
4078
4079 /* .. total integration time */
4080
4081 double dit = enu_get_dit(jitters->limages[j]->plist);
4082 double exptime = dit * cpl_propertylist_get_int(
4083 jitters->limages[j]->plist, "ESO DET NDIT");
4084 total_exptime += exptime;
4085
4086 /* .. MJD of start and end of measurements used */
4087
4088 double jitter_start = cpl_propertylist_get_double(
4089 jitters->limages[j]->plist, "MJD-OBS");
4090 if (jitter_start < mjd_start) {
4091 mjd_start = jitter_start;
4092 }
4093 double jitter_end = cpl_propertylist_get_double(
4094 jitters->limages[j]->plist, "MJD-END");
4095 if (jitter_end > mjd_end) {
4096 mjd_end = jitter_end;
4097 }
4098 cpl_msg_info(cpl_func, "..combined mjd start: %15.8f end: %15.8f",
4099 mjd_start, mjd_end);
4100
4101 /* .. the OBS_IDs of the component measurements, no duplicates */
4102
4103 int obs_id = cpl_propertylist_get_int(jitters->limages[j]->plist,
4104 "ESO OBS ID");
4105 for (cpl_size jj = 0; jj < cpl_vector_get_size(obsid); jj++) {
4106 if ((int) cpl_vector_get(obsid, jj) == obs_id) {
4107 break;
4108 } else if (cpl_vector_get(obsid, jj) < 0.0) {
4109 cpl_vector_set(obsid, jj, obs_id);
4110 break;
4111 }
4112 }
4113 }
4114
4115 /* set the output grid */
4116
4117 outgrid = hdrl_resample_parameter_create_outgrid2D(pixsize / 3600.0,
4118 pixsize / 3600.0);
4119
4120 double photzp_0 = 0.0;
4121 double photzper_0 = 0.0;
4122 double extcoef_0 = 0.0;
4123
4124 cpl_msg_info(cpl_func, "stacking image data");
4125 {
4126
4127 for (cpl_size j = 0; j < jitters->size; j++) {
4128 cpl_msg_info(cpl_func, "ingesting jitter %d", (int)j);
4129
4130 /* get calibration info */
4131
4132 const cpl_property * fluxcal_j = cpl_propertylist_get_property(
4133 jitters->limages[j]->plist, "FLUXCAL");
4134 const char * photsys_j = cpl_propertylist_get_string(
4135 jitters->limages[j]->plist, "PHOTSYS");
4136 const cpl_property * zp_method_j = cpl_propertylist_get_property(
4137 jitters->limages[j]->plist,
4138 "ZPMETHOD");
4139 double photzp_j = cpl_propertylist_get_double(
4140 jitters->limages[j]->plist, "PHOTZP");
4141 double photzper_j = cpl_propertylist_get_double(
4142 jitters->limages[j]->plist, "PHOTZPER");
4143 double extcoef_j = cpl_propertylist_get_double(
4144 jitters->limages[j]->plist,
4145 "ESO DRS EXTCOEF");
4146
4147 cpl_msg_info(cpl_func, "..fluxcal: %s",
4148 cpl_property_get_string(fluxcal_j));
4149 cpl_msg_info(cpl_func, "..photsys: %s", photsys_j);
4150 cpl_msg_info(cpl_func, "..extcoef: %f", extcoef_j);
4151 cpl_msg_info(cpl_func, "..zp_method: %s",
4152 cpl_property_get_string(zp_method_j));
4153 cpl_msg_info(cpl_func, "..photzp: %f photzper: %f", photzp_j,
4154 photzper_j);
4155
4156 if (j == 0) {
4157 photzp_0 = photzp_j;
4158 photzper_0 = photzper_j;
4159 fluxcal_0 = cpl_property_duplicate(fluxcal_j);
4160 photsys_0 = cpl_strdup(photsys_j);
4161 zp_method_0 = cpl_property_duplicate(zp_method_j);
4162 extcoef_0 = extcoef_j;
4163 } else {
4164
4165 if (!strcmp(cpl_property_get_string(fluxcal_j), "CALIBRATED")) {
4166 cpl_msg_warning(cpl_func, "jitter is not calbrated");
4167 }
4168 if (strcmp(photsys_j, "VEGA")) {
4169 cpl_msg_warning(cpl_func, "PHOTSYS is not recognized");
4170 }
4171 if (extcoef_j != extcoef_0) {
4172 cpl_msg_warning(cpl_func,
4173 "..inconsistent extcoef: %d %5.3e %5.3e",
4174 (int) j, extcoef_0, extcoef_j);
4175 }
4176
4177 /* other checks? */
4178 }
4179
4180 /* factor to multiply jitter j to get on same intensity scale as
4181 jitter 0 */
4182
4183 double factor = pow(10.0, (photzp_0 - photzp_j) / 2.5);
4184 cpl_msg_info(cpl_func, "..scaling jitter %d by %5.3e", (int)j,
4185 factor);
4186 hdrl_image_mul_scalar(jitters->limages[j]->himage,
4187 (hdrl_value){factor, 0.0});
4188
4189 /* The following commented-out code snippet would be useful if
4190 we wanted to weight according to the confidence array. In
4191 this case use_errorweights would be set TRUE in resampling
4192 'method' so that 'an additional weight defined as 1/variance'
4193 would be applied. To use confidence rather than pixel
4194 variance the 'resampling variance' should be 1/confidence,
4195 and the 'resampling error' the sqrt of that.
4196
4197 Not being done now because I don't think it's currently
4198 possible to resample the image errors weighted by
4199 the confidence. */
4200/*
4201 cpl_image * inverse_conf = cpl_image_duplicate(
4202 jitters->limages[j]->confidence);
4203 double * ic_data = cpl_image_get_data_double(inverse_conf);
4204 const cpl_size nx = cpl_image_get_size_x(inverse_conf);
4205 const cpl_size ny = cpl_image_get_size_y(inverse_conf);
4206 for (cpl_size i=0; i<nx*ny; i++) {
4207*/
4208 /* assume case of 0 confidence pixel is also 'bad' in image */
4209/*
4210 if (ic_data[i] > 0.0) {
4211 ic_data[i] = sqrt(1.0 / ic_data[i]);
4212 }
4213 }
4214*/
4215
4216 /* add the jitter to the resampling table */
4217
4218 cpl_wcs * wcs = cpl_wcs_new_from_propertylist(
4219 jitters->limages[j]->plist);
4220 cpl_table * jitter_table = hdrl_resample_image_to_table(
4221 jitters->limages[j]->himage,
4222 wcs);
4223 cpl_wcs_delete(wcs);
4224
4225 if (restable == NULL) {
4226 restable = jitter_table;
4227 } else {
4228 cpl_size nrow = cpl_table_get_nrow(restable);
4229 cpl_table_insert(restable, jitter_table, nrow+1);
4230 cpl_table_delete(jitter_table);
4231 }
4232 }
4233
4234 enu_check_error_code("error set after loading jitters");
4235
4236 /* delete the jitters to free up memory */
4237
4238 enu_located_imagelist_delete(jitters); jitters = NULL;
4239 object_jitters = std_jitters = NULL;
4240
4241 /* Stack the jitter image data */
4242
4243 cpl_msg_info(cpl_func, "calling hdrl_resample_compute");
4244 result = hdrl_resample_compute(restable, method, outgrid,
4245 template_wcs);
4246
4247 /* release the resampling table as no longer needed */
4248
4249 cpl_table_delete(restable); restable = NULL;
4250 enu_check_error_code("error set computing resample_compute");
4251
4252 /* keep the resampled image and header for later but delete the
4253 rest of the result */
4254
4255 stack_himage = hdrl_image_duplicate(
4257 result->himlist, 0));
4258 stack_header = cpl_propertylist_duplicate(result->header);
4259 hdrl_resample_result_delete(result); result = NULL;
4260 }
4261
4262 cpl_msg_info(cpl_func, "stacking the confidence");
4263
4264 {
4265 /* reload jitter data, with fewer checks this time*/
4266
4267 cpl_frameset * ignore = cpl_frameset_new();
4268 object_jitters = enu_limlist_load_from_frameset(frameset,
4269 ERIS_NIX_CAL_PHOT_OBJECT_JITTER_PRO_CATG,
4270 ignore);
4271 std_jitters = enu_limlist_load_from_frameset(frameset,
4272 ERIS_NIX_CAL_PHOT_STD_JITTER_PRO_CATG,
4273 ignore);
4274 if(object_jitters->size > 0) {
4275 jitters = object_jitters;
4276 enu_located_imagelist_delete(std_jitters); std_jitters = NULL;
4277 } else {
4278 jitters = std_jitters;
4279 enu_located_imagelist_delete(object_jitters); object_jitters = NULL;
4280 }
4281
4282 /* build the data table */
4283
4284 for (cpl_size j = 0; j < jitters->size; j++) {
4285 cpl_msg_info(cpl_func, "ingesting jitter %d", (int)j);
4286
4287 double photzp_j = cpl_propertylist_get_double(
4288 jitters->limages[j]->plist, "PHOTZP");
4289
4290 double factor = pow(10.0, (photzp_0 - photzp_j) / 2.5);
4291 cpl_msg_info(cpl_func, "..scaling by %5.3e", factor);
4292 hdrl_image_mul_scalar(jitters->limages[j]->himage,
4293 (hdrl_value){factor, 0.0});
4294
4295 /* To resample the confidence we replace the data error
4296 plane with numbers derived from the confidence. Confidence
4297 is 1 / variance so we want error = sqrt(1 / confidence) */
4298
4299 cpl_image * inverse_conf = cpl_image_duplicate(
4300 jitters->limages[j]->confidence);
4301 double * ic_data = cpl_image_get_data_double(inverse_conf);
4302 const cpl_size nx = cpl_image_get_size_x(inverse_conf);
4303 const cpl_size ny = cpl_image_get_size_y(inverse_conf);
4304 for (cpl_size i=0; i<nx*ny; i++) {
4305 if (ic_data[i] > 0.0) {
4306 ic_data[i] = sqrt(1.0 / ic_data[i]);
4307 }
4308 }
4309
4310 hdrl_image * jitter_error = hdrl_image_create(hdrl_image_get_image(
4311 jitters->limages[j]->himage),
4312 inverse_conf);
4313 cpl_wcs * wcs = cpl_wcs_new_from_propertylist(
4314 jitters->limages[j]->plist);
4315 cpl_table * jitter_table = hdrl_resample_image_to_table(
4316 jitter_error,
4317 wcs);
4318 cpl_wcs_delete(wcs);
4319 cpl_image_delete(inverse_conf);
4320 hdrl_image_delete(jitter_error);
4321
4322 if (restable == NULL) {
4323 restable = jitter_table;
4324 } else {
4325 cpl_size nrow = cpl_table_get_nrow(restable);
4326 cpl_table_insert(restable, jitter_table, nrow+1);
4327 cpl_table_delete(jitter_table);
4328 }
4329 }
4330
4331 enu_located_imagelist_delete(jitters); jitters = NULL;
4332 object_jitters = std_jitters = NULL;
4333 enu_check_error_code("error set after loading error image of jitters");
4334
4335 cpl_msg_info(cpl_func, "calling hdrl_resample_compute");
4336 result = hdrl_resample_compute(restable, method, outgrid, template_wcs);
4337 cpl_table_delete(restable); restable = NULL;
4338 enu_check_error_code("error after resample_compute of image confidence");
4339
4340 /* Calculate the confidence from the result errors. Raw confidence is
4341 1 / variance or result_error / result_error^3 */
4342
4343 stack_conf = cpl_image_duplicate(
4346 result->himlist, 0)));
4347 cpl_image * sc_copy = cpl_image_duplicate(stack_conf);
4348 cpl_image_divide(stack_conf, sc_copy);
4349 cpl_image_divide(stack_conf, sc_copy);
4350 cpl_image_divide(stack_conf, sc_copy);
4351 cpl_image_delete(sc_copy);
4352
4353 enu_normalise_confidence(stack_conf);
4354
4355 hdrl_resample_result_delete(result); result = NULL;
4356 }
4357
4358 /* assemble result. hdrl_create makes copies, located_image_new takes
4359 ownership, hence the different memory management */
4360
4361 stacked = enu_located_image_new(stack_himage,
4362 NULL,
4363 stack_conf,
4364 NULL,
4365 NULL,
4366 stack_header,
4367 NULL,
4368 NULL,
4369 NULL,
4370 NULL,
4371 NULL);
4372 enu_check_error_code("error set after image stacking");
4373
4374 /* generate a source catalogue for the stacked result */
4375
4376 cpl_wcs * result_wcs = cpl_wcs_new_from_propertylist(stacked->plist);
4377 stacked->objects = enu_catalogue_compute(stacked->himage,
4378 stacked->confidence,
4379 result_wcs,
4380 cat_params);
4381 cpl_wcs_delete(result_wcs);
4382 enu_check_error_code("error in target reduction: catalogue");
4383
4384 /* add result properties in applist */
4385
4386 applist = cpl_propertylist_new();
4387
4388 /* update PRO.CATG and stack info */
4389
4390 cpl_propertylist_update_string(applist, CPL_DFS_PRO_CATG, out_catg);
4391 cpl_propertylist_update_string(applist, "PRODCATG", "SCIENCE.IMAGE");
4392 cpl_propertylist_update_string(applist, "BUNIT", cpl_property_get_string(bunit));
4393 cpl_propertylist_set_comment(applist, "BUNIT", cpl_property_get_comment(bunit));
4394 cpl_propertylist_update_int(applist, "NCOMBINE", ncombine);
4395 cpl_propertylist_update_double(applist, "TEXPTIME", total_exptime);
4396 cpl_propertylist_update_double(applist, "EXPTIME", total_exptime);
4397 cpl_propertylist_update_double(applist, "MJD-OBS", mjd_start);
4398 cpl_propertylist_update_double(applist, "MJD-END", mjd_end);
4399 for (cpl_size j = 0; j < njitters; ++j) {
4400 if (cpl_vector_get(obsid, j) > 0.0) {
4401 char * pname = cpl_sprintf("OBID%.0i", (int)(j+1));
4402 cpl_propertylist_update_int(applist, pname,
4403 (int)cpl_vector_get(obsid, j));
4404 cpl_free(pname);
4405 }
4406 }
4407
4408 /* write PHOTZP info */
4409
4410 cpl_propertylist_update_string(applist, "PHOTSYS", photsys_0);
4411 cpl_propertylist_update_double(applist, "PHOTZP", photzp_0);
4412 cpl_propertylist_set_comment(applist, "PHOTZP",
4413 "MAG=-2.5*log(data)+PHOTZP+APCOR");
4414 cpl_propertylist_update_string(applist, "FLUXCAL",
4415 cpl_property_get_string(fluxcal_0));
4416 cpl_propertylist_set_comment(applist, "FLUXCAL",
4417 cpl_property_get_comment(fluxcal_0));
4418 cpl_propertylist_update_double(applist, "PHOTZPER", photzper_0);
4419 cpl_propertylist_update_string(applist, "ZPMETHOD",
4420 cpl_property_get_string(zp_method_0));
4421 cpl_propertylist_set_comment(applist, "ZPMETHOD",
4422 cpl_property_get_comment(zp_method_0));
4423 cpl_propertylist_update_double(applist, "ESO DRS EXTCOEF", extcoef_0);
4424 cpl_propertylist_set_comment(applist, "ESO DRS EXTCOEF",
4425 "[mag] Assumed extinction coefficient");
4426
4427 /* try to get actual fwhm from catalogue, failing that use the PSF
4428 from the first stacked image */
4429
4430 double fwhm_pix = -1.0;
4431 if (stacked->objects &&
4432 stacked->objects->qclist &&
4433 cpl_propertylist_has(stacked->objects->qclist, "ESO QC IMAGE_SIZE")) {
4434
4435 fwhm_pix = cpl_propertylist_get_double(stacked->objects->qclist,
4436 "ESO QC IMAGE_SIZE");
4437 }
4438
4439 if (fwhm_pix != -1.0) {
4440 cpl_propertylist_update_double(applist, "PSF_FWHM",
4441 fwhm_pix * pixsize);
4442 cpl_propertylist_set_comment(applist, "PSF_FWHM",
4443 "Average FWHM of stellar objects[arcsec]");
4444 } else {
4445 cpl_propertylist_update_double(applist, "PSF_FWHM",
4446 cpl_property_get_double(jitter_psf_fwhm));
4447 cpl_propertylist_set_comment(applist, "PSF_FWHM",
4448 cpl_property_get_comment(jitter_psf_fwhm));
4449 fwhm_pix = cpl_property_get_double(jitter_psf_fwhm) / pixsize;
4450 }
4451
4452 double abmaglim = -1.0;
4453 enu_calc_maglim(stacked, photzp_0, fwhm_pix, &abmaglim);
4454 cpl_propertylist_update_double(applist, "ABMAGLIM", abmaglim);
4455 cpl_propertylist_set_comment(applist, "ABMAGLIM", "5-sigma "
4456 "limiting AB magnitude");
4457
4458 /* ABMAGSAT. Data calibrated as photons/s so exptime=1 for calculation.
4459 Formula copied from CASU casu_calculate_abmag_sat */
4460
4461 double mean_sky = 0.0;
4462 if (cpl_propertylist_has(stacked->objects->qclist, "ESO QC MEAN_SKY")) {
4463 mean_sky = cpl_propertylist_get_double(stacked->objects->qclist,
4464 "ESO QC MEAN_SKY");
4465 } else {
4466 cpl_msg_warning(cpl_func, "ESO QC MEAN_SKY not found, mean "
4467 "sky assumed 0");
4468 }
4469 double exptime = 1.0;
4470 double abmagsat = -1.0;
4471 if ((CPL_MATH_PI_4 * CPL_MATH_LN2 * (saturation - mean_sky) *
4472 pow(fwhm_pix, 2.0) / exptime) > 0.0) {
4473 abmagsat = photzp_0 - 2.5 * log10(CPL_MATH_PI_4 * CPL_MATH_LN2 *
4474 (saturation - mean_sky) * pow(fwhm_pix, 2.0) / exptime);
4475 }
4476 cpl_msg_debug(cpl_func, "abmagsat stack %5.3e %5.3e %5.3e %5.3e %5.3e",
4477 photzp_0, saturation, mean_sky, fwhm_pix, exptime);
4478 cpl_propertylist_update_double(applist, "ABMAGSAT", abmagsat);
4479 cpl_propertylist_set_comment(applist, "ABMAGSAT", "Saturation "
4480 "limit for point sources (AB mag)");
4481
4482 /* set RA, DEC from WCS rather than let dfs copy it from one of the
4483 frames */
4484
4485 {
4486 cpl_wcs * stack_wcs = cpl_wcs_new_from_propertylist(stacked->plist);
4487 double ra = 0.0;
4488 double dec = 0.0;
4489 enu_get_ra_dec(stack_wcs, &ra, &dec);
4490
4491 cpl_propertylist_update_double(applist, "RA", ra);
4492 cpl_propertylist_update_double(applist, "DEC", dec);
4493
4494 cpl_wcs_delete(stack_wcs);
4495 }
4496 enu_check_error_code("error set after setting header keywords");
4497
4498 /* generate name of file with stacked image */
4499
4500 char * stack_fname = enu_repreface(proto_copy, "stack");
4501
4502 enu_dfs_save_limage(frameset,
4503 parlist,
4504 used,
4505 CPL_FALSE,
4506 stacked,
4507 recipe_name,
4508 inherit,
4509 applist,
4510 PACKAGE "/" PACKAGE_VERSION,
4511 stack_fname);
4512
4513 /* save the catalogue */
4514
4515 cpl_frame * stack_frame = cpl_frame_new();
4516 cpl_frame_set_filename(stack_frame, stack_fname);
4517 cpl_frame_set_tag(stack_frame, ERIS_NIX_IMG_CATALOGUE_PRO_CATG);
4518 cpl_frame_set_type(stack_frame, CPL_FRAME_TYPE_ANY);
4519 cpl_frame_set_group(stack_frame, CPL_FRAME_GROUP_PRODUCT);
4520 cpl_frame_set_level(stack_frame, CPL_FRAME_LEVEL_FINAL);
4521 cpl_frameset_insert(used, stack_frame);
4522 cpl_free(stack_fname);
4523
4524 //cpl_table_dump(stacked->objects->catalogue, 1, 10, NULL);
4525
4526 /* ..the header for the table extension */
4527 tablelist = cpl_propertylist_duplicate(stacked->objects->qclist);
4528 cpl_propertylist_copy_property_regexp(tablelist,
4529 applist,
4530 "ABMAGLIM|ABMAGSAT|PSF_FWHM|PHOTSYS|"
4531 "RA|DEC",
4532 CPL_FALSE);
4533 enu_dfs_save_catalogue(frameset,
4534 stack_frame,
4535 parlist,
4536 stacked->objects->catalogue,
4537 tablelist,
4538 "image source catalogue",
4539 recipe_name,
4540 PACKAGE "/" PACKAGE_VERSION,
4541 "cat.stack",
4542 ERIS_NIX_IMG_CATALOGUE_PRO_CATG);
4543
4544 /* useful for outputting stack result with catalogue for debugging
4545 BUT CATALOGUE OUTPUT TBD IN enu_dfs_save_limage */
4546 if (CPL_FALSE) {
4547 cpl_propertylist_update_string(applist, "PRODCATG", "ANCILLARY.IMAGE");
4548 enu_dfs_save_limage(frameset,
4549 parlist,
4550 provenance,
4551 CPL_FALSE,
4552 stacked,
4553 recipe_name,
4554 inherit,
4555 applist,
4556 PACKAGE "/" PACKAGE_VERSION,
4557 "stack_cat_debug.fits");
4558 }
4559
4560cleanup:
4561 cpl_propertylist_delete(applist);
4562 cpl_property_delete(bunit);
4563 hdrl_parameter_delete(cat_params);
4564 cpl_property_delete(fluxcal_0);
4565 cpl_frame_delete(inherit);
4566 cpl_property_delete(jitter_psf_fwhm);
4567 hdrl_parameter_delete(method);
4568 enu_located_imagelist_delete(object_jitters);
4569 cpl_vector_delete(obsid);
4570 hdrl_parameter_delete(outgrid);
4571 cpl_free(photsys_0);
4572 cpl_free(proto_copy);
4573 cpl_frameset_delete(provenance);
4574 cpl_table_delete(restable);
4576 enu_located_image_delete(stacked);
4577 enu_located_imagelist_delete(std_jitters);
4578 cpl_propertylist_delete(tablelist);
4579 cpl_wcs_delete(template_wcs);
4580 cpl_frameset_delete(used);
4581 cpl_property_delete(zp_method_0);
4582
4583 return (int)cpl_error_get_code();
4584}
4585
4586
4587
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:907
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:57
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:273
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()