45 #include <uves_extract.h>
47 #include <uves_extract_iterate.h>
48 #include <uves_extract_profile.h>
49 #include <uves_parameters.h>
50 #include <uves_utils.h>
51 #include <uves_utils_cpl.h>
52 #include <uves_utils_wrappers.h>
54 #include <uves_plot.h>
56 #include <uves_dump.h>
57 #include <uves_error.h>
60 #include <irplib_utils.h>
70 #define DATA(name, pos) (name[((pos)->x-1)+((pos)->y-1)*(pos)->nx])
73 #define SPECTRUM_DATA(name, pos) (name[((pos)->x-1)+((pos)->order-(pos)->minorder)*(pos)->nx])
76 #define ISBAD(weights, pos) (weights[((pos)->x-1)+((pos)->y-1)*(pos)->nx] < 0)
79 #define SETBAD(weights, image_bpm, pos) \
81 weights [((pos)->x-1)+((pos)->y-1)*(pos)->nx] = -1.0; \
82 image_bpm[((pos)->x-1)+((pos)->y-1)*(pos)->nx] = CPL_BINARY_1;\
86 #define ISGOOD(bpm, pos) (bpm[((pos)->x-1)+((pos)->y-1)*(pos)->nx] == CPL_BINARY_0)
93 #define CREATE_DEBUGGING_TABLE 1
105 int order,
int minorder,
109 extract_method method,
110 const cpl_image *weights,
111 bool extract_partial,
113 cpl_image *spectrum_noise,
114 cpl_binary*spectrum_badmap,
115 cpl_table **info_tbl,
120 static cpl_table *
opt_define_sky(
const cpl_image *image,
const cpl_image *weights,
121 uves_iterate_position *pos);
123 static cpl_image *
opt_extract_sky(
const cpl_image *image,
const cpl_image *image_noise,
124 const cpl_image *weights,
125 uves_iterate_position *pos,
126 cpl_image *sky_spectrum,
127 cpl_image *sky_spectrum_noise);
130 const cpl_image *image,
const cpl_image *image_noise,
131 const cpl_image *weights,
132 uves_iterate_position *pos,
133 const cpl_table *sky_map,
134 cpl_image *sky_spectrum,
135 cpl_image *sky_spectrum_noise);
138 const cpl_image *image,
const cpl_image *weights,
139 uves_iterate_position *pos,
145 const cpl_image *image,
const cpl_image *image_noise,
146 const cpl_image *weights,
147 uves_iterate_position *pos,
148 int chunk,
int sampling_factor,
149 int (*f) (
const double x[],
const double a[],
double *result),
150 int (*dfda)(
const double x[],
const double a[],
double result[]),
152 const cpl_image *sky_spectrum,
154 cpl_table **profile_global);
157 const cpl_image *image,
const cpl_image *image_noise,
158 const cpl_binary *image_bpm,
159 uves_iterate_position *pos,
161 int (*f) (
const double x[],
const double a[],
double *result),
162 int (*dfda)(
const double x[],
const double a[],
double result[]),
164 const cpl_image *sky_spectrum);
168 const cpl_binary *image_bpm,
170 uves_iterate_position *pos,
171 const cpl_image *spectrum,
172 const cpl_image *sky_spectrum,
173 const uves_extract_profile *profile,
174 enum uves_chip chip);
178 const cpl_image *image_noise,
179 uves_iterate_position *pos,
180 const uves_extract_profile *profile,
181 bool optimal_extract_sky,
183 cpl_table *blemish_mask,
184 cpl_table *cosmic_mask,
186 cpl_table *profile_table,
189 cpl_image *spectrum_noise,
191 cpl_image *sky_spectrum,
192 cpl_image *sky_spectrum_noise,
197 estimate_sn(
const cpl_image *image,
const cpl_image *image_noise,
198 uves_iterate_position *pos);
200 static double opt_get_sky(
const double *image_data,
201 const double *noise_data,
202 const double *weights_data,
203 uves_iterate_position *pos,
204 const cpl_table *sky_map,
205 double buffer_flux[],
double buffer_noise[],
206 double *sky_background_noise);
209 const cpl_binary *image_bpm,
210 uves_iterate_position *pos,
211 double noise_buffer[]);
214 const double *noise_data,
215 double *weights_data,
216 uves_iterate_position *pos,
217 const uves_extract_profile *profile,
218 bool optimal_extract_sky,
221 double *sky_background,
222 double *sky_background_noise);
225 const double *noise_data,
226 cpl_binary *image_bpm,
227 double *weights_data,
228 uves_iterate_position *pos,
229 const uves_extract_profile *profile,
232 double sky_background,
234 cpl_table *cosmic_mask,
int *cr_row,
235 int *hot_pixels,
int *cold_pixels);
238 const uves_iterate_position *pos);
243 cpl_table *info_tbl);
246 detect_ripples(
const cpl_image *spectrum,
const uves_iterate_position *pos,
266 const char *name =
"";
267 char *full_name = NULL;
268 cpl_parameter *p = NULL;
269 cpl_parameterlist *parameters = NULL;
271 parameters = cpl_parameterlist_new();
275 full_name = uves_sprintf(
"%s.%s", UVES_EXTRACT_ID, name);
277 uves_parameter_new_enum(p, full_name,
279 "Extraction method. (2d/optimal not supported by uves_cal_wavecal, weighted supported only by uves_cal_wavecal, 2d not supported by uves_cal_response)",
289 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, name);
290 cpl_parameterlist_append(parameters, p);
296 full_name = uves_sprintf(
"%s.%s", UVES_EXTRACT_ID, name);
298 uves_parameter_new_range(p, full_name,
300 "In optimal extraction mode, this is the "
301 "threshold for bad (i.e. hot/cold) "
302 "pixel rejection. If a pixel deviates more than "
303 "kappa*sigma (where sigma is "
304 "the uncertainty of the pixel flux) from "
305 "the inferred spatial profile, its "
306 "weight is set to zero. Range: [-1,100]. If this parameter "
307 "is negative, no rejection is performed.",
311 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, name);
312 cpl_parameterlist_append(parameters, p);
318 full_name = uves_sprintf(
"%s.%s", UVES_EXTRACT_ID, name);
320 uves_parameter_new_range(p, full_name,
322 "In optimal extraction mode, the chunk size (in pixels) "
323 "used for fitting the analytical profile (a fit of the "
324 "analytical profile to single bins would suffer from "
330 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, name);
331 cpl_parameterlist_append(parameters, p);
337 full_name = uves_sprintf(
"%s.%s", UVES_EXTRACT_ID, name);
339 uves_parameter_new_enum(p, full_name,
341 "In optimal extraction mode, the kind of profile to use. "
342 "'gauss' gives a Gaussian profile, 'moffat' gives "
343 "a Moffat profile with beta=4 and a possible linear sky "
344 "contribution. 'virtual' uses "
345 "a virtual resampling algorithm (i.e. measures and "
346 "uses the actual object profile). "
347 "'constant' assumes a constant spatial profile and "
348 "allows optimal extraction of wavelength "
349 "calibration frames. 'auto' will automatically "
350 "select the best method based on the estimated S/N of the "
351 "object. For low S/N, 'moffat' or 'gauss' are "
352 "recommended (for robustness). For high S/N, 'virtual' is "
353 "recommended (for accuracy). In the case of virtual resampling, "
354 "a precise determination of the order positions is required; "
355 "therefore the order-definition is repeated "
356 "using the (assumed non-low S/N) science frame",
366 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, name);
367 cpl_parameterlist_append(parameters, p);
373 full_name = uves_sprintf(
"%s.%s", UVES_EXTRACT_ID, name);
375 uves_parameter_new_enum(p, full_name,
377 "In optimal extraction mode, the sky subtraction method "
378 "to use. 'median' estimates the sky as the median of pixels "
379 "along the slit (ignoring pixels close to the object), whereas "
380 "'optimal' does a chi square minimization along the slit "
381 "to obtain the best combined object and sky levels. The optimal "
382 "method gives the most accurate sky determination but is also "
383 "a bit slower than the median method",
390 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, name);
391 cpl_parameterlist_append(parameters, p);
397 full_name = uves_sprintf(
"%s.%s", UVES_EXTRACT_ID, name);
399 uves_parameter_new_range(p, full_name,
401 "The oversampling factor used for the virtual "
402 "resampling algorithm. If negative, the value 5 is "
403 "used for S/N <=200, and the value 10 is used if the estimated "
409 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, name);
410 cpl_parameterlist_append(parameters, p);
416 full_name = uves_sprintf(
"%s.%s", UVES_EXTRACT_ID, name);
418 uves_parameter_new_value(p, full_name,
420 "(optimal extraction only) "
421 "If false (fastest), the spectrum is extracted only once. "
422 "If true (best), the spectrum is extracted twice, the "
423 "second time using improved variance estimates "
424 "based on the first iteration. Better variance "
425 "estimates slightly improve the obtained signal to "
426 "noise but at the cost of increased execution time",
430 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, name);
431 cpl_parameterlist_append(parameters, p);
435 if (cpl_error_get_code() != CPL_ERROR_NONE)
437 cpl_msg_error(__func__,
"Creation of extraction parameters failed: '%s'",
438 cpl_error_get_where());
439 cpl_parameterlist_delete(parameters);
463 const char *context,
const char *subcontext)
465 const char *method =
"";
466 extract_method result = 0;
468 check( uves_get_parameter(parameters, context, subcontext,
"method",
469 CPL_TYPE_STRING, &method),
470 "Could not read parameter");
472 if (strcmp(method,
"average" ) == 0) result = EXTRACT_AVERAGE;
473 else if (strcmp(method,
"linear" ) == 0) result = EXTRACT_LINEAR;
474 else if (strcmp(method,
"2d" ) == 0) result = EXTRACT_2D;
475 else if (strcmp(method,
"weighted") == 0) result = EXTRACT_WEIGHTED;
476 else if (strcmp(method,
"optimal" ) == 0) result = EXTRACT_OPTIMAL;
479 assure(
false, CPL_ERROR_ILLEGAL_INPUT,
"No such extraction method: '%s'", method);
570 cpl_image *image_noise,
572 const cpl_table *ordertable,
576 const cpl_parameterlist *parameters,
579 bool extract_partial,
583 cpl_image **spectrum_noise,
584 cpl_image **sky_spectrum,
585 cpl_image **sky_spectrum_noise,
586 cpl_table **cosmic_mask,
587 cpl_image **cosmic_image,
588 cpl_table **profile_table,
590 cpl_table **info_tbl,
591 cpl_table **order_trace)
593 cpl_image *spectrum = NULL;
594 cpl_mask *spectrum_bad = NULL;
595 cpl_binary*spectrum_badmap = NULL;
596 cpl_image *sky_subtracted = NULL;
597 cpl_image *temp = NULL;
598 cpl_image *reconstruct = NULL;
602 extract_method method;
605 const char *p_method;
608 bool optimal_extract_sky;
609 int (*prof_func) (
const double x[],
const double a[],
double *result) = NULL;
610 int (*prof_func_der)(
const double x[],
const double a[],
double result[]) = NULL;
618 int iteration, trace;
622 uves_extract_profile *profile = NULL;
623 uves_iterate_position *pos = NULL;
625 cpl_table* blemish_mask=NULL;
628 assure(image != NULL, CPL_ERROR_NULL_INPUT,
"Missing input image");
630 assure( spectrum_noise == NULL || image_noise != NULL, CPL_ERROR_DATA_NOT_FOUND,
631 "Need image noise in order to calculate spectrum errors");
632 assure( ordertable != NULL, CPL_ERROR_NULL_INPUT,
"Missing order table");
633 assure( order_locations_raw != NULL, CPL_ERROR_NULL_INPUT,
"Missing order polynomial");
634 assure( parameters != NULL, CPL_ERROR_NULL_INPUT,
"Null parameter list");
635 assure( context != NULL, CPL_ERROR_NULL_INPUT,
"Missing context string!");
636 assure( cpl_table_has_column(ordertable,
"Order"),
637 CPL_ERROR_DATA_NOT_FOUND,
"No 'Order' column in order table!");
640 assure( slit_length > 0, CPL_ERROR_ILLEGAL_INPUT,
641 "Slit length must a be positive number! It is %e", slit_length);
643 assure( (sky_spectrum == NULL) == (sky_spectrum_noise == NULL), CPL_ERROR_INCOMPATIBLE_INPUT,
644 "Need 0 or 2 of sky spectrum + sky noise spectrum");
648 sg.length = slit_length;
652 if(strcmp(mode,
".efficiency")==0) {
653 sprintf(ex_context,
"uves_cal_response%s.reduce",mode);
655 sprintf(ex_context,
"%s",context);
661 check( uves_get_parameter(parameters, context, UVES_EXTRACT_ID,
662 "kappa" , CPL_TYPE_DOUBLE, &kappa) ,
663 "Could not read parameter");
664 check( uves_get_parameter(parameters, context, UVES_EXTRACT_ID,
665 "chunk" , CPL_TYPE_INT, &chunk) ,
666 "Could not read parameter");
673 check( uves_get_parameter(parameters, context, UVES_EXTRACT_ID,
674 "skymethod", CPL_TYPE_STRING, &s_method),
675 "Could not read parameter");
676 if (strcmp(s_method,
"median" ) == 0) optimal_extract_sky =
false;
677 else if (strcmp(s_method,
"optimal") == 0) optimal_extract_sky =
true;
680 assure(
false, CPL_ERROR_ILLEGAL_INPUT,
681 "Unrecognized sky extraction method: '%s'", s_method);
687 int minorder, maxorder;
688 check(( minorder = cpl_table_get_column_min(ordertable,
"Order"),
689 maxorder = cpl_table_get_column_max(ordertable,
"Order")),
690 "Error getting order range");
693 cpl_image_get_size_y(image),
695 minorder, maxorder, sg);
698 if (method == EXTRACT_OPTIMAL)
700 assure( image_noise != NULL, CPL_ERROR_ILLEGAL_INPUT,
701 "Extraction method is optimal, but no noise image is provided");
703 assure( weights != NULL, CPL_ERROR_ILLEGAL_INPUT,
704 "Extraction method is optimal, but no weight image is provided");
706 assure( cosmic_mask != NULL, CPL_ERROR_ILLEGAL_INPUT,
707 "Extraction method is optimal, but no cosmic ray mask table is provided");
709 assure( cosmic_image != NULL, CPL_ERROR_ILLEGAL_INPUT,
710 "Extraction method is optimal, but no cosmic ray mask image is provided");
712 assure( order_trace != NULL, CPL_ERROR_ILLEGAL_INPUT,
713 "Extraction method is optimal, but no order trace table is provided");
715 assure( *weights == NULL, CPL_ERROR_ILLEGAL_INPUT,
716 "Weight image already exists");
718 check( uves_get_parameter(parameters, context, UVES_EXTRACT_ID,
"oversample",
719 CPL_TYPE_INT, &sampling_factor),
720 "Could not read parameter");
722 check( uves_get_parameter(parameters, context, UVES_EXTRACT_ID,
"best",
723 CPL_TYPE_BOOL, &best),
724 "Could not read parameter");
726 check( uves_get_parameter(parameters, context, UVES_EXTRACT_ID,
"profile",
727 CPL_TYPE_STRING, &p_method),
728 "Could not read parameter");
730 assure( strcmp(p_method,
"constant") == 0 ||
731 sky_spectrum != NULL, CPL_ERROR_ILLEGAL_INPUT,
732 "Extraction method is optimal, but no sky spectrum is provided");
734 if (strcmp(p_method,
"auto" ) == 0)
744 "Could not estimate image S/N");
746 if (sn_estimate < 10)
752 p_method =
"virtual";
756 "auto-selecting profile measuring method '%s'", sn_estimate,
760 if (strcmp(p_method,
"gauss" ) == 0)
762 else if (strcmp(p_method,
"moffat" ) == 0)
764 else if (strcmp(p_method,
"virtual") == 0)
765 {prof_func = NULL ; prof_func_der = NULL ; prof_pars = 0;}
766 else if (strcmp(p_method,
"constant") != 0)
768 assure(
false, CPL_ERROR_ILLEGAL_INPUT,
769 "Unrecognized profile method: '%s'", p_method);
772 assure( sampling_factor != 0, CPL_ERROR_ILLEGAL_INPUT,
773 "Illegal oversampling factor = %d", sampling_factor);
775 if (strcmp(p_method,
"virtual") == 0 && sampling_factor < 0)
782 "Could not estimate image S/N");
784 if (sn_estimate <= 200)
790 sampling_factor = 10;
794 "auto-selecting oversampling factor = %d", sn_estimate,
799 assure( method != EXTRACT_WEIGHTED || weights != NULL, CPL_ERROR_ILLEGAL_INPUT,
800 "Extraction method is weighted, but no weight image is provided");
802 if (method == EXTRACT_2D)
805 n_traces = uves_round_double(slit_length);
807 assure( n_traces % 2 == 0, CPL_ERROR_ILLEGAL_INPUT,
808 "For 2d extraction slit length (%d) must be an even number", n_traces);
815 if (method == EXTRACT_2D)
821 uves_msg_low(
"Slit length = %.1f pixels; offset = %.1f pixel(s)",
822 sg.length, sg.offset);
826 check(( spectrum = cpl_image_new(pos->nx,
827 n_traces*(pos->maxorder - pos->minorder + 1),
829 spectrum_bad = cpl_image_get_bpm(spectrum),
830 spectrum_badmap = cpl_mask_get_data(spectrum_bad)),
831 "Error creating spectrum image");
834 if (spectrum_noise != NULL)
836 check( *spectrum_noise = cpl_image_new(cpl_image_get_size_x(spectrum),
837 cpl_image_get_size_y(spectrum),
839 "Could not create image");
842 if (info_tbl != NULL &&
843 (method == EXTRACT_LINEAR || method == EXTRACT_AVERAGE ||
844 method == EXTRACT_OPTIMAL)
847 *info_tbl = cpl_table_new(pos->maxorder-pos->minorder+1);
848 cpl_table_new_column(*info_tbl,
"Order", CPL_TYPE_INT);
849 cpl_table_new_column(*info_tbl,
"ObjSnBlzCentre", CPL_TYPE_DOUBLE);
850 cpl_table_new_column(*info_tbl,
"Ripple", CPL_TYPE_DOUBLE);
855 cpl_table_new_column(*info_tbl,
"ObjPosOnSlit", CPL_TYPE_DOUBLE);
856 cpl_table_new_column(*info_tbl,
"ObjFwhmAvg", CPL_TYPE_DOUBLE);
860 if (method == EXTRACT_OPTIMAL)
863 check( *weights = cpl_image_new(pos->nx, pos->ny, CPL_TYPE_DOUBLE),
864 "Could not allocate weight image");
867 check(( *cosmic_mask = cpl_table_new(1),
868 cpl_table_new_column(*cosmic_mask,
"Order", CPL_TYPE_INT),
869 cpl_table_new_column(*cosmic_mask,
"X" , CPL_TYPE_INT),
870 cpl_table_new_column(*cosmic_mask,
"Y" , CPL_TYPE_INT),
871 cpl_table_new_column(*cosmic_mask,
"Flux" , CPL_TYPE_DOUBLE),
873 "Error creating cosmic ray table");
876 if(*cosmic_image!=NULL) {
889 double blemish_frac=0;
892 flux=cpl_image_get_flux(*cosmic_image);
893 sx=cpl_image_get_size_x(*cosmic_image);
894 sy=cpl_image_get_size_y(*cosmic_image);
895 nblemish=sx*sy-(int)flux;
896 blemish_frac=(sx*sy-flux)/(sx*sy);
897 uves_msg(
"nblemish=%d frac=%g",nblemish,blemish_frac);
899 if(blemish_frac< 0.02) {
902 blemish_mask=cpl_table_new(nblemish);
903 cpl_table_new_column(blemish_mask,
"X",CPL_TYPE_INT);
904 cpl_table_new_column(blemish_mask,
"Y",CPL_TYPE_INT);
905 cpl_table_fill_column_window_int(blemish_mask,
"X",
907 cpl_table_fill_column_window_int(blemish_mask,
"Y",
910 pcmask=cpl_image_get_data_double(*cosmic_image);
911 px=cpl_table_get_data_int(blemish_mask,
"X");
912 py=cpl_table_get_data_int(blemish_mask,
"Y");
916 if(pcmask[j*sx+i]==0) {
929 uves_msg_warning(
"%d pixels affected by detector blemishes %g (>0.02) of total. Not flag them in optimal extraction",nblemish,blemish_frac);
935 if (profile_table != NULL)
937 check( (*profile_table = cpl_table_new((pos->maxorder - pos->minorder + 1) *
939 (3+uves_round_double(sg.length))),
940 cpl_table_new_column(*profile_table,
"Order" , CPL_TYPE_INT),
941 cpl_table_new_column(*profile_table,
"X" , CPL_TYPE_INT),
942 cpl_table_new_column(*profile_table,
"DY" , CPL_TYPE_DOUBLE),
943 cpl_table_new_column(*profile_table,
"Profile_raw", CPL_TYPE_DOUBLE),
944 cpl_table_new_column(*profile_table,
"Profile_int", CPL_TYPE_DOUBLE)),
945 "Error creating profile table");
949 if (strcmp(p_method,
"constant") != 0) {
950 check( *sky_spectrum = cpl_image_new(
951 pos->nx, pos->maxorder - pos->minorder + 1, CPL_TYPE_DOUBLE),
952 "Could not allocate sky spectrum");
953 check( *sky_spectrum_noise = cpl_image_new(
954 pos->nx, pos->maxorder - pos->minorder + 1, CPL_TYPE_DOUBLE),
955 "Could not allocate sky spectrum noise");
959 if (method == EXTRACT_OPTIMAL &&
960 strcmp(p_method,
"constant") != 0 && prof_func == NULL)
970 uves_msg(
"Refining order definition using the object frame");
973 pos->minorder, pos->maxorder,
976 "Could not refine order definition");
983 pos->order_locations = order_locations;
998 if (method == EXTRACT_OPTIMAL)
1000 if (strcmp(p_method,
"constant") == 0) {
1002 uves_msg(
"Assuming constant spatial profile");
1004 profile = uves_extract_profile_new_constant(sg.length);
1007 sky_subtracted = cpl_image_duplicate(image);
1008 optimal_extract_sky =
false;
1013 image, image_noise, *weights,
1016 *sky_spectrum_noise),
1017 "Could not extract sky");
1018 if (prof_func != NULL)
1020 uves_msg(
"Measuring spatial profile "
1021 "(method = %s, chunk = %d bins)",
1026 uves_msg(
"Measuring spatial profile "
1027 "(method = %s, oversampling = %d)",
1028 p_method, sampling_factor);
1031 uves_extract_profile_delete(&profile);
1036 chunk, sampling_factor,
1037 prof_func, prof_func_der, prof_pars,
1041 "Could not measure profile");
1053 passure( method == EXTRACT_2D || n_traces == 1,
"%d", n_traces);
1055 n_iterations = (method == EXTRACT_OPTIMAL &&
1057 strcmp(p_method,
"constant") != 0) ? 2 : 1;
1067 iteration <= n_iterations;
1070 uves_msg(
"Extracting object %s(method = %s)",
1071 (method == EXTRACT_OPTIMAL && optimal_extract_sky)
1073 (method == EXTRACT_OPTIMAL) ?
"optimal" :
1074 (method == EXTRACT_AVERAGE) ?
"average" :
1075 (method == EXTRACT_LINEAR ) ?
"linear" :
1076 (method == EXTRACT_2D ) ?
"2d" :
1077 (method == EXTRACT_WEIGHTED) ?
"weighted" :
"???");
1081 cr_row = cr_row_max;
1084 for (pos->order = pos->minorder; pos->order <= pos->maxorder; pos->order++) {
1085 for (trace = 1; trace <= n_traces; trace++) {
1091 spectrum_row = (pos->order - pos->minorder)*n_traces + trace;
1094 if (method == EXTRACT_OPTIMAL)
1102 optimal_extract_sky ?
1103 image : sky_subtracted,
1107 optimal_extract_sky,
1112 (profile_table != NULL) ?
1113 *profile_table : NULL,
1116 (spectrum_noise != NULL) ?
1117 *spectrum_noise : NULL,
1119 optimal_extract_sky ? *sky_spectrum : NULL,
1120 optimal_extract_sky ? *sky_spectrum_noise : NULL,
1122 "Error extracting order #%d", pos->order);
1123 cr_row_max=(cr_row>cr_row_max) ? cr_row:cr_row_max;
1140 double offset_2d = trace - (n_traces+1)/2.0;
1146 pos->order, pos->minorder,
1148 (method == EXTRACT_2D) ? offset_2d : sg.offset,
1149 (method == EXTRACT_2D) ? slit_2d : sg.length,
1150 (method == EXTRACT_2D) ? EXTRACT_LINEAR : method,
1151 (weights != NULL) ? *weights : NULL,
1154 (spectrum_noise != NULL) ? *spectrum_noise : NULL,
1158 "Could not extract order #%d ; trace #%d",
1163 if (info_tbl != NULL &&
1164 (method == EXTRACT_LINEAR || method == EXTRACT_AVERAGE ||
1165 method == EXTRACT_OPTIMAL)
1175 if (
false && ripple_index > 3) {
1181 "It might help to use average or linear extraction "
1182 "or optimal/virtual extraction with larger "
1183 "oversampling factor", ripple_index);
1186 cpl_table_set_int (*info_tbl,
"Order",
1187 pos->order - pos->minorder, pos->order);
1188 cpl_table_set_double(*info_tbl,
"ObjSnBlzCentre" ,
1189 pos->order - pos->minorder, sn);
1190 cpl_table_set_double(*info_tbl,
"Ripple",
1191 pos->order - pos->minorder,
1192 (ripple_index > -0.5) ? ripple_index : -1);
1196 "Order #%d; trace #%d: %d of %d bins extracted",
1197 pos->order, trace, bins_extracted, pos->nx);
1204 if (method == EXTRACT_OPTIMAL)
1206 if (spectrum_noise != NULL)
1208 uves_free_image(&temp);
1209 temp = cpl_image_divide_create(spectrum, *spectrum_noise);
1210 uves_msg(
"Average S/N = %.3f", cpl_image_get_median(temp));
1213 if (iteration == 1 && n_iterations >= 2)
1220 cpl_image_get_bpm(sky_subtracted)),
1222 spectrum, *sky_spectrum, profile,
1224 "Error refining input image variances");
1232 if (method == EXTRACT_OPTIMAL)
1236 check( cpl_table_set_size(*cosmic_mask, cr_row_max),
1237 "Error setting cosmic ray table size to %d", cr_row_max);
1238 if(*cosmic_image==NULL) {
1239 *cosmic_image = cpl_image_new(pos->nx, pos->ny, CPL_TYPE_DOUBLE);
1243 for (i = 0; i < cpl_table_get_nrow(*cosmic_mask); i++)
1245 cpl_image_set(*cosmic_image,
1246 cpl_table_get_int(*cosmic_mask,
"X", i, NULL),
1247 cpl_table_get_int(*cosmic_mask,
"Y", i, NULL),
1248 cpl_table_get_double(*cosmic_mask,
"Flux", i, NULL));
1251 if (profile_table != NULL)
1253 check( cpl_table_set_size(*profile_table, prof_row),
1254 "Error setting profile table size to %d", prof_row);
1261 check( cpl_image_threshold(*weights,
1264 "Error thresholding weight image");
1273 double *weights_data = cpl_image_get_data_double(*weights);
1277 pos->minorder, pos->maxorder,
1282 double sum_weights = 0.0;
1284 for (pos->y = pos->ylow; pos->y <= pos->yhigh; pos->y++)
1286 double weight = DATA(weights_data, pos);
1287 sum_weights += weight;
1290 for (pos->y = pos->ylow; pos->y <= pos->yhigh; pos->y++)
1292 if (sum_weights > 0)
1294 DATA(weights_data, pos) /= sum_weights;
1302 uves_msg_debug(
"Rejecting %" CPL_SIZE_FORMAT
" bins", cpl_mask_count(spectrum_bad));
1304 if (spectrum_noise != NULL)
1306 check( cpl_image_reject_from_mask(*spectrum_noise, spectrum_bad),
1307 "Error setting bad pixels");
1315 "PIXEL", (method == EXTRACT_2D) ?
"PIXEL" :
"ORDER",
1316 "PIXEL", (method == EXTRACT_2D) ?
"PIXEL" :
"ORDER",
1321 "Error initializing spectrum header");
1324 if (debug_mode && header != NULL) {
1325 if (profile == NULL) {
1328 profile = uves_extract_profile_new_constant(sg.length);
1334 sky_spectrum != NULL ? *sky_spectrum : NULL,
1335 cosmic_image != NULL ? *cosmic_image : NULL,
1343 check( uves_save_image_local(
"Reconstructed image",
"simulate",
1344 reconstruct, chip, -1, -1, *header,
true),
1345 "Error saving image");
1349 if (spectrum_noise != NULL)
1362 assure( cpl_image_get_min(*spectrum_noise) > 0, CPL_ERROR_ILLEGAL_OUTPUT,
1363 "Non-positive noise: %e at (%" CPL_SIZE_FORMAT
", %" CPL_SIZE_FORMAT
")",
1364 cpl_image_get_min(*spectrum_noise),
1365 (cpl_image_get_minpos(*spectrum_noise, &x, &y), x),
1366 (cpl_image_get_minpos(*spectrum_noise, &x, &y), y));
1377 uves_free_image(&reconstruct);
1378 uves_free_image(&sky_subtracted);
1379 uves_extract_profile_delete(&profile);
1382 uves_free_image(&temp);
1383 uves_free_table(&blemish_mask);
1385 if (cpl_error_get_code() != CPL_ERROR_NONE)
1387 uves_free_image(&spectrum);
1388 uves_free_image(spectrum_noise);
1389 uves_free_table(profile_table);
1413 int nx = cpl_image_get_size_x(spectrum);
1414 cpl_image *spectrum_order = NULL;
1415 cpl_vector *tempx = NULL;
1416 cpl_vector *tempy = NULL;
1417 double *auto_corr = NULL;
1419 int spectrum_row = (pos->order - pos->minorder)*n_traces + trace;
1422 uves_free_image(&spectrum_order);
1424 check( spectrum_order = cpl_image_extract(spectrum,
1427 "Error extracting order %d from spectrum", pos->order);
1429 n_rejected = cpl_image_count_rejected(spectrum_order);
1434 if (n_rejected == 0)
1437 double order_slope =
1440 int expected_period = uves_round_double(1.0/order_slope);
1441 int max_period = 2*expected_period;
1444 uves_msg_debug(
"Estimated ripple period = %d pixels", expected_period);
1446 auto_corr = cpl_calloc(
sizeof(
double), 1+max_period);
1448 for (shift = 0; shift <= max_period; shift += 1) {
1452 auto_corr[shift] = 0;
1454 for (x = 1; x <= nx - max_period; x++) {
1455 int rejected1, rejected2;
1458 val1 = cpl_image_get(spectrum_order, x, 1, &rejected1);
1459 val2 = cpl_image_get(spectrum_order, x+shift, 1, &rejected2);
1461 if (!rejected1 && !rejected2)
1463 auto_corr[shift] += val1*val2;
1470 auto_corr[shift] /= N;
1474 auto_corr[shift] = 0;
1477 if (shift > 0 && auto_corr[0] > 0)
1479 auto_corr[shift] /= auto_corr[0];
1483 shift, N, (shift == 0) ? 1 : auto_corr[shift]);
1490 double auto_amplitude;
1491 int imax = expected_period;
1492 int imin1 = expected_period/2;
1493 int imin2 = (expected_period*3)/2;
1499 auto_amplitude = auto_corr[imax] -
1500 (auto_corr[imin1] + auto_corr[imin2])/2.0;
1514 if (auto_amplitude > 0 && sn > 0)
1516 double rel_ripple = sqrt(auto_amplitude);
1518 "relative error bars = %f",
1519 pos->order, rel_ripple, 2.0*1/sn);
1521 ratio = rel_ripple * sn/2.0;
1527 uves_free_double(&auto_corr);
1528 uves_free_vector(&tempx);
1529 uves_unwrap_vector(&tempy);
1530 uves_free_image(&spectrum_order);
1551 uves_iterate_position *pos)
1555 cpl_table *sn_temp = NULL;
1556 cpl_table *sky_temp = NULL;
1557 int sn_row, sky_row;
1558 int sky_size = 2 + 2*uves_round_double(pos->sg.length);
1562 passure( image_noise != NULL,
" ");
1564 assure( pos->nx >= 2*(range+1), CPL_ERROR_ILLEGAL_INPUT,
1565 "Input image is too small. Width = %d", pos->nx);
1567 sn_temp = cpl_table_new((pos->maxorder - pos->minorder + 1) * (2*range + 1));
1568 cpl_table_new_column(sn_temp,
"SN", CPL_TYPE_DOUBLE);
1571 sky_temp = cpl_table_new(sky_size);
1572 cpl_table_new_column(sky_temp,
"Sky", CPL_TYPE_DOUBLE);
1575 pos->nx/2 - range, pos->nx/2 + range,
1576 pos->minorder, pos->maxorder,
1587 for (pos->y = pos->ylow; pos->y <= pos->yhigh; pos->y++)
1589 int pis_rejected1, pis_rejected2;
1590 double pixel = cpl_image_get(image,
1591 pos->x, pos->y, &pis_rejected1);
1592 double pixel_noise = cpl_image_get(image_noise,
1593 pos->x, pos->y, &pis_rejected2);
1595 if (!pis_rejected1 && !pis_rejected2)
1598 error += pixel_noise*pixel_noise;
1601 cpl_table_set_double(sky_temp,
"Sky",
1611 while(sky_row < sky_size)
1614 cpl_table_set_invalid(sky_temp,
"Sky",
1620 sky = cpl_table_get_column_median(sky_temp,
"Sky");
1622 flux = flux - N*sky;
1623 error = sqrt(error);
1629 pos->order, flux/error);
1631 cpl_table_set_double(sn_temp,
"SN",
1632 sn_row, flux/error);
1638 assure(sn_row > 0, CPL_ERROR_DATA_NOT_FOUND,
1639 "Extraction of central bins failed!");
1641 cpl_table_set_size(sn_temp, sn_row);
1643 sn = cpl_table_get_column_median(sn_temp,
"SN");
1646 uves_free_table(&sn_temp);
1647 uves_free_table(&sky_temp);
1687 const cpl_image *image_noise,
1694 extract_method method,
1695 const cpl_image *weights,
1696 bool extract_partial,
1697 cpl_image *spectrum,
1698 cpl_image *spectrum_noise,
1699 cpl_binary*spectrum_badmap,
1700 cpl_table **info_tbl,
1703 int bins_extracted = 0;
1704 double *spectrum_data;
1706 double flux_y, flux_yy, flux_tot;
1709 cpl_table *signal_to_noise = NULL;
1711 passure( method == EXTRACT_AVERAGE ||
1712 method == EXTRACT_LINEAR ||
1713 method == EXTRACT_WEIGHTED,
"%d", method);
1716 passure( (method == EXTRACT_WEIGHTED) == (weights != NULL),
"%d", method);
1718 nx = cpl_image_get_size_x(image);
1719 ny = cpl_image_get_size_y(image);
1721 check( (signal_to_noise = cpl_table_new(nx),
1722 cpl_table_new_column(signal_to_noise,
"SN", CPL_TYPE_DOUBLE)),
1723 "Error allocating S/N table");
1725 spectrum_data = cpl_image_get_data_double(spectrum);
1731 for (x = 1 ; x <= nx; x++) {
1732 double slope, ycenter;
1735 double flux_variance = 0;
1744 "Error evaluating polynomial");
1746 assure( 0 < slope && slope < 1, CPL_ERROR_ILLEGAL_INPUT,
1747 "At (x, order)=(%d, %d) slope is %f. Must be positive", x, order, slope);
1750 ylo = uves_round_double(ycenter - slit_length/2 - 0.5*slope);
1751 yhi = uves_round_double(ycenter + slit_length/2 + 0.5*slope);
1754 if (ylo < 1 || ny < yhi)
1756 if (extract_partial)
1758 ylo = uves_max_int(ylo, 1);
1759 yhi = uves_min_int(yhi, ny);
1769 for (y = ylo; y <= yhi; y++) {
1773 double pixelvariance;
1777 pixelval = cpl_image_get(image, x, y, &pis_rejected);
1785 if (spectrum_noise != NULL && !pis_rejected)
1787 pixelvariance = cpl_image_get(image_noise, x, y, &pis_rejected);
1788 pixelvariance *= pixelvariance;
1795 if (!pis_rejected) {
1797 if (method == EXTRACT_WEIGHTED)
1802 weight = cpl_image_get(weights, x, y, &pis_rejected);
1804 assure( weight >= 0, CPL_ERROR_ILLEGAL_INPUT,
1805 "Illegal weight: %e at (x, y) = (%d, %d)",
1816 else if (method == EXTRACT_ARCLAMP) {
1817 weight = 1.0 / pixelvariance;
1821 double area_outside_order_top;
1822 double area_outside_order_bottom;
1823 double left = ycenter + slit_length/2 - 0.5*slope;
1824 double right = ycenter + slit_length/2 + 0.5*slope;
1826 check( area_outside_order_top =
1828 "Error calculating area");
1830 left = ycenter - slit_length/2 - 0.5*slope;
1831 right = ycenter - slit_length/2 + 0.5*slope;
1833 check( area_outside_order_bottom =
1835 "Error calculationg area");
1837 weight = 1 - (area_outside_order_top + area_outside_order_bottom);
1839 if (1 < y && y < ny && weight < 1)
1862 int pis_rejected_prev, pis_rejected_next;
1866 double flux_minus = (pixelval + cpl_image_get(
1867 image, x, y - 1, &pis_rejected_prev)) / 2.0;
1868 double flux_plus = (pixelval + cpl_image_get(
1869 image, x, y + 1, &pis_rejected_next)) / 2.0;
1870 if (!pis_rejected_prev && !pis_rejected_next)
1880 double flux_center =
1881 2*pixelval - (flux_minus + flux_plus) / 2.0;
1884 double slope_minus =
1885 (flux_center - flux_minus )/ 0.5;
1887 (flux_plus - flux_center) / 0.5;
1891 uves_min_double(0, -0.5 + area_outside_order_bottom);
1893 uves_min_double(0, 0.5 - area_outside_order_top );
1894 double dy1 = hi1-lo1;
1898 uves_max_double(0, -0.5 + area_outside_order_bottom);
1900 uves_max_double(0, 0.5 - area_outside_order_top );
1901 double dy2 = hi2-lo2;
1907 (flux_center + slope_minus * (lo1+hi1)/2.0) * dy1
1909 (flux_center + slope_plus * (lo2+hi2)/2.0) * dy2
1945 flux += weight*pixelval;
1946 flux_variance += weight*weight * pixelvariance;
1951 if (method != EXTRACT_ARCLAMP)
1953 flux_y += weight * pixelval * (y-ylo);
1954 flux_yy += weight * pixelval * (y-ylo)*(y-ylo);
1955 flux_tot+= weight * pixelval;
1968 bins_extracted += 1;
1970 if (method == EXTRACT_ARCLAMP && flux_variance > 0) {
1972 flux_variance = 1.0 / sum;
1974 else if (method == EXTRACT_AVERAGE || method == EXTRACT_WEIGHTED)
1978 flux_variance *= 1.0 / (sum*sum);
1984 flux *= slit_length / sum;
1985 flux_variance *= (slit_length*slit_length) / (sum*sum);
1994 spectrum_data [(x-1) + (spectrum_row-1) * nx] = flux;
1995 spectrum_badmap[(x-1) + (spectrum_row-1) * nx] = CPL_BINARY_0;
1997 if (spectrum_noise != NULL)
1999 check( cpl_image_set(
2000 spectrum_noise, x, spectrum_row, sqrt(flux_variance)),
2001 "Could not write noise at (%d, %d)", x, spectrum_row);
2005 signal_to_noise,
"SN", sn_row, flux / sqrt(flux_variance)) );
2024 spectrum_badmap[(x-1) + (spectrum_row-1) * nx] = CPL_BINARY_1;
2029 if (info_tbl != NULL && *info_tbl != NULL && method != EXTRACT_ARCLAMP)
2034 objpos = flux_y / flux_tot;
2039 if (flux_yy/flux_tot - objpos*objpos >= 0)
2041 fwhm = sqrt(flux_yy/flux_tot - objpos*objpos) * TWOSQRT2LN2;
2047 cpl_table_set_double(*info_tbl,
"ObjPosOnSlit" , order - minorder, objpos);
2048 cpl_table_set_double(*info_tbl,
"ObjFwhmAvg" , order - minorder, fwhm);
2052 check_nomsg( cpl_table_set_size(signal_to_noise, sn_row) );
2056 check_nomsg( *sn = cpl_table_get_column_median(signal_to_noise,
"SN"));
2064 uves_free_table(&signal_to_noise);
2065 return bins_extracted;
2087 double pixeltop = y + .5;
2088 double pixelbot = y - .5;
2089 double slope = right - left;
2091 assure( 0 <= slope && slope <= 1, CPL_ERROR_ILLEGAL_INPUT,
"Slope is %f", slope);
2133 if (pixelbot > right)
2137 else if (pixelbot > left)
2140 (right - pixelbot) *
2141 (right - pixelbot) / (2*slope);
2143 else if (pixeltop > right)
2145 area = pixeltop - (left + right)/2;
2147 else if (pixeltop > left)
2151 (pixeltop - left) / (2*slope);
2184 const cpl_binary *image_bpm,
2186 uves_iterate_position *pos,
2187 const cpl_image *spectrum,
2188 const cpl_image *sky_spectrum,
2189 const uves_extract_profile *profile,
2190 enum uves_chip chip)
2192 cpl_image *revised = NULL;
2193 cpl_image *simulated = NULL;
2194 const cpl_binary *spectrum_bpm =
2195 cpl_mask_get_data_const(cpl_image_get_bpm_const(spectrum));
2197 const double *spectrum_data;
2198 const double *sky_data;
2200 simulated = cpl_image_new(pos->nx, pos->ny,
2204 simul_data = cpl_image_get_data_double(simulated);
2205 spectrum_data = cpl_image_get_data_double_const(spectrum);
2206 sky_data = cpl_image_get_data_double_const(sky_spectrum);
2210 pos->minorder, pos->maxorder,
2215 if (SPECTRUM_DATA(spectrum_bpm, pos) == CPL_BINARY_0)
2218 uves_extract_profile_set(profile, pos, NULL);
2220 for (pos->y = pos->ylow; pos->y <= pos->yhigh; pos->y++)
2221 if (ISGOOD(image_bpm, pos))
2224 DATA(simul_data, pos) =
2225 SPECTRUM_DATA(sky_data, pos)/pos->sg.length +
2226 SPECTRUM_DATA(spectrum_data, pos) *
2227 uves_extract_profile_evaluate(profile, pos);
2243 "Error computing noise image");
2248 double *revised_data = cpl_image_get_data_double(revised);
2249 double *input_data = cpl_image_get_data_double(image_noise);
2253 pos->minorder, pos->maxorder,
2258 DATA(input_data, pos) = DATA(revised_data, pos);
2263 uves_free_image(&simulated);
2264 uves_free_image(&revised);
2289 const cpl_image *weights,
2290 uves_iterate_position *pos,
2291 cpl_image *sky_spectrum,
2292 cpl_image *sky_spectrum_noise)
2294 cpl_image *sky_subtracted = NULL;
2295 cpl_table *sky_map = NULL;
2301 "Error determining sky window");
2303 uves_msg_low(
"%" CPL_SIZE_FORMAT
"/%" CPL_SIZE_FORMAT
" sky pixels",
2304 cpl_table_count_selected(sky_map),
2305 cpl_table_get_nrow(sky_map));
2308 uves_msg(
"Subtracting sky (method = median of sky channels)");
2314 sky_spectrum_noise),
2315 "Could not subtract sky");
2318 uves_free_table(&sky_map);
2320 return sky_subtracted;
2338 uves_iterate_position *pos)
2341 cpl_table *sky_map = NULL;
2343 cpl_table **resampled = NULL;
2353 "Error measuring spatial profile");
2355 sky_map = cpl_table_new(nbins);
2356 cpl_table_new_column(sky_map,
"DY" , CPL_TYPE_INT);
2357 cpl_table_new_column(sky_map,
"Prof", CPL_TYPE_DOUBLE);
2359 for (i = 0; i < nbins; i++)
2361 cpl_table_set_int(sky_map,
"DY" , i, i - nbins/2);
2362 if (cpl_table_has_valid(resampled[i],
"Prof"))
2371 int row = (cpl_table_get_nrow(resampled[i]) * 9) / 10;
2373 uves_sort_table_1(resampled[i],
"Prof",
false);
2375 cpl_table_set_double(sky_map,
"Prof", i,
2376 cpl_table_get_double(resampled[i],
"Prof", row, NULL));
2380 cpl_table_set_invalid(sky_map,
"Prof", i);
2386 assure( cpl_table_has_valid(sky_map,
"Prof"), CPL_ERROR_DATA_NOT_FOUND,
2387 "Too many (%" CPL_SIZE_FORMAT
"/%d ) bad pixels. Could not measure sky profile",
2388 cpl_image_count_rejected(image),
2396 double prof_min = cpl_table_get_column_min(sky_map,
"Prof");
2397 double prof_max = cpl_table_get_column_max(sky_map,
"Prof");
2398 double prof_med = cpl_table_get_column_median(sky_map,
"Prof");
2399 double sky_threshold = prof_min + 2*(prof_med - prof_min);
2401 sky_threshold = uves_min_double(sky_threshold, (prof_min + prof_max)/2);
2403 check( uves_plot_table(sky_map,
"DY",
"Prof",
2404 "Globally averaged spatial profile (sky threshold = %.5f)",
2408 uves_select_table_rows(sky_map,
"Prof", CPL_NOT_GREATER_THAN, sky_threshold);
2412 if (resampled != NULL)
2414 for (i = 0; i < nbins; i++)
2416 uves_free_table(&(resampled[i]));
2418 cpl_free(resampled);
2445 uves_iterate_position *pos,
2447 int sampling_factor,
2451 cpl_table **resampled = NULL;
2455 int *resampled_row = NULL;
2457 const double *image_data;
2458 const double *weights_data;
2460 assure( stepx >= 1, CPL_ERROR_ILLEGAL_INPUT,
"Step size = %d", stepx);
2461 assure( sampling_factor >= 1, CPL_ERROR_ILLEGAL_INPUT,
2462 "Sampling factor = %d", sampling_factor);
2464 image_data = cpl_image_get_data_double_const(image);
2465 weights_data = cpl_image_get_data_double_const(weights);
2467 *nbins = uves_extract_profile_get_nbins(pos->sg.length, sampling_factor);
2469 resampled = cpl_calloc(*nbins,
sizeof(cpl_table *));
2470 resampled_row = cpl_calloc(*nbins,
sizeof(
int));
2477 for (i = 0; i < *nbins; i++)
2479 resampled[i] = cpl_table_new((pos->nx/stepx+1)*
2480 (pos->maxorder-pos->minorder+1));
2482 resampled_row[i] = 0;
2485 cpl_table_new_column(resampled[i],
"X" , CPL_TYPE_INT);
2486 cpl_table_new_column(resampled[i],
"Order", CPL_TYPE_INT);
2487 cpl_table_new_column(resampled[i],
"Prof" , CPL_TYPE_DOUBLE);
2494 pos->minorder, pos->maxorder,
2498 if ((pos->x - 1) % stepx == 0)
2504 for (pos->y = pos->ylow; pos->y <= pos->yhigh; pos->y++) {
2505 if (!ISBAD(weights_data, pos)) {
2506 flux += DATA(image_data, pos);
2511 for (pos->y = pos->ylow; pos->y <= pos->yhigh; pos->y++) {
2512 if (!ISBAD(weights_data, pos)) {
2513 double f = DATA(image_data, pos);
2516 int bin = uves_round_double(
2517 uves_extract_profile_get_bin(pos, sampling_factor));
2519 passure( bin < *nbins,
"%d %d", bin, *nbins);
2525 cpl_table_set_int (resampled[bin],
"X" ,
2526 resampled_row[bin], pos->x);
2527 cpl_table_set_int (resampled[bin],
"Order",
2528 resampled_row[bin], pos->order);
2529 cpl_table_set_double(resampled[bin],
"Prof" ,
2530 resampled_row[bin], f/flux);
2532 resampled_row[bin]++;
2541 for (i = 0; i < *nbins; i++)
2543 cpl_table_set_size(resampled[i], resampled_row[i]);
2548 passure( cpl_table_get_ncol(resampled[0]) == 3,
"%" CPL_SIZE_FORMAT
"",
2549 cpl_table_get_ncol(resampled[0]));
2550 passure( cpl_table_has_column(resampled[0],
"X"),
" ");
2551 passure( cpl_table_has_column(resampled[0],
"Order"),
" ");
2552 passure( cpl_table_has_column(resampled[0],
"Prof"),
" ");
2555 cpl_free(resampled_row);
2587 const cpl_image *weights,
2588 uves_iterate_position *pos,
2589 const cpl_table *sky_map,
2590 cpl_image *sky_spectrum,
2591 cpl_image *sky_spectrum_noise)
2593 cpl_image *sky_subtracted = cpl_image_duplicate(image);
2595 double *sky_subtracted_data;
2596 const double *image_data;
2597 const double *noise_data;
2598 const double *weights_data;
2599 double *buffer_flux = NULL;
2600 double *buffer_noise = NULL;
2603 double *sky_spectrum_data = NULL;
2604 double *sky_noise_data = NULL;
2605 cpl_binary *sky_spectrum_bpm = NULL;
2606 cpl_binary *sky_noise_bpm = NULL;
2607 cpl_mask *temp = NULL;
2611 image_data = cpl_image_get_data_double_const(image);
2612 noise_data = cpl_image_get_data_double_const(image_noise);
2613 weights_data = cpl_image_get_data_double_const(weights);
2614 sky_subtracted_data = cpl_image_get_data(sky_subtracted);
2616 buffer_flux = cpl_malloc(uves_round_double(pos->sg.length + 5)*
sizeof(
double));
2617 buffer_noise = cpl_malloc(uves_round_double(pos->sg.length + 5)*
sizeof(
double));
2620 if (sky_spectrum != NULL)
2622 sky_spectrum_data = cpl_image_get_data_double(sky_spectrum);
2623 sky_noise_data = cpl_image_get_data_double(sky_spectrum_noise);
2628 temp = cpl_mask_new(cpl_image_get_size_x(sky_spectrum),
2629 cpl_image_get_size_y(sky_spectrum));
2632 cpl_image_reject_from_mask(sky_spectrum , temp);
2633 cpl_image_reject_from_mask(sky_spectrum_noise, temp);
2635 sky_spectrum_bpm = cpl_mask_get_data(cpl_image_get_bpm(sky_spectrum));
2636 sky_noise_bpm = cpl_mask_get_data(cpl_image_get_bpm(sky_spectrum_noise));
2639 UVES_TIME_START(
"Subtract sky");
2643 pos->minorder, pos->maxorder,
2648 double sky_background, sky_background_noise;
2651 sky_background =
opt_get_sky(image_data, noise_data,
2655 buffer_flux, buffer_noise,
2656 &sky_background_noise);
2659 if (sky_spectrum != NULL)
2675 SPECTRUM_DATA(sky_spectrum_data, pos) =
2676 pos->sg.length * sky_background;
2677 SPECTRUM_DATA(sky_noise_data, pos) =
2678 pos->sg.length * sky_background_noise;
2680 SPECTRUM_DATA(sky_spectrum_bpm, pos) = CPL_BINARY_0;
2681 SPECTRUM_DATA(sky_noise_bpm , pos) = CPL_BINARY_0;
2685 for (pos->y = pos->ylow; pos->y <= pos->yhigh; pos->y++)
2687 DATA(sky_subtracted_data, pos) =
2688 DATA(image_data, pos) - sky_background;
2699 uves_free_mask(&temp);
2700 cpl_free(buffer_flux);
2701 cpl_free(buffer_noise);
2703 return sky_subtracted;
2744 static uves_extract_profile *
2746 const cpl_image *weights,
2747 uves_iterate_position *pos,
2748 int chunk,
int sampling_factor,
2749 int (*f) (
const double x[],
const double a[],
double *result),
2750 int (*dfda)(
const double x[],
const double a[],
double result[]),
2752 const cpl_image *sky_spectrum,
2753 cpl_table *info_tbl,
2754 cpl_table **profile_global)
2756 uves_extract_profile *profile = NULL;
2758 int *good_bins = NULL;
2759 cpl_table **profile_data = NULL;
2762 cpl_mask *image_bad = NULL;
2763 cpl_binary*image_bpm = NULL;
2765 cpl_vector *plot0x = NULL;
2766 cpl_vector *plot0y = NULL;
2767 cpl_vector *plot1x = NULL;
2768 cpl_vector *plot1y = NULL;
2769 cpl_bivector *plot[] = {NULL, NULL};
2770 char *plot_titles[] = {NULL, NULL};
2772 int sample_bins = 100;
2775 int spatial_bins = uves_extract_profile_get_nbins(pos->sg.length, sampling_factor);
2782 image_bad = cpl_mask_new(pos->nx, pos->ny);
2784 image_bpm = cpl_mask_get_data(image_bad);
2786 const double *weights_data = cpl_image_get_data_double_const(weights);
2788 for (pos->y = 1; pos->y <= pos->ny; pos->y++)
2790 for (pos->x = 1; pos->x <= pos->nx; pos->x++)
2792 if (ISBAD(weights_data, pos))
2794 DATA(image_bpm, pos) = CPL_BINARY_1;
2803 stepx = cpl_malloc((pos->maxorder-pos->minorder+1) *
sizeof(
int));
2804 good_bins = cpl_malloc((pos->maxorder-pos->minorder+1) *
sizeof(
int));
2805 profile_data = cpl_calloc( pos->maxorder-pos->minorder+1,
sizeof(cpl_table *));
2811 for (pos->order = pos->minorder; pos->order <= pos->maxorder; pos->order++)
2821 "Error estimating width of order #%d", pos->order);
2829 stepx [pos->order-pos->minorder] = order_width / sample_bins + 1;
2830 good_bins[pos->order-pos->minorder] = (2*sample_bins)/3;
2839 stepx = cpl_malloc(
sizeof(
int) * spatial_bins);
2840 good_bins = cpl_malloc(
sizeof(
int) * spatial_bins);
2844 profile_data = NULL;
2849 for (i = 0; i < spatial_bins; i++)
2863 stepx [i] = uves_round_double(
2864 (pos->nx*pos->sg.length)/(sample_bins*spatial_bins)
2867 good_bins[i] = sample_bins - 1;
2897 for (i = 0; i < ((f == NULL) ? spatial_bins : pos->maxorder-pos->minorder+1); i++)
2899 if (f == NULL || profile_data[i] == NULL)
2903 passure(good_bins[i] < sample_bins,
2904 "%d %d", good_bins[i], sample_bins);
2906 stepx[i] = (int) (stepx[i]*(good_bins[i]*0.8/sample_bins));
2931 for (pos->order = pos->minorder; pos->order <= pos->minorder; pos->order++) {
2933 for (pos->order = pos->minorder; pos->order <= pos->maxorder; pos->order++) {
2936 if (profile_data[pos->order-pos->minorder] == NULL) {
2939 check( profile_data[pos->order-pos->minorder] =
2945 "Error measuring profile of order #%d using chunk size = %d",
2948 bins = cpl_table_get_nrow(profile_data[pos->order-pos->minorder]);
2950 uves_msg(
"Order %-2d: Chi^2/N = %.2f; FWHM = %.2f pix; Offset = %.2f pix",
2952 (bins > 0) ? cpl_table_get_column_median(
2953 profile_data[pos->order-pos->minorder],
2954 "Reduced_chisq") : 0,
2956 (bins > 0) ? cpl_table_get_column_median(
2957 profile_data[pos->order-pos->minorder],
2958 "Sigma") * TWOSQRT2LN2 : 0,
2959 (bins > 0) ? cpl_table_get_column_median(
2960 profile_data[pos->order-pos->minorder],
2987 for (i = 0; i < spatial_bins; i++)
2991 step /= spatial_bins;
2993 *profile_global = cpl_table_new(0);
2995 cpl_table_new_column(*profile_global,
"Dummy" , CPL_TYPE_DOUBLE);
3002 "Error measuring profile (virtual method)");
3004 passure( nbins == spatial_bins,
"%d %d", nbins, spatial_bins);
3006 for (i = 0; i < spatial_bins; i++)
3008 good_bins[i] = cpl_table_get_nrow(profile_data[i]);
3013 (good_bins[i] > 0) ?
3014 cpl_table_get_column_median(profile_data[i],
"Prof") : 0,
3039 "resampled profile (%d spatial bins)",
3042 uves_extract_profile_delete(&profile);
3043 profile = uves_extract_profile_new(NULL,
3049 for (i = 0; i < spatial_bins; i++)
3056 bool enough_points = (
3057 cpl_table_get_nrow(profile_data[i]) >= (max_degree + 1)*(max_degree + 1));
3066 double min_reject = -0.01;
3076 "X",
"Order",
"Prof", NULL,
3077 "Proffit", NULL, NULL,
3080 max_degree, max_degree, -1, min_reject,
3082 NULL, NULL, 0, NULL);
3088 profile->dy_poly[i] =
3090 "X",
"Order",
"Prof", NULL,
3092 "Proffit", NULL, NULL,
3093 NULL, NULL, NULL, kappa, -1);
3096 if (cpl_error_get_code() == CPL_ERROR_SINGULAR_MATRIX)
3102 enough_points =
false;
3105 assure( cpl_error_get_code() == CPL_ERROR_NONE,
3106 cpl_error_get_code(),
3107 "Could not fit polynomial to bin %d", i);
3117 cpl_table_new_column(profile_data[i],
"Proffit", CPL_TYPE_DOUBLE);
3118 if (cpl_table_get_nrow(profile_data[i]) > 0)
3120 cpl_table_fill_column_window_double(
3121 profile_data[i],
"Proffit",
3122 0, cpl_table_get_nrow(profile_data[i]),
3131 if (profile->is_zero_degree[i])
3141 double min_rms = 0.1;
3148 uves_free_table(profile_global);
3151 for (pos->order = pos->minorder; order <= pos->minorder; pos->order++)
3153 for (pos->order = pos->minorder; pos->order <= pos->maxorder; pos->order++)
3156 if (pos->order == pos->minorder)
3158 *profile_global = cpl_table_duplicate(profile_data[0]);
3163 cpl_table_insert(*profile_global,
3164 profile_data[pos->order-pos->minorder], 0);
3168 uves_extract_profile_delete(&profile);
3169 profile = uves_extract_profile_new(f, dfda, M, 0, 0);
3181 for (pos->order = pos->minorder; pos->order <= pos->maxorder; pos->order++)
3189 (cpl_table_get_nrow(profile_data[pos->order-pos->minorder])
3192 (cpl_table_get_nrow(*profile_global) >= (max_degree + 1)*(max_degree + 1));
3198 double min_val = -pos->sg.length/2;
3199 double max_val = pos->sg.length/2;
3200 double minmax_pos[4][2];
3201 minmax_pos[0][0] = 1 ; minmax_pos[0][1] = pos->minorder;
3202 minmax_pos[1][0] = 1 ; minmax_pos[1][1] = pos->maxorder;
3203 minmax_pos[2][0] = pos->nx; minmax_pos[2][1] = pos->minorder;
3204 minmax_pos[3][0] = pos->nx; minmax_pos[3][1] = pos->maxorder;
3206 uves_msg_low(
"Fitting profile centroid = polynomial(x, order)");
3210 profile_data[pos->order-pos->minorder],
"dY0", 1.0) );
3212 profile->y0[pos->order - pos->minorder] =
3214 profile_data[pos->order-pos->minorder],
3215 "X",
"Y0",
"dY0", degree,
3219 check_nomsg( uves_raise_to_median_frac(*profile_global,
"dY0", 1.0) );
3224 "X",
"Order",
"Y0",
"dY0",
3225 "Y0fit", NULL, NULL,
3228 max_degree, max_degree, min_rms, -1,
3230 &min_val, &max_val, 4, minmax_pos);
3232 if (cpl_error_get_code() == CPL_ERROR_SINGULAR_MATRIX)
3241 enough_points =
false;
3245 assure( cpl_error_get_code() == CPL_ERROR_NONE,
3246 cpl_error_get_code(),
3247 "Error fitting object position");
3252 uves_msg_low(
"Object offset at chip center = %.2f pixels",
3256 (pos->minorder+pos->maxorder)/2));
3259 if (sqrt(mse) > 0.5)
3262 "(usually RMS ~= 0.1 pixels)");
3271 "object centroid. Setting offset to zero",
3272 cpl_table_get_nrow(profile_data[pos->order - pos->minorder]));
3274 uves_msg_warning(
"Too few points (%" CPL_SIZE_FORMAT
") to fit global polynomial to "
3275 "object centroid. Setting offset to zero",
3276 cpl_table_get_nrow(*profile_global));
3283 cpl_table_new_column(profile_data[pos->order-pos->minorder],
"Y0fit", CPL_TYPE_DOUBLE);
3284 if (cpl_table_get_nrow(profile_data[pos->order-pos->minorder]) > 0)
3286 cpl_table_fill_column_window_double(
3287 profile_data[pos->order-pos->minorder],
"Y0fit",
3288 0, cpl_table_get_nrow(profile_data[pos->order-pos->minorder]),
3294 cpl_table_new_column(*profile_global,
"Y0fit", CPL_TYPE_DOUBLE);
3295 if (cpl_table_get_nrow(*profile_global) > 0)
3297 cpl_table_fill_column_window_double(
3298 *profile_global,
"Y0fit",
3299 0, cpl_table_get_nrow(*profile_global),
3311 for (pos->order = pos->minorder; pos->order <= pos->maxorder; pos->order++)
3318 (cpl_table_get_nrow(profile_data[pos->order-pos->minorder])
3321 (cpl_table_get_nrow(*profile_global) >= (max_degree + 1)*(max_degree + 1));
3325 double min_val = 0.1;
3326 double max_val = pos->sg.length;
3327 double minmax_pos[4][2];
3328 minmax_pos[0][0] = 1 ; minmax_pos[0][1] = pos->minorder;
3329 minmax_pos[1][0] = 1 ; minmax_pos[1][1] = pos->maxorder;
3330 minmax_pos[2][0] = pos->nx; minmax_pos[2][1] = pos->minorder;
3331 minmax_pos[3][0] = pos->nx; minmax_pos[3][1] = pos->maxorder;
3333 uves_msg_low(
"Fitting profile width = polynomial(x, order)");
3337 profile_data[pos->order-pos->minorder],
"dSigma", 1.0) );
3340 profile->sigma[pos->order - pos->minorder] =
3342 profile_data[pos->order-pos->minorder],
3343 "X",
"Sigma",
"dSigma", degree,
3347 check_nomsg( uves_raise_to_median_frac(*profile_global,
"dSigma", 1.0) );
3352 "X",
"Order",
"Sigma",
"dSigma",
3353 "Sigmafit", NULL, NULL,
3356 max_degree, max_degree, min_rms, -1,
3358 &min_val, &max_val, 4, minmax_pos);
3361 if (cpl_error_get_code() == CPL_ERROR_SINGULAR_MATRIX)
3370 enough_points =
false;
3374 assure( cpl_error_get_code() == CPL_ERROR_NONE,
3375 cpl_error_get_code(),
3376 "Error fitting profile width");
3380 uves_msg_low(
"Profile FWHM at chip center = %.2f pixels",
3384 (pos->minorder+pos->maxorder)/2));
3393 "object width. Setting std.dev. to 1 pixel",
3394 cpl_table_get_nrow(profile_data[pos->order - pos->minorder]));
3396 uves_msg_warning(
"Too few points (%" CPL_SIZE_FORMAT
") to fit global polynomial to "
3397 "object width. Setting std.dev. to 1 pixel",
3398 cpl_table_get_nrow(*profile_global));
3406 cpl_table_new_column(profile_data[pos->order-pos->minorder],
"Sigmafit", CPL_TYPE_DOUBLE);
3407 if (cpl_table_get_nrow(profile_data[pos->order-pos->minorder]) > 0)
3409 cpl_table_fill_column_window_double(
3410 profile_data[pos->order-pos->minorder],
"Sigmafit",
3411 0, cpl_table_get_nrow(profile_data[pos->order-pos->minorder]),
3418 cpl_table_new_column(*profile_global,
"Sigmafit", CPL_TYPE_DOUBLE);
3419 if (cpl_table_get_nrow(*profile_global) > 0)
3421 cpl_table_fill_column_window_double(
3422 *profile_global,
"Sigmafit",
3423 0, cpl_table_get_nrow(*profile_global),
3436 cpl_table_get_nrow(profile_data[pos->order - pos->minorder]) > 0 ?
3437 cpl_table_get_column_median(profile_data[pos->order - pos->minorder],
3438 "Reduced_chisq") : 1.0);
3442 cpl_table_get_nrow(*profile_global) > 0 ?
3443 cpl_table_get_column_median(*profile_global,
3444 "Reduced_chisq") : 1.0);
3476 uves_free_table(profile_global);
3477 for (pos->order = pos->minorder; pos->order <= pos->maxorder; pos->order++)
3479 if (pos->order == pos->minorder)
3481 *profile_global = cpl_table_duplicate(profile_data[0]);
3486 cpl_table_insert(*profile_global,
3487 profile_data[pos->order-pos->minorder], 0);
3499 int xmin = uves_max_int(1 , pos->nx/2-100);
3500 int xmax = uves_min_int(pos->nx, pos->nx/2+100);
3501 int order = (pos->minorder + pos->maxorder)/2;
3504 plot0x = cpl_vector_new(uves_round_double(pos->sg.length+5)*(xmax-xmin+1));
3505 plot0y = cpl_vector_new(uves_round_double(pos->sg.length+5)*(xmax-xmin+1));
3506 plot1x = cpl_vector_new(uves_round_double(pos->sg.length+5)*(xmax-xmin+1));
3507 plot1y = cpl_vector_new(uves_round_double(pos->sg.length+5)*(xmax-xmin+1));
3524 for (pos->y = pos->ylow; pos->y <= pos->yhigh; pos->y++)
3527 double pixelval = cpl_image_get(image, pos->x, pos->y, &pis_rejected);
3534 uves_extract_profile_set(profile, pos, NULL);
3537 for (pos->y = pos->ylow; pos->y <= pos->yhigh; pos->y++)
3539 double dy = pos->y - pos->ycenter;
3541 double pixelval = cpl_image_get(
3542 image, pos->x, uves_round_double(pos->y), &pis_rejected);
3544 if (!pis_rejected && flux != 0)
3553 cpl_vector_set(plot0x, indx, dy);
3554 cpl_vector_set(plot0y, indx, uves_extract_profile_evaluate(profile, pos));
3556 cpl_vector_set(plot1x, indx, dy);
3557 cpl_vector_set(plot1y, indx, pixelval);
3565 cpl_vector_set_size(plot0x, indx);
3566 cpl_vector_set_size(plot0y, indx);
3567 cpl_vector_set_size(plot1x, indx);
3568 cpl_vector_set_size(plot1y, indx);
3570 plot[0] = cpl_bivector_wrap_vectors(plot0x, plot0y);
3571 plot[1] = cpl_bivector_wrap_vectors(plot1x, plot1y);
3573 plot_titles[0] = uves_sprintf(
3574 "Model spatial profile at (order, x) = (%d, %d)", order, pos->nx/2);
3575 plot_titles[1] = uves_sprintf(
3576 "Empirical spatial profile at (order, x) = (%d, %d)", order, pos->nx/2);
3578 check( uves_plot_bivectors(plot, plot_titles, 2,
"DY",
"Profile"),
"Plotting failed");
3583 "polynomial is ill-formed");
3595 for (i = 0; i < cpl_table_get_nrow(*profile_global); i++)
3597 double y0fit = cpl_table_get_double(*profile_global,
"Y0fit", i, NULL);
3598 int order = cpl_table_get_int (*profile_global,
"Order", i, NULL);
3599 int x = cpl_table_get_int (*profile_global,
"X" , i, NULL);
3608 cpl_table_set_double(*profile_global,
"Y0fit_world", i, y0fit + pos->ycenter);
3613 for (pos->order = pos->minorder; pos->order <= pos->minorder; pos->order++)
3615 for (pos->order = pos->minorder; pos->order <= pos->maxorder; pos->order++)
3618 if (good_bins[pos->order-pos->minorder] == 0)
3626 for (pos->order = pos->minorder; pos->order <= pos->maxorder; pos->order++)
3634 - ( - pos->sg.length/2 ));
3637 pos->nx/2) * TWOSQRT2LN2);
3640 check_nomsg(cpl_table_set_double(info_tbl,
"ObjPosOnSlit" , pos->order - pos->minorder, objpos));
3641 check_nomsg(cpl_table_set_double(info_tbl,
"ObjFwhmAvg" , pos->order - pos->minorder, fwhm));
3645 pos->nx/2, pos->order)
3646 - ( - pos->sg.length/2 ));
3649 pos->nx/2, pos->order)*
3652 check_nomsg(cpl_table_set_double(info_tbl,
"ObjPosOnSlit" , pos->order - pos->minorder, objpos));
3653 check_nomsg(cpl_table_set_double(info_tbl,
"ObjFwhmAvg" , pos->order - pos->minorder, fwhm));
3658 if (cpl_table_get_nrow(*profile_global) > 0)
3660 double med_chisq = cpl_table_get_column_median(
3661 *profile_global,
"Reduced_chisq");
3664 if (med_chisq > limit || med_chisq < 1/limit)
3676 "good fit to the data: median(Chi^2/N) = %f",
3679 if (f != NULL && med_chisq > limit)
3682 "measuring method: virtual");
3687 uves_msg(
"Median(reduced Chi^2) is %f", med_chisq);
3698 uves_free_mask(&image_bad);
3700 cpl_free(good_bins);
3701 if (profile_data != NULL)
3704 for (i = 0; i < ((f == NULL) ? spatial_bins : pos->maxorder-pos->minorder+1); i++)
3706 if (profile_data[i] != NULL)
3708 uves_free_table(&(profile_data[i]));
3711 cpl_free(profile_data);
3713 cpl_bivector_unwrap_vectors(plot[0]);
3714 cpl_bivector_unwrap_vectors(plot[1]);
3715 cpl_free(plot_titles[0]);
3716 cpl_free(plot_titles[1]);
3717 uves_free_vector(&plot0x);
3718 uves_free_vector(&plot0y);
3719 uves_free_vector(&plot1x);
3720 uves_free_vector(&plot1y);
3732 int (*f) (
const double x[],
const double a[],
double *result);
3733 int (*dfda)(
const double x[],
const double a[],
double result[]);
3746 eval_pol(
const double *coeffs,
3747 int degree1,
int degree2,
3748 double x1,
double x2)
3754 for (j = 0, x2j = 1;
3762 double r = coeffs[i + (degree1+1)*j];
3768 r += coeffs[i + (degree1+1)*j];
3793 profile_f(
const double x[],
const double a[],
double *result)
3795 int xi = uves_round_double(x[0]);
3797 int mi = uves_round_double(x[2]);
3800 double y_0 = eval_pol(a,
3801 profile_params.deg_y0_x,
3802 profile_params.deg_y0_m,
3804 double sigma = eval_pol(a + (1 + profile_params.deg_y0_x)*(1 + profile_params.deg_y0_m),
3805 profile_params.deg_sigma_x,
3806 profile_params.deg_sigma_m,
3823 if (profile_params.f(xf, af, &norm_prof) != 0)
3828 idx = xi + (mi - profile_params.minorder)*(profile_params.nx + 1);
3830 *result = profile_params.sky[idx] + profile_params.flux[idx] * norm_prof;
3858 profile_dfda(
const double x[],
const double a[],
double result[])
3860 int xi = uves_round_double(x[0]);
3862 int mi = uves_round_double(x[2]);
3864 double y_0 = eval_pol(a,
3865 profile_params.deg_y0_x,
3866 profile_params.deg_y0_m,
3868 double sigma = eval_pol(a + (1 + profile_params.deg_y0_x)*(1 + profile_params.deg_y0_m),
3869 profile_params.deg_sigma_x,
3870 profile_params.deg_sigma_m,
3873 double norm_prof_derivatives[5];
3886 if (profile_params.dfda(xf, af, norm_prof_derivatives) != 0)
3892 int idx = xi + (mi - profile_params.minorder)*(profile_params.nx + 1);
3895 double norm_prof_dy0 = norm_prof_derivatives[0];
3896 double norm_prof_dsigma = norm_prof_derivatives[1];
3916 result[i + (profile_params.deg_y0_x + 1) * j] = profile_params.flux[idx] * norm_prof_dy0;
3917 for (j = 0; j <= profile_params.deg_y0_m; j++) {
3921 result[i + (profile_params.deg_y0_x + 1) * j] =
3922 result[i + (profile_params.deg_y0_x + 1) * (j-1)] * mi;
3924 for (i = 1; i <= profile_params.deg_y0_x; i++) {
3925 result[i + (profile_params.deg_y0_x + 1) * j] =
3926 result[i-1 + (profile_params.deg_y0_x + 1) * j] * xi;
3938 result += (profile_params.deg_y0_x + 1) * (profile_params.deg_y0_m + 1);
3944 result[i + (profile_params.deg_sigma_x + 1) * j] =
3945 profile_params.flux[idx] * norm_prof_dsigma;
3946 for (j = 0; j <= profile_params.deg_sigma_m; j++) {
3950 result[i + (profile_params.deg_sigma_x + 1) * j] =
3951 result[i + (profile_params.deg_sigma_x + 1) * (j-1)] * mi;
3953 for (i = 1; i <= profile_params.deg_sigma_x; i++) {
3954 result[i + (profile_params.deg_sigma_x + 1) * j] =
3955 result[i-1 + (profile_params.deg_sigma_x + 1) * j] * xi;
3986 const cpl_binary *image_bpm,
3987 uves_iterate_position *pos,
3989 int (*f) (
const double x[],
const double a[],
double *result),
3990 int (*dfda)(
const double x[],
const double a[],
double result[]),
3992 const cpl_image *sky_spectrum)
3994 cpl_table *profile_data = NULL;
3996 cpl_matrix *covariance = NULL;
3999 cpl_matrix *eval_points = NULL;
4000 cpl_vector *eval_data = NULL;
4001 cpl_vector *eval_err = NULL;
4002 cpl_vector *coeffs = NULL;
4003 #if CREATE_DEBUGGING_TABLE
4004 cpl_table *temp = NULL;
4006 double *fluxes = NULL;
4007 double *skys = NULL;
4010 cpl_table *estimate = NULL;
4011 cpl_table *estimate_dup = NULL;
4017 cpl_vector *dy = NULL;
4018 cpl_vector *prof = NULL;
4019 cpl_vector *prof2= NULL;
4020 cpl_vector *dprof = NULL;
4021 cpl_vector **data = NULL;
4023 double *hicut = NULL;
4024 double *locut = NULL;
4027 const double *image_data;
4028 const double *noise_data;
4033 int norders = pos->maxorder-pos->minorder+1;
4036 sky_spectrum = sky_spectrum;
4041 image_data = cpl_image_get_data_double_const(image);
4042 noise_data = cpl_image_get_data_double_const(image_noise);
4045 profile_data = cpl_table_new((nx/chunk + 3) * norders);
4047 profile_data = cpl_table_new(pos->nx);
4051 check( (cpl_table_new_column(profile_data,
"Order", CPL_TYPE_INT),
4052 cpl_table_new_column(profile_data,
"X", CPL_TYPE_INT),
4053 cpl_table_new_column(profile_data,
"Y0", CPL_TYPE_DOUBLE),
4054 cpl_table_new_column(profile_data,
"Sigma", CPL_TYPE_DOUBLE),
4055 cpl_table_new_column(profile_data,
"Norm", CPL_TYPE_DOUBLE),
4056 cpl_table_new_column(profile_data,
"dY0", CPL_TYPE_DOUBLE),
4057 cpl_table_new_column(profile_data,
"dSigma", CPL_TYPE_DOUBLE),
4058 cpl_table_new_column(profile_data,
"dNorm", CPL_TYPE_DOUBLE),
4059 cpl_table_new_column(profile_data,
"Y0_world", CPL_TYPE_DOUBLE),
4060 cpl_table_new_column(profile_data,
"Y0fit_world", CPL_TYPE_DOUBLE),
4061 cpl_table_new_column(profile_data,
"Reduced_chisq", CPL_TYPE_DOUBLE)),
4062 "Error initializing order trace table for order #%d", pos->order);
4065 cpl_table_set_column_unit(profile_data,
"X" ,
"pixels");
4066 cpl_table_set_column_unit(profile_data,
"Y0",
"pixels");
4067 cpl_table_set_column_unit(profile_data,
"Sigma",
"pixels");
4068 cpl_table_set_column_unit(profile_data,
"dY0",
"pixels");
4069 cpl_table_set_column_unit(profile_data,
"dSigma",
"pixels");
4073 UVES_TIME_START(
"Measure loop");
4075 nbins = uves_round_double(pos->sg.length + 5);
4076 data = cpl_calloc(nbins,
sizeof(cpl_vector *));
4077 size = cpl_calloc(nbins,
sizeof(
int));
4078 locut = cpl_calloc(nbins,
sizeof(
double));
4079 hicut = cpl_calloc(nbins,
sizeof(
double));
4082 for (i = 0; i < nbins; i++)
4084 data[i] = cpl_vector_new(1);
4107 int deg_sigma_x = 0;
4108 int deg_sigma_m = 0;
4111 (deg_y0_x +1)*(deg_y0_m +1) +
4112 (deg_sigma_x+1)*(deg_sigma_m+1);
4118 #if CREATE_DEBUGGING_TABLE
4119 temp = cpl_table_new(norders*nx*uves_round_double(pos->sg.length+3));
4120 cpl_table_new_column(temp,
"x", CPL_TYPE_DOUBLE);
4121 cpl_table_new_column(temp,
"y", CPL_TYPE_DOUBLE);
4122 cpl_table_new_column(temp,
"order", CPL_TYPE_DOUBLE);
4123 cpl_table_new_column(temp,
"dat", CPL_TYPE_DOUBLE);
4124 cpl_table_new_column(temp,
"err", CPL_TYPE_DOUBLE);
4147 eval_points = cpl_matrix_new(norders*nx*uves_round_double(pos->sg.length+3), 3);
4148 eval_data = cpl_vector_new(norders*nx*uves_round_double(pos->sg.length+3));
4149 eval_err = cpl_vector_new(norders*nx*uves_round_double(pos->sg.length+3));
4151 fluxes = cpl_calloc((nx+1)*norders,
sizeof(
double));
4152 skys = cpl_calloc((nx+1)*norders,
sizeof(
double));
4156 estimate = cpl_table_new(norders);
4157 cpl_table_new_column(estimate,
"Order", CPL_TYPE_INT);
4158 cpl_table_new_column(estimate,
"Y0" , CPL_TYPE_DOUBLE);
4159 cpl_table_new_column(estimate,
"Sigma", CPL_TYPE_DOUBLE);
4161 coeffs = cpl_vector_new(ncoeffs);
4162 ia = cpl_calloc(ncoeffs,
sizeof(
int));
4165 for (i = 0; i < ncoeffs; i++)
4167 cpl_vector_set(coeffs, i, 0);
4174 for (order = 17; order <= 17; order++) {
4183 for (x = chunk/2; x <= nx - chunk/2; x += chunk) {
4187 for (i = 0; i < nbins; i++)
4195 cpl_vector_set_size(data[i], 2*(chunk + 1));
4201 x - chunk/2 + 1, x + chunk/2,
4207 int bin = pos->y - pos->ylow;
4210 DATA(image_data, pos)));
4215 for (i = 0; i < nbins; i++)
4221 else if (size[i] <= chunk/2)
4225 locut[i] = cpl_vector_get_max(data[i]) + 1;
4226 hicut[i] = cpl_vector_get_min(data[i]) - 1;
4232 double median, stdev;
4240 cpl_vector_set_size(data[i], k);
4242 data_data = cpl_vector_get_data(data[i]);
4244 median = cpl_vector_get_median_const(data[i]);
4245 stdev = cpl_vector_get_stdev(data[i]);
4246 locut[i] = median - kappa*stdev;
4247 hicut[i] = median + kappa*stdev;
4253 for (j = 0; j < size[i]; j++)
4255 if (locut[i] <= data_data[j] &&
4256 data_data[j] <= hicut[i])
4258 data_data[k] = data_data[j];
4264 while (k < size[i] && k > 1);
4275 x - chunk/2 + 1, x + chunk/2,
4283 for (pos->y = pos->ylow; pos->y <= pos->yhigh; pos->y++)
4285 int bin = pos->y - pos->ylow;
4287 if (ISGOOD(image_bpm, pos) &&
4288 (locut[bin] <= DATA(image_data, pos) &&
4289 DATA(image_data, pos) <= hicut[bin])
4292 double pix = DATA(image_data, pos);
4293 double dy = pos->y - pos->ycenter;
4296 cpl_matrix_set(eval_points, n, 0, pos->x);
4297 cpl_matrix_set(eval_points, n, 1, dy);
4298 cpl_matrix_set(eval_points, n, 2, order);
4299 cpl_vector_set(eval_data, n, pix);
4300 cpl_vector_set(eval_err , n,
4301 DATA(noise_data, pos));
4305 sumwyy += pix * dy * dy;
4306 #if CREATE_DEBUGGING_TABLE
4307 cpl_table_set_double(temp,
"x", n, pos->x);
4308 cpl_table_set_double(temp,
"y", n, dy);
4309 cpl_table_set_double(temp,
"order", n, order);
4310 cpl_table_set_double(temp,
"dat", n, pix);
4311 cpl_table_set_double(temp,
"err", n,
4312 DATA(noise_data, pos));
4323 fluxes[pos->x + (order-pos->minorder)*(pos->nx+1)] = flux;
4324 skys [pos->x + (order-pos->minorder)*(pos->nx+1)] =
4325 cpl_image_get(sky_spectrum,
4326 pos->x, order-pos->minorder+1, &pis_rejected);
4329 skys [pos->x + (order-pos->minorder)*(pos->nx+1)] = 0;
4345 y0_estim = sumwy/sumw;
4347 sigma_estim = sumwyy/sumw - (sumwy/sumw)*(sumwy/sumw);
4348 if (sigma_estim > 0)
4350 sigma_estim = sqrt(sigma_estim);
4351 sigma_is_good =
true;
4355 sigma_is_good =
false;
4362 sigma_is_good =
false;
4365 cpl_table_set_int (estimate,
"Order", order - pos->minorder, order);
4369 cpl_table_set_double(estimate,
"Y0" , order - pos->minorder, y0_estim);
4373 cpl_table_set_invalid(estimate,
"Y0", order - pos->minorder);
4378 cpl_table_set_double(estimate,
"Sigma",
4379 order - pos->minorder, sigma_estim);
4383 cpl_table_set_invalid(estimate,
"Sigma", order - pos->minorder);
4388 if (y0_is_good && sigma_is_good) {
4390 order, y0_estim, sigma_estim*TWOSQRT2LN2);
4392 else if (y0_is_good && !sigma_is_good) {
4396 else if (!y0_is_good && sigma_is_good) {
4398 order, sigma_estim);
4408 cpl_matrix_set_size(eval_points, n, 3);
4409 cpl_vector_set_size(eval_data, n);
4410 cpl_vector_set_size(eval_err , n);
4412 #if CREATE_DEBUGGING_TABLE
4413 cpl_table_set_size(temp, n);
4422 cpl_table_dump(estimate, 0, cpl_table_get_nrow(estimate), stdout);
4426 estimate_dup = cpl_table_duplicate(estimate);
4428 uves_erase_invalid_table_rows(estimate_dup,
"Y0");
4431 degree = (cpl_table_get_nrow(estimate_dup) > 1) ? 1 : 0;
4434 estimate_dup,
"Order",
"Y0", NULL,
4442 if (cpl_error_get_code() != CPL_ERROR_NONE)
4445 "Setting initial offset to zero",
4446 cpl_error_get_message());
4455 uves_free_table(&estimate_dup);
4456 estimate_dup = cpl_table_duplicate(estimate);
4458 uves_erase_invalid_table_rows(estimate_dup,
"Sigma");
4460 degree = (cpl_table_get_nrow(estimate_dup) > 1) ? 1 : 0;
4463 estimate_dup,
"Order",
"Sigma", NULL,
4469 if (cpl_error_get_code() != CPL_ERROR_NONE)
4472 "Setting initial sigma to 1 pixel",
4473 cpl_error_get_message());
4487 cpl_vector_set(coeffs, 0,
4492 cpl_vector_set(coeffs, 0 + (deg_y0_x+1)*1,
4496 cpl_vector_get(coeffs, 0),
4497 cpl_vector_get(coeffs, 0 + (deg_y0_x+1)*1));
4502 cpl_vector_get(coeffs, 0));
4507 cpl_vector_set(coeffs, (deg_y0_x+1)*(deg_y0_m+1),
4510 if (deg_sigma_m >= 1)
4512 cpl_vector_set(coeffs, (deg_y0_x+1)*(deg_y0_m+1) +
4513 0 + (deg_sigma_x+1)*1,
4517 cpl_vector_get(coeffs, (deg_y0_x+1)*(deg_y0_m+1) +
4519 cpl_vector_get(coeffs, (deg_y0_x+1)*(deg_y0_m+1) +
4520 0 + (deg_y0_x+1)*1));
4525 cpl_vector_get(coeffs, (deg_y0_x+1)*(deg_y0_m+1) +
4532 profile_params.flux = fluxes;
4533 profile_params.sky = skys;
4534 profile_params.minorder = pos->minorder;
4535 profile_params.nx = nx;
4537 profile_params.f = f;
4538 profile_params.dfda = dfda;
4540 profile_params.deg_y0_x = deg_y0_x;
4541 profile_params.deg_y0_m = deg_y0_m;
4542 profile_params.deg_sigma_x = deg_sigma_x;
4543 profile_params.deg_sigma_m = deg_sigma_m;
4548 cpl_vector_fill(eval_err,
4549 cpl_vector_get_median_const(eval_err));
4551 uves_msg_error(
"Fitting model to %d positions; %d bad pixels found",
4554 uves_fit(eval_points, NULL,
4555 eval_data, eval_err,
4564 if (cpl_error_get_code() == CPL_ERROR_SINGULAR_MATRIX ||
4565 cpl_error_get_code() == CPL_ERROR_CONTINUE)
4567 uves_msg_warning(
"Fitting global model failed (%s)", cpl_error_get_message());
4569 #if CREATE_DEBUGGING_TABLE
4570 cpl_table_save(temp, NULL, NULL,
"tab.fits", CPL_IO_DEFAULT);
4575 assure( cpl_error_get_code() == CPL_ERROR_NONE,
4576 cpl_error_get_code(),
"Fitting global model failed");
4578 cpl_matrix_dump(covariance, stdout); fflush(stdout);
4580 uves_msg_error(
"Solution: y0 ~= %g", eval_pol(cpl_vector_get_data(coeffs),
4583 (pos->minorder+pos->maxorder)/2));
4584 uves_msg_error(
"Solution: sigma ~= %g", eval_pol(cpl_vector_get_data(coeffs)+
4585 (deg_y0_x+1)*(deg_y0_m+1),
4588 (pos->minorder+pos->maxorder)/2));
4591 for (order = pos->minorder; order <= pos->maxorder; order++) {
4592 for (x = chunk/2; x <= nx - chunk/2; x += chunk)
4594 double y_0 = eval_pol(cpl_vector_get_data(coeffs),
4595 deg_y0_x, deg_y0_m, x, order);
4596 double sigma = fabs(eval_pol(cpl_vector_get_data(coeffs)+
4597 (deg_y0_x+1)*(deg_y0_m+1),
4598 deg_sigma_x, deg_sigma_m, x, order));
4612 int i1, i2, j_1, j2;
4614 for (i1 = 0; i1 < (deg_y0_x+1); i1++)
4615 for (j_1 = 0; j_1 < (deg_y0_m+1); j_1++)
4616 for (i2 = 0; i2 < (deg_y0_x+1); i2++)
4617 for (j2 = 0; j2 < (deg_y0_m+1); j2++)
4619 dy0 += cpl_matrix_get(covariance,
4620 i1+(deg_y0_x+1)*j_1,
4621 i2+(deg_y0_x+1)*j2) *
4635 for (i1 = 0; i1 < (deg_sigma_x+1); i1++)
4636 for (j_1 = 0; j_1 < (deg_sigma_m+1); j_1++)
4637 for (i2 = 0; i2 < (deg_sigma_x+1); i2++)
4638 for (j2 = 0; j2 < (deg_sigma_m+1); j2++)
4643 dsigma += cpl_matrix_get(
4645 (deg_y0_x+1)*(deg_y0_m+1) + i1+(deg_sigma_x+1)*j_1,
4646 (deg_y0_x+1)*(deg_y0_m+1) + i2+(deg_sigma_x+1)*j2) *
4652 dsigma = sqrt(dsigma);
4660 check((cpl_table_set_int (profile_data,
"Order", profile_row, order),
4661 cpl_table_set_int (profile_data,
"X" , profile_row, x),
4662 cpl_table_set_double(profile_data,
"Y0" , profile_row, y_0),
4663 cpl_table_set_double(profile_data,
"Sigma", profile_row, sigma),
4664 cpl_table_set_double(profile_data,
"Norm" , profile_row, 1),
4665 cpl_table_set_double(profile_data,
"dY0" , profile_row, dy0),
4666 cpl_table_set_double(profile_data,
"dSigma", profile_row, dsigma),
4667 cpl_table_set_double(profile_data,
"dNorm", profile_row, 1),
4668 cpl_table_set_double(profile_data,
"Y0_world", profile_row, -1),
4669 cpl_table_set_double(profile_data,
"Reduced_chisq", profile_row,
4671 "Error writing table row %d", profile_row+1);
4675 #if CREATE_DEBUGGING_TABLE
4676 cpl_table_new_column(temp,
"pemp", CPL_TYPE_DOUBLE);
4677 cpl_table_new_column(temp,
"fit", CPL_TYPE_DOUBLE);
4678 cpl_table_new_column(temp,
"pfit", CPL_TYPE_DOUBLE);
4680 for (i = 0; i < cpl_table_get_nrow(temp); i++)
4682 double y = cpl_table_get_double(temp,
"y", i, NULL);
4683 int xi = uves_round_double(cpl_table_get_double(temp,
"x", i, NULL));
4684 int mi = uves_round_double(cpl_table_get_double(temp,
"order", i, NULL));
4685 double dat = cpl_table_get_double(temp,
"dat", i, NULL);
4686 int idx = xi + (mi - profile_params.minorder)*(profile_params.nx + 1);
4694 cpl_vector_get_data(coeffs), &flux_fit);
4696 cpl_table_set(temp,
"pemp", i,
4697 (dat - profile_params.sky[idx])/profile_params.flux[idx]);
4699 cpl_table_set(temp,
"fit", i, flux_fit);
4701 cpl_table_set(temp,
"pfit", i,
4702 (flux_fit - profile_params.sky[idx])/profile_params.flux[idx]);
4706 cpl_table_save(temp, NULL, NULL,
"tab.fits", CPL_IO_DEFAULT));
4712 dy = cpl_vector_new((chunk+1) * ((
int)(pos->sg.length + 3)));
4713 prof = cpl_vector_new((chunk+1) * ((
int)(pos->sg.length + 3)));
4714 prof2 = cpl_vector_new((chunk+1) * ((
int)(pos->sg.length + 3)));
4715 dprof = cpl_vector_new((chunk+1) * ((
int)(pos->sg.length + 3)));
4717 for (x = 1 + chunk/2; x + chunk/2 <= pos->nx; x += chunk) {
4721 const int points_needed_for_fit = 6;
4727 cpl_vector_set_size(dy, (chunk+1) * ((
int)(pos->sg.length + 3)));
4728 cpl_vector_set_size(prof, (chunk+1) * ((
int)(pos->sg.length + 3)));
4729 cpl_vector_set_size(prof2, (chunk+1) * ((
int)(pos->sg.length + 3)));
4730 cpl_vector_set_size(dprof, (chunk+1) * ((
int)(pos->sg.length + 3)));
4733 for (i = 0; i < nbins; i++)
4741 cpl_vector_set_size(data[i], 2*(chunk + 1));
4750 pos->order, pos->order,
4755 int bin = pos->y - pos->ylow;
4759 DATA(image_data, pos)));
4764 for (i = 0; i < nbins; i++)
4770 else if (size[i] <= chunk/2)
4774 locut[i] = cpl_vector_get_max(data[i]) + 1;
4775 hicut[i] = cpl_vector_get_min(data[i]) - 1;
4781 double median, stdev;
4789 cpl_vector_set_size(data[i], k);
4791 data_data = cpl_vector_get_data(data[i]);
4793 median = cpl_vector_get_median_const(data[i]);
4794 stdev = cpl_vector_get_stdev(data[i]);
4795 locut[i] = median - kappa*stdev;
4796 hicut[i] = median + kappa*stdev;
4802 for (j = 0; j < size[i]; j++)
4804 if (locut[i] <= data_data[j] &&
4805 data_data[j] <= hicut[i])
4807 data_data[k] = data_data[j];
4813 while (k < size[i] && k > 1);
4822 pos->order, pos->order,
4828 for (pos->y = pos->ylow; pos->y <= pos->yhigh; pos->y++)
4830 int bin = pos->y - pos->ylow;
4832 if (ISGOOD(image_bpm, pos) &&
4833 (locut[bin] <= DATA(image_data, pos) &&
4834 DATA(image_data, pos) <= hicut[bin])
4837 flux += DATA(image_data, pos);
4843 for (pos->y = pos->ylow; pos->y <= pos->yhigh; pos->y++)
4845 int bin = pos->y - pos->ylow;
4847 if (ISGOOD(image_bpm, pos) &&
4848 (locut[bin] <= DATA(image_data, pos) &&
4849 DATA(image_data, pos) <= hicut[bin])
4852 double pix = DATA(image_data, pos);
4854 cpl_vector_set(dy , n, pos->y - pos->ycenter);
4855 cpl_vector_set(prof , n, pix/flux);
4856 cpl_vector_set(dprof, n, (flux > 0) ?
4857 DATA(noise_data, pos)/flux :
4858 -DATA(noise_data, pos)/flux);
4871 if (n >= points_needed_for_fit) {
4872 double y_0, norm, background, slope, sigma, red_chisq;
4874 cpl_vector_set_size(dy, n);
4875 cpl_vector_set_size(prof, n);
4876 cpl_vector_set_size(prof2, n);
4877 cpl_vector_set_size(dprof, n);
4881 x-chunk/2, x+chunk/2);
4886 uves_free_matrix(&covariance);
4899 double median = cpl_vector_get_median_const(dprof);
4901 cpl_vector_fill(dprof, median);
4903 uves_fit_1d(dy, NULL,
4912 &y_0, &sigma, &norm, &background, &slope,
4923 covariance = cpl_matrix_new(4,4);
4924 cpl_matrix_set(covariance, 0, 0, 1);
4925 cpl_matrix_set(covariance, 1, 1, 1);
4926 cpl_matrix_set(covariance, 2, 2, 1);
4927 cpl_matrix_set(covariance, 3, 3, 1);
4947 cpl_vector *pl[] = {NULL, NULL, NULL};
4949 cpl_vector *fit = cpl_vector_new(cpl_vector_get_size(dy));
4951 for (i = 0; i < cpl_vector_get_size(dy); i++)
4953 double yy = cpl_vector_get(dy, i);
4954 cpl_vector_set(fit, i,
4955 exp(-(yy-y_0)*(yy-y_0)/(2*sigma*sigma))
4956 /(sigma*sqrt(2*M_PI)));
4971 cpl_plot_vectors(
"set grid;set yrange[0:0.5];set xlabel 'dy';",
4972 "t 'Spatial profile' w points",
4974 (
const cpl_vector **)pl, 3);
4981 cpl_plot_vectors(
"set grid;set xrange[-2:2];"
4982 "set yrange[0:0.5];set xlabel 'dy';",
4983 "t 'Spatial profile' w points",
4985 (
const cpl_vector **)pl, 3);
4987 uves_free_vector(&fit);
4994 pos->order, pos->order,
4997 y_0 += pos->ycenter;
5022 if (cpl_error_get_code() == CPL_ERROR_CONTINUE ||
5023 cpl_error_get_code()== CPL_ERROR_SINGULAR_MATRIX ||
5024 4.0*sigma >= pos->sg.length || sigma < 0.2) {
5026 uves_msg_debug(
"Profile fitting failed at (order, x) = (%d, %d) "
5027 "(%s), ignoring chunk",
5028 pos->order, x, cpl_error_get_message());
5033 assure( cpl_error_get_code() == CPL_ERROR_NONE, cpl_error_get_code(),
5034 "Gaussian fitting failed");
5037 (cpl_table_set_int (profile_data,
"Order", profile_row, pos->order),
5038 cpl_table_set_int (profile_data,
"X" , profile_row, x),
5039 cpl_table_set_double(profile_data,
"Y0" , profile_row, y_0 - pos->ycenter),
5040 cpl_table_set_double(profile_data,
"Sigma", profile_row, sigma),
5041 cpl_table_set_double(profile_data,
"Norm" , profile_row, norm),
5042 cpl_table_set_double(profile_data,
"dY0" , profile_row,
5043 sqrt(cpl_matrix_get(covariance, 0, 0))),
5044 cpl_table_set_double(profile_data,
"dSigma", profile_row,
5045 sqrt(cpl_matrix_get(covariance, 1, 1))),
5046 cpl_table_set_double(profile_data,
"dNorm", profile_row,
5047 sqrt(cpl_matrix_get(covariance, 2, 2))),
5048 cpl_table_set_double(profile_data,
"Y0_world", profile_row, y_0),
5049 cpl_table_set_double(profile_data,
"Reduced_chisq", profile_row,
5051 "Error writing table");
5061 "at x = %d - %d, ignoring chunk",
5063 x - chunk/2, x + chunk/2);
5069 cpl_table_set_size(profile_data, profile_row);
5076 uves_free_matrix(&eval_points);
5077 uves_free_vector(&eval_data);
5078 uves_free_vector(&eval_err);
5079 uves_free_vector(&coeffs);
5083 #if CREATE_DEBUGGING_TABLE
5084 uves_free_table(&temp);
5086 uves_free_table(&estimate);
5087 uves_free_table(&estimate_dup);
5092 uves_free_matrix(&covariance);
5093 uves_free_vector(&dy);
5094 uves_free_vector(&prof);
5095 uves_free_vector(&prof2);
5096 uves_free_vector(&dprof);
5099 for (i = 0; i < nbins; i++)
5101 uves_free_vector(&(data[i]));
5109 if (cpl_error_get_code() != CPL_ERROR_NONE)
5111 uves_free_table(&profile_data);
5114 return profile_data;
5134 double x2 = pos->nx;
5137 double slope = (y2 - y_1)/(x2 - x1);
5148 double x_yeq1 = ( 1 - y_1)/slope;
5149 double x_yeqny = (pos->ny - y_1)/slope;
5151 if (1 <= x_yeq1 && x_yeq1 <= pos->nx)
5153 double guess = x_yeq1;
5165 if (cpl_error_get_code() != CPL_ERROR_NONE)
5169 "Order polynomial may be ill-formed", pos->order);
5178 if (1 <= x_yeqny && x_yeqny <= pos->nx)
5180 double guess = x_yeqny;
5192 if (cpl_error_get_code() != CPL_ERROR_NONE)
5196 "Order polynomial may be ill-formed",
5197 pos->ny, pos->order);
5208 result = uves_round_double(
5210 uves_min_double(pos->nx, x_yeqny) -
5211 uves_max_double(1, x_yeq1) + 1));
5215 passure( slope < 0,
"%f", slope);
5216 result = uves_round_double(
5218 uves_min_double(pos->nx, x_yeq1 ) -
5219 uves_max_double(1, x_yeqny) + 1));
5277 const cpl_image *image_noise,
5278 uves_iterate_position *pos,
5279 const uves_extract_profile *profile,
5280 bool optimal_extract_sky,
5282 cpl_table *blemish_mask,
5283 cpl_table *cosmic_mask,
5285 cpl_table *profile_table,
5287 cpl_image *spectrum,
5288 cpl_image *spectrum_noise,
5290 cpl_image *sky_spectrum,
5291 cpl_image *sky_spectrum_noise,
5294 cpl_table *signal_to_noise = NULL;
5300 int bins_extracted = 0;
5301 int cold_pixels = 0;
5305 const double *image_data;
5306 const double *noise_data;
5307 double *weights_data;
5308 cpl_mask *image_bad = NULL;
5309 cpl_binary*image_bpm = NULL;
5310 double *noise_buffer = NULL;
5313 int spectrum_row = pos->order - pos->minorder + 1;
5322 assure( cpl_image_get_type(image) == CPL_TYPE_DOUBLE &&
5323 cpl_image_get_type(image_noise) == CPL_TYPE_DOUBLE, CPL_ERROR_UNSUPPORTED_MODE,
5324 "Input image+noise must have type double. Types are %s + %s",
5328 image_data = cpl_image_get_data_double_const(image);
5329 noise_data = cpl_image_get_data_double_const(image_noise);
5330 weights_data = cpl_image_get_data_double(weights);
5332 image_bad = cpl_image_get_bpm(image);
5335 if(blemish_mask!=NULL) {
5336 check_nomsg(px=cpl_table_get_data_int(blemish_mask,
"X"));
5337 check_nomsg(py=cpl_table_get_data_int(blemish_mask,
"Y"));
5339 for(row=0;row<cpl_table_get_nrow(blemish_mask);row++) {
5340 check_nomsg(cpl_mask_set(image_bad,px[row]+1,py[row]+1,CPL_BINARY_1));
5345 image_bpm = cpl_mask_get_data(image_bad);
5349 noise_buffer = cpl_malloc(uves_round_double(pos->sg.length + 5)*
sizeof(
double));
5351 check( (signal_to_noise = cpl_table_new(pos->nx),
5352 cpl_table_new_column(signal_to_noise,
"SN", CPL_TYPE_DOUBLE)),
5353 "Error allocating S/N table");
5356 "Error estimating width of order #%d", pos->order);
5363 for (x = 1; x <= pos->nx; x++)
5365 cpl_image_reject(spectrum, x, spectrum_row);
5368 if (spectrum_noise != NULL)
5370 cpl_image_reject(spectrum_noise, x, spectrum_row);
5372 if (optimal_extract_sky && sky_spectrum != NULL)
5374 cpl_image_reject(sky_spectrum , x, spectrum_row);
5375 cpl_image_reject(sky_spectrum_noise, x, spectrum_row);
5382 pos->order, pos->order,
5387 double flux = 0, variance = 0;
5388 double sky_background = 0, sky_background_noise = 0;
5395 bool found_bad_pixel;
5396 double median_noise;
5398 double redchisq = 0;
5407 uves_extract_profile_set(profile, pos, &warnings);
5437 for (pos->y = pos->ylow; pos->y <= pos->yhigh; pos->y++)
5439 if (DATA(image_bpm, pos) == CPL_BINARY_1)
5441 DATA(weights_data, pos) = -1.0;
5445 DATA(weights_data, pos) = 0.0;
5455 found_bad_pixel =
false;
5457 for (iteration = 0; iteration < 2 || found_bad_pixel; iteration++)
5466 optimal_extract_sky,
5471 &sky_background_noise);
5476 check( found_bad_pixel =
5485 optimal_extract_sky ? sky_background : 0,
5491 "Error rejecting outlier pixel");
5496 found_bad_pixel =
false;
5502 if (profile_table != NULL) {
5503 double lin_flux = 0;
5504 for (pos->y = pos->ylow; pos->y <= pos->yhigh; pos->y++) {
5506 if (DATA(weights_data, pos) > 0)
5508 double pixelval = DATA(image_data, pos);
5509 lin_flux += pixelval;
5513 for (pos->y = pos->ylow; pos->y <= pos->yhigh; pos->y++) {
5515 if (DATA(weights_data, pos) > 0)
5517 double dy = pos->y - pos->ycenter;
5518 double pixelval = DATA(image_data, pos);
5521 (cpl_table_set_int (profile_table,
"Order" ,
5522 *prof_row, pos->order),
5523 cpl_table_set_int (profile_table,
"X" ,
5525 cpl_table_set_double(profile_table,
"DY" ,
5527 cpl_table_set_double(profile_table,
"Profile_raw",
5528 *prof_row, pixelval/lin_flux),
5529 cpl_table_set_double(profile_table,
"Profile_int",
5531 uves_extract_profile_evaluate(profile, pos))));
5537 bins_extracted += 1;
5549 SPECTRUM_DATA(cpl_image_get_data_double(spectrum), pos) = flux;
5550 SPECTRUM_DATA(cpl_mask_get_data(cpl_image_get_bpm(spectrum)), pos)
5554 if (spectrum_noise != NULL)
5556 cpl_image_set(spectrum_noise, pos->x, spectrum_row, sqrt(variance));
5561 if (optimal_extract_sky)
5571 cpl_image_set(sky_spectrum , pos->x, spectrum_row,
5572 pos->sg.length * sky_background);
5573 cpl_image_set(sky_spectrum_noise, pos->x, spectrum_row,
5574 pos->sg.length * sky_background_noise);
5581 if (order_width < pos->nx ||
5582 (0.45*pos->nx <= pos->x && pos->x <= 0.55*pos->nx)
5585 cpl_table_set_double(
5586 signal_to_noise,
"SN", sn_row, flux / sqrt(variance));
5591 uves_msg_debug(
"%d/%d hot/cold pixels rejected", hot_pixels, cold_pixels);
5594 check_nomsg( cpl_table_set_size(signal_to_noise, sn_row) );
5597 check_nomsg( *sn = cpl_table_get_column_median(signal_to_noise,
"SN"));
5605 uves_free_table(&signal_to_noise);
5606 cpl_free(noise_buffer);
5608 return bins_extracted;
5637 const double *noise_data,
5638 const double *weights_data,
5639 uves_iterate_position *pos,
5640 const cpl_table *sky_map,
5641 double buffer_flux[],
double buffer_noise[],
5642 double *sky_background_noise)
5644 double sky_background;
5645 bool found_good =
false;
5646 double flux_max = 0;
5647 double flux_min = 0;
5651 for (pos->y = pos->ylow; pos->y <= pos->yhigh; pos->y++)
5653 int row = pos->y - pos->ylow;
5655 if (!ISBAD(weights_data, pos))
5657 double fflux = DATA(image_data, pos);
5658 double noise = DATA(noise_data, pos);
5668 flux_max = uves_max_double(flux_max, fflux);
5669 flux_min = uves_min_double(flux_min, fflux);
5679 if (cpl_table_is_selected(sky_map, row))
5681 buffer_flux [ngood] = fflux;
5682 buffer_noise[ngood] = noise;
5699 *sky_background_noise = avg_noise;
5711 *sky_background_noise = avg_noise / sqrt(ngood * 2 / M_PI);
5719 sky_background = flux_min;
5720 *sky_background_noise = flux_max - flux_min;
5724 if (*sky_background_noise <= 0) *sky_background_noise = 1;
5730 *sky_background_noise = 1;
5735 return sky_background;
5753 uves_iterate_position *pos,
double noise_buffer[])
5755 double median_noise;
5759 for (pos->y = pos->ylow; pos->y <= pos->yhigh; pos->y++)
5761 if (ISGOOD(image_bpm, pos))
5763 noise_buffer[ngood] = DATA(noise_data, pos);
5777 return median_noise;
5857 double *weights_data,
5858 uves_iterate_position *pos,
5859 const uves_extract_profile *profile,
5860 bool optimal_extract_sky,
5861 double median_noise,
5863 double *sky_background,
5864 double *sky_background_noise)
5873 for (pos->y = pos->ylow; pos->y <= pos->yhigh; pos->y++)
5876 if (!ISBAD(weights_data, pos))
5878 double pixel_variance, pixelval, weight;
5879 double prof = uves_extract_profile_evaluate(profile, pos);
5881 pixelval = DATA(image_data, pos);
5882 pixel_variance = DATA(noise_data, pos);
5883 pixel_variance *= pixel_variance;
5885 if (median_noise >= 0 && pixel_variance < median_noise*median_noise)
5889 pixel_variance = median_noise*median_noise;
5892 weight = prof / pixel_variance;
5893 DATA(weights_data, pos) = weight;
5898 sumpfv += pixelval * weight;
5899 sumppv += prof * weight;
5900 if (optimal_extract_sky)
5904 sum1v += 1 / pixel_variance;
5905 sumfv += pixelval / pixel_variance;
5920 if (!optimal_extract_sky)
5923 if (sumppv > 0 && !irplib_isnan(sumppv) && !irplib_isinf(sumppv))
5925 flux = sumpfv / sumppv;
5926 *variance = 1 / sumppv;
5937 long double denominator = (
long double)sum1v*sumppv - (
long double)sumpv*sumpv;
5939 if (fabsl(denominator) > DBL_MIN)
5941 flux = ((
long double)sum1v * sumpfv - (
long double)sumpv * sumfv) / denominator;
5954 *variance = (
long double)sum1v / denominator;
5956 *sky_background = (sumppv*sumfv - sumpv*sumpfv) / denominator;
5957 *sky_background_noise = sqrt(sumppv / denominator);
5964 *sky_background = 0;
5965 *sky_background_noise = 1;
6008 const double *noise_data,
6009 cpl_binary *image_bpm,
6010 double *weights_data,
6011 uves_iterate_position *pos,
6012 const uves_extract_profile *profile,
6015 double sky_background,
6017 cpl_table *cosmic_mask,
6022 bool found_outlier =
false;
6025 double max_residual_sq = 0;
6027 bool outlier_is_hot =
false;
6028 int new_crh_tab_size=0;
6032 for (pos->y = pos->ylow; pos->y <= pos->yhigh; pos->y++)
6034 double prof = uves_extract_profile_evaluate(profile, pos);
6035 double pixel_variance, pixelval;
6038 pixel_variance = DATA(noise_data, pos);
6039 pixel_variance *= pixel_variance;
6041 pixelval = DATA(image_data, pos);
6043 best_fit = flux * prof + sky_background;
6053 if (!ISBAD(weights_data, pos) &&
6057 (pixelval - best_fit)*(pixelval - best_fit) / pixel_variance
6061 (pixelval - best_fit) *
6062 (pixelval - best_fit) / pixel_variance;
6066 outlier_is_hot = (pixelval > best_fit);
6074 if (max_residual_sq > kappa*kappa * red_chisq)
6076 uves_msg_debug(
"Order #%d: Bad pixel at (x, y) = (%d, %d) residual^2 = %.2f sigma^2",
6077 pos->order, pos->x, y_outlier, max_residual_sq);
6080 SETBAD(weights_data, image_bpm, pos);
6082 found_outlier =
true;
6088 crh_tab_size=cpl_table_get_nrow(cosmic_mask);
6089 while (*cr_row >= crh_tab_size )
6091 new_crh_tab_size=( *cr_row > 2*crh_tab_size) ? (*cr_row)+10: 2*crh_tab_size;
6092 cpl_table_set_size(cosmic_mask,new_crh_tab_size );
6093 crh_tab_size=cpl_table_get_nrow(cosmic_mask);
6096 check(( cpl_table_set_int (cosmic_mask,
"Order", *cr_row, pos->order),
6097 cpl_table_set_int (cosmic_mask,
"X" , *cr_row, pos->x),
6098 cpl_table_set_int (cosmic_mask,
"Y" , *cr_row, y_outlier),
6099 cpl_table_set_double(cosmic_mask,
"Flux" , *cr_row,
6100 DATA(image_data, pos)),
6102 "Error updating cosmic ray table");
6112 return found_outlier;
6128 const uves_iterate_position *pos)
6130 if (profile->constant) {
6133 if (profile->f != NULL)
6135 return uves_max_double(1,
6138 profile->red_chisq[pos->order-pos->minorder], pos->x));
6141 profile->red_chisq, pos->x, pos->order));
6176 cpl_table *info_tbl)
6179 int nx = cpl_image_get_size_x(image);
6180 int ny = cpl_image_get_size_y(image);
6181 double max_shift = sg.length/2;
6185 cpl_table *ordertab = NULL;
6186 cpl_table *temp = NULL;
6188 ordertab = cpl_table_new((maxorder - minorder + 1)*nx);
6190 cpl_table_new_column(ordertab,
"X" , CPL_TYPE_INT);
6191 cpl_table_new_column(ordertab,
"Order", CPL_TYPE_INT);
6192 cpl_table_new_column(ordertab,
"Y" , CPL_TYPE_DOUBLE);
6193 cpl_table_new_column(ordertab,
"Yold" , CPL_TYPE_DOUBLE);
6194 cpl_table_new_column(ordertab,
"Sigma", CPL_TYPE_DOUBLE);
6195 cpl_table_set_column_unit(ordertab,
"Y",
"pixels");
6198 for (order = minorder; order <= maxorder; order++) {
6199 for (x = 1 + stepx/2; x <= nx; x += stepx) {
6203 double y_0, sigma, norm, background;
6205 "Error evaluating polynomial");
6207 ylow = uves_round_double(ycenter - max_shift);
6208 yhigh = uves_round_double(ycenter + max_shift);
6210 if (1 <= ylow && yhigh <= ny) {
6211 uves_fit_1d_image(image, image_noise, NULL,
6215 &y_0, &sigma, &norm, &background, NULL,
6219 if (cpl_error_get_code() == CPL_ERROR_CONTINUE) {
6222 "at (x,y) = (%d, %e), ignoring bin",
6226 assure(cpl_error_get_code() == CPL_ERROR_NONE,
6227 cpl_error_get_code(),
"Gaussian fitting failed");
6229 cpl_table_set_int (ordertab,
"X" , ordertab_row, x);
6230 cpl_table_set_int (ordertab,
"Order" , ordertab_row, order);
6231 cpl_table_set_double(ordertab,
"Y" , ordertab_row, y_0);
6232 cpl_table_set_double(ordertab,
"Yold" , ordertab_row, ycenter);
6233 cpl_table_set_double(ordertab,
"Sigma" , ordertab_row, sigma);
6240 cpl_table_set_size(ordertab, ordertab_row);
6243 if (ordertab_row < 300)
6246 "Using calibration solution", ordertab_row);
6251 cpl_table_duplicate_column(ordertab,
"Yfit", ordertab,
"Yold");
6255 int max_degree = 10;
6257 double min_rms = 0.05;
6261 "X",
"Order",
"Y", NULL,
6265 max_degree, max_degree, min_rms, -1,
6267 NULL, NULL, -1, NULL);
6269 if (cpl_error_get_code() == CPL_ERROR_SINGULAR_MATRIX)
6273 "Using calibration solution");
6278 cpl_table_duplicate_column(ordertab,
"Yfit", ordertab,
"Yold");
6284 assure( cpl_error_get_code() == CPL_ERROR_NONE,
6285 cpl_error_get_code(),
6286 "Error fitting orders polynomial");
6291 cpl_table_duplicate_column(ordertab,
"Yshift", ordertab,
"Yfit");
6292 cpl_table_subtract_columns(ordertab,
"Yshift",
"Yold");
6295 double mean = cpl_table_get_column_mean(ordertab,
"Yshift");
6296 double stdev = cpl_table_get_column_mean(ordertab,
"Yshift");
6297 double rms = sqrt(mean*mean + stdev*stdev);
6299 uves_msg(
"Average shift with respect to calibration solution is %.2f pixels", rms);
6303 for (order = minorder; order <= maxorder; order++)
6314 uves_free_table(&temp);
6315 temp = uves_extract_table_rows(ordertab,
"Order",
6320 if (cpl_table_get_nrow(temp) < 1)
6323 "Setting QC FHWM parameter to zero",
6329 fwhm = cpl_table_get_column_median(temp,
"Sigma") * TWOSQRT2LN2;
6333 cpl_table_set_int (info_tbl,
"Order", order - minorder, order);
6334 cpl_table_set_double(info_tbl,
"ObjPosOnSlit" , order - minorder,
6335 pos - (-sg.length/2 + sg.offset));
6336 cpl_table_set_double(info_tbl,
"ObjFwhmAvg" , order - minorder, fwhm);
6340 uves_free_table(&ordertab);
6341 uves_free_table(&temp);
6343 return order_locations;