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