CR2RE Pipeline Reference Manual 1.6.8
hdrl_cat_classify.c
1/*
2 * This file is part of the HDRL
3 * Copyright (C) 2017 European Southern Observatory
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 */
19
20#include "hdrl_cat_classify.h"
21
22#include "hdrl_cat_casu.h"
23#include "hdrl_cat_table.h"
24#include "hdrl_cat_utils_sort.h"
25
26
27/*** DEFINES ***/
28
29#define STEP 0.05 /* */
30#define NSAMPLE 150 /* */
31#define MAXLOOP 5 /* */
32
33#define NCOLFULL 15 /* */
34#define FRAMECUT 0.05 /* */
35
36
37/*** GLOBAL VARIABLES (INTO FILE) ***/
38
39/* Make the data arrays and header values global */
40static cpl_size g_nrows;
41static double g_thresh;
42static double g_skylevel;
43static double g_skynoise;
44static double g_rcore;
45
46/* Derived values */
47static cpl_size g_poor;
48static double g_sigell, g_fitell, g_elllim, g_sigellf, g_fitellf, g_sigpa, g_fitpa;
49static double g_blim, g_flim, g_cmin, g_cmax;
50static double g_fit1, g_fit2, g_fit3, g_fit4, g_fit5, g_fit6, g_fit7;
51static double g_fit_final, g_sigma_final;
52static double *g_lower1, *g_lower2, *g_lower3, *g_upper1, *g_upper2, *g_upper3, *g_uppere;
53static double g_avsig1, g_avsig2, g_avsig3, g_wt1, g_wt2, g_wt3;
54
55/* Classification values */
56static cpl_size g_nstar, g_ngal, g_njunk, g_ncmp;
57
58/* Values for the data quality and aperture corrections */
59static double g_avsat, g_corlim, g_cormin, g_apcpkht;
60static double g_apcor1, g_apcor2, g_apcor3, g_apcor4, g_apcor5;
61static double g_apcor6, g_apcor7;
62
63/* Data arrays */
64static double *g_workspace = NULL;
65static cpl_table *g_catcopy = NULL;
66static double *g_areal[NAREAL];
67static double *g_core_flux, *g_core1_flux, *g_core2_flux, *g_core3_flux;
68static double *g_core4_flux, *g_core5_flux, *g_core6_flux;
69static double *g_peak_height, *g_peak_mag, *g_ellipticity, *g_iso_flux;
70static double *g_total_flux, *g_cls, *g_sig, *g_xpos, *g_ypos, *g_pa, *g_skylev;
71
72/* Column definitions */
73static double g_xmin, g_xmax, g_ymin, g_ymax;
74static double g_pixlim;
75static const char *g_colsfull[NCOLFULL] = {
76 "Aper_flux_3", "Aper_flux_1", "Aper_flux_4", "Aper_flux_5", "Aper_flux_6",
77 "Peak_height", "Ellipticity", "Isophotal_flux", "Isophotal_flux",
78 "Aper_flux_7", "X_coordinate","Y_coordinate", "Position_angle","Sky_level",
79 "Aper_flux_2"};
80
81
82/*** PROTOTYPES ***/
83
84static void anhist(double *data, cpl_size n, double *medval, double *sigma);
85
86static void boundaries(double *core1, double *core2, double *core3, double medval1,
87 double sigma1, double medval2, double sigma2, cpl_size small,
88 double area1, double area2,
89 double *wt, double *avsig, double *lower, double *upper);
90static void boundpk( double *core, double *pkht, double medval, double sigma,
91 double *wt, double *avsig, double *lower, double *upper);
92
93static void classify_run(void);
94
95static void classstats( double *core1, double *core2, cpl_size small, double cutlev,
96 double *medval, double *sigma);
97static void classstats_ap0( double *medval, double *sigma);
98static void classstats_ap67( double *mag1, double *mag2, double *medval, double *sigma);
99static void classstats_el( void);
100static void classstats_pa( void);
101static void classstats_ellf( double);
102static void classstats_final(void);
103
104static void medstat(double *array, cpl_size n, double *medval, double *sigval);
105
106
107/*----------------------------------------------------------------------------*/
115/*----------------------------------------------------------------------------*/
116
119/* ---------------------------------------------------------------------------*/
152/* ---------------------------------------------------------------------------*/
153cpl_error_code hdrl_classify(hdrl_casu_tfits *catalogue, double minsize)
154{
155 /* Get the number of columns and decide which column labels to use */
156 cpl_table *cat = hdrl_casu_tfits_get_table(catalogue);
157 if (cpl_table_get_ncol(cat) != NCOLS) {
158 return CPL_ERROR_INCOMPATIBLE_INPUT;
159 }
160
161 /* Get some DQC info from the extra propertylist generated by catalogue */
162 cpl_propertylist *extra = hdrl_casu_tfits_get_ehu(catalogue);
163
164 double fwhm = cpl_propertylist_get_double(extra, "ESO DRS SEEING" );
165 cpl_size nxout = cpl_propertylist_get_int( extra, "ESO DRS NXOUT" );
166 cpl_size nyout = cpl_propertylist_get_int( extra, "ESO DRS NYOUT" );
167
168 g_thresh = cpl_propertylist_get_double(extra, "ESO DRS THRESHOL");
169 g_skylevel = cpl_propertylist_get_double(extra, "ESO QC MEAN_SKY" );
170 g_skynoise = cpl_propertylist_get_double(extra, "ESO QC SKY_NOISE");
171 g_rcore = cpl_propertylist_get_double(extra, "ESO DRS RCORE" );
172
173 g_xmin = FRAMECUT * (double)nxout;
174 g_xmax = (1. - FRAMECUT) * (double)nxout;
175 g_ymin = FRAMECUT * (double)nyout;
176 g_ymax = (1. - FRAMECUT) * (double)nyout;
177 g_pixlim = minsize;
178
179 /* Make a copy of the table as you are going to muck about with the
180 * column values. Get the column data */
181 g_catcopy = cpl_table_duplicate(cat);
182 g_nrows = cpl_table_get_nrow(cat);
183
184 g_cls = cpl_table_get_data_double(cat, "Classification");
185 g_sig = cpl_table_get_data_double(cat, "Statistic");
186
187 const char *cols[ NCOLFULL];
188 for (cpl_size i = 0; i < NCOLFULL; i++) {
189 cols[ i] = g_colsfull[ i];
190 }
191
192 g_core_flux = cpl_table_get_data_double(g_catcopy, cols[ 0]);
193 g_core1_flux = cpl_table_get_data_double(g_catcopy, cols[ 1]);
194 g_core2_flux = cpl_table_get_data_double(g_catcopy, cols[ 2]);
195 g_core3_flux = cpl_table_get_data_double(g_catcopy, cols[ 3]);
196 g_core4_flux = cpl_table_get_data_double(g_catcopy, cols[ 4]);
197 g_peak_height = cpl_table_get_data_double(g_catcopy, cols[ 5]);
198 g_ellipticity = cpl_table_get_data_double(g_catcopy, cols[ 6]);
199 g_iso_flux = cpl_table_get_data_double(g_catcopy, cols[ 7]);
200 g_total_flux = cpl_table_get_data_double(g_catcopy, cols[ 8]);
201 g_core5_flux = cpl_table_get_data_double(g_catcopy, cols[ 9]);
202 g_xpos = cpl_table_get_data_double(g_catcopy, cols[10]);
203 g_ypos = cpl_table_get_data_double(g_catcopy, cols[11]);
204 g_pa = cpl_table_get_data_double(g_catcopy, cols[12]);
205 g_skylev = cpl_table_get_data_double(g_catcopy, cols[13]);
206 g_core6_flux = cpl_table_get_data_double(g_catcopy, cols[14]);
207
208 /* Get some workspace */
209 g_workspace = cpl_malloc(2 * g_nrows * sizeof(*g_workspace));
210 g_peak_mag = g_workspace;
211
212 double *work = g_workspace + g_nrows;
213
214 /* Convert fluxes to "magnitudes" */
215 for (cpl_size i = 0; i < g_nrows; i++) {
216
217 g_core_flux[i] = 2.5 * log10(CPL_MAX(g_core_flux[i], 1.));
218 g_core1_flux[i] = 2.5 * log10(CPL_MAX(g_core1_flux[i], 1.));
219 g_core2_flux[i] = 2.5 * log10(CPL_MAX(g_core2_flux[i], 1.));
220 g_core3_flux[i] = 2.5 * log10(CPL_MAX(g_core3_flux[i], 1.));
221 g_core4_flux[i] = 2.5 * log10(CPL_MAX(g_core4_flux[i], 1.));
222 g_core5_flux[i] = 2.5 * log10(CPL_MAX(g_core5_flux[i], 1.));
223
224 double moff = 1. / (1. - pow((g_thresh / CPL_MAX(g_peak_height[i] ,g_thresh)), 0.6));
225 g_iso_flux[i] = 2.5 * log10(CPL_MAX(moff *g_iso_flux[i], 1.));
226
227 g_peak_mag[i] = 2.5 * log10(CPL_MAX(g_peak_height[i] - g_skynoise, 0.1));
228 }
229
230 if (g_core6_flux != NULL) {
231 for (cpl_size i = 0; i < g_nrows; i++) {
232 g_core6_flux[i] = 2.5 * log10(CPL_MAX(g_core6_flux[i], 1.));
233 }
234 }
235
236 /* Now get the g_areal profile information. You'll need this in a sec */
237 for (cpl_size i = 0; i < NAREAL; i++) {
238 char colname[32];
239 sprintf(colname, "Areal_%ld_profile", (long int)i + 1);
240 g_areal[i] = cpl_table_get_data_double(g_catcopy, colname);
241 }
242
243 /* What is the seeing like? */
244 g_poor = 0;
245 if (fwhm > CPL_MAX(5., g_rcore * sqrt(2.))) g_poor = 1;
246
247 /* Ok, now call the routine that does all the work */
248 classify_run();
249
250 /* Right, now get a better estimate of the seeing */
251 cpl_size n = 0;
252 for (cpl_size i = 0; i < g_nrows; i++) {
253
254 double ell = g_ellipticity[i];
255 double core = g_core_flux[ i];
256 double pkht = g_peak_height[i];
257
258 if (g_cls[i] == -1. && ell < g_elllim && core < g_corlim && pkht > 10. * g_thresh) {
259
260 double ap = log(0.5 * pkht / g_thresh) / log(2.) + 1.;
261 cpl_size iap = (cpl_size)ap;
262 double delap = ap - (double)iap;
263
264 if (iap > 0 && iap < NAREAL && g_areal[1][i] > 0.) {
265
266 double area = g_areal[iap - 1][i]*(1. - delap) + g_areal[iap][i] * delap;
267 work[n++] = 2. * sqrt(area / CPL_MATH_PI);
268 }
269 }
270 }
271
272 if (n > 2) {
273
274 double junk;
275 medstat(work, n, &fwhm, &junk);
276
277 /* Allow for finite pixel size */
278 double arg = (0.25 * CPL_MATH_PI * fwhm * fwhm) - 1;
279 fwhm = 2. * sqrt(CPL_MAX(0., arg / CPL_MATH_PI));
280
281 } else {
282 fwhm = -1.;
283 }
284
285 if (g_catcopy != NULL) {
286 cpl_table_delete(g_catcopy);
287 g_catcopy = NULL;
288 }
289
290
291 /* Qc keywords */
292 cpl_propertylist_update_double(extra, "ESO QC IMAGE_SIZE", fwhm);
293 cpl_propertylist_update_double(extra, "ESO QC ELLIPTICITY", g_fitell);
294 cpl_propertylist_update_double(extra, "ESO QC POSANG", g_fitpa);
295 cpl_propertylist_update_double(extra, "ESO QC APERTURE_CORR", g_apcor3);
296 cpl_propertylist_update_int( extra, "ESO QC NOISE_OBJ", g_njunk);
297 cpl_propertylist_update_double(extra, "ESO QC SATURATION", g_avsat);
298
299 cpl_propertylist_set_comment( extra, "ESO QC IMAGE_SIZE", "[pixels] Average FWHM of stellar objects");
300 cpl_propertylist_set_comment( extra, "ESO QC ELLIPTICITY", "Average stellar ellipticity (1-b/a)");
301 cpl_propertylist_set_comment( extra, "ESO QC POSANG", "[degrees] Median position angle");
302 cpl_propertylist_set_comment( extra, "ESO QC APERTURE_CORR", "Stellar ap-corr 1x core flux");
303 cpl_propertylist_set_comment( extra, "ESO QC NOISE_OBJ", "Number of noise objects");
304
305
306 /* DRS keywords */
307 cpl_propertylist_update_bool( extra, "ESO DRS CLASSIFD", 1);
308
309 cpl_propertylist_set_comment( extra, "ESO DRS CLASSIFD", "Catalogue has been classified");
310
311
312 /* Aperture correction keywords */
313 cpl_propertylist_update_double(extra, "APCORPK", g_apcpkht);
314 cpl_propertylist_update_double(extra, "APCOR1", g_apcor1);
315 cpl_propertylist_update_double(extra, "APCOR2", g_apcor2);
316 cpl_propertylist_update_double(extra, "APCOR3", g_apcor3);
317 cpl_propertylist_update_double(extra, "APCOR4", g_apcor4);
318 cpl_propertylist_update_double(extra, "APCOR5", g_apcor5);
319 cpl_propertylist_update_double(extra, "APCOR6", g_apcor6);
320 cpl_propertylist_update_double(extra, "APCOR7", g_apcor7);
321
322 cpl_propertylist_set_comment( extra, "APCORPK", "Stellar aperture correction - peak height");
323 cpl_propertylist_set_comment( extra, "APCOR1", "Stellar aperture correction - 1/2x core flux");
324 cpl_propertylist_set_comment( extra, "APCOR2", "Stellar aperture correction - core/sqrt(2) flux");
325 cpl_propertylist_set_comment( extra, "APCOR3", "Stellar aperture correction - 1x core flux");
326 cpl_propertylist_set_comment( extra, "APCOR4", "Stellar aperture correction - sqrt(2)x core flux");
327 cpl_propertylist_set_comment( extra, "APCOR5", "Stellar aperture correction - 2x core flux");
328 cpl_propertylist_set_comment( extra, "APCOR6", "Stellar aperture correction - 2*sqrt(2)x core flux");
329 cpl_propertylist_set_comment( extra, "APCOR7", "Stellar aperture correction - 4x core flux");
330
331
332 /* Write header information to help GAIA */
333 cpl_propertylist_update_string(extra, "SYMBOL1", "{Ellipticity Position_angle Areal_1_profile Classification} {el");
334 cpl_propertylist_update_string(extra, "SYMBOL2", "lipse blue (1.0-$Ellipticity) $Position_angle+90 {} $Classific");
335 cpl_propertylist_update_string(extra, "SYMBOL3", "ation==1} {sqrt($Areal_1_profile*(1.0-$Ellipticity)/3.142)} : {");
336 cpl_propertylist_update_string(extra, "SYMBOL4", "Ellipticity Position_angle Areal_1_profile Classification} {el");
337 cpl_propertylist_update_string(extra, "SYMBOL5", "lipse red (1.0-$Ellipticity) $Position_angle+90 {} $Classific");
338 cpl_propertylist_update_string(extra, "SYMBOL6", "ation==-1} {sqrt($Areal_1_profile*(1.0-$Ellipticity)/3.142)} :");
339 cpl_propertylist_update_string(extra, "SYMBOL7", "{Ellipticity Position_angle Areal_1_profile Classification} {el");
340 cpl_propertylist_update_string(extra, "SYMBOL8", "lipse green (1.0-$Ellipticity) $Position_angle+90 {} $Classifi");
341 cpl_propertylist_update_string(extra, "SYMBOL9", "cation==0} {sqrt($Areal_1_profile*(1.0-$Ellipticity)/3.142)}");
342
343
344 /* Clean up */
345 if (g_workspace != NULL) {
346 cpl_free(g_workspace);
347 g_workspace = NULL;
348 }
349
350 return CPL_ERROR_NONE;
351}
352
355/* ---------------------------------------------------------------------------*/
370/* ---------------------------------------------------------------------------*/
371static void anhist(double *data, cpl_size n, double *medval, double *sigma)
372{
373 #define MAXHIST 66536 /* maximum size of histogram array */
374
375 /* Get some workspace for the histogram */
376 cpl_size *histo = cpl_calloc(MAXHIST, sizeof(cpl_size));
377 double *sval = cpl_calloc(MAXHIST, sizeof(double));
378
379 /* Sort data into the histogram */
380 for (cpl_size i = 0; i < n; i++) {
381
382 double aux = data[i] / STEP;
383 cpl_size ilev = (cpl_size)(aux + (aux < 0. ? -0.5 : 0.5));
384
385 if (ilev >= -10 && ilev <= 100) {
386 ilev += 10;
387 histo[ilev] += 1;
388 }
389 }
390
391 /* Now find the maximum of the histogram and its position ... */
392 double hmax = 0.;
393 cpl_size imax = 0;
394 for (cpl_size i = 0; i < MAXHIST; i++) {
395 if (histo[i] > hmax) {
396 hmax = (double)(histo[i]);
397 imax = i;
398 }
399 }
400
401 /* Trap for hmax == 0 */
402 if (hmax == 0.) {
403
404 if (n >= 10) {
405 *medval = data[(n+1)/2-1];
406 *sigma = CPL_MATH_STD_MAD * 0.5 * (data[(3 * n + 3) / 4 - 1] - data[(n + 3) / 4 - 1]);
407 } else {
408 *medval = 0.;
409 *sigma = 1.;
410 }
411
412 } else {
413
414 /* Now do three point running average to see if there are other local maxime */
415 double smax = 0.;
416 cpl_size ismax = 0;
417 for (cpl_size i = 1; i < MAXHIST-1; i++) {
418 sval[i] = (histo[i - 1] + histo[i] + histo[i + 1]) / 3.;
419 if (sval[i] > smax) {
420 smax = sval[i];
421 ismax = i;
422 }
423 }
424
425 if (ismax < imax) {
426 imax = ismax;
427 hmax = (double)(histo[imax]);
428 }
429
430 /* Now check for lower local maxima */
431 for (cpl_size i = imax-1; i > 0; i--) {
432 if (sval[i] >= sval[i + 1] && sval[i] >= sval[i - 1]) {
433 if (sval[i] > 0.5 * smax)
434 ismax = i;
435 }
436 }
437
438 if (ismax < imax) {
439 imax = ismax;
440 hmax = (double)(histo[imax]);
441 }
442
443 /* Now work out where the peak is */
444 *medval = CPL_MIN((double)(imax - 10) * STEP, data[(n + 1) / 2 - 1]);
445
446 double aux = 0.5 * hmax;
447 double hlim = (cpl_size)(aux + (aux < 0. ? -0.5 : 0.5));
448
449 cpl_size i = 1;
450 while (imax - i > 1 && histo[imax - i] > hlim) {
451 i++;
452 }
453
454 if (imax - i >= 0) {
455 double ratio = hmax / CPL_MAX(1., (double)(histo[imax - i]));
456 *sigma = (double)i * STEP / (sqrt(2.) * CPL_MAX(1., log(ratio)));
457 *sigma = CPL_MAX(*sigma, 0.5 * STEP);
458 } else {
459 *sigma = 1.;
460 }
461 }
462
463 /* Clean up */
464 if (histo) cpl_free(histo);
465 if (sval) cpl_free(sval);
466}
467
468/* ---------------------------------------------------------------------------*/
492/* ---------------------------------------------------------------------------*/
493static void boundaries(double *core1, double *core2, double *core3, double medval1,
494 double sigma1, double medval2, double sigma2, cpl_size small,
495 double area1, double area2,
496 double *wt, double *avsig, double *lower, double *upper)
497{
498 /* Get a workspace */
499 double *work = cpl_malloc(g_nrows * sizeof(double));
500
501 /* Initialise the lower boundary */
502 lower[0] = g_cmin;
503 lower[1] = g_cmax;
504
505 double asign = (small == 1 ? -1. : 1.);
506
507 /* Now collect the data */
508 cpl_size n = 0;
509 for (cpl_size i = 0; i < g_nrows; i++) {
510
511 double c1 = core1[i];
512
513 if (!g_poor) {
514
515 double c2 = core2[i];
516 double dc = asign * (c2 - c1);
517
518 if (dc > medval1 - 3. * sigma1 && c1 < g_blim - 3.) {
519 work[n++] = dc - medval1;
520 }
521
522 } else {
523
524 double c2 = core3[i];
525 double dc = c2 - c1;
526
527 if (dc > medval2 - 3. * sigma2 && c1 < g_blim - 3.) {
528 work[n++] = dc - medval2;
529 }
530 }
531 }
532
533 /* Find the median */
534 double junk;
535 medstat(work, n, avsig, &junk);
536 cpl_free(work);
537
538 /* Work out sigma levels for both types of seeing */
539 double xnoise;
540 if (! g_poor) {
541 *wt = CPL_MIN(5., CPL_MAX(1., * avsig / sigma1));
542 xnoise = sqrt(area1) * g_skynoise;
543 } else {
544 *wt = CPL_MIN(2.5, CPL_MAX(1., * avsig / sigma2));
545 xnoise = sqrt(area2) * g_skynoise;
546 }
547
548 /* Now work out the boundaries */
549 /* The term pow(10.0,(double)(0.4*xmag)); comes from the magitude formula */
550 for (cpl_size i = 0; i < NSAMPLE; i++) {
551
552 double xmag = 5. + (double)(i + 1) * 0.1;
553 double xflux = pow(10., (double)(0.4 * xmag));
554 double ratio = 2.5 * log10(CPL_MAX(1. + xnoise / xflux, 0.));
555
556 if (! g_poor) {
557 lower[i] = medval1 - 3. * sqrt(sigma1 * sigma1 + ratio * ratio);
558 upper[i] = medval1 + 3. * sqrt(sigma1 * sigma1 + 0.5 * ratio * ratio);
559 } else {
560 lower[i] = medval2 - 3. * sqrt(sigma2 * sigma2 + ratio * ratio);
561 upper[i] = medval2 + 3. * sqrt(sigma2 * sigma2 + 0.5 * ratio * ratio);
562 }
563 }
564
565 upper[0] = (g_poor == 0 ? medval1 : medval2);
566 upper[1] = upper[0];
567}
568
569/* ---------------------------------------------------------------------------*/
587/* ---------------------------------------------------------------------------*/
588static void boundpk(double *core, double *pkht, double medval, double sigma,
589 double *wt, double *avsig, double *lower, double *upper)
590{
591 /* Get the space for the boundry lines and a workspace */
592 double *work = cpl_malloc(g_nrows * sizeof(double));
593
594 /* Collect the data */
595 cpl_size n = 0;
596 for (cpl_size i = 0; i < g_nrows; i++) {
597
598 double c = core[i];
599 double p = pkht[i];
600
601 if (c - p > medval - 3. * sigma && c < g_blim - 3.) {
602 work[n++] = c - p - medval;
603 }
604 }
605
606 /* Find the median */
607 double junk;
608 medstat(work, n, avsig, &junk);
609 cpl_free(work);
610
611 *wt = CPL_MIN(5., CPL_MAX(1., *avsig / sigma));
612
613 /* Now work out boundaries */
614 double xnoise = sqrt(CPL_MATH_PI * g_rcore * g_rcore) * g_skynoise;
615 for (cpl_size i = 0; i < NSAMPLE; i++) {
616
617 double xmag = 5.0 + (double)(i + 1) * 0.1;
618 double pmag = xmag - medval;
619
620 /* The term pow(10.0,(double)(0.4*xmag)) comes from the magnitude formula */
621 double xflux = pow(10., (double)(0.4 * xmag));
622 double pflux = pow(10., (double)(0.4 * pmag));
623
624 /* The term 2.5*log10 comes from the magnitude formula */
625 double ratio = 2.5 * log10((double)(1. + CPL_MAX(xnoise / xflux, g_skynoise / pflux)));
626
627 lower[i] = medval - 3. * sqrt(sigma * sigma + ratio * ratio);
628 upper[i] = medval + 3. * sqrt(sigma * sigma + 0.5 * ratio * ratio);
629 }
630
631 upper[0] = medval;
632 upper[1] = upper[0];
633}
634
635/* ---------------------------------------------------------------------------*/
645/* ---------------------------------------------------------------------------*/
646static void classify_run(void)
647{
648 #define BLIMDEF 15.
649 #define FLIMDEF 11.
650 #define CMINDEF 7.5
651 #define CMAXDEF 15.
652
653 /* Update faint limit to cope with short exposures */
654 g_blim = BLIMDEF;
655 g_flim = FLIMDEF;
656
657 /* the following formula comes from the magnitude computation */
658 double fluxlim = 2.5 * log10((double)(5. * sqrt(CPL_MATH_PI * g_rcore * g_rcore) * g_skynoise));
659
660 g_flim = CPL_MIN(g_flim, CPL_MAX( 6., fluxlim + 3.));
661 g_corlim = CPL_MIN(g_blim, CPL_MAX(12.5, fluxlim + 5.));
662 g_cormin = CPL_MIN(g_blim, CPL_MAX(12.5, fluxlim + 5.));
663
664 /* Work out min and max core flux */
665 g_cmin = CMINDEF;
666 g_cmax = CMAXDEF;
667 for (cpl_size i = 0; i < g_nrows; i++) {
668 double xflux = g_core_flux[i];
669 g_cmin = CPL_MIN(g_cmin, xflux);
670 g_cmax = CPL_MAX(g_cmax, xflux);
671 }
672 g_cmin = CPL_MAX(fluxlim - 0.5, g_cmin);
673 g_cmax += 0.1;
674 g_cmax = CPL_MIN(g_cmax, 20.);
675
676 /* Work out g_ellipticity stats for likely stellar objects */
677 classstats_el();
678
679 /* Get the classification statistics for each of the tests */
680 double sigma1, sigma2, sigma3, sigma4, sigma5, sigma6, sigma7;
681 classstats(g_core_flux, g_core1_flux, 1, 0.2, &g_fit1, &sigma1); /* Core flux vs 1/2 * core flux */
682 classstats(g_core_flux, g_core3_flux, 0, 0.1, &g_fit2, &sigma2); /* Core flux vs 2 * core flux */
683 classstats(g_core_flux, g_core2_flux, 0, 0.0, &g_fit4, &sigma4); /* Core flux vs sqrt(2) * core flux */
684 classstats(g_core_flux, g_core4_flux, 0, 0.1, &g_fit5, &sigma5); /* Core flux vs 2 * sqrt(2) * core flux */
685 classstats(g_core_flux, g_peak_mag, 1, 0.2, &g_fit3, &sigma3); /* Core flux vs Peak height */
686
687 /* Faint end g_ellipticity */
688 classstats_ellf(fluxlim);
689
690 /* Work out position angle stats for likely stellar objects */
691 classstats_pa();
692
693 /* Get workspace for the boundary arrays */
694 g_lower1 = cpl_malloc(NSAMPLE * sizeof(*g_lower1));
695 g_lower2 = cpl_malloc(NSAMPLE * sizeof(*g_lower2));
696 g_lower3 = cpl_malloc(NSAMPLE * sizeof(*g_lower3));
697 g_upper1 = cpl_malloc(NSAMPLE * sizeof(*g_upper1));
698 g_upper2 = cpl_malloc(NSAMPLE * sizeof(*g_upper2));
699 g_upper3 = cpl_malloc(NSAMPLE * sizeof(*g_upper3));
700
701 /* Boundaries: (Core vs sqrt(2) * Core) or (Core vs 0.5 * Core) */
702 boundaries(g_core_flux, g_core1_flux, g_core2_flux, g_fit1,
703 sigma1, g_fit4, sigma4, 1,
704 CPL_MATH_PI * g_rcore * g_rcore, 2. * CPL_MATH_PI * g_rcore * g_rcore,
705 &g_wt1, &g_avsig1, g_lower1, g_upper1);
706
707 /* Boundaries: (Core vs 2 * Core) or (Core vs 2 * sqrt(2) * Core) */
708 boundaries(g_core_flux, g_core3_flux, g_core4_flux, g_fit2,
709 sigma2, g_fit5, sigma5, 0,
710 4. * CPL_MATH_PI * g_rcore * g_rcore, 8. * CPL_MATH_PI * g_rcore * g_rcore,
711 &g_wt2, &g_avsig2, g_lower2, g_upper2);
712
713 /* Boundaries: (Core vs peak height) */
714 boundpk(g_core_flux, g_peak_mag, g_fit3, sigma3, &g_wt3, &g_avsig3, g_lower3, g_upper3);
715
716 /* Do final classification statistics and find the saturation limit */
717 classstats_final();
718
719 /* Define final boundaries: The term pow(10.0,(0.4*fluxlim+1.5)); comes from the magitude formula */
720 double *lower = cpl_malloc(NSAMPLE * sizeof(double));
721 double *upper = cpl_malloc(NSAMPLE * sizeof(double));
722 g_uppere = cpl_malloc(NSAMPLE * sizeof(*g_uppere));
723
724 double xnoise = sqrt(CPL_MATH_PI * g_rcore * g_rcore) * g_skynoise;
725
726 double ratell;
727 ratell = xnoise / pow(10., 0.4 * (fluxlim + 1.5));
728 ratell = 2.5 * log10(CPL_MAX(1. + ratell, 0.));
729
730 double ratscl;
731 ratscl = (pow((g_fitellf + 2. * g_sigellf - g_fitell), 2.) - 4. * g_sigell * g_sigell) / (4. * ratell * ratell);
732 ratscl = CPL_MAX(0.25, CPL_MIN(10., ratscl));
733
734 for (cpl_size i = 0; i < NSAMPLE; i++) {
735
736 double xmag = 5. + 0.1 * (double)(i + 1);
737 double xflux = pow(10., 0.4 * xmag);
738 double ratio = 2.5 * log10(1. + xnoise / xflux);
739
740 /* TODO: Check if it's correct the assign to upper[i] --> exist a factor multiply by zero */
741 lower[i] = g_fit_final - 5. * sqrt( g_sigma_final * g_sigma_final + ratio * ratio);
742 upper[i] = g_fit_final + sqrt(9. * g_sigma_final * g_sigma_final + 0. * ratio * ratio);
743
744 g_uppere[i] = g_fitell + 2. * sqrt(g_sigell * g_sigell + ratscl * ratio * ratio);
745 g_uppere[i] = CPL_MIN(0.5, g_uppere[i]);
746 }
747
748 g_elllim = CPL_MIN(0.5, CPL_MAX(0.2, g_fitell + 2. * g_sigell));
749 fluxlim = 2.5 * log10((double)(2.5 * sqrt(CPL_MATH_PI * g_rcore * g_rcore) * g_skynoise));
750
751 g_nstar = 0;
752 g_ngal = 0;
753 g_njunk = 0;
754 g_ncmp = 0;
755
756 for (cpl_size i = 0; i < g_nrows; i++) {
757
758 double ell = g_ellipticity[i];
759 double core = g_core_flux[i];
760 double pkht = g_peak_mag[i];
761
762 double aux1 = 10. * (core - 5.);
763
764 cpl_size iarg = CPL_MAX(1, CPL_MIN(NSAMPLE, (cpl_size)(aux1 + (aux1 < 0. ? -0.5 : 0.5)))) - 1;
765
766 double sig1;
767 double sig2;
768 if (! g_poor) {
769 sig1 = CPL_MAX(0.01, (g_fit1 - g_lower1[iarg]) / 3.);
770 sig2 = CPL_MAX(0.01, (g_fit2 - g_lower2[iarg]) / 3.);
771 } else {
772 sig1 = CPL_MAX(0.01, (g_fit4 - g_lower1[iarg]) / 3.);
773 sig2 = CPL_MAX(0.01, (g_fit5 - g_lower2[iarg]) / 3.);
774 }
775 double sig3 = CPL_MAX(0.01, (g_fit3 - g_lower3[iarg]) / 3.);
776
777 double denom = (g_wt1 / sig1 + g_wt2 / sig2 + g_wt3 / sig3);
778
779 double w1 = (g_wt1 / sig1) / denom;
780 double w2 = (g_wt2 / sig2) / denom;
781 double w3 = (g_wt3 / sig3) / denom;
782
783 double statistic;
784 if (! g_poor) {
785
786 double core_small = g_core1_flux[i];
787 double core_large = g_core3_flux[i];
788
789 statistic = ( core - core_small - g_fit1 ) * w1
790 + (CPL_MAX(core_large - core - g_fit2, -3. * sig2)) * w2
791 + ( core - pkht - g_fit3 ) * w3;
792 } else {
793
794 double core_midd = g_core2_flux[i];
795 double core_large = g_core4_flux[i];
796
797 statistic = ( core_midd - core - g_fit4 ) * w1
798 + (CPL_MAX(core_large - core - g_fit5, -3. * sig2)) * w2
799 + ( core - pkht - g_fit3 ) * w3;
800 }
801
802 g_cls[i] = -1.;
803 double aux2 = exp(CPL_MAX(0., core - g_corlim + 1.));
804 double statcut = upper[iarg] + 3. * g_sigma_final * (aux2 - 1.);
805 if (statistic >= statcut) {
806 g_cls[i] = 1.;
807 } else if (statistic <= lower[iarg]) {
808 g_cls[i] = 0.;
809 }
810
811 /* Save distance from the stellar locus */
812 g_sig[i] = (statistic - g_fit_final) / ((g_fit_final - lower[iarg]) / 5.);
813
814 /* Right, now here are lots of overrides for special circumstances */
815
816 /* Too spikey? -> junk */
817 if (core - pkht - g_fit3 < -4. * sig3) g_cls[i] = 0.;
818
819 /* Elliptical star? -> compact */
820 double ellbound = CPL_MAX(g_elllim, g_uppere[iarg]);
821 if (ell > ellbound && g_cls[i] == -1. && core < g_flim && g_sig[i] > -2.) g_cls[i] = -2.;
822
823 /* Saturated? -> star */
824 if (core > g_corlim && statistic >= lower[iarg]) g_cls[i] = -1.;
825
826 /* Too elliptical? -> junk */
827 if (ell > 0.9 && core < g_corlim) g_cls[i] = 0.;
828
829 /* Too faint? -> junk */
830 if (core < fluxlim) g_cls[i] = 0.;
831
832
833 /* Now count how many you have of each */
834 if (g_cls[i] == -1.) {
835 g_nstar++;
836 } else if (g_cls[i] == 1.) {
837 g_ngal++;
838 } else if (g_cls[i] == -2.) {
839 g_ncmp++;
840 } else {
841 g_njunk++;
842 }
843 }
844 cpl_free(lower);
845 cpl_free(upper);
846
847 /* Do stats to get the aperture corrections */
848 classstats_ap67(g_core5_flux, g_core3_flux, &g_fit6, &sigma6);
849 classstats_ap67(g_core_flux, g_core6_flux, &g_fit7, &sigma7);
850 g_fit6 += g_fit2;
851
852 double fit0;
853 double sigma0;
854 classstats_ap0(&fit0, &sigma0);
855 fit0 = CPL_MAX(g_fit6, fit0);
856
857 /* pkht */
858 g_apcpkht = fit0 + g_fit3;
859
860 g_apcor1 = fit0 + g_fit1; /* 0.5 * core */
861 g_apcor2 = fit0 + g_fit7; /* 1 / sqrt(2) * core */
862 g_apcor3 = fit0; /* core */
863 g_apcor4 = fit0 - g_fit4; /* sqrt(2) * core */
864 g_apcor5 = fit0 - g_fit2; /* 2 * core */
865 g_apcor6 = fit0 - g_fit5; /* 2 * sqrt(2) * core */
866 g_apcor7 = fit0 - g_fit6; /* 4 * core */
867
868 /* Now do a better job on the saturation */
869 double *work = cpl_malloc(g_nrows * sizeof(double));
870
871 cpl_size ii = 0;
872 for (cpl_size i = 0; i < g_nrows; i++) {
873
874 double ell = g_ellipticity[i];
875 double core = g_core_flux[i];
876 double pkht = CPL_MAX(g_thresh, g_peak_height[i]) + g_skylev[i];
877
878 if ( ( ( ell < g_elllim
879 && core > g_flim
880 && g_cls[i] == -1
881 && g_sig[i] >= 5.
882 && g_areal[0][i] >= g_pixlim
883 )
884 || pkht >= 0.9 * g_avsat
885 )
886 && g_xpos[i] >= g_xmin
887 && g_xpos[i] <= g_xmax
888 && g_ypos[i] >= g_ymin
889 && g_ypos[i] <= g_ymax
890 ){
891 work[ii++] = pkht;
892 }
893 }
894
895 double avsatnew;
896 if (ii > 0) {
897 double junk;
898 medstat(work,ii,&avsatnew,&junk);
899 avsatnew = CPL_MAX(10000.0+g_skylevel,avsatnew);
900 } else {
901 avsatnew = 10000.0 + g_skylevel;
902 }
903
904 g_avsat = avsatnew;
905
906 /* Clean up */
907 cpl_free(work);
908
909 if (g_lower1 != NULL) {cpl_free(g_lower1); g_lower1 = NULL;}
910 if (g_lower2 != NULL) {cpl_free(g_lower2); g_lower2 = NULL;}
911 if (g_lower3 != NULL) {cpl_free(g_lower3); g_lower3 = NULL;}
912
913 if (g_upper1 != NULL) {cpl_free(g_upper1); g_upper1 = NULL;}
914 if (g_upper2 != NULL) {cpl_free(g_upper2); g_upper2 = NULL;}
915 if (g_upper3 != NULL) {cpl_free(g_upper3); g_upper3 = NULL;}
916
917 if (g_uppere != NULL) {cpl_free(g_uppere); g_uppere = NULL;}
918}
919
920/* ---------------------------------------------------------------------------*/
935/* ---------------------------------------------------------------------------*/
936static void classstats(double *core1, double *core2, cpl_size small, double cutlev,
937 double *medval, double *sigma) {
938
939 /* Initialise the output values to something stupid */
940 *medval = 0.0;
941 *sigma = 1.0e6;
942
943 double amult = (small == 1 ? -1. : 1.);
944
945 /* Get some workspace */
946 double *work = cpl_malloc(g_nrows * sizeof(double));
947 double *dc = cpl_malloc(g_nrows * sizeof(double));
948
949 /* Work out differences */
950 for (cpl_size i = 0; i < g_nrows; i++) {
951 dc[i] = amult * (core2[i] - core1[i]);
952 }
953
954 /* Do an iteration loop */
955 for (cpl_size iloop = 0; iloop < MAXLOOP; iloop++) {
956
957 double sigmaold = *sigma;
958
959 /* Ok, gather up all the stats */
960 cpl_size n = 0;
961 for (cpl_size i = 0; i < g_nrows; i++) {
962
963 /* Clipping criteria */
964 if ( g_ellipticity[i] < g_elllim
965 && core1[i] < g_blim
966 && core1[i] > g_flim
967 && fabs(dc[i] - *medval) < 3.*(*sigma)
968 && g_xpos[i] >= g_xmin
969 && g_xpos[i] <= g_xmax
970 && g_ypos[i] >= g_ymin
971 && g_ypos[i] <= g_ymax
972 && g_areal[0][i] >= g_pixlim)
973 {
974 if (iloop > 0 || (iloop == 0 && dc[i] >= cutlev)) {
975 work[n++] = dc[i];
976 }
977 }
978 }
979
980 /* Sort the work array and find the median and sigma */
981 if (n > 0) {
982
983 sort_array(work, n, sizeof(*work), HDRL_SORT_DOUBLE, CPL_SORT_ASCENDING);
984
985 if (iloop == 0) {
986
987 anhist( work, n, medval, sigma);
988
989 } else {
990
991 medstat(work, n, medval, sigma);
992
993 *sigma = CPL_MIN(sigmaold, *sigma);
994 }
995
996 } else {
997
998 *medval = 0.;
999 *sigma = 0.01;
1000 }
1001
1002 /* Just in case ... */
1003 *sigma = CPL_MAX(*sigma, 0.01);
1004 }
1005
1006 /* Clean up */
1007 cpl_free(work);
1008 cpl_free(dc);
1009}
1010
1011/* ---------------------------------------------------------------------------*/
1018/* ---------------------------------------------------------------------------*/
1019static void classstats_el(void)
1020{
1021 /* Initialise the mean and sigma to something stupid */
1022 g_sigell = 1.e6;
1023 g_fitell = 0.;
1024
1025 /* Get some workspace */
1026 double *work = cpl_malloc(g_nrows * sizeof(double));
1027
1028 /* Do iteration loop */
1029 for (cpl_size iloop = 0; iloop < MAXLOOP; iloop++) {
1030
1031 cpl_size n = 0;
1032 for (cpl_size i = 0; i < g_nrows; i++) {
1033 if ( g_ellipticity[i] < 0.5
1034 && g_core_flux[i] < g_blim
1035 && g_core_flux[i] > g_flim
1036 && fabs(g_ellipticity[i] - g_fitell) < 2. * g_sigell
1037 && g_xpos[i] >= g_xmin
1038 && g_xpos[i] <= g_xmax
1039 && g_ypos[i] >= g_ymin
1040 && g_ypos[i] <= g_ymax
1041 && g_areal[0][i] >= g_pixlim)
1042 {
1043 work[n++] = g_ellipticity[i];
1044 }
1045 }
1046
1047 if (n > 2) {
1048 medstat(work, n, &g_fitell, &g_sigell);
1049 } else {
1050 g_fitell = 0.25;
1051 g_sigell = 0.05;
1052 }
1053 }
1054
1055 g_elllim = CPL_MIN(0.5, CPL_MAX(0.2, g_fitell + 2. * g_sigell));
1056
1057 /* Clean up */
1058 cpl_free(work);
1059}
1060
1061/* ---------------------------------------------------------------------------*/
1068/* ---------------------------------------------------------------------------*/
1069static void classstats_pa(void)
1070{
1071 /* Initialise the mean and sigma to something stupid */
1072 g_sigpa = 1.e6;
1073 g_fitpa = 0.;
1074
1075 /* Get some workspace */
1076 double *work = cpl_malloc(g_nrows * sizeof(double));
1077
1078 /* Do iteration loop */
1079 for (cpl_size iloop = 0; iloop < MAXLOOP; iloop++) {
1080
1081 cpl_size n = 0;
1082 for (cpl_size i = 0; i < g_nrows; i++) {
1083
1084 if ( g_core_flux[i] < g_blim
1085 && g_core_flux[i] > g_flim
1086 && fabs(g_pa[i] - g_fitpa) < 2. * g_sigpa
1087 && g_xpos[i] >= g_xmin
1088 && g_xpos[i] <= g_xmax
1089 && g_ypos[i] >= g_ymin
1090 && g_ypos[i] <= g_ymax
1091 && g_areal[0][i] >= g_pixlim)
1092 {
1093 work[n++] = g_pa[i];
1094 }
1095 }
1096
1097 if (n > 2) {
1098 medstat(work, n, &g_fitpa, &g_sigpa);
1099 } else {
1100 g_fitpa = 0.;
1101 g_sigpa = 0.05;
1102 }
1103 }
1104
1105 /* Get out of here */
1106 cpl_free(work);
1107}
1108
1109/* ---------------------------------------------------------------------------*/
1119/* ---------------------------------------------------------------------------*/
1120static void classstats_ellf(double fluxlim)
1121{
1122 /* Initialise the mean and sigma to something stupid */
1123 g_sigellf = 1.e6;
1124 g_fitellf = 0.;
1125
1126 /* Get some workspace */
1127 double *work = cpl_malloc(g_nrows * sizeof(double));
1128
1129 /* Do iteration loop */
1130 for (cpl_size iloop = 0; iloop < MAXLOOP; iloop++) {
1131
1132 cpl_size n = 0;
1133 for (cpl_size i = 0; i < g_nrows; i++) {
1134
1135 if ( g_ellipticity[i] < 0.75
1136 && g_core_flux[i] > fluxlim + 1.
1137 && g_core_flux[i] < fluxlim + 2.
1138 && fabs(g_ellipticity[i] - g_fitellf) < 2. * g_sigellf)
1139 {
1140 work[n++] = g_ellipticity[i];
1141 }
1142 }
1143
1144 if (n > 2) {
1145 medstat(work, n, &g_fitellf, &g_sigellf);
1146 } else {
1147 g_fitellf = 0.25;
1148 g_sigellf = 0.05;
1149 }
1150 }
1151
1152 /* Get out of here */
1153 cpl_free(work);
1154}
1155
1156/* ---------------------------------------------------------------------------*/
1167/* ---------------------------------------------------------------------------*/
1168static void classstats_ap0(double *medval, double *sigma)
1169{
1170 /* Initialise the output values to something stupid */
1171 *medval = 0.;
1172 *sigma = 1.e6;
1173 g_elllim = CPL_MIN(0.5, CPL_MAX(0.2, g_fitell + 2. * g_sigell));
1174
1175 /* Get some workspace */
1176 double *work = cpl_malloc(g_nrows * sizeof(double));
1177 double *dc = cpl_malloc(g_nrows * sizeof(double));
1178
1179 /* Work out differences */
1180 for (cpl_size i = 0; i < g_nrows; i++) {
1181 dc[i] = CPL_MAX(0., CPL_MAX(g_iso_flux[i], g_core5_flux[i])) - g_core_flux[i];
1182 }
1183
1184 /* Do an iteration loop */
1185 for (cpl_size iloop = 0; iloop < MAXLOOP; iloop++) {
1186
1187 /* Ok, gather up all the stats */
1188 cpl_size n = 0;
1189 for (cpl_size i = 0; i < g_nrows; i++) {
1190
1191 /* Clipping criteria */
1192 if ( g_ellipticity[i] < g_elllim
1193 && g_core_flux[i] < g_blim
1194 && g_core_flux[i] > g_flim
1195 && fabs(dc[i] - *medval) < 3. * (*sigma)
1196 && g_cls[i] == -1.
1197 && g_sig[i] < 5.
1198 && g_xpos[i] >= g_xmin
1199 && g_xpos[i] <= g_xmax
1200 && g_ypos[i] >= g_ymin
1201 && g_ypos[i] <= g_ymax
1202 && g_areal[0][i] >= g_pixlim)
1203 {
1204 if (iloop > 0 || (iloop == 0 && dc[i] >= 0.)) {
1205 work[n++] = dc[i];
1206 }
1207 }
1208 }
1209
1210 /* Sort the work array and find the median and sigma */
1211 if (n > 0) {
1212
1213 sort_array(work, n, sizeof(*work), HDRL_SORT_DOUBLE, CPL_SORT_ASCENDING);
1214
1215 if (iloop == 0) {
1216
1217 anhist(work, n, medval, sigma);
1218
1219 *sigma = CPL_MATH_STD_MAD * (*medval - work[(cpl_size)(0.25 * (double)(n + 3)) - 1]);
1220 *sigma = CPL_MAX(0.025, *sigma);
1221
1222 } else {
1223
1224 double sigmanew;
1225 medstat(work, n, medval, &sigmanew);
1226
1227 *sigma = CPL_MIN(*sigma, sigmanew);
1228 *sigma = CPL_MAX(0.01, *sigma);
1229 }
1230
1231 } else {
1232
1233 *medval = 0.;
1234 *sigma = 0.01;
1235 }
1236
1237 /* Just in case ... */
1238 *sigma = CPL_MAX(*sigma, 0.01);
1239 }
1240
1241 /* Clean up */
1242 cpl_free(work);
1243 cpl_free(dc);
1244}
1245
1246/* ---------------------------------------------------------------------------*/
1258/* ---------------------------------------------------------------------------*/
1259static void classstats_ap67(double *mag1, double *mag2, double *medval, double *sigma)
1260{
1261 /* Initialise the output values to something stupid */
1262 *medval = 0.;
1263 *sigma = 1.e6;
1264 g_elllim = CPL_MIN(0.5, CPL_MAX(0.2, g_fitell + 2. * g_sigell));
1265
1266 /* Get some workspace */
1267 double *work = cpl_malloc(g_nrows * sizeof(double));
1268 double *dc = cpl_malloc(g_nrows * sizeof(double));
1269
1270 /* Work out differences */
1271 for (cpl_size i = 0; i < g_nrows; i++) {
1272 dc[i] = mag1[i] - mag2[i];
1273 }
1274
1275 /* Do an iteration loop */
1276 for (cpl_size iloop = 0; iloop < MAXLOOP; iloop++) {
1277
1278 /* Ok, gather up all the stats */
1279 cpl_size n = 0;
1280 for (cpl_size i = 0; i < g_nrows; i++) {
1281
1282 /* Clipping criteria */
1283 if ( g_ellipticity[i] < g_elllim
1284 && g_core_flux[i] < g_blim
1285 && g_core_flux[i] > g_flim
1286 && fabs(dc[i] - *medval) < 3. * (*sigma)
1287 && g_cls[i] == -1. && g_sig[i] < 5.
1288 && g_xpos[i] >= g_xmin
1289 && g_xpos[i] <= g_xmax
1290 && g_ypos[i] >= g_ymin
1291 && g_ypos[i] <= g_ymax
1292 && g_areal[0][i] >= g_pixlim)
1293 {
1294 if (iloop > 0 || (iloop == 0 && dc[i] >= 0.)) {
1295 work[n++] = dc[i];
1296 }
1297 }
1298 }
1299
1300 /* Sort the work array and find the median and sigma */
1301 if (n > 0) {
1302
1303 sort_array(work, n, sizeof(*work), HDRL_SORT_DOUBLE, CPL_SORT_ASCENDING);
1304
1305 if (iloop == 0) {
1306
1307 anhist(work, n, medval, sigma);
1308
1309 *sigma = CPL_MATH_STD_MAD * (*medval - work[(cpl_size)(0.25 * (double)(n + 3)) - 1]);
1310 *sigma = CPL_MAX(0.025, *sigma);
1311
1312 } else {
1313
1314 double sigmanew;
1315 medstat(work, n, medval, &sigmanew);
1316
1317 *sigma = CPL_MIN(*sigma, sigmanew);
1318 *sigma = CPL_MAX(0.01, *sigma);
1319 }
1320
1321 } else {
1322 *medval = 0.;
1323 *sigma = 0.01;
1324 }
1325
1326 /* Just in case ... */
1327 *sigma = CPL_MAX(*sigma, 0.01);
1328 }
1329
1330 /* Clean up */
1331 cpl_free(work);
1332 cpl_free(dc);
1333}
1334
1335/* ---------------------------------------------------------------------------*/
1344/* ---------------------------------------------------------------------------*/
1345static void classstats_final(void)
1346{
1347 /* Initialise */
1348 g_sigma_final = 1.e6;
1349 g_fit_final = 0.;
1350
1351 cpl_size ncls = 0;
1352
1353 /* Get some workspace */
1354 double *work = cpl_malloc(g_nrows * sizeof(double));
1355 double *work1 = cpl_malloc(g_nrows * sizeof(double));
1356 double *statistic = cpl_malloc(g_nrows * sizeof(double));
1357
1358 /* Calculate the statistic now */
1359 for (cpl_size i = 0; i < g_nrows; i++) {
1360
1361 double pkht = g_peak_mag[i];
1362 double core = g_core_flux[i];
1363
1364 double aux = 10. * (core - 5.);
1365 cpl_size iarg = CPL_MAX(1, CPL_MIN(NSAMPLE, (cpl_size)(aux + (aux < 0. ? -0.5 : 0.5)))) - 1;
1366
1367 double sig1;
1368 double sig2;
1369 if (!g_poor) {
1370 sig1 = CPL_MAX(0.01, (g_fit1 - g_lower1[iarg]) / 3.);
1371 sig2 = CPL_MAX(0.01, (g_fit2 - g_lower2[iarg]) / 3.);
1372 } else {
1373 sig1 = CPL_MAX(0.01, (g_fit4 - g_lower1[iarg]) / 3.);
1374 sig2 = CPL_MAX(0.01, (g_fit5 - g_lower2[iarg]) / 3.);
1375 }
1376 double sig3 = CPL_MAX(0.01, (g_fit3 - g_lower3[iarg]) / 3.);
1377
1378 double denom = (g_wt1 / sig1 + g_wt2 / sig2 + g_wt3 / sig3);
1379
1380 double w1 = (g_wt1 / sig1) / denom;
1381 double w2 = (g_wt2 / sig2) / denom;
1382 double w3 = (g_wt3 / sig3) / denom;
1383
1384 if (! g_poor) {
1385
1386 double core_small = g_core1_flux[i];
1387 double core_large = g_core3_flux[i];
1388
1389 statistic[i] = (core - core_small - g_fit1) * w1
1390 + (core_large - core - g_fit2) * w2
1391 + (core - pkht - g_fit3) * w3;
1392
1393 } else {
1394
1395 double core_midd = g_core2_flux[i];
1396 double core_large = g_core4_flux[i];
1397
1398 statistic[i] = (core_midd - core - g_fit4) * w1
1399 + (core_large - core - g_fit5) * w2
1400 + (core - pkht - g_fit3) * w3;
1401 }
1402 }
1403
1404 /* Iteration loop. Use only lower g_ellipticity images and relevant peak height range */
1405 for (cpl_size iloop = 0; iloop < MAXLOOP; iloop++) {
1406
1407 double sigmaold = g_sigma_final;
1408
1409 cpl_size n = 0;
1410 for (cpl_size i = 0; i < g_nrows ; i++) {
1411
1412 double ell = g_ellipticity[i];
1413 double core = g_core_flux[i];
1414
1415 if ( ell < g_elllim
1416 && core < g_blim
1417 && core > g_flim
1418 && fabs((double)(statistic[i] - g_fit_final)) < 3. * g_sigma_final
1419 && g_areal[0][i] >= g_pixlim)
1420 {
1421 work[n++] = statistic[i];
1422 }
1423
1424 /* This information is to be used later to find the curvature of saturated region */
1425 if (core > g_corlim && iloop == MAXLOOP - 2) {
1426 g_cls[ncls] = statistic[i];
1427 g_sig[ncls++] = core;
1428 }
1429 }
1430
1431 /* Median defines general fit */
1432 if (n > 2) {
1433
1434 sort_array(work, n, sizeof(*work), HDRL_SORT_DOUBLE, CPL_SORT_ASCENDING);
1435
1436 if (iloop == 0 && n > 10) {
1437 anhist( work, n, &g_fit_final, &g_sigma_final);
1438 } else {
1439 medstat(work, n, &g_fit_final, &g_sigma_final);
1440 }
1441
1442 g_sigma_final = CPL_MAX(0.01, CPL_MIN(sigmaold, g_sigma_final));
1443
1444 } else {
1445
1446 g_fit_final = 0.;
1447 g_sigma_final = 0.01;
1448 }
1449 }
1450
1451 /* Now work out the curvature in the saturated region */
1452 sort_array_index(g_sig, ncls, g_cls, HDRL_SORT_DOUBLE, CPL_SORT_ASCENDING);
1453
1454 cpl_size ii = 0;
1455 cpl_size idx = -1;
1456 cpl_size iend = 0;
1457
1458 double xcor = 12.5;
1459 double corlim1 = 0.;
1460 double corlim2 = 0.;
1461 double corval1 = 0.;
1462 double corval2 = 0.;
1463
1464 while (iend == 0 && idx < ncls-1) {
1465
1466 idx++;
1467 if (g_sig[idx] > xcor+0.25 && ii >= 3) {
1468
1469 double cfit;
1470 double csig;
1471 medstat(work, ii, &cfit, &csig);
1472
1473 for (cpl_size iloop = 0; iloop < 3; iloop++) {
1474
1475 cpl_size kk = 0;
1476 for (cpl_size k = 0; k < ii; k++) {
1477 if (work[k] <= cfit + 3. * csig)
1478 work1[kk++] = work[k];
1479 }
1480
1481 double junk;
1482 medstat(work1, kk, &cfit, &junk);
1483 }
1484
1485 if (cfit <= g_fit_final + 3. * g_sigma_final) {
1486
1487 corlim1 = xcor;
1488 corval1 = cfit;
1489
1490 } else {
1491
1492 corlim2 = xcor;
1493 corval2 = cfit;
1494
1495 iend = 1;
1496 }
1497
1498 } else {
1499
1500 work[ii++] = g_cls[idx];
1501 }
1502 }
1503
1504 /* Estimate where core measure and statistic become unreliable */
1505 if (iend == 1) {
1506 g_corlim = corlim2 - 0.5 * (corval2 - g_fit_final - 3. * g_sigma_final) / (corval2 - corval1);
1507 } else {
1508 g_corlim = corlim1;
1509 }
1510 g_corlim = CPL_MAX(g_cormin, g_corlim);
1511
1512 cpl_size kk = 0;
1513 for (cpl_size i = 0; i < g_nrows; i++) {
1514
1515 double core = g_core_flux[i];
1516 if (core >= g_corlim) {
1517 work[kk++] = g_peak_height[i] + g_skylevel;
1518 }
1519 }
1520
1521 if (kk > 0) {
1522
1523 double junk;
1524 medstat(work, kk, &g_avsat, &junk);
1525
1526 g_avsat = CPL_MAX(10000. + g_skylevel, g_avsat);
1527
1528 } else {
1529 g_avsat = 10000. + g_skylevel;
1530 }
1531
1532 /* Clean up */
1533 cpl_free(work);
1534 cpl_free(work1);
1535 cpl_free(statistic);
1536}
1537
1538/* ---------------------------------------------------------------------------*/
1552/* ---------------------------------------------------------------------------*/
1553static void medstat(double *array, cpl_size n, double *medval, double *sigval)
1554{
1555 /* Sort the array first, then choose the median. The sigma is defined
1556 * as half the distance between the two quartile points multiplied by
1557 * the appropriate scaling factor (1.48) */
1558
1559 if (n == 0) {
1560
1561 *medval = 0.;
1562 *sigval = 0.;
1563
1564 } else {
1565
1566 sort_array(array, n, sizeof(*array), HDRL_SORT_DOUBLE, CPL_SORT_ASCENDING);
1567
1568 cpl_size lev1 = ( n + 1) / 2;
1569 cpl_size lev2 = (3 * n + 3) / 4;
1570 cpl_size lev3 = ( n + 3) / 4;
1571
1572 *medval = array[lev1 - 1];
1573 *sigval = CPL_MATH_STD_MAD * 0.5 * (array[lev2 - 1] - array[lev3 - 1]);
1574 }
1575}
cpl_propertylist * hdrl_casu_tfits_get_ehu(hdrl_casu_tfits *p)
Get the propertylist for the extension header for a given hdrl_casu_tfits image.
Definition: hdrl_cat_casu.c:98
cpl_table * hdrl_casu_tfits_get_table(hdrl_casu_tfits *p)
Get the CPL table from the hdrl_casu_tfits object.
cpl_error_code hdrl_classify(hdrl_casu_tfits *catalogue, double minsize)
Do star/galaxy classification.
cpl_error_code sort_array(void *a, cpl_size nE, cpl_size sE, hdrl_sort_type type, cpl_sort_direction dir)
sort_array hdrl function for order arrays with know types. Using the type parameter for select the co...
cpl_error_code sort_array_index(double *a, cpl_size nE, void *b, hdrl_sort_type type, cpl_sort_direction dir)
sort_array_index hdrl function for sort two arrays The alghorithm sort 'a' and in the same way sort t...