visir_inputs.c

00001 /* $Id: visir_inputs.c,v 1.155 2011/03/24 08:52:03 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/03/24 08:52:03 $
00024  * $Revision: 1.155 $
00025  * $Name: HEAD $
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 /* The values range from 0 (or 1) to 2**16-1 (or 2**16) */
00056 #define VISIR_HCYCLE_BPM_THRESHOLD  65000.0
00057 
00058 #ifndef VISIR_DESTRIPE_DETECT
00059 #define VISIR_DESTRIPE_DETECT           (3.5 * 1.64)
00060 #endif
00061 
00062 #ifndef VISIR_DESTRIPE_DETECT_THRESHOLD
00063 #define VISIR_DESTRIPE_DETECT_THRESHOLD 1.3
00064 #endif
00065 
00066 /* FIXME: Use correct image size */
00067 #define VISIRSZ 256
00068 
00069 
00070 /*-----------------------------------------------------------------------------
00071                                    Functions prototypes
00072  -----------------------------------------------------------------------------*/
00073 
00074 #include "visir_destripe.h"
00075 
00076 static cpl_image * visir_load_average(const char *,
00077                                       const cpl_propertylist *);
00078 static cpl_imagelist * visir_load_intermint(const irplib_framelist *, int);
00079 static cpl_error_code visir_imagelist_unpack_interm(cpl_imagelist *);
00080 static cpl_error_code visir_rem_glitch(cpl_image *);
00081 static cpl_error_code visir_rem_bad_images(cpl_imagelist *); 
00082 static cpl_error_code visir_offset_hcycle(cpl_image *);
00083 
00084 static cpl_image ** visir_img_collapse_beam_four(cpl_propertylist       *,
00085                                                  const cpl_image        *,
00086                                                  const cpl_image        *,
00087                                                  double, double,
00088                                                  const cpl_propertylist *);
00089 
00090 static cpl_image ** visir_img_collapse_beam_three(cpl_propertylist       *,
00091                                                   const cpl_image        *,
00092                                                   const cpl_image        *,
00093                                                   double, double,
00094                                                   const cpl_propertylist *);
00095 
00096 
00097 static cpl_error_code visir_img_find_beam_three(cpl_propertylist       *,
00098                                                 const cpl_image        *,
00099                                                 const cpl_image        *,
00100                                                 double, double,
00101                                                 double                 *,
00102                                                 double                 *);
00103 
00104 static cpl_error_code visir_img_find_beam_four(cpl_propertylist       *,
00105                                                const cpl_image        *,
00106                                                const cpl_image        *,
00107                                                double, double,
00108                                                double                 *,
00109                                                double                 *);
00110 
00111 /*----------------------------------------------------------------------------*/
00115 /*----------------------------------------------------------------------------*/
00116 
00119 /*----------------------------------------------------------------------------*/
00141 /*----------------------------------------------------------------------------*/
00142 cpl_image ** visir_img_collapse_beam(cpl_propertylist        * qclist,
00143                                      const cpl_image         * self,
00144                                      const cpl_parameterlist * parlist,
00145                                      const char              * recipename,
00146                                      visir_chopnod_mode        mode,
00147                                      const cpl_propertylist  * plist)
00148 {
00149 
00150     cpl_image ** combined = NULL;
00151     /* Need to invert the negative beams */
00152     cpl_image  * inverse = cpl_image_multiply_scalar_create(self, -1.0);
00153 
00154     const double eccmax   = visir_parameterlist_get_double(parlist, recipename,
00155                                                            VISIR_PARAM_ECCMAX);
00156 
00157     /* Get the chopping throw in pixels */
00158     const char * sthrow       = visir_pfits_get_pixscale(plist);
00159     const double pscale       = sthrow ? atof(sthrow) : 0.0;
00160     const double pthrow       = pscale > 0.0
00161         ? visir_pfits_get_chop_throw(plist) / pscale : 0.0;
00162 
00163 
00164     skip_if(self    == NULL);
00165     skip_if(parlist == NULL);
00166     skip_if(qclist  == NULL);
00167     skip_if(plist   == NULL);
00168 
00169     if (mode == VISIR_CHOPNOD_PERPENDICULAR) {
00170         /* 4 sources */
00171         combined = visir_img_collapse_beam_four(qclist, self, inverse, eccmax,
00172                                                 pthrow, plist);
00173     } else if (mode == VISIR_CHOPNOD_PARALLEL) {
00174         /* 3 sources */
00175         combined = visir_img_collapse_beam_three(qclist, self, inverse, eccmax,
00176                                                  pthrow, plist);
00177     } else if (mode == VISIR_CHOPNOD_AUTO) {
00178         cpl_errorstate cleanstate = cpl_errorstate_get();
00179 
00180         const char   * sdir = visir_pfits_get_chopnod_dir(plist);
00181 
00182         if (sdir != NULL && !strcmp(sdir, "PERPENDICULAR")) {
00183             /* 4 sources */
00184             combined = visir_img_collapse_beam_four(qclist, self, inverse,
00185                                                   eccmax, pthrow, plist);
00186         } else if (sdir != NULL && !strcmp(sdir, "PARALLEL")) {
00187             /* 3 sources */
00188             combined = visir_img_collapse_beam_three(qclist, self, inverse,
00189                                                      eccmax, pthrow, plist);
00190         } else {
00191             if (sdir == NULL) {
00192                 visir_error_reset("Could not get FITS key");
00193             } else {
00194                 cpl_msg_warning(cpl_func, "Unknown chopping direction: %s",
00195                                 sdir);
00196             }
00197             cpl_msg_warning(cpl_func, "Proceeding as if FITS card "
00198                             VISIR_PFITS_STRING_CHOPNOD_DIR " had value: %s",
00199                             "PERPENDICULAR");
00200             combined = visir_img_collapse_beam_four(qclist, self, inverse,
00201                                                     eccmax, pthrow, plist);
00202             if (combined == NULL) {
00203                 visir_error_reset("Proceeding as if FITS card "
00204                                   VISIR_PFITS_STRING_CHOPNOD_DIR
00205                                   " had value: %s", "PARALLEL");
00206                 combined = visir_img_collapse_beam_three(qclist, self, inverse,
00207                                                          eccmax, pthrow, plist);
00208             }
00209         }
00210     } else {
00211         bug_if(1);
00212     }
00213 
00214     skip_if(combined == NULL);
00215 
00216     bug_if (cpl_propertylist_append_double(qclist, "ESO QC ONEBEAM THROW",
00217                                            pthrow));
00218     bug_if (cpl_propertylist_set_comment(qclist, "ESO QC ONEBEAM THROW",
00219                                          "The throw in pixels (TEL CHOP THROW "
00220                                          "divided by INS PFOV)"));
00221 
00222     bug_if (cpl_propertylist_set_comment(qclist, "ESO QC ONEBEAM XPOS",
00223                                          "The X pixel position (centroid) "
00224                                          "of the one-beam object"));
00225 
00226     bug_if (cpl_propertylist_set_comment(qclist, "ESO QC ONEBEAM YPOS",
00227                                          "The Y pixel position (centroid) "
00228                                          "of the one-beam object"));
00229     bug_if (cpl_propertylist_set_comment(qclist, "ESO QC ONEBEAM ECCENTRICITY",
00230                                          "Eccentricity: 0 for perfect, throw-"
00231                                          "sized square/line"));
00232 
00233     end_skip;
00234 
00235     cpl_image_delete(inverse);
00236 
00237     return combined;
00238 }
00239 
00240 
00241 /*----------------------------------------------------------------------------*/
00324 /*----------------------------------------------------------------------------*/
00325 cpl_imagelist * visir_inputs_combine(const char * recipename,
00326                                      const cpl_parameterlist * parlist,
00327                                      const irplib_framelist * rawframes,
00328                                      const char      *   badpix,
00329                                      const char      *   flat,
00330                                      int             *   nodding_p,
00331                                      cpl_boolean         do_spc_fix,
00332                                      double              wlen,
00333                                      visir_spc_resol resol)
00334 {
00335     const char       * fnodpos;
00336     int                nfiles;
00337     cpl_imagelist    * in = NULL;
00338     cpl_image        * collapsed = NULL;
00339     cpl_image        * prev = NULL;
00340     cpl_vector       * nods_vec = NULL;
00341     double           * nods_data;
00342     int              * nod_pos = NULL;
00343     cpl_image       ** images = NULL;
00344     cpl_imagelist    * nodded = NULL;
00345     int                nnod;
00346     cpl_image        * flat_image = NULL;
00347     cpl_image        * bpm_im_int = NULL;
00348     cpl_mask         * bpm_im_bin = NULL;
00349     cpl_imagelist    * hcycle = NULL;
00350     cpl_boolean        no_rem;
00351     cpl_boolean        is_nodding = CPL_FALSE;
00352     int                i, j;
00353     cpl_boolean        auto_bpm, rem_glitch, rem_bad;
00354     int                ndestripe;
00355     cpl_boolean        morpho_destripe;
00356     double             tstart, tstop;
00357 #ifdef _OPENMP
00358     cpl_errorstate     cleanstate = cpl_errorstate_get();
00359 #endif
00360     cpl_error_code     didfail = CPL_ERROR_NONE;
00361 
00362 
00363     skip_if (0);
00364     skip_if(recipename == NULL);
00365     skip_if(parlist    == NULL);
00366     skip_if(rawframes  == NULL);
00367     
00368     /* Get the number of files */
00369     nfiles = irplib_framelist_get_size(rawframes);
00370 
00371     /* There should be an even number of files */
00372     if (nfiles % 2) {
00373         cpl_msg_warning(cpl_func, "Expecting even number of files, "
00374                         "ignoring the last of %d file(s)", nfiles);
00375         error_if (nfiles == 1, CPL_ERROR_DATA_NOT_FOUND,
00376                   "At least two files are required");
00377         nfiles--;
00378     }
00379 
00380     nnod = nfiles/2;
00381 
00382     skip_if (nnod <= 0);
00383 
00384     skip_if(irplib_framelist_contains(rawframes, VISIR_PFITS_STRING_FRAME_TYPE,
00385                                        CPL_TYPE_STRING, CPL_FALSE, 0.0));
00386     skip_if(irplib_framelist_contains(rawframes, VISIR_PFITS_DOUBLE_DIT,
00387                                        CPL_TYPE_DOUBLE, CPL_FALSE, 0.0));
00388     skip_if(irplib_framelist_contains(rawframes, VISIR_PFITS_INT_NAXIS3,
00389                                        CPL_TYPE_INT, CPL_FALSE, 0.0));
00390     skip_if(irplib_framelist_contains(rawframes, VISIR_PFITS_INT_CHOP_NCYCLES,
00391                                        CPL_TYPE_INT, CPL_FALSE, 0.0));
00392 
00393 
00394     /* Retrieve input parameters */
00395     fnodpos = visir_parameterlist_get_string(parlist, recipename,
00396                                              VISIR_PARAM_NODPOS);
00397     skip_if (0);
00398 
00399     auto_bpm = visir_parameterlist_get_bool(parlist, recipename,
00400                                             VISIR_PARAM_AUTOBPM);
00401     skip_if (0);
00402 
00403     rem_glitch = visir_parameterlist_get_bool(parlist, recipename,
00404                                               VISIR_PARAM_GLITCH);
00405     skip_if (0);
00406 
00407     rem_bad = visir_parameterlist_get_bool(parlist, recipename,
00408                                            VISIR_PARAM_PURGE);
00409     skip_if (0);
00410 
00411     ndestripe = visir_parameterlist_get_int(parlist, recipename,
00412                                             VISIR_PARAM_STRIPITE);
00413     bug_if (0);
00414 
00415     morpho_destripe = ndestripe <= 0 ? CPL_FALSE :
00416         visir_parameterlist_get_bool(parlist, recipename,
00417                                      VISIR_PARAM_STRIPMOR);
00418     bug_if (0);
00419 
00420     no_rem = !rem_glitch && !rem_bad;
00421 
00422     /* Each file corresponds to a nodding position (object=1 or sky=-1) */
00423     /* Return nod_pos array if requested */
00424     nod_pos = nodding_p ? nodding_p : cpl_malloc(nfiles * sizeof(int));
00425     j = 0;
00426     if (fnodpos != NULL && strlen(fnodpos) > 0) {
00427         /* Get the nodding positions from the user-provided ascii file */
00428         nods_vec = cpl_vector_read(fnodpos);
00429         skip_if (cpl_vector_get_size(nods_vec) != nfiles);
00430         nods_data = cpl_vector_get_data(nods_vec);
00431         skip_if (0);
00432         for (i=0 ; i<nfiles ; i++) {
00433             if ((int)nods_data[i] == 0) {
00434                 nod_pos[i] = 1;
00435                 j++;
00436             } else if ((int)nods_data[i] == 1) {
00437                 nod_pos[i] = -1;
00438                 is_nodding = CPL_TRUE;
00439             } else {
00440                 error_if(1, CPL_ERROR_BAD_FILE_FORMAT,
00441                          "Wrong values in line %d in %s", i+1, fnodpos);
00442             }
00443         }
00444     } else {
00445         skip_if (irplib_framelist_contains(rawframes, VISIR_PFITS_STRING_NODPOS,
00446                                             CPL_TYPE_STRING, CPL_FALSE, 0.0));
00447     }
00448 
00449     if (no_rem) cpl_msg_info(cpl_func, "No glitch removal and no purge of bad "
00450                              "frames requested: Using fast I/O method");
00451 
00452     /* Initialize the Bad Pixel Map */
00453     if (badpix != NULL) {
00454         /* The bpm is provided by the user */
00455         cpl_msg_info(cpl_func, "Loading bad pixel map from %s", badpix);
00456         /* Load the bad pixels image */
00457         bpm_im_int = cpl_image_load(badpix, CPL_TYPE_INT, 0, 0);
00458         skip_if (0);
00459 
00460         /* Convert the map from integer to binary */
00461         bpm_im_bin = cpl_mask_threshold_image_create(bpm_im_int, -0.5, 0.5);
00462         cpl_image_delete(bpm_im_int);
00463         bpm_im_int = NULL;
00464         skip_if (cpl_mask_not(bpm_im_bin));
00465     } else if (auto_bpm) {
00466         /* Initialize the Bad Pixel Map using the hcycle */
00467 
00468         /* i == 0 */
00469         hcycle = visir_load_imagelist(rawframes, 0, CPL_FALSE);
00470         skip_if(0);
00471 
00472         bpm_im_bin =
00473             cpl_mask_threshold_image_create(cpl_imagelist_get(hcycle,0),
00474                                             VISIR_HCYCLE_BPM_THRESHOLD,
00475                                             DBL_MAX);
00476         cpl_imagelist_delete(hcycle);
00477         hcycle = NULL;
00478         skip_if(0);
00479     }
00480 
00481     /* Initialize the flat field image */
00482     if (flat != NULL) {
00483         cpl_msg_info(cpl_func, "Divide the nodded images by the flatfield");
00484         /* Load the flat image */
00485         flat_image = cpl_image_load(flat, CPL_TYPE_FLOAT, 0, 0);
00486         any_if ("Cannot load the flat field %s", flat ? flat : "<NULL>");
00487     }
00488  
00489     /* Get nodding position (if needed) and DIT from the header */
00490     nodded = cpl_imagelist_new();
00491 
00492     tstart = cpl_test_get_walltime();
00493 
00494     /* Fill list with empty images of proper size and type */
00495 
00496     for (i=0; i < nfiles/2 ; i++) {
00497         cpl_image * empty = cpl_image_new(VISIRSZ, VISIRSZ, CPL_TYPE_FLOAT);
00498 
00499         /* i'th image can only be inserted when i-1'th is there,
00500            which prevents parallelism */
00501 
00502         bug_if (cpl_imagelist_set(nodded, empty, i));
00503     }
00504 
00505 #ifdef _OPENMP
00506 #pragma omp parallel for private(i) firstprivate(prev, collapsed)       \
00507                          schedule(static, 2)
00508 #endif
00509     for (i = 0; i < nfiles ; i++) {
00510         cpl_error_code errori = cpl_error_get_code();
00511 
00512         /* The total number of iterations must be pre-determined for the
00513            parallelism to work. In case of an error we can therefore not
00514            break, so instead we skip immediately to the next iteration.
00515            FIXME: This check on didfail does not guarantee that only one
00516                   iteration can cause an error to be dumped, but it is not
00517                   worse than checking on the thread-local state, errori. */
00518         if (didfail) continue;
00519 
00520         do {
00521 
00522         const char * file =
00523             cpl_frame_get_filename(irplib_framelist_get_const(rawframes, i));
00524         const cpl_propertylist * plist;
00525 
00526         double dit;
00527         double factor;
00528 
00529 
00530         plist = irplib_framelist_get_propertylist_const(rawframes, i);
00531         if (plist == NULL) {
00532             errori = cpl_error_set_where(cpl_func);
00533             break;
00534         }
00535 
00536         if (nods_vec == NULL) {
00537             const char * sval = visir_pfits_get_nodpos(plist);
00538             if (sval == NULL) {
00539                 errori = cpl_error_set_message(cpl_func,
00540                                                 CPL_ERROR_DATA_NOT_FOUND,
00541                                                 "Cannot get nodding position "
00542                                                 "for file %d/%d", i+1, nfiles);
00543                 break;
00544             }
00545             if (!strcmp(sval, "A")) {
00546                 nod_pos[i] = 1;
00547                 j++;
00548             } else {
00549                 nod_pos[i] = -1;
00550                 is_nodding = CPL_TRUE;
00551             }
00552         }
00553 
00554         /* Print the file name with its nodding position */
00555         cpl_msg_info(cpl_func, "File %02d: %s (%c)", i+1, file,
00556                      nod_pos[i]==1 ? '+' : '-');
00557 
00558         /* With nodding each pair must have exactly one object observation */
00559         if (is_nodding && (i & 1) == 1 && nod_pos[i] == nod_pos[i-1]) {
00560             cpl_msg_error(cpl_func, "Nodding pair (%d,%d) does not comprise an "
00561                           "on-object (A) and an off-object (B) image: %s", i-1,
00562                           i, nod_pos[i] == 1 ? "A" : "B");
00563         }
00564 
00565         /* Compute the normalization factor from the Detector Integration Time */
00566         dit = visir_pfits_get_dit(plist);
00567         if (cpl_error_get_code()) {
00568             errori = cpl_error_set_where(cpl_func);
00569             break;
00570         }
00571 
00572         if (dit <= 0) {
00573             errori = cpl_error_set_message(cpl_func,
00574                                             CPL_ERROR_ILLEGAL_INPUT,
00575                                             "DIT in file %d/%d is too small: "
00576                                             "%g", i+1, nfiles, dit);
00577             break;
00578         }
00579 
00580         factor = dit * nod_pos[i] * 2.0;
00581 
00582         if (no_rem){
00583             collapsed = visir_load_average(file, plist);
00584         } else {
00585             in = visir_load_intermint(rawframes, i);
00586             if (in == NULL) {
00587                 errori = cpl_error_set_message(cpl_func,
00588                                                 CPL_ERROR_ILLEGAL_INPUT,
00589                                                 "Could not load image set %d",
00590                                                 i+1);
00591                 break;
00592             }
00593 
00594             /* Convert the image lists from 'INTERM' to A-B' */
00595             if (visir_imagelist_unpack_interm(in)) {
00596                 errori = cpl_error_set_message(cpl_func,
00597                                                 cpl_error_get_code(),
00598                                                 "Failure for file %d/%d",
00599                                                 i+1, nfiles);
00600                 break;
00601             }
00602 
00603             /* Remove the glitch in each A-B image in each input cube
00604                if requested */
00605             if (rem_glitch) {
00606                 int jj;
00607                 for (jj=0 ; jj < cpl_imagelist_get_size(in); jj++) {
00608                     if (visir_rem_glitch(cpl_imagelist_get(in, jj))) {
00609                         errori = cpl_error_set_message(cpl_func,
00610                                                         cpl_error_get_code(),
00611                                                         "Could not remove "
00612                                                         "glitch in image %d in "
00613                                                         "set %d", jj+1, i+1);
00614                         break;
00615                     }
00616                 }
00617             }
00618 
00619             /* Remove the bad A-B images in each input file/cube if requested */
00620             if (rem_bad) {
00621                 cpl_msg_info(cpl_func, "Remove the bad A-B input images");
00622                 if (visir_rem_bad_images(in)) {
00623                     errori = cpl_error_set_message(cpl_func,
00624                                                     cpl_error_get_code(),
00625                                                     "Could not remove bad "
00626                                                     "images in list %d", i+1);
00627                     break;
00628                 }
00629             }
00630             /* Average each cube */
00631             collapsed = cpl_imagelist_collapse_create(in);
00632 
00633             cpl_imagelist_delete(in);
00634             in = NULL;
00635 
00636         }
00637 
00638         if (cpl_error_get_code()) {
00639             errori = cpl_error_set_message(cpl_func, cpl_error_get_code(),
00640                                             "Failure for file %d/%d",
00641                                             i+1, nfiles);
00642             break;
00643         }
00644         /* Normalise to have ADU/s. */
00645         /* Also divide with 2 to achieve average of image pair */
00646         if (cpl_image_divide_scalar(collapsed, 2*factor)) {
00647             errori = cpl_error_set_message(cpl_func, cpl_error_get_code(),
00648                                             "Failure for file %d/%d",
00649                                             i+1, nfiles);
00650             break;
00651         }
00652 
00653         /* Each pair of input files gives a nodded image in nodded */
00654         if (i & 1) {
00655             if (cpl_image_add(prev, collapsed)) {
00656                 errori = cpl_error_set_message(cpl_func, cpl_error_get_code(),
00657                                                 "Failure for file %d/%d",
00658                                                 i+1, nfiles);
00659                 break;
00660             }
00661             cpl_image_delete(collapsed);
00662             collapsed = NULL;
00663 
00664             /* At this point prev is the image to be put into
00665                the list of nodded images */
00666 
00667             if (bpm_im_bin != NULL) {
00668                 /* Apply the bad pixels cleaning */
00669                 if (cpl_image_reject_from_mask(prev, bpm_im_bin)) {
00670                     errori = cpl_error_set_message(cpl_func,
00671                                                     cpl_error_get_code(),
00672                                                     "Failure for file %d/%d",
00673                                                     i+1, nfiles);
00674                     break;
00675                 }
00676                 if (cpl_detector_interpolate_rejected(prev)) {
00677                     errori = cpl_error_set_message(cpl_func,
00678                                                     cpl_error_get_code(),
00679                                                     "Failure for file %d/%d",
00680                                                     i+1, nfiles);
00681                     break;
00682                 }
00683             }
00684 
00685             if (ndestripe > 0)
00686                 if(visir_destripe_image(prev, ndestripe,
00687                                              VISIR_DESTRIPE_DETECT,
00688                                              VISIR_DESTRIPE_DETECT_THRESHOLD,
00689                                         morpho_destripe)) {
00690                     errori = cpl_error_set_message(cpl_func,
00691                                                     cpl_error_get_code(),
00692                                                     "Failure for file %d/%d",
00693                                                     i+1, nfiles);
00694                     break;
00695                 }
00696 
00697             if (flat_image != NULL) {
00698                 /* Apply the flatfield correction */
00699                 if (cpl_image_divide(prev, flat_image)) {
00700                     errori = cpl_error_set_message(cpl_func,
00701                                                     cpl_error_get_code(),
00702                                                     "Failure for file %d/%d",
00703                                                     i+1, nfiles);
00704                     break;
00705                 }
00706             }
00707 
00708             if (cpl_imagelist_set(nodded, prev, i/2)) {
00709                 errori = cpl_error_set_message(cpl_func, cpl_error_get_code(),
00710                                                "Failure for file %d/%d",
00711                                                i+1, nfiles);
00712                 break;
00713             }
00714             prev = NULL;
00715         } else {
00716             prev = collapsed;
00717             collapsed = NULL;
00718         }
00719         } while (0);
00720 
00721         if (errori) {
00722 #ifdef _OPENMP
00723             /* Cannot access these errors after the join,
00724                so dump them now. :-(((((((((((((((((((( */
00725             cpl_errorstate_dump(cleanstate, CPL_FALSE, NULL);
00726 
00727             /* Need to deallocate the thread-private instances in the loop */
00728             cpl_image_delete(prev); prev = NULL;
00729             cpl_image_delete(collapsed); collapsed = NULL;
00730 
00731 #pragma omp critical
00732 #endif
00733             didfail = errori;
00734         }
00735     }
00736 
00737     error_if(didfail, didfail, "Failed to create %d nodded images from %d "
00738              "files", nnod, nfiles);
00739 
00740     tstop = cpl_test_get_walltime();
00741     cpl_msg_info(cpl_func, "Time to create %d nodded images [s]: %g", nnod,
00742                  tstop - tstart);
00743 
00744     cpl_vector_delete(nods_vec);
00745     nods_vec = NULL;
00746 
00747     cpl_image_delete(flat_image);
00748     flat_image = NULL;
00749 
00750     cpl_mask_delete(bpm_im_bin);
00751     bpm_im_bin = NULL;
00752 
00753     if (nod_pos != nodding_p) cpl_free(nod_pos);
00754     nod_pos = NULL;
00755     
00756     error_if(is_nodding && j != nnod, CPL_ERROR_INCOMPATIBLE_INPUT,
00757          "With nodding exactly half of the images "
00758              "must be on-object, not %d of %d", j, 2*nnod);
00759 
00760     if (do_spc_fix) {
00761         const double ksi   = visir_parameterlist_get_double(parlist, recipename,
00762                                                           VISIR_PARAM_SPECSKEW);
00763         const double eps   = visir_parameterlist_get_double(parlist, recipename,
00764                                                             VISIR_PARAM_VERTARC);
00765         const double delta = visir_parameterlist_get_double(parlist, recipename,
00766                                                             VISIR_PARAM_HORIARC);
00767         const double phi   = visir_parameterlist_get_double(parlist, recipename,
00768                                                           VISIR_PARAM_SLITSKEW);
00769         const int doplot   = visir_parameterlist_get_int(parlist, recipename,
00770                                                          VISIR_PARAM_PLOT);
00771 
00772 
00773         skip_if (0);
00774 
00775         images = cpl_malloc(nnod * sizeof(cpl_image*));
00776 
00777         for (j = 0; j < nnod; j++) images[j] = cpl_imagelist_get(nodded, j);
00778 
00779         skip_if (visir_spc_det_fix(images, nnod, CPL_TRUE, wlen, resol,
00780                                    phi, ksi, eps, delta, doplot));
00781     }
00782 
00783     end_skip;
00784 
00785     cpl_msg_set_time_off();
00786 
00787     cpl_free(images);
00788     cpl_imagelist_delete(in);
00789 
00790     if (nod_pos != nodding_p) cpl_free(nod_pos);
00791     cpl_vector_delete(nods_vec);
00792     cpl_image_delete(bpm_im_int);
00793     cpl_mask_delete(bpm_im_bin);
00794     cpl_image_delete(collapsed);
00795     cpl_image_delete(prev);
00796     if (cpl_error_get_code() && nodded != NULL) {
00797         cpl_imagelist_delete(nodded);
00798         nodded = NULL;
00799     }
00800 
00801     return nodded;
00802 }
00803 
00804 /*----------------------------------------------------------------------------*/
00851 /*----------------------------------------------------------------------------*/
00852 cpl_image ** visir_img_recombine(const char * recipename,
00853                                  const cpl_parameterlist * parlist,
00854                                  const irplib_framelist  * rawframes,
00855                                  const char        * badpix,
00856                                  const char        * flat,
00857                                  cpl_geom_combine    combine_mode,
00858                                  cpl_boolean       * pdid_resize,
00859                                  cpl_boolean         do_spc_fix,
00860                                  double              wlen,
00861                                  visir_spc_resol     resol)
00862 {
00863     int                     nfiles;
00864     int                 *   nod_pos = NULL;
00865     cpl_imagelist       *   nodded = NULL;
00866     int                     nnod;
00867     cpl_bivector        *   offsets_est = NULL;
00868     cpl_bivector        *   objs = NULL;
00869     cpl_image           **  combined = NULL;
00870     const cpl_vector    *   sigmas = NULL;
00871     double                  xoff, yoff;
00872     cpl_propertylist    *   qclist = cpl_propertylist_new();
00873     int                     i;
00874 
00875 
00876     bug_if (0);
00877 
00878     bug_if (recipename == NULL);
00879     bug_if (parlist    == NULL);
00880     bug_if (rawframes  == NULL);
00881     bug_if (pdid_resize  == NULL);
00882 
00883     /* Get the number of files */
00884     nfiles = irplib_framelist_get_size(rawframes);
00885 
00886     /* There should be an even number of files */
00887     if (nfiles % 2) {
00888         cpl_msg_warning(cpl_func, "Expecting even number of files, "
00889                         "ignoring the last of %d file(s)", nfiles);
00890         error_if (nfiles == 1, CPL_ERROR_DATA_NOT_FOUND,
00891                   "At least two files are required");
00892         nfiles--;
00893     }
00894 
00895     skip_if ( nfiles <= 0);
00896 
00897     /* Each file corresponds to a nodding position (object=1 or sky=-1) */
00898     nod_pos = cpl_malloc(nfiles * sizeof(int));
00899 
00900     /* Combine the input frames into the nodded images */
00901     cpl_msg_info(cpl_func, "Combining the input frames into the nodded images");
00902     nodded = visir_inputs_combine(recipename, parlist, rawframes, badpix, flat,
00903                                   nod_pos, do_spc_fix, wlen, resol);
00904 
00905     skip_if (nodded == NULL);
00906     nnod = cpl_imagelist_get_size(nodded);
00907 
00908     /* If only one nodded image, the work is finished */
00909     if (nnod == 1) {
00910 
00911         combined = cpl_malloc(2*sizeof(cpl_image*)); 
00912         combined[1] = NULL; /* In case the unset fails */
00913 
00914         combined[0] = cpl_imagelist_unset(nodded, 0);
00915         bug_if (combined[0] == NULL);
00916 
00917         combined[1] = cpl_image_new(cpl_image_get_size_x(combined[0]),
00918                                     cpl_image_get_size_y(combined[0]),
00919                                     CPL_TYPE_INT);
00920         bug_if (combined[1] == NULL);
00921 
00922         /* Set all pixel values to 1 */
00923         bug_if(cpl_image_threshold(combined[1], 1.0, 1.0, 1.0, 1.0));
00924 
00925         *pdid_resize = CPL_FALSE;
00926 
00927     } else {
00928         const double psigmas[] = {5, 2, 1, 0.5};
00929         const char * sval;
00930         const char * offsets;
00931         const char * objects;
00932         int sx, sy, mx, my;
00933         int rej_low, rej_high;
00934         cpl_boolean refine;
00935 
00936 
00937         refine = visir_parameterlist_get_bool(parlist, recipename,
00938                                               VISIR_PARAM_REFINE);
00939         skip_if (0);
00940 
00941         offsets = visir_parameterlist_get_string(parlist, recipename,
00942                                                  VISIR_PARAM_OFFSETS);
00943         skip_if (0);
00944 
00945         objects = visir_parameterlist_get_string(parlist, recipename,
00946                                                  VISIR_PARAM_OBJECTS);
00947         skip_if (0);
00948 
00949         sval = visir_parameterlist_get_string(parlist, recipename,
00950                                               VISIR_PARAM_XCORR);
00951         skip_if (0);
00952 
00953         skip_if (sscanf(sval, "%d %d %d %d", &sx, &sy, &mx, &my) != 4);
00954 
00955         sval = visir_parameterlist_get_string(parlist, recipename,
00956                                               VISIR_PARAM_REJECT);
00957         skip_if (0);
00958 
00959         skip_if (sscanf(sval, "%d %d", &rej_low, &rej_high) !=2 );
00960 
00961         /* Get the offsets estimation of each input file pair */
00962         cpl_msg_info(cpl_func, "Get the offsets estimation");
00963         if (offsets != NULL && strlen(offsets)) {
00964             /* A file has been provided on the command line */
00965             offsets_est = cpl_bivector_read(offsets);
00966             skip_if (offsets_est==NULL);
00967 
00968             error_if (cpl_bivector_get_size(offsets_est) != nnod,
00969                       CPL_ERROR_BAD_FILE_FORMAT, "The offsets file %s must "
00970                       "have %d entries, not %d", offsets, nnod,
00971                       cpl_bivector_get_size(offsets_est));
00972         } else {
00973             double * offsets_est_x;
00974             double * offsets_est_y;
00975             double   xoff0 = 0.0;  /* Avoid (false) uninit warning */
00976             double   yoff0 = 0.0;  /* Avoid (false) uninit warning */
00977             
00978             /* Get the offsets from the header */
00979             offsets_est = cpl_bivector_new(nnod);
00980             offsets_est_x = cpl_bivector_get_x_data(offsets_est);
00981             offsets_est_y = cpl_bivector_get_y_data(offsets_est);
00982 
00983             skip_if (0);
00984 
00985             offsets_est_x[0] = 0.0;
00986             offsets_est_y[0] = 0.0;
00987 
00988             for (i=0; i < nnod ; i++) {
00989                 const cpl_propertylist * plist;
00990 
00991                 /* Skip every other, non-object frame */ 
00992                 const int iframe = nod_pos[2*i] == 1 ? 2*i : 2*i+1;
00993 
00994                 plist = irplib_framelist_get_propertylist_const(rawframes,
00995                                                                 iframe);
00996                 skip_if(plist == NULL);
00997 
00998                 xoff = visir_pfits_get_cumoffsetx(plist);
00999                 yoff = visir_pfits_get_cumoffsety(plist);
01000 
01001                 skip_if (0);
01002 
01003                 if (i == 0) {
01004                     xoff0 = xoff;
01005                     yoff0 = yoff;
01006                 } else {
01007                     /* Subtract the first offset from all offsets */
01008                     offsets_est_x[i] = xoff0 - xoff;
01009                     offsets_est_y[i] = yoff0 - yoff;
01010                 }
01011             }
01012         }
01013         cpl_free(nod_pos);
01014         nod_pos = NULL;
01015     
01016         /* Read the provided objects file if provided
01017            - if a file has been provided on the command line */
01018         if (objects != NULL && strlen(objects) > 0) {
01019             objs = cpl_bivector_read(objects);
01020             any_if ("Could not read objects from %s", objects);
01021         }
01022    
01023         cpl_msg_info(cpl_func, "Recombining the list of nodded images using "
01024                      "mode: %d (I=%d:U=%d:F=%d), rej-lo=%d, rej-hi=%d",
01025                      combine_mode, CPL_GEOM_INTERSECT, CPL_GEOM_UNION,
01026                      CPL_GEOM_FIRST, rej_low, rej_high);
01027 
01028         if (cpl_msg_get_level() <= CPL_MSG_DEBUG) {
01029             cpl_msg_debug(cpl_func, "The offsets for the recombination:");
01030             cpl_bivector_dump(offsets_est, stdout);
01031         }
01032 
01033         sigmas = cpl_vector_wrap(4, (double*)psigmas); /* Not changed */
01034         combined = cpl_geom_img_offset_combine(nodded, offsets_est, refine,
01035                                                objs, sigmas, NULL, sx, sy,
01036                                                mx, my, rej_low, rej_high,
01037                                                combine_mode);
01038         any_if("Could not recombine the images");
01039 
01040         *pdid_resize = (cpl_boolean)(cpl_image_get_size_x(combined[0])
01041                 != cpl_image_get_size_x(cpl_imagelist_get_const(nodded, 0)) ||
01042                 cpl_image_get_size_y(combined[0])
01043                 != cpl_image_get_size_y(cpl_imagelist_get_const(nodded, 0)));
01044     }
01045 
01046     if (visir_parameterlist_get_int(parlist, recipename, VISIR_PARAM_PLOT) > 0)
01047         visir_image_plot("", "t 'The combined image'", "", combined[0]);
01048 
01049     end_skip;
01050 
01051     cpl_propertylist_delete(qclist);
01052     cpl_free(nod_pos);
01053     cpl_imagelist_delete(nodded);
01054     cpl_bivector_delete(offsets_est);
01055     cpl_bivector_delete(objs);
01056     cpl_vector_unwrap((cpl_vector*)sigmas);
01057 
01058     return combined;
01059 }
01060 
01061 /*----------------------------------------------------------------------------*/
01084 /*----------------------------------------------------------------------------*/
01085 cpl_imagelist * visir_load_hcycle(const irplib_framelist * rawframes, int pos)
01086 {
01087     return visir_load_imagelist(rawframes, pos, CPL_FALSE);
01088 }
01089 
01090 /*----------------------------------------------------------------------------*/
01101 /*----------------------------------------------------------------------------*/
01102 cpl_error_code visir_image_reject_hot(cpl_image * self, const char * bpmfile)
01103 {
01104 
01105     cpl_image  * im_bpm = NULL;
01106     cpl_mask   * bpm = NULL;
01107     const int upper = VISIR_HCYCLE_BPM_THRESHOLD;
01108 
01109 
01110     skip_if (0);
01111 
01112     skip_if (self == NULL);
01113 
01114     if (bpmfile == NULL) {
01115         bpm = cpl_mask_threshold_image_create(self, upper, DBL_MAX);
01116         skip_if (0);
01117     } else {
01118 
01119         /* The bpm is provided by the user */
01120         cpl_msg_info(cpl_func, "Clean user specified bad pixels");
01121         /* Load the bad pixel image */
01122         im_bpm = cpl_image_load(bpmfile, CPL_TYPE_INT, 0, 0);
01123         any_if ("Could not load the bad pixel map %s",
01124                 bpmfile ? bpmfile : "<NULL>");
01125         /* Convert the map from integer to binary */
01126         bpm = cpl_mask_threshold_image_create(im_bpm, -0.5, 0.5);
01127         skip_if (0);
01128         cpl_image_delete(im_bpm);
01129         im_bpm = NULL;
01130 
01131         skip_if (cpl_mask_not(bpm));
01132     }
01133 
01134     skip_if (cpl_image_reject_from_mask(self, bpm));
01135 
01136     end_skip;
01137 
01138     cpl_image_delete(im_bpm);
01139     cpl_mask_delete(bpm);
01140 
01141     return cpl_error_get_code();
01142 
01143 }
01144 
01145 
01146 /*----------------------------------------------------------------------------*/
01153 /*----------------------------------------------------------------------------*/
01154 cpl_imagelist * visir_imagelist_load_last(const irplib_framelist * rawframes)
01155 {
01156     cpl_imagelist * self = NULL;
01157     int naxis3;
01158 
01159     /* Verify that NAXIS3 is the same in all files */
01160     skip_if(irplib_framelist_contains(rawframes, VISIR_PFITS_INT_NAXIS3,
01161                                       CPL_TYPE_INT, CPL_TRUE, 0.0));
01162 
01163     naxis3 = visir_pfits_get_naxis3(irplib_framelist_get_propertylist_const(
01164                                                                       rawframes,
01165                                                                       0));
01166 
01167     /* Load the image set */
01168     self = irplib_imagelist_load_framelist(rawframes, CPL_TYPE_FLOAT, naxis3-1,
01169                                            0);
01170 
01171     skip_if (self == NULL);
01172 
01173     end_skip;
01174 
01175     return self;
01176 
01177 }
01178 
01179 
01180 /*----------------------------------------------------------------------------*/
01190 /*----------------------------------------------------------------------------*/
01191 cpl_imagelist * visir_load_imagelist(const irplib_framelist * rawframes,
01192                                      int pos, cpl_boolean is_interm)
01193 {
01194     cpl_errorstate cleanstate = cpl_errorstate_get();
01195     cpl_imagelist    * self = NULL;
01196     cpl_image        * image = NULL;
01197     const char       * file = NULL;
01198     const cpl_propertylist * plist;
01199     int                nchop, naxis3;
01200 
01201 
01202     /* Check the error code */
01203     skip_if (0);
01204 
01205     skip_if (rawframes == NULL);
01206 
01207     file = cpl_frame_get_filename(irplib_framelist_get_const(rawframes, pos));
01208     skip_if (file == NULL);
01209 
01210     /* First check if there is no chopping */
01211     plist = irplib_framelist_get_propertylist_const(rawframes, pos);
01212     skip_if (plist == NULL);
01213 
01214     naxis3 = visir_pfits_get_naxis3(plist);
01215     nchop = visir_pfits_get_chop_ncycles(plist);
01216 
01217     skip_if (0);
01218 
01219     if (nchop == 0 && naxis3 == 1 && is_interm) {
01220         self = cpl_imagelist_load(file, CPL_TYPE_FLOAT, 0);
01221     } else {
01222         const char   * sval;
01223         /* If nchop == 1 (and naxis3 == 3) the data unit is both a valid CUBE1
01224            and a valid CUBE2; Set plane_step as if the frame type is CUBE2 */
01225         const int      plane_step = (naxis3 == 2 * nchop + 1) ? 2 : 1;
01226         const cpl_type pixel_type = CPL_TYPE_FLOAT;
01227         int            nsize;
01228         int            iplane;
01229         int            i;
01230 
01231 
01232         error_if (nchop <= 0, CPL_ERROR_BAD_FILE_FORMAT,
01233                   "CHOP NCYCLES in %s is non-positive (and NAXIS3=%d): %d",
01234                   file, naxis3, nchop);
01235 
01236         error_if (plane_step == 1 && naxis3 != nchop+2,
01237                   CPL_ERROR_BAD_FILE_FORMAT, "NAXIS3=%d and CHOP NCYCLES=%d in "
01238                   "%s is not a valid VISIR INTERM+Half-Cycle "
01239                   "format", naxis3, nchop, file);
01240 
01241         if (plane_step == 1 && nchop > 1)
01242             cpl_msg_debug(cpl_func, "%s has %d INTERM-frames and one Half-"
01243                           "Cycle frame (old CUBE1-format)", file, nchop);
01244 
01245         /* Check the data format */
01246         sval = visir_pfits_get_frame_type(plist);
01247         if (sval == NULL) {
01248             /* Has warned about missing frame type card */
01249             visir_error_reset("Could not get FITS key");
01250             /* Don't know whether or not to expect CUBE1 or CUBE2 */
01251         } else if (strlen(sval) == 0) {
01252             /* Don't know whether or not to expect CUBE1 or CUBE2 */
01253         } else if (plane_step == 1) {
01254             if (strcmp(sval, "CUBE2")==0)
01255                 cpl_msg_error(cpl_func, "%s has FRAM TYPE = CUBE2, but NAXIS3=%d"
01256                                 " and CHOP NCYCLES=%d imply a CUBE1. Assuming "
01257                                 " the frame type is really CUBE1",  file,
01258                                 naxis3, nchop);
01259         } else if (nchop > 1) {
01260             /* if nchop == 1 format can be CUBE1 or CUBE2 */
01261             if (strcmp(sval, "CUBE1")==0)
01262                 cpl_msg_error(cpl_func, "%s has FRAM TYPE = CUBE1, but NAXIS3=%d"
01263                                 " and CHOP NCYCLES=%d imply a CUBE2. Assuming "
01264                                 " the frame type is really CUBE2",  file,
01265                                 naxis3, nchop);
01266         } 
01267 
01268         self = cpl_imagelist_new();
01269 
01270         if (plane_step == 1) {
01271             /* All INTERM frames are in the first part of the cube */
01272             iplane = is_interm ? 0 : nchop;
01273             /* - followed by a single Half-cycle image */
01274             nsize  = is_interm ? nchop : 1;
01275         } else {
01276             /* Each INTERM frame follows the Half-cycle frame */
01277             iplane = is_interm ? 1 : 0;
01278             nsize  = nchop;
01279         }
01280 
01281         for (i=0 ; i < nsize; i++, iplane += plane_step) {
01282 
01283             image = cpl_image_load(file, pixel_type, iplane, 0);
01284             skip_if (image == NULL);
01285 
01286             skip_if (!is_interm && visir_offset_hcycle(image));
01287 
01288             skip_if (cpl_imagelist_set(self, image, i));
01289 
01290             image = NULL;
01291         }
01292 
01293         skip_if (i < nsize);
01294     }
01295 
01296     end_skip;
01297 
01298     if (cpl_error_get_code()) {
01299         if (file != NULL) cpl_msg_warning(cpl_func, "Could not load the %s "
01300                                           "frame(s) from: %s",
01301                                           is_interm ? "INTERM" : "Half-Cycle",
01302                                           file);
01303         cpl_image_delete(image);
01304         cpl_imagelist_delete(self);
01305         self = NULL;
01306     }
01307 
01308     return self;
01309 }
01310 
01311 
01314 /*----------------------------------------------------------------------------*/
01338 /*----------------------------------------------------------------------------*/
01339 static cpl_imagelist * visir_load_intermint(const irplib_framelist * rawframes,
01340                                             int pos)
01341 {
01342     return visir_load_imagelist(rawframes, pos, CPL_TRUE);
01343 
01344 }
01345 
01346 /*----------------------------------------------------------------------------*/
01355 /*----------------------------------------------------------------------------*/
01356 static cpl_image * visir_load_average(const char * file,
01357                                       const cpl_propertylist * plist)
01358 {
01359     cpl_errorstate cleanstate = cpl_errorstate_get();
01360     cpl_image        * self = NULL;
01361     int                nchop, naxis3;
01362 
01363 
01364     skip_if (0);
01365     skip_if (file   == NULL);
01366     skip_if (plist == NULL);
01367 
01368     naxis3 = visir_pfits_get_naxis3(plist);
01369     nchop = visir_pfits_get_chop_ncycles(plist);
01370 
01371     skip_if (0);
01372 
01373     if (nchop == 0 && naxis3 == 1) {
01374         self = cpl_image_load(file, CPL_TYPE_FLOAT, 0, 0);
01375     } else {
01376         const char   * sval;
01377         /* If nchop == 1 (and naxis3 == 3) the data unit is both a valid CUBE1
01378            and a valid CUBE2; Set plane_offset as if the frame type is CUBE2 */
01379         const int      plane_offset = (naxis3 == 2 * nchop + 1) ? 2 : 3;
01380 
01381 
01382         error_if (nchop <= 0, CPL_ERROR_BAD_FILE_FORMAT, "CHOP NCYCLES in %s "
01383                   "is non-positive (and NAXIS3=%d): %d", file, naxis3, nchop);
01384 
01385         error_if (plane_offset == 3 && naxis3 != nchop+2,
01386                   CPL_ERROR_BAD_FILE_FORMAT, "NAXIS3=%d and CHOP NCYCLES=%d "
01387                   "in %s is not a valid VISIR INTERM+Half-Cycle format", naxis3,
01388                   nchop, file);
01389 
01390         if (plane_offset == 3 && nchop > 1)
01391             cpl_msg_debug(cpl_func, "%s has %d INTERM-frames and one Half-"
01392                           "Cycle frame (old CUBE1-format)", file, nchop);
01393 
01394         /* Check the data format */
01395         sval = visir_pfits_get_frame_type(plist);
01396         if (sval == NULL) {
01397             /* Has warned about missing frame type card */
01398             visir_error_reset("Could not get FITS key");
01399             /* Don't know whether or not to expect CUBE1 or CUBE2 */
01400         } else if (strlen(sval) == 0) {
01401             /* Don't know whether or not to expect CUBE1 or CUBE2 */
01402         } else if (plane_offset == 3) {
01403             if (strcmp(sval, "CUBE2")==0)
01404                 cpl_msg_error(cpl_func, "%s has FRAM TYPE = CUBE2, but NAXIS3=%d"
01405                                 " and CHOP NCYCLES=%d imply a CUBE1. Assuming "
01406                                 " the frame type is really CUBE1",  file,
01407                                 naxis3, nchop);
01408         } else if (nchop > 1) {
01409             /* if nchop == 1 format can be CUBE1 or CUBE2 */
01410             if (strcmp(sval, "CUBE1")==0)
01411                 cpl_msg_error(cpl_func, "%s has FRAM TYPE = CUBE1, but NAXIS3=%d"
01412                                 " and CHOP NCYCLES=%d imply a CUBE2. Assuming "
01413                                 " the frame type is really CUBE2",  file,
01414                                 naxis3, nchop);
01415         } 
01416 
01417         /* Load last INTERM frame */
01418         self = cpl_image_load(file, CPL_TYPE_FLOAT, naxis3-plane_offset, 0);
01419 
01420     }
01421 
01422     skip_if (0);
01423 
01424     end_skip;
01425 
01426     if (cpl_error_get_code()) {
01427         cpl_msg_warning(cpl_func, "Could not load the last INTERM frame from: "
01428                         "%s", file ? file : "<NULL>");
01429         cpl_image_delete(self);
01430         self = NULL;
01431     }
01432 
01433     return self;
01434 }
01435 
01436 /*----------------------------------------------------------------------------*/
01459 /*----------------------------------------------------------------------------*/
01460 static cpl_error_code visir_imagelist_unpack_interm(cpl_imagelist * self) 
01461 {
01462     cpl_image * iprev;
01463     cpl_image * image;
01464     const int   n = cpl_imagelist_get_size(self);
01465     int         i;
01466 
01467 
01468     skip_if (0);
01469 
01470     if (n == 1) return CPL_ERROR_NONE;
01471 
01472     iprev = cpl_imagelist_get(self, n - 1);
01473 
01474     skip_if (0);
01475 
01476     skip_if (cpl_image_multiply_scalar(iprev, n));
01477 
01478     /* Loop on the images - with first and last iteration peeled off */
01479     for (i = n-1 ; i > 1 ; i--, iprev = image) {
01480         image = cpl_imagelist_get(self, i-1);
01481 
01482         skip_if (0);
01483 
01484         skip_if (cpl_image_multiply_scalar(image, i));
01485 
01486         skip_if (cpl_image_subtract(iprev, image));
01487 
01488     }
01489 
01490     image = cpl_imagelist_get(self, 0);
01491 
01492     skip_if (0);
01493 
01494     skip_if (cpl_image_subtract(iprev, image));
01495 
01496     end_skip;
01497 
01498     return cpl_error_get_code();
01499 }
01500 
01501 /*----------------------------------------------------------------------------*/
01514 /*----------------------------------------------------------------------------*/
01515 static cpl_error_code visir_rem_glitch(cpl_image * glitchy) 
01516 {
01517     cpl_image * med_filt = NULL;
01518     cpl_mask  * bpm = NULL;
01519     cpl_mask  * kernel = cpl_mask_new(3, 3);
01520     double      mean, stdev;
01521     double      low_thresh, high_thresh;
01522     const int   nx = cpl_image_get_size_x(glitchy);
01523     const int   ny = cpl_image_get_size_y(glitchy);
01524     int         i;
01525 
01526     /* Some heuristic constants */
01527     double          factor1 = 3.0;
01528     double          factor2 = 10.0;
01529     const int       niterations = 5;
01530     const double    median_corr = 1.5;
01531 
01532     bug_if (0);
01533 
01534     /* Create the filtering kernel */
01535     bug_if(cpl_mask_not(kernel));
01536     
01537     /* Apply a 3x3 median filter to the input image  */
01538     med_filt = cpl_image_new(cpl_image_get_size_x(glitchy),
01539                              cpl_image_get_size_y(glitchy),
01540                              cpl_image_get_type(glitchy));
01541     bug_if(med_filt == NULL);
01542     bug_if(cpl_image_filter_mask(med_filt, glitchy, kernel, CPL_FILTER_MEDIAN,
01543                                  CPL_BORDER_FILTER));
01544     cpl_mask_delete(kernel);
01545     kernel = NULL;
01546 
01547     /* Noise is glitchy - med_filt */
01548     skip_if (cpl_image_subtract(glitchy, med_filt));
01549 
01550     /* niterations iterations */
01551     for (i=0 ; i < niterations ; i++) {
01552         /* Compute mean and stdev */
01553         mean = cpl_image_get_mean(glitchy);
01554         stdev = cpl_image_get_stdev(glitchy);
01555         
01556         skip_if (0);
01557 
01558         /* Set the thresholds */
01559         low_thresh  = mean - factor1 * stdev;
01560         high_thresh = mean + factor1 * stdev;
01561 
01562         /* Identify where mean-factor1*stdev < glitchy < mean+factor1*stdev */
01563         bpm = cpl_mask_threshold_image_create(glitchy,low_thresh,high_thresh);
01564         skip_if (cpl_mask_not(bpm));
01565         skip_if (cpl_image_reject_from_mask(glitchy, bpm));
01566         cpl_mask_delete(bpm);
01567         bpm = NULL;
01568 
01569         /* Test the number of bad pixels */
01570         skip_if (cpl_image_count_rejected(glitchy) == nx*ny);
01571     }
01572 
01573     /* Last iteration */
01574     /* Compute mean and stdev */
01575     mean = cpl_image_get_mean(glitchy);
01576     stdev = cpl_image_get_stdev(glitchy) * median_corr;
01577 
01578     skip_if (0);
01579 
01580     low_thresh  = mean - factor2 * stdev;
01581     high_thresh = mean + factor2 * stdev;
01582 
01583     bpm = cpl_mask_threshold_image_create(glitchy, low_thresh, high_thresh);
01584     skip_if (cpl_mask_not(bpm));
01585     skip_if (cpl_image_reject_from_mask(glitchy, bpm));
01586     cpl_mask_delete(bpm);
01587     bpm = NULL;
01588 
01589     /* Test the number of bad pixels */
01590     skip_if (cpl_image_count_rejected(glitchy) == nx*ny);
01591     
01592     /* Set the bad pixels to 0 */
01593     skip_if (cpl_image_fill_rejected(glitchy, 0.0));
01594     skip_if (cpl_image_accept_all(glitchy));
01595 
01596     /* Reconstruct the corrected image */
01597     skip_if (cpl_image_add(glitchy, med_filt));
01598 
01599     end_skip;
01600 
01601     cpl_image_delete(med_filt);
01602     cpl_mask_delete(bpm);
01603     cpl_mask_delete(kernel);
01604     
01605     return cpl_error_get_code();
01606 }
01607 
01608 /*----------------------------------------------------------------------------*/
01619 /*----------------------------------------------------------------------------*/
01620 static cpl_error_code visir_rem_bad_images(cpl_imagelist * in) 
01621 {
01622     cpl_vector * medians = NULL;
01623     cpl_vector * stdevs = NULL;
01624     cpl_vector * selection = NULL;
01625     double       mean_medians, mean_stdevs, stdev_medians, stdev_stdevs;
01626     const double threshold = 3;
01627     const int    nima = cpl_imagelist_get_size(in);
01628     int          i;
01629 
01630 
01631     /* This will catch a NULL input */
01632     skip_if (0);
01633 
01634     if (nima <= 3) return CPL_ERROR_NONE;
01635     
01636     /* Create medians and stdevs arrays */
01637     medians = cpl_vector_new(nima);
01638     stdevs = cpl_vector_new(nima);
01639 
01640     /* Compute the statistics */
01641     for (i=0 ; i < nima ; i++) {
01642         cpl_stats * stats = cpl_stats_new_from_image(cpl_imagelist_get(in, i),
01643                                             CPL_STATS_STDEV | CPL_STATS_MEDIAN);
01644 
01645         cpl_vector_set(medians, i, cpl_stats_get_median(stats));
01646         cpl_vector_set(stdevs,  i, cpl_stats_get_stdev(stats));
01647         cpl_stats_delete(stats); /* :-( */
01648     }
01649 
01650     skip_if( 0);
01651 
01652     /* Get the stats on these arrays */
01653     mean_medians  = cpl_vector_get_mean(medians);
01654     stdev_medians = cpl_vector_get_stdev(medians);
01655     mean_stdevs   = cpl_vector_get_mean(stdevs);
01656     stdev_stdevs  = cpl_vector_get_stdev(stdevs);
01657 
01658     skip_if (cpl_vector_subtract_scalar(medians, mean_medians));
01659     skip_if (cpl_vector_subtract_scalar(stdevs,  mean_stdevs));
01660 
01661     stdev_medians *= threshold;
01662     stdev_stdevs  *= threshold;
01663 
01664     /* Create the selection vector */
01665     selection = cpl_vector_new(nima);
01666     skip_if( cpl_vector_fill(selection, 0)); /* Flag all as good */
01667     for (i=0 ; i < nima ; i++) {
01668         if (fabs(cpl_vector_get(medians, i)) <= stdev_medians &&
01669             fabs(cpl_vector_get(stdevs,  i)) <= stdev_stdevs) continue;
01670 
01671         cpl_vector_set(selection, i, -1);
01672         cpl_msg_info(cpl_func, "Image %d of %d rejected: median=%g, stdev=%g",
01673                      i+1, nima, stdev_medians, stdev_stdevs);
01674     }
01675 
01676     /* Purge the bad images in the images set */
01677     cpl_imagelist_erase(in, selection);
01678 
01679     end_skip;
01680 
01681     cpl_vector_delete(medians);
01682     cpl_vector_delete(stdevs);
01683     
01684     cpl_vector_delete(selection);
01685 
01686     return CPL_ERROR_NONE;
01687 
01688 }
01689 
01690 /*----------------------------------------------------------------------------*/
01699 /*----------------------------------------------------------------------------*/
01700 static cpl_error_code visir_offset_hcycle(cpl_image * hcycle) 
01701 {
01702     double minval;
01703 
01704 
01705     skip_if (0);
01706 
01707     skip_if (cpl_image_add_scalar(hcycle, VISIR_HCYCLE_OFFSET));
01708 
01709     minval = cpl_image_get_min(hcycle);
01710 
01711     /* It seems that the offset really is VISIR_HCYCLE_OFFSET-1, warn if not */
01712     if (minval < 1) cpl_msg_warning(cpl_func, "HCycle pixel minval: %g", minval);
01713 
01714     end_skip;
01715 
01716     return CPL_ERROR_NONE;
01717 }
01718 
01719 /*----------------------------------------------------------------------------*/
01731 /*----------------------------------------------------------------------------*/
01732 static
01733 cpl_image ** visir_img_collapse_beam_four(cpl_propertylist       * qclist,
01734                                           const cpl_image        * self,
01735                                           const cpl_image        * inverse,
01736                                           double                   eccmax,
01737                                           double                   pthrow,
01738                                           const cpl_propertylist * plist)
01739 {
01740 
01741     cpl_image    ** combined = NULL;
01742     const int       nx = cpl_image_get_size_x(self);
01743     const int       ny = cpl_image_get_size_y(self);
01744     const cpl_type  type = cpl_image_get_type(self);
01745     cpl_imagelist * list4 = cpl_imagelist_new();
01746     cpl_image     * swrap = type == CPL_TYPE_DOUBLE
01747         ? cpl_image_wrap_double(nx, ny, cpl_image_get_data((cpl_image*)self))
01748         : cpl_image_wrap_float(nx, ny, cpl_image_get_data((cpl_image*)self));
01749     cpl_image     * iwrap = type == CPL_TYPE_DOUBLE
01750         ? cpl_image_wrap_double(nx, ny, cpl_image_get_data((cpl_image*)inverse))
01751         : cpl_image_wrap_float(nx, ny, cpl_image_get_data((cpl_image*)inverse));
01752     cpl_bivector  * offs = cpl_bivector_new(4);
01753     double * x4 = cpl_bivector_get_x_data(offs);
01754     double * y4 = cpl_bivector_get_y_data(offs);
01755     double pos_x, pos_y;
01756     int i;
01757 
01758     skip_if (0);
01759 
01760     skip_if(plist  == NULL);
01761 
01762     skip_if(visir_img_find_beam_four(qclist, self, inverse, eccmax, pthrow,
01763                                      x4, y4));
01764 
01765     /* Combine the four beams */
01766     for (i = 1; i < 4; i++) {
01767         x4[i] = x4[0] - x4[i];
01768         y4[i] = y4[0] - y4[i];
01769     }
01770 
01771     bug_if (cpl_propertylist_append_double(qclist, "ESO QC ONEBEAM XPOS",
01772                                            x4[0]));
01773     bug_if (cpl_propertylist_append_double(qclist, "ESO QC ONEBEAM YPOS",
01774                                            y4[0]));
01775     x4[0] = y4[0] = 0.0;
01776 
01777     bug_if(cpl_imagelist_set(list4, (cpl_image*)self,    0));
01778     bug_if(cpl_imagelist_set(list4, swrap,   1));
01779     bug_if(cpl_imagelist_set(list4, (cpl_image*)inverse, 2));
01780     bug_if(cpl_imagelist_set(list4, iwrap,   3));
01781 
01782     combined = cpl_geom_img_offset_saa(list4, offs, CPL_KERNEL_DEFAULT, 0, 0,
01783                                        CPL_GEOM_FIRST, &pos_x, &pos_y);
01784 
01785     skip_if(combined == NULL);
01786 
01787     end_skip;
01788 
01789     cpl_bivector_delete(offs);
01790     for (i = cpl_imagelist_get_size(list4) - 1; i >= 0; i--) {
01791         (void)cpl_imagelist_unset(list4, i);
01792     }
01793     cpl_imagelist_delete(list4);
01794     (void)cpl_image_unwrap(swrap);
01795     (void)cpl_image_unwrap(iwrap);
01796     if (cpl_error_get_code() && combined != NULL) {
01797         cpl_image_delete(combined[0]);
01798         cpl_image_delete(combined[1]);
01799         cpl_free(combined);
01800     }
01801 
01802     return combined;
01803 }
01804 
01805 /*----------------------------------------------------------------------------*/
01817 /*----------------------------------------------------------------------------*/
01818 static
01819 cpl_error_code visir_img_find_beam_four(cpl_propertylist * qclist,
01820                                         const cpl_image  * self,
01821                                         const cpl_image  * inverse,
01822                                         double             eccmax,
01823                                         double             pthrow,
01824                                         double             x4[],
01825                                         double             y4[])
01826 {
01827 
01828     cpl_errorstate  cleanstate = cpl_errorstate_get();
01829     cpl_apertures * appos = NULL;
01830     cpl_apertures * apneg = NULL;
01831     const double    psigmas[] = {2.0, 1.0, 0.5};
01832     const int       nsigmas = sizeof(psigmas)/sizeof(double);
01833     int             isigma;
01834     int             iappos2[] = {1, 2};
01835     int             iapneg2[] = {1, 2};
01836 
01837     bug_if(0);
01838     skip_if(self   == NULL);
01839     skip_if(qclist == NULL);
01840     skip_if(pthrow <= 0.0);
01841     skip_if(x4     == NULL);
01842     skip_if(y4     == NULL);
01843 
01844     cpl_msg_info(cpl_func, "Detecting the 4-beam object with %g pixel throw "
01845                  "using %d sigma-levels ranging from %g down to %g", pthrow,
01846                  nsigmas, psigmas[0], psigmas[nsigmas-1]);
01847 
01848     bug_if(0);
01849     for (isigma = 0; isigma < nsigmas; isigma++) {
01850         int npos = 0;
01851         int nneg = 0;
01852 
01853         /* Detect the (two) POSITIVE objects */
01854         cpl_apertures_delete(appos);
01855         appos = cpl_apertures_extract_sigma(self, psigmas[isigma]);
01856 
01857         if (appos != NULL) {
01858             npos = cpl_apertures_get_size(appos);
01859         }
01860 
01861 
01862         /* Detect the (two) NEGATIVE objects */
01863         cpl_apertures_delete(apneg);
01864         apneg = cpl_apertures_extract_sigma(inverse, psigmas[isigma]);
01865         if (apneg != NULL) {
01866             nneg = cpl_apertures_get_size(apneg);
01867         }
01868 
01869         cpl_msg_info(cpl_func, "Found %d positive (need 2) and %d negative "
01870                      "(need 2) object(s) at sigma=%g (%d of %d)", npos, nneg,
01871                      psigmas[isigma], 1+isigma, nsigmas);
01872 
01873         if (eccmax > 0.0) {
01874             int ipos1;
01875             double eccbest = eccmax;
01876             double eccmin  = DBL_MAX;
01877             double fluxbest = 0.0;
01878             double fluxecc = DBL_MAX;
01879             cpl_boolean is_first = CPL_TRUE;
01880 
01881 #ifdef _OPENMP
01882 #pragma omp parallel for private(ipos1)
01883 #endif
01884             for (ipos1 = 2; ipos1 <= npos; ipos1++) {
01885                 int ipos2, ineg1, ineg2;
01886                 for (ipos2 = 1; ipos2 < ipos1; ipos2++) {
01887                     for (ineg1 = 2; ineg1 <= nneg; ineg1++) {
01888                         for (ineg2 = 1; ineg2 < ineg1; ineg2++) {
01889                             cpl_boolean swappos, swapneg;
01890                             const double ecc
01891                                 = visir_img_check_box(appos, ipos1, ipos2,
01892                                                       apneg, ineg1, ineg2,
01893                                                       pthrow, &swappos,
01894                                                       &swapneg);
01895 
01896                             const double flux
01897                                 = cpl_apertures_get_flux(appos, ipos1)
01898                                 + cpl_apertures_get_flux(appos, ipos2)
01899                                 + cpl_apertures_get_flux(apneg, ineg1)
01900                                 + cpl_apertures_get_flux(apneg, ineg2);
01901 
01902 
01903                             if (ecc < 0.0 || flux <= 0.0 ||
01904                                 !cpl_errorstate_is_equal(cleanstate)) {
01905                                 irplib_error_recover(cleanstate, "Invalid 4-"
01906                                                      "object (%d & %d of %d, "
01907                                                      "%d & %d of %d)",
01908                                                      ipos2, ipos1, npos,
01909                                                      ineg2, ineg1, nneg);
01910                                 continue;
01911                             }
01912 
01913                             if (ecc < eccmin)
01914 #ifdef _OPENMP
01915 #pragma omp critical
01916 #endif
01917                             {
01918                                 eccmin = ecc;
01919                                 fluxecc = flux;
01920                             }
01921 
01922                             if (eccmax <= ecc) continue;
01923 
01924                             if (is_first || ecc * fluxbest < eccbest * flux)
01925 #ifdef _OPENMP
01926 #pragma omp critical
01927 #endif
01928                                 {
01929                                 if (is_first) {
01930                                     is_first = CPL_FALSE;
01931                                     cpl_msg_info(cpl_func, "Found 4 object "
01932                                                  "positions with throw-"
01933                                                  "scaled eccentricity %g "
01934                                                  "and flux %g", ecc, flux);
01935                                 } else {
01936                                     cpl_msg_info(cpl_func, "Found 4 object "
01937                                                  "positions with throw-"
01938                                                  "scaled eccentricity %g "
01939                                                  "< %g and/or flux %g > %g",
01940                                                  ecc, eccbest, flux, fluxbest);
01941                                 }
01942                                 eccbest = ecc;
01943                                 fluxbest = flux;
01944                                 iappos2[0] = swappos ? ipos2 : ipos1;
01945                                 iappos2[1] = swappos ? ipos1 : ipos2;
01946                                 iapneg2[0] = swapneg ? ineg2 : ineg1;
01947                                 iapneg2[1] = swapneg ? ineg1 : ineg2;
01948                             }
01949                         }
01950                     }
01951                 }
01952             }
01953             if (eccbest < eccmax) {
01954                 bug_if(cpl_propertylist_append_double(qclist, "ESO QC ONEBEAM "
01955                                                       "ECCENTRICITY", eccbest));
01956 
01957                 break;
01958             }
01959             if (eccmin < DBL_MAX) {
01960                 cpl_msg_info(cpl_func, "Found 4 sigma-%g object positions with "
01961                              "too large throw-scaled eccentricity %g >= %g and "
01962                              "flux %g", psigmas[isigma], eccmin, eccmax,
01963                              fluxecc);
01964             }
01965         } else if (npos >= 2 && nneg >= 2) {
01966             cpl_apertures_sort_by_flux(appos);
01967             cpl_apertures_sort_by_flux(apneg);
01968             break;
01969         }
01970 
01971         if (isigma + 1 < nsigmas) {
01972             irplib_error_recover(cleanstate, "4-Beam positions not found among "
01973                                  "%d postive and %d negative object(s) at "
01974                                  "sigma=%g, (%d of %d)", npos, nneg,
01975                                  psigmas[isigma], 1+isigma, nsigmas);
01976         }
01977     }
01978 
01979     error_if (isigma == nsigmas, CPL_ERROR_DATA_NOT_FOUND,
01980               "4-Beam positions not found w. %d sigma(s) down to %g",
01981               nsigmas, psigmas[nsigmas - 1]);
01982 
01983     if (cpl_msg_get_level() == CPL_MSG_DEBUG) {
01984         cpl_apertures_dump(appos, stdout);
01985         cpl_apertures_dump(apneg, stdout);
01986     }
01987 
01988     x4[0] = cpl_apertures_get_centroid_x(appos, iappos2[0]);
01989     y4[0] = cpl_apertures_get_centroid_y(appos, iappos2[0]);
01990     x4[1] = cpl_apertures_get_centroid_x(appos, iappos2[1]);
01991     y4[1] = cpl_apertures_get_centroid_y(appos, iappos2[1]);
01992 
01993     x4[2] = cpl_apertures_get_centroid_x(apneg, iapneg2[0]);
01994     y4[2] = cpl_apertures_get_centroid_y(apneg, iapneg2[0]);
01995     x4[3] = cpl_apertures_get_centroid_x(apneg, iapneg2[1]);
01996     y4[3] = cpl_apertures_get_centroid_y(apneg, iapneg2[1]);
01997 
01998     cpl_msg_info(cpl_func, "Centroid of positive object 1 [pixel]: %g %g",
01999                  x4[0], y4[0]);
02000     cpl_msg_info(cpl_func, "Centroid of positive object 2 [pixel]: %g %g",
02001                  x4[1], y4[1]);
02002 
02003     cpl_msg_info(cpl_func, "Centroid of negative object 1 [pixel]: %g %g",
02004                  x4[2], y4[2]);
02005     cpl_msg_info(cpl_func, "Centroid of negative object 2 [pixel]: %g %g",
02006                  x4[3], y4[3]);
02007 
02008     cpl_msg_info(cpl_func, "Expected object distance (chop throw) [pixel]: %g",
02009                  pthrow);
02010     cpl_msg_info(cpl_func, "Object Pos -> Pos x/y-distance [pixel]: %g %g",
02011                  x4[1] - x4[0], y4[1] - y4[0]);
02012     cpl_msg_info(cpl_func, "Object Neg -> Neg x/y-distance [pixel]: %g %g",
02013                  x4[3] - x4[2], y4[3] - y4[2]);
02014     cpl_msg_info(cpl_func, "Object Pos -> Pos angle [degrees]: %g",
02015                  atan2(y4[1] - y4[0], x4[1] - x4[0]) * CPL_MATH_DEG_RAD);
02016     cpl_msg_info(cpl_func, "Object Neg -> Neg angle [degrees]: %g",
02017                  atan2(y4[3] - y4[2], x4[3] - x4[2]) * CPL_MATH_DEG_RAD);
02018 
02019     end_skip;
02020 
02021     cpl_apertures_delete(appos);
02022     cpl_apertures_delete(apneg);
02023 
02024     return cpl_error_get_code();
02025 }
02026 
02027 /*----------------------------------------------------------------------------*/
02039 /*----------------------------------------------------------------------------*/
02040 static
02041 cpl_image ** visir_img_collapse_beam_three(cpl_propertylist       * qclist,
02042                                            const cpl_image        * self,
02043                                            const cpl_image        * inverse,
02044                                            double                   eccmax,
02045                                            double                   pthrow,
02046                                            const cpl_propertylist * plist)
02047 {
02048 
02049     cpl_image    ** combined = NULL;
02050     const int       nx = cpl_image_get_size_x(self);
02051     const int       ny = cpl_image_get_size_y(self);
02052     const cpl_type  type = cpl_image_get_type(self);
02053     cpl_imagelist * list3 = cpl_imagelist_new();
02054     cpl_image     * iwrap = type == CPL_TYPE_DOUBLE
02055         ? cpl_image_wrap_double(nx, ny, cpl_image_get_data((cpl_image*)inverse))
02056         : cpl_image_wrap_float(nx, ny, cpl_image_get_data((cpl_image*)inverse));
02057     cpl_bivector  * offs = cpl_bivector_new(3);
02058     double * x3 = cpl_bivector_get_x_data(offs);
02059     double * y3 = cpl_bivector_get_y_data(offs);
02060     double pos_x, pos_y;
02061     int i;
02062 
02063     skip_if (0);
02064 
02065     skip_if(plist  == NULL);
02066 
02067     skip_if(visir_img_find_beam_three(qclist, self, inverse, eccmax, pthrow,
02068                                       x3, y3));
02069 
02070     /* Combine the four beams */
02071     for (i = 1; i < 3; i++) {
02072         x3[i] = x3[0] - x3[i];
02073         y3[i] = y3[0] - y3[i];
02074     }
02075     bug_if (cpl_propertylist_append_double(qclist, "ESO QC ONEBEAM XPOS",
02076                                            x3[0]));
02077     bug_if (cpl_propertylist_append_double(qclist, "ESO QC ONEBEAM YPOS",
02078                                            y3[0]));
02079 
02080     x3[0] = y3[0] = 0.0;
02081 
02082     bug_if(cpl_imagelist_set(list3, (cpl_image*)self,    0));
02083     bug_if(cpl_imagelist_set(list3, (cpl_image*)inverse, 1));
02084     bug_if(cpl_imagelist_set(list3, iwrap,   2));
02085 
02086     combined = cpl_geom_img_offset_saa(list3, offs, CPL_KERNEL_DEFAULT, 0, 0,
02087                                        CPL_GEOM_FIRST, &pos_x, &pos_y);
02088 
02089     skip_if(combined == NULL);
02090 
02091     end_skip;
02092 
02093     cpl_bivector_delete(offs);
02094     for (i = cpl_imagelist_get_size(list3) - 1; i >= 0; i--) {
02095         (void)cpl_imagelist_unset(list3, i);
02096     }
02097     cpl_imagelist_delete(list3);
02098     (void)cpl_image_unwrap(iwrap);
02099     if (cpl_error_get_code() && combined != NULL) {
02100         cpl_image_delete(combined[0]);
02101         cpl_image_delete(combined[1]);
02102         cpl_free(combined);
02103     }
02104 
02105     return combined;
02106 }
02107 
02108 
02109 /*----------------------------------------------------------------------------*/
02122 /*----------------------------------------------------------------------------*/
02123 static
02124 cpl_error_code visir_img_find_beam_three(cpl_propertylist * qclist,
02125                                         const cpl_image  * self,
02126                                         const cpl_image  * inverse,
02127                                         double             eccmax,
02128                                         double             pthrow,
02129                                         double             x3[],
02130                                         double             y3[])
02131 {
02132 
02133     cpl_errorstate  cleanstate = cpl_errorstate_get();
02134     cpl_apertures * appos = NULL;
02135     cpl_apertures * apneg = NULL;
02136     const double    psigmas[] = {2.0, 1.0, 0.5};
02137     const int       nsigmas = sizeof(psigmas)/sizeof(double);
02138     int             isigma;
02139     int             iappos [] = {1};
02140     int             iapneg2[] = {1, 2};
02141 
02142     bug_if(0);
02143     skip_if(self   == NULL);
02144     skip_if(qclist == NULL);
02145     skip_if(pthrow <= 0.0);
02146     skip_if(eccmax <  0.0);
02147     skip_if(x3     == NULL);
02148     skip_if(y3     == NULL);
02149 
02150 
02151     cpl_msg_info(cpl_func, "Detecting the 3-beam object with %g pixel throw "
02152                  "using %d sigma-levels ranging from %g down to %g", pthrow,
02153                  nsigmas, psigmas[0], psigmas[nsigmas-1]);
02154 
02155     bug_if(0);
02156     for (isigma = 0; isigma < nsigmas; isigma++) {
02157         int npos = 0;
02158         int nneg = 0;
02159 
02160         /* Detect the (single) POSITIVE object */
02161         cpl_apertures_delete(appos);
02162         appos = cpl_apertures_extract_sigma(self, psigmas[isigma]);
02163 
02164         if (appos != NULL) {
02165             npos = cpl_apertures_get_size(appos);
02166         }
02167 
02168 
02169         /* Detect the (two) NEGATIVE objects */
02170         cpl_apertures_delete(apneg);
02171         apneg = cpl_apertures_extract_sigma(inverse, psigmas[isigma]);
02172         if (apneg != NULL) {
02173             nneg = cpl_apertures_get_size(apneg);
02174         }
02175 
02176         cpl_msg_info(cpl_func, "Found %d positive (need 1) and %d negative "
02177                      "(need 2) object(s) at sigma=%g (%d of %d)", npos, nneg,
02178                      psigmas[isigma], 1+isigma, nsigmas);
02179 
02180         if (eccmax > 0.0) {
02181             int ipos;
02182             double eccbest = eccmax;
02183             double eccmin  = DBL_MAX;
02184             double fluxbest = 0.0;
02185             double fluxecc = DBL_MAX;
02186             cpl_boolean is_first = CPL_TRUE;
02187 
02188 #ifdef _OPENMP
02189 #pragma omp parallel for private(ipos)
02190 #endif
02191             for (ipos = 1; ipos <= npos; ipos++) {
02192                 int ineg1, ineg2;
02193                 for (ineg1 = 2; ineg1 <= nneg; ineg1++) {
02194                     for (ineg2 = 1; ineg2 < ineg1; ineg2++) {
02195                         cpl_boolean swapnegh, swapnegv;
02196                         const double ecch
02197                             = visir_img_check_align(appos, ipos, apneg, ineg1,
02198                                                     ineg2, pthrow, CPL_TRUE,
02199                                                     &swapnegh);
02200                         const double eccv
02201                             = visir_img_check_align(appos, ipos, apneg, ineg1,
02202                                                     ineg2, pthrow, CPL_FALSE,
02203                                                     &swapnegv);
02204                         const double ecc = ecch < eccv ? ecch : eccv;
02205                         const cpl_boolean swapneg = ecch < eccv
02206                             ? swapnegh : swapnegv;
02207 
02208                         const double flux
02209                             = cpl_apertures_get_flux(appos, ipos)
02210                             + cpl_apertures_get_flux(apneg, ineg1)
02211                             + cpl_apertures_get_flux(apneg, ineg2);
02212 
02213 
02214                         if (ecc < 0.0 || flux <= 0.0 ||
02215                             !cpl_errorstate_is_equal(cleanstate)) {
02216                             irplib_error_recover(cleanstate, "Invalid 3-"
02217                                                  "object (%d of %d, "
02218                                                  "%d & %d of %d)",
02219                                                  ipos, npos,
02220                                                  ineg2, ineg1, nneg);
02221                             continue;
02222                         }
02223 
02224                         if (ecc < eccmin)
02225 #ifdef _OPENMP
02226 #pragma omp critical
02227 #endif
02228                         {
02229                             eccmin = ecc;
02230                             fluxecc = flux;
02231                         }
02232 
02233                         if (eccmax <= ecc) continue;
02234 
02235                         if (is_first || ecc * fluxbest < eccbest * flux)
02236 #ifdef _OPENMP
02237 #pragma omp critical
02238 #endif
02239                         {
02240                             if (is_first) {
02241                                 is_first = CPL_FALSE;
02242                                 cpl_msg_info(cpl_func, "Found 3 object posi"
02243                                              "tions with throw-scaled (ver"
02244                                              "tical/horizontal) eccentrici"
02245                                              "ty %g/%g and flux %g", eccv,
02246                                              ecch, flux);
02247                             } else {
02248                                 cpl_msg_info(cpl_func, "Found 3 object posi"
02249                                              "tions with throw-scaled (ver"
02250                                              "tical/horizontal) eccentrici"
02251                                              "ty %g/%g < %g and/or flux %g "
02252                                              "> %g", eccv, ecch, eccbest,
02253                                              flux, fluxbest);
02254                             }
02255                             eccbest = ecc;
02256                             fluxbest = flux;
02257                             iappos[0] = ipos;
02258                             iapneg2[0] = swapneg ? ineg2 : ineg1;
02259                             iapneg2[1] = swapneg ? ineg1 : ineg2;
02260                         }
02261                     }
02262                 }
02263             }
02264             if (eccbest < eccmax) {
02265                 bug_if(cpl_propertylist_append_double(qclist, "ESO QC ONEBEAM "
02266                                                       "ECCENTRICITY", eccbest));
02267                 break;
02268             }
02269             if (eccmin < DBL_MAX) {
02270                 cpl_msg_info(cpl_func, "Found 3 sigma-%g object positions with "
02271                              "too large throw-scaled eccentricity %g >= %g and "
02272                              "flux %g", psigmas[isigma], eccmin, eccmax,
02273                              fluxecc);
02274             }
02275         } else if (npos >= 1 && nneg >= 2) {
02276             cpl_apertures_sort_by_flux(appos);
02277             cpl_apertures_sort_by_flux(apneg);
02278             break;
02279         }
02280 
02281         if (isigma + 1 < nsigmas) {
02282             irplib_error_recover(cleanstate, "3-Beam positions not found among "
02283                                  "%d postive and %d negative object(s) at "
02284                                  "sigma=%g, (%d of %d)", npos, nneg,
02285                                  psigmas[isigma], 1+isigma, nsigmas);
02286         }
02287     }
02288 
02289     error_if (isigma == nsigmas, CPL_ERROR_DATA_NOT_FOUND,
02290               "3-Beam positions not found w. %d sigma(s) down to %g",
02291               nsigmas, psigmas[nsigmas - 1]);
02292 
02293     if (cpl_msg_get_level() == CPL_MSG_DEBUG) {
02294         cpl_apertures_dump(appos, stdout);
02295         cpl_apertures_dump(apneg, stdout);
02296     }
02297 
02298     x3[0] = cpl_apertures_get_centroid_x(appos, iappos[0]);
02299     y3[0] = cpl_apertures_get_centroid_y(appos, iappos[0]);
02300 
02301     x3[1] = cpl_apertures_get_centroid_x(apneg, iapneg2[0]);
02302     y3[1] = cpl_apertures_get_centroid_y(apneg, iapneg2[0]);
02303     x3[2] = cpl_apertures_get_centroid_x(apneg, iapneg2[1]);
02304     y3[2] = cpl_apertures_get_centroid_y(apneg, iapneg2[1]);
02305 
02306     cpl_msg_info(cpl_func, "Centroid of positive object [pixel]: %g %g",
02307                  x3[0], y3[0]);
02308 
02309     cpl_msg_info(cpl_func, "Centroid of negative object 1 [pixel]: %g %g",
02310                  x3[1], y3[1]);
02311     cpl_msg_info(cpl_func, "Centroid of negative object 2 [pixel]: %g %g",
02312                  x3[2], y3[2]);
02313 
02314     cpl_msg_info(cpl_func, "Expected object distance (chop throw) [pixel]: %g",
02315                  pthrow);
02316     cpl_msg_info(cpl_func, "Object Neg1 -> Pos x/y-distance [pixel]: %g %g",
02317                  x3[2] - x3[0], y3[2] - y3[0]);
02318     cpl_msg_info(cpl_func, "Object Pos -> Neg2 x/y-distance [pixel]: %g %g",
02319                  x3[0] - x3[1], y3[0] - y3[1]);
02320 
02321     end_skip;
02322 
02323     cpl_apertures_delete(appos);
02324     cpl_apertures_delete(apneg);
02325 
02326     return cpl_error_get_code();
02327 }
02328 
02329 
02330 
02331 /*----------------------------------------------------------------------------*/
02350 /*----------------------------------------------------------------------------*/
02351 double visir_img_check_box(const cpl_apertures * appos,
02352                            int ipos1, int ipos2,
02353                            const cpl_apertures * apneg,
02354                            int ineg1, int ineg2, double ssize,
02355                            cpl_boolean * pswapp, cpl_boolean * pswapn)
02356 {
02357 
02358     /* NB: Lower left pixel is (1, 1) */
02359 
02360     /* The two positive points */
02361     const double xp1 = cpl_apertures_get_centroid_x(appos, ipos1);
02362     const double xp2 = cpl_apertures_get_centroid_x(appos, ipos2);
02363     const double yp1 = cpl_apertures_get_centroid_y(appos, ipos1);
02364     const double yp2 = cpl_apertures_get_centroid_y(appos, ipos2);
02365 
02366     /* The leftmost positive point */
02367     const double xpl = xp1 < xp2 ? xp1 : xp2;
02368     const double ypl = xp1 < xp2 ? yp1 : yp2;
02369 
02370     /* The rightmost positive point */
02371     const double xpr = xp1 < xp2 ? xp2 : xp1;
02372     const double ypr = xp1 < xp2 ? yp2 : yp1;
02373 
02374     /* The two negative points */
02375     const double xn1 = cpl_apertures_get_centroid_x(apneg, ineg1);
02376     const double yn1 = cpl_apertures_get_centroid_y(apneg, ineg1);
02377     const double xn2 = cpl_apertures_get_centroid_x(apneg, ineg2);
02378     const double yn2 = cpl_apertures_get_centroid_y(apneg, ineg2);
02379 
02380     /* The leftmost negative point */
02381     const double xnl = xn1 < xn2 ? xn1 : xn2;
02382     const double ynl = xn1 < xn2 ? yn1 : yn2;
02383 
02384     /* The rightmost negative point */
02385     const double xnr = xn1 < xn2 ? xn2 : xn1;
02386     const double ynr = xn1 < xn2 ? yn2 : yn1;
02387 
02388     const double lx1 = xnr - xpl; /* The length of the top x-side */
02389     const double lx2 = xpr - xnl; /* The length of the bottom x-side */
02390     const double ly1 = ypl - ynl; /* The length of the left y-side */
02391     const double ly2 = ynr - ypr; /* The length of the right y-side */
02392 
02393     const double dx1 = lx1 - ssize;
02394     const double dx2 = lx2 - ssize;
02395     const double dy1 = ly1 - ssize;
02396     const double dy2 = ly2 - ssize;
02397 
02398     const double ey1 = ynr - ypl; /* The displacement in the top x-side */
02399     const double ey2 = ypr - ynl; /* The displacement in the bottom x-side */
02400     const double ex1 = xpl - xnl; /* The displacement in the left y-side */
02401     const double ex2 = xpr - xnr; /* The displacement in the right y-side */
02402 
02403     const double ok = sqrt(dx1 * dx1 + dx2 * dx2 + dy1 * dy1 + dy2 * dy2 +
02404                            ex1 * ex1 + ex2 * ex2 + ey1 * ey1 + ey2 * ey2);
02405 
02406     double result = -1.0; /* Assume failure */
02407 
02408     skip_if(0); /* Catches NULL apertures and illegal index input */
02409 
02410     skip_if(pswapp == NULL);
02411     skip_if(pswapn == NULL);
02412     skip_if(appos == apneg);
02413     skip_if(ipos1 == ipos2);
02414     skip_if(ineg1 == ineg2);
02415 
02416     skip_if(ssize <= 0.0);
02417 
02418     *pswapp = xp1 < xp2 ? CPL_FALSE : CPL_TRUE;
02419     *pswapn = xn1 < xn2 ? CPL_FALSE : CPL_TRUE;
02420 
02421     result = ok/ssize; /* OK to divide now */
02422 
02423     end_skip;    
02424 
02425     return result;
02426 
02427 }
02428 
02429 
02430 /*----------------------------------------------------------------------------*/
02449 /*----------------------------------------------------------------------------*/
02450 double visir_img_check_align(const cpl_apertures * appos, int ipos,
02451                              const cpl_apertures * apneg, int ineg1, int ineg2,
02452                              double ssize, cpl_boolean is_hor,
02453                              cpl_boolean * pswapn)
02454 {
02455 
02456     /* NB: Lower left pixel is (1, 1) */
02457 
02458     /* The positive point */
02459     const double xp = cpl_apertures_get_centroid_x(appos, ipos);
02460     const double yp = cpl_apertures_get_centroid_y(appos, ipos);
02461 
02462     /* The two negative points */
02463     const double xn1 = cpl_apertures_get_centroid_x(apneg, ineg1);
02464     const double yn1 = cpl_apertures_get_centroid_y(apneg, ineg1);
02465     const double xn2 = cpl_apertures_get_centroid_x(apneg, ineg2);
02466     const double yn2 = cpl_apertures_get_centroid_y(apneg, ineg2);
02467 
02468     double result = -1.0; /* Assume failure */
02469 
02470     double ok;
02471 
02472     cpl_boolean swapn;
02473 
02474     if (is_hor) {
02475         /* The leftmost negative point */
02476         const double xnl = xn1 < xn2 ? xn1 : xn2;
02477         const double ynl = xn1 < xn2 ? yn1 : yn2;
02478 
02479         /* The rightmost negative point */
02480         const double xnr = xn1 < xn2 ? xn2 : xn1;
02481         const double ynr = xn1 < xn2 ? yn2 : yn1;
02482 
02483         const double d1 = xnr - xp - ssize; /* The rightmost length deviation */
02484         const double d2 = xp - xnl - ssize; /* The  leftmost length deviation */
02485 
02486         const double e1 = ynr - yp;  /* The rigthmost orthogonal deviation */
02487         const double e2 = yp - ynl;  /* The leftmost  orthogonal deviation */
02488 
02489         swapn = xn1 < xn2 ? CPL_FALSE : CPL_TRUE;
02490 
02491         ok = sqrt(d1 * d1 + d2 * d2 + e1 * e1 + e2 * e2);
02492 
02493     } else {
02494         /* The lower negative point */
02495         const double xnl = yn1 < yn2 ? xn1 : xn2;
02496         const double ynl = yn1 < yn2 ? yn1 : yn2;
02497 
02498         /* The upper negative point */
02499         const double xnr = yn1 < yn2 ? xn2 : xn1;
02500         const double ynr = yn1 < yn2 ? yn2 : yn1;
02501 
02502         const double d1 = ynr - yp - ssize; /* The upper length deviation */
02503         const double d2 = yp - ynl - ssize; /* The lower length deviation */
02504 
02505         const double e1 = xnr - xp;  /* The upper orthogonal deviation */
02506         const double e2 = xp - xnl;  /* The lower orthogonal deviation */
02507 
02508         swapn = yn1 < yn2 ? CPL_FALSE : CPL_TRUE;
02509 
02510         ok = sqrt(d1 * d1 + d2 * d2 + e1 * e1 + e2 * e2);
02511 
02512     }
02513 
02514     skip_if(0); /* Catches NULL apertures and illegal index input */
02515 
02516     skip_if(pswapn == NULL);
02517     skip_if(appos == apneg);
02518     skip_if(ineg1 == ineg2);
02519 
02520     skip_if(ssize <= 0.0);
02521 
02522     *pswapn = swapn;
02523 
02524     result = ok/ssize; /* OK to divide now */
02525 
02526     end_skip;    
02527 
02528     return result;
02529 
02530 }
02531 
02532 #include "visir_destripe.c"

Generated on Thu Mar 24 11:59:39 2011 for VISIR Pipeline Reference Manual by  doxygen 1.5.8