naco_img_jitter.c

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