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 #ifdef HAVE_CONFIG_H
00028 #include <config.h>
00029 #endif
00030
00031
00032
00033 #include <xsh_utils_table.h>
00034 #include <xsh_utils.h>
00035 #include <xsh_error.h>
00036 #include <xsh_pfits.h>
00037 #include <xsh_msg.h>
00038 #include <xsh_data_resid_tab.h>
00039 #include <xsh_data_arclist.h>
00040 #include <math.h>
00041
00042 #define LINETAB_PIXELSIZE "Pixel"
00043 #define TWOSQRT2LN2 2.35482004503095
00044
00045
00046
00047
00048
00049
00057
00058
00063
00079
00080 static int
00081 xsh_wavecal_find_nearest(const cpl_table *line_refer, const char* col_ref,double lambda, int lo, int hi)
00082 {
00083
00084 if (lo == hi)
00085 {
00086 return lo;
00087 }
00088 else if (lo + 1 == hi)
00089 {
00090 double llo, lhi;
00091 check(lhi = cpl_table_get_double(line_refer, col_ref, hi, NULL));
00092 check(llo = cpl_table_get_double(line_refer, col_ref, lo, NULL));
00093
00094
00095 return ((llo-lambda)*(llo-lambda) < (lhi-lambda)*(lhi-lambda)) ? lo : hi;
00096 }
00097 else
00098 {
00099 double lmid;
00100 int mid = (lo + hi)/2;
00101
00102
00103 check(lmid = cpl_table_get_double(line_refer, col_ref, mid, NULL));
00104
00105 if (lmid < lambda)
00106 {
00107 return xsh_wavecal_find_nearest(line_refer, col_ref, lambda, mid, hi);
00108 }
00109 else
00110 {
00111 return xsh_wavecal_find_nearest(line_refer, col_ref, lambda, lo, mid);
00112 }
00113 }
00114
00115 cleanup:
00116 return -1;
00117 }
00118
00119
00126 static cpl_error_code
00127 xsh_wavecal_qclog_compute(cpl_table* temp,
00128 cpl_propertylist** header_check,
00129 const char* element)
00130
00131 {
00132 char qc_intavg_name[40];
00133 char qc_nlinint_name[40];
00134 char comment[40];
00135
00136 double mean;
00137 int nrows=cpl_table_get_nrow(temp);
00138 if (nrows == 0)
00139 {
00140 xsh_msg_warning("No bright lines found!");
00141 mean = 0;
00142 }
00143 else
00144 {
00145 mean = cpl_table_get_column_mean(temp, "Intensity");
00146 }
00147
00148 sprintf(qc_intavg_name,"%s %s",QC_WAVECAL_INTAVG,element);
00149 sprintf(comment,QC_WAVECAL_INTAVG_C);
00150 check(cpl_propertylist_append_double(*header_check,qc_intavg_name,mean));
00151 check(cpl_propertylist_set_comment(*header_check,qc_intavg_name,comment));
00152
00153 sprintf(qc_nlinint_name,"%s %s",QC_WAVECAL_NLININT,element);
00154 sprintf(comment,QC_WAVECAL_NLININT_C);
00155 check(cpl_propertylist_append_int(*header_check,qc_nlinint_name,nrows));
00156 check(cpl_propertylist_set_comment(*header_check,qc_nlinint_name,comment));
00157
00158 cleanup:
00159 return cpl_error_get_code();
00160
00161 }
00162
00170 static cpl_table*
00171 xsh_table_select_matching_waves(cpl_table* table_intmon,
00172 const char* col_wave_intmon,
00173 cpl_table* table_check,
00174 const char* col_wave_intcheck,
00175 const double exptime)
00176
00177 {
00178
00179
00180 double tolerance = 0.001;
00181
00182
00183
00184
00185
00186
00187 int N_bright = cpl_table_get_nrow(table_intmon);
00188
00189 int i=0;
00190 double wmin=cpl_table_get_column_min(table_intmon,"WAVELENGTH");
00191 double wmax=cpl_table_get_column_max(table_intmon,"WAVELENGTH");
00192 check(cpl_table_and_selected_double(table_check,"Wavelength",CPL_LESS_THAN,wmax+tolerance));
00193 check(cpl_table_and_selected_double(table_check,"Wavelength",CPL_GREATER_THAN,wmin-tolerance));
00194
00195 cpl_table* table_ext=cpl_table_extract_selected(table_check);
00196
00197 check(cpl_table_new_column(table_ext, "Intensity", CPL_TYPE_DOUBLE));
00198 for (i = 0; i < cpl_table_get_nrow(table_ext); i++)
00199 {
00200 int is_null=0;
00201 double ident=0;
00202 check(ident=cpl_table_get_double(table_ext, "Wavelength", i, &is_null));
00203
00204 if (!is_null)
00205 {
00206 int bright_index = 0;
00207 check(bright_index=xsh_wavecal_find_nearest(table_intmon, "WAVELENGTH",
00208 ident, 0, N_bright-1));
00209
00210
00211 double bright = 0;
00212 check(bright=cpl_table_get_double(table_intmon, "WAVELENGTH", bright_index, NULL));
00213
00214 if (fabs(bright - ident) < tolerance)
00215 {
00216
00217
00218
00219
00220
00221
00222
00223
00224
00225
00226
00227 double norm=0;
00228 check(norm=cpl_table_get_double(table_ext, "NormGauss", i, NULL));
00229
00230
00231
00232 double intensity=norm/exptime;
00233
00234
00235 check(cpl_table_set_double(table_ext, "Intensity", i, intensity));
00236
00237 }
00238 else
00239 {
00240 check(cpl_table_set_invalid(table_ext, "Intensity", i));
00241 }
00242 }
00243 else
00244 {
00245 check(cpl_table_set_invalid(table_ext, "Intensity", i));
00246 }
00247 }
00248
00249 cleanup:
00250 return table_ext;
00251 }
00252
00253
00254
00263 static cpl_error_code
00264 xsh_wavecal_qclog_element(cpl_table* table_intmon,
00265 cpl_table *table_check,
00266 const double exptime,
00267 const char* atom_name,
00268 cpl_propertylist** header_check)
00269 {
00270 cpl_table *ext_intmon = NULL;
00271 cpl_table* table_ext=NULL;
00272 cpl_table *temp = NULL;
00273
00274 cpl_table_and_selected_string(table_intmon,"element",CPL_EQUAL_TO,atom_name);
00275 ext_intmon=cpl_table_extract_selected(table_intmon);
00276
00277 check(table_ext=xsh_table_select_matching_waves(ext_intmon,
00278 "WAVELENGTH",
00279 table_check,
00280 "Wavelength",exptime));
00281 xsh_free_table(&temp);
00282 temp = cpl_table_duplicate(table_ext);
00283 cpl_table_erase_invalid(temp);
00284 check(xsh_wavecal_qclog_compute(temp,header_check,atom_name));
00285 cpl_table_select_all(table_intmon);
00286
00287 cleanup:
00288 xsh_free_table(&temp);
00289 xsh_free_table(&ext_intmon);
00290 xsh_free_table(&table_ext);
00291 return cpl_error_get_code();
00292
00293 }
00294
00302 cpl_error_code
00303 xsh_wavecal_qclog_intmon(cpl_frame* line_check,
00304 const cpl_frame *line_intmon,
00305 const double exptime,
00306 xsh_instrument* inst)
00307 {
00308 cpl_table *temp = NULL;
00309 cpl_table *table_check = NULL;
00310 cpl_table *table_intmon = NULL;
00311 const char* name_check=NULL;
00312 const char* name_intmon=NULL;
00313 cpl_propertylist* header_check=NULL;
00314 cpl_table* table_ext=NULL;
00315
00316 check(name_check=cpl_frame_get_filename(line_check));
00317 check(table_check=cpl_table_load(name_check,1,0));
00318 check(header_check=cpl_propertylist_load(name_check,0));
00319
00320 check(name_intmon=cpl_frame_get_filename(line_intmon));
00321 check(table_intmon=cpl_table_load(name_intmon,1,0));
00322
00323 if( xsh_instrument_get_arm(inst) == XSH_ARM_NIR) {
00324
00325 check(xsh_wavecal_qclog_element(table_intmon,table_check,exptime,
00326 "AR",&header_check));
00327
00328 check(xsh_wavecal_qclog_element(table_intmon,table_check,exptime,
00329 "NE",&header_check));
00330
00331 check(xsh_wavecal_qclog_element(table_intmon,table_check,exptime,
00332 "XE",&header_check));
00333
00334 } else {
00335
00336 check(xsh_wavecal_qclog_element(table_intmon,table_check,exptime,
00337 "THAR",&header_check));
00338
00339 }
00340 check(cpl_table_save(table_check,header_check,NULL,name_check,CPL_IO_DEFAULT));
00341
00342 cleanup:
00343 xsh_free_table(&temp);
00344 xsh_free_propertylist(&header_check);
00345 xsh_free_table(&table_check);
00346 xsh_free_table(&table_ext);
00347 xsh_free_table(&table_intmon);
00348
00349 return cpl_error_get_code();
00350 }
00351
00352
00353
00365
00366 cpl_error_code xsh_get_table_value (const cpl_table* table,
00367 const char *colname, cpl_type coltype, int i, void* result)
00368 {
00369 int flag = 0;
00370
00371 XSH_ASSURE_NOT_NULL( table);
00372 XSH_ASSURE_NOT_NULL( colname);
00373 XSH_ASSURE_NOT_NULL( result);
00374
00375
00376
00377 switch (coltype) {
00378 case CPL_TYPE_INT:
00379 check_msg (*((int *) result) = cpl_table_get_int(table,colname,i,&flag),
00380 "Could not get (integer) value of %s at row %d", colname,i);
00381 break;
00382 case CPL_TYPE_FLOAT:
00383 check_msg (*((float *) result) = cpl_table_get_float( table,
00384 colname,i,&flag),
00385 "Could not get (float) value of %s at row %d",colname,i);
00386 break;
00387 case CPL_TYPE_DOUBLE:
00388 check_msg (*((double *) result) = cpl_table_get_double (table,
00389 colname,i,&flag),
00390 "Could not get (double) value of %s at row %d",colname,i);
00391 break;
00392 case CPL_TYPE_STRING:
00393 check_msg (*((const char **) result) =
00394 cpl_table_get_string (table, colname,i),
00395 "Could not get (string) value of %s at row %d",colname,i);
00396 break;
00397 default:
00398 assure (false, CPL_ERROR_INVALID_TYPE, "Unknown type");
00399 }
00400
00401 cleanup:
00402 return cpl_error_get_code ();
00403 }
00404
00405 XSH_TABLE_GET_ARRAY(int)
00406 XSH_TABLE_GET_ARRAY(float)
00407 XSH_TABLE_GET_ARRAY(double)
00408
00409
00422
00423 cpl_error_code
00424 xsh_sort_table_1(cpl_table *t, const char *column, cpl_boolean reverse)
00425 {
00426 cpl_propertylist *plist = NULL;
00427
00428 assure(t != NULL, CPL_ERROR_NULL_INPUT, "Null table");
00429 assure(cpl_table_has_column(t, column), CPL_ERROR_ILLEGAL_INPUT,
00430 "No column '%s'", column);
00431
00432 check_msg(( plist = cpl_propertylist_new(),
00433 cpl_propertylist_append_bool(plist, column, reverse)),
00434 "Could not create property list for sorting");
00435
00436 check_msg( cpl_table_sort(t, plist), "Could not sort table");
00437
00438 cleanup:
00439 xsh_free_propertylist(&plist);
00440 return cpl_error_get_code();
00441 }
00442
00443
00460
00461 cpl_error_code
00462 xsh_sort_table_2(cpl_table *t, const char *column1, const char *column2,
00463 cpl_boolean reverse1, cpl_boolean reverse2)
00464 {
00465 cpl_propertylist *plist = NULL;
00466
00467 assure(t != NULL, CPL_ERROR_NULL_INPUT, "Null table");
00468 assure(cpl_table_has_column(t, column1), CPL_ERROR_ILLEGAL_INPUT,
00469 "No column '%s'", column1);
00470 assure(cpl_table_has_column(t, column2), CPL_ERROR_ILLEGAL_INPUT,
00471 "No column '%s'", column2);
00472
00473 check_msg(( plist = cpl_propertylist_new(),
00474 cpl_propertylist_append_bool(plist, column1, reverse1),
00475 cpl_propertylist_append_bool(plist, column2, reverse2)),
00476 "Could not create property list for sorting");
00477 check_msg( cpl_table_sort(t, plist), "Could not sort table");
00478
00479 cleanup:
00480 xsh_free_propertylist(&plist);
00481 return cpl_error_get_code();
00482 }
00483
00484
00493
00494 double
00495 xsh_data_interpolate(
00496 double wav,
00497 int nrow,
00498 double* pw,
00499 double* pe
00500 )
00501 {
00502 double y = 0;
00503 double w1=pw[0];
00504 double w2=pw[nrow-1];
00505 double y1_=pe[0];
00506 double y2=pe[nrow-1];
00507 if(wav < pw[0])
00508 {
00509 w1=pw[0];
00510 w2=pw[1];
00511 y1_=pe[0];
00512 y2=pe[1];
00513 }
00514 else if (wav > pw[nrow - 1])
00515 {
00516 w1=pw[nrow - 2];
00517 w2=pw[nrow - 1];
00518 y1_=pe[nrow - 2];
00519 y2=pe[nrow - 1];
00520 }
00521 else
00522 {
00523 int l = 0;
00524 int h = nrow - 1;
00525 int curr_row = 0;
00526 curr_row = (h-l) / 2;
00527 while( h-l >1 )
00528 {
00529 if(wav < pw[curr_row])
00530 {
00531 h = curr_row;
00532 }
00533 else
00534 {
00535 l = curr_row;
00536 }
00537 curr_row = (h-l) / 2 + l;
00538 }
00539 w1=pw[curr_row];
00540 w2=pw[curr_row + 1];
00541 y1_=pe[curr_row];
00542 y2=pe[curr_row + 1];
00543 }
00544 y=y1_+(y2-y1_)/(w2-w1)*(wav-w1);
00545 return y;
00546 }
00547
00548
00559
00560 double
00561 xsh_table_interpolate(cpl_table* tbl,
00562 double wav,
00563 const char* colx,
00564 const char* coly)
00565 {
00566
00567 double y=0;
00568 double* pe=NULL;
00569 double* pw=NULL;
00570 int nrow=0;
00571
00572 check(pw=cpl_table_get_data_double(tbl,colx));
00573 check(pe=cpl_table_get_data_double(tbl,coly));
00574 check(nrow=cpl_table_get_nrow(tbl));
00575
00576 y = xsh_data_interpolate(wav, nrow, pw, pe);
00577 cleanup:
00578 return y;
00579
00580 }
00581
00592 static cpl_error_code
00593 xsh_table_monitor_flux_qc(cpl_table* table,
00594 const double ws,
00595 const double we,
00596 const char* prefix,
00597 const int index,
00598 cpl_propertylist** header)
00599 {
00600
00601 double flux=0;
00602 cpl_table* ext=NULL;
00603 char comment[40];
00604 char qc_key[20];
00605 int next=0;
00606
00607 check(cpl_table_and_selected_double(table,"W",CPL_GREATER_THAN,ws));
00608 check(next=cpl_table_and_selected_double(table,"W",CPL_LESS_THAN,we));
00609 if(next>0) {
00610 check(ext=cpl_table_extract_selected(table));
00611 check(cpl_table_select_all(table));
00612 if(cpl_table_has_valid(ext,"F")) {
00613 check(flux=cpl_table_get_column_mean(ext,"F"));
00614 } else {
00615 flux=-999;
00616 }
00617 sprintf(qc_key,"ESO QC %s%d",prefix,index);
00618 sprintf(comment,"Mean value of %s in %4.0f-%4.0f nm",prefix,ws,we);
00619 check(cpl_propertylist_append_double(*header,qc_key,flux));
00620 check(cpl_propertylist_set_comment(*header,qc_key,comment));
00621 }
00622
00623
00624 cleanup:
00625 xsh_free_table(&ext);
00626
00627 return cpl_error_get_code();
00628
00629 }
00630
00631
00632
00633
00634
00644 static cpl_propertylist*
00645 xsh_frame_table_monitor_flux_qc_ext(cpl_table* table,
00646 const char* colw,
00647 const char* colf,
00648 const char* prefix,
00649 xsh_instrument* instrument)
00650 {
00651 cpl_propertylist* header=NULL;
00652
00653 XSH_ASSURE_NOT_NULL_MSG(table,"Null input table");
00654 header=cpl_propertylist_new();
00655 check(cpl_table_cast_column(table,colw,"W",CPL_TYPE_DOUBLE));
00656 check(cpl_table_cast_column(table,colf,"F",CPL_TYPE_DOUBLE));
00657
00658 if ( xsh_instrument_get_arm(instrument) == XSH_ARM_UVB){
00659
00660 check( xsh_table_monitor_flux_qc(table,450,470,prefix,1,&header));
00661 check( xsh_table_monitor_flux_qc(table,510,530,prefix,2,&header));
00662
00663 }
00664 else if ( xsh_instrument_get_arm(instrument) == XSH_ARM_VIS){
00665
00666 check( xsh_table_monitor_flux_qc(table,672,680,prefix,1,&header));
00667 check( xsh_table_monitor_flux_qc(table,745,756,prefix,2,&header));
00668 check( xsh_table_monitor_flux_qc(table,992,999,prefix,3,&header));
00669
00670 }
00671 else if ( xsh_instrument_get_arm(instrument) == XSH_ARM_NIR){
00672
00673 check( xsh_table_monitor_flux_qc(table,1514,1548,prefix,1,&header));
00674 check( xsh_table_monitor_flux_qc(table,2214,2243,prefix,2,&header));
00675
00676 }
00677
00678 cpl_table_erase_column(table,"W");
00679 cpl_table_erase_column(table,"F");
00680
00681 cleanup:
00682 if(cpl_error_get_code() != CPL_ERROR_NONE) {
00683 return NULL;
00684 } else {
00685 return header;
00686 }
00687 }
00688
00689
00690
00700
00701 cpl_error_code
00702 xsh_frame_table_monitor_flux_qc(cpl_frame* frm,
00703 const char* colw,
00704 const char* colf,
00705 const char* prefix,
00706 xsh_instrument* instrument)
00707 {
00708
00709 const char* name=NULL;
00710 cpl_table* table=NULL;
00711 cpl_propertylist* header=NULL;
00712 cpl_propertylist* qc_header=NULL;
00713
00714 int next=0;
00715 int ext=0;
00716
00717 XSH_ASSURE_NOT_NULL_MSG(frm,"Null input spectrum frame");
00718 next=cpl_frame_get_nextensions(frm);
00719 name=cpl_frame_get_filename(frm);
00720
00721
00722
00723 if (next) {
00724 for(ext=1;ext<=next;ext++) {
00725
00726 table=cpl_table_load(name,1,ext);
00727 check(header=cpl_propertylist_load(name,0));
00728 check(qc_header=xsh_frame_table_monitor_flux_qc_ext(table,colw,colf,
00729 prefix,instrument));
00730 cpl_propertylist_append(header,qc_header);
00731 if(next==1) {
00732 check(cpl_table_save(table,header,NULL,name,CPL_IO_DEFAULT));
00733 } else {
00734 check(cpl_table_save(table,header,NULL,name,CPL_IO_EXTEND));
00735 }
00736 xsh_free_table(&table);
00737 xsh_free_propertylist(&qc_header);
00738 xsh_free_propertylist(&header);
00739 }
00740 } else {
00741 table=cpl_table_load(name,1,0);
00742 check(header=cpl_propertylist_load(name,0));
00743 check(qc_header=xsh_frame_table_monitor_flux_qc_ext(table,colw,colf,
00744 prefix,instrument));
00745 cpl_propertylist_append(header,qc_header);
00746 check(cpl_table_save(table,header,NULL,name,CPL_IO_DEFAULT));
00747 xsh_free_propertylist(&qc_header);
00748 xsh_free_propertylist(&header);
00749 }
00750
00751 cleanup:
00752 xsh_free_table(&table);
00753 xsh_free_propertylist(&qc_header);
00754 xsh_free_propertylist(&header);
00755
00756 return cpl_error_get_code();
00757
00758 }
00759
00760 cpl_error_code
00761 xsh_table_merge_clean_and_resid_tabs(cpl_frame* frm_resid,cpl_frame* frm_clean)
00762 {
00763
00764 double* pwav_resid=NULL;
00765 float* pwav_clean=NULL;
00766 double* pwav_extra=NULL;
00767 cpl_table* resid=NULL;
00768 cpl_table* clean=NULL;
00769
00770 int nrows_clean=0;
00771 int nrows_resid=0;
00772 int i=0;
00773 int k=0;
00774 double wave_acc=0.001;
00775 const char* name=NULL;
00776 cpl_propertylist* rhead=NULL;
00777 cpl_propertylist* qc_head=NULL;
00778
00779
00780 XSH_ASSURE_NOT_NULL_MSG(frm_resid, "Null input resid table frame");
00781 XSH_ASSURE_NOT_NULL_MSG(frm_clean, "Null input clean table frame");
00782
00783 check(name = cpl_frame_get_filename(frm_clean));
00784 check(clean = cpl_table_load(name, 1, 0));
00785 check(nrows_clean = cpl_table_get_nrow(clean));
00786 check(name = cpl_frame_get_filename(frm_resid));
00787 resid = cpl_table_load(name, 1, 0);
00788
00789 rhead = cpl_propertylist_load(name, 0);
00790
00791 qc_head=cpl_propertylist_load_regexp(cpl_frame_get_filename(frm_clean),0,"^ESO QC",0);
00792 cpl_propertylist_append(rhead,qc_head);
00793
00794 cpl_frame_get_nextensions(frm_resid);
00795 check(nrows_resid=cpl_table_get_nrow(resid));
00796 cpl_table_new_column(resid,"WavelengthClean",CPL_TYPE_DOUBLE);
00797 cpl_table_fill_column_window_double(resid,"WavelengthClean",0,nrows_resid,0);
00798 check(pwav_resid=cpl_table_get_data_double(resid,XSH_RESID_TAB_TABLE_COLNAME_WAVELENGTH));
00799 check(pwav_clean=cpl_table_get_data_float(clean,XSH_ARCLIST_TABLE_COLNAME_WAVELENGTH));
00800 check(pwav_extra=cpl_table_get_data_double(resid,"WavelengthClean"));
00801
00802 for (i = 0; i < nrows_clean; i++) {
00803 for (k = 0; k < nrows_resid; k++) {
00804 if (fabs(pwav_resid[k] - pwav_clean[i]) < wave_acc) {
00805 pwav_extra[i] = pwav_clean[i];
00806 }
00807 }
00808 }
00809
00810 check(cpl_table_save(resid,rhead,NULL,name,CPL_IO_DEFAULT));
00811
00812 cleanup:
00813
00814 xsh_free_table(&resid);
00815 xsh_free_table(&clean);
00816 xsh_free_propertylist(&rhead);
00817 xsh_free_propertylist(&qc_head);
00818 return cpl_error_get_code();
00819 }
00820
00821
00822 cpl_table*
00823 xsh_table_shift_rv(cpl_table* orig, const char* col_wave,const double offset) {
00824 cpl_table* shifted = NULL;
00825 double* pwav = NULL;
00826 int nrows=0;
00827 int i=0;
00828 XSH_ASSURE_NOT_NULL_MSG(orig, "Null input table");
00829
00830 shifted=cpl_table_duplicate(orig);
00831 pwav = cpl_table_get_data_double(shifted, col_wave);
00832 nrows=cpl_table_get_nrow(shifted);
00833 for(i=0;i<nrows;i++){
00834 pwav[i] *= (1.+offset);
00835 }
00836 cleanup:
00837 return shifted;
00838 }