naco_img_jitter.c

00001 /* $Id: naco_img_jitter.c,v 1.120 2010/05/06 12:16:03 llundin Exp $
00002  *
00003  * This file is part of the NACO Pipeline
00004  * Copyright (C) 2002,2003 European Southern Observatory
00005  *
00006  * This program is free software; you can redistribute it and/or modify
00007  * it under the terms of the GNU General Public License as published by
00008  * the Free Software Foundation; either version 2 of the License, or
00009  * (at your option) any later version.
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License
00017  * along with this program; if not, write to the Free Software
00018  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02111-1307  USA
00019  */
00020 
00021 /*
00022  * $Author: llundin $
00023  * $Date: 2010/05/06 12:16:03 $
00024  * $Revision: 1.120 $
00025  * $Name: HEAD $
00026  */
00027 
00028 #ifdef HAVE_CONFIG_H
00029 #include <config.h>
00030 #endif
00031 
00032 /*-----------------------------------------------------------------------------
00033                                 Includes
00034  -----------------------------------------------------------------------------*/
00035 
00036 #include "naco_recipe.h"
00037 #include "irplib_calib.h"
00038 #include "irplib_strehl.h"
00039 
00040 /* Needed for strstr() */
00041 #include <string.h>
00042 
00043 /*-----------------------------------------------------------------------------
00044                             Defines
00045  -----------------------------------------------------------------------------*/
00046 
00047 #define RECIPE_STRING "naco_img_jitter"
00048 
00049 #define EXT0 0
00050 
00051 #define NACO_MIN(A,B) ((A) < (B) ? (A) : (B))
00052 #define NACO_MAX(A,B) ((A) > (B) ? (A) : (B))
00053 
00054 /*-----------------------------------------------------------------------------
00055                             Private Functions prototypes
00056  -----------------------------------------------------------------------------*/
00057 
00058 #ifndef NACO_IMG_JITTER_KEEP_SKY_OBJECTS
00059 static cpl_error_code naco_img_jitter_reject_objects(cpl_image *, double,
00060                                                      double);
00061 #endif
00062 
00063 static cpl_error_code naco_img_jitter_find_strehl(const cpl_imagelist *,
00064                                                   const irplib_framelist *);
00065 
00066 static cpl_image * naco_img_jitter_saa_center(const cpl_imagelist *,
00067                                               cpl_bivector *);
00068 
00069 static cpl_image * naco_img_jitter_saa_lucky(const cpl_imagelist *,
00070                                              const cpl_vector *,
00071                                              const cpl_bivector *, double);
00072 
00073 static cpl_image * naco_img_jitter_find_sky_cube(int, int, const cpl_array *,
00074                                                  const irplib_framelist *);
00075 
00076 static cpl_error_code naco_img_jitter_imagelist_wrap_nocube(cpl_imagelist *,
00077                                                             const cpl_array *,
00078                                                             cpl_imagelist *);
00079 
00080 
00081 static cpl_image * naco_img_jitter_combine_cube(cpl_table *, const cpl_imagelist *,
00082                                                 const cpl_propertylist *,
00083                                                 const cpl_parameterlist *, int);
00084 
00085 static cpl_error_code naco_img_jitter_check_cube(const cpl_imagelist *,
00086                                                  const cpl_image *);
00087 
00088 static cpl_error_code naco_img_jitter_do_cube(cpl_imagelist *, cpl_table *,
00089                                               cpl_propertylist *,
00090                                               const cpl_array *,
00091                                               const irplib_framelist *,
00092                                               const cpl_parameterlist *);
00093 
00094 static
00095 cpl_imagelist * naco_img_jitter_load_objimages(cpl_array *,
00096                                                const irplib_framelist *,
00097                                                const cpl_parameterlist *);
00098 
00099 static cpl_image ** naco_img_jitter_reduce(cpl_table *, cpl_propertylist *,
00100                                            const irplib_framelist *,
00101                                            const irplib_framelist *,
00102                                            const cpl_parameterlist *,
00103                                            const char *,
00104                                            const char *,
00105                                            const char *,
00106                                            cpl_boolean *);
00107 
00108 static cpl_image * naco_img_jitter_find_sky(cpl_propertylist *,
00109                                             const cpl_imagelist *,
00110                                             const cpl_imagelist *);
00111 static cpl_image ** naco_img_jitter_saa(cpl_imagelist *,
00112                                         const irplib_framelist *,
00113                                         const cpl_parameterlist *);
00114 static cpl_error_code naco_img_jitter_qc(cpl_propertylist *, cpl_propertylist *,
00115                                          const irplib_framelist *,
00116                                          const cpl_image *, cpl_boolean);
00117 static cpl_error_code naco_img_jitter_qc_apertures(cpl_propertylist *,
00118                                                    const irplib_framelist *,
00119                                                    const cpl_image *);
00120 static cpl_error_code naco_img_jitter_save(cpl_frameset *,
00121                                            const cpl_parameterlist *,
00122                                            const cpl_propertylist *,
00123                                            const cpl_propertylist *,
00124                                            const cpl_image *,
00125                                            const cpl_image *,
00126                                            const cpl_table *);
00127 
00128 NACO_RECIPE_DEFINE(naco_img_jitter, 
00129                    NACO_PARAM_OFFSETS |
00130                    NACO_PARAM_OBJECTS |
00131                    NACO_PARAM_ODDEVEN |
00132                    NACO_PARAM_XCORR   |
00133                    NACO_PARAM_UNION   |
00134                    NACO_PARAM_COMBINE |
00135                    NACO_PARAM_SKYPLANE|
00136                    NACO_PARAM_CUBEMODE|
00137                    NACO_PARAM_LUCK_STR|
00138                    NACO_PARAM_REJ_HILO,
00139                    "Jitter recipe",
00140                   RECIPE_STRING " -- NACO imaging jitter recipe.\n"         
00141                   "The files listed in the Set Of Frames (sof-file) "
00142                   "must be tagged:\n" 
00143                   "NACO-raw-file.fits "NACO_IMG_JITTER_OBJ" or\n"            
00144                   "NACO-raw-file.fits "NACO_IMG_JITTER_SKY" or\n"            
00145                   "NACO-raw-file.fits "NACO_IMG_JITTER_OBJ_POL" or\n"        
00146                   "NACO-raw-file.fits "NACO_IMG_JITTER_SKY_POL" or\n"        
00147                   "NACO-flat-file.fits "NACO_CALIB_FLAT" or\n"               
00148                   "NACO-bpm-file.fits "NACO_CALIB_BPM" or\n"               
00149                   "NACO-dark-file.fits "NACO_CALIB_DARK"\n");
00150 
00151 /*----------------------------------------------------------------------------*/
00155 /*----------------------------------------------------------------------------*/
00156 
00157 /*-----------------------------------------------------------------------------
00158                                 Functions code
00159  -----------------------------------------------------------------------------*/
00160 
00161 /*----------------------------------------------------------------------------*/
00168 /*----------------------------------------------------------------------------*/
00169 static int naco_img_jitter(cpl_frameset            * framelist,
00170                            const cpl_parameterlist * parlist)
00171 {
00172     cpl_errorstate cleanstate = cpl_errorstate_get();
00173     irplib_framelist * allframes = NULL;
00174     irplib_framelist * objframes = NULL;
00175     irplib_framelist * skyframes = NULL;
00176     cpl_propertylist * qclist    = cpl_propertylist_new();
00177     cpl_propertylist * paflist   = cpl_propertylist_new();
00178     cpl_image       ** combined  = NULL;
00179     cpl_table        * cubetable = cpl_table_new(1);
00180     const char       * badpix;
00181     const char       * dark;
00182     const char       * flat;
00183     cpl_boolean        drop_wcs = CPL_FALSE;
00184 
00185 
00186     /* Identify the RAW and CALIB frames in the input frameset */
00187     skip_if (naco_dfs_set_groups(framelist));
00188 
00189     allframes = irplib_framelist_cast(framelist);
00190     skip_if(allframes == NULL);
00191 
00192     objframes = irplib_framelist_extract_regexp(allframes,
00193                                                 "^(" NACO_IMG_JITTER_OBJ "|"
00194                                                 NACO_IMG_JITTER_OBJ_POL ")$",
00195                                                 CPL_FALSE);
00196     skip_if(objframes == NULL);
00197 
00198     skyframes = irplib_framelist_extract_regexp(allframes,
00199                                                 "^(" NACO_IMG_JITTER_SKY "|"
00200                                                 NACO_IMG_JITTER_SKY_POL ")$",
00201                                                 CPL_FALSE);
00202     irplib_framelist_empty(allframes);
00203     if (skyframes == NULL) {
00204         naco_error_reset("The set of frames has no sky frames:");
00205     }
00206 
00207     flat = irplib_frameset_find_file(framelist, NACO_CALIB_FLAT);
00208     bug_if(0);
00209 
00210     badpix = irplib_frameset_find_file(framelist, NACO_CALIB_BPM);
00211     bug_if(0);
00212 
00213     dark = irplib_frameset_find_file(framelist, NACO_CALIB_DARK);
00214     bug_if(0);
00215 
00216     skip_if(irplib_framelist_load_propertylist(objframes, 0, 0, "^("
00217                                                NACO_PFITS_REGEXP_JITTER_FIRST
00218                                                ")$", CPL_FALSE));
00219 
00220     skip_if(irplib_framelist_load_propertylist_all(objframes, 0, "^("
00221                                                    NACO_PFITS_REGEXP_JITTER_ALL
00222                                                    ")$", CPL_FALSE));
00223 
00224     /* Apply the reduction */
00225     cpl_msg_info(cpl_func, "Apply the data recombination");
00226     combined = naco_img_jitter_reduce(cubetable, qclist, objframes, skyframes,
00227                                       parlist, dark, flat, badpix, &drop_wcs);
00228 
00229     skip_if (combined == NULL);
00230 
00231     irplib_framelist_empty(skyframes);
00232 
00233     /* Compute QC parameters from the combined image */
00234     cpl_msg_info(cpl_func, "Compute QC parameters from the combined image");
00235     skip_if (naco_img_jitter_qc(qclist, paflist, objframes, combined[0], drop_wcs));
00236 
00237     irplib_framelist_empty(objframes);
00238     
00239     /* Save the products */
00240     cpl_msg_info(cpl_func, "Save the products");
00241 
00242     /* PRO.CATG */
00243     bug_if (cpl_propertylist_append_string(paflist, CPL_DFS_PRO_CATG,
00244                                            cpl_table_get_ncol(cubetable) > 0 ?
00245                                            NACO_IMG_JITTER_CUBE :
00246                                            NACO_IMG_JITTER_COMB));
00247 
00248     skip_if (naco_img_jitter_save(framelist, parlist, qclist, paflist,
00249                                   combined[0], combined[1], cubetable));
00250 
00251     end_skip;
00252     
00253     if (combined != NULL) {
00254         cpl_image_delete(combined[0]);
00255         cpl_image_delete(combined[1]);
00256         cpl_free(combined);
00257     }
00258     irplib_framelist_delete(allframes);
00259     irplib_framelist_delete(objframes);
00260     irplib_framelist_delete(skyframes);
00261     cpl_propertylist_delete(qclist);
00262     cpl_propertylist_delete(paflist);
00263     cpl_table_delete(cubetable);
00264 
00265     return cpl_error_get_code();
00266 }
00267 
00268 /*----------------------------------------------------------------------------*/
00281 /*----------------------------------------------------------------------------*/
00282 static cpl_image ** naco_img_jitter_reduce(cpl_table              * cubetable,
00283                                            cpl_propertylist       * qclist,
00284                                            const irplib_framelist * obj,
00285                                            const irplib_framelist * sky,
00286                                            const cpl_parameterlist * parlist,
00287                                            const char             * dark,
00288                                            const char             * flat,
00289                                            const char             * bpm,
00290                                            cpl_boolean            * pdid_resize)
00291 {
00292     cpl_errorstate  prestate = cpl_errorstate_get();
00293     const int        nobj = irplib_framelist_get_size(obj);
00294     cpl_imagelist  * objimages  = NULL;
00295     cpl_imagelist  * nocubeimgs = NULL;
00296     cpl_imagelist  * skyimages  = NULL;
00297     cpl_image      * skyimage   = NULL;
00298     cpl_image     ** combined   = NULL;
00299     cpl_array      * iscube     = NULL;
00300     cpl_boolean      has_cube   = CPL_FALSE;
00301     const char     * scubemode = naco_parameterlist_get_string
00302         (parlist, RECIPE_STRING, NACO_PARAM_CUBEMODE);
00303     int              inocube    = 0;
00304 
00305 
00306     bug_if(pdid_resize == NULL);
00307     bug_if(scubemode == NULL);
00308 
00309     skip_if (irplib_framelist_contains(obj, NACO_PFITS_DOUBLE_CUMOFFSETX,
00310                                        CPL_TYPE_DOUBLE, CPL_FALSE, 0.0));
00311 
00312     skip_if (irplib_framelist_contains(obj, NACO_PFITS_DOUBLE_CUMOFFSETY,
00313                                        CPL_TYPE_DOUBLE, CPL_FALSE, 0.0));
00314 
00315     /* Load the input data */
00316     cpl_msg_info(cpl_func, "Loading the %d object and %d sky images",
00317                  irplib_framelist_get_size(obj),
00318                  sky == NULL ? 0 : irplib_framelist_get_size(sky));
00319 
00320     iscube = cpl_array_new(nobj, CPL_TYPE_INT);
00321 
00322     objimages = naco_img_jitter_load_objimages(iscube, obj, parlist);
00323 
00324     any_if("Could not load the %d object images", nobj);
00325 
00326     cpl_msg_info(cpl_func, "Loaded %d object images", nobj);
00327 
00328     skip_if(cpl_imagelist_get_size(objimages) != nobj);
00329 
00330     skip_if (irplib_flat_dark_bpm_calib(objimages, flat, dark, bpm));
00331 
00332     cpl_msg_info(cpl_func, "Sky estimation and correction");
00333 
00334     if (scubemode[0] == 'a') {
00335         /* Just add without shifting */
00336         const int mcube = nobj - cpl_array_count_invalid(iscube);
00337 
00338         if (mcube > 0) {
00339             cpl_msg_info(cpl_func, "Collapsing %d cube(s) with no shifting",
00340                          mcube);
00341             cpl_array_delete(iscube);
00342             iscube = cpl_array_new(nobj, CPL_TYPE_INT);
00343         }
00344     }
00345 
00346     if (cpl_array_has_valid(iscube)) {
00347         has_cube = CPL_TRUE;
00348 
00349         skip_if(naco_img_jitter_do_cube(objimages, cubetable, qclist,
00350                                         iscube, obj, parlist));
00351 
00352 #ifdef NACO_IMG_JITTER_DEVELOPMENT
00353         skip_if(cpl_imagelist_save(objimages, "Collapsed.fits", CPL_BPP_IEEE_FLOAT,
00354                                    NULL, CPL_IO_CREATE));
00355 #endif
00356     }
00357 
00358     if (cpl_array_has_invalid(iscube)) {
00359 
00360         nocubeimgs = has_cube ? cpl_imagelist_new() : objimages;
00361         if (has_cube) {
00362             skip_if(naco_img_jitter_imagelist_wrap_nocube(nocubeimgs, iscube,
00363                                                           objimages));
00364             inocube = cpl_imagelist_get_size(nocubeimgs);
00365         }
00366 
00367         /* Estimate the sky */
00368         if (sky != NULL) {
00369             skyimages = irplib_imagelist_load_framelist(sky, CPL_TYPE_FLOAT, 0, 0);
00370             any_if("Could not load sky images");
00371             skip_if (irplib_flat_dark_bpm_calib(skyimages, flat, dark, bpm));
00372         }
00373 
00374         skyimage = naco_img_jitter_find_sky(qclist, nocubeimgs, skyimages);
00375         any_if("Could not estimate sky");
00376 
00377         cpl_imagelist_delete(skyimages);
00378         skyimages = NULL;
00379 
00380         /* Apply the sky correction */
00381         skip_if (cpl_imagelist_subtract_image(nocubeimgs, skyimage));
00382     }
00383 
00384     /* Find the Strehl ratio of all object frames */
00385     if(naco_img_jitter_find_strehl(objimages, obj)) {
00386         irplib_error_recover(prestate, "Could not compute Strehl-ratio "
00387                              "for %d frame(s)", nobj);
00388     }
00389 
00390     /* Apply the shift and add */
00391     cpl_msg_info(cpl_func, "Shift and add");
00392     combined = naco_img_jitter_saa(objimages, obj, parlist);
00393     skip_if (combined == NULL);
00394 
00395     *pdid_resize = (cpl_boolean)
00396         (cpl_image_get_size_x(combined[0])
00397          != cpl_image_get_size_x(cpl_imagelist_get_const(objimages, 0)) ||
00398          cpl_image_get_size_y(combined[0])
00399          != cpl_image_get_size_y(cpl_imagelist_get_const(objimages, 0)));
00400 
00401     end_skip;
00402 
00403     /* Unwrap the wrapped no-cube images */
00404     for (;inocube > 0;) {
00405         (void)cpl_imagelist_unset(nocubeimgs, --inocube);
00406     }
00407 
00408     if (nocubeimgs != objimages) cpl_imagelist_delete(nocubeimgs);
00409     cpl_imagelist_delete(objimages);
00410     cpl_imagelist_delete(skyimages);
00411     cpl_image_delete(skyimage);
00412     cpl_array_delete(iscube);
00413 
00414     return combined;
00415 }
00416 
00417 /*----------------------------------------------------------------------------*/
00425 /*----------------------------------------------------------------------------*/
00426 static cpl_image * naco_img_jitter_find_sky(cpl_propertylist    * qclist,
00427                                             const cpl_imagelist * objs,
00428                                             const cpl_imagelist * skys)
00429 {
00430     cpl_image * self = NULL;
00431 
00432     if (skys != NULL) {
00433         /* Use sky images */
00434         self = cpl_imagelist_collapse_median_create(skys);
00435         any_if("Could not compute the median of %d sky images",
00436                cpl_imagelist_get_size(skys));
00437     } else {
00438         /* Use objects images */
00439         /* FIXME: This will work badly for few (one!) images */
00440         self = cpl_imagelist_collapse_median_create(objs);
00441         any_if("Could not compute the median of %d object images",
00442                cpl_imagelist_get_size(objs));
00443     }
00444 
00445     /* Get the background value */
00446     bug_if(cpl_propertylist_append_double(qclist, "ESO QC BACKGD",
00447                                           cpl_image_get_median(self)));
00448     bug_if(cpl_propertylist_append_double(qclist, "ESO QC BACKGD STDEV",
00449                                           cpl_image_get_stdev(self)));
00450 
00451     end_skip;
00452     
00453     return self;
00454 }
00455 
00456 /*----------------------------------------------------------------------------*/
00464 /*----------------------------------------------------------------------------*/
00465 static cpl_image ** naco_img_jitter_saa(cpl_imagelist    * imlist,
00466                                         const irplib_framelist * objframes,
00467                                         const cpl_parameterlist * parlist)
00468 {
00469     const char   * sval;
00470     cpl_bivector * offsets_est = NULL;
00471     cpl_bivector * objs = NULL;
00472     cpl_image   ** combined = NULL;
00473     cpl_vector   * sigmas = NULL;
00474     double         psigmas[] = {5.0, 2.0, 1.0, 0.5};
00475     const char   * offsets;
00476     const char   * objects;
00477     cpl_boolean    oddeven_flag;
00478     const int      nsigmas = (int)(sizeof(psigmas)/sizeof(double));
00479     const int      nfiles = cpl_imagelist_get_size(imlist);
00480     int            sx, sy, mx, my;
00481     int            rej_low, rej_high;
00482     const char   * combine_string;
00483     cpl_geom_combine combine_mode;
00484 
00485 
00486     bug_if(0);
00487     bug_if (irplib_framelist_get_size(objframes) != nfiles);
00488 
00489     /* Retrieve input parameters */
00490 
00491     /* Offsets */
00492     offsets = naco_parameterlist_get_string(parlist, RECIPE_STRING,
00493                                             NACO_PARAM_OFFSETS);
00494     /* Objects */
00495     objects = naco_parameterlist_get_string(parlist, RECIPE_STRING,
00496                                             NACO_PARAM_OBJECTS);
00497     /* Oddeven flag */
00498     oddeven_flag = naco_parameterlist_get_bool(parlist, RECIPE_STRING,
00499                                                NACO_PARAM_ODDEVEN);
00500 
00501     /* Cross correlation windows parameters */
00502     sval = naco_parameterlist_get_string(parlist, RECIPE_STRING,
00503                                       NACO_PARAM_XCORR);
00504     bug_if (sval == NULL);
00505 
00506     skip_if (sscanf(sval, "%d %d %d %d", &sx, &sy, &mx, &my) != 4);
00507 
00508     combine_string = naco_parameterlist_get_string(parlist, RECIPE_STRING,
00509                                                    NACO_PARAM_COMBINE);
00510 
00511     bug_if (combine_string == NULL);
00512 
00513     if (combine_string[0] == 'u')
00514         combine_mode = CPL_GEOM_UNION;
00515     else if (combine_string[0] == 'f')
00516         combine_mode = CPL_GEOM_FIRST;
00517     else if (combine_string[0] == 'i')
00518         combine_mode = CPL_GEOM_INTERSECT;
00519     else
00520         skip_if(1);
00521 
00522     /* Number of rejected values in stacking */
00523     sval = naco_parameterlist_get_string(parlist, RECIPE_STRING,
00524                                       NACO_PARAM_REJ_HILO);
00525     bug_if (sval == NULL);
00526 
00527     skip_if (sscanf(sval, "%d %d", &rej_low, &rej_high) != 2);
00528 
00529     
00530     /* Get the offsets estimation of each input file pair */
00531     cpl_msg_info(cpl_func, "Get the offsets estimation");
00532     offsets_est = NULL;
00533     if (offsets &&
00534             offsets[0] != (char)0) {
00535         /* A file has been provided on the command line */
00536         offsets_est = cpl_bivector_read(offsets);
00537         if (offsets_est == NULL ||
00538             cpl_bivector_get_size(offsets_est) != nfiles) {
00539             cpl_msg_error(cpl_func, "Cannot get offsets from %s", 
00540                     offsets);
00541             skip_if(1);
00542         }
00543     } else {
00544         double * offsets_est_x;
00545         double * offsets_est_y;
00546         double offx0 = DBL_MAX; /* Avoid (false) uninit warning */
00547         double offy0 = DBL_MAX; /* Avoid (false) uninit warning */
00548         int i;
00549 
00550         /* Get the offsets from the header */
00551         offsets_est = cpl_bivector_new(nfiles);
00552         offsets_est_x = cpl_bivector_get_x_data(offsets_est);
00553         offsets_est_y = cpl_bivector_get_y_data(offsets_est);
00554         for (i=0 ; i < nfiles ; i++) {
00555             const cpl_propertylist * plist
00556                 = irplib_framelist_get_propertylist_const(objframes, i);
00557 
00558             /* X and Y offsets */
00559             if (i == 0) {
00560                 offx0 = naco_pfits_get_cumoffsetx(plist);
00561                 offy0 = naco_pfits_get_cumoffsety(plist);
00562             }
00563 
00564             /* Subtract the first offset to all offsets */
00565             offsets_est_x[i] = offx0 - naco_pfits_get_cumoffsetx(plist);
00566             offsets_est_y[i] = offy0 - naco_pfits_get_cumoffsety(plist);
00567 
00568             bug_if(0);
00569         }
00570     }
00571 
00572     /* Read the provided objects file if provided */
00573     if (objects &&
00574             objects[0] != (char)0) {
00575         cpl_msg_info(cpl_func, "Get the user provided correlation objects");
00576         /* A file has been provided on the command line */
00577         objs = cpl_bivector_read(objects);
00578         if (objs==NULL) {
00579             cpl_msg_error(cpl_func, "Cannot get objects from %s",
00580                     objects);
00581             skip_if (1);
00582         }
00583     }
00584 
00585     /* Create the vector for the detection thresholds */
00586     sigmas = cpl_vector_wrap(nsigmas, psigmas);
00587     
00588     /* Recombine the images */
00589     cpl_msg_info(cpl_func, "Recombine the images set");
00590     combined = cpl_geom_img_offset_combine(imlist, offsets_est, 1, objs,
00591                                            sigmas, NULL, sx, sy, mx, my,
00592                                            rej_low, rej_high, combine_mode);
00593 
00594     skip_if (combined == NULL);
00595 
00596     end_skip;
00597 
00598     cpl_bivector_delete(offsets_est);
00599     cpl_bivector_delete(objs);
00600     cpl_vector_unwrap(sigmas);
00601 
00602     return combined;
00603 }
00604 
00605 /*----------------------------------------------------------------------------*/
00615 /*----------------------------------------------------------------------------*/
00616 static cpl_error_code naco_img_jitter_qc(cpl_propertylist       * qclist,
00617                                          cpl_propertylist       * paflist,
00618                                          const irplib_framelist * objframes,
00619                                          const cpl_image        * combined,
00620                                          cpl_boolean              drop_wcs)
00621 {
00622     cpl_errorstate cleanstate = cpl_errorstate_get();
00623     const cpl_propertylist * reflist
00624         = irplib_framelist_get_propertylist_const(objframes, 0);
00625     const char    * sval;
00626 
00627 
00628     bug_if(combined == NULL);
00629 
00630     bug_if(cpl_propertylist_copy_property_regexp(paflist, reflist, "^("
00631                                                  NACO_PFITS_REGEXP_JITTER_PAF
00632                                                  ")$", 0));
00633 
00634     if (naco_img_jitter_qc_apertures(qclist, objframes, combined)) {
00635         naco_error_reset("Could not compute all QC parameters");
00636     }
00637 
00638     sval = naco_pfits_get_filter(reflist);
00639     if (cpl_error_get_code()) {
00640         naco_error_reset("Could not get FITS key:");
00641     } else {
00642         cpl_propertylist_append_string(qclist, "ESO QC FILTER OBS", sval);
00643     }
00644     sval = naco_pfits_get_opti3_name(reflist);
00645     if (cpl_error_get_code()) {
00646         naco_error_reset("Could not get FITS key:");
00647     } else {
00648         cpl_propertylist_append_string(qclist, "ESO QC FILTER NDENS", sval);
00649     }
00650     sval = naco_pfits_get_opti4_name(reflist);
00651     if (cpl_error_get_code()) {
00652         naco_error_reset("Could not get FITS key:");
00653     } else {
00654         cpl_propertylist_append_string(qclist, "ESO QC FILTER POL", sval);
00655     }
00656 
00657     bug_if(0);
00658 
00659     bug_if (cpl_propertylist_append(paflist, qclist));
00660 
00661     if (drop_wcs) {
00662         cpl_propertylist * pcopy = cpl_propertylist_new();
00663         const cpl_error_code error
00664             = cpl_propertylist_copy_property_regexp(pcopy, reflist, "^("
00665                                                     IRPLIB_PFITS_WCS_REGEXP
00666                                                     ")$", 0);
00667         if (!error && cpl_propertylist_get_size(pcopy) > 0) {
00668             cpl_msg_warning(cpl_func, "Combined image will have no WCS "
00669                             "coordinates");
00670         }
00671         cpl_propertylist_delete(pcopy);
00672 
00673         bug_if (cpl_propertylist_copy_property_regexp(qclist, reflist, "^("
00674                                                       NACO_PFITS_REGEXP_JITTER_COPY
00675                                                       ")$", 0));
00676     } else {
00677         bug_if(cpl_propertylist_copy_property_regexp(qclist, reflist, "^("
00678                                                      IRPLIB_PFITS_WCS_REGEXP "|"
00679                                                      NACO_PFITS_REGEXP_JITTER_COPY
00680                                                      ")$", 0));
00681     }
00682 
00683     if (cpl_propertylist_has(qclist, "AIRMASS"))
00684         bug_if (irplib_pfits_set_airmass(qclist, objframes));
00685 
00686     end_skip;
00687 
00688     return cpl_error_get_code();
00689 }
00690 
00691 /*----------------------------------------------------------------------------*/
00699 /*----------------------------------------------------------------------------*/
00700 static cpl_error_code naco_img_jitter_qc_apertures(cpl_propertylist * qclist,
00701                                                    const irplib_framelist *
00702                                                    objframes,
00703                                                    const cpl_image  * combined)
00704 {
00705     const cpl_propertylist * reflist
00706         = irplib_framelist_get_propertylist_const(objframes, 0);
00707 
00708     cpl_apertures * aperts = NULL;
00709     cpl_bivector  * fwhms  = NULL;
00710     cpl_vector    * fwhms_sum = NULL;
00711     cpl_vector    * sigmas = NULL;
00712     double        * fwhms_x;
00713     double        * fwhms_y;
00714     double        * fwhms_sum_data;
00715     int             nb_val, nb_good;
00716     double          f_min, f_max;
00717     double          psigmas[] = {5.0, 2.0, 1.0, 0.5}; /* Not modified */
00718     const int       nsigmas = (int)(sizeof(psigmas)/sizeof(double));
00719     int             isigma;
00720     int             i;
00721 
00722     const double    pixscale = naco_pfits_get_pixscale(reflist);
00723     /* FIXME: Some hard-coded constants */
00724     const double    seeing_min_arcsec = 0.1;
00725     const double    seeing_max_arcsec = 5.0;
00726     const double    seeing_fwhm_var   = 0.2;
00727 
00728     double iq, fwhm_pix, fwhm_arcsec;
00729 
00730 
00731     /* Detect apertures */
00732     cpl_msg_info(cpl_func, "Detecting apertures using %d sigma-levels "
00733                  "ranging from %g down to %g", nsigmas, psigmas[0],
00734                  psigmas[nsigmas-1]);
00735 
00736     /* pixscale could be mising */
00737     skip_if( pixscale <= 0.0 );
00738     bug_if( seeing_min_arcsec < 0.0);
00739 
00740     /* Create the vector for the detection thresholds. (Not modified) */
00741     sigmas = cpl_vector_wrap(nsigmas, psigmas);
00742 
00743     aperts = cpl_apertures_extract(combined, sigmas, &isigma);
00744     if (aperts == NULL) {
00745         cpl_msg_warning(cpl_func, "Could not detect any apertures in combined "
00746                         "image");
00747         skip_if(1);
00748     }
00749     bug_if(0);
00750 
00751     /* Compute the FHWM of the detected apertures */
00752     fwhms = cpl_apertures_get_fwhm(combined, aperts);
00753     if (fwhms == NULL) {
00754         cpl_msg_warning(cpl_func, "Could not compute any FWHMs of the "
00755                           "apertures in the combined image");
00756         skip_if(1);
00757     }
00758     bug_if(0);
00759     cpl_apertures_delete(aperts);
00760     aperts = NULL;
00761 
00762     /* Access the data */
00763     nb_val  = cpl_bivector_get_size(fwhms);
00764     fwhms_x = cpl_bivector_get_x_data(fwhms);
00765     fwhms_y = cpl_bivector_get_y_data(fwhms);
00766 
00767     /* Get the number of good values */
00768     nb_good = 0;
00769     for (i=0 ; i < nb_val ; i++) {
00770         if (fwhms_x[i] <= 0.0 || fwhms_y[i] <= 0.0) continue;
00771         fwhms_x[nb_good] = fwhms_x[i];
00772         fwhms_y[nb_good] = fwhms_y[i];
00773         nb_good++;
00774     }
00775 
00776     cpl_msg_info(cpl_func, "Detected %d (%d) apertures at sigma=%g",
00777                  nb_good, nb_val, psigmas[isigma]);
00778 
00779     skip_if_lt (nb_good, 1, "aperture with a FWHM");
00780 
00781     nb_val = nb_good;
00782     /* This resizing is not really needed */
00783     bug_if(cpl_vector_set_size(cpl_bivector_get_x(fwhms), nb_val));
00784     bug_if(cpl_vector_set_size(cpl_bivector_get_y(fwhms), nb_val));
00785     fwhms_x = cpl_bivector_get_x_data(fwhms);
00786     fwhms_y = cpl_bivector_get_y_data(fwhms);
00787 
00788     /* Get the good values */
00789     fwhms_sum = cpl_vector_new(nb_good);
00790     fwhms_sum_data = cpl_vector_get_data(fwhms_sum);
00791     for (i=0; i < nb_good; i++) {
00792         fwhms_sum_data[i] = fwhms_x[i] + fwhms_y[i];
00793     }
00794     /* Compute the fwhm as the median of the average of the FHWMs in x and y */
00795     fwhm_pix = 0.5 * cpl_vector_get_median(fwhms_sum);
00796 
00797     bug_if(cpl_propertylist_append_double(qclist, "ESO QC FWHM PIX", fwhm_pix));
00798 
00799     fwhm_arcsec = fwhm_pix * pixscale;
00800 
00801     bug_if(cpl_propertylist_append_double(qclist, "ESO QC FWHM ARCSEC",
00802                                           fwhm_arcsec));
00803 
00804     /* iq is the median of the (fwhm_x+fwhm_y)/2 */
00805     /* of the good stars */
00806 
00807     /* Compute f_min and f_max */
00808     f_min = seeing_min_arcsec / pixscale;
00809     f_max = seeing_max_arcsec / pixscale;
00810 
00811     /* Sum the the good values */
00812     nb_good = 0;
00813     for (i=0 ; i < nb_val ; i++) {
00814         const double fx = fwhms_x[i];
00815         const double fy = fwhms_y[i];
00816 
00817         if (fx <= f_min || f_max <= fx || fy <= f_min || f_max <= fy) continue;
00818         if (fabs(fx-fy) >= 0.5 * (fx + fy) * seeing_fwhm_var) continue;
00819 
00820         fwhms_sum_data[nb_good] = fx + fy;
00821         nb_good++;
00822     }
00823 
00824     cpl_msg_info(cpl_func, "%d of the apertures have FWHMs within the range "
00825                  "%g to %g and eccentricity within %g", nb_good, f_min, f_max,
00826                  seeing_fwhm_var);
00827 
00828     skip_if_lt (nb_good, 1, "aperture with a good FWHM");
00829 
00830     bug_if(cpl_vector_set_size(fwhms_sum, nb_good));
00831 
00832     /* Compute the fwhm */
00833     iq = pixscale * 0.5 * cpl_vector_get_median(fwhms_sum);
00834 
00835     bug_if(cpl_propertylist_append_double(qclist, "ESO QC IQ", iq));
00836 
00837     end_skip;
00838 
00839     cpl_vector_delete(fwhms_sum);
00840     cpl_bivector_delete(fwhms);
00841     cpl_vector_unwrap(sigmas);
00842     cpl_apertures_delete(aperts);
00843 
00844     return cpl_error_get_code();
00845 }
00846 
00847 /*----------------------------------------------------------------------------*/
00859 /*----------------------------------------------------------------------------*/
00860 static cpl_error_code naco_img_jitter_save(cpl_frameset            * set,
00861                                            const cpl_parameterlist * parlist,
00862                                            const cpl_propertylist  * qclist,
00863                                            const cpl_propertylist  * paflist,
00864                                            const cpl_image         * combined,
00865                                            const cpl_image         * contrib,
00866                                            const cpl_table         * cubetable)
00867 {
00868 
00869     const cpl_boolean is_cube = cpl_table_get_ncol(cubetable) > 0
00870         ? CPL_TRUE : CPL_FALSE;
00871     const char * procatg =  is_cube ? NACO_IMG_JITTER_CUBE
00872         : NACO_IMG_JITTER_COMB;
00873     cpl_propertylist * xtlist = cpl_propertylist_new();
00874 
00875     bug_if (0);
00876     bug_if (contrib == NULL);
00877 
00878     /* Write the FITS file */
00879     skip_if (irplib_dfs_save_image(set, parlist, set, combined,
00880                                    CPL_BPP_IEEE_FLOAT, RECIPE_STRING,
00881                                    procatg, qclist, NULL,
00882                                    naco_pipe_id, RECIPE_STRING CPL_DFS_FITS));
00883 
00884     bug_if(cpl_propertylist_append_string(xtlist, "EXTNAME",
00885                                           "Contribution Map"));
00886     skip_if (cpl_image_save(contrib, RECIPE_STRING CPL_DFS_FITS,
00887                             CPL_BPP_16_SIGNED, xtlist, CPL_IO_EXTEND));
00888 
00889     if (is_cube) {
00890 
00891         bug_if(cpl_propertylist_update_string(xtlist, "EXTNAME",
00892                                               "Plane Properties"));
00893         skip_if (cpl_table_save(cubetable, NULL, xtlist,
00894                                 RECIPE_STRING CPL_DFS_FITS, CPL_IO_EXTEND));
00895     }
00896 
00897 #ifdef NACO_SAVE_PAF
00898     skip_if (cpl_dfs_save_paf("NACO", RECIPE_STRING, paflist,
00899                              RECIPE_STRING CPL_DFS_PAF));
00900 #else
00901     bug_if(paflist == NULL);
00902 #endif
00903 
00904     end_skip;
00905 
00906     cpl_propertylist_delete(xtlist);
00907 
00908     return cpl_error_get_code();
00909 
00910 }
00911 
00912 /*----------------------------------------------------------------------------*/
00924 /*----------------------------------------------------------------------------*/
00925 static cpl_imagelist *
00926 naco_img_jitter_load_objimages(cpl_array * iscube,
00927                                const irplib_framelist * self,
00928                                const cpl_parameterlist * parlist)
00929 {
00930     cpl_imagelist * objlist = cpl_imagelist_new();
00931     const int nframes = irplib_framelist_get_size(self);
00932     cpl_image * image = NULL;
00933     int i;
00934 
00935     bug_if(self    == NULL);
00936     bug_if(iscube  == NULL);
00937     bug_if(parlist == NULL);
00938 
00939     for (i=0; i < nframes; i++, image = NULL) {
00940         const char * filename
00941             = cpl_frame_get_filename(irplib_framelist_get_const(self, i));
00942         const cpl_propertylist * plist
00943             = irplib_framelist_get_propertylist_const(self, i);
00944         const int naxis3 = cpl_propertylist_has(plist, "NAXIS3") ? 
00945             cpl_propertylist_get_int(plist, "NAXIS3") : 1;
00946 
00947 
00948         if (naxis3 > 2) { /* Real cube mode has at least two frames + sum */
00949 
00950             bug_if(cpl_array_set_int(iscube, i, 1));
00951 
00952             /* EPompei 2009-11-13:
00953                The last frame in the cube is the sum of all the previous ones.
00954                This is not DICB compliant and may change.
00955                See also the NACO user manual.
00956             */
00957 
00958             image = cpl_image_load(filename, CPL_TYPE_FLOAT, naxis3-1, EXT0);
00959 
00960             any_if("Could not load %d-cube-sum from frame %d/%d, file=%s",
00961                    naxis3-1, i+1, nframes, filename);
00962 
00963         } else {
00964             image = cpl_image_load(filename, CPL_TYPE_FLOAT, 0, EXT0);
00965 
00966             any_if("Could not load FITS-image from extension %d in frame "
00967                    "%d/%d, file=%s", EXT0, i+1, nframes, filename);
00968 
00969         }
00970         bug_if(cpl_imagelist_set(objlist, image, i));
00971     }
00972 
00973     end_skip;
00974 
00975     cpl_image_delete(image);
00976 
00977     if (cpl_error_get_code()) {
00978         cpl_imagelist_delete(objlist);
00979         objlist = NULL;
00980     }
00981 
00982     return objlist;
00983 
00984 }
00985 
00986 /*----------------------------------------------------------------------------*/
00994 /*----------------------------------------------------------------------------*/
00995 static cpl_error_code naco_img_jitter_check_cube(const cpl_imagelist * self,
00996                                                  const cpl_image * sum)
00997 {
00998     cpl_image * accu = cpl_imagelist_collapse_create(self);
00999     double err;
01000 
01001     cpl_image_subtract(accu, sum);
01002 
01003     err = cpl_image_get_absflux(accu);
01004 
01005     if (err > 0.0) {
01006         err /= cpl_image_get_size_x(sum) * cpl_image_get_size_y(sum);
01007 
01008         cpl_msg_info(cpl_func, "Average per-pixel error in final sum frame "
01009                      "in %d-cube: %g", cpl_imagelist_get_size(self), err);
01010     }
01011 
01012     cpl_image_delete(accu);
01013 
01014     return cpl_error_get_code();
01015 }
01016 
01017 
01018 /*----------------------------------------------------------------------------*/
01030 /*----------------------------------------------------------------------------*/
01031 static cpl_error_code naco_img_jitter_do_cube(cpl_imagelist * self,
01032                                               cpl_table * cubetable,
01033                                               cpl_propertylist * qclist,
01034                                               const cpl_array * iscube,
01035                                               const irplib_framelist * obj,
01036                                               const cpl_parameterlist * parlist)
01037 {
01038 
01039     const int       nframes = irplib_framelist_get_size(obj);
01040     cpl_imagelist * onelist = NULL;
01041     cpl_image     * sum = NULL;
01042     cpl_image     * onesky = NULL;
01043     const int       nskyplane = naco_parameterlist_get_int(parlist,
01044                                                            RECIPE_STRING,
01045                                                            NACO_PARAM_SKYPLANE);
01046     cpl_vector    * skymedians = cpl_vector_new(nframes);
01047     int             nsky = 0;
01048     int             i;
01049 
01050     bug_if(self == NULL);
01051     bug_if(cubetable == NULL);
01052     bug_if(qclist == NULL);
01053     bug_if(obj == NULL);
01054     bug_if(parlist   == NULL);
01055     bug_if(nframes != cpl_array_get_size(iscube));
01056     bug_if(nframes != cpl_imagelist_get_size(self));
01057 
01058 
01059     for (i=0; i < nframes; i++) {
01060         int is_invalid = 0;
01061 
01062         (void)cpl_array_get_int(iscube, i, &is_invalid);
01063 
01064         if (!is_invalid) {
01065             const char * filename
01066                 = cpl_frame_get_filename(irplib_framelist_get_const(obj, i));
01067             const cpl_propertylist * plist
01068                 = irplib_framelist_get_propertylist_const(obj, i);
01069             double skymedian;
01070             int naxis3;
01071 
01072             /* Estimate the sky from nearby cube(s) */
01073             cpl_image_delete(onesky);
01074             onesky = naco_img_jitter_find_sky_cube(i, nskyplane, iscube, obj);
01075             any_if("Could not estimate sky for frame %d/%d, file=%s",
01076                    i+1, nframes, filename);
01077 
01078             skymedian = cpl_image_get_median(onesky);
01079 #ifdef NACO_IMG_JITTER_DEVELOPMENT
01080             if (onelist == NULL) {
01081 
01082                 /* FIXME: Compute from all cube-sky frames ? */
01083                 /* Get the background value */
01084                 bug_if(cpl_propertylist_append_double(qclist, "ESO QC BACKGD",
01085                                                       skymedian));
01086 
01087                 cpl_image_save(onesky, "Sky.fits", CPL_BPP_IEEE_FLOAT, NULL,
01088                                CPL_IO_CREATE);
01089             } else {
01090                 cpl_image_save(onesky, "Sky.fits", CPL_BPP_IEEE_FLOAT, NULL,
01091                                CPL_IO_EXTEND);
01092             }
01093 #endif
01094             cpl_imagelist_delete(onelist);
01095             onelist = cpl_imagelist_load(filename, CPL_TYPE_FLOAT, EXT0);
01096 
01097             any_if("Could not load cube from frame %d/%d, file=%s",
01098                    i+1, nframes, filename);
01099 
01100             naxis3 = cpl_imagelist_get_size(onelist);
01101 
01102             cpl_msg_info(cpl_func, "Processing %d-cube from frame %d/%d, "
01103                          "file=%s. Median of sky-estimate: %g",
01104                          naxis3-1, i+1, nframes, filename, skymedian);
01105             cpl_vector_set(skymedians, nsky++, skymedian);
01106 
01107             bug_if(naxis3 < 3);
01108 
01109             sum = cpl_imagelist_unset(onelist, naxis3-1);
01110 
01111             bug_if(naco_img_jitter_check_cube(onelist, sum));
01112 
01113             skip_if(cpl_imagelist_subtract_image(onelist, onesky));
01114 
01115             cpl_image_delete(sum);
01116             sum = naco_img_jitter_combine_cube(cubetable, onelist, plist,
01117                                                parlist, i);
01118             any_if("Could not combine %d images from frame %d/%d, file=%s",
01119                    naxis3-1, i+1, nframes, filename);
01120 
01121             bug_if(cpl_imagelist_set(self, sum, i));
01122             sum = NULL;
01123         }
01124     }
01125 
01126     if (nsky > 1) {
01127         double skystdev, skymean;
01128 
01129         bug_if(cpl_vector_set_size(skymedians, nsky));
01130 
01131         skymean = cpl_vector_get_mean(skymedians);
01132         skystdev = cpl_vector_get_stdev(skymedians);
01133 
01134         cpl_msg_info(cpl_func, "Mean and stdev of %d medians of sky estimates: "
01135                      "%g %g", nsky, skymean, skystdev);
01136 
01137         bug_if(cpl_propertylist_append_double(qclist, "ESO QC SKY STDEV",
01138                                               skystdev));
01139     }
01140 
01141     end_skip;
01142 
01143     cpl_imagelist_delete(onelist);
01144     cpl_image_delete(sum);
01145     cpl_image_delete(onesky);
01146     cpl_vector_delete(skymedians);
01147 
01148     return cpl_error_get_code();
01149 }
01150 
01151 
01152 
01153 /*----------------------------------------------------------------------------*/
01164 /*----------------------------------------------------------------------------*/
01165 static
01166 cpl_image * naco_img_jitter_combine_cube(cpl_table * cubetable,
01167                                          const cpl_imagelist * cube,
01168                                          const cpl_propertylist * plist,
01169                                          const cpl_parameterlist * parlist,
01170                                          int idx)
01171 {
01172 
01173     cpl_errorstate  prestate = cpl_errorstate_get();
01174     cpl_image     * self = NULL;
01175     const int       ncube = cpl_imagelist_get_size(cube);
01176     cpl_image    ** combined = NULL;
01177     cpl_apertures * apert = NULL;
01178     cpl_bivector  * offs = cpl_bivector_new(ncube);
01179     cpl_vector    * offsx = cpl_bivector_get_x(offs);
01180     cpl_vector    * offsy = cpl_bivector_get_y(offs);
01181     cpl_vector    * sigmas = NULL;
01182     cpl_vector    * vstrehl = cpl_vector_new(ncube);
01183     double          psigmas[] = {5.0, 2.0, 1.0, 0.5}; /* not modified */
01184     const int       nsigmas = (int)(sizeof(psigmas)/sizeof(double));
01185     /* Use half of default value to support images windowed to 128 x 130 */
01186     /* FIXME: Adjust according to image size ? */
01187     const double    rstar  = 0.5 * STREHL_STAR_RADIUS;
01188     const double    rbgint = 0.5 * STREHL_BACKGROUND_R1;
01189     const double    rbgext = 0.5 * STREHL_BACKGROUND_R2;
01190     const double    pixscale = naco_pfits_get_pixscale(plist);
01191     const double    lucky = naco_parameterlist_get_double(parlist,
01192                                                           RECIPE_STRING,
01193                                                           NACO_PARAM_LUCK_STR);
01194     const char    * filter = naco_pfits_get_filter(plist);
01195     double          lam  = DBL_MAX; /* Avoid uninit warning */
01196     double          dlam = DBL_MAX; /* Avoid uninit warning */
01197     int             isigma = 0;
01198     const int       ncubetable = cpl_table_get_nrow(cubetable);
01199     int             icubetable; /* 1st table row to write to */
01200     int i;
01201 
01202 
01203     skip_if(rbgext <= rbgint);
01204     skip_if(pixscale <= 0.0);
01205 
01206     irplib_check(naco_get_filter_infos(filter, &lam, &dlam),
01207                  "Frame has no info for filter %s", filter);
01208 
01209     cpl_msg_debug(cpl_func, "Frame %d has pixelscale [Arcsecond/pixel]=%g, "
01210                   "Central wavelength [micron]=%g, Filter bandwidth "
01211                   "[micron]=%g", 1+idx, pixscale, lam, dlam);
01212     cpl_msg_debug(cpl_func, "Frame %d assumes Rstar [pixel]=%g, Rint "
01213                   "[pixel]=%g, Rext [pixel]=%g", 1+idx, rstar/pixscale,
01214                   rbgint/pixscale, rbgext/pixscale);
01215 
01216     if (cpl_table_get_ncol(cubetable) == 0) {
01217         cpl_table_new_column(cubetable, "Frame", CPL_TYPE_INT);
01218         cpl_table_new_column(cubetable, "Plane", CPL_TYPE_INT);
01219         cpl_table_new_column(cubetable, "XCentroid", CPL_TYPE_DOUBLE);
01220         cpl_table_new_column(cubetable, "YCentroid", CPL_TYPE_DOUBLE);
01221         cpl_table_set_column_unit(cubetable, "XCentroid", "pixel");
01222         cpl_table_set_column_unit(cubetable, "YCentroid", "pixel");
01223         cpl_table_new_column(cubetable, "Strehl", CPL_TYPE_DOUBLE);
01224         cpl_table_new_column(cubetable, "Strehl_Error", CPL_TYPE_DOUBLE);
01225         cpl_table_new_column(cubetable, "Star_Background", CPL_TYPE_DOUBLE);
01226         cpl_table_new_column(cubetable, "Star_Peak", CPL_TYPE_DOUBLE);
01227         cpl_table_new_column(cubetable, "Star_Flux", CPL_TYPE_DOUBLE);
01228         cpl_table_new_column(cubetable, "PSF_Peak_per_Flux", CPL_TYPE_DOUBLE);
01229         cpl_table_set_column_unit(cubetable, "PSF_Peak_per_Flux", "unitless");
01230         cpl_table_new_column(cubetable, "Background_Noise", CPL_TYPE_DOUBLE);
01231         cpl_table_set_size(cubetable, ncube);
01232         icubetable = 0;
01233     } else {
01234         cpl_table_set_size(cubetable, ncubetable + ncube);
01235         icubetable = ncubetable;
01236     }
01237 
01238     /* Create the vector for the detection thresholds */
01239     sigmas = cpl_vector_wrap(nsigmas, psigmas);
01240     for (i = 0; i < ncube; i++) {
01241         const cpl_image * one = cpl_imagelist_get_const(cube, i);
01242         double            cent_x, cent_y;
01243         double            strehl, strehl_err, star_bg,star_peak, star_flux;
01244         double            psf_peak, psf_flux, bg_noise;
01245         int               iflux;
01246 
01247 
01248         cpl_apertures_delete(apert);
01249         apert = cpl_apertures_extract(one, sigmas, &isigma);
01250 
01251         any_if("No object found in image %d/%d in frame %d", i+1, ncube, 1+idx);
01252 
01253         bug_if(irplib_apertures_find_max_flux(apert, &iflux, 1));
01254 
01255         cent_x = cpl_apertures_get_centroid_x(apert, iflux);
01256         cent_y = cpl_apertures_get_centroid_y(apert, iflux);
01257         cpl_vector_set(offsx, i, cent_x);
01258         cpl_vector_set(offsy, i, cent_y);
01259 
01260         cpl_msg_debug(cpl_func, "Detected %d/%d sigma=%g-aperture(s) (x,y)"
01261                       "=(%g,%g) (%d/%d) in %d/%d-image in frame %d", iflux,
01262                       cpl_apertures_get_size(apert), psigmas[isigma], cent_x,
01263                       cent_y, 1+isigma, nsigmas, 1+i, ncube, 1+idx);
01264 
01265         cpl_table_set_int(cubetable, "Frame", i+icubetable, 1+idx);
01266         cpl_table_set_int(cubetable, "Plane", i+icubetable, 1+i);
01267         cpl_table_set_double(cubetable, "XCentroid", i+icubetable, cent_x);
01268         cpl_table_set_double(cubetable, "YCentroid", i+icubetable, cent_y);
01269 
01270 
01271         if (irplib_strehl_compute(one, STREHL_M1, STREHL_M2, lam, dlam,
01272                                   pixscale, STREHL_BOX_SIZE,  cent_x, cent_y,
01273                                   rstar, rbgint, rbgext, -1, -1,
01274                                   &strehl, &strehl_err,
01275                                   &star_bg, &star_peak, &star_flux,
01276                                   &psf_peak, &psf_flux,
01277                                   &bg_noise)) {
01278             cpl_msg_info(cpl_func, "Could not compute strehl for "
01279                          "image %d in frame %d", 1+i, 1+idx);
01280             cpl_errorstate_dump(prestate, CPL_FALSE,
01281                                 irplib_errorstate_dump_debug);
01282             cpl_errorstate_set(prestate);
01283 
01284             cpl_table_set_invalid(cubetable, "Strehl", i+icubetable);
01285             cpl_table_set_invalid(cubetable, "Strehl_Error", i+icubetable);
01286             cpl_table_set_invalid(cubetable, "Star_Background", i+icubetable);
01287             cpl_table_set_invalid(cubetable, "Star_Peak", i+icubetable);
01288             cpl_table_set_invalid(cubetable, "Star_Flux", i+icubetable);
01289             cpl_table_set_invalid(cubetable, "PSF_Peak_per_Flux", i+icubetable);
01290             cpl_table_set_invalid(cubetable, "Background_Noise", i+icubetable);
01291             cpl_vector_set(vstrehl, i, 0.0);
01292 
01293         } else {
01294             cpl_vector_set(vstrehl, i, strehl);
01295             cpl_table_set_double(cubetable, "Strehl", i+icubetable, strehl);
01296             cpl_table_set_double(cubetable, "Strehl_Error", i+icubetable,
01297                                  strehl_err);
01298             cpl_table_set_double(cubetable, "Star_Background", i+icubetable,
01299                                  star_bg);
01300             cpl_table_set_double(cubetable, "Star_Peak", i+icubetable,
01301                                  star_peak);
01302             cpl_table_set_double(cubetable, "Star_Flux", i+icubetable,
01303                                  star_flux);
01304             cpl_table_set_double(cubetable, "PSF_Peak_per_Flux", i+icubetable,
01305                                  psf_peak/psf_flux);
01306             cpl_table_set_double(cubetable, "Background_Noise", i+icubetable,
01307                                  bg_noise);
01308         }
01309     }
01310 
01311     self = naco_img_jitter_saa_lucky(cube, vstrehl, offs, lucky);
01312 
01313     end_skip;
01314 
01315     if (combined != NULL) {
01316         cpl_image_delete(combined[0]);
01317         cpl_free(combined);
01318     }
01319 
01320      cpl_bivector_delete(offs);
01321     (void)cpl_vector_unwrap(sigmas);
01322     cpl_apertures_delete(apert);
01323     cpl_vector_delete(vstrehl);
01324 
01325     cpl_ensure(self != NULL, cpl_error_get_code(), NULL);
01326 
01327     return self;
01328 
01329 }
01330 
01331 
01332 /*----------------------------------------------------------------------------*/
01342 /*----------------------------------------------------------------------------*/
01343 static cpl_image * naco_img_jitter_find_sky_cube(int isky, int nskyplane,
01344                                                  const cpl_array * iscube,
01345                                                  const irplib_framelist * obj)
01346 {
01347 
01348     cpl_image     * self = NULL;
01349     const int       nframes = irplib_framelist_get_size(obj);
01350     cpl_imagelist * belowcube = NULL;
01351     cpl_imagelist * abovecube = NULL;
01352     cpl_imagelist * skycube   = NULL;
01353     cpl_imagelist * mycube    = NULL;
01354     cpl_image     * mysky     = NULL;
01355     cpl_mask      * fillbpm   = NULL;
01356     int             is_invalid = 0;
01357     int             ibelow, iabove;
01358     int             i;
01359 
01360     bug_if(isky <  0);
01361     bug_if(isky >= nframes);
01362     bug_if(nframes != cpl_array_get_size(iscube));
01363     if (nskyplane > 0) skip_if_lt(nskyplane, 3, "sky planes for median");
01364 
01365 
01366     (void)cpl_array_get_int(iscube, isky, &is_invalid);
01367 
01368     bug_if(is_invalid); /* isky must be a cube */
01369 
01370     /* Find 1st cube below isky */
01371     for (i = isky - 1; i >= 0; i++) {
01372 
01373         (void)cpl_array_get_int(iscube, i, &is_invalid);
01374 
01375         if (!is_invalid) break;
01376     }
01377 
01378     ibelow = i; /* -1 means no cube below */
01379 
01380     /* Find 1st cube above isky */
01381     for (i = isky + 1; i < nframes; i++) {
01382 
01383         (void)cpl_array_get_int(iscube, i, &is_invalid);
01384 
01385         if (!is_invalid) break;
01386     }
01387 
01388     iabove = i; /* nframes means no cube above */
01389 
01390     cpl_msg_info(cpl_func, "Estimating sky for cube %d/%d via cubes %d and %d",
01391                  1+isky, nframes, 1+ibelow, 1+iabove);
01392 
01393 
01394     if (ibelow >= 0) {
01395         const char * filename
01396             = cpl_frame_get_filename(irplib_framelist_get_const(obj, ibelow));
01397 
01398         if (nskyplane > 0) {
01399             /* Load the last nskyplane frames */
01400             const cpl_propertylist * plist
01401                 = irplib_framelist_get_propertylist_const(obj, ibelow);
01402             /* Ignore the last sum plane */
01403             const int istop  = irplib_pfits_get_int(plist, "NAXIS3") - 2;
01404             const int istart = NACO_MAX(0, istop - nskyplane + 1);
01405 
01406             skip_if_lt(istop - istart, 2, "sky planes for median");
01407 
01408             belowcube = cpl_imagelist_new();
01409 
01410             for (i = istart; i <= istop; i++) {
01411                 self = cpl_image_load(filename, CPL_TYPE_FLOAT, i, EXT0);
01412 
01413                 any_if("Could not load plane %d from frame %d/%d, file=%s",
01414                        1+i, 1+ibelow, nframes, filename);
01415 
01416                 bug_if(cpl_imagelist_set(belowcube, self, i - istart));
01417             }
01418 
01419         } else {
01420             int naxis3;
01421 
01422             belowcube = cpl_imagelist_load(filename, CPL_TYPE_FLOAT, EXT0);
01423 
01424             any_if("Could not load cube from frame %d/%d, file=%s",
01425                    1+ibelow, nframes, filename);
01426 
01427             naxis3 = cpl_imagelist_get_size(belowcube);
01428 
01429             bug_if(naxis3 < 3);
01430 
01431             cpl_image_delete(cpl_imagelist_unset(belowcube, naxis3-1));
01432 
01433         }
01434 
01435     }
01436 
01437     if (iabove < nframes) {
01438         const char * filename
01439             = cpl_frame_get_filename(irplib_framelist_get_const(obj, iabove));
01440 
01441         if (nskyplane > 0) {
01442             /* Load the first nskyplane frames */
01443             const cpl_propertylist * plist
01444                 = irplib_framelist_get_propertylist_const(obj, iabove);
01445             const int istart = 0;
01446             /* Ignore the last sum plane */
01447             const int istop  = NACO_MIN(nskyplane-1, irplib_pfits_get_int
01448                                         (plist, "NAXIS3") - 2);
01449 
01450             skip_if_lt(istop - istart, 2, "sky planes for median");
01451 
01452             abovecube = cpl_imagelist_new();
01453 
01454             for (i = istart; i <= istop; i++) {
01455                 self = cpl_image_load(filename, CPL_TYPE_FLOAT, i, EXT0);
01456 
01457                 any_if("Could not load plane %d from frame %d/%d, file=%s",
01458                        1+i, 1+iabove, nframes, filename);
01459 
01460                 bug_if(cpl_imagelist_set(abovecube, self, i - istart));
01461             }
01462 
01463         } else {
01464 
01465             int naxis3;
01466 
01467             abovecube = cpl_imagelist_load(filename, CPL_TYPE_FLOAT, EXT0);
01468 
01469             any_if("Could not load cube from frame %d/%d, file=%s",
01470                    1+iabove, nframes, filename);
01471 
01472             naxis3 = cpl_imagelist_get_size(abovecube);
01473 
01474             bug_if(naxis3 < 3);
01475 
01476             cpl_image_delete(cpl_imagelist_unset(abovecube, naxis3-1));
01477         }
01478 
01479     }
01480 
01481     error_if(belowcube == NULL && abovecube == NULL, CPL_ERROR_DATA_NOT_FOUND,
01482              "No cube(s) available for sky estimation among %d object frames",
01483              nframes);
01484 
01485     if (belowcube == NULL) {
01486         skycube = abovecube;
01487     } else if (abovecube == NULL) {
01488         skycube = belowcube;
01489     } else {
01490         /* Wrap around the images in the two cubes */
01491 
01492         const int nbelow = cpl_imagelist_get_size(belowcube);
01493         const int nabove = cpl_imagelist_get_size(abovecube);
01494         int       nwrap = 0;
01495 
01496         skycube = cpl_imagelist_new();
01497 
01498         for (i = 0; i < nbelow; i++) {
01499             skip_if(cpl_imagelist_set(skycube, cpl_imagelist_get(belowcube, i),
01500                                       nwrap++));
01501         }
01502         for (i = 0; i < nabove; i++) {
01503             skip_if(cpl_imagelist_set(skycube, cpl_imagelist_get(abovecube, i),
01504                                       nwrap++));
01505         }
01506         skip_if(cpl_imagelist_get_size(skycube) != nwrap);
01507         skip_if(nbelow + nabove != nwrap);
01508     }
01509 
01510     self = cpl_imagelist_collapse_median_create(skycube);
01511 
01512 #ifndef NACO_IMG_JITTER_KEEP_SKY_OBJECTS
01513     if (belowcube == NULL || abovecube == NULL) {
01514         /* Try to replace object-pixels with sky-pixels from the object image */
01515         const cpl_mask * fill2bpm;
01516         const cpl_mask * selfbpm = NULL;
01517         const double lo_skysigma = 0.2;
01518         const double hi_skysigma = 5.0;
01519 
01520         skip_if(naco_img_jitter_reject_objects(self, lo_skysigma, hi_skysigma));
01521 
01522         selfbpm = cpl_image_get_bpm_const(self);
01523 
01524         if (selfbpm != NULL) {
01525             const cpl_mask * mybpm;
01526 
01527             /* Substitute the objects pixels with sky pixels from isky */
01528 
01529             const char * filename
01530                 = cpl_frame_get_filename(irplib_framelist_get_const(obj, isky));
01531             int naxis3;
01532 
01533             mycube = cpl_imagelist_load(filename, CPL_TYPE_FLOAT, EXT0);
01534 
01535             any_if("Could not load cube from frame %d/%d, file=%s",
01536                    1+isky, nframes, filename);
01537 
01538             naxis3 = cpl_imagelist_get_size(mycube);
01539 
01540             bug_if(naxis3 < 3);
01541 
01542             cpl_image_delete(cpl_imagelist_unset(mycube, naxis3-1));
01543 
01544             mysky = cpl_imagelist_collapse_median_create(mycube);
01545 
01546             skip_if(naco_img_jitter_reject_objects(mysky, lo_skysigma,
01547                                                    hi_skysigma));
01548 
01549             /* When a pixel is bad in self and good in mysky: Set to mysky */
01550             /* Other pixels in self are unchanged */
01551 
01552             mybpm = cpl_image_get_bpm_const(mysky);
01553 
01554             if (mybpm == NULL) {
01555                 /* Fill all bad pixels in self with values from mysky */
01556                 fill2bpm = selfbpm;
01557             } else {
01558                 /* Fill those bad pixels in self with values from mysky
01559                    when those pixels are good */
01560                 fillbpm = cpl_mask_duplicate(mybpm);
01561                 bug_if(cpl_mask_not(fillbpm));
01562                 bug_if(cpl_mask_and(fillbpm, selfbpm));
01563 
01564                 fill2bpm = fillbpm;
01565 
01566             }
01567             cpl_msg_info(cpl_func, "Filling %d object-pixels in sky image "
01568                          "with %d sky-pixels from object image",
01569                          cpl_mask_count(selfbpm), cpl_mask_count(fill2bpm));
01570             if (fill2bpm != selfbpm) {
01571                 /* These rejected pixels will be filled */
01572                 bug_if(cpl_image_reject_from_mask(self, fill2bpm));
01573             }
01574 
01575             if (fillbpm == NULL) {
01576                 fillbpm = cpl_mask_duplicate(fill2bpm);
01577             } else if (fillbpm != fill2bpm) {
01578                 bug_if(cpl_mask_copy(fillbpm, fill2bpm, 1, 1));
01579             }
01580             
01581             bug_if(cpl_image_fill_rejected(self, 0.0)); /* Use addition to fill */
01582             bug_if(cpl_image_accept_all(self)); /* fill2bpm may be invalid now */
01583 
01584             bug_if(cpl_mask_not(fillbpm));
01585             bug_if(cpl_image_reject_from_mask(mysky, fillbpm));
01586             bug_if(cpl_image_fill_rejected(mysky, 0.0)); /* Use addition to fill */
01587             bug_if(cpl_image_accept_all(mysky));
01588             bug_if(cpl_image_add(self, mysky));
01589         }
01590     }
01591 #endif
01592 
01593     end_skip;
01594 
01595     if (cpl_error_get_code()) {
01596         cpl_image_delete(self);
01597         self = NULL;
01598     }
01599 
01600 
01601     if (skycube != belowcube && skycube != abovecube) {
01602         int nwrap = cpl_imagelist_get_size(skycube);
01603 
01604         /* Unwrap the wrapped images */
01605         for (;nwrap > 0;) {
01606             (void)cpl_imagelist_unset(skycube, --nwrap);
01607         }
01608 
01609         cpl_imagelist_delete(skycube);
01610     }
01611 
01612     cpl_mask_delete(fillbpm);
01613     cpl_image_delete(mysky);
01614     cpl_imagelist_delete(mycube);
01615     cpl_imagelist_delete(belowcube);
01616     cpl_imagelist_delete(abovecube);
01617 
01618     return self;
01619 }
01620 
01621 
01622 /*----------------------------------------------------------------------------*/
01633 /*----------------------------------------------------------------------------*/
01634 static
01635 cpl_error_code naco_img_jitter_imagelist_wrap_nocube(cpl_imagelist * self,
01636                                                      const cpl_array * iscube,
01637                                                      cpl_imagelist * other)
01638 {
01639 
01640     const int ncube = cpl_imagelist_get_size(other);
01641     int       nwrap = cpl_imagelist_get_size(self);
01642     int       i;
01643 
01644     bug_if(self   == NULL);
01645     bug_if(iscube == NULL);
01646     bug_if(other  == NULL);
01647     bug_if(nwrap != 0);
01648     bug_if(cpl_array_get_size(iscube) != ncube);
01649 
01650     for (i = 0; i < ncube; i++) {
01651         int is_invalid;
01652 
01653         (void)cpl_array_get_int(iscube, i, &is_invalid);
01654 
01655         if (is_invalid) {
01656             cpl_imagelist_set(self, cpl_imagelist_get(other, i), nwrap);
01657             nwrap++;
01658         }
01659     }
01660 
01661     bug_if(cpl_imagelist_get_size(self) != nwrap);
01662 
01663     end_skip;
01664 
01665     return cpl_error_get_code();
01666 }
01667 
01668 
01669 #ifndef NACO_IMG_JITTER_KEEP_SKY_OBJECTS
01670 
01671 /*----------------------------------------------------------------------------*/
01682 /*----------------------------------------------------------------------------*/
01683 static cpl_error_code naco_img_jitter_reject_objects(cpl_image * self,
01684                                                      double lo_sigma, 
01685                                                      double hi_sigma)
01686 {
01687     double       median;
01688     double       med_dist = DBL_MAX;
01689     double       hi_threshold;
01690     cpl_mask   * hi_objects = NULL;
01691     cpl_mask   * lo_objects = NULL;
01692     cpl_mask   * rejects = NULL;
01693     cpl_image  * hi_label = NULL;
01694     cpl_image  * lo_label = NULL;
01695     cpl_apertures * hi_apert = NULL;
01696 #if defined CPL_VERSION_CODE && CPL_VERSION_CODE >= CPL_VERSION(5, 2, 0)
01697     cpl_mask * kernel = NULL;
01698 #else
01699     cpl_matrix * kernel = NULL;
01700 #endif
01701 
01702 
01703     bug_if(self == NULL);
01704     bug_if(lo_sigma <= 0.0);
01705     bug_if(hi_sigma < lo_sigma);
01706 
01707     /* Compute the threshold */
01708     median = cpl_image_get_median_dev(self, &med_dist);
01709     hi_threshold = median + hi_sigma * med_dist;
01710 
01711     /* Binarise the image with the high sigma threshold */
01712     hi_objects = cpl_mask_threshold_image_create(self, hi_threshold, DBL_MAX);
01713     bug_if(hi_objects == NULL);
01714 
01715     /* Apply a morphological opening to remove the single pixel detections */
01716     /* Copied from cpl_apertures_extract_sigma() */
01717 #if defined CPL_VERSION_CODE && CPL_VERSION_CODE >= CPL_VERSION(5, 2, 0)
01718     kernel = cpl_mask_new(3, 3);
01719     bug_if(cpl_mask_not(kernel));
01720     bug_if(cpl_mask_filter(hi_objects, hi_objects, kernel, CPL_FILTER_OPENING,
01721                            CPL_BORDER_ZERO));
01722 #else
01723     kernel = cpl_matrix_new(3, 3);
01724     bug_if(cpl_matrix_fill(kernel, 1.0));
01725     bug_if (cpl_mask_opening(hi_objects, kernel));
01726 #endif
01727 
01728     if (!cpl_mask_is_empty(hi_objects)) {
01729         /* Any low-sigma aperture overlapping a high-sigma
01730            aperture is assumed to be (all of) an object */
01731 
01732         const double lo_threshold = median + lo_sigma * med_dist;
01733         int hi_ilabel, hi_nlabel, lo_nlabel;
01734 
01735         /* Binarise the image with the low sigma threshold */
01736         lo_objects = cpl_mask_threshold_image_create(self, lo_threshold, DBL_MAX);
01737         bug_if(lo_objects == NULL);
01738 #if defined CPL_VERSION_CODE && CPL_VERSION_CODE >= CPL_VERSION(5, 2, 0)
01739         bug_if(cpl_mask_filter(lo_objects, lo_objects, kernel,
01740                                CPL_FILTER_OPENING, CPL_BORDER_ZERO));
01741 #else
01742         bug_if (cpl_mask_opening(lo_objects, kernel));
01743 #endif
01744 
01745         hi_label = cpl_image_labelise_mask_create(hi_objects, &hi_nlabel);
01746         lo_label = cpl_image_labelise_mask_create(lo_objects, &lo_nlabel);
01747 
01748         hi_apert = cpl_apertures_new_from_image(self, hi_label);
01749         bug_if(hi_apert == NULL);
01750 
01751         for (hi_ilabel = 1; hi_ilabel <= hi_nlabel; hi_ilabel++) {
01752             /* Get one pixel from the high-sigma aperture */
01753             const int pos_x = cpl_apertures_get_top_x(hi_apert, hi_ilabel);
01754             const int pos_y = cpl_apertures_get_top(hi_apert, hi_ilabel);
01755             /* The corresponding low-sigma aperture */
01756             int is_rejected;
01757             const int lo_ilabel = (int)cpl_image_get(lo_label, pos_x, pos_y,
01758                                                      &is_rejected);
01759 
01760             /* The mask of pixels with the corresponding low-sigma aperture */
01761             cpl_mask_delete(rejects);
01762             rejects = cpl_mask_threshold_image_create(lo_label,
01763                                                       (double)lo_ilabel - 0.5,
01764                                                       (double)lo_ilabel + 0.5);
01765 
01766             /* Add to the rejection mask */
01767             cpl_mask_or(hi_objects, rejects);
01768 
01769         }
01770 
01771         cpl_msg_info(cpl_func, "Found %d object(s) of %d pixel(s) "
01772                      "in sky image using sigmas %g and %g", hi_nlabel,
01773                      cpl_mask_count(hi_objects), lo_sigma, hi_sigma);
01774         bug_if(cpl_image_reject_from_mask(self, hi_objects));
01775 
01776     }
01777 
01778     end_skip;
01779 
01780     cpl_apertures_delete(hi_apert);
01781     cpl_image_delete(hi_label);
01782     cpl_image_delete(lo_label);
01783 #if defined CPL_VERSION_CODE && CPL_VERSION_CODE >= CPL_VERSION(5, 2, 0)
01784     cpl_mask_delete(kernel);
01785 #else
01786     cpl_matrix_delete(kernel);
01787 #endif
01788     cpl_mask_delete(hi_objects);
01789     cpl_mask_delete(lo_objects);
01790     cpl_mask_delete(rejects);
01791 
01792     return cpl_error_get_code();
01793 }
01794 #endif
01795 
01796 
01797 
01798 /*----------------------------------------------------------------------------*/
01808 /*----------------------------------------------------------------------------*/
01809 static cpl_image * naco_img_jitter_saa_lucky(const cpl_imagelist * cube,
01810                                              const cpl_vector * strehl,
01811                                              const cpl_bivector * offs,
01812                                              double fraction)
01813 {
01814 
01815     cpl_image * self = NULL;
01816     const int ncube = cpl_imagelist_get_size(cube);
01817     const int mcube = NACO_MAX(NACO_MIN(ncube, (int)(0.5 + fraction * ncube)),
01818                                1);
01819     cpl_imagelist * lcube   = mcube == ncube ? (cpl_imagelist*)cube
01820         : cpl_imagelist_new();
01821     cpl_vector    * lstrehl = mcube == ncube ? (cpl_vector*)strehl
01822         : cpl_vector_duplicate(strehl);
01823     /* Always need to duplicate due to pesky offset convention in
01824        cpl_geom_img_offset_saa() */
01825     cpl_bivector  * loffs   = cpl_bivector_duplicate(offs);
01826     cpl_vector    * loffsx  = cpl_bivector_get_x(loffs);
01827     cpl_vector    * loffsy  = cpl_bivector_get_y(loffs);
01828     cpl_table     * tsort = NULL;
01829     cpl_propertylist * psort = NULL;
01830     int i;
01831 
01832 
01833 
01834     bug_if(cpl_vector_get_size(strehl) != ncube);
01835     bug_if(cpl_bivector_get_size(offs) != ncube);
01836     bug_if(fraction <= 0.0);
01837     bug_if(fraction >  1.0);
01838 
01839     if (mcube < ncube) {
01840         double strehlmin; /* Smallest to be used */
01841         int  * pindex;
01842 
01843         tsort = cpl_table_new(ncube);
01844         psort = cpl_propertylist_new();
01845 
01846         /* Largest Strehl 1st */
01847         bug_if(cpl_propertylist_append_bool(psort, "LSTREHL", CPL_TRUE));
01848 
01849         bug_if(cpl_table_wrap_double(tsort, cpl_vector_get_data(lstrehl),
01850                                      "LSTREHL"));
01851         bug_if(cpl_table_wrap_double(tsort, cpl_vector_get_data(loffsx),
01852                                      "LOFFSX"));
01853         bug_if(cpl_table_wrap_double(tsort, cpl_vector_get_data(loffsy),
01854                                      "LOFFSY"));
01855         bug_if(cpl_table_new_column(tsort, "INDEX", CPL_TYPE_INT));
01856 
01857         /* The indices for the imagelist */
01858         pindex = cpl_table_get_data_int(tsort, "INDEX");
01859         for (i = 0; i < ncube; i++) {
01860             pindex[i] = i;
01861         }
01862 
01863         bug_if(cpl_table_sort(tsort, psort));
01864         /* Strehl, offsets and the (imagelist) indices have been sorted */
01865 
01866         /* Use the index column to create a sorted list of wrapped images */
01867         for (i = 0; i < mcube; i++) {
01868             const int j = pindex[i];
01869 
01870             cpl_imagelist_set(lcube, cpl_imagelist_get((cpl_imagelist*)cube,
01871                                                        j), i);
01872         }
01873         /* tsort no longer accessed */
01874 
01875         /* loffs and the imagelist must both have length mcube */
01876         bug_if(cpl_vector_set_size(loffsx, mcube));
01877         bug_if(cpl_vector_set_size(loffsy, mcube));
01878 
01879         strehlmin = cpl_vector_get(lstrehl, mcube - 1);
01880         cpl_vector_delete(lstrehl);
01881         lstrehl = NULL;
01882 
01883         cpl_msg_info(cpl_func, "%g%% (%d/%d) lucky mode at Strehl=%g",
01884                      100.0*fraction, mcube, ncube, strehlmin);
01885     } else {
01886     }
01887 
01888     self = naco_img_jitter_saa_center(lcube, loffs);
01889     any_if("Could not center and saa %d-cube", ncube);
01890 
01891     end_skip;
01892 
01893     if (lcube != cube) {
01894         /* Unwrap the wrapped images */
01895         for (i = cpl_imagelist_get_size(lcube); i > 0;) {
01896             (void)cpl_imagelist_unset(lcube, --i);
01897         }
01898 
01899         cpl_imagelist_delete(lcube);
01900     }
01901 
01902     if (lstrehl != strehl)
01903         cpl_vector_delete(lstrehl);
01904 
01905     cpl_bivector_delete(loffs);
01906 
01907     if (tsort != NULL) {
01908         if (cpl_table_has_column(tsort, "LSTREHL"))
01909             (void)cpl_table_unwrap(tsort, "LSTREHL");
01910         if (cpl_table_has_column(tsort, "LOFFSX"))
01911             (void)cpl_table_unwrap(tsort, "LOFFSX");
01912         if (cpl_table_has_column(tsort, "LOFFSY"))
01913             (void)cpl_table_unwrap(tsort, "LOFFSY");
01914         cpl_table_delete(tsort);
01915     }
01916     cpl_propertylist_delete(psort);
01917 
01918     return self;
01919 }
01920 
01921 
01922 /*----------------------------------------------------------------------------*/
01930 /*----------------------------------------------------------------------------*/
01931 static
01932 cpl_error_code naco_img_jitter_find_strehl(const cpl_imagelist * self,
01933                                            const irplib_framelist * objframes)
01934 {
01935 
01936     const int       nobj = irplib_framelist_get_size(objframes);
01937     cpl_apertures * apert = NULL;
01938     cpl_vector    * sigmas = NULL;
01939     double          psigmas[] = {5.0, 2.0, 1.0, 0.5}; /* not modified */
01940     const int       nsigmas = (int)(sizeof(psigmas)/sizeof(double));
01941     /* Use half of default value to support images windowed to 128 x 130 */
01942     /* FIXME: Adjust according to image size ? */
01943     const double    rstar  = 0.5 * STREHL_STAR_RADIUS;
01944     const double    rbgint = 0.5 * STREHL_BACKGROUND_R1;
01945     const double    rbgext = 0.5 * STREHL_BACKGROUND_R2;
01946     int             isigma = 0;
01947     int             i;
01948 
01949 
01950     skip_if(rbgext <= rbgint);
01951 
01952     bug_if(cpl_imagelist_get_size(self) != nobj);
01953 
01954     /* Create the vector for the detection thresholds */
01955     sigmas = cpl_vector_wrap(nsigmas, psigmas);
01956 
01957     for (i = 0; i < nobj; i++) {
01958         const cpl_propertylist * plist
01959             = irplib_framelist_get_propertylist_const(objframes, i);
01960         const cpl_image * oimage = cpl_imagelist_get_const(self, i);
01961 
01962         const double      pixscale = naco_pfits_get_pixscale(plist);
01963         const char      * filter = naco_pfits_get_filter(plist);
01964         double            lam  = DBL_MAX; /* Avoid uninit warning */
01965         double            dlam = DBL_MAX; /* Avoid uninit warning */
01966 
01967         double            cent_x, cent_y;
01968         double            strehl = 0, strehl_err, star_bg,star_peak, star_flux;
01969         double            psf_peak, psf_flux, bg_noise;
01970         int               iflux;
01971 
01972 
01973         skip_if(pixscale <= 0.0);
01974 
01975         irplib_check(naco_get_filter_infos(filter, &lam, &dlam),
01976                      "Frame %d has no info for filter %s", 1+i, filter);
01977 
01978         cpl_apertures_delete(apert);
01979         apert = cpl_apertures_extract(oimage, sigmas, &isigma);
01980 
01981         any_if("No object found in combined image of frame %d", 1+i);
01982 
01983         bug_if(irplib_apertures_find_max_flux(apert, &iflux, 1));
01984 
01985         cent_x = cpl_apertures_get_centroid_x(apert, iflux);
01986         cent_y = cpl_apertures_get_centroid_y(apert, iflux);
01987 
01988         skip_if (irplib_strehl_compute(oimage, STREHL_M1, STREHL_M2, lam, dlam,
01989                                        pixscale, STREHL_BOX_SIZE, cent_x, cent_y,
01990                                        rstar, rbgint, rbgext, -1, -1,
01991                                        &strehl, &strehl_err,
01992                                        &star_bg, &star_peak, &star_flux,
01993                                        &psf_peak, &psf_flux,
01994                                        &bg_noise));
01995         cpl_msg_info(cpl_func, "Image of frame %d/%d has strehl=%g at (x,y)"
01996                      "=(%g,%g)", 1+i, nobj, strehl, cent_x, cent_y);
01997     }
01998 
01999     end_skip;
02000 
02001     (void)cpl_vector_unwrap(sigmas);
02002     cpl_apertures_delete(apert);
02003 
02004     return cpl_error_get_code();
02005 }
02006 
02007 
02008 
02009 /*----------------------------------------------------------------------------*/
02017 /*----------------------------------------------------------------------------*/
02018 static cpl_image * naco_img_jitter_saa_center(const cpl_imagelist * cube,
02019                                               cpl_bivector * offs)
02020 {
02021 
02022     const int       ncube  = cpl_imagelist_get_size(cube);
02023     cpl_image     * self   = NULL;
02024     const cpl_image * image;
02025     cpl_image    ** combined = NULL;
02026     cpl_imagelist * ccube  = NULL;
02027     cpl_vector    * offsx  = cpl_bivector_get_x(offs);
02028     cpl_vector    * offsy  = cpl_bivector_get_y(offs);
02029     double        * doffsx = cpl_vector_get_data(offsx);
02030     double        * doffsy = cpl_vector_get_data(offsy);
02031     const double    med_x  = cpl_vector_get_median_const(offsx);
02032     const double    med_y  = cpl_vector_get_median_const(offsy);
02033     double          pos_x, pos_y;
02034     double          minsqdist = DBL_MAX;
02035     int             imin = -1;
02036     int             i;
02037 
02038 
02039     bug_if(cpl_bivector_get_size(offs) != ncube);
02040 
02041     /* Find image with object closest to object median location */
02042     for (i = 0; i < ncube; i++) {
02043         const double x = cpl_vector_get(offsx, i);
02044         const double y = cpl_vector_get(offsy, i);
02045         const double sqdist
02046             = (x - med_x) * (x - med_x) + (y - med_y) * (y - med_y);
02047 
02048         if (sqdist < minsqdist) {
02049             minsqdist = sqdist;
02050             imin = i;
02051         }
02052     }
02053 
02054     cpl_msg_info(cpl_func, "Plane %d/%d has minimal object distance %g "
02055                  "from median (x,y)=(%g,%g)", 1+imin, ncube,
02056                  sqrt(minsqdist), med_x, med_y);
02057 
02058 
02059     if (imin > 0) {
02060         /* Wrap ccube around the images - with image imin first */
02061 
02062         ccube = cpl_imagelist_new();
02063 
02064         image = cpl_imagelist_get_const(cube, imin);
02065         bug_if(cpl_imagelist_set(ccube, (cpl_image*)image, 0));
02066 
02067         for (i = 0; i < imin; i++) {
02068             image = cpl_imagelist_get_const(cube, i);
02069             bug_if(cpl_imagelist_set(ccube, (cpl_image*)image, 1+i));
02070         }
02071         for (i = 1+imin; i < ncube; i++) {
02072             image = cpl_imagelist_get_const(cube, i);
02073             bug_if(cpl_imagelist_set(ccube, (cpl_image*)image, i));
02074         }
02075 
02076         bug_if(cpl_imagelist_get_size(ccube) != ncube);
02077 
02078         /* Reorder offs accordingly */
02079         pos_x = cpl_vector_get(offsx, imin);
02080         pos_y = cpl_vector_get(offsy, imin);
02081 
02082         /* Move all offsets below imin 1 place up */
02083         memmove(doffsx + 1, doffsx, (size_t)imin * sizeof(*doffsx));
02084         memmove(doffsy + 1, doffsy, (size_t)imin * sizeof(*doffsy));
02085 
02086         /* Copy the imin offset to the 1st element */
02087         cpl_vector_set(offsx, 0, pos_x);
02088         cpl_vector_set(offsy, 0, pos_y);
02089     } else {
02090         ccube = (cpl_imagelist*)cube;
02091     }
02092 
02093     /* Strange convention for the offsets :-(((((((((((((((( */
02094     cpl_vector_subtract_scalar(offsx, cpl_vector_get(offsx, 0));
02095     cpl_vector_subtract_scalar(offsy, cpl_vector_get(offsy, 0));
02096     cpl_vector_multiply_scalar(offsx, -1.0);
02097     cpl_vector_multiply_scalar(offsy, -1.0);
02098 
02099     combined = cpl_geom_img_offset_saa(ccube, offs, CPL_KERNEL_DEFAULT,
02100                                        0, 0, CPL_GEOM_FIRST, &pos_x, &pos_y);
02101 
02102     any_if("Could not shift and add %d-cube", ncube);
02103 
02104     cpl_msg_info(cpl_func, "Shift-and-added %d-cube, 1st pos=(%g,%g)",
02105                  ncube, pos_x, pos_y);
02106 
02107     self = combined[0];
02108     cpl_image_delete(combined[1]);
02109     combined[0] = NULL;
02110     combined[1] = NULL;
02111 
02112     end_skip;
02113 
02114     if (combined != NULL) {
02115         cpl_image_delete(combined[0]);
02116         cpl_image_delete(combined[1]);
02117         cpl_free(combined);
02118     }
02119 
02120     if (ccube != NULL && ccube != cube) {
02121         /* Unwrap the wrapped no-cube images */
02122         for (i = cpl_imagelist_get_size(ccube); i > 0;) {
02123             (void)cpl_imagelist_unset(ccube, --i);
02124         }
02125 
02126         cpl_imagelist_delete(ccube);
02127     }
02128 
02129     return self;
02130 }
02131 

Generated on Wed Mar 9 15:46:17 2011 for NACO Pipeline Reference Manual by  doxygen 1.5.8