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