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 #ifdef HAVE_CONFIG_H
00141 # include <config.h>
00142 #endif
00143
00144
00151
00154
00155
00156
00157
00158 #include <uves_rebin.h>
00159
00160 #include <uves_parameters.h>
00161 #include <uves.h>
00162 #include <uves_pfits.h>
00163 #include <uves_dump.h>
00164 #include <uves_utils.h>
00165 #include <uves_utils_wrappers.h>
00166 #include <uves_wavecal_utils.h>
00167 #include <uves_error.h>
00168
00169 #include <irplib_access.h>
00170 #include <cpl.h>
00171
00172
00173
00174
00175 inline static double
00176 integrate_flux(const double *spectrum_data,
00177 const cpl_binary *spectrum_bad,
00178 int spectrum_row,
00179 int nx,
00180 double x_min, double x_max,
00181 bool threshold_to_positive,
00182 bool *is_bad);
00183
00184
00185
00186
00187
00188
00196
00197 cpl_parameterlist *
00198 uves_rebin_define_parameters(void)
00199 {
00200 const char *name = "";
00201 char *full_name = NULL;
00202 cpl_parameter *p = NULL;
00203 cpl_parameterlist *parameters = NULL;
00204
00205 parameters = cpl_parameterlist_new();
00206
00207 {
00208 name = "wavestep";
00209 full_name = uves_sprintf("%s.%s", UVES_REBIN_ID, name);
00210 uves_parameter_new_value(p, full_name,
00211 CPL_TYPE_DOUBLE,
00212 "The bin size (in w.l.u.) in wavelength space. "
00213 "If negative, a step size of "
00214 "2/3 * ( average pixel size ) is used.",
00215 UVES_REBIN_ID,
00216 -1.0);
00217 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, name);
00218 cpl_parameterlist_append(parameters, p);
00219 cpl_free(full_name);
00220
00221 name = "scale";
00222 full_name = uves_sprintf("%s.%s", UVES_REBIN_ID, name);
00223 uves_parameter_new_value(p, full_name,
00224 CPL_TYPE_BOOL,
00225 "Whether or not to multiply by the factor "
00226 "dx/dlambda (pixels per wavelength) "
00227 "during the rebinning. This option is disabled "
00228 "as default in concordance with the "
00229 "method used in the MIDAS pipeline. This "
00230 "option should be set to true "
00231 "to convert the observed flux (in pixel-space) "
00232 "to a flux per wavelength (in "
00233 "wavelength-space).",
00234 UVES_REBIN_ID,
00235 false);
00236 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, name);
00237 cpl_parameterlist_append(parameters, p);
00238 cpl_free(full_name);
00239 }
00240
00241 if (cpl_error_get_code() != CPL_ERROR_NONE)
00242 {
00243 cpl_msg_error(__func__, "Creation of rebinning parameters failed: '%s'",
00244 cpl_error_get_where());
00245 cpl_parameterlist_delete(parameters);
00246 return NULL;
00247 }
00248 else
00249 {
00250 return parameters;
00251 }
00252 }
00253
00254
00299
00300 cpl_image *
00301 uves_rebin(const cpl_image *spectrum,
00302 const cpl_parameterlist *parameters, const char *context,
00303 const cpl_table *linetable, const polynomial *dispersion_relation,
00304 int first_abs_order, int last_abs_order,
00305 int n_traces,
00306 bool threshold_to_positive,
00307 uves_propertylist **rebinned_header)
00308 {
00309 double wavestep;
00310 bool scale;
00311 cpl_image *rebinned = NULL;
00312 double *rebinned_data = NULL;
00313 cpl_mask *rebinned_badmap = NULL;
00314 cpl_binary *rebinned_bad = NULL;
00315
00316 const double *spectrum_data = NULL;
00317
00318 const cpl_mask *spectrum_badmap = NULL;
00319 const cpl_binary *spectrum_bad = NULL;
00320
00321 polynomial *disprel_1d = NULL;
00322
00323 int nx, ny, nlambda, norders;
00324 int order;
00325 bool warning_shown = false;
00326
00327 passure( spectrum != NULL, " ");
00328 passure( dispersion_relation != NULL, " ");
00329 passure( rebinned_header != NULL, " ");
00330
00331 assure( cpl_image_get_type(spectrum) == CPL_TYPE_DOUBLE, CPL_ERROR_TYPE_MISMATCH,
00332 "Spectrum must have type double. It is '%s'",
00333 uves_tostring_cpl_type(cpl_image_get_type(spectrum)));
00334
00335
00336 check( uves_get_parameter(parameters, context, UVES_REBIN_ID, "wavestep",
00337 CPL_TYPE_DOUBLE, &wavestep ),
00338 "Could not read parameter");
00339 check( uves_get_parameter(parameters, context, UVES_REBIN_ID, "scale" ,
00340 CPL_TYPE_BOOL, &scale ),
00341 "Could not read parameter");
00342
00343
00344 if (wavestep < 0)
00345 {
00346 double pixelsize;
00347 check( pixelsize = cpl_table_get_column_mean(linetable, LINETAB_PIXELSIZE),
00348 "Error reading mean pixelsize");
00349 uves_msg_debug("Average pixelsize = %f w.l.u.", pixelsize);
00350
00351 wavestep = pixelsize*2.0/3;
00352 }
00353
00354 assure( wavestep > 0 , CPL_ERROR_ILLEGAL_INPUT,
00355 "Illegal step size: %e wlu", wavestep);
00356 assure( n_traces >= 1, CPL_ERROR_ILLEGAL_INPUT,
00357 "Illegal number of traces: %d", n_traces);
00358
00359 nx = cpl_image_get_size_x(spectrum);
00360 ny = cpl_image_get_size_y(spectrum);
00361
00362 assure( ny % n_traces == 0, CPL_ERROR_INCOMPATIBLE_INPUT,
00363 "Spectrum image height (%d) is not a multiple of "
00364 "the number of traces (%d). Confused, bailing out",
00365 ny, n_traces);
00366
00367 norders = ny / n_traces;
00368
00369 spectrum_data = irplib_image_get_data_double_const(spectrum);
00370 spectrum_badmap = irplib_image_get_bpm_const(spectrum);
00371 spectrum_bad = irplib_mask_get_data_const(spectrum_badmap);
00372
00373 assure( norders >= 1, CPL_ERROR_ILLEGAL_INPUT, "Empty spectrum");
00374 assure( uves_round_double(fabs(first_abs_order - last_abs_order)) + 1 == norders,
00375 CPL_ERROR_INCOMPATIBLE_INPUT,
00376 "Spectrum contains %d orders, but line table absolute "
00377 "order numbering is %d - %d",
00378 norders, first_abs_order, last_abs_order);
00379
00380 check( *rebinned_header = uves_initialize_image_header(
00381 "Angstrom",
00382 (n_traces > 1) ? "PIXEL" : "ORDER",
00383 (scale) ? "FLUX PER WAVEL" : "FLUX",
00384 0.0, 1.0,
00385 1.0, 1.0,
00386 wavestep, 1.0),
00387 "Error setting up rebinned image header");
00388
00389
00390
00391
00392
00393
00394
00395 nlambda = -1;
00396 for (order = 1; order <= norders; order++)
00397 {
00398
00399
00400
00401
00402
00403
00404
00405 int absorder = uves_absolute_order(first_abs_order, last_abs_order, order);
00406 double lambda_min, lambda_max;
00407 int nbins;
00408
00409 int minx, maxx;
00410
00411 minx = 1;
00412
00413
00414
00415
00416 maxx = nx;
00417
00418 if ( minx > nx )
00419 {
00420 uves_msg_debug("Nothing extracted in order #%d", order);
00421 minx = maxx = nx/2;
00422 }
00423
00424 lambda_min = uves_polynomial_evaluate_2d(
00425 dispersion_relation, minx - 0.5, absorder)/absorder;
00426 lambda_max = uves_polynomial_evaluate_2d(
00427 dispersion_relation, maxx + 0.5, absorder)/absorder;
00428
00429 nbins =
00430 uves_round_double(lambda_max / wavestep) -
00431 uves_round_double(lambda_min / wavestep) + 1;
00432
00433 nlambda = uves_max_int(nlambda, nbins);
00434
00435 check( uves_pfits_set_wstart(
00436 *rebinned_header, order,
00437 wavestep * uves_round_double(lambda_min / wavestep)),
00438 "Error writing adding WSTART keyword to header");
00439
00440 check( uves_pfits_set_wend(
00441 *rebinned_header, order,
00442 wavestep * uves_round_double(lambda_max / wavestep)),
00443 "Error writing adding WEND keyword to header");
00444
00445 uves_msg_debug("Rebinning abs. order #%d. "
00446 "Range = %d - %d pix = %f - %f wlu, %d bins",
00447 absorder,
00448 minx, maxx,
00449 lambda_min,
00450 lambda_max,
00451 nbins);
00452 }
00453
00454 uves_msg_debug("Step size = %f wlu (%d orders x %d bins)", wavestep, norders, nlambda);
00455
00456
00457
00458
00459 check(( rebinned = cpl_image_new(nlambda, norders*n_traces, CPL_TYPE_DOUBLE),
00460 rebinned_data = irplib_image_get_data_double(rebinned),
00461 rebinned_badmap = irplib_image_get_bpm(rebinned),
00462 rebinned_bad = irplib_mask_get_data(rebinned_badmap)),
00463 "Error allocating rebinned spectrum");
00464
00465
00466
00467 uves_image_reject_all(rebinned);
00468
00469 for (order = 1; order <= norders; order++)
00470 {
00471 int absorder = uves_absolute_order(first_abs_order, last_abs_order, order);
00472 double lambda_start;
00473 int trace;
00474
00475
00476
00477 check( lambda_start = uves_pfits_get_wstart(*rebinned_header, order),
00478 "Error reading product header");
00479
00480
00481 uves_polynomial_delete(&disprel_1d);
00482 check( disprel_1d = uves_polynomial_collapse(dispersion_relation,
00483 2,
00484 absorder),
00485 "Error getting 1d dispersion relation for absolute order #%d", absorder);
00486
00487
00488 for (trace = 1; trace <= n_traces; trace++)
00489 {
00490 int spectrum_row = (order - 1)*n_traces + trace;
00491 int bin;
00492
00493 double x = 1;
00494 double x_min = 1;
00495 double x_max = 1;
00496
00497 for (bin = 1; bin <= nlambda && x_min <= nx+0.5; bin++)
00498 {
00499 double lambda = lambda_start + (bin-1) * wavestep;
00500
00501 int multiplicity = 1;
00502 double x_guess = x;
00503
00504 x = uves_polynomial_solve_1d(disprel_1d,
00505 lambda * absorder,
00506 x_guess,
00507 multiplicity);
00508
00509 if (cpl_error_get_code() == CPL_ERROR_DIVISION_BY_ZERO) {
00510 uves_error_reset();
00511 if (!warning_shown) {
00512 uves_msg_warning("Could not invert dispersion relation at "
00513 "order = %d, x = %f. This might be caused "
00514 "by fitting a too high degree polynomial to "
00515 "too few lines. Decrease dispersion "
00516 "polynomial degree "
00517 "or relax rejection parameters!",
00518 absorder, x_guess);
00519 warning_shown = true;
00520 }
00521 x = x_guess;
00522 }
00523 else {
00524 assure( cpl_error_get_code() == CPL_ERROR_NONE,
00525 cpl_error_get_code(),
00526 "Could not invert dispersion relation");
00527 }
00528
00529 x_guess = x;
00530 x_min = uves_polynomial_solve_1d(
00531 disprel_1d,
00532 (lambda - 0.5*wavestep) * absorder,
00533 x_guess,
00534 multiplicity);
00535
00536 if (cpl_error_get_code() == CPL_ERROR_DIVISION_BY_ZERO) {
00537 uves_error_reset();
00538 if (!warning_shown) {
00539 uves_msg_warning("Could not invert dispersion relation at "
00540 "order = %d, x = %f. This might be caused "
00541 "by fitting a too high degree polynomial to "
00542 "too few lines. Decrease dispersion "
00543 "polynomial degree "
00544 "or relax rejection parameters!",
00545 absorder, x_guess);
00546 warning_shown = true;
00547 }
00548 x_min = x_guess;
00549 }
00550 else {
00551 assure( cpl_error_get_code() == CPL_ERROR_NONE,
00552 cpl_error_get_code(),
00553 "Could not invert dispersion relation");
00554 }
00555
00556 x_max = uves_polynomial_solve_1d(
00557 disprel_1d,
00558 (lambda + 0.5*wavestep) * absorder,
00559 x_guess,
00560 multiplicity);
00561
00562 if (cpl_error_get_code() == CPL_ERROR_DIVISION_BY_ZERO) {
00563 uves_error_reset();
00564 if (!warning_shown) {
00565 uves_msg_warning("Could not invert dispersion relation at "
00566 "order = %d, x = %f. This might be caused "
00567 "by fitting a too high degree polynomial to "
00568 "too few lines. Decrease dispersion "
00569 "polynomial degree "
00570 "or relax rejection parameters!",
00571 absorder, x_guess);
00572 warning_shown = true;
00573 }
00574 x_max = x_guess;
00575 }
00576 else {
00577 assure( cpl_error_get_code() == CPL_ERROR_NONE,
00578 cpl_error_get_code(),
00579 "Could not invert dispersion relation");
00580 }
00581
00582
00583 if (uves_max_double(0.5, uves_min_double(nx+0.5, x_min)) <
00584 uves_max_double(0.5, uves_min_double(nx+0.5, x_max)))
00585 {
00586
00587
00588
00589
00590
00591 bool pis_rejected;
00592 double flux_x = integrate_flux(
00593 spectrum_data,
00594 spectrum_bad,
00595 spectrum_row,
00596 nx,
00597 uves_max_double(0.5, uves_min_double(nx+0.5, x_min)),
00598 uves_max_double(0.5, uves_min_double(nx+0.5, x_max)),
00599 threshold_to_positive,
00600 &pis_rejected)
00601 / ( uves_max_double(0.5, uves_min_double(nx+0.5, x_max)) -
00602 uves_max_double(0.5, uves_min_double(nx+0.5, x_min)) );
00603
00604 if (!pis_rejected)
00605 {
00606
00607
00608 double dldx;
00609
00610 if (scale)
00611 {
00612
00613
00614
00615 dldx = uves_polynomial_derivative_2d(
00616 dispersion_relation, x, absorder, 1)
00617 / absorder;
00618 }
00619 else
00620 {
00621 dldx = 1;
00622 }
00623
00624
00625
00626 rebinned_data[(bin-1) +
00627 (spectrum_row-1)*nlambda] =
00628 flux_x / fabs(dldx);
00629
00630 rebinned_bad[(bin-1) +
00631 (spectrum_row-1)*nlambda] =
00632 CPL_BINARY_0;
00633 }
00634 else
00635 {
00636
00637
00638 }
00639 }
00640 else
00641 {
00642
00643
00644 }
00645
00646 }
00647 }
00648 }
00649
00650
00651 cleanup:
00652 uves_polynomial_delete(&disprel_1d);
00653 if (cpl_error_get_code() != CPL_ERROR_NONE)
00654 {
00655 uves_free_image(&rebinned);
00656 uves_free_propertylist(rebinned_header);
00657 }
00658
00659 return rebinned;
00660 }
00661
00662
00682
00683 inline static double
00684 integrate_flux(const double *spectrum_data,
00685 const cpl_binary *spectrum_bad,
00686 int spectrum_row,
00687 int nx,
00688 double x_min, double x_max,
00689 bool threshold_to_positive,
00690 bool *is_bad)
00691 {
00692 double sum = 0;
00693 double sum_interval = 0;
00694
00695 int x;
00696 int first_good = 0;
00697
00698 *is_bad = true;
00699
00700 for (x = uves_min_int(nx, uves_max_int(1, uves_round_double(x_min)));
00701
00702
00703 x <= uves_min_int(nx, uves_max_int(1, uves_round_double(x_max)));
00704 x++)
00705 {
00706 if (spectrum_bad[(x-1) + (spectrum_row-1)*nx] == CPL_BINARY_0)
00707
00708 {
00709
00710 double flux = spectrum_data[(x-1) + (spectrum_row-1)*nx];
00711 double interval_length;
00712 double current_term;
00713
00714
00715
00716
00717
00718
00719
00720
00721
00722
00723
00724
00725
00726
00727
00728
00729
00730
00731
00732
00733 int x_prev = x-1;
00734 int x_next = x+1;
00735 bool pis_rejected_prev = (x_prev < 1 ) ||
00736 (spectrum_bad[(x_prev-1) + (spectrum_row-1)*nx] == CPL_BINARY_1);
00737 bool pis_rejected_next = (nx < x_next) ||
00738 (spectrum_bad[(x_next-1) + (spectrum_row-1)*nx] == CPL_BINARY_1);
00739
00740 if (!pis_rejected_prev && !pis_rejected_next)
00741 {
00742
00743
00744 double flux_minus =
00745 (flux + spectrum_data[(x_prev-1) + (spectrum_row-1)*nx]) / 2.0;
00746 double flux_plus =
00747 (flux + spectrum_data[(x_next-1) + (spectrum_row-1)*nx]) / 2.0;
00748
00749
00750
00751
00752
00753
00754
00755
00756 double flux_center = 2*flux - (flux_minus + flux_plus) / 2.0;
00757
00758
00759 double slope_minus = (flux_center - flux_minus )/ 0.5;
00760 double slope_plus = (flux_plus - flux_center) / 0.5;
00761
00762
00763
00764 double lo1 = uves_max_double(x-0.5, uves_min_double(x, x_min));
00765 double hi1 = uves_max_double(x-0.5, uves_min_double(x, x_max));
00766 double dy1 = hi1-lo1;
00767
00768
00769
00770 double lo2 = uves_max_double(x, uves_min_double(x+0.5, x_min));
00771 double hi2 = uves_max_double(x, uves_min_double(x+0.5, x_max));
00772 double dy2 = hi2-lo2;
00773
00774
00775
00776
00777
00778
00779 current_term =
00780 dy1 * (flux_center + slope_minus * ((lo1+hi1)/2.0 - x))
00781 +
00782 dy2 * (flux_center + slope_plus * ((lo2+hi2)/2.0 - x));
00783
00784 interval_length = dy1 + dy2;
00785
00786
00787 }
00788 else
00789 {
00790 interval_length =
00791 uves_min_double(x_max, x+0.5) -
00792 uves_max_double(x_min, x-0.5);
00793
00794 current_term = interval_length * flux;
00795 }
00796
00797 if (*is_bad) {
00798 first_good = x;
00799 }
00800 *is_bad = false;
00801
00802 sum += current_term;
00803 sum_interval += interval_length;
00804 }
00805 }
00806
00807 if (sum_interval == 0)
00808 {
00809 *is_bad = true;
00810 return -1;
00811 }
00812 else
00813 {
00814
00815
00816
00817 double result = sum*(x_max-x_min)/sum_interval;
00818
00819 if (threshold_to_positive) {
00820 if (result == 0) {
00821
00822 *is_bad = true;
00823 return -1;
00824 }
00825 else {
00826 result = fabs(result);
00827 }
00828 }
00829
00830 return result;
00831 }
00832 }
00833