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 #ifdef HAVE_CONFIG_H
00156 # include <config.h>
00157 #endif
00158
00159
00166
00169
00170
00171
00172
00173 #include <uves_rebin.h>
00174
00175 #include <uves_parameters.h>
00176 #include <uves.h>
00177 #include <uves_pfits.h>
00178 #include <uves_dump.h>
00179 #include <uves_utils.h>
00180 #include <uves_utils_wrappers.h>
00181 #include <uves_wavecal_utils.h>
00182 #include <uves_error.h>
00183
00184 #include <cpl.h>
00185
00186
00187
00188
00189 inline static double
00190 integrate_flux(const double *spectrum_data_double,
00191 const float *spectrum_data_float,
00192 const int *spectrum_data_int,
00193 const cpl_binary *spectrum_bad,
00194 int spectrum_row,
00195 int nx,
00196 double x_min, double x_max,
00197 bool threshold_to_positive,
00198 bool *is_bad);
00199
00200
00201
00202
00203
00204
00212
00213 cpl_parameterlist *
00214 uves_rebin_define_parameters(void)
00215 {
00216 const char *name = "";
00217 char *full_name = NULL;
00218 cpl_parameter *p = NULL;
00219 cpl_parameterlist *parameters = NULL;
00220
00221 parameters = cpl_parameterlist_new();
00222
00223 {
00224 name = "wavestep";
00225 full_name = uves_sprintf("%s.%s", UVES_REBIN_ID, name);
00226 uves_parameter_new_value(p, full_name,
00227 CPL_TYPE_DOUBLE,
00228 "The bin size (in w.l.u.) in wavelength space. "
00229 "If negative, a step size of "
00230 "2/3 * ( average pixel size ) is used.",
00231 UVES_REBIN_ID,
00232 -1.0);
00233 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, name);
00234 cpl_parameterlist_append(parameters, p);
00235 cpl_free(full_name);
00236
00237 name = "scale";
00238 full_name = uves_sprintf("%s.%s", UVES_REBIN_ID, name);
00239 uves_parameter_new_value(p, full_name,
00240 CPL_TYPE_BOOL,
00241 "Whether or not to multiply by the factor "
00242 "dx/dlambda (pixels per wavelength) "
00243 "during the rebinning. This option is disabled "
00244 "as default in concordance with the "
00245 "method used in the MIDAS pipeline. This "
00246 "option should be set to true "
00247 "to convert the observed flux (in pixel-space) "
00248 "to a flux per wavelength (in "
00249 "wavelength-space).",
00250 UVES_REBIN_ID,
00251 false);
00252 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, name);
00253 cpl_parameterlist_append(parameters, p);
00254 cpl_free(full_name);
00255 }
00256
00257 if (cpl_error_get_code() != CPL_ERROR_NONE)
00258 {
00259 cpl_msg_error(__func__, "Creation of rebinning parameters failed: '%s'",
00260 cpl_error_get_where());
00261 cpl_parameterlist_delete(parameters);
00262 return NULL;
00263 }
00264 else
00265 {
00266 return parameters;
00267 }
00268 }
00269
00270
00315
00316 cpl_image *
00317 uves_rebin(const cpl_image *spectrum,
00318 const cpl_parameterlist *parameters, const char *context,
00319 const cpl_table *linetable, const polynomial *dispersion_relation,
00320 int first_abs_order, int last_abs_order,
00321 int n_traces,
00322 bool threshold_to_positive,
00323 uves_propertylist **rebinned_header)
00324 {
00325 double wavestep;
00326 bool scale;
00327 cpl_image *rebinned = NULL;
00328 double *rebinned_data_double = NULL;
00329 float *rebinned_data_float = NULL;
00330 int *rebinned_data_int = NULL;
00331 cpl_mask *rebinned_badmap = NULL;
00332 cpl_binary *rebinned_bad = NULL;
00333
00334 const double *spectrum_data_double = NULL;
00335 const float *spectrum_data_float = NULL;
00336 const int *spectrum_data_int = NULL;
00337
00338 const cpl_mask *spectrum_badmap = NULL;
00339 const cpl_binary *spectrum_bad = NULL;
00340
00341 polynomial *disprel_1d = NULL;
00342
00343 int nx, ny, nlambda, norders;
00344 int order;
00345 bool warning_shown = false;
00346
00347
00348 passure( spectrum != NULL, " ");
00349 passure( dispersion_relation != NULL, " ");
00350 passure( rebinned_header != NULL, " ");
00351
00352 assure( cpl_image_get_type(spectrum) == CPL_TYPE_DOUBLE ||
00353 cpl_image_get_type(spectrum) == CPL_TYPE_FLOAT ||
00354 cpl_image_get_type(spectrum) == CPL_TYPE_INT,
00355 CPL_ERROR_TYPE_MISMATCH,
00356 "Spectrum must have type double, float or int. It is '%s'",
00357 uves_tostring_cpl_type(cpl_image_get_type(spectrum)));
00358
00359
00360 check( uves_get_parameter(parameters, context, UVES_REBIN_ID, "wavestep",
00361 CPL_TYPE_DOUBLE, &wavestep ),
00362 "Could not read parameter");
00363 check( uves_get_parameter(parameters, context, UVES_REBIN_ID, "scale" ,
00364 CPL_TYPE_BOOL, &scale ),
00365 "Could not read parameter");
00366
00367
00368
00369 if (wavestep < 0)
00370 {
00371 double pixelsize;
00372 check( pixelsize = cpl_table_get_column_mean(linetable, LINETAB_PIXELSIZE),
00373 "Error reading mean pixelsize");
00374 uves_msg_debug("Average pixelsize = %f w.l.u.", pixelsize);
00375
00376 wavestep = pixelsize*2.0/3;
00377 }
00378
00379 assure( wavestep > 0 , CPL_ERROR_ILLEGAL_INPUT,
00380 "Illegal step size: %e wlu", wavestep);
00381 assure( n_traces >= 1, CPL_ERROR_ILLEGAL_INPUT,
00382 "Illegal number of traces: %d", n_traces);
00383
00384 nx = cpl_image_get_size_x(spectrum);
00385 ny = cpl_image_get_size_y(spectrum);
00386
00387 assure( ny % n_traces == 0, CPL_ERROR_INCOMPATIBLE_INPUT,
00388 "Spectrum image height (%d) is not a multiple of "
00389 "the number of traces (%d). Confused, bailing out",
00390 ny, n_traces);
00391
00392 norders = ny / n_traces;
00393
00394
00395 if (cpl_image_get_type(spectrum) == CPL_TYPE_DOUBLE) {
00396 spectrum_data_double = cpl_image_get_data_double_const(spectrum);
00397 }
00398 else if (cpl_image_get_type(spectrum) == CPL_TYPE_FLOAT) {
00399 spectrum_data_float = cpl_image_get_data_float_const(spectrum);
00400 } else {
00401 spectrum_data_int = cpl_image_get_data_int_const(spectrum);
00402 }
00403 spectrum_badmap = cpl_image_get_bpm_const(spectrum);
00404 spectrum_bad = cpl_mask_get_data_const(spectrum_badmap);
00405
00406 assure( norders >= 1, CPL_ERROR_ILLEGAL_INPUT, "Empty spectrum");
00407 assure( uves_round_double(fabs(first_abs_order - last_abs_order)) + 1 == norders,
00408 CPL_ERROR_INCOMPATIBLE_INPUT,
00409 "Spectrum contains %d orders, but line table absolute "
00410 "order numbering is %d - %d",
00411 norders, first_abs_order, last_abs_order);
00412
00413
00414 check( *rebinned_header = uves_initialize_image_header(
00415 "Angstrom",
00416 (n_traces > 1) ? "PIXEL" : "ORDER",
00417 (scale) ? "FLUX PER WAVEL" : "FLUX",
00418 0.0, 1.0,
00419 1.0, 1.0,
00420 wavestep, 1.0),
00421 "Error setting up rebinned image header");
00422
00423
00424
00425
00426
00427
00428
00429 nlambda = -1;
00430
00431 for (order = 1; order <= norders; order++)
00432 {
00433
00434
00435
00436
00437
00438
00439
00440 int absorder = uves_absolute_order(first_abs_order, last_abs_order, order);
00441 double lambda_min, lambda_max;
00442 int nbins;
00443
00444 int minx, maxx;
00445
00446 minx = 1;
00447
00448
00449
00450
00451 maxx = nx;
00452
00453 if ( minx > nx )
00454 {
00455 uves_msg_debug("Nothing extracted in order #%d", order);
00456 minx = maxx = nx/2;
00457 }
00458
00459 lambda_min = uves_polynomial_evaluate_2d(
00460 dispersion_relation, minx - 0.5, absorder)/absorder;
00461 lambda_max = uves_polynomial_evaluate_2d(
00462 dispersion_relation, maxx + 0.5, absorder)/absorder;
00463
00464 nbins =
00465 uves_round_double(lambda_max / wavestep) -
00466 uves_round_double(lambda_min / wavestep) + 1;
00467
00468 nlambda = uves_max_int(nlambda, nbins);
00469
00470 check( uves_pfits_set_wstart(
00471 *rebinned_header, order,
00472 wavestep * uves_round_double(lambda_min / wavestep)),
00473 "Error writing adding WSTART keyword to header");
00474
00475 check( uves_pfits_set_wend(
00476 *rebinned_header, order,
00477 wavestep * uves_round_double(lambda_max / wavestep)),
00478 "Error writing adding WEND keyword to header");
00479
00480 uves_msg_debug("Rebinning abs. order #%d. "
00481 "Range = %d - %d pix = %f - %f wlu, %d bins",
00482 absorder,
00483 minx, maxx,
00484 lambda_min,
00485 lambda_max,
00486 nbins);
00487 }
00488
00489
00490 uves_msg_debug("Step size = %f wlu (%d orders x %d bins)", wavestep, norders, nlambda);
00491
00492
00493
00494
00495 check_nomsg( rebinned = cpl_image_new(nlambda, norders*n_traces, cpl_image_get_type(spectrum)));
00496 assure_mem( rebinned );
00497
00498 if (cpl_image_get_type(spectrum) == CPL_TYPE_DOUBLE) {
00499 rebinned_data_double = cpl_image_get_data_double(rebinned);
00500 }
00501 else if (cpl_image_get_type(spectrum) == CPL_TYPE_FLOAT) {
00502 rebinned_data_float = cpl_image_get_data_float(rebinned);
00503 } else {
00504 rebinned_data_int = cpl_image_get_data_int(rebinned);
00505 }
00506 rebinned_badmap = cpl_image_get_bpm(rebinned);
00507 rebinned_bad = cpl_mask_get_data(rebinned_badmap);
00508
00509
00510
00511 uves_image_reject_all(rebinned);
00512
00513 for (order = 1; order <= norders; order++)
00514 {
00515 int absorder = uves_absolute_order(first_abs_order, last_abs_order, order);
00516 double lambda_start;
00517 int trace;
00518
00519
00520
00521 check( lambda_start = uves_pfits_get_wstart(*rebinned_header, order),
00522 "Error reading product header");
00523
00524
00525 uves_polynomial_delete(&disprel_1d);
00526 check( disprel_1d = uves_polynomial_collapse(dispersion_relation,
00527 2,
00528 absorder),
00529 "Error getting 1d dispersion relation for absolute order #%d", absorder);
00530
00531
00532
00533 for (trace = 1; trace <= n_traces; trace++)
00534 {
00535 int spectrum_row = (order - 1)*n_traces + trace;
00536 int bin;
00537
00538 double x = 1;
00539 double x_min = 1;
00540 double x_max = 1;
00541
00542 for (bin = 1; bin <= nlambda && x_min <= nx+0.5; bin++)
00543 {
00544 double lambda = lambda_start + (bin-1) * wavestep;
00545
00546 int multiplicity = 1;
00547 double x_guess = x;
00548
00549
00550
00551 x = uves_polynomial_solve_1d(disprel_1d,
00552 lambda * absorder,
00553 x_guess,
00554 multiplicity);
00555
00556 if (cpl_error_get_code() == CPL_ERROR_DIVISION_BY_ZERO) {
00557 uves_error_reset();
00558 if (!warning_shown) {
00559 uves_msg_warning("Could not invert dispersion relation at "
00560 "order = %d, x = %f. This might be caused "
00561 "by fitting a too high degree polynomial to "
00562 "too few lines. Decrease dispersion "
00563 "polynomial degree "
00564 "or relax rejection parameters!",
00565 absorder, x_guess);
00566 warning_shown = true;
00567 }
00568 x = x_guess;
00569 }
00570 else {
00571 assure( cpl_error_get_code() == CPL_ERROR_NONE,
00572 cpl_error_get_code(),
00573 "Could not invert dispersion relation");
00574 }
00575
00576
00577 x_guess = x;
00578 x_min = uves_polynomial_solve_1d(
00579 disprel_1d,
00580 (lambda - 0.5*wavestep) * absorder,
00581 x_guess,
00582 multiplicity);
00583
00584 if (cpl_error_get_code() == CPL_ERROR_DIVISION_BY_ZERO) {
00585 uves_error_reset();
00586 if (!warning_shown) {
00587 uves_msg_warning("Could not invert dispersion relation at "
00588 "order = %d, x = %f. This might be caused "
00589 "by fitting a too high degree polynomial to "
00590 "too few lines. Decrease dispersion "
00591 "polynomial degree "
00592 "or relax rejection parameters!",
00593 absorder, x_guess);
00594 warning_shown = true;
00595 }
00596 x_min = x_guess;
00597 }
00598 else {
00599 assure( cpl_error_get_code() == CPL_ERROR_NONE,
00600 cpl_error_get_code(),
00601 "Could not invert dispersion relation");
00602 }
00603
00604
00605 x_max = uves_polynomial_solve_1d(
00606 disprel_1d,
00607 (lambda + 0.5*wavestep) * absorder,
00608 x_guess,
00609 multiplicity);
00610
00611 if (cpl_error_get_code() == CPL_ERROR_DIVISION_BY_ZERO) {
00612 uves_error_reset();
00613 if (!warning_shown) {
00614 uves_msg_warning("Could not invert dispersion relation at "
00615 "order = %d, x = %f. This might be caused "
00616 "by fitting a too high degree polynomial to "
00617 "too few lines. Decrease dispersion "
00618 "polynomial degree "
00619 "or relax rejection parameters!",
00620 absorder, x_guess);
00621 warning_shown = true;
00622 }
00623 x_max = x_guess;
00624 }
00625 else {
00626 assure( cpl_error_get_code() == CPL_ERROR_NONE,
00627 cpl_error_get_code(),
00628 "Could not invert dispersion relation");
00629 }
00630
00631
00632 if (uves_max_double(0.5, uves_min_double(nx+0.5, x_min)) <
00633 uves_max_double(0.5, uves_min_double(nx+0.5, x_max)))
00634 {
00635
00636
00637
00638
00639
00640 bool pis_rejected;
00641 double flux_x = integrate_flux(
00642 spectrum_data_double,
00643 spectrum_data_float,
00644 spectrum_data_int,
00645 spectrum_bad,
00646 spectrum_row,
00647 nx,
00648 uves_max_double(0.5, uves_min_double(nx+0.5, x_min)),
00649 uves_max_double(0.5, uves_min_double(nx+0.5, x_max)),
00650 threshold_to_positive,
00651 &pis_rejected)
00652 / ( uves_max_double(0.5, uves_min_double(nx+0.5, x_max)) -
00653 uves_max_double(0.5, uves_min_double(nx+0.5, x_min)) );
00654
00655 if (!pis_rejected)
00656 {
00657
00658
00659 double dldx;
00660
00661
00662 if (scale)
00663 {
00664
00665
00666
00667 dldx = uves_polynomial_derivative_2d(
00668 dispersion_relation, x, absorder, 1)
00669 / absorder;
00670 }
00671 else
00672 {
00673 dldx = 1;
00674 }
00675
00676
00677
00678
00679 if (cpl_image_get_type(spectrum) == CPL_TYPE_DOUBLE) {
00680 rebinned_data_double[(bin-1) +
00681 (spectrum_row-1)*nlambda] =
00682 flux_x / fabs(dldx);
00683 }
00684 else if (cpl_image_get_type(spectrum) == CPL_TYPE_FLOAT) {
00685 rebinned_data_float[(bin-1) +
00686 (spectrum_row-1)*nlambda] =
00687 flux_x / fabs(dldx);
00688 } else {
00689 rebinned_data_int[(bin-1) +
00690 (spectrum_row-1)*nlambda] =
00691 flux_x / fabs(dldx);
00692
00693
00694 }
00695
00696
00697 rebinned_bad[(bin-1) +
00698 (spectrum_row-1)*nlambda] =
00699 CPL_BINARY_0;
00700 }
00701 else
00702 {
00703
00704
00705 }
00706
00707 }
00708 else
00709 {
00710
00711
00712 }
00713
00714
00715 }
00716 }
00717
00718 }
00719
00720
00721
00722 cleanup:
00723 uves_polynomial_delete(&disprel_1d);
00724 if (cpl_error_get_code() != CPL_ERROR_NONE)
00725 {
00726 uves_free_image(&rebinned);
00727 uves_free_propertylist(rebinned_header);
00728 }
00729
00730 return rebinned;
00731 }
00732
00733
00758
00759 inline static double
00760 integrate_flux(const double *spectrum_data_double,
00761 const float *spectrum_data_float,
00762 const int *spectrum_data_int,
00763 const cpl_binary *spectrum_bad,
00764 int spectrum_row,
00765 int nx,
00766 double x_min, double x_max,
00767 bool threshold_to_positive,
00768 bool *is_bad)
00769 {
00770 double sum = 0;
00771 double sum_interval = 0;
00772
00773 int x;
00774 int first_good = 0;
00775
00776 *is_bad = true;
00777
00778 for (x = uves_min_int(nx, uves_max_int(1, uves_round_double(x_min)));
00779
00780
00781 x <= uves_min_int(nx, uves_max_int(1, uves_round_double(x_max)));
00782 x++)
00783 {
00784
00785 if (spectrum_bad[(x-1) + (spectrum_row-1)*nx] == CPL_BINARY_0)
00786
00787 {
00788 double flux;
00789 double interval_length;
00790 double current_term;
00791
00792
00793
00794
00795
00796
00797
00798
00799
00800
00801
00802
00803
00804
00805
00806
00807
00808
00809
00810
00811 int x_prev = x-1;
00812 int x_next = x+1;
00813 bool pis_rejected_prev = (x_prev < 1 ) ||
00814 (spectrum_bad[(x_prev-1) + (spectrum_row-1)*nx] == CPL_BINARY_1);
00815 bool pis_rejected_next = (nx < x_next) ||
00816 (spectrum_bad[(x_next-1) + (spectrum_row-1)*nx] == CPL_BINARY_1);
00817
00818 if (spectrum_data_double != NULL) {
00819 flux = spectrum_data_double[(x-1) + (spectrum_row-1)*nx];
00820 }
00821 else if (spectrum_data_float != NULL) {
00822 flux = spectrum_data_float [(x-1) + (spectrum_row-1)*nx];
00823 } else {
00824 flux = spectrum_data_int [(x-1) + (spectrum_row-1)*nx];
00825 }
00826
00827 if (!pis_rejected_prev && !pis_rejected_next)
00828 {
00829
00830
00831
00832 double flux_minus, flux_plus;
00833 if (spectrum_data_double != NULL) {
00834 flux_minus =
00835 (flux + spectrum_data_double[(x_prev-1) + (spectrum_row-1)*nx])
00836 / 2.0;
00837 flux_plus =
00838 (flux + spectrum_data_double[(x_next-1) + (spectrum_row-1)*nx])
00839 / 2.0;
00840 }
00841 else if (spectrum_data_float != NULL) {
00842 flux_minus =
00843 (flux + spectrum_data_float[(x_prev-1) + (spectrum_row-1)*nx])
00844 / 2.0;
00845 flux_plus =
00846 (flux + spectrum_data_float[(x_next-1) + (spectrum_row-1)*nx])
00847 / 2.0;
00848 } else {
00849 flux_minus =
00850 (flux + spectrum_data_int[(x_prev-1) + (spectrum_row-1)*nx])
00851 / 2.0;
00852 flux_plus =
00853 (flux + spectrum_data_int[(x_next-1) + (spectrum_row-1)*nx])
00854 / 2.0;
00855 }
00856
00857
00858
00859
00860
00861
00862
00863
00864 {
00865 double flux_center = 2*flux - (flux_minus + flux_plus) / 2.0;
00866
00867
00868 double slope_minus = (flux_center - flux_minus )/ 0.5;
00869 double slope_plus = (flux_plus - flux_center) / 0.5;
00870
00871
00872
00873 double lo1 = uves_max_double(x-0.5, uves_min_double(x, x_min));
00874 double hi1 = uves_max_double(x-0.5, uves_min_double(x, x_max));
00875 double dy1 = hi1-lo1;
00876
00877
00878
00879 double lo2 = uves_max_double(x, uves_min_double(x+0.5, x_min));
00880 double hi2 = uves_max_double(x, uves_min_double(x+0.5, x_max));
00881 double dy2 = hi2-lo2;
00882
00883
00884
00885
00886
00887
00888
00889
00890 current_term =
00891 dy1 * (flux_center + slope_minus * ((lo1+hi1)/2.0 - x))
00892 +
00893 dy2 * (flux_center + slope_plus * ((lo2+hi2)/2.0 - x));
00894
00895 interval_length = dy1 + dy2;
00896 }
00897
00898 }
00899 else
00900 {
00901 interval_length =
00902 uves_min_double(x_max, x+0.5) -
00903 uves_max_double(x_min, x-0.5);
00904
00905 current_term = interval_length * flux;
00906 }
00907
00908 if (*is_bad) {
00909 first_good = x;
00910 }
00911 *is_bad = false;
00912
00913 sum += current_term;
00914 sum_interval += interval_length;
00915 }
00916 }
00917
00918 if (sum_interval == 0)
00919 {
00920 *is_bad = true;
00921 return -1;
00922 }
00923 else
00924 {
00925
00926
00927
00928 double result = sum*(x_max-x_min)/sum_interval;
00929
00930 if (threshold_to_positive) {
00931 if (result == 0) {
00932
00933 *is_bad = true;
00934 return -1;
00935 }
00936 else {
00937 result = fabs(result);
00938 }
00939 }
00940 return result;
00941 }
00942 }
00943