visir_inputs.c

00001 /* $Id: visir_inputs.c,v 1.206 2012/02/02 10:30:05 jtaylor 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: jtaylor $
00023  * $Date: 2012/02/02 10:30:05 $
00024  * $Revision: 1.206 $
00025  * $Name: visir-3_5_0 $
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 /* TEMPORARY SUPPORT OF CPL 5.x */
00039 #ifndef CPL_SIZE_FORMAT
00040 #define CPL_SIZE_FORMAT "d"
00041 #define cpl_size int
00042 #endif
00043 /* END TEMPORARY SUPPORT OF CPL 5.x */
00044 
00045 #include "visir_utils.h"
00046 #include "visir_pfits.h"
00047 #include "visir_parameter.h"
00048 #include "visir_pfits.h"
00049 #include "visir_spc_distortion.h"
00050 #include "visir_inputs.h"
00051 #include "irplib_framelist.h"
00052 #include "irplib_wcs.h"
00053 
00054 #include <string.h>
00055 #include <math.h>
00056 #include <float.h>
00057 #include <assert.h>
00058 
00059 /*-----------------------------------------------------------------------------
00060                                    Define
00061  -----------------------------------------------------------------------------*/
00062 
00063 #ifndef VISIR_DESTRIPE_DETECT
00064 #define VISIR_DESTRIPE_DETECT           (3.5 * 1.64)
00065 #endif
00066 
00067 #ifndef VISIR_DESTRIPE_DETECT_THRESHOLD
00068 #define VISIR_DESTRIPE_DETECT_THRESHOLD 1.3
00069 #endif
00070 
00071 #define VISIR_SECS_PER_DAY (24 * 3600)
00072 
00073 typedef enum {
00074     VISIR_CUBE1,
00075     VISIR_CUBE2
00076 } visir_cube_type;
00077 
00078 
00079 /*-----------------------------------------------------------------------------
00080                                    Functions prototypes
00081  -----------------------------------------------------------------------------*/
00082 
00083 #include "visir_destripe.h"
00084 
00085 static cpl_image * visir_load_average(const char *,
00086                                       const cpl_propertylist *);
00087 static cpl_imagelist * visir_load_intermint(const irplib_framelist *, int);
00088 static cpl_error_code visir_imagelist_unpack_interm(cpl_imagelist *);
00089 static cpl_error_code visir_rem_glitch(cpl_image *);
00090 static cpl_error_code visir_rem_bad_images(cpl_imagelist *); 
00091 static cpl_error_code visir_offset_hcycle(cpl_image *);
00092 
00093 static cpl_image ** visir_img_collapse_beam_four(cpl_propertylist       *,
00094                                                  const cpl_image        *,
00095                                                  const cpl_image        *,
00096                                                  double, double,
00097                                                  const cpl_propertylist *);
00098 
00099 static cpl_image ** visir_img_collapse_beam_three(cpl_propertylist       *,
00100                                                   const cpl_image        *,
00101                                                   const cpl_image        *,
00102                                                   double, double,
00103                                                   const cpl_propertylist *);
00104 
00105 
00106 static cpl_error_code visir_img_find_beam_three(cpl_propertylist       *,
00107                                                 const cpl_image        *,
00108                                                 const cpl_image        *,
00109                                                 double, double,
00110                                                 double                 *,
00111                                                 double                 *);
00112 
00113 static cpl_error_code visir_img_find_beam_four(cpl_propertylist       *,
00114                                                const cpl_image        *,
00115                                                const cpl_image        *,
00116                                                double, double,
00117                                                double                 *,
00118                                                double                 *);
00119 
00120 static cpl_error_code visir_get_type(const irplib_framelist *, int,
00121                                      visir_cube_type *, int *, int *);
00122 
00123 
00124 /*----------------------------------------------------------------------------*/
00128 /*----------------------------------------------------------------------------*/
00129 
00133 /*----------------------------------------------------------------------------*/
00146 /*----------------------------------------------------------------------------*/
00147 
00148 static
00149 cpl_error_code visir_load_cube2_split_(cpl_imagelist * alist, cpl_imagelist * blist,
00150                                        cpl_imagelist * packed, cpl_image * prevd)
00151 {
00152 
00153     int naxis3 = cpl_imagelist_get_size(packed);
00154     int prevd_insert_pos = cpl_imagelist_get_size(blist);
00155 
00156     bug_if(alist     == NULL);
00157     bug_if(blist     == NULL);
00158 
00159 
00160     if (prevd)
00161         cpl_imagelist_set(blist, prevd, prevd_insert_pos);
00162 
00163     /* Split the cube */
00164     for (int i = 0; i < naxis3/2; i++) {
00165         cpl_image * aimage = cpl_imagelist_unset(packed, 0); /* Ai */
00166         cpl_image * dimage = cpl_imagelist_unset(packed, 0); /* Ai - Bi mean */
00167 
00168         cpl_imagelist_set(alist, aimage, cpl_imagelist_get_size(alist));
00169         cpl_imagelist_set(blist, dimage, cpl_imagelist_get_size(blist));
00170 
00171     }
00172 
00173     skip_if_lt(0, cpl_imagelist_get_size(packed), "Too many packed frames");
00174 
00175     /* After this call the ith image in the list is Ai - Bi */
00176     bug_if(visir_imagelist_unpack_interm(blist));
00177 
00178     /* remove extra image again */
00179     if (prevd)
00180         cpl_imagelist_unset(blist, prevd_insert_pos);
00181 
00182     for (int i = 0; i < naxis3/2; i++) {
00183         const cpl_image * aimage = cpl_imagelist_get_const(alist, i);
00184         const cpl_image * dimage = cpl_imagelist_get_const(blist, i);
00185         /* Compute Bi from Ai - (Ai - Bi). */
00186         cpl_image       * bimage = cpl_image_subtract_create(aimage, dimage);
00187 
00188         /* Deallocate the difference image and set Bi in its place */
00189         bug_if(cpl_imagelist_set(blist, bimage, i));
00190 
00191     }
00192 
00193     skip_if_lt(0, cpl_imagelist_get_size(packed), "Too many packed frames");
00194 
00195     end_skip;
00196 
00197     return cpl_error_get_code();
00198 
00199 }
00200 
00201 
00202 /*----------------------------------------------------------------------------*/
00214 /*----------------------------------------------------------------------------*/
00215 static cpl_imagelist * load_range(const char * filename,
00216                                   cpl_type     im_type,
00217                                   int          pstart,
00218                                   int          pend)
00219 {
00220     int        selfsize = 0;
00221     cpl_imagelist * self = cpl_imagelist_new();
00222 
00223     for (int iplane = pstart; iplane < pend; iplane++) {
00224         cpl_image * image = cpl_image_load(filename, im_type, iplane, 0);
00225 
00226         if (image == NULL) break;
00227 
00228         if (cpl_imagelist_set(self, image, selfsize)) {
00229             cpl_image_delete(image);
00230             break;
00231         }
00232 
00233         selfsize++;
00234     }
00235     return self;
00236 }
00237 
00238 
00239 /*----------------------------------------------------------------------------*/
00262 /*----------------------------------------------------------------------------*/
00263 cpl_error_code visir_load_cube2_split(cpl_imagelist * alist, cpl_imagelist * blist,
00264                                       const irplib_framelist * rawframes, int pos,
00265                                       const int planestart, const int planeend)
00266 {
00267 
00268     cpl_imagelist      * packed = NULL;
00269     const char         * file
00270         = cpl_frame_get_filename(irplib_framelist_get_const(rawframes, pos));
00271     int                  naxis3, nchop;
00272     visir_cube_type      cube_type;
00273     int pend;
00274     cpl_image * prevd = NULL;
00275 
00276     skip_if(0);
00277 
00278     (void)visir_get_type(rawframes, pos, &cube_type, &naxis3, &nchop);
00279 
00280     /* both ranges must be even except for the last chunk where it must
00281      * be uneven for the average image at the end of the CUBE2 file */
00282     error_if(planestart % 2 == 1, CPL_ERROR_ILLEGAL_INPUT,
00283              "Plane start %d wrong. It must be even.", planestart);
00284     error_if(planeend < naxis3 && planeend % 2 == 1, CPL_ERROR_ILLEGAL_INPUT,
00285              "Plane end %d wrong. It must be even if not larger naxis3=%d",
00286              planeend, naxis3);
00287 
00288     any_if("Cannot split non-CUBE2 frame %d/%d in %s", 1+pos,
00289            irplib_framelist_get_size(rawframes), file);
00290     bug_if(alist     == NULL);
00291     bug_if(blist     == NULL);
00292 
00293     error_if(cube_type != VISIR_CUBE2, CPL_ERROR_INCOMPATIBLE_INPUT, "Cannot "
00294              "split non-CUBE2 frame %d/%d w. NAXIS3=%d, NCYCLES=%d in %s",
00295              1+pos, irplib_framelist_get_size(rawframes), naxis3, nchop, file);
00296 
00297     if (planeend >= naxis3 || planeend < 0)
00298         pend = naxis3 - 1; /* don't load sum */
00299     else
00300         pend = planeend;
00301 
00302     if (planestart != 0) {
00303         packed = load_range(file, CPL_TYPE_UNSPECIFIED, planestart - 1, pend);
00304         prevd = cpl_imagelist_unset(packed, 0);
00305     }
00306     else
00307         packed = load_range(file, CPL_TYPE_UNSPECIFIED, planestart, pend);
00308 
00309     skip_if(visir_load_cube2_split_(alist, blist, packed, prevd));
00310 
00311     end_skip;
00312 
00313     cpl_image_delete(prevd);
00314     cpl_imagelist_delete(packed);
00315 
00316     return cpl_error_get_code();
00317 }
00318 
00319 
00320 /*----------------------------------------------------------------------------*/
00337 /*----------------------------------------------------------------------------*/
00338 static
00339 cpl_error_code visir_load_burst_(cpl_imagelist * alist, cpl_imagelist * blist,
00340                                  cpl_imagelist * packed,
00341                                  const int ichopchange, const int ihalfcycle,
00342                                  const int trimlow, int const trimhigh)
00343 {
00344     cpl_boolean bon = CPL_TRUE;
00345     const int offset = 0;
00346     const int pend = cpl_imagelist_get_size(packed);
00347     int lorej = ihalfcycle - trimlow;
00348     int hirej = trimhigh + 1; /* +1 to reject the actual changing frame too */
00349 
00350     /* get frame where chopper moved from on to off in the _previous_
00351      * half exposure */
00352     int chpmv =  ichopchange - ihalfcycle * 2;
00353 
00354     cpl_ensure_code(trimhigh >= -1, CPL_ERROR_ILLEGAL_INPUT);
00355     cpl_ensure_code(trimlow >= 0, CPL_ERROR_ILLEGAL_INPUT);
00356     cpl_ensure_code(ichopchange < ihalfcycle * 2, CPL_ERROR_ILLEGAL_INPUT);
00357     cpl_ensure_code(alist != NULL, CPL_ERROR_NULL_INPUT);
00358     cpl_ensure_code(blist != NULL, CPL_ERROR_NULL_INPUT);
00359 
00360     skip_if(0);
00361 
00362     /* Split the cube and skip the planes where the chopper
00363      * changes +- a safety margin
00364      * always starts from on -> off movement even if negative */
00365     for (int i = chpmv; i < pend; i++) {
00366         if ((i + ihalfcycle * 2) % ihalfcycle == ichopchange % ihalfcycle) {
00367             bon = !bon;
00368             hirej = trimhigh + 1;
00369             lorej = ihalfcycle - trimlow;
00370         }
00371         if (hirej <= 0 && lorej > 0 && i >= 0) {
00372             if (bon) {
00373                 cpl_image * image= cpl_imagelist_unset(packed, offset);
00374                 cpl_imagelist_set(alist, image, cpl_imagelist_get_size(alist));
00375             }
00376             else {
00377                 cpl_image * image= cpl_imagelist_unset(packed, offset);
00378                 cpl_imagelist_set(blist, image, cpl_imagelist_get_size(blist));
00379             }
00380         }
00381         else if (i >= 0)
00382             cpl_image_delete(cpl_imagelist_unset(packed, offset));
00383 
00384         hirej--;
00385         lorej--;
00386     }
00387 
00388     cpl_msg_info(cpl_func, "On: %d, Off %d, Skipped %d",
00389                  (int)cpl_imagelist_get_size(alist),
00390                  (int)cpl_imagelist_get_size(blist),
00391                  (int)(pend - cpl_imagelist_get_size(alist)
00392                             - cpl_imagelist_get_size(blist)));
00393 
00394     skip_if_lt(0, cpl_imagelist_get_size(packed), "Too many packed frames");
00395 
00396     end_skip;
00397 
00398     return cpl_error_get_code();
00399 }
00400 
00401 
00402 /*----------------------------------------------------------------------------*/
00411 /*----------------------------------------------------------------------------*/
00412 static int get_to_off_plane(int chopchange, const int offset,
00413                             const int ihalfcycle)
00414 {
00415     /* if offset in second hcycle beginning on/off state is flipped */
00416     if (offset -
00417         (offset / (ihalfcycle * 2)) * ihalfcycle * 2 > chopchange)
00418         chopchange += ihalfcycle * 2 - (offset % (ihalfcycle * 2));
00419     else
00420         chopchange -= (offset % ihalfcycle);
00421     return chopchange;
00422 }
00423 
00424 
00425 /*----------------------------------------------------------------------------*/
00444 /*----------------------------------------------------------------------------*/
00445 cpl_error_code visir_load_burst(cpl_imagelist * alist, cpl_imagelist * blist,
00446                                 const cpl_frame * frame, const cpl_propertylist * plist,
00447                                 const int ichopchange, const int ihalfcycle,
00448                                 const int planestart, const int planeend,
00449                                 const int trimlow, const int trimhigh)
00450 {
00451     const char * file = cpl_frame_get_filename(frame);
00452     const int    naxis3 = visir_pfits_get_naxis3(plist);
00453     const int    pend = planeend <= 0 || planeend > naxis3 ? naxis3 : planeend;
00454     cpl_imagelist * packed;
00455     int to_off = get_to_off_plane(ichopchange, planestart, ihalfcycle);
00456 
00457     cpl_msg_info(cpl_func, "Loading planes %d to %d, to off %d",
00458                  planestart, pend, planestart + to_off);
00459 
00460     packed = load_range(file, CPL_TYPE_UNSPECIFIED, planestart, pend);
00461 
00462     skip_if(packed == NULL);
00463 
00464     skip_if(visir_load_burst_(alist, blist, packed, to_off, ihalfcycle,
00465                               trimlow, trimhigh));
00466 
00467     end_skip;
00468 
00469     cpl_imagelist_delete(packed);
00470 
00471     return cpl_error_get_code();
00472 }
00473 
00474 
00475 /*----------------------------------------------------------------------------*/
00497 /*----------------------------------------------------------------------------*/
00498 cpl_image ** visir_img_collapse_beam(cpl_propertylist        * qclist,
00499                                      const cpl_image         * self,
00500                                      const cpl_parameterlist * parlist,
00501                                      const char              * recipename,
00502                                      visir_chopnod_mode        mode,
00503                                      const cpl_propertylist  * plist)
00504 {
00505 
00506     cpl_image ** combined = NULL;
00507     /* Need to invert the negative beams */
00508     cpl_image  * inverse = cpl_image_multiply_scalar_create(self, -1.0);
00509 
00510     const double eccmax   = visir_parameterlist_get_double(parlist, recipename,
00511                                                            VISIR_PARAM_ECCMAX);
00512 
00513     /* Get the chopping throw in pixels */
00514     const char * sscale       = visir_pfits_get_pixscale(plist);
00515     const double pscale       = sscale ? atof(sscale) : 0.0;
00516     const double pthrow       = pscale > 0.0
00517         ? visir_pfits_get_chop_throw(plist) / pscale : 0.0;
00518 
00519 
00520     skip_if(self    == NULL);
00521     skip_if(parlist == NULL);
00522     skip_if(qclist  == NULL);
00523     skip_if(plist   == NULL);
00524 
00525     if (mode == VISIR_CHOPNOD_PERPENDICULAR) {
00526         /* 4 sources */
00527         combined = visir_img_collapse_beam_four(qclist, self, inverse, eccmax,
00528                                                 pthrow, plist);
00529     } else if (mode == VISIR_CHOPNOD_PARALLEL) {
00530         /* 3 sources */
00531         combined = visir_img_collapse_beam_three(qclist, self, inverse, eccmax,
00532                                                  pthrow, plist);
00533     } else if (mode == VISIR_CHOPNOD_AUTO) {
00534         cpl_errorstate cleanstate = cpl_errorstate_get();
00535 
00536         const char   * sdir = visir_pfits_get_chopnod_dir(plist);
00537 
00538         if (sdir != NULL && !strcmp(sdir, "PERPENDICULAR")) {
00539             /* 4 sources */
00540             combined = visir_img_collapse_beam_four(qclist, self, inverse,
00541                                                   eccmax, pthrow, plist);
00542         } else if (sdir != NULL && !strcmp(sdir, "PARALLEL")) {
00543             /* 3 sources */
00544             combined = visir_img_collapse_beam_three(qclist, self, inverse,
00545                                                      eccmax, pthrow, plist);
00546         } else {
00547             if (sdir == NULL) {
00548                 visir_error_reset("Could not get FITS key");
00549             } else {
00550                 cpl_msg_warning(cpl_func, "Unknown chopping direction: %s",
00551                                 sdir);
00552             }
00553             cpl_msg_warning(cpl_func, "Proceeding as if FITS card "
00554                             VISIR_PFITS_STRING_CHOPNOD_DIR " had value: %s",
00555                             "PERPENDICULAR");
00556             combined = visir_img_collapse_beam_four(qclist, self, inverse,
00557                                                     eccmax, pthrow, plist);
00558             if (combined == NULL) {
00559                 visir_error_reset("Proceeding as if FITS card "
00560                                   VISIR_PFITS_STRING_CHOPNOD_DIR
00561                                   " had value: %s", "PARALLEL");
00562                 combined = visir_img_collapse_beam_three(qclist, self, inverse,
00563                                                          eccmax, pthrow, plist);
00564             }
00565         }
00566     } else {
00567         bug_if(1);
00568     }
00569 
00570     skip_if(combined == NULL);
00571 
00572     bug_if (cpl_propertylist_append_double(qclist, "ESO QC ONEBEAM THROW",
00573                                            pthrow));
00574     bug_if (cpl_propertylist_set_comment(qclist, "ESO QC ONEBEAM THROW",
00575                                          "The throw in pixels (TEL CHOP THROW "
00576                                          "divided by INS PFOV)"));
00577 
00578     bug_if (cpl_propertylist_set_comment(qclist, "ESO QC ONEBEAM XPOS",
00579                                          "The X pixel position (centroid) "
00580                                          "of the one-beam object"));
00581 
00582     bug_if (cpl_propertylist_set_comment(qclist, "ESO QC ONEBEAM YPOS",
00583                                          "The Y pixel position (centroid) "
00584                                          "of the one-beam object"));
00585     bug_if (cpl_propertylist_set_comment(qclist, "ESO QC ONEBEAM ECCENTRICITY",
00586                                          "Eccentricity: 0 for perfect, throw-"
00587                                          "sized square/line"));
00588 
00589     end_skip;
00590 
00591     cpl_image_delete(inverse);
00592 
00593     return combined;
00594 }
00595 
00596 
00597 /*----------------------------------------------------------------------------*/
00680 /*----------------------------------------------------------------------------*/
00681 cpl_imagelist * visir_inputs_combine(const char * recipename,
00682                                      const cpl_parameterlist * parlist,
00683                                      const irplib_framelist * rawframes,
00684                                      const char      *   badpix,
00685                                      const char      *   flat,
00686                                      int             *   nodding_p,
00687                                      cpl_boolean         do_spc_fix,
00688                                      double              wlen,
00689                                      visir_spc_resol resol)
00690 {
00691     const char       * fnodpos;
00692     int                nfiles;
00693     cpl_imagelist    * in = NULL;
00694     cpl_image        * collapsed = NULL;
00695     cpl_image        * prev = NULL;
00696     cpl_vector       * nods_vec = NULL;
00697     double           * nods_data;
00698     int              * nod_pos = NULL;
00699     cpl_image       ** images = NULL;
00700     cpl_imagelist    * nodded = NULL;
00701     int                nnod;
00702     cpl_image        * flat_image = NULL;
00703     cpl_image        * bpm_im_int = NULL;
00704     cpl_mask         * bpm_im_bin = NULL;
00705     cpl_imagelist    * hcycle = NULL;
00706     cpl_boolean        no_rem;
00707     cpl_boolean        is_nodding = CPL_FALSE;
00708     int                i, j;
00709     cpl_boolean        auto_bpm, rem_glitch, rem_bad;
00710     int                ndestripe;
00711     int                naxis1, naxis2;
00712     cpl_boolean        morpho_destripe;
00713     double             tstart, tstop;
00714     const cpl_propertylist * plist1;
00715 #ifdef _OPENMP
00716     cpl_errorstate     cleanstate = cpl_errorstate_get();
00717 #endif
00718     cpl_error_code     didfail = CPL_ERROR_NONE;
00719 
00720 
00721     skip_if (0);
00722     skip_if(recipename == NULL);
00723     skip_if(parlist    == NULL);
00724     skip_if(rawframes  == NULL);
00725     
00726     /* Get the number of files */
00727     nfiles = irplib_framelist_get_size(rawframes);
00728 
00729     /* There should be an even number of files */
00730     if (nfiles % 2) {
00731         cpl_msg_warning(cpl_func, "Expecting even number of files, "
00732                         "ignoring the last of %d file(s)", nfiles);
00733         error_if (nfiles == 1, CPL_ERROR_DATA_NOT_FOUND,
00734                   "At least two files are required");
00735         nfiles--;
00736     }
00737 
00738     nnod = nfiles/2;
00739 
00740     skip_if (nnod <= 0);
00741 
00742     skip_if(irplib_framelist_contains(rawframes, VISIR_PFITS_STRING_FRAME_TYPE,
00743                                        CPL_TYPE_STRING, CPL_FALSE, 0.0));
00744     skip_if(irplib_framelist_contains(rawframes, VISIR_PFITS_DOUBLE_DIT,
00745                                        CPL_TYPE_DOUBLE, CPL_FALSE, 0.0));
00746     /* Can only combine images of the same size */
00747     skip_if (irplib_framelist_contains(rawframes, "NAXIS1",
00748                                        CPL_TYPE_INT, CPL_TRUE, 0.0));
00749     skip_if (irplib_framelist_contains(rawframes, "NAXIS2",
00750                                        CPL_TYPE_INT, CPL_TRUE, 0.0));
00751     skip_if(irplib_framelist_contains(rawframes, VISIR_PFITS_INT_NAXIS3,
00752                                        CPL_TYPE_INT, CPL_FALSE, 0.0));
00753     skip_if(irplib_framelist_contains(rawframes, VISIR_PFITS_INT_CHOP_NCYCLES,
00754                                        CPL_TYPE_INT, CPL_FALSE, 0.0));
00755 
00756     plist1 = irplib_framelist_get_propertylist_const(rawframes, 0);
00757     naxis1 = irplib_pfits_get_int(plist1, "NAXIS1");
00758     naxis2 = irplib_pfits_get_int(plist1, "NAXIS2");
00759     skip_if(0);
00760 
00761     /* Retrieve input parameters */
00762     fnodpos = visir_parameterlist_get_string(parlist, recipename,
00763                                              VISIR_PARAM_NODPOS);
00764     skip_if (0);
00765 
00766     auto_bpm = visir_parameterlist_get_bool(parlist, recipename,
00767                                             VISIR_PARAM_AUTOBPM);
00768     skip_if (0);
00769 
00770     rem_glitch = visir_parameterlist_get_bool(parlist, recipename,
00771                                               VISIR_PARAM_GLITCH);
00772     skip_if (0);
00773 
00774     rem_bad = visir_parameterlist_get_bool(parlist, recipename,
00775                                            VISIR_PARAM_PURGE);
00776     skip_if (0);
00777 
00778     ndestripe = visir_parameterlist_get_int(parlist, recipename,
00779                                             VISIR_PARAM_STRIPITE);
00780     bug_if (0);
00781 
00782     morpho_destripe = ndestripe <= 0 ? CPL_FALSE :
00783         visir_parameterlist_get_bool(parlist, recipename,
00784                                      VISIR_PARAM_STRIPMOR);
00785     bug_if (0);
00786 
00787     no_rem = !rem_glitch && !rem_bad;
00788 
00789     /* Each file corresponds to a nodding position (object=1 or sky=-1) */
00790     /* Return nod_pos array if requested */
00791     nod_pos = nodding_p ? nodding_p : cpl_malloc(nfiles * sizeof(int));
00792     j = 0;
00793     if (fnodpos != NULL && strlen(fnodpos) > 0 && strcmp(fnodpos, ".") != 0) {
00794         /* Get the nodding positions from the user-provided ascii file */
00795         nods_vec = cpl_vector_read(fnodpos);
00796         skip_if (cpl_vector_get_size(nods_vec) != nfiles);
00797         nods_data = cpl_vector_get_data(nods_vec);
00798         skip_if (0);
00799         for (i=0 ; i<nfiles ; i++) {
00800             if ((int)nods_data[i] == 0) {
00801                 nod_pos[i] = 1;
00802                 j++;
00803             } else if ((int)nods_data[i] == 1) {
00804                 nod_pos[i] = -1;
00805                 is_nodding = CPL_TRUE;
00806             } else {
00807                 error_if(1, CPL_ERROR_BAD_FILE_FORMAT,
00808                          "Wrong values in line %d in %s", i+1, fnodpos);
00809             }
00810         }
00811     } else {
00812         skip_if (irplib_framelist_contains(rawframes, VISIR_PFITS_STRING_NODPOS,
00813                                             CPL_TYPE_STRING, CPL_FALSE, 0.0));
00814     }
00815 
00816     if (no_rem) cpl_msg_info(cpl_func, "No glitch removal and no purge of bad "
00817                              "frames requested: Using fast I/O method");
00818 
00819     /* Initialize the Bad Pixel Map */
00820     if (badpix != NULL) {
00821         /* The bpm is provided by the user */
00822         cpl_msg_info(cpl_func, "Loading bad pixel map from %s", badpix);
00823         /* Load the bad pixels image */
00824         bpm_im_int = cpl_image_load(badpix, CPL_TYPE_INT, 0, 0);
00825         skip_if (0);
00826 
00827         /* Convert the map from integer to binary */
00828         bpm_im_bin = cpl_mask_threshold_image_create(bpm_im_int, -0.5, 0.5);
00829         cpl_image_delete(bpm_im_int);
00830         bpm_im_int = NULL;
00831         skip_if (cpl_mask_not(bpm_im_bin));
00832     } else if (auto_bpm) {
00833         /* Initialize the Bad Pixel Map using the hcycle */
00834 
00835         /* i == 0 */
00836         hcycle = visir_load_imagelist(rawframes, 0, CPL_FALSE);
00837         skip_if(0);
00838 
00839         bpm_im_bin =
00840             cpl_mask_threshold_image_create(cpl_imagelist_get(hcycle,0),
00841                                             VISIR_HCYCLE_BPM_THRESHOLD,
00842                                             DBL_MAX);
00843         cpl_imagelist_delete(hcycle);
00844         hcycle = NULL;
00845         skip_if(0);
00846     }
00847 
00848     /* Initialize the flat field image */
00849     if (flat != NULL) {
00850         cpl_msg_info(cpl_func, "Divide the nodded images by the flatfield");
00851         /* Load the flat image */
00852         flat_image = cpl_image_load(flat, CPL_TYPE_FLOAT, 0, 0);
00853         any_if ("Cannot load the flat field %s", flat ? flat : "<NULL>");
00854     }
00855  
00856     /* Get nodding position (if needed) and DIT from the header */
00857     nodded = cpl_imagelist_new();
00858 
00859     tstart = cpl_test_get_walltime();
00860 
00861     /* Fill list with empty images of proper size and type */
00862 
00863     for (i=0; i < nfiles/2 ; i++) {
00864         cpl_image * empty = cpl_image_new(naxis1, naxis2, CPL_TYPE_FLOAT);
00865 
00866         /* i'th image can only be inserted when i-1'th is there,
00867            which prevents parallelism */
00868 
00869         bug_if (cpl_imagelist_set(nodded, empty, i));
00870     }
00871 
00872 #ifdef _OPENMP
00873 #pragma omp parallel for private(i) firstprivate(prev, collapsed)       \
00874                          schedule(static, 2)
00875 #endif
00876     for (i = 0; i < nfiles ; i++) {
00877         cpl_error_code errori = cpl_error_get_code();
00878 
00879         /* The total number of iterations must be pre-determined for the
00880            parallelism to work. In case of an error we can therefore not
00881            break, so instead we skip immediately to the next iteration.
00882            FIXME: This check on didfail does not guarantee that only one
00883                   iteration can cause an error to be dumped, but it is not
00884                   worse than checking on the thread-local state, errori. */
00885         if (didfail) continue;
00886 
00887         do {
00888 
00889         const char * file =
00890             cpl_frame_get_filename(irplib_framelist_get_const(rawframes, i));
00891         const cpl_propertylist * plist;
00892 
00893         double dit;
00894         double factor;
00895 
00896 
00897         plist = irplib_framelist_get_propertylist_const(rawframes, i);
00898         if (plist == NULL) {
00899             errori = cpl_error_set_where(cpl_func);
00900             break;
00901         }
00902 
00903         if (nods_vec == NULL) {
00904             const char * sval = visir_pfits_get_nodpos(plist);
00905             if (sval == NULL) {
00906                 errori = cpl_error_set_message(cpl_func,
00907                                                 CPL_ERROR_DATA_NOT_FOUND,
00908                                                 "Cannot get nodding position "
00909                                                 "for file %d/%d", i+1, nfiles);
00910                 break;
00911             }
00912             if (!strcmp(sval, "A")) {
00913                 nod_pos[i] = 1;
00914                 j++;
00915             } else {
00916                 nod_pos[i] = -1;
00917                 is_nodding = CPL_TRUE;
00918             }
00919         }
00920 
00921         /* Print the file name with its nodding position */
00922         cpl_msg_info(cpl_func, "File %02d: %s (%c)", i+1, file,
00923                      nod_pos[i]==1 ? '+' : '-');
00924 
00925         /* With nodding each pair must have exactly one object observation */
00926         if (is_nodding && (i & 1) == 1 && nod_pos[i] == nod_pos[i-1]) {
00927             cpl_msg_error(cpl_func, "Nodding pair (%d,%d) does not comprise an "
00928                           "on-object (A) and an off-object (B) image: %s", i-1,
00929                           i, nod_pos[i] == 1 ? "A" : "B");
00930         }
00931 
00932         /* Compute the normalization factor from the Detector Integration Time */
00933         dit = visir_pfits_get_dit(plist);
00934         if (cpl_error_get_code()) {
00935             errori = cpl_error_set_where(cpl_func);
00936             break;
00937         }
00938 
00939         if (dit <= 0) {
00940             errori = cpl_error_set_message(cpl_func,
00941                                             CPL_ERROR_ILLEGAL_INPUT,
00942                                             "DIT in file %d/%d is too small: "
00943                                             "%g", i+1, nfiles, dit);
00944             break;
00945         }
00946 
00947         factor = dit * nod_pos[i] * 2.0;
00948 
00949         if (no_rem){
00950             collapsed = visir_load_average(file, plist);
00951         } else {
00952             in = visir_load_intermint(rawframes, i);
00953             if (in == NULL) {
00954                 errori = cpl_error_set_message(cpl_func,
00955                                                 CPL_ERROR_ILLEGAL_INPUT,
00956                                                 "Could not load image set %d",
00957                                                 i+1);
00958                 break;
00959             }
00960 
00961             /* Convert the image lists from 'INTERM' to A-B' */
00962             if (visir_imagelist_unpack_interm(in)) {
00963                 errori = cpl_error_set_message(cpl_func,
00964                                                 cpl_error_get_code(),
00965                                                 "Failure for file %d/%d",
00966                                                 i+1, nfiles);
00967                 break;
00968             }
00969 
00970             /* Remove the glitch in each A-B image in each input cube
00971                if requested */
00972             if (rem_glitch) {
00973                 int jj;
00974                 for (jj=0 ; jj < cpl_imagelist_get_size(in); jj++) {
00975                     if (visir_rem_glitch(cpl_imagelist_get(in, jj))) {
00976                         errori = cpl_error_set_message(cpl_func,
00977                                                         cpl_error_get_code(),
00978                                                         "Could not remove "
00979                                                         "glitch in image %d in "
00980                                                         "set %d", jj+1, i+1);
00981                         break;
00982                     }
00983                 }
00984             }
00985 
00986             /* Remove the bad A-B images in each input file/cube if requested */
00987             if (rem_bad) {
00988                 cpl_msg_info(cpl_func, "Remove the bad A-B input images");
00989                 if (visir_rem_bad_images(in)) {
00990                     errori = cpl_error_set_message(cpl_func,
00991                                                     cpl_error_get_code(),
00992                                                     "Could not remove bad "
00993                                                     "images in list %d", i+1);
00994                     break;
00995                 }
00996             }
00997             /* Average each cube */
00998             collapsed = cpl_imagelist_collapse_create(in);
00999 
01000             cpl_imagelist_delete(in);
01001             in = NULL;
01002 
01003         }
01004 
01005         if (cpl_error_get_code()) {
01006             errori = cpl_error_set_message(cpl_func, cpl_error_get_code(),
01007                                             "Failure for file %d/%d",
01008                                             i+1, nfiles);
01009             break;
01010         }
01011         /* Normalise to have ADU/s. */
01012         /* Also divide with 2 to achieve average of image pair */
01013         if (cpl_image_divide_scalar(collapsed, 2*factor)) {
01014             errori = cpl_error_set_message(cpl_func, cpl_error_get_code(),
01015                                             "Failure for file %d/%d",
01016                                             i+1, nfiles);
01017             break;
01018         }
01019 
01020         /* Each pair of input files gives a nodded image in nodded */
01021         if (i & 1) {
01022             if (cpl_image_add(prev, collapsed)) {
01023                 errori = cpl_error_set_message(cpl_func, cpl_error_get_code(),
01024                                                 "Failure for file %d/%d",
01025                                                 i+1, nfiles);
01026                 break;
01027             }
01028             cpl_image_delete(collapsed);
01029             collapsed = NULL;
01030 
01031             /* At this point prev is the image to be put into
01032                the list of nodded images */
01033 
01034             if (bpm_im_bin != NULL) {
01035                 /* Apply the bad pixels cleaning */
01036                 if (cpl_image_reject_from_mask(prev, bpm_im_bin)) {
01037                     errori = cpl_error_set_message(cpl_func,
01038                                                     cpl_error_get_code(),
01039                                                     "Failure for file %d/%d",
01040                                                     i+1, nfiles);
01041                     break;
01042                 }
01043                 if (cpl_detector_interpolate_rejected(prev)) {
01044                     errori = cpl_error_set_message(cpl_func,
01045                                                     cpl_error_get_code(),
01046                                                     "Failure for file %d/%d",
01047                                                     i+1, nfiles);
01048                     break;
01049                 }
01050             }
01051 
01052             if (ndestripe > 0)
01053                 if(visir_destripe_image(prev, ndestripe,
01054                                         VISIR_DESTRIPE_DETECT,
01055                                         VISIR_DESTRIPE_DETECT_THRESHOLD,
01056                                         morpho_destripe)) {
01057                     errori = cpl_error_set_message(cpl_func,
01058                                                     cpl_error_get_code(),
01059                                                     "Failure for file %d/%d",
01060                                                     i+1, nfiles);
01061                     break;
01062                 }
01063 
01064             if (flat_image != NULL) {
01065                 /* Apply the flatfield correction */
01066                 if (cpl_image_divide(prev, flat_image)) {
01067                     errori = cpl_error_set_message(cpl_func,
01068                                                     cpl_error_get_code(),
01069                                                     "Failure for file %d/%d",
01070                                                     i+1, nfiles);
01071                     break;
01072                 }
01073             }
01074 
01075             if (cpl_imagelist_set(nodded, prev, i/2)) {
01076                 errori = cpl_error_set_message(cpl_func, cpl_error_get_code(),
01077                                                "Failure for file %d/%d",
01078                                                i+1, nfiles);
01079                 break;
01080             }
01081             prev = NULL;
01082         } else {
01083             prev = collapsed;
01084             collapsed = NULL;
01085         }
01086         } while (0);
01087 
01088         if (errori) {
01089 #ifdef _OPENMP
01090             /* Cannot access these errors after the join,
01091                so dump them now. :-(((((((((((((((((((( */
01092             cpl_errorstate_dump(cleanstate, CPL_FALSE, NULL);
01093             cpl_errorstate_set(cleanstate);
01094 
01095             /* Need to deallocate the thread-private instances in the loop */
01096             cpl_image_delete(prev); prev = NULL;
01097             cpl_image_delete(collapsed); collapsed = NULL;
01098 
01099 #pragma omp critical(visir_inputs_combine)
01100 #endif
01101             didfail = errori;
01102         }
01103     }
01104 
01105     error_if(didfail, didfail, "Failed to create %d nodded images from %d "
01106              "files", nnod, nfiles);
01107 
01108     tstop = cpl_test_get_walltime();
01109     cpl_msg_info(cpl_func, "Time to create %d nodded images [s]: %g", nnod,
01110                  tstop - tstart);
01111 
01112     cpl_vector_delete(nods_vec);
01113     nods_vec = NULL;
01114 
01115     cpl_image_delete(flat_image);
01116     flat_image = NULL;
01117 
01118     cpl_mask_delete(bpm_im_bin);
01119     bpm_im_bin = NULL;
01120 
01121     if (nod_pos != nodding_p) cpl_free(nod_pos);
01122     nod_pos = NULL;
01123     
01124     error_if(is_nodding && j != nnod, CPL_ERROR_INCOMPATIBLE_INPUT,
01125          "With nodding exactly half of the images "
01126              "must be on-object, not %d of %d", j, 2*nnod);
01127 
01128     if (do_spc_fix) {
01129         const double ksi   = visir_parameterlist_get_double(parlist, recipename,
01130                                                           VISIR_PARAM_SPECSKEW);
01131         const double eps   = visir_parameterlist_get_double(parlist, recipename,
01132                                                             VISIR_PARAM_VERTARC);
01133         const double delta = visir_parameterlist_get_double(parlist, recipename,
01134                                                             VISIR_PARAM_HORIARC);
01135         const double phi   = visir_parameterlist_get_double(parlist, recipename,
01136                                                           VISIR_PARAM_SLITSKEW);
01137         const int doplot   = visir_parameterlist_get_int(parlist, recipename,
01138                                                          VISIR_PARAM_PLOT);
01139 
01140 
01141         skip_if (0);
01142 
01143         images = cpl_malloc(nnod * sizeof(cpl_image*));
01144 
01145         for (j = 0; j < nnod; j++) images[j] = cpl_imagelist_get(nodded, j);
01146 
01147         skip_if (visir_spc_det_fix(images, nnod, CPL_TRUE, wlen, resol,
01148                                    phi, ksi, eps, delta, doplot));
01149     }
01150 
01151     end_skip;
01152 
01153     cpl_msg_set_time_off();
01154 
01155     cpl_free(images);
01156     cpl_imagelist_delete(in);
01157 
01158     if (nod_pos != nodding_p) cpl_free(nod_pos);
01159     cpl_vector_delete(nods_vec);
01160     cpl_image_delete(bpm_im_int);
01161     cpl_mask_delete(bpm_im_bin);
01162     cpl_image_delete(collapsed);
01163     cpl_image_delete(prev);
01164     if (cpl_error_get_code() && nodded != NULL) {
01165         cpl_imagelist_delete(nodded);
01166         nodded = NULL;
01167     }
01168 
01169     return nodded;
01170 }
01171 
01172 /*----------------------------------------------------------------------------*/
01219 /*----------------------------------------------------------------------------*/
01220 cpl_image ** visir_img_recombine(const char * recipename,
01221                                  const cpl_parameterlist * parlist,
01222                                  const irplib_framelist  * rawframes,
01223                                  const char        * badpix,
01224                                  const char        * flat,
01225                                  cpl_geom_combine    combine_mode,
01226                                  cpl_boolean       * pdid_resize,
01227                                  cpl_boolean         do_spc_fix,
01228                                  double              wlen,
01229                                  visir_spc_resol     resol)
01230 {
01231     int                     nfiles;
01232     int                 *   nod_pos = NULL;
01233     cpl_imagelist       *   nodded = NULL;
01234     int                     nnod;
01235     cpl_bivector        *   offsets_est = NULL;
01236     cpl_bivector        *   objs = NULL;
01237     cpl_image           **  combined = NULL;
01238     const cpl_vector    *   sigmas = NULL;
01239     double                  xoff, yoff;
01240     cpl_propertylist    *   qclist = cpl_propertylist_new();
01241     int                     i;
01242 
01243 
01244     bug_if (0);
01245 
01246     bug_if (recipename == NULL);
01247     bug_if (parlist    == NULL);
01248     bug_if (rawframes  == NULL);
01249     bug_if (pdid_resize  == NULL);
01250 
01251     /* Get the number of files */
01252     nfiles = irplib_framelist_get_size(rawframes);
01253 
01254     /* There should be an even number of files */
01255     if (nfiles % 2) {
01256         cpl_msg_warning(cpl_func, "Expecting even number of files, "
01257                         "ignoring the last of %d file(s)", nfiles);
01258         error_if (nfiles == 1, CPL_ERROR_DATA_NOT_FOUND,
01259                   "At least two files are required");
01260         nfiles--;
01261     }
01262 
01263     skip_if ( nfiles <= 0);
01264 
01265     /* Each file corresponds to a nodding position (object=1 or sky=-1) */
01266     nod_pos = cpl_malloc(nfiles * sizeof(int));
01267 
01268     /* Combine the input frames into the nodded images */
01269     cpl_msg_info(cpl_func, "Combining the input frames into the nodded images");
01270     nodded = visir_inputs_combine(recipename, parlist, rawframes, badpix, flat,
01271                                   nod_pos, do_spc_fix, wlen, resol);
01272 
01273     skip_if (nodded == NULL);
01274     nnod = cpl_imagelist_get_size(nodded);
01275 
01276     /* If only one nodded image, the work is finished */
01277     if (nnod == 1) {
01278 
01279         combined = cpl_malloc(2*sizeof(cpl_image*)); 
01280         combined[1] = NULL; /* In case the unset fails */
01281 
01282         combined[0] = cpl_imagelist_unset(nodded, 0);
01283         bug_if (combined[0] == NULL);
01284 
01285         combined[1] = cpl_image_new(cpl_image_get_size_x(combined[0]),
01286                                     cpl_image_get_size_y(combined[0]),
01287                                     CPL_TYPE_INT);
01288         bug_if (combined[1] == NULL);
01289 
01290         /* Set all pixel values to 1 */
01291         bug_if(cpl_image_threshold(combined[1], 1.0, 1.0, 1.0, 1.0));
01292 
01293         *pdid_resize = CPL_FALSE;
01294 
01295     } else {
01296         const double psigmas[] = {5, 2, 1, 0.5};
01297         const char * sval;
01298         const char * offsets;
01299         const char * objects;
01300         int sx, sy, mx, my;
01301         int rej_low, rej_high;
01302         cpl_boolean refine;
01303 
01304 
01305         refine = visir_parameterlist_get_bool(parlist, recipename,
01306                                               VISIR_PARAM_REFINE);
01307         skip_if (0);
01308 
01309         offsets = visir_parameterlist_get_string(parlist, recipename,
01310                                                  VISIR_PARAM_OFFSETS);
01311         skip_if (0);
01312 
01313         objects = visir_parameterlist_get_string(parlist, recipename,
01314                                                  VISIR_PARAM_OBJECTS);
01315         skip_if (0);
01316 
01317         sval = visir_parameterlist_get_string(parlist, recipename,
01318                                               VISIR_PARAM_XCORR);
01319         skip_if (0);
01320 
01321         if (sscanf(sval, "%d-%d-%d-%d", &sx, &sy, &mx, &my) != 4)
01322             skip_if (sscanf(sval, "%d %d %d %d", &sx, &sy, &mx, &my) != 4);
01323 
01324 
01325         sval = visir_parameterlist_get_string(parlist, recipename,
01326                                               VISIR_PARAM_REJECT);
01327         skip_if (0);
01328 
01329         if (sscanf(sval, "%d-%d", &rej_low, &rej_high) !=2 )
01330             skip_if (sscanf(sval, "%d %d", &rej_low, &rej_high) !=2 );
01331 
01332         /* Get the offsets estimation of each input file pair */
01333         cpl_msg_info(cpl_func, "Get the offsets estimation");
01334         if (offsets != NULL && strlen(offsets) && strcmp(offsets, ".") != 0) {
01335             /* A file has been provided on the command line */
01336             offsets_est = cpl_bivector_read(offsets);
01337             skip_if (offsets_est==NULL);
01338 
01339             error_if (cpl_bivector_get_size(offsets_est) != nnod,
01340                       CPL_ERROR_BAD_FILE_FORMAT, "The offsets file %s must "
01341                       "have %d entries, not %d", offsets, nnod,
01342                       (int)cpl_bivector_get_size(offsets_est));
01343         } else {
01344             double * offsets_est_x;
01345             double * offsets_est_y;
01346             double   xoff0 = 0.0;  /* Avoid (false) uninit warning */
01347             double   yoff0 = 0.0;  /* Avoid (false) uninit warning */
01348             
01349             /* Get the offsets from the header */
01350             offsets_est = cpl_bivector_new(nnod);
01351             offsets_est_x = cpl_bivector_get_x_data(offsets_est);
01352             offsets_est_y = cpl_bivector_get_y_data(offsets_est);
01353 
01354             skip_if (0);
01355 
01356             offsets_est_x[0] = 0.0;
01357             offsets_est_y[0] = 0.0;
01358 
01359             for (i=0; i < nnod ; i++) {
01360                 const cpl_propertylist * plist;
01361 
01362                 /* Skip every other, non-object frame */ 
01363                 const int iframe = nod_pos[2*i] == 1 ? 2*i : 2*i+1;
01364 
01365                 plist = irplib_framelist_get_propertylist_const(rawframes,
01366                                                                 iframe);
01367                 skip_if(plist == NULL);
01368 
01369                 xoff = visir_pfits_get_cumoffsetx(plist);
01370                 yoff = visir_pfits_get_cumoffsety(plist);
01371 
01372                 skip_if (0);
01373 
01374                 if (i == 0) {
01375                     xoff0 = xoff;
01376                     yoff0 = yoff;
01377                 } else {
01378                     /* Subtract the first offset from all offsets */
01379                     offsets_est_x[i] = xoff0 - xoff;
01380                     offsets_est_y[i] = yoff0 - yoff;
01381                 }
01382             }
01383         }
01384         cpl_free(nod_pos);
01385         nod_pos = NULL;
01386     
01387         /* Read the provided objects file if provided
01388            - if a file has been provided on the command line */
01389         if (objects != NULL && strlen(objects) > 0 && strcmp(offsets, ".") != 0) {
01390             objs = cpl_bivector_read(objects);
01391             any_if ("Could not read objects from %s", objects);
01392         }
01393    
01394         cpl_msg_info(cpl_func, "Recombining the list of nodded images using "
01395                      "mode: %d (I=%d:U=%d:F=%d), rej-lo=%d, rej-hi=%d",
01396                      combine_mode, CPL_GEOM_INTERSECT, CPL_GEOM_UNION,
01397                      CPL_GEOM_FIRST, rej_low, rej_high);
01398 
01399         if (cpl_msg_get_level() <= CPL_MSG_DEBUG) {
01400             cpl_msg_debug(cpl_func, "The offsets for the recombination:");
01401             cpl_bivector_dump(offsets_est, stdout);
01402         }
01403 
01404         sigmas = cpl_vector_wrap(4, (double*)psigmas); /* Not changed */
01405         combined = cpl_geom_img_offset_combine(nodded, offsets_est, refine,
01406                                                objs, sigmas, NULL, sx, sy,
01407                                                mx, my, rej_low, rej_high,
01408                                                combine_mode);
01409         any_if("Could not recombine the images");
01410 
01411         *pdid_resize = (cpl_boolean)(cpl_image_get_size_x(combined[0])
01412                 != cpl_image_get_size_x(cpl_imagelist_get_const(nodded, 0)) ||
01413                 cpl_image_get_size_y(combined[0])
01414                 != cpl_image_get_size_y(cpl_imagelist_get_const(nodded, 0)));
01415     }
01416 
01417     if (visir_parameterlist_get_int(parlist, recipename, VISIR_PARAM_PLOT) > 0)
01418         visir_image_plot("", "t 'The combined image'", "", combined[0]);
01419 
01420     end_skip;
01421 
01422     cpl_propertylist_delete(qclist);
01423     cpl_free(nod_pos);
01424     cpl_imagelist_delete(nodded);
01425     cpl_bivector_delete(offsets_est);
01426     cpl_bivector_delete(objs);
01427     cpl_vector_unwrap((cpl_vector*)sigmas);
01428 
01429     return combined;
01430 }
01431 
01432 /*----------------------------------------------------------------------------*/
01455 /*----------------------------------------------------------------------------*/
01456 cpl_imagelist * visir_load_hcycle(const irplib_framelist * rawframes, int pos)
01457 {
01458     return visir_load_imagelist(rawframes, pos, CPL_FALSE);
01459 }
01460 
01461 /*----------------------------------------------------------------------------*/
01472 /*----------------------------------------------------------------------------*/
01473 cpl_error_code visir_image_reject_hot(cpl_image * self, const char * bpmfile)
01474 {
01475 
01476     cpl_image  * im_bpm = NULL;
01477     cpl_mask   * bpm = NULL;
01478     const int upper = VISIR_HCYCLE_BPM_THRESHOLD;
01479 
01480 
01481     skip_if (0);
01482 
01483     skip_if (self == NULL);
01484 
01485     if (bpmfile == NULL) {
01486         bpm = cpl_mask_threshold_image_create(self, upper, DBL_MAX);
01487         skip_if (0);
01488     } else {
01489 
01490         /* The bpm is provided by the user */
01491         cpl_msg_info(cpl_func, "Clean user specified bad pixels");
01492         /* Load the bad pixel image */
01493         im_bpm = cpl_image_load(bpmfile, CPL_TYPE_INT, 0, 0);
01494         any_if ("Could not load the bad pixel map %s",
01495                 bpmfile ? bpmfile : "<NULL>");
01496         /* Convert the map from integer to binary */
01497         bpm = cpl_mask_threshold_image_create(im_bpm, -0.5, 0.5);
01498         skip_if (0);
01499         cpl_image_delete(im_bpm);
01500         im_bpm = NULL;
01501 
01502         skip_if (cpl_mask_not(bpm));
01503     }
01504 
01505     skip_if (cpl_image_reject_from_mask(self, bpm));
01506 
01507     end_skip;
01508 
01509     cpl_image_delete(im_bpm);
01510     cpl_mask_delete(bpm);
01511 
01512     return cpl_error_get_code();
01513 
01514 }
01515 
01516 
01517 /*----------------------------------------------------------------------------*/
01524 /*----------------------------------------------------------------------------*/
01525 cpl_imagelist * visir_imagelist_load_last(const irplib_framelist * rawframes)
01526 {
01527     cpl_imagelist * self = NULL;
01528     int naxis3;
01529 
01530     /* Verify that NAXIS3 is the same in all files */
01531     skip_if(irplib_framelist_contains(rawframes, VISIR_PFITS_INT_NAXIS3,
01532                                       CPL_TYPE_INT, CPL_TRUE, 0.0));
01533 
01534     naxis3 = visir_pfits_get_naxis3(irplib_framelist_get_propertylist_const(
01535                                                                       rawframes,
01536                                                                       0));
01537 
01538     /* Load the image set */
01539     self = irplib_imagelist_load_framelist(rawframes, CPL_TYPE_FLOAT, naxis3-1,
01540                                            0);
01541 
01542     skip_if (self == NULL);
01543 
01544     end_skip;
01545 
01546     return self;
01547 
01548 }
01549 
01550 
01551 /*----------------------------------------------------------------------------*/
01561 /*----------------------------------------------------------------------------*/
01562 cpl_imagelist * visir_load_imagelist(const irplib_framelist * rawframes,
01563                                      int pos, cpl_boolean is_interm)
01564 {
01565     cpl_imagelist    * self = NULL;
01566     cpl_image        * image = NULL;
01567     const char       * file
01568         = cpl_frame_get_filename(irplib_framelist_get_const(rawframes, pos));
01569     int                naxis3, nchop;
01570     visir_cube_type    cube_type;
01571     const cpl_error_code code = visir_get_type(rawframes, pos, &cube_type,
01572                                                &naxis3, &nchop);
01573     int            plane_step;
01574     int            nsize;
01575     int            iplane;
01576     int            i;
01577 
01578     /* Check the error code */
01579     skip_if (code);
01580     bug_if (file == NULL);
01581 
01582     if (cube_type == VISIR_CUBE1) {
01583         /* All INTERM frames are in the first part of the cube */
01584         iplane = is_interm ? 0 : nchop;
01585         /* - followed by a single Half-cycle image */
01586         nsize  = is_interm ? nchop : 1;
01587         plane_step = 1;
01588     } else if (naxis3 == 1) {
01589         iplane = 0;
01590         nsize  = 1;
01591         plane_step = 1;
01592     } else {
01593         /* Each INTERM frame follows the Half-cycle frame */
01594         iplane = is_interm ? 1 : 0;
01595         nsize  = nchop;
01596         plane_step = 2;
01597     }
01598 
01599     self = cpl_imagelist_new();
01600 
01601     for (i=0 ; i < nsize; i++, iplane += plane_step) {
01602 
01603         image = cpl_image_load(file, CPL_TYPE_FLOAT, iplane, 0);
01604         skip_if (image == NULL);
01605 
01606         skip_if (!is_interm && visir_offset_hcycle(image));
01607 
01608         skip_if (cpl_imagelist_set(self, image, i));
01609 
01610         image = NULL;
01611     }
01612 
01613     skip_if (i < nsize);
01614 
01615     end_skip;
01616 
01617     if (cpl_error_get_code()) {
01618         if (file != NULL) cpl_msg_warning(cpl_func, "Could not load the %s "
01619                                           "frame(s) from: %s",
01620                                           is_interm ? "INTERM" : "Half-Cycle",
01621                                           file);
01622         cpl_image_delete(image);
01623         cpl_imagelist_delete(self);
01624         self = NULL;
01625     }
01626 
01627     return self;
01628 }
01629 
01630 
01633 /*----------------------------------------------------------------------------*/
01657 /*----------------------------------------------------------------------------*/
01658 static cpl_imagelist * visir_load_intermint(const irplib_framelist * rawframes,
01659                                             int pos)
01660 {
01661     return visir_load_imagelist(rawframes, pos, CPL_TRUE);
01662 
01663 }
01664 
01665 /*----------------------------------------------------------------------------*/
01674 /*----------------------------------------------------------------------------*/
01675 static cpl_image * visir_load_average(const char * file,
01676                                       const cpl_propertylist * plist)
01677 {
01678     cpl_errorstate cleanstate = cpl_errorstate_get();
01679     cpl_image        * self = NULL;
01680     int                nchop, naxis3;
01681 
01682 
01683     skip_if (0);
01684     skip_if (file   == NULL);
01685     skip_if (plist == NULL);
01686 
01687     naxis3 = visir_pfits_get_naxis3(plist);
01688     nchop = visir_pfits_get_chop_ncycles(plist);
01689 
01690     skip_if (0);
01691 
01692     if (nchop == 0 && naxis3 == 1) {
01693         self = cpl_image_load(file, CPL_TYPE_FLOAT, 0, 0);
01694     } else {
01695         const char   * sval;
01696         /* If nchop == 1 (and naxis3 == 3) the data unit is both a valid CUBE1
01697            and a valid CUBE2; Set plane_offset as if the frame type is CUBE2 */
01698         const int      plane_offset = (naxis3 == 2 * nchop + 1) ? 2 : 3;
01699 
01700 
01701         error_if (nchop <= 0, CPL_ERROR_BAD_FILE_FORMAT, "CHOP NCYCLES in %s "
01702                   "is non-positive (and NAXIS3=%d): %d", file, naxis3, nchop);
01703 
01704         error_if (plane_offset == 3 && naxis3 != nchop+2,
01705                   CPL_ERROR_BAD_FILE_FORMAT, "NAXIS3=%d and CHOP NCYCLES=%d "
01706                   "in %s is not a valid VISIR INTERM+Half-Cycle format", naxis3,
01707                   nchop, file);
01708 
01709         if (plane_offset == 3 && nchop > 1)
01710             cpl_msg_debug(cpl_func, "%s has %d INTERM-frames and one Half-"
01711                           "Cycle frame (old CUBE1-format)", file, nchop);
01712 
01713         /* Check the data format */
01714         sval = visir_pfits_get_frame_type(plist);
01715         if (sval == NULL) {
01716             /* Has warned about missing frame type card */
01717             visir_error_reset("Could not get FITS key");
01718             /* Don't know whether or not to expect CUBE1 or CUBE2 */
01719         } else if (strlen(sval) == 0) {
01720             /* Don't know whether or not to expect CUBE1 or CUBE2 */
01721         } else if (plane_offset == 3) {
01722             if (strcmp(sval, "CUBE2")==0)
01723                 cpl_msg_error(cpl_func, "%s has FRAM TYPE = CUBE2, but NAXIS3="
01724                                 "%d and CHOP NCYCLES=%d imply a CUBE1. Assuming"
01725                                 " the frame type is really CUBE1",  file,
01726                                 naxis3, nchop);
01727         } else if (nchop > 1) {
01728             /* if nchop == 1 format can be CUBE1 or CUBE2 */
01729             if (strcmp(sval, "CUBE1")==0)
01730                 cpl_msg_error(cpl_func, "%s has FRAM TYPE = CUBE1, but NAXIS3="
01731                                 "%d and CHOP NCYCLES=%d imply a CUBE2. Assuming"
01732                                 "the frame type is really CUBE2",  file,
01733                                 naxis3, nchop);
01734         } 
01735 
01736         /* Load last INTERM frame */
01737         self = cpl_image_load(file, CPL_TYPE_FLOAT, naxis3-plane_offset, 0);
01738 
01739     }
01740 
01741     skip_if (0);
01742 
01743     end_skip;
01744 
01745     if (cpl_error_get_code()) {
01746         cpl_msg_warning(cpl_func, "Could not load the last INTERM frame from: "
01747                         "%s", file ? file : "<NULL>");
01748         cpl_image_delete(self);
01749         self = NULL;
01750     }
01751 
01752     return self;
01753 }
01754 
01755 /*----------------------------------------------------------------------------*/
01778 /*----------------------------------------------------------------------------*/
01779 static cpl_error_code visir_imagelist_unpack_interm(cpl_imagelist * self) 
01780 {
01781     cpl_image * iprev;
01782     cpl_image * image;
01783     const int   n = cpl_imagelist_get_size(self);
01784     int         i;
01785 
01786 
01787     skip_if (0);
01788 
01789     if (n == 1) return CPL_ERROR_NONE;
01790 
01791     iprev = cpl_imagelist_get(self, n - 1);
01792 
01793     skip_if (0);
01794 
01795     skip_if (cpl_image_multiply_scalar(iprev, n));
01796 
01797     /* Loop on the images - with first and last iteration peeled off */
01798     for (i = n-1 ; i > 1 ; i--, iprev = image) {
01799         image = cpl_imagelist_get(self, i-1);
01800 
01801         skip_if (0);
01802 
01803         skip_if (cpl_image_multiply_scalar(image, i));
01804 
01805         skip_if (cpl_image_subtract(iprev, image));
01806 
01807     }
01808 
01809     image = cpl_imagelist_get(self, 0);
01810 
01811     skip_if (0);
01812 
01813     skip_if (cpl_image_subtract(iprev, image));
01814 
01815     end_skip;
01816 
01817     return cpl_error_get_code();
01818 }
01819 
01820 /*----------------------------------------------------------------------------*/
01833 /*----------------------------------------------------------------------------*/
01834 static cpl_error_code visir_rem_glitch(cpl_image * glitchy) 
01835 {
01836     cpl_image * med_filt = NULL;
01837     cpl_mask  * bpm = NULL;
01838     cpl_mask  * kernel = cpl_mask_new(3, 3);
01839     double      mean, stdev;
01840     double      low_thresh, high_thresh;
01841     const int   nx = cpl_image_get_size_x(glitchy);
01842     const int   ny = cpl_image_get_size_y(glitchy);
01843     int         i;
01844 
01845     /* Some heuristic constants */
01846     double          factor1 = 3.0;
01847     double          factor2 = 10.0;
01848     const int       niterations = 5;
01849     const double    median_corr = 1.5;
01850 
01851     bug_if (0);
01852 
01853     /* Create the filtering kernel */
01854     bug_if(cpl_mask_not(kernel));
01855     
01856     /* Apply a 3x3 median filter to the input image  */
01857     med_filt = cpl_image_new(cpl_image_get_size_x(glitchy),
01858                              cpl_image_get_size_y(glitchy),
01859                              cpl_image_get_type(glitchy));
01860     bug_if(med_filt == NULL);
01861     bug_if(cpl_image_filter_mask(med_filt, glitchy, kernel, CPL_FILTER_MEDIAN,
01862                                  CPL_BORDER_FILTER));
01863     cpl_mask_delete(kernel);
01864     kernel = NULL;
01865 
01866     /* Noise is glitchy - med_filt */
01867     skip_if (cpl_image_subtract(glitchy, med_filt));
01868 
01869     /* niterations iterations */
01870     for (i=0 ; i < niterations ; i++) {
01871         /* Compute mean and stdev */
01872         mean = cpl_image_get_mean(glitchy);
01873         stdev = cpl_image_get_stdev(glitchy);
01874         
01875         skip_if (0);
01876 
01877         /* Set the thresholds */
01878         low_thresh  = mean - factor1 * stdev;
01879         high_thresh = mean + factor1 * stdev;
01880 
01881         /* Identify where mean-factor1*stdev < glitchy < mean+factor1*stdev */
01882         bpm = cpl_mask_threshold_image_create(glitchy,low_thresh,high_thresh);
01883         skip_if (cpl_mask_not(bpm));
01884         skip_if (cpl_image_reject_from_mask(glitchy, bpm));
01885         cpl_mask_delete(bpm);
01886         bpm = NULL;
01887 
01888         /* Test the number of bad pixels */
01889         skip_if (cpl_image_count_rejected(glitchy) == nx*ny);
01890     }
01891 
01892     /* Last iteration */
01893     /* Compute mean and stdev */
01894     mean = cpl_image_get_mean(glitchy);
01895     stdev = cpl_image_get_stdev(glitchy) * median_corr;
01896 
01897     skip_if (0);
01898 
01899     low_thresh  = mean - factor2 * stdev;
01900     high_thresh = mean + factor2 * stdev;
01901 
01902     bpm = cpl_mask_threshold_image_create(glitchy, low_thresh, high_thresh);
01903     skip_if (cpl_mask_not(bpm));
01904     skip_if (cpl_image_reject_from_mask(glitchy, bpm));
01905     cpl_mask_delete(bpm);
01906     bpm = NULL;
01907 
01908     /* Test the number of bad pixels */
01909     skip_if (cpl_image_count_rejected(glitchy) == nx*ny);
01910     
01911     /* Set the bad pixels to 0 */
01912     skip_if (cpl_image_fill_rejected(glitchy, 0.0));
01913     skip_if (cpl_image_accept_all(glitchy));
01914 
01915     /* Reconstruct the corrected image */
01916     skip_if (cpl_image_add(glitchy, med_filt));
01917 
01918     end_skip;
01919 
01920     cpl_image_delete(med_filt);
01921     cpl_mask_delete(bpm);
01922     cpl_mask_delete(kernel);
01923     
01924     return cpl_error_get_code();
01925 }
01926 
01927 /*----------------------------------------------------------------------------*/
01938 /*----------------------------------------------------------------------------*/
01939 static cpl_error_code visir_rem_bad_images(cpl_imagelist * in) 
01940 {
01941     cpl_vector * medians = NULL;
01942     cpl_vector * stdevs = NULL;
01943     cpl_vector * selection = NULL;
01944     double       mean_medians, mean_stdevs, stdev_medians, stdev_stdevs;
01945     const double threshold = 3;
01946     const int    nima = cpl_imagelist_get_size(in);
01947     int          i;
01948 
01949 
01950     /* This will catch a NULL input */
01951     skip_if (0);
01952 
01953     if (nima <= 3) return CPL_ERROR_NONE;
01954     
01955     /* Create medians and stdevs arrays */
01956     medians = cpl_vector_new(nima);
01957     stdevs = cpl_vector_new(nima);
01958 
01959     /* Compute the statistics */
01960     for (i=0 ; i < nima ; i++) {
01961         cpl_stats * stats = cpl_stats_new_from_image(cpl_imagelist_get(in, i),
01962                                             CPL_STATS_STDEV | CPL_STATS_MEDIAN);
01963 
01964         cpl_vector_set(medians, i, cpl_stats_get_median(stats));
01965         cpl_vector_set(stdevs,  i, cpl_stats_get_stdev(stats));
01966         cpl_stats_delete(stats); /* :-( */
01967     }
01968 
01969     skip_if( 0);
01970 
01971     /* Get the stats on these arrays */
01972     mean_medians  = cpl_vector_get_mean(medians);
01973     stdev_medians = cpl_vector_get_stdev(medians);
01974     mean_stdevs   = cpl_vector_get_mean(stdevs);
01975     stdev_stdevs  = cpl_vector_get_stdev(stdevs);
01976 
01977     skip_if (cpl_vector_subtract_scalar(medians, mean_medians));
01978     skip_if (cpl_vector_subtract_scalar(stdevs,  mean_stdevs));
01979 
01980     stdev_medians *= threshold;
01981     stdev_stdevs  *= threshold;
01982 
01983     /* Create the selection vector */
01984     selection = cpl_vector_new(nima);
01985     skip_if( cpl_vector_fill(selection, 0)); /* Flag all as good */
01986     for (i=0 ; i < nima ; i++) {
01987         if (fabs(cpl_vector_get(medians, i)) <= stdev_medians &&
01988             fabs(cpl_vector_get(stdevs,  i)) <= stdev_stdevs) continue;
01989 
01990         cpl_vector_set(selection, i, -1);
01991         cpl_msg_info(cpl_func, "Image %d of %d rejected: median=%g, stdev=%g",
01992                      i+1, nima, stdev_medians, stdev_stdevs);
01993     }
01994 
01995     /* Purge the bad images in the images set */
01996     cpl_imagelist_erase(in, selection);
01997 
01998     end_skip;
01999 
02000     cpl_vector_delete(medians);
02001     cpl_vector_delete(stdevs);
02002     
02003     cpl_vector_delete(selection);
02004 
02005     return CPL_ERROR_NONE;
02006 
02007 }
02008 
02009 /*----------------------------------------------------------------------------*/
02018 /*----------------------------------------------------------------------------*/
02019 static cpl_error_code visir_offset_hcycle(cpl_image * hcycle) 
02020 {
02021     double minval;
02022 
02023 
02024     skip_if (0);
02025 
02026     skip_if (cpl_image_add_scalar(hcycle, VISIR_HCYCLE_OFFSET));
02027 
02028     minval = cpl_image_get_min(hcycle);
02029 
02030     /* It seems that the offset really is VISIR_HCYCLE_OFFSET-1, warn if not */
02031     if (minval < 1) cpl_msg_warning(cpl_func, "HCycle pixel minval: %g", minval);
02032 
02033     end_skip;
02034 
02035     return CPL_ERROR_NONE;
02036 }
02037 
02038 /*----------------------------------------------------------------------------*/
02050 /*----------------------------------------------------------------------------*/
02051 static
02052 cpl_image ** visir_img_collapse_beam_four(cpl_propertylist       * qclist,
02053                                           const cpl_image        * self,
02054                                           const cpl_image        * inverse,
02055                                           double                   eccmax,
02056                                           double                   pthrow,
02057                                           const cpl_propertylist * plist)
02058 {
02059 
02060     cpl_image    ** combined = NULL;
02061     const int       nx = cpl_image_get_size_x(self);
02062     const int       ny = cpl_image_get_size_y(self);
02063     const cpl_type  type = cpl_image_get_type(self);
02064     cpl_imagelist * list4 = cpl_imagelist_new();
02065     cpl_image     * swrap = type == CPL_TYPE_DOUBLE
02066         ? cpl_image_wrap_double(nx, ny, cpl_image_get_data((cpl_image*)self))
02067         : cpl_image_wrap_float(nx, ny, cpl_image_get_data((cpl_image*)self));
02068     cpl_image     * iwrap = type == CPL_TYPE_DOUBLE
02069         ? cpl_image_wrap_double(nx, ny, cpl_image_get_data((cpl_image*)inverse))
02070         : cpl_image_wrap_float(nx, ny, cpl_image_get_data((cpl_image*)inverse));
02071     cpl_bivector  * offs = cpl_bivector_new(4);
02072     double * x4 = cpl_bivector_get_x_data(offs);
02073     double * y4 = cpl_bivector_get_y_data(offs);
02074     double pos_x, pos_y;
02075     int i;
02076 
02077     skip_if (0);
02078 
02079     skip_if(plist  == NULL);
02080 
02081     skip_if(visir_img_find_beam_four(qclist, self, inverse, eccmax, pthrow,
02082                                      x4, y4));
02083 
02084     /* Combine the four beams */
02085     for (i = 1; i < 4; i++) {
02086         x4[i] = x4[0] - x4[i];
02087         y4[i] = y4[0] - y4[i];
02088     }
02089 
02090     bug_if (cpl_propertylist_append_double(qclist, "ESO QC ONEBEAM XPOS",
02091                                            x4[0]));
02092     bug_if (cpl_propertylist_append_double(qclist, "ESO QC ONEBEAM YPOS",
02093                                            y4[0]));
02094     x4[0] = y4[0] = 0.0;
02095 
02096     bug_if(cpl_imagelist_set(list4, (cpl_image*)self,    0));
02097     bug_if(cpl_imagelist_set(list4, swrap,   1));
02098     bug_if(cpl_imagelist_set(list4, (cpl_image*)inverse, 2));
02099     bug_if(cpl_imagelist_set(list4, iwrap,   3));
02100 
02101     combined = cpl_geom_img_offset_saa(list4, offs, CPL_KERNEL_DEFAULT, 0, 0,
02102                                        CPL_GEOM_FIRST, &pos_x, &pos_y);
02103 
02104     skip_if(combined == NULL);
02105 
02106     end_skip;
02107 
02108     cpl_bivector_delete(offs);
02109     for (i = cpl_imagelist_get_size(list4) - 1; i >= 0; i--) {
02110         (void)cpl_imagelist_unset(list4, i);
02111     }
02112     cpl_imagelist_delete(list4);
02113     (void)cpl_image_unwrap(swrap);
02114     (void)cpl_image_unwrap(iwrap);
02115     if (cpl_error_get_code() && combined != NULL) {
02116         cpl_image_delete(combined[0]);
02117         cpl_image_delete(combined[1]);
02118         cpl_free(combined);
02119     }
02120 
02121     return combined;
02122 }
02123 
02124 /*----------------------------------------------------------------------------*/
02138 /*----------------------------------------------------------------------------*/
02139 visir_chopnod_mode visir_img_find_beam(cpl_propertylist        * qclist,
02140                                        const cpl_image         * self,
02141                                        const cpl_image         * inverse,
02142                                        const cpl_propertylist  * plist,
02143                                        const cpl_parameterlist * parlist,
02144                                        const char              * recipename,
02145                                        double                    x4[],
02146                                        double                    y4[])
02147 {
02148 
02149     cpl_errorstate cleanstate = cpl_errorstate_get();
02150     visir_chopnod_mode mode = VISIR_CHOPNOD_AUTO; /* Assume failure */
02151 
02152     const double eccmax   = visir_parameterlist_get_double(parlist, recipename,
02153                                                            VISIR_PARAM_ECCMAX);
02154 
02155     const char   * sdir;
02156 
02157     /* Get the chopping throw in pixels */
02158     const char * sscale       = visir_pfits_get_pixscale(plist);
02159     const double pscale       = sscale ? atof(sscale) : 0.0;
02160     const double pthrow       = pscale > 0.0
02161         ? visir_pfits_get_chop_throw(plist) / pscale : 0.0;
02162 
02163 
02164     skip_if(x4         == NULL);
02165     skip_if(y4         == NULL);
02166     skip_if(sscale     == NULL);
02167     skip_if(self       == NULL);
02168     skip_if(inverse    == NULL);
02169     skip_if(parlist    == NULL);
02170     skip_if(recipename == NULL);
02171     skip_if(qclist     == NULL);
02172 
02173     sdir = visir_pfits_get_chopnod_dir(plist);
02174 
02175     if (sdir != NULL && !strcmp(sdir, "PERPENDICULAR")) {
02176 
02177         skip_if (visir_img_find_beam_four(qclist, self, inverse, eccmax,
02178                                           pthrow, x4, y4));
02179 
02180         /* 4 sources - expected and detected */
02181         mode = VISIR_CHOPNOD_PERPENDICULAR;
02182 
02183     } else if (sdir != NULL && !strcmp(sdir, "PARALLEL")) {
02184 
02185         skip_if (visir_img_find_beam_three(qclist, self, inverse, eccmax,
02186                                            pthrow, x4, y4));
02187 
02188         /* 3 sources - expected and detected */
02189         mode = VISIR_CHOPNOD_PARALLEL;
02190 
02191     } else {
02192         if (sdir == NULL) {
02193             visir_error_reset("Could not get FITS key");
02194         } else {
02195             cpl_msg_warning(cpl_func, "Unknown chopping direction: %s",
02196                             sdir);
02197         }
02198         cpl_msg_warning(cpl_func, "Proceeding as if FITS card "
02199                         VISIR_PFITS_STRING_CHOPNOD_DIR " had value: %s",
02200                         "PERPENDICULAR");
02201 
02202         if (visir_img_find_beam_four(qclist, self, inverse, eccmax,
02203                                      pthrow, x4, y4)) {
02204 
02205             visir_error_reset("Proceeding as if FITS card "
02206                               VISIR_PFITS_STRING_CHOPNOD_DIR
02207                               " had value: %s", "PARALLEL");
02208 
02209             skip_if (visir_img_find_beam_three(qclist, self, inverse,
02210                                                eccmax, pthrow, x4, y4));
02211 
02212             /* 3 sources - unexpected, but detected */
02213             mode = VISIR_CHOPNOD_PARALLEL;
02214 
02215         } else {
02216             /* 4 sources - unexpected, but detected */
02217             mode = VISIR_CHOPNOD_PERPENDICULAR;
02218         }
02219     }
02220 
02221     bug_if (cpl_propertylist_append_double(qclist, "ESO QC ONEBEAM THROW",
02222                                            pthrow));
02223     bug_if (cpl_propertylist_set_comment(qclist, "ESO QC ONEBEAM THROW",
02224                                          "The throw in pixels (TEL CHOP THROW "
02225                                          "divided by INS PFOV)"));
02226     end_skip;
02227 
02228     return mode;
02229 }
02230 
02231 
02232 /*----------------------------------------------------------------------------*/
02244 /*----------------------------------------------------------------------------*/
02245 static
02246 cpl_error_code visir_img_find_beam_four(cpl_propertylist * qclist,
02247                                         const cpl_image  * self,
02248                                         const cpl_image  * inverse,
02249                                         double             eccmax,
02250                                         double             pthrow,
02251                                         double             x4[],
02252                                         double             y4[])
02253 {
02254 
02255     cpl_errorstate  cleanstate = cpl_errorstate_get();
02256     cpl_apertures * appos = NULL;
02257     cpl_apertures * apneg = NULL;
02258     const double    psigmas[] = {2.0, 1.0, 0.5};
02259     const int       nsigmas = sizeof(psigmas)/sizeof(double);
02260     int             isigma;
02261     int             iappos2[] = {1, 2};
02262     int             iapneg2[] = {1, 2};
02263 
02264     bug_if(0);
02265     skip_if(self   == NULL);
02266     skip_if(qclist == NULL);
02267     skip_if(pthrow <= 0.0);
02268     skip_if(x4     == NULL);
02269     skip_if(y4     == NULL);
02270 
02271     cpl_msg_info(cpl_func, "Detecting the 4-beam object with %g pixel throw "
02272                  "using %d sigma-levels ranging from %g down to %g", pthrow,
02273                  nsigmas, psigmas[0], psigmas[nsigmas-1]);
02274 
02275     bug_if(0);
02276     for (isigma = 0; isigma < nsigmas; isigma++) {
02277         int npos = 0;
02278         int nneg = 0;
02279 
02280         /* Detect the (two) POSITIVE objects */
02281         cpl_apertures_delete(appos);
02282         appos = cpl_apertures_extract_sigma(self, psigmas[isigma]);
02283 
02284         if (appos != NULL) {
02285             npos = cpl_apertures_get_size(appos);
02286         }
02287 
02288 
02289         /* Detect the (two) NEGATIVE objects */
02290         cpl_apertures_delete(apneg);
02291         apneg = cpl_apertures_extract_sigma(inverse, psigmas[isigma]);
02292         if (apneg != NULL) {
02293             nneg = cpl_apertures_get_size(apneg);
02294         }
02295 
02296         cpl_msg_info(cpl_func, "Found %d positive (need 2) and %d negative "
02297                      "(need 2) object(s) at sigma=%g (%d of %d)", npos, nneg,
02298                      psigmas[isigma], 1+isigma, nsigmas);
02299 
02300         if (eccmax > 0.0) {
02301             int ipos1;
02302             double eccbest = eccmax;
02303             double eccmin  = DBL_MAX;
02304             double fluxbest = 0.0;
02305             double fluxecc = DBL_MAX;
02306             cpl_boolean is_first = CPL_TRUE;
02307 
02308 #ifdef _OPENMP
02309 #pragma omp parallel for private(ipos1)
02310 #endif
02311             for (ipos1 = 2; ipos1 <= npos; ipos1++) {
02312                 int ipos2, ineg1, ineg2;
02313                 for (ipos2 = 1; ipos2 < ipos1; ipos2++) {
02314                     for (ineg1 = 2; ineg1 <= nneg; ineg1++) {
02315                         for (ineg2 = 1; ineg2 < ineg1; ineg2++) {
02316                             cpl_boolean swappos, swapneg;
02317                             const double ecc
02318                                 = visir_img_check_box(appos, ipos1, ipos2,
02319                                                       apneg, ineg1, ineg2,
02320                                                       pthrow, &swappos,
02321                                                       &swapneg);
02322 
02323                             const double flux
02324                                 = cpl_apertures_get_flux(appos, ipos1)
02325                                 + cpl_apertures_get_flux(appos, ipos2)
02326                                 + cpl_apertures_get_flux(apneg, ineg1)
02327                                 + cpl_apertures_get_flux(apneg, ineg2);
02328 
02329 
02330                             if (ecc < 0.0 || flux <= 0.0 ||
02331                                 !cpl_errorstate_is_equal(cleanstate)) {
02332                                 irplib_error_recover(cleanstate, "Invalid 4-"
02333                                                      "object (%d & %d of %d, "
02334                                                      "%d & %d of %d)",
02335                                                      ipos2, ipos1, npos,
02336                                                      ineg2, ineg1, nneg);
02337                                 continue;
02338                             }
02339 
02340 #ifdef _OPENMP
02341 #pragma omp critical(visir_img_find_beam_four_min)
02342 #endif
02343                             if (ecc < eccmin)
02344                             {
02345                                 eccmin = ecc;
02346                                 fluxecc = flux;
02347                             }
02348 
02349                             if (eccmax <= ecc) continue;
02350 
02351 #ifdef _OPENMP
02352 #pragma omp critical(visir_img_find_beam_four_ok)
02353 #endif
02354                             if (is_first || ecc * fluxbest < eccbest * flux)
02355                                 {
02356                                 if (is_first) {
02357                                     is_first = CPL_FALSE;
02358                                     cpl_msg_info(cpl_func, "Found 4 object "
02359                                                  "positions with throw-"
02360                                                  "scaled eccentricity %g "
02361                                                  "and flux %g", ecc, flux);
02362                                 } else {
02363                                     cpl_msg_info(cpl_func, "Found 4 object "
02364                                                  "positions with throw-"
02365                                                  "scaled eccentricity %g "
02366                                                  "< %g and/or flux %g > %g",
02367                                                  ecc, eccbest, flux, fluxbest);
02368                                 }
02369                                 eccbest = ecc;
02370                                 fluxbest = flux;
02371                                 iappos2[0] = swappos ? ipos2 : ipos1;
02372                                 iappos2[1] = swappos ? ipos1 : ipos2;
02373                                 iapneg2[0] = swapneg ? ineg2 : ineg1;
02374                                 iapneg2[1] = swapneg ? ineg1 : ineg2;
02375                             }
02376                         }
02377                     }
02378                 }
02379             }
02380             if (eccbest < eccmax) {
02381                 bug_if(cpl_propertylist_append_double(qclist, "ESO QC ONEBEAM "
02382                                                       "ECCENTRICITY", eccbest));
02383 
02384                 break;
02385             }
02386             if (eccmin < DBL_MAX) {
02387                 cpl_msg_info(cpl_func, "Found 4 sigma-%g object positions with "
02388                              "too large throw-scaled eccentricity %g >= %g and "
02389                              "flux %g", psigmas[isigma], eccmin, eccmax,
02390                              fluxecc);
02391             }
02392         } else if (npos >= 2 && nneg >= 2) {
02393             cpl_apertures_sort_by_flux(appos);
02394             cpl_apertures_sort_by_flux(apneg);
02395             break;
02396         }
02397 
02398         if (isigma + 1 < nsigmas) {
02399             irplib_error_recover(cleanstate, "4-Beam positions not found among "
02400                                  "%d postive and %d negative object(s) at "
02401                                  "sigma=%g, (%d of %d)", npos, nneg,
02402                                  psigmas[isigma], 1+isigma, nsigmas);
02403         }
02404     }
02405 
02406     error_if (isigma == nsigmas, CPL_ERROR_DATA_NOT_FOUND,
02407               "4-Beam positions not found w. %d sigma(s) down to %g",
02408               nsigmas, psigmas[nsigmas - 1]);
02409 
02410     if (cpl_msg_get_level() == CPL_MSG_DEBUG) {
02411         cpl_apertures_dump(appos, stdout);
02412         cpl_apertures_dump(apneg, stdout);
02413     }
02414 
02415     x4[0] = cpl_apertures_get_centroid_x(appos, iappos2[0]);
02416     y4[0] = cpl_apertures_get_centroid_y(appos, iappos2[0]);
02417     x4[1] = cpl_apertures_get_centroid_x(appos, iappos2[1]);
02418     y4[1] = cpl_apertures_get_centroid_y(appos, iappos2[1]);
02419 
02420     x4[2] = cpl_apertures_get_centroid_x(apneg, iapneg2[0]);
02421     y4[2] = cpl_apertures_get_centroid_y(apneg, iapneg2[0]);
02422     x4[3] = cpl_apertures_get_centroid_x(apneg, iapneg2[1]);
02423     y4[3] = cpl_apertures_get_centroid_y(apneg, iapneg2[1]);
02424 
02425     bug_if(cpl_propertylist_append_double(qclist, "ESO QC ONEBEAM FLUX",
02426                                           cpl_apertures_get_flux(appos,
02427                                                                  iappos2[0])));
02428 
02429     cpl_msg_info(cpl_func, "Centroid of positive object 1 [pixel]: %g %g",
02430                  x4[0], y4[0]);
02431     cpl_msg_info(cpl_func, "Centroid of positive object 2 [pixel]: %g %g",
02432                  x4[1], y4[1]);
02433 
02434     cpl_msg_info(cpl_func, "Centroid of negative object 1 [pixel]: %g %g",
02435                  x4[2], y4[2]);
02436     cpl_msg_info(cpl_func, "Centroid of negative object 2 [pixel]: %g %g",
02437                  x4[3], y4[3]);
02438 
02439     cpl_msg_info(cpl_func, "Expected object distance (chop throw) [pixel]: %g",
02440                  pthrow);
02441     cpl_msg_info(cpl_func, "Object Pos -> Pos x/y-distance [pixel]: %g %g",
02442                  x4[1] - x4[0], y4[1] - y4[0]);
02443     cpl_msg_info(cpl_func, "Object Neg -> Neg x/y-distance [pixel]: %g %g",
02444                  x4[3] - x4[2], y4[3] - y4[2]);
02445     cpl_msg_info(cpl_func, "Object Pos -> Pos angle [degrees]: %g",
02446                  atan2(y4[1] - y4[0], x4[1] - x4[0]) * CPL_MATH_DEG_RAD);
02447     cpl_msg_info(cpl_func, "Object Neg -> Neg angle [degrees]: %g",
02448                  atan2(y4[3] - y4[2], x4[3] - x4[2]) * CPL_MATH_DEG_RAD);
02449 
02450     end_skip;
02451 
02452     cpl_apertures_delete(appos);
02453     cpl_apertures_delete(apneg);
02454 
02455     return cpl_error_get_code();
02456 }
02457 
02458 /*----------------------------------------------------------------------------*/
02470 /*----------------------------------------------------------------------------*/
02471 static
02472 cpl_image ** visir_img_collapse_beam_three(cpl_propertylist       * qclist,
02473                                            const cpl_image        * self,
02474                                            const cpl_image        * inverse,
02475                                            double                   eccmax,
02476                                            double                   pthrow,
02477                                            const cpl_propertylist * plist)
02478 {
02479 
02480     cpl_image    ** combined = NULL;
02481     const int       nx = cpl_image_get_size_x(self);
02482     const int       ny = cpl_image_get_size_y(self);
02483     const cpl_type  type = cpl_image_get_type(self);
02484     cpl_imagelist * list3 = cpl_imagelist_new();
02485     cpl_image     * iwrap = type == CPL_TYPE_DOUBLE
02486         ? cpl_image_wrap_double(nx, ny, cpl_image_get_data((cpl_image*)inverse))
02487         : cpl_image_wrap_float(nx, ny, cpl_image_get_data((cpl_image*)inverse));
02488     cpl_bivector  * offs = cpl_bivector_new(3);
02489     double * x3 = cpl_bivector_get_x_data(offs);
02490     double * y3 = cpl_bivector_get_y_data(offs);
02491     double pos_x, pos_y;
02492     int i;
02493 
02494     skip_if (0);
02495 
02496     skip_if(plist  == NULL);
02497 
02498     skip_if(visir_img_find_beam_three(qclist, self, inverse, eccmax, pthrow,
02499                                       x3, y3));
02500 
02501     /* Combine the four beams */
02502     for (i = 1; i < 3; i++) {
02503         x3[i] = x3[0] - x3[i];
02504         y3[i] = y3[0] - y3[i];
02505     }
02506     bug_if (cpl_propertylist_append_double(qclist, "ESO QC ONEBEAM XPOS",
02507                                            x3[0]));
02508     bug_if (cpl_propertylist_append_double(qclist, "ESO QC ONEBEAM YPOS",
02509                                            y3[0]));
02510 
02511     x3[0] = y3[0] = 0.0;
02512 
02513     bug_if(cpl_imagelist_set(list3, (cpl_image*)self,    0));
02514     bug_if(cpl_imagelist_set(list3, (cpl_image*)inverse, 1));
02515     bug_if(cpl_imagelist_set(list3, iwrap,   2));
02516 
02517     combined = cpl_geom_img_offset_saa(list3, offs, CPL_KERNEL_DEFAULT, 0, 0,
02518                                        CPL_GEOM_FIRST, &pos_x, &pos_y);
02519 
02520     skip_if(combined == NULL);
02521 
02522     end_skip;
02523 
02524     cpl_bivector_delete(offs);
02525     for (i = cpl_imagelist_get_size(list3) - 1; i >= 0; i--) {
02526         (void)cpl_imagelist_unset(list3, i);
02527     }
02528     cpl_imagelist_delete(list3);
02529     (void)cpl_image_unwrap(iwrap);
02530     if (cpl_error_get_code() && combined != NULL) {
02531         cpl_image_delete(combined[0]);
02532         cpl_image_delete(combined[1]);
02533         cpl_free(combined);
02534     }
02535 
02536     return combined;
02537 }
02538 
02539 
02540 /*----------------------------------------------------------------------------*/
02553 /*----------------------------------------------------------------------------*/
02554 static
02555 cpl_error_code visir_img_find_beam_three(cpl_propertylist * qclist,
02556                                         const cpl_image  * self,
02557                                         const cpl_image  * inverse,
02558                                         double             eccmax,
02559                                         double             pthrow,
02560                                         double             x3[],
02561                                         double             y3[])
02562 {
02563 
02564     cpl_errorstate  cleanstate = cpl_errorstate_get();
02565     cpl_apertures * appos = NULL;
02566     cpl_apertures * apneg = NULL;
02567     const double    psigmas[] = {2.0, 1.0, 0.5};
02568     const int       nsigmas = sizeof(psigmas)/sizeof(double);
02569     int             isigma;
02570     int             iappos [] = {1};
02571     int             iapneg2[] = {1, 2};
02572 
02573     bug_if(0);
02574     skip_if(self   == NULL);
02575     skip_if(qclist == NULL);
02576     skip_if(pthrow <= 0.0);
02577     skip_if(eccmax <  0.0);
02578     skip_if(x3     == NULL);
02579     skip_if(y3     == NULL);
02580 
02581 
02582     cpl_msg_info(cpl_func, "Detecting the 3-beam object with %g pixel throw "
02583                  "using %d sigma-levels ranging from %g down to %g", pthrow,
02584                  nsigmas, psigmas[0], psigmas[nsigmas-1]);
02585 
02586     bug_if(0);
02587     for (isigma = 0; isigma < nsigmas; isigma++) {
02588         int npos = 0;
02589         int nneg = 0;
02590 
02591         /* Detect the (single) POSITIVE object */
02592         cpl_apertures_delete(appos);
02593         appos = cpl_apertures_extract_sigma(self, psigmas[isigma]);
02594 
02595         if (appos != NULL) {
02596             npos = cpl_apertures_get_size(appos);
02597         }
02598 
02599 
02600         /* Detect the (two) NEGATIVE objects */
02601         cpl_apertures_delete(apneg);
02602         apneg = cpl_apertures_extract_sigma(inverse, psigmas[isigma]);
02603         if (apneg != NULL) {
02604             nneg = cpl_apertures_get_size(apneg);
02605         }
02606 
02607         cpl_msg_info(cpl_func, "Found %d positive (need 1) and %d negative "
02608                      "(need 2) object(s) at sigma=%g (%d of %d)", npos, nneg,
02609                      psigmas[isigma], 1+isigma, nsigmas);
02610 
02611         if (eccmax > 0.0) {
02612             int ipos;
02613             double eccbest = eccmax;
02614             double eccmin  = DBL_MAX;
02615             double fluxbest = 0.0;
02616             double fluxecc = DBL_MAX;
02617             cpl_boolean is_first = CPL_TRUE;
02618 
02619 #ifdef _OPENMP
02620 #pragma omp parallel for private(ipos)
02621 #endif
02622             for (ipos = 1; ipos <= npos; ipos++) {
02623                 int ineg1, ineg2;
02624                 for (ineg1 = 2; ineg1 <= nneg; ineg1++) {
02625                     for (ineg2 = 1; ineg2 < ineg1; ineg2++) {
02626                         cpl_boolean swapnegh, swapnegv;
02627                         /* Find best of horizontal/vertical ecc */
02628                         const double ecch
02629                             = visir_img_check_align(appos, ipos, apneg, ineg1,
02630                                                     ineg2, pthrow, CPL_TRUE,
02631                                                     &swapnegh);
02632                         const double eccv
02633                             = visir_img_check_align(appos, ipos, apneg, ineg1,
02634                                                     ineg2, pthrow, CPL_FALSE,
02635                                                     &swapnegv);
02636                         const double ecc = ecch < eccv ? ecch : eccv;
02637                         const cpl_boolean swapneg = ecch < eccv
02638                             ? swapnegh : swapnegv;
02639 
02640                         const double flux
02641                             = cpl_apertures_get_flux(appos, ipos)
02642                             + cpl_apertures_get_flux(apneg, ineg1)
02643                             + cpl_apertures_get_flux(apneg, ineg2);
02644 
02645 
02646                         if (ecc < 0.0 || flux <= 0.0 ||
02647                             !cpl_errorstate_is_equal(cleanstate)) {
02648                             irplib_error_recover(cleanstate, "Invalid 3-"
02649                                                  "object (%d of %d, "
02650                                                  "%d & %d of %d)",
02651                                                  ipos, npos,
02652                                                  ineg2, ineg1, nneg);
02653                             continue;
02654                         }
02655 
02656 #ifdef _OPENMP
02657 #pragma omp critical(visir_img_collapse_beam_three_min)
02658 #endif
02659                         if (ecc < eccmin)
02660                         {
02661                             eccmin = ecc;
02662                             fluxecc = flux;
02663                         }
02664 
02665                         if (eccmax <= ecc) continue;
02666 
02667 #ifdef _OPENMP
02668 #pragma omp critical(visir_img_collapse_beam_three_ok)
02669 #endif
02670                         if (is_first || ecc * fluxbest < eccbest * flux)
02671                         {
02672                             if (is_first) {
02673                                 is_first = CPL_FALSE;
02674                                 cpl_msg_info(cpl_func, "Found 3 object posi"
02675                                              "tions with throw-scaled (ver"
02676                                              "tical/horizontal) eccentrici"
02677                                              "ty %g/%g and flux %g", eccv,
02678                                              ecch, flux);
02679                             } else {
02680                                 cpl_msg_info(cpl_func, "Found 3 object posi"
02681                                              "tions with throw-scaled (ver"
02682                                              "tical/horizontal) eccentrici"
02683                                              "ty %g/%g < %g and/or flux %g "
02684                                              "> %g", eccv, ecch, eccbest,
02685                                              flux, fluxbest);
02686                             }
02687                             eccbest = ecc;
02688                             fluxbest = flux;
02689                             iappos[0] = ipos;
02690                             iapneg2[0] = swapneg ? ineg2 : ineg1;
02691                             iapneg2[1] = swapneg ? ineg1 : ineg2;
02692                         }
02693                     }
02694                 }
02695             }
02696             if (eccbest < eccmax) {
02697                 bug_if(cpl_propertylist_append_double(qclist, "ESO QC ONEBEAM "
02698                                                       "ECCENTRICITY", eccbest));
02699                 break;
02700             }
02701             if (eccmin < DBL_MAX) {
02702                 cpl_msg_info(cpl_func, "Found 3 sigma-%g object positions with "
02703                              "too large throw-scaled eccentricity %g >= %g and "
02704                              "flux %g", psigmas[isigma], eccmin, eccmax,
02705                              fluxecc);
02706             }
02707         } else if (npos >= 1 && nneg >= 2) {
02708             cpl_apertures_sort_by_flux(appos);
02709             cpl_apertures_sort_by_flux(apneg);
02710             break;
02711         }
02712 
02713         if (isigma + 1 < nsigmas) {
02714             irplib_error_recover(cleanstate, "3-Beam positions not found among "
02715                                  "%d postive and %d negative object(s) at "
02716                                  "sigma=%g, (%d of %d)", npos, nneg,
02717                                  psigmas[isigma], 1+isigma, nsigmas);
02718         }
02719     }
02720 
02721     error_if (isigma == nsigmas, CPL_ERROR_DATA_NOT_FOUND,
02722               "3-Beam positions not found w. %d sigma(s) down to %g",
02723               nsigmas, psigmas[nsigmas - 1]);
02724 
02725     if (cpl_msg_get_level() == CPL_MSG_DEBUG) {
02726         cpl_apertures_dump(appos, stdout);
02727         cpl_apertures_dump(apneg, stdout);
02728     }
02729 
02730     x3[0] = cpl_apertures_get_centroid_x(appos, iappos[0]);
02731     y3[0] = cpl_apertures_get_centroid_y(appos, iappos[0]);
02732 
02733     x3[1] = cpl_apertures_get_centroid_x(apneg, iapneg2[0]);
02734     y3[1] = cpl_apertures_get_centroid_y(apneg, iapneg2[0]);
02735     x3[2] = cpl_apertures_get_centroid_x(apneg, iapneg2[1]);
02736     y3[2] = cpl_apertures_get_centroid_y(apneg, iapneg2[1]);
02737 
02738     bug_if(cpl_propertylist_append_double(qclist, "ESO QC ONEBEAM FLUX",
02739                                           cpl_apertures_get_flux(appos,
02740                                                                  iappos[0])));
02741 
02742     cpl_msg_info(cpl_func, "Centroid of positive object [pixel]: %g %g",
02743                  x3[0], y3[0]);
02744 
02745     cpl_msg_info(cpl_func, "Centroid of negative object 1 [pixel]: %g %g",
02746                  x3[1], y3[1]);
02747     cpl_msg_info(cpl_func, "Centroid of negative object 2 [pixel]: %g %g",
02748                  x3[2], y3[2]);
02749 
02750     cpl_msg_info(cpl_func, "Expected object distance (chop throw) [pixel]: %g",
02751                  pthrow);
02752     cpl_msg_info(cpl_func, "Object Neg1 -> Pos x/y-distance [pixel]: %g %g",
02753                  x3[2] - x3[0], y3[2] - y3[0]);
02754     cpl_msg_info(cpl_func, "Object Pos -> Neg2 x/y-distance [pixel]: %g %g",
02755                  x3[0] - x3[1], y3[0] - y3[1]);
02756 
02757     end_skip;
02758 
02759     cpl_apertures_delete(appos);
02760     cpl_apertures_delete(apneg);
02761 
02762     return cpl_error_get_code();
02763 }
02764 
02765 
02766 /*----------------------------------------------------------------------------*/
02780 /*----------------------------------------------------------------------------*/
02781 cpl_error_code visir_img_find_beam_two(cpl_propertylist * qclist,
02782                                        const cpl_image  * self,
02783                                        const cpl_image  * inverse,
02784                                        double             eccmax,
02785                                        double             pthrow,
02786                                        double             x2[],
02787                                        double             y2[])
02788 {
02789 
02790     cpl_errorstate  cleanstate = cpl_errorstate_get();
02791     cpl_apertures * appos = NULL;
02792     cpl_apertures * apneg = NULL;
02793     const double    psigmas[] = {2.0, 1.0, 0.5};
02794     const int       nsigmas = sizeof(psigmas)/sizeof(double);
02795     int             isigma;
02796     int             iappos[] = {1};
02797     int             iapneg[] = {1};
02798 
02799     bug_if(0);
02800     skip_if(self   == NULL);
02801     skip_if(qclist == NULL);
02802     skip_if(eccmax <  0.0);
02803     skip_if(x2     == NULL);
02804     skip_if(y2     == NULL);
02805 
02806     if (pthrow > 0.0) {
02807         cpl_msg_info(cpl_func, "Detecting the 2-beam object (Pos -> Neg) with "
02808                      "%g pixel throw using %d sigma-levels ranging from %g down"
02809                      " to %g", pthrow, nsigmas, psigmas[0], psigmas[nsigmas-1]);
02810     } else if (pthrow < 0.0) {
02811         cpl_msg_info(cpl_func, "Detecting the 2-beam object (Neg -> Pos) with "
02812                      "%g pixel throw using %d sigma-levels ranging from %g down"
02813                      " to %g", pthrow, nsigmas, psigmas[0], psigmas[nsigmas-1]);
02814     } else {
02815         skip_if(1);
02816     }
02817 
02818     bug_if(0);
02819     for (isigma = 0; isigma < nsigmas; isigma++) {
02820         int npos = 0;
02821         int nneg = 0;
02822 
02823         /* Detect the (single) POSITIVE object */
02824         cpl_apertures_delete(appos);
02825         appos = cpl_apertures_extract_sigma(self, psigmas[isigma]);
02826 
02827         if (appos != NULL) {
02828             npos = cpl_apertures_get_size(appos);
02829         }
02830 
02831 
02832         /* Detect the NEGATIVE object */
02833         cpl_apertures_delete(apneg);
02834         apneg = cpl_apertures_extract_sigma(inverse, psigmas[isigma]);
02835         if (apneg != NULL) {
02836             nneg = cpl_apertures_get_size(apneg);
02837         }
02838 
02839         cpl_msg_info(cpl_func, "Found %d positive (need 1) and %d negative "
02840                      "(need 1) object(s) at sigma=%g (%d of %d)", npos, nneg,
02841                      psigmas[isigma], 1+isigma, nsigmas);
02842 
02843         if (eccmax > 0.0) {
02844             int ipos;
02845             double eccbest = eccmax;
02846             double eccmin  = DBL_MAX;
02847             double fluxbest = 0.0;
02848             double fluxecc = DBL_MAX;
02849             cpl_boolean is_first = CPL_TRUE;
02850 
02851 #ifdef _OPENMP
02852 #pragma omp parallel for private(ipos)
02853 #endif
02854             for (ipos = 1; ipos <= npos; ipos++) {
02855                 int ineg;
02856                 for (ineg = 1; ineg <= nneg; ineg++) {
02857                     const double ecc = pthrow > 0.0
02858                         ? visir_img_check_line(appos, ipos, apneg, ineg,
02859                                                pthrow, CPL_FALSE)
02860                         : visir_img_check_line(apneg, ineg, appos, ipos,
02861                                                -pthrow, CPL_FALSE);
02862 
02863                     const double flux
02864                         = cpl_apertures_get_flux(appos, ipos)
02865                         + cpl_apertures_get_flux(apneg, ineg);
02866 
02867 
02868                     if (ecc < 0.0 || flux <= 0.0 ||
02869                         !cpl_errorstate_is_equal(cleanstate)) {
02870                         irplib_error_recover(cleanstate, "Invalid 2-"
02871                                              "object (%d of %d, "
02872                                              "%d of %d)",
02873                                              ipos, npos,
02874                                              ineg, nneg);
02875                         continue;
02876                     }
02877 
02878 #ifdef _OPENMP
02879 #pragma omp critical(visir_img_collapse_beam_two_min)
02880 #endif
02881                     if (ecc < eccmin)
02882                         {
02883                             eccmin = ecc;
02884                             fluxecc = flux;
02885                         }
02886 
02887                     if (eccmax <= ecc) continue;
02888 
02889 #ifdef _OPENMP
02890 #pragma omp critical(visir_img_collapse_beam_two_ok)
02891 #endif
02892                     if (is_first || ecc * fluxbest < eccbest * flux)
02893                         {
02894                             if (is_first) {
02895                                 is_first = CPL_FALSE;
02896                                 cpl_msg_info(cpl_func, "Found 2 object posi"
02897                                              "tions with throw-scaled eccen"
02898                                              "tricity %g and flux %g", ecc,
02899                                              flux);
02900                             } else {
02901                                 cpl_msg_info(cpl_func, "Found 2 object posi"
02902                                              "tions with throw-scaled eccen"
02903                                              "tricity %g < %g and/or flux %g "
02904                                              "> %g", ecc, eccbest, flux,
02905                                              fluxbest);
02906                             }
02907                             eccbest = ecc;
02908                             fluxbest = flux;
02909                             iappos[0] = ipos;
02910                             iapneg[0] = ineg;
02911                         }
02912                 }
02913             }
02914             if (eccbest < eccmax) {
02915                 bug_if(cpl_propertylist_append_double(qclist, "ESO QC ONEBEAM "
02916                                                       "ECCENTRICITY", eccbest));
02917                 break;
02918             }
02919             if (eccmin < DBL_MAX) {
02920                 cpl_msg_info(cpl_func, "Found 2 sigma-%g object positions with "
02921                              "too large throw-scaled eccentricity %g >= %g and "
02922                              "flux %g", psigmas[isigma], eccmin, eccmax,
02923                              fluxecc);
02924             }
02925         } else if (npos >= 1 && nneg >= 2) {
02926             cpl_apertures_sort_by_flux(appos);
02927             cpl_apertures_sort_by_flux(apneg);
02928             break;
02929         }
02930 
02931         if (isigma + 1 < nsigmas) {
02932             irplib_error_recover(cleanstate, "2-Beam positions not found among "
02933                                  "%d postive and %d negative object(s) at "
02934                                  "sigma=%g, (%d of %d)", npos, nneg,
02935                                  psigmas[isigma], 1+isigma, nsigmas);
02936         }
02937     }
02938 
02939     error_if (isigma == nsigmas, CPL_ERROR_DATA_NOT_FOUND,
02940               "2-Beam positions not found w. %d sigma(s) down to %g",
02941               nsigmas, psigmas[nsigmas - 1]);
02942 
02943     if (cpl_msg_get_level() == CPL_MSG_DEBUG) {
02944         cpl_apertures_dump(appos, stdout);
02945         cpl_apertures_dump(apneg, stdout);
02946     }
02947 
02948     x2[0] = cpl_apertures_get_centroid_x(appos, iappos[0]);
02949     y2[0] = cpl_apertures_get_centroid_y(appos, iappos[0]);
02950 
02951     x2[1] = cpl_apertures_get_centroid_x(apneg, iapneg[0]);
02952     y2[1] = cpl_apertures_get_centroid_y(apneg, iapneg[0]);
02953 
02954     bug_if(cpl_propertylist_append_double(qclist, "ESO QC ONEBEAM FLUX",
02955                                           cpl_apertures_get_flux(appos,
02956                                                                  iappos[0])));
02957 
02958     cpl_msg_info(cpl_func, "Centroid of positive object [pixel]: %g %g",
02959                  x2[0], y2[0]);
02960 
02961     cpl_msg_info(cpl_func, "Centroid of negative object [pixel]: %g %g",
02962                  x2[1], y2[1]);
02963 
02964     if (pthrow > 0.0) {
02965         cpl_msg_info(cpl_func, "Expected object distance (chop throw) "
02966                      "[pixel]: %g", pthrow);
02967 
02968         cpl_msg_info(cpl_func, "Object Pos -> Neg x/y-distance [pixel]: %g %g",
02969                      x2[1] - x2[0], y2[1] - y2[0]);
02970     } else {
02971         cpl_msg_info(cpl_func, "Expected object distance (chop throw) "
02972                      "[pixel]: %g", -pthrow);
02973 
02974         cpl_msg_info(cpl_func, "Object Neg -> x/y-distance [pixel]: %g %g",
02975                      x2[0] - x2[1], y2[0] - y2[1]);
02976     }
02977 
02978     end_skip;
02979 
02980     cpl_apertures_delete(appos);
02981     cpl_apertures_delete(apneg);
02982 
02983     return cpl_error_get_code();
02984 }
02985 
02986 
02987 
02988 /*----------------------------------------------------------------------------*/
03007 /*----------------------------------------------------------------------------*/
03008 double visir_img_check_box(const cpl_apertures * appos,
03009                            int ipos1, int ipos2,
03010                            const cpl_apertures * apneg,
03011                            int ineg1, int ineg2, double ssize,
03012                            cpl_boolean * pswapp, cpl_boolean * pswapn)
03013 {
03014 
03015     /* NB: Lower left pixel is (1, 1) */
03016 
03017     /* The two positive points */
03018     const double xp1 = cpl_apertures_get_centroid_x(appos, ipos1);
03019     const double xp2 = cpl_apertures_get_centroid_x(appos, ipos2);
03020     const double yp1 = cpl_apertures_get_centroid_y(appos, ipos1);
03021     const double yp2 = cpl_apertures_get_centroid_y(appos, ipos2);
03022 
03023     /* The leftmost positive point */
03024     const double xpl = xp1 < xp2 ? xp1 : xp2;
03025     const double ypl = xp1 < xp2 ? yp1 : yp2;
03026 
03027     /* The rightmost positive point */
03028     const double xpr = xp1 < xp2 ? xp2 : xp1;
03029     const double ypr = xp1 < xp2 ? yp2 : yp1;
03030 
03031     /* The two negative points */
03032     const double xn1 = cpl_apertures_get_centroid_x(apneg, ineg1);
03033     const double yn1 = cpl_apertures_get_centroid_y(apneg, ineg1);
03034     const double xn2 = cpl_apertures_get_centroid_x(apneg, ineg2);
03035     const double yn2 = cpl_apertures_get_centroid_y(apneg, ineg2);
03036 
03037     /* The leftmost negative point */
03038     const double xnl = xn1 < xn2 ? xn1 : xn2;
03039     const double ynl = xn1 < xn2 ? yn1 : yn2;
03040 
03041     /* The rightmost negative point */
03042     const double xnr = xn1 < xn2 ? xn2 : xn1;
03043     const double ynr = xn1 < xn2 ? yn2 : yn1;
03044 
03045     const double lx1 = xnr - xpl; /* The length of the top x-side */
03046     const double lx2 = xpr - xnl; /* The length of the bottom x-side */
03047     const double ly1 = ypl - ynl; /* The length of the left y-side */
03048     const double ly2 = ynr - ypr; /* The length of the right y-side */
03049 
03050     const double dx1 = lx1 - ssize;
03051     const double dx2 = lx2 - ssize;
03052     const double dy1 = ly1 - ssize;
03053     const double dy2 = ly2 - ssize;
03054 
03055     const double ey1 = ynr - ypl; /* The displacement in the top x-side */
03056     const double ey2 = ypr - ynl; /* The displacement in the bottom x-side */
03057     const double ex1 = xpl - xnl; /* The displacement in the left y-side */
03058     const double ex2 = xpr - xnr; /* The displacement in the right y-side */
03059 
03060     const double ok = sqrt(dx1 * dx1 + dx2 * dx2 + dy1 * dy1 + dy2 * dy2 +
03061                            ex1 * ex1 + ex2 * ex2 + ey1 * ey1 + ey2 * ey2);
03062 
03063     double result = -1.0; /* Assume failure */
03064 
03065     skip_if(0); /* Catches NULL apertures and illegal index input */
03066 
03067     skip_if(pswapp == NULL);
03068     skip_if(pswapn == NULL);
03069     skip_if(appos == apneg);
03070     skip_if(ipos1 == ipos2);
03071     skip_if(ineg1 == ineg2);
03072 
03073     skip_if(ssize <= 0.0);
03074 
03075     *pswapp = xp1 < xp2 ? CPL_FALSE : CPL_TRUE;
03076     *pswapn = xn1 < xn2 ? CPL_FALSE : CPL_TRUE;
03077 
03078     result = ok/ssize; /* OK to divide now */
03079 
03080     end_skip;    
03081 
03082     return result;
03083 
03084 }
03085 
03086 
03087 /*----------------------------------------------------------------------------*/
03106 /*----------------------------------------------------------------------------*/
03107 double visir_img_check_align(const cpl_apertures * appos, int ipos,
03108                              const cpl_apertures * apneg, int ineg1, int ineg2,
03109                              double ssize, cpl_boolean is_hor,
03110                              cpl_boolean * pswapn)
03111 {
03112 
03113     /* NB: Lower left pixel is (1, 1) */
03114 
03115     /* The positive point */
03116     const double xp = cpl_apertures_get_centroid_x(appos, ipos);
03117     const double yp = cpl_apertures_get_centroid_y(appos, ipos);
03118 
03119     /* The two negative points */
03120     const double xn1 = cpl_apertures_get_centroid_x(apneg, ineg1);
03121     const double yn1 = cpl_apertures_get_centroid_y(apneg, ineg1);
03122     const double xn2 = cpl_apertures_get_centroid_x(apneg, ineg2);
03123     const double yn2 = cpl_apertures_get_centroid_y(apneg, ineg2);
03124 
03125     double result = -1.0; /* Assume failure */
03126 
03127     double ok;
03128 
03129     cpl_boolean swapn;
03130 
03131     if (is_hor) {
03132         /* The leftmost negative point */
03133         const double xnl = xn1 < xn2 ? xn1 : xn2;
03134         const double ynl = xn1 < xn2 ? yn1 : yn2;
03135 
03136         /* The rightmost negative point */
03137         const double xnr = xn1 < xn2 ? xn2 : xn1;
03138         const double ynr = xn1 < xn2 ? yn2 : yn1;
03139 
03140         const double d1 = xnr - xp - ssize; /* The rightmost length deviation */
03141         const double d2 = xp - xnl - ssize; /* The  leftmost length deviation */
03142 
03143         const double e1 = ynr - yp;  /* The rigthmost orthogonal deviation */
03144         const double e2 = yp - ynl;  /* The leftmost  orthogonal deviation */
03145 
03146         swapn = xn1 < xn2 ? CPL_FALSE : CPL_TRUE;
03147 
03148         ok = sqrt(d1 * d1 + d2 * d2 + e1 * e1 + e2 * e2);
03149 
03150     } else {
03151         /* The lower negative point */
03152         const double xnl = yn1 < yn2 ? xn1 : xn2;
03153         const double ynl = yn1 < yn2 ? yn1 : yn2;
03154 
03155         /* The upper negative point */
03156         const double xnr = yn1 < yn2 ? xn2 : xn1;
03157         const double ynr = yn1 < yn2 ? yn2 : yn1;
03158 
03159         const double d1 = ynr - yp - ssize; /* The upper length deviation */
03160         const double d2 = yp - ynl - ssize; /* The lower length deviation */
03161 
03162         const double e1 = xnr - xp;  /* The upper orthogonal deviation */
03163         const double e2 = xp - xnl;  /* The lower orthogonal deviation */
03164 
03165         swapn = yn1 < yn2 ? CPL_FALSE : CPL_TRUE;
03166 
03167         ok = sqrt(d1 * d1 + d2 * d2 + e1 * e1 + e2 * e2);
03168 
03169     }
03170 
03171     skip_if(0); /* Catches NULL apertures and illegal index input */
03172 
03173     skip_if(pswapn == NULL);
03174     skip_if(appos == apneg);
03175     skip_if(ineg1 == ineg2);
03176 
03177     skip_if(ssize <= 0.0);
03178 
03179     *pswapn = swapn;
03180 
03181     result = ok/ssize; /* OK to divide now */
03182 
03183     end_skip;    
03184 
03185     return result;
03186 
03187 }
03188 
03189 
03190 /*----------------------------------------------------------------------------*/
03207 /*----------------------------------------------------------------------------*/
03208 double visir_img_check_line(const cpl_apertures * apnear, int inear,
03209                             const cpl_apertures * apfar, int ifar,
03210                             double ssize, cpl_boolean is_hor)
03211 {
03212 
03213     /* NB: Lower left pixel is (1, 1) */
03214 
03215     /* The near point */
03216     const double xn = cpl_apertures_get_centroid_x(apnear, inear);
03217     const double yn = cpl_apertures_get_centroid_y(apnear, inear);
03218 
03219     /* The far point */
03220     const double xf = cpl_apertures_get_centroid_x(apfar, ifar);
03221     const double yf = cpl_apertures_get_centroid_y(apfar, ifar);
03222 
03223     double result = -1.0; /* Assume failure */
03224 
03225     double ok;
03226 
03227     if (is_hor) {
03228 
03229         const double d = xf - xn - ssize; /* The length deviation */
03230 
03231         const double e = yf - yn;  /* The orthogonal deviation */
03232 
03233         ok = sqrt(d * d + e * e);
03234 
03235     } else {
03236 
03237         const double d = yf - yn - ssize; /* The length deviation */
03238 
03239         const double e = xf - xn;  /* The orthogonal deviation */
03240 
03241         ok = sqrt(d * d + e * e);
03242 
03243     }
03244 
03245     skip_if(0); /* Catches NULL apertures and illegal index input */
03246 
03247     skip_if(apnear == apfar);
03248 
03249     skip_if(ssize <= 0.0);
03250 
03251     result = ok/ssize; /* OK to divide now */
03252 
03253     end_skip;    
03254 
03255     return result;
03256 
03257 }
03258 
03259 
03260 /*----------------------------------------------------------------------------*/
03271 /*----------------------------------------------------------------------------*/
03272 static cpl_error_code visir_get_type(const irplib_framelist * rawframes,
03273                                      int pos, visir_cube_type * ptype,
03274                                      int * pnaxis3, int * pnchop) {
03275 
03276 
03277 
03278     cpl_errorstate     cleanstate = cpl_errorstate_get();
03279     const char       * file
03280         = cpl_frame_get_filename(irplib_framelist_get_const(rawframes, pos));
03281     const cpl_propertylist * plist
03282         = irplib_framelist_get_propertylist_const(rawframes, pos);
03283     const int          nchop  = visir_pfits_get_chop_ncycles(plist);
03284     const int          naxis3 = visir_pfits_get_naxis3(plist);
03285     const char       * sval = NULL;
03286     /* If nchop == 1 (and naxis3 == 3) the data unit is both a valid CUBE1
03287        and a valid CUBE2; Assume the frame type to be CUBE2 */
03288 
03289 
03290     skip_if(0);
03291     bug_if(ptype == NULL);
03292     bug_if(pnaxis3 == NULL);
03293 
03294     sval = visir_pfits_get_frame_type(plist);
03295     if (sval == NULL) {
03296         /* Has warned about missing frame type card */
03297         visir_error_reset("Could not get FITS key");
03298         /* Don't know whether or not to expect CUBE1 or CUBE2 */
03299     } else if (strcmp(sval, "CUBE1")==0) {
03300         *ptype = VISIR_CUBE1;
03301     } else if (strcmp(sval, "CUBE2")==0) {
03302         *ptype = VISIR_CUBE2;
03303     }
03304 
03305     if (*ptype == VISIR_CUBE2) {
03306         if (naxis3 == 2 * nchop + 1) {
03307             /* OK. FRAME TYPE cannot be verified from naxis3 when nchop = 1 */
03308         } else if (naxis3 == nchop + 2) {
03309             cpl_msg_warning(cpl_func, "%s has FRAM TYPE = '%s', but NAXIS3=%d "
03310                             "and CHOP NCYCLES=%d imply a CUBE1. Assuming "
03311                             "the frame type is really CUBE1", file, sval,
03312                           naxis3, nchop);
03313             *ptype = VISIR_CUBE1;
03314         } else {
03315             cpl_msg_warning(cpl_func, "%s has FRAM TYPE = '%s', but NAXIS3=%d "
03316                             "and CHOP NCYCLES=%d is not a valid VISIR INTERM+"
03317                             "Half-Cycle format", file, sval, naxis3, nchop);
03318             skip_if(1);
03319         }
03320     } else if (*ptype == VISIR_CUBE1) {
03321         if (naxis3 == nchop + 2) {
03322             /* OK. FRAME TYPE cannot be verified from naxis3 when nchop = 1 */
03323             if (nchop > 1)
03324                 cpl_msg_debug(cpl_func, "%s has %d INTERM-frames and one Half-"
03325                               "Cycle frame (old CUBE1-format)", file, nchop);
03326 
03327         } else if (naxis3 == 2 * nchop + 1) {
03328             cpl_msg_warning(cpl_func, "%s has FRAM TYPE = '%s', but NAXIS3=%d "
03329                             "and CHOP NCYCLES=%d imply a CUBE2. Assuming "
03330                             "the frame type is really CUBE2", file, sval,
03331                             naxis3, nchop);
03332             *ptype = VISIR_CUBE2;
03333         } else {
03334             cpl_msg_warning(cpl_func, "%s has FRAM TYPE = '%s', but NAXIS3=%d "
03335                             "and CHOP NCYCLES=%d is not a valid VISIR INTERM+"
03336                             "Half-Cycle format", file, sval, naxis3, nchop);
03337             skip_if(1);
03338         }
03339     } else if (naxis3 == 2 * nchop + 1) {
03340         cpl_msg_warning(cpl_func, "%s has FRAM TYPE='%s', but NAXIS3=%d and "
03341                         "CHOP NCYCLES=%d imply a CUBE2. Assuming the frame "
03342                         "type is CUBE2", file, sval ? sval : "<NULL>", naxis3,
03343                         nchop);
03344         *ptype = VISIR_CUBE2;
03345     } else if (naxis3 == nchop + 2) {
03346         cpl_msg_warning(cpl_func, "%s has FRAM TYPE='%s', but NAXIS3=%d and "
03347                         "CHOP NCYCLES=%d imply a CUBE1. Assuming the frame "
03348                         "type is CUBE1", file, sval ? sval : "<NULL>", naxis3,
03349                         nchop);
03350         *ptype = VISIR_CUBE1;
03351     } else {
03352        return cpl_error_set_message(cpl_func, CPL_ERROR_BAD_FILE_FORMAT,
03353                                     "%s has FRAM TYPE='%s', NAXIS3 = %d and "
03354                                     "CHOP NCYCLES = %d", file,
03355                                     sval ? sval : "<NULL>", naxis3, nchop);
03356     }
03357 
03358     *pnaxis3 = naxis3;
03359     *pnchop  = nchop;
03360 
03361     end_skip;
03362 
03363     return cpl_error_get_code();
03364 }
03365 
03366 
03367 /*----------------------------------------------------------------------------*/
03375 /*----------------------------------------------------------------------------*/
03376 cpl_error_code visir_img_burst_find_delta_chop(const cpl_propertylist * self,
03377                                                int * ichopchange, int * ihalfcycle)
03378 {
03379 
03380     const char * sdateobs   =
03381         cpl_propertylist_get_string(self, VISIR_PFITS_STRING_OBS_START);
03382     const char * schopstart =
03383         cpl_propertylist_get_string(self, VISIR_PFITS_STRING_CHOP_START);
03384     const double chop_freq  =
03385         cpl_propertylist_get_double(self, VISIR_PFITS_DOUBLE_CHOP_FREQ);
03386     const int nditskip  =
03387         cpl_propertylist_get_int(self, VISIR_PFITS_INT_NDITSKIP);
03388     const double dit        = visir_pfits_get_dit(self);
03389     double       ddateobs, dchopstart;
03390     double       period; /* Number of A+B frames in one full chopping cycle */
03391 
03392     skip_if(0);
03393 
03394     bug_if(irplib_wcs_mjd_from_string(&ddateobs, sdateobs));
03395     bug_if(irplib_wcs_mjd_from_string(&dchopstart, schopstart));
03396 
03397     skip_if(chop_freq <= 0.0);
03398     skip_if(dit <= 0.0);
03399 
03400     /* adapt for skipped exposures after obs start */
03401     ddateobs += dit * nditskip / (double)VISIR_SECS_PER_DAY;
03402 
03403     period = 1.0/(chop_freq * dit);
03404 
03405     /* FIXME: handle this case */
03406     bug_if((int)(period + 0.5) % 2 !=  0);
03407 
03408     *ihalfcycle = (int)(period + 0.5)/2;
03409 
03410     cpl_msg_info(cpl_func, "Number of A+B frames in one full chopping cycle: %g",
03411                  period);
03412 
03413     if (dchopstart < ddateobs) {
03414         double tchop = (ddateobs - dchopstart) * (double)VISIR_SECS_PER_DAY;
03415         /* Number of chopping cycles before obs+chopper start */
03416         double dprecycle = tchop * chop_freq;
03417         /* Phase to skip to point to first A frame
03418            in first complete chopping cycle */
03419         const double phase = ceil(dprecycle) - dprecycle;
03420 
03421         /* First valid frame is the frame at ddateobs (except for startindex) */
03422         *ichopchange = (int)ceil(phase * period) - 1;
03423 
03424         cpl_msg_info(cpl_func, "Chopping started %gs (%f cycles) before OBS start: "
03425                      "%f < %f", tchop, dprecycle, dchopstart, ddateobs);
03426 
03427     } else if (ddateobs < dchopstart) {
03428         /* FIXME: Allowed ? */
03429         /* First valid frame is the frame at dchopstart (except for startindex) */
03430         double tchop = (dchopstart - ddateobs) * (double)VISIR_SECS_PER_DAY;
03431         *ichopchange = (int)ceil(tchop / dit) - 1;
03432         cpl_msg_info(cpl_func, "Chopping started %gs (wasted %g cycles) after OBS "
03433                      "start: %f > %f", tchop, tchop * chop_freq, dchopstart,
03434                      ddateobs);
03435     } else {
03436         /* FIXME: Allowed ? */
03437         /* First valid frame is the first frame (at both ddateobs and dchopstart)
03438            (except for startindex) */
03439         *ichopchange = 0;
03440         cpl_msg_info(cpl_func, "Chopping started with OBS start: %f == %f",
03441                      dchopstart, ddateobs);
03442     }
03443 
03444     /* wrap value to cycle */
03445     *ichopchange = *ichopchange % (*ihalfcycle * 2);
03446 
03447     cpl_msg_info(cpl_func, "Frame of chop change: %d", *ichopchange);
03448 
03449     end_skip;
03450 
03451     return cpl_error_get_code();
03452 }
03453 
03454 #include "visir_destripe.c"

Generated on Mon Feb 6 15:23:49 2012 for VISIR Pipeline Reference Manual by  doxygen 1.5.8