X-shooter Pipeline Reference Manual 3.8.15
xsh_detect_continuum.c
Go to the documentation of this file.
1/* *
2 * This file is part of the ESO X-shooter Pipeline *
3 * Copyright (C) 2006 European Southern Observatory *
4 * *
5 * This library 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, 51 Franklin St, Fifth Floor, Boston, MA 02111-1307 USA *
18 * */
19
20/*
21 * $Author: amodigli $
22 * $Date: 2013-03-18 11:39:42 $
23 * $Revision: 1.96 $
24 */
25
26#ifdef HAVE_CONFIG_H
27#include <config.h>
28#endif
29
30/*---------------------------------------------------------------------------*/
38/*---------------------------------------------------------------------------*/
41/*---------------------------------------------------------------------------
42 Includes
43 ----------------------------------------------------------------------------*/
44
45#include <math.h>
46#include <xsh_drl.h>
47#include <xsh_data_order.h>
48#include <xsh_error.h>
49#include <xsh_utils_wrappers.h>
50#include <xsh_utils.h>
51#include <xsh_msg.h>
52#include <xsh_data_pre.h>
53#include <xsh_pfits.h>
54#include <xsh_parameters.h>
56#include <cpl.h>
57
58/*---------------------------------------------------------------------------
59 Typedefs
60 ---------------------------------------------------------------------------*/
61
62struct gauss_res {
63 double centroid,
68} ;
69
70typedef struct {
73 int flag; // flag outliers
74 double position ;
75 double pos_x ;
76 double centervalue ;
77 double sigmavalue ;
78 double final_x ;
80
81/*---------------------------------------------------------------------------
82 Functions prototypes
83 ---------------------------------------------------------------------------*/
84static cpl_error_code
86 int x, int y, int nx,
87 float *data, float *p_errs,
88 struct gauss_res *result,
90 int order, double threshold ) ;
91
92/*---------------------------------------------------------------------------
93 Implementation
94 ---------------------------------------------------------------------------*/
95
96static int Nb_noflux, Nb_nofit ;
97
98/* The BAD_POSITION_FLAG is used to flag the positions where the
99 gaussian fit failed.
100 Used in the sigma clipping
101*/
102/*
103 TBD: even with a rather large window, even if the maximum is inside the
104 window, sometimes the fit does not find correctly the maximum.
105 Probably because the maximum is too close to the edge of the window.
106 A possible solution would be to use 2 windows:
107 a "large" one to find the maximum.
108 a smaller one, centered on the maximum, to make the fit.
109*/
110#define BAD_POSITION_FLAG 999999
111#define THRESH_POSITION_FLAG 9999999
112
113
114/* Using FITS pixel convention */
115static cpl_error_code
117 int x, int y, int nx,
118 float *data, float *p_errs,
119 struct gauss_res * result,
121 int order, double threshold )
122{
123 cpl_vector *v_pos = NULL ;
124 cpl_vector *v_values = NULL ;
125 cpl_error_code err = CPL_ERROR_NONE ;
126 int l, nelem ;
127 int x0 ;
128 double flux=0.0, min_flux=0.0;
129 int search_window ;
130 int running_window ;
131 int fit_window ;
132 int x1, x2 ;
133 double *warray = NULL ;
134 int pix_shift=(y-1)*nx-1;
135
136 /* check input parameters */
137 XSH_ASSURE_NOT_NULL( detect_param);
139 XSH_ASSURE_NOT_NULL( p_errs);
140 XSH_ASSURE_NOT_NULL( result);
142
143 search_window = detect_param->search_window ;
144 fit_window = detect_param->fit_window ;
145 running_window = detect_param->running_window ;
146
147 /* Create temporary vectors */
148 // xsh_msg_dbg_high( "Entering xsh_fit_gaussian: X,Y = %d,%d (%d elements)",
149 // x, y, nelem ) ;
150 x0 = x - search_window;
151 x2 = x + search_window;
152 if ( x0 < 1 ) x0 = 1;
153 if ( x2 > nx ) x2 = nx;
154 nelem = x2 - x0 +1 ;
155 x1 = x0 ;
156 /*
157 Find maximum flux in large window using the running window:
158 ==> the maximum is the maximum of the medians in all the running windows.
159 */
160 if ( running_window != 0 ) {
161 XSH_MALLOC( warray, double, nelem);
162 for( l = 0 ; l<nelem ; l++, x0++ )
163 warray[l] = data[x0+pix_shift];
164
165 // Center of the fit window is at the maximum found
166 x0 = x1 + xsh_tools_running_median_1d_get_max( warray, nelem,
167 running_window);
168 xsh_msg_dbg_high( " Found running maximum at %d,%d (was %d)",
169 x0, y, x );
170 XSH_FREE(warray) ;
171
172 /* build vector centered on the maximum, using a smaller window */
173 nelem = (fit_window*2)+1 ;
174 x0 -= fit_window ;
175 }
176
177
178 xsh_msg_dbg_high( " Final fit window: %d,%d %d elements", x0, y, nelem ) ;
179 check( v_pos = cpl_vector_new( nelem ) ) ;
180 check( v_values = cpl_vector_new( nelem ) ) ;
181
182 /* Fill vectors */
183 for( l = 0 ; l<nelem ; l++, x0++ ) {
184 cpl_vector_set( v_pos, l, (double)x0 ) ;
185 cpl_vector_set( v_values, l, (double)data[x0+pix_shift] ) ;
186 }
187
188 err = cpl_vector_fit_gaussian( v_pos, NULL, v_values, NULL,
189 CPL_FIT_ALL,
190 &result->centroid, &result->sigma,
191 &result->area, &result->offset,
192 &result->mse, NULL, NULL ) ;
193 if ( err == CPL_ERROR_NONE ) {
194 x0 = floor( result->centroid +0.5);
195 flux = (double)data[x0+pix_shift] ;
196 //xsh_msg( " Fitted position: %d, Flux: %lf", x0, flux ) ;
197 min_flux = (double)p_errs[x0+pix_shift] * threshold ;
198 if ( flux < min_flux ) {
199 err = CPL_ERROR_UNSPECIFIED ;
200 }
201 }
202
203 if ( err != CPL_ERROR_NONE ) {
204 int i ;
205
206 if ( err == CPL_ERROR_UNSPECIFIED ) {
207 xsh_msg_dbg_medium( " NOT ENOUGH FLUX at X,Y = %d,%d (%lf < %lf)",
208 x, y, flux, min_flux ) ;
209 Nb_noflux++ ;
210 }
211 else {
212 cpl_error_reset() ;
213 /* Dump values */
214 xsh_msg_dbg_medium( " CPL_FIT_GAUSSIAN ERROR at X,Y = %d,%d", x, y ) ;
215 Nb_nofit++ ;
216 for( i = 0 ; i<nelem ; i++ ) {
217 xsh_msg_dbg_high( " X = %.0lf, Value = %lf",
218 cpl_vector_get( v_pos, i ),
219 cpl_vector_get( v_values, i ) ) ;
220 }
221 }
222 }
224 (y % 10) == 0 ) {
225 /* Save data to file (only 1/10 of Y points) */
226 char dirname1[128], dirname2[128], fname[256], cmd[256] ;
227 FILE *fout ;
228
229 sprintf( dirname1, "Ord_%s", xsh_instrument_arm_tostring( instrument ) ) ;
230 if ( access( dirname1, 0 ) != 0 ) {
231 sprintf( cmd, "mkdir %s", dirname1 ) ;
232 system( cmd ) ;
233 }
234 sprintf( dirname2, "%s/O_%02d", dirname1, order ) ;
235 if ( access( dirname2, 0 ) != 0 ) {
236 sprintf( cmd, "mkdir %s", dirname2 ) ;
237 system( cmd ) ;
238 }
239
240 sprintf( fname, "%s/fit_%04d", dirname2, y ) ;
241 fout = fopen( fname, "w" ) ;
242 for( l = 0 ; l<nelem ; l++ ) {
243 fprintf( fout, "%lf %lf %lf %lf\n", cpl_vector_get( v_pos, l ),
244 cpl_vector_get( v_values, l ),
245 result->centroid, result->sigma ) ;
246 }
247 fclose( fout ) ;
248 }
249
250 cleanup:
251 xsh_free_vector( &v_pos ) ;
252 xsh_free_vector( &v_values ) ;
253 return err ;
254}
255
256static double * Deltas = NULL, * PosY = NULL, * PosX = NULL,
257 * XorderPos = NULL ;
258static int * Orders = NULL ;
259static int DeltaSize = 0 ;
260static int DeltaPoints = 0 ;
261
262static cpl_frame*
264 ORDERPOS_QC_PARAM * qcparam )
265{
266 int dbg_lvl ;
267 FILE * flog = NULL ;
268 char logname[256];
269 int n ;
270 cpl_frame * resid_frame = NULL ;
271 xsh_resid_order_tab * resid_tab = NULL ;
272 char frame_name[256] ;
273 char tag[256];
274
276
277 if ( (dbg_lvl = xsh_debug_level_get()) >= XSH_DEBUG_LEVEL_LOW ) {
278 // Output ASCII file
279 // First open output file
280 sprintf(logname,"orderpos_%s.dat",xsh_instrument_arm_tostring(instrument));
281 if ( (flog = fopen( logname, "w" ) ) == NULL )
282 xsh_msg( "Cant open log file \"%s\"", logname ) ;
283 else xsh_msg( " ASCII File '%s'", logname ) ;
284 }
285
286 for ( n = 0 ; n<DeltaPoints ; n++ ) {
287 if ( dbg_lvl >= XSH_DEBUG_LEVEL_LOW && flog != NULL )
288 fprintf( flog, "%d %lf %lf %lf %lf\n",
289 *(Orders+n), *(PosY+n), *(PosX+n),
290 *(XorderPos+n), *(Deltas+n) ) ;
291 }
292
294 Deltas, XorderPos ) ) ;
295 resid_tab->residmin = qcparam->residmin ;
296 resid_tab->residmax = qcparam->residmax ;
297 resid_tab->residavg = qcparam->residavg ;
298 resid_tab->residrms = qcparam->residrms ;
299
300 sprintf(tag,"%s%s%s",XSH_ORDERPOS_RESID_TAB,"_",
302 sprintf(frame_name,"%s.fits",tag);
303
304 check( resid_frame = xsh_resid_order_save( resid_tab, frame_name,
305 instrument,qcparam,tag ) ) ;
306
307 cleanup:
308 xsh_resid_order_free(&resid_tab);
309
310 if(cpl_error_get_code() != CPL_ERROR_NONE) {
311 xsh_free_frame(&resid_frame);
312 }
313 if(flog != NULL) {
314 fclose(flog);
315 }
316 return resid_frame;
317
318}
319
320/* the following generate a leak */
322 CENTROIDS_STRUCT * pcent, int npts )
323{
324 int j, absorder ;
325 double diff ;
326 double * Delta0 ;
327 int prevSize ;
328
329 absorder = list->list[order].absorder ;
330 xsh_msg_dbg_low( " Cumulate: Order %d, Nb of Points: %d", absorder, npts ) ;
331 prevSize = DeltaSize ;
332
333 DeltaSize += npts ;
334 if ( order == 0 ) {
335 XSH_CALLOC( Deltas, double, DeltaSize ) ;
336 XSH_CALLOC( PosX, double, DeltaSize ) ;
337 XSH_CALLOC( PosY, double, DeltaSize ) ;
338 XSH_CALLOC( Orders, int, DeltaSize ) ;
339 XSH_CALLOC( XorderPos, double, DeltaSize ) ;
340 }
341 else {
342 //XSH_REALLOC( Deltas, double, DeltaSize ) ;
343 Deltas = cpl_realloc( Deltas, DeltaSize*sizeof(double) ) ;
344 PosX = cpl_realloc( PosX, DeltaSize*sizeof(double) ) ;
345 PosY = cpl_realloc( PosY, DeltaSize*sizeof(double) ) ;
346 Orders = cpl_realloc( Orders, DeltaSize*sizeof(int) ) ;
347 XorderPos = cpl_realloc( XorderPos, DeltaSize*sizeof(double) ) ;
348 }
349 xsh_msg_dbg_low( "Cumulated points: %d", DeltaSize ) ;
350 Delta0 = Deltas + prevSize ;
351
352
353 for( j = 0 ; j<npts ; j++, pcent++ ) {
354 double x1 ;
355 double y ;
356
357 y = pcent->position ;
358 x1 = cpl_polynomial_eval_1d( list->list[order].cenpoly, y, NULL ) ;
359 diff= ( x1 - pcent->centervalue ) ;
360
361 xsh_msg_dbg_medium( " ---- Y = %lf, x0 = %lf, x1 = %lf, diff = %lf", y,
362 pcent->centervalue, x1, diff ) ;
363 *(Deltas+DeltaPoints) = diff ;
364 *(PosX+DeltaPoints) = pcent->centervalue ;
365 *(PosY+DeltaPoints) = y ;
366 *(Orders+DeltaPoints) = absorder ;
367 *(XorderPos+DeltaPoints) = x1 ;
368 DeltaPoints++ ;
369 }
370 {
371 // Residuals per order
372 cpl_vector *v_avg = NULL ;
373 double residavg, residmax, residmin, residrms ;
374 v_avg = cpl_vector_wrap( npts, Delta0 ) ;
375
376 residavg = cpl_vector_get_mean( v_avg ) ;
377 residmax = cpl_vector_get_max( v_avg ) ;
378 residmin = cpl_vector_get_min( v_avg ) ;
379 residrms = cpl_vector_get_stdev( v_avg ) ;
380 xsh_msg_dbg_low( " Residuals for Order %d:", absorder ) ;
381 xsh_msg_dbg_low( " Mean: %lf, Max: %lf, Min: %lf, Rms: %lf",
382 residavg, residmax, residmin, residrms ) ;
383 xsh_msg_dbg_low( " StartY: %d, Endy: %d", list->list[order].starty,
384 list->list[order].endy ) ;
385 cpl_vector_unwrap( v_avg ) ;
386 }
387
388 cleanup:
389 return ;
390}
391
392static cpl_frame*
395{
396 cpl_vector *v_avg = NULL ;
397 cpl_frame* resid_frame=NULL;
398
399 check(v_avg = cpl_vector_wrap( DeltaPoints, Deltas )) ;
400 assure( v_avg != NULL, cpl_error_get_code(),
401 "Cant wrap the v_avg vector" ) ;
402
403 qcparam->residavg = cpl_vector_get_mean( v_avg ) ;
404 qcparam->residmax = cpl_vector_get_max( v_avg ) ;
405 qcparam->residmin = cpl_vector_get_min( v_avg ) ;
406 qcparam->residrms = cpl_vector_get_stdev( v_avg ) ;
407 check(resid_frame=create_resid_tab( instrument, qcparam ) );
408
409 cleanup:
410 cpl_vector_unwrap( v_avg ) ;
411 XSH_FREE( Deltas ) ;
412 XSH_FREE( PosX ) ;
413 XSH_FREE( PosY ) ;
414 XSH_FREE( Orders ) ;
416 if(cpl_error_get_code() != CPL_ERROR_NONE) {
417 xsh_free_frame(&resid_frame);
418 }
419 return resid_frame;
420
421}
422
423static int comp_pos( const void * un, const void * deux )
424{
425 CENTROIDS_STRUCT * one = (CENTROIDS_STRUCT *)un ;
426 CENTROIDS_STRUCT * two = (CENTROIDS_STRUCT *)deux ;
427
428 if ( one->position < two->position ) return -1 ;
429 else if ( one->position == two->position ) return 0 ;
430 else return 1 ;
431}
432
435{
436 cpl_propertylist * header=NULL ;
437
440
441 header = xsh_order_list_get_header( list ) ;
442 XSH_ASSURE_NOT_NULL( header );
443
444 check( xsh_pfits_set_qc( header, &pqc->residmin,
446 instrument ) ) ;
447 check( xsh_pfits_set_qc( header, &pqc->residmax,
449 instrument ) ) ;
450 check( xsh_pfits_set_qc( header, &pqc->residavg,
452 instrument ) ) ;
453 check( xsh_pfits_set_qc( header, &pqc->residrms,
455 instrument ) ) ;
456 check( xsh_pfits_set_qc( header, &pqc->ndet,
458 instrument ) ) ;
459 check( xsh_pfits_set_qc( header, &pqc->npred,
461 instrument ) ) ;
462 /*
463 check( xsh_pfits_set_qc( header, &pqc->max_pred,
464 QC_ORD_ORDERPOS_MAX_PRED,
465 instrument ) ) ;
466 check( xsh_pfits_set_qc( header, &pqc->min_pred,
467 QC_ORD_ORDERPOS_MIN_PRED,
468 instrument ) ) ;
469 check( xsh_pfits_set_qc( header, &pqc->nposall,
470 QC_ORD_ORDERPOS_NPOSALL,
471 instrument ) ) ;
472 check( xsh_pfits_set_qc( header, &pqc->npossel,
473 QC_ORD_ORDERPOS_NPOSSEL,
474 instrument ) ) ;
475 */
476
477
478 cleanup:
479
480 return ;
481}
482
506/*---------------------------------------------------------------------------*/
507cpl_frame* xsh_detect_continuum( cpl_frame *frame, cpl_frame *order_table,
508 cpl_frame *spectral_frame,
509 xsh_detect_continuum_param *detect_param,
510 xsh_clipping_param *dcn_clipping,
511 xsh_instrument *instr,
512 cpl_frame** resid_frame)
513{
514 /* MUST BE DEALLOCATED in caller */
515 cpl_frame *result = NULL;
516 /* ALLOCATED locally */
517 xsh_pre *pre = NULL;
518 xsh_order_list *list = NULL;
519 xsh_order_list *guess_list = NULL;
520 CENTROIDS_STRUCT *Centroids = NULL;
521 cpl_vector *centers = NULL ;
522 cpl_vector *xpos = NULL ;
523
524 /* Others */
525 float *data = NULL;
526 float *p_errs = NULL;
527 int y = 0;
528 int i = 0;
529 int ndetected = 0 ;
530 ORDERPOS_QC_PARAM ord_qc_param ;
531 static FILE *flog = NULL ;
532 int step, degree;
533 double fit_threshold ;
534
535 /* check input */
536 XSH_ASSURE_NOT_NULL( frame);
537 XSH_ASSURE_NOT_NULL( order_table);
538 XSH_ASSURE_NOT_NULL( detect_param);
539 XSH_ASSURE_NOT_NULL( dcn_clipping);
540 XSH_ASSURE_NOT_NULL( instr);
541
542 /* Running window may be zero */
543 assure(detect_param->search_window > 0 &&
544 detect_param->fit_window > 0, CPL_ERROR_NULL_INPUT,
545 "Windows must be > 0" ) ;
546
547 /* parameters */
548 fit_threshold = detect_param->fit_threshold ;
549 degree = detect_param->poly_degree ;
550
551 /* Showing parameters */
552 xsh_msg_dbg_medium("Clipping parameters :");
553 xsh_msg_dbg_medium(" Sigma %f Niter %d Frac %f", dcn_clipping->sigma,
554 dcn_clipping->niter, dcn_clipping->frac);
555
556 /* load the frames */
557 check( pre = xsh_pre_load( frame, instr));
558 check( list = xsh_order_list_load (order_table, instr));
559
560 assure(detect_param->search_window > 0 &&
561 detect_param->search_window < (pre->nx/list->size),
562 CPL_ERROR_ILLEGAL_INPUT,
563 "Search windows half size %d must be > 0 and < %d change value of "
564 "parameter detectcontinuum-search-win-hsize",
565 detect_param->search_window ,(pre->nx/list->size)) ;
566
568 /* Save the guessed order list (used to calculate QC parameters) */
569 check( guess_list = xsh_order_list_load( order_table, instr));
570
571 /* clean header */
572 xsh_free_propertylist( &(list->header));
574
575 XSH_ASSURE_NOT_NULL( guess_list);
576
577 /* get the data */
578 check( data = cpl_image_get_data_float(pre->data));
579 check( p_errs = cpl_image_get_data_float( pre->errs));
580
581 /* Create/initialize temporary array (maximum size) */
582 XSH_MALLOC( Centroids, CENTROIDS_STRUCT, pre->ny);
583
584 /* detect order continuum */
585 /* Loop over all orders */
586 xsh_msg_dbg_high( "Loop over %d Orders", list->size);
587
588 step = detect_param->poly_step ;
589
590
591 for(i=0; i< list->size; i++){
592 int x = 0 ;
593 double fx ;
594 int npts = 0, totpts = 0, npos, nn, mm, niter, totnbad = 0 ;
595 cpl_error_code err ;
596 int low_y=0, up_y=0;
597 int ycenter ;
598 int absorder ;
599
600 Nb_nofit = 0 ;
601 Nb_noflux = 0 ;
602 absorder = list->list[i].absorder ;
603 /* Calculate at the center */
604 ycenter = pre->ny/2;
605
606 if ( ycenter < list->list[i].starty ) ycenter = list->list[i].starty;
607 /* Default position of the center from input order table */
608 check( fx = cpl_polynomial_eval_1d(list->list[i].cenpoly,
609 (double)ycenter,NULL));
610 /* rounding x value */
611 x = floor( fx+0.5);
612
613 /* X, Y using FITS convention */
614
615 xsh_msg_dbg_medium( ">>>> Order #%d, At Center X,Y: %d,%d",
616 absorder, x, ycenter ) ;
617
618 /* VALID X,Y coordinate*/
619 if ( x >= 1 && x <= pre->nx) {
620 struct gauss_res fit_result ;
621
622 /* Fit Gaussian */
623 err = xsh_fit_gaussian( detect_param, x, ycenter,
624 pre->nx, data, p_errs,
625 &fit_result,
626 instr, absorder,
627 fit_threshold );
628
629 if ( err == CPL_ERROR_NONE ) {
630 /* And now store the result of the fit somewhere (?) */
631 (Centroids+npts)->position = (double) ycenter ;
632 (Centroids+npts)->pos_x = (double) x;
633 (Centroids+npts)->centervalue = fit_result.centroid ;
634 (Centroids+npts)->sigmavalue = fit_result.sigma ;
635 (Centroids+npts)->absorder = absorder ;
636 npts++ ;
637 }
638 totpts++ ;
639 }
640
641 /* Loop over all Y pixels starting from center to starty */
642 xsh_msg_dbg_medium( " Down Y from %d to %d",
643 ycenter -1, list->list[i].starty ) ;
644 low_y = ycenter ;
645 for( y = ycenter - 1; y >= list->list[i].starty ; y-=step ) {
646
647 check( fx=cpl_polynomial_eval_1d(list->list[i].cenpoly,
648 (double)y,NULL));
649 x = floor( fx+0.5) ;
650 /* VALID X,Y coordinate*/
651 if ( x >= 1 && x <= pre->nx) {
652 struct gauss_res fit_result ;
653
654 /* Fit Gaussian */
655 check_msg(err = xsh_fit_gaussian( detect_param, x, y,
656 pre->nx, data, p_errs,
657 &fit_result,
658 instr, list->list[i].absorder,
659 fit_threshold ),"Try to increase detectcontinuum-fit-win-hsize") ;
660 if ( err == CPL_ERROR_NONE ) {
661 /* And now store the result of the fit somewhere (?) */
662 (Centroids+npts)->position = (double)y ;
663 (Centroids+npts)->pos_x = (double)x;
664 (Centroids+npts)->centervalue = fit_result.centroid ;
665 (Centroids+npts)->sigmavalue = fit_result.sigma ;
666 (Centroids+npts)->absorder = absorder ;
667 low_y = y ;
668 npts++ ;
669 } else {
670 cpl_error_reset();
671 }
672 totpts++ ;
673 }
674 }
675
676 xsh_msg_dbg_medium( " --> Nb of points: %d", npts ) ;
677 /* Loop over all Y pixels starting from center to endy */
678 xsh_msg_dbg_medium( " Up Y from %d to %d",
679 ycenter+1, list->list[i].endy ) ;
680 up_y = ycenter ;
681 for( y = ycenter + 1; y <= list->list[i].endy ; y+=step ) {
682 check( fx=cpl_polynomial_eval_1d(list->list[i].cenpoly,
683 (double)y,NULL));
684 x = floor( fx+0.5);
685 /* VALID X,Y coordinate*/
686 if ( x >= 1 && x <= pre->nx) {
687 struct gauss_res fit_result ;
688
689 /* Fit Gaussian */
690 err = xsh_fit_gaussian( detect_param, x, y,
691 pre->nx, data, p_errs,
692 &fit_result,
693 instr, list->list[i].absorder,
694 fit_threshold ) ;
695 if ( err == CPL_ERROR_NONE ) {
696 /* And now store the result of the fit somewhere */
697 (Centroids+npts)->position = (double)y ;
698 (Centroids+npts)->pos_x = (double)x ;
699 (Centroids+npts)->centervalue = fit_result.centroid ;
700 (Centroids+npts)->sigmavalue = fit_result.sigma ;
701 (Centroids+npts)->absorder = absorder ;
702 up_y = y ;
703 npts++ ;
704
705 } else {
706 cpl_error_reset();
707 }
708 totpts++ ;
709 }
710 }
711
713 FILE* debug_file = NULL;
714 char debug_name[256];
715 int idebug;
716
717 sprintf(debug_name, "centroid_%d.reg", list->list[i].absorder);
718
719 debug_file = fopen( debug_name, "w");
720 fprintf( debug_file, "# Region file format: DS9 version 4.0\n"\
721 "global color=red font=\"helvetica 4 normal\""\
722 "select=1 highlite=1 edit=1 move=1 delete=1 include=1 fixed=0 "\
723 "source\nimage\n");
724 for( idebug=0; idebug < npts; idebug++){
725 fprintf( debug_file, "point(%f,%f) #point=cross color=blue\n",
726 Centroids[idebug].pos_x, Centroids[idebug].position);
727 fprintf( debug_file, "point(%f,%f) #point=cross color=red\n",
728 Centroids[idebug].centervalue, Centroids[idebug].position);
729 }
730 fclose( debug_file);
731 }
732 xsh_msg_dbg_medium( " --> Nb of points: %d", npts ) ;
733 xsh_msg_dbg_low( " No enough flux: %d, No fit: %d", Nb_noflux,
734 Nb_nofit ) ;
735
736 xsh_msg_dbg_high( " Nb of correct points found: %d/%d",
737 npts, totpts ) ;
738 xsh_msg_dbg_high( " LowY: %d, UpY: %d", low_y, up_y ) ;
739
740
741 assure(npts > 3,CPL_ERROR_ILLEGAL_OUTPUT,
742 "can't fit polynomial solution with nb of points %d", npts );
743
744 /*
745 Now ready to fit a polynomial.
746 But first, order data by positions !
747 */
748 qsort( Centroids, npts, sizeof( CENTROIDS_STRUCT ), comp_pos ) ;
749
750 /********* Sigma clipping
751 After fit polynome, suppress "bad" positions
752 then refit the polynomial
753 **********/
754 xsh_msg( "Sigma Clipping on residuals over %d pts", npts ) ;
755
756 npos = npts ;
757 //First remove too large outliers
758 {
759 double poly_rms ;
760 int nthresh = 0 ;
761 /* put the start and end of order in Y */
762 list->list[i].starty = low_y ;//Centroids->position ;
763 list->list[i].endy = up_y ; //(Centroids+npos-1)->position ;
764
765 /* create vector from values */
766 check( xpos = cpl_vector_new( npos ) ) ;
767 check( centers = cpl_vector_new( npos ) ) ;
768 {
769 int j ;
770 for( j = 0 ; j<npos ; j++ ) {
771 cpl_vector_set( xpos, j, (Centroids+j)->position ) ;
772 cpl_vector_set( centers, j, (Centroids+j)->centervalue ) ;
773 }
774 }
775
776 /* create polynomial solutions */
778
779 xsh_msg_dbg_low( "Polynomial degree: %d", degree ) ;
780 check(list->list[i].cenpoly =
781 xsh_polynomial_fit_1d_create( xpos, centers, degree, &poly_rms));
782 xsh_free_vector( &centers ) ;
783 xsh_free_vector( &xpos ) ;
784
785
786
787
788 // Now sigma clipping outliers aboth fixed threshold
789
790 poly_rms = sqrt( poly_rms ) ;
791 xsh_msg_dbg_low( " Sigma Clipping - Polynomial RMS: %lf",
792 poly_rms ) ;
793
794 for( nn = 0 ; nn < npos ; nn++ ) {
795 /* Compute distance between Centroids->xpos and poly value at x
796 with rms of polynomial
797 */
798 double xpoly, delta ;
799
800 xpoly = cpl_polynomial_eval_1d( list->list[i].cenpoly,
801 (Centroids+nn)->position,
802 NULL ) ;
803 delta = fabs( xpoly - (Centroids+nn)->centervalue) ;
804 if ( delta > dcn_clipping->res_max ) {
805 /* Reject this position (set the position at an
806 impossible value) */
807 xsh_msg_dbg_high( " Rejected at %.0lf,%.0lf (%lf > %lf)",
808 (Centroids+nn)->centervalue,
809 (Centroids+nn)->position,
810 delta, poly_rms ) ;
811 (Centroids+nn)->position = THRESH_POSITION_FLAG ;
812 (Centroids+nn)->flag = THRESH_POSITION_FLAG ;
813 nthresh++ ;
814 }
815 }
816
817
818
819 totnbad += nthresh ;
820 xsh_msg_dbg_low( " Rejected Positions: %d (%d)", nthresh, totnbad ) ;
821
822 /*
823 if too many rejected positions, discard the order
824 */
825 if ( ((float)(npts-totnbad)/(float)npts) < dcn_clipping->frac ) {
826 /* Tag the order as undetected and break */
827 list->list[i].starty = -1 ;
828 list->list[i].endy = -1 ;
829 xsh_msg_warning( "**** Too many rejected points: %d/%d (%.2f) Discard Order %d",
830 totnbad, npts, (float)(npts-totnbad)/(float)npts, absorder ) ;
831 xsh_msg_warning("Try to increase detectcontinuum-clip-res-max and/or decrease detectcontinuum-clip-frac and/or detectcontinuum-search-win-hsize");
832 break ;
833 }
834
835 /* Reorder Centroids (suppress bad positions) */
836 for( nn = 0, mm = 0 ; nn<npos ; nn++ ) {
837 if ( (Centroids+nn)->position != THRESH_POSITION_FLAG ) {
838 if ( mm != nn ) *(Centroids+mm) = *(Centroids+nn) ;
839 mm++ ;
840 }
841 }
842 npts = mm ;
843 }
844
845 npos = npts ;
846 for( niter = 0 ; niter < dcn_clipping->niter ; niter++ ) {
847 double poly_rms ;
848 int nbad = 0 ;
849
850 /* put the start and end of order in Y */
851 list->list[i].starty = low_y ;//Centroids->position ;
852 list->list[i].endy = up_y ; //(Centroids+npos-1)->position ;
853
854 xsh_msg_dbg_low( " Iteration %d, Starty = %d, Endy = %d, Npos = %d",
855 niter, list->list[i].starty, list->list[i].endy, npos ) ;
856 /* create vector from values */
857 check( xpos = cpl_vector_new( npos ) ) ;
858 check( centers = cpl_vector_new( npos ) ) ;
859 {
860 int j ;
861 for( j = 0 ; j<npos ; j++ ) {
862 cpl_vector_set( xpos, j, (Centroids+j)->position ) ;
863 cpl_vector_set( centers, j, (Centroids+j)->centervalue ) ;
864 }
865 }
866
867 /* create polynomial solutions */
869
870 xsh_msg_dbg_low( "Polynomial degree: %d", degree ) ;
871 check(list->list[i].cenpoly =
872 xsh_polynomial_fit_1d_create( xpos, centers, degree, &poly_rms));
873 xsh_free_vector( &centers ) ;
874 xsh_free_vector( &xpos ) ;
875 {
876 double coeff0, coeff1, coeff2 ;
877 cpl_size icoeff = 0 ;
878
879 coeff0 = cpl_polynomial_get_coeff( list->list[i].cenpoly, &icoeff ) ;
880 icoeff = 1 ;
881 coeff1 = cpl_polynomial_get_coeff( list->list[i].cenpoly, &icoeff ) ;
882 icoeff = 2 ;
883 coeff2 = cpl_polynomial_get_coeff( list->list[i].cenpoly, &icoeff ) ;
884 xsh_msg_dbg_low( " Calculated Poly: %lf %lf %lf", coeff0, coeff1, coeff2 ) ;
885 icoeff = 0 ;
886 coeff0 = cpl_polynomial_get_coeff( guess_list->list[i].cenpoly, &icoeff ) ;
887 icoeff = 1 ;
888 coeff1 = cpl_polynomial_get_coeff( guess_list->list[i].cenpoly, &icoeff ) ;
889 icoeff = 2 ;
890 coeff2 = cpl_polynomial_get_coeff( guess_list->list[i].cenpoly, &icoeff ) ;
891 xsh_msg_dbg_low( " Initial Poly: %lf %lf %lf", coeff0, coeff1, coeff2 ) ;
892 }
893 /*
894 Now sigma clipping
895 */
896 poly_rms = sqrt( poly_rms ) ;
897 xsh_msg_dbg_low( " Sigma Clipping - Polynomial RMS: %lf", poly_rms ) ;
898
899 for( nn = 0 ; nn < npos ; nn++ ) {
900 /* Compute distance between Centroids->xpos and poly value at x
901 with rms of polynomial
902 */
903 double xpoly, delta ;
904
905 xpoly = cpl_polynomial_eval_1d( list->list[i].cenpoly,
906 (Centroids+nn)->position,
907 NULL ) ;
908 delta = fabs( xpoly - (Centroids+nn)->centervalue) ;
909 if ( delta > poly_rms*dcn_clipping->sigma ) {
910 /* Reject this position (set the position at an
911 impossible value) */
912 xsh_msg_dbg_high( " Rejected at %.0lf,%.0lf (%lf > %lf)",
913 (Centroids+nn)->centervalue,
914 (Centroids+nn)->position,
915 delta, poly_rms ) ;
916 (Centroids+nn)->position = BAD_POSITION_FLAG ;
917 (Centroids+nn)->flag = BAD_POSITION_FLAG ;
918 nbad++ ;
919 }
920 }
921 if ( nbad == 0 ) break ;
922 totnbad += nbad ;
923 xsh_msg_dbg_low( " Rejected Positions: %d (%d)", nbad, totnbad ) ;
924
925 /*
926 if too many rejected positions, discard the order
927 */
928 if ( ((float)(npts-totnbad)/(float)npts) < dcn_clipping->frac ) {
929 /* Tag the order as undetected and break */
930 list->list[i].starty = -1 ;
931 list->list[i].endy = -1 ;
932 xsh_msg( "**** Too many rejected points: %d/%d (%.2f) Discard Order %d",
933 totnbad, npts, (float)(npts-totnbad)/(float)npts, absorder ) ;
934 break ;
935 }
936
937 /* Reorder Centroids (suppress bad positions) */
938 for( nn = 0, mm = 0 ; nn<npos ; nn++ ) {
939 if ( (Centroids+nn)->position != BAD_POSITION_FLAG ) {
940 if ( mm != nn ) *(Centroids+mm) = *(Centroids+nn) ;
941 mm++ ;
942 }
943 }
944 npos = mm ;
945 }
946
947 if ( list->list[i].starty != -1 ) {
948 double coeff0, coeff1, coeff2 ;
949 cpl_size icoeff = 0 ;
950
951 ndetected++ ;
952 coeff0 = cpl_polynomial_get_coeff( list->list[i].cenpoly, &icoeff ) ;
953 icoeff = 1 ;
954 coeff1 = cpl_polynomial_get_coeff( list->list[i].cenpoly, &icoeff ) ;
955 icoeff = 2 ;
956 coeff2 = cpl_polynomial_get_coeff( list->list[i].cenpoly, &icoeff ) ;
957 xsh_msg( " Polynomial Coeffs: %lf %lf %lf",
958 coeff0, coeff1, coeff2 ) ;
959
960
961 // Prepare to calculate QC parameters
962 cumulate_qc_parameter( i, list, Centroids, npos ) ;
963 }
964 }
965
966 xsh_msg( " ++ Nb of Detected Orders: %d", ndetected ) ;
967 assure(ndetected > 0,CPL_ERROR_ILLEGAL_INPUT,
968 "parameter detectcontinuum-search-wind-hsize may have a too large value or detectcontinuum-ordertab-deg-y or detectcontinuum-clip-sigma or detectcontinuum-clip-res-max may have a too small value");
969 if(DeltaPoints>0) {
970 check(*resid_frame=calculate_qc_parameters( &ord_qc_param, instr )) ;
971 }
972
973 ord_qc_param.ndet = ndetected ;
974
975 //xsh_order_list_dump( list, "final_order.out" ) ;
976 /*
977 Setup more QC parameters
978 */
979 ord_qc_param.npred = list->size ;
980 ord_qc_param.max_pred = 0;
981 ord_qc_param.min_pred = 0 ;
982 ord_qc_param.nposall = 0 ;
983 ord_qc_param.npossel = 0 ;
984
985 /*
986 Set QC parameters
987 */
988 check(set_qc_parameters( list, &ord_qc_param, instr ) );
989
990 /*
991 Save table frame
992 */
993 {
994 char frame_name[256];
995 char tag[256];
996 sprintf(tag,"%s",XSH_GET_TAG_FROM_ARM(XSH_ORDER_TAB_CENTR,instr));
997 sprintf(frame_name,"%s%s",tag,".fits");
998
999 check(result = xsh_order_list_save(list,instr,frame_name,tag,pre->ny ));
1000 //xsh_add_temporary_file( frame_name ) ;
1001
1002 xsh_msg_dbg_high("%s Created", frame_name ) ;
1003 }
1004
1005
1006
1007 cleanup:
1008 if ( flog ) fclose( flog ) ;
1009
1010 xsh_free_vector( &centers ) ;
1011 xsh_free_vector( &xpos ) ;
1012 XSH_FREE( Centroids ) ;
1013 xsh_pre_free(&pre);
1014 xsh_order_list_free(&list);
1015 xsh_order_list_free(&guess_list);
1016
1017
1018 return result;
1019}
1020
static int starty
static int degree
static const double step
static xsh_instrument * instrument
cpl_frame * xsh_order_list_save(xsh_order_list *order_list, xsh_instrument *instrument, const char *filename, const char *tag, const int ny)
Save an order list to a frame.
xsh_order_list * xsh_order_list_load(cpl_frame *frame, xsh_instrument *instr)
load an order list from a frame
cpl_propertylist * xsh_order_list_get_header(xsh_order_list *list)
get header of the table
void xsh_order_list_free(xsh_order_list **list)
free memory associated to an order_list
void xsh_order_list_verify(xsh_order_list *list, int ny)
xsh_pre * xsh_pre_load(cpl_frame *frame, xsh_instrument *instr)
Load a xsh_pre structure from a frame.
Definition: xsh_data_pre.c:849
int xsh_pre_get_ny(const xsh_pre *pre)
Get ny of pre structure.
void xsh_pre_free(xsh_pre **pre)
Free a xsh_pre structure.
Definition: xsh_data_pre.c:823
xsh_resid_order_tab * xsh_resid_order_create(int size, int *orders, double *posx, double *posy, double *resx, double *polx)
Create a residual tab structure.
void xsh_resid_order_free(xsh_resid_order_tab **resid)
Free memory associated to a resid_tab.
cpl_frame * xsh_resid_order_save(xsh_resid_order_tab *resid, const char *filename, xsh_instrument *instrument, ORDERPOS_QC_PARAM *ord_qc_param, const char *tag)
Save a residual tab to a frame.
static cpl_frame * create_resid_tab(xsh_instrument *instrument, ORDERPOS_QC_PARAM *qcparam)
static int DeltaSize
static cpl_frame * calculate_qc_parameters(ORDERPOS_QC_PARAM *qcparam, xsh_instrument *instrument)
static int Nb_nofit
static double * XorderPos
static double * PosY
static int * Orders
cpl_frame * xsh_detect_continuum(cpl_frame *frame, cpl_frame *order_table, cpl_frame *spectral_frame, xsh_detect_continuum_param *detect_param, xsh_clipping_param *dcn_clipping, xsh_instrument *instr, cpl_frame **resid_frame)
Detect order and compute polynomial description of ordermin and order max. Uses a guess order table i...
static cpl_error_code xsh_fit_gaussian(xsh_detect_continuum_param *detect_param, int x, int y, int nx, float *data, float *p_errs, struct gauss_res *result, xsh_instrument *instrument, int order, double threshold)
static double * Deltas
static int comp_pos(const void *un, const void *deux)
static void cumulate_qc_parameter(int order, xsh_order_list *list, CENTROIDS_STRUCT *pcent, int npts)
static double * PosX
#define THRESH_POSITION_FLAG
static int DeltaPoints
static void set_qc_parameters(xsh_order_list *list, ORDERPOS_QC_PARAM *pqc, xsh_instrument *instrument)
#define BAD_POSITION_FLAG
static int Nb_noflux
#define assure(CONDITION, ERROR_CODE,...)
Definition: xsh_error.h:54
#define check(COMMAND)
Definition: xsh_error.h:71
#define check_msg(COMMAND,...)
Definition: xsh_error.h:62
#define XSH_ASSURE_NOT_NULL(pointer)
Definition: xsh_error.h:99
const char * xsh_instrument_arm_tostring(xsh_instrument *i)
Get the string associated with an arm.
int mm
int * y
int * x
#define xsh_msg_warning(...)
Print an warning message.
Definition: xsh_msg.h:88
#define xsh_msg_dbg_medium(...)
Definition: xsh_msg.h:44
#define xsh_msg(...)
Print a message on info level.
Definition: xsh_msg.h:121
#define xsh_msg_dbg_low(...)
Definition: xsh_msg.h:48
#define xsh_msg_dbg_high(...)
Definition: xsh_msg.h:40
void xsh_pfits_set_qc(cpl_propertylist *plist, void *value, const char *kw, xsh_instrument *instrument)
void xsh_free_polynomial(cpl_polynomial **p)
Deallocate a polynomial and set the pointer to NULL.
Definition: xsh_utils.c:2194
void xsh_free_vector(cpl_vector **v)
Deallocate a vector and set the pointer to NULL.
Definition: xsh_utils.c:2284
int xsh_debug_level_get(void)
get debug level
Definition: xsh_utils.c:3142
void xsh_free_frame(cpl_frame **f)
Deallocate a frame and set the pointer to NULL.
Definition: xsh_utils.c:2269
int xsh_tools_running_median_1d_get_max(double *tab, int size, int wsize)
get max of a list of doubles after running median
Definition: xsh_utils.c:2748
void xsh_free_propertylist(cpl_propertylist **p)
Deallocate a property list and set the pointer to NULL.
Definition: xsh_utils.c:2179
cpl_propertylist * header
xsh_order * list
cpl_polynomial * cenpoly
cpl_image * data
Definition: xsh_data_pre.h:65
cpl_image * errs
Definition: xsh_data_pre.h:68
int nx
int niter
Definition: xsh_detmon_lg.c:82
int threshold
Definition: xsh_detmon_lg.c:90
int n
Definition: xsh_detmon_lg.c:92
int order
Definition: xsh_detmon_lg.c:80
#define XSH_ORDERPOS_RESID_TAB
Definition: xsh_dfs.h:320
#define XSH_GET_TAG_FROM_ARM(TAG, instr)
Definition: xsh_dfs.h:1548
#define XSH_ORDER_TAB_CENTR
Definition: xsh_dfs.h:553
#define QC_ORD_ORDERPOS_RESIDMAX
Definition: xsh_pfits_qc.h:175
#define QC_ORD_ORDERPOS_RESIDAVG
Definition: xsh_pfits_qc.h:176
#define QC_ORD_ORDERPOS_NPRED
Definition: xsh_pfits_qc.h:190
#define QC_ORD_ORDERPOS_RESIDMIN
Definition: xsh_pfits_qc.h:174
#define QC_ORD_ORDERPOS_RESIDRMS
Definition: xsh_pfits_qc.h:177
#define QC_ORD_ORDERPOS_NDET
Definition: xsh_pfits_qc.h:187
#define XSH_NEW_PROPERTYLIST(POINTER)
Definition: xsh_utils.h:70
#define XSH_FREE(POINTER)
Definition: xsh_utils.h:92
@ XSH_DEBUG_LEVEL_HIGH
Definition: xsh_utils.h:138
@ XSH_DEBUG_LEVEL_LOW
Definition: xsh_utils.h:137
@ XSH_DEBUG_LEVEL_MEDIUM
Definition: xsh_utils.h:138
#define XSH_MALLOC(POINTER, TYPE, SIZE)
Definition: xsh_utils.h:49
#define XSH_CALLOC(POINTER, TYPE, SIZE)
Definition: xsh_utils.h:56
cpl_polynomial * xsh_polynomial_fit_1d_create(const cpl_vector *x_pos, const cpl_vector *values, int degree, double *mse)