VIRCAM Pipeline 2.3.12
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
54static long nrows;
55static float thresh,skylevel,skynoise,rcore;
56
57/* Derived values */
58
59static int poor;
60static float sigell,fitell,elllim,sigellf,fitellf,sigpa,fitpa;
61static float blim,flim,cmin,cmax;
62static float fit1,fit2,fit3,fit4,fit5,fit6,fit7;
63static float fit_final,sigma_final;
64static float *lower1,*lower2,*lower3,*upper1,*upper2,*upper3,*uppere;
65static float avsig1,avsig2,avsig3,wt1,wt2,wt3;
66
67/* Classification values */
68
69static int nstar,ngal,njunk,ncmp;
70
71/* Values for the data quality and aperture corrections */
72
73static float avsat,corlim,cormin,apcpkht,apcor,apcor1,apcor2,apcor3,apcor4;
74static float apcor5,apcor6,apcor7;
75
76/* Data arrays */
77
78static float *workspace = NULL;
79static cpl_table *catcopy = NULL;
80static float *areal[NAREAL];
81static float *core_flux,*core1_flux,*core2_flux,*core3_flux,*core4_flux;
82static float *core5_flux,*peak_height,*peak_mag,*ellipticity,*iso_flux;
83static 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
91static 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
98static 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
106static int ncols;
107static float xmin;
108static float xmax;
109static float ymin;
110static float ymax;
111static float pixlim;
112
113#define FRAMECUT 0.05
114
115/* Subroutine prototypes */
116
117static void anhist(float *, int, float *, float *);
118static void boundaries(float *, float *, float *, float, float, float, float,
119 int, float, float, float *, float *, float *, float *);
120static void boundpk(float *, float *, float, float, float *, float *,
121 float *, float *);
122static void classify_run(void);
123static void classstats(float *, float *, int, float, float *, float *);
124static void classstats_ap0(float *, float *);
125static void classstats_ap67(float *, float *, float *, float *);
126static void classstats_el(void);
127static void classstats_pa(void);
128static void classstats_ellf(float);
129static void classstats_final(void);
130static void medstat(float *, int, float *, float *);
131static void sort1(float *, int);
132static void sort2(float *, float *, int);
133
136/*---------------------------------------------------------------------------*/
201/*---------------------------------------------------------------------------*/
202
203extern 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
494static 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
631static 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
732static 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
793static 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
1098static 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
1184static 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
1240static 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
1297static 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
1355static 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
1429static 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
1522static 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
1703static 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
1744static 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
1798static 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 $
1836Revision 1.3 2015/08/12 11:16:55 jim
1837Modified procedure names to protect namespace
1838
1839Revision 1.2 2015/08/07 13:06:54 jim
1840Fixed copyright to ESO
1841
1842Revision 1.1.1.1 2015/06/12 10:44:32 jim
1843Initial import
1844
1845Revision 1.4 2015/03/03 10:48:11 jim
1846Fixed some memory leaks
1847
1848Revision 1.3 2014/04/09 11:08:21 jim
1849Get rid of a couple of compiler moans
1850
1851Revision 1.2 2014/04/09 09:09:51 jim
1852Detabbed
1853
1854Revision 1.1.1.1 2013/08/27 12:07:48 jim
1855Imported
1856
1857
1858*/
cpl_propertylist * casu_tfits_get_ehu(casu_tfits *p)
Definition: casu_tfits.c:473
cpl_table * casu_tfits_get_table(casu_tfits *p)
Definition: casu_tfits.c:364
int imcore_classify(casu_tfits *catalogue, float minsize, int cattype)
Do star/galaxy classification.
Definition: classify.c:203