visir_inputs.c

00001 /* $Id: visir_inputs.c,v 1.164 2011/04/14 07:59:08 llundin Exp $
00002  *
00003  * This file is part of the VISIR 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/04/14 07:59:08 $
00024  * $Revision: 1.164 $
00025  * $Name: visir-3_4_4 $
00026  */
00027 
00028 #ifdef HAVE_CONFIG_H
00029 #include <config.h>
00030 #endif
00031 
00032 /*-----------------------------------------------------------------------------
00033                                    Includes
00034  -----------------------------------------------------------------------------*/
00035 
00036 #include <cpl.h>
00037 
00038 #include "visir_utils.h"
00039 #include "visir_pfits.h"
00040 #include "visir_parameter.h"
00041 #include "visir_pfits.h"
00042 #include "visir_spc_distortion.h"
00043 #include "visir_inputs.h"
00044 #include "irplib_framelist.h"
00045 
00046 #include <string.h>
00047 #include <math.h>
00048 #include <float.h>
00049 #include <assert.h>
00050 
00051 /*-----------------------------------------------------------------------------
00052                                    Define
00053  -----------------------------------------------------------------------------*/
00054 
00055 #ifndef VISIR_DESTRIPE_DETECT
00056 #define VISIR_DESTRIPE_DETECT           (3.5 * 1.64)
00057 #endif
00058 
00059 #ifndef VISIR_DESTRIPE_DETECT_THRESHOLD
00060 #define VISIR_DESTRIPE_DETECT_THRESHOLD 1.3
00061 #endif
00062 
00063 /* FIXME: Use correct image size */
00064 #define VISIRSZ 256
00065 
00066 typedef enum {
00067     VISIR_CUBE1,
00068     VISIR_CUBE2
00069 } visir_cube_type;
00070 
00071 
00072 /*-----------------------------------------------------------------------------
00073                                    Functions prototypes
00074  -----------------------------------------------------------------------------*/
00075 
00076 #include "visir_destripe.h"
00077 
00078 static cpl_image * visir_load_average(const char *,
00079                                       const cpl_propertylist *);
00080 static cpl_imagelist * visir_load_intermint(const irplib_framelist *, int);
00081 static cpl_error_code visir_imagelist_unpack_interm(cpl_imagelist *);
00082 static cpl_error_code visir_rem_glitch(cpl_image *);
00083 static cpl_error_code visir_rem_bad_images(cpl_imagelist *); 
00084 static cpl_error_code visir_offset_hcycle(cpl_image *);
00085 
00086 static cpl_image ** visir_img_collapse_beam_four(cpl_propertylist       *,
00087                                                  const cpl_image        *,
00088                                                  const cpl_image        *,
00089                                                  double, double,
00090                                                  const cpl_propertylist *);
00091 
00092 static cpl_image ** visir_img_collapse_beam_three(cpl_propertylist       *,
00093                                                   const cpl_image        *,
00094                                                   const cpl_image        *,
00095                                                   double, double,
00096                                                   const cpl_propertylist *);
00097 
00098 
00099 static cpl_error_code visir_img_find_beam_three(cpl_propertylist       *,
00100                                                 const cpl_image        *,
00101                                                 const cpl_image        *,
00102                                                 double, double,
00103                                                 double                 *,
00104                                                 double                 *);
00105 
00106 static cpl_error_code visir_img_find_beam_four(cpl_propertylist       *,
00107                                                const cpl_image        *,
00108                                                const cpl_image        *,
00109                                                double, double,
00110                                                double                 *,
00111                                                double                 *);
00112 
00113 static cpl_error_code visir_get_type(const irplib_framelist *, int,
00114                                      visir_cube_type *, int *, int *);
00115 
00116 /*----------------------------------------------------------------------------*/
00120 /*----------------------------------------------------------------------------*/
00121 
00125 /*----------------------------------------------------------------------------*/
00146 /*----------------------------------------------------------------------------*/
00147 
00148 cpl_image * visir_load_cube2_split(cpl_imagelist * alist, cpl_imagelist * blist,
00149                                    const irplib_framelist * rawframes, int pos)
00150 {
00151 
00152     cpl_image          * self = NULL;
00153     cpl_imagelist      * packed = NULL;
00154     const char         * file
00155         = cpl_frame_get_filename(irplib_framelist_get_const(rawframes, pos));
00156     int                  naxis3, nchop;
00157     visir_cube_type      cube_type;
00158     int i;
00159 
00160     (void)visir_get_type(rawframes, pos, &cube_type, &naxis3, &nchop);
00161 
00162     any_if("Cannot split non-CUBE2 frame %d/%d in %s", 1+pos,
00163            irplib_framelist_get_size(rawframes), file);
00164     bug_if(alist     == NULL);
00165     bug_if(blist     == NULL);
00166 
00167     error_if(cube_type != VISIR_CUBE2, CPL_ERROR_INCOMPATIBLE_INPUT, "Cannot "
00168              "split non-CUBE2 frame %d/%d w. NAXIS3=%d, NCYCLES=%d in %s",
00169              1+pos, irplib_framelist_get_size(rawframes), naxis3, nchop, file);
00170 
00171     packed = cpl_imagelist_load(file, CPL_TYPE_UNSPECIFIED, 0);
00172     skip_if(cpl_imagelist_get_size(packed) != naxis3);
00173 
00174     self = cpl_imagelist_unset(packed, naxis3 - 1);
00175 
00176     /* Split the cube */
00177     for (i = 0; i < naxis3/2; i++) {
00178         cpl_image * hcycle = cpl_imagelist_unset(packed, 0);
00179         cpl_image * image  = cpl_imagelist_unset(packed, 0);
00180 
00181         cpl_imagelist_set(alist, image,  i);
00182         cpl_imagelist_set(blist, hcycle, i);
00183 
00184     }
00185 
00186     skip_if_lt(0, cpl_imagelist_get_size(packed), "Too many packed frames");
00187 
00188     bug_if(visir_imagelist_unpack_interm(alist));
00189 
00190     for (i = 0; i < naxis3/2; i++) {
00191         const cpl_image * hcycle = cpl_imagelist_get_const(blist, i);
00192         cpl_image * image  = cpl_imagelist_get(alist, i);
00193 
00194         cpl_image_add(image, hcycle);
00195 
00196     }
00197 
00198 
00199     end_skip;
00200 
00201     cpl_imagelist_delete(packed);
00202 
00203     return self;
00204 
00205 }
00206 
00207 
00208 /*----------------------------------------------------------------------------*/
00230 /*----------------------------------------------------------------------------*/
00231 cpl_image ** visir_img_collapse_beam(cpl_propertylist        * qclist,
00232                                      const cpl_image         * self,
00233                                      const cpl_parameterlist * parlist,
00234                                      const char              * recipename,
00235                                      visir_chopnod_mode        mode,
00236                                      const cpl_propertylist  * plist)
00237 {
00238 
00239     cpl_image ** combined = NULL;
00240     /* Need to invert the negative beams */
00241     cpl_image  * inverse = cpl_image_multiply_scalar_create(self, -1.0);
00242 
00243     const double eccmax   = visir_parameterlist_get_double(parlist, recipename,
00244                                                            VISIR_PARAM_ECCMAX);
00245 
00246     /* Get the chopping throw in pixels */
00247     const char * sscale       = visir_pfits_get_pixscale(plist);
00248     const double pscale       = sscale ? atof(sscale) : 0.0;
00249     const double pthrow       = pscale > 0.0
00250         ? visir_pfits_get_chop_throw(plist) / pscale : 0.0;
00251 
00252 
00253     skip_if(self    == NULL);
00254     skip_if(parlist == NULL);
00255     skip_if(qclist  == NULL);
00256     skip_if(plist   == NULL);
00257 
00258     if (mode == VISIR_CHOPNOD_PERPENDICULAR) {
00259         /* 4 sources */
00260         combined = visir_img_collapse_beam_four(qclist, self, inverse, eccmax,
00261                                                 pthrow, plist);
00262     } else if (mode == VISIR_CHOPNOD_PARALLEL) {
00263         /* 3 sources */
00264         combined = visir_img_collapse_beam_three(qclist, self, inverse, eccmax,
00265                                                  pthrow, plist);
00266     } else if (mode == VISIR_CHOPNOD_AUTO) {
00267         cpl_errorstate cleanstate = cpl_errorstate_get();
00268 
00269         const char   * sdir = visir_pfits_get_chopnod_dir(plist);
00270 
00271         if (sdir != NULL && !strcmp(sdir, "PERPENDICULAR")) {
00272             /* 4 sources */
00273             combined = visir_img_collapse_beam_four(qclist, self, inverse,
00274                                                   eccmax, pthrow, plist);
00275         } else if (sdir != NULL && !strcmp(sdir, "PARALLEL")) {
00276             /* 3 sources */
00277             combined = visir_img_collapse_beam_three(qclist, self, inverse,
00278                                                      eccmax, pthrow, plist);
00279         } else {
00280             if (sdir == NULL) {
00281                 visir_error_reset("Could not get FITS key");
00282             } else {
00283                 cpl_msg_warning(cpl_func, "Unknown chopping direction: %s",
00284                                 sdir);
00285             }
00286             cpl_msg_warning(cpl_func, "Proceeding as if FITS card "
00287                             VISIR_PFITS_STRING_CHOPNOD_DIR " had value: %s",
00288                             "PERPENDICULAR");
00289             combined = visir_img_collapse_beam_four(qclist, self, inverse,
00290                                                     eccmax, pthrow, plist);
00291             if (combined == NULL) {
00292                 visir_error_reset("Proceeding as if FITS card "
00293                                   VISIR_PFITS_STRING_CHOPNOD_DIR
00294                                   " had value: %s", "PARALLEL");
00295                 combined = visir_img_collapse_beam_three(qclist, self, inverse,
00296                                                          eccmax, pthrow, plist);
00297             }
00298         }
00299     } else {
00300         bug_if(1);
00301     }
00302 
00303     skip_if(combined == NULL);
00304 
00305     bug_if (cpl_propertylist_append_double(qclist, "ESO QC ONEBEAM THROW",
00306                                            pthrow));
00307     bug_if (cpl_propertylist_set_comment(qclist, "ESO QC ONEBEAM THROW",
00308                                          "The throw in pixels (TEL CHOP THROW "
00309                                          "divided by INS PFOV)"));
00310 
00311     bug_if (cpl_propertylist_set_comment(qclist, "ESO QC ONEBEAM XPOS",
00312                                          "The X pixel position (centroid) "
00313                                          "of the one-beam object"));
00314 
00315     bug_if (cpl_propertylist_set_comment(qclist, "ESO QC ONEBEAM YPOS",
00316                                          "The Y pixel position (centroid) "
00317                                          "of the one-beam object"));
00318     bug_if (cpl_propertylist_set_comment(qclist, "ESO QC ONEBEAM ECCENTRICITY",
00319                                          "Eccentricity: 0 for perfect, throw-"
00320                                          "sized square/line"));
00321 
00322     end_skip;
00323 
00324     cpl_image_delete(inverse);
00325 
00326     return combined;
00327 }
00328 
00329 
00330 /*----------------------------------------------------------------------------*/
00413 /*----------------------------------------------------------------------------*/
00414 cpl_imagelist * visir_inputs_combine(const char * recipename,
00415                                      const cpl_parameterlist * parlist,
00416                                      const irplib_framelist * rawframes,
00417                                      const char      *   badpix,
00418                                      const char      *   flat,
00419                                      int             *   nodding_p,
00420                                      cpl_boolean         do_spc_fix,
00421                                      double              wlen,
00422                                      visir_spc_resol resol)
00423 {
00424     const char       * fnodpos;
00425     int                nfiles;
00426     cpl_imagelist    * in = NULL;
00427     cpl_image        * collapsed = NULL;
00428     cpl_image        * prev = NULL;
00429     cpl_vector       * nods_vec = NULL;
00430     double           * nods_data;
00431     int              * nod_pos = NULL;
00432     cpl_image       ** images = NULL;
00433     cpl_imagelist    * nodded = NULL;
00434     int                nnod;
00435     cpl_image        * flat_image = NULL;
00436     cpl_image        * bpm_im_int = NULL;
00437     cpl_mask         * bpm_im_bin = NULL;
00438     cpl_imagelist    * hcycle = NULL;
00439     cpl_boolean        no_rem;
00440     cpl_boolean        is_nodding = CPL_FALSE;
00441     int                i, j;
00442     cpl_boolean        auto_bpm, rem_glitch, rem_bad;
00443     int                ndestripe;
00444     cpl_boolean        morpho_destripe;
00445     double             tstart, tstop;
00446 #ifdef _OPENMP
00447     cpl_errorstate     cleanstate = cpl_errorstate_get();
00448 #endif
00449     cpl_error_code     didfail = CPL_ERROR_NONE;
00450 
00451 
00452     skip_if (0);
00453     skip_if(recipename == NULL);
00454     skip_if(parlist    == NULL);
00455     skip_if(rawframes  == NULL);
00456     
00457     /* Get the number of files */
00458     nfiles = irplib_framelist_get_size(rawframes);
00459 
00460     /* There should be an even number of files */
00461     if (nfiles % 2) {
00462         cpl_msg_warning(cpl_func, "Expecting even number of files, "
00463                         "ignoring the last of %d file(s)", nfiles);
00464         error_if (nfiles == 1, CPL_ERROR_DATA_NOT_FOUND,
00465                   "At least two files are required");
00466         nfiles--;
00467     }
00468 
00469     nnod = nfiles/2;
00470 
00471     skip_if (nnod <= 0);
00472 
00473     skip_if(irplib_framelist_contains(rawframes, VISIR_PFITS_STRING_FRAME_TYPE,
00474                                        CPL_TYPE_STRING, CPL_FALSE, 0.0));
00475     skip_if(irplib_framelist_contains(rawframes, VISIR_PFITS_DOUBLE_DIT,
00476                                        CPL_TYPE_DOUBLE, CPL_FALSE, 0.0));
00477     skip_if(irplib_framelist_contains(rawframes, VISIR_PFITS_INT_NAXIS3,
00478                                        CPL_TYPE_INT, CPL_FALSE, 0.0));
00479     skip_if(irplib_framelist_contains(rawframes, VISIR_PFITS_INT_CHOP_NCYCLES,
00480                                        CPL_TYPE_INT, CPL_FALSE, 0.0));
00481 
00482 
00483     /* Retrieve input parameters */
00484     fnodpos = visir_parameterlist_get_string(parlist, recipename,
00485                                              VISIR_PARAM_NODPOS);
00486     skip_if (0);
00487 
00488     auto_bpm = visir_parameterlist_get_bool(parlist, recipename,
00489                                             VISIR_PARAM_AUTOBPM);
00490     skip_if (0);
00491 
00492     rem_glitch = visir_parameterlist_get_bool(parlist, recipename,
00493                                               VISIR_PARAM_GLITCH);
00494     skip_if (0);
00495 
00496     rem_bad = visir_parameterlist_get_bool(parlist, recipename,
00497                                            VISIR_PARAM_PURGE);
00498     skip_if (0);
00499 
00500     ndestripe = visir_parameterlist_get_int(parlist, recipename,
00501                                             VISIR_PARAM_STRIPITE);
00502     bug_if (0);
00503 
00504     morpho_destripe = ndestripe <= 0 ? CPL_FALSE :
00505         visir_parameterlist_get_bool(parlist, recipename,
00506                                      VISIR_PARAM_STRIPMOR);
00507     bug_if (0);
00508 
00509     no_rem = !rem_glitch && !rem_bad;
00510 
00511     /* Each file corresponds to a nodding position (object=1 or sky=-1) */
00512     /* Return nod_pos array if requested */
00513     nod_pos = nodding_p ? nodding_p : cpl_malloc(nfiles * sizeof(int));
00514     j = 0;
00515     if (fnodpos != NULL && strlen(fnodpos) > 0) {
00516         /* Get the nodding positions from the user-provided ascii file */
00517         nods_vec = cpl_vector_read(fnodpos);
00518         skip_if (cpl_vector_get_size(nods_vec) != nfiles);
00519         nods_data = cpl_vector_get_data(nods_vec);
00520         skip_if (0);
00521         for (i=0 ; i<nfiles ; i++) {
00522             if ((int)nods_data[i] == 0) {
00523                 nod_pos[i] = 1;
00524                 j++;
00525             } else if ((int)nods_data[i] == 1) {
00526                 nod_pos[i] = -1;
00527                 is_nodding = CPL_TRUE;
00528             } else {
00529                 error_if(1, CPL_ERROR_BAD_FILE_FORMAT,
00530                          "Wrong values in line %d in %s", i+1, fnodpos);
00531             }
00532         }
00533     } else {
00534         skip_if (irplib_framelist_contains(rawframes, VISIR_PFITS_STRING_NODPOS,
00535                                             CPL_TYPE_STRING, CPL_FALSE, 0.0));
00536     }
00537 
00538     if (no_rem) cpl_msg_info(cpl_func, "No glitch removal and no purge of bad "
00539                              "frames requested: Using fast I/O method");
00540 
00541     /* Initialize the Bad Pixel Map */
00542     if (badpix != NULL) {
00543         /* The bpm is provided by the user */
00544         cpl_msg_info(cpl_func, "Loading bad pixel map from %s", badpix);
00545         /* Load the bad pixels image */
00546         bpm_im_int = cpl_image_load(badpix, CPL_TYPE_INT, 0, 0);
00547         skip_if (0);
00548 
00549         /* Convert the map from integer to binary */
00550         bpm_im_bin = cpl_mask_threshold_image_create(bpm_im_int, -0.5, 0.5);
00551         cpl_image_delete(bpm_im_int);
00552         bpm_im_int = NULL;
00553         skip_if (cpl_mask_not(bpm_im_bin));
00554     } else if (auto_bpm) {
00555         /* Initialize the Bad Pixel Map using the hcycle */
00556 
00557         /* i == 0 */
00558         hcycle = visir_load_imagelist(rawframes, 0, CPL_FALSE);
00559         skip_if(0);
00560 
00561         bpm_im_bin =
00562             cpl_mask_threshold_image_create(cpl_imagelist_get(hcycle,0),
00563                                             VISIR_HCYCLE_BPM_THRESHOLD,
00564                                             DBL_MAX);
00565         cpl_imagelist_delete(hcycle);
00566         hcycle = NULL;
00567         skip_if(0);
00568     }
00569 
00570     /* Initialize the flat field image */
00571     if (flat != NULL) {
00572         cpl_msg_info(cpl_func, "Divide the nodded images by the flatfield");
00573         /* Load the flat image */
00574         flat_image = cpl_image_load(flat, CPL_TYPE_FLOAT, 0, 0);
00575         any_if ("Cannot load the flat field %s", flat ? flat : "<NULL>");
00576     }
00577  
00578     /* Get nodding position (if needed) and DIT from the header */
00579     nodded = cpl_imagelist_new();
00580 
00581     tstart = cpl_test_get_walltime();
00582 
00583     /* Fill list with empty images of proper size and type */
00584 
00585     for (i=0; i < nfiles/2 ; i++) {
00586         cpl_image * empty = cpl_image_new(VISIRSZ, VISIRSZ, CPL_TYPE_FLOAT);
00587 
00588         /* i'th image can only be inserted when i-1'th is there,
00589            which prevents parallelism */
00590 
00591         bug_if (cpl_imagelist_set(nodded, empty, i));
00592     }
00593 
00594 #ifdef _OPENMP
00595 #pragma omp parallel for private(i) firstprivate(prev, collapsed)       \
00596                          schedule(static, 2)
00597 #endif
00598     for (i = 0; i < nfiles ; i++) {
00599         cpl_error_code errori = cpl_error_get_code();
00600 
00601         /* The total number of iterations must be pre-determined for the
00602            parallelism to work. In case of an error we can therefore not
00603            break, so instead we skip immediately to the next iteration.
00604            FIXME: This check on didfail does not guarantee that only one
00605                   iteration can cause an error to be dumped, but it is not
00606                   worse than checking on the thread-local state, errori. */
00607         if (didfail) continue;
00608 
00609         do {
00610 
00611         const char * file =
00612             cpl_frame_get_filename(irplib_framelist_get_const(rawframes, i));
00613         const cpl_propertylist * plist;
00614 
00615         double dit;
00616         double factor;
00617 
00618 
00619         plist = irplib_framelist_get_propertylist_const(rawframes, i);
00620         if (plist == NULL) {
00621             errori = cpl_error_set_where(cpl_func);
00622             break;
00623         }
00624 
00625         if (nods_vec == NULL) {
00626             const char * sval = visir_pfits_get_nodpos(plist);
00627             if (sval == NULL) {
00628                 errori = cpl_error_set_message(cpl_func,
00629                                                 CPL_ERROR_DATA_NOT_FOUND,
00630                                                 "Cannot get nodding position "
00631                                                 "for file %d/%d", i+1, nfiles);
00632                 break;
00633             }
00634             if (!strcmp(sval, "A")) {
00635                 nod_pos[i] = 1;
00636                 j++;
00637             } else {
00638                 nod_pos[i] = -1;
00639                 is_nodding = CPL_TRUE;
00640             }
00641         }
00642 
00643         /* Print the file name with its nodding position */
00644         cpl_msg_info(cpl_func, "File %02d: %s (%c)", i+1, file,
00645                      nod_pos[i]==1 ? '+' : '-');
00646 
00647         /* With nodding each pair must have exactly one object observation */
00648         if (is_nodding && (i & 1) == 1 && nod_pos[i] == nod_pos[i-1]) {
00649             cpl_msg_error(cpl_func, "Nodding pair (%d,%d) does not comprise an "
00650                           "on-object (A) and an off-object (B) image: %s", i-1,
00651                           i, nod_pos[i] == 1 ? "A" : "B");
00652         }
00653 
00654         /* Compute the normalization factor from the Detector Integration Time */
00655         dit = visir_pfits_get_dit(plist);
00656         if (cpl_error_get_code()) {
00657             errori = cpl_error_set_where(cpl_func);
00658             break;
00659         }
00660 
00661         if (dit <= 0) {
00662             errori = cpl_error_set_message(cpl_func,
00663                                             CPL_ERROR_ILLEGAL_INPUT,
00664                                             "DIT in file %d/%d is too small: "
00665                                             "%g", i+1, nfiles, dit);
00666             break;
00667         }
00668 
00669         factor = dit * nod_pos[i] * 2.0;
00670 
00671         if (no_rem){
00672             collapsed = visir_load_average(file, plist);
00673         } else {
00674             in = visir_load_intermint(rawframes, i);
00675             if (in == NULL) {
00676                 errori = cpl_error_set_message(cpl_func,
00677                                                 CPL_ERROR_ILLEGAL_INPUT,
00678                                                 "Could not load image set %d",
00679                                                 i+1);
00680                 break;
00681             }
00682 
00683             /* Convert the image lists from 'INTERM' to A-B' */
00684             if (visir_imagelist_unpack_interm(in)) {
00685                 errori = cpl_error_set_message(cpl_func,
00686                                                 cpl_error_get_code(),
00687                                                 "Failure for file %d/%d",
00688                                                 i+1, nfiles);
00689                 break;
00690             }
00691 
00692             /* Remove the glitch in each A-B image in each input cube
00693                if requested */
00694             if (rem_glitch) {
00695                 int jj;
00696                 for (jj=0 ; jj < cpl_imagelist_get_size(in); jj++) {
00697                     if (visir_rem_glitch(cpl_imagelist_get(in, jj))) {
00698                         errori = cpl_error_set_message(cpl_func,
00699                                                         cpl_error_get_code(),
00700                                                         "Could not remove "
00701                                                         "glitch in image %d in "
00702                                                         "set %d", jj+1, i+1);
00703                         break;
00704                     }
00705                 }
00706             }
00707 
00708             /* Remove the bad A-B images in each input file/cube if requested */
00709             if (rem_bad) {
00710                 cpl_msg_info(cpl_func, "Remove the bad A-B input images");
00711                 if (visir_rem_bad_images(in)) {
00712                     errori = cpl_error_set_message(cpl_func,
00713                                                     cpl_error_get_code(),
00714                                                     "Could not remove bad "
00715                                                     "images in list %d", i+1);
00716                     break;
00717                 }
00718             }
00719             /* Average each cube */
00720             collapsed = cpl_imagelist_collapse_create(in);
00721 
00722             cpl_imagelist_delete(in);
00723             in = NULL;
00724 
00725         }
00726 
00727         if (cpl_error_get_code()) {
00728             errori = cpl_error_set_message(cpl_func, cpl_error_get_code(),
00729                                             "Failure for file %d/%d",
00730                                             i+1, nfiles);
00731             break;
00732         }
00733         /* Normalise to have ADU/s. */
00734         /* Also divide with 2 to achieve average of image pair */
00735         if (cpl_image_divide_scalar(collapsed, 2*factor)) {
00736             errori = cpl_error_set_message(cpl_func, cpl_error_get_code(),
00737                                             "Failure for file %d/%d",
00738                                             i+1, nfiles);
00739             break;
00740         }
00741 
00742         /* Each pair of input files gives a nodded image in nodded */
00743         if (i & 1) {
00744             if (cpl_image_add(prev, collapsed)) {
00745                 errori = cpl_error_set_message(cpl_func, cpl_error_get_code(),
00746                                                 "Failure for file %d/%d",
00747                                                 i+1, nfiles);
00748                 break;
00749             }
00750             cpl_image_delete(collapsed);
00751             collapsed = NULL;
00752 
00753             /* At this point prev is the image to be put into
00754                the list of nodded images */
00755 
00756             if (bpm_im_bin != NULL) {
00757                 /* Apply the bad pixels cleaning */
00758                 if (cpl_image_reject_from_mask(prev, bpm_im_bin)) {
00759                     errori = cpl_error_set_message(cpl_func,
00760                                                     cpl_error_get_code(),
00761                                                     "Failure for file %d/%d",
00762                                                     i+1, nfiles);
00763                     break;
00764                 }
00765                 if (cpl_detector_interpolate_rejected(prev)) {
00766                     errori = cpl_error_set_message(cpl_func,
00767                                                     cpl_error_get_code(),
00768                                                     "Failure for file %d/%d",
00769                                                     i+1, nfiles);
00770                     break;
00771                 }
00772             }
00773 
00774             if (ndestripe > 0)
00775                 if(visir_destripe_image(prev, ndestripe,
00776                                              VISIR_DESTRIPE_DETECT,
00777                                              VISIR_DESTRIPE_DETECT_THRESHOLD,
00778                                         morpho_destripe)) {
00779                     errori = cpl_error_set_message(cpl_func,
00780                                                     cpl_error_get_code(),
00781                                                     "Failure for file %d/%d",
00782                                                     i+1, nfiles);
00783                     break;
00784                 }
00785 
00786             if (flat_image != NULL) {
00787                 /* Apply the flatfield correction */
00788                 if (cpl_image_divide(prev, flat_image)) {
00789                     errori = cpl_error_set_message(cpl_func,
00790                                                     cpl_error_get_code(),
00791                                                     "Failure for file %d/%d",
00792                                                     i+1, nfiles);
00793                     break;
00794                 }
00795             }
00796 
00797             if (cpl_imagelist_set(nodded, prev, i/2)) {
00798                 errori = cpl_error_set_message(cpl_func, cpl_error_get_code(),
00799                                                "Failure for file %d/%d",
00800                                                i+1, nfiles);
00801                 break;
00802             }
00803             prev = NULL;
00804         } else {
00805             prev = collapsed;
00806             collapsed = NULL;
00807         }
00808         } while (0);
00809 
00810         if (errori) {
00811 #ifdef _OPENMP
00812             /* Cannot access these errors after the join,
00813                so dump them now. :-(((((((((((((((((((( */
00814             cpl_errorstate_dump(cleanstate, CPL_FALSE, NULL);
00815             cpl_errorstate_set(cleanstate);
00816 
00817             /* Need to deallocate the thread-private instances in the loop */
00818             cpl_image_delete(prev); prev = NULL;
00819             cpl_image_delete(collapsed); collapsed = NULL;
00820 
00821 #pragma omp critical(visir_inputs_combine)
00822 #endif
00823             didfail = errori;
00824         }
00825     }
00826 
00827     error_if(didfail, didfail, "Failed to create %d nodded images from %d "
00828              "files", nnod, nfiles);
00829 
00830     tstop = cpl_test_get_walltime();
00831     cpl_msg_info(cpl_func, "Time to create %d nodded images [s]: %g", nnod,
00832                  tstop - tstart);
00833 
00834     cpl_vector_delete(nods_vec);
00835     nods_vec = NULL;
00836 
00837     cpl_image_delete(flat_image);
00838     flat_image = NULL;
00839 
00840     cpl_mask_delete(bpm_im_bin);
00841     bpm_im_bin = NULL;
00842 
00843     if (nod_pos != nodding_p) cpl_free(nod_pos);
00844     nod_pos = NULL;
00845     
00846     error_if(is_nodding && j != nnod, CPL_ERROR_INCOMPATIBLE_INPUT,
00847          "With nodding exactly half of the images "
00848              "must be on-object, not %d of %d", j, 2*nnod);
00849 
00850     if (do_spc_fix) {
00851         const double ksi   = visir_parameterlist_get_double(parlist, recipename,
00852                                                           VISIR_PARAM_SPECSKEW);
00853         const double eps   = visir_parameterlist_get_double(parlist, recipename,
00854                                                             VISIR_PARAM_VERTARC);
00855         const double delta = visir_parameterlist_get_double(parlist, recipename,
00856                                                             VISIR_PARAM_HORIARC);
00857         const double phi   = visir_parameterlist_get_double(parlist, recipename,
00858                                                           VISIR_PARAM_SLITSKEW);
00859         const int doplot   = visir_parameterlist_get_int(parlist, recipename,
00860                                                          VISIR_PARAM_PLOT);
00861 
00862 
00863         skip_if (0);
00864 
00865         images = cpl_malloc(nnod * sizeof(cpl_image*));
00866 
00867         for (j = 0; j < nnod; j++) images[j] = cpl_imagelist_get(nodded, j);
00868 
00869         skip_if (visir_spc_det_fix(images, nnod, CPL_TRUE, wlen, resol,
00870                                    phi, ksi, eps, delta, doplot));
00871     }
00872 
00873     end_skip;
00874 
00875     cpl_msg_set_time_off();
00876 
00877     cpl_free(images);
00878     cpl_imagelist_delete(in);
00879 
00880     if (nod_pos != nodding_p) cpl_free(nod_pos);
00881     cpl_vector_delete(nods_vec);
00882     cpl_image_delete(bpm_im_int);
00883     cpl_mask_delete(bpm_im_bin);
00884     cpl_image_delete(collapsed);
00885     cpl_image_delete(prev);
00886     if (cpl_error_get_code() && nodded != NULL) {
00887         cpl_imagelist_delete(nodded);
00888         nodded = NULL;
00889     }
00890 
00891     return nodded;
00892 }
00893 
00894 /*----------------------------------------------------------------------------*/
00941 /*----------------------------------------------------------------------------*/
00942 cpl_image ** visir_img_recombine(const char * recipename,
00943                                  const cpl_parameterlist * parlist,
00944                                  const irplib_framelist  * rawframes,
00945                                  const char        * badpix,
00946                                  const char        * flat,
00947                                  cpl_geom_combine    combine_mode,
00948                                  cpl_boolean       * pdid_resize,
00949                                  cpl_boolean         do_spc_fix,
00950                                  double              wlen,
00951                                  visir_spc_resol     resol)
00952 {
00953     int                     nfiles;
00954     int                 *   nod_pos = NULL;
00955     cpl_imagelist       *   nodded = NULL;
00956     int                     nnod;
00957     cpl_bivector        *   offsets_est = NULL;
00958     cpl_bivector        *   objs = NULL;
00959     cpl_image           **  combined = NULL;
00960     const cpl_vector    *   sigmas = NULL;
00961     double                  xoff, yoff;
00962     cpl_propertylist    *   qclist = cpl_propertylist_new();
00963     int                     i;
00964 
00965 
00966     bug_if (0);
00967 
00968     bug_if (recipename == NULL);
00969     bug_if (parlist    == NULL);
00970     bug_if (rawframes  == NULL);
00971     bug_if (pdid_resize  == NULL);
00972 
00973     /* Get the number of files */
00974     nfiles = irplib_framelist_get_size(rawframes);
00975 
00976     /* There should be an even number of files */
00977     if (nfiles % 2) {
00978         cpl_msg_warning(cpl_func, "Expecting even number of files, "
00979                         "ignoring the last of %d file(s)", nfiles);
00980         error_if (nfiles == 1, CPL_ERROR_DATA_NOT_FOUND,
00981                   "At least two files are required");
00982         nfiles--;
00983     }
00984 
00985     skip_if ( nfiles <= 0);
00986 
00987     /* Each file corresponds to a nodding position (object=1 or sky=-1) */
00988     nod_pos = cpl_malloc(nfiles * sizeof(int));
00989 
00990     /* Combine the input frames into the nodded images */
00991     cpl_msg_info(cpl_func, "Combining the input frames into the nodded images");
00992     nodded = visir_inputs_combine(recipename, parlist, rawframes, badpix, flat,
00993                                   nod_pos, do_spc_fix, wlen, resol);
00994 
00995     skip_if (nodded == NULL);
00996     nnod = cpl_imagelist_get_size(nodded);
00997 
00998     /* If only one nodded image, the work is finished */
00999     if (nnod == 1) {
01000 
01001         combined = cpl_malloc(2*sizeof(cpl_image*)); 
01002         combined[1] = NULL; /* In case the unset fails */
01003 
01004         combined[0] = cpl_imagelist_unset(nodded, 0);
01005         bug_if (combined[0] == NULL);
01006 
01007         combined[1] = cpl_image_new(cpl_image_get_size_x(combined[0]),
01008                                     cpl_image_get_size_y(combined[0]),
01009                                     CPL_TYPE_INT);
01010         bug_if (combined[1] == NULL);
01011 
01012         /* Set all pixel values to 1 */
01013         bug_if(cpl_image_threshold(combined[1], 1.0, 1.0, 1.0, 1.0));
01014 
01015         *pdid_resize = CPL_FALSE;
01016 
01017     } else {
01018         const double psigmas[] = {5, 2, 1, 0.5};
01019         const char * sval;
01020         const char * offsets;
01021         const char * objects;
01022         int sx, sy, mx, my;
01023         int rej_low, rej_high;
01024         cpl_boolean refine;
01025 
01026 
01027         refine = visir_parameterlist_get_bool(parlist, recipename,
01028                                               VISIR_PARAM_REFINE);
01029         skip_if (0);
01030 
01031         offsets = visir_parameterlist_get_string(parlist, recipename,
01032                                                  VISIR_PARAM_OFFSETS);
01033         skip_if (0);
01034 
01035         objects = visir_parameterlist_get_string(parlist, recipename,
01036                                                  VISIR_PARAM_OBJECTS);
01037         skip_if (0);
01038 
01039         sval = visir_parameterlist_get_string(parlist, recipename,
01040                                               VISIR_PARAM_XCORR);
01041         skip_if (0);
01042 
01043         skip_if (sscanf(sval, "%d %d %d %d", &sx, &sy, &mx, &my) != 4);
01044 
01045         sval = visir_parameterlist_get_string(parlist, recipename,
01046                                               VISIR_PARAM_REJECT);
01047         skip_if (0);
01048 
01049         skip_if (sscanf(sval, "%d %d", &rej_low, &rej_high) !=2 );
01050 
01051         /* Get the offsets estimation of each input file pair */
01052         cpl_msg_info(cpl_func, "Get the offsets estimation");
01053         if (offsets != NULL && strlen(offsets)) {
01054             /* A file has been provided on the command line */
01055             offsets_est = cpl_bivector_read(offsets);
01056             skip_if (offsets_est==NULL);
01057 
01058             error_if (cpl_bivector_get_size(offsets_est) != nnod,
01059                       CPL_ERROR_BAD_FILE_FORMAT, "The offsets file %s must "
01060                       "have %d entries, not %d", offsets, nnod,
01061                       cpl_bivector_get_size(offsets_est));
01062         } else {
01063             double * offsets_est_x;
01064             double * offsets_est_y;
01065             double   xoff0 = 0.0;  /* Avoid (false) uninit warning */
01066             double   yoff0 = 0.0;  /* Avoid (false) uninit warning */
01067             
01068             /* Get the offsets from the header */
01069             offsets_est = cpl_bivector_new(nnod);
01070             offsets_est_x = cpl_bivector_get_x_data(offsets_est);
01071             offsets_est_y = cpl_bivector_get_y_data(offsets_est);
01072 
01073             skip_if (0);
01074 
01075             offsets_est_x[0] = 0.0;
01076             offsets_est_y[0] = 0.0;
01077 
01078             for (i=0; i < nnod ; i++) {
01079                 const cpl_propertylist * plist;
01080 
01081                 /* Skip every other, non-object frame */ 
01082                 const int iframe = nod_pos[2*i] == 1 ? 2*i : 2*i+1;
01083 
01084                 plist = irplib_framelist_get_propertylist_const(rawframes,
01085                                                                 iframe);
01086                 skip_if(plist == NULL);
01087 
01088                 xoff = visir_pfits_get_cumoffsetx(plist);
01089                 yoff = visir_pfits_get_cumoffsety(plist);
01090 
01091                 skip_if (0);
01092 
01093                 if (i == 0) {
01094                     xoff0 = xoff;
01095                     yoff0 = yoff;
01096                 } else {
01097                     /* Subtract the first offset from all offsets */
01098                     offsets_est_x[i] = xoff0 - xoff;
01099                     offsets_est_y[i] = yoff0 - yoff;
01100                 }
01101             }
01102         }
01103         cpl_free(nod_pos);
01104         nod_pos = NULL;
01105     
01106         /* Read the provided objects file if provided
01107            - if a file has been provided on the command line */
01108         if (objects != NULL && strlen(objects) > 0) {
01109             objs = cpl_bivector_read(objects);
01110             any_if ("Could not read objects from %s", objects);
01111         }
01112    
01113         cpl_msg_info(cpl_func, "Recombining the list of nodded images using "
01114                      "mode: %d (I=%d:U=%d:F=%d), rej-lo=%d, rej-hi=%d",
01115                      combine_mode, CPL_GEOM_INTERSECT, CPL_GEOM_UNION,
01116                      CPL_GEOM_FIRST, rej_low, rej_high);
01117 
01118         if (cpl_msg_get_level() <= CPL_MSG_DEBUG) {
01119             cpl_msg_debug(cpl_func, "The offsets for the recombination:");
01120             cpl_bivector_dump(offsets_est, stdout);
01121         }
01122 
01123         sigmas = cpl_vector_wrap(4, (double*)psigmas); /* Not changed */
01124         combined = cpl_geom_img_offset_combine(nodded, offsets_est, refine,
01125                                                objs, sigmas, NULL, sx, sy,
01126                                                mx, my, rej_low, rej_high,
01127                                                combine_mode);
01128         any_if("Could not recombine the images");
01129 
01130         *pdid_resize = (cpl_boolean)(cpl_image_get_size_x(combined[0])
01131                 != cpl_image_get_size_x(cpl_imagelist_get_const(nodded, 0)) ||
01132                 cpl_image_get_size_y(combined[0])
01133                 != cpl_image_get_size_y(cpl_imagelist_get_const(nodded, 0)));
01134     }
01135 
01136     if (visir_parameterlist_get_int(parlist, recipename, VISIR_PARAM_PLOT) > 0)
01137         visir_image_plot("", "t 'The combined image'", "", combined[0]);
01138 
01139     end_skip;
01140 
01141     cpl_propertylist_delete(qclist);
01142     cpl_free(nod_pos);
01143     cpl_imagelist_delete(nodded);
01144     cpl_bivector_delete(offsets_est);
01145     cpl_bivector_delete(objs);
01146     cpl_vector_unwrap((cpl_vector*)sigmas);
01147 
01148     return combined;
01149 }
01150 
01151 /*----------------------------------------------------------------------------*/
01174 /*----------------------------------------------------------------------------*/
01175 cpl_imagelist * visir_load_hcycle(const irplib_framelist * rawframes, int pos)
01176 {
01177     return visir_load_imagelist(rawframes, pos, CPL_FALSE);
01178 }
01179 
01180 /*----------------------------------------------------------------------------*/
01191 /*----------------------------------------------------------------------------*/
01192 cpl_error_code visir_image_reject_hot(cpl_image * self, const char * bpmfile)
01193 {
01194 
01195     cpl_image  * im_bpm = NULL;
01196     cpl_mask   * bpm = NULL;
01197     const int upper = VISIR_HCYCLE_BPM_THRESHOLD;
01198 
01199 
01200     skip_if (0);
01201 
01202     skip_if (self == NULL);
01203 
01204     if (bpmfile == NULL) {
01205         bpm = cpl_mask_threshold_image_create(self, upper, DBL_MAX);
01206         skip_if (0);
01207     } else {
01208 
01209         /* The bpm is provided by the user */
01210         cpl_msg_info(cpl_func, "Clean user specified bad pixels");
01211         /* Load the bad pixel image */
01212         im_bpm = cpl_image_load(bpmfile, CPL_TYPE_INT, 0, 0);
01213         any_if ("Could not load the bad pixel map %s",
01214                 bpmfile ? bpmfile : "<NULL>");
01215         /* Convert the map from integer to binary */
01216         bpm = cpl_mask_threshold_image_create(im_bpm, -0.5, 0.5);
01217         skip_if (0);
01218         cpl_image_delete(im_bpm);
01219         im_bpm = NULL;
01220 
01221         skip_if (cpl_mask_not(bpm));
01222     }
01223 
01224     skip_if (cpl_image_reject_from_mask(self, bpm));
01225 
01226     end_skip;
01227 
01228     cpl_image_delete(im_bpm);
01229     cpl_mask_delete(bpm);
01230 
01231     return cpl_error_get_code();
01232 
01233 }
01234 
01235 
01236 /*----------------------------------------------------------------------------*/
01243 /*----------------------------------------------------------------------------*/
01244 cpl_imagelist * visir_imagelist_load_last(const irplib_framelist * rawframes)
01245 {
01246     cpl_imagelist * self = NULL;
01247     int naxis3;
01248 
01249     /* Verify that NAXIS3 is the same in all files */
01250     skip_if(irplib_framelist_contains(rawframes, VISIR_PFITS_INT_NAXIS3,
01251                                       CPL_TYPE_INT, CPL_TRUE, 0.0));
01252 
01253     naxis3 = visir_pfits_get_naxis3(irplib_framelist_get_propertylist_const(
01254                                                                       rawframes,
01255                                                                       0));
01256 
01257     /* Load the image set */
01258     self = irplib_imagelist_load_framelist(rawframes, CPL_TYPE_FLOAT, naxis3-1,
01259                                            0);
01260 
01261     skip_if (self == NULL);
01262 
01263     end_skip;
01264 
01265     return self;
01266 
01267 }
01268 
01269 
01270 /*----------------------------------------------------------------------------*/
01280 /*----------------------------------------------------------------------------*/
01281 cpl_imagelist * visir_load_imagelist(const irplib_framelist * rawframes,
01282                                      int pos, cpl_boolean is_interm)
01283 {
01284     cpl_imagelist    * self = NULL;
01285     cpl_image        * image = NULL;
01286     const char       * file
01287         = cpl_frame_get_filename(irplib_framelist_get_const(rawframes, pos));
01288     int                naxis3, nchop;
01289     visir_cube_type    cube_type;
01290     const cpl_error_code code = visir_get_type(rawframes, pos, &cube_type,
01291                                                &naxis3, &nchop);
01292     int            plane_step;
01293     int            nsize;
01294     int            iplane;
01295     int            i;
01296 
01297     /* Check the error code */
01298     skip_if (code);
01299     bug_if (file == NULL);
01300 
01301     if (cube_type == VISIR_CUBE1) {
01302         /* All INTERM frames are in the first part of the cube */
01303         iplane = is_interm ? 0 : nchop;
01304         /* - followed by a single Half-cycle image */
01305         nsize  = is_interm ? nchop : 1;
01306         plane_step = 1;
01307     } else if (naxis3 == 1) {
01308         iplane = 0;
01309         nsize  = 1;
01310         plane_step = 1;
01311     } else {
01312         /* Each INTERM frame follows the Half-cycle frame */
01313         iplane = is_interm ? 1 : 0;
01314         nsize  = nchop;
01315         plane_step = 2;
01316     }
01317 
01318     self = cpl_imagelist_new();
01319 
01320     for (i=0 ; i < nsize; i++, iplane += plane_step) {
01321 
01322         image = cpl_image_load(file, CPL_TYPE_FLOAT, iplane, 0);
01323         skip_if (image == NULL);
01324 
01325         skip_if (!is_interm && visir_offset_hcycle(image));
01326 
01327         skip_if (cpl_imagelist_set(self, image, i));
01328 
01329         image = NULL;
01330     }
01331 
01332     skip_if (i < nsize);
01333 
01334     end_skip;
01335 
01336     if (cpl_error_get_code()) {
01337         if (file != NULL) cpl_msg_warning(cpl_func, "Could not load the %s "
01338                                           "frame(s) from: %s",
01339                                           is_interm ? "INTERM" : "Half-Cycle",
01340                                           file);
01341         cpl_image_delete(image);
01342         cpl_imagelist_delete(self);
01343         self = NULL;
01344     }
01345 
01346     return self;
01347 }
01348 
01349 
01352 /*----------------------------------------------------------------------------*/
01376 /*----------------------------------------------------------------------------*/
01377 static cpl_imagelist * visir_load_intermint(const irplib_framelist * rawframes,
01378                                             int pos)
01379 {
01380     return visir_load_imagelist(rawframes, pos, CPL_TRUE);
01381 
01382 }
01383 
01384 /*----------------------------------------------------------------------------*/
01393 /*----------------------------------------------------------------------------*/
01394 static cpl_image * visir_load_average(const char * file,
01395                                       const cpl_propertylist * plist)
01396 {
01397     cpl_errorstate cleanstate = cpl_errorstate_get();
01398     cpl_image        * self = NULL;
01399     int                nchop, naxis3;
01400 
01401 
01402     skip_if (0);
01403     skip_if (file   == NULL);
01404     skip_if (plist == NULL);
01405 
01406     naxis3 = visir_pfits_get_naxis3(plist);
01407     nchop = visir_pfits_get_chop_ncycles(plist);
01408 
01409     skip_if (0);
01410 
01411     if (nchop == 0 && naxis3 == 1) {
01412         self = cpl_image_load(file, CPL_TYPE_FLOAT, 0, 0);
01413     } else {
01414         const char   * sval;
01415         /* If nchop == 1 (and naxis3 == 3) the data unit is both a valid CUBE1
01416            and a valid CUBE2; Set plane_offset as if the frame type is CUBE2 */
01417         const int      plane_offset = (naxis3 == 2 * nchop + 1) ? 2 : 3;
01418 
01419 
01420         error_if (nchop <= 0, CPL_ERROR_BAD_FILE_FORMAT, "CHOP NCYCLES in %s "
01421                   "is non-positive (and NAXIS3=%d): %d", file, naxis3, nchop);
01422 
01423         error_if (plane_offset == 3 && naxis3 != nchop+2,
01424                   CPL_ERROR_BAD_FILE_FORMAT, "NAXIS3=%d and CHOP NCYCLES=%d "
01425                   "in %s is not a valid VISIR INTERM+Half-Cycle format", naxis3,
01426                   nchop, file);
01427 
01428         if (plane_offset == 3 && nchop > 1)
01429             cpl_msg_debug(cpl_func, "%s has %d INTERM-frames and one Half-"
01430                           "Cycle frame (old CUBE1-format)", file, nchop);
01431 
01432         /* Check the data format */
01433         sval = visir_pfits_get_frame_type(plist);
01434         if (sval == NULL) {
01435             /* Has warned about missing frame type card */
01436             visir_error_reset("Could not get FITS key");
01437             /* Don't know whether or not to expect CUBE1 or CUBE2 */
01438         } else if (strlen(sval) == 0) {
01439             /* Don't know whether or not to expect CUBE1 or CUBE2 */
01440         } else if (plane_offset == 3) {
01441             if (strcmp(sval, "CUBE2")==0)
01442                 cpl_msg_error(cpl_func, "%s has FRAM TYPE = CUBE2, but NAXIS3="
01443                                 "%d and CHOP NCYCLES=%d imply a CUBE1. Assuming"
01444                                 " the frame type is really CUBE1",  file,
01445                                 naxis3, nchop);
01446         } else if (nchop > 1) {
01447             /* if nchop == 1 format can be CUBE1 or CUBE2 */
01448             if (strcmp(sval, "CUBE1")==0)
01449                 cpl_msg_error(cpl_func, "%s has FRAM TYPE = CUBE1, but NAXIS3="
01450                                 "%d and CHOP NCYCLES=%d imply a CUBE2. Assuming"
01451                                 "the frame type is really CUBE2",  file,
01452                                 naxis3, nchop);
01453         } 
01454 
01455         /* Load last INTERM frame */
01456         self = cpl_image_load(file, CPL_TYPE_FLOAT, naxis3-plane_offset, 0);
01457 
01458     }
01459 
01460     skip_if (0);
01461 
01462     end_skip;
01463 
01464     if (cpl_error_get_code()) {
01465         cpl_msg_warning(cpl_func, "Could not load the last INTERM frame from: "
01466                         "%s", file ? file : "<NULL>");
01467         cpl_image_delete(self);
01468         self = NULL;
01469     }
01470 
01471     return self;
01472 }
01473 
01474 /*----------------------------------------------------------------------------*/
01497 /*----------------------------------------------------------------------------*/
01498 static cpl_error_code visir_imagelist_unpack_interm(cpl_imagelist * self) 
01499 {
01500     cpl_image * iprev;
01501     cpl_image * image;
01502     const int   n = cpl_imagelist_get_size(self);
01503     int         i;
01504 
01505 
01506     skip_if (0);
01507 
01508     if (n == 1) return CPL_ERROR_NONE;
01509 
01510     iprev = cpl_imagelist_get(self, n - 1);
01511 
01512     skip_if (0);
01513 
01514     skip_if (cpl_image_multiply_scalar(iprev, n));
01515 
01516     /* Loop on the images - with first and last iteration peeled off */
01517     for (i = n-1 ; i > 1 ; i--, iprev = image) {
01518         image = cpl_imagelist_get(self, i-1);
01519 
01520         skip_if (0);
01521 
01522         skip_if (cpl_image_multiply_scalar(image, i));
01523 
01524         skip_if (cpl_image_subtract(iprev, image));
01525 
01526     }
01527 
01528     image = cpl_imagelist_get(self, 0);
01529 
01530     skip_if (0);
01531 
01532     skip_if (cpl_image_subtract(iprev, image));
01533 
01534     end_skip;
01535 
01536     return cpl_error_get_code();
01537 }
01538 
01539 /*----------------------------------------------------------------------------*/
01552 /*----------------------------------------------------------------------------*/
01553 static cpl_error_code visir_rem_glitch(cpl_image * glitchy) 
01554 {
01555     cpl_image * med_filt = NULL;
01556     cpl_mask  * bpm = NULL;
01557     cpl_mask  * kernel = cpl_mask_new(3, 3);
01558     double      mean, stdev;
01559     double      low_thresh, high_thresh;
01560     const int   nx = cpl_image_get_size_x(glitchy);
01561     const int   ny = cpl_image_get_size_y(glitchy);
01562     int         i;
01563 
01564     /* Some heuristic constants */
01565     double          factor1 = 3.0;
01566     double          factor2 = 10.0;
01567     const int       niterations = 5;
01568     const double    median_corr = 1.5;
01569 
01570     bug_if (0);
01571 
01572     /* Create the filtering kernel */
01573     bug_if(cpl_mask_not(kernel));
01574     
01575     /* Apply a 3x3 median filter to the input image  */
01576     med_filt = cpl_image_new(cpl_image_get_size_x(glitchy),
01577                              cpl_image_get_size_y(glitchy),
01578                              cpl_image_get_type(glitchy));
01579     bug_if(med_filt == NULL);
01580     bug_if(cpl_image_filter_mask(med_filt, glitchy, kernel, CPL_FILTER_MEDIAN,
01581                                  CPL_BORDER_FILTER));
01582     cpl_mask_delete(kernel);
01583     kernel = NULL;
01584 
01585     /* Noise is glitchy - med_filt */
01586     skip_if (cpl_image_subtract(glitchy, med_filt));
01587 
01588     /* niterations iterations */
01589     for (i=0 ; i < niterations ; i++) {
01590         /* Compute mean and stdev */
01591         mean = cpl_image_get_mean(glitchy);
01592         stdev = cpl_image_get_stdev(glitchy);
01593         
01594         skip_if (0);
01595 
01596         /* Set the thresholds */
01597         low_thresh  = mean - factor1 * stdev;
01598         high_thresh = mean + factor1 * stdev;
01599 
01600         /* Identify where mean-factor1*stdev < glitchy < mean+factor1*stdev */
01601         bpm = cpl_mask_threshold_image_create(glitchy,low_thresh,high_thresh);
01602         skip_if (cpl_mask_not(bpm));
01603         skip_if (cpl_image_reject_from_mask(glitchy, bpm));
01604         cpl_mask_delete(bpm);
01605         bpm = NULL;
01606 
01607         /* Test the number of bad pixels */
01608         skip_if (cpl_image_count_rejected(glitchy) == nx*ny);
01609     }
01610 
01611     /* Last iteration */
01612     /* Compute mean and stdev */
01613     mean = cpl_image_get_mean(glitchy);
01614     stdev = cpl_image_get_stdev(glitchy) * median_corr;
01615 
01616     skip_if (0);
01617 
01618     low_thresh  = mean - factor2 * stdev;
01619     high_thresh = mean + factor2 * stdev;
01620 
01621     bpm = cpl_mask_threshold_image_create(glitchy, low_thresh, high_thresh);
01622     skip_if (cpl_mask_not(bpm));
01623     skip_if (cpl_image_reject_from_mask(glitchy, bpm));
01624     cpl_mask_delete(bpm);
01625     bpm = NULL;
01626 
01627     /* Test the number of bad pixels */
01628     skip_if (cpl_image_count_rejected(glitchy) == nx*ny);
01629     
01630     /* Set the bad pixels to 0 */
01631     skip_if (cpl_image_fill_rejected(glitchy, 0.0));
01632     skip_if (cpl_image_accept_all(glitchy));
01633 
01634     /* Reconstruct the corrected image */
01635     skip_if (cpl_image_add(glitchy, med_filt));
01636 
01637     end_skip;
01638 
01639     cpl_image_delete(med_filt);
01640     cpl_mask_delete(bpm);
01641     cpl_mask_delete(kernel);
01642     
01643     return cpl_error_get_code();
01644 }
01645 
01646 /*----------------------------------------------------------------------------*/
01657 /*----------------------------------------------------------------------------*/
01658 static cpl_error_code visir_rem_bad_images(cpl_imagelist * in) 
01659 {
01660     cpl_vector * medians = NULL;
01661     cpl_vector * stdevs = NULL;
01662     cpl_vector * selection = NULL;
01663     double       mean_medians, mean_stdevs, stdev_medians, stdev_stdevs;
01664     const double threshold = 3;
01665     const int    nima = cpl_imagelist_get_size(in);
01666     int          i;
01667 
01668 
01669     /* This will catch a NULL input */
01670     skip_if (0);
01671 
01672     if (nima <= 3) return CPL_ERROR_NONE;
01673     
01674     /* Create medians and stdevs arrays */
01675     medians = cpl_vector_new(nima);
01676     stdevs = cpl_vector_new(nima);
01677 
01678     /* Compute the statistics */
01679     for (i=0 ; i < nima ; i++) {
01680         cpl_stats * stats = cpl_stats_new_from_image(cpl_imagelist_get(in, i),
01681                                             CPL_STATS_STDEV | CPL_STATS_MEDIAN);
01682 
01683         cpl_vector_set(medians, i, cpl_stats_get_median(stats));
01684         cpl_vector_set(stdevs,  i, cpl_stats_get_stdev(stats));
01685         cpl_stats_delete(stats); /* :-( */
01686     }
01687 
01688     skip_if( 0);
01689 
01690     /* Get the stats on these arrays */
01691     mean_medians  = cpl_vector_get_mean(medians);
01692     stdev_medians = cpl_vector_get_stdev(medians);
01693     mean_stdevs   = cpl_vector_get_mean(stdevs);
01694     stdev_stdevs  = cpl_vector_get_stdev(stdevs);
01695 
01696     skip_if (cpl_vector_subtract_scalar(medians, mean_medians));
01697     skip_if (cpl_vector_subtract_scalar(stdevs,  mean_stdevs));
01698 
01699     stdev_medians *= threshold;
01700     stdev_stdevs  *= threshold;
01701 
01702     /* Create the selection vector */
01703     selection = cpl_vector_new(nima);
01704     skip_if( cpl_vector_fill(selection, 0)); /* Flag all as good */
01705     for (i=0 ; i < nima ; i++) {
01706         if (fabs(cpl_vector_get(medians, i)) <= stdev_medians &&
01707             fabs(cpl_vector_get(stdevs,  i)) <= stdev_stdevs) continue;
01708 
01709         cpl_vector_set(selection, i, -1);
01710         cpl_msg_info(cpl_func, "Image %d of %d rejected: median=%g, stdev=%g",
01711                      i+1, nima, stdev_medians, stdev_stdevs);
01712     }
01713 
01714     /* Purge the bad images in the images set */
01715     cpl_imagelist_erase(in, selection);
01716 
01717     end_skip;
01718 
01719     cpl_vector_delete(medians);
01720     cpl_vector_delete(stdevs);
01721     
01722     cpl_vector_delete(selection);
01723 
01724     return CPL_ERROR_NONE;
01725 
01726 }
01727 
01728 /*----------------------------------------------------------------------------*/
01737 /*----------------------------------------------------------------------------*/
01738 static cpl_error_code visir_offset_hcycle(cpl_image * hcycle) 
01739 {
01740     double minval;
01741 
01742 
01743     skip_if (0);
01744 
01745     skip_if (cpl_image_add_scalar(hcycle, VISIR_HCYCLE_OFFSET));
01746 
01747     minval = cpl_image_get_min(hcycle);
01748 
01749     /* It seems that the offset really is VISIR_HCYCLE_OFFSET-1, warn if not */
01750     if (minval < 1) cpl_msg_warning(cpl_func, "HCycle pixel minval: %g", minval);
01751 
01752     end_skip;
01753 
01754     return CPL_ERROR_NONE;
01755 }
01756 
01757 /*----------------------------------------------------------------------------*/
01769 /*----------------------------------------------------------------------------*/
01770 static
01771 cpl_image ** visir_img_collapse_beam_four(cpl_propertylist       * qclist,
01772                                           const cpl_image        * self,
01773                                           const cpl_image        * inverse,
01774                                           double                   eccmax,
01775                                           double                   pthrow,
01776                                           const cpl_propertylist * plist)
01777 {
01778 
01779     cpl_image    ** combined = NULL;
01780     const int       nx = cpl_image_get_size_x(self);
01781     const int       ny = cpl_image_get_size_y(self);
01782     const cpl_type  type = cpl_image_get_type(self);
01783     cpl_imagelist * list4 = cpl_imagelist_new();
01784     cpl_image     * swrap = type == CPL_TYPE_DOUBLE
01785         ? cpl_image_wrap_double(nx, ny, cpl_image_get_data((cpl_image*)self))
01786         : cpl_image_wrap_float(nx, ny, cpl_image_get_data((cpl_image*)self));
01787     cpl_image     * iwrap = type == CPL_TYPE_DOUBLE
01788         ? cpl_image_wrap_double(nx, ny, cpl_image_get_data((cpl_image*)inverse))
01789         : cpl_image_wrap_float(nx, ny, cpl_image_get_data((cpl_image*)inverse));
01790     cpl_bivector  * offs = cpl_bivector_new(4);
01791     double * x4 = cpl_bivector_get_x_data(offs);
01792     double * y4 = cpl_bivector_get_y_data(offs);
01793     double pos_x, pos_y;
01794     int i;
01795 
01796     skip_if (0);
01797 
01798     skip_if(plist  == NULL);
01799 
01800     skip_if(visir_img_find_beam_four(qclist, self, inverse, eccmax, pthrow,
01801                                      x4, y4));
01802 
01803     /* Combine the four beams */
01804     for (i = 1; i < 4; i++) {
01805         x4[i] = x4[0] - x4[i];
01806         y4[i] = y4[0] - y4[i];
01807     }
01808 
01809     bug_if (cpl_propertylist_append_double(qclist, "ESO QC ONEBEAM XPOS",
01810                                            x4[0]));
01811     bug_if (cpl_propertylist_append_double(qclist, "ESO QC ONEBEAM YPOS",
01812                                            y4[0]));
01813     x4[0] = y4[0] = 0.0;
01814 
01815     bug_if(cpl_imagelist_set(list4, (cpl_image*)self,    0));
01816     bug_if(cpl_imagelist_set(list4, swrap,   1));
01817     bug_if(cpl_imagelist_set(list4, (cpl_image*)inverse, 2));
01818     bug_if(cpl_imagelist_set(list4, iwrap,   3));
01819 
01820     combined = cpl_geom_img_offset_saa(list4, offs, CPL_KERNEL_DEFAULT, 0, 0,
01821                                        CPL_GEOM_FIRST, &pos_x, &pos_y);
01822 
01823     skip_if(combined == NULL);
01824 
01825     end_skip;
01826 
01827     cpl_bivector_delete(offs);
01828     for (i = cpl_imagelist_get_size(list4) - 1; i >= 0; i--) {
01829         (void)cpl_imagelist_unset(list4, i);
01830     }
01831     cpl_imagelist_delete(list4);
01832     (void)cpl_image_unwrap(swrap);
01833     (void)cpl_image_unwrap(iwrap);
01834     if (cpl_error_get_code() && combined != NULL) {
01835         cpl_image_delete(combined[0]);
01836         cpl_image_delete(combined[1]);
01837         cpl_free(combined);
01838     }
01839 
01840     return combined;
01841 }
01842 
01843 /*----------------------------------------------------------------------------*/
01855 /*----------------------------------------------------------------------------*/
01856 static
01857 cpl_error_code visir_img_find_beam_four(cpl_propertylist * qclist,
01858                                         const cpl_image  * self,
01859                                         const cpl_image  * inverse,
01860                                         double             eccmax,
01861                                         double             pthrow,
01862                                         double             x4[],
01863                                         double             y4[])
01864 {
01865 
01866     cpl_errorstate  cleanstate = cpl_errorstate_get();
01867     cpl_apertures * appos = NULL;
01868     cpl_apertures * apneg = NULL;
01869     const double    psigmas[] = {2.0, 1.0, 0.5};
01870     const int       nsigmas = sizeof(psigmas)/sizeof(double);
01871     int             isigma;
01872     int             iappos2[] = {1, 2};
01873     int             iapneg2[] = {1, 2};
01874 
01875     bug_if(0);
01876     skip_if(self   == NULL);
01877     skip_if(qclist == NULL);
01878     skip_if(pthrow <= 0.0);
01879     skip_if(x4     == NULL);
01880     skip_if(y4     == NULL);
01881 
01882     cpl_msg_info(cpl_func, "Detecting the 4-beam object with %g pixel throw "
01883                  "using %d sigma-levels ranging from %g down to %g", pthrow,
01884                  nsigmas, psigmas[0], psigmas[nsigmas-1]);
01885 
01886     bug_if(0);
01887     for (isigma = 0; isigma < nsigmas; isigma++) {
01888         int npos = 0;
01889         int nneg = 0;
01890 
01891         /* Detect the (two) POSITIVE objects */
01892         cpl_apertures_delete(appos);
01893         appos = cpl_apertures_extract_sigma(self, psigmas[isigma]);
01894 
01895         if (appos != NULL) {
01896             npos = cpl_apertures_get_size(appos);
01897         }
01898 
01899 
01900         /* Detect the (two) NEGATIVE objects */
01901         cpl_apertures_delete(apneg);
01902         apneg = cpl_apertures_extract_sigma(inverse, psigmas[isigma]);
01903         if (apneg != NULL) {
01904             nneg = cpl_apertures_get_size(apneg);
01905         }
01906 
01907         cpl_msg_info(cpl_func, "Found %d positive (need 2) and %d negative "
01908                      "(need 2) object(s) at sigma=%g (%d of %d)", npos, nneg,
01909                      psigmas[isigma], 1+isigma, nsigmas);
01910 
01911         if (eccmax > 0.0) {
01912             int ipos1;
01913             double eccbest = eccmax;
01914             double eccmin  = DBL_MAX;
01915             double fluxbest = 0.0;
01916             double fluxecc = DBL_MAX;
01917             cpl_boolean is_first = CPL_TRUE;
01918 
01919 #ifdef _OPENMP
01920 #pragma omp parallel for private(ipos1)
01921 #endif
01922             for (ipos1 = 2; ipos1 <= npos; ipos1++) {
01923                 int ipos2, ineg1, ineg2;
01924                 for (ipos2 = 1; ipos2 < ipos1; ipos2++) {
01925                     for (ineg1 = 2; ineg1 <= nneg; ineg1++) {
01926                         for (ineg2 = 1; ineg2 < ineg1; ineg2++) {
01927                             cpl_boolean swappos, swapneg;
01928                             const double ecc
01929                                 = visir_img_check_box(appos, ipos1, ipos2,
01930                                                       apneg, ineg1, ineg2,
01931                                                       pthrow, &swappos,
01932                                                       &swapneg);
01933 
01934                             const double flux
01935                                 = cpl_apertures_get_flux(appos, ipos1)
01936                                 + cpl_apertures_get_flux(appos, ipos2)
01937                                 + cpl_apertures_get_flux(apneg, ineg1)
01938                                 + cpl_apertures_get_flux(apneg, ineg2);
01939 
01940 
01941                             if (ecc < 0.0 || flux <= 0.0 ||
01942                                 !cpl_errorstate_is_equal(cleanstate)) {
01943                                 irplib_error_recover(cleanstate, "Invalid 4-"
01944                                                      "object (%d & %d of %d, "
01945                                                      "%d & %d of %d)",
01946                                                      ipos2, ipos1, npos,
01947                                                      ineg2, ineg1, nneg);
01948                                 continue;
01949                             }
01950 
01951 #ifdef _OPENMP
01952 #pragma omp critical(visir_img_find_beam_four_min)
01953 #endif
01954                             if (ecc < eccmin)
01955                             {
01956                                 eccmin = ecc;
01957                                 fluxecc = flux;
01958                             }
01959 
01960                             if (eccmax <= ecc) continue;
01961 
01962 #ifdef _OPENMP
01963 #pragma omp critical(visir_img_find_beam_four_ok)
01964 #endif
01965                             if (is_first || ecc * fluxbest < eccbest * flux)
01966                                 {
01967                                 if (is_first) {
01968                                     is_first = CPL_FALSE;
01969                                     cpl_msg_info(cpl_func, "Found 4 object "
01970                                                  "positions with throw-"
01971                                                  "scaled eccentricity %g "
01972                                                  "and flux %g", ecc, flux);
01973                                 } else {
01974                                     cpl_msg_info(cpl_func, "Found 4 object "
01975                                                  "positions with throw-"
01976                                                  "scaled eccentricity %g "
01977                                                  "< %g and/or flux %g > %g",
01978                                                  ecc, eccbest, flux, fluxbest);
01979                                 }
01980                                 eccbest = ecc;
01981                                 fluxbest = flux;
01982                                 iappos2[0] = swappos ? ipos2 : ipos1;
01983                                 iappos2[1] = swappos ? ipos1 : ipos2;
01984                                 iapneg2[0] = swapneg ? ineg2 : ineg1;
01985                                 iapneg2[1] = swapneg ? ineg1 : ineg2;
01986                             }
01987                         }
01988                     }
01989                 }
01990             }
01991             if (eccbest < eccmax) {
01992                 bug_if(cpl_propertylist_append_double(qclist, "ESO QC ONEBEAM "
01993                                                       "ECCENTRICITY", eccbest));
01994 
01995                 break;
01996             }
01997             if (eccmin < DBL_MAX) {
01998                 cpl_msg_info(cpl_func, "Found 4 sigma-%g object positions with "
01999                              "too large throw-scaled eccentricity %g >= %g and "
02000                              "flux %g", psigmas[isigma], eccmin, eccmax,
02001                              fluxecc);
02002             }
02003         } else if (npos >= 2 && nneg >= 2) {
02004             cpl_apertures_sort_by_flux(appos);
02005             cpl_apertures_sort_by_flux(apneg);
02006             break;
02007         }
02008 
02009         if (isigma + 1 < nsigmas) {
02010             irplib_error_recover(cleanstate, "4-Beam positions not found among "
02011                                  "%d postive and %d negative object(s) at "
02012                                  "sigma=%g, (%d of %d)", npos, nneg,
02013                                  psigmas[isigma], 1+isigma, nsigmas);
02014         }
02015     }
02016 
02017     error_if (isigma == nsigmas, CPL_ERROR_DATA_NOT_FOUND,
02018               "4-Beam positions not found w. %d sigma(s) down to %g",
02019               nsigmas, psigmas[nsigmas - 1]);
02020 
02021     if (cpl_msg_get_level() == CPL_MSG_DEBUG) {
02022         cpl_apertures_dump(appos, stdout);
02023         cpl_apertures_dump(apneg, stdout);
02024     }
02025 
02026     x4[0] = cpl_apertures_get_centroid_x(appos, iappos2[0]);
02027     y4[0] = cpl_apertures_get_centroid_y(appos, iappos2[0]);
02028     x4[1] = cpl_apertures_get_centroid_x(appos, iappos2[1]);
02029     y4[1] = cpl_apertures_get_centroid_y(appos, iappos2[1]);
02030 
02031     x4[2] = cpl_apertures_get_centroid_x(apneg, iapneg2[0]);
02032     y4[2] = cpl_apertures_get_centroid_y(apneg, iapneg2[0]);
02033     x4[3] = cpl_apertures_get_centroid_x(apneg, iapneg2[1]);
02034     y4[3] = cpl_apertures_get_centroid_y(apneg, iapneg2[1]);
02035 
02036     cpl_msg_info(cpl_func, "Centroid of positive object 1 [pixel]: %g %g",
02037                  x4[0], y4[0]);
02038     cpl_msg_info(cpl_func, "Centroid of positive object 2 [pixel]: %g %g",
02039                  x4[1], y4[1]);
02040 
02041     cpl_msg_info(cpl_func, "Centroid of negative object 1 [pixel]: %g %g",
02042                  x4[2], y4[2]);
02043     cpl_msg_info(cpl_func, "Centroid of negative object 2 [pixel]: %g %g",
02044                  x4[3], y4[3]);
02045 
02046     cpl_msg_info(cpl_func, "Expected object distance (chop throw) [pixel]: %g",
02047                  pthrow);
02048     cpl_msg_info(cpl_func, "Object Pos -> Pos x/y-distance [pixel]: %g %g",
02049                  x4[1] - x4[0], y4[1] - y4[0]);
02050     cpl_msg_info(cpl_func, "Object Neg -> Neg x/y-distance [pixel]: %g %g",
02051                  x4[3] - x4[2], y4[3] - y4[2]);
02052     cpl_msg_info(cpl_func, "Object Pos -> Pos angle [degrees]: %g",
02053                  atan2(y4[1] - y4[0], x4[1] - x4[0]) * CPL_MATH_DEG_RAD);
02054     cpl_msg_info(cpl_func, "Object Neg -> Neg angle [degrees]: %g",
02055                  atan2(y4[3] - y4[2], x4[3] - x4[2]) * CPL_MATH_DEG_RAD);
02056 
02057     end_skip;
02058 
02059     cpl_apertures_delete(appos);
02060     cpl_apertures_delete(apneg);
02061 
02062     return cpl_error_get_code();
02063 }
02064 
02065 /*----------------------------------------------------------------------------*/
02077 /*----------------------------------------------------------------------------*/
02078 static
02079 cpl_image ** visir_img_collapse_beam_three(cpl_propertylist       * qclist,
02080                                            const cpl_image        * self,
02081                                            const cpl_image        * inverse,
02082                                            double                   eccmax,
02083                                            double                   pthrow,
02084                                            const cpl_propertylist * plist)
02085 {
02086 
02087     cpl_image    ** combined = NULL;
02088     const int       nx = cpl_image_get_size_x(self);
02089     const int       ny = cpl_image_get_size_y(self);
02090     const cpl_type  type = cpl_image_get_type(self);
02091     cpl_imagelist * list3 = cpl_imagelist_new();
02092     cpl_image     * iwrap = type == CPL_TYPE_DOUBLE
02093         ? cpl_image_wrap_double(nx, ny, cpl_image_get_data((cpl_image*)inverse))
02094         : cpl_image_wrap_float(nx, ny, cpl_image_get_data((cpl_image*)inverse));
02095     cpl_bivector  * offs = cpl_bivector_new(3);
02096     double * x3 = cpl_bivector_get_x_data(offs);
02097     double * y3 = cpl_bivector_get_y_data(offs);
02098     double pos_x, pos_y;
02099     int i;
02100 
02101     skip_if (0);
02102 
02103     skip_if(plist  == NULL);
02104 
02105     skip_if(visir_img_find_beam_three(qclist, self, inverse, eccmax, pthrow,
02106                                       x3, y3));
02107 
02108     /* Combine the four beams */
02109     for (i = 1; i < 3; i++) {
02110         x3[i] = x3[0] - x3[i];
02111         y3[i] = y3[0] - y3[i];
02112     }
02113     bug_if (cpl_propertylist_append_double(qclist, "ESO QC ONEBEAM XPOS",
02114                                            x3[0]));
02115     bug_if (cpl_propertylist_append_double(qclist, "ESO QC ONEBEAM YPOS",
02116                                            y3[0]));
02117 
02118     x3[0] = y3[0] = 0.0;
02119 
02120     bug_if(cpl_imagelist_set(list3, (cpl_image*)self,    0));
02121     bug_if(cpl_imagelist_set(list3, (cpl_image*)inverse, 1));
02122     bug_if(cpl_imagelist_set(list3, iwrap,   2));
02123 
02124     combined = cpl_geom_img_offset_saa(list3, offs, CPL_KERNEL_DEFAULT, 0, 0,
02125                                        CPL_GEOM_FIRST, &pos_x, &pos_y);
02126 
02127     skip_if(combined == NULL);
02128 
02129     end_skip;
02130 
02131     cpl_bivector_delete(offs);
02132     for (i = cpl_imagelist_get_size(list3) - 1; i >= 0; i--) {
02133         (void)cpl_imagelist_unset(list3, i);
02134     }
02135     cpl_imagelist_delete(list3);
02136     (void)cpl_image_unwrap(iwrap);
02137     if (cpl_error_get_code() && combined != NULL) {
02138         cpl_image_delete(combined[0]);
02139         cpl_image_delete(combined[1]);
02140         cpl_free(combined);
02141     }
02142 
02143     return combined;
02144 }
02145 
02146 
02147 /*----------------------------------------------------------------------------*/
02160 /*----------------------------------------------------------------------------*/
02161 static
02162 cpl_error_code visir_img_find_beam_three(cpl_propertylist * qclist,
02163                                         const cpl_image  * self,
02164                                         const cpl_image  * inverse,
02165                                         double             eccmax,
02166                                         double             pthrow,
02167                                         double             x3[],
02168                                         double             y3[])
02169 {
02170 
02171     cpl_errorstate  cleanstate = cpl_errorstate_get();
02172     cpl_apertures * appos = NULL;
02173     cpl_apertures * apneg = NULL;
02174     const double    psigmas[] = {2.0, 1.0, 0.5};
02175     const int       nsigmas = sizeof(psigmas)/sizeof(double);
02176     int             isigma;
02177     int             iappos [] = {1};
02178     int             iapneg2[] = {1, 2};
02179 
02180     bug_if(0);
02181     skip_if(self   == NULL);
02182     skip_if(qclist == NULL);
02183     skip_if(pthrow <= 0.0);
02184     skip_if(eccmax <  0.0);
02185     skip_if(x3     == NULL);
02186     skip_if(y3     == NULL);
02187 
02188 
02189     cpl_msg_info(cpl_func, "Detecting the 3-beam object with %g pixel throw "
02190                  "using %d sigma-levels ranging from %g down to %g", pthrow,
02191                  nsigmas, psigmas[0], psigmas[nsigmas-1]);
02192 
02193     bug_if(0);
02194     for (isigma = 0; isigma < nsigmas; isigma++) {
02195         int npos = 0;
02196         int nneg = 0;
02197 
02198         /* Detect the (single) POSITIVE object */
02199         cpl_apertures_delete(appos);
02200         appos = cpl_apertures_extract_sigma(self, psigmas[isigma]);
02201 
02202         if (appos != NULL) {
02203             npos = cpl_apertures_get_size(appos);
02204         }
02205 
02206 
02207         /* Detect the (two) NEGATIVE objects */
02208         cpl_apertures_delete(apneg);
02209         apneg = cpl_apertures_extract_sigma(inverse, psigmas[isigma]);
02210         if (apneg != NULL) {
02211             nneg = cpl_apertures_get_size(apneg);
02212         }
02213 
02214         cpl_msg_info(cpl_func, "Found %d positive (need 1) and %d negative "
02215                      "(need 2) object(s) at sigma=%g (%d of %d)", npos, nneg,
02216                      psigmas[isigma], 1+isigma, nsigmas);
02217 
02218         if (eccmax > 0.0) {
02219             int ipos;
02220             double eccbest = eccmax;
02221             double eccmin  = DBL_MAX;
02222             double fluxbest = 0.0;
02223             double fluxecc = DBL_MAX;
02224             cpl_boolean is_first = CPL_TRUE;
02225 
02226 #ifdef _OPENMP
02227 #pragma omp parallel for private(ipos)
02228 #endif
02229             for (ipos = 1; ipos <= npos; ipos++) {
02230                 int ineg1, ineg2;
02231                 for (ineg1 = 2; ineg1 <= nneg; ineg1++) {
02232                     for (ineg2 = 1; ineg2 < ineg1; ineg2++) {
02233                         cpl_boolean swapnegh, swapnegv;
02234                         const double ecch
02235                             = visir_img_check_align(appos, ipos, apneg, ineg1,
02236                                                     ineg2, pthrow, CPL_TRUE,
02237                                                     &swapnegh);
02238                         const double eccv
02239                             = visir_img_check_align(appos, ipos, apneg, ineg1,
02240                                                     ineg2, pthrow, CPL_FALSE,
02241                                                     &swapnegv);
02242                         const double ecc = ecch < eccv ? ecch : eccv;
02243                         const cpl_boolean swapneg = ecch < eccv
02244                             ? swapnegh : swapnegv;
02245 
02246                         const double flux
02247                             = cpl_apertures_get_flux(appos, ipos)
02248                             + cpl_apertures_get_flux(apneg, ineg1)
02249                             + cpl_apertures_get_flux(apneg, ineg2);
02250 
02251 
02252                         if (ecc < 0.0 || flux <= 0.0 ||
02253                             !cpl_errorstate_is_equal(cleanstate)) {
02254                             irplib_error_recover(cleanstate, "Invalid 3-"
02255                                                  "object (%d of %d, "
02256                                                  "%d & %d of %d)",
02257                                                  ipos, npos,
02258                                                  ineg2, ineg1, nneg);
02259                             continue;
02260                         }
02261 
02262 #ifdef _OPENMP
02263 #pragma omp critical(visir_img_collapse_beam_three_min)
02264 #endif
02265                         if (ecc < eccmin)
02266                         {
02267                             eccmin = ecc;
02268                             fluxecc = flux;
02269                         }
02270 
02271                         if (eccmax <= ecc) continue;
02272 
02273 #ifdef _OPENMP
02274 #pragma omp critical(visir_img_collapse_beam_three_ok)
02275 #endif
02276                         if (is_first || ecc * fluxbest < eccbest * flux)
02277                         {
02278                             if (is_first) {
02279                                 is_first = CPL_FALSE;
02280                                 cpl_msg_info(cpl_func, "Found 3 object posi"
02281                                              "tions with throw-scaled (ver"
02282                                              "tical/horizontal) eccentrici"
02283                                              "ty %g/%g and flux %g", eccv,
02284                                              ecch, flux);
02285                             } else {
02286                                 cpl_msg_info(cpl_func, "Found 3 object posi"
02287                                              "tions with throw-scaled (ver"
02288                                              "tical/horizontal) eccentrici"
02289                                              "ty %g/%g < %g and/or flux %g "
02290                                              "> %g", eccv, ecch, eccbest,
02291                                              flux, fluxbest);
02292                             }
02293                             eccbest = ecc;
02294                             fluxbest = flux;
02295                             iappos[0] = ipos;
02296                             iapneg2[0] = swapneg ? ineg2 : ineg1;
02297                             iapneg2[1] = swapneg ? ineg1 : ineg2;
02298                         }
02299                     }
02300                 }
02301             }
02302             if (eccbest < eccmax) {
02303                 bug_if(cpl_propertylist_append_double(qclist, "ESO QC ONEBEAM "
02304                                                       "ECCENTRICITY", eccbest));
02305                 break;
02306             }
02307             if (eccmin < DBL_MAX) {
02308                 cpl_msg_info(cpl_func, "Found 3 sigma-%g object positions with "
02309                              "too large throw-scaled eccentricity %g >= %g and "
02310                              "flux %g", psigmas[isigma], eccmin, eccmax,
02311                              fluxecc);
02312             }
02313         } else if (npos >= 1 && nneg >= 2) {
02314             cpl_apertures_sort_by_flux(appos);
02315             cpl_apertures_sort_by_flux(apneg);
02316             break;
02317         }
02318 
02319         if (isigma + 1 < nsigmas) {
02320             irplib_error_recover(cleanstate, "3-Beam positions not found among "
02321                                  "%d postive and %d negative object(s) at "
02322                                  "sigma=%g, (%d of %d)", npos, nneg,
02323                                  psigmas[isigma], 1+isigma, nsigmas);
02324         }
02325     }
02326 
02327     error_if (isigma == nsigmas, CPL_ERROR_DATA_NOT_FOUND,
02328               "3-Beam positions not found w. %d sigma(s) down to %g",
02329               nsigmas, psigmas[nsigmas - 1]);
02330 
02331     if (cpl_msg_get_level() == CPL_MSG_DEBUG) {
02332         cpl_apertures_dump(appos, stdout);
02333         cpl_apertures_dump(apneg, stdout);
02334     }
02335 
02336     x3[0] = cpl_apertures_get_centroid_x(appos, iappos[0]);
02337     y3[0] = cpl_apertures_get_centroid_y(appos, iappos[0]);
02338 
02339     x3[1] = cpl_apertures_get_centroid_x(apneg, iapneg2[0]);
02340     y3[1] = cpl_apertures_get_centroid_y(apneg, iapneg2[0]);
02341     x3[2] = cpl_apertures_get_centroid_x(apneg, iapneg2[1]);
02342     y3[2] = cpl_apertures_get_centroid_y(apneg, iapneg2[1]);
02343 
02344     cpl_msg_info(cpl_func, "Centroid of positive object [pixel]: %g %g",
02345                  x3[0], y3[0]);
02346 
02347     cpl_msg_info(cpl_func, "Centroid of negative object 1 [pixel]: %g %g",
02348                  x3[1], y3[1]);
02349     cpl_msg_info(cpl_func, "Centroid of negative object 2 [pixel]: %g %g",
02350                  x3[2], y3[2]);
02351 
02352     cpl_msg_info(cpl_func, "Expected object distance (chop throw) [pixel]: %g",
02353                  pthrow);
02354     cpl_msg_info(cpl_func, "Object Neg1 -> Pos x/y-distance [pixel]: %g %g",
02355                  x3[2] - x3[0], y3[2] - y3[0]);
02356     cpl_msg_info(cpl_func, "Object Pos -> Neg2 x/y-distance [pixel]: %g %g",
02357                  x3[0] - x3[1], y3[0] - y3[1]);
02358 
02359     end_skip;
02360 
02361     cpl_apertures_delete(appos);
02362     cpl_apertures_delete(apneg);
02363 
02364     return cpl_error_get_code();
02365 }
02366 
02367 
02368 
02369 /*----------------------------------------------------------------------------*/
02388 /*----------------------------------------------------------------------------*/
02389 double visir_img_check_box(const cpl_apertures * appos,
02390                            int ipos1, int ipos2,
02391                            const cpl_apertures * apneg,
02392                            int ineg1, int ineg2, double ssize,
02393                            cpl_boolean * pswapp, cpl_boolean * pswapn)
02394 {
02395 
02396     /* NB: Lower left pixel is (1, 1) */
02397 
02398     /* The two positive points */
02399     const double xp1 = cpl_apertures_get_centroid_x(appos, ipos1);
02400     const double xp2 = cpl_apertures_get_centroid_x(appos, ipos2);
02401     const double yp1 = cpl_apertures_get_centroid_y(appos, ipos1);
02402     const double yp2 = cpl_apertures_get_centroid_y(appos, ipos2);
02403 
02404     /* The leftmost positive point */
02405     const double xpl = xp1 < xp2 ? xp1 : xp2;
02406     const double ypl = xp1 < xp2 ? yp1 : yp2;
02407 
02408     /* The rightmost positive point */
02409     const double xpr = xp1 < xp2 ? xp2 : xp1;
02410     const double ypr = xp1 < xp2 ? yp2 : yp1;
02411 
02412     /* The two negative points */
02413     const double xn1 = cpl_apertures_get_centroid_x(apneg, ineg1);
02414     const double yn1 = cpl_apertures_get_centroid_y(apneg, ineg1);
02415     const double xn2 = cpl_apertures_get_centroid_x(apneg, ineg2);
02416     const double yn2 = cpl_apertures_get_centroid_y(apneg, ineg2);
02417 
02418     /* The leftmost negative point */
02419     const double xnl = xn1 < xn2 ? xn1 : xn2;
02420     const double ynl = xn1 < xn2 ? yn1 : yn2;
02421 
02422     /* The rightmost negative point */
02423     const double xnr = xn1 < xn2 ? xn2 : xn1;
02424     const double ynr = xn1 < xn2 ? yn2 : yn1;
02425 
02426     const double lx1 = xnr - xpl; /* The length of the top x-side */
02427     const double lx2 = xpr - xnl; /* The length of the bottom x-side */
02428     const double ly1 = ypl - ynl; /* The length of the left y-side */
02429     const double ly2 = ynr - ypr; /* The length of the right y-side */
02430 
02431     const double dx1 = lx1 - ssize;
02432     const double dx2 = lx2 - ssize;
02433     const double dy1 = ly1 - ssize;
02434     const double dy2 = ly2 - ssize;
02435 
02436     const double ey1 = ynr - ypl; /* The displacement in the top x-side */
02437     const double ey2 = ypr - ynl; /* The displacement in the bottom x-side */
02438     const double ex1 = xpl - xnl; /* The displacement in the left y-side */
02439     const double ex2 = xpr - xnr; /* The displacement in the right y-side */
02440 
02441     const double ok = sqrt(dx1 * dx1 + dx2 * dx2 + dy1 * dy1 + dy2 * dy2 +
02442                            ex1 * ex1 + ex2 * ex2 + ey1 * ey1 + ey2 * ey2);
02443 
02444     double result = -1.0; /* Assume failure */
02445 
02446     skip_if(0); /* Catches NULL apertures and illegal index input */
02447 
02448     skip_if(pswapp == NULL);
02449     skip_if(pswapn == NULL);
02450     skip_if(appos == apneg);
02451     skip_if(ipos1 == ipos2);
02452     skip_if(ineg1 == ineg2);
02453 
02454     skip_if(ssize <= 0.0);
02455 
02456     *pswapp = xp1 < xp2 ? CPL_FALSE : CPL_TRUE;
02457     *pswapn = xn1 < xn2 ? CPL_FALSE : CPL_TRUE;
02458 
02459     result = ok/ssize; /* OK to divide now */
02460 
02461     end_skip;    
02462 
02463     return result;
02464 
02465 }
02466 
02467 
02468 /*----------------------------------------------------------------------------*/
02487 /*----------------------------------------------------------------------------*/
02488 double visir_img_check_align(const cpl_apertures * appos, int ipos,
02489                              const cpl_apertures * apneg, int ineg1, int ineg2,
02490                              double ssize, cpl_boolean is_hor,
02491                              cpl_boolean * pswapn)
02492 {
02493 
02494     /* NB: Lower left pixel is (1, 1) */
02495 
02496     /* The positive point */
02497     const double xp = cpl_apertures_get_centroid_x(appos, ipos);
02498     const double yp = cpl_apertures_get_centroid_y(appos, ipos);
02499 
02500     /* The two negative points */
02501     const double xn1 = cpl_apertures_get_centroid_x(apneg, ineg1);
02502     const double yn1 = cpl_apertures_get_centroid_y(apneg, ineg1);
02503     const double xn2 = cpl_apertures_get_centroid_x(apneg, ineg2);
02504     const double yn2 = cpl_apertures_get_centroid_y(apneg, ineg2);
02505 
02506     double result = -1.0; /* Assume failure */
02507 
02508     double ok;
02509 
02510     cpl_boolean swapn;
02511 
02512     if (is_hor) {
02513         /* The leftmost negative point */
02514         const double xnl = xn1 < xn2 ? xn1 : xn2;
02515         const double ynl = xn1 < xn2 ? yn1 : yn2;
02516 
02517         /* The rightmost negative point */
02518         const double xnr = xn1 < xn2 ? xn2 : xn1;
02519         const double ynr = xn1 < xn2 ? yn2 : yn1;
02520 
02521         const double d1 = xnr - xp - ssize; /* The rightmost length deviation */
02522         const double d2 = xp - xnl - ssize; /* The  leftmost length deviation */
02523 
02524         const double e1 = ynr - yp;  /* The rigthmost orthogonal deviation */
02525         const double e2 = yp - ynl;  /* The leftmost  orthogonal deviation */
02526 
02527         swapn = xn1 < xn2 ? CPL_FALSE : CPL_TRUE;
02528 
02529         ok = sqrt(d1 * d1 + d2 * d2 + e1 * e1 + e2 * e2);
02530 
02531     } else {
02532         /* The lower negative point */
02533         const double xnl = yn1 < yn2 ? xn1 : xn2;
02534         const double ynl = yn1 < yn2 ? yn1 : yn2;
02535 
02536         /* The upper negative point */
02537         const double xnr = yn1 < yn2 ? xn2 : xn1;
02538         const double ynr = yn1 < yn2 ? yn2 : yn1;
02539 
02540         const double d1 = ynr - yp - ssize; /* The upper length deviation */
02541         const double d2 = yp - ynl - ssize; /* The lower length deviation */
02542 
02543         const double e1 = xnr - xp;  /* The upper orthogonal deviation */
02544         const double e2 = xp - xnl;  /* The lower orthogonal deviation */
02545 
02546         swapn = yn1 < yn2 ? CPL_FALSE : CPL_TRUE;
02547 
02548         ok = sqrt(d1 * d1 + d2 * d2 + e1 * e1 + e2 * e2);
02549 
02550     }
02551 
02552     skip_if(0); /* Catches NULL apertures and illegal index input */
02553 
02554     skip_if(pswapn == NULL);
02555     skip_if(appos == apneg);
02556     skip_if(ineg1 == ineg2);
02557 
02558     skip_if(ssize <= 0.0);
02559 
02560     *pswapn = swapn;
02561 
02562     result = ok/ssize; /* OK to divide now */
02563 
02564     end_skip;    
02565 
02566     return result;
02567 
02568 }
02569 
02570 
02571 /*----------------------------------------------------------------------------*/
02582 /*----------------------------------------------------------------------------*/
02583 static cpl_error_code visir_get_type(const irplib_framelist * rawframes,
02584                                      int pos, visir_cube_type * ptype,
02585                                      int * pnaxis3, int * pnchop) {
02586 
02587 
02588 
02589     cpl_errorstate     cleanstate = cpl_errorstate_get();
02590     const char       * file
02591         = cpl_frame_get_filename(irplib_framelist_get_const(rawframes, pos));
02592     const cpl_propertylist * plist
02593         = irplib_framelist_get_propertylist_const(rawframes, pos);
02594     const int          nchop  = visir_pfits_get_chop_ncycles(plist);
02595     const int          naxis3 = visir_pfits_get_naxis3(plist);
02596     const char       * sval = NULL;
02597     /* If nchop == 1 (and naxis3 == 3) the data unit is both a valid CUBE1
02598        and a valid CUBE2; Assume the frame type to be CUBE2 */
02599 
02600 
02601     skip_if(0);
02602     bug_if(ptype == NULL);
02603     bug_if(pnaxis3 == NULL);
02604 
02605     sval = visir_pfits_get_frame_type(plist);
02606     if (sval == NULL) {
02607         /* Has warned about missing frame type card */
02608         visir_error_reset("Could not get FITS key");
02609         /* Don't know whether or not to expect CUBE1 or CUBE2 */
02610     } else if (strcmp(sval, "CUBE1")==0) {
02611         *ptype = VISIR_CUBE1;
02612     } else if (strcmp(sval, "CUBE2")==0) {
02613         *ptype = VISIR_CUBE2;
02614     }
02615 
02616     if (*ptype == VISIR_CUBE2) {
02617         if (naxis3 == 2 * nchop + 1) {
02618             /* OK. FRAME TYPE cannot be verified from naxis3 when nchop = 1 */
02619         } else if (naxis3 == nchop + 2) {
02620             cpl_msg_warning(cpl_func, "%s has FRAM TYPE = '%s', but NAXIS3=%d "
02621                             "and CHOP NCYCLES=%d imply a CUBE1. Assuming "
02622                             "the frame type is really CUBE1", file, sval,
02623                           naxis3, nchop);
02624             *ptype = VISIR_CUBE1;
02625         } else {
02626             cpl_msg_warning(cpl_func, "%s has FRAM TYPE = '%s', but NAXIS3=%d "
02627                             "and CHOP NCYCLES=%d is not a valid VISIR INTERM+"
02628                             "Half-Cycle format", file, sval, naxis3, nchop);
02629             skip_if(1);
02630         }
02631     } else if (*ptype == VISIR_CUBE1) {
02632         if (naxis3 == nchop + 2) {
02633             /* OK. FRAME TYPE cannot be verified from naxis3 when nchop = 1 */
02634             if (nchop > 1)
02635                 cpl_msg_debug(cpl_func, "%s has %d INTERM-frames and one Half-"
02636                               "Cycle frame (old CUBE1-format)", file, nchop);
02637 
02638         } else if (naxis3 == 2 * nchop + 1) {
02639             cpl_msg_warning(cpl_func, "%s has FRAM TYPE = '%s', but NAXIS3=%d "
02640                             "and CHOP NCYCLES=%d imply a CUBE2. Assuming "
02641                             "the frame type is really CUBE2", file, sval,
02642                             naxis3, nchop);
02643             *ptype = VISIR_CUBE2;
02644         } else {
02645             cpl_msg_warning(cpl_func, "%s has FRAM TYPE = '%s', but NAXIS3=%d "
02646                             "and CHOP NCYCLES=%d is not a valid VISIR INTERM+"
02647                             "Half-Cycle format", file, sval, naxis3, nchop);
02648             skip_if(1);
02649         }
02650     } else if (naxis3 == 2 * nchop + 1) {
02651         cpl_msg_warning(cpl_func, "%s has FRAM TYPE='%s', but NAXIS3=%d and "
02652                         "CHOP NCYCLES=%d imply a CUBE2. Assuming the frame "
02653                         "type is CUBE2", file, sval ? sval : "<NULL>", naxis3,
02654                         nchop);
02655         *ptype = VISIR_CUBE2;
02656     } else if (naxis3 == nchop + 2) {
02657         cpl_msg_warning(cpl_func, "%s has FRAM TYPE='%s', but NAXIS3=%d and "
02658                         "CHOP NCYCLES=%d imply a CUBE1. Assuming the frame "
02659                         "type is CUBE1", file, sval ? sval : "<NULL>", naxis3,
02660                         nchop);
02661         *ptype = VISIR_CUBE1;
02662     } else {
02663        return cpl_error_set_message(cpl_func, CPL_ERROR_BAD_FILE_FORMAT,
02664                                     "%s has FRAM TYPE='%s', NAXIS3 = %d and "
02665                                     "CHOP NCYCLES = %d", file,
02666                                     sval ? sval : "<NULL>", naxis3, nchop);
02667     }
02668 
02669     *pnaxis3 = naxis3;
02670     *pnchop  = nchop;
02671 
02672     end_skip;
02673 
02674     return cpl_error_get_code();
02675 }
02676 
02677 
02678 #include "visir_destripe.c"

Generated on Thu May 12 12:12:20 2011 for VISIR Pipeline Reference Manual by  doxygen 1.4.7