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
00210
00211
00212
00213
00214
00215
00216
00217
00218
00219
00220
00221
00222
00223
00224
00225
00226
00227
00228
00229
00230
00231
00232
00233
00234
00235
00236
00237
00238
00239
00240
00241
00242
00243
00244
00245
00246
00247
00248
00249
00250
00251
00252
00253
00254
00255
00256
00257
00258
00259
00260
00261
00262
00263
00264
00265
00266
00267
00268
00269
00270
00271
00272
00273
00274
00275
00276
00277
00278
00279
00280
00281
00282
00283
00284
00285
00286
00287
00288
00289
00290
00291
00292
00293
00294
00295
00296
00297
00298
00299
00300
00301
00302
00303
00304
00305
00306
00307
00308
00309
00310
00311
00312
00313
00314
00315
00316
00317
00318
00319
00320
00321
00322
00323
00324
00325
00326
00327
00328
00329
00330
00331
00332
00333
00334
00335
00336
00337
00338
00339
00340
00341
00342
00343
00344
00345 #ifdef HAVE_CONFIG_H
00346 # include <config.h>
00347 #endif
00348
00349
00356
00357
00358
00359
00360
00361
00362 #include <uves_extract.h>
00363
00364 #include <uves_extract_iterate.h>
00365 #include <uves_extract_profile.h>
00366 #include <uves_parameters.h>
00367 #include <uves_utils.h>
00368 #include <uves_utils_cpl.h>
00369 #include <uves_utils_wrappers.h>
00370 #include <uves_dfs.h>
00371 #include <uves_plot.h>
00372 #include <uves_dump.h>
00373 #include <uves_error.h>
00374 #include <uves.h>
00375
00376 #include <irplib_plot.h>
00377 #include <irplib_utils.h>
00378
00379 #include <cpl.h>
00380
00381 #include <stdbool.h>
00382
00383
00384
00385
00387 #define DATA(name, pos) (name[((pos)->x-1)+((pos)->y-1)*(pos)->nx])
00388
00390 #define SPECTRUM_DATA(name, pos) (name[((pos)->x-1)+((pos)->order-(pos)->minorder)*(pos)->nx])
00391
00393 #define ISBAD(weights, pos) (weights[((pos)->x-1)+((pos)->y-1)*(pos)->nx] < 0)
00394
00396 #define SETBAD(weights, image_bpm, pos) \
00397 do { \
00398 weights [((pos)->x-1)+((pos)->y-1)*(pos)->nx] = -1.0; \
00399 image_bpm[((pos)->x-1)+((pos)->y-1)*(pos)->nx] = CPL_BINARY_1;\
00400 } \
00401 while (false)
00402
00403 #define ISGOOD(bpm, pos) (bpm[((pos)->x-1)+((pos)->y-1)*(pos)->nx] == CPL_BINARY_0)
00404
00405
00406
00407 #define NEW_METHOD 0
00408
00409 #if NEW_METHOD
00410 #define CREATE_DEBUGGING_TABLE 1
00411
00412 #endif
00413
00414
00415
00416
00419 static int
00420 extract_order_simple(const cpl_image *image, const cpl_image *image_noise,
00421 const polynomial *order_locations,
00422 int order, int minorder,
00423 int spectrum_row,
00424 double offset,
00425 double slit_length,
00426 extract_method method,
00427 const cpl_image *weights,
00428 bool extract_partial,
00429 cpl_image *spectrum,
00430 cpl_image *spectrum_noise,
00431 cpl_binary*spectrum_badmap,
00432 cpl_table **info_tbl,
00433 double *sn);
00434
00435 static double area_above_line(int y, double left, double right);
00436
00437 static cpl_table *opt_define_sky(const cpl_image *image, const cpl_image *weights,
00438 uves_iterate_position *pos);
00439
00440 static cpl_image *opt_extract_sky(const cpl_image *image, const cpl_image *image_noise,
00441 const cpl_image *weights,
00442 uves_iterate_position *pos,
00443 cpl_image *sky_spectrum,
00444 cpl_image *sky_spectrum_noise);
00445
00446 static cpl_image * opt_subtract_sky(
00447 const cpl_image *image, const cpl_image *image_noise,
00448 const cpl_image *weights,
00449 uves_iterate_position *pos,
00450 const cpl_table *sky_map,
00451 cpl_image *sky_spectrum,
00452 cpl_image *sky_spectrum_noise);
00453
00454 static cpl_table **opt_sample_spatial_profile(
00455 const cpl_image *image, const cpl_image *weights,
00456 uves_iterate_position *pos,
00457 int chunk,
00458 int sampling_factor,
00459 int *nbins);
00460
00461 static uves_extract_profile *opt_measure_profile(
00462 const cpl_image *image, const cpl_image *image_noise,
00463 const cpl_image *weights,
00464 uves_iterate_position *pos,
00465 int chunk, int sampling_factor,
00466 int (*f) (const double x[], const double a[], double *result),
00467 int (*dfda)(const double x[], const double a[], double result[]),
00468 int M,
00469 const cpl_image *sky_spectrum,
00470 cpl_table *info_tbl,
00471 cpl_table **profile_global);
00472
00473 static cpl_table *opt_measure_profile_order(
00474 const cpl_image *image, const cpl_image *image_noise,
00475 const cpl_binary *image_bpm,
00476 uves_iterate_position *pos,
00477 int chunk,
00478 int (*f) (const double x[], const double a[], double *result),
00479 int (*dfda)(const double x[], const double a[], double result[]),
00480 int M,
00481 const cpl_image *sky_spectrum);
00482
00483 static void
00484 revise_noise(cpl_image *image_noise,
00485 const cpl_binary *image_bpm,
00486 const uves_propertylist *image_header,
00487 uves_iterate_position *pos,
00488 const cpl_image *spectrum,
00489 const cpl_image *sky_spectrum,
00490 const uves_extract_profile *profile,
00491 enum uves_chip chip);
00492
00493 static int
00494 opt_extract(cpl_image *image, const cpl_image *image_noise,
00495 uves_iterate_position *pos,
00496 const uves_extract_profile *profile,
00497 bool optimal_extract_sky,
00498 double kappa,
00499 cpl_table *cosmic_mask, int *cr_row,
00500 cpl_table *profile_table, int *prof_row,
00501 cpl_image *spectrum, cpl_image *spectrum_noise,
00502 cpl_image *weights,
00503 cpl_image *sky_spectrum,
00504 cpl_image *sky_spectrum_noise,
00505 double *sn);
00506
00507 static int opt_get_order_width(const uves_iterate_position *pos);
00508 static double
00509 estimate_sn(const cpl_image *image, const cpl_image *image_noise,
00510 uves_iterate_position *pos);
00511
00512 inline static double opt_get_sky(const double *image_data,
00513 const double *noise_data,
00514 const double *weights_data,
00515 uves_iterate_position *pos,
00516 const cpl_table *sky_map,
00517 double buffer_flux[], double buffer_noise[],
00518 double *sky_background_noise);
00519
00520 inline static double opt_get_noise_median(const double *noise_data,
00521 const cpl_binary *image_bpm,
00522 uves_iterate_position *pos,
00523 double noise_buffer[]);
00524
00525 inline static double opt_get_flux_sky_variance(const double *image_data,
00526 const double *noise_data,
00527 double *weights_data,
00528 uves_iterate_position *pos,
00529 const uves_extract_profile *profile,
00530 bool optimal_extract_sky,
00531 double median_noise,
00532 double *variance,
00533 double *sky_background,
00534 double *sky_background_noise);
00535
00536 inline static bool opt_reject_outlier(const double *image_data,
00537 const double *noise_data,
00538 cpl_binary *image_bpm,
00539 double *weights_data,
00540 uves_iterate_position *pos,
00541 const uves_extract_profile *profile,
00542 double kappa,
00543 double flux,
00544 double sky_background,
00545 double red_chisq,
00546 cpl_table *cosmic_mask, int *cr_row,
00547 int *hot_pixels, int *cold_pixels);
00548
00549 static double opt_get_redchisq(const uves_extract_profile *profile,
00550 const uves_iterate_position *pos);
00551
00552 static polynomial *repeat_orderdef(const cpl_image *image, const cpl_image *image_noise,
00553 const polynomial *guess_locations,
00554 int minorder, int maxorder, slit_geometry sg,
00555 cpl_table *info_tbl);
00556
00557 static double
00558 detect_ripples(const cpl_image *spectrum, const uves_iterate_position *pos,
00559 double sn);
00560
00561
00562
00563
00564
00565
00573
00574
00575 cpl_parameterlist *
00576 uves_extract_define_parameters(void)
00577 {
00578 const char *name = "";
00579 char *full_name = NULL;
00580 cpl_parameter *p = NULL;
00581 cpl_parameterlist *parameters = NULL;
00582
00583 parameters = cpl_parameterlist_new();
00584
00585 {
00586 name = "method";
00587 full_name = uves_sprintf("%s.%s", UVES_EXTRACT_ID, name);
00588
00589 uves_parameter_new_enum(p, full_name,
00590 CPL_TYPE_STRING,
00591 "Extraction method",
00592 UVES_EXTRACT_ID,
00593 "optimal",
00594 5,
00595 "average",
00596 "linear",
00597 "2d",
00598 "weighted",
00599 "optimal");
00600
00601 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, name);
00602 cpl_parameterlist_append(parameters, p);
00603 cpl_free(full_name);
00604 }
00605
00606 {
00607 name = "kappa";
00608 full_name = uves_sprintf("%s.%s", UVES_EXTRACT_ID, name);
00609
00610 uves_parameter_new_value(p, full_name,
00611 CPL_TYPE_DOUBLE,
00612 "In optimal extraction mode, this is the "
00613 "threshold for bad (i.e. hot/cold) "
00614 "pixel rejection. If a pixel deviates more than "
00615 "kappa*sigma (where sigma is "
00616 "the uncertainty of the pixel flux) from "
00617 "the inferred spatial profile, its "
00618 "weight is set to zero. If this parameter "
00619 "is negative, no rejection is performed.",
00620 UVES_EXTRACT_ID,
00621 10.0);
00622
00623 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, name);
00624 cpl_parameterlist_append(parameters, p);
00625 cpl_free(full_name);
00626 }
00627
00628 {
00629 name = "chunk";
00630 full_name = uves_sprintf("%s.%s", UVES_EXTRACT_ID, name);
00631
00632 uves_parameter_new_range(p, full_name,
00633 CPL_TYPE_INT,
00634 "In optimal extraction mode, the chunk size (in pixels) "
00635 "used for fitting the analytical profile (a fit of the "
00636 "analytical profile to single bins would suffer from "
00637 "low statistics).",
00638 UVES_EXTRACT_ID,
00639 32,
00640 1, INT_MAX);
00641
00642 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, name);
00643 cpl_parameterlist_append(parameters, p);
00644 cpl_free(full_name);
00645 }
00646
00647 {
00648 name = "profile";
00649 full_name = uves_sprintf("%s.%s", UVES_EXTRACT_ID, name);
00650
00651 uves_parameter_new_enum(p, full_name,
00652 CPL_TYPE_STRING,
00653 "In optimal extraction mode, the kind of profile to use. "
00654 "'gauss' gives a Gaussian profile, 'moffat' gives "
00655 "a Moffat profile with beta=4 and a possible linear sky "
00656 "contribution. 'virtual' uses "
00657 "a virtual resampling algorithm (i.e. measures and "
00658 "uses the actual object profile). "
00659 "'constant' assumes a constant spatial profile and "
00660 "allows optimal extraction of wavelength "
00661 "calibration frames. 'auto' will automatically "
00662 "select the best method based on the estimated S/N of the "
00663 "object. For low S/N, 'moffat' or 'gauss' are "
00664 "recommended (for robustness). For high S/N, 'virtual' is "
00665 "recommended (for accuracy). In the case of virtual resampling, "
00666 "a precise determination of the order positions is required; "
00667 "therefore the order-definition is repeated "
00668 "using the (assumed non-low S/N) science frame",
00669 UVES_EXTRACT_ID,
00670 "auto",
00671 5,
00672 "constant",
00673 "gauss",
00674 "moffat",
00675 "virtual",
00676 "auto");
00677
00678 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, name);
00679 cpl_parameterlist_append(parameters, p);
00680 cpl_free(full_name);
00681 }
00682
00683 {
00684 name = "skymethod";
00685 full_name = uves_sprintf("%s.%s", UVES_EXTRACT_ID, name);
00686
00687 uves_parameter_new_enum(p, full_name,
00688 CPL_TYPE_STRING,
00689 "In optimal extraction mode, the sky subtraction method "
00690 "to use. 'median' estimates the sky as the median of pixels "
00691 "along the slit (ignoring pixels close to the object), whereas "
00692 "'optimal' does a chi square minimization along the slit "
00693 "to obtain the best combined object and sky levels. The optimal "
00694 "method gives the most accurate sky determination but is also "
00695 "a bit slower than the median method",
00696 UVES_EXTRACT_ID,
00697 "optimal",
00698 2,
00699 "median",
00700 "optimal");
00701
00702 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, name);
00703 cpl_parameterlist_append(parameters, p);
00704 cpl_free(full_name);
00705 }
00706
00707 {
00708 name = "oversample";
00709 full_name = uves_sprintf("%s.%s", UVES_EXTRACT_ID, name);
00710
00711 uves_parameter_new_range(p, full_name,
00712 CPL_TYPE_INT,
00713 "The oversampling factor used for the virtual "
00714 "resampling algorithm. If negative, the value 5 is "
00715 "used for S/N <=200, and the value 10 is used if the estimated "
00716 "S/N is > 200",
00717 UVES_EXTRACT_ID,
00718 -1,
00719 -2, INT_MAX);
00720
00721 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, name);
00722 cpl_parameterlist_append(parameters, p);
00723 cpl_free(full_name);
00724 }
00725
00726 {
00727 name = "best";
00728 full_name = uves_sprintf("%s.%s", UVES_EXTRACT_ID, name);
00729
00730 uves_parameter_new_value(p, full_name,
00731 CPL_TYPE_BOOL,
00732 "(optimal extraction only) "
00733 "If false (fastest), the spectrum is extracted only once. "
00734 "If true (best), the spectrum is extracted twice, the "
00735 "second time using improved variance estimates "
00736 "based on the first iteration. Better variance "
00737 "estimates slightly improve the obtained signal to "
00738 "noise but at the cost of increased execution time",
00739 UVES_EXTRACT_ID,
00740 true);
00741
00742 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, name);
00743 cpl_parameterlist_append(parameters, p);
00744 cpl_free(full_name);
00745 }
00746
00747 if (cpl_error_get_code() != CPL_ERROR_NONE)
00748 {
00749 cpl_msg_error(__func__, "Creation of extraction parameters failed: '%s'",
00750 cpl_error_get_where());
00751 cpl_parameterlist_delete(parameters);
00752 return NULL;
00753 }
00754 else
00755 {
00756 return parameters;
00757 }
00758 }
00759
00760
00761
00762
00772
00773 extract_method
00774 uves_get_extract_method(const cpl_parameterlist *parameters,
00775 const char *context, const char *subcontext)
00776 {
00777 const char *method = "";
00778 extract_method result = 0;
00779
00780 check( uves_get_parameter(parameters, context, subcontext, "method",
00781 CPL_TYPE_STRING, &method),
00782 "Could not read parameter");
00783
00784 if (strcmp(method, "average" ) == 0) result = EXTRACT_AVERAGE;
00785 else if (strcmp(method, "linear" ) == 0) result = EXTRACT_LINEAR;
00786 else if (strcmp(method, "2d" ) == 0) result = EXTRACT_2D;
00787 else if (strcmp(method, "weighted") == 0) result = EXTRACT_WEIGHTED;
00788 else if (strcmp(method, "optimal" ) == 0) result = EXTRACT_OPTIMAL;
00789 else
00790 {
00791 assure(false, CPL_ERROR_ILLEGAL_INPUT, "No such extraction method: '%s'", method);
00792 }
00793
00794 cleanup:
00795 return result;
00796 }
00797
00798
00879
00880 cpl_image *
00881 uves_extract(cpl_image *image,
00882 cpl_image *image_noise,
00883 const uves_propertylist *image_header,
00884 const cpl_table *ordertable,
00885 const polynomial *order_locations_raw,
00886 double slit_length,
00887 double offset,
00888 const cpl_parameterlist *parameters,
00889 const char *context,
00890 bool extract_partial,
00891 bool DEBUG,
00892 enum uves_chip chip,
00893 uves_propertylist **header,
00894 cpl_image **spectrum_noise,
00895 cpl_image **sky_spectrum,
00896 cpl_image **sky_spectrum_noise,
00897 cpl_table **cosmic_mask,
00898 cpl_image **cosmic_image,
00899 cpl_table **profile_table,
00900 cpl_image **weights,
00901 cpl_table **info_tbl,
00902 cpl_table **order_trace)
00903 {
00904 cpl_image *spectrum = NULL;
00905 cpl_mask *spectrum_bad = NULL;
00906 cpl_binary*spectrum_badmap = NULL;
00907 cpl_image *sky_subtracted = NULL;
00908 cpl_image *temp = NULL;
00909 cpl_image *reconstruct = NULL;
00910 slit_geometry sg;
00911
00912
00913 extract_method method;
00914 double kappa;
00915 int chunk;
00916 const char *p_method;
00917 int sampling_factor;
00918 bool best;
00919 bool optimal_extract_sky;
00920 int (*prof_func) (const double x[], const double a[], double *result) = NULL;
00921 int (*prof_func_der)(const double x[], const double a[], double result[]) = NULL;
00922 int prof_pars = 0;
00923
00924 polynomial *order_locations = NULL;
00925
00926 int n_traces;
00927
00928
00929 int iteration, trace;
00930 int n_iterations;
00931 int cr_row = 0;
00932 int prof_row = 0;
00933 uves_extract_profile *profile = NULL;
00934 uves_iterate_position *pos = NULL;
00935
00936
00937 assure(image != NULL, CPL_ERROR_NULL_INPUT, "Missing input image");
00938
00939 assure( spectrum_noise == NULL || image_noise != NULL, CPL_ERROR_DATA_NOT_FOUND,
00940 "Need image noise in order to calculate spectrum errors");
00941 assure( ordertable != NULL, CPL_ERROR_NULL_INPUT, "Missing order table");
00942 assure( order_locations_raw != NULL, CPL_ERROR_NULL_INPUT, "Missing order polynomial");
00943 assure( parameters != NULL, CPL_ERROR_NULL_INPUT, "Null parameter list");
00944 assure( context != NULL, CPL_ERROR_NULL_INPUT, "Missing context string!");
00945 assure( cpl_table_has_column(ordertable, "Order"),
00946 CPL_ERROR_DATA_NOT_FOUND, "No 'Order' column in order table!");
00947 passure( uves_polynomial_get_dimension(order_locations_raw) == 2, "%d",
00948 uves_polynomial_get_dimension(order_locations));
00949 assure( slit_length > 0, CPL_ERROR_ILLEGAL_INPUT,
00950 "Slit length must a be positive number! It is %e", slit_length);
00951
00952 assure( (sky_spectrum == NULL) == (sky_spectrum_noise == NULL), CPL_ERROR_INCOMPATIBLE_INPUT,
00953 "Need 0 or 2 of sky spectrum + sky noise spectrum");
00954
00955
00956 sg.length = slit_length;
00957 sg.offset = offset;
00958
00959
00960 check( uves_get_parameter(parameters, context, UVES_EXTRACT_ID,
00961 "kappa" , CPL_TYPE_DOUBLE, &kappa) ,
00962 "Could not read parameter");
00963 check( uves_get_parameter(parameters, context, UVES_EXTRACT_ID,
00964 "chunk" , CPL_TYPE_INT, &chunk) ,
00965 "Could not read parameter");
00966
00967 check_nomsg( method = uves_get_extract_method(parameters, context, UVES_EXTRACT_ID) );
00968
00969 {
00970 char *s_method;
00971
00972 check( uves_get_parameter(parameters, context, UVES_EXTRACT_ID,
00973 "skymethod", CPL_TYPE_STRING, &s_method),
00974 "Could not read parameter");
00975 if (strcmp(s_method, "median" ) == 0) optimal_extract_sky = false;
00976 else if (strcmp(s_method, "optimal") == 0) optimal_extract_sky = true;
00977 else
00978 {
00979 assure( false, CPL_ERROR_ILLEGAL_INPUT,
00980 "Unrecognized sky extraction method: '%s'", s_method);
00981 }
00982
00983 }
00984
00985 {
00986 int minorder, maxorder;
00987 check(( minorder = cpl_table_get_column_min(ordertable, "Order"),
00988 maxorder = cpl_table_get_column_max(ordertable, "Order")),
00989 "Error getting order range");
00990
00991 pos = uves_iterate_new(cpl_image_get_size_x(image),
00992 cpl_image_get_size_y(image),
00993 order_locations_raw,
00994 minorder, maxorder, sg);
00995
00996 }
00997
00998 if (method == EXTRACT_OPTIMAL)
00999 {
01000 assure( image_noise != NULL, CPL_ERROR_ILLEGAL_INPUT,
01001 "Extraction method is optimal, but no noise image is provided");
01002
01003 assure( weights != NULL, CPL_ERROR_ILLEGAL_INPUT,
01004 "Extraction method is optimal, but no weight image is provided");
01005
01006 assure( cosmic_mask != NULL, CPL_ERROR_ILLEGAL_INPUT,
01007 "Extraction method is optimal, but no cosmic ray mask table is provided");
01008
01009 assure( cosmic_image != NULL, CPL_ERROR_ILLEGAL_INPUT,
01010 "Extraction method is optimal, but no cosmic ray mask image is provided");
01011
01012 assure( order_trace != NULL, CPL_ERROR_ILLEGAL_INPUT,
01013 "Extraction method is optimal, but no order trace table is provided");
01014
01015 assure( *weights == NULL, CPL_ERROR_ILLEGAL_INPUT,
01016 "Weight image already exists");
01017
01018 check( uves_get_parameter(parameters, context, UVES_EXTRACT_ID, "oversample",
01019 CPL_TYPE_INT, &sampling_factor),
01020 "Could not read parameter");
01021
01022 check( uves_get_parameter(parameters, context, UVES_EXTRACT_ID, "best",
01023 CPL_TYPE_BOOL, &best),
01024 "Could not read parameter");
01025
01026 check( uves_get_parameter(parameters, context, UVES_EXTRACT_ID, "profile",
01027 CPL_TYPE_STRING, &p_method),
01028 "Could not read parameter");
01029
01030 assure( strcmp(p_method, "constant") == 0 ||
01031 sky_spectrum != NULL, CPL_ERROR_ILLEGAL_INPUT,
01032 "Extraction method is optimal, but no sky spectrum is provided");
01033
01034 if (strcmp(p_method, "auto" ) == 0)
01035 {
01036
01037
01038
01039
01040 double sn_estimate;
01041
01042 check( sn_estimate = estimate_sn(image, image_noise,
01043 pos),
01044 "Could not estimate image S/N");
01045
01046 if (sn_estimate < 10)
01047 {
01048 p_method = "gauss";
01049 }
01050 else
01051 {
01052 p_method = "virtual";
01053 }
01054
01055 uves_msg("Estimated S/N is %.2f, "
01056 "auto-selecting profile measuring method '%s'", sn_estimate,
01057 p_method);
01058 }
01059
01060 if (strcmp(p_method, "gauss" ) == 0)
01061 {prof_func = uves_gauss ; prof_func_der = uves_gauss_derivative ; prof_pars = 4;}
01062 else if (strcmp(p_method, "moffat" ) == 0)
01063 {prof_func = uves_moffat; prof_func_der = uves_moffat_derivative; prof_pars = 5;}
01064 else if (strcmp(p_method, "virtual") == 0)
01065 {prof_func = NULL ; prof_func_der = NULL ; prof_pars = 0;}
01066 else if (strcmp(p_method, "constant") != 0)
01067 {
01068 assure( false, CPL_ERROR_ILLEGAL_INPUT,
01069 "Unrecognized profile method: '%s'", p_method);
01070 }
01071
01072 assure( sampling_factor != 0, CPL_ERROR_ILLEGAL_INPUT,
01073 "Illegal oversampling factor = %d", sampling_factor);
01074
01075 if (strcmp(p_method, "virtual") == 0 && sampling_factor < 0)
01076
01077 {
01078 double sn_estimate;
01079
01080 check( sn_estimate = estimate_sn(image, image_noise,
01081 pos),
01082 "Could not estimate image S/N");
01083
01084 if (sn_estimate <= 200)
01085 {
01086 sampling_factor = 5;
01087 }
01088 else
01089 {
01090 sampling_factor = 10;
01091 }
01092
01093 uves_msg("Estimated S/N is %.2f, "
01094 "auto-selecting oversampling factor = %d", sn_estimate,
01095 sampling_factor);
01096 }
01097 }
01098
01099 assure( method != EXTRACT_WEIGHTED || weights != NULL, CPL_ERROR_ILLEGAL_INPUT,
01100 "Extraction method is weighted, but no weight image is provided");
01101
01102 if (method == EXTRACT_2D)
01103 {
01104
01105 n_traces = uves_round_double(slit_length);
01106
01107 assure( n_traces % 2 == 0, CPL_ERROR_ILLEGAL_INPUT,
01108 "For 2d extraction slit length (%d) must be an even number", n_traces);
01109 }
01110 else
01111 {
01112 n_traces = 1;
01113 }
01114
01115 if (method == EXTRACT_2D)
01116 {
01117 uves_msg_low("Slit length = %.1f pixels", slit_length);
01118 }
01119 else
01120 {
01121 uves_msg_low("Slit length = %.1f pixels; offset = %.1f pixel(s)",
01122 sg.length, sg.offset);
01123 }
01124
01125
01126 check(( spectrum = cpl_image_new(pos->nx,
01127 n_traces*(pos->maxorder - pos->minorder + 1),
01128 CPL_TYPE_DOUBLE),
01129 spectrum_bad = cpl_image_get_bpm(spectrum),
01130 spectrum_badmap = cpl_mask_get_data(spectrum_bad)),
01131 "Error creating spectrum image");
01132
01133
01134 if (spectrum_noise != NULL)
01135 {
01136 check( *spectrum_noise = cpl_image_new(cpl_image_get_size_x(spectrum),
01137 cpl_image_get_size_y(spectrum),
01138 CPL_TYPE_DOUBLE),
01139 "Could not create image");
01140 }
01141
01142 if (info_tbl != NULL &&
01143 (method == EXTRACT_LINEAR || method == EXTRACT_AVERAGE ||
01144 method == EXTRACT_OPTIMAL)
01145 )
01146 {
01147 *info_tbl = cpl_table_new(pos->maxorder-pos->minorder+1);
01148 cpl_table_new_column(*info_tbl, "Order", CPL_TYPE_INT);
01149 cpl_table_new_column(*info_tbl, "S/N", CPL_TYPE_DOUBLE);
01150 cpl_table_new_column(*info_tbl, "Ripple", CPL_TYPE_DOUBLE);
01151
01152
01153
01154
01155 cpl_table_new_column(*info_tbl, "Pos", CPL_TYPE_DOUBLE);
01156 cpl_table_new_column(*info_tbl, "FWHM", CPL_TYPE_DOUBLE);
01157 }
01158
01159
01160 if (method == EXTRACT_OPTIMAL)
01161 {
01162
01163 check( *weights = cpl_image_new(pos->nx, pos->ny, CPL_TYPE_DOUBLE),
01164 "Could not allocate weight image");
01165
01166
01167 check(( *cosmic_mask = cpl_table_new(1),
01168 cpl_table_new_column(*cosmic_mask, "Order", CPL_TYPE_INT),
01169 cpl_table_new_column(*cosmic_mask, "X" , CPL_TYPE_INT),
01170 cpl_table_new_column(*cosmic_mask, "Y" , CPL_TYPE_INT),
01171 cpl_table_new_column(*cosmic_mask, "Flux" , CPL_TYPE_DOUBLE),
01172 cr_row = 0),
01173 "Error creating cosmic ray table");
01174
01175 if (profile_table != NULL)
01176 {
01177 check( (*profile_table = cpl_table_new((pos->maxorder - pos->minorder + 1) *
01178 pos->nx *
01179 (3+uves_round_double(sg.length))),
01180 cpl_table_new_column(*profile_table, "Order" , CPL_TYPE_INT),
01181 cpl_table_new_column(*profile_table, "X" , CPL_TYPE_INT),
01182 cpl_table_new_column(*profile_table, "DY" , CPL_TYPE_DOUBLE),
01183 cpl_table_new_column(*profile_table, "Profile_raw", CPL_TYPE_DOUBLE),
01184 cpl_table_new_column(*profile_table, "Profile_int", CPL_TYPE_DOUBLE)),
01185 "Error creating profile table");
01186 prof_row = 0;
01187 }
01188
01189 if (strcmp(p_method, "constant") != 0) {
01190 check( *sky_spectrum = cpl_image_new(
01191 pos->nx, pos->maxorder - pos->minorder + 1, CPL_TYPE_DOUBLE),
01192 "Could not allocate sky spectrum");
01193 check( *sky_spectrum_noise = cpl_image_new(
01194 pos->nx, pos->maxorder - pos->minorder + 1, CPL_TYPE_DOUBLE),
01195 "Could not allocate sky spectrum noise");
01196 }
01197 }
01198
01199 if (method == EXTRACT_OPTIMAL &&
01200 strcmp(p_method, "constant") != 0 && prof_func == NULL)
01201 {
01202
01203
01204
01205
01206
01207
01208
01209
01210 uves_msg("Refining order definition using the object frame");
01211
01212 check( order_locations = repeat_orderdef(image, image_noise, order_locations_raw,
01213 pos->minorder, pos->maxorder,
01214 pos->sg,
01215 *info_tbl),
01216 "Could not refine order definition");
01217 }
01218 else
01219 {
01220 order_locations = uves_polynomial_duplicate(order_locations_raw);
01221 }
01222
01223 pos->order_locations = order_locations;
01224
01225
01226
01227
01228
01229
01230
01231
01232
01233
01234
01235
01236
01237
01238 if (method == EXTRACT_OPTIMAL)
01239 {
01240 if (strcmp(p_method, "constant") == 0) {
01241
01242 uves_msg("Assuming constant spatial profile");
01243
01244 profile = uves_extract_profile_new_constant(sg.length);
01245
01246
01247 sky_subtracted = cpl_image_duplicate(image);
01248 optimal_extract_sky = false;
01249
01250 }
01251 else {
01252 check( sky_subtracted = opt_extract_sky(
01253 image, image_noise, *weights,
01254 pos,
01255 *sky_spectrum,
01256 *sky_spectrum_noise),
01257 "Could not extract sky");
01258
01259 if (prof_func != NULL)
01260 {
01261 uves_msg("Measuring spatial profile "
01262 "(method = %s, chunk = %d bins)",
01263 p_method, chunk);
01264 }
01265 else
01266 {
01267 uves_msg("Measuring spatial profile "
01268 "(method = %s, oversampling = %d)",
01269 p_method, sampling_factor);
01270 }
01271
01272 uves_extract_profile_delete(&profile);
01273
01274
01275 check( profile = opt_measure_profile(sky_subtracted, image_noise, *weights,
01276 pos,
01277 chunk, sampling_factor,
01278 prof_func, prof_func_der, prof_pars,
01279 *sky_spectrum,
01280 *info_tbl,
01281 order_trace),
01282 "Could not measure profile");
01283
01284
01285
01286
01287
01288
01289
01290 }
01291 }
01292
01293
01294 passure( method == EXTRACT_2D || n_traces == 1, "%d", n_traces);
01295
01296 n_iterations = (method == EXTRACT_OPTIMAL &&
01297 best &&
01298 strcmp(p_method, "constant") != 0) ? 2 : 1;
01299
01300 for (iteration = 1;
01301 iteration <= n_iterations;
01302 iteration++)
01303 {
01304 uves_msg("Extracting object %s(method = %s)",
01305 (method == EXTRACT_OPTIMAL && optimal_extract_sky)
01306 ? "and sky " : "",
01307 (method == EXTRACT_OPTIMAL) ? "optimal" :
01308 (method == EXTRACT_AVERAGE) ? "average" :
01309 (method == EXTRACT_LINEAR ) ? "linear" :
01310 (method == EXTRACT_2D ) ? "2d" :
01311 (method == EXTRACT_WEIGHTED) ? "weighted" : "???");
01312
01313
01314 cr_row = 0;
01315 prof_row = 0;
01316 for (pos->order = pos->minorder; pos->order <= pos->maxorder; pos->order++) {
01317 for (trace = 1; trace <= n_traces; trace++) {
01318 int spectrum_row;
01319 int bins_extracted;
01320
01321 double sn = 0;
01322
01323 spectrum_row = (pos->order - pos->minorder)*n_traces + trace;
01324
01325
01326 if (method == EXTRACT_OPTIMAL)
01327 {
01328
01329
01330
01331
01332
01333 check( bins_extracted = opt_extract(
01334 optimal_extract_sky ?
01335 image : sky_subtracted,
01336 image_noise,
01337 pos,
01338 profile,
01339 optimal_extract_sky,
01340 kappa,
01341 *cosmic_mask, &cr_row,
01342 (profile_table != NULL) ?
01343 *profile_table : NULL,
01344 &prof_row,
01345 spectrum,
01346 (spectrum_noise != NULL) ?
01347 *spectrum_noise : NULL,
01348 *weights,
01349 optimal_extract_sky ? *sky_spectrum : NULL,
01350 optimal_extract_sky ? *sky_spectrum_noise : NULL,
01351 &sn),
01352 "Error extracting order #%d", pos->order);
01353 }
01354 else
01355 {
01356
01357
01358
01359
01360
01361
01362
01363
01364
01365
01366
01367
01368
01369 double offset_2d = trace - (n_traces+1)/2.0;
01370 double slit_2d = 1;
01371
01372 check( bins_extracted = extract_order_simple(
01373 image, image_noise,
01374 order_locations,
01375 pos->order, pos->minorder,
01376 spectrum_row,
01377 (method == EXTRACT_2D) ? offset_2d : sg.offset,
01378 (method == EXTRACT_2D) ? slit_2d : sg.length,
01379 (method == EXTRACT_2D) ? EXTRACT_LINEAR : method,
01380 (weights != NULL) ? *weights : NULL,
01381 extract_partial,
01382 spectrum,
01383 (spectrum_noise != NULL) ? *spectrum_noise : NULL,
01384 spectrum_badmap,
01385 info_tbl,
01386 &sn),
01387 "Could not extract order #%d ; trace #%d",
01388 pos->order, trace);
01389 }
01390
01391
01392 if (info_tbl != NULL &&
01393 (method == EXTRACT_LINEAR || method == EXTRACT_AVERAGE ||
01394 method == EXTRACT_OPTIMAL)
01395 )
01396 {
01397
01398 double ripple_index = detect_ripples(spectrum, pos, sn);
01399 uves_msg("Order #%d: S/N = %.2f",
01400 pos->order, sn);
01401 uves_msg_debug("Ripple index = %.2f (should be less than 2)",
01402 ripple_index);
01403
01404 if (false && ripple_index > 3) {
01405
01406
01407
01408
01409 uves_msg_warning("Short period ripples detected (index = %f). "
01410 "It might help to use average or linear extraction "
01411 "or optimal/virtual extraction with larger "
01412 "oversampling factor", ripple_index);
01413 }
01414
01415 cpl_table_set_int (*info_tbl, "Order",
01416 pos->order - pos->minorder, pos->order);
01417 cpl_table_set_double(*info_tbl, "S/N" ,
01418 pos->order - pos->minorder, sn);
01419 cpl_table_set_double(*info_tbl, "Ripple",
01420 pos->order - pos->minorder,
01421 (ripple_index > -0.5) ? ripple_index : -1);
01422 }
01423
01424 uves_msg_debug(
01425 "Order #%d; trace #%d: %d of %d bins extracted",
01426 pos->order, trace, bins_extracted, pos->nx);
01427
01428 }
01429
01430 }
01431
01432
01433 if (method == EXTRACT_OPTIMAL)
01434 {
01435 if (spectrum_noise != NULL)
01436 {
01437 uves_free_image(&temp);
01438 temp = cpl_image_divide_create(spectrum, *spectrum_noise);
01439 uves_msg("Average S/N = %.3f", cpl_image_get_median(temp));
01440 }
01441
01442 if (iteration == 1 && n_iterations >= 2)
01443 {
01444
01445 uves_msg_low("Recomputing pixel variances");
01446
01447 check( revise_noise(image_noise,
01448 cpl_mask_get_data(
01449 cpl_image_get_bpm(sky_subtracted)),
01450 image_header, pos,
01451 spectrum, *sky_spectrum, profile,
01452 chip),
01453 "Error refining input image variances");
01454 }
01455 }
01456
01457 }
01458
01459
01460 if (method == EXTRACT_OPTIMAL)
01461 {
01462 int i;
01463
01464 check( cpl_table_set_size(*cosmic_mask, cr_row),
01465 "Error setting cosmic ray table size to %d", cr_row);
01466
01467 *cosmic_image = cpl_image_new(pos->nx, pos->ny, CPL_TYPE_DOUBLE);
01468 assure_mem(*cosmic_image);
01469
01470 for (i = 0; i < cpl_table_get_nrow(*cosmic_mask); i++)
01471 {
01472 cpl_image_set(*cosmic_image,
01473 cpl_table_get_int(*cosmic_mask, "X", i, NULL),
01474 cpl_table_get_int(*cosmic_mask, "Y", i, NULL),
01475 cpl_table_get_double(*cosmic_mask, "Flux", i, NULL));
01476 }
01477
01478 if (profile_table != NULL)
01479 {
01480 check( cpl_table_set_size(*profile_table, prof_row),
01481 "Error setting profile table size to %d", prof_row);
01482 }
01483
01484
01485
01486
01487
01488 check( cpl_image_threshold(*weights,
01489 0, DBL_MAX,
01490 0, DBL_MAX),
01491 "Error thresholding weight image");
01492
01493
01494
01495
01496
01497
01498
01499 {
01500 double *weights_data = cpl_image_get_data_double(*weights);
01501
01502 for (uves_iterate_set_first(pos,
01503 1, pos->nx,
01504 pos->minorder, pos->maxorder,
01505 NULL, false);
01506 !uves_iterate_finished(pos);
01507 uves_iterate_increment(pos))
01508 {
01509 double sum_weights = 0.0;
01510
01511 for (pos->y = pos->ylow; pos->y <= pos->yhigh; pos->y++)
01512 {
01513 double weight = DATA(weights_data, pos);
01514 sum_weights += weight;
01515 }
01516
01517 for (pos->y = pos->ylow; pos->y <= pos->yhigh; pos->y++)
01518 {
01519 if (sum_weights > 0)
01520 {
01521 DATA(weights_data, pos) /= sum_weights;
01522 }
01523 }
01524 }
01525 }
01526 }
01527
01528
01529 uves_msg_debug("Rejecting %d bins", cpl_mask_count(spectrum_bad));
01530
01531 if (spectrum_noise != NULL)
01532 {
01533 check( cpl_image_reject_from_mask(*spectrum_noise, spectrum_bad),
01534 "Error setting bad pixels");
01535 }
01536
01537
01538 if (header != NULL)
01539 {
01540
01541 check( *header = uves_initialize_image_header(
01542 "PIXEL", (method == EXTRACT_2D) ? "PIXEL" : "ORDER",
01543 "FLUX",
01544 1.0, pos->minorder,
01545 1.0, 1.0,
01546 1.0, 1.0),
01547 "Error initializing spectrum header");
01548 }
01549
01550 if (DEBUG && header != NULL) {
01551 if (profile == NULL) {
01552
01553
01554 profile = uves_extract_profile_new_constant(sg.length);
01555 }
01556
01557 check_nomsg( reconstruct =
01558 uves_create_image(pos, chip,
01559 spectrum,
01560 sky_spectrum != NULL ? *sky_spectrum : NULL,
01561 cosmic_image != NULL ? *cosmic_image : NULL,
01562 profile,
01563 NULL, NULL));
01564
01565 check( uves_save_image_local("Reconstructed image", "simulate",
01566 reconstruct, chip, -1, -1, *header, true),
01567 "Error saving image");
01568
01569 }
01570
01571 if (spectrum_noise != NULL)
01572 {
01573 int x, y;
01574
01575
01576
01577
01578
01579
01580
01581
01582
01583
01584 assure( cpl_image_get_min(*spectrum_noise) > 0, CPL_ERROR_ILLEGAL_OUTPUT,
01585 "Non-positive noise: %e at (%d, %d)",
01586 cpl_image_get_min(*spectrum_noise),
01587 (cpl_image_get_minpos(*spectrum_noise, &x, &y), x),
01588 (cpl_image_get_minpos(*spectrum_noise, &x, &y), y));
01589
01590
01591
01592
01593
01594
01595 }
01596
01597 cleanup:
01598 uves_free_image(&reconstruct);
01599 uves_free_image(&sky_subtracted);
01600 uves_extract_profile_delete(&profile);
01601 uves_polynomial_delete(&order_locations);
01602 uves_iterate_delete(&pos);
01603 uves_free_image(&temp);
01604
01605 if (cpl_error_get_code() != CPL_ERROR_NONE)
01606 {
01607 uves_free_image(&spectrum);
01608 uves_free_image(spectrum_noise);
01609 uves_free_table(profile_table);
01610 }
01611
01612 return spectrum;
01613 }
01614
01615
01625
01626 static double
01627 detect_ripples(const cpl_image *spectrum, const uves_iterate_position *pos,
01628 double sn)
01629 {
01630 double ratio = -1;
01631 int n_traces = 1;
01632 int trace = 1;
01633 int nx = cpl_image_get_size_x(spectrum);
01634 cpl_image *spectrum_order = NULL;
01635 cpl_vector *tempx = NULL;
01636 cpl_vector *tempy = NULL;
01637 double *auto_corr = NULL;
01638
01639 int spectrum_row = (pos->order - pos->minorder)*n_traces + trace;
01640 int n_rejected;
01641
01642 uves_free_image(&spectrum_order);
01643
01644 check( spectrum_order = cpl_image_extract(spectrum,
01645 1, spectrum_row,
01646 nx, spectrum_row),
01647 "Error extracting order %d from spectrum", pos->order);
01648
01649 n_rejected = cpl_image_count_rejected(spectrum_order);
01650 uves_msg_debug("Order %d: %d/%d invalid values", pos->order,
01651 n_rejected,
01652 nx);
01653
01654 if (n_rejected == 0)
01655
01656 {
01657 double order_slope =
01658 uves_polynomial_derivative_2d(pos->order_locations, nx/2, pos->order, 1);
01659
01660 int expected_period = uves_round_double(1.0/order_slope);
01661 int max_period = 2*expected_period;
01662 int shift;
01663
01664 uves_msg_debug("Estimated ripple period = %d pixels", expected_period);
01665
01666 auto_corr = cpl_calloc(sizeof(double), 1+max_period);
01667
01668 for (shift = 0; shift <= max_period; shift += 1) {
01669 int N = 0;
01670 int x;
01671
01672 auto_corr[shift] = 0;
01673
01674 for (x = 1; x <= nx - max_period; x++) {
01675 int rejected1, rejected2;
01676 double val1, val2;
01677
01678 val1 = cpl_image_get(spectrum_order, x, 1, &rejected1);
01679 val2 = cpl_image_get(spectrum_order, x+shift, 1, &rejected2);
01680
01681 if (!rejected1 && !rejected2)
01682 {
01683 auto_corr[shift] += val1*val2;
01684 N++;
01685 }
01686 }
01687
01688 if (N != 0)
01689 {
01690 auto_corr[shift] /= N;
01691 }
01692 else
01693 {
01694 auto_corr[shift] = 0;
01695 }
01696
01697 if (shift > 0 && auto_corr[0] > 0)
01698 {
01699 auto_corr[shift] /= auto_corr[0];
01700 }
01701
01702 uves_msg_debug("Auto-correlation (%d pixels, %d samples) = %f",
01703 shift, N, (shift == 0) ? 1 : auto_corr[shift]);
01704 }
01705 auto_corr[0] = 1;
01706
01707
01708 {
01709
01710 double auto_amplitude;
01711 int imax = expected_period;
01712 int imin1 = expected_period/2;
01713 int imin2 = (expected_period*3)/2;
01714
01715
01716
01717
01718
01719 auto_amplitude = auto_corr[imax] -
01720 (auto_corr[imin1] + auto_corr[imin2])/2.0;
01721
01722
01723
01724
01725
01726
01727
01728
01729
01730
01731
01732
01733
01734 if (auto_amplitude > 0 && sn > 0)
01735 {
01736 double rel_ripple = sqrt(auto_amplitude);
01737 uves_msg_debug("Order %d: Relative ripple amplitude = %f, "
01738 "relative error bars = %f",
01739 pos->order, rel_ripple, 2.0*1/sn);
01740
01741 ratio = rel_ripple * sn/2.0;
01742 }
01743 }
01744 }
01745
01746 cleanup:
01747 uves_free_double(&auto_corr);
01748 uves_free_vector(&tempx);
01749 uves_unwrap_vector(&tempy);
01750 uves_free_image(&spectrum_order);
01751
01752
01753 return ratio;
01754 }
01755
01756
01768
01769 static double
01770 estimate_sn(const cpl_image *image, const cpl_image *image_noise,
01771 uves_iterate_position *pos)
01772 {
01773 double sn = -1;
01774 int range = 5;
01775 cpl_table *sn_temp = NULL;
01776 cpl_table *sky_temp = NULL;
01777 int sn_row, sky_row;
01778 int sky_size = 2 + 2*uves_round_double(pos->sg.length);
01779
01780
01781
01782 passure( image_noise != NULL, " ");
01783
01784 assure( pos->nx >= 2*(range+1), CPL_ERROR_ILLEGAL_INPUT,
01785 "Input image is too small. Width = %d", pos->nx);
01786
01787 sn_temp = cpl_table_new((pos->maxorder - pos->minorder + 1) * (2*range + 1));
01788 cpl_table_new_column(sn_temp, "SN", CPL_TYPE_DOUBLE);
01789 sn_row = 0;
01790
01791 sky_temp = cpl_table_new(sky_size);
01792 cpl_table_new_column(sky_temp, "Sky", CPL_TYPE_DOUBLE);
01793
01794 for (uves_iterate_set_first(pos,
01795 pos->nx/2 - range, pos->nx/2 + range,
01796 pos->minorder, pos->maxorder,
01797 NULL, false);
01798 !uves_iterate_finished(pos);
01799 uves_iterate_increment(pos))
01800 {
01801 double flux = 0;
01802 double error = 0;
01803 int N = 0;
01804
01805 sky_row = 0;
01806
01807 for (pos->y = pos->ylow; pos->y <= pos->yhigh; pos->y++)
01808 {
01809 int pis_rejected1, pis_rejected2;
01810 double pixel = cpl_image_get(image,
01811 pos->x, pos->y, &pis_rejected1);
01812 double pixel_noise = cpl_image_get(image_noise,
01813 pos->x, pos->y, &pis_rejected2);
01814
01815 if (!pis_rejected1 && !pis_rejected2)
01816 {
01817 flux += pixel;
01818 error += pixel_noise*pixel_noise;
01819 N++;
01820
01821 cpl_table_set_double(sky_temp, "Sky",
01822 sky_row, pixel);
01823 sky_row++;
01824 }
01825 }
01826
01827 if (N > 0)
01828 {
01829 double sky;
01830
01831 while(sky_row < sky_size)
01832
01833 {
01834 cpl_table_set_invalid(sky_temp, "Sky",
01835 sky_row);
01836
01837 sky_row++;
01838 }
01839
01840 sky = cpl_table_get_column_median(sky_temp, "Sky");
01841
01842 flux = flux - N*sky;
01843 error = sqrt(error);
01844
01845
01846 if (error > 0)
01847 {
01848 uves_msg_debug("Order %d: S/N estimate = %f",
01849 pos->order, flux/error);
01850
01851 cpl_table_set_double(sn_temp, "SN",
01852 sn_row, flux/error);
01853 sn_row++;
01854 }
01855 }
01856 }
01857
01858 assure(sn_row > 0, CPL_ERROR_DATA_NOT_FOUND,
01859 "Extraction of central bins failed!");
01860
01861 cpl_table_set_size(sn_temp, sn_row);
01862
01863 sn = cpl_table_get_column_median(sn_temp, "SN");
01864
01865 cleanup:
01866 uves_free_table(&sn_temp);
01867 uves_free_table(&sky_temp);
01868 return sn;
01869 }
01870
01871
01903
01904
01905 static int
01906 extract_order_simple(const cpl_image *image,
01907 const cpl_image *image_noise,
01908 const polynomial *order_locations,
01909 int order,
01910 int minorder,
01911 int spectrum_row,
01912 double offset,
01913 double slit_length,
01914 extract_method method,
01915 const cpl_image *weights,
01916 bool extract_partial,
01917 cpl_image *spectrum,
01918 cpl_image *spectrum_noise,
01919 cpl_binary*spectrum_badmap,
01920 cpl_table **info_tbl,
01921 double *sn)
01922 {
01923 int bins_extracted = 0;
01924 double *spectrum_data;
01925 int x, nx, ny;
01926 double flux_y, flux_yy, flux_tot;
01927 int sn_row = 0;
01928
01929 cpl_table *signal_to_noise = NULL;
01930
01931 passure( method == EXTRACT_AVERAGE ||
01932 method == EXTRACT_LINEAR ||
01933 method == EXTRACT_WEIGHTED, "%d", method);
01934
01935
01936 passure( (method == EXTRACT_WEIGHTED) == (weights != NULL), "%d", method);
01937
01938 nx = cpl_image_get_size_x(image);
01939 ny = cpl_image_get_size_y(image);
01940
01941 check( (signal_to_noise = cpl_table_new(nx),
01942 cpl_table_new_column(signal_to_noise, "SN", CPL_TYPE_DOUBLE)),
01943 "Error allocating S/N table");
01944
01945 spectrum_data = cpl_image_get_data_double(spectrum);
01946
01947 flux_y = 0;
01948 flux_yy = 0;
01949 flux_tot = 0;
01950
01951 for (x = 1 ; x <= nx; x++) {
01952 double slope, ycenter;
01953 int ylo, yhi;
01954 double flux = 0;
01955 double flux_variance = 0;
01956 double sum = 0;
01957 int y;
01958
01959
01960 check(( slope = (uves_polynomial_evaluate_2d(order_locations, x+1, order) -
01961 uves_polynomial_evaluate_2d(order_locations, x-1, order) ) / 2,
01962
01963 ycenter = uves_polynomial_evaluate_2d(order_locations, x, order) + offset),
01964 "Error evaluating polynomial");
01965
01966 assure( 0 < slope && slope < 1, CPL_ERROR_ILLEGAL_INPUT,
01967 "At (x, order)=(%d, %d) slope is %f. Must be positive", x, order, slope);
01968
01969
01970 ylo = uves_round_double(ycenter - slit_length/2 - 0.5*slope);
01971 yhi = uves_round_double(ycenter + slit_length/2 + 0.5*slope);
01972
01973
01974 if (ylo < 1 || ny < yhi)
01975 {
01976 if (extract_partial)
01977 {
01978 ylo = uves_max_int(ylo, 1);
01979 yhi = uves_min_int(yhi, ny);
01980 }
01981 else
01982 {
01983
01984 ylo = yhi + 1;
01985 }
01986 }
01987
01988
01989 for (y = ylo; y <= yhi; y++) {
01990
01991 int pis_rejected;
01992 double pixelval;
01993 double pixelvariance;
01994 double weight;
01995
01996
01997 pixelval = cpl_image_get(image, x, y, &pis_rejected);
01998
01999
02000
02001
02002
02003
02004
02005 if (spectrum_noise != NULL && !pis_rejected)
02006 {
02007 pixelvariance = cpl_image_get(image_noise, x, y, &pis_rejected);
02008 pixelvariance *= pixelvariance;
02009 }
02010 else
02011 {
02012 pixelvariance = 1;
02013 }
02014
02015 if (!pis_rejected) {
02016
02017 if (method == EXTRACT_WEIGHTED)
02018 {
02019
02020
02021
02022 weight = cpl_image_get(weights, x, y, &pis_rejected);
02023
02024 assure( weight >= 0, CPL_ERROR_ILLEGAL_INPUT,
02025 "Illegal weight: %e at (x, y) = (%d, %d)",
02026 weight, x, y);
02027
02028 if (weight == 0)
02029 {
02030
02031
02032
02033
02034 }
02035 }
02036 else if (method == EXTRACT_ARCLAMP) {
02037 weight = 1.0 / pixelvariance;
02038 }
02039 else {
02040
02041 double area_outside_order_top;
02042 double area_outside_order_bottom;
02043 double left = ycenter + slit_length/2 - 0.5*slope;
02044 double right = ycenter + slit_length/2 + 0.5*slope;
02045
02046 check( area_outside_order_top =
02047 area_above_line(y, left, right),
02048 "Error calculating area");
02049
02050 left = ycenter - slit_length/2 - 0.5*slope;
02051 right = ycenter - slit_length/2 + 0.5*slope;
02052
02053 check( area_outside_order_bottom =
02054 1 - area_above_line(y, left, right),
02055 "Error calculationg area");
02056
02057 weight = 1 - (area_outside_order_top + area_outside_order_bottom);
02058
02059 if (1 < y && y < ny && weight < 1)
02060 {
02061
02062
02063
02064
02065
02066
02067
02068
02069
02070
02071
02072
02073
02074
02075
02076
02077
02078
02079
02080
02081
02082 int pis_rejected_prev, pis_rejected_next;
02083
02084
02085
02086 double flux_minus = (pixelval + cpl_image_get(
02087 image, x, y - 1, &pis_rejected_prev)) / 2.0;
02088 double flux_plus = (pixelval + cpl_image_get(
02089 image, x, y + 1, &pis_rejected_next)) / 2.0;
02090 if (!pis_rejected_prev && !pis_rejected_next)
02091 {
02092
02093
02094
02095
02096
02097
02098
02099
02100 double flux_center =
02101 2*pixelval - (flux_minus + flux_plus) / 2.0;
02102
02103
02104 double slope_minus =
02105 (flux_center - flux_minus )/ 0.5;
02106 double slope_plus =
02107 (flux_plus - flux_center) / 0.5;
02108
02109
02110 double lo1 =
02111 uves_min_double(0, -0.5 + area_outside_order_bottom);
02112 double hi1 =
02113 uves_min_double(0, 0.5 - area_outside_order_top );
02114 double dy1 = hi1-lo1;
02115
02116
02117 double lo2 =
02118 uves_max_double(0, -0.5 + area_outside_order_bottom);
02119 double hi2 =
02120 uves_max_double(0, 0.5 - area_outside_order_top );
02121 double dy2 = hi2-lo2;
02122
02123 if (dy1 + dy2 > 0)
02124 {
02125
02126 pixelval = (
02127 (flux_center + slope_minus * (lo1+hi1)/2.0) * dy1
02128 +
02129 (flux_center + slope_plus * (lo2+hi2)/2.0) * dy2
02130 ) / (dy1 + dy2);
02131
02132
02133
02134
02135 }
02136
02137 }
02138 }
02139 else
02140 {
02141
02142 }
02143 }
02144
02145
02146
02147
02148
02149
02150
02151
02152
02153
02154
02155
02156
02157
02158
02159
02160
02161
02162
02163
02164
02165 flux += weight*pixelval;
02166 flux_variance += weight*weight * pixelvariance;
02167 sum += weight;
02168
02169
02170
02171 if (method != EXTRACT_ARCLAMP)
02172 {
02173 flux_y += weight * pixelval * (y-ylo);
02174 flux_yy += weight * pixelval * (y-ylo)*(y-ylo);
02175 flux_tot+= weight * pixelval;
02176 }
02177 }
02178 }
02179
02180
02181
02182
02183
02184
02185
02186 if (sum > 0)
02187 {
02188 bins_extracted += 1;
02189
02190 if (method == EXTRACT_ARCLAMP && flux_variance > 0) {
02191 flux *= 1.0 / sum;
02192 flux_variance = 1.0 / sum;
02193 }
02194 else if (method == EXTRACT_AVERAGE || method == EXTRACT_WEIGHTED)
02195 {
02196
02197 flux *= 1.0 / sum;
02198 flux_variance *= 1.0 / (sum*sum);
02199 }
02200 else {
02201
02202
02203
02204 flux *= slit_length / sum;
02205 flux_variance *= (slit_length*slit_length) / (sum*sum);
02206 }
02207
02208
02209
02210
02211
02212
02213
02214 spectrum_data [(x-1) + (spectrum_row-1) * nx] = flux;
02215 spectrum_badmap[(x-1) + (spectrum_row-1) * nx] = CPL_BINARY_0;
02216
02217 if (spectrum_noise != NULL)
02218 {
02219 check( cpl_image_set(
02220 spectrum_noise, x, spectrum_row, sqrt(flux_variance)),
02221 "Could not write noise at (%d, %d)", x, spectrum_row);
02222 }
02223
02224 check_nomsg( cpl_table_set_double(
02225 signal_to_noise, "SN", sn_row, flux / sqrt(flux_variance)) );
02226 sn_row++;
02227
02228 }
02229 else
02230 {
02231
02232
02233
02234
02235
02236
02237
02238
02239
02240
02241
02242
02243
02244 spectrum_badmap[(x-1) + (spectrum_row-1) * nx] = CPL_BINARY_1;
02245 }
02246
02247 }
02248
02249 if (info_tbl != NULL && *info_tbl != NULL && method != EXTRACT_ARCLAMP)
02250 {
02251 double objpos = 0;
02252 double fwhm =0;
02253 if(flux_tot != 0) {
02254 objpos = flux_y / flux_tot;
02255 } else {
02256 objpos = -1;
02257
02258 }
02259 if (flux_yy/flux_tot - objpos*objpos >= 0)
02260 {
02261 fwhm = sqrt(flux_yy/flux_tot - objpos*objpos) * TWOSQRT2LN2;
02262 }
02263 else
02264 {
02265 fwhm = 0;
02266 }
02267 cpl_table_set_double(*info_tbl, "Pos" , order - minorder, objpos);
02268 cpl_table_set_double(*info_tbl, "FWHM" , order - minorder, fwhm);
02269 }
02270
02271
02272 check_nomsg( cpl_table_set_size(signal_to_noise, sn_row) );
02273
02274 if (sn_row > 0)
02275 {
02276 check_nomsg( *sn = cpl_table_get_column_median(signal_to_noise, "SN"));
02277 }
02278 else
02279 {
02280 *sn = 0;
02281 }
02282
02283 cleanup:
02284 uves_free_table(&signal_to_noise);
02285 return bins_extracted;
02286 }
02287
02288
02302
02303 static double
02304 area_above_line(int y, double left, double right)
02305 {
02306 double area = -1;
02307 double pixeltop = y + .5;
02308 double pixelbot = y - .5;
02309 double slope = right - left;
02310
02311 assure( 0 <= slope && slope <= 1, CPL_ERROR_ILLEGAL_INPUT, "Slope is %f", slope);
02312
02313
02314
02315
02316
02317
02318
02319
02320
02321
02322
02323
02324
02325
02326
02327
02328
02329
02330
02331
02332
02333
02334
02335
02336
02337
02338
02339
02340
02341
02342
02343
02344
02345
02346
02347
02348
02349
02350
02351
02352
02353 if (pixelbot > right)
02354 {
02355 area = 1;
02356 }
02357 else if (pixelbot > left)
02358 {
02359 area = 1 -
02360 (right - pixelbot) *
02361 (right - pixelbot) / (2*slope);
02362 }
02363 else if (pixeltop > right)
02364 {
02365 area = pixeltop - (left + right)/2;
02366 }
02367 else if (pixeltop > left)
02368 {
02369 area =
02370 (pixeltop - left) *
02371 (pixeltop - left) / (2*slope);
02372 }
02373 else
02374 {
02375
02376 area = 0;
02377 }
02378
02379 cleanup:
02380 return area;
02381 }
02382
02383
02384
02400
02401
02402 static void
02403 revise_noise(cpl_image *image_noise,
02404 const cpl_binary *image_bpm,
02405 const uves_propertylist *image_header,
02406 uves_iterate_position *pos,
02407 const cpl_image *spectrum,
02408 const cpl_image *sky_spectrum,
02409 const uves_extract_profile *profile,
02410 enum uves_chip chip)
02411 {
02412 cpl_image *revised = NULL;
02413 cpl_image *simulated = NULL;
02414 const cpl_binary *spectrum_bpm =
02415 cpl_mask_get_data_const(cpl_image_get_bpm_const(spectrum));
02416 double *simul_data;
02417 const double *spectrum_data;
02418 const double *sky_data;
02419
02420 simulated = cpl_image_new(pos->nx, pos->ny,
02421 CPL_TYPE_DOUBLE);
02422 assure_mem( simulated );
02423
02424 simul_data = cpl_image_get_data_double(simulated);
02425 spectrum_data = cpl_image_get_data_double_const(spectrum);
02426 sky_data = cpl_image_get_data_double_const(sky_spectrum);
02427
02428 for (uves_iterate_set_first(pos,
02429 1, pos->nx,
02430 pos->minorder, pos->maxorder,
02431 NULL, false);
02432 !uves_iterate_finished(pos);
02433 uves_iterate_increment(pos))
02434 {
02435 if (SPECTRUM_DATA(spectrum_bpm, pos) == CPL_BINARY_0)
02436 {
02437
02438 uves_extract_profile_set(profile, pos, NULL);
02439
02440 for (pos->y = pos->ylow; pos->y <= pos->yhigh; pos->y++)
02441 if (ISGOOD(image_bpm, pos))
02442 {
02443
02444 DATA(simul_data, pos) =
02445 SPECTRUM_DATA(sky_data, pos)/pos->sg.length +
02446 SPECTRUM_DATA(spectrum_data, pos) *
02447 uves_extract_profile_evaluate(profile, pos);
02448 }
02449 }
02450 }
02451
02452
02453
02454
02455
02456 {
02457 int ncom = 1;
02458
02459
02460 check( revised = uves_define_noise(simulated,
02461 image_header,
02462 ncom, chip),
02463 "Error computing noise image");
02464 }
02465
02466
02467 {
02468 double *revised_data = cpl_image_get_data_double(revised);
02469 double *input_data = cpl_image_get_data_double(image_noise);
02470
02471 for (uves_iterate_set_first(pos,
02472 1, pos->nx,
02473 pos->minorder, pos->maxorder,
02474 image_bpm, true);
02475 !uves_iterate_finished(pos);
02476 uves_iterate_increment(pos))
02477 {
02478 DATA(input_data, pos) = DATA(revised_data, pos);
02479 }
02480 }
02481
02482 cleanup:
02483 uves_free_image(&simulated);
02484 uves_free_image(&revised);
02485
02486 return;
02487 }
02488
02489
02506
02507 static cpl_image *
02508 opt_extract_sky(const cpl_image *image, const cpl_image *image_noise,
02509 const cpl_image *weights,
02510 uves_iterate_position *pos,
02511 cpl_image *sky_spectrum,
02512 cpl_image *sky_spectrum_noise)
02513 {
02514 cpl_image *sky_subtracted = NULL;
02515 cpl_table *sky_map = NULL;
02516
02517 uves_msg("Defining sky region");
02518
02519 check( sky_map = opt_define_sky(image, weights,
02520 pos),
02521 "Error determining sky window");
02522
02523 uves_msg_low("%d/%d sky pixels",
02524 cpl_table_count_selected(sky_map),
02525 cpl_table_get_nrow(sky_map));
02526
02527
02528 uves_msg("Subtracting sky (method = median of sky channels)");
02529
02530 check( sky_subtracted = opt_subtract_sky(image, image_noise, weights,
02531 pos,
02532 sky_map,
02533 sky_spectrum,
02534 sky_spectrum_noise),
02535 "Could not subtract sky");
02536
02537 cleanup:
02538 uves_free_table(&sky_map);
02539
02540 return sky_subtracted;
02541 }
02542
02543
02555
02556 static cpl_table *
02557 opt_define_sky(const cpl_image *image, const cpl_image *weights,
02558 uves_iterate_position *pos)
02559
02560 {
02561 cpl_table *sky_map = NULL;
02562
02563 cpl_table **resampled = NULL;
02564 int nbins = 0;
02565 int i;
02566
02567
02568 check( resampled = opt_sample_spatial_profile(image, weights,
02569 pos,
02570 50,
02571 1,
02572 &nbins),
02573 "Error measuring spatial profile");
02574
02575 sky_map = cpl_table_new(nbins);
02576 cpl_table_new_column(sky_map, "DY" , CPL_TYPE_INT);
02577 cpl_table_new_column(sky_map, "Prof", CPL_TYPE_DOUBLE);
02578
02579 for (i = 0; i < nbins; i++)
02580 {
02581 cpl_table_set_int(sky_map, "DY" , i, i - nbins/2);
02582 if (cpl_table_has_valid(resampled[i], "Prof"))
02583 {
02584
02585
02586
02587
02588
02589
02590
02591 int row = (cpl_table_get_nrow(resampled[i]) * 9) / 10;
02592
02593 uves_sort_table_1(resampled[i], "Prof", false);
02594
02595 cpl_table_set_double(sky_map, "Prof", i,
02596 cpl_table_get_double(resampled[i], "Prof", row, NULL));
02597 }
02598 else
02599 {
02600 cpl_table_set_invalid(sky_map, "Prof", i);
02601 }
02602 }
02603
02604
02605
02606 assure( cpl_table_has_valid(sky_map, "Prof"), CPL_ERROR_DATA_NOT_FOUND,
02607 "Too many (%d/%d) bad pixels. Could not measure sky profile",
02608 cpl_image_count_rejected(image),
02609 pos->nx * pos->ny);
02610
02611
02612
02613
02614
02615 {
02616 double prof_min = cpl_table_get_column_min(sky_map, "Prof");
02617 double prof_max = cpl_table_get_column_max(sky_map, "Prof");
02618 double prof_med = cpl_table_get_column_median(sky_map, "Prof");
02619 double sky_threshold = prof_min + 2*(prof_med - prof_min);
02620
02621 sky_threshold = uves_min_double(sky_threshold, (prof_min + prof_max)/2);
02622
02623 check( uves_plot_table(sky_map, "DY", "Prof",
02624 "Globally averaged spatial profile (sky threshold = %.5f)",
02625 sky_threshold),
02626 "Plotting failed");
02627
02628 uves_select_table_rows(sky_map, "Prof", CPL_NOT_GREATER_THAN, sky_threshold);
02629 }
02630
02631 cleanup:
02632 if (resampled != NULL)
02633 {
02634 for (i = 0; i < nbins; i++)
02635 {
02636 uves_free_table(&(resampled[i]));
02637 }
02638 cpl_free(resampled);
02639 }
02640
02641 return sky_map;
02642 }
02643
02644
02662
02663 static cpl_table **
02664 opt_sample_spatial_profile(const cpl_image *image, const cpl_image *weights,
02665 uves_iterate_position *pos,
02666 int stepx,
02667 int sampling_factor,
02668 int *nbins)
02669
02670 {
02671 cpl_table **resampled = NULL;
02672
02673
02674
02675 int *resampled_row = NULL;
02676
02677 const double *image_data;
02678 const double *weights_data;
02679
02680 assure( stepx >= 1, CPL_ERROR_ILLEGAL_INPUT, "Step size = %d", stepx);
02681 assure( sampling_factor >= 1, CPL_ERROR_ILLEGAL_INPUT,
02682 "Sampling factor = %d", sampling_factor);
02683
02684 image_data = cpl_image_get_data_double_const(image);
02685 weights_data = cpl_image_get_data_double_const(weights);
02686
02687 *nbins = uves_extract_profile_get_nbins(pos->sg.length, sampling_factor);
02688
02689 resampled = cpl_calloc(*nbins, sizeof(cpl_table *));
02690 resampled_row = cpl_calloc(*nbins, sizeof(int));
02691
02692 assure_mem(resampled );
02693 assure_mem(resampled_row);
02694
02695 {
02696 int i;
02697 for (i = 0; i < *nbins; i++)
02698 {
02699 resampled[i] = cpl_table_new((pos->nx/stepx+1)*
02700 (pos->maxorder-pos->minorder+1));
02701
02702 resampled_row[i] = 0;
02703 assure_mem( resampled[i] );
02704
02705 cpl_table_new_column(resampled[i], "X" , CPL_TYPE_INT);
02706 cpl_table_new_column(resampled[i], "Order", CPL_TYPE_INT);
02707 cpl_table_new_column(resampled[i], "Prof" , CPL_TYPE_DOUBLE);
02708
02709 }
02710 }
02711
02712 for (uves_iterate_set_first(pos,
02713 1, pos->nx,
02714 pos->minorder, pos->maxorder,
02715 NULL, false);
02716 !uves_iterate_finished(pos);
02717 uves_iterate_increment(pos)) {
02718 if ((pos->x - 1) % stepx == 0)
02719
02720 {
02721
02722 double flux = 0;
02723
02724 for (pos->y = pos->ylow; pos->y <= pos->yhigh; pos->y++) {
02725 if (!ISBAD(weights_data, pos)) {
02726 flux += DATA(image_data, pos);
02727 }
02728 }
02729
02730 if (flux != 0) {
02731 for (pos->y = pos->ylow; pos->y <= pos->yhigh; pos->y++) {
02732 if (!ISBAD(weights_data, pos)) {
02733 double f = DATA(image_data, pos);
02734
02735
02736 int bin = uves_round_double(
02737 uves_extract_profile_get_bin(pos, sampling_factor));
02738
02739 passure( bin < *nbins, "%d %d", bin, *nbins);
02740
02741
02742
02743
02744
02745 cpl_table_set_int (resampled[bin], "X" ,
02746 resampled_row[bin], pos->x);
02747 cpl_table_set_int (resampled[bin], "Order",
02748 resampled_row[bin], pos->order);
02749 cpl_table_set_double(resampled[bin], "Prof" ,
02750 resampled_row[bin], f/flux);
02751
02752 resampled_row[bin]++;
02753 }
02754 }
02755 }
02756 }
02757 }
02758
02759 {
02760 int i;
02761 for (i = 0; i < *nbins; i++)
02762 {
02763 cpl_table_set_size(resampled[i], resampled_row[i]);
02764 }
02765 }
02766
02767
02768 passure( cpl_table_get_ncol(resampled[0]) == 3, "%d",
02769 cpl_table_get_ncol(resampled[0]));
02770 passure( cpl_table_has_column(resampled[0], "X"), " ");
02771 passure( cpl_table_has_column(resampled[0], "Order"), " ");
02772 passure( cpl_table_has_column(resampled[0], "Prof"), " ");
02773
02774 cleanup:
02775 cpl_free(resampled_row);
02776
02777 return resampled;
02778 }
02779
02780
02781
02782
02804
02805 static cpl_image *
02806 opt_subtract_sky(const cpl_image *image, const cpl_image *image_noise,
02807 const cpl_image *weights,
02808 uves_iterate_position *pos,
02809 const cpl_table *sky_map,
02810 cpl_image *sky_spectrum,
02811 cpl_image *sky_spectrum_noise)
02812 {
02813 cpl_image *sky_subtracted = cpl_image_duplicate(image);
02814
02815 double *sky_subtracted_data;
02816 const double *image_data;
02817 const double *noise_data;
02818 const double *weights_data;
02819 double *buffer_flux = NULL;
02820 double *buffer_noise = NULL;
02821
02822
02823 double *sky_spectrum_data = NULL;
02824 double *sky_noise_data = NULL;
02825 cpl_binary *sky_spectrum_bpm = NULL;
02826 cpl_binary *sky_noise_bpm = NULL;
02827 cpl_mask *temp = NULL;
02828
02829 assure_mem( sky_subtracted );
02830
02831 image_data = cpl_image_get_data_double_const(image);
02832 noise_data = cpl_image_get_data_double_const(image_noise);
02833 weights_data = cpl_image_get_data_double_const(weights);
02834 sky_subtracted_data = cpl_image_get_data(sky_subtracted);
02835
02836 buffer_flux = cpl_malloc(uves_round_double(pos->sg.length + 5)*sizeof(double));
02837 buffer_noise = cpl_malloc(uves_round_double(pos->sg.length + 5)*sizeof(double));
02838
02839
02840 if (sky_spectrum != NULL)
02841 {
02842 sky_spectrum_data = cpl_image_get_data_double(sky_spectrum);
02843 sky_noise_data = cpl_image_get_data_double(sky_spectrum_noise);
02844
02845
02846
02847
02848 temp = cpl_mask_new(cpl_image_get_size_x(sky_spectrum),
02849 cpl_image_get_size_y(sky_spectrum));
02850 cpl_mask_not(temp);
02851
02852 cpl_image_reject_from_mask(sky_spectrum , temp);
02853 cpl_image_reject_from_mask(sky_spectrum_noise, temp);
02854
02855 sky_spectrum_bpm = cpl_mask_get_data(cpl_image_get_bpm(sky_spectrum));
02856 sky_noise_bpm = cpl_mask_get_data(cpl_image_get_bpm(sky_spectrum_noise));
02857 }
02858
02859 UVES_TIME_START("Subtract sky");
02860
02861 for (uves_iterate_set_first(pos,
02862 1, pos->nx,
02863 pos->minorder, pos->maxorder,
02864 NULL, false);
02865 !uves_iterate_finished(pos);
02866 uves_iterate_increment(pos))
02867 {
02868 double sky_background, sky_background_noise;
02869
02870
02871 sky_background = opt_get_sky(image_data, noise_data,
02872 weights_data,
02873 pos,
02874 sky_map,
02875 buffer_flux, buffer_noise,
02876 &sky_background_noise);
02877
02878
02879 if (sky_spectrum != NULL)
02880 {
02881
02882
02883
02884
02885
02886
02887
02888
02889
02890
02891
02892
02893
02894
02895 SPECTRUM_DATA(sky_spectrum_data, pos) =
02896 pos->sg.length * sky_background;
02897 SPECTRUM_DATA(sky_noise_data, pos) =
02898 pos->sg.length * sky_background_noise;
02899
02900 SPECTRUM_DATA(sky_spectrum_bpm, pos) = CPL_BINARY_0;
02901 SPECTRUM_DATA(sky_noise_bpm , pos) = CPL_BINARY_0;
02902 }
02903
02904
02905 for (pos->y = pos->ylow; pos->y <= pos->yhigh; pos->y++)
02906 {
02907 DATA(sky_subtracted_data, pos) =
02908 DATA(image_data, pos) - sky_background;
02909
02910
02911
02912
02913 }
02914 }
02915
02916 UVES_TIME_END;
02917
02918 cleanup:
02919 uves_free_mask(&temp);
02920 cpl_free(buffer_flux);
02921 cpl_free(buffer_noise);
02922
02923 return sky_subtracted;
02924 }
02925
02926
02927
02962
02963
02964 static uves_extract_profile *
02965 opt_measure_profile(const cpl_image *image, const cpl_image *image_noise,
02966 const cpl_image *weights,
02967 uves_iterate_position *pos,
02968 int chunk, int sampling_factor,
02969 int (*f) (const double x[], const double a[], double *result),
02970 int (*dfda)(const double x[], const double a[], double result[]),
02971 int M,
02972 const cpl_image *sky_spectrum,
02973 cpl_table *info_tbl,
02974 cpl_table **profile_global)
02975 {
02976 uves_extract_profile *profile = NULL;
02977 int *stepx = NULL;
02978 int *good_bins = NULL;
02979 cpl_table **profile_data = NULL;
02980 bool cont;
02981
02982 cpl_mask *image_bad = NULL;
02983 cpl_binary*image_bpm = NULL;
02984
02985 cpl_vector *plot0x = NULL;
02986 cpl_vector *plot0y = NULL;
02987 cpl_vector *plot1x = NULL;
02988 cpl_vector *plot1y = NULL;
02989 cpl_bivector *plot[] = {NULL, NULL};
02990 char *plot_titles[] = {NULL, NULL};
02991
02992 int sample_bins = 100;
02993
02994
02995 int spatial_bins = uves_extract_profile_get_nbins(pos->sg.length, sampling_factor);
02996
02997
02998
02999
03000 if (f != NULL)
03001 {
03002 image_bad = cpl_mask_new(pos->nx, pos->ny);
03003 assure_mem(image_bad);
03004 image_bpm = cpl_mask_get_data(image_bad);
03005 {
03006 const double *weights_data = cpl_image_get_data_double_const(weights);
03007
03008 for (pos->y = 1; pos->y <= pos->ny; pos->y++)
03009 {
03010 for (pos->x = 1; pos->x <= pos->nx; pos->x++)
03011 {
03012 if (ISBAD(weights_data, pos))
03013 {
03014 DATA(image_bpm, pos) = CPL_BINARY_1;
03015 }
03016 }
03017 }
03018 }
03019 }
03020
03021 if (f != NULL)
03022 {
03023 stepx = cpl_malloc((pos->maxorder-pos->minorder+1) * sizeof(int));
03024 good_bins = cpl_malloc((pos->maxorder-pos->minorder+1) * sizeof(int));
03025 profile_data = cpl_calloc( pos->maxorder-pos->minorder+1, sizeof(cpl_table *));
03026
03027 assure_mem(stepx);
03028 assure_mem(good_bins);
03029 assure_mem(profile_data);
03030
03031 for (pos->order = pos->minorder; pos->order <= pos->maxorder; pos->order++)
03032 {
03033
03034
03035
03036
03037
03038 int order_width;
03039
03040 check( order_width = opt_get_order_width(pos),
03041 "Error estimating width of order #%d", pos->order);
03042
03043
03044
03045
03046
03047
03048
03049 stepx [pos->order-pos->minorder] = order_width / sample_bins + 1;
03050 good_bins[pos->order-pos->minorder] = (2*sample_bins)/3;
03051 }
03052 }
03053 else
03054 {
03055 int i;
03056
03057 passure( f == NULL, " ");
03058
03059 stepx = cpl_malloc(sizeof(int) * spatial_bins);
03060 good_bins = cpl_malloc(sizeof(int) * spatial_bins);
03061
03062
03063
03064 profile_data = NULL;
03065
03066 assure_mem(stepx);
03067 assure_mem(good_bins);
03068
03069 for (i = 0; i < spatial_bins; i++)
03070 {
03071
03072
03073
03074
03075
03076
03077
03078
03079
03080
03081
03082
03083 stepx [i] = uves_round_double(
03084 (pos->nx*pos->sg.length)/(sample_bins*spatial_bins)
03085 ) + 1;
03086
03087 good_bins[i] = sample_bins - 1;
03088 }
03089 }
03090
03091
03092
03093
03094
03095
03096
03097
03098
03099
03100
03101
03102
03103
03104
03105
03106
03107
03108
03109
03110
03111
03112
03113 do {
03114
03115 int i;
03116
03117 for (i = 0; i < ((f == NULL) ? spatial_bins : pos->maxorder-pos->minorder+1); i++)
03118 {
03119 if (f == NULL || profile_data[i] == NULL)
03120
03121
03122 {
03123 passure(good_bins[i] < sample_bins,
03124 "%d %d", good_bins[i], sample_bins);
03125
03126 stepx[i] = (int) (stepx[i]*(good_bins[i]*0.8/sample_bins));
03127 if (stepx[i] == 0)
03128 {
03129 stepx[i] = 1;
03130 }
03131
03132
03133
03134
03135
03136
03137
03138
03139
03140
03141
03142
03143 }
03144 }
03145
03146 cont = false;
03147
03148
03149 if (f != NULL) {
03150 #if NEW_METHOD
03151 for (pos->order = pos->minorder; pos->order <= pos->minorder; pos->order++) {
03152 #else
03153 for (pos->order = pos->minorder; pos->order <= pos->maxorder; pos->order++) {
03154 #endif
03155
03156 if (profile_data[pos->order-pos->minorder] == NULL) {
03157 int bins;
03158
03159 check( profile_data[pos->order-pos->minorder] =
03160 opt_measure_profile_order(image, image_noise, image_bpm,
03161 pos,
03162 chunk,
03163 f, dfda, M,
03164 sky_spectrum),
03165 "Error measuring profile of order #%d using chunk size = %d",
03166 pos->order, chunk);
03167
03168 bins = cpl_table_get_nrow(profile_data[pos->order-pos->minorder]);
03169
03170 uves_msg("Order %-2d: Chi^2/N = %.2f; FWHM = %.2f pix; Offset = %.2f pix",
03171 pos->order,
03172 (bins > 0) ? cpl_table_get_column_median(
03173 profile_data[pos->order-pos->minorder],
03174 "Reduced_chisq") : 0,
03175
03176 (bins > 0) ? cpl_table_get_column_median(
03177 profile_data[pos->order-pos->minorder],
03178 "Sigma") * TWOSQRT2LN2 : 0,
03179 (bins > 0) ? cpl_table_get_column_median(
03180 profile_data[pos->order-pos->minorder],
03181 "Y0") : 0);
03182
03183
03184
03185
03186
03187
03188
03189
03190
03191
03192
03193
03194
03195
03196 cont = false;
03197
03198 }
03199 }
03200 }
03201 else
03202
03203 {
03204 int nbins = 0;
03205
03206 int step = 0;
03207 for (i = 0; i < spatial_bins; i++)
03208 {
03209 step += stepx[i];
03210 }
03211 step /= spatial_bins;
03212
03213 *profile_global = cpl_table_new(0);
03214 assure_mem( *profile_global );
03215 cpl_table_new_column(*profile_global, "Dummy" , CPL_TYPE_DOUBLE);
03216
03217 check( profile_data = opt_sample_spatial_profile(image, weights,
03218 pos,
03219 step,
03220 sampling_factor,
03221 &nbins),
03222 "Error measuring profile (virtual method)");
03223
03224 passure( nbins == spatial_bins, "%d %d", nbins, spatial_bins);
03225
03226 for (i = 0; i < spatial_bins; i++)
03227 {
03228 good_bins[i] = cpl_table_get_nrow(profile_data[i]);
03229
03230 uves_msg_debug("Bin %d (%-3d samples): Prof = %f %d",
03231 i,
03232 good_bins[i],
03233 (good_bins[i] > 0) ?
03234 cpl_table_get_column_median(profile_data[i], "Prof") : 0,
03235 stepx[i]);
03236
03237
03238
03239
03240
03241
03242
03243
03244
03245 }
03246 }
03247
03248 } while(cont);
03249
03250
03251
03252 if (f == NULL)
03253 {
03254 int max_degree = 8;
03255 double kappa = 3.0;
03256 int i;
03257
03258 uves_msg_low("Fitting global polynomials to "
03259 "resampled profile (%d spatial bins)",
03260 spatial_bins);
03261
03262 uves_extract_profile_delete(&profile);
03263 profile = uves_extract_profile_new(NULL,
03264 NULL,
03265 0,
03266 pos->sg.length,
03267 sampling_factor);
03268
03269 for (i = 0; i < spatial_bins; i++)
03270 {
03271
03272
03273
03274
03275
03276 bool enough_points = (
03277 cpl_table_get_nrow(profile_data[i]) >= (max_degree + 1)*(max_degree + 1));
03278
03279 if (enough_points)
03280 {
03281 uves_msg_debug("Fitting 2d polynomial to spatial bin %d", i);
03282
03283 if (true) {
03284
03285
03286 double min_reject = -0.01;
03287
03288
03289
03290
03291
03292
03293
03294 profile->dy_poly[i] = uves_polynomial_regression_2d_autodegree(
03295 profile_data[i],
03296 "X", "Order", "Prof", NULL,
03297 "Proffit", NULL, NULL,
03298 NULL, NULL, NULL,
03299 kappa,
03300 max_degree, max_degree, -1, min_reject,
03301 false,
03302 NULL, NULL, 0, NULL);
03303 } else {
03304
03305
03306
03307
03308 profile->dy_poly[i] =
03309 uves_polynomial_regression_2d(profile_data[i],
03310 "X", "Order", "Prof", NULL,
03311 0, 0,
03312 "Proffit", NULL, NULL,
03313 NULL, NULL, NULL, kappa, -1);
03314 }
03315
03316 if (cpl_error_get_code() == CPL_ERROR_SINGULAR_MATRIX)
03317 {
03318 uves_error_reset();
03319 uves_msg_debug("Fitting bin %d failed", i);
03320
03321 uves_polynomial_delete(&(profile->dy_poly[i]));
03322 enough_points = false;
03323 }
03324
03325 assure( cpl_error_get_code() == CPL_ERROR_NONE,
03326 cpl_error_get_code(),
03327 "Could not fit polynomial to bin %d", i);
03328
03329 }
03330
03331 if (!enough_points)
03332 {
03333
03334
03335 profile->dy_poly[i] = uves_polynomial_new_zero(2);
03336
03337 cpl_table_new_column(profile_data[i], "Proffit", CPL_TYPE_DOUBLE);
03338 if (cpl_table_get_nrow(profile_data[i]) > 0)
03339 {
03340 cpl_table_fill_column_window_double(
03341 profile_data[i], "Proffit",
03342 0, cpl_table_get_nrow(profile_data[i]),
03343 0);
03344 }
03345 }
03346
03347
03348
03349
03350 profile->is_zero_degree[i] = (uves_polynomial_get_degree(profile->dy_poly[i]) == 0);
03351 if (profile->is_zero_degree[i])
03352 {
03353 profile->dy_double[i] = uves_polynomial_evaluate_2d(profile->dy_poly[i], 0, 0);
03354 }
03355 }
03356 }
03357 else
03358
03359 {
03360 int max_degree;
03361 double min_rms = 0.1;
03362 double kappa = 3.0;
03363
03364
03365 bool enough_points;
03366
03367
03368 uves_free_table(profile_global);
03369
03370 #if NEW_METHOD
03371 for (pos->order = pos->minorder; order <= pos->minorder; pos->order++)
03372 #else
03373 for (pos->order = pos->minorder; pos->order <= pos->maxorder; pos->order++)
03374 #endif
03375 {
03376 if (pos->order == pos->minorder)
03377 {
03378 *profile_global = cpl_table_duplicate(profile_data[0]);
03379 }
03380 else
03381 {
03382
03383 cpl_table_insert(*profile_global,
03384 profile_data[pos->order-pos->minorder], 0);
03385 }
03386 }
03387
03388 uves_extract_profile_delete(&profile);
03389 profile = uves_extract_profile_new(f, dfda, M, 0, 0);
03390
03391
03392
03393
03394
03395
03396
03397
03398 max_degree = 5;
03399
03400 #if ORDER_PER_ORDER
03401 for (pos->order = pos->minorder; pos->order <= pos->maxorder; pos->order++)
03402 {
03403 int degree = 4;
03404 #else
03405 #endif
03406
03407 enough_points =
03408 #if ORDER_PER_ORDER
03409 (cpl_table_get_nrow(profile_data[pos->order-pos->minorder])
03410 >= (degree + 1));
03411 #else
03412 (cpl_table_get_nrow(*profile_global) >= (max_degree + 1)*(max_degree + 1));
03413 #endif
03414 if (enough_points)
03415 {
03416 double mse;
03417
03418 double min_val = -pos->sg.length/2;
03419 double max_val = pos->sg.length/2;
03420 double minmax_pos[4][2];
03421 minmax_pos[0][0] = 1 ; minmax_pos[0][1] = pos->minorder;
03422 minmax_pos[1][0] = 1 ; minmax_pos[1][1] = pos->maxorder;
03423 minmax_pos[2][0] = pos->nx; minmax_pos[2][1] = pos->minorder;
03424 minmax_pos[3][0] = pos->nx; minmax_pos[3][1] = pos->maxorder;
03425
03426 uves_msg_low("Fitting profile centroid = polynomial(x, order)");
03427
03428 #if ORDER_PER_ORDER
03429 check_nomsg( uves_raise_to_median_frac(
03430 profile_data[pos->order-pos->minorder], "dY0", 1.0) );
03431
03432 profile->y0[pos->order - pos->minorder] =
03433 uves_polynomial_regression_1d(
03434 profile_data[pos->order-pos->minorder],
03435 "X", "Y0", "dY0", degree,
03436 "Y0fit", NULL,
03437 &mse, kappa);
03438 #else
03439 check_nomsg( uves_raise_to_median_frac(*profile_global, "dY0", 1.0) );
03440
03441 profile->y0 =
03442 uves_polynomial_regression_2d_autodegree(
03443 *profile_global,
03444 "X", "Order", "Y0", "dY0",
03445 "Y0fit", NULL, NULL,
03446 &mse, NULL, NULL,
03447 kappa,
03448 max_degree, max_degree, min_rms, -1,
03449 true,
03450 &min_val, &max_val, 4, minmax_pos);
03451 #endif
03452 if (cpl_error_get_code() == CPL_ERROR_SINGULAR_MATRIX)
03453 {
03454 uves_error_reset();
03455 #if ORDER_PER_ORDER
03456 uves_polynomial_delete(&(profile->y0[pos->order - pos->minorder]));
03457 #else
03458 uves_polynomial_delete(&(profile->y0));
03459 #endif
03460
03461 enough_points = false;
03462 }
03463 else
03464 {
03465 assure( cpl_error_get_code() == CPL_ERROR_NONE,
03466 cpl_error_get_code(),
03467 "Error fitting object position");
03468
03469
03470 #if ORDER_PER_ORDER
03471 #else
03472 uves_msg_low("Object offset at chip center = %.2f pixels",
03473 uves_polynomial_evaluate_2d(
03474 profile->y0,
03475 pos->nx/2,
03476 (pos->minorder+pos->maxorder)/2));
03477 #endif
03478
03479 if (sqrt(mse) > 0.5)
03480 {
03481 uves_msg_warning("Problem localizing object "
03482 "(usually RMS ~= 0.1 pixels)");
03483 }
03484 }
03485 }
03486
03487 if (!enough_points)
03488 {
03489 #if ORDER_PER_ORDER
03490 uves_msg_warning("Too few points (%d) to fit global polynomial to "
03491 "object centroid. Setting offset to zero",
03492 cpl_table_get_nrow(profile_data[pos->order - pos->minorder]));
03493 #else
03494 uves_msg_warning("Too few points (%d) to fit global polynomial to "
03495 "object centroid. Setting offset to zero",
03496 cpl_table_get_nrow(*profile_global));
03497 #endif
03498
03499
03500 #if ORDER_PER_ORDER
03501 profile->y0[pos->order - pos->minorder] = uves_polynomial_new_zero(1);
03502
03503 cpl_table_new_column(profile_data[pos->order-pos->minorder], "Y0fit", CPL_TYPE_DOUBLE);
03504 if (cpl_table_get_nrow(profile_data[pos->order-pos->minorder]) > 0)
03505 {
03506 cpl_table_fill_column_window_double(
03507 profile_data[pos->order-pos->minorder], "Y0fit",
03508 0, cpl_table_get_nrow(profile_data[pos->order-pos->minorder]),
03509 0);
03510 }
03511 #else
03512 profile->y0 = uves_polynomial_new_zero(2);
03513
03514 cpl_table_new_column(*profile_global, "Y0fit", CPL_TYPE_DOUBLE);
03515 if (cpl_table_get_nrow(*profile_global) > 0)
03516 {
03517 cpl_table_fill_column_window_double(
03518 *profile_global, "Y0fit",
03519 0, cpl_table_get_nrow(*profile_global),
03520 0);
03521 }
03522 #endif
03523 }
03524 #if ORDER_PER_ORDER
03525 }
03526 #else
03527 #endif
03528 max_degree = 3;
03529
03530 #if ORDER_PER_ORDER
03531 for (pos->order = pos->minorder; pos->order <= pos->maxorder; pos->order++)
03532 {
03533 int degree = 4;
03534 #else
03535 #endif
03536 enough_points =
03537 #if ORDER_PER_ORDER
03538 (cpl_table_get_nrow(profile_data[pos->order-pos->minorder])
03539 >= (degree + 1));
03540 #else
03541 (cpl_table_get_nrow(*profile_global) >= (max_degree + 1)*(max_degree + 1));
03542 #endif
03543 if (enough_points)
03544 {
03545 double min_val = 0.1;
03546 double max_val = pos->sg.length;
03547 double minmax_pos[4][2];
03548 minmax_pos[0][0] = 1 ; minmax_pos[0][1] = pos->minorder;
03549 minmax_pos[1][0] = 1 ; minmax_pos[1][1] = pos->maxorder;
03550 minmax_pos[2][0] = pos->nx; minmax_pos[2][1] = pos->minorder;
03551 minmax_pos[3][0] = pos->nx; minmax_pos[3][1] = pos->maxorder;
03552
03553 uves_msg_low("Fitting profile width = polynomial(x, order)");
03554
03555 #if ORDER_PER_ORDER
03556 check_nomsg( uves_raise_to_median_frac(
03557 profile_data[pos->order-pos->minorder], "dSigma", 1.0) );
03558
03559
03560 profile->sigma[pos->order - pos->minorder] =
03561 uves_polynomial_regression_1d(
03562 profile_data[pos->order-pos->minorder],
03563 "X", "Sigma", "dSigma", degree,
03564 "Sigmafit", NULL,
03565 NULL, kappa);
03566 #else
03567 check_nomsg( uves_raise_to_median_frac(*profile_global, "dSigma", 1.0) );
03568
03569 profile->sigma =
03570 uves_polynomial_regression_2d_autodegree(
03571 *profile_global,
03572 "X", "Order", "Sigma", "dSigma",
03573 "Sigmafit", NULL, NULL,
03574 NULL, NULL, NULL,
03575 kappa,
03576 max_degree, max_degree, min_rms, -1,
03577 true,
03578 &min_val, &max_val, 4, minmax_pos);
03579 #endif
03580
03581 if (cpl_error_get_code() == CPL_ERROR_SINGULAR_MATRIX)
03582 {
03583 uves_error_reset();
03584 #if ORDER_PER_ORDER
03585 uves_polynomial_delete(&(profile->sigma[pos->order - pos->minorder]));
03586 #else
03587 uves_polynomial_delete(&(profile->sigma));
03588 #endif
03589
03590 enough_points = false;
03591 }
03592 else
03593 {
03594 assure( cpl_error_get_code() == CPL_ERROR_NONE,
03595 cpl_error_get_code(),
03596 "Error fitting profile width");
03597
03598 #if ORDER_PER_ORDER
03599 #else
03600 uves_msg_low("Profile FWHM at chip center = %.2f pixels",
03601 TWOSQRT2LN2 * uves_polynomial_evaluate_2d(
03602 profile->sigma,
03603 pos->nx/2,
03604 (pos->minorder+pos->maxorder)/2));
03605 #endif
03606 }
03607 }
03608
03609 if (!enough_points)
03610 {
03611 #if ORDER_PER_ORDER
03612 uves_msg_warning("Too few points (%d) to fit global polynomial to "
03613 "object width. Setting std.dev. to 1 pixel",
03614 cpl_table_get_nrow(profile_data[pos->order - pos->minorder]));
03615 #else
03616 uves_msg_warning("Too few points (%d) to fit global polynomial to "
03617 "object width. Setting std.dev. to 1 pixel",
03618 cpl_table_get_nrow(*profile_global));
03619 #endif
03620
03621
03622 #if ORDER_PER_ORDER
03623 profile->sigma[pos->order - pos->minorder] = uves_polynomial_new_zero(1);
03624 uves_polynomial_shift(profile->sigma[pos->order - pos->minorder], 0, 1.0);
03625
03626 cpl_table_new_column(profile_data[pos->order-pos->minorder], "Sigmafit", CPL_TYPE_DOUBLE);
03627 if (cpl_table_get_nrow(profile_data[pos->order-pos->minorder]) > 0)
03628 {
03629 cpl_table_fill_column_window_double(
03630 profile_data[pos->order-pos->minorder], "Sigmafit",
03631 0, cpl_table_get_nrow(profile_data[pos->order-pos->minorder]),
03632 1.0);
03633 }
03634 #else
03635 profile->sigma = uves_polynomial_new_zero(2);
03636 uves_polynomial_shift(profile->sigma, 0, 1.0);
03637
03638 cpl_table_new_column(*profile_global, "Sigmafit", CPL_TYPE_DOUBLE);
03639 if (cpl_table_get_nrow(*profile_global) > 0)
03640 {
03641 cpl_table_fill_column_window_double(
03642 *profile_global, "Sigmafit",
03643 0, cpl_table_get_nrow(*profile_global),
03644 1.0);
03645 }
03646 #endif
03647
03648 }
03649
03650
03651
03652
03653 #if ORDER_PER_ORDER
03654 profile->red_chisq[pos->order - pos->minorder] = uves_polynomial_new_zero(1);
03655 uves_polynomial_shift(profile->red_chisq[pos->order - pos->minorder], 0,
03656 cpl_table_get_nrow(profile_data[pos->order - pos->minorder]) > 0 ?
03657 cpl_table_get_column_median(profile_data[pos->order - pos->minorder],
03658 "Reduced_chisq") : 1.0);
03659 #else
03660 profile->red_chisq = uves_polynomial_new_zero(2);
03661 uves_polynomial_shift(profile->red_chisq, 0,
03662 cpl_table_get_nrow(*profile_global) > 0 ?
03663 cpl_table_get_column_median(*profile_global,
03664 "Reduced_chisq") : 1.0);
03665 #endif
03666
03667
03668
03669
03670
03671
03672
03673
03674
03675
03676
03677
03678
03679
03680
03681
03682
03683
03684
03685
03686
03687
03688
03689
03690
03691
03692 #if ORDER_PER_ORDER
03693 }
03694
03695
03696 uves_free_table(profile_global);
03697 for (pos->order = pos->minorder; pos->order <= pos->maxorder; pos->order++)
03698 {
03699 if (pos->order == pos->minorder)
03700 {
03701 *profile_global = cpl_table_duplicate(profile_data[0]);
03702 }
03703 else
03704 {
03705
03706 cpl_table_insert(*profile_global,
03707 profile_data[pos->order-pos->minorder], 0);
03708 }
03709 }
03710 #else
03711 #endif
03712
03713 }
03714
03715
03716
03717
03718 {
03719 int xmin = uves_max_int(1 , pos->nx/2-100);
03720 int xmax = uves_min_int(pos->nx, pos->nx/2+100);
03721 int order = (pos->minorder + pos->maxorder)/2;
03722 int indx;
03723
03724 plot0x = cpl_vector_new(uves_round_double(pos->sg.length+5)*(xmax-xmin+1));
03725 plot0y = cpl_vector_new(uves_round_double(pos->sg.length+5)*(xmax-xmin+1));
03726 plot1x = cpl_vector_new(uves_round_double(pos->sg.length+5)*(xmax-xmin+1));
03727 plot1y = cpl_vector_new(uves_round_double(pos->sg.length+5)*(xmax-xmin+1));
03728 indx = 0;
03729 assure_mem( plot0x );
03730 assure_mem( plot0y );
03731 assure_mem( plot1x );
03732 assure_mem( plot1y );
03733
03734 for (uves_iterate_set_first(pos,
03735 xmin, xmax,
03736 order, order,
03737 NULL, false);
03738 !uves_iterate_finished(pos);
03739 uves_iterate_increment(pos))
03740
03741 {
03742
03743 double flux = 0;
03744 for (pos->y = pos->ylow; pos->y <= pos->yhigh; pos->y++)
03745 {
03746 int pis_rejected;
03747 double pixelval = cpl_image_get(image, pos->x, pos->y, &pis_rejected);
03748 if (!pis_rejected)
03749 {
03750 flux += pixelval;
03751 }
03752 }
03753
03754 uves_extract_profile_set(profile, pos, NULL);
03755
03756
03757 for (pos->y = pos->ylow; pos->y <= pos->yhigh; pos->y++)
03758 {
03759 double dy = pos->y - pos->ycenter;
03760 int pis_rejected;
03761 double pixelval = cpl_image_get(
03762 image, pos->x, uves_round_double(pos->y), &pis_rejected);
03763
03764 if (!pis_rejected && flux != 0)
03765 {
03766 pixelval /= flux;
03767 }
03768 else
03769 {
03770 pixelval = 0;
03771 }
03772
03773 cpl_vector_set(plot0x, indx, dy);
03774 cpl_vector_set(plot0y, indx, uves_extract_profile_evaluate(profile, pos));
03775
03776 cpl_vector_set(plot1x, indx, dy);
03777 cpl_vector_set(plot1y, indx, pixelval);
03778
03779 indx++;
03780 }
03781 }
03782
03783 if (indx > 0)
03784 {
03785 cpl_vector_set_size(plot0x, indx);
03786 cpl_vector_set_size(plot0y, indx);
03787 cpl_vector_set_size(plot1x, indx);
03788 cpl_vector_set_size(plot1y, indx);
03789
03790 plot[0] = cpl_bivector_wrap_vectors(plot0x, plot0y);
03791 plot[1] = cpl_bivector_wrap_vectors(plot1x, plot1y);
03792
03793 plot_titles[0] = uves_sprintf(
03794 "Model spatial profile at (order, x) = (%d, %d)", order, pos->nx/2);
03795 plot_titles[1] = uves_sprintf(
03796 "Empirical spatial profile at (order, x) = (%d, %d)", order, pos->nx/2);
03797
03798 check( uves_plot_bivectors(plot, plot_titles, 2, "DY", "Profile"), "Plotting failed");
03799 }
03800 else
03801 {
03802 uves_msg_warning("No points to plot. This may happen if the order "
03803 "polynomial is ill-formed");
03804 }
03805 }
03806
03807 if (f != NULL)
03808 {
03809
03810
03811
03812
03813 int i;
03814
03815 for (i = 0; i < cpl_table_get_nrow(*profile_global); i++)
03816 {
03817 double y0fit = cpl_table_get_double(*profile_global, "Y0fit", i, NULL);
03818 int order = cpl_table_get_int (*profile_global, "Order", i, NULL);
03819 int x = cpl_table_get_int (*profile_global, "X" , i, NULL);
03820
03821
03822 uves_iterate_set_first(pos,
03823 x, x,
03824 order, order,
03825 NULL,
03826 false);
03827
03828 cpl_table_set_double(*profile_global, "Y0fit_world", i, y0fit + pos->ycenter);
03829 }
03830
03831
03832 #if NEW_METHOD
03833 for (pos->order = pos->minorder; pos->order <= pos->minorder; pos->order++)
03834 #else
03835 for (pos->order = pos->minorder; pos->order <= pos->maxorder; pos->order++)
03836 #endif
03837 {
03838 if (good_bins[pos->order-pos->minorder] == 0)
03839 {
03840 uves_msg_warning("Order %d: Failed to detect object!", pos->order);
03841 }
03842 }
03843
03844
03845
03846 for (pos->order = pos->minorder; pos->order <= pos->maxorder; pos->order++)
03847 {
03848 #if ORDER_PER_ORDER
03849 double objpos;
03850 check_nomsg(
03851 objpos =
03852 uves_polynomial_evaluate_1d(profile->y0[pos->order-pos->minorder],
03853 pos->nx/2)
03854 - ( - pos->sg.length/2 ));
03855 double fwhm =
03856 uves_polynomial_evaluate_1d(profile->sigma[pos->order-pos->minorder],
03857 pos->nx/2) * TWOSQRT2LN2;
03858
03859
03860 cpl_table_set_double(info_tbl, "Pos" , pos->order - pos->minorder, objpos);
03861 cpl_table_set_double(info_tbl, "FWHM" , pos->order - pos->minorder, fwhm);
03862 #else
03863 double objpos =
03864 uves_polynomial_evaluate_2d(profile->y0, pos->nx/2, pos->order)
03865 - ( - pos->sg.length/2 );
03866 double fwhm =
03867 uves_polynomial_evaluate_2d(profile->sigma , pos->nx/2, pos->order)*
03868 TWOSQRT2LN2;
03869
03870 cpl_table_set_double(info_tbl, "Pos" , pos->order - pos->minorder, objpos);
03871 cpl_table_set_double(info_tbl, "FWHM" , pos->order - pos->minorder, fwhm);
03872 #endif
03873 }
03874
03875
03876 if (cpl_table_get_nrow(*profile_global) > 0)
03877 {
03878 double med_chisq = cpl_table_get_column_median(
03879 *profile_global, "Reduced_chisq");
03880 double limit = 5.0;
03881
03882 if (med_chisq > limit || med_chisq < 1/limit)
03883 {
03884
03885
03886
03887
03888
03889
03890
03891
03892
03893 uves_msg_warning("Assumed spatial profile might not be a "
03894 "good fit to the data: median(Chi^2/N) = %f",
03895 med_chisq);
03896
03897 if (f != NULL && med_chisq > limit)
03898 {
03899 uves_msg_warning("Recommended profile "
03900 "measuring method: virtual");
03901 }
03902 }
03903 else
03904 {
03905 uves_msg("Median(reduced Chi^2) is %f", med_chisq);
03906 }
03907 }
03908 }
03909 else
03910 {
03911
03912
03913 }
03914
03915 cleanup:
03916 uves_free_mask(&image_bad);
03917 cpl_free(stepx);
03918 cpl_free(good_bins);
03919 if (profile_data != NULL)
03920 {
03921 int i;
03922 for (i = 0; i < ((f == NULL) ? spatial_bins : pos->maxorder-pos->minorder+1); i++)
03923 {
03924 if (profile_data[i] != NULL)
03925 {
03926 uves_free_table(&(profile_data[i]));
03927 }
03928 }
03929 cpl_free(profile_data);
03930 }
03931 cpl_bivector_unwrap_vectors(plot[0]);
03932 cpl_bivector_unwrap_vectors(plot[1]);
03933 cpl_free(plot_titles[0]);
03934 cpl_free(plot_titles[1]);
03935 uves_free_vector(&plot0x);
03936 uves_free_vector(&plot0y);
03937 uves_free_vector(&plot1x);
03938 uves_free_vector(&plot1y);
03939
03940 return profile;
03941 }
03942
03943 #if NEW_METHOD
03944 struct
03945 {
03946 double *flux;
03947 double *sky;
03948 int minorder, nx;
03949
03950 int (*f) (const double x[], const double a[], double *result);
03951 int (*dfda)(const double x[], const double a[], double result[]);
03952
03953 int deg_y0_x;
03954 int deg_y0_m;
03955 int deg_sigma_x;
03956 int deg_sigma_m;
03957 } profile_params;
03958
03959
03960
03961
03962
03963 inline static double
03964 eval_pol(const double *coeffs,
03965 int degree1, int degree2,
03966 double x1, double x2)
03967 {
03968 double result = 0;
03969 double x2j;
03970 int j;
03971
03972 for (j = 0, x2j = 1;
03973 j <= degree2;
03974 j++, x2j *= x2)
03975 {
03976
03977
03978
03979 int i = degree1;
03980 double r = coeffs[i + (degree1+1)*j];
03981
03982 while(i > 0)
03983 {
03984 r *= x1;
03985 i -= 1;
03986 r += coeffs[i + (degree1+1)*j];
03987 }
03988
03989
03990 result += x2j*r;
03991 }
03992
03993 return result;
03994 }
03995
03996
03997
03998
03999
04000
04001
04002
04003
04004
04005
04006
04007
04008
04009
04010 static int
04011 profile_f(const double x[], const double a[], double *result)
04012 {
04013 int xi = uves_round_double(x[0]);
04014 double yi = x[1];
04015 int mi = uves_round_double(x[2]);
04016 int idx;
04017
04018 double y_0 = eval_pol(a,
04019 profile_params.deg_y0_x,
04020 profile_params.deg_y0_m,
04021 xi, mi);
04022 double sigma = eval_pol(a + (1 + profile_params.deg_y0_x)*(1 + profile_params.deg_y0_m),
04023 profile_params.deg_sigma_x,
04024 profile_params.deg_sigma_m,
04025 xi, mi);
04026
04027
04028 double norm_prof;
04029
04030 double xf[1];
04031
04032 double af[5];
04033 af[0] = y_0;
04034 af[1] = sigma;
04035 af[2] = 1;
04036 af[3] = 0;
04037 af[4] = 0;
04038
04039 xf[0] = yi;
04040
04041 if (profile_params.f(xf, af, &norm_prof) != 0)
04042 {
04043 return 1;
04044 }
04045
04046 idx = xi + (mi - profile_params.minorder)*(profile_params.nx + 1);
04047
04048 *result = profile_params.sky[idx] + profile_params.flux[idx] * norm_prof;
04049
04050 return 0;
04051 }
04052
04053
04054
04055
04056
04057
04058
04059
04060
04061
04062
04063
04064
04065
04066
04067
04068
04069
04070
04071
04072
04073
04074
04075 static int
04076 profile_dfda(const double x[], const double a[], double result[])
04077 {
04078 int xi = uves_round_double(x[0]);
04079 double yi = x[1];
04080 int mi = uves_round_double(x[2]);
04081
04082 double y_0 = eval_pol(a,
04083 profile_params.deg_y0_x,
04084 profile_params.deg_y0_m,
04085 xi, mi);
04086 double sigma = eval_pol(a + (1 + profile_params.deg_y0_x)*(1 + profile_params.deg_y0_m),
04087 profile_params.deg_sigma_x,
04088 profile_params.deg_sigma_m,
04089 xi, mi);
04090
04091 double norm_prof_derivatives[5];
04092
04093 double xf[1];
04094
04095 double af[5];
04096 af[0] = y_0;
04097 af[1] = sigma;
04098 af[2] = 1;
04099 af[3] = 0;
04100 af[4] = 0;
04101
04102 xf[0] = yi;
04103
04104 if (profile_params.dfda(xf, af, norm_prof_derivatives) != 0)
04105 {
04106 return 1;
04107 }
04108
04109 {
04110 int idx = xi + (mi - profile_params.minorder)*(profile_params.nx + 1);
04111
04112
04113 double norm_prof_dy0 = norm_prof_derivatives[0];
04114 double norm_prof_dsigma = norm_prof_derivatives[1];
04115 int i, j;
04116
04117
04118
04119
04120
04121
04122
04123
04124
04125
04126
04127
04128
04129
04130
04131
04132 i = 0;
04133 j = 0;
04134 result[i + (profile_params.deg_y0_x + 1) * j] = profile_params.flux[idx] * norm_prof_dy0;
04135 for (j = 0; j <= profile_params.deg_y0_m; j++) {
04136 if (j >= 1)
04137 {
04138 i = 0;
04139 result[i + (profile_params.deg_y0_x + 1) * j] =
04140 result[i + (profile_params.deg_y0_x + 1) * (j-1)] * mi;
04141 }
04142 for (i = 1; i <= profile_params.deg_y0_x; i++) {
04143 result[i + (profile_params.deg_y0_x + 1) * j] =
04144 result[i-1 + (profile_params.deg_y0_x + 1) * j] * xi;
04145 }
04146 }
04147
04148
04149
04150
04151
04152
04153
04154
04155
04156 result += (profile_params.deg_y0_x + 1) * (profile_params.deg_y0_m + 1);
04157
04158
04159
04160 i = 0;
04161 j = 0;
04162 result[i + (profile_params.deg_sigma_x + 1) * j] =
04163 profile_params.flux[idx] * norm_prof_dsigma;
04164 for (j = 0; j <= profile_params.deg_sigma_m; j++) {
04165 if (j >= 1)
04166 {
04167 i = 0;
04168 result[i + (profile_params.deg_sigma_x + 1) * j] =
04169 result[i + (profile_params.deg_sigma_x + 1) * (j-1)] * mi;
04170 }
04171 for (i = 1; i <= profile_params.deg_sigma_x; i++) {
04172 result[i + (profile_params.deg_sigma_x + 1) * j] =
04173 result[i-1 + (profile_params.deg_sigma_x + 1) * j] * xi;
04174 }
04175 }
04176 }
04177
04178 return 0;
04179 }
04180 #endif
04181
04201
04202 static cpl_table *
04203 opt_measure_profile_order(const cpl_image *image, const cpl_image *image_noise,
04204 const cpl_binary *image_bpm,
04205 uves_iterate_position *pos,
04206 int chunk,
04207 int (*f) (const double x[], const double a[], double *result),
04208 int (*dfda)(const double x[], const double a[], double result[]),
04209 int M,
04210 const cpl_image *sky_spectrum)
04211 {
04212 cpl_table *profile_data = NULL;
04213 int profile_row;
04214 cpl_matrix *covariance = NULL;
04215
04216 #if NEW_METHOD
04217 cpl_matrix *eval_points = NULL;
04218 cpl_vector *eval_data = NULL;
04219 cpl_vector *eval_err = NULL;
04220 cpl_vector *coeffs = NULL;
04221 #if CREATE_DEBUGGING_TABLE
04222 cpl_table *temp = NULL;
04223 #endif
04224 double *fluxes = NULL;
04225 double *skys = NULL;
04226 int *ia = NULL;
04227
04228 cpl_table *estimate = NULL;
04229 cpl_table *estimate_dup = NULL;
04230 polynomial *y0_estim_pol = NULL;
04231 polynomial *sigma_estim_pol = NULL;
04232 #endif
04233
04234
04235 cpl_vector *dy = NULL;
04236 cpl_vector *prof = NULL;
04237 cpl_vector *prof2= NULL;
04238 cpl_vector *dprof = NULL;
04239 cpl_vector **data = NULL;
04240 int *size = NULL;
04241 double *hicut = NULL;
04242 double *locut = NULL;
04243 int nbins = 0;
04244
04245 const double *image_data;
04246 const double *noise_data;
04247
04248 int x;
04249
04250 #if NEW_METHOD
04251 int norders = pos->maxorder-pos->minorder+1;
04252 #else
04253
04254 sky_spectrum = sky_spectrum;
04255 #endif
04256
04257 passure( f != NULL, " ");
04258
04259 image_data = cpl_image_get_data_double_const(image);
04260 noise_data = cpl_image_get_data_double_const(image_noise);
04261
04262 #if NEW_METHOD
04263 profile_data = cpl_table_new((nx/chunk + 3) * norders);
04264 #else
04265 profile_data = cpl_table_new(pos->nx);
04266 #endif
04267 assure_mem( profile_data );
04268
04269 check( (cpl_table_new_column(profile_data, "Order", CPL_TYPE_INT),
04270 cpl_table_new_column(profile_data, "X", CPL_TYPE_INT),
04271 cpl_table_new_column(profile_data, "Y0", CPL_TYPE_DOUBLE),
04272 cpl_table_new_column(profile_data, "Sigma", CPL_TYPE_DOUBLE),
04273 cpl_table_new_column(profile_data, "Norm", CPL_TYPE_DOUBLE),
04274 cpl_table_new_column(profile_data, "dY0", CPL_TYPE_DOUBLE),
04275 cpl_table_new_column(profile_data, "dSigma", CPL_TYPE_DOUBLE),
04276 cpl_table_new_column(profile_data, "dNorm", CPL_TYPE_DOUBLE),
04277 cpl_table_new_column(profile_data, "Y0_world", CPL_TYPE_DOUBLE),
04278 cpl_table_new_column(profile_data, "Y0fit_world", CPL_TYPE_DOUBLE),
04279 cpl_table_new_column(profile_data, "Reduced_chisq", CPL_TYPE_DOUBLE)),
04280 "Error initializing order trace table for order #%d", pos->order);
04281
04282
04283 cpl_table_set_column_unit(profile_data, "X" , "pixels");
04284 cpl_table_set_column_unit(profile_data, "Y0", "pixels");
04285 cpl_table_set_column_unit(profile_data, "Sigma", "pixels");
04286 cpl_table_set_column_unit(profile_data, "dY0", "pixels");
04287 cpl_table_set_column_unit(profile_data, "dSigma", "pixels");
04288
04289 profile_row = 0;
04290
04291 UVES_TIME_START("Measure loop");
04292
04293 nbins = uves_round_double(pos->sg.length + 5);
04294 data = cpl_calloc(nbins, sizeof(cpl_vector *));
04295 size = cpl_calloc(nbins, sizeof(int));
04296 locut = cpl_calloc(nbins, sizeof(double));
04297 hicut = cpl_calloc(nbins, sizeof(double));
04298 {
04299 int i;
04300 for (i = 0; i < nbins; i++)
04301 {
04302 data[i] = cpl_vector_new(1);
04303 }
04304 }
04305
04306
04307 #if NEW_METHOD
04308
04309
04310
04311
04312
04313
04314
04315
04316
04317
04318 {
04319
04320
04321
04322
04323 int deg_y0_x = 0;
04324 int deg_y0_m = 0;
04325 int deg_sigma_x = 0;
04326 int deg_sigma_m = 0;
04327
04328 int ncoeffs =
04329 (deg_y0_x +1)*(deg_y0_m +1) +
04330 (deg_sigma_x+1)*(deg_sigma_m+1);
04331
04332 double red_chisq;
04333 int n = 0;
04334 int nbad = 0;
04335
04336 #if CREATE_DEBUGGING_TABLE
04337 temp = cpl_table_new(norders*nx*uves_round_double(pos->sg.length+3));
04338 cpl_table_new_column(temp, "x", CPL_TYPE_DOUBLE);
04339 cpl_table_new_column(temp, "y", CPL_TYPE_DOUBLE);
04340 cpl_table_new_column(temp, "order", CPL_TYPE_DOUBLE);
04341 cpl_table_new_column(temp, "dat", CPL_TYPE_DOUBLE);
04342 cpl_table_new_column(temp, "err", CPL_TYPE_DOUBLE);
04343
04344 #endif
04345
04346
04347
04348
04349
04350
04351
04352
04353
04354
04355
04356
04357
04358
04359
04360
04361
04362
04363
04364
04365 eval_points = cpl_matrix_new(norders*nx*uves_round_double(pos->sg.length+3), 3);
04366 eval_data = cpl_vector_new(norders*nx*uves_round_double(pos->sg.length+3));
04367 eval_err = cpl_vector_new(norders*nx*uves_round_double(pos->sg.length+3));
04368
04369 fluxes = cpl_calloc((nx+1)*norders, sizeof(double));
04370 skys = cpl_calloc((nx+1)*norders, sizeof(double));
04371
04372
04373
04374 estimate = cpl_table_new(norders);
04375 cpl_table_new_column(estimate, "Order", CPL_TYPE_INT);
04376 cpl_table_new_column(estimate, "Y0" , CPL_TYPE_DOUBLE);
04377 cpl_table_new_column(estimate, "Sigma", CPL_TYPE_DOUBLE);
04378
04379 coeffs = cpl_vector_new(ncoeffs);
04380 ia = cpl_calloc(ncoeffs, sizeof(int));
04381 {
04382 int i;
04383 for (i = 0; i < ncoeffs; i++)
04384 {
04385 cpl_vector_set(coeffs, i, 0);
04386
04387 ia[i] = 1;
04388 }
04389 }
04390
04391
04392 for (order = 17; order <= 17; order++) {
04393
04394
04395
04396
04397 double sumw = 0;
04398 double sumwy = 0;
04399 double sumwyy = 0;
04400
04401 for (x = chunk/2; x <= nx - chunk/2; x += chunk) {
04402
04403
04404 int i;
04405 for (i = 0; i < nbins; i++)
04406 {
04407
04408
04409
04410
04411
04412
04413 cpl_vector_set_size(data[i], 2*(chunk + 1));
04414 size[i] = 0;
04415 }
04416
04417
04418 for (uves_iterate_set_first(pos,
04419 x - chunk/2 + 1, x + chunk/2,
04420 order, order,
04421 image_bpm, true);
04422 !uves_iterate_finished(pos);
04423 uves_iterate_increment(pos))
04424 {
04425 int bin = pos->y - pos->ylow;
04426
04427 check_nomsg(cpl_vector_set(data[bin], size[bin],
04428 DATA(image_data, pos)));
04429 size[bin]++;
04430 }
04431
04432
04433 for (i = 0; i < nbins; i++)
04434 {
04435 if (size[i] == 0)
04436 {
04437
04438 }
04439 else if (size[i] <= chunk/2)
04440 {
04441
04442
04443 locut[i] = cpl_vector_get_max(data[i]) + 1;
04444 hicut[i] = cpl_vector_get_min(data[i]) - 1;
04445 }
04446 else
04447 {
04448
04449
04450 double median, stdev;
04451 double kappa = 3.0;
04452 double *data_data;
04453 int k;
04454
04455 k = size[i];
04456
04457 do {
04458 cpl_vector_set_size(data[i], k);
04459 size[i] = k;
04460 data_data = cpl_vector_get_data(data[i]);
04461
04462 #if defined CPL_VERSION_CODE && CPL_VERSION_CODE >= CPL_VERSION(4, 0, 0)
04463 median = cpl_vector_get_median_const(data[i]);
04464 #else
04465 median = cpl_vector_get_median(data[i]);
04466 #endif
04467 stdev = cpl_vector_get_stdev(data[i]);
04468 locut[i] = median - kappa*stdev;
04469 hicut[i] = median + kappa*stdev;
04470
04471
04472 k = 0;
04473 {
04474 int j;
04475 for (j = 0; j < size[i]; j++)
04476 {
04477 if (locut[i] <= data_data[j] &&
04478 data_data[j] <= hicut[i])
04479 {
04480 data_data[k] = data_data[j];
04481 k++;
04482 }
04483 }
04484 }
04485 }
04486 while (k < size[i] && k > 1);
04487
04488 }
04489 }
04490
04491
04492
04493
04494
04495
04496 for (uves_iterate_set_first(pos,
04497 x - chunk/2 + 1, x + chunk/2,
04498 order, order,
04499 NULL, false)
04500 !uves_iterate_finished(pos);
04501 uves_iterate_increment(pos))
04502 {
04503 int pis_rejected;
04504 double flux = 0;
04505 for (pos->y = pos->ylow; pos->y <= pos->yhigh; pos->y++)
04506 {
04507 int bin = pos->y - pos->ylow;
04508
04509 if (ISGOOD(image_bpm, pos) &&
04510 (locut[bin] <= DATA(image_data, pos) &&
04511 DATA(image_data, pos) <= hicut[bin])
04512 )
04513 {
04514 double pix = DATA(image_data, pos);
04515 double dy = pos->y - pos->ycenter;
04516 flux += pix;
04517
04518 cpl_matrix_set(eval_points, n, 0, pos->x);
04519 cpl_matrix_set(eval_points, n, 1, dy);
04520 cpl_matrix_set(eval_points, n, 2, order);
04521 cpl_vector_set(eval_data, n, pix);
04522 cpl_vector_set(eval_err , n,
04523 DATA(noise_data, pos));
04524
04525 sumw += pix;
04526 sumwy += pix * dy;
04527 sumwyy += pix * dy * dy;
04528 #if CREATE_DEBUGGING_TABLE
04529 cpl_table_set_double(temp, "x", n, pos->x);
04530 cpl_table_set_double(temp, "y", n, dy);
04531 cpl_table_set_double(temp, "order", n, order);
04532 cpl_table_set_double(temp, "dat", n, pix);
04533 cpl_table_set_double(temp, "err", n,
04534 DATA(noise_data, pos));
04535
04536 #endif
04537 n++;
04538 }
04539 else
04540 {
04541 nbad += 1;
04542
04543 }
04544 }
04545 fluxes[pos->x + (order-pos->minorder)*(pos->nx+1)] = flux;
04546 skys [pos->x + (order-pos->minorder)*(pos->nx+1)] =
04547 cpl_image_get(sky_spectrum,
04548 pos->x, order-pos->minorder+1, &pis_rejected);
04549
04550
04551 skys [pos->x + (order-pos->minorder)*(pos->nx+1)] = 0;
04552
04553
04554 }
04555 }
04556
04557
04558 {
04559 double y0_estim;
04560 double sigma_estim;
04561 bool y0_is_good;
04562 bool sigma_is_good;
04563
04564 if (sumw != 0)
04565 {
04566 y0_is_good = true;
04567 y0_estim = sumwy/sumw;
04568
04569 sigma_estim = sumwyy/sumw - (sumwy/sumw)*(sumwy/sumw);
04570 if (sigma_estim > 0)
04571 {
04572 sigma_estim = sqrt(sigma_estim);
04573 sigma_is_good = true;
04574 }
04575 else
04576 {
04577 sigma_is_good = false;
04578 }
04579 }
04580 else
04581 {
04582
04583 y0_is_good = false;
04584 sigma_is_good = false;
04585 }
04586
04587 cpl_table_set_int (estimate, "Order", order - pos->minorder, order);
04588
04589 if (y0_is_good)
04590 {
04591 cpl_table_set_double(estimate, "Y0" , order - pos->minorder, y0_estim);
04592 }
04593 else
04594 {
04595 cpl_table_set_invalid(estimate, "Y0", order - pos->minorder);
04596 }
04597
04598 if (sigma_is_good)
04599 {
04600 cpl_table_set_double(estimate, "Sigma",
04601 order - pos->minorder, sigma_estim);
04602 }
04603 else
04604 {
04605 cpl_table_set_invalid(estimate, "Sigma", order - pos->minorder);
04606 }
04607
04608
04609
04610 if (y0_is_good && sigma_is_good) {
04611 uves_msg_error("Order #%d: Offset = %.2f pix; FWHM = %.2f pix",
04612 order, y0_estim, sigma_estim*TWOSQRT2LN2);
04613 }
04614 else if (y0_is_good && !sigma_is_good) {
04615 uves_msg_error("Order #%d: Offset = %.2f pix; FWHM = -- pix",
04616 order, y0_estim);
04617 }
04618 else if (!y0_is_good && sigma_is_good) {
04619 uves_msg_error("Order #%d: Offset = -- pix; FWHM = %.2f pix",
04620 order, sigma_estim);
04621 }
04622 else {
04623 uves_msg_error("Order #%d: Offset = -- pix; FWHM = -- pix",
04624 order);
04625 }
04626 }
04627
04628 }
04629
04630 cpl_matrix_set_size(eval_points, n, 3);
04631 cpl_vector_set_size(eval_data, n);
04632 cpl_vector_set_size(eval_err , n);
04633
04634 #if CREATE_DEBUGGING_TABLE
04635 cpl_table_set_size(temp, n);
04636 #endif
04637
04638
04639
04640 {
04641 double kappa = 3.0;
04642 int degree;
04643
04644 cpl_table_dump(estimate, 0, cpl_table_get_nrow(estimate), stdout);
04645
04646
04647
04648 estimate_dup = cpl_table_duplicate(estimate);
04649 assure_mem( estimate_dup );
04650 uves_erase_invalid_table_rows(estimate_dup, "Y0");
04651
04652
04653 degree = (cpl_table_get_nrow(estimate_dup) > 1) ? 1 : 0;
04654
04655 y0_estim_pol = uves_polynomial_regression_1d(
04656 estimate_dup, "Order", "Y0", NULL,
04657 degree,
04658 NULL, NULL,
04659 NULL,
04660 kappa);
04661
04662 uves_polynomial_dump(y0_estim_pol, stdout); fflush(stdout);
04663
04664 if (cpl_error_get_code() != CPL_ERROR_NONE)
04665 {
04666 uves_msg_warning("Could not estimate object centroid (%s). "
04667 "Setting initial offset to zero",
04668 cpl_error_get_message());
04669
04670 uves_error_reset();
04671
04672
04673 uves_polynomial_delete(&y0_estim_pol);
04674 y0_estim_pol = uves_polynomial_new_zero(1);
04675 }
04676
04677 uves_free_table(&estimate_dup);
04678 estimate_dup = cpl_table_duplicate(estimate);
04679 assure_mem( estimate_dup );
04680 uves_erase_invalid_table_rows(estimate_dup, "Sigma");
04681
04682 degree = (cpl_table_get_nrow(estimate_dup) > 1) ? 1 : 0;
04683
04684 sigma_estim_pol = uves_polynomial_regression_1d(
04685 estimate_dup, "Order", "Sigma", NULL,
04686 degree,
04687 NULL, NULL,
04688 NULL,
04689 kappa);
04690
04691 if (cpl_error_get_code() != CPL_ERROR_NONE)
04692 {
04693 uves_msg_warning("Could not estimate object width (%s). "
04694 "Setting initial sigma to 1 pixel",
04695 cpl_error_get_message());
04696
04697 uves_error_reset();
04698
04699
04700 uves_polynomial_delete(&sigma_estim_pol);
04701 sigma_estim_pol = uves_polynomial_new_zero(1);
04702 uves_polynomial_shift(sigma_estim_pol, 0, 1.0);
04703 }
04704 }
04705
04706
04707
04708
04709 cpl_vector_set(coeffs, 0,
04710 uves_polynomial_get_coeff_1d(y0_estim_pol, 0));
04711
04712 if (deg_y0_m >= 1)
04713 {
04714 cpl_vector_set(coeffs, 0 + (deg_y0_x+1)*1,
04715 uves_polynomial_get_coeff_1d(y0_estim_pol, 1));
04716
04717 uves_msg_error("Estimate: y0 ~= %g + %g * m",
04718 cpl_vector_get(coeffs, 0),
04719 cpl_vector_get(coeffs, 0 + (deg_y0_x+1)*1));
04720 }
04721 else
04722 {
04723 uves_msg_error("Estimate: y0 ~= %g",
04724 cpl_vector_get(coeffs, 0));
04725 }
04726
04727
04728
04729 cpl_vector_set(coeffs, (deg_y0_x+1)*(deg_y0_m+1),
04730 uves_polynomial_get_coeff_1d(sigma_estim_pol, 0));
04731
04732 if (deg_sigma_m >= 1)
04733 {
04734 cpl_vector_set(coeffs, (deg_y0_x+1)*(deg_y0_m+1) +
04735 0 + (deg_sigma_x+1)*1,
04736 uves_polynomial_get_coeff_1d(sigma_estim_pol, 1));
04737
04738 uves_msg_error("Estimate: sigma ~= %g + %g * m",
04739 cpl_vector_get(coeffs, (deg_y0_x+1)*(deg_y0_m+1) +
04740 0),
04741 cpl_vector_get(coeffs, (deg_y0_x+1)*(deg_y0_m+1) +
04742 0 + (deg_y0_x+1)*1));
04743 }
04744 else
04745 {
04746 uves_msg_error("Estimate: sigma ~= %g",
04747 cpl_vector_get(coeffs, (deg_y0_x+1)*(deg_y0_m+1) +
04748 0));
04749
04750 }
04751
04752
04753
04754 profile_params.flux = fluxes;
04755 profile_params.sky = skys;
04756 profile_params.minorder = pos->minorder;
04757 profile_params.nx = nx;
04758
04759 profile_params.f = f;
04760 profile_params.dfda = dfda;
04761
04762 profile_params.deg_y0_x = deg_y0_x;
04763 profile_params.deg_y0_m = deg_y0_m;
04764 profile_params.deg_sigma_x = deg_sigma_x;
04765 profile_params.deg_sigma_m = deg_sigma_m;
04766
04767
04768
04769
04770 #if defined CPL_VERSION_CODE && CPL_VERSION_CODE >= CPL_VERSION(4, 0, 0)
04771 cpl_vector_fill(eval_err,
04772 cpl_vector_get_median_const(eval_err));
04773 #else
04774 cpl_vector_fill(eval_err,
04775 cpl_vector_get_median(eval_err));
04776 #endif
04777
04778 uves_msg_error("Fitting model to %d positions; %d bad pixels found",
04779 n, nbad);
04780
04781 uves_fit(eval_points, NULL,
04782 eval_data, eval_err,
04783 coeffs, ia,
04784 profile_f,
04785 profile_dfda,
04786 NULL,
04787 &red_chisq,
04788 &covariance);
04789
04790
04791 if (cpl_error_get_code() == CPL_ERROR_SINGULAR_MATRIX ||
04792 cpl_error_get_code() == CPL_ERROR_CONTINUE)
04793 {
04794 uves_msg_warning("Fitting global model failed (%s)", cpl_error_get_message());
04795 uves_error_reset();
04796 #if CREATE_DEBUGGING_TABLE
04797 cpl_table_save(temp, NULL, NULL, "tab.fits", CPL_IO_DEFAULT);
04798 #endif
04799 }
04800 else
04801 {
04802 assure( cpl_error_get_code() == CPL_ERROR_NONE,
04803 cpl_error_get_code(), "Fitting global model failed");
04804
04805 cpl_matrix_dump(covariance, stdout); fflush(stdout);
04806
04807 uves_msg_error("Solution: y0 ~= %g", eval_pol(cpl_vector_get_data(coeffs),
04808 deg_y0_x, deg_y0_m,
04809 pos->nx/2,
04810 (pos->minorder+pos->maxorder)/2));
04811 uves_msg_error("Solution: sigma ~= %g", eval_pol(cpl_vector_get_data(coeffs)+
04812 (deg_y0_x+1)*(deg_y0_m+1),
04813 deg_y0_x, deg_y0_m,
04814 pos->nx/2,
04815 (pos->minorder+pos->maxorder)/2));
04816
04817
04818 for (order = pos->minorder; order <= pos->maxorder; order++) {
04819 for (x = chunk/2; x <= nx - chunk/2; x += chunk)
04820 {
04821 double y_0 = eval_pol(cpl_vector_get_data(coeffs),
04822 deg_y0_x, deg_y0_m, x, order);
04823 double sigma = fabs(eval_pol(cpl_vector_get_data(coeffs)+
04824 (deg_y0_x+1)*(deg_y0_m+1),
04825 deg_sigma_x, deg_sigma_m, x, order));
04826
04827
04828
04829
04830
04831
04832
04833
04834
04835
04836
04837 double dy0 = 0;
04838 double dsigma = 0;
04839 int i1, i2, j_1, j2;
04840
04841 for (i1 = 0; i1 < (deg_y0_x+1); i1++)
04842 for (j_1 = 0; j_1 < (deg_y0_m+1); j_1++)
04843 for (i2 = 0; i2 < (deg_y0_x+1); i2++)
04844 for (j2 = 0; j2 < (deg_y0_m+1); j2++)
04845 {
04846 dy0 += cpl_matrix_get(covariance,
04847 i1+(deg_y0_x+1)*j_1,
04848 i2+(deg_y0_x+1)*j2) *
04849 uves_pow_int(x, i1+i2) *
04850 uves_pow_int(order, j_1+j2);
04851 }
04852 if (dy0 > 0)
04853 {
04854 dy0 = sqrt(dy0);
04855 }
04856 else
04857
04858 {
04859 dy0 = 1.0;
04860 }
04861
04862 for (i1 = 0; i1 < (deg_sigma_x+1); i1++)
04863 for (j_1 = 0; j_1 < (deg_sigma_m+1); j_1++)
04864 for (i2 = 0; i2 < (deg_sigma_x+1); i2++)
04865 for (j2 = 0; j2 < (deg_sigma_m+1); j2++)
04866 {
04867
04868
04869
04870 dsigma += cpl_matrix_get(
04871 covariance,
04872 (deg_y0_x+1)*(deg_y0_m+1) + i1+(deg_sigma_x+1)*j_1,
04873 (deg_y0_x+1)*(deg_y0_m+1) + i2+(deg_sigma_x+1)*j2) *
04874 uves_pow_int(x, i1+i1) *
04875 uves_pow_int(order, j_1+j2);
04876 }
04877 if (dsigma > 0)
04878 {
04879 dsigma = sqrt(dsigma);
04880 }
04881 else
04882
04883 {
04884 dsigma = 1.0;
04885 }
04886
04887 check((cpl_table_set_int (profile_data, "Order", profile_row, order),
04888 cpl_table_set_int (profile_data, "X" , profile_row, x),
04889 cpl_table_set_double(profile_data, "Y0" , profile_row, y_0),
04890 cpl_table_set_double(profile_data, "Sigma", profile_row, sigma),
04891 cpl_table_set_double(profile_data, "Norm" , profile_row, 1),
04892 cpl_table_set_double(profile_data, "dY0" , profile_row, dy0),
04893 cpl_table_set_double(profile_data, "dSigma", profile_row, dsigma),
04894 cpl_table_set_double(profile_data, "dNorm", profile_row, 1),
04895 cpl_table_set_double(profile_data, "Y0_world", profile_row, -1),
04896 cpl_table_set_double(profile_data, "Reduced_chisq", profile_row,
04897 red_chisq)),
04898 "Error writing table row %d", profile_row+1);
04899 profile_row += 1;
04900 }
04901 }
04902 #if CREATE_DEBUGGING_TABLE
04903 cpl_table_new_column(temp, "pemp", CPL_TYPE_DOUBLE);
04904 cpl_table_new_column(temp, "fit", CPL_TYPE_DOUBLE);
04905 cpl_table_new_column(temp, "pfit", CPL_TYPE_DOUBLE);
04906 {int i;
04907 for (i = 0; i < cpl_table_get_nrow(temp); i++)
04908 {
04909 double y = cpl_table_get_double(temp, "y", i, NULL);
04910 int xi = uves_round_double(cpl_table_get_double(temp, "x", i, NULL));
04911 int mi = uves_round_double(cpl_table_get_double(temp, "order", i, NULL));
04912 double dat = cpl_table_get_double(temp, "dat", i, NULL);
04913 int idx = xi + (mi - profile_params.minorder)*(profile_params.nx + 1);
04914 double flux_fit;
04915 double xar[3];
04916 xar[0] = xi;
04917 xar[1] = y;
04918 xar[2] = mi;
04919
04920 profile_f(xar,
04921 cpl_vector_get_data(coeffs), &flux_fit);
04922
04923 cpl_table_set(temp, "pemp", i,
04924 (dat - profile_params.sky[idx])/profile_params.flux[idx]);
04925
04926 cpl_table_set(temp, "fit", i, flux_fit);
04927
04928 cpl_table_set(temp, "pfit", i,
04929 (flux_fit - profile_params.sky[idx])/profile_params.flux[idx]);
04930 }
04931 }
04932 check_nomsg(
04933 cpl_table_save(temp, NULL, NULL, "tab.fits", CPL_IO_DEFAULT));
04934 #endif
04935 }
04936 }
04937
04938 #else
04939 dy = cpl_vector_new((chunk+1) * ((int)(pos->sg.length + 3)));
04940 prof = cpl_vector_new((chunk+1) * ((int)(pos->sg.length + 3)));
04941 prof2 = cpl_vector_new((chunk+1) * ((int)(pos->sg.length + 3)));
04942 dprof = cpl_vector_new((chunk+1) * ((int)(pos->sg.length + 3)));
04943
04944 for (x = 1 + chunk/2; x + chunk/2 <= pos->nx; x += chunk) {
04945
04946
04947
04948 const int points_needed_for_fit = 6;
04949 int n = 0;
04950 int nbad = 0;
04951 int i;
04952
04953
04954 cpl_vector_set_size(dy, (chunk+1) * ((int)(pos->sg.length + 3)));
04955 cpl_vector_set_size(prof, (chunk+1) * ((int)(pos->sg.length + 3)));
04956 cpl_vector_set_size(prof2, (chunk+1) * ((int)(pos->sg.length + 3)));
04957 cpl_vector_set_size(dprof, (chunk+1) * ((int)(pos->sg.length + 3)));
04958 n = 0;
04959
04960 for (i = 0; i < nbins; i++)
04961 {
04962
04963
04964
04965
04966
04967
04968 cpl_vector_set_size(data[i], 2*(chunk + 1));
04969 size[i] = 0;
04970 }
04971
04972
04973
04974 for (uves_iterate_set_first(pos,
04975 x - chunk/2 + 1,
04976 x + chunk/2,
04977 pos->order, pos->order,
04978 image_bpm, true);
04979 !uves_iterate_finished(pos);
04980 uves_iterate_increment(pos))
04981 {
04982 int bin = pos->y - pos->ylow;
04983
04984
04985 check_nomsg(cpl_vector_set(data[bin], size[bin],
04986 DATA(image_data, pos)));
04987 size[bin]++;
04988 }
04989
04990
04991 for (i = 0; i < nbins; i++)
04992 {
04993 if (size[i] == 0)
04994 {
04995
04996 }
04997 else if (size[i] <= chunk/2)
04998 {
04999
05000
05001 locut[i] = cpl_vector_get_max(data[i]) + 1;
05002 hicut[i] = cpl_vector_get_min(data[i]) - 1;
05003 }
05004 else
05005 {
05006
05007
05008 double median, stdev;
05009 double kappa = 3.0;
05010 double *data_data;
05011 int k;
05012
05013 k = size[i];
05014
05015 do {
05016 cpl_vector_set_size(data[i], k);
05017 size[i] = k;
05018 data_data = cpl_vector_get_data(data[i]);
05019
05020 #if defined CPL_VERSION_CODE && CPL_VERSION_CODE >= CPL_VERSION(4, 0, 0)
05021 median = cpl_vector_get_median_const(data[i]);
05022 #else
05023 median = cpl_vector_get_median(data[i]);
05024 #endif
05025 stdev = cpl_vector_get_stdev(data[i]);
05026 locut[i] = median - kappa*stdev;
05027 hicut[i] = median + kappa*stdev;
05028
05029
05030 k = 0;
05031 {
05032 int j;
05033 for (j = 0; j < size[i]; j++)
05034 {
05035 if (locut[i] <= data_data[j] &&
05036 data_data[j] <= hicut[i])
05037 {
05038 data_data[k] = data_data[j];
05039 k++;
05040 }
05041 }
05042 }
05043 }
05044 while (k < size[i] && k > 1);
05045
05046 }
05047 }
05048
05049
05050 for (uves_iterate_set_first(pos,
05051 x - chunk/2 + 1,
05052 x + chunk/2,
05053 pos->order, pos->order,
05054 NULL, false);
05055 !uves_iterate_finished(pos);
05056 uves_iterate_increment(pos))
05057 {
05058 double flux = 0;
05059 for (pos->y = pos->ylow; pos->y <= pos->yhigh; pos->y++)
05060 {
05061 int bin = pos->y - pos->ylow;
05062
05063 if (ISGOOD(image_bpm, pos) &&
05064 (locut[bin] <= DATA(image_data, pos) &&
05065 DATA(image_data, pos) <= hicut[bin])
05066 )
05067 {
05068 flux += DATA(image_data, pos);
05069 }
05070 }
05071
05072 if (flux != 0)
05073 {
05074 for (pos->y = pos->ylow; pos->y <= pos->yhigh; pos->y++)
05075 {
05076 int bin = pos->y - pos->ylow;
05077
05078 if (ISGOOD(image_bpm, pos) &&
05079 (locut[bin] <= DATA(image_data, pos) &&
05080 DATA(image_data, pos) <= hicut[bin])
05081 )
05082 {
05083 double pix = DATA(image_data, pos);
05084
05085 cpl_vector_set(dy , n, pos->y - pos->ycenter);
05086 cpl_vector_set(prof , n, pix/flux);
05087 cpl_vector_set(dprof, n, (flux > 0) ?
05088 DATA(noise_data, pos)/flux :
05089 -DATA(noise_data, pos)/flux);
05090 n++;
05091 }
05092 else
05093 {
05094 nbad += 1;
05095
05096
05097 }
05098 }
05099 }
05100 }
05101
05102 if (n >= points_needed_for_fit) {
05103 double y_0, norm, background, slope, sigma, red_chisq;
05104
05105 cpl_vector_set_size(dy, n);
05106 cpl_vector_set_size(prof, n);
05107 cpl_vector_set_size(prof2, n);
05108 cpl_vector_set_size(dprof, n);
05109
05110
05111 uves_msg_debug("Fitting chunk (%d, %d)",
05112 x-chunk/2, x+chunk/2);
05113
05114
05115
05116
05117 uves_free_matrix(&covariance);
05118
05119 background = 0;
05120 norm = 1.0;
05121
05122
05123
05124
05125
05126 if (0) {
05127
05128
05129
05130 #if defined CPL_VERSION_CODE && CPL_VERSION_CODE >= CPL_VERSION(4, 0, 0)
05131 double median = cpl_vector_get_median_const(dprof);
05132 #else
05133 double median = cpl_vector_get_median(dprof);
05134 #endif
05135 cpl_vector_fill(dprof, median);
05136 }
05137 uves_fit_1d(dy, NULL,
05138 #if 1
05139 prof, dprof,
05140 #else
05141 prof, NULL,
05142 #endif
05143 CPL_FIT_CENTROID |
05144 CPL_FIT_STDEV,
05145 false,
05146 &y_0, &sigma, &norm, &background, &slope,
05147 #if 1
05148 NULL, &red_chisq,
05149 &covariance,
05150 #else
05151 NULL, NULL,
05152 NULL,
05153 #endif
05154 f, dfda, M);
05155 #if 1
05156 #else
05157 covariance = cpl_matrix_new(4,4);
05158 cpl_matrix_set(covariance, 0, 0, 1);
05159 cpl_matrix_set(covariance, 1, 1, 1);
05160 cpl_matrix_set(covariance, 2, 2, 1);
05161 cpl_matrix_set(covariance, 3, 3, 1);
05162 red_chisq = 1;
05163 #endif
05164 if (false)
05165 {
05166
05167
05168
05169
05170
05171
05172
05173
05174
05175
05176
05177
05178
05179
05180
05181 cpl_vector *pl[] = {NULL, NULL, NULL};
05182
05183 cpl_vector *fit = cpl_vector_new(cpl_vector_get_size(dy));
05184 {
05185 for (i = 0; i < cpl_vector_get_size(dy); i++)
05186 {
05187 double yy = cpl_vector_get(dy, i);
05188 cpl_vector_set(fit, i,
05189 exp(-(yy-y_0)*(yy-y_0)/(2*sigma*sigma))
05190 /(sigma*sqrt(2*M_PI)));
05191 }
05192 }
05193
05194
05195
05196
05197
05198 pl[0] = prof2;
05199 pl[1] = dprof;
05200 pl[2] = dprof;
05201
05202
05203
05204 uves_error_reset();
05205 irplib_vectors_plot("set grid;set yrange[0:0.5];set xlabel 'dy';",
05206 "t 'Spatial profile' w points",
05207 "",
05208 (const cpl_vector **)pl, 3);
05209
05210
05211 pl[0] = prof;
05212 pl[1] = dprof;
05213 pl[2] = dprof;
05214
05215 irplib_vectors_plot("set grid;set xrange[-2:2];"
05216 "set yrange[0:0.5];set xlabel 'dy';",
05217 "t 'Spatial profile' w points",
05218 "",
05219 (const cpl_vector **)pl, 3);
05220
05221 uves_free_vector(&fit);
05222
05223 }
05224
05225
05226 uves_iterate_set_first(pos,
05227 x, x,
05228 pos->order, pos->order,
05229 NULL,
05230 false);
05231 y_0 += pos->ycenter;
05232
05233
05234
05235
05236
05237
05238
05239
05240
05241
05242
05243
05244
05245
05246
05247
05248
05249
05250
05251
05252
05253
05254
05255
05256 if (cpl_error_get_code() == CPL_ERROR_CONTINUE ||
05257 cpl_error_get_code()== CPL_ERROR_SINGULAR_MATRIX ||
05258 4.0*sigma >= pos->sg.length || sigma < 0.2) {
05259
05260 uves_msg_debug("Profile fitting failed at (order, x) = (%d, %d) "
05261 "(%s), ignoring chunk",
05262 pos->order, x, cpl_error_get_message());
05263
05264 uves_error_reset();
05265 }
05266 else {
05267 assure( cpl_error_get_code() == CPL_ERROR_NONE, cpl_error_get_code(),
05268 "Gaussian fitting failed");
05269
05270 check(
05271 (cpl_table_set_int (profile_data, "Order", profile_row, pos->order),
05272 cpl_table_set_int (profile_data, "X" , profile_row, x),
05273 cpl_table_set_double(profile_data, "Y0" , profile_row, y_0 - pos->ycenter),
05274 cpl_table_set_double(profile_data, "Sigma", profile_row, sigma),
05275 cpl_table_set_double(profile_data, "Norm" , profile_row, norm),
05276 cpl_table_set_double(profile_data, "dY0" , profile_row,
05277 sqrt(cpl_matrix_get(covariance, 0, 0))),
05278 cpl_table_set_double(profile_data, "dSigma", profile_row,
05279 sqrt(cpl_matrix_get(covariance, 1, 1))),
05280 cpl_table_set_double(profile_data, "dNorm", profile_row,
05281 sqrt(cpl_matrix_get(covariance, 2, 2))),
05282 cpl_table_set_double(profile_data, "Y0_world", profile_row, y_0),
05283 cpl_table_set_double(profile_data, "Reduced_chisq", profile_row,
05284 red_chisq)),
05285 "Error writing table");
05286
05287 profile_row += 1;
05288
05289
05290 }
05291 }
05292 else
05293 {
05294 uves_msg_debug("Order #%d: Too few (%d) points available in "
05295 "at x = %d - %d, ignoring chunk",
05296 pos->order, n,
05297 x - chunk/2, x + chunk/2);
05298 }
05299 }
05300
05301 #endif
05302
05303 cpl_table_set_size(profile_data, profile_row);
05304
05305 UVES_TIME_END;
05306
05307
05308 cleanup:
05309 #if NEW_METHOD
05310 uves_free_matrix(&eval_points);
05311 uves_free_vector(&eval_data);
05312 uves_free_vector(&eval_err);
05313 uves_free_vector(&coeffs);
05314 cpl_free(fluxes);
05315 cpl_free(skys);
05316 cpl_free(ia);
05317 #if CREATE_DEBUGGING_TABLE
05318 uves_free_table(&temp);
05319 #endif
05320 uves_free_table(&estimate);
05321 uves_free_table(&estimate_dup);
05322 uves_polynomial_delete(&y0_estim_pol);
05323 uves_polynomial_delete(&sigma_estim_pol);
05324 #endif
05325
05326 uves_free_matrix(&covariance);
05327 uves_free_vector(&dy);
05328 uves_free_vector(&prof);
05329 uves_free_vector(&prof2);
05330 uves_free_vector(&dprof);
05331 {
05332 int i;
05333 for (i = 0; i < nbins; i++)
05334 {
05335 uves_free_vector(&(data[i]));
05336 }
05337 }
05338 cpl_free(data);
05339 cpl_free(size);
05340 cpl_free(locut);
05341 cpl_free(hicut);
05342
05343 if (cpl_error_get_code() != CPL_ERROR_NONE)
05344 {
05345 uves_free_table(&profile_data);
05346 }
05347
05348 return profile_data;
05349 }
05350
05351
05352
05361
05362 static int
05363 opt_get_order_width(const uves_iterate_position *pos)
05364 {
05365 int result = -1;
05366
05367 double x1 = 1;
05368 double x2 = pos->nx;
05369 double y_1 = uves_polynomial_evaluate_2d(pos->order_locations, x1, pos->order);
05370 double y2 = uves_polynomial_evaluate_2d(pos->order_locations, x2, pos->order);
05371 double slope = (y2 - y_1)/(x2 - x1);
05372
05373 if (slope != 0)
05374 {
05375
05376
05377
05378
05379
05380
05381
05382 double x_yeq1 = ( 1 - y_1)/slope;
05383 double x_yeqny = (pos->ny - y_1)/slope;
05384
05385 if (1 <= x_yeq1 && x_yeq1 <= pos->nx)
05386 {
05387 double guess = x_yeq1;
05388
05389 uves_msg_debug("Guess value (y = 1) x = %f", guess);
05390
05391 x_yeq1 = uves_polynomial_solve_2d(pos->order_locations,
05392 1,
05393 guess,
05394 1,
05395 2,
05396
05397 pos->order);
05398
05399 if (cpl_error_get_code() != CPL_ERROR_NONE)
05400 {
05401 uves_error_reset();
05402 uves_msg_warning("Could not solve order polynomial = 1 at order #%d. "
05403 "Order polynomial may be ill-formed", pos->order);
05404 x_yeq1 = guess;
05405 }
05406 else
05407 {
05408 uves_msg_debug("Exact value (y = 1) x = %f", x_yeq1);
05409 }
05410 }
05411
05412 if (1 <= x_yeqny && x_yeqny <= pos->nx)
05413 {
05414 double guess = x_yeqny;
05415
05416 uves_msg_debug("Guess value (y = %d) = %f", pos->ny, guess);
05417
05418 x_yeqny = uves_polynomial_solve_2d(pos->order_locations,
05419 pos->ny,
05420 guess,
05421 1,
05422 2,
05423
05424 pos->order);
05425
05426 if (cpl_error_get_code() != CPL_ERROR_NONE)
05427 {
05428 uves_error_reset();
05429 uves_msg_warning("Could not solve order polynomial = %d at order #%d. "
05430 "Order polynomial may be ill-formed",
05431 pos->ny, pos->order);
05432 x_yeqny = guess;
05433 }
05434 else
05435 {
05436 uves_msg_debug("Exact value (y = %d) x = %f", pos->ny, x_yeqny);
05437 }
05438 }
05439
05440 if (slope > 0)
05441 {
05442 result = uves_round_double(
05443 uves_max_double(1,
05444 uves_min_double(pos->nx, x_yeqny) -
05445 uves_max_double(1, x_yeq1) + 1));
05446 }
05447 else
05448 {
05449 passure( slope < 0, "%f", slope);
05450 result = uves_round_double(
05451 uves_max_double(1,
05452 uves_min_double(pos->nx, x_yeq1 ) -
05453 uves_max_double(1, x_yeqny) + 1));
05454 }
05455 }
05456 else
05457 {
05458 result = pos->nx;
05459 }
05460
05461 uves_msg_debug("Order width = %d pixels", result);
05462
05463 cleanup:
05464
05465 return result;
05466 }
05467
05468
05469
05507
05508 static int
05509 opt_extract(cpl_image *image, const cpl_image *image_noise,
05510 uves_iterate_position *pos,
05511 const uves_extract_profile *profile,
05512 bool optimal_extract_sky,
05513 double kappa,
05514 cpl_table *cosmic_mask, int *cr_row,
05515 cpl_table *profile_table, int *prof_row,
05516 cpl_image *spectrum, cpl_image *spectrum_noise,
05517 cpl_image *weights,
05518 cpl_image *sky_spectrum,
05519 cpl_image *sky_spectrum_noise,
05520 double *sn)
05521 {
05522 cpl_table *signal_to_noise = NULL;
05523
05524
05525 int sn_row = 0;
05526
05527
05528 int bins_extracted = 0;
05529 int cold_pixels = 0;
05530 int hot_pixels = 0;
05531 int warnings = 0;
05532
05533 const double *image_data;
05534 const double *noise_data;
05535 double *weights_data;
05536 cpl_mask *image_bad = NULL;
05537 cpl_binary*image_bpm = NULL;
05538 double *noise_buffer = NULL;
05539
05540 int order_width;
05541 int spectrum_row = pos->order - pos->minorder + 1;
05542
05543
05544
05545
05546 assure( cpl_image_get_type(image) == CPL_TYPE_DOUBLE &&
05547 cpl_image_get_type(image_noise) == CPL_TYPE_DOUBLE, CPL_ERROR_UNSUPPORTED_MODE,
05548 "Input image+noise must have type double. Types are %s + %s",
05549 uves_tostring_cpl_type(cpl_image_get_type(image)),
05550 uves_tostring_cpl_type(cpl_image_get_type(image_noise)));
05551
05552 image_data = cpl_image_get_data_double_const(image);
05553 noise_data = cpl_image_get_data_double_const(image_noise);
05554 weights_data = cpl_image_get_data_double(weights);
05555
05556 image_bad = cpl_image_get_bpm(image);
05557 image_bpm = cpl_mask_get_data(image_bad);
05558
05559 noise_buffer = cpl_malloc(uves_round_double(pos->sg.length + 5)*sizeof(double));
05560
05561 check( (signal_to_noise = cpl_table_new(pos->nx),
05562 cpl_table_new_column(signal_to_noise, "SN", CPL_TYPE_DOUBLE)),
05563 "Error allocating S/N table");
05564
05565 check( order_width = opt_get_order_width(pos),
05566 "Error estimating width of order #%d", pos->order);
05567
05568
05569
05570
05571 {
05572 int x;
05573 for (x = 1; x <= pos->nx; x++)
05574 {
05575 cpl_image_reject(spectrum, x, spectrum_row);
05576
05577
05578 if (spectrum_noise != NULL)
05579 {
05580 cpl_image_reject(spectrum_noise, x, spectrum_row);
05581 }
05582 if (optimal_extract_sky && sky_spectrum != NULL)
05583 {
05584 cpl_image_reject(sky_spectrum , x, spectrum_row);
05585 cpl_image_reject(sky_spectrum_noise, x, spectrum_row);
05586 }
05587 }
05588 }
05589
05590 for (uves_iterate_set_first(pos,
05591 1, pos->nx,
05592 pos->order, pos->order,
05593 NULL, false);
05594 !uves_iterate_finished(pos);
05595 uves_iterate_increment(pos))
05596 {
05597 double flux = 0, variance = 0;
05598 double sky_background = 0, sky_background_noise = 0;
05599
05600
05601
05602
05603 int iteration;
05604
05605 bool found_bad_pixel;
05606 double median_noise;
05607
05608 double redchisq = 0;
05609
05610
05611 if (kappa > 0)
05612 {
05613 redchisq = opt_get_redchisq(profile, pos);
05614 }
05615
05616
05617 uves_extract_profile_set(profile, pos, &warnings);
05618
05619
05620
05621
05622
05623
05624
05625
05626
05627
05628
05629
05630
05631
05632
05633
05634
05635
05636
05637
05638
05639
05640
05641
05642
05643
05644
05645
05646
05647 for (pos->y = pos->ylow; pos->y <= pos->yhigh; pos->y++)
05648 {
05649 if (DATA(image_bpm, pos) == CPL_BINARY_1)
05650 {
05651 DATA(weights_data, pos) = -1.0;
05652 }
05653 else
05654 {
05655 DATA(weights_data, pos) = 0.0;
05656 }
05657 }
05658
05659
05660 median_noise = opt_get_noise_median(noise_data, image_bpm,
05661 pos, noise_buffer);
05662
05663
05664
05665 found_bad_pixel = false;
05666
05667 for (iteration = 0; iteration < 2 || found_bad_pixel; iteration++)
05668 {
05669
05670
05671
05672 flux = opt_get_flux_sky_variance(image_data, noise_data,
05673 weights_data,
05674 pos,
05675 profile,
05676 optimal_extract_sky,
05677 (iteration == 0) ?
05678 median_noise : -1,
05679 &variance,
05680 &sky_background,
05681 &sky_background_noise);
05682
05683
05684 if (kappa > 0)
05685 {
05686 check( found_bad_pixel = opt_reject_outlier(
05687 image_data, noise_data,
05688 image_bpm,
05689 weights_data,
05690 pos,
05691 profile,
05692 kappa,
05693 flux,
05694 optimal_extract_sky ? sky_background : 0,
05695 redchisq,
05696 cosmic_mask, cr_row,
05697 &hot_pixels, &cold_pixels),
05698 "Error rejecting outlier pixel");
05699
05700 }
05701 else
05702 {
05703 found_bad_pixel = false;
05704 }
05705
05706 }
05707
05708
05709 if (profile_table != NULL) {
05710 double lin_flux = 0;
05711 for (pos->y = pos->ylow; pos->y <= pos->yhigh; pos->y++) {
05712
05713 if (DATA(weights_data, pos) > 0)
05714 {
05715 double pixelval = DATA(image_data, pos);
05716 lin_flux += pixelval;
05717 }
05718 }
05719
05720 for (pos->y = pos->ylow; pos->y <= pos->yhigh; pos->y++) {
05721
05722 if (DATA(weights_data, pos) > 0)
05723 {
05724 double dy = pos->y - pos->ycenter;
05725 double pixelval = DATA(image_data, pos);
05726
05727 check_nomsg(
05728 (cpl_table_set_int (profile_table, "Order" ,
05729 *prof_row, pos->order),
05730 cpl_table_set_int (profile_table, "X" ,
05731 *prof_row, pos->x),
05732 cpl_table_set_double(profile_table, "DY" ,
05733 *prof_row, dy),
05734 cpl_table_set_double(profile_table, "Profile_raw",
05735 *prof_row, pixelval/lin_flux),
05736 cpl_table_set_double(profile_table, "Profile_int",
05737 *prof_row,
05738 uves_extract_profile_evaluate(profile, pos))));
05739 (*prof_row)++;
05740 }
05741 }
05742 }
05743
05744 bins_extracted += 1;
05745
05746
05747
05748
05749
05750
05751
05752
05753
05754
05755
05756 SPECTRUM_DATA(cpl_image_get_data_double(spectrum), pos) = flux;
05757 SPECTRUM_DATA(cpl_mask_get_data(cpl_image_get_bpm(spectrum)), pos)
05758 = CPL_BINARY_0;
05759
05760
05761 if (spectrum_noise != NULL)
05762 {
05763 cpl_image_set(spectrum_noise, pos->x, spectrum_row, sqrt(variance));
05764 }
05765
05766
05767
05768 if (optimal_extract_sky)
05769 {
05770
05771
05772
05773
05774
05775
05776
05777
05778 cpl_image_set(sky_spectrum , pos->x, spectrum_row,
05779 pos->sg.length * sky_background);
05780 cpl_image_set(sky_spectrum_noise, pos->x, spectrum_row,
05781 pos->sg.length * sky_background_noise);
05782 }
05783
05784
05785
05786
05787
05788 if (order_width < pos->nx ||
05789 (0.45*pos->nx <= pos->x && pos->x <= 0.55*pos->nx)
05790 )
05791 {
05792 cpl_table_set_double(
05793 signal_to_noise, "SN", sn_row, flux / sqrt(variance));
05794 sn_row++;
05795 }
05796
05797 }
05798 uves_msg_debug("%d/%d hot/cold pixels rejected", hot_pixels, cold_pixels);
05799
05800
05801 check_nomsg( cpl_table_set_size(signal_to_noise, sn_row) );
05802 if (sn_row > 0)
05803 {
05804 check_nomsg( *sn = cpl_table_get_column_median(signal_to_noise, "SN"));
05805 }
05806 else
05807 {
05808 *sn = 0;
05809 }
05810
05811 cleanup:
05812 uves_free_table(&signal_to_noise);
05813 cpl_free(noise_buffer);
05814
05815 return bins_extracted;
05816 }
05817
05818
05841
05842 inline static double
05843 opt_get_sky(const double *image_data,
05844 const double *noise_data,
05845 const double *weights_data,
05846 uves_iterate_position *pos,
05847 const cpl_table *sky_map,
05848 double buffer_flux[], double buffer_noise[],
05849 double *sky_background_noise)
05850 {
05851 double sky_background;
05852 bool found_good = false;
05853 double flux_max = 0;
05854 double flux_min = 0;
05855 int ngood = 0;
05856
05857
05858 for (pos->y = pos->ylow; pos->y <= pos->yhigh; pos->y++)
05859 {
05860 int row = pos->y - pos->ylow;
05861
05862 if (!ISBAD(weights_data, pos))
05863 {
05864 double fflux = DATA(image_data, pos);
05865 double noise = DATA(noise_data, pos);
05866
05867 if (!found_good)
05868 {
05869 found_good = true;
05870 flux_max = fflux;
05871 flux_min = fflux;
05872 }
05873 else
05874 {
05875 flux_max = uves_max_double(flux_max, fflux);
05876 flux_min = uves_min_double(flux_min, fflux);
05877 }
05878
05879
05880
05881
05882
05883
05884
05885
05886 if (cpl_table_is_selected(sky_map, row))
05887 {
05888 buffer_flux [ngood] = fflux;
05889 buffer_noise[ngood] = noise;
05890 ngood++;
05891 }
05892 }
05893 }
05894
05895
05896 if (ngood > 0)
05897 {
05898
05899 double avg_noise = uves_tools_get_median(buffer_noise, ngood);
05900
05901 sky_background = uves_tools_get_median(buffer_flux, ngood);
05902
05903
05904 if (ngood == 1)
05905 {
05906 *sky_background_noise = avg_noise;
05907 }
05908 else
05909 {
05910
05911
05912
05913
05914
05915
05916
05917
05918 *sky_background_noise = avg_noise / sqrt(ngood * 2 / M_PI);
05919 }
05920 }
05921 else
05922
05923 {
05924 if (found_good)
05925 {
05926 sky_background = flux_min;
05927 *sky_background_noise = flux_max - flux_min;
05928
05929
05930
05931 if (*sky_background_noise <= 0) *sky_background_noise = 1;
05932 }
05933 else
05934
05935 {
05936 sky_background = 0;
05937 *sky_background_noise = 1;
05938 }
05939 }
05940
05941
05942 return sky_background;
05943
05944 }
05945
05946
05947
05957
05958 inline static double
05959 opt_get_noise_median(const double *noise_data, const cpl_binary *image_bpm,
05960 uves_iterate_position *pos, double noise_buffer[])
05961 {
05962 double median_noise;
05963 int ngood;
05964
05965 ngood = 0;
05966 for (pos->y = pos->ylow; pos->y <= pos->yhigh; pos->y++)
05967 {
05968 if (ISGOOD(image_bpm, pos))
05969 {
05970 noise_buffer[ngood] = DATA(noise_data, pos);
05971 ngood++;
05972 }
05973 }
05974
05975 if (ngood >= 1)
05976 {
05977 median_noise = uves_tools_get_median(noise_buffer, ngood);
05978 }
05979 else
05980 {
05981 median_noise = 1;
05982 }
05983
05984 return median_noise;
05985 }
05986
05987
06060
06061
06062 inline static double
06063 opt_get_flux_sky_variance(const double *image_data, const double *noise_data,
06064 double *weights_data,
06065 uves_iterate_position *pos,
06066 const uves_extract_profile *profile,
06067 bool optimal_extract_sky,
06068 double median_noise,
06069 double *variance,
06070 double *sky_background,
06071 double *sky_background_noise)
06072 {
06073 double flux;
06074 double sumpfv = 0;
06075 double sumppv = 0;
06076 double sum1v = 0;
06077 double sumpv = 0;
06078 double sumfv = 0;
06079
06080 for (pos->y = pos->ylow; pos->y <= pos->yhigh; pos->y++)
06081 {
06082
06083 if (!ISBAD(weights_data, pos))
06084 {
06085 double pixel_variance, pixelval, weight;
06086 double prof = uves_extract_profile_evaluate(profile, pos);
06087
06088 pixelval = DATA(image_data, pos);
06089 pixel_variance = DATA(noise_data, pos);
06090 pixel_variance *= pixel_variance;
06091
06092 if (median_noise >= 0 && pixel_variance < median_noise*median_noise)
06093 {
06094
06095
06096 pixel_variance = median_noise*median_noise;
06097 }
06098
06099 weight = prof / pixel_variance;
06100 DATA(weights_data, pos) = weight;
06101
06102
06103
06104
06105 sumpfv += pixelval * weight;
06106 sumppv += prof * weight;
06107 if (optimal_extract_sky)
06108
06109 {
06110 sumpv += weight;
06111 sum1v += 1 / pixel_variance;
06112 sumfv += pixelval / pixel_variance;
06113 }
06114 }
06115
06116
06117
06118
06119
06120
06121
06122
06123
06124
06125 }
06126
06127 if (!optimal_extract_sky)
06128 {
06129
06130 if (sumppv > 0)
06131 {
06132 flux = sumpfv / sumppv;
06133 *variance = 1 / sumppv;
06134 }
06135 else
06136 {
06137 flux = 0;
06138 *variance = 1;
06139 }
06140 }
06141 else
06142 {
06143
06144 double denominator = sum1v*sumppv - sumpv*sumpv;
06145 if (denominator != 0)
06146 {
06147 flux = (sum1v * sumpfv - sumpv * sumfv) / denominator;
06148
06149
06150
06151
06152
06153
06154
06155
06156 *variance = sum1v / denominator;
06157
06158 *sky_background = (sumppv*sumfv - sumpv*sumpfv) / denominator;
06159 *sky_background_noise = sqrt(sumppv / denominator);
06160 }
06161 else
06162 {
06163 flux = 0;
06164 *variance = 1;
06165
06166 *sky_background = 0;
06167 *sky_background_noise = 1;
06168 }
06169 }
06170
06171
06172
06173
06174
06175
06176
06177
06178 return flux;
06179 }
06180
06181
06182
06207
06208 inline static bool
06209 opt_reject_outlier(const double *image_data, const double *noise_data,
06210 cpl_binary *image_bpm,
06211 double *weights_data,
06212 uves_iterate_position *pos,
06213 const uves_extract_profile *profile,
06214 double kappa,
06215 double flux,
06216 double sky_background,
06217 double red_chisq,
06218 cpl_table *cosmic_mask, int *cr_row,
06219 int *hot_pixels, int *cold_pixels)
06220 {
06221 bool found_outlier = false;
06222
06223 int y_outlier = -1;
06224 double max_residual_sq = 0;
06225
06226 bool outlier_is_hot = false;
06227
06228
06229 for (pos->y = pos->ylow; pos->y <= pos->yhigh; pos->y++)
06230 {
06231 double prof = uves_extract_profile_evaluate(profile, pos);
06232 double pixel_variance, pixelval;
06233 double best_fit;
06234
06235 pixel_variance = DATA(noise_data, pos);
06236 pixel_variance *= pixel_variance;
06237
06238 pixelval = DATA(image_data, pos);
06239
06240 best_fit = flux * prof + sky_background;
06241
06242
06243
06244
06245
06246
06247
06248 if (!ISBAD(weights_data, pos) &&
06249
06250
06251
06252 (pixelval - best_fit)*(pixelval - best_fit) / pixel_variance
06253 >= max_residual_sq)
06254 {
06255 max_residual_sq =
06256 (pixelval - best_fit) *
06257 (pixelval - best_fit) / pixel_variance;
06258
06259 y_outlier = pos->y;
06260
06261 outlier_is_hot = (pixelval > best_fit);
06262 }
06263 }
06264
06265
06266
06267
06268 if (max_residual_sq > kappa*kappa * red_chisq)
06269 {
06270 uves_msg_debug("Order #%d: Bad pixel at (x, y) = (%d, %d) residual^2 = %.2f sigma^2",
06271 pos->order, pos->x, y_outlier, max_residual_sq);
06272
06273 pos->y = y_outlier;
06274 SETBAD(weights_data, image_bpm, pos);
06275
06276 found_outlier = true;
06277 if (outlier_is_hot)
06278 {
06279 *hot_pixels += 1;
06280
06281
06282 while (*cr_row >= cpl_table_get_nrow(cosmic_mask))
06283 {
06284 cpl_table_set_size(cosmic_mask, 2*cpl_table_get_nrow(cosmic_mask));
06285 uves_msg_debug("Setting CR table size to %d",
06286 cpl_table_get_nrow(cosmic_mask));
06287 }
06288
06289 check(( cpl_table_set_int (cosmic_mask, "Order", *cr_row, pos->order),
06290 cpl_table_set_int (cosmic_mask, "X" , *cr_row, pos->x),
06291 cpl_table_set_int (cosmic_mask, "Y" , *cr_row, y_outlier),
06292 cpl_table_set_double(cosmic_mask, "Flux" , *cr_row,
06293 DATA(image_data, pos)),
06294 (*cr_row)++),
06295 "Error updating cosmic ray table");
06296 }
06297 else
06298 {
06299 *cold_pixels += 1;
06300 }
06301 }
06302
06303 cleanup:
06304 return found_outlier;
06305 }
06306
06307
06317
06318 static double
06319 opt_get_redchisq(const uves_extract_profile *profile,
06320 const uves_iterate_position *pos)
06321 {
06322 if (profile->constant) {
06323 return 1.0;
06324 }
06325 if (profile->f != NULL)
06326 {
06327 return uves_max_double(1,
06328 #if ORDER_PER_ORDER
06329 uves_polynomial_evaluate_1d(
06330 profile->red_chisq[pos->order-pos->minorder], pos->x));
06331 #else
06332 uves_polynomial_evaluate_2d(
06333 profile->red_chisq, pos->x, pos->order));
06334 #endif
06335 }
06336 else
06337 {
06338
06339 return 1.0;
06340 }
06341 }
06342
06343
06363
06364 static polynomial *
06365 repeat_orderdef(const cpl_image *image, const cpl_image *image_noise,
06366 const polynomial *guess_locations,
06367 int minorder, int maxorder, slit_geometry sg,
06368 cpl_table *info_tbl)
06369 {
06370 polynomial *order_locations = NULL;
06371 int nx = cpl_image_get_size_x(image);
06372 int ny = cpl_image_get_size_y(image);
06373 double max_shift = sg.length/2;
06374 int stepx = 10;
06375 int x, order;
06376 int ordertab_row;
06377 cpl_table *ordertab = NULL;
06378 cpl_table *temp = NULL;
06379
06380 ordertab = cpl_table_new((maxorder - minorder + 1)*nx);
06381 ordertab_row = 0;
06382 cpl_table_new_column(ordertab, "X" , CPL_TYPE_INT);
06383 cpl_table_new_column(ordertab, "Order", CPL_TYPE_INT);
06384 cpl_table_new_column(ordertab, "Y" , CPL_TYPE_DOUBLE);
06385 cpl_table_new_column(ordertab, "Yold" , CPL_TYPE_DOUBLE);
06386 cpl_table_new_column(ordertab, "Sigma", CPL_TYPE_DOUBLE);
06387 cpl_table_set_column_unit(ordertab, "Y", "pixels");
06388
06389
06390 for (order = minorder; order <= maxorder; order++) {
06391 for (x = 1 + stepx/2; x <= nx; x += stepx) {
06392 double ycenter;
06393 int yhigh, ylow;
06394
06395 double y_0, sigma, norm, background;
06396 check( ycenter = uves_polynomial_evaluate_2d(guess_locations, x, order),
06397 "Error evaluating polynomial");
06398
06399 ylow = uves_round_double(ycenter - max_shift);
06400 yhigh = uves_round_double(ycenter + max_shift);
06401
06402 if (1 <= ylow && yhigh <= ny) {
06403 uves_fit_1d_image(image, image_noise, NULL,
06404 false,
06405 false, false,
06406 ylow, yhigh, x,
06407 &y_0, &sigma, &norm, &background, NULL,
06408 NULL, NULL, NULL,
06409 uves_gauss, uves_gauss_derivative, 4);
06410
06411 if (cpl_error_get_code() == CPL_ERROR_CONTINUE) {
06412 uves_error_reset();
06413 uves_msg_debug("Profile fitting failed "
06414 "at (x,y) = (%d, %e), ignoring bin",
06415 x, ycenter);
06416 }
06417 else {
06418 assure(cpl_error_get_code() == CPL_ERROR_NONE,
06419 cpl_error_get_code(), "Gaussian fitting failed");
06420
06421 cpl_table_set_int (ordertab, "X" , ordertab_row, x);
06422 cpl_table_set_int (ordertab, "Order" , ordertab_row, order);
06423 cpl_table_set_double(ordertab, "Y" , ordertab_row, y_0);
06424 cpl_table_set_double(ordertab, "Yold" , ordertab_row, ycenter);
06425 cpl_table_set_double(ordertab, "Sigma" , ordertab_row, sigma);
06426 ordertab_row += 1;
06427 }
06428 }
06429 }
06430 }
06431
06432 cpl_table_set_size(ordertab, ordertab_row);
06433
06434
06435 if (ordertab_row < 300)
06436 {
06437 uves_msg_warning("Too few points (%d) to reliably fit order polynomial. "
06438 "Using calibration solution", ordertab_row);
06439
06440 uves_polynomial_delete(&order_locations);
06441 order_locations = uves_polynomial_duplicate(guess_locations);
06442
06443 cpl_table_duplicate_column(ordertab, "Yfit", ordertab, "Yold");
06444 }
06445 else
06446 {
06447 int max_degree = 10;
06448 double kappa = 4.0;
06449 double min_rms = 0.05;
06450
06451 order_locations =
06452 uves_polynomial_regression_2d_autodegree(ordertab,
06453 "X", "Order", "Y", NULL,
06454 "Yfit", NULL, NULL,
06455 NULL, NULL, NULL,
06456 kappa,
06457 max_degree, max_degree, min_rms, -1,
06458 true,
06459 NULL, NULL, -1, NULL);
06460
06461 if (cpl_error_get_code() == CPL_ERROR_SINGULAR_MATRIX)
06462 {
06463 uves_error_reset();
06464 uves_msg_warning("Could not fit new order polynomial. "
06465 "Using calibration solution");
06466
06467 uves_polynomial_delete(&order_locations);
06468 order_locations = uves_polynomial_duplicate(guess_locations);
06469
06470 cpl_table_duplicate_column(ordertab, "Yfit", ordertab, "Yold");
06471
06472
06473 }
06474 else
06475 {
06476 assure( cpl_error_get_code() == CPL_ERROR_NONE,
06477 cpl_error_get_code(),
06478 "Error fitting orders polynomial");
06479 }
06480 }
06481
06482
06483 cpl_table_duplicate_column(ordertab, "Yshift", ordertab, "Yfit");
06484 cpl_table_subtract_columns(ordertab, "Yshift", "Yold");
06485
06486 {
06487 double mean = cpl_table_get_column_mean(ordertab, "Yshift");
06488 double stdev = cpl_table_get_column_mean(ordertab, "Yshift");
06489 double rms = sqrt(mean*mean + stdev*stdev);
06490
06491 uves_msg("Average shift with respect to calibration solution is %.2f pixels", rms);
06492 }
06493
06494
06495 for (order = minorder; order <= maxorder; order++)
06496 {
06497 double pos =
06498 uves_polynomial_evaluate_2d(order_locations, nx/2, order)-
06499 uves_polynomial_evaluate_2d(guess_locations, nx/2, order);
06500
06501 double fwhm;
06502
06503
06504
06505
06506 uves_free_table(&temp);
06507 temp = uves_extract_table_rows(ordertab, "Order",
06508 CPL_EQUAL_TO,
06509 order);
06510
06511
06512 if (cpl_table_get_nrow(temp) < 1)
06513 {
06514 uves_msg_warning("Problem tracing object in order %d. "
06515 "Setting QC FHWM parameter to zero",
06516 order);
06517 fwhm = 0;
06518 }
06519 else
06520 {
06521 fwhm = cpl_table_get_column_median(temp, "Sigma") * TWOSQRT2LN2;
06522 }
06523
06524
06525 cpl_table_set_int (info_tbl, "Order", order - minorder, order);
06526 cpl_table_set_double(info_tbl, "Pos" , order - minorder,
06527 pos - (-sg.length/2 + sg.offset));
06528 cpl_table_set_double(info_tbl, "FWHM" , order - minorder, fwhm);
06529 }
06530
06531 cleanup:
06532 uves_free_table(&ordertab);
06533 uves_free_table(&temp);
06534
06535 return order_locations;
06536 }
06537