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 #ifdef HAVE_CONFIG_H
00029 #include <config.h>
00030 #endif
00031
00032
00033
00034
00035
00036 #include "irplib_wavecal.h"
00037
00038 #include "visir_spectro.h"
00039
00040 #include "visir_utils.h"
00041 #include "visir_pfits.h"
00042 #include "visir_inputs.h"
00043 #include "visir_parameter.h"
00044 #include "visir_spc_distortion.h"
00045
00046 #include "irplib_framelist.h"
00047
00048 #include <cpl.h>
00049
00050 #include <string.h>
00051 #include <math.h>
00052 #include <float.h>
00053 #include <assert.h>
00054
00055
00061
00062
00063
00064
00065
00066
00067 typedef struct {
00068 cpl_size cost;
00069 cpl_size xcost;
00070 cpl_size ulines;
00071
00072 double temp;
00073 const cpl_vector * vsymm;
00074
00075
00076
00077 const cpl_bivector * lines;
00078
00079 const cpl_bivector * tqeff;
00080
00081 } visir_spectrum_model;
00082
00083
00084
00085
00086
00087
00088 static cpl_error_code
00089 visir_polynomial_shift_1d_from_correlation(cpl_polynomial *,
00090 const cpl_vector *,
00091 irplib_base_spectrum_model *,
00092 cpl_error_code (*)
00093 (cpl_vector *,
00094 const cpl_polynomial *,
00095 irplib_base_spectrum_model *),
00096 int, int, cpl_boolean,
00097 double *, double *);
00098
00099 static cpl_error_code visir_spectro_refine(cpl_polynomial *,
00100 const cpl_vector *,
00101 visir_spectrum_model *,
00102 const cpl_polynomial *,
00103 int, cpl_boolean, visir_spc_resol,
00104 double *, cpl_boolean *, double *);
00105
00106 static cpl_error_code visir_spectro_fill(cpl_vector *, const cpl_polynomial *,
00107 irplib_base_spectrum_model *);
00108
00109 static cpl_bivector * visir_spc_extract(cpl_image *, cpl_propertylist *,
00110 cpl_image **, int, int);
00111
00112 static cpl_error_code visir_spc_emission(cpl_bivector *, const cpl_vector *,
00113 const cpl_bivector *,
00114 const cpl_bivector *,
00115 const cpl_vector *, double);
00116
00117 static cpl_polynomial * visir_spc_phys_disp(int, double, visir_spc_resol, int,
00118 int);
00119 static cpl_polynomial * visir_spc_phys_lrp(void);
00120 static double visir_spc_get_dispersion(const cpl_polynomial *, double);
00121 static cpl_error_code visir_vector_convolve_symm(cpl_vector *,
00122 const cpl_vector *);
00123 static cpl_vector * cpl_spc_convolve_init(int, double, double, int);
00124
00125 static cpl_error_code visir_spectro_qclist_wcal(cpl_propertylist *,
00126 int, double,
00127 cpl_boolean, double,
00128 const cpl_polynomial *,
00129 const cpl_polynomial *);
00130
00131 static cpl_error_code visir_spectro_qclist_obs(cpl_propertylist *,
00132 double, double);
00133
00134 static const double N_upper = 13.4e-6;
00135 static const double whechelle = 35.8/2;
00136
00137 #ifndef VISIR_XC_LEN
00138 #define VISIR_XC_LEN 50
00139 #endif
00140 #ifndef VISIR_XC_SUBSEARCH
00141 #define VISIR_XC_SUBSEARCH 100
00142 #endif
00143
00144 #ifndef VISIR_SPECTRO_SIGMA
00145 #define VISIR_SPECTRO_SIGMA 3.0
00146 #endif
00147
00150
00151
00152
00153
00154
00155 cpl_error_code
00156 visir_spc_extract_order(cpl_image ** order,
00157 cpl_image ** comorder,
00158 const cpl_image * combined,
00159 const cpl_image * imhcycle,
00160 const double wlen,
00161 const visir_spc_config * pconfig,
00162 const cpl_boolean do_ech,
00163 int is_aqu)
00164 {
00165 int icol1, icol2;
00166 int jcol1, jcol2;
00167
00168 jcol1 = visir_parameterlist_get_int(pconfig->parlist, pconfig->recipename,
00169 VISIR_PARAM_REJLEFT);
00170 jcol2 = visir_parameterlist_get_int(pconfig->parlist, pconfig->recipename,
00171 VISIR_PARAM_REJRIGHT);
00172
00173
00174 if (do_ech) {
00175 skip_if (visir_spc_echelle_limit(&icol1, &icol2, wlen,
00176 pconfig->orderoffset,
00177 1, cpl_image_get_size_y(combined),
00178 is_aqu));
00179 } else {
00180 icol1 = 1;
00181 icol2 = cpl_image_get_size_x(imhcycle);
00182 }
00183
00184 if (do_ech) {
00185 if (jcol1 != 0) {
00186 cpl_msg_info(cpl_func, "Ignoring %d leftmost columns from %d to %d",
00187 jcol1, icol1, icol1 + jcol1);
00188 icol1 += jcol1;
00189 }
00190 if (jcol2 != 0) {
00191 cpl_msg_info(cpl_func, "Ignoring %d rightmost columns from %d to %d",
00192 jcol2, icol2 - jcol2, icol2);
00193 icol2 -= jcol2;
00194 }
00195 } else {
00196 if (jcol1 != 0) {
00197 cpl_msg_info(cpl_func, "Ignoring %d leftmost columns", jcol1);
00198 icol1 += jcol1;
00199 }
00200 if (jcol2 != 0) {
00201 cpl_msg_info(cpl_func, "Ignoring %d rightmost columns", jcol2);
00202 icol2 -= jcol2;
00203 }
00204 }
00205
00206 if (icol1 != 1 || icol2 != cpl_image_get_size_x(imhcycle)) {
00207 *order = visir_spc_column_extract(imhcycle, icol1, icol2,
00208 pconfig->plot);
00209 skip_if (0);
00210
00211 *comorder = visir_spc_column_extract(combined, icol1, icol2,
00212 pconfig->plot);
00213 skip_if (0);
00214
00215 } else {
00216 *order = cpl_image_duplicate(imhcycle);
00217 *comorder = cpl_image_duplicate(combined);
00218 }
00219
00220 end_skip;
00221
00222 return cpl_error_get_code();
00223 }
00224
00225
00241
00242 visir_spc_resol visir_spc_get_res_wl(const irplib_framelist * rawframes,
00243 double * pwlen, double * pslitw,
00244 double * ptemp, double * pfwhm,
00245 int is_aqu)
00246 {
00247 cpl_errorstate cleanstate = cpl_errorstate_get();
00248
00249 visir_spc_resol resol = VISIR_SPC_R_ERR;
00250 char ptmp[IRPLIB_FITS_STRLEN+1];
00251 double wl, spx, pfov = 0.127;
00252 double sl = 0.0;
00253 cpl_boolean need_temp = ptemp != NULL;
00254 int n;
00255
00256
00257 cpl_ensure(rawframes != NULL, CPL_ERROR_NULL_INPUT, VISIR_SPC_R_ERR);
00258 cpl_ensure(pwlen != NULL, CPL_ERROR_NULL_INPUT, VISIR_SPC_R_ERR);
00259 cpl_ensure(pslitw != NULL, CPL_ERROR_NULL_INPUT, VISIR_SPC_R_ERR);
00260 cpl_ensure(pfwhm != NULL, CPL_ERROR_NULL_INPUT, VISIR_SPC_R_ERR);
00261
00262 n = irplib_framelist_get_size(rawframes);
00263
00264 cpl_ensure(n > 0, CPL_ERROR_DATA_NOT_FOUND, VISIR_SPC_R_ERR);
00265
00266
00267 skip_if(irplib_framelist_contains(rawframes, VISIR_PFITS_DOUBLE_PIXSPACE,
00268 CPL_TYPE_DOUBLE, CPL_TRUE, 1e-6));
00269
00270
00271 skip_if(irplib_framelist_contains(rawframes, VISIR_PFITS_DOUBLE_SLITWIDTH,
00272 CPL_TYPE_DOUBLE, CPL_FALSE, 0.0));
00273
00274 skip_if(irplib_framelist_contains(rawframes, VISIR_PFITS_STRING_RESOL,
00275 CPL_TYPE_STRING, CPL_TRUE, 0.0));
00276
00277 skip_if(irplib_framelist_contains(rawframes, VISIR_PFITS_STRING_SLITNAME,
00278 CPL_TYPE_STRING, CPL_TRUE, 0.0));
00279
00280 for (int i = 0; i < n; i++) {
00281 const cpl_propertylist * plist;
00282 const char * filename =
00283 cpl_frame_get_filename(irplib_framelist_get_const(rawframes, i));
00284 const char * pfits;
00285 double wl_tmp, sl_tmp, spx_tmp, pfov_tmp;
00286
00287
00288 cpl_ensure(!cpl_error_get_code(), CPL_ERROR_DATA_NOT_FOUND,
00289 VISIR_SPC_R_ERR);
00290
00291 cpl_ensure(filename != NULL, CPL_ERROR_DATA_NOT_FOUND,
00292 VISIR_SPC_R_ERR);
00293
00294 plist = irplib_framelist_get_propertylist_const(rawframes, i);
00295
00296 cpl_ensure(plist != NULL, CPL_ERROR_DATA_NOT_FOUND, VISIR_SPC_R_ERR);
00297
00298 wl_tmp = visir_pfits_get_wlen(plist);
00299 if (wl_tmp <= 0.0 || !cpl_errorstate_is_equal(cleanstate)) {
00300 irplib_error_recover(cleanstate, "Missing or invalid FITS card");
00301 wl_tmp = VISIR_SPC_LRP_CWLEN;
00302 }
00303 pfits = visir_pfits_get_resol(plist);
00304 if (pfits == NULL || !cpl_errorstate_is_equal(cleanstate)) {
00305 irplib_error_recover(cleanstate, "Missing or invalid FITS card");
00306 pfits = VISIR_SPC_LRP_NAME;
00307 }
00308 sl_tmp = visir_pfits_get_slitwidth(plist);
00309 spx_tmp = visir_pfits_get_pixspace(plist);
00310
00311
00312 {
00313 pfov_tmp = visir_pfits_get_pixscale(plist);
00314 if (pfov_tmp <= 0.) {
00315 cpl_errorstate_set(cleanstate);
00316 cpl_msg_warning(cpl_func, VISIR_PFITS_STRING_PIXSCALE
00317 " not set, falling back to 0.127");
00318 pfov_tmp = 0.127;
00319 }
00320 }
00321
00322 cpl_ensure(!cpl_error_get_code(), CPL_ERROR_DATA_NOT_FOUND,
00323 VISIR_SPC_R_ERR);
00324
00325 if (i == 0) {
00326
00327 visir_optmod ins_settings;
00328
00329 sl = sl_tmp;
00330 spx = spx_tmp;
00331 wl = wl_tmp;
00332 pfov = pfov_tmp;
00333
00334
00335
00336 *pslitw = sl / pfov;
00337
00338 *pwlen = wl * 1e-6;
00339
00340 strncpy(ptmp, pfits, IRPLIB_FITS_STRLEN);
00341 ptmp[IRPLIB_FITS_STRLEN] = '\0';
00342
00343 cpl_msg_info(cpl_func, "RESOL [" VISIR_SPC_LRP_NAME "|LR|MR|HRS|HRG]"
00344 " and WLEN [m] (%d frames): %s %g", n, ptmp, *pwlen);
00345
00346 if (spx <= 0) {
00347 cpl_msg_error(cpl_func,"Pixel Spacing (%g) in %s is non-"
00348 "positive", spx, filename);
00349 cpl_ensure(0, CPL_ERROR_ILLEGAL_INPUT, VISIR_SPC_R_ERR);
00350 }
00351
00352 if (*pslitw <= 0) {
00353 cpl_msg_error(cpl_func,"Slit Width (%g) in %s is non-positive",
00354 sl, filename);
00355 cpl_ensure(0, CPL_ERROR_ILLEGAL_INPUT, VISIR_SPC_R_ERR);
00356 }
00357
00358 cpl_msg_info(cpl_func, "Slit Width [pixel] and Pixel Spacing [m]: "
00359 "%g %g", *pslitw, spx);
00360
00361 if (!strcmp(VISIR_SPC_LRP_NAME, ptmp)) {
00362 resol = VISIR_SPC_R_LRP;
00363 } else if (!strcmp("LR", ptmp)) {
00364 resol = VISIR_SPC_R_LR;
00365 } else if (!strcmp("MR", ptmp)) {
00366 resol = VISIR_SPC_R_MR;
00367 } else if (!strcmp("HRS", ptmp)) {
00368 resol = VISIR_SPC_R_HR;
00369 } else if (!strcmp("HRG", ptmp)) {
00370 resol = VISIR_SPC_R_GHR;
00371 } else {
00372 cpl_msg_error(cpl_func,"Unsupported resolution (%s) in %s",
00373 ptmp, filename);
00374 cpl_ensure(0, CPL_ERROR_UNSUPPORTED_MODE, VISIR_SPC_R_ERR);
00375 }
00376
00377 if (resol != VISIR_SPC_R_LRP) {
00378
00379 skip_if(irplib_framelist_contains(rawframes,
00380 VISIR_PFITS_DOUBLE_WLEN,
00381 CPL_TYPE_DOUBLE, CPL_TRUE,
00382 1e-3));
00383 }
00384
00385 if (visir_spc_optmod_init(resol, *pwlen, &ins_settings, is_aqu)) {
00386 cpl_msg_error(cpl_func, "Resolution %s does not support "
00387 "Central Wavelength [m]: %g", ptmp, *pwlen);
00388 cpl_ensure(0, CPL_ERROR_INCOMPATIBLE_INPUT, VISIR_SPC_R_ERR);
00389 }
00390
00391 cpl_msg_info(cpl_func, "The %s-Spectral Resolution at %gm: %g",
00392 ptmp, *pwlen,
00393 visir_spc_optmod_resolution(&ins_settings));
00394 cpl_msg_info(cpl_func, "The %s-Linear Dispersion at %gm [pixel/m]: "
00395 "%g", ptmp, *pwlen,
00396 visir_spc_optmod_dispersion(&ins_settings));
00397
00398 *pfwhm = *pwlen * visir_spc_optmod_dispersion(&ins_settings)
00399 / visir_spc_optmod_resolution(&ins_settings);
00400
00401 cpl_msg_info(cpl_func, "The %s-FWHM at %gm [pixel]: %g",
00402 ptmp, *pwlen, *pfwhm);
00403 } else {
00404 if (fabs(sl-sl_tmp) > 1e-3) {
00405 cpl_msg_error(cpl_func, "Inconsistent slit width (%g <=>"
00406 " %g) in %s (%d of %d)",
00407 sl, sl_tmp, filename, i+1, n);
00408 cpl_ensure(0, CPL_ERROR_INCOMPATIBLE_INPUT, VISIR_SPC_R_ERR);
00409 }
00410 if (fabs(pfov-pfov_tmp) > 1e-4) {
00411 cpl_msg_error(cpl_func, "Inconsistent pfov (%g <=>"
00412 " %g) in %s (%d of %d)",
00413 pfov, pfov_tmp, filename, i+1, n);
00414 cpl_ensure(0, CPL_ERROR_INCOMPATIBLE_INPUT, VISIR_SPC_R_ERR);
00415 }
00416 }
00417 if (need_temp) {
00418
00419 const double temp = visir_pfits_get_temp(plist);
00420 if (cpl_error_get_code()) {
00421 visir_error_reset("Could not get FITS key");
00422 } else if ((-20 < temp) && (temp < 60)) {
00423
00424 need_temp = CPL_FALSE;
00425 *ptemp = temp;
00426 }
00427 }
00428
00429 }
00430
00431 if (need_temp) {
00432 cpl_msg_warning(cpl_func, "No FITS-files specify the M1 temperature, "
00433 "using default");
00434 *ptemp = 10;
00435 }
00436
00437
00438 if (ptemp != NULL) {
00439 *ptemp += 273.15;
00440 cpl_msg_info(cpl_func, "The M1 temperature [Kelvin]: %g", *ptemp);
00441 }
00442
00443 end_skip;
00444
00445 return resol;
00446
00447 }
00448
00449
00470
00471 cpl_error_code visir_vector_resample(cpl_vector * self,
00472 const cpl_vector * xbounds,
00473 const cpl_bivector * source)
00474 {
00475
00476 const cpl_vector * xsource = cpl_bivector_get_x_const(source);
00477 const cpl_vector * ysource = cpl_bivector_get_y_const(source);
00478
00479 const double * pxsource = cpl_vector_get_data_const(xsource);
00480 const double * pysource = cpl_vector_get_data_const(ysource);
00481 const double * pxbounds = cpl_vector_get_data_const(xbounds);
00482
00483
00484 cpl_vector * ybounds = cpl_vector_new(cpl_vector_get_size(xbounds));
00485 IRPLIB_DIAG_PRAGMA_PUSH_IGN(-Wcast-qual)
00486 cpl_bivector * boundary = cpl_bivector_wrap_vectors((cpl_vector*)xbounds,
00487 ybounds);
00488 IRPLIB_DIAG_PRAGMA_POP
00489 double * pybounds = cpl_vector_get_data(ybounds);
00490
00491 double * pself = cpl_vector_get_data(self);
00492 const int npix = cpl_vector_get_size(self);
00493 int i;
00494 int itt;
00495
00496
00497 cpl_ensure_code(cpl_bivector_get_size(boundary) == npix + 1,
00498 CPL_ERROR_ILLEGAL_INPUT);
00499
00500 skip_if (0);
00501
00502 itt = cpl_vector_find(xsource, pxbounds[0]);
00503
00504 skip_if (0);
00505
00506 skip_if (cpl_bivector_interpolate_linear(boundary, source));
00507
00508
00509
00510 while (pxsource[itt] < pxbounds[0]) itt++;
00511
00512 for (i=0; i < npix; i++) {
00513
00514
00515
00516
00517 double xlow = pxbounds[i];
00518 double x = pxsource[itt];
00519
00520 if (x > pxbounds[i+1]) x = pxbounds[i+1];
00521
00522 pself[i] = pybounds[i] * (x - xlow);
00523
00524
00525 while (pxsource[itt] < pxbounds[i+1]) {
00526 const double xprev = x;
00527 x = pxsource[itt+1];
00528 if (x > pxbounds[i+1]) x = pxbounds[i+1];
00529 pself[i] += pysource[itt] * (x - xlow);
00530 xlow = xprev;
00531 itt++;
00532 }
00533
00534
00535 pself[i] += pybounds[i+1] * (pxbounds[i+1] - xlow);
00536
00537
00538
00539 pself[i] /= 2 * (pxbounds[i+1] - pxbounds[i]);
00540
00541 }
00542
00543
00544 end_skip;
00545
00546 cpl_vector_delete(ybounds);
00547 cpl_bivector_unwrap_vectors(boundary);
00548
00549 return cpl_error_get_code();
00550 }
00551
00552
00553
00554
00578
00579 cpl_error_code visir_spc_extract_wcal(const cpl_image * combined,
00580 const cpl_image * hcycle,
00581 double wlen, double slitw,
00582 double temp, double fwhm,
00583 visir_spc_resol resol,
00584 int ioffset,
00585 const char * spc_cal_lines,
00586 const char * spc_cal_qeff,
00587 cpl_table ** pspc_table,
00588 cpl_image ** pweight2d,
00589 cpl_propertylist * qclist,
00590 int doplot, int bkgcorrect,
00591 int is_aqu)
00592 {
00593
00594
00595 cpl_bivector * spc_n_err = NULL;
00596 cpl_image * flipped = NULL;
00597 const int npix = cpl_image_get_size_y(combined);
00598
00599
00600 cpl_ensure_code(pweight2d != NULL, CPL_ERROR_NULL_INPUT);
00601
00602 *pweight2d = NULL;
00603
00604 cpl_ensure_code(npix > 0, CPL_ERROR_ILLEGAL_INPUT);
00605 error_if(npix != cpl_image_get_size_y(hcycle), CPL_ERROR_ILLEGAL_INPUT,
00606 "Sky frame does not have same size as the object frame."
00607 " %d vs %d pixels", (int)cpl_image_get_size_y(hcycle), npix);
00608
00609
00610 skip_if (0);
00611
00612 skip_if (visir_spc_wavecal(hcycle, qclist, wlen, slitw, temp, fwhm, resol,
00613 ioffset, spc_cal_lines, spc_cal_qeff,
00614 pspc_table, doplot, is_aqu));
00615
00616
00617 flipped = cpl_image_cast(combined, CPL_TYPE_DOUBLE);
00618 skip_if (0);
00619
00620
00621
00622 spc_n_err = visir_spc_extract(flipped, qclist, pweight2d,
00623 doplot, bkgcorrect);
00624 skip_if (0);
00625
00626 cpl_image_delete(flipped);
00627 flipped = NULL;
00628
00629 skip_if (*pspc_table == NULL);
00630
00631 skip_if (cpl_table_new_column(*pspc_table, "SPC_EXTRACTED", CPL_TYPE_DOUBLE));
00632 skip_if (cpl_table_new_column(*pspc_table, "SPC_ERROR", CPL_TYPE_DOUBLE));
00633
00634 skip_if (cpl_table_set_column_unit(*pspc_table, "SPC_EXTRACTED", "ADU/s"));
00635 skip_if (cpl_table_set_column_unit(*pspc_table, "SPC_ERROR", "ADU/s"));
00636
00637 skip_if (cpl_table_copy_data_double(*pspc_table, "SPC_EXTRACTED",
00638 cpl_bivector_get_x_data(spc_n_err)));
00639 skip_if (cpl_table_copy_data_double(*pspc_table, "SPC_ERROR",
00640 cpl_bivector_get_y_data(spc_n_err)));
00641
00642 if (doplot) {
00643 visir_table_plot("set grid;set xlabel 'Wavelength [m]';",
00644 "t 'Extracted Spectrum' w linespoints",
00645 "", *pspc_table, "WLEN", "SPC_EXTRACTED");
00646 visir_table_plot("set grid;set xlabel 'Wavelength [m]';",
00647 "t 'Error on Extracted Spectrum' w linespoints",
00648 "", *pspc_table, "WLEN", "SPC_ERROR");
00649 }
00650
00651 end_skip;
00652
00653 cpl_image_delete(flipped);
00654 cpl_bivector_delete(spc_n_err);
00655
00656 return cpl_error_get_code();
00657 }
00658
00659
00660
00686
00687 cpl_error_code visir_spc_wavecal(const cpl_image * hcycle,
00688 cpl_propertylist * qclist,
00689 double wlen, double slitw,
00690 double temp, double fwhm,
00691 visir_spc_resol resol,
00692 int ioffset,
00693 const char * linefile,
00694 const char * qefffile,
00695 cpl_table ** pspc_table, int doplot,
00696 int is_aqu)
00697 {
00698
00699
00700 cpl_polynomial * phdisp = NULL;
00701
00702 cpl_polynomial * xcdisp = NULL;
00703
00704 visir_spectrum_model mymodel;
00705 cpl_vector * wlvals = NULL;
00706 cpl_vector * spmodel = NULL;
00707
00708 cpl_bivector * emission = NULL;
00709 cpl_vector * boundary = NULL;
00710
00711 cpl_bivector * temiss = NULL;
00712 cpl_bivector * tqeff = NULL;
00713
00714 cpl_image * corrected = NULL;
00715
00716 cpl_image * xc_image = NULL;
00717 cpl_vector * xc_vector = NULL;
00718
00719 cpl_vector * vsymm = NULL;
00720 cpl_vector * vxc = NULL;
00721
00722 const int npix = cpl_image_get_size_y(hcycle);
00723 #if 0
00724 double xc0;
00725 #endif
00726 double qcxc = -1.0, qcsubdelta = 0.;
00727 double hc_min;
00728 const cpl_size i0 = 0;
00729 const cpl_size i1 = 1;
00730 cpl_boolean didshift = CPL_FALSE;
00731
00732
00733 cpl_ensure_code(!cpl_error_get_code(), cpl_error_get_code());
00734 cpl_ensure_code(pspc_table, CPL_ERROR_NULL_INPUT);
00735 cpl_ensure_code(npix > 0, CPL_ERROR_ILLEGAL_INPUT);
00736
00737
00738
00739 corrected = cpl_image_cast(hcycle, CPL_TYPE_DOUBLE);
00740 skip_if (0);
00741
00742 hc_min = cpl_image_get_min(corrected);
00743 skip_if (0);
00744 cpl_msg_info(cpl_func,"Half-cycle image [%d X %d] has minimum intensity: %g",
00745 (int)cpl_image_get_size_x(hcycle), npix, hc_min);
00746 if (hc_min < 0) {
00747 cpl_msg_warning(cpl_func, "Thresholding negative intensities in half-"
00748 "cycle image: %g", hc_min);
00749 skip_if (cpl_image_threshold(corrected, 0.0, DBL_MAX, 0.0, DBL_MAX));
00750 } else if (hc_min > 0) {
00751 skip_if (cpl_image_subtract_scalar(corrected, hc_min));
00752 }
00753
00754 xc_image = cpl_image_duplicate(corrected);
00755
00756
00757 cpl_image_delete(corrected);
00758 corrected = cpl_image_collapse_create(xc_image, 1);
00759 cpl_image_delete(xc_image);
00760 xc_image = corrected;
00761 corrected = NULL;
00762
00763 skip_if(cpl_image_divide_scalar(xc_image, npix));
00764
00765 xc_vector = cpl_vector_wrap(npix, cpl_image_get_data(xc_image));
00766
00767 skip_if (0);
00768
00769 #ifdef VISIR_SPC_LRP
00770 phdisp = visir_spc_phys_lrp();
00771 cpl_msg_info(cpl_func, "Central Dispersion (physical model) [pixel/m]: %g",
00772 1.0/visir_spc_get_dispersion(phdisp, npix/2.0 + 0.5));
00773 cpl_msg_info(cpl_func, "Central Wavelength (physical model) [m]: %g",
00774 cpl_polynomial_eval_1d(phdisp, npix/2.0 + 0.5, NULL));
00775 cpl_msg_info(cpl_func, "First Wavelength (physical model) [m]: %g",
00776 cpl_polynomial_eval_1d(phdisp, 1.0, NULL));
00777 cpl_msg_info(cpl_func, "Last Wavelength (physical model) [m]: %g",
00778 cpl_polynomial_eval_1d(phdisp, 1024, NULL));
00779 cpl_polynomial_dump(phdisp, stdout);
00780 cpl_polynomial_delete(phdisp);
00781 #endif
00782
00783 phdisp = visir_spc_phys_disp(npix, wlen, resol, ioffset, is_aqu);
00784 skip_if (0);
00785
00786 if (cpl_polynomial_get_degree(phdisp) == 2) {
00787 const cpl_size i2 = 2;
00788 cpl_msg_info(cpl_func, "Dispersion polynomial of physical model:"
00789 " %gmum + ipix * %gmum/pixel + ipix^2 * (%g)mum/pixel^2 "
00790 "[ipix = 1, 2, ..., %d]",
00791 cpl_polynomial_get_coeff(phdisp, &i0) * 1e6,
00792 cpl_polynomial_get_coeff(phdisp, &i1) * 1e6,
00793 cpl_polynomial_get_coeff(phdisp, &i2) * 1e6,
00794 npix);
00795 }
00796 else {
00797 cpl_msg_info(cpl_func, "Dispersion polynomial of physical model:"
00798 " %gmum + ipix * %gmum/pixel [ipix = 1, 2, ..., %d]",
00799 cpl_polynomial_get_coeff(phdisp, &i0) * 1e6,
00800 cpl_polynomial_get_coeff(phdisp, &i1) * 1e6, npix);
00801 }
00802
00803 temiss = visir_bivector_load_fits(linefile, "Wavelength", "Emission", 1);
00804 any_if ("Could not load file with Emission Lines");
00805
00806 tqeff = visir_bivector_load_fits(qefffile, "Wavelength", "Efficiency",
00807 npix > 256 ? 2 : 1);
00808 any_if("Could not load file with Quantum-Efficiencies");
00809
00810 if (doplot) {
00811 visir_bivector_plot("set grid;set xlabel 'Wavelength [m]';", "t '"
00812 "Quantum Efficiency' w linespoints", "", tqeff);
00813 }
00814
00815 vsymm = cpl_spc_convolve_init(npix, slitw, fwhm, doplot);
00816
00817 skip_if (vsymm == NULL);
00818
00819 vxc = cpl_vector_new(1);
00820 xcdisp = cpl_polynomial_new(1);
00821
00822 mymodel.lines = temiss;
00823 mymodel.tqeff = tqeff;
00824 mymodel.vsymm = vsymm;
00825 mymodel.temp = temp;
00826 mymodel.ulines = 0;
00827 mymodel.cost = 0;
00828 mymodel.xcost = 0;
00829
00830 skip_if(visir_spectro_refine(xcdisp, xc_vector, &mymodel, phdisp,
00831 VISIR_XC_LEN, doplot, resol,
00832 &qcxc, &didshift, &qcsubdelta));
00833
00834 if (didshift) {
00835 if (fabs(qcsubdelta) >= VISIR_XC_LEN) {
00836 cpl_msg_warning(cpl_func, "Cross-correlation (%g pixel shift): %g",
00837 qcsubdelta, qcxc);
00838 } else {
00839 cpl_msg_info(cpl_func,"Cross-correlation (%g pixel shift): %g",
00840 qcsubdelta, qcxc);
00841 }
00842 }
00843
00844 cpl_msg_info(cpl_func, "Dispersion polynomial from cross-correlation: "
00845 "%gm + ipix * %gm/pixel [ipix = 1, 2, ..., %d]",
00846 cpl_polynomial_get_coeff(xcdisp, &i0),
00847 cpl_polynomial_get_coeff(xcdisp, &i1), npix);
00848
00849 cpl_msg_info(cpl_func, "New Central Wavelength [m]: %g",
00850 cpl_polynomial_eval_1d(xcdisp, 0.5*npix+0.5, NULL));
00851
00852 *pspc_table = cpl_table_new(npix);
00853 skip_if (0);
00854
00855
00856 wlvals = cpl_vector_new(npix);
00857 bug_if (cpl_table_wrap_double(*pspc_table, cpl_vector_get_data(wlvals),
00858 "WLEN"));
00859
00860 skip_if (cpl_vector_fill_polynomial(wlvals, xcdisp, 1.0, 1.0));
00861
00862
00863 spmodel = cpl_vector_new(npix);
00864 bug_if (cpl_table_wrap_double(*pspc_table, cpl_vector_get_data(spmodel),
00865 "SPC_MODEL_PH"));
00866 skip_if (visir_spectro_fill(spmodel, phdisp,
00867 (irplib_base_spectrum_model*)&mymodel));
00868
00869
00870 (void)cpl_vector_unwrap(spmodel);
00871 spmodel = cpl_vector_new(npix);
00872 bug_if (cpl_table_wrap_double(*pspc_table, cpl_vector_get_data(spmodel),
00873 "SPC_MODEL_XC"));
00874
00875 skip_if (visir_spectro_fill(spmodel, xcdisp,
00876 (irplib_base_spectrum_model*)&mymodel));
00877
00878 bug_if (cpl_table_wrap_double(*pspc_table,
00879 cpl_image_get_data_double(xc_image),
00880 "SPC_SKY"));
00881 (void)cpl_image_unwrap(xc_image);
00882 xc_image = NULL;
00883
00884
00885 (void)cpl_vector_unwrap(spmodel);
00886 spmodel = cpl_vector_new(npix);
00887 bug_if (cpl_table_wrap_double(*pspc_table, cpl_vector_get_data(spmodel),
00888 "SPC_EMISSIVITY"));
00889
00890 boundary = cpl_vector_new(npix + 1);
00891 skip_if (cpl_vector_fill_polynomial(boundary, xcdisp, 0.5, 1.0));
00892 skip_if (visir_vector_resample(spmodel, boundary, temiss));
00893
00894 bug_if (cpl_table_set_column_unit(*pspc_table, "WLEN", "m"));
00895 bug_if (cpl_table_set_column_unit(*pspc_table, "SPC_MODEL_PH",
00896 "J*radian/m^3/s"));
00897 bug_if (cpl_table_set_column_unit(*pspc_table, "SPC_MODEL_XC",
00898 "J*radian/m^3/s"));
00899 bug_if (cpl_table_set_column_unit(*pspc_table, "SPC_SKY", "ADU/s"));
00900
00901
00902
00903
00904
00905 if (resol != VISIR_SPC_R_LRP && cpl_vector_get(wlvals, 0) < N_upper &&
00906 N_upper < cpl_vector_get(wlvals, npix-1))
00907 cpl_msg_warning(cpl_func, "Spectrum goes above N-band (%gm). Wavelength"
00908 " Calibration may be entirely inaccurate", N_upper);
00909
00910 bug_if(visir_spectro_qclist_wcal(qclist, npix, qcxc, didshift, qcsubdelta,
00911 phdisp, xcdisp));
00912
00913 if (doplot) {
00914 cpl_bivector * plot = cpl_bivector_wrap_vectors(wlvals, xc_vector);
00915
00916 visir_bivector_plot("set grid;set xlabel 'Wavelength [m]';", "t 'Spec"
00917 "trum from Half-cycle' w linespoints", "", plot);
00918 cpl_bivector_unwrap_vectors(plot);
00919
00920 visir_table_plot("set grid;set xlabel 'Wavelength [m]';",
00921 "t 'Calibrated Model Spectrum' w linespoints",
00922 "", *pspc_table, "WLEN", "SPC_MODEL_XC");
00923
00924
00925 visir_table_plot("set grid;set xlabel 'Wavelength [m]';",
00926 "t 'Physical Model Spectrum' w linespoints",
00927 "", *pspc_table, "WLEN", "SPC_MODEL_PH");
00928
00929 if (resol != VISIR_SPC_R_LRP) {
00930
00931
00932 emission = cpl_bivector_new(2 * npix);
00933
00934 cpl_vector_delete(boundary);
00935 boundary = cpl_vector_new(2 * npix + 1);
00936
00937 cpl_vector_fill_polynomial(cpl_bivector_get_x(emission),
00938 phdisp, -0.5*npix, 1);
00939 cpl_vector_fill_polynomial(boundary, phdisp, -0.5*(npix+1), 1);
00940
00941
00942 visir_spc_emission(emission, boundary, temiss, tqeff, vsymm, temp);
00943 cpl_vector_delete(boundary);
00944 boundary = NULL;
00945
00946 visir_bivector_plot("set grid;set xlabel 'Wavelength [m]';",
00947 "t 'Extended Model Spectrum' w linespoints",
00948 "", emission);
00949 }
00950 }
00951
00952 end_skip;
00953
00954 (void)cpl_vector_unwrap(wlvals);
00955 (void)cpl_vector_unwrap(spmodel);
00956 cpl_polynomial_delete(phdisp);
00957 cpl_polynomial_delete(xcdisp);
00958 cpl_image_delete(xc_image);
00959 cpl_vector_delete(vsymm);
00960 cpl_image_delete(corrected);
00961 cpl_bivector_delete(temiss);
00962 cpl_bivector_delete(tqeff);
00963 cpl_vector_delete(boundary);
00964 cpl_bivector_delete(emission);
00965 (void)cpl_vector_unwrap(xc_vector);
00966 cpl_vector_delete(vxc);
00967
00968 return cpl_error_get_code();
00969 }
00970
00971
00972
00989
00990 cpl_error_code visir_spc_echelle_limit(int * pcol1, int * pcol2, double wlen,
00991 int ioffset, int icolmin, int icolmax,
00992 int is_aqu)
00993 {
00994
00995 visir_optmod ins_settings;
00996 double echpos;
00997 double wleni;
00998 int order;
00999 int error;
01000
01001
01002 cpl_ensure_code(wlen > 0, CPL_ERROR_ILLEGAL_INPUT);
01003 cpl_ensure_code(pcol1, CPL_ERROR_NULL_INPUT);
01004 cpl_ensure_code(pcol2, CPL_ERROR_NULL_INPUT);
01005 cpl_ensure_code(icolmin > 0, CPL_ERROR_ILLEGAL_INPUT);
01006 cpl_ensure_code(icolmax >= icolmin, CPL_ERROR_ILLEGAL_INPUT);
01007
01008 cpl_ensure_code(ioffset >= -4, CPL_ERROR_ILLEGAL_INPUT);
01009 cpl_ensure_code(ioffset <= 4, CPL_ERROR_ILLEGAL_INPUT);
01010
01011 error = visir_spc_optmod_init(VISIR_SPC_R_GHR, wlen, &ins_settings, is_aqu);
01012 if (error) {
01013 cpl_msg_error(cpl_func, "HRG Optical model initialization (%p) failed: %d "
01014 "(%g)", (void*)&ins_settings, error, wlen);
01015 cpl_ensure_code(0, CPL_ERROR_ILLEGAL_INPUT);
01016 }
01017 order = ioffset + visir_spc_optmod_get_echelle_order(&ins_settings);
01018
01019
01020 cpl_ensure_code(order > 0, CPL_ERROR_ILLEGAL_INPUT);
01021 cpl_ensure_code(order <= 18, CPL_ERROR_ILLEGAL_INPUT);
01022
01023 wleni = visir_spc_optmod_echelle(&ins_settings, wlen, ioffset );
01024
01025 echpos = visir_spc_optmod_cross_dispersion(&ins_settings, wleni);
01026 if (echpos <= whechelle || echpos >= icolmax-whechelle) {
01027 cpl_msg_error(cpl_func, "Echelle (%d) location out of range [%d;%d]: %g",
01028 order, icolmin, icolmax, echpos);
01029 cpl_ensure_code(0, CPL_ERROR_DATA_NOT_FOUND);
01030 }
01031
01032 *pcol1 = ceil(echpos - whechelle);
01033 *pcol2 = echpos + whechelle;
01034
01035 if (*pcol1 < icolmin) *pcol1 = icolmin;
01036 if (*pcol2 > icolmax) *pcol2 = icolmax;
01037
01038 cpl_msg_info(cpl_func, "Echelle order %d at col %g [%d; %d]", order, echpos,
01039 *pcol1, *pcol2);
01040
01041 return cpl_error_get_code();
01042
01043 }
01044
01045
01058
01059 cpl_image * visir_spc_column_extract(const cpl_image * self, int icol1,
01060 int icol2, int doplot)
01061 {
01062
01063 cpl_image * band = NULL;
01064 cpl_image * spatial = NULL;
01065 const int nrow = cpl_image_get_size_y(self);
01066 const int ncol = cpl_image_get_size_x(self);
01067
01068 cpl_ensure(self != NULL, CPL_ERROR_NULL_INPUT, NULL);
01069 cpl_ensure(icol1 > 0, CPL_ERROR_ILLEGAL_INPUT, NULL);
01070 cpl_ensure(icol2 >= icol1, CPL_ERROR_ILLEGAL_INPUT, NULL);
01071
01072 cpl_ensure(ncol >= icol2, CPL_ERROR_ILLEGAL_INPUT, NULL);
01073
01074 band = cpl_image_extract(self, icol1, 1, icol2, nrow);
01075 skip_if (0);
01076
01077 if (doplot > 0) {
01078 visir_image_plot("", "t 'The full-width image'", "", self);
01079
01080 if (doplot > 1) {
01081
01082 spatial = cpl_image_collapse_create(self, 0);
01083 skip_if (0);
01084 skip_if (cpl_image_divide_scalar(spatial, nrow));
01085
01086 visir_image_row_plot("set grid;", "t 'Spectral direction "
01087 "collapsed' w linespoints", "",
01088 spatial, 1, 1, 1);
01089 }
01090 }
01091
01092 end_skip;
01093
01094 cpl_image_delete(spatial);
01095 if (cpl_error_get_code() && band != NULL) {
01096 cpl_image_delete(band);
01097 band = NULL;
01098 }
01099
01100 return band;
01101
01102 }
01103
01104
01105
01118
01119 cpl_error_code visir_spectro_qc(cpl_propertylist * qclist,
01120 cpl_propertylist * paflist,
01121 cpl_boolean drop_wcs,
01122 const irplib_framelist * rawframes,
01123 const char * regcopy,
01124 const char * regcopypaf)
01125 {
01126
01127 const cpl_propertylist * reflist
01128 = irplib_framelist_get_propertylist_const(rawframes, 0);
01129
01130 bug_if (0);
01131
01132 bug_if (visir_qc_append_capa(qclist, rawframes));
01133
01134 if (regcopy != NULL)
01135 bug_if (cpl_propertylist_copy_property_regexp(qclist, reflist,
01136 regcopy, 0));
01137
01138 if (regcopypaf != NULL)
01139 bug_if (cpl_propertylist_copy_property_regexp(paflist, reflist,
01140 regcopypaf, 0));
01141
01142 bug_if (cpl_propertylist_append(paflist, qclist));
01143
01144 if (drop_wcs) {
01145 cpl_propertylist * pcopy = cpl_propertylist_new();
01146 const cpl_error_code error
01147 = cpl_propertylist_copy_property_regexp(pcopy, reflist, "^("
01148 IRPLIB_PFITS_WCS_REGEXP
01149 ")$", 0);
01150 if (!error && cpl_propertylist_get_size(pcopy) > 0) {
01151 cpl_msg_warning(cpl_func, "Combined image will have no WCS "
01152 "coordinates");
01153 }
01154 cpl_propertylist_delete(pcopy);
01155 bug_if(0);
01156 } else {
01157 bug_if(cpl_propertylist_copy_property_regexp(qclist, reflist, "^("
01158 IRPLIB_PFITS_WCS_REGEXP
01159 ")$", 0));
01160 }
01161
01162 end_skip;
01163
01164 return cpl_error_get_code();
01165
01166 }
01167
01168
01172
01185
01186 static cpl_error_code visir_spectro_qclist_wcal(cpl_propertylist * self,
01187 int npix, double xc,
01188 cpl_boolean didshift,
01189 double subdelta,
01190 const cpl_polynomial * phdisp,
01191 const cpl_polynomial * xcdisp)
01192 {
01193
01194 const cpl_size phdegree = cpl_polynomial_get_degree(phdisp);
01195 const cpl_size xcdegree = cpl_polynomial_get_degree(xcdisp);
01196
01197 const double phdisp0 = cpl_polynomial_eval_1d(phdisp, 1.0, NULL);
01198 const double xcdisp0 = cpl_polynomial_eval_1d(xcdisp, 1.0, NULL);
01199
01200 const double xcwlen = cpl_polynomial_eval_1d(xcdisp, 0.5*(double)npix+0.5,
01201 NULL);
01202 const double phcdisp = visir_spc_get_dispersion(phdisp, npix/2.0 + 0.5);
01203 const double xccdisp = visir_spc_get_dispersion(xcdisp, npix/2.0 + 0.5);
01204 cpl_size i;
01205
01206
01207 bug_if (0);
01208 skip_if (phdegree < 1);
01209 skip_if (xcdegree < 1);
01210
01211 cpl_msg_info(cpl_func, "Central Dispersion (physical model) [m/pixel]: %g",
01212 phcdisp);
01213 cpl_msg_info(cpl_func, "Central Dispersion (calibrated) [m/pixel]: %g",
01214 xccdisp);
01215
01216 bug_if (cpl_propertylist_append_double(self, "ESO QC XC", xc));
01217
01218 if (didshift)
01219 bug_if (cpl_propertylist_append_double(self, "ESO QC XCSHIFT",
01220 subdelta));;
01221
01222 bug_if (cpl_propertylist_append_int(self, "ESO QC PHDEGREE", phdegree));
01223 bug_if (cpl_propertylist_append_double(self, "ESO QC PHDISPX0", phdisp0));
01224 for (i = 1; i <= phdegree; i++) {
01225 const double coeff = cpl_polynomial_get_coeff(phdisp, &i);
01226 char * label = cpl_sprintf("ESO QC PHDISPX%d", (int)i);
01227
01228 bug_if (cpl_propertylist_append_double(self, label, coeff));
01229 cpl_free(label);
01230 }
01231
01232 bug_if (cpl_propertylist_append_double(self, "ESO QC XCWLEN", xcwlen));
01233
01234 bug_if (cpl_propertylist_append_int(self, "ESO QC XCDEGREE", xcdegree));
01235 bug_if (cpl_propertylist_append_double(self, "ESO QC XCDISPX0", xcdisp0));
01236
01237 for (i = 1; i <= xcdegree; i++) {
01238 const double coeff = cpl_polynomial_get_coeff(xcdisp, &i);
01239 char * label = cpl_sprintf("ESO QC XCDISPX%d", (int)i);
01240
01241 bug_if (cpl_propertylist_append_double(self, label, coeff));
01242 cpl_free(label);
01243 }
01244
01245 end_skip;
01246
01247 return cpl_error_get_code();
01248
01249 }
01250
01251
01252
01253
01265
01266 static cpl_error_code visir_spectro_qclist_obs(cpl_propertylist * self,
01267 double xfwhm, double xcentro)
01268 {
01269
01270
01271 bug_if (0);
01272
01273 bug_if (cpl_propertylist_append_double(self, "ESO QC XFWHM", xfwhm));
01274 bug_if (cpl_propertylist_append_double(self, "ESO QC XCENTROI", xcentro));
01275
01276 end_skip;
01277
01278 return cpl_error_get_code();
01279
01280 }
01281
01282
01283
01295
01296 static cpl_error_code visir_vector_convolve_symm(cpl_vector * self,
01297 const cpl_vector * vsymm)
01298 {
01299
01300 const int npix = cpl_vector_get_size(self);
01301 const int ihwidth = cpl_vector_get_size(vsymm) - 1;
01302 cpl_vector * raw = cpl_vector_duplicate(self);
01303 double * pself= cpl_vector_get_data(self);
01304 double * praw = cpl_vector_get_data(raw);
01305 const double * psymm = cpl_vector_get_data_const(vsymm);
01306
01307 int i, j;
01308
01309
01310 skip_if (0);
01311
01312
01313 skip_if (ihwidth >= npix);
01314
01315
01316 for (i = 0; i < ihwidth; i++) {
01317 pself[i] = praw[i] * psymm[0];
01318 for (j = 1; j <= ihwidth; j++) {
01319 const int k = i-j < 0 ? 0 : i-j;
01320 pself[i] += (praw[k]+praw[i+j]) * psymm[j];
01321 }
01322
01323 }
01324
01325 for (i = ihwidth; i < npix-ihwidth; i++) {
01326 pself[i] = praw[i] * psymm[0];
01327 for (j = 1; j <= ihwidth; j++)
01328 pself[i] += (praw[i-j]+praw[i+j]) * psymm[j];
01329
01330 }
01331 for (i = npix-ihwidth; i < npix; i++) {
01332 pself[i] = praw[i] * psymm[0];
01333 for (j = 1; j <= ihwidth; j++) {
01334 const int k = i+j > npix-1 ? npix - 1 : i+j;
01335 pself[i] += (praw[k]+praw[i-j]) * psymm[j];
01336 }
01337
01338 }
01339
01340 end_skip;
01341
01342 cpl_vector_delete(raw);
01343
01344 return cpl_error_get_code();
01345 }
01346
01347
01368
01369 cpl_image * visir_spc_flip(const cpl_image * image, double wlen,
01370 visir_spc_resol resol, visir_data_type dtype)
01371 {
01372 cpl_image * flipped = cpl_image_cast(image, CPL_TYPE_DOUBLE);
01373 visir_optmod ins_settings;
01374
01375
01376 skip_if (0);
01377
01378 if ((resol == VISIR_SPC_R_HR || resol == VISIR_SPC_R_GHR) &&
01379 visir_spc_optmod_init(resol, wlen, &ins_settings,
01380 visir_data_is_aqu(dtype))) {
01381 visir_error_set(CPL_ERROR_ILLEGAL_INPUT);
01382 skip_if (1);
01383 }
01384
01385
01386
01387
01388 if (visir_data_is_aqu(dtype)) {
01389 skip_if (cpl_image_turn(flipped, 1));
01390 if ((resol == VISIR_SPC_R_HR || resol == VISIR_SPC_R_GHR) &&
01391 visir_spc_optmod_side_is_A(&ins_settings) == 0) {
01392 skip_if (cpl_image_flip(flipped, 0));
01393 }
01394 }
01395
01396 else if ((resol != VISIR_SPC_R_HR && resol != VISIR_SPC_R_GHR) ||
01397 visir_spc_optmod_side_is_A(&ins_settings) > 0) {
01398
01399 cpl_msg_info(cpl_func, "Flipping image");
01400
01401 skip_if (cpl_image_flip(flipped, 0));
01402 }
01403
01404 end_skip;
01405
01406 if (cpl_error_get_code() && flipped) {
01407 cpl_image_delete(flipped);
01408 flipped = NULL;
01409 }
01410
01411 return flipped;
01412
01413 }
01414
01415
01431
01432 static cpl_polynomial * visir_spc_phys_disp(int npix, double wlen,
01433 visir_spc_resol resol, int ioffset,
01434 int is_aqu)
01435 {
01436
01437 cpl_polynomial * phdisp = NULL;
01438 visir_optmod ins_settings;
01439
01440 double dwl;
01441 double wlen0;
01442 double wlen1;
01443 double disp;
01444 const cpl_size i1 = 1;
01445 const cpl_size i0 = 0;
01446
01447
01448 cpl_ensure(resol, CPL_ERROR_ILLEGAL_INPUT, NULL);
01449 cpl_ensure(wlen > 0, CPL_ERROR_ILLEGAL_INPUT, NULL);
01450 cpl_ensure(npix > 1, CPL_ERROR_ILLEGAL_INPUT, NULL);
01451
01452
01453
01454
01455
01456
01457 cpl_ensure(!visir_spc_optmod_init(resol, wlen, &ins_settings, is_aqu),
01458 CPL_ERROR_ILLEGAL_INPUT, NULL);
01459
01460
01461
01462
01463 dwl = visir_spc_optmod_wlen(&ins_settings, &wlen0, &wlen1);
01464
01465 cpl_ensure(dwl >= 0, CPL_ERROR_ILLEGAL_INPUT, NULL);
01466
01467
01468 dwl -= wlen;
01469
01470 if (fabs(dwl) > 2*wlen*DBL_EPSILON) cpl_msg_warning(cpl_func, "Too large res"
01471 "idual in Scan-Angle determination [meps]: %g", dwl/DBL_EPSILON/wlen);
01472
01473 if ((resol == VISIR_SPC_R_HR || resol == VISIR_SPC_R_GHR) &&
01474 !visir_spc_optmod_side_is_A(&ins_settings)) {
01475 const double swap = wlen1;
01476 wlen1 = wlen0;
01477 wlen0 = swap;
01478 }
01479 cpl_ensure(wlen1 > wlen0, CPL_ERROR_ILLEGAL_INPUT, NULL);
01480
01481 if (resol == VISIR_SPC_R_LRP) {
01482 phdisp = visir_spc_phys_lrp();
01483 } else {
01484
01485
01486 phdisp = cpl_polynomial_new(1);
01487
01488
01489 disp = (wlen1-wlen0)/(npix-1);
01490
01491 skip_if (0);
01492
01493 skip_if (cpl_polynomial_set_coeff(phdisp, &i1, disp));
01494
01495 skip_if (cpl_polynomial_set_coeff(phdisp, &i0, wlen0-disp));
01496 }
01497
01498 if ((resol == VISIR_SPC_R_HR || resol == VISIR_SPC_R_GHR) &&
01499 !visir_spc_optmod_side_is_A(&ins_settings)) {
01500 cpl_msg_info(cpl_func,"HR B-side WLMin, WLMax, Disp: %g %g %g", wlen0,
01501 wlen1, cpl_polynomial_get_coeff(phdisp, &i1));
01502 } else {
01503 cpl_msg_info(cpl_func,"WLMin, WLMax, Disp: %g %g %g", wlen0, wlen1,
01504 cpl_polynomial_get_coeff(phdisp, &i1));
01505 }
01506
01507 if (resol == VISIR_SPC_R_GHR && ioffset != 0) {
01508
01509
01510 const double dispi = visir_spc_optmod_echelle(&ins_settings,
01511 cpl_polynomial_get_coeff(phdisp, &i1), ioffset);
01512 const double wlen0i= visir_spc_optmod_echelle(&ins_settings,
01513 cpl_polynomial_get_coeff(phdisp, &i0), ioffset);
01514
01515 skip_if (cpl_polynomial_set_coeff(phdisp, &i1, dispi));
01516
01517 skip_if (cpl_polynomial_set_coeff(phdisp, &i0, wlen0i));
01518
01519 cpl_msg_info(cpl_func, "WLc relative error(%d): %g", ioffset,
01520 (wlen0i - cpl_polynomial_eval_1d(phdisp, 1, NULL))/wlen0i);
01521 }
01522
01523
01524 end_skip;
01525
01526 if (cpl_error_get_code() && phdisp != NULL) {
01527 cpl_polynomial_delete(phdisp);
01528 phdisp = NULL;
01529 }
01530
01531 return phdisp;
01532
01533 }
01534
01535
01536
01550
01551
01552 cpl_bivector * visir_bivector_load_fits(const char * file,
01553 const char * labelx,
01554 const char * labely,
01555 int extnum)
01556 {
01557
01558 cpl_bivector * result = NULL;
01559 cpl_table * table = NULL;
01560 cpl_propertylist * extlist = NULL;
01561 cpl_vector * xwrapper;
01562 cpl_vector * ywrapper;
01563 char * sext = NULL;
01564 double * prowx;
01565 double * prowy;
01566 int next;
01567 int nlines;
01568
01569
01570 bug_if (extnum < 1);
01571
01572 next = cpl_fits_count_extensions(file);
01573 any_if("Could not load FITS table from (extension %d in) file: %s",
01574 extnum, file ? file : "<NULL>");
01575
01576 skip_if_lt(next, extnum, "extensions in file: %s", file);
01577
01578 table = cpl_table_load(file, extnum, 0);
01579 any_if ("Could not load FITS table from extension %d of %d in file: %s",
01580 extnum, next, file ? file : "<NULL>");
01581
01582 extlist = cpl_propertylist_load_regexp(file, extnum, "EXTNAME", 0);
01583 if (cpl_propertylist_has(extlist, "EXTNAME")) {
01584 const char * extname = cpl_propertylist_get_string(extlist, "EXTNAME");
01585 sext = cpl_sprintf(" (EXTNAME=%s)", extname);
01586 }
01587
01588 nlines = cpl_table_get_nrow(table);
01589 skip_if_lt(nlines, 2, "rows in table from extension %d%s of %d "
01590 "in %s", extnum, sext, next, file);
01591
01592 prowx = cpl_table_get_data_double(table, labelx);
01593 any_if("Table from extension %d%s of %d in %s has no column %s",
01594 extnum, sext, next, file, labelx);
01595
01596 prowy = cpl_table_get_data_double(table, labely);
01597 any_if("Table from extension %d%s of %d in %s has no column %s",
01598 extnum, sext, next, file, labely);
01599
01600 xwrapper = cpl_vector_wrap(nlines, prowx);
01601 ywrapper = cpl_vector_wrap(nlines, prowy);
01602
01603 result = cpl_bivector_wrap_vectors(xwrapper, ywrapper);
01604 cpl_table_unwrap(table, labelx);
01605 cpl_table_unwrap(table, labely);
01606
01607 cpl_msg_info(cpl_func, "Read %d rows from extension %d%s of %d "
01608 "in %s [%g;%g]", nlines, extnum, sext, next, file,
01609 cpl_vector_get(xwrapper, 0),
01610 cpl_vector_get(ywrapper, nlines-1));
01611
01612 end_skip;
01613
01614 cpl_free(sext);
01615 cpl_table_delete(table);
01616 cpl_propertylist_delete(extlist);
01617
01618 if (result && cpl_error_get_code()) {
01619 cpl_bivector_delete(result);
01620 result = NULL;
01621 }
01622
01623 return result;
01624
01625 }
01626
01627
01628
01655
01656 static cpl_error_code visir_spc_emission(cpl_bivector * emission,
01657 const cpl_vector * boundary,
01658 const cpl_bivector * temiss,
01659 const cpl_bivector * tqeff,
01660 const cpl_vector * vsymm,
01661 double temp)
01662 {
01663 cpl_bivector * tqeffi = NULL;
01664 cpl_vector * planck = NULL;
01665 const int npix = cpl_bivector_get_size(emission);
01666
01667
01668 bug_if(emission == NULL);
01669 bug_if(boundary == NULL);
01670 bug_if(temiss == NULL);
01671 bug_if(tqeff == NULL);
01672
01673
01674 skip_if(npix <= 1);
01675
01676 skip_if(cpl_vector_get_size(boundary) != npix + 1);
01677
01678 planck = cpl_vector_new(npix);
01679 skip_if (0);
01680
01681
01682
01683 cpl_photom_fill_blackbody(planck, CPL_UNIT_ENERGYRADIANCE,
01684 cpl_bivector_get_x(emission),
01685 CPL_UNIT_LENGTH, 253);
01686
01687 skip_if (visir_vector_resample(cpl_bivector_get_y(emission),
01688 boundary, temiss));
01689
01690
01691 skip_if (visir_vector_convolve_symm(cpl_bivector_get_y(emission),
01692 vsymm));
01693
01694 skip_if (cpl_vector_multiply(cpl_bivector_get_y(emission), planck));
01695
01696
01697
01698 cpl_photom_fill_blackbody(planck, CPL_UNIT_ENERGYRADIANCE,
01699 cpl_bivector_get_x(emission),
01700 CPL_UNIT_LENGTH, temp);
01701
01702
01703 skip_if (cpl_vector_multiply_scalar(planck, 0.12));
01704
01705
01706 skip_if (cpl_vector_add(cpl_bivector_get_y(emission), planck));
01707
01708
01709 tqeffi = cpl_bivector_duplicate(emission);
01710 skip_if (cpl_bivector_interpolate_linear(tqeffi, tqeff));
01711
01712 skip_if (cpl_vector_multiply(cpl_bivector_get_y(emission),
01713 cpl_bivector_get_y(tqeffi)));
01714
01715 end_skip;
01716
01717 cpl_bivector_delete(tqeffi);
01718 cpl_vector_delete(planck);
01719
01720 return cpl_error_get_code();
01721 }
01722
01723
01724
01747
01748 static cpl_vector * cpl_spc_convolve_init(int maxlen, double slitw,
01749 double fwhm, int doplot)
01750 {
01751
01752 const double sigma = fwhm * CPL_MATH_SIG_FWHM;
01753 const int ihtophat = (int)slitw/2;
01754 const int gausshlen = 1 + 5 * sigma + ihtophat < maxlen/2
01755 ? 1 + 5 * sigma + ihtophat : maxlen/2 - 1;
01756
01757 const int convolen = 1 + 10 * sigma + 8*ihtophat;
01758 cpl_vector * self = cpl_vector_new(gausshlen);
01759 cpl_vector * tophat = cpl_vector_new(convolen);
01760 int i;
01761
01762
01763 cpl_image * iself = cpl_image_wrap_double(gausshlen, 1,
01764 cpl_vector_get_data(self));
01765
01766
01767 skip_if (0);
01768
01769 skip_if( slitw <= 0.0);
01770 skip_if( fwhm <= 0.0);
01771 skip_if( convolen < 2 * gausshlen);
01772
01773
01774 skip_if (cpl_image_fill_gaussian(iself, 1.0, 1.0, CPL_MATH_SQRT2PI,
01775 sigma, 1.0));
01776
01777 if (doplot > 2) visir_vector_plot("set grid;", "t 'Right Half of Gaussian' "
01778 "w linespoints", "", self);
01779
01780
01781 skip_if( cpl_vector_fill(tophat, 0.0));
01782
01783 for (i = convolen/2-ihtophat; i < 1+convolen/2+ihtophat; i++)
01784 skip_if (cpl_vector_set(tophat, i, 1.0/(1.0+2.0*ihtophat)));
01785
01786
01787 skip_if (visir_vector_convolve_symm(tophat, self));
01788
01789 if (doplot > 2) visir_vector_plot("set grid;","t 'Full Width Convolution' "
01790 "w linespoints", "", tophat);
01791
01792
01793
01794 #if 1
01795 memcpy(cpl_vector_get_data(self),
01796 cpl_vector_get_data(tophat) + convolen/2,
01797 sizeof(double)*gausshlen);
01798 #else
01799
01800 for (i = 0 ; i < gausshlen; i++)
01801 skip_if (cpl_vector_set(self, i, cpl_vector_get(tophat,
01802 i + convolen/2)));
01803 #endif
01804
01805 skip_if (0);
01806
01807 cpl_msg_info(cpl_func, "Convolving Model Spectrum, Gauss-sigma=%g, "
01808 "Tophat-width=%d, Truncation-Error=%g with width=%d", sigma,
01809 1+2*ihtophat,
01810 cpl_vector_get(self,gausshlen-1)/cpl_vector_get(self,0),
01811 2*gausshlen-1);
01812
01813 if (doplot > 1) visir_vector_plot("set grid;","t 'Right Half of Convolution"
01814 "' w linespoints", "", self);
01815
01816 end_skip;
01817
01818 cpl_vector_delete(tophat);
01819 cpl_image_unwrap(iself);
01820
01821 if (cpl_error_get_code()) {
01822 cpl_vector_delete(self);
01823 self = NULL;
01824 }
01825
01826 return self;
01827
01828 }
01829
01830
01831 static cpl_error_code
01832 fit_gaussians(const cpl_image * flipped, const cpl_vector * error,
01833 cpl_size icollo, cpl_size icolhi,
01834 cpl_propertylist * qclist)
01835 {
01836 cpl_size nrow = cpl_image_get_size_y(flipped);
01837 cpl_size ncol = cpl_image_get_size_x(flipped);
01838 icollo = CX_MAX(1, icollo);
01839 icolhi = CX_MIN(ncol, icolhi);
01840 cpl_errorstate cleanstate = cpl_errorstate_get();
01841 double sigs[nrow];
01842 double sigs_err = 0.;
01843 double peaks[nrow];
01844 double peaks_err = 0.;
01845 size_t nmeas = 0;
01846 for (cpl_size row = 0; row < nrow; row++) {
01847 const cpl_binary * dmask = cpl_image_get_bpm_const(flipped) ?
01848 cpl_mask_get_data_const(cpl_image_get_bpm_const(flipped)) : NULL;
01849 const double *dflipped = cpl_image_get_data_double_const(flipped);
01850 double * dx = cpl_malloc(ncol * sizeof(*dx));
01851 double * dy = cpl_malloc(ncol * sizeof(*dy));
01852 double * dye = cpl_malloc(ncol * sizeof(*dye));
01853 cpl_vector * x;
01854 cpl_vector * y;
01855 cpl_vector * ye;
01856 size_t n = 0;
01857 for (cpl_size i = icollo; i <= icolhi; i++) {
01858 if (dmask == NULL || !dmask[row * ncol + i]) {
01859 dx[n] = i;
01860 dy[n] = dflipped[row * ncol + (i - 1)];
01861 dye[n] = cpl_vector_get(error, (i - 1));
01862 n++;
01863 }
01864 }
01865 if (n > 0) {
01866 x = cpl_vector_wrap(n, dx);
01867 y = cpl_vector_wrap(n, dy);
01868 ye = cpl_vector_wrap(n, dye);
01869 double x0, sigma, sigma_err, peak, peak_err;
01870 fit_1d_gauss(x, y, ye, &x0, NULL, &peak, &peak_err, &sigma, &sigma_err);
01871 if (cpl_error_get_code() != CPL_ERROR_NONE) {
01872 cpl_msg_debug(cpl_func, "FIT row %lld failed", row);
01873 cpl_errorstate_set(cleanstate);
01874 }
01875 else {
01876 sigs[nmeas] = sigma;
01877 peaks[nmeas] = peak;
01878 sigs_err += sigma * sigma;
01879 peaks_err += peak * peak;
01880 nmeas++;
01881 cpl_msg_debug(cpl_func, "FIT row %lld x %g sig %g +- %g "
01882 "peak %g +- %g",
01883 row, x0, sigma, sigma_err, peak, peak_err);
01884 }
01885 cpl_vector_delete(x);
01886 cpl_vector_delete(y);
01887 cpl_vector_delete(ye);
01888 }
01889 else {
01890 cpl_free(dx);
01891 cpl_free(dy);
01892 cpl_free(dye);
01893 }
01894 }
01895 cpl_vector * sigv = cpl_vector_wrap(nmeas, sigs);
01896 cpl_vector * peakv = cpl_vector_wrap(nmeas, peaks);
01897 double medsigma = cpl_vector_get_median(sigv);
01898 double medsigma_err = sqrt(sigs_err) * sqrt(CPL_MATH_PI_2) / nmeas;
01899 double medpeak = cpl_vector_get_median(peakv);
01900 double medpeak_err = sqrt(peaks_err) * sqrt(CPL_MATH_PI_2) / nmeas;
01901 cpl_msg_info(cpl_func, "Median FWHM of spectrum: %g +- %g, Peak %g +- %g",
01902 medsigma, medsigma_err, medpeak, medpeak_err);
01903 cpl_propertylist_append_double(qclist, "ESO QC GAUSSFIT FWHM",
01904 medsigma * 2.355);
01905 cpl_propertylist_set_comment(qclist, "ESO QC GAUSSFIT FWHM", "[pix]");
01906 cpl_propertylist_append_double(qclist, "ESO QC GAUSSFIT FWHM_ERR",
01907 medsigma_err * 2.355);
01908 cpl_propertylist_append_double(qclist, "ESO QC GAUSSFIT PEAK", medpeak);
01909 cpl_propertylist_set_comment(qclist, "ESO QC GAUSSFIT PEAK", "[adu/s]");
01910 cpl_propertylist_append_double(qclist, "ESO QC GAUSSFIT PEAK_ERR",
01911 medpeak_err);
01912 cpl_vector_unwrap(sigv);
01913 cpl_vector_unwrap(peakv);
01914
01915 return cpl_error_get_code();
01916 }
01917
01918
01925
01926 static cpl_error_code
01927 add_qc_background_sigma(const cpl_image * flipped, cpl_propertylist * qclist)
01928 {
01929 cpl_size lly, ury;
01930
01931 if (cpl_image_get_size_y(flipped) > VISIR_AQU_APPROX_WLEN13) {
01932 lly = VISIR_AQU_APPROX_WLEN8;
01933 ury = VISIR_AQU_APPROX_WLEN13;
01934 }
01935 else {
01936 lly = 1;
01937 ury = cpl_image_get_size_y(flipped);
01938 }
01939
01940 cpl_image * cutimg =
01941 cpl_image_extract(flipped, 1, lly, cpl_image_get_size_x(flipped), ury);
01942
01943
01944 double bkgmad, bkgmed;
01945 bkgmed = cpl_image_get_mad(cutimg, &bkgmad);
01946 for (size_t i = 0; i < 3; i++) {
01947 cpl_mask * rej =
01948 cpl_mask_threshold_image_create(cutimg,
01949 bkgmed - bkgmad * CPL_MATH_STD_MAD * 3,
01950 bkgmed + bkgmad * CPL_MATH_STD_MAD * 3);
01951 cpl_mask_not(rej);
01952 cpl_image_reject_from_mask(cutimg, rej);
01953 cpl_mask_delete(rej);
01954 bkgmed = cpl_image_get_mad(cutimg, &bkgmad);
01955 }
01956
01957 cpl_propertylist_append_double(qclist, "ESO QC BACKGD SIGMA",
01958 bkgmad * CPL_MATH_STD_MAD);
01959 cpl_propertylist_set_comment(qclist, "ESO QC BACKGD SIGMA",
01960 "[adu/s] background corrected");
01961 cpl_image_delete(cutimg);
01962
01963 return cpl_error_get_code();
01964 }
01965
01966
01983
01984 static cpl_bivector * visir_spc_extract(cpl_image * flipped,
01985 cpl_propertylist * qclist,
01986 cpl_image ** pweight2d,
01987 int doplot, int bkgcorrect)
01988 {
01989 const int ncol = cpl_image_get_size_x(flipped);
01990 const int npix = cpl_image_get_size_y(flipped);
01991
01992 cpl_bivector * result = NULL;
01993 cpl_vector * spectrum = NULL;
01994 cpl_vector * error = NULL;
01995 cpl_vector * col = NULL;
01996
01997 cpl_image * spatial = NULL;
01998 cpl_image * iweight = NULL;
01999 cpl_vector * row = NULL;
02000 cpl_image * imrow = NULL;
02001
02002 double * pweight = NULL;
02003
02004 cpl_apertures * objects = NULL;
02005 cpl_mask * binary = NULL;
02006 cpl_image * locnoise = NULL;
02007
02008 double xfwhm;
02009 double xcentro;
02010
02011 int i, j;
02012 int is_rejected;
02013
02014 const double sigma = VISIR_SPECTRO_SIGMA;
02015 double sp_median;
02016 double stdev2d, min, max, yfwhm;
02017 double weight_2norm;
02018
02019 cpl_size ifwhm, jfwhm;
02020 int mspix;
02021
02022 int ilnoise, ihnoise;
02023 const int is_echelle = ncol <= 2 * (whechelle + 1);
02024
02025
02026 cpl_ensure(pweight2d != NULL, CPL_ERROR_NULL_INPUT, NULL);
02027
02028 cpl_ensure(sigma > 0.0, CPL_ERROR_UNSUPPORTED_MODE, NULL);
02029
02030 *pweight2d = NULL;
02031
02032 skip_if(add_qc_background_sigma(flipped, qclist));
02033
02034
02035
02036
02037 if (bkgcorrect) {
02038 cpl_image * imean = cpl_image_duplicate(flipped);
02039 for (int h = 0; h < cpl_image_get_size_y(flipped); h++) {
02040 cpl_vector * n = cpl_vector_new_from_image_row(flipped, h+1);
02041 double mean = cpl_vector_get_median(n);
02042 cpl_vector_delete(n);
02043 for (int g = 0; g < cpl_image_get_size_x(flipped); g++) {
02044 cpl_image_set(imean, g+1, h + 1, mean);
02045 }
02046 }
02047 cpl_image_subtract(flipped, imean);
02048 cpl_image_delete(imean);
02049 }
02050
02051 if (!is_echelle) {
02052
02053
02054
02055 cpl_msg_info(cpl_func, "Combined image has mean: %g",
02056 cpl_image_get_mean(flipped));
02057
02058 col = cpl_vector_new(npix);
02059 skip_if (0);
02060
02061
02062 pweight = cpl_image_get_data_double(flipped);
02063 for (j=0; j < npix; j++, pweight += ncol) {
02064 double mean;
02065
02066 imrow = cpl_image_wrap_double(1, ncol, pweight);
02067 skip_if (0);
02068
02069 mean = cpl_image_get_mean(imrow);
02070 skip_if (0);
02071
02072 skip_if (cpl_vector_set(col, j, mean));
02073
02074 skip_if (cpl_image_subtract_scalar(imrow, mean));
02075
02076 (void)cpl_image_unwrap(imrow);
02077 imrow = NULL;
02078
02079 }
02080
02081 if (doplot > 1) visir_vector_plot("set grid;","t 'Estimated Background'"
02082 " w linespoints", "", col);
02083 cpl_vector_delete(col);
02084 col = NULL;
02085 }
02086
02087
02088 stdev2d = visir_img_phot_sigma_clip(flipped)/sqrt(npix);
02089 skip_if (0);
02090
02091 cpl_msg_info(cpl_func, "St.Dev. on noise in 2D-combined image: %g",
02092 stdev2d);
02093
02094
02095 spatial = cpl_image_collapse_create(flipped, 0);
02096 skip_if (0);
02097 skip_if (cpl_image_divide_scalar(spatial, npix));
02098
02099 iweight = cpl_image_duplicate(spatial);
02100
02101
02102 sp_median = cpl_image_get_median(spatial);
02103 binary = cpl_mask_threshold_image_create(spatial, sp_median - sigma * stdev2d,
02104 sp_median + sigma * stdev2d);
02105
02106 if (cpl_mask_count(binary) == ncol) {
02107 (void)cpl_error_set_message(cpl_func, CPL_ERROR_DATA_NOT_FOUND,
02108 "%d spatial weights too noisy. sigma=%g. "
02109 "stdev2d=%g. Spatial median=%g", ncol,
02110 sigma, stdev2d, sp_median);
02111 skip_if (1);
02112 }
02113
02114
02115 bug_if (cpl_image_reject_from_mask(spatial, binary));
02116
02117 bug_if (cpl_image_get_maxpos(spatial, &ifwhm, &jfwhm));
02118
02119 if (doplot > 1) {
02120 visir_image_col_plot("","t 'Most intense column' w linespoints",
02121 "", flipped, ifwhm, ifwhm, 1);
02122 visir_image_row_plot("set grid;", "t 'Combined image with "
02123 "spectral direction collapsed' w linespoints",
02124 "", spatial, 1, 1, 1);
02125 }
02126
02127 max = cpl_image_get(spatial, ifwhm, 1, &is_rejected);
02128 bug_if(is_rejected);
02129 if (max <= 0.0) {
02130 (void)cpl_error_set_message(cpl_func, CPL_ERROR_DATA_NOT_FOUND,
02131 "Cannot compute FWHM on a collapsed "
02132 "spectrum with a non-positive maximum: %g "
02133 "(at i=%d)", max, (int)ifwhm);
02134 skip_if (1);
02135 }
02136
02137 skip_if (cpl_image_get_fwhm(spatial, ifwhm, 1, &xfwhm, &yfwhm));
02138
02139
02140 for (ilnoise = ifwhm; ilnoise > 0 &&
02141 !cpl_image_is_rejected(spatial, ilnoise, 1); ilnoise--);
02142 bug_if (0);
02143 for (ihnoise = ifwhm; ihnoise <= ncol &&
02144 !cpl_image_is_rejected(spatial, ihnoise, 1); ihnoise++);
02145 bug_if (0);
02146
02147 if (!ilnoise) ilnoise = 1;
02148 if (ihnoise > ncol) ihnoise = ncol;
02149
02150 xcentro = cpl_image_get_centroid_x_window(spatial, ilnoise, 1, ihnoise, 1);
02151
02152 cpl_msg_info(cpl_func, "Spatial FWHM(%d:%d:%d:%g): %g", (int)ilnoise,
02153 (int)ifwhm, (int)ihnoise, xcentro, xfwhm);
02154
02155
02156 skip_if (cpl_image_normalise(iweight, CPL_NORM_ABSFLUX));
02157
02158 if (doplot > 1) visir_image_row_plot("set grid;", "t 'Cleaned, normalized "
02159 "combined image with spectral direction"
02160 " averaged' w linespoints", "",
02161 iweight, 1, 1, 1);
02162
02163 weight_2norm = sqrt(cpl_image_get_sqflux(iweight));
02164
02165 cpl_msg_info(cpl_func, "2-norm of weights: %g", weight_2norm);
02166
02167
02168
02169
02170 if (is_echelle) {
02171 int ileft = 5;
02172 int iright = ncol - 5;
02173 cpl_binary * pbin;
02174
02175
02176 if (ileft > xcentro - xfwhm * 2)
02177 ileft = xcentro - xfwhm * 2;
02178 if (iright < xcentro + xfwhm * 2)
02179 iright = xcentro + xfwhm * 2;
02180
02181 cpl_msg_info(cpl_func, "HRG pixels of noise: [1 %d] [%d %d]", ileft,
02182 iright, ncol);
02183
02184 bug_if(cpl_mask_xor(binary, binary));
02185
02186 pbin = cpl_mask_get_data(binary);
02187 bug_if (0);
02188
02189 for (i = 0; i < ncol; i++) pbin[i] = CPL_BINARY_0;
02190 for (i = 0; i < ileft; i++) pbin[i] = CPL_BINARY_1;
02191 for (i = iright; i < ncol; i++) pbin[i] = CPL_BINARY_1;
02192
02193 }
02194 skip_if (0);
02195
02196 mspix = cpl_mask_count(binary);
02197 cpl_msg_info(cpl_func, "Pixels of noise(%g +/- %g*%g): %d",
02198 sp_median, stdev2d, sigma, mspix);
02199 skip_if (0);
02200
02201 if (mspix < 2) {
02202
02203 cpl_msg_error(cpl_func, "Cannot estimate spectrum noise with just %d "
02204 "pixels of noise", mspix);
02205 visir_error_set(CPL_ERROR_DATA_NOT_FOUND);
02206 skip_if (1);
02207 }
02208
02209 locnoise = cpl_image_new_from_mask(binary);
02210 cpl_mask_delete(binary);
02211 binary = NULL;
02212
02213 skip_if (0);
02214
02215 error = cpl_vector_new(npix);
02216 skip_if (0);
02217
02218
02219
02220 for (j=0; j < npix; j++) {
02221
02222 double npp, stdev1d;
02223
02224
02225 imrow = cpl_image_extract(flipped, 1, j+1, ncol, j+1);
02226
02227 skip_if (0);
02228
02229 objects = cpl_apertures_new_from_image(imrow, locnoise);
02230 cpl_image_delete(imrow);
02231 imrow = NULL;
02232
02233 skip_if (0);
02234
02235 stdev1d = cpl_apertures_get_stdev(objects, 1);
02236 cpl_apertures_delete(objects);
02237 objects = NULL;
02238
02239
02240
02241
02242
02243
02244 npp = weight_2norm * stdev1d;
02245
02246 skip_if (cpl_vector_set(error, j, npp));
02247 }
02248
02249
02250
02251
02252
02253 for (i=1; i <= ncol; i++) {
02254 const double weight = cpl_image_get(iweight, i, 1, &is_rejected);
02255
02256 skip_if (0);
02257 if (is_rejected) {
02258
02259 visir_error_set(CPL_ERROR_DATA_NOT_FOUND);
02260 skip_if (1);
02261 }
02262
02263
02264 if (weight == 0) continue;
02265
02266 col = cpl_vector_new_from_image_column(flipped, i);
02267 skip_if (0);
02268
02269 skip_if (cpl_vector_multiply_scalar(col, weight));
02270
02271 if (spectrum == NULL) {
02272 spectrum = col;
02273 } else {
02274 skip_if (cpl_vector_add(spectrum, col));
02275 cpl_vector_delete(col);
02276 }
02277 col = NULL;
02278 }
02279
02280 fit_gaussians(flipped, error, ifwhm - 20, ifwhm + 20, qclist);
02281
02282
02283
02284 min = cpl_vector_get_min(spectrum);
02285 if (min <0) cpl_msg_warning(cpl_func, "Extracted spectrum has negative "
02286 "intensity: %g", min);
02287
02288
02289
02290
02291 *pweight2d = cpl_image_new(ncol, npix, CPL_TYPE_DOUBLE);
02292
02293 for (j=1; j <= npix; j++)
02294 skip_if (cpl_image_copy(*pweight2d, iweight, 1, j));
02295
02296 if (doplot > 0) visir_image_plot("", "t 'The weight map'", "", *pweight2d);
02297
02298 bug_if(visir_spectro_qclist_obs(qclist, xfwhm, xcentro));
02299
02300 end_skip;
02301
02302 cpl_image_delete(locnoise);
02303 cpl_mask_delete(binary);
02304 cpl_image_delete(spatial);
02305 cpl_apertures_delete(objects);
02306 cpl_vector_delete(col);
02307 cpl_vector_delete(row);
02308 cpl_image_delete(imrow);
02309 cpl_image_delete(iweight);
02310
02311 if (cpl_error_get_code()) {
02312 cpl_vector_delete(spectrum);
02313 cpl_vector_delete(error);
02314 } else {
02315
02316 result = cpl_bivector_wrap_vectors(spectrum, error);
02317
02318 if (doplot > 2) visir_bivector_plot("", "t 'error versus spectrum'",
02319 "", result);
02320 }
02321
02322 return result;
02323 }
02324
02325
02347
02348 static cpl_error_code visir_spectro_fill(cpl_vector * self,
02349 const cpl_polynomial * disp,
02350 irplib_base_spectrum_model * model)
02351 {
02352
02353 visir_spectrum_model * mymodel = (visir_spectrum_model*)model;
02354 const cpl_size npix = cpl_vector_get_size(self);
02355
02356 cpl_ensure_code(self, CPL_ERROR_NULL_INPUT);
02357 cpl_ensure_code(model, CPL_ERROR_NULL_INPUT);
02358 cpl_ensure_code(disp, CPL_ERROR_NULL_INPUT);
02359
02360 cpl_vector * wavelength = cpl_vector_new(npix);
02361 cpl_bivector * emission = cpl_bivector_wrap_vectors(wavelength, self);
02362 cpl_vector * boundary = cpl_vector_new(npix + 1);
02363
02364
02365
02366 skip_if (cpl_vector_fill_polynomial(cpl_bivector_get_x(emission),
02367 disp, 1, 1));
02368 skip_if (cpl_vector_fill_polynomial(boundary, disp, 0.5, 1));
02369
02370
02371 skip_if (visir_spc_emission(emission, boundary, mymodel->lines,
02372 mymodel->tqeff, mymodel->vsymm,
02373 mymodel->temp));
02374 end_skip;
02375
02376 cpl_bivector_unwrap_vectors(emission);
02377 cpl_vector_delete(wavelength);
02378 cpl_vector_delete(boundary);
02379
02380 return cpl_error_get_code();
02381 }
02382
02383
02384
02385
02400
02401 static cpl_error_code visir_spectro_refine(cpl_polynomial * self,
02402 const cpl_vector * xc_vector,
02403 visir_spectrum_model * pmymodel,
02404 const cpl_polynomial * phdisp,
02405 int hsize, cpl_boolean doplot,
02406 visir_spc_resol resol,
02407 double * pxc,
02408 cpl_boolean * pdidshift,
02409 double * pdelta)
02410 {
02411 const int subres = VISIR_XC_SUBSEARCH;
02412 cpl_polynomial * shifted = NULL;
02413 #ifdef VISIR_SPC_CAL_HIGH
02414 const int fitdeg = 2;
02415 double pixstep = 0.5;
02416 double pixtol = 1e-5;
02417 const int maxite = fitdeg * 200;
02418 int maxfail = 3;
02419 int maxcont = 3;
02420 const int clines = (int)(cpl_bivector_get_size(pmymodel->lines) *
02421 cpl_vector_get_size(xc_vector));
02422 cpl_errorstate prestate = cpl_errorstate_get();
02423 #endif
02424
02425 cpl_ensure_code(self, CPL_ERROR_NULL_INPUT);
02426 cpl_ensure_code(xc_vector, CPL_ERROR_NULL_INPUT);
02427 cpl_ensure_code(pmymodel, CPL_ERROR_NULL_INPUT);
02428 cpl_ensure_code(phdisp, CPL_ERROR_NULL_INPUT);
02429 cpl_ensure_code(pxc, CPL_ERROR_NULL_INPUT);
02430 cpl_ensure_code(pdidshift, CPL_ERROR_NULL_INPUT);
02431 cpl_ensure_code(pdelta, CPL_ERROR_NULL_INPUT);
02432
02433 skip_if(cpl_polynomial_copy(self, phdisp));
02434
02435 #ifdef VISIR_SPC_CAL_HIGH
02436 if (irplib_polynomial_find_1d_from_correlation_all
02437 (self, fitdeg, xc_vector, 1, clines,
02438 (irplib_base_spectrum_model*)pmymodel,
02439 visir_spectro_fill, pixtol, pixstep,
02440 hsize, maxite, maxfail, maxcont, doplot, pxc) || *pxc <= 0.0) {
02441
02442 irplib_error_recover(prestate, "Could not optimize %d "
02443 "coefficients, trying shifting", fitdeg);
02444 skip_if(cpl_polynomial_copy(self, phdisp));
02445
02446 skip_if(visir_polynomial_shift_1d_from_correlation
02447 (self, xc_vector, (irplib_base_spectrum_model*) pmymodel,
02448 visir_spectro_fill, hsize, subres, doplot, pxc, pdelta));
02449 *pdidshift = CPL_TRUE;
02450
02451
02452 shifted = cpl_polynomial_duplicate(self);
02453
02454 if (irplib_polynomial_find_1d_from_correlation_all
02455 (self, fitdeg, xc_vector, 1, clines,
02456 (irplib_base_spectrum_model*)pmymodel,
02457 visir_spectro_fill, pixtol, pixstep,
02458 hsize, maxite, maxfail, maxcont, doplot, pxc) || *pxc <= 0.0) {
02459
02460 irplib_error_recover(prestate, "Could not re-optimize %d "
02461 "coefficients, keeping shifted", fitdeg);
02462 skip_if(cpl_polynomial_copy(self, shifted));
02463 }
02464 }
02465
02466 #else
02467 cpl_size clow = 0, chigh = 0;
02468
02469 if (resol == VISIR_SPC_R_LRP) {
02470 clow = 155;
02471 chigh = 155;
02472 }
02473 cpl_vector * xc_vector_cut = cpl_vector_extract(xc_vector, clow,
02474 cpl_vector_get_size(xc_vector)
02475 - chigh - 1, 1);
02476 cpl_polynomial_shift_1d(self, 0, clow);
02477 skip_if(visir_polynomial_shift_1d_from_correlation
02478 (self, xc_vector_cut, (irplib_base_spectrum_model*) pmymodel,
02479 visir_spectro_fill, hsize, subres, doplot, pxc, pdelta));
02480 cpl_polynomial_shift_1d(self, 0, -clow);
02481 cpl_vector_delete(xc_vector_cut);
02482 *pdidshift = CPL_TRUE;
02483 #endif
02484
02485 error_if (*pxc <= 0.0, CPL_ERROR_DATA_NOT_FOUND, "Atmospheric and Model "
02486 "Spectra have non-positive cross-correlation (%g pixel shift): "
02487 "%g", *pdelta, *pxc);
02488
02489 end_skip;
02490
02491 cpl_polynomial_delete(shifted);
02492
02493 return cpl_error_get_code();
02494
02495 }
02496
02497
02520
02521 static cpl_error_code
02522 visir_polynomial_shift_1d_from_correlation(cpl_polynomial * self,
02523 const cpl_vector * obs,
02524 irplib_base_spectrum_model * model,
02525 cpl_error_code (*filler)
02526 (cpl_vector *,
02527 const cpl_polynomial *,
02528 irplib_base_spectrum_model *),
02529 int hsize,
02530 int subres,
02531 cpl_boolean doplot,
02532 double * pxc, double *pshift)
02533 {
02534 const int nobs = cpl_vector_get_size(obs);
02535 cpl_polynomial * cand = NULL;
02536 cpl_bivector * xcplot = NULL;
02537 double * xcplotx = NULL;
02538 double * xcploty = NULL;
02539 cpl_vector * mspec1d = NULL;
02540 cpl_vector * vxc;
02541 double bestxc = -1.0;
02542 double bestdelta = -1.0;
02543 int bestxxc = -1;
02544 int i;
02545
02546 cpl_ensure_code(self != NULL, CPL_ERROR_NULL_INPUT);
02547 cpl_ensure_code(obs != NULL, CPL_ERROR_NULL_INPUT);
02548 cpl_ensure_code(model != NULL, CPL_ERROR_NULL_INPUT);
02549 cpl_ensure_code(filler != NULL, CPL_ERROR_NULL_INPUT);
02550 cpl_ensure_code(subres > 0, CPL_ERROR_ILLEGAL_INPUT);
02551 cpl_ensure_code(hsize > 0, CPL_ERROR_ILLEGAL_INPUT);
02552
02553 cand = cpl_polynomial_new(1);
02554 mspec1d = cpl_vector_new(2 * hsize + nobs);
02555 vxc = cpl_vector_new(2 * hsize + 1);
02556 if (doplot) {
02557 xcplot = cpl_bivector_new(subres * (2 * hsize + 1));
02558 xcplotx = cpl_bivector_get_x_data(xcplot);
02559 xcploty = cpl_bivector_get_y_data(xcplot);
02560 }
02561
02562
02563 for (i = 0; i < subres; i++) {
02564 const double delta = i / (double)subres;
02565 double xc;
02566 int ixc;
02567
02568 bug_if (cpl_polynomial_copy(cand, self));
02569 bug_if (cpl_polynomial_shift_1d(cand, 0, delta - hsize));
02570
02571 skip_if (filler(mspec1d, cand, model));
02572
02573 ixc = cpl_vector_correlate(vxc, mspec1d, obs);
02574 xc = cpl_vector_get(vxc, ixc);
02575
02576 if (xc > bestxc) {
02577 bestxc = xc;
02578 bestxxc = ixc - hsize;
02579 bestdelta = delta + bestxxc;
02580 cpl_msg_debug(cpl_func, "Shifting %g = %d + %g pixels (XC=%g)",
02581 bestdelta, bestxxc, delta, bestxc);
02582 }
02583 if (doplot) {
02584 int j;
02585 for (j = 0; j <= 2 * hsize; j++) {
02586 const double xcj = cpl_vector_get(vxc, j);
02587 xcplotx[i + j * subres] = (double)(j - hsize) + delta;
02588 xcploty[i + j * subres] = xcj;
02589 }
02590 }
02591 }
02592
02593 #ifdef IRPLIB_SPC_DUMP
02594
02595 irplib_polynomial_dump_corr_step(self, vxc, "Shift");
02596 #endif
02597
02598 skip_if(cpl_polynomial_shift_1d(self, 0, bestdelta));
02599
02600
02601 cpl_vector_set_size(vxc, 1);
02602 cpl_vector_set_size(mspec1d, nobs);
02603 skip_if (filler(mspec1d, self, model));
02604 bug_if(cpl_vector_correlate(vxc, mspec1d, obs));
02605
02606 if (doplot) {
02607 char * title = cpl_sprintf("t 'Cross-correlation of %d-pixel spectrum "
02608 "(max=%.4g at %g pixel)' w points", nobs,
02609 cpl_vector_get(vxc, 0), bestdelta);
02610
02611 cpl_plot_bivector("set grid;set xlabel 'Offset [pixel]';set ylabel "
02612 "'Cross-correlation';", title, "", xcplot);
02613 cpl_free(title);
02614
02615 irplib_plot_spectrum_and_model(obs, self, model, filler);
02616 }
02617
02618 cpl_msg_info(cpl_func, "Shifting %g = %d + %g pixels (XC: %g <=> %g)",
02619 bestdelta, bestxxc, bestdelta - (double)bestxxc,
02620 cpl_vector_get(vxc, 0), bestxc);
02621
02622 if (pxc != NULL) *pxc = cpl_vector_get(vxc, 0);
02623 if (pshift != NULL) *pshift = bestdelta;
02624
02625 end_skip;
02626
02627 cpl_vector_delete(mspec1d);
02628 cpl_polynomial_delete(cand);
02629 cpl_vector_delete(vxc);
02630 cpl_bivector_delete(xcplot);
02631
02632 return cpl_error_get_code();
02633
02634 }
02635
02636
02641
02642 static cpl_polynomial * visir_spc_phys_lrp(void)
02643 {
02644 const double xval[] = {161, 307, 336, 449, 491, 518, 623, 760, 795, 839};
02645 const double yval[] = {8.22e-6, 9.50e-06, 9.660e-06, 10.5e-06, 10.82e-6,
02646 11.e-06, 11.7e-06, 12.54e-06, 12.76e-06,
02647 13.02e-06 };
02648
02649 const cpl_size maxdeg1d = 2;
02650
02651 cpl_polynomial * self = cpl_polynomial_new(1);
02652 const cpl_boolean sampsym = CPL_FALSE;
02653 const size_t nvals = sizeof(xval)/sizeof(*xval);
02654
02655 IRPLIB_DIAG_PRAGMA_PUSH_IGN(-Wcast-qual)
02656 cpl_matrix * xmatrix = cpl_matrix_wrap(1, nvals, (double*)xval);
02657 cpl_vector * yvector = cpl_vector_wrap(nvals, (double*)yval);
02658 IRPLIB_DIAG_PRAGMA_POP;
02659 cpl_vector * fitres = cpl_vector_new(nvals);
02660
02661 const cpl_error_code error = cpl_polynomial_fit(self, xmatrix, &sampsym,
02662 yvector, NULL,
02663 CPL_FALSE, NULL, &maxdeg1d)
02664 || cpl_vector_fill_polynomial_fit_residual(fitres, yvector, NULL, self,
02665 xmatrix, NULL);
02666
02667 const double mse = cpl_vector_product(fitres, fitres) / (double)nvals;
02668
02669 (void)cpl_matrix_unwrap(xmatrix);
02670 (void)cpl_vector_unwrap(yvector);
02671 cpl_vector_delete(fitres);
02672
02673 if (error) {
02674 cpl_error_set_where(cpl_func);
02675 cpl_polynomial_delete(self);
02676 self = NULL;
02677 } else {
02678 cpl_msg_info(cpl_func, "Fitted %d degree 1D-polynomial to %u "
02679 "wavelengths with a root mean square error [m]: %g",
02680 (int)maxdeg1d, (unsigned)nvals, sqrt(mse));
02681 }
02682
02683 return self;
02684 }
02685
02686
02693
02694 static double visir_spc_get_dispersion(const cpl_polynomial * self, double xval)
02695 {
02696
02697 cpl_errorstate prestate = cpl_errorstate_get();
02698 double disp;
02699
02700 (void)cpl_polynomial_eval_1d(self, xval, &disp);
02701
02702 if (!cpl_errorstate_is_equal(prestate)) {
02703 (void)cpl_error_set_where(cpl_func);
02704 }
02705
02706 return disp;
02707 }