vircam_genlincur.c

00001 /* $Id: vircam_genlincur.c,v 1.34 2012/01/15 17:40:09 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: 2012/01/15 17:40:09 $
00024  * $Revision: 1.34 $
00025  * $Name: vcam-1_3_2 $
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 
00049 
00050 static double linval(double inval, double *kfacs, double tolerance,
00051                      int niter, double *b, int norder);
00052 static double getkfac(long index, long ncpts, float reset_time, 
00053                       float read_time, float delay_time, float exptime);
00054 static void getco(double *a, int nord, int m);
00055 
00058 /*---------------------------------------------------------------------------*/
00115 /*---------------------------------------------------------------------------*/
00116 
00117 extern int vircam_genlincur(double **fdata, int nimages, double *exps, 
00118                             double mindit, vir_tfits *chantab, 
00119                             int norder, cpl_table **lchantab, 
00120                             double **lindata, int *status) {
00121 
00122     const char *fctid = "vircam_genlincur";
00123     int retval,i,j,nbad,oldnorder,k,ii,nullval;
00124     long np;
00125     double *meds,sigfit,**aco,c0,lin_nom,*temp,*polyco,pt,*work,kfac;
00126     double sum,t10000,*kfacs;
00127     parquet *p,*pp;
00128     cpl_table *ctab,*lc;
00129     cpl_array *exparray,*medsarray,*polyfitco,*workarray;
00130     char colname[SZCOLNAME];
00131 
00132     /* Inherited status */
00133 
00134     *lchantab = NULL;
00135     if (*status != VIR_OK)
00136         return(*status);
00137 
00138     /* Check that you have enough images in the list */
00139 
00140     if (nimages < norder+1) {
00141         cpl_msg_error(fctid,
00142                       "Not enought images (%" CPL_SIZE_FORMAT ") for fit order (%" CPL_SIZE_FORMAT ")",
00143                       (cpl_size)nimages,(cpl_size)norder);
00144         FATAL_ERROR
00145     }
00146 
00147     /* Open the parquet structure for the channel table */
00148 
00149     ctab = vircam_tfits_get_table(chantab);
00150     retval = vircam_chan_fill(ctab,&pp,&np);
00151     if (retval != VIR_OK) {
00152         *status = retval;
00153         return(retval);
00154     }
00155 
00156     /* Create an output channel table. Copy the input channel table and then
00157        massage the linearity part */
00158 
00159     lc = cpl_table_duplicate(ctab);
00160     oldnorder = cpl_table_get_int(lc,"norder",0,&nullval);
00161     if (oldnorder > norder) {
00162         for (i = norder+1; i <= oldnorder; i++) {
00163             snprintf(colname,SZCOLNAME,"coeff_%d",i);
00164             cpl_table_erase_column(lc,colname);
00165         }
00166     } else if (oldnorder < norder) {
00167         for (i = oldnorder+1; i <= norder; i++) {
00168             snprintf(colname,SZCOLNAME,"coeff_%d",i);
00169             if (cpl_table_has_column(lc,colname)) 
00170                 continue;
00171             cpl_table_new_column(lc,colname,CPL_TYPE_DOUBLE);
00172         }
00173     }
00174 
00175     /* Get some memory for the fitting arrays */
00176 
00177     exparray = cpl_array_wrap_double(exps,nimages);
00178     medsarray = cpl_array_new((cpl_size)nimages,CPL_TYPE_DOUBLE);
00179     meds = cpl_array_get_data_double(medsarray);
00180     aco = cpl_malloc(norder*sizeof(double *));
00181     for (i = 0; i < norder; i++) 
00182         aco[i] = cpl_malloc(norder*sizeof(double));
00183     temp = cpl_malloc(norder*sizeof(double));
00184     kfacs = cpl_malloc(norder*sizeof(double));
00185 
00186     /* Get memory for output array of linearised stats */
00187 
00188     *lindata = cpl_malloc(nimages*np*sizeof(double));
00189 
00190     /* Loop for each channel */
00191 
00192     nbad = 0;
00193     for (i = 0; i < np; i++) {
00194         p = pp + i;
00195 
00196         /* Load the data up for this channel */
00197 
00198         for (j = 0; j < nimages; j++) 
00199             meds[j] = fdata[j][i];
00200 
00201         /* Do the initial fit */
00202 
00203         if (vircam_polyfit(exparray,medsarray,norder,1,2,2.0,2.0,&polyfitco,
00204                            &sigfit) != VIR_OK) {
00205             nbad++;
00206             cpl_table_set_int(lc,"norder",(cpl_size)i,norder);
00207             cpl_table_set_double(lc,"coeff_1",(cpl_size)i,1.0);
00208             for (k = 1; k < norder; k++) {
00209                 snprintf(colname,SZCOLNAME,"coeff_%d",k+1);
00210                 cpl_table_set_double(lc,colname,(cpl_size)i,0.0);
00211             }
00212             freearray(polyfitco);
00213             continue;
00214         }
00215         polyco = cpl_array_get_data_double(polyfitco);
00216 
00217         /* Work out linearity */
00218 
00219         for (j = 0; j < nimages; j++) 
00220             if (meds[j] > nom_val)
00221                 break;
00222         t10000 = exps[j-1] + (nom_val - meds[j-1])/(meds[j] - meds[j-1]);
00223         sum = 0.0;
00224         for (j = 0; j < norder; j++)
00225             sum += (double)(j+1)*polyco[j]*pow(t10000,(double)j);
00226         lin_nom = 100.0*fabs(sum - polyco[0])/polyco[0];
00227 
00228         /* Get intermediate coefficients for matrix */
00229 
00230         for (j = 0; j < norder; j++) {
00231             getco(temp,norder,j+1);
00232             for (k = 0; k < norder; k++) {
00233                 pt = pow(mindit,(double)(j-k));
00234                 aco[j][k] = pt*temp[k];
00235             }
00236         }
00237 
00238         /* Solve matrix equation to do the back substitution */
00239 
00240         if (vircam_solve_gauss(aco,polyco,norder) != VIR_OK) {
00241             nbad++;
00242             cpl_table_set_int(lc,"norder",(cpl_size)i,norder);
00243             cpl_table_set_double(lc,"coeff_1",(cpl_size)i,1.0);
00244             for (k = 1; k < norder; k++) {
00245                 snprintf(colname,SZCOLNAME,"coeff_%d",k+1);
00246                 cpl_table_set_double(lc,colname,(cpl_size)i,0.0);
00247             }
00248             freearray(polyfitco);
00249             continue;
00250         }
00251 
00252         /* Now normalise to unit slope and write the result to the table*/
00253 
00254         c0 = polyco[0];
00255         for (j = 0; j < norder; j++) {
00256             polyco[j] /= pow(c0,(double)(j+1));
00257             snprintf(colname,SZCOLNAME,"coeff_%d",j+1);
00258             cpl_table_set_double(lc,colname,(cpl_size)i,polyco[j]);
00259         }
00260         cpl_table_set_int(lc,"norder",(cpl_size)i,norder);
00261 
00262         /* Work out how well the solution creates a linear system. Loop 
00263            for each input image and work out a 'linearised' median. Then
00264            do a linear fit to the linearsed median vs exposure time. */
00265 
00266         workarray = cpl_array_new((cpl_size)nimages,CPL_TYPE_DOUBLE);
00267         work = cpl_array_get_data_double(workarray);
00268         for (j = 0; j < nimages; j++) {
00269             kfac = mindit/exps[j];
00270             kfacs[0] = 1.0;
00271             for (ii = 1; ii < norder; ii++) 
00272                 kfacs[ii] = pow((kfac+1.0),(double)(ii+1)) - 
00273                     pow(kfac,(double)(ii+1));
00274             work[j] = linval(meds[j],kfacs,0.5,10,polyco,norder);
00275             (*lindata)[j*np+i] = work[j];
00276         }       
00277         freearray(polyfitco);
00278         (void)vircam_polyfit(exparray,workarray,2,0,2,2.0,2.0,&polyfitco,
00279                              &sigfit);
00280         polyco = cpl_array_get_data_double(polyfitco);
00281         sigfit *= 100.0/nom_val;
00282         freearray(workarray);
00283         freearray(polyfitco);
00284                        
00285         /* Put the nominal linearity and the fit quality into the header */
00286 
00287         cpl_table_set_double(lc,"lin_10000_err",(cpl_size)i,sigfit);
00288         cpl_table_set_double(lc,"lin_10000",(cpl_size)i,lin_nom);
00289     }
00290 
00291     /* Tidy and get out of here */
00292 
00293     *lchantab = cpl_table_duplicate(lc);
00294     cpl_array_unwrap(exparray);
00295     freearray(medsarray);
00296     freespace2(aco,norder);
00297     freespace(temp);
00298     freetable(lc);
00299     vircam_chan_free(np,&pp);
00300     freespace(kfacs);
00301     if (nbad != 0) {
00302         cpl_msg_warning(fctid,
00303                         "%" CPL_SIZE_FORMAT "channels have a failed solution",
00304                         (cpl_size)nbad);
00305         WARN_RETURN
00306     }
00307     GOOD_STATUS
00308 }
00309 
00310 
00311 /*---------------------------------------------------------------------------*/
00352 /*--------------------------------------------------------------------------*/
00353 
00354 extern int vircam_lincor(vir_fits *infile, vir_tfits *lchantab, int kconst, 
00355                          int ndit, int *status) {
00356     int retval,i,norder,ii;
00357     long naxis[2],j,rind,aind,ncpts,np;
00358     float *data,texp,reset_time,read_time,delay_time;
00359     double kfac_nom,lkfac,inval,outval,*lbb,dnd,*kfacs;
00360     const char *fctid = "vircam_lincor";
00361     parquet *pp;
00362     cpl_propertylist *plist;
00363     cpl_table *lctab;
00364     parquet *p;
00365 
00366     /* Inherited status */
00367 
00368     if (*status != VIR_OK)
00369         return(*status);
00370 
00371     /* Do we even need to be here? */
00372 
00373     if (cpl_propertylist_has(vircam_fits_get_ehu(infile),"ESO DRS LINCOR"))
00374         return(*status);
00375 
00376     /* Open the parquet structure for the channel table */
00377 
00378     lctab = vircam_tfits_get_table(lchantab);
00379     retval = vircam_chan_fill(lctab,&p,&np);
00380     if (retval != VIR_OK)
00381         return(retval);
00382 
00383     /* Get the data array for the image */
00384 
00385     data = cpl_image_get_data(vircam_fits_get_image(infile));
00386     if (data == NULL) {
00387         vircam_chan_free(np,&p);
00388         cpl_msg_error(fctid,"Error mapping data in input image");
00389         FATAL_ERROR
00390     }
00391     naxis[0] = (long)cpl_image_get_size_x(vircam_fits_get_image(infile));
00392     naxis[1] = (long)cpl_image_get_size_y(vircam_fits_get_image(infile));
00393 
00394     /* Get the required parameters from the header */
00395 
00396     plist = vircam_fits_get_ehu(infile);
00397     if (vircam_pfits_get_exptime(plist,&texp) != VIR_OK) {
00398         vircam_chan_free(np,&p);
00399         cpl_msg_error(fctid,"No exposure time in %s",
00400                       vircam_fits_get_fullname(infile));
00401         FATAL_ERROR
00402     }
00403     if (vircam_pfits_get_mindit(plist,&reset_time) != VIR_OK) {
00404         vircam_chan_free(np,&p);
00405         cpl_msg_error(fctid,"No mindit time in %s",
00406                       vircam_fits_get_fullname(infile));
00407         FATAL_ERROR
00408     }
00409     read_time = reset_time;
00410     if (vircam_pfits_get_ditdelay(plist,&delay_time) != VIR_OK) {
00411         vircam_chan_free(np,&p);
00412         cpl_msg_error(fctid,"No dit delay time in %s",
00413                       vircam_fits_get_fullname(infile));
00414         FATAL_ERROR
00415     }
00416       
00417     /* If there is a constant k factor, then calculate it now */
00418 
00419     kfac_nom = (double)(read_time/texp);
00420 
00421     /* Factor to take the number of DITs into account */
00422 
00423     dnd = (double)ndit;
00424         
00425     /* Loop for each channel now */
00426 
00427     for (i = 0; i < np; i++) {
00428         pp = p + i;
00429         ncpts = (pp->delta_i)*(pp->delta_j);
00430 
00431         /* Load up the fit coefficients. If there is only one coefficient
00432            this is by definition 1 and therefore we can skip this channel */
00433 
00434         norder = pp->norder;
00435         if (norder == 1)
00436             continue;
00437         lbb = pp->bb;
00438 
00439         /* Get workspace for K array and fill it in for situation of constant
00440            k factor */
00441 
00442         kfacs = cpl_malloc(norder*sizeof(double));
00443         if (kconst) {
00444             kfacs[0] = 1.0;
00445             for (ii = 1; ii < norder; ii++) 
00446                 kfacs[ii] = pow((kfac_nom+1.0),(double)(ii+1)) - 
00447                     pow(kfac_nom,(double)(ii+1));
00448         }
00449 
00450         /* Now for each pixel */
00451 
00452         for (j = 0; j < ncpts; j++) {
00453 
00454             /* Get the 'non-constant' k-factor and fill in the K array. */
00455 
00456             rind = vircam_chan_d2r(pp,j);
00457             aind = vircam_chan_r2a(pp,naxis,rind);
00458             if (! kconst) {
00459                 lkfac = getkfac(j,ncpts,reset_time,read_time,delay_time,texp);
00460                 kfacs[0] = 1.0;
00461                 for (ii = 1; ii < norder; ii++) 
00462                      kfacs[ii] = pow((lkfac+1.0),(double)(ii+1)) - 
00463                          pow(lkfac,(double)(ii+1));
00464             }
00465 
00466             /* Calculate the linearised value now */
00467 
00468             inval = ((double)data[aind])/dnd;
00469             outval = linval(inval,kfacs,0.5,10,lbb,norder);
00470             data[aind] = (float)(dnd*outval);
00471         }
00472         freespace(kfacs);
00473     }
00474 
00475     /* Add the linearity table to the DRS header */
00476 
00477     cpl_propertylist_update_string(vircam_fits_get_ehu(infile),
00478                                    "ESO DRS LINCOR",
00479                                    vircam_tfits_get_filename(lchantab));
00480 
00481     /* Right, get out of here */
00482 
00483     vircam_chan_free(np,&p);
00484     GOOD_STATUS
00485 }
00486 
00487 /*---------------------------------------------------------------------------*/
00516 /*---------------------------------------------------------------------------*/
00517 
00518 static double linval(double inval, double *kfacs, double tolerance,
00519                      int niter, double *b, int norder) {
00520     int jj,iter;
00521     double val_old,val,tol,sum;
00522 
00523     val = inval;
00524     iter = 0;
00525     tol = tolerance + 1.0;
00526     while (iter < niter && tol > tolerance) {
00527         val_old = val;
00528         iter++;
00529         sum = 0.0;
00530         for (jj = norder - 1; jj >= 1; jj--) 
00531             sum = (sum + b[jj]*kfacs[jj])*val;
00532         sum *= val;
00533         val = inval - sum;
00534         tol = fabs(val - val_old);
00535         if (val > 65535.0) {
00536             val = 65535.0;
00537             break;
00538         } else if (val < -1000.0) {
00539             val = -1000.0;
00540             break;
00541         }
00542     }
00543     return(val);
00544 }
00545 
00546     
00547 /*---------------------------------------------------------------------------*/
00575 /*---------------------------------------------------------------------------*/
00576 
00577 static double getkfac(long index, long npts, float reset_time, 
00578                       float read_time, float delay_time, float exptime) {
00579     double tkfac,dt1,dt2,dt3,dt4,df;
00580 
00581     df = ((double)index/(double)npts);
00582     dt1 = (double)exptime;
00583     dt2 = (double)read_time;
00584     dt3 = (double)reset_time;
00585     dt4 = (double)delay_time;
00586     tkfac = (dt3 + dt4 + (dt2 - dt3)*df)/dt1;
00587     return(tkfac);
00588 }
00589 
00590 /*---------------------------------------------------------------------------*/
00612 /*---------------------------------------------------------------------------*/
00613 
00614 static void getco(double *a, int nord, int m) {
00615     int i,j,start;
00616 
00617     for (i = 0; i < nord; i++)
00618         a[i] = 0.0;
00619     start = m-1;
00620     a[start] = 1.0;
00621     j = 1;
00622     for (i = start-1; i >= 0; i--) {
00623         j++;
00624         a[i] = a[i+1]*(double)(m - j + 2)/(double)(j-1);
00625     }
00626 }
00627 
00628 
00632 /*
00633 
00634 $Log: vircam_genlincur.c,v $
00635 Revision 1.34  2012/01/15 17:40:09  jim
00636 Minor modifications to take into accout the changes in cpl API for v6
00637 
00638 Revision 1.33  2010/06/03 12:15:31  jim
00639 A few mods to get rid of compiler warnings
00640 
00641 Revision 1.32  2009/12/11 06:53:35  jim
00642 Minor changes to documentation
00643 
00644 Revision 1.31  2009/09/09 09:45:36  jim
00645 Modified to speed things up
00646 
00647 Revision 1.30  2009/06/08 08:08:15  jim
00648 Fixed memory leak and changed clipping parameters to vircam_polyfit
00649 
00650 Revision 1.29  2009/05/20 12:18:42  jim
00651 Modified so that if the operation is already done, then it just returns
00652 
00653 Revision 1.28  2009/02/20 10:50:55  jim
00654 Removed superfluous declarations
00655 
00656 Revision 1.27  2008/10/21 08:38:48  jim
00657 Final estiamte on linearity error done with vircam_polyfit now
00658 
00659 Revision 1.26  2008/09/29 11:26:18  jim
00660 Modified linval to provide a lower limit in case the fit goes crazy
00661 
00662 Revision 1.25  2008/08/28 09:05:37  jim
00663 Fixed bug where QC was being duplicated from master BPM on rare occasions.
00664 Fixed bug where ARCFILE wasn't being written to the paf file for illum_cor
00665 tables. Sky combine is done with medians
00666 
00667 Revision 1.24  2008/01/22 19:45:24  jim
00668 New version of genlincur to take into account the equality of readout and
00669 reset time
00670 
00671 Revision 1.23  2007/11/26 09:57:14  jim
00672 Linearity correction routines now take account of ndit
00673 
00674 Revision 1.22  2007/11/22 12:36:15  jim
00675 Modified to return linearised values in an array
00676 
00677 Revision 1.21  2007/11/20 09:38:57  jim
00678 changed definition of fit quality to percentage error at 10000 counts
00679 
00680 Revision 1.20  2007/11/14 14:47:32  jim
00681 Modified the qualfit definition to be back in line with DRLD
00682 
00683 Revision 1.19  2007/11/14 12:34:21  jim
00684 Fixed header comments
00685 
00686 Revision 1.18  2007/11/14 10:48:29  jim
00687 Major rewrite to incorporate simpler and more robust algorithm
00688 
00689 Revision 1.17  2007/03/29 12:19:39  jim
00690 Little changes to improve documentation
00691 
00692 Revision 1.16  2007/03/01 12:42:41  jim
00693 Modified slightly after code checking
00694 
00695 Revision 1.15  2006/11/27 12:08:18  jim
00696 Modified lincor to get a better answer. Also modified the way the fit quality
00697 is calculated
00698 
00699 Revision 1.14  2006/09/29 11:19:31  jim
00700 changed aliases on parameter names
00701 
00702 Revision 1.13  2006/07/04 09:19:05  jim
00703 replaced all sprintf statements with snprintf
00704 
00705 Revision 1.12  2006/06/09 11:26:26  jim
00706 Small changes to keep lint happy
00707 
00708 Revision 1.11  2006/04/20 11:23:15  jim
00709 Now medians the data before accumulation in the event that k is constant.
00710 
00711 Revision 1.10  2006/03/23 21:18:47  jim
00712 Minor changes mainly to comment headers
00713 
00714 Revision 1.9  2006/03/22 13:36:50  jim
00715 cosmetic changes to keep lint happy
00716 
00717 Revision 1.8  2006/03/15 10:43:41  jim
00718 Fixed a few things
00719 
00720 Revision 1.7  2006/03/08 14:32:21  jim
00721 Lots of little modifications
00722 
00723 Revision 1.6  2006/03/03 14:29:46  jim
00724 Modified definition of vir_fits and channel table
00725 
00726 Revision 1.5  2006/03/01 10:31:28  jim
00727 Now uses new vir_fits objects
00728 
00729 Revision 1.4  2006/02/18 11:45:59  jim
00730 Fixed a couple of memory bugs
00731 
00732 Revision 1.3  2006/01/23 22:58:14  jim
00733 Added vircam_lincor module
00734 
00735 Revision 1.2  2006/01/23 16:06:03  jim
00736 Added in header comments and section to evaluate the goodness of fit
00737 
00738 Revision 1.1  2006/01/23 10:31:56  jim
00739 New file
00740 
00741 
00742 */

Generated on 5 Mar 2013 for VIRCAM Pipeline by  doxygen 1.6.1