classify.c

00001 /* $Id: classify.c,v 1.19 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.19 $
00025  * $Name: vcam-1_3_2 $
00026  */
00027 
00028 #include <stdio.h>
00029 #include <stdlib.h>
00030 #include <math.h>
00031 #include <strings.h>
00032 
00033 #include <cpl.h>
00034 #include <vircam_utils.h>
00035 #include <vircam_pfits.h>
00036 #include "classify.h"
00037 
00038 #define MAXHIST   111
00039 #define STEP      0.05
00040 #define NSAMPLE   150
00041 #define MAXLOOP   5
00042 #define BLIMDEF   15.0;
00043 #define FLIMDEF   11.0;
00044 #define CMINDEF   7.5
00045 #define CMAXDEF   15.0
00046 #define NAREAL    8
00047 #define PI        3.14159265358979323846
00048 #define DEGRAD 57.2957795130823229
00049 
00050 #define COREMAG(A,B,C) 2.5*log10((double)(max(C,A-B)))
00051 #define MAX(A,B) (A > B ? A : B)
00052 
00053 /* Make the data arrays and header values global */
00054 
00055 static long nrows;
00056 static float thresh,skylevel,skynoise,rcore,exptime;
00057 
00058 /* Derived values */
00059 
00060 static int poor;
00061 static float sigell,fitell,elllim,sigellf,fitellf,sigpa,fitpa;
00062 static float blim,flim,cmin,cmax;
00063 static float fit1,fit2,fit3,fit4,fit5,fit6,fit7;
00064 static float fit_final,sigma_final;
00065 static float *lower1,*lower2,*lower3,*upper1,*upper2,*upper3,*uppere;
00066 static float avsig1,avsig2,avsig3,wt1,wt2,wt3;
00067 
00068 /* Classification values */
00069 
00070 static int nstar,ngal,njunk,ncmp;
00071 
00072 /* Values for the data quality and aperture corrections */
00073 
00074 static float avsat,corlim,cormin,apcpkht,apcor,apcor1,apcor2,apcor3,apcor4;
00075 static float apcor5,apcor6,apcor7;
00076 
00077 /* Data arrays */
00078 
00079 static float *workspace = NULL;
00080 static cpl_table *catcopy = NULL;
00081 static float *areal[NAREAL];
00082 static float *core_flux,*core1_flux,*core2_flux,*core3_flux,*core4_flux;
00083 static float *core5_flux,*peak_height,*peak_mag,*ellipticity,*iso_flux;
00084 static float *total_flux,*cls,*sig,*xpos,*ypos,*pa,*core6_flux,*skylev;
00085 
00086 
00087 /* Column definitions */
00088 
00089 #define NCOL32 14
00090 #define NCOL80 15
00091 
00092 static const char *cols32[NCOL32] = {"Core_flux","Core1_flux","Core2_flux",
00093                                      "Core3_flux","Core4_flux","Peak_height",
00094                                      "Ellipticity","Isophotal_flux",
00095                                      "Total_flux","Core5_flux","X_coordinate",
00096                                      "Y_coordinate","Position_angle",
00097                                      "Skylev"};
00098 
00099 static const char *cols80[NCOL80] = {"Aper_flux_3","Aper_flux_1","Aper_flux_4",
00100                                      "Aper_flux_5","Aper_flux_6","Peak_height",
00101                                      "Ellipticity","Isophotal_flux",
00102                                      "Isophotal_flux","Aper_flux_7",
00103                                      "X_coordinate","Y_coordinate",
00104                                      "Position_angle","Sky_level",
00105                                      "Aper_flux_2"};
00106 
00107 static int ncols;
00108 static float xmin;
00109 static float xmax;
00110 static float ymin;
00111 static float ymax;
00112 static float pixlim;
00113 
00114 #define FRAMECUT 0.05
00115 
00116 /* Subroutine prototypes */
00117 
00118 static void anhist(float *, int, float *, float *);
00119 static void boundaries(float *, float *, float *, float, float, float, float,
00120                        int, float, float, float *, float *, float *, float *);
00121 static void boundpk(float *, float *, float, float, float *, float *,
00122                     float *, float *);
00123 static void classify_run(void);
00124 static void classstats(float *, float *, int, float, float *, float *);
00125 static void classstats_ap0(float *, float *);
00126 static void classstats_ap67(float *, float *, float *, float *);
00127 static void classstats_el(void);
00128 static void classstats_pa(void);
00129 static void classstats_ellf(float);
00130 static void classstats_final(void);
00131 static void medstat(float *, int, float *, float *);
00132 static void sort1(float *, int);
00133 static void sort2(float *, float *, int);
00134 
00137 /*---------------------------------------------------------------------------*/
00202 /*---------------------------------------------------------------------------*/
00203 
00204 extern int classify(vir_tfits *catalogue, cpl_propertylist *plist, 
00205                     float minsize, int cattype) {
00206     float fwhm,*work,moff;
00207     float pkht,ell,core,ap,delap,area,junk,arg;
00208     char *cols[MAX(NCOL32,NCOL80)],colname[32];
00209     cpl_propertylist *extra;
00210     cpl_table *cat;
00211     const char *fctid = "vircam_classify";
00212     int i,n,iap,i1,i2,nxout,nyout;
00213 
00214     /* Get some DQC info from the extra propertylist generated by imcore */
00215 
00216     extra = vircam_tfits_get_ehu(catalogue);
00217     thresh = cpl_propertylist_get_float(extra,"ESO DRS THRESHOL");
00218     skylevel = cpl_propertylist_get_float(extra,"ESO QC MEAN_SKY");
00219     skynoise = cpl_propertylist_get_float(extra,"ESO QC SKY_NOISE");
00220     rcore = cpl_propertylist_get_float(extra,"ESO DRS RCORE");
00221     fwhm = cpl_propertylist_get_float(extra,"ESO DRS SEEING");
00222     nxout = cpl_propertylist_get_int(extra,"ESO DRS NXOUT");
00223     nyout = cpl_propertylist_get_int(extra,"ESO DRS NYOUT");
00224     xmin = FRAMECUT*(float)nxout;
00225     xmax = (1.0 - FRAMECUT)*(float)nxout;
00226     ymin = FRAMECUT*(float)nyout;
00227     ymax = (1.0 - FRAMECUT)*(float)nyout;
00228     pixlim = minsize;
00229 
00230     /* Get the exposure time */
00231 
00232     if (vircam_pfits_get_exptime(plist,&exptime) != VIR_OK) {
00233         cpl_msg_warning(fctid,"Unable to get expsoure time!");
00234         exptime = 10.0;
00235     }
00236     
00237     /* Get the number of columns and decide which column labels to use */
00238 
00239     cat = vircam_tfits_get_table(catalogue);
00240     ncols = cpl_table_get_ncol(cat);
00241     switch (cattype) {
00242     case 1:
00243         for (i = 0; i < NCOL32; i++)
00244             cols[i] = (char *)cols32[i];
00245         break;
00246     case 2:
00247         for (i = 0; i < NCOL80; i++)
00248             cols[i] = (char *)cols80[i];
00249         break;
00250     default:
00251         cpl_msg_error(fctid,"Don't recognise catalogues with %" CPL_SIZE_FORMAT " columns: cattype == %" CPL_SIZE_FORMAT,(cpl_size)ncols,(cpl_size)cattype);
00252         return(VIR_FATAL);
00253     }
00254 
00255     /* Make a copy of the table as you are going to muck about with the
00256        column values. Get the column data */
00257 
00258     catcopy = cpl_table_duplicate(cat);
00259     nrows = cpl_table_get_nrow(cat);
00260     core_flux = cpl_table_get_data_float(catcopy,cols[0]);
00261     core1_flux = cpl_table_get_data_float(catcopy,cols[1]);
00262     core2_flux = cpl_table_get_data_float(catcopy,cols[2]);
00263     core3_flux = cpl_table_get_data_float(catcopy,cols[3]);
00264     core4_flux = cpl_table_get_data_float(catcopy,cols[4]);
00265     peak_height = cpl_table_get_data_float(catcopy,cols[5]);
00266     ellipticity = cpl_table_get_data_float(catcopy,cols[6]);
00267     iso_flux = cpl_table_get_data_float(catcopy,cols[7]);
00268     total_flux = cpl_table_get_data_float(catcopy,cols[8]);
00269     core5_flux = cpl_table_get_data_float(catcopy,cols[9]);
00270     xpos = cpl_table_get_data_float(catcopy,cols[10]);
00271     ypos = cpl_table_get_data_float(catcopy,cols[11]);
00272     pa = cpl_table_get_data_float(catcopy,cols[12]);
00273     skylev = cpl_table_get_data_float(catcopy,cols[13]);
00274     if (cattype == 2) 
00275         core6_flux = cpl_table_get_data_float(catcopy,cols[14]);
00276     else 
00277         core6_flux = NULL;
00278     cls = cpl_table_get_data_float(cat,"Classification");
00279     sig = cpl_table_get_data_float(cat,"Statistic");
00280 
00281     /* Get some workspace */
00282 
00283     workspace = cpl_malloc(2*nrows*sizeof(float));
00284     peak_mag = workspace;
00285     work = workspace + nrows;
00286     
00287     /* Convert fluxes to "magnitudes" */
00288 
00289     for (i = 0; i < nrows; i++) {
00290         core_flux[i] = COREMAG(core_flux[i],0.0,1.0);
00291         core1_flux[i] = COREMAG(core1_flux[i],0.0,1.0);
00292         core2_flux[i] = COREMAG(core2_flux[i],0.0,1.0);
00293         core3_flux[i] = COREMAG(core3_flux[i],0.0,1.0);
00294         core4_flux[i] = COREMAG(core4_flux[i],0.0,1.0);
00295         core5_flux[i] = COREMAG(core5_flux[i],0.0,1.0);
00296         moff = 1.0/(1.0 - pow((thresh/MAX(peak_height[i],thresh)),0.6));
00297         iso_flux[i] = COREMAG(moff*iso_flux[i],0.0,1.0);
00298         peak_mag[i] = COREMAG(peak_height[i],skynoise,0.1);
00299     }
00300     if (core6_flux != NULL) 
00301         for (i = 0; i < nrows; i++)
00302             core6_flux[i] = COREMAG(core6_flux[i],0.0,1.0);
00303     if (ncols == 32)
00304         for (i = 0; i < nrows; i++)
00305             total_flux[i] = COREMAG(total_flux[i],0.0,1.0);
00306 
00307     /*  Now get the areal profile information. You'll need this in a sec */
00308 
00309     for (i = 0; i < NAREAL; i++) {
00310         sprintf(colname,"Areal_%d_profile",i+1);
00311         areal[i] = cpl_table_get_data_float(catcopy,colname);
00312     }
00313 
00314     /* What is the seeing like? */
00315 
00316     poor = 0;
00317     if (fwhm > max(5.0,rcore*sqrt(2.0)))
00318         poor = 1;
00319 
00320     /* Ok, now call the routine that does all the work */
00321 
00322     classify_run();
00323 
00324     /* Right, now get a better estimate of the seeing */
00325 
00326     n = 0;
00327     for (i = 0; i < nrows; i++) {
00328         pkht = peak_height[i];
00329         ell = ellipticity[i];
00330         core = core_flux[i];
00331         if (cls[i] == -1.0 && ell < elllim && core < corlim && 
00332             pkht > 10.0*thresh) { 
00333             ap = log(0.5*pkht/thresh)/log(2.0) + 1.0;
00334             iap = (int)ap;
00335             delap = ap - (float)iap;
00336             if (iap > 0 && iap < NAREAL && areal[1][i] > 0.0) {
00337                 i1 = (iap-1)*nrows + i;
00338                 i2 = iap*nrows + i;
00339                 area = areal[iap-1][i]*(1.0 - delap) + areal[iap][i]*delap;
00340                 work[n++] = 2.0*sqrt(area/PI);
00341             }
00342         }
00343     }
00344     if (n > 2) { 
00345         medstat(work,n,&fwhm,&junk);
00346        
00347         /* Allow for finite pixel size */
00348 
00349         arg = 0.25*PI*fwhm*fwhm - 1;
00350         fwhm = 2.0*sqrt(max(0.0,arg/PI));
00351        
00352     } else
00353         fwhm = -1.0;
00354 
00355     /* Tidy up a bit */
00356 
00357     freespace(workspace);
00358     freetable(catcopy);
00359 
00360     /* Write header results into extra property list. First the QC */
00361 
00362     cpl_propertylist_update_float(extra,"ESO QC IMAGE_SIZE",fwhm);
00363     cpl_propertylist_set_comment(extra,"ESO QC IMAGE_SIZE",
00364                                  "[pixels] Average FWHM of stellar objects");
00365     cpl_propertylist_update_float(extra,"ESO QC ELLIPTICITY",fitell);
00366     cpl_propertylist_set_comment(extra,"ESO QC ELLIPTICITY",
00367                                  "Average stellar ellipticity (1-b/a)");
00368     cpl_propertylist_update_float(extra,"ESO QC POSANG",fitpa);
00369     cpl_propertylist_set_comment(extra,"ESO QC POSANG",
00370                                  "[degrees] Median position angle");
00371     switch (cattype) {
00372     case 1:
00373         cpl_propertylist_update_float(extra,"ESO QC APERTURE_CORR",apcor);
00374         cpl_propertylist_set_comment(extra,"ESO QC APERTURE_CORR",
00375                                      "Stellar ap-corr 1x core flux");
00376         break;
00377     case 2:
00378         cpl_propertylist_update_float(extra,"ESO QC APERTURE_CORR",apcor3);
00379         cpl_propertylist_set_comment(extra,"ESO QC APERTURE_CORR",
00380                                      "Stellar ap-corr 1x core flux");
00381         break;
00382     }
00383     cpl_propertylist_update_int(extra,"ESO QC NOISE_OBJ",njunk);
00384     cpl_propertylist_set_comment(extra,"ESO QC NOISE_OBJ",
00385                                  "Number of noise objects");
00386     cpl_propertylist_update_float(extra,"ESO QC SATURATION",avsat);
00387     
00388     /* Now some helpful DRS keywords */
00389 
00390     cpl_propertylist_update_bool(extra,"ESO DRS CLASSIFD",1);
00391     cpl_propertylist_set_comment(extra,"ESO DRS CLASSIFD",
00392                                  "Catalogue has been classified");
00393 
00394     /* Now the aperture correction keywords */
00395 
00396     switch (cattype) {
00397     case 1:
00398         cpl_propertylist_update_float(extra,"APCORPK",apcpkht);
00399         cpl_propertylist_set_comment(extra,"APCORPK","Stellar aperture correction - peak height");
00400         cpl_propertylist_update_float(extra,"APCOR1",apcor1);
00401         cpl_propertylist_set_comment(extra,"APCOR1","Stellar aperture correction - 1/2x core flux");
00402         cpl_propertylist_update_float(extra,"APCOR",apcor);
00403         cpl_propertylist_set_comment(extra,"APCOR","Stellar aperture correction - 1x core flux");
00404         cpl_propertylist_update_float(extra,"APCOR2",apcor2);
00405         cpl_propertylist_set_comment(extra,"APCOR2","Stellar aperture correction - sqrt(2)x core flux");
00406         cpl_propertylist_update_float(extra,"APCOR3",apcor3);
00407         cpl_propertylist_set_comment(extra,"APCOR3","Stellar aperture correction - 2x core flux");
00408         cpl_propertylist_update_float(extra,"APCOR4",apcor4);
00409         cpl_propertylist_set_comment(extra,"APCOR4","Stellar aperture correction - 2*sqrt(2)x core flux");
00410         cpl_propertylist_update_float(extra,"APCOR5",apcor5);
00411         cpl_propertylist_set_comment(extra,"APCOR5","Stellar aperture correction - 4x core flux");
00412         break;
00413     case 2:
00414         cpl_propertylist_update_float(extra,"APCORPK",apcpkht);
00415         cpl_propertylist_set_comment(extra,"APCORPK","Stellar aperture correction - peak height");
00416         cpl_propertylist_update_float(extra,"APCOR1",apcor1);
00417         cpl_propertylist_set_comment(extra,"APCOR1","Stellar aperture correction - 1/2x core flux");
00418         cpl_propertylist_update_float(extra,"APCOR2",apcor2);
00419         cpl_propertylist_set_comment(extra,"APCOR2","Stellar aperture correction - core/sqrt(2) flux");
00420         cpl_propertylist_update_float(extra,"APCOR3",apcor3);
00421         cpl_propertylist_set_comment(extra,"APCOR3","Stellar aperture correction - 1x core flux");
00422         cpl_propertylist_update_float(extra,"APCOR4",apcor4);
00423         cpl_propertylist_set_comment(extra,"APCOR4","Stellar aperture correction - sqrt(2)x core flux");
00424         cpl_propertylist_update_float(extra,"APCOR5",apcor5);
00425         cpl_propertylist_set_comment(extra,"APCOR5","Stellar aperture correction - 2x core flux");
00426         cpl_propertylist_update_float(extra,"APCOR6",apcor6);
00427         cpl_propertylist_set_comment(extra,"APCOR6","Stellar aperture correction - 2*sqrt(2)x core flux");
00428         cpl_propertylist_update_float(extra,"APCOR7",apcor7);
00429         cpl_propertylist_set_comment(extra,"APCOR7","Stellar aperture correction - 4x core flux");
00430 
00431         break;
00432     }
00433 
00434     /* Write header information to help GAIA */
00435 
00436     cpl_propertylist_update_string(extra,"SYMBOL1","{Ellipticity Position_angle Areal_1_profile Classification} {el");
00437     cpl_propertylist_update_string(extra,"SYMBOL2","lipse blue (1.0-$Ellipticity) $Position_angle+90 {} $Classific");
00438     cpl_propertylist_update_string(extra,"SYMBOL3","ation==1} {sqrt($Areal_1_profile*(1.0-$Ellipticity)/3.142)} : {");
00439     cpl_propertylist_update_string(extra,"SYMBOL4","Ellipticity Position_angle Areal_1_profile Classification} {el");
00440     cpl_propertylist_update_string(extra,"SYMBOL5","lipse red (1.0-$Ellipticity) $Position_angle+90 {} $Classific");
00441     cpl_propertylist_update_string(extra,"SYMBOL6","ation==-1} {sqrt($Areal_1_profile*(1.0-$Ellipticity)/3.142)} :");
00442     cpl_propertylist_update_string(extra,"SYMBOL7","{Ellipticity Position_angle Areal_1_profile Classification} {el");
00443     cpl_propertylist_update_string(extra,"SYMBOL8","lipse green (1.0-$Ellipticity) $Position_angle+90 {} $Classifi");
00444     cpl_propertylist_update_string(extra,"SYMBOL9","cation==0} {sqrt($Areal_1_profile*(1.0-$Ellipticity)/3.142)}");
00445 
00446     /* Get out of here */
00447 
00448     return(VIR_OK);
00449 }
00450 
00451 /*---------------------------------------------------------------------------*/
00477 /*---------------------------------------------------------------------------*/
00478 
00479 static void anhist(float *data, int n, float *medval, float *sigma) {
00480     int i,*histo,ilev,imax,ismax;
00481     float *sval,hmax,smax,hlim,ratio;
00482 
00483     /* Get some workspace for the histogram */
00484 
00485     histo = cpl_calloc(MAXHIST,sizeof(int));
00486     sval = cpl_calloc(MAXHIST,sizeof(float));
00487 
00488     /* Sort data into the histogram */
00489 
00490     for (i = 0; i < n; i++) {
00491         ilev = vircam_nint(data[i]/STEP);
00492         if (ilev >= -10 && ilev <= 100) {
00493             ilev += 10;
00494             histo[ilev] += 1;
00495         }
00496     }
00497 
00498     /* Now find the maximum of the histogram and its position... */
00499 
00500     hmax = 0.0;
00501     imax = 0;
00502     for (i = 0; i < MAXHIST; i++) {
00503         if (histo[i] > hmax) {
00504             hmax = (float)histo[i];
00505             imax = i;
00506         }
00507     }
00508 
00509     /* Trap for hmax == 0 */
00510 
00511     if (hmax == 0.0) {
00512         if (n >= 10) {
00513             *medval = data[(n+1)/2-1];
00514             *sigma = 1.48*0.5*(data[(3*n+3)/4-1] - data[(n+3)/4-1]);
00515         } else {
00516             *medval = 0.0;
00517             *sigma = 1.0;
00518         }
00519         return;
00520     }
00521 
00522     /* Now do three point running average to see if there are other local
00523        maxima */
00524 
00525     smax = 0.0;
00526     ismax = 0;
00527     for (i = 1; i < MAXHIST-1; i++) {
00528         sval[i] = (histo[i-1] + histo[i] + histo[i+1])/3.0;
00529         if (sval[i] > smax) {
00530             smax = sval[i];
00531             ismax = i;
00532         }
00533     }
00534     if (ismax < imax) {
00535         imax = ismax;
00536         hmax = (float)histo[imax];
00537     }
00538 
00539     /* Now check for lower local maxima */
00540 
00541     for (i = imax-1; i > 0; i--) {
00542         if (sval[i] >= sval[i+1] && sval[i] >= sval[i-1]) {
00543             if (sval[i] > 0.5*smax)
00544                 ismax = i;
00545         }
00546     }
00547     if (ismax < imax) {
00548         imax = ismax;
00549         hmax = (float)histo[imax];
00550     }
00551     
00552     /* Now work out where the peak is */
00553     
00554     *medval = min((float)(imax-10)*STEP,data[(n+1)/2-1]);
00555     hlim = vircam_nint(0.5*hmax);
00556     i = 1;
00557     while (histo[imax-i] > hlim && imax-i > 1)
00558         i++;
00559     ratio = hmax/max(1.0,(float)histo[imax-i]);
00560     *sigma = (float)i*STEP/(sqrt(2.0)*max(1.0,log(ratio)));
00561     *sigma = max(*sigma,0.5*STEP);
00562 
00563     /* Tidy and exit */
00564     
00565     freespace(histo);
00566     freespace(sval);
00567 }
00568 
00569 /*---------------------------------------------------------------------------*/
00608 /*---------------------------------------------------------------------------*/
00609 
00610 static void boundaries(float *core1, float *core2, float *core3, float medval1,
00611                        float sigma1, float medval2, float sigma2, int small, 
00612                        float area1, float area2, float *wt, float *avsig, 
00613                        float *lower, float *upper) {
00614     int i,n;
00615     float c1,c2,dc,*work,xnoise,xmag,xflux,ratio,asign,junk;
00616 
00617     /* Get a workspace */
00618 
00619     work = cpl_malloc(nrows*sizeof(float));
00620 
00621     /* Initialise the lower boundary */
00622 
00623     lower[0] = cmin;
00624     lower[1] = cmax;
00625     asign = ((small == 1) ? -1.0 : 1.0);
00626     
00627     /* Now collect the data */
00628 
00629     n = 0;
00630     for (i = 0; i < nrows; i++) {
00631         c1 = core1[i];
00632         if (! poor) {
00633             c2 = core2[i];
00634             dc = asign*(c2 - c1);
00635             if (dc > medval1 - 3.0*sigma1 && c1 < blim - 3.0)
00636                 work[n++] = dc - medval1;
00637         } else {
00638             c2 = core3[i];
00639             dc = c2 - c1;
00640             if (dc > medval2 - 3.0*sigma2 && c1 < blim - 3.0)
00641                 work[n++] = dc - medval2;
00642         }
00643     }
00644  
00645     /* Find the median */
00646 
00647     medstat(work,n,avsig,&junk);
00648     freespace(work);
00649 
00650     /* Work out sigma levels for both types of seeing */
00651 
00652     if (! poor) {
00653         *wt = min(5.0,max(1.0,*avsig/sigma1));
00654         xnoise = sqrt(area1)*skynoise;
00655     } else {
00656         *wt = min(2.5,max(1.0,*avsig/sigma2));
00657         xnoise = sqrt(area2)*skynoise;
00658     }
00659 
00660     /* Now work out the boundaries */
00661 
00662     for (i = 0; i < NSAMPLE; i++) {
00663         xmag = 5.0 + (float)(i+1)*0.1;
00664         xflux = pow(10.0,(double)(0.4*xmag));
00665         ratio = COREMAG(1.0+xnoise/xflux,0.0,0.0);
00666         if (! poor) {
00667             lower[i] = medval1 - 3.0*sqrt(sigma1*sigma1 + ratio*ratio);
00668             upper[i] = medval1 + 3.0*sqrt(sigma1*sigma1 + 0.5*ratio*ratio);
00669         } else {
00670             lower[i] = medval2 - 3.0*sqrt(sigma2*sigma2 + ratio*ratio);
00671             upper[i] = medval2 + 3.0*sqrt(sigma2*sigma2 + 0.5*ratio*ratio);
00672         }
00673     }
00674     upper[0] = ((poor == 0) ? medval1 : medval2);
00675     upper[1] = upper[0];
00676 }
00677 
00678 /*---------------------------------------------------------------------------*/
00709 /*---------------------------------------------------------------------------*/
00710 
00711 static void boundpk(float *core, float *pkht, float medval, float sigma, 
00712                     float *wt, float *avsig, float *lower, float *upper) {
00713     int i,n;
00714     float c,p,*work,xnoise,xmag,pmag,xflux,pflux,ratio,junk;
00715 
00716     /* Get the space for the boundry lines and a workspace */
00717 
00718     work = cpl_malloc(nrows*sizeof(float));
00719 
00720     /* Collect the data */
00721 
00722     n = 0;
00723     for (i = 0; i < nrows; i++) {
00724         c = core[i];
00725         p = pkht[i];
00726         if (c - p > medval - 3.0*sigma && c < blim - 3.0)
00727             work[n++] = c - p - medval;
00728     }
00729 
00730     /* Find the median */
00731 
00732     medstat(work,n,avsig,&junk);
00733     freespace(work);
00734     *wt = min(5.0,max(1.0,*avsig/sigma));
00735 
00736     /* Now work out boundaries */
00737 
00738     xnoise = sqrt(PI*rcore*rcore)*skynoise;
00739     for (i = 0; i < NSAMPLE; i++) {
00740         xmag = 5.0 + (float)(i+1)*0.1;
00741         pmag = xmag - medval;
00742         xflux = pow(10.0,(double)(0.4*xmag));
00743         pflux = pow(10.0,(double)(0.4*pmag));
00744         ratio = 2.5*log10((double)(1.0+max(xnoise/xflux,skynoise/pflux)));
00745         lower[i] = medval - 3.0*sqrt(sigma*sigma + ratio*ratio);
00746         upper[i] = medval + 3.0*sqrt(sigma*sigma + 0.5*ratio*ratio);
00747     }
00748     upper[0] = medval;
00749     upper[1] = upper[0];
00750 }
00751 
00752 /*---------------------------------------------------------------------------*/
00770 /*---------------------------------------------------------------------------*/
00771 
00772 static void classify_run() {
00773     float fluxlim,ell,pk,pkht,core,sig1,sig2,sig3,denom,w1,w2,w3;
00774     float core_small,core_large,core_midd,statistic,statcut,sigtot;
00775     float fit0,sigma0,xnoise,xmag,ratio,xflux,ratell,ratscl,ellbound;
00776     float *lower,*upper,sigma1,sigma2,sigma3,sigma4,sigma5,sigma6,sigma7;
00777     float *work,avsatnew,junk;
00778     int i,iarg,ii;
00779 
00780     /* Update faint limit to cope with short exposures */
00781 
00782     blim = BLIMDEF;
00783     flim = FLIMDEF;
00784     fluxlim = 2.5*log10((double)(5.0*sqrt(PI*rcore*rcore)*skynoise));
00785     flim = min(flim,max(6.0,fluxlim+3.0));
00786     corlim = min(blim,max(12.5,fluxlim+5.0));
00787     cormin = min(blim,max(12.5,fluxlim+5.0));
00788 
00789     /* Work out min and max core flux */
00790 
00791     cmin = CMINDEF;
00792     cmax = CMAXDEF;
00793     for (i = 0; i < nrows; i++) {
00794         xflux = core_flux[i];
00795         cmin = min(cmin,xflux);
00796         cmax = max(cmax,xflux);
00797     }
00798     cmin = max(fluxlim-0.5,cmin);
00799     cmax += 0.1;
00800     cmax = min(cmax,20.0);
00801 
00802     /* Work out ellipticity stats for likely stellar objects */
00803 
00804     classstats_el();
00805 
00806     /* Ok, get the classification statistics for each of the tests.  First
00807        the core flux vs 1/2*core flux */
00808 
00809     classstats(core_flux,core1_flux,1,0.2,&fit1,&sigma1);
00810 
00811     /* Core flux vs 2*core flux */
00812 
00813     classstats(core_flux,core3_flux,0,0.1,&fit2,&sigma2);
00814 
00815     /* Core flux vs sqrt(2)*core flux */
00816 
00817     classstats(core_flux,core2_flux,0,0.0,&fit4,&sigma4);
00818 
00819     /* Core flux vs 2*sqrt(2)*core flux */
00820 
00821     classstats(core_flux,core4_flux,0,0.1,&fit5,&sigma5);
00822 
00823     /* Core flux vs Peak height */
00824 
00825     classstats(core_flux,peak_mag,1,0.2,&fit3,&sigma3);
00826 
00827     /* Faint end ellipticity */
00828 
00829     classstats_ellf(fluxlim);
00830 
00831     /* Work out position angle stats for likely stellar objects */
00832 
00833     classstats_pa();
00834 
00835     /* Get workspace for the boundary arrays */
00836    
00837     lower1 = cpl_malloc(NSAMPLE*sizeof(float));
00838     lower2 = cpl_malloc(NSAMPLE*sizeof(float));
00839     lower3 = cpl_malloc(NSAMPLE*sizeof(float));
00840     upper1 = cpl_malloc(NSAMPLE*sizeof(float));
00841     upper2 = cpl_malloc(NSAMPLE*sizeof(float));
00842     upper3 = cpl_malloc(NSAMPLE*sizeof(float));
00843 
00844     /* Right, work out the boundaries for the classification tests 
00845        First core vs sqrt(2)*core or core vs 0.5*core depending upon
00846        the seeing */
00847 
00848     boundaries(core_flux,core1_flux,core2_flux,fit1,sigma1,fit4,sigma4,
00849                1,PI*rcore*rcore,2.0*PI*rcore*rcore,&wt1,&avsig1,lower1,
00850                upper1);
00851 
00852     /* Now core vs 2*core or core vs 2*sqrt(2)*core */
00853 
00854     boundaries(core_flux,core3_flux,core4_flux,fit2,sigma2,fit5,sigma5,
00855                0,4.0*PI*rcore*rcore,8.0*PI*rcore*rcore,&wt2,&avsig2,lower2,
00856                upper2);
00857 
00858     /* Now core vs peak height */
00859 
00860     boundpk(core_flux,peak_mag,fit3,sigma3,&wt3,&avsig3,lower3,upper3); 
00861 
00862      
00863     /* Do final classification statistics and find the saturation limit */
00864 
00865     classstats_final();
00866 
00867     /* Define final boundaries */
00868 
00869     lower = cpl_malloc(NSAMPLE*sizeof(float));
00870     upper = cpl_malloc(NSAMPLE*sizeof(float));
00871     uppere = cpl_malloc(NSAMPLE*sizeof(float));
00872     xnoise = sqrt(PI*rcore*rcore)*skynoise;
00873     ratell = xnoise/pow(10.0,0.4*(fluxlim+1.5));
00874     ratell = COREMAG(1.0+ratell,0.0,0.0);
00875     ratscl = (pow((fitellf + 2.0*sigellf - fitell),2.0) - 4.0*sigell*sigell)/(4.0*ratell*ratell);
00876     ratscl = max(0.25,min(10.0,ratscl));
00877     for (i = 0; i < NSAMPLE; i++) {
00878         xmag = 5.0 + 0.1*(float)(i+1);
00879         xflux = pow(10.0,0.4*xmag);
00880         ratio = 2.5*log10(1.0+xnoise/xflux);
00881         lower[i] = fit_final - 5.0*sqrt(sigma_final*sigma_final + ratio*ratio);
00882         upper[i] = fit_final + sqrt(9.0*sigma_final*sigma_final + 0.0*ratio*ratio);
00883         uppere[i] = fitell + 2.0*sqrt(sigell*sigell + ratscl*ratio*ratio);
00884         uppere[i] = min(0.5,uppere[i]);
00885     }
00886     elllim = min(0.5,max(0.2,fitell+2.0*sigell));
00887     fluxlim = 2.5*log10((double)(2.5*sqrt(PI*rcore*rcore)*skynoise));
00888 
00889     /* Ok, final classification loop now... */
00890 
00891     nstar = 0;
00892     ngal = 0;
00893     njunk = 0;
00894     ncmp = 0;
00895     for (i = 0; i < nrows; i++) {
00896         ell = ellipticity[i];
00897         pk = peak_height[i] + skylevel;
00898         pkht = peak_mag[i];
00899         core = core_flux[i];
00900         iarg = vircam_nint(10.0*(core - 5.0));
00901         iarg = max(1,min(NSAMPLE,iarg)) - 1;
00902         if (! poor) {
00903             sig1 = max(0.01,(fit1 - lower1[iarg])/3.0);
00904             sig2 = max(0.01,(fit2 - lower2[iarg])/3.0);
00905         } else {
00906             sig1 = max(0.01,(fit4 - lower1[iarg])/3.0);
00907             sig2 = max(0.01,(fit5 - lower2[iarg])/3.0);
00908         }
00909         sig3 = max(0.01,(fit3 - lower3[iarg])/3.0);
00910         denom = (wt1/sig1 + wt2/sig2 + wt3/sig3);
00911         w1 = (wt1/sig1)/denom;
00912         w2 = (wt2/sig2)/denom;
00913         w3 = (wt3/sig3)/denom;
00914         if (! poor) {
00915             core_small = core1_flux[i];
00916             core_large = core3_flux[i];
00917             statistic = (core - core_small - fit1)*w1 + 
00918                 (max(-3.0*sig2,core_large - core - fit2))*w2 + 
00919                 (core - pkht - fit3)*w3;
00920         } else {
00921             core_midd = core2_flux[i];
00922             core_large = core4_flux[i];
00923             statistic = (core_midd - core - fit4)*w1 +
00924                 (max(-3.0*sig2,core_large - core - fit5))*w2 + 
00925                 (core - pkht - fit3)*w3;
00926         }
00927         cls[i] = -1.0;
00928         statcut = upper[iarg] + 3.0*sigma_final*(exp(max(0.0,core-corlim+1.0)) - 1.0);
00929         if (statistic  >= statcut) 
00930             cls[i] = 1.0;
00931         else if (statistic <= lower[iarg])
00932             cls[i] = 0.0;
00933 
00934         /* Save distance from the stellar locus */
00935 
00936         sigtot = (fit_final - lower[iarg])/5.0;
00937         sig[i] = (statistic - fit_final)/sigtot;
00938 
00939         /* Right, now here are lots of overrides for special circumstances */
00940         /* Too spikey? -> junk */
00941 
00942         if (core - pkht - fit3 < -4.0*sig3) 
00943             cls[i] = 0.0;
00944 
00945         /* Elliptical star? -> compact */
00946 
00947         ellbound = max(elllim,uppere[iarg]);
00948         if (ell > ellbound && cls[i] == -1.0 && core < flim && sig[i] > -2.0)
00949             cls[i] = -2.0;
00950 
00951         /* Saturated? -> star */
00952 
00953         if (core > corlim && statistic >= lower[iarg])
00954             cls[i] = -1.0;
00955 
00956         /* Too elliptical? -> junk */
00957 
00958         if (ell > 0.9 && core < corlim)
00959             cls[i] = 0.0;
00960 
00961         /* Too faint? -> junk */
00962 
00963         if (core < fluxlim)
00964             cls[i] = 0.0;
00965 
00966         /* Now count how many you have of each */
00967 
00968         if (cls[i] == -1.0)
00969             nstar++;
00970         else if (cls[i] == 1.0)
00971             ngal++;
00972         else if (cls[i] == -2.0)
00973             ncmp++;
00974         else
00975             njunk++;
00976     }
00977 
00978     /* Do stats to get the aperture corrections */
00979 
00980     if (ncols == 80) {
00981         classstats_ap67(core5_flux,core3_flux,&fit6,&sigma6);
00982         classstats_ap67(core_flux,core6_flux,&fit7,&sigma7);
00983         fit6 += fit2;
00984     }
00985     classstats_ap0(&fit0,&sigma0);
00986     if (ncols == 80) 
00987         fit0 = max(fit6,fit0);
00988     else
00989         fit0 = max(fit5,fit0);
00990     apcpkht = fit0 + fit3; /* pkht */
00991     switch (ncols) {
00992     case 32:
00993         apcor1 = fit0 + fit1;  /* 0.5*core */
00994         apcor = fit0;          /* core */
00995         apcor2 = fit0 - fit4;  /* sqrt(2)*core */
00996         apcor3 = fit0 - fit2;  /* 2*core */
00997         apcor4 = fit0 - fit5;  /* 2*sqrt(2)*core */
00998         apcor5 = 0.0;          /* 4*core */
00999         break;
01000     case 80:
01001         apcor1 = fit0 + fit1;      /* 0.5*core */
01002         apcor2 = fit0 + fit7;      /* 1/sqrt(2) * core */
01003         apcor3 = fit0;             /* core */
01004         apcor4 = fit0 - fit4;      /* core * sqrt(2) */
01005         apcor5 = fit0 - fit2;      /* 2*core */
01006         apcor6 = fit0 - fit5;      /* 2*sqrt(2)*core */
01007         apcor7 = fit0 - fit6;      /* 4*core */
01008         break;
01009     }
01010 
01011     /* Now do a better job on the saturation */
01012 
01013     ii = 0;
01014     work = cpl_malloc(nrows*sizeof(float));
01015     for (i = 0; i < nrows; i++) {
01016         ell = ellipticity[i];
01017         core = core_flux[i];
01018         pkht = max(thresh,peak_height[i]) + skylev[i];
01019         if (((ell < elllim && core > flim && cls[i] == -1 && sig[i] >= 5.0 &&
01020              areal[0][i] >= pixlim) || pkht >= 0.9*avsat) && xpos[i] >= xmin && 
01021              xpos[i] <= xmax && ypos[i] >= ymin && ypos[i] <= ymax) {
01022             work[ii++] = pkht;
01023         }
01024     }
01025     if (ii > 0) {
01026         medstat(work,ii,&avsatnew,&junk);
01027         avsatnew = max(10000.0+skylevel,avsatnew);
01028     } else {
01029         avsatnew = 10000.0 + skylevel;
01030     }
01031     avsat = avsatnew;
01032     freespace(work);    
01033 
01034     /* Ok, now get rid of some workspace */
01035         
01036     freespace(lower1);
01037     freespace(lower2);
01038     freespace(lower3);
01039     freespace(upper1);
01040     freespace(upper2);
01041     freespace(upper3);
01042     freespace(lower);
01043     freespace(upper);
01044     freespace(uppere);
01045 
01046 }
01047 
01048 /*---------------------------------------------------------------------------*/
01076 /*---------------------------------------------------------------------------*/
01077 
01078 static void classstats(float *core1, float *core2, int small, float cutlev,
01079                        float *medval, float *sigma) {
01080 
01081     int i,iloop,n;
01082     float *work,*dc,sigmaold,amult;
01083 
01084     /* Initialise the output values to something stupid */
01085 
01086     *medval = 0.0;
01087     *sigma = 1.0e6;
01088     amult = (small == 1 ? -1.0 : 1.0);
01089 
01090     /* Get some workspace */
01091 
01092     work = cpl_malloc(nrows*sizeof(float));
01093     dc = cpl_malloc(nrows*sizeof(float));
01094 
01095     /* Work out differences */
01096 
01097     for (i = 0; i < nrows; i++)
01098         dc[i] = amult*(core2[i] - core1[i]);
01099 
01100     /* Do an iteration loop */
01101 
01102     for (iloop = 0; iloop < MAXLOOP; iloop++) {
01103         sigmaold = *sigma;
01104         n = 0;
01105 
01106         /* Ok, gather up all the stats */
01107 
01108         for (i = 0; i < nrows; i++) {
01109             
01110             /* Clipping criteria */
01111 
01112             if (ellipticity[i] < elllim && core1[i] < blim && core1[i] > flim &&
01113                 fabs(dc[i] - *medval) < 3.0*(*sigma) &&
01114                 xpos[i] >= xmin && xpos[i] <= xmax && ypos[i] >= ymin &&
01115                 ypos[i] <= ymax && areal[0][i] >= pixlim) {
01116                 if (iloop > 0 || (iloop == 0 && dc[i] >= cutlev)) 
01117                     work[n++] = dc[i];
01118             }
01119         }
01120 
01121         /* Sort the work array and find the median and sigma */
01122 
01123         if (n > 0) {
01124             sort1(work,n);
01125             if (iloop == 0) {
01126                 anhist(work,n,medval,sigma);
01127             } else {
01128                 medstat(work,n,medval,sigma);
01129                 *sigma = min(sigmaold,*sigma);
01130             }
01131         } else {
01132             *medval = 0.0; 
01133             *sigma = 0.01;
01134         }
01135 
01136         /* Just in case... */
01137 
01138         *sigma = max(*sigma,0.01);
01139     }
01140 
01141     /* Tidy and exit */
01142 
01143     free(work);
01144     free(dc);
01145 }
01146 
01147 /*---------------------------------------------------------------------------*/
01162 /*---------------------------------------------------------------------------*/
01163 
01164 static void classstats_el(void) {
01165     int iloop,n,i;
01166     float *work;
01167 
01168     /* Initialise the mean and sigma to something stupid */
01169 
01170     sigell = 1.0e6;
01171     fitell = 0.0;
01172 
01173     /* Get some workspace */
01174 
01175     work = cpl_malloc(nrows*sizeof(float));
01176 
01177     /* Do iteration loop */
01178 
01179     for (iloop = 0; iloop < MAXLOOP; iloop++) {
01180         n = 0;
01181         for (i = 0; i < nrows; i++) {
01182             if (ellipticity[i] < 0.5 && core_flux[i] < blim && 
01183                 core_flux[i] > flim && 
01184                 fabs(ellipticity[i] - fitell) < 2.0*sigell &&
01185                 xpos[i] >= xmin && xpos[i] <= xmax && ypos[i] >= ymin &&
01186                 ypos[i] <= ymax && areal[0][i] >= pixlim)
01187                 work[n++] = ellipticity[i];
01188         }
01189         if (n > 2)
01190             medstat(work,n,&fitell,&sigell);
01191         else {
01192             fitell = 0.25;
01193             sigell = 0.05;
01194         }
01195     }
01196     elllim = min(0.5,max(0.2,fitell+2.0*sigell));
01197 
01198     /* Get out of here */
01199 
01200     freespace(work);
01201 }
01202 
01203 /*---------------------------------------------------------------------------*/
01218 /*---------------------------------------------------------------------------*/
01219 
01220 static void classstats_pa() {
01221     int iloop,n,i;
01222     float *work;
01223 
01224     /* Initialise the mean and sigma to something stupid */
01225 
01226     sigpa = 1.0e6;
01227     fitpa = 0.0;
01228 
01229     /* Get some workspace */
01230 
01231     work = cpl_malloc(nrows*sizeof(float));
01232 
01233     /* Do iteration loop */
01234 
01235     for (iloop = 0; iloop < MAXLOOP; iloop++) {
01236         n = 0;
01237         for (i = 0; i < nrows; i++) {
01238             if (core_flux[i] < blim && core_flux[i] > flim && 
01239                 fabs(pa[i] - fitpa) < 2.0*sigpa &&
01240                 xpos[i] >= xmin && xpos[i] <= xmax && ypos[i] >= ymin &&
01241                 ypos[i] <= ymax && areal[0][i] >= pixlim)
01242                 work[n++] = pa[i];
01243         }
01244         if (n > 2)
01245             medstat(work,n,&fitpa,&sigpa);
01246         else {
01247             fitpa = 0.0;
01248             sigpa = 0.05;
01249         }
01250     }
01251 
01252     /* Get out of here */
01253 
01254     freespace(work);
01255 }
01256 
01257 /*---------------------------------------------------------------------------*/
01275 /*---------------------------------------------------------------------------*/
01276 
01277 static void classstats_ellf(float fluxlim) {
01278     int iloop,n,i;
01279     float *work;
01280 
01281     /* Initialise the mean and sigma to something stupid */
01282 
01283     sigellf = 1.0e6;
01284     fitellf = 0.0;
01285 
01286     /* Get some workspace */
01287 
01288     work = cpl_malloc(nrows*sizeof(float));
01289 
01290     /* Do iteration loop */
01291 
01292     for (iloop = 0; iloop < MAXLOOP; iloop++) {
01293         n = 0;
01294         for (i = 0; i < nrows; i++) {
01295             if (ellipticity[i] < 0.75 && core_flux[i] > fluxlim+1.0 && 
01296                 core_flux[i] < fluxlim+2.0 &&
01297                 fabs(ellipticity[i] - fitellf) < 2.0*sigellf)
01298                 work[n++] = ellipticity[i];
01299         }
01300         if (n > 2)
01301             medstat(work,n,&fitellf,&sigellf);
01302         else {
01303             fitellf = 0.25;
01304             sigellf = 0.05;
01305         }
01306     }
01307 
01308     /* Get out of here */
01309 
01310     freespace(work);
01311 }
01312 
01313 /*---------------------------------------------------------------------------*/
01333 /*---------------------------------------------------------------------------*/
01334 
01335 static void classstats_ap0(float *medval, float *sigma) {
01336 
01337     int i,iloop,n;
01338     float *work,*dc,c2,sigmanew;
01339 
01340     /* Initialise the output values to something stupid */
01341 
01342     *medval = 0.0;
01343     *sigma = 1.0e6;
01344     elllim = min(0.5,max(0.2,fitell+2.0*sigell));
01345 
01346     /* Get some workspace */
01347 
01348     work = cpl_malloc(nrows*sizeof(float));
01349     dc = cpl_malloc(nrows*sizeof(float));
01350 
01351     /* Work out differences */
01352 
01353     for (i = 0; i < nrows; i++) {
01354         c2 = max(0.0,max(iso_flux[i],core5_flux[i]));
01355         dc[i] = c2 - core_flux[i];
01356     }
01357 
01358     /* Do an iteration loop */
01359 
01360     for (iloop = 0; iloop < MAXLOOP; iloop++) {
01361         n = 0;
01362 
01363         /* Ok, gather up all the stats */
01364 
01365         for (i = 0; i < nrows; i++) {
01366             
01367             /* Clipping criteria */
01368 
01369             if (ellipticity[i] < elllim && core_flux[i] < blim && 
01370                 core_flux[i] > flim && 
01371                 fabs(dc[i] - *medval) < 3.0*(*sigma) && 
01372                 cls[i] == -1.0 && sig[i] < 5.0 &&
01373                 xpos[i] >= xmin && xpos[i] <= xmax && ypos[i] >= ymin &&
01374                 ypos[i] <= ymax && areal[0][i] >= pixlim) 
01375                 if (iloop > 0 || (iloop == 0 && dc[i] >= 0.0)) {
01376                     work[n++] = dc[i];
01377                 }
01378         }
01379 
01380         /* Sort the work array and find the median and sigma */
01381 
01382         if (n > 0) {
01383             sort1(work,n);
01384             if (iloop == 0) {
01385                 anhist(work,n,medval,sigma);
01386                 *sigma = 1.48*(*medval - work[(int)(0.25*(float)(n+3))-1]);
01387                 *sigma = max(0.025,*sigma);
01388             } else {
01389                 medstat(work,n,medval,&sigmanew);
01390                 *sigma = min(*sigma,sigmanew);
01391                 *sigma = max(0.01,*sigma);
01392             }
01393         } else {
01394             *medval = 0.0;
01395             *sigma = 0.01;
01396         }
01397 
01398         /* Just in case... */
01399 
01400         *sigma = max(*sigma,0.01);
01401     }
01402 
01403     /* Tidy and exit */
01404 
01405     freespace(work);
01406     freespace(dc);
01407 }
01408 
01409 static void classstats_ap67(float *mag1, float *mag2, float *medval, 
01410                             float *sigma) {
01411 
01412     int i,iloop,n;
01413     float *work,*dc,sigmanew;
01414 
01415     /* Initialise the output values to something stupid */
01416 
01417     *medval = 0.0;
01418     *sigma = 1.0e6;
01419     elllim = min(0.5,max(0.2,fitell+2.0*sigell));
01420 
01421     /* Get some workspace */
01422 
01423     work = cpl_malloc(nrows*sizeof(float));
01424     dc = cpl_malloc(nrows*sizeof(float));
01425 
01426     /* Work out differences */
01427 
01428     for (i = 0; i < nrows; i++) 
01429         dc[i] = mag1[i] - mag2[i];
01430 
01431     /* Do an iteration loop */
01432 
01433     for (iloop = 0; iloop < MAXLOOP; iloop++) {
01434         n = 0;
01435 
01436         /* Ok, gather up all the stats */
01437 
01438         for (i = 0; i < nrows; i++) {
01439             
01440             /* Clipping criteria */
01441 
01442             if (ellipticity[i] < elllim && core_flux[i] < blim && 
01443                 core_flux[i] > flim && 
01444                 fabs(dc[i] - *medval) < 3.0*(*sigma) && 
01445                 cls[i] == -1.0 && sig[i] < 5.0 &&
01446                 xpos[i] >= xmin && xpos[i] <= xmax && ypos[i] >= ymin &&
01447                 ypos[i] <= ymax && areal[0][i] >= pixlim) {
01448                 if (iloop > 0 || (iloop == 0 && dc[i] >= 0.0)) {
01449                     work[n++] = dc[i];
01450                 }
01451             }
01452         }
01453 
01454         /* Sort the work array and find the median and sigma */
01455 
01456         if (n > 0) {
01457             sort1(work,n);
01458             if (iloop == 0) {
01459                 anhist(work,n,medval,sigma);
01460                 *sigma = 1.48*(*medval - work[(int)(0.25*(float)(n+3))-1]);
01461                 *sigma = max(0.025,*sigma);
01462             } else {
01463                 medstat(work,n,medval,&sigmanew);
01464                 *sigma = min(*sigma,sigmanew);
01465                 *sigma = max(0.01,*sigma);
01466             }
01467         } else {
01468             *medval = 0.0;
01469             *sigma = 0.01;
01470         }
01471 
01472         /* Just in case... */
01473 
01474         *sigma = max(*sigma,0.01);
01475     }
01476 
01477     /* Tidy and exit */
01478 
01479     free(work);
01480     free(dc);
01481 }
01482 
01483 /*---------------------------------------------------------------------------*/
01500 /*---------------------------------------------------------------------------*/
01501 
01502 static void classstats_final(void) {
01503     int n,i,iloop,iarg,ii,iend,ncls,kk,k;
01504     float *work,ell,core,sig1,sig2,sig3,denom,w1,w2,w3,core_small;
01505     float core_large,*statistic,core_midd,pkht,xcor,cfit,csig;
01506     float *work1,junk,corlim1,corval1,corlim2,corval2,sigmaold;
01507 
01508     /* Initialise */
01509 
01510     sigma_final = 1.0e6;
01511     fit_final = 0.0;
01512     ncls = 0;
01513 
01514     /* Get some workspace */
01515 
01516     work = cpl_malloc(nrows*sizeof(float));
01517     work1 = cpl_malloc(nrows*sizeof(float));
01518     statistic = cpl_malloc(nrows*sizeof(float));
01519 
01520     /* Calculate the statistic now */
01521 
01522     for (i = 0; i < nrows; i++) {
01523         ell = ellipticity[i];
01524         pkht = peak_mag[i];
01525         core = core_flux[i];
01526         iarg = vircam_nint(10.0*(core - 5.0));
01527         iarg = max(1,min(NSAMPLE,iarg)) - 1;
01528         if (! poor) {
01529             sig1 = max(0.01,(fit1 - lower1[iarg])/3.0);
01530             sig2 = max(0.01,(fit2 - lower2[iarg])/3.0);
01531         } else {
01532             sig1 = max(0.01,(fit4 - lower1[iarg])/3.0);
01533             sig2 = max(0.01,(fit5 - lower2[iarg])/3.0);
01534         }
01535         sig3 = max(0.01,(fit3 - lower3[iarg])/3.0);
01536         denom = (wt1/sig1 + wt2/sig2 + wt3/sig3);
01537         w1 = (wt1/sig1)/denom;
01538         w2 = (wt2/sig2)/denom;
01539         w3 = (wt3/sig3)/denom;
01540         if (! poor) {
01541             core_small = core1_flux[i];
01542             core_large = core3_flux[i];
01543             statistic[i] = (core - core_small - fit1)*w1 + 
01544                 (core_large - core - fit2)*w2 + (core - pkht - fit3)*w3;
01545         } else {
01546             core_midd = core2_flux[i];
01547             core_large = core4_flux[i];
01548             statistic[i] = (core_midd - core - fit4)*w1 +
01549                 (core_large - core - fit5)*w2 + (core - pkht - fit3)*w3;
01550         }
01551     }
01552 
01553     /* Iteration loop.  Use only lower ellipticity images and relevant
01554        peak height range */
01555 
01556     for (iloop = 0; iloop < MAXLOOP; iloop++) {
01557         sigmaold = sigma_final;
01558         n = 0;
01559         for (i = 0; i < nrows ; i++) {
01560 
01561             ell = ellipticity[i];
01562             core = core_flux[i];
01563             if (ell < elllim && core < blim && core > flim && 
01564                 fabs((double)(statistic[i] - fit_final)) < 3.0*sigma_final &&
01565                 areal[0][i] >= pixlim)
01566                 work[n++] = statistic[i];
01567 
01568             /* This information is to be used later to find the curvature of 
01569                saturated region */
01570 
01571             if (core > corlim && iloop == MAXLOOP-2) {
01572                 cls[ncls] = statistic[i];
01573                 sig[ncls++] = core;
01574             }
01575         }
01576 
01577         /* Median defines general fit */
01578 
01579         if (n > 2) {
01580             sort1(work,n);
01581             if (iloop == 0 && n > 10) {
01582                 anhist(work,n,&fit_final,&sigma_final);
01583             } else {
01584                 medstat(work,n,&fit_final,&sigma_final);
01585             }
01586             sigma_final = max(0.01,min(sigmaold,sigma_final));
01587         } else {
01588             fit_final = 0.0;
01589             sigma_final = 0.01;
01590         }
01591     }
01592 
01593     /* Now work out the curvature in the saturated region */
01594 
01595     sort2(sig,cls,ncls);
01596     ii = 0;
01597     xcor = 12.5;
01598     iend = 0;
01599     i = -1;
01600     corlim1 = 0.0;
01601     corlim2 = 0.0;
01602     corval1 = 0.0;
01603     corval2 = 0.0;
01604     while (iend == 0 && i < ncls-1) {
01605         i++;
01606         if (sig[i] > xcor+0.25 && ii >= 3) {
01607             medstat(work,ii,&cfit,&csig);
01608             for (iloop = 0; iloop < 3; iloop++) {
01609                 kk = 0;
01610                 for (k = 0; k < ii; k++) {
01611                     if (work[k] <= cfit + 3.0*csig)
01612                         work1[kk++] = work[k];
01613                 }
01614                 medstat(work1,kk,&cfit,&junk);
01615             }
01616             if (cfit <= fit_final + 3.0*sigma_final) {
01617                 corlim1 = xcor;
01618                 corval1 = cfit;
01619             } else {
01620                 corlim2 = xcor;
01621                 corval2 = cfit;
01622                 iend = 1;
01623             }
01624         } else {
01625             work[ii++] = cls[i];
01626         }
01627     }
01628 
01629     /* Estimate where core measure and statistic become unreliable */
01630 
01631     if (iend == 1) 
01632         corlim = corlim2 - 0.5*(corval2 - fit_final - 3.0*sigma_final)/(corval2 - corval1);
01633     else 
01634         corlim = corlim1;
01635     corlim = max(cormin,corlim);
01636     kk = 0;
01637     for (i = 0; i < nrows; i++) {
01638         core = core_flux[i];
01639         if (core >= corlim)
01640             work[kk++] = peak_height[i] + skylevel;
01641     }
01642     if (kk > 0) {
01643         medstat(work,kk,&avsat,&junk);
01644         avsat = max(10000.0+skylevel,avsat);
01645     } else {
01646         avsat = 10000.0 + skylevel;
01647     }
01648 
01649     /* Tidy and exit */
01650   
01651     freespace(work);
01652     freespace(work1);
01653     freespace(statistic);
01654 }
01655 
01656 /*---------------------------------------------------------------------------*/
01681 /*---------------------------------------------------------------------------*/
01682 
01683 static void medstat(float *array, int n, float *medval, float *sigval) {
01684     int lev1,lev2,lev3;
01685 
01686     /* Sort the array first, then choose the median.  The sigma is defined
01687        as half the distance between the two quartile points multiplied by
01688        the appropriate scaling factor (1.48) */
01689 
01690     if (n == 0) {
01691         *medval = 0.0;
01692         *sigval = 0.0;
01693         return;
01694     }
01695     sort1(array,n);
01696     lev1 = (n + 1)/2;
01697     lev2 = (3*n + 3)/4;
01698     lev3 = (n + 3)/4;
01699     *medval = array[lev1-1];
01700     *sigval = 1.48*0.5*(array[lev2-1] - array[lev3-1]);
01701 }
01702 
01703 /*---------------------------------------------------------------------------*/
01722 /*---------------------------------------------------------------------------*/
01723 
01724 static void sort1(float *a, int n) {
01725     int iii,ii,i,ifin,j;
01726     float b;
01727 
01728     iii = 4;
01729     while (iii < n)
01730         iii *= 2;
01731     iii = min(n,(3*iii)/4 - 1);
01732 
01733     while (iii > 1) {
01734         iii /= 2;
01735         ifin = n - iii;
01736         for (ii = 0; ii < ifin; ii++) {
01737             i = ii;
01738             j = i + iii;
01739             if (a[i] > a[j]) {
01740                 b = a[j];
01741                 while (1) {
01742                     a[j] = a[i];
01743                     j = i;
01744                     i = i - iii;
01745                     if (i < 0 || a[i] <= b) 
01746                         break;
01747                 }
01748                 a[j] = b;
01749             }
01750         }
01751     }
01752 }
01753 
01754 /*---------------------------------------------------------------------------*/
01776 /*---------------------------------------------------------------------------*/
01777 
01778 static void sort2(float *a1, float *a2, int n) {
01779     int iii,ii,i,ifin,j;
01780     float b1,b2;
01781 
01782     iii = 4;
01783     while (iii < n)
01784         iii *= 2;
01785     iii = min(n,(3*iii)/4 - 1);
01786 
01787     while (iii > 1) {
01788         iii /= 2;
01789         ifin = n - iii;
01790         for (ii = 0; ii < ifin; ii++) {
01791             i = ii;
01792             j = i + iii;
01793             if (a1[i] > a1[j]) {
01794                 b1 = a1[j];
01795                 b2 = a2[j];
01796                 while (1) {
01797                     a1[j] = a1[i];
01798                     a2[j] = a2[i];
01799                     j = i;
01800                     i = i - iii;
01801                     if (i < 0 || a1[i] <= b1) 
01802                         break;
01803                 }
01804                 a1[j] = b1;
01805                 a2[j] = b2;
01806             }
01807         }
01808     }
01809 }
01810 
01813 /*
01814 
01815 $Log: classify.c,v $
01816 Revision 1.19  2012/01/15 17:40:09  jim
01817 Minor modifications to take into accout the changes in cpl API for v6
01818 
01819 Revision 1.18  2012/01/04 08:57:42  jim
01820 fixed ap0 and ap67 routines to provide sensible lower limits for sigmas
01821 
01822 Revision 1.17  2011/02/01 15:33:35  jim
01823 Fixed mistaken column ID
01824 
01825 Revision 1.16  2011/02/01 10:06:35  jim
01826 tweaked a few parameters to bring it in line with the standard version
01827 
01828 Revision 1.15  2011/01/31 15:02:38  jim
01829 Mods to re-calculate the saturation limit
01830 
01831 Revision 1.14  2011/01/21 10:59:07  jim
01832 Modified to calculate all aperture corrections directly. Many small mods
01833 to make sure this is in synch with the standard version
01834 
01835 Revision 1.13  2010/12/09 13:24:32  jim
01836 Added classstats_pa to work out median position angle
01837 
01838 Revision 1.12  2010/09/09 12:09:57  jim
01839 Added docs
01840 
01841 Revision 1.11  2010/01/31 18:58:17  jim
01842 Fixed little bug in the columns that are read
01843 
01844 Revision 1.10  2009/11/18 21:03:50  jim
01845 Many small upgrades to bring it into line with the latest CASU version
01846 
01847 Revision 1.9  2007/05/02 09:11:34  jim
01848 Modified to allow for inclusion of table WCS keywords into FITS header
01849 
01850 Revision 1.8  2007/03/01 12:38:26  jim
01851 Small modifications after a bit of code checking
01852 
01853 Revision 1.7  2006/06/13 14:06:57  jim
01854 The classification and statistic data rows must come from the original table
01855 rather than the copy as they are being written to
01856 
01857 Revision 1.6  2006/05/26 15:00:36  jim
01858 Now makes a copy of the input table so that it doesn't muck up the column
01859 values
01860 
01861 Revision 1.5  2006/05/18 12:34:20  jim
01862 Fixed header keywords for input information
01863 
01864 Revision 1.4  2006/03/15 10:43:42  jim
01865 Fixed a few things
01866 
01867 Revision 1.3  2005/11/28 13:50:06  jim
01868 Touched up a few things to make splint happy
01869 
01870 Revision 1.2  2005/11/03 13:28:51  jim
01871 All sorts of changes to tighten up error handling
01872 
01873 Revision 1.1  2005/09/22 08:41:03  jim
01874 first entry
01875 
01876 
01877 */

Generated on 5 Mar 2013 for VIRCAM Pipeline by  doxygen 1.6.1