vircam_genlincur.c

00001 /* $Id: vircam_genlincur.c,v 1.24 2008/01/22 19:45:24 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:45:24 $
00024  * $Revision: 1.24 $
00025  * $Name:  $
00026  */
00027 
00028 /* Includes */
00029 
00030 #ifdef HAVE_CONFIG_H
00031 #include <config.h>
00032 #endif
00033 
00034 #include <cpl.h>
00035 
00036 #include <math.h>
00037 
00038 #include "vircam_mods.h"
00039 #include "vircam_utils.h"
00040 #include "vircam_stats.h"
00041 #include "vircam_pfits.h"
00042 #include "vircam_channel.h"
00043 
00044 
00045 #define SZCOLNAME 16
00046 
00047 static double nom_val = 10000;
00048 static double nom_kfac = 0.1;
00049 
00050 
00051 static double linval(double inval, double k, double tolerance, int niter,
00052                      double *b, int norder);
00053 static double getkfac(long index, long ncpts, float reset_time, 
00054                       float read_time, float delay_time, float exptime);
00055 static void getco(double *a, int nord, int m);
00056 
00059 /*---------------------------------------------------------------------------*/
00114 /*---------------------------------------------------------------------------*/
00115 
00116 extern int vircam_genlincur(double **fdata, int nimages, double *exps, 
00117                             double mindit, vir_tfits *chantab, 
00118                             int norder, cpl_table **lchantab, 
00119                             double **lindata, int *status) {
00120 
00121     const char *fctid = "vircam_genlincur";
00122     int retval,i,j,nbad,oldnorder,nullval,k;
00123     long np;
00124     double *meds,sigfit,**aco,c0,val,lin_nom,*temp,*polyco,pt,*work,kfac;
00125     double a0,a1,sum,sumsq;
00126     parquet *p,*pp;
00127     cpl_table *ctab,*lc;
00128     cpl_array *exparray,*medsarray,*polyfitco;
00129     char colname[SZCOLNAME];
00130 
00131     /* Inherited status */
00132 
00133     *lchantab = NULL;
00134     if (*status != VIR_OK)
00135         return(*status);
00136 
00137     /* Check that you have enough images in the list */
00138 
00139     if (nimages < norder+1) {
00140         cpl_msg_error(fctid,"Not enought images (%d) for fit order (%d)",
00141                       nimages,norder);
00142         FATAL_ERROR
00143     }
00144 
00145     /* Open the parquet structure for the channel table */
00146 
00147     ctab = vircam_tfits_get_table(chantab);
00148     retval = vircam_chan_fill(ctab,&pp,&np);
00149     if (retval != VIR_OK) {
00150         *status = retval;
00151         return(retval);
00152     }
00153 
00154     /* Create an output channel table. Copy the input channel table and then
00155        massage the linearity part */
00156 
00157     lc = cpl_table_duplicate(ctab);
00158     oldnorder = cpl_table_get_int(lc,"norder",0,&nullval);
00159     if (oldnorder > norder) {
00160         for (i = norder+1; i <= oldnorder; i++) {
00161             snprintf(colname,SZCOLNAME,"coeff_%d",i);
00162             cpl_table_erase_column(lc,colname);
00163         }
00164     } else if (oldnorder < norder) {
00165         for (i = oldnorder+1; i <= norder; i++) {
00166             snprintf(colname,SZCOLNAME,"coeff_%d",i);
00167             if (cpl_table_has_column(lc,colname)) 
00168                 continue;
00169             cpl_table_new_column(lc,colname,CPL_TYPE_DOUBLE);
00170         }
00171     }
00172 
00173     /* Get some memory for the fitting arrays */
00174 
00175     exparray = cpl_array_wrap_double(exps,nimages);
00176     medsarray = cpl_array_new(nimages,CPL_TYPE_DOUBLE);
00177     meds = cpl_array_get_data_double(medsarray);
00178     aco = cpl_malloc(norder*sizeof(double *));
00179     for (i = 0; i < norder; i++) 
00180         aco[i] = cpl_malloc(norder*sizeof(double));
00181     temp = cpl_malloc(norder*sizeof(double));
00182 
00183     /* Get memory for output array of linearised stats */
00184 
00185     *lindata = cpl_malloc(nimages*np*sizeof(double));
00186 
00187     /* Loop for each channel */
00188 
00189     nbad = 0;
00190     for (i = 0; i < np; i++) {
00191         p = pp + i;
00192 
00193         /* Load the data up for this channel */
00194 
00195         for (j = 0; j < nimages; j++) 
00196             meds[j] = fdata[j][i];
00197 
00198         /* Do the initial fit */
00199 
00200         if (vircam_polyfit(exparray,medsarray,norder,1,1,3.0,3.0,&polyfitco,
00201                            &sigfit) != VIR_OK) {
00202             nbad++;
00203             cpl_table_set_int(lc,"norder",i,norder);
00204             cpl_table_set_double(lc,"coeff_1",i,1.0);
00205             for (k = 1; k < norder; k++) {
00206                 snprintf(colname,SZCOLNAME,"coeff_%d",k+1);
00207                 cpl_table_set_double(lc,colname,i,0.0);
00208             }
00209             continue;
00210         }
00211         polyco = cpl_array_get_data_double(polyfitco);
00212 
00213         /* Get intermediate coefficients for matrix */
00214 
00215         for (j = 0; j < norder; j++) {
00216             getco(temp,norder,j+1);
00217             for (k = 0; k < norder; k++) {
00218                 pt = pow(mindit,(double)(j-k));
00219                 aco[j][k] = pt*temp[k];
00220             }
00221         }
00222 
00223         /* Solve matrix equation to do the back substitution */
00224 
00225         if (vircam_solve_gauss(aco,polyco,norder) != VIR_OK) {
00226             nbad++;
00227             cpl_table_set_int(lc,"norder",i,norder);
00228             cpl_table_set_double(lc,"coeff_1",i,1.0);
00229             for (k = 1; k < norder; k++) {
00230                 snprintf(colname,SZCOLNAME,"coeff_%d",k+1);
00231                 cpl_table_set_double(lc,colname,i,0.0);
00232             }
00233             continue;
00234         }
00235 
00236         /* Now normalise to unit slope and write the result to the table*/
00237 
00238         c0 = polyco[0];
00239         for (j = 0; j < norder; j++) {
00240             polyco[j] /= pow(c0,(double)(j+1));
00241             snprintf(colname,SZCOLNAME,"coeff_%d",j+1);
00242             cpl_table_set_double(lc,colname,i,polyco[j]);
00243         }
00244         cpl_table_set_int(lc,"norder",i,norder);
00245 
00246         /* Work out the percentage of non-linearity for nominal kfac and
00247            intensity values */
00248 
00249         val = linval(nom_val,nom_kfac,0.5,10,polyco,norder);
00250         lin_nom = 100*fabs(val - nom_val)/nom_val;
00251 
00252         /* Work out how well the solution creates a linear system. Loop 
00253            for each input image and work out a 'linearised' median. Then
00254            do a linear fit to the linearsed median vs exposure time. */
00255 
00256         work = cpl_malloc(nimages*sizeof(double));
00257         for (j = 0; j < nimages; j++) {
00258             kfac = mindit/exps[j];
00259             work[j] = linval(meds[j],kfac,0.5,10,polyco,norder);
00260             (*lindata)[j*np+i] = work[j];
00261         }
00262         vircam_linfit(nimages,exps,work,&a0,&a1,&sigfit);
00263         sigfit *= 100.0/nom_val;
00264         freearray(polyfitco)
00265                        
00266         /* Put the nominal linearity and the fit quality into the header */
00267 
00268         cpl_table_set_double(lc,"lin_10000_err",i,sigfit);
00269         cpl_table_set_double(lc,"lin_10000",i,lin_nom);
00270         freespace(work);
00271     }
00272 
00273     /* Tidy and get out of here */
00274 
00275     *lchantab = cpl_table_duplicate(lc);
00276     cpl_array_unwrap(exparray);
00277     freearray(medsarray);
00278     freespace2(aco,norder);
00279     freespace(temp);
00280     freetable(lc);
00281     vircam_chan_free(np,&pp);
00282     if (nbad != 0) {
00283         cpl_msg_warning(fctid,"%d channels have a failed solution",nbad);
00284         WARN_RETURN
00285     }
00286     GOOD_STATUS
00287 }
00288 
00289 
00290 /*---------------------------------------------------------------------------*/
00331 /*--------------------------------------------------------------------------*/
00332 
00333 extern int vircam_lincor(vir_fits *infile, vir_tfits *lchantab, int kconst, 
00334                          int ndit, int *status) {
00335     int retval,i,norder;
00336     long naxis[2],j,rind,aind,ncpts,np;
00337     float *data,texp,reset_time,read_time,delay_time;
00338     double kfac_nom,lkfac,inval,outval,*lbb,dnd;
00339     const char *fctid = "vircam_lincor";
00340     parquet *pp;
00341     cpl_propertylist *plist;
00342     cpl_table *lctab;
00343     parquet *p;
00344 
00345     /* Inherited status */
00346 
00347     if (*status != VIR_OK)
00348         return(*status);
00349 
00350     /* Open the parquet structure for the channel table */
00351 
00352     lctab = vircam_tfits_get_table(lchantab);
00353     retval = vircam_chan_fill(lctab,&p,&np);
00354     if (retval != VIR_OK)
00355         return(retval);
00356 
00357     /* Get the data array for the image */
00358 
00359     data = cpl_image_get_data(vircam_fits_get_image(infile));
00360     if (data == NULL) {
00361         vircam_chan_free(np,&p);
00362         cpl_msg_error(fctid,"Error mapping data in input image");
00363         FATAL_ERROR
00364     }
00365     naxis[0] = (long)cpl_image_get_size_x(vircam_fits_get_image(infile));
00366     naxis[1] = (long)cpl_image_get_size_y(vircam_fits_get_image(infile));
00367 
00368     /* Get the required parameters from the header */
00369 
00370     plist = vircam_fits_get_ehu(infile);
00371     if (vircam_pfits_get_exptime(plist,&texp) != VIR_OK) {
00372         vircam_chan_free(np,&p);
00373         cpl_msg_error(fctid,"No exposure time in %s",
00374                       vircam_fits_get_fullname(infile));
00375         FATAL_ERROR
00376     }
00377     if (vircam_pfits_get_mindit(plist,&reset_time) != VIR_OK) {
00378         vircam_chan_free(np,&p);
00379         cpl_msg_error(fctid,"No mindit time in %s",
00380                       vircam_fits_get_fullname(infile));
00381         FATAL_ERROR
00382     }
00383     read_time = reset_time;
00384     if (vircam_pfits_get_ditdelay(plist,&delay_time) != VIR_OK) {
00385         vircam_chan_free(np,&p);
00386         cpl_msg_error(fctid,"No dit delay time in %s",
00387                       vircam_fits_get_fullname(infile));
00388         FATAL_ERROR
00389     }
00390       
00391     /* If there is a constant k factor, then calculate it now */
00392 
00393     kfac_nom = (double)(read_time/texp);
00394 
00395     /* Factor to take the number of DITs into account */
00396 
00397     dnd = (double)ndit;
00398         
00399     /* Loop for each channel now */
00400 
00401     for (i = 0; i < np; i++) {
00402         pp = p + i;
00403         ncpts = (pp->delta_i)*(pp->delta_j);
00404 
00405         /* Load up the fit coefficients. If there is only one coefficient
00406            this is by definition 1 and therefore we can skip this channel */
00407 
00408         norder = pp->norder;
00409         if (norder == 1)
00410             continue;
00411         lbb = pp->bb;
00412 
00413         /* Now for each pixel */
00414 
00415         for (j = 0; j < ncpts; j++) {
00416 
00417             /* Get the k-factor */
00418 
00419             rind = vircam_chan_d2r(pp,j);
00420             aind = vircam_chan_r2a(pp,naxis,rind);
00421             if (kconst == 1)
00422                 lkfac = kfac_nom;
00423             else
00424                 lkfac = getkfac(j,ncpts,reset_time,read_time,delay_time,texp);
00425 
00426             /* Calculate the linearised value now */
00427 
00428             inval = ((double)data[aind])/dnd;
00429             outval = linval(inval,lkfac,0.5,10,lbb,norder);
00430             data[aind] = (float)(dnd*outval);
00431         }
00432     }
00433 
00434     /* Add the linearity table to the DRS header */
00435 
00436     cpl_propertylist_update_string(vircam_fits_get_ehu(infile),
00437                                    "ESO DRS LINCOR",
00438                                    vircam_tfits_get_filename(lchantab));
00439 
00440     /* Right, get out of here */
00441 
00442     vircam_chan_free(np,&p);
00443     GOOD_STATUS
00444 }
00445 
00446 /*---------------------------------------------------------------------------*/
00475 /*---------------------------------------------------------------------------*/
00476 
00477 static double linval(double inval, double k, double tolerance, int niter,
00478                      double *b, int norder) {
00479     int jj,iter;
00480     double sc1,val_old,val,tol;
00481 
00482     val = inval;
00483     iter = 0;
00484     tol = tolerance + 1.0;
00485     while (iter < niter && tol > tolerance) {
00486         val_old = val;
00487         iter++;
00488         sc1 = inval;
00489         for (jj = 1; jj < norder; jj++)
00490             sc1 -= b[jj]*pow(val,(double)jj+1)*
00491                 ((pow((1.0+k),(double)jj+1) - pow(k,(double)(jj+1))));
00492         val = sc1;
00493         tol = fabs(val - val_old);
00494     }
00495     return(val);
00496 }
00497 
00498     
00499 /*---------------------------------------------------------------------------*/
00527 /*---------------------------------------------------------------------------*/
00528 
00529 static double getkfac(long index, long npts, float reset_time, 
00530                       float read_time, float delay_time, float exptime) {
00531     double tkfac,dt1,dt2,dt3,dt4,df;
00532 
00533     df = ((double)index/(double)npts);
00534     dt1 = (double)exptime;
00535     dt2 = (double)read_time;
00536     dt3 = (double)reset_time;
00537     dt4 = (double)delay_time;
00538     tkfac = (dt3 + dt4 + (dt2 - dt3)*df)/dt1;
00539     return(tkfac);
00540 }
00541 
00542 /*---------------------------------------------------------------------------*/
00564 /*---------------------------------------------------------------------------*/
00565 
00566 static void getco(double *a, int nord, int m) {
00567     int i,j,start;
00568 
00569     for (i = 0; i < nord; i++)
00570         a[i] = 0.0;
00571     start = m-1;
00572     a[start] = 1.0;
00573     j = 1;
00574     for (i = start-1; i >= 0; i--) {
00575         j++;
00576         a[i] = a[i+1]*(double)(m - j + 2)/(double)(j-1);
00577     }
00578 }
00579 
00580 
00584 /*
00585 
00586 $Log: vircam_genlincur.c,v $
00587 Revision 1.24  2008/01/22 19:45:24  jim
00588 New version of genlincur to take into account the equality of readout and
00589 reset time
00590 
00591 Revision 1.23  2007/11/26 09:57:14  jim
00592 Linearity correction routines now take account of ndit
00593 
00594 Revision 1.22  2007/11/22 12:36:15  jim
00595 Modified to return linearised values in an array
00596 
00597 Revision 1.21  2007/11/20 09:38:57  jim
00598 changed definition of fit quality to percentage error at 10000 counts
00599 
00600 Revision 1.20  2007/11/14 14:47:32  jim
00601 Modified the qualfit definition to be back in line with DRLD
00602 
00603 Revision 1.19  2007/11/14 12:34:21  jim
00604 Fixed header comments
00605 
00606 Revision 1.18  2007/11/14 10:48:29  jim
00607 Major rewrite to incorporate simpler and more robust algorithm
00608 
00609 Revision 1.17  2007/03/29 12:19:39  jim
00610 Little changes to improve documentation
00611 
00612 Revision 1.16  2007/03/01 12:42:41  jim
00613 Modified slightly after code checking
00614 
00615 Revision 1.15  2006/11/27 12:08:18  jim
00616 Modified lincor to get a better answer. Also modified the way the fit quality
00617 is calculated
00618 
00619 Revision 1.14  2006/09/29 11:19:31  jim
00620 changed aliases on parameter names
00621 
00622 Revision 1.13  2006/07/04 09:19:05  jim
00623 replaced all sprintf statements with snprintf
00624 
00625 Revision 1.12  2006/06/09 11:26:26  jim
00626 Small changes to keep lint happy
00627 
00628 Revision 1.11  2006/04/20 11:23:15  jim
00629 Now medians the data before accumulation in the event that k is constant.
00630 
00631 Revision 1.10  2006/03/23 21:18:47  jim
00632 Minor changes mainly to comment headers
00633 
00634 Revision 1.9  2006/03/22 13:36:50  jim
00635 cosmetic changes to keep lint happy
00636 
00637 Revision 1.8  2006/03/15 10:43:41  jim
00638 Fixed a few things
00639 
00640 Revision 1.7  2006/03/08 14:32:21  jim
00641 Lots of little modifications
00642 
00643 Revision 1.6  2006/03/03 14:29:46  jim
00644 Modified definition of vir_fits and channel table
00645 
00646 Revision 1.5  2006/03/01 10:31:28  jim
00647 Now uses new vir_fits objects
00648 
00649 Revision 1.4  2006/02/18 11:45:59  jim
00650 Fixed a couple of memory bugs
00651 
00652 Revision 1.3  2006/01/23 22:58:14  jim
00653 Added vircam_lincor module
00654 
00655 Revision 1.2  2006/01/23 16:06:03  jim
00656 Added in header comments and section to evaluate the goodness of fit
00657 
00658 Revision 1.1  2006/01/23 10:31:56  jim
00659 New file
00660 
00661 
00662 */

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