VIRCAM Pipeline  1.3.4
classify.c
1 /* $Id: classify.c,v 1.20 2013-10-15 16:18:38 jim Exp $
2  *
3  * This file is part of the VIRCAM Pipeline
4  * Copyright (C) 2005 Cambridge Astronomy Survey Unit
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19  */
20 
21 /*
22  * $Author: jim $
23  * $Date: 2013-10-15 16:18:38 $
24  * $Revision: 1.20 $
25  * $Name: not supported by cvs2svn $
26  */
27 
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <math.h>
31 #include <strings.h>
32 
33 #include <cpl.h>
34 #include <vircam_utils.h>
35 #include <vircam_pfits.h>
36 #include "classify.h"
37 
38 #define MAXHIST 111
39 #define STEP 0.05
40 #define NSAMPLE 150
41 #define MAXLOOP 5
42 #define BLIMDEF 15.0;
43 #define FLIMDEF 11.0;
44 #define CMINDEF 7.5
45 #define CMAXDEF 15.0
46 #define NAREAL 8
47 #define PI 3.14159265358979323846
48 #define DEGRAD 57.2957795130823229
49 
50 #define COREMAG(A,B,C) 2.5*log10((double)(max(C,A-B)))
51 #define MAX(A,B) (A > B ? A : B)
52 
53 /* Make the data arrays and header values global */
54 
55 static long nrows;
56 static float thresh,skylevel,skynoise,rcore,exptime;
57 
58 /* Derived values */
59 
60 static int poor;
61 static float sigell,fitell,elllim,sigellf,fitellf,sigpa,fitpa;
62 static float blim,flim,cmin,cmax;
63 static float fit1,fit2,fit3,fit4,fit5,fit6,fit7;
64 static float fit_final,sigma_final;
65 static float *lower1,*lower2,*lower3,*upper1,*upper2,*upper3,*uppere;
66 static float avsig1,avsig2,avsig3,wt1,wt2,wt3;
67 
68 /* Classification values */
69 
70 static int nstar,ngal,njunk,ncmp;
71 
72 /* Values for the data quality and aperture corrections */
73 
74 static float avsat,corlim,cormin,apcpkht,apcor,apcor1,apcor2,apcor3,apcor4;
75 static float apcor5,apcor6,apcor7;
76 
77 /* Data arrays */
78 
79 static float *workspace = NULL;
80 static cpl_table *catcopy = NULL;
81 static float *areal[NAREAL];
82 static float *core_flux,*core1_flux,*core2_flux,*core3_flux,*core4_flux;
83 static float *core5_flux,*peak_height,*peak_mag,*ellipticity,*iso_flux;
84 static float *total_flux,*cls,*sig,*xpos,*ypos,*pa,*core6_flux,*skylev;
85 
86 
87 /* Column definitions */
88 
89 #define NCOL32 14
90 #define NCOL80 15
91 
92 static const char *cols32[NCOL32] = {"Core_flux","Core1_flux","Core2_flux",
93  "Core3_flux","Core4_flux","Peak_height",
94  "Ellipticity","Isophotal_flux",
95  "Total_flux","Core5_flux","X_coordinate",
96  "Y_coordinate","Position_angle",
97  "Skylev"};
98 
99 static const char *cols80[NCOL80] = {"Aper_flux_3","Aper_flux_1","Aper_flux_4",
100  "Aper_flux_5","Aper_flux_6","Peak_height",
101  "Ellipticity","Isophotal_flux",
102  "Isophotal_flux","Aper_flux_7",
103  "X_coordinate","Y_coordinate",
104  "Position_angle","Sky_level",
105  "Aper_flux_2"};
106 
107 static int ncols;
108 static float xmin;
109 static float xmax;
110 static float ymin;
111 static float ymax;
112 static float pixlim;
113 
114 #define FRAMECUT 0.05
115 
116 /* Subroutine prototypes */
117 
118 static void anhist(float *, int, float *, float *);
119 static void boundaries(float *, float *, float *, float, float, float, float,
120  int, float, float, float *, float *, float *, float *);
121 static void boundpk(float *, float *, float, float, float *, float *,
122  float *, float *);
123 static void classify_run(void);
124 static void classstats(float *, float *, int, float, float *, float *);
125 static void classstats_ap0(float *, float *);
126 static void classstats_ap67(float *, float *, float *, float *);
127 static void classstats_el(void);
128 static void classstats_pa(void);
129 static void classstats_ellf(float);
130 static void classstats_final(void);
131 static void medstat(float *, int, float *, float *);
132 static void sort1(float *, int);
133 static void sort2(float *, float *, int);
134 
137 /*---------------------------------------------------------------------------*/
202 /*---------------------------------------------------------------------------*/
203 
204 extern int classify(vir_tfits *catalogue, cpl_propertylist *plist,
205  float minsize, int cattype) {
206  float fwhm,*work,moff;
207  float pkht,ell,core,ap,delap,area,junk,arg;
208  char *cols[MAX(NCOL32,NCOL80)],colname[32];
209  cpl_propertylist *extra;
210  cpl_table *cat;
211  const char *fctid = "vircam_classify";
212  int i,n,iap,i1,i2,nxout,nyout;
213 
214  /* Get some DQC info from the extra propertylist generated by imcore */
215 
216  extra = vircam_tfits_get_ehu(catalogue);
217  thresh = cpl_propertylist_get_float(extra,"ESO DRS THRESHOL");
218  skylevel = cpl_propertylist_get_float(extra,"ESO QC MEAN_SKY");
219  skynoise = cpl_propertylist_get_float(extra,"ESO QC SKY_NOISE");
220  rcore = cpl_propertylist_get_float(extra,"ESO DRS RCORE");
221  fwhm = cpl_propertylist_get_float(extra,"ESO DRS SEEING");
222  nxout = cpl_propertylist_get_int(extra,"ESO DRS NXOUT");
223  nyout = cpl_propertylist_get_int(extra,"ESO DRS NYOUT");
224  xmin = FRAMECUT*(float)nxout;
225  xmax = (1.0 - FRAMECUT)*(float)nxout;
226  ymin = FRAMECUT*(float)nyout;
227  ymax = (1.0 - FRAMECUT)*(float)nyout;
228  pixlim = minsize;
229 
230  /* Get the exposure time */
231 
232  if (vircam_pfits_get_exptime(plist,&exptime) != VIR_OK) {
233  cpl_msg_warning(fctid,"Unable to get expsoure time!");
234  exptime = 10.0;
235  }
236 
237  /* Get the number of columns and decide which column labels to use */
238 
239  cat = vircam_tfits_get_table(catalogue);
240  ncols = cpl_table_get_ncol(cat);
241  switch (cattype) {
242  case 1:
243  for (i = 0; i < NCOL32; i++)
244  cols[i] = (char *)cols32[i];
245  break;
246  case 2:
247  for (i = 0; i < NCOL80; i++)
248  cols[i] = (char *)cols80[i];
249  break;
250  case 6:
251  for (i = 0; i < NCOL80; i++)
252  cols[i] = (char *)cols80[i];
253  break;
254  default:
255  cpl_msg_error(fctid,"Don't recognise catalogues with %" CPL_SIZE_FORMAT " columns: cattype == %" CPL_SIZE_FORMAT,(cpl_size)ncols,(cpl_size)cattype);
256  return(VIR_FATAL);
257  }
258 
259  /* Make a copy of the table as you are going to muck about with the
260  column values. Get the column data */
261 
262  catcopy = cpl_table_duplicate(cat);
263  nrows = cpl_table_get_nrow(cat);
264  core_flux = cpl_table_get_data_float(catcopy,cols[0]);
265  core1_flux = cpl_table_get_data_float(catcopy,cols[1]);
266  core2_flux = cpl_table_get_data_float(catcopy,cols[2]);
267  core3_flux = cpl_table_get_data_float(catcopy,cols[3]);
268  core4_flux = cpl_table_get_data_float(catcopy,cols[4]);
269  peak_height = cpl_table_get_data_float(catcopy,cols[5]);
270  ellipticity = cpl_table_get_data_float(catcopy,cols[6]);
271  iso_flux = cpl_table_get_data_float(catcopy,cols[7]);
272  total_flux = cpl_table_get_data_float(catcopy,cols[8]);
273  core5_flux = cpl_table_get_data_float(catcopy,cols[9]);
274  xpos = cpl_table_get_data_float(catcopy,cols[10]);
275  ypos = cpl_table_get_data_float(catcopy,cols[11]);
276  pa = cpl_table_get_data_float(catcopy,cols[12]);
277  skylev = cpl_table_get_data_float(catcopy,cols[13]);
278  if (cattype == 2 || cattype == 6)
279  core6_flux = cpl_table_get_data_float(catcopy,cols[14]);
280  else
281  core6_flux = NULL;
282  cls = cpl_table_get_data_float(cat,"Classification");
283  sig = cpl_table_get_data_float(cat,"Statistic");
284 
285  /* Get some workspace */
286 
287  workspace = cpl_malloc(2*nrows*sizeof(float));
288  peak_mag = workspace;
289  work = workspace + nrows;
290 
291  /* Convert fluxes to "magnitudes" */
292 
293  for (i = 0; i < nrows; i++) {
294  core_flux[i] = COREMAG(core_flux[i],0.0,1.0);
295  core1_flux[i] = COREMAG(core1_flux[i],0.0,1.0);
296  core2_flux[i] = COREMAG(core2_flux[i],0.0,1.0);
297  core3_flux[i] = COREMAG(core3_flux[i],0.0,1.0);
298  core4_flux[i] = COREMAG(core4_flux[i],0.0,1.0);
299  core5_flux[i] = COREMAG(core5_flux[i],0.0,1.0);
300  moff = 1.0/(1.0 - pow((thresh/MAX(peak_height[i],thresh)),0.6));
301  iso_flux[i] = COREMAG(moff*iso_flux[i],0.0,1.0);
302  peak_mag[i] = COREMAG(peak_height[i],skynoise,0.1);
303  }
304  if (core6_flux != NULL)
305  for (i = 0; i < nrows; i++)
306  core6_flux[i] = COREMAG(core6_flux[i],0.0,1.0);
307  if (ncols == 32)
308  for (i = 0; i < nrows; i++)
309  total_flux[i] = COREMAG(total_flux[i],0.0,1.0);
310 
311  /* Now get the areal profile information. You'll need this in a sec */
312 
313  for (i = 0; i < NAREAL; i++) {
314  sprintf(colname,"Areal_%d_profile",i+1);
315  areal[i] = cpl_table_get_data_float(catcopy,colname);
316  }
317 
318  /* What is the seeing like? */
319 
320  poor = 0;
321  if (fwhm > max(5.0,rcore*sqrt(2.0)))
322  poor = 1;
323 
324  /* Ok, now call the routine that does all the work */
325 
326  classify_run();
327 
328  /* Right, now get a better estimate of the seeing */
329 
330  n = 0;
331  for (i = 0; i < nrows; i++) {
332  pkht = peak_height[i];
333  ell = ellipticity[i];
334  core = core_flux[i];
335  if (cls[i] == -1.0 && ell < elllim && core < corlim &&
336  pkht > 10.0*thresh) {
337  ap = log(0.5*pkht/thresh)/log(2.0) + 1.0;
338  iap = (int)ap;
339  delap = ap - (float)iap;
340  if (iap > 0 && iap < NAREAL && areal[1][i] > 0.0) {
341  i1 = (iap-1)*nrows + i;
342  i2 = iap*nrows + i;
343  area = areal[iap-1][i]*(1.0 - delap) + areal[iap][i]*delap;
344  work[n++] = 2.0*sqrt(area/PI);
345  }
346  }
347  }
348  if (n > 2) {
349  medstat(work,n,&fwhm,&junk);
350 
351  /* Allow for finite pixel size */
352 
353  arg = 0.25*PI*fwhm*fwhm - 1;
354  fwhm = 2.0*sqrt(max(0.0,arg/PI));
355 
356  } else
357  fwhm = -1.0;
358 
359  /* Tidy up a bit */
360 
361  freespace(workspace);
362  freetable(catcopy);
363 
364  /* Write header results into extra property list. First the QC */
365 
366  cpl_propertylist_update_float(extra,"ESO QC IMAGE_SIZE",fwhm);
367  cpl_propertylist_set_comment(extra,"ESO QC IMAGE_SIZE",
368  "[pixels] Average FWHM of stellar objects");
369  cpl_propertylist_update_float(extra,"ESO QC ELLIPTICITY",fitell);
370  cpl_propertylist_set_comment(extra,"ESO QC ELLIPTICITY",
371  "Average stellar ellipticity (1-b/a)");
372  cpl_propertylist_update_float(extra,"ESO QC POSANG",fitpa);
373  cpl_propertylist_set_comment(extra,"ESO QC POSANG",
374  "[degrees] Median position angle");
375  switch (cattype) {
376  case 1:
377  cpl_propertylist_update_float(extra,"ESO QC APERTURE_CORR",apcor);
378  cpl_propertylist_set_comment(extra,"ESO QC APERTURE_CORR",
379  "Stellar ap-corr 1x core flux");
380  break;
381  case 2:
382  cpl_propertylist_update_float(extra,"ESO QC APERTURE_CORR",apcor3);
383  cpl_propertylist_set_comment(extra,"ESO QC APERTURE_CORR",
384  "Stellar ap-corr 1x core flux");
385  break;
386  case 6:
387  cpl_propertylist_update_float(extra,"ESO QC APERTURE_CORR",apcor3);
388  cpl_propertylist_set_comment(extra,"ESO QC APERTURE_CORR",
389  "Stellar ap-corr 1x core flux");
390  break;
391  }
392  cpl_propertylist_update_int(extra,"ESO QC NOISE_OBJ",njunk);
393  cpl_propertylist_set_comment(extra,"ESO QC NOISE_OBJ",
394  "Number of noise objects");
395  cpl_propertylist_update_float(extra,"ESO QC SATURATION",avsat);
396 
397  /* Now some helpful DRS keywords */
398 
399  cpl_propertylist_update_bool(extra,"ESO DRS CLASSIFD",1);
400  cpl_propertylist_set_comment(extra,"ESO DRS CLASSIFD",
401  "Catalogue has been classified");
402 
403  /* Now the aperture correction keywords */
404 
405  switch (cattype) {
406  case 1:
407  cpl_propertylist_update_float(extra,"APCORPK",apcpkht);
408  cpl_propertylist_set_comment(extra,"APCORPK","Stellar aperture correction - peak height");
409  cpl_propertylist_update_float(extra,"APCOR1",apcor1);
410  cpl_propertylist_set_comment(extra,"APCOR1","Stellar aperture correction - 1/2x core flux");
411  cpl_propertylist_update_float(extra,"APCOR",apcor);
412  cpl_propertylist_set_comment(extra,"APCOR","Stellar aperture correction - 1x core flux");
413  cpl_propertylist_update_float(extra,"APCOR2",apcor2);
414  cpl_propertylist_set_comment(extra,"APCOR2","Stellar aperture correction - sqrt(2)x core flux");
415  cpl_propertylist_update_float(extra,"APCOR3",apcor3);
416  cpl_propertylist_set_comment(extra,"APCOR3","Stellar aperture correction - 2x core flux");
417  cpl_propertylist_update_float(extra,"APCOR4",apcor4);
418  cpl_propertylist_set_comment(extra,"APCOR4","Stellar aperture correction - 2*sqrt(2)x core flux");
419  cpl_propertylist_update_float(extra,"APCOR5",apcor5);
420  cpl_propertylist_set_comment(extra,"APCOR5","Stellar aperture correction - 4x core flux");
421  break;
422  case 2:
423  cpl_propertylist_update_float(extra,"APCORPK",apcpkht);
424  cpl_propertylist_set_comment(extra,"APCORPK","Stellar aperture correction - peak height");
425  cpl_propertylist_update_float(extra,"APCOR1",apcor1);
426  cpl_propertylist_set_comment(extra,"APCOR1","Stellar aperture correction - 1/2x core flux");
427  cpl_propertylist_update_float(extra,"APCOR2",apcor2);
428  cpl_propertylist_set_comment(extra,"APCOR2","Stellar aperture correction - core/sqrt(2) flux");
429  cpl_propertylist_update_float(extra,"APCOR3",apcor3);
430  cpl_propertylist_set_comment(extra,"APCOR3","Stellar aperture correction - 1x core flux");
431  cpl_propertylist_update_float(extra,"APCOR4",apcor4);
432  cpl_propertylist_set_comment(extra,"APCOR4","Stellar aperture correction - sqrt(2)x core flux");
433  cpl_propertylist_update_float(extra,"APCOR5",apcor5);
434  cpl_propertylist_set_comment(extra,"APCOR5","Stellar aperture correction - 2x core flux");
435  cpl_propertylist_update_float(extra,"APCOR6",apcor6);
436  cpl_propertylist_set_comment(extra,"APCOR6","Stellar aperture correction - 2*sqrt(2)x core flux");
437  cpl_propertylist_update_float(extra,"APCOR7",apcor7);
438  cpl_propertylist_set_comment(extra,"APCOR7","Stellar aperture correction - 4x core flux");
439  break;
440  case 6:
441  cpl_propertylist_update_float(extra,"APCORPK",apcpkht);
442  cpl_propertylist_set_comment(extra,"APCORPK","Stellar aperture correction - peak height");
443  cpl_propertylist_update_float(extra,"APCOR1",apcor1);
444  cpl_propertylist_set_comment(extra,"APCOR1","Stellar aperture correction - 1/2x core flux");
445  cpl_propertylist_update_float(extra,"APCOR2",apcor2);
446  cpl_propertylist_set_comment(extra,"APCOR2","Stellar aperture correction - core/sqrt(2) flux");
447  cpl_propertylist_update_float(extra,"APCOR3",apcor3);
448  cpl_propertylist_set_comment(extra,"APCOR3","Stellar aperture correction - 1x core flux");
449  cpl_propertylist_update_float(extra,"APCOR4",apcor4);
450  cpl_propertylist_set_comment(extra,"APCOR4","Stellar aperture correction - sqrt(2)x core flux");
451  cpl_propertylist_update_float(extra,"APCOR5",apcor5);
452  cpl_propertylist_set_comment(extra,"APCOR5","Stellar aperture correction - 2x core flux");
453  cpl_propertylist_update_float(extra,"APCOR6",apcor6);
454  cpl_propertylist_set_comment(extra,"APCOR6","Stellar aperture correction - 2*sqrt(2)x core flux");
455  cpl_propertylist_update_float(extra,"APCOR7",apcor7);
456  cpl_propertylist_set_comment(extra,"APCOR7","Stellar aperture correction - 4x core flux");
457  break;
458  }
459 
460  /* Write header information to help GAIA */
461 
462  cpl_propertylist_update_string(extra,"SYMBOL1","{Ellipticity Position_angle Areal_1_profile Classification} {el");
463  cpl_propertylist_update_string(extra,"SYMBOL2","lipse blue (1.0-$Ellipticity) $Position_angle+90 {} $Classific");
464  cpl_propertylist_update_string(extra,"SYMBOL3","ation==1} {sqrt($Areal_1_profile*(1.0-$Ellipticity)/3.142)} : {");
465  cpl_propertylist_update_string(extra,"SYMBOL4","Ellipticity Position_angle Areal_1_profile Classification} {el");
466  cpl_propertylist_update_string(extra,"SYMBOL5","lipse red (1.0-$Ellipticity) $Position_angle+90 {} $Classific");
467  cpl_propertylist_update_string(extra,"SYMBOL6","ation==-1} {sqrt($Areal_1_profile*(1.0-$Ellipticity)/3.142)} :");
468  cpl_propertylist_update_string(extra,"SYMBOL7","{Ellipticity Position_angle Areal_1_profile Classification} {el");
469  cpl_propertylist_update_string(extra,"SYMBOL8","lipse green (1.0-$Ellipticity) $Position_angle+90 {} $Classifi");
470  cpl_propertylist_update_string(extra,"SYMBOL9","cation==0} {sqrt($Areal_1_profile*(1.0-$Ellipticity)/3.142)}");
471 
472  /* Get out of here */
473 
474  return(VIR_OK);
475 }
476 
477 /*---------------------------------------------------------------------------*/
503 /*---------------------------------------------------------------------------*/
504 
505 static void anhist(float *data, int n, float *medval, float *sigma) {
506  int i,*histo,ilev,imax,ismax;
507  float *sval,hmax,smax,hlim,ratio;
508 
509  /* Get some workspace for the histogram */
510 
511  histo = cpl_calloc(MAXHIST,sizeof(int));
512  sval = cpl_calloc(MAXHIST,sizeof(float));
513 
514  /* Sort data into the histogram */
515 
516  for (i = 0; i < n; i++) {
517  ilev = vircam_nint(data[i]/STEP);
518  if (ilev >= -10 && ilev <= 100) {
519  ilev += 10;
520  histo[ilev] += 1;
521  }
522  }
523 
524  /* Now find the maximum of the histogram and its position... */
525 
526  hmax = 0.0;
527  imax = 0;
528  for (i = 0; i < MAXHIST; i++) {
529  if (histo[i] > hmax) {
530  hmax = (float)histo[i];
531  imax = i;
532  }
533  }
534 
535  /* Trap for hmax == 0 */
536 
537  if (hmax == 0.0) {
538  if (n >= 10) {
539  *medval = data[(n+1)/2-1];
540  *sigma = 1.48*0.5*(data[(3*n+3)/4-1] - data[(n+3)/4-1]);
541  } else {
542  *medval = 0.0;
543  *sigma = 1.0;
544  }
545  return;
546  }
547 
548  /* Now do three point running average to see if there are other local
549  maxima */
550 
551  smax = 0.0;
552  ismax = 0;
553  for (i = 1; i < MAXHIST-1; i++) {
554  sval[i] = (histo[i-1] + histo[i] + histo[i+1])/3.0;
555  if (sval[i] > smax) {
556  smax = sval[i];
557  ismax = i;
558  }
559  }
560  if (ismax < imax) {
561  imax = ismax;
562  hmax = (float)histo[imax];
563  }
564 
565  /* Now check for lower local maxima */
566 
567  for (i = imax-1; i > 0; i--) {
568  if (sval[i] >= sval[i+1] && sval[i] >= sval[i-1]) {
569  if (sval[i] > 0.5*smax)
570  ismax = i;
571  }
572  }
573  if (ismax < imax) {
574  imax = ismax;
575  hmax = (float)histo[imax];
576  }
577 
578  /* Now work out where the peak is */
579 
580  *medval = min((float)(imax-10)*STEP,data[(n+1)/2-1]);
581  hlim = vircam_nint(0.5*hmax);
582  i = 1;
583  while (histo[imax-i] > hlim && imax-i > 1)
584  i++;
585  ratio = hmax/max(1.0,(float)histo[imax-i]);
586  *sigma = (float)i*STEP/(sqrt(2.0)*max(1.0,log(ratio)));
587  *sigma = max(*sigma,0.5*STEP);
588 
589  /* Tidy and exit */
590 
591  freespace(histo);
592  freespace(sval);
593 }
594 
595 /*---------------------------------------------------------------------------*/
634 /*---------------------------------------------------------------------------*/
635 
636 static void boundaries(float *core1, float *core2, float *core3, float medval1,
637  float sigma1, float medval2, float sigma2, int small,
638  float area1, float area2, float *wt, float *avsig,
639  float *lower, float *upper) {
640  int i,n;
641  float c1,c2,dc,*work,xnoise,xmag,xflux,ratio,asign,junk;
642 
643  /* Get a workspace */
644 
645  work = cpl_malloc(nrows*sizeof(float));
646 
647  /* Initialise the lower boundary */
648 
649  lower[0] = cmin;
650  lower[1] = cmax;
651  asign = ((small == 1) ? -1.0 : 1.0);
652 
653  /* Now collect the data */
654 
655  n = 0;
656  for (i = 0; i < nrows; i++) {
657  c1 = core1[i];
658  if (! poor) {
659  c2 = core2[i];
660  dc = asign*(c2 - c1);
661  if (dc > medval1 - 3.0*sigma1 && c1 < blim - 3.0)
662  work[n++] = dc - medval1;
663  } else {
664  c2 = core3[i];
665  dc = c2 - c1;
666  if (dc > medval2 - 3.0*sigma2 && c1 < blim - 3.0)
667  work[n++] = dc - medval2;
668  }
669  }
670 
671  /* Find the median */
672 
673  medstat(work,n,avsig,&junk);
674  freespace(work);
675 
676  /* Work out sigma levels for both types of seeing */
677 
678  if (! poor) {
679  *wt = min(5.0,max(1.0,*avsig/sigma1));
680  xnoise = sqrt(area1)*skynoise;
681  } else {
682  *wt = min(2.5,max(1.0,*avsig/sigma2));
683  xnoise = sqrt(area2)*skynoise;
684  }
685 
686  /* Now work out the boundaries */
687 
688  for (i = 0; i < NSAMPLE; i++) {
689  xmag = 5.0 + (float)(i+1)*0.1;
690  xflux = pow(10.0,(double)(0.4*xmag));
691  ratio = COREMAG(1.0+xnoise/xflux,0.0,0.0);
692  if (! poor) {
693  lower[i] = medval1 - 3.0*sqrt(sigma1*sigma1 + ratio*ratio);
694  upper[i] = medval1 + 3.0*sqrt(sigma1*sigma1 + 0.5*ratio*ratio);
695  } else {
696  lower[i] = medval2 - 3.0*sqrt(sigma2*sigma2 + ratio*ratio);
697  upper[i] = medval2 + 3.0*sqrt(sigma2*sigma2 + 0.5*ratio*ratio);
698  }
699  }
700  upper[0] = ((poor == 0) ? medval1 : medval2);
701  upper[1] = upper[0];
702 }
703 
704 /*---------------------------------------------------------------------------*/
735 /*---------------------------------------------------------------------------*/
736 
737 static void boundpk(float *core, float *pkht, float medval, float sigma,
738  float *wt, float *avsig, float *lower, float *upper) {
739  int i,n;
740  float c,p,*work,xnoise,xmag,pmag,xflux,pflux,ratio,junk;
741 
742  /* Get the space for the boundry lines and a workspace */
743 
744  work = cpl_malloc(nrows*sizeof(float));
745 
746  /* Collect the data */
747 
748  n = 0;
749  for (i = 0; i < nrows; i++) {
750  c = core[i];
751  p = pkht[i];
752  if (c - p > medval - 3.0*sigma && c < blim - 3.0)
753  work[n++] = c - p - medval;
754  }
755 
756  /* Find the median */
757 
758  medstat(work,n,avsig,&junk);
759  freespace(work);
760  *wt = min(5.0,max(1.0,*avsig/sigma));
761 
762  /* Now work out boundaries */
763 
764  xnoise = sqrt(PI*rcore*rcore)*skynoise;
765  for (i = 0; i < NSAMPLE; i++) {
766  xmag = 5.0 + (float)(i+1)*0.1;
767  pmag = xmag - medval;
768  xflux = pow(10.0,(double)(0.4*xmag));
769  pflux = pow(10.0,(double)(0.4*pmag));
770  ratio = 2.5*log10((double)(1.0+max(xnoise/xflux,skynoise/pflux)));
771  lower[i] = medval - 3.0*sqrt(sigma*sigma + ratio*ratio);
772  upper[i] = medval + 3.0*sqrt(sigma*sigma + 0.5*ratio*ratio);
773  }
774  upper[0] = medval;
775  upper[1] = upper[0];
776 }
777 
778 /*---------------------------------------------------------------------------*/
796 /*---------------------------------------------------------------------------*/
797 
798 static void classify_run() {
799  float fluxlim,ell,pk,pkht,core,sig1,sig2,sig3,denom,w1,w2,w3;
800  float core_small,core_large,core_midd,statistic,statcut,sigtot;
801  float fit0,sigma0,xnoise,xmag,ratio,xflux,ratell,ratscl,ellbound;
802  float *lower,*upper,sigma1,sigma2,sigma3,sigma4,sigma5,sigma6,sigma7;
803  float *work,avsatnew,junk;
804  int i,iarg,ii;
805 
806  /* Update faint limit to cope with short exposures */
807 
808  blim = BLIMDEF;
809  flim = FLIMDEF;
810  fluxlim = 2.5*log10((double)(5.0*sqrt(PI*rcore*rcore)*skynoise));
811  flim = min(flim,max(6.0,fluxlim+3.0));
812  corlim = min(blim,max(12.5,fluxlim+5.0));
813  cormin = min(blim,max(12.5,fluxlim+5.0));
814 
815  /* Work out min and max core flux */
816 
817  cmin = CMINDEF;
818  cmax = CMAXDEF;
819  for (i = 0; i < nrows; i++) {
820  xflux = core_flux[i];
821  cmin = min(cmin,xflux);
822  cmax = max(cmax,xflux);
823  }
824  cmin = max(fluxlim-0.5,cmin);
825  cmax += 0.1;
826  cmax = min(cmax,20.0);
827 
828  /* Work out ellipticity stats for likely stellar objects */
829 
830  classstats_el();
831 
832  /* Ok, get the classification statistics for each of the tests. First
833  the core flux vs 1/2*core flux */
834 
835  classstats(core_flux,core1_flux,1,0.2,&fit1,&sigma1);
836 
837  /* Core flux vs 2*core flux */
838 
839  classstats(core_flux,core3_flux,0,0.1,&fit2,&sigma2);
840 
841  /* Core flux vs sqrt(2)*core flux */
842 
843  classstats(core_flux,core2_flux,0,0.0,&fit4,&sigma4);
844 
845  /* Core flux vs 2*sqrt(2)*core flux */
846 
847  classstats(core_flux,core4_flux,0,0.1,&fit5,&sigma5);
848 
849  /* Core flux vs Peak height */
850 
851  classstats(core_flux,peak_mag,1,0.2,&fit3,&sigma3);
852 
853  /* Faint end ellipticity */
854 
855  classstats_ellf(fluxlim);
856 
857  /* Work out position angle stats for likely stellar objects */
858 
859  classstats_pa();
860 
861  /* Get workspace for the boundary arrays */
862 
863  lower1 = cpl_malloc(NSAMPLE*sizeof(float));
864  lower2 = cpl_malloc(NSAMPLE*sizeof(float));
865  lower3 = cpl_malloc(NSAMPLE*sizeof(float));
866  upper1 = cpl_malloc(NSAMPLE*sizeof(float));
867  upper2 = cpl_malloc(NSAMPLE*sizeof(float));
868  upper3 = cpl_malloc(NSAMPLE*sizeof(float));
869 
870  /* Right, work out the boundaries for the classification tests
871  First core vs sqrt(2)*core or core vs 0.5*core depending upon
872  the seeing */
873 
874  boundaries(core_flux,core1_flux,core2_flux,fit1,sigma1,fit4,sigma4,
875  1,PI*rcore*rcore,2.0*PI*rcore*rcore,&wt1,&avsig1,lower1,
876  upper1);
877 
878  /* Now core vs 2*core or core vs 2*sqrt(2)*core */
879 
880  boundaries(core_flux,core3_flux,core4_flux,fit2,sigma2,fit5,sigma5,
881  0,4.0*PI*rcore*rcore,8.0*PI*rcore*rcore,&wt2,&avsig2,lower2,
882  upper2);
883 
884  /* Now core vs peak height */
885 
886  boundpk(core_flux,peak_mag,fit3,sigma3,&wt3,&avsig3,lower3,upper3);
887 
888 
889  /* Do final classification statistics and find the saturation limit */
890 
891  classstats_final();
892 
893  /* Define final boundaries */
894 
895  lower = cpl_malloc(NSAMPLE*sizeof(float));
896  upper = cpl_malloc(NSAMPLE*sizeof(float));
897  uppere = cpl_malloc(NSAMPLE*sizeof(float));
898  xnoise = sqrt(PI*rcore*rcore)*skynoise;
899  ratell = xnoise/pow(10.0,0.4*(fluxlim+1.5));
900  ratell = COREMAG(1.0+ratell,0.0,0.0);
901  ratscl = (pow((fitellf + 2.0*sigellf - fitell),2.0) - 4.0*sigell*sigell)/(4.0*ratell*ratell);
902  ratscl = max(0.25,min(10.0,ratscl));
903  for (i = 0; i < NSAMPLE; i++) {
904  xmag = 5.0 + 0.1*(float)(i+1);
905  xflux = pow(10.0,0.4*xmag);
906  ratio = 2.5*log10(1.0+xnoise/xflux);
907  lower[i] = fit_final - 5.0*sqrt(sigma_final*sigma_final + ratio*ratio);
908  upper[i] = fit_final + sqrt(9.0*sigma_final*sigma_final + 0.0*ratio*ratio);
909  uppere[i] = fitell + 2.0*sqrt(sigell*sigell + ratscl*ratio*ratio);
910  uppere[i] = min(0.5,uppere[i]);
911  }
912  elllim = min(0.5,max(0.2,fitell+2.0*sigell));
913  fluxlim = 2.5*log10((double)(2.5*sqrt(PI*rcore*rcore)*skynoise));
914 
915  /* Ok, final classification loop now... */
916 
917  nstar = 0;
918  ngal = 0;
919  njunk = 0;
920  ncmp = 0;
921  for (i = 0; i < nrows; i++) {
922  ell = ellipticity[i];
923  pk = peak_height[i] + skylevel;
924  pkht = peak_mag[i];
925  core = core_flux[i];
926  iarg = vircam_nint(10.0*(core - 5.0));
927  iarg = max(1,min(NSAMPLE,iarg)) - 1;
928  if (! poor) {
929  sig1 = max(0.01,(fit1 - lower1[iarg])/3.0);
930  sig2 = max(0.01,(fit2 - lower2[iarg])/3.0);
931  } else {
932  sig1 = max(0.01,(fit4 - lower1[iarg])/3.0);
933  sig2 = max(0.01,(fit5 - lower2[iarg])/3.0);
934  }
935  sig3 = max(0.01,(fit3 - lower3[iarg])/3.0);
936  denom = (wt1/sig1 + wt2/sig2 + wt3/sig3);
937  w1 = (wt1/sig1)/denom;
938  w2 = (wt2/sig2)/denom;
939  w3 = (wt3/sig3)/denom;
940  if (! poor) {
941  core_small = core1_flux[i];
942  core_large = core3_flux[i];
943  statistic = (core - core_small - fit1)*w1 +
944  (max(-3.0*sig2,core_large - core - fit2))*w2 +
945  (core - pkht - fit3)*w3;
946  } else {
947  core_midd = core2_flux[i];
948  core_large = core4_flux[i];
949  statistic = (core_midd - core - fit4)*w1 +
950  (max(-3.0*sig2,core_large - core - fit5))*w2 +
951  (core - pkht - fit3)*w3;
952  }
953  cls[i] = -1.0;
954  statcut = upper[iarg] + 3.0*sigma_final*(exp(max(0.0,core-corlim+1.0)) - 1.0);
955  if (statistic >= statcut)
956  cls[i] = 1.0;
957  else if (statistic <= lower[iarg])
958  cls[i] = 0.0;
959 
960  /* Save distance from the stellar locus */
961 
962  sigtot = (fit_final - lower[iarg])/5.0;
963  sig[i] = (statistic - fit_final)/sigtot;
964 
965  /* Right, now here are lots of overrides for special circumstances */
966  /* Too spikey? -> junk */
967 
968  if (core - pkht - fit3 < -4.0*sig3)
969  cls[i] = 0.0;
970 
971  /* Elliptical star? -> compact */
972 
973  ellbound = max(elllim,uppere[iarg]);
974  if (ell > ellbound && cls[i] == -1.0 && core < flim && sig[i] > -2.0)
975  cls[i] = -2.0;
976 
977  /* Saturated? -> star */
978 
979  if (core > corlim && statistic >= lower[iarg])
980  cls[i] = -1.0;
981 
982  /* Too elliptical? -> junk */
983 
984  if (ell > 0.9 && core < corlim)
985  cls[i] = 0.0;
986 
987  /* Too faint? -> junk */
988 
989  if (core < fluxlim)
990  cls[i] = 0.0;
991 
992  /* Now count how many you have of each */
993 
994  if (cls[i] == -1.0)
995  nstar++;
996  else if (cls[i] == 1.0)
997  ngal++;
998  else if (cls[i] == -2.0)
999  ncmp++;
1000  else
1001  njunk++;
1002  }
1003 
1004  /* Do stats to get the aperture corrections */
1005 
1006  if (ncols == 80) {
1007  classstats_ap67(core5_flux,core3_flux,&fit6,&sigma6);
1008  classstats_ap67(core_flux,core6_flux,&fit7,&sigma7);
1009  fit6 += fit2;
1010  }
1011  classstats_ap0(&fit0,&sigma0);
1012  if (ncols == 80)
1013  fit0 = max(fit6,fit0);
1014  else
1015  fit0 = max(fit5,fit0);
1016  apcpkht = fit0 + fit3; /* pkht */
1017  switch (ncols) {
1018  case 32:
1019  apcor1 = fit0 + fit1; /* 0.5*core */
1020  apcor = fit0; /* core */
1021  apcor2 = fit0 - fit4; /* sqrt(2)*core */
1022  apcor3 = fit0 - fit2; /* 2*core */
1023  apcor4 = fit0 - fit5; /* 2*sqrt(2)*core */
1024  apcor5 = 0.0; /* 4*core */
1025  break;
1026  case 80:
1027  apcor1 = fit0 + fit1; /* 0.5*core */
1028  apcor2 = fit0 + fit7; /* 1/sqrt(2) * core */
1029  apcor3 = fit0; /* core */
1030  apcor4 = fit0 - fit4; /* core * sqrt(2) */
1031  apcor5 = fit0 - fit2; /* 2*core */
1032  apcor6 = fit0 - fit5; /* 2*sqrt(2)*core */
1033  apcor7 = fit0 - fit6; /* 4*core */
1034  break;
1035  }
1036 
1037  /* Now do a better job on the saturation */
1038 
1039  ii = 0;
1040  work = cpl_malloc(nrows*sizeof(float));
1041  for (i = 0; i < nrows; i++) {
1042  ell = ellipticity[i];
1043  core = core_flux[i];
1044  pkht = max(thresh,peak_height[i]) + skylev[i];
1045  if (((ell < elllim && core > flim && cls[i] == -1 && sig[i] >= 5.0 &&
1046  areal[0][i] >= pixlim) || pkht >= 0.9*avsat) && xpos[i] >= xmin &&
1047  xpos[i] <= xmax && ypos[i] >= ymin && ypos[i] <= ymax) {
1048  work[ii++] = pkht;
1049  }
1050  }
1051  if (ii > 0) {
1052  medstat(work,ii,&avsatnew,&junk);
1053  avsatnew = max(10000.0+skylevel,avsatnew);
1054  } else {
1055  avsatnew = 10000.0 + skylevel;
1056  }
1057  avsat = avsatnew;
1058  freespace(work);
1059 
1060  /* Ok, now get rid of some workspace */
1061 
1062  freespace(lower1);
1063  freespace(lower2);
1064  freespace(lower3);
1065  freespace(upper1);
1066  freespace(upper2);
1067  freespace(upper3);
1068  freespace(lower);
1069  freespace(upper);
1070  freespace(uppere);
1071 
1072 }
1073 
1074 /*---------------------------------------------------------------------------*/
1102 /*---------------------------------------------------------------------------*/
1103 
1104 static void classstats(float *core1, float *core2, int small, float cutlev,
1105  float *medval, float *sigma) {
1106 
1107  int i,iloop,n;
1108  float *work,*dc,sigmaold,amult;
1109 
1110  /* Initialise the output values to something stupid */
1111 
1112  *medval = 0.0;
1113  *sigma = 1.0e6;
1114  amult = (small == 1 ? -1.0 : 1.0);
1115 
1116  /* Get some workspace */
1117 
1118  work = cpl_malloc(nrows*sizeof(float));
1119  dc = cpl_malloc(nrows*sizeof(float));
1120 
1121  /* Work out differences */
1122 
1123  for (i = 0; i < nrows; i++)
1124  dc[i] = amult*(core2[i] - core1[i]);
1125 
1126  /* Do an iteration loop */
1127 
1128  for (iloop = 0; iloop < MAXLOOP; iloop++) {
1129  sigmaold = *sigma;
1130  n = 0;
1131 
1132  /* Ok, gather up all the stats */
1133 
1134  for (i = 0; i < nrows; i++) {
1135 
1136  /* Clipping criteria */
1137 
1138  if (ellipticity[i] < elllim && core1[i] < blim && core1[i] > flim &&
1139  fabs(dc[i] - *medval) < 3.0*(*sigma) &&
1140  xpos[i] >= xmin && xpos[i] <= xmax && ypos[i] >= ymin &&
1141  ypos[i] <= ymax && areal[0][i] >= pixlim) {
1142  if (iloop > 0 || (iloop == 0 && dc[i] >= cutlev))
1143  work[n++] = dc[i];
1144  }
1145  }
1146 
1147  /* Sort the work array and find the median and sigma */
1148 
1149  if (n > 0) {
1150  sort1(work,n);
1151  if (iloop == 0) {
1152  anhist(work,n,medval,sigma);
1153  } else {
1154  medstat(work,n,medval,sigma);
1155  *sigma = min(sigmaold,*sigma);
1156  }
1157  } else {
1158  *medval = 0.0;
1159  *sigma = 0.01;
1160  }
1161 
1162  /* Just in case... */
1163 
1164  *sigma = max(*sigma,0.01);
1165  }
1166 
1167  /* Tidy and exit */
1168 
1169  free(work);
1170  free(dc);
1171 }
1172 
1173 /*---------------------------------------------------------------------------*/
1188 /*---------------------------------------------------------------------------*/
1189 
1190 static void classstats_el(void) {
1191  int iloop,n,i;
1192  float *work;
1193 
1194  /* Initialise the mean and sigma to something stupid */
1195 
1196  sigell = 1.0e6;
1197  fitell = 0.0;
1198 
1199  /* Get some workspace */
1200 
1201  work = cpl_malloc(nrows*sizeof(float));
1202 
1203  /* Do iteration loop */
1204 
1205  for (iloop = 0; iloop < MAXLOOP; iloop++) {
1206  n = 0;
1207  for (i = 0; i < nrows; i++) {
1208  if (ellipticity[i] < 0.5 && core_flux[i] < blim &&
1209  core_flux[i] > flim &&
1210  fabs(ellipticity[i] - fitell) < 2.0*sigell &&
1211  xpos[i] >= xmin && xpos[i] <= xmax && ypos[i] >= ymin &&
1212  ypos[i] <= ymax && areal[0][i] >= pixlim)
1213  work[n++] = ellipticity[i];
1214  }
1215  if (n > 2)
1216  medstat(work,n,&fitell,&sigell);
1217  else {
1218  fitell = 0.25;
1219  sigell = 0.05;
1220  }
1221  }
1222  elllim = min(0.5,max(0.2,fitell+2.0*sigell));
1223 
1224  /* Get out of here */
1225 
1226  freespace(work);
1227 }
1228 
1229 /*---------------------------------------------------------------------------*/
1244 /*---------------------------------------------------------------------------*/
1245 
1246 static void classstats_pa() {
1247  int iloop,n,i;
1248  float *work;
1249 
1250  /* Initialise the mean and sigma to something stupid */
1251 
1252  sigpa = 1.0e6;
1253  fitpa = 0.0;
1254 
1255  /* Get some workspace */
1256 
1257  work = cpl_malloc(nrows*sizeof(float));
1258 
1259  /* Do iteration loop */
1260 
1261  for (iloop = 0; iloop < MAXLOOP; iloop++) {
1262  n = 0;
1263  for (i = 0; i < nrows; i++) {
1264  if (core_flux[i] < blim && core_flux[i] > flim &&
1265  fabs(pa[i] - fitpa) < 2.0*sigpa &&
1266  xpos[i] >= xmin && xpos[i] <= xmax && ypos[i] >= ymin &&
1267  ypos[i] <= ymax && areal[0][i] >= pixlim)
1268  work[n++] = pa[i];
1269  }
1270  if (n > 2)
1271  medstat(work,n,&fitpa,&sigpa);
1272  else {
1273  fitpa = 0.0;
1274  sigpa = 0.05;
1275  }
1276  }
1277 
1278  /* Get out of here */
1279 
1280  freespace(work);
1281 }
1282 
1283 /*---------------------------------------------------------------------------*/
1301 /*---------------------------------------------------------------------------*/
1302 
1303 static void classstats_ellf(float fluxlim) {
1304  int iloop,n,i;
1305  float *work;
1306 
1307  /* Initialise the mean and sigma to something stupid */
1308 
1309  sigellf = 1.0e6;
1310  fitellf = 0.0;
1311 
1312  /* Get some workspace */
1313 
1314  work = cpl_malloc(nrows*sizeof(float));
1315 
1316  /* Do iteration loop */
1317 
1318  for (iloop = 0; iloop < MAXLOOP; iloop++) {
1319  n = 0;
1320  for (i = 0; i < nrows; i++) {
1321  if (ellipticity[i] < 0.75 && core_flux[i] > fluxlim+1.0 &&
1322  core_flux[i] < fluxlim+2.0 &&
1323  fabs(ellipticity[i] - fitellf) < 2.0*sigellf)
1324  work[n++] = ellipticity[i];
1325  }
1326  if (n > 2)
1327  medstat(work,n,&fitellf,&sigellf);
1328  else {
1329  fitellf = 0.25;
1330  sigellf = 0.05;
1331  }
1332  }
1333 
1334  /* Get out of here */
1335 
1336  freespace(work);
1337 }
1338 
1339 /*---------------------------------------------------------------------------*/
1359 /*---------------------------------------------------------------------------*/
1360 
1361 static void classstats_ap0(float *medval, float *sigma) {
1362 
1363  int i,iloop,n;
1364  float *work,*dc,c2,sigmanew;
1365 
1366  /* Initialise the output values to something stupid */
1367 
1368  *medval = 0.0;
1369  *sigma = 1.0e6;
1370  elllim = min(0.5,max(0.2,fitell+2.0*sigell));
1371 
1372  /* Get some workspace */
1373 
1374  work = cpl_malloc(nrows*sizeof(float));
1375  dc = cpl_malloc(nrows*sizeof(float));
1376 
1377  /* Work out differences */
1378 
1379  for (i = 0; i < nrows; i++) {
1380  c2 = max(0.0,max(iso_flux[i],core5_flux[i]));
1381  dc[i] = c2 - core_flux[i];
1382  }
1383 
1384  /* Do an iteration loop */
1385 
1386  for (iloop = 0; iloop < MAXLOOP; iloop++) {
1387  n = 0;
1388 
1389  /* Ok, gather up all the stats */
1390 
1391  for (i = 0; i < nrows; i++) {
1392 
1393  /* Clipping criteria */
1394 
1395  if (ellipticity[i] < elllim && core_flux[i] < blim &&
1396  core_flux[i] > flim &&
1397  fabs(dc[i] - *medval) < 3.0*(*sigma) &&
1398  cls[i] == -1.0 && sig[i] < 5.0 &&
1399  xpos[i] >= xmin && xpos[i] <= xmax && ypos[i] >= ymin &&
1400  ypos[i] <= ymax && areal[0][i] >= pixlim)
1401  if (iloop > 0 || (iloop == 0 && dc[i] >= 0.0)) {
1402  work[n++] = dc[i];
1403  }
1404  }
1405 
1406  /* Sort the work array and find the median and sigma */
1407 
1408  if (n > 0) {
1409  sort1(work,n);
1410  if (iloop == 0) {
1411  anhist(work,n,medval,sigma);
1412  *sigma = 1.48*(*medval - work[(int)(0.25*(float)(n+3))-1]);
1413  *sigma = max(0.025,*sigma);
1414  } else {
1415  medstat(work,n,medval,&sigmanew);
1416  *sigma = min(*sigma,sigmanew);
1417  *sigma = max(0.01,*sigma);
1418  }
1419  } else {
1420  *medval = 0.0;
1421  *sigma = 0.01;
1422  }
1423 
1424  /* Just in case... */
1425 
1426  *sigma = max(*sigma,0.01);
1427  }
1428 
1429  /* Tidy and exit */
1430 
1431  freespace(work);
1432  freespace(dc);
1433 }
1434 
1435 static void classstats_ap67(float *mag1, float *mag2, float *medval,
1436  float *sigma) {
1437 
1438  int i,iloop,n;
1439  float *work,*dc,sigmanew;
1440 
1441  /* Initialise the output values to something stupid */
1442 
1443  *medval = 0.0;
1444  *sigma = 1.0e6;
1445  elllim = min(0.5,max(0.2,fitell+2.0*sigell));
1446 
1447  /* Get some workspace */
1448 
1449  work = cpl_malloc(nrows*sizeof(float));
1450  dc = cpl_malloc(nrows*sizeof(float));
1451 
1452  /* Work out differences */
1453 
1454  for (i = 0; i < nrows; i++)
1455  dc[i] = mag1[i] - mag2[i];
1456 
1457  /* Do an iteration loop */
1458 
1459  for (iloop = 0; iloop < MAXLOOP; iloop++) {
1460  n = 0;
1461 
1462  /* Ok, gather up all the stats */
1463 
1464  for (i = 0; i < nrows; i++) {
1465 
1466  /* Clipping criteria */
1467 
1468  if (ellipticity[i] < elllim && core_flux[i] < blim &&
1469  core_flux[i] > flim &&
1470  fabs(dc[i] - *medval) < 3.0*(*sigma) &&
1471  cls[i] == -1.0 && sig[i] < 5.0 &&
1472  xpos[i] >= xmin && xpos[i] <= xmax && ypos[i] >= ymin &&
1473  ypos[i] <= ymax && areal[0][i] >= pixlim) {
1474  if (iloop > 0 || (iloop == 0 && dc[i] >= 0.0)) {
1475  work[n++] = dc[i];
1476  }
1477  }
1478  }
1479 
1480  /* Sort the work array and find the median and sigma */
1481 
1482  if (n > 0) {
1483  sort1(work,n);
1484  if (iloop == 0) {
1485  anhist(work,n,medval,sigma);
1486  *sigma = 1.48*(*medval - work[(int)(0.25*(float)(n+3))-1]);
1487  *sigma = max(0.025,*sigma);
1488  } else {
1489  medstat(work,n,medval,&sigmanew);
1490  *sigma = min(*sigma,sigmanew);
1491  *sigma = max(0.01,*sigma);
1492  }
1493  } else {
1494  *medval = 0.0;
1495  *sigma = 0.01;
1496  }
1497 
1498  /* Just in case... */
1499 
1500  *sigma = max(*sigma,0.01);
1501  }
1502 
1503  /* Tidy and exit */
1504 
1505  free(work);
1506  free(dc);
1507 }
1508 
1509 /*---------------------------------------------------------------------------*/
1526 /*---------------------------------------------------------------------------*/
1527 
1528 static void classstats_final(void) {
1529  int n,i,iloop,iarg,ii,iend,ncls,kk,k;
1530  float *work,ell,core,sig1,sig2,sig3,denom,w1,w2,w3,core_small;
1531  float core_large,*statistic,core_midd,pkht,xcor,cfit,csig;
1532  float *work1,junk,corlim1,corval1,corlim2,corval2,sigmaold;
1533 
1534  /* Initialise */
1535 
1536  sigma_final = 1.0e6;
1537  fit_final = 0.0;
1538  ncls = 0;
1539 
1540  /* Get some workspace */
1541 
1542  work = cpl_malloc(nrows*sizeof(float));
1543  work1 = cpl_malloc(nrows*sizeof(float));
1544  statistic = cpl_malloc(nrows*sizeof(float));
1545 
1546  /* Calculate the statistic now */
1547 
1548  for (i = 0; i < nrows; i++) {
1549  ell = ellipticity[i];
1550  pkht = peak_mag[i];
1551  core = core_flux[i];
1552  iarg = vircam_nint(10.0*(core - 5.0));
1553  iarg = max(1,min(NSAMPLE,iarg)) - 1;
1554  if (! poor) {
1555  sig1 = max(0.01,(fit1 - lower1[iarg])/3.0);
1556  sig2 = max(0.01,(fit2 - lower2[iarg])/3.0);
1557  } else {
1558  sig1 = max(0.01,(fit4 - lower1[iarg])/3.0);
1559  sig2 = max(0.01,(fit5 - lower2[iarg])/3.0);
1560  }
1561  sig3 = max(0.01,(fit3 - lower3[iarg])/3.0);
1562  denom = (wt1/sig1 + wt2/sig2 + wt3/sig3);
1563  w1 = (wt1/sig1)/denom;
1564  w2 = (wt2/sig2)/denom;
1565  w3 = (wt3/sig3)/denom;
1566  if (! poor) {
1567  core_small = core1_flux[i];
1568  core_large = core3_flux[i];
1569  statistic[i] = (core - core_small - fit1)*w1 +
1570  (core_large - core - fit2)*w2 + (core - pkht - fit3)*w3;
1571  } else {
1572  core_midd = core2_flux[i];
1573  core_large = core4_flux[i];
1574  statistic[i] = (core_midd - core - fit4)*w1 +
1575  (core_large - core - fit5)*w2 + (core - pkht - fit3)*w3;
1576  }
1577  }
1578 
1579  /* Iteration loop. Use only lower ellipticity images and relevant
1580  peak height range */
1581 
1582  for (iloop = 0; iloop < MAXLOOP; iloop++) {
1583  sigmaold = sigma_final;
1584  n = 0;
1585  for (i = 0; i < nrows ; i++) {
1586 
1587  ell = ellipticity[i];
1588  core = core_flux[i];
1589  if (ell < elllim && core < blim && core > flim &&
1590  fabs((double)(statistic[i] - fit_final)) < 3.0*sigma_final &&
1591  areal[0][i] >= pixlim)
1592  work[n++] = statistic[i];
1593 
1594  /* This information is to be used later to find the curvature of
1595  saturated region */
1596 
1597  if (core > corlim && iloop == MAXLOOP-2) {
1598  cls[ncls] = statistic[i];
1599  sig[ncls++] = core;
1600  }
1601  }
1602 
1603  /* Median defines general fit */
1604 
1605  if (n > 2) {
1606  sort1(work,n);
1607  if (iloop == 0 && n > 10) {
1608  anhist(work,n,&fit_final,&sigma_final);
1609  } else {
1610  medstat(work,n,&fit_final,&sigma_final);
1611  }
1612  sigma_final = max(0.01,min(sigmaold,sigma_final));
1613  } else {
1614  fit_final = 0.0;
1615  sigma_final = 0.01;
1616  }
1617  }
1618 
1619  /* Now work out the curvature in the saturated region */
1620 
1621  sort2(sig,cls,ncls);
1622  ii = 0;
1623  xcor = 12.5;
1624  iend = 0;
1625  i = -1;
1626  corlim1 = 0.0;
1627  corlim2 = 0.0;
1628  corval1 = 0.0;
1629  corval2 = 0.0;
1630  while (iend == 0 && i < ncls-1) {
1631  i++;
1632  if (sig[i] > xcor+0.25 && ii >= 3) {
1633  medstat(work,ii,&cfit,&csig);
1634  for (iloop = 0; iloop < 3; iloop++) {
1635  kk = 0;
1636  for (k = 0; k < ii; k++) {
1637  if (work[k] <= cfit + 3.0*csig)
1638  work1[kk++] = work[k];
1639  }
1640  medstat(work1,kk,&cfit,&junk);
1641  }
1642  if (cfit <= fit_final + 3.0*sigma_final) {
1643  corlim1 = xcor;
1644  corval1 = cfit;
1645  } else {
1646  corlim2 = xcor;
1647  corval2 = cfit;
1648  iend = 1;
1649  }
1650  } else {
1651  work[ii++] = cls[i];
1652  }
1653  }
1654 
1655  /* Estimate where core measure and statistic become unreliable */
1656 
1657  if (iend == 1)
1658  corlim = corlim2 - 0.5*(corval2 - fit_final - 3.0*sigma_final)/(corval2 - corval1);
1659  else
1660  corlim = corlim1;
1661  corlim = max(cormin,corlim);
1662  kk = 0;
1663  for (i = 0; i < nrows; i++) {
1664  core = core_flux[i];
1665  if (core >= corlim)
1666  work[kk++] = peak_height[i] + skylevel;
1667  }
1668  if (kk > 0) {
1669  medstat(work,kk,&avsat,&junk);
1670  avsat = max(10000.0+skylevel,avsat);
1671  } else {
1672  avsat = 10000.0 + skylevel;
1673  }
1674 
1675  /* Tidy and exit */
1676 
1677  freespace(work);
1678  freespace(work1);
1679  freespace(statistic);
1680 }
1681 
1682 /*---------------------------------------------------------------------------*/
1707 /*---------------------------------------------------------------------------*/
1708 
1709 static void medstat(float *array, int n, float *medval, float *sigval) {
1710  int lev1,lev2,lev3;
1711 
1712  /* Sort the array first, then choose the median. The sigma is defined
1713  as half the distance between the two quartile points multiplied by
1714  the appropriate scaling factor (1.48) */
1715 
1716  if (n == 0) {
1717  *medval = 0.0;
1718  *sigval = 0.0;
1719  return;
1720  }
1721  sort1(array,n);
1722  lev1 = (n + 1)/2;
1723  lev2 = (3*n + 3)/4;
1724  lev3 = (n + 3)/4;
1725  *medval = array[lev1-1];
1726  *sigval = 1.48*0.5*(array[lev2-1] - array[lev3-1]);
1727 }
1728 
1729 /*---------------------------------------------------------------------------*/
1748 /*---------------------------------------------------------------------------*/
1749 
1750 static void sort1(float *a, int n) {
1751  int iii,ii,i,ifin,j;
1752  float b;
1753 
1754  iii = 4;
1755  while (iii < n)
1756  iii *= 2;
1757  iii = min(n,(3*iii)/4 - 1);
1758 
1759  while (iii > 1) {
1760  iii /= 2;
1761  ifin = n - iii;
1762  for (ii = 0; ii < ifin; ii++) {
1763  i = ii;
1764  j = i + iii;
1765  if (a[i] > a[j]) {
1766  b = a[j];
1767  while (1) {
1768  a[j] = a[i];
1769  j = i;
1770  i = i - iii;
1771  if (i < 0 || a[i] <= b)
1772  break;
1773  }
1774  a[j] = b;
1775  }
1776  }
1777  }
1778 }
1779 
1780 /*---------------------------------------------------------------------------*/
1802 /*---------------------------------------------------------------------------*/
1803 
1804 static void sort2(float *a1, float *a2, int n) {
1805  int iii,ii,i,ifin,j;
1806  float b1,b2;
1807 
1808  iii = 4;
1809  while (iii < n)
1810  iii *= 2;
1811  iii = min(n,(3*iii)/4 - 1);
1812 
1813  while (iii > 1) {
1814  iii /= 2;
1815  ifin = n - iii;
1816  for (ii = 0; ii < ifin; ii++) {
1817  i = ii;
1818  j = i + iii;
1819  if (a1[i] > a1[j]) {
1820  b1 = a1[j];
1821  b2 = a2[j];
1822  while (1) {
1823  a1[j] = a1[i];
1824  a2[j] = a2[i];
1825  j = i;
1826  i = i - iii;
1827  if (i < 0 || a1[i] <= b1)
1828  break;
1829  }
1830  a1[j] = b1;
1831  a2[j] = b2;
1832  }
1833  }
1834  }
1835 }
1836 
1839 /*
1840 
1841 $Log: not supported by cvs2svn $
1842 Revision 1.19 2012/01/15 17:40:09 jim
1843 Minor modifications to take into accout the changes in cpl API for v6
1844 
1845 Revision 1.18 2012/01/04 08:57:42 jim
1846 fixed ap0 and ap67 routines to provide sensible lower limits for sigmas
1847 
1848 Revision 1.17 2011/02/01 15:33:35 jim
1849 Fixed mistaken column ID
1850 
1851 Revision 1.16 2011/02/01 10:06:35 jim
1852 tweaked a few parameters to bring it in line with the standard version
1853 
1854 Revision 1.15 2011/01/31 15:02:38 jim
1855 Mods to re-calculate the saturation limit
1856 
1857 Revision 1.14 2011/01/21 10:59:07 jim
1858 Modified to calculate all aperture corrections directly. Many small mods
1859 to make sure this is in synch with the standard version
1860 
1861 Revision 1.13 2010/12/09 13:24:32 jim
1862 Added classstats_pa to work out median position angle
1863 
1864 Revision 1.12 2010/09/09 12:09:57 jim
1865 Added docs
1866 
1867 Revision 1.11 2010/01/31 18:58:17 jim
1868 Fixed little bug in the columns that are read
1869 
1870 Revision 1.10 2009/11/18 21:03:50 jim
1871 Many small upgrades to bring it into line with the latest CASU version
1872 
1873 Revision 1.9 2007/05/02 09:11:34 jim
1874 Modified to allow for inclusion of table WCS keywords into FITS header
1875 
1876 Revision 1.8 2007/03/01 12:38:26 jim
1877 Small modifications after a bit of code checking
1878 
1879 Revision 1.7 2006/06/13 14:06:57 jim
1880 The classification and statistic data rows must come from the original table
1881 rather than the copy as they are being written to
1882 
1883 Revision 1.6 2006/05/26 15:00:36 jim
1884 Now makes a copy of the input table so that it doesn't muck up the column
1885 values
1886 
1887 Revision 1.5 2006/05/18 12:34:20 jim
1888 Fixed header keywords for input information
1889 
1890 Revision 1.4 2006/03/15 10:43:42 jim
1891 Fixed a few things
1892 
1893 Revision 1.3 2005/11/28 13:50:06 jim
1894 Touched up a few things to make splint happy
1895 
1896 Revision 1.2 2005/11/03 13:28:51 jim
1897 All sorts of changes to tighten up error handling
1898 
1899 Revision 1.1 2005/09/22 08:41:03 jim
1900 first entry
1901 
1902 
1903 */
cpl_table * vircam_tfits_get_table(vir_tfits *p)
Definition: vircam_tfits.c:364
cpl_propertylist * vircam_tfits_get_ehu(vir_tfits *p)
Definition: vircam_tfits.c:473
int vircam_pfits_get_exptime(const cpl_propertylist *plist, float *exptime)
Get the value of exposure time.
Definition: vircam_pfits.c:245
int classify(vir_tfits *catalogue, cpl_propertylist *plist, float minsize, int cattype)
Do star/galaxy classification.
Definition: classify.c:204