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);
851 cpl_table_set_column_unit(*info_tbl,
"Order",
" ");
852 cpl_table_set_column_unit(*info_tbl,
"ObjSnBlzCentre",
" ");
853 cpl_table_set_column_unit(*info_tbl,
"Ripple",
" ");
859 cpl_table_new_column(*info_tbl,
"ObjPosOnSlit", CPL_TYPE_DOUBLE);
860 cpl_table_new_column(*info_tbl,
"ObjFwhmAvg", CPL_TYPE_DOUBLE);
861 cpl_table_set_column_unit(*info_tbl,
"ObjPosOnSlit",
"pix");
862 cpl_table_set_column_unit(*info_tbl,
"ObjFwhmAvg",
"pix");
866 if (method == EXTRACT_OPTIMAL)
869 check( *weights = cpl_image_new(pos->nx, pos->ny, CPL_TYPE_DOUBLE),
870 "Could not allocate weight image");
873 check(( *cosmic_mask = cpl_table_new(1),
874 cpl_table_new_column(*cosmic_mask,
"Order", CPL_TYPE_INT),
875 cpl_table_new_column(*cosmic_mask,
"X" , CPL_TYPE_INT),
876 cpl_table_new_column(*cosmic_mask,
"Y" , CPL_TYPE_INT),
877 cpl_table_new_column(*cosmic_mask,
"Flux" , CPL_TYPE_DOUBLE),
879 "Error creating cosmic ray table");
880 cpl_table_set_column_unit(*cosmic_mask,
"Order",
"");
881 cpl_table_set_column_unit(*cosmic_mask,
"X",
"pix");
882 cpl_table_set_column_unit(*cosmic_mask,
"Y",
"pix");
883 cpl_table_set_column_unit(*cosmic_mask,
"Flux",
"ADU");
886 if(*cosmic_image!=NULL) {
899 double blemish_frac=0;
902 flux=cpl_image_get_flux(*cosmic_image);
903 sx=cpl_image_get_size_x(*cosmic_image);
904 sy=cpl_image_get_size_y(*cosmic_image);
905 nblemish=sx*sy-(int)flux;
906 blemish_frac=(sx*sy-flux)/(sx*sy);
907 uves_msg(
"nblemish=%d frac=%g",nblemish,blemish_frac);
909 if(blemish_frac< 0.02) {
912 blemish_mask=cpl_table_new(nblemish);
913 cpl_table_new_column(blemish_mask,
"X",CPL_TYPE_INT);
914 cpl_table_new_column(blemish_mask,
"Y",CPL_TYPE_INT);
915 cpl_table_fill_column_window_int(blemish_mask,
"X",
917 cpl_table_fill_column_window_int(blemish_mask,
"Y",
920 pcmask=cpl_image_get_data_double(*cosmic_image);
921 px=cpl_table_get_data_int(blemish_mask,
"X");
922 py=cpl_table_get_data_int(blemish_mask,
"Y");
926 if(pcmask[j*sx+i]==0) {
939 uves_msg_warning(
"%d pixels affected by detector blemishes %g (>0.02) of total. Not flag them in optimal extraction",nblemish,blemish_frac);
945 if (profile_table != NULL)
947 check( (*profile_table = cpl_table_new((pos->maxorder - pos->minorder + 1) *
949 (3+uves_round_double(sg.length))),
950 cpl_table_new_column(*profile_table,
"Order" , CPL_TYPE_INT),
951 cpl_table_new_column(*profile_table,
"X" , CPL_TYPE_INT),
952 cpl_table_new_column(*profile_table,
"DY" , CPL_TYPE_DOUBLE),
953 cpl_table_new_column(*profile_table,
"Profile_raw", CPL_TYPE_DOUBLE),
954 cpl_table_new_column(*profile_table,
"Profile_int", CPL_TYPE_DOUBLE)),
955 "Error creating profile table");
957 cpl_table_set_column_unit(*profile_table,
"Order",
" ");
958 cpl_table_set_column_unit(*profile_table,
"X",
"pix");
959 cpl_table_set_column_unit(*profile_table,
"DY",
"pix");
960 cpl_table_set_column_unit(*profile_table,
"Profile_raw",
"ADU");
961 cpl_table_set_column_unit(*profile_table,
"Profile_int",
"ADU");
964 if (strcmp(p_method,
"constant") != 0) {
965 check( *sky_spectrum = cpl_image_new(
966 pos->nx, pos->maxorder - pos->minorder + 1, CPL_TYPE_DOUBLE),
967 "Could not allocate sky spectrum");
968 check( *sky_spectrum_noise = cpl_image_new(
969 pos->nx, pos->maxorder - pos->minorder + 1, CPL_TYPE_DOUBLE),
970 "Could not allocate sky spectrum noise");
974 if (method == EXTRACT_OPTIMAL &&
975 strcmp(p_method,
"constant") != 0 && prof_func == NULL)
985 uves_msg(
"Refining order definition using the object frame");
988 pos->minorder, pos->maxorder,
991 "Could not refine order definition");
998 pos->order_locations = order_locations;
1013 if (method == EXTRACT_OPTIMAL)
1015 if (strcmp(p_method,
"constant") == 0) {
1017 uves_msg(
"Assuming constant spatial profile");
1019 profile = uves_extract_profile_new_constant(sg.length);
1022 sky_subtracted = cpl_image_duplicate(image);
1023 optimal_extract_sky =
false;
1028 image, image_noise, *weights,
1031 *sky_spectrum_noise),
1032 "Could not extract sky");
1033 if (prof_func != NULL)
1035 uves_msg(
"Measuring spatial profile "
1036 "(method = %s, chunk = %d bins)",
1041 uves_msg(
"Measuring spatial profile "
1042 "(method = %s, oversampling = %d)",
1043 p_method, sampling_factor);
1046 uves_extract_profile_delete(&profile);
1051 chunk, sampling_factor,
1052 prof_func, prof_func_der, prof_pars,
1056 "Could not measure profile");
1068 passure( method == EXTRACT_2D || n_traces == 1,
"%d", n_traces);
1070 n_iterations = (method == EXTRACT_OPTIMAL &&
1072 strcmp(p_method,
"constant") != 0) ? 2 : 1;
1082 iteration <= n_iterations;
1085 uves_msg(
"Extracting object %s(method = %s)",
1086 (method == EXTRACT_OPTIMAL && optimal_extract_sky)
1088 (method == EXTRACT_OPTIMAL) ?
"optimal" :
1089 (method == EXTRACT_AVERAGE) ?
"average" :
1090 (method == EXTRACT_LINEAR ) ?
"linear" :
1091 (method == EXTRACT_2D ) ?
"2d" :
1092 (method == EXTRACT_WEIGHTED) ?
"weighted" :
"???");
1096 cr_row = cr_row_max;
1099 for (pos->order = pos->minorder; pos->order <= pos->maxorder; pos->order++) {
1100 for (trace = 1; trace <= n_traces; trace++) {
1106 spectrum_row = (pos->order - pos->minorder)*n_traces + trace;
1109 if (method == EXTRACT_OPTIMAL)
1117 optimal_extract_sky ?
1118 image : sky_subtracted,
1122 optimal_extract_sky,
1127 (profile_table != NULL) ?
1128 *profile_table : NULL,
1131 (spectrum_noise != NULL) ?
1132 *spectrum_noise : NULL,
1134 optimal_extract_sky ? *sky_spectrum : NULL,
1135 optimal_extract_sky ? *sky_spectrum_noise : NULL,
1137 "Error extracting order #%d", pos->order);
1138 cr_row_max=(cr_row>cr_row_max) ? cr_row:cr_row_max;
1155 double offset_2d = trace - (n_traces+1)/2.0;
1161 pos->order, pos->minorder,
1163 (method == EXTRACT_2D) ? offset_2d : sg.offset,
1164 (method == EXTRACT_2D) ? slit_2d : sg.length,
1165 (method == EXTRACT_2D) ? EXTRACT_LINEAR : method,
1166 (weights != NULL) ? *weights : NULL,
1169 (spectrum_noise != NULL) ? *spectrum_noise : NULL,
1173 "Could not extract order #%d ; trace #%d",
1178 if (info_tbl != NULL &&
1179 (method == EXTRACT_LINEAR || method == EXTRACT_AVERAGE ||
1180 method == EXTRACT_OPTIMAL)
1190 if (
false && ripple_index > 3) {
1196 "It might help to use average or linear extraction "
1197 "or optimal/virtual extraction with larger "
1198 "oversampling factor", ripple_index);
1201 cpl_table_set_int (*info_tbl,
"Order",
1202 pos->order - pos->minorder, pos->order);
1203 cpl_table_set_double(*info_tbl,
"ObjSnBlzCentre" ,
1204 pos->order - pos->minorder, sn);
1205 cpl_table_set_double(*info_tbl,
"Ripple",
1206 pos->order - pos->minorder,
1207 (ripple_index > -0.5) ? ripple_index : -1);
1211 "Order #%d; trace #%d: %d of %d bins extracted",
1212 pos->order, trace, bins_extracted, pos->nx);
1219 if (method == EXTRACT_OPTIMAL)
1221 if (spectrum_noise != NULL)
1223 uves_free_image(&temp);
1224 temp = cpl_image_divide_create(spectrum, *spectrum_noise);
1225 uves_msg(
"Average S/N = %.3f", cpl_image_get_median(temp));
1228 if (iteration == 1 && n_iterations >= 2)
1235 cpl_image_get_bpm(sky_subtracted)),
1237 spectrum, *sky_spectrum, profile,
1239 "Error refining input image variances");
1247 if (method == EXTRACT_OPTIMAL)
1251 check( cpl_table_set_size(*cosmic_mask, cr_row_max),
1252 "Error setting cosmic ray table size to %d", cr_row_max);
1253 if(*cosmic_image==NULL) {
1254 *cosmic_image = cpl_image_new(pos->nx, pos->ny, CPL_TYPE_DOUBLE);
1258 for (i = 0; i < cpl_table_get_nrow(*cosmic_mask); i++)
1260 cpl_image_set(*cosmic_image,
1261 cpl_table_get_int(*cosmic_mask,
"X", i, NULL),
1262 cpl_table_get_int(*cosmic_mask,
"Y", i, NULL),
1263 cpl_table_get_double(*cosmic_mask,
"Flux", i, NULL));
1266 if (profile_table != NULL)
1268 check( cpl_table_set_size(*profile_table, prof_row),
1269 "Error setting profile table size to %d", prof_row);
1276 check( cpl_image_threshold(*weights,
1279 "Error thresholding weight image");
1288 double *weights_data = cpl_image_get_data_double(*weights);
1292 pos->minorder, pos->maxorder,
1297 double sum_weights = 0.0;
1299 for (pos->y = pos->ylow; pos->y <= pos->yhigh; pos->y++)
1301 double weight = DATA(weights_data, pos);
1302 sum_weights += weight;
1305 for (pos->y = pos->ylow; pos->y <= pos->yhigh; pos->y++)
1307 if (sum_weights > 0)
1309 DATA(weights_data, pos) /= sum_weights;
1317 uves_msg_debug(
"Rejecting %" CPL_SIZE_FORMAT
" bins", cpl_mask_count(spectrum_bad));
1319 if (spectrum_noise != NULL)
1321 check( cpl_image_reject_from_mask(*spectrum_noise, spectrum_bad),
1322 "Error setting bad pixels");
1330 "PIXEL", (method == EXTRACT_2D) ?
"PIXEL" :
"ORDER",
1331 "PIXEL", (method == EXTRACT_2D) ?
"PIXEL" :
"ORDER",
1336 "Error initializing spectrum header");
1339 if (debug_mode && header != NULL) {
1340 if (profile == NULL) {
1343 profile = uves_extract_profile_new_constant(sg.length);
1349 sky_spectrum != NULL ? *sky_spectrum : NULL,
1350 cosmic_image != NULL ? *cosmic_image : NULL,
1358 check( uves_save_image_local(
"Reconstructed image",
"simulate",
1359 reconstruct, chip, -1, -1, *header,
true),
1360 "Error saving image");
1364 if (spectrum_noise != NULL)
1377 assure( cpl_image_get_min(*spectrum_noise) > 0, CPL_ERROR_ILLEGAL_OUTPUT,
1378 "Non-positive noise: %e at (%" CPL_SIZE_FORMAT
", %" CPL_SIZE_FORMAT
")",
1379 cpl_image_get_min(*spectrum_noise),
1380 (cpl_image_get_minpos(*spectrum_noise, &x, &y), x),
1381 (cpl_image_get_minpos(*spectrum_noise, &x, &y), y));
1392 uves_free_image(&reconstruct);
1393 uves_free_image(&sky_subtracted);
1394 uves_extract_profile_delete(&profile);
1397 uves_free_image(&temp);
1398 uves_free_table(&blemish_mask);
1400 if (cpl_error_get_code() != CPL_ERROR_NONE)
1402 uves_free_image(&spectrum);
1403 uves_free_image(spectrum_noise);
1404 uves_free_table(profile_table);
1428 int nx = cpl_image_get_size_x(spectrum);
1429 cpl_image *spectrum_order = NULL;
1430 cpl_vector *tempx = NULL;
1431 cpl_vector *tempy = NULL;
1432 double *auto_corr = NULL;
1434 int spectrum_row = (pos->order - pos->minorder)*n_traces + trace;
1437 uves_free_image(&spectrum_order);
1439 check( spectrum_order = cpl_image_extract(spectrum,
1442 "Error extracting order %d from spectrum", pos->order);
1444 n_rejected = cpl_image_count_rejected(spectrum_order);
1449 if (n_rejected == 0)
1452 double order_slope =
1455 int expected_period = uves_round_double(1.0/order_slope);
1456 int max_period = 2*expected_period;
1459 uves_msg_debug(
"Estimated ripple period = %d pixels", expected_period);
1461 auto_corr = cpl_calloc(
sizeof(
double), 1+max_period);
1463 for (shift = 0; shift <= max_period; shift += 1) {
1467 auto_corr[shift] = 0;
1469 for (x = 1; x <= nx - max_period; x++) {
1470 int rejected1, rejected2;
1473 val1 = cpl_image_get(spectrum_order, x, 1, &rejected1);
1474 val2 = cpl_image_get(spectrum_order, x+shift, 1, &rejected2);
1476 if (!rejected1 && !rejected2)
1478 auto_corr[shift] += val1*val2;
1485 auto_corr[shift] /= N;
1489 auto_corr[shift] = 0;
1492 if (shift > 0 && auto_corr[0] > 0)
1494 auto_corr[shift] /= auto_corr[0];
1498 shift, N, (shift == 0) ? 1 : auto_corr[shift]);
1505 double auto_amplitude;
1506 int imax = expected_period;
1507 int imin1 = expected_period/2;
1508 int imin2 = (expected_period*3)/2;
1514 auto_amplitude = auto_corr[imax] -
1515 (auto_corr[imin1] + auto_corr[imin2])/2.0;
1529 if (auto_amplitude > 0 && sn > 0)
1531 double rel_ripple = sqrt(auto_amplitude);
1533 "relative error bars = %f",
1534 pos->order, rel_ripple, 2.0*1/sn);
1536 ratio = rel_ripple * sn/2.0;
1542 uves_free_double(&auto_corr);
1543 uves_free_vector(&tempx);
1544 uves_unwrap_vector(&tempy);
1545 uves_free_image(&spectrum_order);
1566 uves_iterate_position *pos)
1570 cpl_table *sn_temp = NULL;
1571 cpl_table *sky_temp = NULL;
1572 int sn_row, sky_row;
1573 int sky_size = 2 + 2*uves_round_double(pos->sg.length);
1577 passure( image_noise != NULL,
" ");
1579 assure( pos->nx >= 2*(range+1), CPL_ERROR_ILLEGAL_INPUT,
1580 "Input image is too small. Width = %d", pos->nx);
1582 sn_temp = cpl_table_new((pos->maxorder - pos->minorder + 1) * (2*range + 1));
1583 cpl_table_new_column(sn_temp,
"SN", CPL_TYPE_DOUBLE);
1586 sky_temp = cpl_table_new(sky_size);
1587 cpl_table_new_column(sky_temp,
"Sky", CPL_TYPE_DOUBLE);
1590 pos->nx/2 - range, pos->nx/2 + range,
1591 pos->minorder, pos->maxorder,
1602 for (pos->y = pos->ylow; pos->y <= pos->yhigh; pos->y++)
1604 int pis_rejected1, pis_rejected2;
1605 double pixel = cpl_image_get(image,
1606 pos->x, pos->y, &pis_rejected1);
1607 double pixel_noise = cpl_image_get(image_noise,
1608 pos->x, pos->y, &pis_rejected2);
1610 if (!pis_rejected1 && !pis_rejected2)
1613 error += pixel_noise*pixel_noise;
1616 cpl_table_set_double(sky_temp,
"Sky",
1626 while(sky_row < sky_size)
1629 cpl_table_set_invalid(sky_temp,
"Sky",
1635 sky = cpl_table_get_column_median(sky_temp,
"Sky");
1637 flux = flux - N*sky;
1638 error = sqrt(error);
1644 pos->order, flux/error);
1646 cpl_table_set_double(sn_temp,
"SN",
1647 sn_row, flux/error);
1653 assure(sn_row > 0, CPL_ERROR_DATA_NOT_FOUND,
1654 "Extraction of central bins failed!");
1656 cpl_table_set_size(sn_temp, sn_row);
1658 sn = cpl_table_get_column_median(sn_temp,
"SN");
1661 uves_free_table(&sn_temp);
1662 uves_free_table(&sky_temp);
1702 const cpl_image *image_noise,
1709 extract_method method,
1710 const cpl_image *weights,
1711 bool extract_partial,
1712 cpl_image *spectrum,
1713 cpl_image *spectrum_noise,
1714 cpl_binary*spectrum_badmap,
1715 cpl_table **info_tbl,
1718 int bins_extracted = 0;
1719 double *spectrum_data;
1721 double flux_y, flux_yy, flux_tot;
1724 cpl_table *signal_to_noise = NULL;
1726 passure( method == EXTRACT_AVERAGE ||
1727 method == EXTRACT_LINEAR ||
1728 method == EXTRACT_WEIGHTED,
"%d", method);
1731 passure( (method == EXTRACT_WEIGHTED) == (weights != NULL),
"%d", method);
1733 nx = cpl_image_get_size_x(image);
1734 ny = cpl_image_get_size_y(image);
1736 check( (signal_to_noise = cpl_table_new(nx),
1737 cpl_table_new_column(signal_to_noise,
"SN", CPL_TYPE_DOUBLE)),
1738 "Error allocating S/N table");
1740 spectrum_data = cpl_image_get_data_double(spectrum);
1746 for (x = 1 ; x <= nx; x++) {
1747 double slope, ycenter;
1750 double flux_variance = 0;
1759 "Error evaluating polynomial");
1761 assure( 0 < slope && slope < 1, CPL_ERROR_ILLEGAL_INPUT,
1762 "At (x, order)=(%d, %d) slope is %f. Must be positive", x, order, slope);
1765 ylo = uves_round_double(ycenter - slit_length/2 - 0.5*slope);
1766 yhi = uves_round_double(ycenter + slit_length/2 + 0.5*slope);
1769 if (ylo < 1 || ny < yhi)
1771 if (extract_partial)
1773 ylo = uves_max_int(ylo, 1);
1774 yhi = uves_min_int(yhi, ny);
1784 for (y = ylo; y <= yhi; y++) {
1788 double pixelvariance;
1792 pixelval = cpl_image_get(image, x, y, &pis_rejected);
1800 if (spectrum_noise != NULL && !pis_rejected)
1802 pixelvariance = cpl_image_get(image_noise, x, y, &pis_rejected);
1803 pixelvariance *= pixelvariance;
1810 if (!pis_rejected) {
1812 if (method == EXTRACT_WEIGHTED)
1817 weight = cpl_image_get(weights, x, y, &pis_rejected);
1819 assure( weight >= 0, CPL_ERROR_ILLEGAL_INPUT,
1820 "Illegal weight: %e at (x, y) = (%d, %d)",
1831 else if (method == EXTRACT_ARCLAMP) {
1832 weight = 1.0 / pixelvariance;
1836 double area_outside_order_top;
1837 double area_outside_order_bottom;
1838 double left = ycenter + slit_length/2 - 0.5*slope;
1839 double right = ycenter + slit_length/2 + 0.5*slope;
1841 check( area_outside_order_top =
1843 "Error calculating area");
1845 left = ycenter - slit_length/2 - 0.5*slope;
1846 right = ycenter - slit_length/2 + 0.5*slope;
1848 check( area_outside_order_bottom =
1850 "Error calculationg area");
1852 weight = 1 - (area_outside_order_top + area_outside_order_bottom);
1854 if (1 < y && y < ny && weight < 1)
1877 int pis_rejected_prev, pis_rejected_next;
1881 double flux_minus = (pixelval + cpl_image_get(
1882 image, x, y - 1, &pis_rejected_prev)) / 2.0;
1883 double flux_plus = (pixelval + cpl_image_get(
1884 image, x, y + 1, &pis_rejected_next)) / 2.0;
1885 if (!pis_rejected_prev && !pis_rejected_next)
1895 double flux_center =
1896 2*pixelval - (flux_minus + flux_plus) / 2.0;
1899 double slope_minus =
1900 (flux_center - flux_minus )/ 0.5;
1902 (flux_plus - flux_center) / 0.5;
1906 uves_min_double(0, -0.5 + area_outside_order_bottom);
1908 uves_min_double(0, 0.5 - area_outside_order_top );
1909 double dy1 = hi1-lo1;
1913 uves_max_double(0, -0.5 + area_outside_order_bottom);
1915 uves_max_double(0, 0.5 - area_outside_order_top );
1916 double dy2 = hi2-lo2;
1922 (flux_center + slope_minus * (lo1+hi1)/2.0) * dy1
1924 (flux_center + slope_plus * (lo2+hi2)/2.0) * dy2
1960 flux += weight*pixelval;
1961 flux_variance += weight*weight * pixelvariance;
1966 if (method != EXTRACT_ARCLAMP)
1968 flux_y += weight * pixelval * (y-ylo);
1969 flux_yy += weight * pixelval * (y-ylo)*(y-ylo);
1970 flux_tot+= weight * pixelval;
1983 bins_extracted += 1;
1985 if (method == EXTRACT_ARCLAMP && flux_variance > 0) {
1987 flux_variance = 1.0 / sum;
1989 else if (method == EXTRACT_AVERAGE || method == EXTRACT_WEIGHTED)
1993 flux_variance *= 1.0 / (sum*sum);
1999 flux *= slit_length / sum;
2000 flux_variance *= (slit_length*slit_length) / (sum*sum);
2009 spectrum_data [(x-1) + (spectrum_row-1) * nx] = flux;
2010 spectrum_badmap[(x-1) + (spectrum_row-1) * nx] = CPL_BINARY_0;
2012 if (spectrum_noise != NULL)
2014 check( cpl_image_set(
2015 spectrum_noise, x, spectrum_row, sqrt(flux_variance)),
2016 "Could not write noise at (%d, %d)", x, spectrum_row);
2020 signal_to_noise,
"SN", sn_row, flux / sqrt(flux_variance)) );
2039 spectrum_badmap[(x-1) + (spectrum_row-1) * nx] = CPL_BINARY_1;
2044 if (info_tbl != NULL && *info_tbl != NULL && method != EXTRACT_ARCLAMP)
2049 objpos = flux_y / flux_tot;
2054 if (flux_yy/flux_tot - objpos*objpos >= 0)
2056 fwhm = sqrt(flux_yy/flux_tot - objpos*objpos) * TWOSQRT2LN2;
2062 cpl_table_set_double(*info_tbl,
"ObjPosOnSlit" , order - minorder, objpos);
2063 cpl_table_set_double(*info_tbl,
"ObjFwhmAvg" , order - minorder, fwhm);
2067 check_nomsg( cpl_table_set_size(signal_to_noise, sn_row) );
2071 check_nomsg( *sn = cpl_table_get_column_median(signal_to_noise,
"SN"));
2079 uves_free_table(&signal_to_noise);
2080 return bins_extracted;
2102 double pixeltop = y + .5;
2103 double pixelbot = y - .5;
2104 double slope = right - left;
2106 assure( 0 <= slope && slope <= 1, CPL_ERROR_ILLEGAL_INPUT,
"Slope is %f", slope);
2148 if (pixelbot > right)
2152 else if (pixelbot > left)
2155 (right - pixelbot) *
2156 (right - pixelbot) / (2*slope);
2158 else if (pixeltop > right)
2160 area = pixeltop - (left + right)/2;
2162 else if (pixeltop > left)
2166 (pixeltop - left) / (2*slope);
2199 const cpl_binary *image_bpm,
2201 uves_iterate_position *pos,
2202 const cpl_image *spectrum,
2203 const cpl_image *sky_spectrum,
2204 const uves_extract_profile *profile,
2205 enum uves_chip chip)
2207 cpl_image *revised = NULL;
2208 cpl_image *simulated = NULL;
2209 const cpl_binary *spectrum_bpm =
2210 cpl_mask_get_data_const(cpl_image_get_bpm_const(spectrum));
2212 const double *spectrum_data;
2213 const double *sky_data;
2215 simulated = cpl_image_new(pos->nx, pos->ny,
2219 simul_data = cpl_image_get_data_double(simulated);
2220 spectrum_data = cpl_image_get_data_double_const(spectrum);
2221 sky_data = cpl_image_get_data_double_const(sky_spectrum);
2225 pos->minorder, pos->maxorder,
2230 if (SPECTRUM_DATA(spectrum_bpm, pos) == CPL_BINARY_0)
2233 uves_extract_profile_set(profile, pos, NULL);
2235 for (pos->y = pos->ylow; pos->y <= pos->yhigh; pos->y++)
2236 if (ISGOOD(image_bpm, pos))
2239 DATA(simul_data, pos) =
2240 SPECTRUM_DATA(sky_data, pos)/pos->sg.length +
2241 SPECTRUM_DATA(spectrum_data, pos) *
2242 uves_extract_profile_evaluate(profile, pos);
2258 "Error computing noise image");
2263 double *revised_data = cpl_image_get_data_double(revised);
2264 double *input_data = cpl_image_get_data_double(image_noise);
2268 pos->minorder, pos->maxorder,
2273 DATA(input_data, pos) = DATA(revised_data, pos);
2278 uves_free_image(&simulated);
2279 uves_free_image(&revised);
2304 const cpl_image *weights,
2305 uves_iterate_position *pos,
2306 cpl_image *sky_spectrum,
2307 cpl_image *sky_spectrum_noise)
2309 cpl_image *sky_subtracted = NULL;
2310 cpl_table *sky_map = NULL;
2316 "Error determining sky window");
2318 uves_msg_low(
"%" CPL_SIZE_FORMAT
"/%" CPL_SIZE_FORMAT
" sky pixels",
2319 cpl_table_count_selected(sky_map),
2320 cpl_table_get_nrow(sky_map));
2323 uves_msg(
"Subtracting sky (method = median of sky channels)");
2329 sky_spectrum_noise),
2330 "Could not subtract sky");
2333 uves_free_table(&sky_map);
2335 return sky_subtracted;
2353 uves_iterate_position *pos)
2356 cpl_table *sky_map = NULL;
2358 cpl_table **resampled = NULL;
2368 "Error measuring spatial profile");
2370 sky_map = cpl_table_new(nbins);
2371 cpl_table_new_column(sky_map,
"DY" , CPL_TYPE_INT);
2372 cpl_table_new_column(sky_map,
"Prof", CPL_TYPE_DOUBLE);
2374 for (i = 0; i < nbins; i++)
2376 cpl_table_set_int(sky_map,
"DY" , i, i - nbins/2);
2377 if (cpl_table_has_valid(resampled[i],
"Prof"))
2386 int row = (cpl_table_get_nrow(resampled[i]) * 9) / 10;
2388 uves_sort_table_1(resampled[i],
"Prof",
false);
2390 cpl_table_set_double(sky_map,
"Prof", i,
2391 cpl_table_get_double(resampled[i],
"Prof", row, NULL));
2395 cpl_table_set_invalid(sky_map,
"Prof", i);
2401 assure( cpl_table_has_valid(sky_map,
"Prof"), CPL_ERROR_DATA_NOT_FOUND,
2402 "Too many (%" CPL_SIZE_FORMAT
"/%d ) bad pixels. Could not measure sky profile",
2403 cpl_image_count_rejected(image),
2411 double prof_min = cpl_table_get_column_min(sky_map,
"Prof");
2412 double prof_max = cpl_table_get_column_max(sky_map,
"Prof");
2413 double prof_med = cpl_table_get_column_median(sky_map,
"Prof");
2414 double sky_threshold = prof_min + 2*(prof_med - prof_min);
2416 sky_threshold = uves_min_double(sky_threshold, (prof_min + prof_max)/2);
2418 check( uves_plot_table(sky_map,
"DY",
"Prof",
2419 "Globally averaged spatial profile (sky threshold = %.5f)",
2423 uves_select_table_rows(sky_map,
"Prof", CPL_NOT_GREATER_THAN, sky_threshold);
2427 if (resampled != NULL)
2429 for (i = 0; i < nbins; i++)
2431 uves_free_table(&(resampled[i]));
2433 cpl_free(resampled);
2460 uves_iterate_position *pos,
2462 int sampling_factor,
2466 cpl_table **resampled = NULL;
2470 int *resampled_row = NULL;
2472 const double *image_data;
2473 const double *weights_data;
2475 assure( stepx >= 1, CPL_ERROR_ILLEGAL_INPUT,
"Step size = %d", stepx);
2476 assure( sampling_factor >= 1, CPL_ERROR_ILLEGAL_INPUT,
2477 "Sampling factor = %d", sampling_factor);
2479 image_data = cpl_image_get_data_double_const(image);
2480 weights_data = cpl_image_get_data_double_const(weights);
2482 *nbins = uves_extract_profile_get_nbins(pos->sg.length, sampling_factor);
2484 resampled = cpl_calloc(*nbins,
sizeof(cpl_table *));
2485 resampled_row = cpl_calloc(*nbins,
sizeof(
int));
2492 for (i = 0; i < *nbins; i++)
2494 resampled[i] = cpl_table_new((pos->nx/stepx+1)*
2495 (pos->maxorder-pos->minorder+1));
2497 resampled_row[i] = 0;
2500 cpl_table_new_column(resampled[i],
"X" , CPL_TYPE_INT);
2501 cpl_table_new_column(resampled[i],
"Order", CPL_TYPE_INT);
2502 cpl_table_new_column(resampled[i],
"Prof" , CPL_TYPE_DOUBLE);
2509 pos->minorder, pos->maxorder,
2513 if ((pos->x - 1) % stepx == 0)
2519 for (pos->y = pos->ylow; pos->y <= pos->yhigh; pos->y++) {
2520 if (!ISBAD(weights_data, pos)) {
2521 flux += DATA(image_data, pos);
2526 for (pos->y = pos->ylow; pos->y <= pos->yhigh; pos->y++) {
2527 if (!ISBAD(weights_data, pos)) {
2528 double f = DATA(image_data, pos);
2531 int bin = uves_round_double(
2532 uves_extract_profile_get_bin(pos, sampling_factor));
2534 passure( bin < *nbins,
"%d %d", bin, *nbins);
2540 cpl_table_set_int (resampled[bin],
"X" ,
2541 resampled_row[bin], pos->x);
2542 cpl_table_set_int (resampled[bin],
"Order",
2543 resampled_row[bin], pos->order);
2544 cpl_table_set_double(resampled[bin],
"Prof" ,
2545 resampled_row[bin], f/flux);
2547 resampled_row[bin]++;
2556 for (i = 0; i < *nbins; i++)
2558 cpl_table_set_size(resampled[i], resampled_row[i]);
2563 passure( cpl_table_get_ncol(resampled[0]) == 3,
"%" CPL_SIZE_FORMAT
"",
2564 cpl_table_get_ncol(resampled[0]));
2565 passure( cpl_table_has_column(resampled[0],
"X"),
" ");
2566 passure( cpl_table_has_column(resampled[0],
"Order"),
" ");
2567 passure( cpl_table_has_column(resampled[0],
"Prof"),
" ");
2570 cpl_free(resampled_row);
2602 const cpl_image *weights,
2603 uves_iterate_position *pos,
2604 const cpl_table *sky_map,
2605 cpl_image *sky_spectrum,
2606 cpl_image *sky_spectrum_noise)
2608 cpl_image *sky_subtracted = cpl_image_duplicate(image);
2610 double *sky_subtracted_data;
2611 const double *image_data;
2612 const double *noise_data;
2613 const double *weights_data;
2614 double *buffer_flux = NULL;
2615 double *buffer_noise = NULL;
2618 double *sky_spectrum_data = NULL;
2619 double *sky_noise_data = NULL;
2620 cpl_binary *sky_spectrum_bpm = NULL;
2621 cpl_binary *sky_noise_bpm = NULL;
2622 cpl_mask *temp = NULL;
2626 image_data = cpl_image_get_data_double_const(image);
2627 noise_data = cpl_image_get_data_double_const(image_noise);
2628 weights_data = cpl_image_get_data_double_const(weights);
2629 sky_subtracted_data = cpl_image_get_data(sky_subtracted);
2631 buffer_flux = cpl_malloc(uves_round_double(pos->sg.length + 5)*
sizeof(
double));
2632 buffer_noise = cpl_malloc(uves_round_double(pos->sg.length + 5)*
sizeof(
double));
2635 if (sky_spectrum != NULL)
2637 sky_spectrum_data = cpl_image_get_data_double(sky_spectrum);
2638 sky_noise_data = cpl_image_get_data_double(sky_spectrum_noise);
2643 temp = cpl_mask_new(cpl_image_get_size_x(sky_spectrum),
2644 cpl_image_get_size_y(sky_spectrum));
2647 cpl_image_reject_from_mask(sky_spectrum , temp);
2648 cpl_image_reject_from_mask(sky_spectrum_noise, temp);
2650 sky_spectrum_bpm = cpl_mask_get_data(cpl_image_get_bpm(sky_spectrum));
2651 sky_noise_bpm = cpl_mask_get_data(cpl_image_get_bpm(sky_spectrum_noise));
2654 UVES_TIME_START(
"Subtract sky");
2658 pos->minorder, pos->maxorder,
2663 double sky_background, sky_background_noise;
2666 sky_background =
opt_get_sky(image_data, noise_data,
2670 buffer_flux, buffer_noise,
2671 &sky_background_noise);
2674 if (sky_spectrum != NULL)
2690 SPECTRUM_DATA(sky_spectrum_data, pos) =
2691 pos->sg.length * sky_background;
2692 SPECTRUM_DATA(sky_noise_data, pos) =
2693 pos->sg.length * sky_background_noise;
2695 SPECTRUM_DATA(sky_spectrum_bpm, pos) = CPL_BINARY_0;
2696 SPECTRUM_DATA(sky_noise_bpm , pos) = CPL_BINARY_0;
2700 for (pos->y = pos->ylow; pos->y <= pos->yhigh; pos->y++)
2702 DATA(sky_subtracted_data, pos) =
2703 DATA(image_data, pos) - sky_background;
2714 uves_free_mask(&temp);
2715 cpl_free(buffer_flux);
2716 cpl_free(buffer_noise);
2718 return sky_subtracted;
2759 static uves_extract_profile *
2761 const cpl_image *weights,
2762 uves_iterate_position *pos,
2763 int chunk,
int sampling_factor,
2764 int (*f) (
const double x[],
const double a[],
double *result),
2765 int (*dfda)(
const double x[],
const double a[],
double result[]),
2767 const cpl_image *sky_spectrum,
2768 cpl_table *info_tbl,
2769 cpl_table **profile_global)
2771 uves_extract_profile *profile = NULL;
2773 int *good_bins = NULL;
2774 cpl_table **profile_data = NULL;
2777 cpl_mask *image_bad = NULL;
2778 cpl_binary*image_bpm = NULL;
2780 cpl_vector *plot0x = NULL;
2781 cpl_vector *plot0y = NULL;
2782 cpl_vector *plot1x = NULL;
2783 cpl_vector *plot1y = NULL;
2784 cpl_bivector *plot[] = {NULL, NULL};
2785 char *plot_titles[] = {NULL, NULL};
2787 int sample_bins = 100;
2790 int spatial_bins = uves_extract_profile_get_nbins(pos->sg.length, sampling_factor);
2797 image_bad = cpl_mask_new(pos->nx, pos->ny);
2799 image_bpm = cpl_mask_get_data(image_bad);
2801 const double *weights_data = cpl_image_get_data_double_const(weights);
2803 for (pos->y = 1; pos->y <= pos->ny; pos->y++)
2805 for (pos->x = 1; pos->x <= pos->nx; pos->x++)
2807 if (ISBAD(weights_data, pos))
2809 DATA(image_bpm, pos) = CPL_BINARY_1;
2818 stepx = cpl_malloc((pos->maxorder-pos->minorder+1) *
sizeof(
int));
2819 good_bins = cpl_malloc((pos->maxorder-pos->minorder+1) *
sizeof(
int));
2820 profile_data = cpl_calloc( pos->maxorder-pos->minorder+1,
sizeof(cpl_table *));
2826 for (pos->order = pos->minorder; pos->order <= pos->maxorder; pos->order++)
2836 "Error estimating width of order #%d", pos->order);
2844 stepx [pos->order-pos->minorder] = order_width / sample_bins + 1;
2845 good_bins[pos->order-pos->minorder] = (2*sample_bins)/3;
2854 stepx = cpl_malloc(
sizeof(
int) * spatial_bins);
2855 good_bins = cpl_malloc(
sizeof(
int) * spatial_bins);
2859 profile_data = NULL;
2864 for (i = 0; i < spatial_bins; i++)
2878 stepx [i] = uves_round_double(
2879 (pos->nx*pos->sg.length)/(sample_bins*spatial_bins)
2882 good_bins[i] = sample_bins - 1;
2912 for (i = 0; i < ((f == NULL) ? spatial_bins : pos->maxorder-pos->minorder+1); i++)
2914 if (f == NULL || profile_data[i] == NULL)
2918 passure(good_bins[i] < sample_bins,
2919 "%d %d", good_bins[i], sample_bins);
2921 stepx[i] = (int) (stepx[i]*(good_bins[i]*0.8/sample_bins));
2946 for (pos->order = pos->minorder; pos->order <= pos->minorder; pos->order++) {
2948 for (pos->order = pos->minorder; pos->order <= pos->maxorder; pos->order++) {
2951 if (profile_data[pos->order-pos->minorder] == NULL) {
2954 check( profile_data[pos->order-pos->minorder] =
2960 "Error measuring profile of order #%d using chunk size = %d",
2963 bins = cpl_table_get_nrow(profile_data[pos->order-pos->minorder]);
2965 uves_msg(
"Order %-2d: Chi^2/N = %.2f; FWHM = %.2f pix; Offset = %.2f pix",
2967 (bins > 0) ? cpl_table_get_column_median(
2968 profile_data[pos->order-pos->minorder],
2969 "Reduced_chisq") : 0,
2971 (bins > 0) ? cpl_table_get_column_median(
2972 profile_data[pos->order-pos->minorder],
2973 "Sigma") * TWOSQRT2LN2 : 0,
2974 (bins > 0) ? cpl_table_get_column_median(
2975 profile_data[pos->order-pos->minorder],
3002 for (i = 0; i < spatial_bins; i++)
3006 step /= spatial_bins;
3008 *profile_global = cpl_table_new(0);
3010 cpl_table_new_column(*profile_global,
"Dummy" , CPL_TYPE_DOUBLE);
3017 "Error measuring profile (virtual method)");
3019 passure( nbins == spatial_bins,
"%d %d", nbins, spatial_bins);
3021 for (i = 0; i < spatial_bins; i++)
3023 good_bins[i] = cpl_table_get_nrow(profile_data[i]);
3028 (good_bins[i] > 0) ?
3029 cpl_table_get_column_median(profile_data[i],
"Prof") : 0,
3054 "resampled profile (%d spatial bins)",
3057 uves_extract_profile_delete(&profile);
3058 profile = uves_extract_profile_new(NULL,
3064 for (i = 0; i < spatial_bins; i++)
3071 bool enough_points = (
3072 cpl_table_get_nrow(profile_data[i]) >= (max_degree + 1)*(max_degree + 1));
3081 double min_reject = -0.01;
3091 "X",
"Order",
"Prof", NULL,
3092 "Proffit", NULL, NULL,
3095 max_degree, max_degree, -1, min_reject,
3097 NULL, NULL, 0, NULL);
3103 profile->dy_poly[i] =
3105 "X",
"Order",
"Prof", NULL,
3107 "Proffit", NULL, NULL,
3108 NULL, NULL, NULL, kappa, -1);
3111 if (cpl_error_get_code() == CPL_ERROR_SINGULAR_MATRIX)
3117 enough_points =
false;
3120 assure( cpl_error_get_code() == CPL_ERROR_NONE,
3121 cpl_error_get_code(),
3122 "Could not fit polynomial to bin %d", i);
3132 cpl_table_new_column(profile_data[i],
"Proffit", CPL_TYPE_DOUBLE);
3133 if (cpl_table_get_nrow(profile_data[i]) > 0)
3135 cpl_table_fill_column_window_double(
3136 profile_data[i],
"Proffit",
3137 0, cpl_table_get_nrow(profile_data[i]),
3146 if (profile->is_zero_degree[i])
3156 double min_rms = 0.1;
3163 uves_free_table(profile_global);
3166 for (pos->order = pos->minorder; order <= pos->minorder; pos->order++)
3168 for (pos->order = pos->minorder; pos->order <= pos->maxorder; pos->order++)
3171 if (pos->order == pos->minorder)
3173 *profile_global = cpl_table_duplicate(profile_data[0]);
3178 cpl_table_insert(*profile_global,
3179 profile_data[pos->order-pos->minorder], 0);
3183 uves_extract_profile_delete(&profile);
3184 profile = uves_extract_profile_new(f, dfda, M, 0, 0);
3196 for (pos->order = pos->minorder; pos->order <= pos->maxorder; pos->order++)
3204 (cpl_table_get_nrow(profile_data[pos->order-pos->minorder])
3207 (cpl_table_get_nrow(*profile_global) >= (max_degree + 1)*(max_degree + 1));
3213 double min_val = -pos->sg.length/2;
3214 double max_val = pos->sg.length/2;
3215 double minmax_pos[4][2];
3216 minmax_pos[0][0] = 1 ; minmax_pos[0][1] = pos->minorder;
3217 minmax_pos[1][0] = 1 ; minmax_pos[1][1] = pos->maxorder;
3218 minmax_pos[2][0] = pos->nx; minmax_pos[2][1] = pos->minorder;
3219 minmax_pos[3][0] = pos->nx; minmax_pos[3][1] = pos->maxorder;
3221 uves_msg_low(
"Fitting profile centroid = polynomial(x, order)");
3225 profile_data[pos->order-pos->minorder],
"dY0", 1.0) );
3227 profile->y0[pos->order - pos->minorder] =
3229 profile_data[pos->order-pos->minorder],
3230 "X",
"Y0",
"dY0", degree,
3234 check_nomsg( uves_raise_to_median_frac(*profile_global,
"dY0", 1.0) );
3239 "X",
"Order",
"Y0",
"dY0",
3240 "Y0fit", NULL, NULL,
3243 max_degree, max_degree, min_rms, -1,
3245 &min_val, &max_val, 4, minmax_pos);
3247 if (cpl_error_get_code() == CPL_ERROR_SINGULAR_MATRIX)
3256 enough_points =
false;
3260 assure( cpl_error_get_code() == CPL_ERROR_NONE,
3261 cpl_error_get_code(),
3262 "Error fitting object position");
3267 uves_msg_low(
"Object offset at chip center = %.2f pixels",
3271 (pos->minorder+pos->maxorder)/2));
3274 if (sqrt(mse) > 0.5)
3277 "(usually RMS ~= 0.1 pixels)");
3286 "object centroid. Setting offset to zero",
3287 cpl_table_get_nrow(profile_data[pos->order - pos->minorder]));
3289 uves_msg_warning(
"Too few points (%" CPL_SIZE_FORMAT
") to fit global polynomial to "
3290 "object centroid. Setting offset to zero",
3291 cpl_table_get_nrow(*profile_global));
3298 cpl_table_new_column(profile_data[pos->order-pos->minorder],
"Y0fit", CPL_TYPE_DOUBLE);
3299 if (cpl_table_get_nrow(profile_data[pos->order-pos->minorder]) > 0)
3301 cpl_table_fill_column_window_double(
3302 profile_data[pos->order-pos->minorder],
"Y0fit",
3303 0, cpl_table_get_nrow(profile_data[pos->order-pos->minorder]),
3309 cpl_table_new_column(*profile_global,
"Y0fit", CPL_TYPE_DOUBLE);
3310 if (cpl_table_get_nrow(*profile_global) > 0)
3312 cpl_table_fill_column_window_double(
3313 *profile_global,
"Y0fit",
3314 0, cpl_table_get_nrow(*profile_global),
3326 for (pos->order = pos->minorder; pos->order <= pos->maxorder; pos->order++)
3333 (cpl_table_get_nrow(profile_data[pos->order-pos->minorder])
3336 (cpl_table_get_nrow(*profile_global) >= (max_degree + 1)*(max_degree + 1));
3340 double min_val = 0.1;
3341 double max_val = pos->sg.length;
3342 double minmax_pos[4][2];
3343 minmax_pos[0][0] = 1 ; minmax_pos[0][1] = pos->minorder;
3344 minmax_pos[1][0] = 1 ; minmax_pos[1][1] = pos->maxorder;
3345 minmax_pos[2][0] = pos->nx; minmax_pos[2][1] = pos->minorder;
3346 minmax_pos[3][0] = pos->nx; minmax_pos[3][1] = pos->maxorder;
3348 uves_msg_low(
"Fitting profile width = polynomial(x, order)");
3352 profile_data[pos->order-pos->minorder],
"dSigma", 1.0) );
3355 profile->sigma[pos->order - pos->minorder] =
3357 profile_data[pos->order-pos->minorder],
3358 "X",
"Sigma",
"dSigma", degree,
3362 check_nomsg( uves_raise_to_median_frac(*profile_global,
"dSigma", 1.0) );
3367 "X",
"Order",
"Sigma",
"dSigma",
3368 "Sigmafit", NULL, NULL,
3371 max_degree, max_degree, min_rms, -1,
3373 &min_val, &max_val, 4, minmax_pos);
3376 if (cpl_error_get_code() == CPL_ERROR_SINGULAR_MATRIX)
3385 enough_points =
false;
3389 assure( cpl_error_get_code() == CPL_ERROR_NONE,
3390 cpl_error_get_code(),
3391 "Error fitting profile width");
3395 uves_msg_low(
"Profile FWHM at chip center = %.2f pixels",
3399 (pos->minorder+pos->maxorder)/2));
3408 "object width. Setting std.dev. to 1 pixel",
3409 cpl_table_get_nrow(profile_data[pos->order - pos->minorder]));
3411 uves_msg_warning(
"Too few points (%" CPL_SIZE_FORMAT
") to fit global polynomial to "
3412 "object width. Setting std.dev. to 1 pixel",
3413 cpl_table_get_nrow(*profile_global));
3421 cpl_table_new_column(profile_data[pos->order-pos->minorder],
"Sigmafit", CPL_TYPE_DOUBLE);
3422 if (cpl_table_get_nrow(profile_data[pos->order-pos->minorder]) > 0)
3424 cpl_table_fill_column_window_double(
3425 profile_data[pos->order-pos->minorder],
"Sigmafit",
3426 0, cpl_table_get_nrow(profile_data[pos->order-pos->minorder]),
3433 cpl_table_new_column(*profile_global,
"Sigmafit", CPL_TYPE_DOUBLE);
3434 if (cpl_table_get_nrow(*profile_global) > 0)
3436 cpl_table_fill_column_window_double(
3437 *profile_global,
"Sigmafit",
3438 0, cpl_table_get_nrow(*profile_global),
3451 cpl_table_get_nrow(profile_data[pos->order - pos->minorder]) > 0 ?
3452 cpl_table_get_column_median(profile_data[pos->order - pos->minorder],
3453 "Reduced_chisq") : 1.0);
3457 cpl_table_get_nrow(*profile_global) > 0 ?
3458 cpl_table_get_column_median(*profile_global,
3459 "Reduced_chisq") : 1.0);
3491 uves_free_table(profile_global);
3492 for (pos->order = pos->minorder; pos->order <= pos->maxorder; pos->order++)
3494 if (pos->order == pos->minorder)
3496 *profile_global = cpl_table_duplicate(profile_data[0]);
3501 cpl_table_insert(*profile_global,
3502 profile_data[pos->order-pos->minorder], 0);
3514 int xmin = uves_max_int(1 , pos->nx/2-100);
3515 int xmax = uves_min_int(pos->nx, pos->nx/2+100);
3516 int order = (pos->minorder + pos->maxorder)/2;
3519 plot0x = cpl_vector_new(uves_round_double(pos->sg.length+5)*(xmax-xmin+1));
3520 plot0y = cpl_vector_new(uves_round_double(pos->sg.length+5)*(xmax-xmin+1));
3521 plot1x = cpl_vector_new(uves_round_double(pos->sg.length+5)*(xmax-xmin+1));
3522 plot1y = cpl_vector_new(uves_round_double(pos->sg.length+5)*(xmax-xmin+1));
3539 for (pos->y = pos->ylow; pos->y <= pos->yhigh; pos->y++)
3542 double pixelval = cpl_image_get(image, pos->x, pos->y, &pis_rejected);
3549 uves_extract_profile_set(profile, pos, NULL);
3552 for (pos->y = pos->ylow; pos->y <= pos->yhigh; pos->y++)
3554 double dy = pos->y - pos->ycenter;
3556 double pixelval = cpl_image_get(
3557 image, pos->x, uves_round_double(pos->y), &pis_rejected);
3559 if (!pis_rejected && flux != 0)
3568 cpl_vector_set(plot0x, indx, dy);
3569 cpl_vector_set(plot0y, indx, uves_extract_profile_evaluate(profile, pos));
3571 cpl_vector_set(plot1x, indx, dy);
3572 cpl_vector_set(plot1y, indx, pixelval);
3580 cpl_vector_set_size(plot0x, indx);
3581 cpl_vector_set_size(plot0y, indx);
3582 cpl_vector_set_size(plot1x, indx);
3583 cpl_vector_set_size(plot1y, indx);
3585 plot[0] = cpl_bivector_wrap_vectors(plot0x, plot0y);
3586 plot[1] = cpl_bivector_wrap_vectors(plot1x, plot1y);
3588 plot_titles[0] = uves_sprintf(
3589 "Model spatial profile at (order, x) = (%d, %d)", order, pos->nx/2);
3590 plot_titles[1] = uves_sprintf(
3591 "Empirical spatial profile at (order, x) = (%d, %d)", order, pos->nx/2);
3593 check( uves_plot_bivectors(plot, plot_titles, 2,
"DY",
"Profile"),
"Plotting failed");
3598 "polynomial is ill-formed");
3610 for (i = 0; i < cpl_table_get_nrow(*profile_global); i++)
3612 double y0fit = cpl_table_get_double(*profile_global,
"Y0fit", i, NULL);
3613 int order = cpl_table_get_int (*profile_global,
"Order", i, NULL);
3614 int x = cpl_table_get_int (*profile_global,
"X" , i, NULL);
3623 cpl_table_set_double(*profile_global,
"Y0fit_world", i, y0fit + pos->ycenter);
3628 for (pos->order = pos->minorder; pos->order <= pos->minorder; pos->order++)
3630 for (pos->order = pos->minorder; pos->order <= pos->maxorder; pos->order++)
3633 if (good_bins[pos->order-pos->minorder] == 0)
3641 for (pos->order = pos->minorder; pos->order <= pos->maxorder; pos->order++)
3649 - ( - pos->sg.length/2 ));
3652 pos->nx/2) * TWOSQRT2LN2);
3655 check_nomsg(cpl_table_set_double(info_tbl,
"ObjPosOnSlit" , pos->order - pos->minorder, objpos));
3656 check_nomsg(cpl_table_set_double(info_tbl,
"ObjFwhmAvg" , pos->order - pos->minorder, fwhm));
3660 pos->nx/2, pos->order)
3661 - ( - pos->sg.length/2 ));
3664 pos->nx/2, pos->order)*
3667 check_nomsg(cpl_table_set_double(info_tbl,
"ObjPosOnSlit" , pos->order - pos->minorder, objpos));
3668 check_nomsg(cpl_table_set_double(info_tbl,
"ObjFwhmAvg" , pos->order - pos->minorder, fwhm));
3673 if (cpl_table_get_nrow(*profile_global) > 0)
3675 double med_chisq = cpl_table_get_column_median(
3676 *profile_global,
"Reduced_chisq");
3679 if (med_chisq > limit || med_chisq < 1/limit)
3691 "good fit to the data: median(Chi^2/N) = %f",
3694 if (f != NULL && med_chisq > limit)
3697 "measuring method: virtual");
3702 uves_msg(
"Median(reduced Chi^2) is %f", med_chisq);
3713 uves_free_mask(&image_bad);
3715 cpl_free(good_bins);
3716 if (profile_data != NULL)
3719 for (i = 0; i < ((f == NULL) ? spatial_bins : pos->maxorder-pos->minorder+1); i++)
3721 if (profile_data[i] != NULL)
3723 uves_free_table(&(profile_data[i]));
3726 cpl_free(profile_data);
3728 cpl_bivector_unwrap_vectors(plot[0]);
3729 cpl_bivector_unwrap_vectors(plot[1]);
3730 cpl_free(plot_titles[0]);
3731 cpl_free(plot_titles[1]);
3732 uves_free_vector(&plot0x);
3733 uves_free_vector(&plot0y);
3734 uves_free_vector(&plot1x);
3735 uves_free_vector(&plot1y);
3747 int (*f) (
const double x[],
const double a[],
double *result);
3748 int (*dfda)(
const double x[],
const double a[],
double result[]);
3761 eval_pol(
const double *coeffs,
3762 int degree1,
int degree2,
3763 double x1,
double x2)
3769 for (j = 0, x2j = 1;
3777 double r = coeffs[i + (degree1+1)*j];
3783 r += coeffs[i + (degree1+1)*j];
3808 profile_f(
const double x[],
const double a[],
double *result)
3810 int xi = uves_round_double(x[0]);
3812 int mi = uves_round_double(x[2]);
3815 double y_0 = eval_pol(a,
3816 profile_params.deg_y0_x,
3817 profile_params.deg_y0_m,
3819 double sigma = eval_pol(a + (1 + profile_params.deg_y0_x)*(1 + profile_params.deg_y0_m),
3820 profile_params.deg_sigma_x,
3821 profile_params.deg_sigma_m,
3838 if (profile_params.f(xf, af, &norm_prof) != 0)
3843 idx = xi + (mi - profile_params.minorder)*(profile_params.nx + 1);
3845 *result = profile_params.sky[idx] + profile_params.flux[idx] * norm_prof;
3873 profile_dfda(
const double x[],
const double a[],
double result[])
3875 int xi = uves_round_double(x[0]);
3877 int mi = uves_round_double(x[2]);
3879 double y_0 = eval_pol(a,
3880 profile_params.deg_y0_x,
3881 profile_params.deg_y0_m,
3883 double sigma = eval_pol(a + (1 + profile_params.deg_y0_x)*(1 + profile_params.deg_y0_m),
3884 profile_params.deg_sigma_x,
3885 profile_params.deg_sigma_m,
3888 double norm_prof_derivatives[5];
3901 if (profile_params.dfda(xf, af, norm_prof_derivatives) != 0)
3907 int idx = xi + (mi - profile_params.minorder)*(profile_params.nx + 1);
3910 double norm_prof_dy0 = norm_prof_derivatives[0];
3911 double norm_prof_dsigma = norm_prof_derivatives[1];
3931 result[i + (profile_params.deg_y0_x + 1) * j] = profile_params.flux[idx] * norm_prof_dy0;
3932 for (j = 0; j <= profile_params.deg_y0_m; j++) {
3936 result[i + (profile_params.deg_y0_x + 1) * j] =
3937 result[i + (profile_params.deg_y0_x + 1) * (j-1)] * mi;
3939 for (i = 1; i <= profile_params.deg_y0_x; i++) {
3940 result[i + (profile_params.deg_y0_x + 1) * j] =
3941 result[i-1 + (profile_params.deg_y0_x + 1) * j] * xi;
3953 result += (profile_params.deg_y0_x + 1) * (profile_params.deg_y0_m + 1);
3959 result[i + (profile_params.deg_sigma_x + 1) * j] =
3960 profile_params.flux[idx] * norm_prof_dsigma;
3961 for (j = 0; j <= profile_params.deg_sigma_m; j++) {
3965 result[i + (profile_params.deg_sigma_x + 1) * j] =
3966 result[i + (profile_params.deg_sigma_x + 1) * (j-1)] * mi;
3968 for (i = 1; i <= profile_params.deg_sigma_x; i++) {
3969 result[i + (profile_params.deg_sigma_x + 1) * j] =
3970 result[i-1 + (profile_params.deg_sigma_x + 1) * j] * xi;
4001 const cpl_binary *image_bpm,
4002 uves_iterate_position *pos,
4004 int (*f) (
const double x[],
const double a[],
double *result),
4005 int (*dfda)(
const double x[],
const double a[],
double result[]),
4007 const cpl_image *sky_spectrum)
4009 cpl_table *profile_data = NULL;
4011 cpl_matrix *covariance = NULL;
4014 cpl_matrix *eval_points = NULL;
4015 cpl_vector *eval_data = NULL;
4016 cpl_vector *eval_err = NULL;
4017 cpl_vector *coeffs = NULL;
4018 #if CREATE_DEBUGGING_TABLE
4019 cpl_table *temp = NULL;
4021 double *fluxes = NULL;
4022 double *skys = NULL;
4025 cpl_table *estimate = NULL;
4026 cpl_table *estimate_dup = NULL;
4032 cpl_vector *dy = NULL;
4033 cpl_vector *prof = NULL;
4034 cpl_vector *prof2= NULL;
4035 cpl_vector *dprof = NULL;
4036 cpl_vector **data = NULL;
4038 double *hicut = NULL;
4039 double *locut = NULL;
4042 const double *image_data;
4043 const double *noise_data;
4048 int norders = pos->maxorder-pos->minorder+1;
4051 sky_spectrum = sky_spectrum;
4056 image_data = cpl_image_get_data_double_const(image);
4057 noise_data = cpl_image_get_data_double_const(image_noise);
4060 profile_data = cpl_table_new((nx/chunk + 3) * norders);
4062 profile_data = cpl_table_new(pos->nx);
4066 check( (cpl_table_new_column(profile_data,
"Order", CPL_TYPE_INT),
4067 cpl_table_new_column(profile_data,
"X", CPL_TYPE_INT),
4068 cpl_table_new_column(profile_data,
"Y0", CPL_TYPE_DOUBLE),
4069 cpl_table_new_column(profile_data,
"Sigma", CPL_TYPE_DOUBLE),
4070 cpl_table_new_column(profile_data,
"Norm", CPL_TYPE_DOUBLE),
4071 cpl_table_new_column(profile_data,
"dY0", CPL_TYPE_DOUBLE),
4072 cpl_table_new_column(profile_data,
"dSigma", CPL_TYPE_DOUBLE),
4073 cpl_table_new_column(profile_data,
"dNorm", CPL_TYPE_DOUBLE),
4074 cpl_table_new_column(profile_data,
"Y0_world", CPL_TYPE_DOUBLE),
4075 cpl_table_new_column(profile_data,
"Y0fit_world", CPL_TYPE_DOUBLE),
4076 cpl_table_new_column(profile_data,
"Reduced_chisq", CPL_TYPE_DOUBLE)),
4077 "Error initializing order trace table for order #%d", pos->order);
4080 cpl_table_set_column_unit(profile_data,
"X" ,
"pixels");
4081 cpl_table_set_column_unit(profile_data,
"Y0",
"pixels");
4082 cpl_table_set_column_unit(profile_data,
"Sigma",
"pixels");
4083 cpl_table_set_column_unit(profile_data,
"dY0",
"pixels");
4084 cpl_table_set_column_unit(profile_data,
"dSigma",
"pixels");
4088 UVES_TIME_START(
"Measure loop");
4090 nbins = uves_round_double(pos->sg.length + 5);
4091 data = cpl_calloc(nbins,
sizeof(cpl_vector *));
4092 size = cpl_calloc(nbins,
sizeof(
int));
4093 locut = cpl_calloc(nbins,
sizeof(
double));
4094 hicut = cpl_calloc(nbins,
sizeof(
double));
4097 for (i = 0; i < nbins; i++)
4099 data[i] = cpl_vector_new(1);
4122 int deg_sigma_x = 0;
4123 int deg_sigma_m = 0;
4126 (deg_y0_x +1)*(deg_y0_m +1) +
4127 (deg_sigma_x+1)*(deg_sigma_m+1);
4133 #if CREATE_DEBUGGING_TABLE
4134 temp = cpl_table_new(norders*nx*uves_round_double(pos->sg.length+3));
4135 cpl_table_new_column(temp,
"x", CPL_TYPE_DOUBLE);
4136 cpl_table_new_column(temp,
"y", CPL_TYPE_DOUBLE);
4137 cpl_table_new_column(temp,
"order", CPL_TYPE_DOUBLE);
4138 cpl_table_new_column(temp,
"dat", CPL_TYPE_DOUBLE);
4139 cpl_table_new_column(temp,
"err", CPL_TYPE_DOUBLE);
4162 eval_points = cpl_matrix_new(norders*nx*uves_round_double(pos->sg.length+3), 3);
4163 eval_data = cpl_vector_new(norders*nx*uves_round_double(pos->sg.length+3));
4164 eval_err = cpl_vector_new(norders*nx*uves_round_double(pos->sg.length+3));
4166 fluxes = cpl_calloc((nx+1)*norders,
sizeof(
double));
4167 skys = cpl_calloc((nx+1)*norders,
sizeof(
double));
4171 estimate = cpl_table_new(norders);
4172 cpl_table_new_column(estimate,
"Order", CPL_TYPE_INT);
4173 cpl_table_new_column(estimate,
"Y0" , CPL_TYPE_DOUBLE);
4174 cpl_table_new_column(estimate,
"Sigma", CPL_TYPE_DOUBLE);
4176 coeffs = cpl_vector_new(ncoeffs);
4177 ia = cpl_calloc(ncoeffs,
sizeof(
int));
4180 for (i = 0; i < ncoeffs; i++)
4182 cpl_vector_set(coeffs, i, 0);
4189 for (order = 17; order <= 17; order++) {
4198 for (x = chunk/2; x <= nx - chunk/2; x += chunk) {
4202 for (i = 0; i < nbins; i++)
4210 cpl_vector_set_size(data[i], 2*(chunk + 1));
4216 x - chunk/2 + 1, x + chunk/2,
4222 int bin = pos->y - pos->ylow;
4225 DATA(image_data, pos)));
4230 for (i = 0; i < nbins; i++)
4236 else if (size[i] <= chunk/2)
4240 locut[i] = cpl_vector_get_max(data[i]) + 1;
4241 hicut[i] = cpl_vector_get_min(data[i]) - 1;
4247 double median, stdev;
4255 cpl_vector_set_size(data[i], k);
4257 data_data = cpl_vector_get_data(data[i]);
4259 median = cpl_vector_get_median_const(data[i]);
4260 stdev = cpl_vector_get_stdev(data[i]);
4261 locut[i] = median - kappa*stdev;
4262 hicut[i] = median + kappa*stdev;
4268 for (j = 0; j < size[i]; j++)
4270 if (locut[i] <= data_data[j] &&
4271 data_data[j] <= hicut[i])
4273 data_data[k] = data_data[j];
4279 while (k < size[i] && k > 1);
4290 x - chunk/2 + 1, x + chunk/2,
4298 for (pos->y = pos->ylow; pos->y <= pos->yhigh; pos->y++)
4300 int bin = pos->y - pos->ylow;
4302 if (ISGOOD(image_bpm, pos) &&
4303 (locut[bin] <= DATA(image_data, pos) &&
4304 DATA(image_data, pos) <= hicut[bin])
4307 double pix = DATA(image_data, pos);
4308 double dy = pos->y - pos->ycenter;
4311 cpl_matrix_set(eval_points, n, 0, pos->x);
4312 cpl_matrix_set(eval_points, n, 1, dy);
4313 cpl_matrix_set(eval_points, n, 2, order);
4314 cpl_vector_set(eval_data, n, pix);
4315 cpl_vector_set(eval_err , n,
4316 DATA(noise_data, pos));
4320 sumwyy += pix * dy * dy;
4321 #if CREATE_DEBUGGING_TABLE
4322 cpl_table_set_double(temp,
"x", n, pos->x);
4323 cpl_table_set_double(temp,
"y", n, dy);
4324 cpl_table_set_double(temp,
"order", n, order);
4325 cpl_table_set_double(temp,
"dat", n, pix);
4326 cpl_table_set_double(temp,
"err", n,
4327 DATA(noise_data, pos));
4338 fluxes[pos->x + (order-pos->minorder)*(pos->nx+1)] = flux;
4339 skys [pos->x + (order-pos->minorder)*(pos->nx+1)] =
4340 cpl_image_get(sky_spectrum,
4341 pos->x, order-pos->minorder+1, &pis_rejected);
4344 skys [pos->x + (order-pos->minorder)*(pos->nx+1)] = 0;
4360 y0_estim = sumwy/sumw;
4362 sigma_estim = sumwyy/sumw - (sumwy/sumw)*(sumwy/sumw);
4363 if (sigma_estim > 0)
4365 sigma_estim = sqrt(sigma_estim);
4366 sigma_is_good =
true;
4370 sigma_is_good =
false;
4377 sigma_is_good =
false;
4380 cpl_table_set_int (estimate,
"Order", order - pos->minorder, order);
4384 cpl_table_set_double(estimate,
"Y0" , order - pos->minorder, y0_estim);
4388 cpl_table_set_invalid(estimate,
"Y0", order - pos->minorder);
4393 cpl_table_set_double(estimate,
"Sigma",
4394 order - pos->minorder, sigma_estim);
4398 cpl_table_set_invalid(estimate,
"Sigma", order - pos->minorder);
4403 if (y0_is_good && sigma_is_good) {
4405 order, y0_estim, sigma_estim*TWOSQRT2LN2);
4407 else if (y0_is_good && !sigma_is_good) {
4411 else if (!y0_is_good && sigma_is_good) {
4413 order, sigma_estim);
4423 cpl_matrix_set_size(eval_points, n, 3);
4424 cpl_vector_set_size(eval_data, n);
4425 cpl_vector_set_size(eval_err , n);
4427 #if CREATE_DEBUGGING_TABLE
4428 cpl_table_set_size(temp, n);
4437 cpl_table_dump(estimate, 0, cpl_table_get_nrow(estimate), stdout);
4441 estimate_dup = cpl_table_duplicate(estimate);
4443 uves_erase_invalid_table_rows(estimate_dup,
"Y0");
4446 degree = (cpl_table_get_nrow(estimate_dup) > 1) ? 1 : 0;
4449 estimate_dup,
"Order",
"Y0", NULL,
4457 if (cpl_error_get_code() != CPL_ERROR_NONE)
4460 "Setting initial offset to zero",
4461 cpl_error_get_message());
4470 uves_free_table(&estimate_dup);
4471 estimate_dup = cpl_table_duplicate(estimate);
4473 uves_erase_invalid_table_rows(estimate_dup,
"Sigma");
4475 degree = (cpl_table_get_nrow(estimate_dup) > 1) ? 1 : 0;
4478 estimate_dup,
"Order",
"Sigma", NULL,
4484 if (cpl_error_get_code() != CPL_ERROR_NONE)
4487 "Setting initial sigma to 1 pixel",
4488 cpl_error_get_message());
4502 cpl_vector_set(coeffs, 0,
4507 cpl_vector_set(coeffs, 0 + (deg_y0_x+1)*1,
4511 cpl_vector_get(coeffs, 0),
4512 cpl_vector_get(coeffs, 0 + (deg_y0_x+1)*1));
4517 cpl_vector_get(coeffs, 0));
4522 cpl_vector_set(coeffs, (deg_y0_x+1)*(deg_y0_m+1),
4525 if (deg_sigma_m >= 1)
4527 cpl_vector_set(coeffs, (deg_y0_x+1)*(deg_y0_m+1) +
4528 0 + (deg_sigma_x+1)*1,
4532 cpl_vector_get(coeffs, (deg_y0_x+1)*(deg_y0_m+1) +
4534 cpl_vector_get(coeffs, (deg_y0_x+1)*(deg_y0_m+1) +
4535 0 + (deg_y0_x+1)*1));
4540 cpl_vector_get(coeffs, (deg_y0_x+1)*(deg_y0_m+1) +
4547 profile_params.flux = fluxes;
4548 profile_params.sky = skys;
4549 profile_params.minorder = pos->minorder;
4550 profile_params.nx = nx;
4552 profile_params.f = f;
4553 profile_params.dfda = dfda;
4555 profile_params.deg_y0_x = deg_y0_x;
4556 profile_params.deg_y0_m = deg_y0_m;
4557 profile_params.deg_sigma_x = deg_sigma_x;
4558 profile_params.deg_sigma_m = deg_sigma_m;
4563 cpl_vector_fill(eval_err,
4564 cpl_vector_get_median_const(eval_err));
4566 uves_msg_error(
"Fitting model to %d positions; %d bad pixels found",
4569 uves_fit(eval_points, NULL,
4570 eval_data, eval_err,
4579 if (cpl_error_get_code() == CPL_ERROR_SINGULAR_MATRIX ||
4580 cpl_error_get_code() == CPL_ERROR_CONTINUE)
4582 uves_msg_warning(
"Fitting global model failed (%s)", cpl_error_get_message());
4584 #if CREATE_DEBUGGING_TABLE
4585 cpl_table_save(temp, NULL, NULL,
"tab.fits", CPL_IO_DEFAULT);
4590 assure( cpl_error_get_code() == CPL_ERROR_NONE,
4591 cpl_error_get_code(),
"Fitting global model failed");
4593 cpl_matrix_dump(covariance, stdout); fflush(stdout);
4595 uves_msg_error(
"Solution: y0 ~= %g", eval_pol(cpl_vector_get_data(coeffs),
4598 (pos->minorder+pos->maxorder)/2));
4599 uves_msg_error(
"Solution: sigma ~= %g", eval_pol(cpl_vector_get_data(coeffs)+
4600 (deg_y0_x+1)*(deg_y0_m+1),
4603 (pos->minorder+pos->maxorder)/2));
4606 for (order = pos->minorder; order <= pos->maxorder; order++) {
4607 for (x = chunk/2; x <= nx - chunk/2; x += chunk)
4609 double y_0 = eval_pol(cpl_vector_get_data(coeffs),
4610 deg_y0_x, deg_y0_m, x, order);
4611 double sigma = fabs(eval_pol(cpl_vector_get_data(coeffs)+
4612 (deg_y0_x+1)*(deg_y0_m+1),
4613 deg_sigma_x, deg_sigma_m, x, order));
4627 int i1, i2, j_1, j2;
4629 for (i1 = 0; i1 < (deg_y0_x+1); i1++)
4630 for (j_1 = 0; j_1 < (deg_y0_m+1); j_1++)
4631 for (i2 = 0; i2 < (deg_y0_x+1); i2++)
4632 for (j2 = 0; j2 < (deg_y0_m+1); j2++)
4634 dy0 += cpl_matrix_get(covariance,
4635 i1+(deg_y0_x+1)*j_1,
4636 i2+(deg_y0_x+1)*j2) *
4650 for (i1 = 0; i1 < (deg_sigma_x+1); i1++)
4651 for (j_1 = 0; j_1 < (deg_sigma_m+1); j_1++)
4652 for (i2 = 0; i2 < (deg_sigma_x+1); i2++)
4653 for (j2 = 0; j2 < (deg_sigma_m+1); j2++)
4658 dsigma += cpl_matrix_get(
4660 (deg_y0_x+1)*(deg_y0_m+1) + i1+(deg_sigma_x+1)*j_1,
4661 (deg_y0_x+1)*(deg_y0_m+1) + i2+(deg_sigma_x+1)*j2) *
4667 dsigma = sqrt(dsigma);
4675 check((cpl_table_set_int (profile_data,
"Order", profile_row, order),
4676 cpl_table_set_int (profile_data,
"X" , profile_row, x),
4677 cpl_table_set_double(profile_data,
"Y0" , profile_row, y_0),
4678 cpl_table_set_double(profile_data,
"Sigma", profile_row, sigma),
4679 cpl_table_set_double(profile_data,
"Norm" , profile_row, 1),
4680 cpl_table_set_double(profile_data,
"dY0" , profile_row, dy0),
4681 cpl_table_set_double(profile_data,
"dSigma", profile_row, dsigma),
4682 cpl_table_set_double(profile_data,
"dNorm", profile_row, 1),
4683 cpl_table_set_double(profile_data,
"Y0_world", profile_row, -1),
4684 cpl_table_set_double(profile_data,
"Reduced_chisq", profile_row,
4686 "Error writing table row %d", profile_row+1);
4690 #if CREATE_DEBUGGING_TABLE
4691 cpl_table_new_column(temp,
"pemp", CPL_TYPE_DOUBLE);
4692 cpl_table_new_column(temp,
"fit", CPL_TYPE_DOUBLE);
4693 cpl_table_new_column(temp,
"pfit", CPL_TYPE_DOUBLE);
4695 for (i = 0; i < cpl_table_get_nrow(temp); i++)
4697 double y = cpl_table_get_double(temp,
"y", i, NULL);
4698 int xi = uves_round_double(cpl_table_get_double(temp,
"x", i, NULL));
4699 int mi = uves_round_double(cpl_table_get_double(temp,
"order", i, NULL));
4700 double dat = cpl_table_get_double(temp,
"dat", i, NULL);
4701 int idx = xi + (mi - profile_params.minorder)*(profile_params.nx + 1);
4709 cpl_vector_get_data(coeffs), &flux_fit);
4711 cpl_table_set(temp,
"pemp", i,
4712 (dat - profile_params.sky[idx])/profile_params.flux[idx]);
4714 cpl_table_set(temp,
"fit", i, flux_fit);
4716 cpl_table_set(temp,
"pfit", i,
4717 (flux_fit - profile_params.sky[idx])/profile_params.flux[idx]);
4721 cpl_table_save(temp, NULL, NULL,
"tab.fits", CPL_IO_DEFAULT));
4727 dy = cpl_vector_new((chunk+1) * ((
int)(pos->sg.length + 3)));
4728 prof = cpl_vector_new((chunk+1) * ((
int)(pos->sg.length + 3)));
4729 prof2 = cpl_vector_new((chunk+1) * ((
int)(pos->sg.length + 3)));
4730 dprof = cpl_vector_new((chunk+1) * ((
int)(pos->sg.length + 3)));
4732 for (x = 1 + chunk/2; x + chunk/2 <= pos->nx; x += chunk) {
4736 const int points_needed_for_fit = 6;
4742 cpl_vector_set_size(dy, (chunk+1) * ((
int)(pos->sg.length + 3)));
4743 cpl_vector_set_size(prof, (chunk+1) * ((
int)(pos->sg.length + 3)));
4744 cpl_vector_set_size(prof2, (chunk+1) * ((
int)(pos->sg.length + 3)));
4745 cpl_vector_set_size(dprof, (chunk+1) * ((
int)(pos->sg.length + 3)));
4748 for (i = 0; i < nbins; i++)
4756 cpl_vector_set_size(data[i], 2*(chunk + 1));
4765 pos->order, pos->order,
4770 int bin = pos->y - pos->ylow;
4774 DATA(image_data, pos)));
4779 for (i = 0; i < nbins; i++)
4785 else if (size[i] <= chunk/2)
4789 locut[i] = cpl_vector_get_max(data[i]) + 1;
4790 hicut[i] = cpl_vector_get_min(data[i]) - 1;
4796 double median, stdev;
4804 cpl_vector_set_size(data[i], k);
4806 data_data = cpl_vector_get_data(data[i]);
4808 median = cpl_vector_get_median_const(data[i]);
4809 stdev = cpl_vector_get_stdev(data[i]);
4810 locut[i] = median - kappa*stdev;
4811 hicut[i] = median + kappa*stdev;
4817 for (j = 0; j < size[i]; j++)
4819 if (locut[i] <= data_data[j] &&
4820 data_data[j] <= hicut[i])
4822 data_data[k] = data_data[j];
4828 while (k < size[i] && k > 1);
4837 pos->order, pos->order,
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 flux += DATA(image_data, pos);
4858 for (pos->y = pos->ylow; pos->y <= pos->yhigh; pos->y++)
4860 int bin = pos->y - pos->ylow;
4862 if (ISGOOD(image_bpm, pos) &&
4863 (locut[bin] <= DATA(image_data, pos) &&
4864 DATA(image_data, pos) <= hicut[bin])
4867 double pix = DATA(image_data, pos);
4869 cpl_vector_set(dy , n, pos->y - pos->ycenter);
4870 cpl_vector_set(prof , n, pix/flux);
4871 cpl_vector_set(dprof, n, (flux > 0) ?
4872 DATA(noise_data, pos)/flux :
4873 -DATA(noise_data, pos)/flux);
4886 if (n >= points_needed_for_fit) {
4887 double y_0, norm, background, slope, sigma, red_chisq;
4889 cpl_vector_set_size(dy, n);
4890 cpl_vector_set_size(prof, n);
4891 cpl_vector_set_size(prof2, n);
4892 cpl_vector_set_size(dprof, n);
4896 x-chunk/2, x+chunk/2);
4901 uves_free_matrix(&covariance);
4914 double median = cpl_vector_get_median_const(dprof);
4916 cpl_vector_fill(dprof, median);
4918 uves_fit_1d(dy, NULL,
4927 &y_0, &sigma, &norm, &background, &slope,
4938 covariance = cpl_matrix_new(4,4);
4939 cpl_matrix_set(covariance, 0, 0, 1);
4940 cpl_matrix_set(covariance, 1, 1, 1);
4941 cpl_matrix_set(covariance, 2, 2, 1);
4942 cpl_matrix_set(covariance, 3, 3, 1);
4962 cpl_vector *pl[] = {NULL, NULL, NULL};
4964 cpl_vector *fit = cpl_vector_new(cpl_vector_get_size(dy));
4966 for (i = 0; i < cpl_vector_get_size(dy); i++)
4968 double yy = cpl_vector_get(dy, i);
4969 cpl_vector_set(fit, i,
4970 exp(-(yy-y_0)*(yy-y_0)/(2*sigma*sigma))
4971 /(sigma*sqrt(2*M_PI)));
4986 cpl_plot_vectors(
"set grid;set yrange[0:0.5];set xlabel 'dy';",
4987 "t 'Spatial profile' w points",
4989 (
const cpl_vector **)pl, 3);
4996 cpl_plot_vectors(
"set grid;set xrange[-2:2];"
4997 "set yrange[0:0.5];set xlabel 'dy';",
4998 "t 'Spatial profile' w points",
5000 (
const cpl_vector **)pl, 3);
5002 uves_free_vector(&fit);
5009 pos->order, pos->order,
5012 y_0 += pos->ycenter;
5037 if (cpl_error_get_code() == CPL_ERROR_CONTINUE ||
5038 cpl_error_get_code()== CPL_ERROR_SINGULAR_MATRIX ||
5039 4.0*sigma >= pos->sg.length || sigma < 0.2) {
5041 uves_msg_debug(
"Profile fitting failed at (order, x) = (%d, %d) "
5042 "(%s), ignoring chunk",
5043 pos->order, x, cpl_error_get_message());
5048 assure( cpl_error_get_code() == CPL_ERROR_NONE, cpl_error_get_code(),
5049 "Gaussian fitting failed");
5052 (cpl_table_set_int (profile_data,
"Order", profile_row, pos->order),
5053 cpl_table_set_int (profile_data,
"X" , profile_row, x),
5054 cpl_table_set_double(profile_data,
"Y0" , profile_row, y_0 - pos->ycenter),
5055 cpl_table_set_double(profile_data,
"Sigma", profile_row, sigma),
5056 cpl_table_set_double(profile_data,
"Norm" , profile_row, norm),
5057 cpl_table_set_double(profile_data,
"dY0" , profile_row,
5058 sqrt(cpl_matrix_get(covariance, 0, 0))),
5059 cpl_table_set_double(profile_data,
"dSigma", profile_row,
5060 sqrt(cpl_matrix_get(covariance, 1, 1))),
5061 cpl_table_set_double(profile_data,
"dNorm", profile_row,
5062 sqrt(cpl_matrix_get(covariance, 2, 2))),
5063 cpl_table_set_double(profile_data,
"Y0_world", profile_row, y_0),
5064 cpl_table_set_double(profile_data,
"Reduced_chisq", profile_row,
5066 "Error writing table");
5076 "at x = %d - %d, ignoring chunk",
5078 x - chunk/2, x + chunk/2);
5084 cpl_table_set_size(profile_data, profile_row);
5091 uves_free_matrix(&eval_points);
5092 uves_free_vector(&eval_data);
5093 uves_free_vector(&eval_err);
5094 uves_free_vector(&coeffs);
5098 #if CREATE_DEBUGGING_TABLE
5099 uves_free_table(&temp);
5101 uves_free_table(&estimate);
5102 uves_free_table(&estimate_dup);
5107 uves_free_matrix(&covariance);
5108 uves_free_vector(&dy);
5109 uves_free_vector(&prof);
5110 uves_free_vector(&prof2);
5111 uves_free_vector(&dprof);
5114 for (i = 0; i < nbins; i++)
5116 uves_free_vector(&(data[i]));
5124 if (cpl_error_get_code() != CPL_ERROR_NONE)
5126 uves_free_table(&profile_data);
5129 return profile_data;
5149 double x2 = pos->nx;
5152 double slope = (y2 - y_1)/(x2 - x1);
5163 double x_yeq1 = ( 1 - y_1)/slope;
5164 double x_yeqny = (pos->ny - y_1)/slope;
5166 if (1 <= x_yeq1 && x_yeq1 <= pos->nx)
5168 double guess = x_yeq1;
5180 if (cpl_error_get_code() != CPL_ERROR_NONE)
5184 "Order polynomial may be ill-formed", pos->order);
5193 if (1 <= x_yeqny && x_yeqny <= pos->nx)
5195 double guess = x_yeqny;
5207 if (cpl_error_get_code() != CPL_ERROR_NONE)
5211 "Order polynomial may be ill-formed",
5212 pos->ny, pos->order);
5223 result = uves_round_double(
5225 uves_min_double(pos->nx, x_yeqny) -
5226 uves_max_double(1, x_yeq1) + 1));
5230 passure( slope < 0,
"%f", slope);
5231 result = uves_round_double(
5233 uves_min_double(pos->nx, x_yeq1 ) -
5234 uves_max_double(1, x_yeqny) + 1));
5292 const cpl_image *image_noise,
5293 uves_iterate_position *pos,
5294 const uves_extract_profile *profile,
5295 bool optimal_extract_sky,
5297 cpl_table *blemish_mask,
5298 cpl_table *cosmic_mask,
5300 cpl_table *profile_table,
5302 cpl_image *spectrum,
5303 cpl_image *spectrum_noise,
5305 cpl_image *sky_spectrum,
5306 cpl_image *sky_spectrum_noise,
5309 cpl_table *signal_to_noise = NULL;
5315 int bins_extracted = 0;
5316 int cold_pixels = 0;
5320 const double *image_data;
5321 const double *noise_data;
5322 double *weights_data;
5323 cpl_mask *image_bad = NULL;
5324 cpl_binary*image_bpm = NULL;
5325 double *noise_buffer = NULL;
5328 int spectrum_row = pos->order - pos->minorder + 1;
5337 assure( cpl_image_get_type(image) == CPL_TYPE_DOUBLE &&
5338 cpl_image_get_type(image_noise) == CPL_TYPE_DOUBLE, CPL_ERROR_UNSUPPORTED_MODE,
5339 "Input image+noise must have type double. Types are %s + %s",
5343 image_data = cpl_image_get_data_double_const(image);
5344 noise_data = cpl_image_get_data_double_const(image_noise);
5345 weights_data = cpl_image_get_data_double(weights);
5347 image_bad = cpl_image_get_bpm(image);
5350 if(blemish_mask!=NULL) {
5351 check_nomsg(px=cpl_table_get_data_int(blemish_mask,
"X"));
5352 check_nomsg(py=cpl_table_get_data_int(blemish_mask,
"Y"));
5354 for(row=0;row<cpl_table_get_nrow(blemish_mask);row++) {
5355 check_nomsg(cpl_mask_set(image_bad,px[row]+1,py[row]+1,CPL_BINARY_1));
5360 image_bpm = cpl_mask_get_data(image_bad);
5364 noise_buffer = cpl_malloc(uves_round_double(pos->sg.length + 5)*
sizeof(
double));
5366 check( (signal_to_noise = cpl_table_new(pos->nx),
5367 cpl_table_new_column(signal_to_noise,
"SN", CPL_TYPE_DOUBLE)),
5368 "Error allocating S/N table");
5371 "Error estimating width of order #%d", pos->order);
5378 for (x = 1; x <= pos->nx; x++)
5380 cpl_image_reject(spectrum, x, spectrum_row);
5383 if (spectrum_noise != NULL)
5385 cpl_image_reject(spectrum_noise, x, spectrum_row);
5387 if (optimal_extract_sky && sky_spectrum != NULL)
5389 cpl_image_reject(sky_spectrum , x, spectrum_row);
5390 cpl_image_reject(sky_spectrum_noise, x, spectrum_row);
5397 pos->order, pos->order,
5402 double flux = 0, variance = 0;
5403 double sky_background = 0, sky_background_noise = 0;
5410 bool found_bad_pixel;
5411 double median_noise;
5413 double redchisq = 0;
5422 uves_extract_profile_set(profile, pos, &warnings);
5452 for (pos->y = pos->ylow; pos->y <= pos->yhigh; pos->y++)
5454 if (DATA(image_bpm, pos) == CPL_BINARY_1)
5456 DATA(weights_data, pos) = -1.0;
5460 DATA(weights_data, pos) = 0.0;
5470 found_bad_pixel =
false;
5472 for (iteration = 0; iteration < 2 || found_bad_pixel; iteration++)
5481 optimal_extract_sky,
5486 &sky_background_noise);
5491 check( found_bad_pixel =
5500 optimal_extract_sky ? sky_background : 0,
5506 "Error rejecting outlier pixel");
5511 found_bad_pixel =
false;
5517 if (profile_table != NULL) {
5518 double lin_flux = 0;
5519 for (pos->y = pos->ylow; pos->y <= pos->yhigh; pos->y++) {
5521 if (DATA(weights_data, pos) > 0)
5523 double pixelval = DATA(image_data, pos);
5524 lin_flux += pixelval;
5528 for (pos->y = pos->ylow; pos->y <= pos->yhigh; pos->y++) {
5530 if (DATA(weights_data, pos) > 0)
5532 double dy = pos->y - pos->ycenter;
5533 double pixelval = DATA(image_data, pos);
5536 (cpl_table_set_int (profile_table,
"Order" ,
5537 *prof_row, pos->order),
5538 cpl_table_set_int (profile_table,
"X" ,
5540 cpl_table_set_double(profile_table,
"DY" ,
5542 cpl_table_set_double(profile_table,
"Profile_raw",
5543 *prof_row, pixelval/lin_flux),
5544 cpl_table_set_double(profile_table,
"Profile_int",
5546 uves_extract_profile_evaluate(profile, pos))));
5552 bins_extracted += 1;
5564 SPECTRUM_DATA(cpl_image_get_data_double(spectrum), pos) = flux;
5565 SPECTRUM_DATA(cpl_mask_get_data(cpl_image_get_bpm(spectrum)), pos)
5569 if (spectrum_noise != NULL)
5571 cpl_image_set(spectrum_noise, pos->x, spectrum_row, sqrt(variance));
5576 if (optimal_extract_sky)
5586 cpl_image_set(sky_spectrum , pos->x, spectrum_row,
5587 pos->sg.length * sky_background);
5588 cpl_image_set(sky_spectrum_noise, pos->x, spectrum_row,
5589 pos->sg.length * sky_background_noise);
5596 if (order_width < pos->nx ||
5597 (0.45*pos->nx <= pos->x && pos->x <= 0.55*pos->nx)
5600 cpl_table_set_double(
5601 signal_to_noise,
"SN", sn_row, flux / sqrt(variance));
5606 uves_msg_debug(
"%d/%d hot/cold pixels rejected", hot_pixels, cold_pixels);
5609 check_nomsg( cpl_table_set_size(signal_to_noise, sn_row) );
5612 check_nomsg( *sn = cpl_table_get_column_median(signal_to_noise,
"SN"));
5620 uves_free_table(&signal_to_noise);
5621 cpl_free(noise_buffer);
5623 return bins_extracted;
5652 const double *noise_data,
5653 const double *weights_data,
5654 uves_iterate_position *pos,
5655 const cpl_table *sky_map,
5656 double buffer_flux[],
double buffer_noise[],
5657 double *sky_background_noise)
5659 double sky_background;
5660 bool found_good =
false;
5661 double flux_max = 0;
5662 double flux_min = 0;
5666 for (pos->y = pos->ylow; pos->y <= pos->yhigh; pos->y++)
5668 int row = pos->y - pos->ylow;
5670 if (!ISBAD(weights_data, pos))
5672 double fflux = DATA(image_data, pos);
5673 double noise = DATA(noise_data, pos);
5683 flux_max = uves_max_double(flux_max, fflux);
5684 flux_min = uves_min_double(flux_min, fflux);
5694 if (cpl_table_is_selected(sky_map, row))
5696 buffer_flux [ngood] = fflux;
5697 buffer_noise[ngood] = noise;
5714 *sky_background_noise = avg_noise;
5726 *sky_background_noise = avg_noise / sqrt(ngood * 2 / M_PI);
5734 sky_background = flux_min;
5735 *sky_background_noise = flux_max - flux_min;
5739 if (*sky_background_noise <= 0) *sky_background_noise = 1;
5745 *sky_background_noise = 1;
5750 return sky_background;
5768 uves_iterate_position *pos,
double noise_buffer[])
5770 double median_noise;
5774 for (pos->y = pos->ylow; pos->y <= pos->yhigh; pos->y++)
5776 if (ISGOOD(image_bpm, pos))
5778 noise_buffer[ngood] = DATA(noise_data, pos);
5792 return median_noise;
5872 double *weights_data,
5873 uves_iterate_position *pos,
5874 const uves_extract_profile *profile,
5875 bool optimal_extract_sky,
5876 double median_noise,
5878 double *sky_background,
5879 double *sky_background_noise)
5888 for (pos->y = pos->ylow; pos->y <= pos->yhigh; pos->y++)
5891 if (!ISBAD(weights_data, pos))
5893 double pixel_variance, pixelval, weight;
5894 double prof = uves_extract_profile_evaluate(profile, pos);
5896 pixelval = DATA(image_data, pos);
5897 pixel_variance = DATA(noise_data, pos);
5898 pixel_variance *= pixel_variance;
5900 if (median_noise >= 0 && pixel_variance < median_noise*median_noise)
5904 pixel_variance = median_noise*median_noise;
5907 weight = prof / pixel_variance;
5908 DATA(weights_data, pos) = weight;
5913 sumpfv += pixelval * weight;
5914 sumppv += prof * weight;
5915 if (optimal_extract_sky)
5919 sum1v += 1 / pixel_variance;
5920 sumfv += pixelval / pixel_variance;
5935 if (!optimal_extract_sky)
5938 if (sumppv > 0 && !irplib_isnan(sumppv) && !irplib_isinf(sumppv))
5940 flux = sumpfv / sumppv;
5941 *variance = 1 / sumppv;
5952 long double denominator = (
long double)sum1v*sumppv - (
long double)sumpv*sumpv;
5954 if (fabsl(denominator) > DBL_MIN)
5956 flux = ((
long double)sum1v * sumpfv - (
long double)sumpv * sumfv) / denominator;
5969 *variance = (
long double)sum1v / denominator;
5971 *sky_background = (sumppv*sumfv - sumpv*sumpfv) / denominator;
5972 *sky_background_noise = sqrt(sumppv / denominator);
5979 *sky_background = 0;
5980 *sky_background_noise = 1;
6023 const double *noise_data,
6024 cpl_binary *image_bpm,
6025 double *weights_data,
6026 uves_iterate_position *pos,
6027 const uves_extract_profile *profile,
6030 double sky_background,
6032 cpl_table *cosmic_mask,
6037 bool found_outlier =
false;
6040 double max_residual_sq = 0;
6042 bool outlier_is_hot =
false;
6043 int new_crh_tab_size=0;
6047 for (pos->y = pos->ylow; pos->y <= pos->yhigh; pos->y++)
6049 double prof = uves_extract_profile_evaluate(profile, pos);
6050 double pixel_variance, pixelval;
6053 pixel_variance = DATA(noise_data, pos);
6054 pixel_variance *= pixel_variance;
6056 pixelval = DATA(image_data, pos);
6058 best_fit = flux * prof + sky_background;
6068 if (!ISBAD(weights_data, pos) &&
6072 (pixelval - best_fit)*(pixelval - best_fit) / pixel_variance
6076 (pixelval - best_fit) *
6077 (pixelval - best_fit) / pixel_variance;
6081 outlier_is_hot = (pixelval > best_fit);
6089 if (max_residual_sq > kappa*kappa * red_chisq)
6091 uves_msg_debug(
"Order #%d: Bad pixel at (x, y) = (%d, %d) residual^2 = %.2f sigma^2",
6092 pos->order, pos->x, y_outlier, max_residual_sq);
6095 SETBAD(weights_data, image_bpm, pos);
6097 found_outlier =
true;
6103 crh_tab_size=cpl_table_get_nrow(cosmic_mask);
6104 while (*cr_row >= crh_tab_size )
6106 new_crh_tab_size=( *cr_row > 2*crh_tab_size) ? (*cr_row)+10: 2*crh_tab_size;
6107 cpl_table_set_size(cosmic_mask,new_crh_tab_size );
6108 crh_tab_size=cpl_table_get_nrow(cosmic_mask);
6111 check(( cpl_table_set_int (cosmic_mask,
"Order", *cr_row, pos->order),
6112 cpl_table_set_int (cosmic_mask,
"X" , *cr_row, pos->x),
6113 cpl_table_set_int (cosmic_mask,
"Y" , *cr_row, y_outlier),
6114 cpl_table_set_double(cosmic_mask,
"Flux" , *cr_row,
6115 DATA(image_data, pos)),
6117 "Error updating cosmic ray table");
6127 return found_outlier;
6143 const uves_iterate_position *pos)
6145 if (profile->constant) {
6148 if (profile->f != NULL)
6150 return uves_max_double(1,
6153 profile->red_chisq[pos->order-pos->minorder], pos->x));
6156 profile->red_chisq, pos->x, pos->order));
6191 cpl_table *info_tbl)
6194 int nx = cpl_image_get_size_x(image);
6195 int ny = cpl_image_get_size_y(image);
6196 double max_shift = sg.length/2;
6200 cpl_table *ordertab = NULL;
6201 cpl_table *temp = NULL;
6203 ordertab = cpl_table_new((maxorder - minorder + 1)*nx);
6205 cpl_table_new_column(ordertab,
"X" , CPL_TYPE_INT);
6206 cpl_table_new_column(ordertab,
"Order", CPL_TYPE_INT);
6207 cpl_table_new_column(ordertab,
"Y" , CPL_TYPE_DOUBLE);
6208 cpl_table_new_column(ordertab,
"Yold" , CPL_TYPE_DOUBLE);
6209 cpl_table_new_column(ordertab,
"Sigma", CPL_TYPE_DOUBLE);
6210 cpl_table_set_column_unit(ordertab,
"Y",
"pixels");
6213 for (order = minorder; order <= maxorder; order++) {
6214 for (x = 1 + stepx/2; x <= nx; x += stepx) {
6218 double y_0, sigma, norm, background;
6220 "Error evaluating polynomial");
6222 ylow = uves_round_double(ycenter - max_shift);
6223 yhigh = uves_round_double(ycenter + max_shift);
6225 if (1 <= ylow && yhigh <= ny) {
6226 uves_fit_1d_image(image, image_noise, NULL,
6230 &y_0, &sigma, &norm, &background, NULL,
6234 if (cpl_error_get_code() == CPL_ERROR_CONTINUE) {
6237 "at (x,y) = (%d, %e), ignoring bin",
6241 assure(cpl_error_get_code() == CPL_ERROR_NONE,
6242 cpl_error_get_code(),
"Gaussian fitting failed");
6244 cpl_table_set_int (ordertab,
"X" , ordertab_row, x);
6245 cpl_table_set_int (ordertab,
"Order" , ordertab_row, order);
6246 cpl_table_set_double(ordertab,
"Y" , ordertab_row, y_0);
6247 cpl_table_set_double(ordertab,
"Yold" , ordertab_row, ycenter);
6248 cpl_table_set_double(ordertab,
"Sigma" , ordertab_row, sigma);
6255 cpl_table_set_size(ordertab, ordertab_row);
6258 if (ordertab_row < 300)
6261 "Using calibration solution", ordertab_row);
6266 cpl_table_duplicate_column(ordertab,
"Yfit", ordertab,
"Yold");
6270 int max_degree = 10;
6272 double min_rms = 0.05;
6276 "X",
"Order",
"Y", NULL,
6280 max_degree, max_degree, min_rms, -1,
6282 NULL, NULL, -1, NULL);
6284 if (cpl_error_get_code() == CPL_ERROR_SINGULAR_MATRIX)
6288 "Using calibration solution");
6293 cpl_table_duplicate_column(ordertab,
"Yfit", ordertab,
"Yold");
6299 assure( cpl_error_get_code() == CPL_ERROR_NONE,
6300 cpl_error_get_code(),
6301 "Error fitting orders polynomial");
6306 cpl_table_duplicate_column(ordertab,
"Yshift", ordertab,
"Yfit");
6307 cpl_table_subtract_columns(ordertab,
"Yshift",
"Yold");
6310 double mean = cpl_table_get_column_mean(ordertab,
"Yshift");
6311 double stdev = cpl_table_get_column_mean(ordertab,
"Yshift");
6312 double rms = sqrt(mean*mean + stdev*stdev);
6314 uves_msg(
"Average shift with respect to calibration solution is %.2f pixels", rms);
6318 for (order = minorder; order <= maxorder; order++)
6329 uves_free_table(&temp);
6330 temp = uves_extract_table_rows(ordertab,
"Order",
6335 if (cpl_table_get_nrow(temp) < 1)
6338 "Setting QC FHWM parameter to zero",
6344 fwhm = cpl_table_get_column_median(temp,
"Sigma") * TWOSQRT2LN2;
6348 cpl_table_set_int (info_tbl,
"Order", order - minorder, order);
6349 cpl_table_set_double(info_tbl,
"ObjPosOnSlit" , order - minorder,
6350 pos - (-sg.length/2 + sg.offset));
6351 cpl_table_set_double(info_tbl,
"ObjFwhmAvg" , order - minorder, fwhm);
6355 uves_free_table(&ordertab);
6356 uves_free_table(&temp);
6358 return order_locations;
int uves_polynomial_get_dimension(const polynomial *p)
Get the dimension of a polynomial.
double uves_polynomial_solve_2d(const polynomial *p, double value, double guess, int multiplicity, int varno, double x_value)
Solve p(x1, x2) = value.
#define uves_msg_error(...)
Print an error message.
void uves_polynomial_delete(polynomial **p)
Delete a polynomial.
#define uves_msg_warning(...)
Print an warning message.
cpl_image * uves_define_noise(const cpl_image *image, const uves_propertylist *image_header, int ncom, enum uves_chip chip)
Create noise image.
double uves_pow_int(double x, int y)
Calculate x to the y'th.
#define passure(BOOL,...)
int uves_gauss_derivative(const double x[], const double a[], double result[])
Evaluate the derivatives of a gaussian.
double uves_polynomial_derivative_2d(const polynomial *p, double x1, double x2, int varno)
Evaluate the partial derivative of a 2d polynomial.
uves_propertylist * uves_initialize_image_header(const char *ctype1, const char *ctype2, const char *cunit1, const char *cunit2, const char *bunit, const double bscale, double crval1, double crval2, double crpix1, double crpix2, double cdelt1, double cdelt2)
Initialize image header.
int uves_polynomial_get_degree(const polynomial *p)
Get degree.
#define uves_msg(...)
Print a message on 'info' or 'debug' level.
int uves_gauss(const double x[], const double a[], double *result)
Evaluate a gaussian.
int uves_moffat(const double x[], const double a[], double *result)
Evaluate a Moffat.
polynomial * uves_polynomial_duplicate(const polynomial *p)
Copy a polynomial.
polynomial * uves_polynomial_regression_2d(cpl_table *t, const char *X1, const char *X2, const char *Y, const char *sigmaY, int degree1, int degree2, const char *polynomial_fit, const char *residual_square, const char *variance_fit, double *mse, double *red_chisq, polynomial **variance, double kappa, double min_reject)
Fit a 2d polynomial to three table columns.
polynomial * uves_polynomial_regression_2d_autodegree(cpl_table *t, const char *X1, const char *X2, const char *Y, const char *sigmaY, const char *polynomial_fit, const char *residual_square, const char *variance_fit, double *mean_squared_error, double *red_chisq, polynomial **variance, double kappa, int maxdeg1, int maxdeg2, double min_rms, double min_reject, bool verbose, const double *min_val, const double *max_val, int npos, double positions[][2])
Fit a 2d polynomial to three table columns.
cpl_image * uves_create_image(uves_iterate_position *pos, enum uves_chip chip, const cpl_image *spectrum, const cpl_image *sky, const cpl_image *cosmic_image, const uves_extract_profile *profile, cpl_image **image_noise, uves_propertylist **image_header)
Reconstruct echelle image from spectrum.
double uves_polynomial_evaluate_2d(const polynomial *p, double x1, double x2)
Evaluate a 2d polynomial.
double uves_polynomial_evaluate_1d(const polynomial *p, double x)
Evaluate a 1d polynomial.
double uves_polynomial_get_coeff_1d(const polynomial *p, int degree)
Get a coefficient of a 1D polynomial.
double uves_tools_get_median(double *a, int n)
returns median (not CPL median) of an array
int uves_moffat_derivative(const double x[], const double a[], double result[])
Evaluate Moffat derivative.
polynomial * uves_polynomial_regression_1d(cpl_table *t, const char *X, const char *Y, const char *sigmaY, int degree, const char *polynomial_fit, const char *residual_square, double *mean_squared_error, double kappa)
Fit a 1d polynomial to two table columns.
void uves_polynomial_dump(const polynomial *p, FILE *stream)
Print a polynomial.
const char * uves_tostring_cpl_type(cpl_type t)
Convert a CPL type to a string.
#define uves_error_reset()
#define uves_msg_low(...)
Print a message on a lower message level.
cpl_error_code uves_polynomial_shift(polynomial *p, int varno, double shift)
Shift a polynomial.
#define uves_msg_debug(...)
Print a debug message.
polynomial * uves_polynomial_new_zero(int dim)
Create a zero polynomial.