00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124
00125
00126
00127
00128
00129
00130
00131
00132
00133
00134
00135
00136
00137
00138
00139
00140
00141
00142
00143
00144
00145
00146
00147
00148
00149
00150
00151
00152
00153
00154
00155
00156
00157
00158
00159
00160
00161
00162
00163
00164
00165
00166
00167
00168
00169
00170
00171
00172
00173
00174
00175
00176
00177
00178
00179
00180
00181
00182
00183
00184
00185
00186
00187
00188
00189
00190
00191
00192
00193
00194 #ifdef HAVE_CONFIG_H
00195 # include <config.h>
00196 #endif
00197
00198
00204
00208
00209
00210
00211
00212 #include "uves_reduce.h"
00213
00214 #include <uves.h>
00215 #include <uves_extract.h>
00216 #include <uves_backsub.h>
00217 #include <uves_parameters.h>
00218 #include <uves_flatfield.h>
00219 #include <uves_rebin.h>
00220 #include <uves_merge.h>
00221 #include <uves_utils_cpl.h>
00222 #include <uves_utils_wrappers.h>
00223 #include <uves_pfits.h>
00224 #include <uves_dfs.h>
00225 #include <uves_dump.h>
00226 #include <uves_plot.h>
00227 #include <uves_error.h>
00228
00229 #include <cpl.h>
00230
00231 #include <float.h>
00232
00233
00234
00235
00236
00237 static cpl_error_code
00238 extract_ff_rebin_merge(cpl_image *back_subbed,
00239 cpl_image *backsubbed_noise,
00240 const uves_propertylist *backsubbed_header,
00241 const cpl_image *master_flat,
00242 cpl_image *mflat_noise,
00243 const cpl_table *ordertable,
00244 const polynomial *order_locations,
00245 const cpl_table *linetable,
00246 const uves_propertylist *linetable_header[3],
00247 const polynomial *dispersion_relation[3],
00248 double slit_length,
00249 double slit_offset,
00250 int window,
00251 enum uves_chip chip,
00252 bool blaze_correct,
00253 bool tilt_corr,
00254 bool DEBUG,
00255 const cpl_parameterlist *parameters,
00256 const char *context,
00257 flatfielding_method ff_method,
00258 extract_method ee_method,
00259 merge_method m_method,
00260
00261 cpl_image **x,
00262 uves_propertylist **x_header,
00263 cpl_image **fx,
00264 cpl_table **cosmic_mask,
00265 cpl_image **flatfielded_variance,
00266 uves_propertylist **flatfielded_variance_header,
00267 cpl_image **resampled_spectrum,
00268 cpl_image **resampled_mf,
00269 cpl_image **merged_sky,
00270 cpl_image **rebinned_spectrum,
00271 cpl_image **rebinned_noise,
00272 uves_propertylist **rebinned_header,
00273 cpl_image **merged_spectrum,
00274 cpl_image **merged_noise,
00275 uves_propertylist **merged_header,
00276 cpl_table** info_tbl,
00277 cpl_table **order_trace);
00278
00279 static cpl_image *
00280 subtract_sky(cpl_image *rebinned_obj,
00281 cpl_image *rebinned_obj_noise,
00282 uves_propertylist *rebinned_obj_header,
00283 const cpl_image *rebinned_sky1,
00284 const cpl_image *rebinned_sky1_noise,
00285 const uves_propertylist *rebinned_sky1_header,
00286 const cpl_image *rebinned_sky2,
00287 const cpl_image *rebinned_sky2_noise,
00288 const uves_propertylist *rebinned_sky2_header,
00289 cpl_image **merged_obj,
00290 cpl_image **merged_obj_noise,
00291 uves_propertylist *merged_obj_header,
00292 const cpl_image *merged_sky1,
00293 const cpl_image *merged_sky1_noise,
00294 const uves_propertylist *merged_sky1_header,
00295 const cpl_image *merged_sky2,
00296 const cpl_image *merged_sky2_noise,
00297 const uves_propertylist *merged_sky2_header,
00298 double obj_slit,
00299 double sky1_slit,
00300 double sky2_slit);
00301
00302
00303 static cpl_image *
00304 subtract_sky_row(cpl_image *obj,
00305 cpl_image *obj_noise,
00306 double obj_start,
00307 double obj_end,
00308 double obj_slit,
00309 const cpl_image *sky1,
00310 const cpl_image *sky1_noise,
00311 double sky1_start,
00312 double sky1_end,
00313 double sky1_slit,
00314 const cpl_image *sky2,
00315 const cpl_image *sky2_noise,
00316 double sky2_start,
00317 double sky2_end,
00318 double sky2_slit,
00319 int row,
00320 double wavestep,
00321 double *common_start,
00322 double *common_end);
00323
00324 static double get_offset(const cpl_image *back_subbed,
00325 const cpl_table *ordertable,
00326 const polynomial *order_locations,
00327 double search_range,
00328 int nsamples,
00329 double *doffset);
00330
00331 static cpl_image *
00332 uves_get_blaze_ratio(const cpl_image *spectrum,
00333 const cpl_image *spectrum_noise);
00334
00335
00336
00337
00338
00339
00340
00341
00348
00349
00350 cpl_parameterlist *
00351 uves_reduce_define_parameters(void)
00352 {
00353 const char *name = "";
00354 char *full_name = NULL;
00355 cpl_parameterlist *parameters = NULL;
00356 cpl_parameter *p = NULL;
00357
00358 parameters = cpl_parameterlist_new();
00359
00360
00361
00362
00363 if (cpl_error_get_code() == CPL_ERROR_NONE)
00364 {
00365 uves_propagate_parameters_step(UVES_BACKSUB_ID, parameters,
00366 UVES_REDUCE_ID, NULL);
00367 }
00368
00369
00370
00371
00372
00373 if (cpl_error_get_code() == CPL_ERROR_NONE)
00374 {
00375 uves_propagate_parameters_step(UVES_EXTRACT_ID, parameters,
00376 UVES_REDUCE_ID, NULL);
00377 }
00378
00379
00380
00381
00382 if (cpl_error_get_code() == CPL_ERROR_NONE)
00383 {
00384 name = "slitlength";
00385 full_name = uves_sprintf("%s.%s", UVES_REDUCE_ID, name);
00386
00387 uves_parameter_new_range(p, full_name,
00388 CPL_TYPE_DOUBLE,
00389 "Extraction slit length (in pixels). "
00390 "If negative, the value "
00391 "inferred from the raw frame header is used",
00392 UVES_REDUCE_ID,
00393 -1.0,
00394 -2.0, DBL_MAX);
00395
00396 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, name);
00397 cpl_parameterlist_append(parameters, p);
00398 cpl_free(full_name);
00399 }
00400
00401 if (cpl_error_get_code() == CPL_ERROR_NONE)
00402 {
00403 name = "skysub";
00404 full_name = uves_sprintf("%s.%s", UVES_REDUCE_ID, name);
00405
00406 uves_parameter_new_value(p, full_name,
00407 CPL_TYPE_BOOL,
00408 "Do sky-subtraction (only applicable to linear "
00409 "and average extractions)?",
00410 UVES_REDUCE_ID,
00411 true);
00412
00413 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, name);
00414 cpl_parameterlist_append(parameters, p);
00415 cpl_free(full_name);
00416 }
00417
00418 if (cpl_error_get_code() == CPL_ERROR_NONE)
00419 {
00420 name = "objoffset";
00421 full_name = uves_sprintf("%s.%s", UVES_REDUCE_ID, name);
00422
00423 uves_parameter_new_value(p, full_name,
00424 CPL_TYPE_DOUBLE,
00425 "Offset (in pixels) of extraction slit "
00426 "with respect to center of order. "
00427 "This parameter applies to linear/average/"
00428 "optimal extraction. "
00429 "For linear/average extraction, if the related "
00430 "parameter objslit is negative, the offset is "
00431 "automatically determined by measuring the "
00432 "actual object position. ",
00433 UVES_REDUCE_ID,
00434 0.0);
00435
00436 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, name);
00437 cpl_parameterlist_append(parameters, p);
00438 cpl_free(full_name);
00439 }
00440
00441 if (cpl_error_get_code() == CPL_ERROR_NONE)
00442 {
00443 name = "objslit";
00444 full_name = uves_sprintf("%s.%s", UVES_REDUCE_ID, name);
00445
00446 uves_parameter_new_range(p, full_name,
00447 CPL_TYPE_DOUBLE,
00448 "Object window size (in pixels). This must "
00449 "be less than the total slit length. If "
00450 "negative, the default value (half of full "
00451 "slit length) is used. The upper and lower "
00452 "sky windows are defined as the part of the "
00453 "full slit (if any) outside the object "
00454 "window. The center of the object window "
00455 "is determined by the offset parameter. "
00456 "This parameter does not apply to optimal "
00457 "extraction.",
00458 UVES_REDUCE_ID,
00459 -1.0,
00460 -2.0, DBL_MAX);
00461
00462 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, name);
00463 cpl_parameterlist_append(parameters, p);
00464 cpl_free(full_name);
00465 }
00466
00467 if (cpl_error_get_code() == CPL_ERROR_NONE)
00468 {
00469 name = "tiltcorr";
00470 full_name = uves_sprintf("%s.%s", UVES_REDUCE_ID, name);
00471
00472 uves_parameter_new_value(p, full_name,
00473 CPL_TYPE_BOOL,
00474 "If enabled (recommended), the provided "
00475 "dispersion solutions "
00476 "obtained at different slit positions are "
00477 "interpolated linearly at the actually "
00478 "measured position of the object/sky. "
00479 "Line tilt correction is currently not supported "
00480 "for 2d extraction, in which case the "
00481 "dispersion solution obtained at the middle of "
00482 "the slit is always used.",
00483 UVES_REDUCE_ID,
00484 true);
00485
00486 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, name);
00487 cpl_parameterlist_append(parameters, p);
00488 cpl_free(full_name);
00489 }
00490
00491
00492
00493
00494
00495
00496
00497 if (cpl_error_get_code() == CPL_ERROR_NONE)
00498 {
00499 name = "ffmethod";
00500 full_name = uves_sprintf("%s.%s", UVES_REDUCE_ID, name);
00501
00502 uves_parameter_new_enum(p, full_name,
00503 CPL_TYPE_STRING,
00504 "Flat-fielding method. If set to 'pixel', "
00505 "flat-fielding is done in pixel-pixel space "
00506 "(before extraction); if set to 'extract', "
00507 "flat-fielding is performed in pixel-order "
00508 "space (i.e. after extraction). If set to "
00509 "'no', no flat-field correction is done",
00510 UVES_REDUCE_ID,
00511 "extract",
00512
00513 3,
00514 "pixel", "extract", "no");
00515
00516 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, name);
00517 cpl_parameterlist_append(parameters, p);
00518 cpl_free(full_name);
00519 }
00520
00521
00522
00523
00524
00525 if (cpl_error_get_code() == CPL_ERROR_NONE)
00526 {
00527 name = "blazecorr";
00528 full_name = uves_sprintf("%s.%s", UVES_REDUCE_ID, name);
00529
00530 uves_parameter_new_value(p, full_name,
00531 CPL_TYPE_BOOL,
00532 "(highly experimental, recommended=false) "
00533 "Apply a correction for the different shapes "
00534 "of flat-field and science blaze functions? "
00535 "For this to be possible, flat-fielding method "
00536 "must be different from 'no'.",
00537 UVES_REDUCE_ID,
00538 false);
00539
00540 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, name);
00541 cpl_parameterlist_append(parameters, p);
00542 cpl_free(full_name);
00543 }
00544
00545
00546
00547
00548 if (cpl_error_get_code() == CPL_ERROR_NONE)
00549 {
00550 uves_propagate_parameters_step(UVES_REBIN_ID, parameters,
00551 UVES_REDUCE_ID, NULL);
00552 }
00553
00554
00555
00556
00557
00558 if (cpl_error_get_code() == CPL_ERROR_NONE)
00559 {
00560 name = "merge";
00561 full_name = uves_sprintf("%s.%s", UVES_REDUCE_ID, name);
00562
00563 uves_parameter_new_enum(p, full_name,
00564 CPL_TYPE_STRING,
00565 "Order merging method. If 'optimal', the "
00566 "flux in the overlapping region is set "
00567 "to the (optimally computed, using the "
00568 "uncertainties) average of single order "
00569 "spectra. If 'sum', the flux in the "
00570 "overlapping region is computed as the "
00571 "sum of the single order spectra. If "
00572 "flat-fielding is done, method 'optimal' "
00573 "is recommended, otherwise 'sum'.",
00574 UVES_REDUCE_ID,
00575 "optimal",
00576 2,
00577 "optimal", "sum");
00578
00579 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, name);
00580 cpl_parameterlist_append(parameters, p);
00581 cpl_free(full_name);
00582 }
00583
00584 if (cpl_error_get_code() != CPL_ERROR_NONE)
00585 {
00586 cpl_msg_error(__func__, "Creation of reduction parameters failed: '%s'",
00587 cpl_error_get_where());
00588 cpl_parameterlist_delete(parameters);
00589 return NULL;
00590 }
00591
00592
00593 return parameters;
00594 }
00595
00596
00686
00687
00688 cpl_error_code uves_reduce(const cpl_image *raw_image,
00689 const uves_propertylist *raw_header,
00690 const uves_propertylist *rotated_header,
00691 const cpl_image *master_bias,
00692 const cpl_image *master_dark,
00693 const uves_propertylist *mdark_header,
00694 const cpl_image *master_flat,
00695 const uves_propertylist *mflat_header,
00696 const cpl_table *ordertable,
00697 const polynomial *order_locations,
00698 const cpl_table *linetable[3],
00699 const uves_propertylist *linetable_header[3],
00700 const polynomial *dispersion_relation[3],
00701 enum uves_chip chip,
00702
00703 bool DEBUG,
00704
00705
00706
00707
00708 const cpl_parameterlist *parameters,
00709 const char *context,
00710
00711 cpl_image **x, uves_propertylist **x_header,
00712 cpl_image **fx,
00713 cpl_table **cosmic_mask,
00714 cpl_image **background,
00715 cpl_image **flatfielded_variance,
00716 uves_propertylist **flatfielded_variance_header,
00717 cpl_image **resampled_spectrum,
00718 cpl_image **resampled_mf,
00719 cpl_image **merged_sky,
00720
00721 cpl_image **rebinned_spectrum,
00722 cpl_image **rebinned_noise,
00723 uves_propertylist **rebinned_header,
00724 cpl_image **merged_spectrum ,
00725 cpl_image **merged_noise,
00726 uves_propertylist **merged_header,
00727
00728 cpl_image **reduced_rebinned_spectrum,
00729 cpl_image **reduced_rebinned_noise,
00730 cpl_image **reduced_spectrum ,
00731 cpl_image **reduced_noise,
00732 cpl_table **info_tbl,
00733 double *extraction_slit,
00734 cpl_table **order_trace)
00735 {
00736
00737 flatfielding_method ff_method;
00738 merge_method m_method;
00739 extract_method ex_method;
00740 bool blaze_corr;
00741 bool sky_sub;
00742 bool tilt_corr;
00743 double full_slit;
00744 double obj_slit;
00745 double obj_offset;
00746
00747 cpl_image *back_subbed = NULL;
00748 cpl_image *backsubbed_noise = NULL;
00749
00750 cpl_image *mflat_noise = NULL;
00751
00752 cpl_image *simple_extracted = NULL;
00753 cpl_image *simple_extracted_mf = NULL;
00754
00755 cpl_image *sky_lo = NULL;
00756 cpl_image *sky_lo_noise = NULL;
00757 cpl_image *sky_hi = NULL;
00758 cpl_image *sky_hi_noise = NULL;
00759 uves_propertylist *sky_lo_header = NULL;
00760 uves_propertylist *sky_hi_header = NULL;
00761
00762 cpl_image *sky_lo_rebinned = NULL;
00763 cpl_image *sky_lo_rebinned_noise = NULL;
00764 cpl_image *sky_hi_rebinned = NULL;
00765 cpl_image *sky_hi_rebinned_noise = NULL;
00766 uves_propertylist *sky_lo_rebinned_header = NULL;
00767 uves_propertylist *sky_hi_rebinned_header = NULL;
00768
00769 char *subcontext = NULL;
00770 double header_full_slit;
00771
00772 char *ex_method_string = NULL;
00773
00774
00775 passure( background != NULL, " "); *background = NULL;
00776
00777 passure( rebinned_spectrum != NULL, " "); *rebinned_spectrum = NULL;
00778 passure( rebinned_noise != NULL, " "); *rebinned_noise = NULL;
00779 passure( rebinned_header != NULL, " "); *rebinned_header = NULL;
00780 passure( merged_spectrum != NULL, " "); *merged_spectrum = NULL;
00781 passure( merged_sky != NULL, " "); *merged_sky = NULL;
00782 passure( merged_noise != NULL, " "); *merged_noise = NULL;
00783 passure( merged_header != NULL, " "); *merged_header = NULL;
00784 passure( reduced_rebinned_spectrum != NULL, " "); *reduced_rebinned_spectrum = NULL;
00785 passure( reduced_rebinned_noise != NULL, " "); *reduced_rebinned_noise = NULL;
00786 passure( reduced_spectrum != NULL, " "); *reduced_spectrum = NULL;
00787 passure( reduced_noise != NULL, " "); *reduced_noise = NULL;
00788
00789 passure( (flatfielded_variance == NULL) == (flatfielded_variance_header == NULL),
00790 "%d %d", flatfielded_variance == NULL, flatfielded_variance_header == NULL);
00791
00792 assure_nomsg( extraction_slit != NULL, CPL_ERROR_NULL_INPUT );
00793
00794
00795
00796 {
00797 check( ff_method = uves_get_flatfield_method(parameters, context, UVES_REDUCE_ID),
00798 "Could not read flat-fielding method");
00799
00800 assure( ff_method == FF_NO || master_flat != NULL, CPL_ERROR_NULL_INPUT,
00801 "Flat-fielding requested, but no flat field provided");
00802
00803
00804 check( ex_method = uves_get_extract_method(parameters, context,
00805 UVES_REDUCE_ID "." UVES_EXTRACT_ID),
00806 "Could not get extraction method");
00807
00808 assure( ex_method != EXTRACT_WEIGHTED, CPL_ERROR_ILLEGAL_INPUT,
00809 "Weighted extraction is used only internally, "
00810 "as a part of optimal extraction");
00811
00812 check( m_method = uves_get_merge_method(parameters, context, UVES_REDUCE_ID),
00813 "Could not get merging method");
00814
00815 check( uves_get_parameter(parameters, context, UVES_REDUCE_ID,
00816 "blazecorr", CPL_TYPE_BOOL, &blaze_corr),
00817 "Could not read parameter");
00818
00819 check( uves_get_parameter(parameters, context, UVES_REDUCE_ID,
00820 "skysub", CPL_TYPE_BOOL, &sky_sub),
00821 "Could not read parameter");
00822
00823 check( uves_get_parameter(parameters, context, UVES_REDUCE_ID,
00824 "tiltcorr", CPL_TYPE_BOOL, &tilt_corr),
00825 "Could not read parameter");
00826
00827 assure( !blaze_corr || ff_method != FF_NO, CPL_ERROR_INCOMPATIBLE_INPUT,
00828 "Sorry, cannot apply blaze function "
00829 "correction when no flatfielding is done");
00830
00831 if (blaze_corr && ex_method == EXTRACT_2D)
00832 {
00833 uves_msg_warning("There will be no blaze function correction "
00834 "for 2d extraction");
00835 }
00836
00837 if (ff_method == FF_NO && m_method == MERGE_OPTIMAL)
00838 {
00839 uves_msg_warning("No flat-fielding done, but merge method = optimal. "
00840 "Is this really what you want?");
00841 }
00842 if (ff_method != FF_NO && m_method == MERGE_SUM)
00843 {
00844 uves_msg_warning("Flat-fielding will be done, but merge method = sum. "
00845 "Is this really what you want?");
00846 }
00847
00848 check( uves_get_parameter(parameters, context, UVES_REDUCE_ID, "slitlength",
00849 CPL_TYPE_DOUBLE, &full_slit), "Could not read parameter");
00850
00851 check( uves_get_parameter(parameters, context, UVES_REDUCE_ID, "objoffset",
00852 CPL_TYPE_DOUBLE, &obj_offset),
00853 "Could not read parameter");
00854 check( uves_get_parameter(parameters, context, UVES_REDUCE_ID, "objslit",
00855 CPL_TYPE_DOUBLE, &obj_slit),
00856 "Could not read parameter");
00857 }
00858
00859
00860 subcontext = uves_sprintf("%s.%s", context, UVES_REDUCE_ID);
00861
00862
00863 check( back_subbed = cpl_image_duplicate(raw_image),
00864 "Error copying raw image");
00865
00866 if (master_bias != NULL)
00867 {
00868 uves_msg("Subtracting master bias");
00869 check( uves_subtract_bias(back_subbed, master_bias),
00870 "Error subtracting master bias");
00871 }
00872 else
00873 {
00874 uves_msg("Skipping bias subtraction");
00875 }
00876
00877
00878 if (master_dark != NULL)
00879 {
00880 uves_msg("Subtracting master dark");
00881 check( uves_subtract_dark(back_subbed, raw_header,
00882 master_dark, mdark_header),
00883 "Error subtracting master dark");
00884 }
00885 else
00886 {
00887 uves_msg("Skipping dark subtraction");
00888 }
00889
00890 if (DEBUG) check( uves_save_image_local("Bias/dark subtracted raw image", "pre",
00891 back_subbed, chip, -1, -1, rotated_header, true),
00892 "Error saving image");
00893
00894 uves_msg("Creating noise image");
00895
00896
00897 check( backsubbed_noise = uves_define_noise(back_subbed, raw_header,
00898 1, chip),
00899 "Could not calculate noise image");
00900
00901
00902 if (DEBUG) check( uves_save_image_local("Background subtracted raw image noise",
00903 "errb", backsubbed_noise,
00904 chip, -1, -1, rotated_header, true),
00905 "Error saving image");
00906
00907
00908 uves_msg("Subtracting inter-order background");
00909
00910 check( uves_backsub_spline(back_subbed, raw_header,
00911 ordertable, order_locations,
00912 parameters, subcontext,
00913 chip,
00914 false,
00915 background),
00916 "Error subtracting background");
00917
00918
00919 if (DEBUG) check( uves_save_image_local("Background subtracted raw image", "b",
00920 back_subbed, chip, -1, -1, rotated_header, true),
00921 "Error saving image");
00922
00923
00924
00925
00926 if (ff_method == FF_NO)
00927 {
00928 uves_msg("Skipping flat-field correction");
00929 }
00930
00931 if (ff_method != FF_NO || resampled_mf != NULL)
00932 {
00933 int mflat_datancom;
00934
00935
00936 if (DEBUG)
00937 {
00938 check( uves_save_image_local("Master flat image", "mf",
00939 master_flat,
00940 chip, -1, -1, rotated_header, true),
00941 "Error saving master flat image");
00942 }
00943
00944
00945
00946 check( mflat_datancom = uves_pfits_get_datancom(mflat_header),
00947 "Error reading number of raw flat field frames "
00948 "used for master flat image");
00949
00950 uves_msg("Creating master flat noise image");
00951
00952 check( mflat_noise = uves_define_noise(master_flat, mflat_header,
00953 mflat_datancom, chip),
00954 "Could not define master flat noise");
00955
00956
00957
00958 if (DEBUG)
00959 {
00960 check( uves_save_image_local("Master flat noise", "errmf", mflat_noise,
00961 chip, -1, -1, rotated_header, true),
00962 "Error saving master flat image");
00963 }
00964 }
00965
00966
00967
00968
00969 check( header_full_slit = uves_pfits_get_slitlength_pixels(raw_header, chip),
00970 "Could not read slit length");
00971
00972
00973 if (full_slit < 0)
00974 {
00975
00976
00977
00978 full_slit = uves_max_double(1.0, header_full_slit - 2);
00979 }
00980 else
00981 {
00982
00983 if (full_slit > header_full_slit)
00984 {
00985 uves_msg_warning("Specified full slit length (%e pixels) "
00986 "is larger than input header slit "
00987 "length (%e pixels)",
00988 full_slit, header_full_slit);
00989 }
00990 }
00991
00992 uves_msg("Slit length = %.2f pixels", full_slit);
00993 *extraction_slit = full_slit;
00994
00995 if (ff_method == FF_PIXEL)
00996 {
00997 uves_msg("Dividing by normalized master flat-field (method = pixel)");
00998
00999 check( uves_flatfielding(back_subbed, backsubbed_noise,
01000 master_flat, mflat_noise),
01001 "Could not perform flat-fielding");
01002
01003
01004 if (DEBUG)
01005 {
01006 check( uves_save_image_local("Flat-fielded image", "fb",
01007 back_subbed, chip, -1, -1,
01008 rotated_header, true),
01009 "Error saving flat-fielded image");
01010
01011 check( uves_save_image_local("Flat-fielded image noise", "errfb",
01012 backsubbed_noise, chip, -1, -1,
01013 rotated_header, true),
01014 "Error saving noise of flat-fielded image");
01015 }
01016 }
01017
01018
01019 switch(ex_method)
01020 {
01021 case EXTRACT_OPTIMAL:
01022 {
01023 int window_number = 2;
01024
01025 check( extract_ff_rebin_merge(back_subbed,
01026 backsubbed_noise,
01027 raw_header,
01028 master_flat,
01029 mflat_noise,
01030 ordertable,
01031 order_locations,
01032 linetable[window_number-1],
01033 linetable_header,
01034 dispersion_relation,
01035 full_slit,
01036 obj_offset,
01037 window_number,
01038 chip,
01039 blaze_corr,
01040 tilt_corr,
01041 DEBUG,
01042 parameters,
01043 subcontext,
01044 ff_method,
01045 ex_method,
01046 m_method,
01047 NULL,
01048 NULL,
01049 NULL,
01050 cosmic_mask,
01051 flatfielded_variance,
01052 flatfielded_variance_header,
01053 resampled_spectrum,
01054 resampled_mf,
01055 merged_sky,
01056
01057
01058 rebinned_spectrum,
01059 rebinned_noise,
01060 rebinned_header,
01061 merged_spectrum,
01062 merged_noise,
01063 merged_header,
01064 info_tbl,
01065 order_trace),
01066 "Error during reduction");
01067
01068
01069
01070
01071 check(( *reduced_spectrum = cpl_image_duplicate(*merged_spectrum),
01072 *reduced_noise = cpl_image_duplicate(*merged_noise),
01073 *reduced_rebinned_spectrum = cpl_image_duplicate(*rebinned_spectrum),
01074 *reduced_rebinned_noise = cpl_image_duplicate(*rebinned_noise)),
01075 "Error creating sky-subtracted spectra");
01076 }
01077 break;
01078 case EXTRACT_LINEAR:
01079 case EXTRACT_AVERAGE:
01080 {
01081
01082
01083
01084
01085
01086 const char *slicer_name;
01087 double doffset = 0;
01088 double obj_hi, obj_lo;
01089 double sky_lo_slit, sky_hi_slit;
01090 int window_number;
01091
01092
01093
01094
01095
01096
01097 check( slicer_name = uves_pfits_get_slit1_name(raw_header),
01098 "Could not read slicer id");
01099
01100 uves_msg("Slicer name = '%s'%s", slicer_name,
01101 (strcmp(slicer_name, "FREE") == 0) ? " (no slicer)" : "");
01102
01103 if ( strncmp(slicer_name, "SLIC", 4) == 0)
01104 {
01105
01106
01107
01108
01109 obj_hi = uves_min_double(+full_slit/2, obj_offset + full_slit/2);
01110 obj_lo = uves_max_double(-full_slit/2, obj_offset - full_slit/2);
01111
01112 obj_slit = obj_hi - obj_lo;
01113
01114 sky_lo_slit = -1;
01115 sky_hi_slit = -1;
01116
01117 uves_msg("Extraction slits (full slit = %.2f pixels)", full_slit);
01118 uves_msg("|* Sky 1 *|******** Obj ********|* Sky 2 *|");
01119 uves_msg("|* %-5.1f *|******* %-5.1f *******|* %-5.1f *|",
01120 0.0, obj_slit, 0.0);
01121 }
01122 else
01123 {
01124
01125 assure( strncmp(slicer_name, "FREE", 4) == 0, CPL_ERROR_UNSUPPORTED_MODE,
01126 "Unrecognized slicer name: '%s'. "
01127 "Recognized names include 'FREE', 'SLIC#1', 'SLIC#2', 'SLIC#3'.",
01128 slicer_name);
01129
01130
01131 if (obj_slit < 0)
01132 {
01133 check( obj_offset =
01134 get_offset(back_subbed,
01135 ordertable, order_locations,
01136 full_slit/2,
01137 10,
01138 &doffset),
01139 "Could not find object offset");
01140
01141 uves_msg("Measured object position = %.2f +- %.2f pixels",
01142 obj_offset, doffset);
01143
01144 if (sky_sub)
01145 {
01146
01147
01148 obj_hi = uves_min_double(+full_slit/2,
01149 obj_offset + full_slit/4.0);
01150 obj_lo = uves_max_double(-full_slit/2,
01151 obj_offset - full_slit/4.0);
01152 }
01153 else
01154
01155 {
01156 obj_hi = uves_min_double(+full_slit/2,
01157 obj_offset + full_slit/2.0);
01158 obj_lo = uves_max_double(-full_slit/2,
01159 obj_offset - full_slit/2.0);
01160 }
01161 obj_slit = obj_hi - obj_lo;
01162 }
01163 else
01164
01165 {
01166 uves_msg("Object offset = %.2f pixels", obj_offset);
01167
01168 obj_hi = obj_offset + obj_slit / 2;
01169 obj_lo = obj_offset - obj_slit / 2;
01170 }
01171
01172 uves_msg("Object slit = %.2f pixels", obj_slit);
01173
01174 assure( -full_slit / 2 < obj_offset && obj_offset < full_slit / 2,
01175 CPL_ERROR_ILLEGAL_INPUT,
01176 "Object is outside slit! Offset = %f, Slit length = %f",
01177 obj_offset, full_slit);
01178
01179
01180 if (sky_sub)
01181 {
01182 sky_lo_slit = obj_lo - (-full_slit/2);
01183 sky_hi_slit = full_slit/2 - obj_hi;
01184
01185 assure( sky_lo_slit > 0 || sky_hi_slit > 0, CPL_ERROR_ILLEGAL_INPUT,
01186 "At least one sky slit length must be positive. "
01187 "They are %f and %f pixels", sky_lo_slit, sky_hi_slit);
01188 }
01189 else
01190 {
01191 sky_lo_slit = -1;
01192 sky_hi_slit = -1;
01193 }
01194
01195 uves_msg("Extraction slits (full slit = %.2f pixels)", full_slit);
01196 uves_msg("|*** Sky 1 **%s|**** Obj ****|%s** Sky 2 ***|",
01197 (obj_lo > -obj_hi) ? "*" : "",
01198 (obj_lo > -obj_hi) ? "" : "*");
01199 uves_msg("|*** %-5.1f **%s|*** %-5.1f ***|%s** %-5.1f ***|",
01200 sky_lo_slit, (obj_lo > -obj_hi) ? "*" : "",
01201 obj_slit , (obj_lo > -obj_hi) ? "" : "*",
01202 sky_hi_slit);
01203 }
01204
01205
01206
01207
01208
01209
01210
01211
01212
01213
01214
01215
01216
01217 window_number = 1;
01218 if ( sky_lo_slit > 0 )
01219 {
01220 uves_msg("Processing sky 1 window");
01221 check( extract_ff_rebin_merge(back_subbed,
01222 backsubbed_noise,
01223 raw_header,
01224 master_flat,
01225 mflat_noise,
01226 ordertable,
01227 order_locations,
01228 linetable[2-1],
01229 linetable_header,
01230 dispersion_relation,
01231 sky_lo_slit,
01232 -full_slit/2 + sky_lo_slit/2,
01233
01234 window_number,
01235 chip,
01236 blaze_corr,
01237 tilt_corr,
01238 DEBUG,
01239 parameters,
01240 subcontext,
01241 ff_method,
01242 ex_method,
01243 m_method,
01244 NULL,
01245 NULL,
01246 NULL,
01247 NULL,
01248 NULL,
01249 NULL,
01250 NULL,
01251 NULL,
01252 NULL,
01253 &sky_lo_rebinned,
01254 &sky_lo_rebinned_noise,
01255 &sky_lo_rebinned_header,
01256 &sky_lo,
01257 &sky_lo_noise,
01258 &sky_lo_header,
01259 NULL,
01260 NULL),
01261 "Error processing lower sky window");
01262 }
01263 else
01264 {
01265 uves_msg("Skipping sky 1 window");
01266 sky_lo_rebinned = NULL;
01267 sky_lo = NULL;
01268 }
01269
01270
01271 window_number = 3;
01272 if ( sky_hi_slit > 0 )
01273 {
01274 uves_msg("Processing sky 2 window");
01275
01276 uves_free_propertylist(rebinned_header);
01277 check( extract_ff_rebin_merge(back_subbed,
01278 backsubbed_noise,
01279 raw_header,
01280 master_flat,
01281 mflat_noise,
01282 ordertable,
01283 order_locations,
01284 linetable[2-1],
01285 linetable_header,
01286 dispersion_relation,
01287 sky_hi_slit,
01288 full_slit/2 - sky_hi_slit/2,
01289
01290 window_number,
01291 chip,
01292 blaze_corr,
01293 tilt_corr,
01294 DEBUG,
01295 parameters,
01296 subcontext,
01297 ff_method,
01298 ex_method,
01299 m_method,
01300 NULL,
01301 NULL,
01302 NULL,
01303 NULL,
01304 NULL,
01305 NULL,
01306 NULL,
01307 NULL,
01308 NULL,
01309 &sky_hi_rebinned,
01310 &sky_hi_rebinned_noise,
01311 &sky_hi_rebinned_header,
01312 &sky_hi,
01313 &sky_hi_noise,
01314 &sky_hi_header,
01315 NULL,
01316 NULL),
01317 "Error processing upper sky window");
01318 }
01319 else
01320 {
01321 uves_msg("Skipping sky 2 window");
01322 sky_hi_rebinned = NULL;
01323 sky_hi = NULL;
01324 }
01325
01326
01327 window_number = 2;
01328 uves_msg("Processing object window");
01329 uves_free_propertylist(rebinned_header);
01330 check( extract_ff_rebin_merge(back_subbed, backsubbed_noise, raw_header,
01331 master_flat, mflat_noise,
01332 ordertable, order_locations,
01333 linetable[window_number-1],
01334 linetable_header,
01335 dispersion_relation,
01336 obj_slit,
01337 obj_offset,
01338
01339 window_number,
01340 chip,
01341 blaze_corr,
01342 tilt_corr,
01343 DEBUG,
01344 parameters,
01345 subcontext,
01346 ff_method,
01347 ex_method,
01348 m_method,
01349 NULL,
01350 NULL,
01351 NULL,
01352 NULL,
01353 flatfielded_variance,
01354 flatfielded_variance_header,
01355 resampled_spectrum,
01356 resampled_mf,
01357 NULL,
01358 rebinned_spectrum,
01359 rebinned_noise,
01360 rebinned_header,
01361 merged_spectrum,
01362 merged_noise,
01363 merged_header,
01364 info_tbl,
01365 NULL),
01366 "Error processing object window");
01367
01368 if (info_tbl != NULL && *info_tbl != NULL)
01369 {
01370
01371
01372 int i;
01373 for (i = 0; i < cpl_table_get_nrow(*info_tbl); i++)
01374 {
01375 cpl_table_set_double(*info_tbl, "Pos", i,
01376 cpl_table_get_double(*info_tbl, "Pos", i, NULL)
01377 +
01378 ((sky_lo_slit >= 0) ? sky_lo_slit : 0));
01379
01380 }
01381 }
01382
01383
01384
01385
01386
01387
01388
01389 check(( *reduced_spectrum = cpl_image_duplicate(*merged_spectrum),
01390 *reduced_noise = cpl_image_duplicate(*merged_noise)),
01391 "Error allocating sky-subtracted spectra");
01392
01393
01394 check(( *reduced_rebinned_spectrum =
01395 cpl_image_duplicate(*rebinned_spectrum),
01396 *reduced_rebinned_noise =
01397 cpl_image_duplicate(*rebinned_noise)),
01398 "Error allocating sky-subtracted spectra");
01399
01400 if (sky_lo != NULL || sky_hi != NULL)
01401 {
01402 uves_msg("Subtracting sky");
01403
01404 check( *merged_sky =
01405 subtract_sky(*reduced_rebinned_spectrum,
01406 *reduced_rebinned_noise, *rebinned_header,
01407 sky_lo_rebinned, sky_lo_rebinned_noise,
01408 sky_lo_rebinned_header,
01409 sky_hi_rebinned, sky_hi_rebinned_noise,
01410 sky_hi_rebinned_header,
01411 reduced_spectrum, reduced_noise, *merged_header,
01412 sky_lo, sky_lo_noise, sky_lo_header,
01413 sky_hi, sky_hi_noise, sky_hi_header,
01414 (ex_method == EXTRACT_AVERAGE) ? 1.0 : obj_slit,
01415 (ex_method == EXTRACT_AVERAGE) ? 1.0 : sky_lo_slit,
01416 (ex_method == EXTRACT_AVERAGE) ? 1.0 : sky_hi_slit),
01417 "Could not subtract sky");
01418
01419 if (*merged_sky == NULL)
01420 {
01421 uves_msg_warning("Could not subtract sky");
01422 }
01423 }
01424 else
01425 {
01426 uves_msg_low("Skipping sky subtraction");
01427
01428
01429 *merged_sky = NULL;
01430 }
01431 }
01432 break;
01433 case EXTRACT_2D:
01434 {
01435 int window_number = 2;
01436
01437
01438 int half_slit_length;
01439
01440
01441
01442 half_slit_length =
01443 uves_max_int(1, uves_round_double(header_full_slit/2) - 1);
01444
01445 check( extract_ff_rebin_merge(back_subbed,
01446 backsubbed_noise,
01447 raw_header,
01448 master_flat,
01449 mflat_noise,
01450 ordertable,
01451 order_locations,
01452 linetable[window_number-1],
01453 linetable_header,
01454 dispersion_relation,
01455 2*half_slit_length,
01456 0,
01457 window_number,
01458 chip,
01459 blaze_corr,
01460 tilt_corr,
01461 DEBUG,
01462 parameters,
01463 subcontext,
01464 ff_method,
01465 ex_method,
01466 m_method,
01467 x,
01468 x_header,
01469 fx,
01470 NULL,
01471 NULL,
01472 NULL,
01473 NULL,
01474
01475 NULL,
01476 NULL,
01477
01478 rebinned_spectrum,
01479 rebinned_noise,
01480 rebinned_header,
01481 merged_spectrum,
01482 merged_noise,
01483 merged_header,
01484 info_tbl,
01485 NULL),
01486 "Error during reduction");
01487
01488 if (x_header != NULL)
01489 {
01490 uves_pfits_set_hs(*x_header,
01491 uves_round_double(2*half_slit_length));
01492 }
01493 if (rebinned_header != NULL)
01494 {
01495 uves_pfits_set_hs(*rebinned_header,
01496 uves_round_double(2*half_slit_length));
01497 }
01498 if (merged_header != NULL)
01499 {
01500 uves_pfits_set_hs(*merged_header,
01501 uves_round_double(2*half_slit_length));
01502 }
01503
01504
01505
01506
01507
01508 check(( *reduced_spectrum = cpl_image_duplicate(*merged_spectrum),
01509 *reduced_noise = cpl_image_duplicate(*merged_noise),
01510 *reduced_rebinned_spectrum = cpl_image_duplicate(*rebinned_spectrum),
01511 *reduced_rebinned_noise = cpl_image_duplicate(*rebinned_noise)),
01512 "Error allocating reduced spectra");
01513 }
01514 break;
01515 default:
01516 assure( false, CPL_ERROR_ILLEGAL_INPUT,
01517 "Unknown extraction method: %d", ex_method);
01518 break;
01519 }
01520
01521 cleanup:
01522 uves_free_image(&back_subbed);
01523 uves_free_image(&backsubbed_noise);
01524 uves_free_image(&mflat_noise);
01525 uves_free_image(&simple_extracted);
01526 uves_free_image(&simple_extracted_mf);
01527 uves_free_image(&sky_lo);
01528 uves_free_image(&sky_lo_noise);
01529 uves_free_image(&sky_hi);
01530 uves_free_image(&sky_hi_noise);
01531 uves_free_image(&sky_lo_rebinned);
01532 uves_free_image(&sky_lo_rebinned_noise);
01533 uves_free_image(&sky_hi_rebinned);
01534 uves_free_image(&sky_hi_rebinned_noise);
01535 uves_free_propertylist(&sky_lo_header);
01536 uves_free_propertylist(&sky_hi_header);
01537 uves_free_propertylist(&sky_lo_rebinned_header);
01538 uves_free_propertylist(&sky_hi_rebinned_header);
01539
01540 cpl_free(subcontext);
01541 cpl_free(ex_method_string);
01542
01543 if (cpl_error_get_code() != CPL_ERROR_NONE)
01544 {
01545 uves_free_image(background);
01546 uves_free_image(flatfielded_variance);
01547 uves_free_propertylist(flatfielded_variance_header);
01548 uves_free_image(resampled_spectrum);
01549 uves_free_image(resampled_mf);
01550 uves_free_image(merged_sky);
01551 uves_free_image(rebinned_spectrum);
01552 uves_free_image(rebinned_noise);
01553 uves_free_propertylist(rebinned_header);
01554
01555 uves_free_image(merged_noise);
01556 uves_free_image(merged_spectrum);
01557 uves_free_propertylist(merged_header);
01558 }
01559
01560 return cpl_error_get_code();
01561 }
01562
01563
01564
01574
01575 static polynomial *
01576 interpolate_wave(const polynomial *dispersion_relation[3],
01577 const uves_propertylist *linetable_header[3],
01578 double objoffset)
01579 {
01580 polynomial *dispersion = NULL;
01581 polynomial *q1 = NULL;
01582 polynomial *q2 = NULL;
01583 cpl_table *offset = cpl_table_new(3);
01584 int ilow, ihigh;
01585 double offset1, offset2;
01586
01587
01588 cpl_table_new_column(offset, "Index", CPL_TYPE_INT);
01589 cpl_table_new_column(offset, "Offset", CPL_TYPE_DOUBLE);
01590
01591 {
01592 int i;
01593 bool reverse;
01594 for (i = 0; i < 3; i++) {
01595 cpl_table_set_int(offset, "Index", i, i);
01596 cpl_table_set_double(offset, "Offset", i,
01597 uves_pfits_get_offset(linetable_header[i]));
01598
01599 uves_msg_debug("Wavecal %d offset is %f pixels", i,
01600 cpl_table_get_double(offset, "Offset", i, NULL));
01601 }
01602
01603 reverse = false;
01604 uves_sort_table_1(offset, "Offset", reverse);
01605 }
01606
01607
01608 if (objoffset <= cpl_table_get_double(offset, "Offset", 1, NULL))
01609 {
01610 ilow = cpl_table_get_int(offset, "Index", 0, NULL);
01611 ihigh = cpl_table_get_int(offset, "Index", 1, NULL);
01612 offset1 = cpl_table_get_double(offset, "Offset", 0, NULL);
01613 offset2 = cpl_table_get_double(offset, "Offset", 1, NULL);
01614 }
01615 else
01616 {
01617 ilow = cpl_table_get_int(offset, "Index", 1, NULL);
01618 ihigh = cpl_table_get_int(offset, "Index", 2, NULL);
01619 offset1 = cpl_table_get_double(offset, "Offset", 1, NULL);
01620 offset2 = cpl_table_get_double(offset, "Offset", 2, NULL);
01621 }
01622
01623 uves_msg("Interpolating dispersion relation at offset = %.2f",
01624 objoffset);
01625
01626 uves_msg_debug("Using previous solutions at %.2f and %.2f pixels",
01627 offset1, offset2);
01628
01629
01630
01631 assure( offset1 < offset2,
01632 CPL_ERROR_DIVISION_BY_ZERO,
01633 "Dispersion solution %d offset = %.2f pixels; "
01634 "dispersion solution %d offset = %.2f pixels; cannot extrapolate",
01635 ilow, offset1,
01636 ihigh, offset2);
01637
01638
01639
01640
01641
01642
01643
01644
01645
01646
01647
01648
01649 {
01650 double a = (offset2 - objoffset) / (offset2 - offset1);
01651 double b = (offset1 - objoffset) / (offset1 - offset2);
01652
01653 q1 = uves_polynomial_duplicate(dispersion_relation[ilow]);
01654 uves_polynomial_rescale(q1, 0, a);
01655
01656
01657 q2 = uves_polynomial_duplicate(dispersion_relation[ihigh]);
01658 uves_polynomial_rescale(q2, 0, b);
01659
01660
01661 dispersion = uves_polynomial_add_2d(q1, q2);
01662 }
01663
01664 cleanup:
01665 uves_free_table(&offset);
01666 uves_polynomial_delete(&q1);
01667 uves_polynomial_delete(&q2);
01668 return dispersion;
01669 }
01670
01671
01672
01751
01752
01753 static cpl_error_code
01754 extract_ff_rebin_merge(cpl_image *back_subbed,
01755 cpl_image *backsubbed_noise,
01756 const uves_propertylist *backsubbed_header,
01757 const cpl_image *master_flat,
01758 cpl_image *mflat_noise,
01759 const cpl_table *ordertable,
01760 const polynomial *order_locations,
01761 const cpl_table *linetable,
01762 const uves_propertylist *linetable_header[3],
01763 const polynomial *dispersion_relation[3],
01764 double slit_length,
01765 double slit_offset,
01766 int window,
01767 enum uves_chip chip,
01768 bool blaze_correct,
01769 bool tilt_corr,
01770 bool DEBUG,
01771 const cpl_parameterlist *parameters,
01772 const char *context,
01773 flatfielding_method ff_method,
01774 extract_method ex_method,
01775 merge_method m_method,
01776
01777 cpl_image **x, uves_propertylist **x_header,
01778 cpl_image **fx,
01779 cpl_table **cosmic_mask,
01780 cpl_image **flatfielded_variance,
01781 uves_propertylist **flatfielded_variance_header,
01782 cpl_image **resampled_spectrum,
01783 cpl_image **resampled_mf,
01784 cpl_image **merged_sky,
01785 cpl_image **rebinned_spectrum,
01786 cpl_image **rebinned_noise,
01787 uves_propertylist **rebinned_header,
01788 cpl_image **merged_spectrum,
01789 cpl_image **merged_noise,
01790 uves_propertylist **merged_header,
01791 cpl_table **info_tbl,
01792 cpl_table **order_trace)
01793 {
01794 cpl_image *extracted = NULL;
01795 cpl_image *extracted_noff = NULL;
01796 cpl_image *extracted_noise = NULL;
01797 cpl_image *extracted_sky = NULL;
01798 cpl_image *extracted_sky_noise = NULL;
01799 cpl_image *blaze_ratio = NULL;
01800
01801
01802 cpl_image *cosmic_image = NULL;
01803 cpl_image *weights = NULL;
01804 cpl_table *profile_table = NULL;
01805 uves_propertylist *extracted_header = NULL;
01806
01807 cpl_image *extracted_mf = NULL;
01808 cpl_image *extracted_mf_noise = NULL;
01809
01810 cpl_image *rebinned_sky = NULL;
01811 cpl_image *rebinned_sky_noise = NULL;
01812 cpl_image *merged_sky_noise = NULL;
01813
01814 polynomial *dispersion_int = NULL;
01815 polynomial *dispersion_int_sky = NULL;
01816
01817
01818
01819 cpl_table *poly_table = NULL;
01820 cpl_image *temp_image = NULL;
01821
01822 int n_traces;
01823
01824 int first_abs_order, last_abs_order;
01825 int filename_window;
01826
01827
01828
01829
01830 passure((ff_method != FF_EXTRACT && resampled_mf == NULL)
01831 ||
01832 master_flat != NULL, " ");
01833
01834
01835
01836 passure( !blaze_correct || ff_method != FF_NO, " ");
01837
01838 passure( ex_method != EXTRACT_OPTIMAL || merged_sky != NULL, " ");
01839 passure( ex_method != EXTRACT_OPTIMAL || cosmic_mask != NULL, " ");
01840
01841 passure(1 <= window && window <= 3, "Illegal window: %d", window);
01842
01843 passure( (x == NULL) == (x_header == NULL) &&
01844 (x == NULL) == (fx == NULL), " ");
01845
01846 if (ex_method == EXTRACT_OPTIMAL || ex_method == EXTRACT_2D)
01847 {
01848
01849
01850
01851
01852
01853
01854 filename_window = -1;
01855
01856 }
01857 else
01858 {
01859 filename_window = window;
01860 }
01861
01862 n_traces = (ex_method == EXTRACT_2D) ? uves_round_double(slit_length) : 1;
01863
01864 check( first_abs_order = uves_pfits_get_firstabsorder(linetable_header[0]),
01865 "Could not read order numbers from line table header");
01866 check( last_abs_order = uves_pfits_get_lastabsorder (linetable_header[0]),
01867 "Could not read order numbers from line table header");
01868
01869 if (window == 2)
01870 {
01871 uves_msg("Extracting object");
01872 }
01873
01874 check( extracted =
01875 uves_extract(back_subbed,
01876 backsubbed_noise,
01877 backsubbed_header,
01878 ordertable,
01879 order_locations,
01880 slit_length,
01881 slit_offset,
01882 parameters,
01883 context,
01884 false,
01885 DEBUG,
01886 chip,
01887 &extracted_header,
01888 &extracted_noise,
01889
01890 &extracted_sky,
01891 &extracted_sky_noise,
01892 cosmic_mask,
01893 &cosmic_image,
01894 (DEBUG) ?
01895 &profile_table : NULL,
01896 &weights,
01897
01898 info_tbl,
01899 order_trace),
01900 "Error extracting spectrum");
01901
01902 if (x != NULL) {
01903 *x = cpl_image_duplicate(extracted);
01904 *x_header = uves_propertylist_duplicate(extracted_header);
01905 }
01906
01907 if (ex_method == EXTRACT_OPTIMAL) {
01908 uves_msg_low("%d hot pixels were detected during optimal extraction",
01909 cpl_table_get_nrow(*cosmic_mask));
01910
01911 if (cpl_table_get_nrow(*cosmic_mask) > 0) {
01912 check( uves_plot_table(*cosmic_mask, "X", "Y",
01913 "%d hot/cold pixels",
01914 cpl_table_get_nrow(*cosmic_mask)),
01915 "Plotting failed");
01916 }
01917 }
01918
01919
01920
01921 if (DEBUG) {
01922
01923
01924
01925
01926 check( uves_save_image_local((ff_method == FF_PIXEL) ?
01927 "Extracted, flatfielded spectrum" :
01928 "Extracted spectrum",
01929 (ff_method == FF_PIXEL) ?
01930 "xfb" : "xb",
01931 extracted, chip, -1,
01932 filename_window, extracted_header, true),
01933 "Error saving extracted%s spectrum",
01934 (ff_method == FF_PIXEL) ? ", flatfielded" : "");
01935
01936 check( uves_save_image_local((ff_method == FF_PIXEL) ?
01937 "Extracted, flatfielded spectrum noise" :
01938 "Extracted spectrum noise",
01939 (ff_method == FF_PIXEL) ?
01940 "errxfb" : "errxb",
01941 extracted_noise, chip, -1,
01942 filename_window, extracted_header, true),
01943 "Error saving noise of extracted%s spectrum",
01944 (ff_method == FF_PIXEL) ? ", flatfielded" : "");
01945
01946 if (extracted_sky != NULL)
01947 {
01948 check( uves_save_image_local((ff_method == FF_PIXEL) ?
01949 "Extracted, flatfielded sky" :
01950 "Extracted sky",
01951 (ff_method == FF_PIXEL) ?
01952 "xfsky" : "xsky",
01953 extracted_sky, chip, -1,
01954 filename_window, extracted_header, true),
01955 "Error saving extracted%s sky",
01956 (ff_method == FF_PIXEL) ? ", flatfielded" : "");
01957
01958 check( uves_save_image_local((ff_method == FF_PIXEL) ?
01959 "Noise of extracted, flatfielded sky" :
01960 "Noise of extracted sky",
01961 (ff_method == FF_PIXEL) ?
01962 "errxfsky" : "errxsky",
01963 extracted_sky_noise, chip, -1,
01964 filename_window, extracted_header, true),
01965 "Error saving extracted%s sky noise",
01966 (ff_method == FF_PIXEL) ? ", flatfielded" : "");
01967 }
01968
01969 if (ex_method == EXTRACT_OPTIMAL)
01970 {
01971 check( uves_save_image_local("Optimal extraction weights",
01972 "weights",
01973 weights, chip, -1,
01974 filename_window, NULL, true),
01975 "Error saving weights map");
01976
01977 check( uves_save_table_local("Cosmic ray table", "crmask",
01978 *cosmic_mask, chip, -1,
01979 filename_window, NULL, NULL),
01980 "Error saving cosmic ray mask");
01981
01982 check( uves_save_image_local("Cosmic ray image", "crimage",
01983 cosmic_image, chip, -1,
01984 filename_window, NULL, true),
01985 "Error saving cosmic ray mask");
01986
01987 if (profile_table != NULL)
01988 {
01989 check( uves_save_table_local("Profile table", "profile",
01990 profile_table, chip, -1,
01991 filename_window, NULL, NULL),
01992 "Error saving profile table");
01993 }
01994 }
01995 }
01996
01997
01998 if (master_flat != NULL && (ff_method == FF_EXTRACT || resampled_mf != NULL))
01999 {
02000 uves_msg("Extracting master flat field");
02001
02002
02003
02004
02005
02006 if (ex_method == EXTRACT_OPTIMAL)
02007 {
02008 const char *temp_method = "weighted";
02009
02010
02011
02012
02013
02014
02015 check( uves_set_parameter((cpl_parameterlist *) parameters,
02016 context, UVES_EXTRACT_ID ".method",
02017 CPL_TYPE_STRING, &temp_method),
02018 "Error setting extraction method to '%s'", temp_method);
02019 }
02020
02021 check( extracted_mf =
02022 uves_extract((cpl_image *)master_flat,
02023
02024
02025
02026 mflat_noise,
02027 NULL,
02028 ordertable,
02029 order_locations,
02030 slit_length,
02031 slit_offset,
02032 parameters, context,
02033
02034 false,
02035 DEBUG,
02036 chip,
02037 NULL,
02038 &extracted_mf_noise,
02039 NULL,
02040 NULL,
02041 NULL,
02042 NULL,
02043 NULL,
02044
02045 &weights,
02046 NULL,
02047 NULL),
02048 "Error extracting master flat spectrum");
02049
02050
02051
02052 if (ex_method == EXTRACT_OPTIMAL) {
02053 const char *method = "optimal";
02054
02055
02056
02057 check( uves_set_parameter((cpl_parameterlist *) parameters,
02058 context, UVES_EXTRACT_ID ".method",
02059 CPL_TYPE_STRING, &method),
02060 "Error resetting extraction method to '%s'", method);
02061 }
02062
02063 if (DEBUG) {
02064 double ff_mean;
02065
02066
02067 uves_free_image(&temp_image);
02068
02069 ff_mean = cpl_image_get_mean(extracted_mf);
02070
02071 check( temp_image =
02072 cpl_image_divide_scalar_create(extracted_mf, ff_mean),
02073 "Could not normalize master flat spectrum");
02074
02075 check( uves_save_image_local("Normalized master flat spectrum",
02076 "xmf",
02077 temp_image, chip, -1,
02078 filename_window, extracted_header, true),
02079 "Error saving image");
02080
02081
02082 uves_free_image(&temp_image);
02083 check( temp_image =
02084 cpl_image_divide_scalar_create(extracted_mf_noise,
02085 ff_mean),
02086 "Could not rescale master flat noise spectrum");
02087
02088 check( uves_save_image_local("Noise of normalized "
02089 "master flat spectrum", "errxmf",
02090 temp_image, chip, -1,
02091 filename_window, extracted_header, true),
02092 "Error saving image");
02093
02094 uves_free_image(&temp_image);
02095 }
02096
02097
02098 if (resampled_mf != NULL) {
02099 uves_msg("Rebinning master flat spectrum");
02100
02101
02102
02103
02104
02105
02106 check( *resampled_mf = uves_rebin(extracted_mf,
02107 parameters, context,
02108 linetable,
02109 dispersion_relation[1],
02110 first_abs_order,
02111 last_abs_order,
02112 n_traces,
02113 false,
02114 rebinned_header),
02115 "Error resampling master flat");
02116
02117 if (DEBUG) {
02118 check( uves_save_image_local("Resampled master flat spectrum",
02119 "wxmf", *resampled_mf, chip, -1,
02120 filename_window, *rebinned_header, true),
02121 "Error saving image");
02122 }
02123 }
02124 }
02125
02126
02127 if (ff_method == FF_EXTRACT)
02128 {
02129 uves_msg("Dividing by normalized master flat-field (method = extract)");
02130
02131
02132 extracted_noff = cpl_image_duplicate(extracted);
02133
02134 check( uves_flatfielding(extracted , extracted_noise,
02135 extracted_mf, extracted_mf_noise),
02136 "Could not perform flat-fielding");
02137
02138 if (extracted_sky != NULL)
02139 {
02140 check( uves_flatfielding(extracted_sky, extracted_sky_noise,
02141 extracted_mf, extracted_mf_noise),
02142 "Could not perform flat-fielding");
02143 }
02144
02145
02146 if (DEBUG)
02147 {
02148 check( uves_save_image_local("Flat-fielded spectrum", "fxb",
02149 extracted, chip, -1, filename_window,
02150 extracted_header, true),
02151 "Error saving image");
02152
02153 check( uves_save_image_local("Flat-fielded spectrum noise",
02154 "errfxb", extracted_noise, chip,
02155 -1, filename_window, extracted_header, true),
02156 "Error saving noise of flat-fielded image");
02157 }
02158
02159 if (DEBUG && extracted_sky != NULL)
02160 {
02161 check( uves_save_image_local("Flat-fielded sky", "fxsky",
02162 extracted_sky, chip, -1,
02163 filename_window, extracted_header, true),
02164 "Error saving image");
02165
02166 check( uves_save_image_local("Flat-fielded sky noise", "errfxsky",
02167 extracted_sky_noise, chip, -1,
02168 filename_window, extracted_header, true),
02169 "Error saving noise of flat-fielded image");
02170 }
02171 }
02172
02173 if (fx != NULL)
02174 {
02175 *fx = cpl_image_duplicate(extracted);
02176 }
02177
02178
02179
02180 if (flatfielded_variance != NULL)
02181 {
02182
02183 check( *flatfielded_variance =
02184 cpl_image_multiply_create(extracted_noise,
02185 extracted_noise),
02186 "Error creating variance of flatfielded spectrum");
02187
02188 passure(flatfielded_variance_header != NULL, " ");
02189 check( *flatfielded_variance_header =
02190 uves_propertylist_duplicate(extracted_header),
02191 "Could not copy extracted spectrum header");
02192 }
02193
02194 if (blaze_correct)
02195 {
02196 if (ex_method == EXTRACT_2D)
02197 {
02198
02199 uves_msg_low("Skipping blaze function correction for 2d extraction mode");
02200 }
02201 else
02202 {
02203 uves_msg("Calculating blaze function correction");
02204
02205 check( blaze_ratio = uves_get_blaze_ratio(extracted, extracted_noise),
02206 "Error calculating blaze function correction");
02207
02208 uves_msg("Applying blaze function correction");
02209
02210 check(( cpl_image_divide(extracted , blaze_ratio),
02211 cpl_image_divide(extracted_noise, blaze_ratio)),
02212 "Error applying blaze function correction");
02213
02214 if (extracted_sky != NULL)
02215 {
02216 check(( cpl_image_multiply(extracted_sky, blaze_ratio),
02217 cpl_image_multiply(extracted_sky_noise, blaze_ratio)),
02218 "Error applying blaze function correction");
02219 }
02220 }
02221 }
02222
02223
02224 uves_msg("Rebinning spectrum");
02225 if (ex_method == EXTRACT_2D) {
02226 if (tilt_corr) {
02227 uves_msg_warning("Line tilt correction in rebinning "
02228 "of 2d spectra is unsupported");
02229 }
02230 dispersion_int = uves_polynomial_duplicate(dispersion_relation[window-1]);
02231 }
02232 else if (tilt_corr) {
02233 double objoffset;
02234
02235 if (info_tbl != NULL) {
02236 objoffset = cpl_table_get_column_median(*info_tbl, "Pos");
02237
02238
02239
02240
02241
02242 uves_msg_debug("Object position (from bottom of extraction window) = %.2f pixels",
02243 objoffset);
02244
02245 objoffset -= slit_length / 2;
02246
02247
02248 objoffset += slit_offset;
02249
02250
02251 uves_msg_debug("Object position (from slit center) = %.2f pixels",
02252 objoffset);
02253 }
02254 else {
02255
02256 uves_msg_debug("Object offset not measured during extraction, "
02257 "using %.2f pixels", slit_offset);
02258 objoffset = slit_offset;
02259 }
02260
02261 check( dispersion_int = interpolate_wave(dispersion_relation,
02262 linetable_header,
02263 objoffset),
02264 "Could not interpolate dispersion solutions");
02265
02266 if (DEBUG) {
02267 check( poly_table = uves_polynomial_convert_to_table(dispersion_int),
02268 "Error converting polynomial to table");
02269
02270 check( uves_save_table_local("Interpolated dispersion relation",
02271 "intdisp",
02272 poly_table, chip, -1,
02273 filename_window, NULL, NULL),
02274 "Error saving interpolated dispersion solution");
02275 }
02276 }
02277 else {
02278 dispersion_int = uves_polynomial_duplicate(dispersion_relation[window-1]);
02279 }
02280
02281 uves_free_propertylist(rebinned_header);
02282 check( *rebinned_spectrum = uves_rebin(extracted,
02283 parameters, context,
02284 linetable, dispersion_int,
02285 first_abs_order,
02286 last_abs_order,
02287 n_traces,
02288 false,
02289 rebinned_header),
02290 "Could not rebin spectrum");
02291
02292 uves_msg("Rebinning spectrum noise");
02293
02294
02295
02296
02297
02298
02299
02300
02301 {
02302 bool threshold_to_positive = true;
02303
02304 uves_free_propertylist(rebinned_header);
02305 check( *rebinned_noise = uves_rebin(extracted_noise,
02306 parameters, context,
02307 linetable, dispersion_int,
02308 first_abs_order,
02309 last_abs_order,
02310 n_traces,
02311 threshold_to_positive,
02312 rebinned_header),
02313 "Could not rebin spectrum noise");
02314 }
02315
02316 if (extracted_sky != NULL) {
02317 uves_msg("Rebinning sky spectrum");
02318
02319 if (tilt_corr) {
02320
02321
02322
02323
02324
02325
02326
02327 check( dispersion_int_sky = interpolate_wave(dispersion_relation,
02328 linetable_header,
02329 slit_offset),
02330 "Could not interpolate dispersion solutions");
02331 }
02332 else {
02333
02334 dispersion_int_sky = uves_polynomial_duplicate(dispersion_relation[1]);
02335 }
02336
02337
02338 uves_free_propertylist(rebinned_header);
02339 check( rebinned_sky = uves_rebin(extracted_sky,
02340 parameters, context,
02341 linetable, dispersion_int_sky,
02342 first_abs_order,
02343 last_abs_order,
02344 n_traces,
02345 false,
02346 rebinned_header),
02347 "Could not rebin sky noise");
02348
02349 uves_msg("Rebinning sky spectrum noise");
02350
02351 uves_free_propertylist(rebinned_header);
02352 check( rebinned_sky_noise = uves_rebin(extracted_sky_noise,
02353 parameters, context,
02354 linetable, dispersion_int_sky,
02355 first_abs_order,
02356 last_abs_order,
02357 n_traces,
02358 true,
02359 rebinned_header),
02360 "Could not rebin sky noise");
02361 }
02362
02363
02364 if (DEBUG)
02365 {
02366 const char *filename = "";
02367 const char *filename_err = "";
02368 const char *filename_sky = "";
02369 const char *filename_sky_err = "";
02370 if (ff_method == FF_PIXEL)
02371 {
02372 filename = "wxfb";
02373 filename_err = "errwxfb";
02374 filename_sky = "wxfsky";
02375 filename_sky_err = "errwxfsky";
02376 }
02377 else if (ff_method == FF_EXTRACT)
02378 {
02379 filename = "wfxb";
02380 filename_err = "errwfxb";
02381 filename_sky = "wfxsky";
02382 filename_sky_err = "errwfxsky";
02383 }
02384 else if (ff_method == FF_NO)
02385 {
02386 filename = "wxb";
02387 filename_err = "errwxb";
02388 filename_sky = "wxsky";
02389 filename_sky_err = "errwxsky";
02390 }
02391 else
02392 {
02393 passure( false, "Unknown ff_method: %d", ff_method);
02394 }
02395
02396 check( uves_save_image_local("Rebinned spectrum",
02397 filename, *rebinned_spectrum,
02398 chip, -1, filename_window, *rebinned_header, true),
02399 "Error saving image");
02400
02401 check( uves_save_image_local("Noise of rebinned spectrum", filename_err,
02402 *rebinned_noise, chip, -1, filename_window,
02403 *rebinned_header, true),
02404 "Error saving image");
02405
02406 if (extracted_sky != NULL)
02407 {
02408 check( uves_save_image_local("Rebinned sky", filename_sky,
02409 rebinned_sky, chip, -1,
02410 filename_window, *rebinned_header, true),
02411 "Error saving image");
02412
02413 check( uves_save_image_local("Noise of rebinned sky",
02414 filename_sky_err,
02415 rebinned_sky_noise, chip, -1,
02416 filename_window, *rebinned_header, true),
02417 "Error saving image");
02418 }
02419 }
02420
02421
02422
02423
02424
02425
02426 if (resampled_spectrum != NULL)
02427 {
02428 if (ff_method == FF_EXTRACT)
02429 {
02430
02431 uves_msg("Rebinning pre-flatfielded spectrum");
02432
02433 uves_free_propertylist(rebinned_header);
02434 check( *resampled_spectrum =
02435 uves_rebin(extracted_noff,
02436 parameters, context,
02437 linetable, dispersion_int,
02438 first_abs_order,
02439 last_abs_order,
02440 n_traces,
02441 false,
02442 rebinned_header),
02443 "Could not rebin spectrum");
02444
02445 if (DEBUG) {
02446 check( uves_save_image_local("Rebinned, extracted spectrum",
02447 "wx", *resampled_spectrum,
02448 chip, -1, filename_window,
02449 *rebinned_header, true),
02450 "Error saving image");
02451 }
02452
02453 }
02454 else
02455 {
02456 check( *resampled_spectrum = cpl_image_duplicate(*rebinned_spectrum),
02457 "Error copying rebinned spectrum");
02458 }
02459 }
02460
02461
02462 if (extracted_sky != NULL)
02463 {
02464 uves_msg("Merging sky");
02465 check( *merged_sky = uves_merge_orders(rebinned_sky, rebinned_sky_noise,
02466 *rebinned_header,
02467 m_method,
02468 n_traces,
02469 merged_header,
02470 &merged_sky_noise),
02471 "Error merging sky");
02472 }
02473
02474 uves_msg("Merging spectrum");
02475 uves_free_propertylist(merged_header);
02476 check( *merged_spectrum = uves_merge_orders(*rebinned_spectrum, *rebinned_noise,
02477 *rebinned_header,
02478 m_method,
02479 n_traces,
02480 merged_header,
02481 merged_noise),
02482 "Error merging orders");
02483
02484
02485 if (DEBUG)
02486 {
02487 check( uves_save_image_local("Merged spectrum", "m", *merged_spectrum,
02488 chip, -1, filename_window, *merged_header, true),
02489 "Error saving image");
02490
02491 check( uves_save_image_local("Noise of merged spectrum", "errm",
02492 *merged_noise, chip, -1,
02493 filename_window, *merged_header, true),
02494 "Error saving image");
02495 }
02496
02497 if (DEBUG && extracted_sky != NULL)
02498 {
02499 check( uves_save_image_local("Merged sky", "msky", *merged_sky,
02500 chip, -1,
02501 filename_window, *merged_header, true),
02502 "Error saving image");
02503
02504 check( uves_save_image_local("Noise of merged sky", "errmsky",
02505 merged_sky_noise, chip, -1,
02506 filename_window, *merged_header, true),
02507 "Error saving image");
02508 }
02509
02510 cleanup:
02511 uves_free_image(&extracted);
02512 uves_free_image(&extracted_noff);
02513 uves_free_image(&extracted_noise);
02514 uves_free_image(&extracted_sky);
02515 uves_free_image(&extracted_sky_noise);
02516 uves_free_image(&cosmic_image);
02517 uves_free_image(&blaze_ratio);
02518 uves_free_image(&weights);
02519 uves_polynomial_delete(&dispersion_int);
02520 uves_polynomial_delete(&dispersion_int_sky);
02521 uves_free_table(&poly_table);
02522 uves_free_propertylist(&extracted_header);
02523 uves_free_table(&profile_table);
02524 uves_free_image(&extracted_mf);
02525 uves_free_image(&extracted_mf_noise);
02526 uves_free_image(&rebinned_sky);
02527 uves_free_image(&rebinned_sky_noise);
02528 uves_free_image(&merged_sky_noise);
02529
02530 uves_free_image(&temp_image);
02531
02532 return cpl_error_get_code();
02533 }
02534
02535
02536
02572
02573
02574 static cpl_image *
02575 subtract_sky(cpl_image *rebinned_obj, cpl_image *rebinned_obj_noise,
02576 uves_propertylist *rebinned_obj_header,
02577 const cpl_image *rebinned_sky1, const cpl_image *rebinned_sky1_noise,
02578 const uves_propertylist *rebinned_sky1_header,
02579 const cpl_image *rebinned_sky2, const cpl_image *rebinned_sky2_noise,
02580 const uves_propertylist *rebinned_sky2_header,
02581 cpl_image **merged_obj, cpl_image **merged_obj_noise,
02582 uves_propertylist *merged_obj_header,
02583 const cpl_image *merged_sky1, const cpl_image *merged_sky1_noise,
02584 const uves_propertylist *merged_sky1_header,
02585 const cpl_image *merged_sky2, const cpl_image *merged_sky2_noise,
02586 const uves_propertylist *merged_sky2_header,
02587 double obj_slit, double sky1_slit, double sky2_slit)
02588 {
02589 double wavestep;
02590 int norders;
02591
02592 cpl_image *merged_sky = NULL;
02593
02594 passure( rebinned_obj != NULL, " ");
02595 passure( rebinned_obj_noise != NULL, " ");
02596 passure( rebinned_obj_header != NULL, " ");
02597 passure( merged_obj != NULL, " ");
02598 passure( merged_obj_noise != NULL, " ");
02599 passure( merged_obj_header != NULL, " ");
02600 passure( *merged_obj != NULL, " ");
02601 passure( *merged_obj_noise != NULL, " ");
02602
02603
02604 check( wavestep = uves_pfits_get_cdelt1(rebinned_obj_header),
02605 "Error reading wavelength step");
02606 norders = cpl_image_get_size_y(rebinned_obj);
02607
02608
02609
02610 assure((rebinned_sky1 == NULL || norders == cpl_image_get_size_y(rebinned_sky1)) &&
02611 (rebinned_sky2 == NULL || norders == cpl_image_get_size_y(rebinned_sky2)),
02612 CPL_ERROR_ILLEGAL_INPUT,
02613 "Different number of orders in object/sky spectra: obj = %d, "
02614 "sky1 = %d, sky3 = %d",
02615 norders,
02616 cpl_image_get_size_y(rebinned_sky1),
02617 cpl_image_get_size_y(rebinned_sky2));
02618
02619 if (rebinned_sky1 != NULL)
02620 {
02621 double wavestep1;
02622 check( wavestep1 = uves_pfits_get_cdelt1(rebinned_sky1_header),
02623 "Error reading wavelength step");
02624 assure( fabs(wavestep1 - wavestep) / wavestep < 0.01,
02625 CPL_ERROR_ILLEGAL_INPUT,
02626 "Different bin widths: sky1 = %f ; obj = %f",
02627 wavestep1, wavestep);
02628 }
02629 if (rebinned_sky2 != NULL)
02630 {
02631 double wavestep2;
02632 check( wavestep2 = uves_pfits_get_cdelt1(rebinned_sky2_header),
02633 "Error reading wavelength step");
02634 assure( fabs(wavestep2 - wavestep) / wavestep < 0.01,
02635 CPL_ERROR_ILLEGAL_INPUT,
02636 "Different bin widths: sky3 = %f ; obj = %f",
02637 wavestep2, wavestep);
02638 }
02639
02640
02641 {
02642 int order;
02643 for (order = 1; order <= norders; order++)
02644 {
02645 double obj_start , obj_end;
02646 double sky1_start , sky1_end;
02647 double sky2_start , sky2_end;
02648 double common_start, common_end;
02649
02650 check( obj_start = uves_pfits_get_wstart(rebinned_obj_header, order),
02651 "Error reading start wavelength for order #%d", order);
02652 check( obj_end = uves_pfits_get_wend (rebinned_obj_header, order),
02653 "Error reading end wavelength for order #%d", order);
02654
02655 if (rebinned_sky1 != NULL)
02656 {
02657 check( sky1_start =
02658 uves_pfits_get_wstart(rebinned_sky1_header, order),
02659 "Error reading start wavelength for order #%d", order);
02660 check( sky1_end =
02661 uves_pfits_get_wend (rebinned_sky1_header, order),
02662 "Error reading end wavelength for order #%d", order);
02663 }
02664 else
02665 {
02666 sky1_start = obj_start;
02667 sky1_end = obj_end;
02668 }
02669
02670 if (rebinned_sky2 != NULL)
02671 {
02672 check( sky2_start =
02673 uves_pfits_get_wstart(rebinned_sky2_header, order),
02674 "Error reading start wavelength for order #%d", order);
02675 check( sky2_end =
02676 uves_pfits_get_wend (rebinned_sky2_header, order),
02677 "Error reading end wavelength for order #%d", order);
02678 }
02679 else
02680 {
02681 sky2_start = obj_start;
02682 sky2_end = obj_end;
02683 }
02684
02685 check( merged_sky =
02686 subtract_sky_row(rebinned_obj , rebinned_obj_noise ,
02687 obj_start , obj_end, obj_slit,
02688 rebinned_sky1, rebinned_sky1_noise,
02689 sky1_start, sky1_end, sky1_slit,
02690 rebinned_sky2, rebinned_sky2_noise,
02691 sky2_start, sky2_end, sky2_slit,
02692 order, wavestep, &common_start,
02693 &common_end),
02694 "Could not subtract sky for rebinned spectrum order #%d", order);
02695 uves_free_image(&merged_sky);
02696
02697 check( uves_pfits_set_wstart(rebinned_obj_header, order, common_start),
02698 "Error updating start wavelength for order #%d", order);
02699 check( uves_pfits_set_wend (rebinned_obj_header, order, common_end ),
02700 "Error updating start wavelength for order #%d", order);
02701 }
02702 }
02703
02704
02705 {
02706 double obj_start , obj_end;
02707 double sky1_start , sky1_end;
02708 double sky2_start , sky2_end;
02709 double common_start, common_end;
02710
02711 obj_start = uves_pfits_get_crval1(merged_obj_header);
02712 obj_end = obj_start + wavestep * (cpl_image_get_size_x(*merged_obj) - 1);
02713
02714 if (merged_sky1 != NULL)
02715 {
02716 sky1_start = uves_pfits_get_crval1(merged_sky1_header);
02717 sky1_end = sky1_start +
02718 wavestep * (cpl_image_get_size_x(merged_sky1) - 1);
02719 }
02720 else
02721 {
02722 sky1_start = obj_start;
02723 sky1_end = obj_end;
02724 }
02725
02726 if (merged_sky2 != NULL)
02727 {
02728 sky2_start = uves_pfits_get_crval1(merged_sky2_header);
02729 sky2_end = sky2_start +
02730 wavestep * (cpl_image_get_size_x(merged_sky2) - 1);
02731 }
02732 else
02733 {
02734 sky2_start = obj_start;
02735 sky2_end = obj_end;
02736 }
02737
02738
02739 check( merged_sky = subtract_sky_row(*merged_obj, *merged_obj_noise,
02740 obj_start , obj_end, obj_slit,
02741 merged_sky1, merged_sky1_noise,
02742 sky1_start, sky1_end, sky1_slit,
02743 merged_sky2, merged_sky2_noise,
02744 sky2_start, sky2_end, sky2_slit,
02745 1, wavestep, &common_start,
02746 &common_end),
02747 "Error subtracting sky of merged spectrum");
02748
02749 check( uves_pfits_set_crval1(merged_obj_header, common_start),
02750 "Could not update start wavelength");
02751
02752
02753 check( uves_crop_image(merged_obj,
02754 1, 1,
02755 1 + uves_round_double((common_end -
02756 common_start)/wavestep),
02757 1),
02758 "Error cropping merged spectrum");
02759
02760 check( uves_crop_image(merged_obj_noise,
02761 1, 1,
02762 1 + uves_round_double((common_end -
02763 common_start)/wavestep),
02764 1),
02765 "Error cropping merged spectrum noise");
02766
02767 if (merged_sky != NULL)
02768 {
02769
02770 assure( cpl_image_get_size_x(merged_sky) ==
02771 cpl_image_get_size_x(*merged_obj), CPL_ERROR_ILLEGAL_OUTPUT,
02772 "Sky and object spectrum sizes differ, "
02773 "sky = %d bins, obj = %d bins",
02774 cpl_image_get_size_x(merged_sky),
02775 cpl_image_get_size_x(*merged_obj));
02776 }
02777 }
02778
02779 cleanup:
02780 if (cpl_error_get_code() != CPL_ERROR_NONE)
02781 {
02782 uves_free_image(&merged_sky);
02783 }
02784 return merged_sky;
02785 }
02786
02787
02819
02820
02821 static cpl_image *
02822 subtract_sky_row(cpl_image *obj, cpl_image *obj_noise,
02823 double obj_start, double obj_end, double obj_slit,
02824 const cpl_image *sky1, const cpl_image *sky1_noise,
02825 double sky1_start, double sky1_end, double sky1_slit,
02826 const cpl_image *sky2, const cpl_image *sky2_noise,
02827 double sky2_start, double sky2_end, double sky2_slit,
02828 int row, double wavestep,
02829 double *common_start, double *common_end)
02830 {
02831 int first_bin_obj;
02832 int first_bin_sky1;
02833 int first_bin_sky2;
02834 int nbins;
02835 cpl_image *common_obj = NULL;
02836 cpl_image *common_sky1 = NULL;
02837 cpl_image *common_sky2 = NULL;
02838 cpl_image *common_obj_noise = NULL;
02839 cpl_image *common_sky1_noise = NULL;
02840 cpl_image *common_sky2_noise = NULL;
02841 bool is_good1, is_good2;
02842
02843 cpl_image *common_sky = NULL;
02844
02845 cpl_image *common_sky_noise = NULL;
02846
02847 cpl_image *temp = NULL;
02848
02849 *common_start = uves_max_double(obj_start, uves_max_double(sky1_start, sky2_start));
02850 *common_end = uves_min_double(obj_end , uves_min_double(sky1_end , sky2_end ));
02851
02852 if (*common_start <= *common_end)
02853 {
02854 nbins = 1 + uves_round_double((*common_end - *common_start) / wavestep);
02855
02856 uves_msg_debug("Lower sky range: %f - %f w.l.u.", sky1_start, sky1_end);
02857 uves_msg_debug("Upper sky range: %f - %f w.l.u.", sky2_start, sky2_end);
02858 uves_msg_debug("Object sky range: %f - %f w.l.u.", obj_start, obj_end);
02859 uves_msg_debug("Sky/object common wavelength range in order %d: "
02860 "%f - %f w.l.u. (%d bins)",
02861 row, *common_start, *common_end, nbins);
02862
02863 first_bin_obj = 1 + uves_round_double((*common_start - obj_start )/wavestep);
02864 first_bin_sky1 = 1 + uves_round_double((*common_start - sky1_start)/wavestep);
02865 first_bin_sky2 = 1 + uves_round_double((*common_start - sky2_start)/wavestep);
02866
02867
02868 check( common_obj = cpl_image_extract(obj,
02869 first_bin_obj, row,
02870 first_bin_obj + nbins-1, row),
02871 "Error extracting common rows (object)");
02872
02873 check( common_obj_noise = cpl_image_extract(obj_noise,
02874 first_bin_obj, row,
02875 first_bin_obj + nbins-1, row),
02876 "Error extracting common rows (object noise)");
02877
02878 if (sky1 != NULL)
02879 {
02880 check( common_sky1 =
02881 cpl_image_extract(sky1,
02882 first_bin_sky1, row,
02883 first_bin_sky1 + nbins-1, row),
02884 "Error extracting common rows (lower sky)");
02885
02886 check( common_sky1_noise =
02887 cpl_image_extract(sky1_noise,
02888 first_bin_sky1, row,
02889 first_bin_sky1 + nbins-1, row),
02890 "Error extracting common rows (lower sky noise)");
02891
02892 check(( cpl_image_multiply_scalar(common_sky1 , obj_slit / sky1_slit),
02893 cpl_image_multiply_scalar(common_sky1_noise, obj_slit / sky1_slit)),
02894 "Error normalizing sky flux");
02895
02896 is_good1 =
02897 cpl_image_count_rejected(common_sky1) <
02898 cpl_image_get_size_x(common_sky1)*
02899 cpl_image_get_size_y(common_sky1) &&
02900
02901
02902 cpl_image_get_min(common_sky1_noise) > 0;
02903 }
02904 else
02905 {
02906 is_good1 = false;
02907 }
02908 if (sky2 != NULL)
02909 {
02910 check( common_sky2 = cpl_image_extract(sky2,
02911 first_bin_sky2, row,
02912 first_bin_sky2 + nbins-1, row),
02913 "Error extracting common rows (upper sky)");
02914
02915 check( common_sky2_noise = cpl_image_extract(sky2_noise,
02916 first_bin_sky2, row,
02917 first_bin_sky2 + nbins-1, row),
02918 "Error extracting common rows (upper sky noise)");
02919
02920 check(( cpl_image_multiply_scalar(common_sky2 , obj_slit / sky2_slit),
02921 cpl_image_multiply_scalar(common_sky2_noise, obj_slit / sky2_slit)),
02922 "Error normalizing sky flux");
02923
02924 is_good2 =
02925 cpl_image_count_rejected(common_sky2) <
02926 cpl_image_get_size_x(common_sky2)*
02927 cpl_image_get_size_y(common_sky2) &&
02928 cpl_image_get_min(common_sky2_noise) > 0;
02929 }
02930 else
02931 {
02932 is_good2 = false;
02933 }
02934
02935
02936
02937
02938 if (is_good1 && is_good2)
02939 {
02940 check( common_sky =
02941 uves_average_images(common_sky1, common_sky1_noise,
02942 common_sky2, common_sky2_noise,
02943 &common_sky_noise),
02944 "Error combining sky windows");
02945 }
02946 else if (is_good1 && !is_good2)
02947 {
02948 common_sky = cpl_image_duplicate(common_sky1);
02949 common_sky_noise = cpl_image_duplicate(common_sky1_noise);
02950 }
02951 else if (!is_good1 && is_good2)
02952 {
02953 common_sky = cpl_image_duplicate(common_sky2);
02954 common_sky_noise = cpl_image_duplicate(common_sky2_noise);
02955 }
02956 else
02957 {
02958 common_sky = NULL;
02959 }
02960
02961 if (common_sky != NULL)
02962 {
02963
02964
02965
02966
02967
02968
02969
02970
02971 check(( cpl_image_subtract (common_obj, common_sky)),
02972 "Error subtracting combined sky");
02973
02974
02975
02976 check(( cpl_image_power(common_obj_noise, 2),
02977 cpl_image_power(common_sky_noise, 2),
02978 cpl_image_add (common_obj_noise, common_sky_noise),
02979 cpl_image_power(common_obj_noise, 0.5)),
02980 "Error propagating noise during sky subtration");
02981
02982
02983 check(( cpl_image_copy(obj,
02984 common_obj,
02985 1, row),
02986 cpl_image_copy(obj_noise,
02987 common_obj_noise,
02988 1, row)),
02989 "Error writing subtracted flux to row %d of spectrum", row);
02990 }
02991
02992 }
02993 else
02994 {
02995 int x;
02996
02997 uves_msg_low("Extracted object and sky spectra have no overlap in order #%d. "
02998 "Order marked as bad", row);
02999
03000 for (x = 1; x <= cpl_image_get_size_x(obj); x++)
03001 {
03002 check(( cpl_image_reject(obj , x, row),
03003 cpl_image_reject(obj_noise, x, row)),
03004 "Error rejecting sky-subtracted spectrum "
03005 "at (x, row) = (%d, %d)", x, row);
03006 }
03007 }
03008
03009 cleanup:
03010 uves_free_image(&common_obj);
03011 uves_free_image(&common_sky1);
03012 uves_free_image(&common_sky2);
03013 uves_free_image(&common_obj_noise);
03014 uves_free_image(&common_sky_noise);
03015 uves_free_image(&common_sky1_noise);
03016 uves_free_image(&common_sky2_noise);
03017 uves_free_image(&temp);
03018 if (cpl_error_get_code() != CPL_ERROR_NONE)
03019 {
03020 uves_free_image(&common_sky);
03021 }
03022
03023 return common_sky;
03024 }
03025
03026
03043
03044 static double get_offset(const cpl_image *back_subbed,
03045 const cpl_table *ordertable,
03046 const polynomial *order_locations,
03047 double search_range, int nsamples, double *doffset)
03048 {
03049 cpl_image *chunk = NULL;
03050 cpl_image *chunk_col = NULL;
03051
03052 int minorder, maxorder;
03053 int order, x, nx, ny;
03054 double sum = 0, sum_o = 0, sum_oo = 0;
03055
03056 int s_r_int = uves_round_double(search_range);
03057
03058 passure( back_subbed != NULL, " ");
03059 passure( ordertable != NULL, " ");
03060 passure( order_locations != NULL, " ");
03061
03062 assure( nsamples >= 1, CPL_ERROR_ILLEGAL_INPUT,
03063 "Illegal number of sample points per order: %d", nsamples);
03064
03065 minorder = cpl_table_get_column_min(ordertable, "Order");
03066 maxorder = cpl_table_get_column_max(ordertable, "Order");
03067 nx = cpl_image_get_size_x(back_subbed);
03068 ny = cpl_image_get_size_y(back_subbed);
03069
03070 sum = 0;
03071 sum_o = 0;
03072 sum_oo = 0;
03073 for (order = minorder; order <= maxorder; order++)
03074 {
03075 int stepx = nx / nsamples;
03076
03077 for (x = stepx/2; x <= nx; x += stepx)
03078 {
03079 int y = uves_round_double(
03080 uves_polynomial_evaluate_2d(order_locations, x, order));
03081
03082 if (1 <= y - s_r_int && y + s_r_int <= ny)
03083 {
03084 double offset;
03085
03086
03087
03088 chunk =
03089 cpl_image_extract(back_subbed,
03090 uves_max_int(1 , x - stepx/2),
03091 y - s_r_int,
03092 uves_min_int(nx, x + stepx/2),
03093 y + s_r_int);
03094
03095 chunk_col =
03096
03097 cpl_image_collapse_median_create(chunk,
03098 1,
03099 0, 0);
03100
03101
03102
03103
03104 offset = (y - s_r_int - 1) +
03105 cpl_image_get_centroid_y_window(chunk_col,
03106 1, 1,
03107 1,
03108 cpl_image_get_size_y(chunk_col));
03109
03110
03111 offset -= y;
03112
03113 uves_free_image(&chunk);
03114 uves_free_image(&chunk_col);
03115
03116 sum += 1;
03117 sum_o += offset;
03118 sum_oo += offset*offset;
03119 }
03120 }
03121 }
03122
03123
03124
03125 assure( sum > 0, CPL_ERROR_ILLEGAL_OUTPUT,
03126 "No evaluation points inside image!");
03127
03128 if (doffset != NULL)
03129 {
03130 *doffset = sqrt(sum_oo/(1.0*sum) -
03131 (sum_o*sum_o) / (sum*1.0*sum));
03132 }
03133
03134 cleanup:
03135 uves_free_image(&chunk);
03136 uves_free_image(&chunk_col);
03137
03138 return (1.0*sum_o) / sum;
03139 }
03140
03141
03142
03164
03165 static cpl_image *
03166 uves_get_blaze_ratio(const cpl_image *spectrum,
03167 const cpl_image *spectrum_noise)
03168 {
03169 int nx, ny;
03170 int smooth_x, smooth_y;
03171
03172 cpl_image *blaze_ratio = NULL;
03173 cpl_image *blaze_ratio_noise = NULL;
03174
03175 cpl_table *values = NULL;
03176 polynomial *p = NULL;
03177
03178 passure( spectrum != NULL, " ");
03179 passure( spectrum_noise != NULL, " ");
03180
03181 nx = cpl_image_get_size_x(spectrum);
03182 ny = cpl_image_get_size_y(spectrum);
03183
03184 blaze_ratio = cpl_image_duplicate(spectrum);
03185 blaze_ratio_noise = cpl_image_duplicate(spectrum_noise);
03186 assure_mem( blaze_ratio );
03187 assure_mem( blaze_ratio_noise );
03188
03189
03190
03191
03192
03193
03194 {
03195 int x, y;
03196
03197 for (y = 1; y <= ny; y++)
03198 {
03199 double median = cpl_image_get_median_window(blaze_ratio,
03200 1, y,
03201 nx, y);
03202
03203 if (median == 0)
03204 {
03205
03206
03207
03208
03209
03210
03211 double max_noise = cpl_image_get_max(blaze_ratio_noise);
03212
03213 for (x = 1; x <= nx; x++)
03214 {
03215 cpl_image_set(blaze_ratio , x, y, 1);
03216
03217
03218 cpl_image_set(blaze_ratio_noise, x, y, max_noise);
03219 }
03220 }
03221 else
03222 {
03223
03224
03225 double exclude = 2;
03226
03227 for (x = 1; x <= nx; x++)
03228 {
03229 int pis_rejected1, pis_rejected2;
03230 double val1, val2;
03231
03232 val1 = cpl_image_get(blaze_ratio ,
03233 x, y, &pis_rejected1);
03234 val2 = cpl_image_get(blaze_ratio_noise,
03235 x, y, &pis_rejected2);
03236
03237 if (!pis_rejected1 && !pis_rejected2 &&
03238 val1/median < exclude && val1/median > 1/exclude)
03239 {
03240 cpl_image_set(blaze_ratio ,
03241 x, y, val1 / median);
03242 cpl_image_set(blaze_ratio_noise,
03243 x, y, val2 / median);
03244 }
03245 else
03246 {
03247
03248
03249 cpl_image_set (blaze_ratio , x, y, 1);
03250
03251 cpl_image_reject(blaze_ratio , x, y);
03252 cpl_image_reject(blaze_ratio_noise, x, y);
03253 }
03254 }
03255 }
03256 }
03257
03258 uves_plot_image_rows(blaze_ratio, 1, ny, ny/10,
03259 "x", "y", "ratio (normalized to 1)");
03260 }
03261
03262 smooth_x = nx / 20 + 1;
03263 smooth_y = ny / 20 + 1;
03264 check( uves_filter_image_median(&blaze_ratio,
03265 smooth_x, smooth_y,
03266 false),
03267 "Error creating smoothed ratio");
03268
03269 uves_plot_image_rows(blaze_ratio, 1, ny, ny/10, "x", "y", "ratio (smoothed)");
03270
03271
03272
03273
03274
03275
03276
03277 {
03278 int x, y;
03279
03280 for (x = 1; x <= nx; x++)
03281 {
03282 int current_row;
03283
03284
03285
03286 uves_free_table(&values);
03287 values = cpl_table_new(ny);
03288 cpl_table_new_column(values, "Y", CPL_TYPE_INT);
03289 cpl_table_new_column(values, "Ratio", CPL_TYPE_DOUBLE);
03290 cpl_table_new_column(values, "dRatio", CPL_TYPE_DOUBLE);
03291
03292 assure_mem( values );
03293
03294 current_row = 0;
03295 for (y = 1; y <= ny; y++)
03296 {
03297 double ratio, dratio;
03298 int pis_rejected1, pis_rejected2;
03299
03300 ratio = cpl_image_get(blaze_ratio ,
03301 x, y, &pis_rejected1);
03302 dratio = cpl_image_get(blaze_ratio_noise,
03303 x, y, &pis_rejected2);
03304
03305 if (!pis_rejected1 && !pis_rejected2)
03306 {
03307 cpl_table_set_int (values, "Y" ,
03308 current_row, y);
03309 cpl_table_set_double(values, "Ratio" ,
03310 current_row, ratio);
03311 cpl_table_set_double(values, "dRatio",
03312 current_row, dratio);
03313 current_row += 1;
03314 }
03315 else
03316 {
03317
03318 }
03319 }
03320
03321 cpl_table_set_size(values, current_row);
03322
03323 {
03324 int degree = 2;
03325 double kappa = 2;
03326
03327 uves_polynomial_delete(&p);
03328 p = uves_polynomial_regression_1d(values,
03329 "Y", "Ratio", "dRatio",
03330 degree,
03331 NULL, NULL,
03332 NULL,
03333 kappa);
03334
03335
03336
03337 if (cpl_error_get_code() == CPL_ERROR_ILLEGAL_INPUT ||
03338 cpl_error_get_code() == CPL_ERROR_ILLEGAL_OUTPUT)
03339 {
03340 uves_error_reset();
03341
03342
03343
03344
03345
03346
03347
03348
03349
03350
03351
03352 uves_free_table(&values);
03353 values = cpl_table_new(2);
03354 cpl_table_new_column(values, "Y", CPL_TYPE_INT);
03355 cpl_table_new_column(values, "Ratio", CPL_TYPE_DOUBLE);
03356 cpl_table_set_int (values, "Y" , 0, 1);
03357 cpl_table_set_double(values, "Ratio" , 0, 1);
03358 cpl_table_set_int (values, "Y" , 1, 2);
03359 cpl_table_set_double(values, "Ratio" , 1, 1);
03360
03361 degree = 2;
03362 kappa = -1;
03363 uves_polynomial_delete(&p);
03364 p = uves_polynomial_regression_1d(values,
03365 "Y", "Ratio", NULL,
03366 degree,
03367 NULL, NULL,
03368 NULL,
03369 kappa);
03370 }
03371
03372 assure( cpl_error_get_code() == CPL_ERROR_NONE, cpl_error_get_code(),
03373 "Could not fit %d. degree polynomial to column %d", degree, x);
03374
03375 }
03376
03377 for (y = 1; y <= ny; y++)
03378 {
03379 double interpolated = uves_polynomial_evaluate_1d(p, y);
03380
03381 cpl_image_set(blaze_ratio, x, y, fabs(interpolated));
03382 }
03383
03384 }
03385
03386
03387 check( uves_filter_image_median(&blaze_ratio,
03388 2*smooth_x, 2*smooth_y,
03389 false),
03390 "Error creating smoothed ratio");
03391
03392 uves_plot_image_rows(blaze_ratio, 1, ny, ny/10, "x", "y", "ratio (poly. fit)");
03393
03394 }
03395
03396
03397
03398
03399
03400
03401
03402
03403
03404
03405
03406
03407
03408
03409 cleanup:
03410 uves_free_table(&values);
03411 uves_polynomial_delete(&p);
03412 uves_free_image(&blaze_ratio_noise);
03413
03414 if (cpl_error_get_code() != CPL_ERROR_NONE)
03415 {
03416 uves_free_image(&blaze_ratio);
03417 }
03418 return blaze_ratio;
03419 }
03420
03421