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