vircam_linearity_analyse.c

00001 /* $Id: vircam_linearity_analyse.c,v 1.51 2008/01/22 19:47:56 jim Exp $
00002  *
00003  * This file is part of the VIRCAM Pipeline
00004  * Copyright (C) 2005 Cambridge Astronomy Survey Unit
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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00019  */
00020 
00021 /*
00022  * $Author: jim $
00023  * $Date: 2008/01/22 19:47:56 $
00024  * $Revision: 1.51 $
00025  * $Name:  $
00026  */
00027 
00028 /* Includes */
00029 
00030 #ifdef HAVE_CONFIG_H
00031 #include <config.h>
00032 #endif
00033 
00034 #include <stdio.h>
00035 #include <cpl.h>
00036 #include <math.h>
00037 
00038 #include "vircam_utils.h"
00039 #include "vircam_pfits.h"
00040 #include "vircam_dfs.h"
00041 #include "vircam_mods.h"
00042 #include "vircam_channel.h"
00043 #include "vircam_stats.h"
00044 #include "vircam_paf.h"
00045 
00046 /* Function prototypes */
00047 
00048 static int vircam_linearity_analyse_create(cpl_plugin *) ;
00049 static int vircam_linearity_analyse_exec(cpl_plugin *) ;
00050 static int vircam_linearity_analyse_destroy(cpl_plugin *) ;
00051 static int vircam_linearity_analyse(cpl_parameterlist *, cpl_frameset *) ;
00052 static int vircam_linearity_analyse_lastbit(int jext, cpl_frameset *framelist,
00053                                             cpl_parameterlist *parlist);
00054 static int vircam_linearity_analyse_save(cpl_frameset *framelist,
00055                                          cpl_parameterlist *parlist);
00056 static int vircam_linearity_analyse_domedark_groups(void);
00057 static double *vircam_linearity_analyse_genstat(vir_fits *fframe, int *bpm,
00058                                                 parquet *p, int np);
00059 static double *vircam_linearity_tweakfac(double **fdata, double *mjd, int nim,
00060                                          int nchan, double *facrng, 
00061                                          double *maxdiff);
00062 static void vircam_mjdsort(double **fdata, double *mjd, int n);
00063 static cpl_table *vircam_linearity_analyse_diagtab_init(int np, int nrows);
00064 static void vircam_linearity_analyse_init(void);
00065 static void vircam_linearity_analyse_tidy(int level);
00066 
00067 /* Static global variables */
00068 
00069 static struct {
00070 
00071     /* Input */
00072 
00073     int     norder;
00074     float   lthr;
00075     float   hthr;
00076     int     maxbpmfr;
00077     int     adjust;
00078     int     diagnostic;
00079     int     extenum;
00080 
00081     /* Output */
00082 
00083     float   linearity;
00084     float   linerror;
00085     float   bad_pixel_stat;
00086     int     bad_pixel_num;
00087     float   facrng;
00088     float   maxdiff;
00089 
00090 } vircam_linearity_analyse_config;
00091 
00092 typedef struct {
00093     cpl_frameset   *darks;
00094     cpl_frameset   *domes;
00095     int            ndarks;
00096     int            ndomes;
00097     float          exptime;
00098     unsigned char  flag;
00099     vir_fits       **proc;
00100 } ddgrp;
00101 
00102 #define OK_FLAG       0
00103 #define SATURATE_FLAG 1
00104 
00105 #define SUBSET 128
00106 #define SUBSET2 (SUBSET/2)
00107 
00108 static struct {
00109     int              *labels;
00110     cpl_frameset     *domelist;
00111     int              ndomes;
00112     cpl_frameset     *darklist;
00113     int              ndarks;
00114     cpl_frameset     *domecheck;
00115     int              ndomecheck;
00116     cpl_frameset     *darkcheck;
00117     int              ndarkcheck;
00118     cpl_frameset     *sorted;
00119     cpl_frame        *chanfrm;
00120     vir_tfits        *chantab;
00121     cpl_table        *lchantab;
00122     cpl_array        *bpm_array;
00123     ddgrp            *ddg;
00124     int              nddg;
00125     vir_fits         **flatlist;
00126     int              nflatlist;
00127     cpl_propertylist *plist;
00128     cpl_propertylist *elist;
00129     int              nx;
00130     int              ny;
00131     cpl_propertylist *phupaf;
00132     cpl_table        *diag1;
00133     cpl_table        *diag2;
00134 } ps;
00135 
00136 static int isfirst;
00137 static int dummy;
00138 static cpl_frame *product_frame_chantab = NULL;
00139 static cpl_frame *product_frame_bpm = NULL;
00140 static cpl_frame *product_frame_diag1 = NULL;
00141 static cpl_frame *product_frame_diag2 = NULL;
00142 
00143 static char vircam_linearity_analyse_description[] =
00144 "vircam_linearity_analyse -- VIRCAM linearity mapping recipe.\n\n"
00145 "Form master dark images from the input raw frames and use these to\n"
00146 "dark correct a series of dome flat exposures Using the dark\n"
00147 "corrected dome flat series, work out linearity coefficients for\n"
00148 "each data channel. The program expects the following files in the SOF\n"
00149 "    Tag                   Description\n"
00150 "    -----------------------------------------------------------------------\n"
00151 "    %-21s A list of raw dome flat images\n"
00152 "    %-21s A list of raw dark images\n"
00153 "    %-21s The channel table\n"
00154 "    %-21s A list of raw dome flat images at the monitor exposure time"
00155 "    %-21s A list of raw dark images at the monitor exposure time"
00156 "The first three of these are required. The last two are only required if"
00157 "the light source monitoring algorithm is to be used"
00158 "\n";
00159 
00281 /* Function code */
00282 
00283 /*---------------------------------------------------------------------------*/
00291 /*---------------------------------------------------------------------------*/
00292 
00293 int cpl_plugin_get_info(cpl_pluginlist *list) {
00294     cpl_recipe  *recipe = cpl_calloc(1,sizeof(*recipe));
00295     cpl_plugin  *plugin = &recipe->interface;
00296     char alldesc[SZ_ALLDESC];
00297     (void)snprintf(alldesc,SZ_ALLDESC,vircam_linearity_analyse_description,
00298                    VIRCAM_LIN_DOME_RAW,VIRCAM_LIN_DARK_RAW,
00299                    VIRCAM_CAL_CHANTAB_INIT,VIRCAM_LIN_DOME_CHECK,
00300                    VIRCAM_LIN_DARK_CHECK);
00301 
00302     cpl_plugin_init(plugin,
00303                     CPL_PLUGIN_API,
00304                     VIRCAM_BINARY_VERSION,
00305                     CPL_PLUGIN_TYPE_RECIPE,
00306                     "vircam_linearity_analyse",
00307                     "VIRCAM linearity analysis recipe",
00308                     alldesc,
00309                     "Jim Lewis",
00310                     "jrl@ast.cam.ac.uk",
00311                     vircam_get_license(),
00312                     vircam_linearity_analyse_create,
00313                     vircam_linearity_analyse_exec,
00314                     vircam_linearity_analyse_destroy);
00315 
00316     cpl_pluginlist_append(list,plugin);
00317 
00318     return(0);
00319 }
00320 
00321 
00322 /*---------------------------------------------------------------------------*/
00331 /*---------------------------------------------------------------------------*/
00332 
00333 static int vircam_linearity_analyse_create(cpl_plugin *plugin) {
00334     cpl_recipe      *recipe;
00335     cpl_parameter   *p;
00336 
00337     /* Get the recipe out of the plugin */
00338 
00339     if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE)
00340         recipe = (cpl_recipe *)plugin;
00341     else
00342         return(-1);
00343 
00344     /* Create the parameters list in the cpl_recipe object */
00345 
00346     recipe->parameters = cpl_parameterlist_new();
00347 
00348     /* Fill in the parameters. First the polynomial order */
00349 
00350     p = cpl_parameter_new_range("vircam.vircam_linearity_analyse.norder",
00351                                 CPL_TYPE_INT,
00352                                 "Order of polynomial fit",
00353                                 "vircam.vircam_linearity_analyse",
00354                                 2,1,6);
00355     cpl_parameter_set_alias(p,CPL_PARAMETER_MODE_CLI,"nord");
00356     cpl_parameterlist_append(recipe->parameters,p);
00357 
00358     /* The lower threshold */
00359 
00360     p = cpl_parameter_new_value("vircam.vircam_linearity_analyse.lthr",
00361                                 CPL_TYPE_DOUBLE,
00362                                 "Lower bad pixel threshold",
00363                                 "vircam.vircam_linearity_analyse",8.0);
00364     cpl_parameter_set_alias(p,CPL_PARAMETER_MODE_CLI,"lthr");
00365     cpl_parameterlist_append(recipe->parameters,p);
00366 
00367     /* The upper threshold */
00368 
00369     p = cpl_parameter_new_value("vircam.vircam_linearity_analyse.hthr",
00370                                 CPL_TYPE_DOUBLE,
00371                                 "Upper bad pixel threshold",
00372                                 "vircam.vircam_linearity_analyse",8.0);
00373     cpl_parameter_set_alias(p,CPL_PARAMETER_MODE_CLI,"hthr");
00374     cpl_parameterlist_append(recipe->parameters,p);
00375 
00376     /* The maximum number of frames to be used in forming the bad pixel mask */
00377 
00378     p = cpl_parameter_new_value("vircam.vircam_linearity_analyse.maxbpmfr",
00379                                 CPL_TYPE_INT,
00380                                 "Maximum # frames used in bpm analysis",
00381                                 "vircam.vircam_linearity_analyse",10);
00382     cpl_parameter_set_alias(p,CPL_PARAMETER_MODE_CLI,"maxbpmfr");
00383     cpl_parameterlist_append(recipe->parameters,p);
00384 
00385     /* The flag to allow statistics of the dome flat frames to be adjusted
00386        using a set of monitor exposures */
00387 
00388     p = cpl_parameter_new_value("vircam.vircam_linearity_analyse.adjust",
00389                                 CPL_TYPE_BOOL,
00390                                 "Adjust stats with monitor set",
00391                                 "vircam.vircam_linearity_analyse",1);
00392     cpl_parameter_set_alias(p,CPL_PARAMETER_MODE_CLI,"adjust");
00393     cpl_parameterlist_append(recipe->parameters,p);
00394 
00395     /* The flag to allow diagnostic curves to be written out */
00396 
00397     p = cpl_parameter_new_value("vircam.vircam_linearity_analyse.diagnostic",
00398                                 CPL_TYPE_BOOL,
00399                                 "Write out diagnostic tables",
00400                                 "vircam.vircam_linearity_analyse",0);
00401     cpl_parameter_set_alias(p,CPL_PARAMETER_MODE_CLI,"diagnostic");
00402     cpl_parameterlist_append(recipe->parameters,p);
00403 
00404     /* Extension number of input frames to use */
00405 
00406     p = cpl_parameter_new_range("vircam.vircam_linearity_analyse.extenum",
00407                                 CPL_TYPE_INT,
00408                                 "Extension number to be done, 0 == all",
00409                                 "vircam.vircam_linearity_analyse",
00410                                 1,0,16);
00411     cpl_parameter_set_alias(p,CPL_PARAMETER_MODE_CLI,"ext");
00412     cpl_parameterlist_append(recipe->parameters,p);
00413 
00414     /* Get out of here */
00415 
00416     return(0);
00417 }
00418 
00419 /*---------------------------------------------------------------------------*/
00425 /*---------------------------------------------------------------------------*/
00426 
00427 static int vircam_linearity_analyse_exec(cpl_plugin *plugin) {
00428     cpl_recipe  *recipe;
00429 
00430     /* Get the recipe out of the plugin */
00431 
00432     if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE)
00433         recipe = (cpl_recipe *)plugin;
00434     else
00435         return(-1);
00436 
00437     return(vircam_linearity_analyse(recipe->parameters,recipe->frames));
00438 }
00439 
00440 /*---------------------------------------------------------------------------*/
00446 /*---------------------------------------------------------------------------*/
00447 
00448 static int vircam_linearity_analyse_destroy(cpl_plugin *plugin) {
00449     cpl_recipe *recipe ;
00450 
00451     /* Get the recipe out of the plugin */
00452 
00453     if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE)
00454         recipe = (cpl_recipe *)plugin;
00455     else
00456         return(-1);
00457 
00458     cpl_parameterlist_delete(recipe->parameters);
00459     return(0);
00460 }
00461 
00462 /*---------------------------------------------------------------------------*/
00469 /*---------------------------------------------------------------------------*/
00470 
00471 static int vircam_linearity_analyse(cpl_parameterlist *parlist,
00472                                     cpl_frameset *framelist) {
00473     const char *fctid="vircam_linearity_analyse";
00474     char colname[16];
00475     int i,jst,jfn,j,status,nlab,k,nbad,ntimes,init,ngood,nuse,krem,irem,n;
00476     int ndarks,ndomes,kk,live,nbmax,ngood_flats,*bpm,nalloc,nfdata,adjust,ndit;
00477     long np,npi;
00478     float *idata,low,high,med,sig,mindit,sat,*exps,badfrac,exp;
00479     unsigned char *rejmask,*rejplus;
00480     double *dexps,**fdata,*d,*mjds,*mjdcheck,mjd,**cdata,*cf,fac;
00481     double facrng,maxdiff,*lindata;
00482     vir_fits **darks,**domes,*outfits,*test,*outdark,*fframe;
00483     parquet *pp;
00484     cpl_parameter *p;
00485     cpl_propertylist *drs,*plist;
00486     cpl_image *master_img,*im,*outimage;
00487     cpl_frame *frame;
00488     
00489     /* Check validity of input frameset */
00490 
00491     if (framelist == NULL || cpl_frameset_get_size(framelist) <= 0) {
00492         cpl_msg_error(fctid,"Input framelist NULL or has no input data\n");
00493         return(-1);
00494     }
00495 
00496     /* Initialise a few things */
00497 
00498     vircam_linearity_analyse_init();
00499 
00500     /* Get the parameters */
00501 
00502     p = cpl_parameterlist_find(parlist,
00503                                "vircam.vircam_linearity_analyse.norder");
00504     vircam_linearity_analyse_config.norder = cpl_parameter_get_int(p);
00505     p = cpl_parameterlist_find(parlist,
00506                                "vircam.vircam_linearity_analyse.lthr");
00507     vircam_linearity_analyse_config.lthr = (float)cpl_parameter_get_double(p);
00508     p = cpl_parameterlist_find(parlist,
00509                                "vircam.vircam_linearity_analyse.hthr");
00510     vircam_linearity_analyse_config.hthr = (float)cpl_parameter_get_double(p);
00511     p = cpl_parameterlist_find(parlist,
00512                                "vircam.vircam_linearity_analyse.maxbpmfr");
00513     vircam_linearity_analyse_config.maxbpmfr = cpl_parameter_get_int(p);
00514     p = cpl_parameterlist_find(parlist,
00515                                "vircam.vircam_linearity_analyse.adjust");
00516     vircam_linearity_analyse_config.adjust = cpl_parameter_get_bool(p);
00517     p = cpl_parameterlist_find(parlist,
00518                                "vircam.vircam_linearity_analyse.diagnostic");
00519     vircam_linearity_analyse_config.diagnostic = cpl_parameter_get_bool(p);
00520     p = cpl_parameterlist_find(parlist,
00521                                "vircam.vircam_linearity_analyse.extenum");
00522     vircam_linearity_analyse_config.extenum = cpl_parameter_get_int(p);
00523 
00524     /* Sort out raw from calib frames */
00525 
00526     if (vircam_dfs_set_groups(framelist) != VIR_OK) {
00527         cpl_msg_error(fctid,"Cannot identify RAW and CALIB frames");
00528         vircam_linearity_analyse_tidy(2);
00529         return(-1);
00530     }
00531 
00532     /* Get framelist labels */
00533 
00534     if ((ps.labels = cpl_frameset_labelise(framelist,vircam_compare_tags,
00535                                            &nlab)) == NULL) {
00536         cpl_msg_error(fctid,"Cannot labelise the input frames");
00537         vircam_linearity_analyse_tidy(2);
00538         return(-1);
00539     }
00540 
00541     /* Get the dome flat frames */
00542 
00543     if ((ps.domelist = vircam_frameset_subgroup(framelist,ps.labels,nlab,
00544                                                 VIRCAM_LIN_DOME_RAW)) == NULL) {
00545         cpl_msg_error(fctid,"Cannot find dome flat frames in input frameset");
00546         vircam_linearity_analyse_tidy(2);
00547         return(-1);
00548     }
00549     ps.ndomes = cpl_frameset_get_size(ps.domelist);
00550 
00551     /* Check to make sure that NDIT == 1 */
00552 
00553     plist = cpl_propertylist_load(cpl_frame_get_filename(cpl_frameset_get_frame(ps.domelist,0)),0);
00554     (void)vircam_pfits_get_ndit(plist,&ndit);
00555     freepropertylist(plist);
00556     if (ndit != 1) {
00557         cpl_msg_error(fctid,"NDIT=%d. Recipe requires that ndit == 1",ndit);
00558         vircam_linearity_analyse_tidy(2);
00559         return(-1);
00560     }
00561 
00562     /* Get the dark frames */
00563 
00564     if ((ps.darklist = vircam_frameset_subgroup(framelist,ps.labels,nlab,
00565                                                 VIRCAM_LIN_DARK_RAW)) == NULL) {
00566         cpl_msg_error(fctid,"Cannot find dark frames in input frameset");
00567         vircam_linearity_analyse_tidy(2);
00568         return(-1);
00569     }
00570     ps.ndarks = cpl_frameset_get_size(ps.darklist);
00571 
00572     /* If you are planning to adjust the stats for the dome frames by using
00573        a monitor exposure set, then read that frameset in now */
00574 
00575     if (vircam_linearity_analyse_config.adjust) {
00576         if ((ps.domecheck = vircam_frameset_subgroup(framelist,ps.labels,nlab,
00577                                                      VIRCAM_LIN_DOME_CHECK)) == NULL) {
00578             cpl_msg_info(fctid,"No monitor frames found in sof. No adjustments made to stats");
00579             vircam_linearity_analyse_config.adjust = 0;
00580             ps.ndomecheck = 0;
00581         } else {
00582             ps.ndomecheck = cpl_frameset_get_size(ps.domecheck);
00583             if ((ps.darkcheck = vircam_frameset_subgroup(framelist,ps.labels,
00584                                                          nlab,VIRCAM_LIN_DARK_CHECK)) == NULL) {
00585                 cpl_msg_info(fctid,"No darks for monitor frames found in sof. No adjustments made to stats");
00586                 vircam_linearity_analyse_config.adjust = 0;
00587                 ps.ndomecheck = 0;
00588                 freeframeset(ps.domecheck);
00589                 ps.ndarkcheck = 0;
00590             } else {
00591                 ps.ndarkcheck = cpl_frameset_get_size(ps.darkcheck);
00592             }
00593         }       
00594     }
00595     
00596     /* Check to see if there is a channel table. If so, then read it */
00597 
00598     if ((ps.chanfrm = vircam_frameset_subgroup_1(framelist,ps.labels,nlab,
00599                                                  VIRCAM_CAL_CHANTAB_INIT)) == NULL) {
00600         cpl_msg_error(fctid,"No initial channel table found");
00601         vircam_linearity_analyse_tidy(2);
00602         return(-1);
00603     }
00604 
00605     /* Create a sorted frameset (needed for creating output header with 
00606        properties copied from a dome rather than from a dark) */
00607 
00608     ps.sorted = cpl_frameset_new();
00609     for (j = 0; j < ps.ndomes; j++) 
00610         cpl_frameset_insert(ps.sorted,cpl_frame_duplicate(cpl_frameset_get_frame(ps.domelist,j)));
00611     for (j = 0; j < ps.ndarks; j++) 
00612         cpl_frameset_insert(ps.sorted,cpl_frame_duplicate(cpl_frameset_get_frame(ps.darklist,j)));
00613     cpl_frameset_insert(ps.sorted,cpl_frame_duplicate(ps.chanfrm));
00614 
00615     /* Group the domes and darks by exposure time */
00616 
00617     if (vircam_linearity_analyse_domedark_groups() != 0) {
00618         vircam_linearity_analyse_tidy(2);
00619         return(-1);
00620     }
00621 
00622     /* See if the number of exposure times is too small for the order of the
00623        polynomial you want to fit. If it is, the adjust the order */
00624 
00625     if (ps.nddg < vircam_linearity_analyse_config.norder+1) {
00626         cpl_msg_warning(fctid,
00627                         "Number of exposure times is too small: %d, order: %d\nTaking fit down to order %d",
00628                         ps.nddg,vircam_linearity_analyse_config.norder,
00629                         ps.nddg-1);
00630         vircam_linearity_analyse_config.norder = ps.nddg - 1;
00631     }
00632 
00633     /* Now, how many image extensions do we want to do? If the extension
00634        number is zero, then we loop for all possible extensions. If it
00635        isn't then we just do the extension specified */
00636 
00637     vircam_exten_range(vircam_linearity_analyse_config.extenum,
00638                        (const cpl_frame *)cpl_frameset_get_frame(ps.ddg[0].darks,0),
00639                        &jst,&jfn);
00640     if (jst == -1 || jfn == -1) {
00641         cpl_msg_error(fctid,"Unable to continue");
00642         vircam_linearity_analyse_tidy(2);
00643         return(-1);
00644     }
00645 
00646     /* Now loop for all the extensions and do the BPM analysis... */
00647 
00648     for (j = jst; j <= jfn; j++) {
00649         cpl_msg_info(fctid,"Beginning BPM work on extension %d",j);
00650         isfirst = (j == jst);
00651         dummy = 0;
00652         vircam_linearity_analyse_config.bad_pixel_stat = 0.0;
00653         vircam_linearity_analyse_config.bad_pixel_num = 0;
00654         vircam_linearity_analyse_config.linerror = 0.0;
00655         vircam_linearity_analyse_config.linearity = 0.0;
00656         vircam_linearity_analyse_config.facrng = 0.0;
00657         vircam_linearity_analyse_config.maxdiff = 0.0;
00658 
00659         /* Get some standard info in case we need it for dummy products */
00660 
00661         test = vircam_fits_load(cpl_frameset_get_first(ps.ddg[0].domes),
00662                                 CPL_TYPE_FLOAT,j);
00663         ps.plist = cpl_propertylist_duplicate(vircam_fits_get_phu(test));
00664         ps.elist = cpl_propertylist_duplicate(vircam_fits_get_ehu(test));
00665         ps.nx = cpl_image_get_size_x(vircam_fits_get_image(test));
00666         ps.ny = cpl_image_get_size_y(vircam_fits_get_image(test));
00667         vircam_fits_delete(test);
00668 
00669         /* Load up the channel table for this detector and verify it. Get 
00670            saturation level for this detector from FITS header */
00671 
00672         ps.chantab = vircam_tfits_load(ps.chanfrm,j);
00673         if (ps.chantab == NULL) {
00674             cpl_msg_error(fctid,"Channel table extension %d failed to load",j);
00675             dummy = 1;
00676             if (vircam_linearity_analyse_lastbit(j,framelist,parlist) != 0)
00677                 return(-1);
00678             continue;
00679         } else if (vircam_chantab_verify(vircam_tfits_get_table(ps.chantab)) 
00680                    != VIR_OK) {
00681             cpl_msg_error(fctid,"Channel table extension %d has errors",j);
00682             dummy = 1;
00683             if (vircam_linearity_analyse_lastbit(j,framelist,parlist) != 0)
00684                 return(-1);
00685             continue;
00686         }
00687         if (vircam_pfits_get_saturation(vircam_tfits_get_ehu(ps.chantab),
00688                                         &sat) != VIR_OK) {
00689             cpl_msg_error(fctid,"Channel table extension header %d missing saturation info",j);
00690             dummy = 1;
00691             if (vircam_linearity_analyse_lastbit(j,framelist,parlist) != 0)
00692                 return(-1);
00693             vircam_linearity_analyse_tidy(1);
00694             continue;
00695         }
00696 
00697         /* Get the channel structure */
00698 
00699         vircam_chan_fill(vircam_tfits_get_table(ps.chantab),&pp,&np);
00700 
00701         /* If doing diagnostics, then create the tables now */
00702 
00703         if (vircam_linearity_analyse_config.diagnostic) {
00704             ps.diag1 = vircam_linearity_analyse_diagtab_init(np,ps.ndomes);
00705             if (vircam_linearity_analyse_config.adjust)
00706                 ps.diag2 = vircam_linearity_analyse_diagtab_init(np,ps.ndomecheck);
00707         }
00708 
00709         /* Check DETLIVE for this extension */
00710 
00711         if (vircam_pfits_get_detlive((const cpl_propertylist *)ps.elist,&live) 
00712             != VIR_OK) {
00713             cpl_msg_error(fctid,"No DET LIVE keyword in this extension");
00714             dummy = 1;
00715             if (vircam_linearity_analyse_lastbit(j,framelist,parlist) != 0) 
00716                 return(-1);
00717             vircam_linearity_analyse_tidy(1);
00718             continue;
00719         }
00720         if (! live) {
00721             cpl_msg_info(fctid,"Detector flagged dead");
00722             dummy = 1;
00723             if (vircam_linearity_analyse_lastbit(j,framelist,parlist) != 0) 
00724                 return(-1);
00725             vircam_linearity_analyse_tidy(1);
00726             continue;
00727         }
00728 
00729         /* Get the value of MINDIT so that you can work out the rough level
00730            of the flats before the reset frame was subtracted off */
00731 
00732         if (vircam_pfits_get_mindit((const cpl_propertylist *)ps.elist,
00733                                     &mindit) != VIR_OK) {
00734             cpl_msg_error(fctid,"No value of MINDIT found in extension %d",j);
00735             dummy = 1;
00736             if (vircam_linearity_analyse_lastbit(j,framelist,parlist) != 0)
00737                 return(-1);
00738             continue;
00739         }
00740 
00741         /* Get a representative from each exposure group and check if it
00742            is saturated. If it is, then reject the group from further 
00743            analysis */
00744 
00745         ngood = 0;
00746         exps = cpl_malloc(ps.nddg*sizeof(float));
00747         ngood_flats = 0;
00748         for (i = 0; i < ps.nddg; i++) {
00749             test = vircam_fits_load(cpl_frameset_get_first(ps.ddg[i].domes),
00750                                     CPL_TYPE_FLOAT,j);
00751             med = cpl_image_get_median((const cpl_image*)vircam_fits_get_image(test));
00752             med *= (1.0 + mindit/ps.ddg[i].exptime);
00753             if (med > sat) {
00754                 ps.ddg[i].flag = SATURATE_FLAG;
00755             } else {
00756                 ngood++;
00757                 exps[ngood-1] = ps.ddg[i].exptime;
00758                 ngood_flats += ps.ddg[i].ndomes;
00759             }
00760             vircam_fits_delete(test);
00761         }
00762         exps = cpl_realloc(exps,ngood*sizeof(float));
00763                
00764         /* Are there enough non-saturated exposures for linearity fit? */
00765 
00766         if (ngood <  vircam_linearity_analyse_config.norder+1) {
00767             cpl_msg_info(fctid,"Too few unsaturated flats for linearity fit for extension %d",j);
00768             dummy = 1;
00769             cpl_free(exps);
00770             if (vircam_linearity_analyse_lastbit(j,framelist,parlist) != 0) 
00771                 return(-1);
00772             continue;
00773         }           
00774 
00775         /* Sort the exposure array */
00776 
00777         vircam_sort(&exps,ngood,1);
00778 
00779         /* Loop for each exposure time. When you have enough flats, then
00780            you can quit this loop */
00781 
00782         nuse = min(vircam_linearity_analyse_config.maxbpmfr,ngood_flats);
00783         ps.nflatlist = 0;
00784         ps.flatlist = cpl_malloc(nuse*sizeof(vir_fits *));
00785         for (i = ngood-1; i >= 0; i--) {
00786             for (k = 0; k <= ps.nddg; k++) {
00787                 if (ps.ddg[k].exptime == exps[i]) {
00788                     krem = k;
00789                     break;
00790                 }
00791             }
00792 
00793             /* Load the dark frames from this exposure time */
00794 
00795             darks = vircam_fits_load_list(ps.ddg[krem].darks,CPL_TYPE_FLOAT,j);
00796             ndarks = ps.ddg[krem].ndarks;
00797             if (darks == NULL) {
00798                 cpl_msg_error(fctid,"Error loading darks extension %d, exptime %g",
00799                               j,ps.ddg[krem].exptime);
00800                 continue;
00801             }
00802 
00803             /* Form a mean dark for this exposure time. If there is only one
00804                then don't bother, just load up that one frame. */
00805 
00806             if (ndarks == 1) {
00807                 outdark = vircam_fits_duplicate(darks[0]);
00808             } else {
00809                 status = VIR_OK;
00810                 (void)vircam_imcombine(darks,ndarks,1,1,1,5.0,&outimage,
00811                                        &rejmask,&rejplus,&drs,&status);
00812                 freespace(rejmask);
00813                 freespace(rejplus);
00814                 freepropertylist(drs);
00815                 if (status != VIR_OK) {
00816                     cpl_msg_error(fctid,"Dark combine failure extension %d exposure %g",
00817                                   j,ps.ddg[krem].exptime);
00818                     freefitslist(darks,ndarks);
00819                     continue;
00820                 }
00821                 outdark = vircam_fits_wrap(outimage,darks[0],NULL,NULL);
00822             }
00823             freefitslist(darks,ndarks);
00824 
00825             /* Load the flats for this group */
00826 
00827             domes = vircam_fits_load_list(ps.ddg[krem].domes,CPL_TYPE_FLOAT,j);
00828             ndomes = ps.ddg[krem].ndomes;
00829             if (domes == NULL) {
00830                 cpl_msg_error(fctid,"Error loading domes extension %d, exptime %g",
00831                               j,ps.ddg[i].exptime);
00832                 freefits(outdark);
00833                 continue;
00834             }
00835             
00836             /* Now loop for each flat in this group or until you have
00837                filled the flats buffer */
00838 
00839             for (kk = 0; kk < ndomes; kk++) {
00840                 status = VIR_OK;
00841                 vircam_darkcor(domes[kk],outdark,1.0,&status);
00842                 ps.flatlist[ps.nflatlist] = vircam_fits_duplicate(domes[kk]);
00843                 ps.ddg[krem].proc[kk] = ps.flatlist[ps.nflatlist];
00844                 ps.nflatlist++;
00845                 if (ps.nflatlist == nuse)
00846                     break;
00847             }
00848 
00849             /* Tidy up a bit */
00850 
00851             freefitslist(domes,ndomes);
00852             freefits(outdark);
00853 
00854             /* Do we have enough yet? */
00855 
00856             if (ps.nflatlist == nuse) 
00857                 break;
00858         }
00859         freespace(exps);
00860         ps.flatlist = cpl_realloc(ps.flatlist,
00861                                   (ps.nflatlist)*sizeof(vir_fits *));
00862         
00863         /* Generate a bad pixel mask now */
00864 
00865         status = VIR_OK;
00866         (void)vircam_genbpm(ps.flatlist,ps.nflatlist,
00867                             vircam_linearity_analyse_config.lthr,
00868                             vircam_linearity_analyse_config.hthr,
00869                             &(ps.bpm_array),&nbad,&badfrac,&status);
00870         bpm = cpl_array_get_data_int(ps.bpm_array);
00871 
00872         /* Store away some useful info */
00873 
00874         vircam_linearity_analyse_config.bad_pixel_num = nbad;
00875         vircam_linearity_analyse_config.bad_pixel_stat = badfrac;
00876 
00877         /* Right. Free the pointer for flatlist, but don't delete the 
00878            vir_fits structures in the list because they are copied into
00879            the ddg structure */
00880 
00881         freespace(ps.flatlist);
00882         ps.nflatlist = 0;
00883 
00884         /* Get an initial allocation of space to hold the stats */
00885 
00886         nalloc = 16;
00887         fdata = cpl_malloc(nalloc*sizeof(double *));
00888         dexps = cpl_malloc(nalloc*sizeof(double));
00889         mjds = cpl_malloc(nalloc*sizeof(double));
00890 
00891         /* Loop through the ddg structure, missing out any that have
00892            overexposed flats. Work out the stats for the images that 
00893            remain. */
00894 
00895         cpl_msg_info(fctid,"Beginning linearity work on extension %d",j);
00896         nfdata = 0;
00897         outdark = NULL;
00898         for (i = 0; i < ps.nddg; i++) {
00899             if (ps.ddg[i].flag == SATURATE_FLAG)
00900                 continue;
00901             for (k = 0; k < ps.ddg[i].ndomes; k++) {
00902 
00903                 /* If this particular frame wasn't processed, then you need
00904                    to form a dark for this group. */
00905 
00906                 if (ps.ddg[i].proc[k] == NULL) {
00907                     if (outdark == NULL) {
00908 
00909                         /* Load the dark frames from this exposure time */
00910 
00911                         darks = vircam_fits_load_list(ps.ddg[i].darks,
00912                                                       CPL_TYPE_FLOAT,j);
00913                         ndarks = ps.ddg[i].ndarks;
00914                         if (darks == NULL) {
00915                             cpl_msg_error(fctid,"Error loading darks extension %d, exptime %g",
00916                                           j,ps.ddg[i].exptime);
00917                             continue;
00918                         }
00919 
00920                         /* Form a mean dark for this exposure time. If there 
00921                            is only one then don't bother, just load up that 
00922                            one frame. */
00923 
00924                         if (ps.ddg[i].ndarks == 1) {
00925                             outdark = vircam_fits_duplicate(darks[0]);
00926                         } else {
00927                             status = VIR_OK;
00928                             (void)vircam_imcombine(darks,ndarks,1,1,1,5.0,
00929                                                    &outimage,&rejmask,&rejplus,
00930                                                    &drs,&status);
00931                             freespace(rejmask);
00932                             freespace(rejplus);
00933                             freepropertylist(drs);
00934                             if (status != VIR_OK) {
00935                                 cpl_msg_error(fctid,
00936                                               "Dark combine failure extension %d exposure %g",
00937                                               j,ps.ddg[i].exptime);
00938                                 freefitslist(darks,ndarks);
00939                                 continue;
00940                             }
00941                             outdark = vircam_fits_wrap(outimage,darks[0],
00942                                                        NULL,NULL);
00943                         }
00944                         freefitslist(darks,ndarks);
00945                     }
00946 
00947                     /* Load the flat and dark correct it */
00948 
00949                     frame = cpl_frameset_get_frame(ps.ddg[i].domes,k);
00950                     fframe = vircam_fits_load(frame,CPL_TYPE_FLOAT,j);
00951                     vircam_darkcor(fframe,outdark,1.0,&status);
00952 
00953                 /* If this frame has already been corrected, then use it */
00954 
00955                 } else {
00956                     fframe = ps.ddg[i].proc[k];
00957                 }
00958 
00959                 /* Generate the stats for this frame and store it */
00960 
00961                 d = vircam_linearity_analyse_genstat(fframe,bpm,pp,np);
00962                 if (nfdata >= nalloc) {
00963                     nalloc += 16;
00964                     fdata = cpl_realloc(fdata,nalloc*sizeof(double *));
00965                     dexps = cpl_realloc(dexps,nalloc*sizeof(double));
00966                     mjds = cpl_realloc(mjds,nalloc*sizeof(double));
00967                 }
00968                 (void)vircam_pfits_get_mjd(vircam_fits_get_phu(fframe),&mjd);
00969                 mjds[nfdata] = mjd;
00970                 dexps[nfdata] = (double)(ps.ddg[i].exptime);            
00971                 fdata[nfdata] = d;              
00972 
00973                 /* If doing diagnostic curves, then add the relevant
00974                    information to the first table now */
00975 
00976                 if (ps.diag1 != NULL) {
00977                     cpl_table_set_string(ps.diag1,"filename",nfdata,
00978                                          vircam_fits_get_filename(fframe));
00979                     cpl_table_set_double(ps.diag1,"exptime",nfdata,
00980                                          dexps[nfdata]);
00981                     cpl_table_set_double(ps.diag1,"mjd",nfdata,mjd);
00982                     for (n = 1; n <= np; n++) {
00983                         snprintf(colname,16,"rawflux_%02d",n);
00984                         cpl_table_set_double(ps.diag1,colname,nfdata,d[n-1]);
00985                     }
00986                 }
00987                 if (ps.ddg[i].proc[k] != NULL) { 
00988                     freefits(ps.ddg[i].proc[k]);
00989                 } else {
00990                     freefits(fframe);
00991                 }
00992                 nfdata++;
00993             }
00994             freefits(outdark);
00995         }
00996         freefits(outdark);
00997         if (ps.diag1 != NULL) 
00998             cpl_table_set_size(ps.diag1,nfdata);
00999 
01000         /* Now, if we are going to tweak the stats using the monitor exposure
01001            then we should do that now */
01002 
01003         if (vircam_linearity_analyse_config.adjust) {
01004 
01005             /* Get some workspace for the data array */
01006 
01007             cdata = cpl_malloc(ps.ndomecheck*sizeof(double *));
01008 
01009             /* Get the exposure time for the monitor set and make sure
01010                that the set isn't saturated */
01011 
01012             test = vircam_fits_load(cpl_frameset_get_first(ps.domecheck),
01013                                     CPL_TYPE_FLOAT,j);
01014             (void)vircam_pfits_get_exptime(vircam_fits_get_phu(test),&exp);
01015             med = cpl_image_get_median((const cpl_image*)vircam_fits_get_image(test));
01016             med *= (1.0 + mindit/exp);
01017             adjust = 1;
01018             if (med > sat) {
01019                 cpl_msg_info(fctid,"Monitor exposures saturated. No drift adjustment made");
01020                 adjust = 0;
01021             }
01022             vircam_fits_delete(test);
01023 
01024             /* Ok assuming all that's going well, then form a mean dark */
01025 
01026             if (adjust) {
01027 
01028                 darks = vircam_fits_load_list(ps.darkcheck,CPL_TYPE_FLOAT,j);
01029                 ndarks = ps.ndarkcheck;
01030                 if (darks == NULL) {
01031                     cpl_msg_error(fctid,
01032                                   "Error loading check darks extension %d",j);
01033                     continue;
01034                 }
01035 
01036                 /* Form a mean dark for this exposure time. If there 
01037                    is only one then don't bother, just load up that 
01038                    one frame. */
01039 
01040                 if (ndarks == 1) {
01041                     outdark = vircam_fits_duplicate(darks[0]);
01042                 } else {
01043                     status = VIR_OK;
01044                     (void)vircam_imcombine(darks,ndarks,1,1,1,5.0,
01045                                            &outimage,&rejmask,&rejplus,
01046                                            &drs,&status);
01047                     freespace(rejmask);
01048                     freespace(rejplus);
01049                     freepropertylist(drs);
01050                     if (status != VIR_OK) {
01051                         cpl_msg_error(fctid,
01052                                       "Dark combine failure extension %d exposure %g",
01053                                       j,ps.ddg[irem].exptime);
01054                         freefitslist(darks,ndarks);
01055                         continue;
01056                     }
01057                     outdark = vircam_fits_wrap(outimage,darks[0],
01058                                                NULL,NULL);
01059                 }
01060                 freefitslist(darks,ndarks);             
01061 
01062                 /* Now, loop through the monitor domes, dark correct and then
01063                    do the stats */
01064                 
01065                 mjdcheck = cpl_malloc(ps.ndomecheck*sizeof(double));
01066                 for (i = 0; i < ps.ndomecheck; i++) {
01067                     frame = cpl_frameset_get_frame(ps.domecheck,i);
01068                     fframe = vircam_fits_load(frame,CPL_TYPE_FLOAT,j);
01069                     vircam_darkcor(fframe,outdark,1.0,&status);
01070                     d = vircam_linearity_analyse_genstat(fframe,bpm,pp,np);
01071                     cdata[i] = d;
01072                     vircam_pfits_get_mjd(vircam_fits_get_phu(fframe),&mjd);
01073                     vircam_pfits_get_exptime(vircam_fits_get_phu(fframe),&exp);
01074                     mjdcheck[i] = mjd;
01075 
01076                     /* If doing diagnostics then fill in the table now */
01077 
01078                     if (ps.diag2 != NULL) {
01079                         cpl_table_set_string(ps.diag2,"filename",i,
01080                                              vircam_fits_get_filename(fframe));
01081                         cpl_table_set_double(ps.diag2,"exptime",i,(double)exp);
01082                         cpl_table_set_double(ps.diag2,"mjd",i,mjd);
01083                         for (n = 1; n <= np; n++) {
01084                             snprintf(colname,16,"rawflux_%02d",n);
01085                             cpl_table_set_double(ps.diag2,colname,i,
01086                                                  d[n-1]);
01087                             snprintf(colname,16,"linflux_%02d",n);
01088                             cpl_table_set_double(ps.diag2,colname,i,
01089                                                  d[n-1]);
01090                         }
01091                     }
01092                     freefits(fframe);
01093                 }
01094                 freefits(outdark);
01095 
01096                 /* Generate the correction factors now */
01097 
01098                 cf = vircam_linearity_tweakfac(cdata,mjdcheck,ps.ndomecheck,
01099                                                np,&facrng,&maxdiff);
01100                 vircam_linearity_analyse_config.facrng = 100.0*(float)facrng;
01101                 vircam_linearity_analyse_config.maxdiff = 100.0*(float)maxdiff;
01102                 if (ps.diag2 != NULL) {
01103                     for (i = 0; i < ps.ndomecheck; i++) 
01104                         cpl_table_set_double(ps.diag2,"adjust_fac",i,cf[i]);
01105                 }
01106 
01107                 /* Ok, now do the correction for each of the linearity
01108                    sequence frames */
01109 
01110                 for (i = 0; i < nfdata; i++) {
01111                     mjd = mjds[i];
01112                     krem = -1;
01113                     for (k = 0; k < ps.ndomecheck; k++) {
01114                         if (mjd < mjdcheck[k]) {
01115                             krem = k;
01116                             break;
01117                         }
01118                     }
01119                     if (krem == -1) {
01120                         fac = cf[ps.ndomecheck-1];
01121                     } else if (krem == 0) {
01122                         fac = cf[0];
01123                     } else {
01124                         fac = 0.5*(cf[krem -1]  + cf[krem]);
01125                     }
01126                     for (k = 0; k < np; k++)
01127                         fdata[i][k] /= fac;
01128                     if (ps.diag1 != NULL) 
01129                         cpl_table_set_double(ps.diag1,"adjust_fac",i,fac);
01130                 }
01131 
01132                 /* Get rid of some stuff now */
01133 
01134                 freespace2(cdata,ps.ndomecheck);
01135                 freespace(cf);
01136                 freespace(mjdcheck);
01137             }
01138         }
01139 
01140         /* Do some intermediate tidying */
01141         
01142         freespace(mjds);
01143         vircam_chan_free(np,&pp);
01144 
01145         /* Right, there should be no images left in memory now. Do the
01146            linearity analysis now. */
01147 
01148         (void)vircam_genlincur(fdata,nfdata,dexps,(double)mindit,ps.chantab,
01149                                vircam_linearity_analyse_config.norder,
01150                                &(ps.lchantab),&lindata,&status);
01151         if (ps.diag1 != NULL) {
01152             for (i = 0; i < nfdata; i++) {
01153                 for (n = 0; n < np; n++) {
01154                     snprintf(colname,16,"linflux_%02d",n+1);
01155                     cpl_table_set_double(ps.diag1,colname,i,lindata[i*np+n]);
01156                 }
01157             }
01158         }
01159         freespace2(fdata,nfdata);
01160         freespace(dexps);
01161         freespace(lindata);
01162         if (status != VIR_OK) {
01163             cpl_msg_error(fctid,"Linearity curve fit failed extension %d",j);
01164             dummy = 1;
01165             if (vircam_linearity_analyse_lastbit(j,framelist,parlist) != 0)
01166                 return(-1);
01167             vircam_linearity_analyse_tidy(1);
01168             continue;
01169         }
01170         
01171         /* Get some QC1 parameters by finding the average fit error and
01172            the average percentage non-linearity */
01173 
01174         vircam_linearity_analyse_config.linearity = 
01175             (float)cpl_table_get_column_mean(ps.lchantab,"lin_10000");
01176         vircam_linearity_analyse_config.linerror = 
01177             (float)cpl_table_get_column_mean(ps.lchantab,"lin_10000_err");
01178 
01179         /* Save new linearity info */
01180 
01181         if (vircam_linearity_analyse_lastbit(j,framelist,parlist) != 0)
01182             return(-1);
01183     }
01184 
01185     /* Get out of here */
01186 
01187     vircam_linearity_analyse_tidy(2);
01188     return(0);
01189 }
01190 
01191 
01192 /*---------------------------------------------------------------------------*/
01199 /*---------------------------------------------------------------------------*/
01200 
01201 static int vircam_linearity_analyse_save(cpl_frameset *framelist,
01202                                          cpl_parameterlist *parlist) {
01203     cpl_propertylist *plist,*elist,*pafprop;
01204     cpl_image *outimg;
01205     const char *outtab = "lchantab.fits";
01206     const char *outbpm = "bpm.fits";
01207     const char *outtabpaf = "lchantab";
01208     const char *outbpmpaf = "bpm";
01209     const char *outdiag1 = "ldiag1.fits";
01210     const char *outdiag2 = "ldiag2.fits";
01211     const char *fctid = "vircam_linearity_analyse_save";
01212     const char *recipeid = "vircam_linearity_analyse";
01213     int nx,ny,nord,*bpm,i;
01214 
01215     /* Do some stuff for the first extension to set up the frame */
01216 
01217     nord = vircam_linearity_analyse_config.norder;
01218     if (isfirst) {
01219 
01220         /* Set up the output frame */
01221 
01222         product_frame_chantab = cpl_frame_new();
01223         cpl_frame_set_filename(product_frame_chantab,outtab);
01224         cpl_frame_set_tag(product_frame_chantab,VIRCAM_PRO_CHANTAB);
01225         cpl_frame_set_type(product_frame_chantab,CPL_FRAME_TYPE_TABLE);
01226         cpl_frame_set_group(product_frame_chantab,CPL_FRAME_GROUP_PRODUCT);
01227         cpl_frame_set_level(product_frame_chantab,CPL_FRAME_LEVEL_FINAL);
01228 
01229         /* Set up the PRO keywords for primary */
01230         
01231         ps.phupaf = vircam_paf_phu_items(ps.plist);
01232         plist = cpl_propertylist_duplicate(ps.plist);
01233         vircam_dfs_set_product_primary_header(plist,product_frame_chantab,
01234                                               ps.sorted,parlist,
01235                                               (char *)recipeid,
01236                                               "PRO-1.15");
01237 
01238         /* Now define the table propertylist and give it an extension name and 
01239            PRO keywords */
01240 
01241         elist = cpl_propertylist_duplicate(ps.elist);
01242         vircam_dfs_set_product_exten_header(elist,product_frame_chantab,
01243                                             ps.sorted,parlist,
01244                                             (char *)recipeid,
01245                                             "PRO-1.15");
01246         
01247         /* Add QC1 info */
01248 
01249         cpl_propertylist_update_float(elist,"ESO QC LINEARITY",
01250                                       vircam_linearity_analyse_config.linearity);
01251         cpl_propertylist_set_comment(elist,"ESO QC LINEARITY",
01252                                      "% non-linearity at 10000 ADU");
01253         cpl_propertylist_update_float(elist,"ESO QC LINERROR",
01254                                       vircam_linearity_analyse_config.linerror);
01255         cpl_propertylist_set_comment(elist,"ESO QC LINERROR",
01256                                      "% error non-linearity at 10000 ADU");
01257         cpl_propertylist_update_float(elist,"ESO QC SCREEN_TOTAL",
01258                                       vircam_linearity_analyse_config.facrng);
01259         cpl_propertylist_set_comment(elist,"ESO QC SCREEN_TOTAL",
01260                                      "total % range in screen variation");
01261         cpl_propertylist_update_float(elist,"ESO QC SCREEN_STEP",
01262                                       vircam_linearity_analyse_config.maxdiff);
01263         cpl_propertylist_set_comment(elist,"ESO QC SCREEN_STEP",
01264                                      "maximum % step in screen variation");
01265 
01266         /* Set up a dummy table if necessary */
01267 
01268         if (dummy == 1) {
01269             vircam_dummy_property(elist);
01270             if (ps.lchantab == NULL) 
01271                 ps.lchantab = vircam_chantab_new(nord,vircam_tfits_get_table(ps.chantab));
01272         }
01273 
01274         /* And finally save the table */
01275  
01276         if (cpl_table_save(ps.lchantab,plist,elist,outtab,CPL_IO_DEFAULT)
01277             != CPL_ERROR_NONE) {
01278             cpl_msg_error(fctid,"Cannot save product table extension");
01279             freepropertylist(plist);
01280             freepropertylist(elist);
01281             return(-1);
01282         }
01283         cpl_frameset_insert(framelist,product_frame_chantab);
01284 
01285         /* Write PAF */
01286 
01287         pafprop = vircam_paf_req_items(elist);
01288         vircam_merge_propertylists(pafprop,ps.phupaf);
01289         vircam_paf_append(pafprop,ps.plist,"ESO INS FILT1 NAME");
01290         if (vircam_paf_print((char *)outtabpaf,"VIRCAM/vircam_linearity_analyse",
01291                              "QC file",pafprop) != VIR_OK)
01292             cpl_msg_warning(fctid,"Unable to save PAF for linearity table");
01293         cpl_propertylist_delete(pafprop);
01294 
01295         /* Quick tidy */
01296 
01297         freepropertylist(plist);
01298         freepropertylist(elist);
01299 
01300         /* Set up the output bad pixel mask primary */
01301 
01302         product_frame_bpm = cpl_frame_new();
01303         cpl_frame_set_filename(product_frame_bpm,outbpm);
01304         cpl_frame_set_tag(product_frame_bpm,VIRCAM_PRO_BPM);
01305         cpl_frame_set_type(product_frame_bpm,CPL_FRAME_TYPE_IMAGE);
01306         cpl_frame_set_group(product_frame_bpm,CPL_FRAME_GROUP_PRODUCT);
01307         cpl_frame_set_level(product_frame_bpm,CPL_FRAME_LEVEL_FINAL);
01308 
01309         /* Set up the PRO keywords for primary header in the bpm */
01310 
01311         plist = ps.plist;
01312         vircam_dfs_set_product_primary_header(plist,product_frame_bpm,
01313                                               ps.sorted,parlist,
01314                                               (char *)recipeid,
01315                                               "PRO-1.15");
01316 
01317         /* Now save the PHU 'image' */
01318 
01319         if (cpl_image_save(NULL,outbpm,CPL_BPP_8_UNSIGNED,plist,
01320                            CPL_IO_DEFAULT) != CPL_ERROR_NONE) {
01321             cpl_msg_error(fctid,"Cannot save product PHU");
01322             cpl_frame_delete(product_frame_bpm);
01323             return(-1);
01324         }
01325         cpl_frameset_insert(framelist,product_frame_bpm);
01326 
01327         /* Section for saving diagnostic tables. First the linearity
01328            sequence diagnostics */
01329 
01330         if (ps.diag1 != NULL) {
01331 
01332             /* Set up the output frame */
01333 
01334             product_frame_diag1 = cpl_frame_new();
01335             cpl_frame_set_filename(product_frame_diag1,outdiag1);
01336             cpl_frame_set_tag(product_frame_diag1,VIRCAM_PRO_LIN_DIAG1);
01337             cpl_frame_set_type(product_frame_diag1,CPL_FRAME_TYPE_TABLE);
01338             cpl_frame_set_group(product_frame_diag1,CPL_FRAME_GROUP_PRODUCT);
01339             cpl_frame_set_level(product_frame_diag1,CPL_FRAME_LEVEL_FINAL);
01340 
01341             /* Set up the PRO keywords for primary */
01342 
01343             plist = cpl_propertylist_duplicate(ps.plist);
01344             vircam_dfs_set_product_primary_header(plist,product_frame_diag1,
01345                                                   ps.sorted,parlist,
01346                                                   (char *)recipeid,
01347                                                   "PRO-1.15");
01348 
01349             /* Now define the table propertylist and give it an extension name and 
01350                PRO keywords */
01351 
01352             elist = cpl_propertylist_duplicate(ps.elist);
01353             vircam_dfs_set_product_exten_header(elist,product_frame_diag1,
01354                                                 ps.sorted,parlist,
01355                                                 (char *)recipeid,
01356                                                     "PRO-1.15");
01357 
01358             /* Set up a dummy property if necessary */
01359 
01360             if (dummy == 1) 
01361                 vircam_dummy_property(elist);
01362 
01363             /* And finally save the table */
01364 
01365             if (cpl_table_save(ps.diag1,plist,elist,outdiag1,CPL_IO_DEFAULT)
01366                 != CPL_ERROR_NONE) {
01367                 cpl_msg_error(fctid,"Cannot save product table extension");
01368                 freepropertylist(plist);
01369                 freepropertylist(elist);
01370                 return(-1);
01371             }
01372             cpl_frameset_insert(framelist,product_frame_diag1);
01373             freepropertylist(plist);
01374             freepropertylist(elist);
01375         }
01376 
01377         /* Now the monitor sequence diagnostics */
01378 
01379         if (ps.diag2 != NULL) {
01380 
01381             /* Set up the output frame */
01382 
01383             product_frame_diag2 = cpl_frame_new();
01384             cpl_frame_set_filename(product_frame_diag2,outdiag2);
01385             cpl_frame_set_tag(product_frame_diag2,VIRCAM_PRO_LIN_DIAG2);
01386             cpl_frame_set_type(product_frame_diag2,CPL_FRAME_TYPE_TABLE);
01387             cpl_frame_set_group(product_frame_diag2,CPL_FRAME_GROUP_PRODUCT);
01388             cpl_frame_set_level(product_frame_diag2,CPL_FRAME_LEVEL_FINAL);
01389 
01390             /* Set up the PRO keywords for primary */
01391 
01392             plist = cpl_propertylist_duplicate(ps.plist);
01393             vircam_dfs_set_product_primary_header(plist,product_frame_diag2,
01394                                                   ps.sorted,parlist,
01395                                                   (char *)recipeid,
01396                                                   "PRO-1.15");
01397 
01398             /* Now define the table propertylist and give it an extension name and 
01399                PRO keywords */
01400 
01401             elist = cpl_propertylist_duplicate(ps.elist);
01402             vircam_dfs_set_product_exten_header(elist,product_frame_diag2,
01403                                                 ps.sorted,parlist,
01404                                                 (char *)recipeid,
01405                                                     "PRO-1.15");
01406 
01407             /* Set up a dummy property if necessary */
01408 
01409             if (dummy == 1) 
01410                 vircam_dummy_property(elist);
01411 
01412             /* And finally save the table */
01413 
01414             if (cpl_table_save(ps.diag2,plist,elist,outdiag2,CPL_IO_DEFAULT)
01415                 != CPL_ERROR_NONE) {
01416                 cpl_msg_error(fctid,"Cannot save product table extension");
01417                 freepropertylist(plist);
01418                 freepropertylist(elist);
01419                 return(-1);
01420             }
01421             cpl_frameset_insert(framelist,product_frame_diag2);
01422             freepropertylist(plist);
01423             freepropertylist(elist);
01424         }
01425 
01426 
01427     /* Section for all other extensions */
01428 
01429     } else {
01430 
01431         /* Do the table extension PRO keywords */
01432 
01433         elist = cpl_propertylist_duplicate(ps.elist);
01434         vircam_dfs_set_product_exten_header(elist,product_frame_chantab,
01435                                             ps.sorted,parlist,
01436                                             (char *)recipeid,
01437                                             "PRO-1.15");
01438 
01439         /* Add QC1 info */
01440 
01441         cpl_propertylist_update_float(elist,"ESO QC LINEARITY",
01442                                       vircam_linearity_analyse_config.linearity);
01443         cpl_propertylist_set_comment(elist,"ESO QC LINEARITY",
01444                                      "% non-linearity at 10000 ADU");
01445         cpl_propertylist_update_float(elist,"ESO QC LINERROR",
01446                                       vircam_linearity_analyse_config.linerror);
01447         cpl_propertylist_set_comment(elist,"ESO QC LINERROR",
01448                                      "% error non-linearity at 10000 ADU");
01449         cpl_propertylist_update_float(elist,"ESO QC SCREEN_TOTAL",
01450                                       vircam_linearity_analyse_config.facrng);
01451         cpl_propertylist_set_comment(elist,"ESO QC SCREEN_TOTAL",
01452                                      "total % range in screen variation");
01453         cpl_propertylist_update_float(elist,"ESO QC SCREEN_STEP",
01454                                       vircam_linearity_analyse_config.maxdiff);
01455         cpl_propertylist_set_comment(elist,"ESO QC SCREEN_STEP",
01456                                      "maximum % step in screen variation");
01457 
01458         /* Set up a dummy table if necessary */
01459 
01460         if (dummy == 1) {
01461             vircam_dummy_property(elist);
01462             if (ps.lchantab == NULL) 
01463                 ps.lchantab = vircam_chantab_new(nord,vircam_tfits_get_table(ps.chantab));
01464         }
01465 
01466         /* And finally save the table */
01467  
01468         if (cpl_table_save(ps.lchantab,NULL,elist,outtab,CPL_IO_EXTEND)
01469             != CPL_ERROR_NONE) {
01470             cpl_msg_error(fctid,"Cannot save product table extension");
01471             freepropertylist(elist);
01472             return(-1);
01473         }
01474 
01475         /* Write PAF */
01476 
01477         pafprop = vircam_paf_req_items(elist);
01478         vircam_merge_propertylists(pafprop,ps.phupaf);
01479         vircam_paf_append(pafprop,ps.plist,"ESO INS FILT1 NAME");
01480         if (vircam_paf_print((char *)outtabpaf,"VIRCAM/vircam_linearity_analyse",
01481                              "QC file",pafprop) != VIR_OK)
01482             cpl_msg_warning(fctid,"Unable to save PAF for BPM");
01483         cpl_propertylist_delete(pafprop);
01484 
01485         /* Quick tidy */
01486 
01487         freepropertylist(elist);
01488 
01489         /* Now the diagnostic tables */
01490 
01491         if (ps.diag1 != NULL) {
01492             elist = cpl_propertylist_duplicate(ps.elist);
01493             vircam_dfs_set_product_exten_header(elist,product_frame_diag1,
01494                                                 ps.sorted,parlist,
01495                                                 (char *)recipeid,
01496                                                 "PRO-1.15");
01497 
01498             /* Set up a dummy property if necessary */
01499 
01500             if (dummy == 1) 
01501                 vircam_dummy_property(elist);
01502 
01503             /* And finally save the table */
01504 
01505             if (cpl_table_save(ps.diag1,NULL,elist,outdiag1,CPL_IO_EXTEND)
01506                 != CPL_ERROR_NONE) {
01507                 cpl_msg_error(fctid,"Cannot save product table extension");
01508                 freepropertylist(elist);
01509                 return(-1);
01510             }
01511             freepropertylist(elist);
01512         }
01513         if (ps.diag2 != NULL) {
01514             elist = cpl_propertylist_duplicate(ps.elist);
01515             vircam_dfs_set_product_exten_header(elist,product_frame_diag2,
01516                                                 ps.sorted,parlist,
01517                                                 (char *)recipeid,
01518                                                 "PRO-1.15");
01519 
01520             /* Set up a dummy property if necessary */
01521 
01522             if (dummy == 1) 
01523                 vircam_dummy_property(elist);
01524 
01525             /* And finally save the table */
01526 
01527             if (cpl_table_save(ps.diag2,NULL,elist,outdiag2,CPL_IO_EXTEND)
01528                 != CPL_ERROR_NONE) {
01529                 cpl_msg_error(fctid,"Cannot save product table extension");
01530                 freepropertylist(elist);
01531                 return(-1);
01532             }
01533             freepropertylist(elist);
01534         }
01535 
01536     }
01537 
01538     /* Save the bpm extension now */
01539 
01540     plist = ps.elist;
01541     nx = ps.nx;
01542     ny = ps.ny;
01543     if (dummy && ps.bpm_array == NULL) {
01544         ps.bpm_array = cpl_array_new(nx*ny,CPL_TYPE_INT);
01545         bpm = cpl_array_get_data_int(ps.bpm_array);
01546         for (i = 0; i < nx*ny; i++)
01547             bpm[i] = 0;
01548     }
01549     bpm = cpl_array_get_data_int(ps.bpm_array);
01550     vircam_dfs_set_product_exten_header(plist,product_frame_bpm,
01551                                         ps.sorted,parlist,
01552                                         (char *)recipeid,
01553                                         "PRO-1.15");
01554     cpl_propertylist_update_float(plist,"ESO QC BAD_PIXEL_STAT",
01555                                   vircam_linearity_analyse_config.bad_pixel_stat);
01556     cpl_propertylist_set_comment(plist,"ESO QC BAD_PIXEL_STAT",
01557                                  "Fraction of pixels that are bad");
01558     cpl_propertylist_update_int(plist,"ESO QC BAD_PIXEL_NUM",
01559                                 vircam_linearity_analyse_config.bad_pixel_num);
01560     cpl_propertylist_set_comment(plist,"ESO QC BAD_PIXEL_NUM",
01561                                  "Number of pixels that are bad");
01562     if (dummy)
01563         vircam_dummy_property(plist);
01564     outimg = cpl_image_wrap_int(nx,ny,bpm);
01565     if (cpl_image_save(outimg,outbpm,CPL_BPP_8_UNSIGNED,plist,
01566                        CPL_IO_EXTEND) != CPL_ERROR_NONE) {
01567         cpl_msg_error(fctid,"Cannot save product image extension");
01568         return(-1);
01569     }
01570 
01571     /* Write PAF */
01572 
01573     pafprop = vircam_paf_req_items(plist);
01574     vircam_merge_propertylists(pafprop,ps.phupaf);
01575     vircam_paf_append(pafprop,ps.plist,"ESO INS FILT1 NAME");
01576     if (vircam_paf_print((char *)outbpmpaf,"VIRCAM/vircam_linearity_analyse",
01577                          "QC file",pafprop) != VIR_OK)
01578         cpl_msg_warning(fctid,"Unable to save PAF for linearity table");
01579     cpl_propertylist_delete(pafprop);
01580 
01581     /* Quick tidy */
01582 
01583     cpl_image_unwrap(outimg);
01584 
01585     return(0);
01586 }
01587 
01588 /*---------------------------------------------------------------------------*/
01596 /*---------------------------------------------------------------------------*/
01597 
01598 static int vircam_linearity_analyse_lastbit(int jext, cpl_frameset *framelist,
01599                                             cpl_parameterlist *parlist) {
01600     int retval;
01601     const char *fctid = "vircam_linearity_analyse_lastbit";
01602 
01603     /* Save the new channel table and bad pixel map */
01604 
01605     cpl_msg_info(fctid,"Saving linearity table and bpm for extension %d",jext);
01606     retval = vircam_linearity_analyse_save(framelist,parlist);
01607     if (retval != 0) {
01608         vircam_linearity_analyse_tidy(2);
01609         return(-1);
01610     }
01611 
01612     /* Do some intermediate tidying */
01613 
01614     vircam_linearity_analyse_tidy(1);
01615     return(0);
01616 }
01617 
01618 /*---------------------------------------------------------------------------*/
01622 /*---------------------------------------------------------------------------*/
01623 
01624 static int vircam_linearity_analyse_domedark_groups(void) {
01625     int i,j,found;
01626     float texp;
01627     cpl_frame *frame;
01628     cpl_propertylist *plist;
01629     const char *fctid = "vircam_linearity_analyse_domedark_groups";
01630 
01631     /* Start by getting the memory for the domedark groups */
01632 
01633     ps.ddg = cpl_calloc(ps.ndomes,sizeof(ddgrp));
01634     ps.nddg = 0;
01635 
01636     /* Loop for each of the dome frames and get its exposure time. If this
01637        doesn't exist, then signal an error and go on */
01638 
01639     for (i = 0; i < ps.ndomes; i++) {
01640         frame = cpl_frameset_get_frame(ps.domelist,i);
01641         plist = cpl_propertylist_load(cpl_frame_get_filename(frame),0);
01642         if (vircam_pfits_get_exptime(plist,&texp) != VIR_OK) {
01643             cpl_msg_warning(fctid,"No exposure time found in %s",
01644                             cpl_frame_get_filename(frame));
01645             cpl_propertylist_delete(plist);
01646             continue;
01647         }
01648         cpl_propertylist_delete(plist);
01649 
01650         /* Search the domedark groups to see if this exposure time has already 
01651            been used. If not, then create a new group. If it has then just add 
01652            this frame to the correct group */
01653 
01654         found = 0;
01655         for (j = 0; j < ps.nddg; j++) {
01656             if (ps.ddg[j].exptime == texp) {
01657                 found = 1;
01658                 break;
01659             }
01660         }
01661         if (found) {
01662             cpl_frameset_insert(ps.ddg[j].domes,cpl_frame_duplicate(frame));
01663             ps.ddg[j].ndomes += 1;
01664         } else {
01665             ps.ddg[ps.nddg].exptime = texp;
01666             ps.ddg[ps.nddg].darks = cpl_frameset_new();
01667             ps.ddg[ps.nddg].domes = cpl_frameset_new();
01668             ps.ddg[ps.nddg].ndarks = 0;
01669             ps.ddg[ps.nddg].ndomes = 1;
01670             ps.ddg[ps.nddg].flag = OK_FLAG;
01671             cpl_frameset_insert(ps.ddg[ps.nddg].domes,
01672                                cpl_frame_duplicate(frame));
01673             ps.nddg += 1;
01674         }
01675     }
01676             
01677     /* Right, now loop through all the darks and get their exposure times */
01678 
01679     for (i = 0; i < ps.ndarks; i++) {
01680         frame = cpl_frameset_get_frame(ps.darklist,i);
01681         plist = cpl_propertylist_load(cpl_frame_get_filename(frame),0);
01682         if (vircam_pfits_get_exptime(plist,&texp) != VIR_OK) {
01683             cpl_msg_warning(fctid,"No exposure time found in %s",
01684                             cpl_frame_get_filename(frame));
01685             cpl_propertylist_delete(plist);
01686             continue;
01687         }
01688         cpl_propertylist_delete(plist);
01689 
01690         /* Search the domedark groups to see if this dark fits into one of
01691            the defined groups. If not, then ignore it. If it does, then
01692            add it into the dark frameset */
01693 
01694         found = 0;
01695         for (j = 0; j < ps.nddg; j++) {
01696             if (ps.ddg[j].exptime == texp) {
01697                 found = 1;
01698                 break;
01699             }
01700         }
01701         if (found) {
01702             cpl_frameset_insert(ps.ddg[j].darks,cpl_frame_duplicate(frame));
01703             ps.ddg[j].ndarks += 1;
01704         }
01705     }
01706 
01707     /* Now go through the domedark groups and ditch any that don't have any
01708        dark frames */
01709 
01710     i = 0;
01711     while (i < ps.nddg) {
01712         if (ps.ddg[i].ndarks == 0) {
01713             cpl_msg_error(fctid,"No dark frames exist for exposure %g\n",
01714                           ps.ddg[i].exptime);
01715             freeframeset(ps.ddg[i].darks);
01716             freeframeset(ps.ddg[i].domes);
01717             for (j = i+1; j < ps.nddg; j++)
01718                 ps.ddg[j-1] = ps.ddg[j];
01719             ps.nddg -= 1;
01720         } else
01721             i++;
01722     }
01723 
01724     /* Allocate some space for vir_fits arrays for processed domes */
01725 
01726     for (i = 0; i < ps.nddg; i++) {
01727         ps.ddg[i].proc = cpl_malloc(ps.ddg[i].ndomes*sizeof(vir_fits *));
01728         for (j = 0; j < ps.ddg[i].ndomes; j++) 
01729             ps.ddg[i].proc[j] = NULL;
01730     }                
01731 
01732     /* Resize the output array and return so long as there is anything
01733        left. If there isn't then signal a major error */
01734 
01735     if (ps.nddg > 0) {
01736         ps.ddg = cpl_realloc(ps.ddg,ps.nddg*sizeof(ddgrp));
01737         return(0);
01738     } else {
01739         cpl_msg_error(fctid,"There are no darks defined for input domes");
01740         return(-1);
01741     }
01742 }
01743 
01744 /*---------------------------------------------------------------------------*/
01753 /*---------------------------------------------------------------------------*/
01754 
01755 static double *vircam_linearity_analyse_genstat(vir_fits *fframe, int *bpm,
01756                                                 parquet *p, int np) {
01757     int i,ist,ifn,jst,jfn,n,jind2,iind2,jj,nx,ii;
01758     parquet *pp;
01759     double *d;
01760     float *tmp,*data;
01761 
01762     /* Get the workspace for the output result */
01763 
01764     d = cpl_malloc(np*sizeof(double));
01765 
01766     /* Get the input data array */
01767 
01768     nx = cpl_image_get_size_x(vircam_fits_get_image(fframe));
01769     data = cpl_image_get_data_float(vircam_fits_get_image(fframe));
01770 
01771     /* Get some workspace for doing the median calculations */
01772 
01773     tmp = cpl_malloc(SUBSET*SUBSET*sizeof(float));
01774 
01775     /* Loop for each channel in the parquet structure */
01776 
01777     for (i = 0; i < np; i++) {
01778         pp = p + i;
01779 
01780         /* Take the central part of the channel */
01781 
01782         ist = ((pp->delta_i)/2 - SUBSET2);
01783         ifn = ist + SUBSET - 1;
01784         jst = ((pp->delta_j)/2 - SUBSET2);
01785         jfn = jst + SUBSET - 1;
01786 
01787         /* Put the data into the workspace and do a median */
01788 
01789         n = 0;
01790         for (jj = jst; jj <= jfn; jj++) {
01791             jind2 = (jj + pp->iymin - 1)*nx;
01792             for (ii = ist; ii <= ifn; ii++) {
01793                 iind2 = jind2 + ii + pp->ixmin - 1;
01794                 if (bpm[iind2] == 0) 
01795                     tmp[n++] = data[iind2];
01796             }
01797         }
01798         d[i] = (double)vircam_med(tmp,NULL,(long)n);
01799     }
01800 
01801     /* Tidy and get out of here */
01802 
01803     freespace(tmp);
01804     return(d);
01805 }
01806 
01807 /*---------------------------------------------------------------------------*/
01819 /*---------------------------------------------------------------------------*/
01820 
01821 static double *vircam_linearity_tweakfac(double **fdata, double *mjd, int nim,
01822                                          int nchan, double *facrng, 
01823                                          double *maxdiff) {
01824     int i,ist,ifn,j;
01825     double *factors,sum,midval,minfac,maxfac;
01826 
01827     /* Get some memory for the output array */
01828 
01829     factors = cpl_malloc(nim*sizeof(double));
01830 
01831     /* First sort the data into order of mjd */
01832 
01833     vircam_mjdsort(fdata,mjd,nim);
01834 
01835     /* Which index is the midpoint? */
01836 
01837     if (nim % 2 == 0) {
01838         ist = nim/2 - 1;
01839         ifn = ist + 1;
01840     } else {
01841         ist = nim/2;
01842         ifn = ist;
01843     }
01844 
01845     /* Loop for each channel */
01846 
01847     for (i = 0; i < nchan; i++) {
01848         
01849         /* Get midpoint value */
01850 
01851         midval = 0.5*(fdata[ist][i] + fdata[ifn][i]);
01852 
01853         /* Now normalise all the ith channels by this value */
01854 
01855         for (j = 0; j < nim; j++) 
01856             fdata[j][i] /= midval;
01857     }
01858 
01859     /* Now loop for each image and average the values for all the channels in
01860        in image */
01861 
01862     *maxdiff = 0.0;
01863     for (j = 0; j < nim; j++) {
01864         sum = 0.0;
01865         for (i = 0; i < nchan; i++)
01866             sum += fdata[j][i];
01867         factors[j] = sum/(double)nchan;
01868         if (j == 0) {
01869             maxfac = factors[j];
01870             minfac = factors[j];
01871         } else {
01872             minfac = min(minfac,factors[j]);
01873             maxfac = max(maxfac,factors[j]);
01874             *maxdiff = max(*maxdiff,fabs(factors[j]-factors[j-1]));
01875         }
01876     }
01877     *facrng = maxfac - minfac;
01878 
01879     /* Get out of here */
01880 
01881     return(factors);
01882 }
01883     
01884 /*---------------------------------------------------------------------------*/
01892 /*---------------------------------------------------------------------------*/
01893 
01894 static void vircam_mjdsort(double **fdata, double *mjd, int n) {
01895     int iii,ii,i,ifin,j,it;
01896     double tmpmjd,*tmpdata;
01897 
01898 
01899     iii = 2;
01900     while (iii < n)
01901         iii *= 2;
01902     iii = min(n,(3*iii)/4 - 1);
01903 
01904     while (iii > 1) {
01905         iii /= 2;
01906         ifin = n - iii;
01907         for (ii = 0; ii < ifin; ii++) {
01908             i = ii;
01909             j = i + iii;
01910             if (mjd[i] > mjd[j]) {
01911                 tmpmjd = mjd[j];
01912                 tmpdata = fdata[j];
01913                 while (1) {
01914                     mjd[j] = mjd[i];
01915                     fdata[j] = fdata[i];
01916                     j = i;
01917                     i = i - iii;
01918                     if (i < 0 || mjd[0] <= tmpmjd) 
01919                         break;
01920                 }
01921                 mjd[j] = tmpmjd;
01922                 fdata[j] = tmpdata;
01923             }
01924         }
01925     }
01926 }
01927 
01928 /*---------------------------------------------------------------------------*/
01935 /*---------------------------------------------------------------------------*/
01936 
01937 static cpl_table *vircam_linearity_analyse_diagtab_init(int np, int nrows) {
01938     int i;
01939     char colname[16];
01940     cpl_table *t;
01941 
01942     /* Create a new table */
01943 
01944     t = cpl_table_new(nrows);
01945 
01946     /* Add the first few columns */
01947 
01948     cpl_table_new_column(t,"filename",CPL_TYPE_STRING);
01949     cpl_table_new_column(t,"exptime",CPL_TYPE_DOUBLE);
01950     cpl_table_set_column_unit(t,"exptime","seconds");
01951     cpl_table_new_column(t,"mjd",CPL_TYPE_DOUBLE);
01952     cpl_table_set_column_unit(t,"mjd","days");
01953 
01954     /* Add columns for each of the channels' raw median flux and linearised 
01955        median flux */
01956 
01957     for (i = 1; i <= 16; i++) {
01958         (void)snprintf(colname,16,"rawflux_%02d",i);
01959         cpl_table_new_column(t,colname,CPL_TYPE_DOUBLE);
01960         cpl_table_set_column_unit(t,colname,"ADU");
01961         (void)snprintf(colname,16,"linflux_%02d",i);
01962         cpl_table_new_column(t,colname,CPL_TYPE_DOUBLE);
01963         cpl_table_set_column_unit(t,colname,"ADU");
01964     }
01965 
01966     /* Finally add the correction factors that were used */
01967 
01968     cpl_table_new_column(t,"adjust_fac",CPL_TYPE_DOUBLE);
01969 
01970     /* Right, get out of here */
01971 
01972     return(t);
01973 }
01974 
01975 /*---------------------------------------------------------------------------*/
01979 /*---------------------------------------------------------------------------*/
01980 
01981 static void vircam_linearity_analyse_init(void) {
01982     ps.labels = NULL;
01983     ps.domelist = NULL;
01984     ps.darklist = NULL;
01985     ps.domecheck = NULL;
01986     ps.darkcheck = NULL;
01987     ps.ndomes = 0;
01988     ps.ndarks = 0;
01989     ps.ndomecheck = 0;
01990     ps.ndarkcheck = 0;
01991     ps.chanfrm = NULL;
01992     ps.chantab = NULL;
01993     ps.lchantab = NULL;
01994     ps.flatlist = NULL;
01995     ps.bpm_array = NULL;
01996     ps.ddg = NULL;
01997     ps.plist = NULL;
01998     ps.elist = NULL;
01999     ps.phupaf = NULL;
02000     ps.diag1 = NULL;
02001     ps.diag2 = NULL;
02002 }
02003 
02004 /*---------------------------------------------------------------------------*/
02008 /*---------------------------------------------------------------------------*/
02009 
02010 static void vircam_linearity_analyse_tidy(int level) {
02011     int i;
02012 
02013     freetfits(ps.chantab);
02014     freearray(ps.bpm_array);
02015     freefitslist(ps.flatlist,ps.nflatlist);
02016     freetable(ps.lchantab);
02017     freepropertylist(ps.plist);
02018     freepropertylist(ps.elist);
02019     freetable(ps.diag1);
02020     freetable(ps.diag2);
02021     if (level == 1)
02022         return;
02023     
02024     freespace(ps.labels);
02025     freeframeset(ps.domelist);
02026     freeframeset(ps.darklist);
02027     freeframeset(ps.domecheck);
02028     freeframeset(ps.darkcheck);
02029     freeframeset(ps.sorted);
02030     freeframe(ps.chanfrm);
02031     if (ps.ddg != NULL) {
02032         for (i = 0; i < ps.nddg; i++) {
02033             freeframeset(ps.ddg[i].darks);
02034             freeframeset(ps.ddg[i].domes);
02035             freefitslist(ps.ddg[i].proc,ps.ddg[i].ndomes);
02036         }
02037         freespace(ps.ddg);
02038     }
02039     freepropertylist(ps.phupaf);
02040 }
02041 
02044 /* 
02045 
02046 $Log: vircam_linearity_analyse.c,v $
02047 Revision 1.51  2008/01/22 19:47:56  jim
02048 New version to implement new algorithm
02049 
02050 Revision 1.50  2007/11/26 09:58:49  jim
02051 Now fails if given observation files done with NDIT != 1
02052 
02053 Revision 1.49  2007/11/23 18:34:28  jim
02054 fixed memory allocation bug
02055 
02056 Revision 1.48  2007/11/22 12:36:55  jim
02057 Modified to create diagnostic tables
02058 
02059 Revision 1.47  2007/11/20 09:41:13  jim
02060 Added ability to alter dome sequence stats by using the monitoring exposures
02061 
02062 Revision 1.46  2007/11/14 10:42:25  jim
02063 Substantial changes to incorporate new linearity analysis algorithm and to
02064 restrict the amount of memory required to do the analysis (especially
02065 the BPM work)
02066 
02067 Revision 1.45  2007/09/07 13:32:12  jim
02068 uses a sorted framelist to ensure that the correct information is given
02069 to the output product header
02070 
02071 Revision 1.44  2007/09/06 21:37:53  jim
02072 fixed call to vircam_dfs_setup_product_ routines to use the full input
02073 frameset
02074 
02075 Revision 1.43  2007/08/29 09:20:33  jim
02076 Primary header is now derived from the same header that forms the PAF rather
02077 than starting off empty and allowing CPL to copy everything it thinks you
02078 want...
02079 
02080 Revision 1.42  2007/08/23 09:02:03  jim
02081 Modified to check domes for DETLIVE before checking darks
02082 
02083 Revision 1.41  2007/07/09 13:21:55  jim
02084 Modified to use new version of vircam_exten_range
02085 
02086 Revision 1.40  2007/06/13 08:11:27  jim
02087 Modified docs to reflect changes in DFS tags
02088 
02089 Revision 1.39  2007/04/30 09:40:17  jim
02090 Added more stuff to paf files
02091 
02092 Revision 1.38  2007/04/04 10:36:07  jim
02093 Fixed typo preventing output of main PAF. Also modified to use dfs tags
02094 
02095 Revision 1.37  2007/03/29 12:19:38  jim
02096 Little changes to improve documentation
02097 
02098 Revision 1.36  2007/03/01 12:41:49  jim
02099 Modified slightly after code checking
02100 
02101 Revision 1.35  2007/02/19 21:13:04  jim
02102 added bad pixel number QC parameter
02103 
02104 Revision 1.34  2007/02/15 11:54:09  jim
02105 Modified to make a distinction between initial channel table and one that
02106 has the proper linearity information
02107 
02108 Revision 1.33  2007/02/15 06:59:38  jim
02109 Added ability to write QC paf files
02110 
02111 Revision 1.32  2007/02/07 10:12:40  jim
02112 Removed calls to vircam_ndit_correct as this is now no longer necessary
02113 
02114 Revision 1.31  2007/02/06 13:11:12  jim
02115 Fixed entry for PRO dictionary in cpl_dfs_set_product_header
02116 
02117 Revision 1.30  2006/12/13 11:45:36  jim
02118 Fixed scaling of sigma error
02119 
02120 Revision 1.29  2006/12/11 22:47:12  jim
02121 Fixed subtle bug in the way that stats were being done.
02122 
02123 Revision 1.28  2006/11/27 12:15:08  jim
02124 changed calls to cpl_propertylist_append to cpl_propertylist_update
02125 
02126 Revision 1.27  2006/11/10 09:23:46  jim
02127 Fixed save routine so to use a new version of vircam_chantab_new
02128 
02129 Revision 1.26  2006/10/31 10:27:27  jim
02130 Fixed a few bugs and modified to make sure than an extension name appear
02131 in each fits extension
02132 
02133 Revision 1.25  2006/09/09 16:49:40  jim
02134 Header comment update
02135 
02136 Revision 1.24  2006/09/08 09:20:22  jim
02137 major upgrade to main processing routine: to deal with bad input better; to
02138 write out dummy results in the case of failure; to combine raw darks on the
02139 fly for use in dark correction, rather than using master darks;
02140 
02141 Revision 1.23  2006/08/03 13:26:44  jim
02142 fixed another typo
02143 
02144 Revision 1.22  2006/08/03 10:36:32  jim
02145 Fixed typo
02146 
02147 Revision 1.21  2006/06/20 19:06:38  jim
02148 Added correction for ndit. Now adjusts the value of norder if the number
02149 of frames given is too small for the order of polynomial requested
02150 
02151 Revision 1.20  2006/06/15 09:58:58  jim
02152 Minor changes to docs
02153 
02154 Revision 1.19  2006/06/06 13:03:42  jim
02155 Fixed scaling that was causing funny stats
02156 
02157 Revision 1.18  2006/05/27 21:40:06  jim
02158 Bad pixels are now defined by a number of sigma above or below the mean
02159 
02160 Revision 1.17  2006/05/09 09:30:47  jim
02161 Fixed _save routine so that bad pixel mask is saved with unsigned char
02162 data type
02163 
02164 Revision 1.16  2006/05/08 12:32:12  jim
02165 Changed default calling parameters for vircam_imcombine
02166 
02167 Revision 1.15  2006/05/04 11:53:15  jim
02168 Fixed the way the _save routine works to be more consistent with the
02169 standard CPL way of doing things
02170 
02171 Revision 1.14  2006/05/03 12:55:17  jim
02172 Fixed some memory leaks
02173 
02174 Revision 1.13  2006/05/02 13:26:32  jim
02175 fixed bug where the wrong amount of memory was being allocated for the dark
02176 exposure times
02177 
02178 Revision 1.12  2006/05/02 11:36:29  jim
02179 fixed illegal propertylist_delete calls
02180 
02181 Revision 1.11  2006/04/27 09:46:01  jim
02182 Modified DFS frame types to conform to new dictionary
02183 
02184 Revision 1.10  2006/04/25 13:45:57  jim
02185 Fixed to adhere to new calling sequence for vircam_dfs routines
02186 
02187 Revision 1.9  2006/04/24 12:12:59  jim
02188 Fixed --help documentation and sorted out filename extension problem
02189 (.fit -> .fits)
02190 
02191 Revision 1.8  2006/04/20 11:31:34  jim
02192 Added bad pixel masking
02193 
02194 Revision 1.7  2006/03/23 21:18:45  jim
02195 Minor changes mainly to comment headers
02196 
02197 Revision 1.6  2006/03/22 14:02:51  jim
02198 cosmetic changes to keep lint happy
02199 
02200 Revision 1.5  2006/03/22 12:13:51  jim
02201 Modified to use new vircam_mask capability
02202 
02203 Revision 1.4  2006/03/15 10:43:40  jim
02204 Fixed a few things
02205 
02206 Revision 1.3  2006/03/03 14:29:06  jim
02207 Now calls routines with vir_fits.
02208 
02209 Revision 1.2  2006/02/22 10:01:22  jim
02210 Added full documentation
02211 
02212 Revision 1.1  2006/02/18 11:49:58  jim
02213 new file
02214 
02215 
02216 */

Generated on Wed Apr 10 04:01:56 2013 for VIRCAM Pipeline by  doxygen 1.5.1