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 <string.h>
00037 #include <math.h>
00038 #include <cpl.h>
00039
00040 #include "irplib_plugin.h"
00041 #include "irplib_utils.h"
00042 #include "irplib_spectrum.h"
00043
00044 #include "sofi_utils.h"
00045 #include "sofi_wavelength.h"
00046 #include "sofi_pfits.h"
00047 #include "sofi_dfs.h"
00048
00049
00050
00051
00052
00053 #define RECIPE_STRING "sofi_spc_jitter"
00054
00055 #define SOFI_SPC_JITTER_OFFSET_ERR 10
00056
00057
00058
00059
00060
00061 static cpl_image ** sofi_spc_jitter_combine(cpl_frameset *, const char *,
00062 const char *, const char *);
00063 static cpl_vector * sofi_spc_jitter_get_offsets(cpl_frameset *);
00064 static int * sofi_spc_jitter_classif(cpl_vector *, int *);
00065 static int off_comp(double, double, double);
00066 static cpl_imagelist * sofi_spc_jitter_saa_groups(cpl_imagelist *,
00067 cpl_vector *, int *, int, cpl_vector **);
00068 static int sofi_spc_jitter_wavecal(const char *, const char *, cpl_image *,
00069 cpl_frameset *);
00070 static cpl_imagelist * sofi_spc_jitter_nodded(cpl_imagelist *, cpl_vector *,
00071 cpl_vector **);
00072 static cpl_imagelist * sofi_spc_jitter_distor(cpl_imagelist *, const char *);
00073 static double sofi_spc_jitter_refine_offset(cpl_image *, cpl_image *);
00074 static cpl_table * sofi_spc_jitter_extract(cpl_image *);
00075 static cpl_error_code sofi_spc_jitter_save(cpl_frameset *, const cpl_image *,
00076 const cpl_table *,
00077 const cpl_parameterlist *);
00078
00079 cpl_recipe_define(sofi_spc_jitter, SOFI_BINARY_VERSION,
00080 "Lars Lundin", PACKAGE_BUGREPORT, "2002,2003,2009",
00081 "SOFI Spectro jitter recipe",
00082 RECIPE_STRING " -- SOFI Spectro jitter recipe"
00083 "The files listed in the Set Of Frames (sof-file) "
00084 "must be tagged:\n"
00085 "raw-file.fits "SOFI_SPC_JITTER_NODOBJ_RAW" or\n"
00086 "raw-file.fits "SOFI_SPC_JITTER_NODSKY_RAW"\n"
00087 "Calibration files:\n"
00088 "oh-cat.fits "SOFI_CALPRO_OH_CAT" or\n"
00089 "flat-file.fits "SOFI_CALIB_SPFLAT" or\n"
00090 "arc-file.fits "SOFI_CALIB_ARC"\n");
00091
00092
00093
00094
00095
00096 static struct {
00097
00098 int display;
00099 int crosstalk;
00100
00101 int wavecal_in;
00102 int wavecal_degree;
00103 double wavecal_err;
00104 int wavecal_nsamples;
00105 int wavecal_ppm;
00106 int saa_refine;
00107 double saa_rej_high;
00108 double saa_rej_low;
00109 int extr_spec_pos;
00110 int extr_spec_width;
00111 int extr_sky_le_width;
00112 int extr_sky_ri_width;
00113 int extr_sky_le_dist;
00114 int extr_sky_ri_dist;
00115
00116
00117 cpl_vector * throws;
00118 cpl_vector * intensities;
00119 char filter[512];
00120 int wavecal_out;
00121 double wavecal_cc;
00122 double wavecal_a0;
00123 double wavecal_a1;
00124 double wavecal_a2;
00125 double wavecal_a3;
00126 double wavecal_a4;
00127 } sofi_spc_jitter_config;
00128
00129
00130
00131
00132
00133
00134
00142
00143 static
00144 cpl_error_code sofi_spc_jitter_fill_parameterlist(cpl_parameterlist * self)
00145 {
00146 const char * context = PACKAGE "." RECIPE_STRING;
00147 cpl_error_code err;
00148
00149 cpl_ensure_code(self, CPL_ERROR_NULL_INPUT);
00150
00151
00152
00153
00154
00155 err = irplib_parameterlist_set_bool(self, PACKAGE, RECIPE_STRING,
00156 "crosstalk", CPL_TRUE, NULL, context,
00157 "Enable removal of the crosstalk "
00158 "effect");
00159 cpl_ensure_code(!err, err);
00160
00161
00162 err = irplib_parameterlist_set_string(self, PACKAGE, RECIPE_STRING,
00163 "wavecal", "sky", NULL, context,
00164 "Wavelength method: "
00165 "phy or sky or arc");
00166 cpl_ensure_code(!err, err);
00167
00168
00169 err = irplib_parameterlist_set_bool(self, PACKAGE, RECIPE_STRING,
00170 "wavecal_ppm", CPL_FALSE, NULL, context,
00171 "Enable Point Pattern Matching in the "
00172 "wavelength calibration");
00173 cpl_ensure_code(!err, err);
00174
00175
00176 err = irplib_parameterlist_set_int(self, PACKAGE, RECIPE_STRING,
00177 "wavecal_degree", 2, NULL, context,
00178 "Degree of the wavelength dispersion "
00179 "polynomial");
00180 cpl_ensure_code(!err, err);
00181
00182
00183 err = irplib_parameterlist_set_int(self, PACKAGE, RECIPE_STRING,
00184 "wavecal_nsamples", 100, NULL, context,
00185 "Number of samples for the wavelength "
00186 "calibration");
00187 cpl_ensure_code(!err, err);
00188
00189
00190 err = irplib_parameterlist_set_double(self, PACKAGE, RECIPE_STRING,
00191 "wavecal_err", 1000.0, NULL, context,
00192 "The wavelength error [Angstrom]");
00193 cpl_ensure_code(!err, err);
00194
00195
00196 err = irplib_parameterlist_set_bool(self, PACKAGE, RECIPE_STRING,
00197 "saa_refine", CPL_TRUE, NULL, context,
00198 "Enable refinement of the offsets");
00199 cpl_ensure_code(!err, err);
00200
00201
00202 err = irplib_parameterlist_set_string(self, PACKAGE, RECIPE_STRING,
00203 "saa_rej", "0.1,0.1", NULL, context,
00204 "Low, high SAA rejection [%,%]");
00205 cpl_ensure_code(!err, err);
00206
00207
00208 err = irplib_parameterlist_set_int(self, PACKAGE, RECIPE_STRING,
00209 "spec_pos", -1, NULL, context,
00210 "Spectrum position");
00211 cpl_ensure_code(!err, err);
00212
00213
00214 err = irplib_parameterlist_set_int(self, PACKAGE, RECIPE_STRING,
00215 "spec_width", 10, NULL, context,
00216 "Spectrum width");
00217 cpl_ensure_code(!err, err);
00218
00219
00220 err = irplib_parameterlist_set_int(self, PACKAGE, RECIPE_STRING,
00221 "sky_le_width", 10, NULL, context,
00222 "Sky width left of the spectrum");
00223 cpl_ensure_code(!err, err);
00224
00225
00226 err = irplib_parameterlist_set_int(self, PACKAGE, RECIPE_STRING,
00227 "sky_ri_width", 10, NULL, context,
00228 "Sky width right of the spectrum");
00229 cpl_ensure_code(!err, err);
00230
00231
00232 err = irplib_parameterlist_set_int(self, PACKAGE, RECIPE_STRING,
00233 "sky_le_dist", -1, NULL, context,
00234 "Sky distance left of the spectrum");
00235 cpl_ensure_code(!err, err);
00236
00237
00238 err = irplib_parameterlist_set_int(self, PACKAGE, RECIPE_STRING,
00239 "sky_ri_dist", -1, NULL, context,
00240 "Sky distance right of the spectrum");
00241 cpl_ensure_code(!err, err);
00242
00243
00244 err = irplib_parameterlist_set_bool(self, PACKAGE, RECIPE_STRING, "display",
00245 CPL_FALSE, NULL, context,
00246 "Enable plotting");
00247 cpl_ensure_code(!err, err);
00248
00249 return CPL_ERROR_NONE;
00250 }
00251
00252
00259
00260 static int sofi_spc_jitter(cpl_frameset * framelist,
00261 const cpl_parameterlist * parlist)
00262 {
00263 cpl_propertylist * plist;
00264 const char * sval;
00265 cpl_frameset * rawframes = NULL;
00266 const cpl_frame * cur_frame;
00267 const char * flat;
00268 const char * oh;
00269 const char * arc;
00270 cpl_image ** combined = NULL;
00271 cpl_table * extracted = NULL;
00272
00273
00274 sofi_spc_jitter_config.wavecal_out = -1;
00275 sofi_spc_jitter_config.wavecal_cc = -1.0;
00276 sofi_spc_jitter_config.throws = NULL;
00277 sofi_spc_jitter_config.intensities = NULL;
00278 sofi_spc_jitter_config.filter[0] = (char)0;
00279
00280
00281
00282
00283 sofi_spc_jitter_config.crosstalk
00284 = irplib_parameterlist_get_bool(parlist, PACKAGE, RECIPE_STRING,
00285 "crosstalk");
00286
00287
00288 sval = irplib_parameterlist_get_string(parlist, PACKAGE, RECIPE_STRING,
00289 "wavecal");
00290 bug_if(sval == NULL);
00291 if (!strcmp(sval, "phy")) sofi_spc_jitter_config.wavecal_in = 0;
00292 else if (!strcmp(sval, "sky")) sofi_spc_jitter_config.wavecal_in = 1;
00293 else if (!strcmp(sval, "arc")) sofi_spc_jitter_config.wavecal_in = 2;
00294 else {
00295 error_if(1, CPL_ERROR_UNSUPPORTED_MODE,
00296 "Invalid value for wavecal option: %s", sval);
00297 }
00298
00299
00300 sofi_spc_jitter_config.wavecal_degree
00301 = irplib_parameterlist_get_int(parlist, PACKAGE, RECIPE_STRING,
00302 "wavecal_degree");
00303
00304
00305 sofi_spc_jitter_config.wavecal_nsamples
00306 = irplib_parameterlist_get_int(parlist, PACKAGE, RECIPE_STRING,
00307 "wavecal_nsamples");
00308
00309
00310 sofi_spc_jitter_config.wavecal_err
00311 = irplib_parameterlist_get_double(parlist, PACKAGE, RECIPE_STRING,
00312 "wavecal_err");
00313
00314
00315 sofi_spc_jitter_config.wavecal_ppm
00316 = irplib_parameterlist_get_bool(parlist, PACKAGE, RECIPE_STRING,
00317 "wavecal_ppm");
00318
00319
00320 sofi_spc_jitter_config.saa_refine
00321 = irplib_parameterlist_get_bool(parlist, PACKAGE, RECIPE_STRING,
00322 "saa_refine");
00323
00324
00325 sval = irplib_parameterlist_get_string(parlist, PACKAGE, RECIPE_STRING,
00326 "saa_rej");
00327 skip_if (sscanf(sval, "%lg,%lg",
00328 &sofi_spc_jitter_config.saa_rej_low,
00329 &sofi_spc_jitter_config.saa_rej_high) != 2);
00330
00331
00332 sofi_spc_jitter_config.extr_spec_pos
00333 = irplib_parameterlist_get_int(parlist, PACKAGE, RECIPE_STRING,
00334 "spec_pos");
00335
00336
00337 sofi_spc_jitter_config.extr_spec_width
00338 = irplib_parameterlist_get_int(parlist, PACKAGE, RECIPE_STRING,
00339 "spec_width");
00340
00341
00342 sofi_spc_jitter_config.extr_sky_le_width
00343 = irplib_parameterlist_get_int(parlist, PACKAGE, RECIPE_STRING,
00344 "sky_le_width");
00345
00346 sofi_spc_jitter_config.extr_sky_ri_width
00347 = irplib_parameterlist_get_int(parlist, PACKAGE, RECIPE_STRING,
00348 "sky_ri_width");
00349
00350
00351 sofi_spc_jitter_config.extr_sky_le_dist
00352 = irplib_parameterlist_get_int(parlist, PACKAGE, RECIPE_STRING,
00353 "sky_le_dist");
00354
00355
00356 sofi_spc_jitter_config.extr_sky_ri_dist
00357 = irplib_parameterlist_get_int(parlist, PACKAGE, RECIPE_STRING,
00358 "sky_ri_dist");
00359
00360 sofi_spc_jitter_config.display
00361 = irplib_parameterlist_get_bool(parlist, PACKAGE, RECIPE_STRING,
00362 "display");
00363
00364
00365 skip_if (sofi_dfs_set_groups(framelist));
00366
00367
00368 cur_frame = cpl_frameset_get_frame(framelist, 0);
00369 plist = cpl_propertylist_load(cpl_frame_get_filename(cur_frame), 0);
00370 skip_if(plist == NULL);
00371
00372 if ((sval = sofi_pfits_get_filter(plist)) != NULL) {
00373 sprintf(sofi_spc_jitter_config.filter, sval);
00374 } else {
00375 cpl_error_reset();
00376 }
00377 cpl_propertylist_delete(plist);
00378
00379
00380 arc = sofi_extract_filename(framelist, SOFI_CALIB_ARC);
00381 flat = sofi_extract_filename(framelist, SOFI_CALIB_SPFLAT);
00382 oh = sofi_extract_filename(framelist, SOFI_CALPRO_OH_CAT);
00383
00384
00385 rawframes = sofi_extract_frameset(framelist, SOFI_SPC_JITTER_NODOBJ_RAW);
00386 error_if (rawframes == NULL, CPL_ERROR_DATA_NOT_FOUND,
00387 "Cannot find the raw frames in the input list");
00388
00389
00390 error_if (arc == NULL && sofi_spc_jitter_config.wavecal_in == 2,
00391 CPL_ERROR_ILLEGAL_INPUT,
00392 "You must provide an ARC file for the wl cal");
00393
00394
00395 cpl_msg_info(cpl_func, "Create the combined image");
00396 cpl_msg_indent_more();
00397 combined = sofi_spc_jitter_combine(rawframes, oh, flat, arc);
00398 cpl_msg_indent_less();
00399
00400 error_if (combined==NULL, CPL_ERROR_ILLEGAL_INPUT,
00401 "Cannot combine the images");
00402
00403
00404 cpl_msg_info(cpl_func, "Extract the spectrum");
00405 cpl_msg_indent_more();
00406 extracted = sofi_spc_jitter_extract(combined[0]);
00407 cpl_msg_indent_less();
00408
00409 error_if (extracted == NULL, CPL_ERROR_DATA_NOT_FOUND,
00410 "Cannot extract the spectrum");
00411
00412
00413 cpl_msg_info(cpl_func, "Save the products");
00414 skip_if(sofi_spc_jitter_save(framelist, combined[0], extracted, parlist));
00415
00416 end_skip;
00417
00418 if (combined != NULL) {
00419 cpl_image_delete(combined[0]);
00420 cpl_image_delete(combined[1]);
00421 cpl_free(combined);
00422 }
00423
00424 cpl_vector_delete(sofi_spc_jitter_config.intensities);
00425 cpl_vector_delete(sofi_spc_jitter_config.throws);
00426
00427 cpl_frameset_delete(rawframes);
00428
00429 cpl_table_delete(extracted);
00430
00431 return cpl_error_get_code();
00432 }
00433
00434
00443
00444 static cpl_image ** sofi_spc_jitter_combine(
00445 cpl_frameset * rawframes,
00446 const char * oh,
00447 const char * flat,
00448 const char * arc)
00449 {
00450 cpl_imagelist * ilist;
00451 cpl_image * tmp_im;
00452 cpl_vector * offsets;
00453 int * groups;
00454 int ngroups;
00455 cpl_imagelist * abba;
00456 cpl_vector * abba_off;
00457 cpl_imagelist * nodded;
00458 cpl_vector * nodded_off_x;
00459 cpl_vector * nodded_off_y;
00460 double throw;
00461 cpl_table * extracted;
00462 double intensity;
00463 double * pnodded_off_x;
00464 cpl_imagelist * nodded_warped;
00465 cpl_bivector * nodded_offsets;
00466 cpl_image ** combined;
00467 int nima;
00468 double new_offset;
00469 int i;
00470
00471
00472 if (rawframes == NULL) return NULL;
00473
00474
00475 cpl_msg_info(cpl_func, "Load the data");
00476 cpl_msg_indent_more();
00477 if ((ilist = cpl_imagelist_load_frameset(rawframes, CPL_TYPE_FLOAT, 1,
00478 0)) == NULL) {
00479 cpl_msg_error(cpl_func, "cannot load the data");
00480 cpl_msg_indent_less();
00481 return NULL;
00482 }
00483 cpl_msg_indent_less();
00484
00485
00486 if (sofi_spc_jitter_config.crosstalk) {
00487 cpl_msg_info(cpl_func, "Apply the cross-talk correction");
00488 cpl_msg_indent_more();
00489 if (sofi_correct_crosstalk_list(ilist) == -1) {
00490 cpl_msg_error(cpl_func, "Cannot correct for Cross-talk");
00491 cpl_imagelist_delete(ilist);
00492 cpl_msg_indent_less();
00493 return NULL;
00494 }
00495 cpl_msg_indent_less();
00496 }
00497
00498
00499 if (flat != NULL) {
00500 cpl_msg_info(cpl_func, "Apply the flatfield correction");
00501 if ((tmp_im = cpl_image_load(flat, CPL_TYPE_FLOAT, 0, 0)) == NULL) {
00502 cpl_msg_warning(cpl_func, "cannot load the flat field");
00503 } else {
00504 if (cpl_imagelist_divide_image(ilist, tmp_im) != CPL_ERROR_NONE) {
00505 cpl_msg_warning(cpl_func, "cannot apply the flat field");
00506 }
00507 cpl_image_delete(tmp_im);
00508 }
00509 }
00510
00511
00512 cpl_msg_info(cpl_func, "Get the offsets");
00513 if ((offsets = sofi_spc_jitter_get_offsets(rawframes)) == NULL) {
00514 cpl_msg_error(cpl_func, "cannot get the offsets");
00515 cpl_imagelist_delete(ilist);
00516 return NULL;
00517 }
00518
00519
00520 cpl_msg_info(cpl_func, "Classify in groups");
00521 cpl_msg_indent_more();
00522 if ((groups = sofi_spc_jitter_classif(offsets, &ngroups)) == NULL) {
00523 cpl_msg_error(cpl_func, "cannot classify the data");
00524 cpl_imagelist_delete(ilist);
00525 cpl_vector_delete(offsets);
00526 cpl_msg_indent_less();
00527 return NULL;
00528 }
00529 cpl_msg_indent_less();
00530
00531
00532 cpl_msg_info(cpl_func, "Shift and add each group to one image");
00533 cpl_msg_indent_more();
00534 if ((abba = sofi_spc_jitter_saa_groups(ilist, offsets, groups,
00535 ngroups, &abba_off)) == NULL) {
00536 cpl_msg_error(cpl_func, "cannot shift and add groups");
00537 cpl_imagelist_delete(ilist);
00538 cpl_vector_delete(offsets);
00539 cpl_free(groups);
00540 cpl_msg_indent_less();
00541 return NULL;
00542 }
00543 cpl_imagelist_delete(ilist);
00544 cpl_free(groups);
00545 cpl_vector_delete(offsets);
00546 cpl_msg_indent_less();
00547
00548
00549 cpl_msg_info(cpl_func, "Compute the wavelength calibration");
00550 cpl_msg_indent_more();
00551 if (sofi_spc_jitter_wavecal(arc, oh, cpl_imagelist_get(abba, 0),
00552 rawframes) == -1) {
00553 cpl_msg_error(cpl_func, "cannot compute the wavelength");
00554 cpl_imagelist_delete(abba);
00555 cpl_vector_delete(abba_off);
00556 cpl_msg_indent_less();
00557 return NULL;
00558 }
00559 cpl_msg_indent_less();
00560
00561
00562 cpl_msg_info(cpl_func, "Create the nodded images");
00563 cpl_msg_indent_more();
00564 if ((nodded = sofi_spc_jitter_nodded(abba, abba_off,
00565 &nodded_off_x))==NULL) {
00566 cpl_msg_error(cpl_func, "cannot create the nodded images");
00567 cpl_imagelist_delete(abba);
00568 cpl_vector_delete(abba_off);
00569 cpl_msg_indent_less();
00570 return NULL;
00571 }
00572 cpl_imagelist_delete(abba);
00573 cpl_msg_indent_less();
00574
00575
00576 nima = cpl_imagelist_get_size(nodded);
00577 sofi_spc_jitter_config.throws = cpl_vector_new(nima);
00578 for (i=0; i<nima/2; i++) {
00579 throw = fabs( (cpl_vector_get(abba_off, 2*i))-
00580 (cpl_vector_get(abba_off, 2*i+1)));
00581 cpl_vector_set(sofi_spc_jitter_config.throws, 2*i, throw);
00582 cpl_vector_set(sofi_spc_jitter_config.throws, 2*i+1, throw);
00583 }
00584 cpl_vector_delete(abba_off);
00585
00586
00587 cpl_msg_info(cpl_func, "Compute the spectra intensities");
00588 cpl_msg_indent_more();
00589 nima = cpl_imagelist_get_size(nodded);
00590 sofi_spc_jitter_config.intensities = cpl_vector_new(nima);
00591 for (i=0; i<nima; i++) {
00592 if ((extracted = sofi_spc_jitter_extract(
00593 cpl_imagelist_get(nodded, i))) == NULL) {
00594 cpl_msg_warning(cpl_func,"Cannot extract the spectrum from nodded %d",
00595 i+1);
00596 intensity = -1.0;
00597 } else {
00598 intensity = cpl_table_get_column_mean(extracted,
00599 "Extracted_spectrum_value");
00600 intensity *= cpl_table_get_nrow(extracted);
00601 cpl_table_delete(extracted);
00602 }
00603 cpl_msg_info(cpl_func, "Spectrum intensity nb %d: %g", i+1,
00604 intensity);
00605 cpl_vector_set(sofi_spc_jitter_config.intensities, i, intensity);
00606 }
00607 cpl_msg_indent_less();
00608
00609
00610 if (arc) {
00611 cpl_msg_info(cpl_func, "Correct the distortion on nodded images");
00612 cpl_msg_indent_more();
00613 if ((nodded_warped = sofi_spc_jitter_distor(nodded, arc)) == NULL) {
00614 cpl_msg_error(cpl_func, "cannot correct the distortion");
00615 cpl_imagelist_delete(nodded);
00616 cpl_vector_delete(nodded_off_x);
00617 cpl_msg_indent_less();
00618 return NULL;
00619 }
00620 cpl_imagelist_delete(nodded);
00621 nodded = nodded_warped;
00622 cpl_msg_indent_less();
00623 }
00624
00625
00626 if (sofi_spc_jitter_config.saa_refine) {
00627 cpl_msg_info(cpl_func, "Refine the offsets");
00628 pnodded_off_x = cpl_vector_get_data(nodded_off_x);
00629 for (i=0; i<cpl_imagelist_get_size(nodded); i++) {
00630 new_offset = sofi_spc_jitter_refine_offset(
00631 cpl_imagelist_get(nodded, 0),
00632 cpl_imagelist_get(nodded, i));
00633 if (new_offset > 5000) {
00634 cpl_msg_debug(cpl_func, "cannot refine the offset - keep %g",
00635 pnodded_off_x[i]);
00636 } else {
00637 if (fabs(new_offset-pnodded_off_x[i]) <
00638 SOFI_SPC_JITTER_OFFSET_ERR) {
00639 cpl_msg_debug(cpl_func, "refined offset : %g (old was %g)",
00640 new_offset, pnodded_off_x[i]);
00641 pnodded_off_x[i] = new_offset;
00642 } else {
00643 cpl_msg_debug(cpl_func,
00644 "refined offset %g too different - keep %g",
00645 new_offset, pnodded_off_x[i]);
00646 }
00647 }
00648 }
00649 }
00650
00651
00652
00653 nodded_off_y = cpl_vector_duplicate(nodded_off_x);
00654 cpl_vector_fill(nodded_off_y, 0.0);
00655 nodded_offsets = cpl_bivector_wrap_vectors(nodded_off_x, nodded_off_y);
00656
00657 cpl_msg_info(cpl_func, "Apply the shift and add on the nodded frames");
00658 nima = cpl_imagelist_get_size(nodded);
00659 if ((combined = cpl_geom_img_offset_saa(nodded, nodded_offsets,
00660 CPL_KERNEL_DEFAULT,
00661 (int)(sofi_spc_jitter_config.saa_rej_low * nima),
00662 (int)(sofi_spc_jitter_config.saa_rej_high * nima),
00663 CPL_GEOM_FIRST, NULL, NULL)) == NULL) {
00664 cpl_msg_error(cpl_func, "Cannot shift and add group");
00665 cpl_imagelist_delete(nodded);
00666 cpl_bivector_unwrap_vectors(nodded_offsets);
00667 cpl_vector_delete(nodded_off_x);
00668 cpl_vector_delete(nodded_off_y);
00669 return NULL;
00670 }
00671 cpl_imagelist_delete(nodded);
00672 cpl_bivector_unwrap_vectors(nodded_offsets);
00673 cpl_vector_delete(nodded_off_x);
00674 cpl_vector_delete(nodded_off_y);
00675 return combined;
00676 }
00677
00678
00684
00685 static cpl_vector * sofi_spc_jitter_get_offsets(cpl_frameset * rawframes)
00686 {
00687 cpl_vector * offsets;
00688 double * pvect;
00689 int nraw;
00690 cpl_frame * cur_frame;
00691 cpl_propertylist * plist;
00692 int i;
00693
00694
00695 if (rawframes == NULL) return NULL;
00696
00697
00698 nraw = cpl_frameset_get_size(rawframes);
00699
00700
00701 offsets = cpl_vector_new(nraw);
00702 pvect = cpl_vector_get_data(offsets);
00703 for (i=0; i<nraw; i++) {
00704 cur_frame = cpl_frameset_get_frame(rawframes, i);
00705 if ((plist=cpl_propertylist_load(cpl_frame_get_filename(cur_frame),
00706 0)) == NULL) {
00707 cpl_msg_error(cpl_func, "cannot get property list");
00708 cpl_vector_delete(offsets);
00709 return NULL;
00710 }
00711 pvect[i] = sofi_pfits_get_cumoffsetx(plist);
00712 if (cpl_error_get_code()) {
00713 cpl_msg_error(cpl_func, "cannot get the offset from the header");
00714 cpl_vector_delete(offsets);
00715 cpl_propertylist_delete(plist);
00716 return NULL;
00717 }
00718 cpl_propertylist_delete(plist);
00719 pvect[i] *= -1.0;
00720 }
00721 return offsets;
00722 }
00723
00724
00762
00763 static int * sofi_spc_jitter_classif(
00764 cpl_vector * offsets,
00765 int * ngroups)
00766 {
00767 double * pvect;
00768 int nraw;
00769 double offset_thresh;
00770 cpl_vector * tmp_vec;
00771 int * groups;
00772 int last_group;
00773 int i, j, k, l;
00774
00775
00776 if (offsets == NULL) return NULL;
00777
00778
00779 nraw = cpl_vector_get_size(offsets);
00780
00781
00782 tmp_vec = cpl_vector_duplicate(offsets);
00783 cpl_vector_sort(tmp_vec, 1);
00784 pvect = cpl_vector_get_data(tmp_vec);
00785 if (pvect[0] == pvect[nraw-1]) {
00786 cpl_msg_error(cpl_func, "Only one offset in the list - abort");
00787 cpl_vector_delete(tmp_vec);
00788 return NULL;
00789 }
00790 offset_thresh = (pvect[0] + pvect[nraw-1]) / 2.0;
00791 cpl_vector_delete(tmp_vec);
00792
00793
00794 pvect = cpl_vector_get_data(offsets);
00795 *ngroups = 0;
00796 groups = cpl_calloc(nraw, sizeof(int));
00797
00798
00799 i = 0;
00800 while (i < nraw) {
00801 j = 0;
00802
00803 while ((i+j<nraw) &&
00804 (!off_comp(pvect[i], pvect[i+j], offset_thresh))) j++;
00805
00806 if (i+j >= nraw) i = nraw;
00807 else {
00808 k = 0;
00809
00810 while ((i+j+k < nraw)
00811 && (!off_comp(pvect[i+j], pvect[i+j+k], offset_thresh))
00812 && (k<j)) k++;
00813 last_group = 1;
00814 if (i+j+k < nraw) {
00815 for (l=i+j+k; l<nraw; l++) {
00816 if (off_comp(pvect[i+j], pvect[l], offset_thresh)) {
00817 last_group = 0;
00818 break;
00819 }
00820 }
00821 }
00822 if (last_group == 0) {
00823 for (l=0; l<j; l++) groups[i+l] = *ngroups + 1;
00824 for (l=0; l<k; l++) groups[i+j+l] = *ngroups + 2;
00825 *ngroups += 2;
00826 i += j+k;
00827 } else {
00828 for (l=0; l<j; l++) groups[i+l] = *ngroups + 1;
00829 for (l=0; l<nraw - (i+j); l++) groups[i+j+l] =*ngroups + 2;
00830 *ngroups += 2;
00831 i = nraw;
00832 }
00833 }
00834 }
00835
00836
00837 if (*ngroups % 2) {
00838 cpl_msg_error(cpl_func, "Odd number of groups found");
00839 cpl_free(groups);
00840 return NULL;
00841 }
00842
00843 return groups;
00844 }
00845
00846
00877
00878 static cpl_imagelist * sofi_spc_jitter_saa_groups(
00879 cpl_imagelist * ilist,
00880 cpl_vector * offsets,
00881 int * groups,
00882 int ngroups,
00883 cpl_vector ** abba_off)
00884 {
00885 cpl_imagelist * abba;
00886 cpl_imagelist * group_list;
00887 cpl_image * tmp_ima;
00888 cpl_image ** combined;
00889 cpl_bivector * group_off;
00890 double * pgroup_off;
00891 double * poffsets;
00892 double * pabba_off;
00893 int nima;
00894 int saa;
00895 int i, j, k;
00896
00897
00898 if ((ilist == NULL) || (offsets == NULL) || (groups == NULL)) return NULL;
00899
00900
00901 nima = cpl_imagelist_get_size(ilist);
00902 poffsets = cpl_vector_get_data(offsets);
00903
00904
00905 abba = cpl_imagelist_new();
00906 *abba_off = cpl_vector_new(ngroups);
00907 pabba_off = cpl_vector_get_data(*abba_off);
00908
00909
00910 for (i=0; i<ngroups; i++) {
00911
00912 saa = 0;
00913
00914 group_list = cpl_imagelist_new();
00915 k = 0;
00916 for (j=0; j<nima; j++) {
00917 if (i+1 == groups[j]) {
00918
00919 if (k==0) pabba_off[i] = poffsets[j];
00920
00921 if (fabs(pabba_off[i]-poffsets[j]) > 1e-3) saa = 1;
00922
00923 tmp_ima = cpl_image_duplicate(cpl_imagelist_get(ilist, j));
00924 cpl_imagelist_set(group_list, tmp_ima, k);
00925 tmp_ima = NULL;
00926 k++;
00927 }
00928 }
00929
00930 if (saa) {
00931
00932 group_off = cpl_bivector_new(k);
00933 cpl_vector_fill(cpl_bivector_get_y(group_off), 0.0);
00934 pgroup_off = cpl_bivector_get_x_data(group_off);
00935 k = 0;
00936 for (j=0; j<nima; j++) {
00937 if (i+1 == groups[j]) {
00938 pgroup_off[k] = poffsets[j];
00939 k++;
00940 }
00941 }
00942 cpl_vector_subtract_scalar(cpl_bivector_get_x(group_off),
00943 pabba_off[i]);
00944
00945 cpl_msg_debug(cpl_func, "Apply shift-and-add for group %d", i+1);
00946 if ((combined = cpl_geom_img_offset_saa(group_list,
00947 group_off, CPL_KERNEL_DEFAULT, 0, 0,
00948 CPL_GEOM_FIRST, NULL, NULL)) == NULL) {
00949 cpl_msg_error(cpl_func,"Cannot shift and add group nb %d", i+1);
00950 cpl_imagelist_delete(group_list);
00951 cpl_bivector_delete(group_off);
00952 cpl_imagelist_delete(abba);
00953 cpl_vector_delete(*abba_off);
00954 return NULL;
00955 }
00956 cpl_bivector_delete(group_off);
00957 cpl_image_delete(combined[1]);
00958 cpl_imagelist_set(abba, combined[0], i);
00959 cpl_free(combined);
00960 } else {
00961
00962 cpl_msg_debug(cpl_func, "Apply averaging for group %d", i+1);
00963 if ((tmp_ima = cpl_imagelist_collapse_create(group_list)) == NULL) {
00964 cpl_msg_error(cpl_func, "Cannot average group nb %d", i+1);
00965 cpl_imagelist_delete(group_list);
00966 cpl_imagelist_delete(abba);
00967 cpl_vector_delete(*abba_off);
00968 return NULL;
00969 }
00970 cpl_imagelist_set(abba, tmp_ima, i);
00971 }
00972 cpl_imagelist_delete(group_list);
00973 }
00974 return abba;
00975 }
00976
00977
00986
00987 static int sofi_spc_jitter_wavecal(
00988 const char * arc,
00989 const char * oh,
00990 cpl_image * ima,
00991 cpl_frameset * raw)
00992 {
00993 cpl_table * arc_tab;
00994 cpl_polynomial * phdisprel;
00995 cpl_frame * cur_frame;
00996 const char * cur_fname;
00997 cpl_polynomial * disprel;
00998 double slit_width;
00999 cpl_size p[5];
01000 double xc, a, b, c, d, e;
01001 int degree;
01002
01003
01004 if (sofi_spc_jitter_config.wavecal_in == 2) {
01005 if (arc == NULL) {
01006 cpl_msg_error(cpl_func, "Missing arc for the wavelength calib");
01007 return -1;
01008 }
01009 cpl_msg_info(cpl_func, "Get the wavelength from the ARC file");
01010 if ((arc_tab = cpl_table_load(arc, 1, 0)) == NULL) {
01011 cpl_msg_error(cpl_func, "Cannot load the arc table");
01012 sofi_spc_jitter_config.wavecal_out = -1;
01013 return -1;
01014 }
01015 sofi_spc_jitter_config.wavecal_a0 =
01016 cpl_table_get_double(arc_tab, "WL_coefficients", 0, NULL);
01017 sofi_spc_jitter_config.wavecal_a1 =
01018 cpl_table_get_double(arc_tab, "WL_coefficients", 1, NULL);
01019 sofi_spc_jitter_config.wavecal_a2 =
01020 cpl_table_get_double(arc_tab, "WL_coefficients", 2, NULL);
01021 sofi_spc_jitter_config.wavecal_a3 =
01022 cpl_table_get_double(arc_tab, "WL_coefficients", 3, NULL);
01023 sofi_spc_jitter_config.wavecal_a4 =
01024 cpl_table_get_double(arc_tab, "WL_coefficients", 4, NULL);
01025 cpl_table_delete(arc_tab);
01026 sofi_spc_jitter_config.wavecal_out = 2;
01027 sofi_spc_jitter_config.wavecal_cc = -1.0;
01028 return 0;
01029 }
01030
01031
01032 cur_frame = cpl_frameset_get_frame(raw, 0);
01033 cur_fname = cpl_frame_get_filename(cur_frame);
01034
01035
01036 cpl_msg_info(cpl_func, "Compute the physical model");
01037 cpl_msg_indent_more();
01038 if ((phdisprel = sofi_get_disprel_estimate(cur_fname, 1)) == NULL) {
01039 cpl_msg_error(cpl_func, "cannot compute the physical model");
01040 sofi_spc_jitter_config.wavecal_out = -1;
01041 cpl_msg_indent_less();
01042 return -1;
01043 }
01044 p[0] = 0; p[1] = 1;
01045 a = cpl_polynomial_get_coeff(phdisprel, p);
01046 b = cpl_polynomial_get_coeff(phdisprel, p + 1);
01047 cpl_msg_info(cpl_func, "f(x)=%g + %g*x", a, b);
01048 sofi_spc_jitter_config.wavecal_a0 = a;
01049 sofi_spc_jitter_config.wavecal_a1 = b;
01050 sofi_spc_jitter_config.wavecal_a2 = 0.0;
01051 sofi_spc_jitter_config.wavecal_a3 = 0.0;
01052 sofi_spc_jitter_config.wavecal_a4 = 0.0;
01053 sofi_spc_jitter_config.wavecal_cc = -1.0;
01054 sofi_spc_jitter_config.wavecal_out = 0;
01055 cpl_msg_indent_less();
01056
01057
01058 if (sofi_spc_jitter_config.wavecal_in == 1) {
01059
01060 if ((slit_width = sofi_get_slitwidth(cur_fname)) == -1) {
01061 cpl_msg_warning(cpl_func, "cannot get the slit width");
01062 cpl_polynomial_delete(phdisprel);
01063 return 0;
01064 }
01065
01066 cpl_msg_info(cpl_func, "Compute the wavelength with the sky lines");
01067 cpl_msg_indent_more();
01068 if ((disprel = sofi_wavelength_engine(ima, "oh", oh, NULL, NULL,
01069 phdisprel, slit_width,
01070 sofi_spc_jitter_config.wavecal_degree,
01071 sofi_spc_jitter_config.wavecal_err,
01072 sofi_spc_jitter_config.wavecal_nsamples,
01073 sofi_spc_jitter_config.wavecal_ppm,
01074 sofi_spc_jitter_config.display, &xc)) == NULL) {
01075 cpl_msg_error(cpl_func, "cannot compute the dispersion relation");
01076 cpl_polynomial_delete(phdisprel);
01077 cpl_msg_indent_less();
01078 return 0;
01079 }
01080 cpl_msg_info(cpl_func, "Cross correlation factor: %g", xc);
01081 p[0] = 0; p[1] = 1; p[2] = 2; p[3] = 3; p[4] = 4;
01082 a = b = c = d = e = 0.0;
01083 degree = cpl_polynomial_get_degree(disprel);
01084 a = cpl_polynomial_get_coeff(disprel, p);
01085 if (degree > 0) b = cpl_polynomial_get_coeff(disprel, p + 1);
01086 if (degree > 1) c = cpl_polynomial_get_coeff(disprel, p + 2);
01087 if (degree > 2) d = cpl_polynomial_get_coeff(disprel, p + 3);
01088 if (degree > 3) e = cpl_polynomial_get_coeff(disprel, p + 4);
01089 if (degree == 0)
01090 cpl_msg_info(cpl_func, "f(x)=%g", a);
01091 if (degree == 1)
01092 cpl_msg_info(cpl_func, "f(x)=%g + %g*x", a, b);
01093 if (degree == 2)
01094 cpl_msg_info(cpl_func, "f(x)=%g + %g*x + %g*x^2", a, b, c);
01095 if (degree == 3)
01096 cpl_msg_info(cpl_func, "f(x)=%g + %g*x + %g*x^2 + %g*x^3",
01097 a, b, c, d);
01098 if (degree == 4)
01099 cpl_msg_info(cpl_func, "f(x)=%g + %g*x + %g*x^2 + %g*x^3 + %g*x^4",
01100 a, b, c, d, e);
01101 sofi_spc_jitter_config.wavecal_a0 = a;
01102 sofi_spc_jitter_config.wavecal_a1 = b;
01103 sofi_spc_jitter_config.wavecal_a2 = c;
01104 sofi_spc_jitter_config.wavecal_a3 = d;
01105 sofi_spc_jitter_config.wavecal_a4 = e;
01106 sofi_spc_jitter_config.wavecal_cc = xc;
01107 sofi_spc_jitter_config.wavecal_out = 1;
01108 cpl_polynomial_delete(disprel);
01109 cpl_msg_indent_less();
01110 }
01111 cpl_polynomial_delete(phdisprel);
01112 return 0;
01113 }
01114
01115
01136
01137 static cpl_imagelist * sofi_spc_jitter_nodded(
01138 cpl_imagelist * abba,
01139 cpl_vector * abba_off,
01140 cpl_vector ** nodded_off)
01141 {
01142 cpl_imagelist * nodded;
01143 cpl_image * tmp_ima;
01144 int nima;
01145 double ref_off;
01146 int i;
01147
01148
01149 if ((abba == NULL) || (abba_off == NULL)) return NULL;
01150
01151
01152 nima = cpl_imagelist_get_size(abba);
01153 if (nima % 2) {
01154 cpl_msg_error(cpl_func, "Number of images should be even");
01155 return NULL;
01156 }
01157
01158
01159 *nodded_off = cpl_vector_duplicate(abba_off);
01160
01161 nodded = cpl_imagelist_new();
01162 for (i=0; i<(nima/2); i++) {
01163
01164 tmp_ima = cpl_image_duplicate(cpl_imagelist_get(abba, 2*i));
01165 cpl_image_subtract(tmp_ima, cpl_imagelist_get(abba, 2*i+1));
01166 cpl_imagelist_set(nodded, tmp_ima, 2*i);
01167
01168 tmp_ima = cpl_image_duplicate(cpl_imagelist_get(abba, 2*i+1));
01169 cpl_image_subtract(tmp_ima, cpl_imagelist_get(abba, 2*i));
01170 cpl_imagelist_set(nodded, tmp_ima, 2*i+1);
01171 }
01172
01173
01174 ref_off = cpl_vector_get(*nodded_off, 0);
01175 cpl_vector_subtract_scalar(*nodded_off, ref_off);
01176 return nodded;
01177 }
01178
01179
01186
01187 static cpl_imagelist * sofi_spc_jitter_distor(
01188 cpl_imagelist * ilist,
01189 const char * arc)
01190 {
01191 cpl_polynomial * arc_poly;
01192 cpl_polynomial * id_poly;
01193 cpl_table * tab;
01194 cpl_size power[2];
01195 cpl_vector * profile;
01196 cpl_imagelist * warped_list;
01197 cpl_image * warped;
01198 int i;
01199
01200
01201 if (ilist == NULL) return NULL;
01202 if (arc == NULL) return NULL;
01203
01204
01205 arc_poly = cpl_polynomial_new(2);
01206 cpl_msg_info(cpl_func, "Get the arc distortion from the file");
01207 if ((tab = cpl_table_load(arc, 1, 0)) == NULL) {
01208 cpl_msg_error(cpl_func, "cannot load the arc table");
01209 cpl_polynomial_delete(arc_poly);
01210 return NULL;
01211 }
01212 for (i=0; i<cpl_table_get_nrow(tab); i++) {
01213 power[0] = cpl_table_get_int(tab, "Degree_of_x", i, NULL);
01214 power[1] = cpl_table_get_int(tab, "Degree_of_y", i, NULL);
01215 cpl_polynomial_set_coeff(arc_poly, power,
01216 cpl_table_get_double(tab, "poly2d_coef", i, NULL));
01217 }
01218 cpl_table_delete(tab);
01219
01220
01221 id_poly = cpl_polynomial_new(2);
01222 power[0] = 1;
01223 power[1] = 0;
01224 cpl_polynomial_set_coeff(id_poly, power, 1.0);
01225
01226
01227 profile = cpl_vector_new(CPL_KERNEL_DEF_SAMPLES);
01228 cpl_vector_fill_kernel_profile(profile, CPL_KERNEL_DEFAULT,
01229 CPL_KERNEL_DEF_WIDTH);
01230
01231
01232 warped_list = cpl_imagelist_new();
01233 for (i=0; i<cpl_imagelist_get_size(ilist); i++) {
01234 warped = cpl_image_duplicate(cpl_imagelist_get(ilist, i));
01235 if (cpl_image_warp_polynomial(warped, cpl_imagelist_get(ilist, i),
01236 id_poly, arc_poly, profile, CPL_KERNEL_DEF_WIDTH, profile,
01237 CPL_KERNEL_DEF_WIDTH) != CPL_ERROR_NONE) {
01238 cpl_msg_error(cpl_func, "cannot correct the distortion");
01239 cpl_image_delete(warped);
01240 cpl_polynomial_delete(arc_poly);
01241 cpl_polynomial_delete(id_poly);
01242 cpl_vector_delete(profile);
01243 return NULL;
01244 }
01245 cpl_imagelist_set(warped_list, warped, i);
01246 }
01247 cpl_vector_delete(profile);
01248 cpl_polynomial_delete(arc_poly);
01249 cpl_polynomial_delete(id_poly);
01250 return warped_list;
01251 }
01252
01253
01260
01261 static double sofi_spc_jitter_refine_offset(
01262 cpl_image * ima1,
01263 cpl_image * ima2)
01264 {
01265 double pos1, pos2;
01266
01267
01268 if (ima1 == NULL) return 10000.0;
01269 if (ima2 == NULL) return 10000.0;
01270
01271
01272 if (irplib_spectrum_find_brightest(ima1, 0.0, NO_SHADOW, 0.0, 1,
01273 &pos1) == -1){
01274 return 10000.0;
01275 }
01276 if (irplib_spectrum_find_brightest(ima2, 0.0, NO_SHADOW, 0.0, 1,
01277 &pos2) == -1){
01278 return 10000.0;
01279 }
01280 return pos1-pos2;
01281 }
01282
01283
01289
01290 static cpl_table * sofi_spc_jitter_extract(cpl_image * combined)
01291 {
01292 int ri_dist, le_dist, ri_width, le_width, spec_pos;
01293 int nx, ny;
01294 double pos;
01295 int right_side, left_side;
01296 int sky_pos[4];
01297 cpl_vector * sky;
01298 cpl_vector * spec;
01299 cpl_vector * wl;
01300 double * pspec;
01301 double * psky;
01302 double * pwl;
01303 cpl_table * out;
01304 cpl_bivector * toplot;
01305 int throw;
01306 int res;
01307 int i;
01308
01309
01310 if (combined == NULL) return NULL;
01311
01312
01313 nx = cpl_image_get_size_x(combined);
01314 ny = cpl_image_get_size_y(combined);
01315 ri_dist = sofi_spc_jitter_config.extr_sky_ri_dist;
01316 le_dist = sofi_spc_jitter_config.extr_sky_le_dist;
01317 ri_width = sofi_spc_jitter_config.extr_sky_ri_width;
01318 le_width = sofi_spc_jitter_config.extr_sky_le_width;
01319 spec_pos = sofi_spc_jitter_config.extr_spec_pos;
01320 res = -1;
01321
01322
01323 if (spec_pos < 0) {
01324 if (sofi_spc_jitter_config.throws == NULL) {
01325 cpl_msg_error(cpl_func,
01326 "Need a throw value to detect the spectra !!");
01327 return NULL;
01328 }
01329 for (i=0; i<cpl_vector_get_size(sofi_spc_jitter_config.throws); i++){
01330 throw = (int)cpl_vector_get(sofi_spc_jitter_config.throws, i);
01331 if ((res = irplib_spectrum_find_brightest(combined, throw,
01332 TWO_SHADOWS, 0.0, 1, &pos)) == 0) break;
01333 if ((res = irplib_spectrum_find_brightest(combined, throw,
01334 ONE_SHADOW, 0.0, 1, &pos)) == 0) break;
01335 }
01336 if (res != 0) {
01337 cpl_msg_error(cpl_func, "Cannot detect the spectrum");
01338 return NULL;
01339 }
01340 spec_pos = (int)pos;
01341 cpl_msg_info(cpl_func, "Spectrum detected at x = %d", spec_pos);
01342 }
01343
01344
01345
01346
01347 left_side = spec_pos - (int)(sofi_spc_jitter_config.extr_spec_width/2);
01348 right_side = left_side + sofi_spc_jitter_config.extr_spec_width;
01349 if ((left_side < 1) || (right_side > ny)) {
01350 cpl_msg_error(cpl_func, "Spectrum zone falls outside the image");
01351 return NULL;
01352 }
01353
01354 if (ri_dist < 0) ri_dist = 2*sofi_spc_jitter_config.extr_spec_width;
01355 if (le_dist < 0) le_dist = 2*sofi_spc_jitter_config.extr_spec_width;
01356 sky_pos[1] = spec_pos - le_dist;
01357 sky_pos[0] = sky_pos[1] - le_width;
01358 sky_pos[2] = spec_pos + ri_dist;
01359 sky_pos[3] = sky_pos[2] + ri_width;
01360
01361
01362 sky = cpl_vector_new(ny);
01363 psky = cpl_vector_get_data(sky);
01364 if (((sky_pos[0] < 1) || (le_width == 0)) &&
01365 ((sky_pos[3] <= nx) && (ri_width > 0))) {
01366 for (i=0; i<ny; i++) {
01367 psky[i] = cpl_image_get_median_window(combined, sky_pos[2],
01368 ny-i, sky_pos[3], ny-i);
01369 }
01370 } else if (((sky_pos[3] > nx) || (ri_width == 0))
01371 && ((sky_pos[0] > 0) && (le_width > 0))) {
01372 for (i=0; i<ny; i++) {
01373 psky[i] = cpl_image_get_median_window(combined, sky_pos[0],
01374 ny-i, sky_pos[1], ny-i);
01375 }
01376 } else if ((ri_width != 0) && (le_width != 0)
01377 && (sky_pos[0] > 0) && (sky_pos[3] <= nx)) {
01378 for (i=0; i<ny; i++) {
01379 psky[i] = cpl_image_get_median_window(combined, sky_pos[2],
01380 ny-i, sky_pos[3], ny-i);
01381 psky[i] += cpl_image_get_median_window(combined, sky_pos[0],
01382 ny-i, sky_pos[1], ny-i);
01383 psky[i] /= 2.0;
01384 }
01385 } else {
01386 for (i=0; i<ny; i++) psky[i] = 0.0;
01387 }
01388
01389
01390 spec = cpl_vector_new(ny);
01391 pspec = cpl_vector_get_data(spec);
01392 for (i=0; i<ny; i++) {
01393 pspec[i] = cpl_image_get_flux_window(combined, left_side, ny-i,
01394 right_side, ny-i);
01395 pspec[i] -= psky[i] * sofi_spc_jitter_config.extr_spec_width;
01396 }
01397
01398
01399 wl = cpl_vector_new(ny);
01400 pwl = cpl_vector_get_data(wl);
01401 for (i=0; i<ny; i++) {
01402 pwl[i] = sofi_spc_jitter_config.wavecal_a0 +
01403 sofi_spc_jitter_config.wavecal_a1 * (i+1) +
01404 sofi_spc_jitter_config.wavecal_a2 * (i+1) * (i+1) +
01405 sofi_spc_jitter_config.wavecal_a3 * (i+1) * (i+1) * (i+1) +
01406 sofi_spc_jitter_config.wavecal_a4 * (i+1) * (i+1) * (i+1) + (i+1);
01407 }
01408
01409
01410 if (sofi_spc_jitter_config.display) {
01411 toplot = cpl_bivector_wrap_vectors(wl, spec);
01412 cpl_plot_bivector(NULL, "t 'Spectrum' w lines", NULL, toplot);
01413 cpl_bivector_unwrap_vectors(toplot);
01414 toplot = cpl_bivector_wrap_vectors(wl, sky);
01415 cpl_plot_bivector(NULL, "t 'Sky' w lines", NULL, toplot);
01416 cpl_bivector_unwrap_vectors(toplot);
01417 }
01418
01419
01420 out = cpl_table_new(nx);
01421 cpl_table_new_column(out, "Y_coordinate", CPL_TYPE_DOUBLE);
01422 cpl_table_new_column(out, "Extracted_spectrum_value", CPL_TYPE_DOUBLE);
01423 cpl_table_new_column(out, "Sky_spectrum", CPL_TYPE_DOUBLE);
01424 for (i=0; i<nx; i++) {
01425 cpl_table_set_double(out, "Y_coordinate", i, pwl[i]);
01426 cpl_table_set_double(out, "Extracted_spectrum_value", i, pspec[i]);
01427 cpl_table_set_double(out, "Sky_spectrum", i, psky[i]);
01428 }
01429 cpl_vector_delete(wl);
01430 cpl_vector_delete(spec);
01431 cpl_vector_delete(sky);
01432 return out;
01433 }
01434
01435
01444
01445 static cpl_error_code sofi_spc_jitter_save(cpl_frameset * set,
01446 const cpl_image * ima,
01447 const cpl_table * tab,
01448 const cpl_parameterlist * parlist)
01449 {
01450 cpl_propertylist * plist;
01451
01452 cpl_propertylist * qclist = cpl_propertylist_new();
01453 cpl_propertylist * paflist;
01454
01455 const cpl_frame * ref_frame
01456 = irplib_frameset_get_first_from_group(set, CPL_FRAME_GROUP_RAW);
01457 char qc_str[128];
01458 int i;
01459
01460
01461
01462 if (sofi_spc_jitter_config.filter[0] != (char)0)
01463 cpl_propertylist_append_string(qclist, "ESO QC FILTER OBS",
01464 sofi_spc_jitter_config.filter);
01465 cpl_propertylist_append_double(qclist, "ESO QC DISPCO1",
01466 sofi_spc_jitter_config.wavecal_a0);
01467 cpl_propertylist_append_double(qclist, "ESO QC DISPCO2",
01468 sofi_spc_jitter_config.wavecal_a1);
01469 cpl_propertylist_append_double(qclist, "ESO QC DISPCO3",
01470 sofi_spc_jitter_config.wavecal_a2);
01471 cpl_propertylist_append_double(qclist, "ESO QC DISPCO4",
01472 sofi_spc_jitter_config.wavecal_a3);
01473 cpl_propertylist_append_double(qclist, "ESO QC DISPCO5",
01474 sofi_spc_jitter_config.wavecal_a4);
01475 cpl_propertylist_append_double(qclist, "ESO QC WLEN",
01476 sofi_spc_jitter_config.wavecal_a0 +
01477 sofi_spc_jitter_config.wavecal_a1 * 512 +
01478 sofi_spc_jitter_config.wavecal_a2 * 512 * 512 +
01479 sofi_spc_jitter_config.wavecal_a3 * 512 * 512 * 512 +
01480 sofi_spc_jitter_config.wavecal_a4 * 512 * 512 * 512 * 512);
01481 cpl_propertylist_append_double(qclist, "ESO QC DISP XCORR",
01482 sofi_spc_jitter_config.wavecal_cc);
01483 if (sofi_spc_jitter_config.wavecal_out == 0) {
01484 cpl_propertylist_append_string(qclist, "ESO QC WLMETHOD",
01485 "physical model");
01486 } else if (sofi_spc_jitter_config.wavecal_out == 1) {
01487 cpl_propertylist_append_string(qclist, "ESO QC WLMETHOD",
01488 "sky lines");
01489 } else if (sofi_spc_jitter_config.wavecal_out == 2) {
01490 cpl_propertylist_append_string(qclist, "ESO QC WLMETHOD",
01491 "arc file");
01492 }
01493 for (i=0; i<cpl_vector_get_size(sofi_spc_jitter_config.intensities);i++) {
01494 sprintf(qc_str, "ESO QC SPEC INTENS%d", i+1);
01495 cpl_propertylist_append_double(qclist, qc_str,
01496 cpl_vector_get(sofi_spc_jitter_config.intensities, i));
01497 }
01498
01499
01500 cpl_propertylist_update_double(qclist, "CRVAL1",
01501 sofi_spc_jitter_config.wavecal_a0);
01502 cpl_propertylist_update_double(qclist, "CRVAL2", 1.0);
01503 cpl_propertylist_update_double(qclist, "CRPIX1", 1.0);
01504 cpl_propertylist_update_double(qclist, "CRPIX2", 1.0);
01505 cpl_propertylist_update_double(qclist, "CDELT1",
01506 sofi_spc_jitter_config.wavecal_a1);
01507 cpl_propertylist_update_double(qclist, "CDELT2", 1.0);
01508 cpl_propertylist_update_string(qclist, "CTYPE1", "LINEAR");
01509 cpl_propertylist_update_string(qclist, "CTYPE2", "LINEAR");
01510 if (cpl_propertylist_has(qclist, "CD1_1")) {
01511 cpl_propertylist_update_double(qclist, "CD1_1",
01512 sofi_spc_jitter_config.wavecal_a1);
01513 } else {
01514 cpl_propertylist_insert_after_double(qclist, "CTYPE2", "CD1_1",
01515 sofi_spc_jitter_config.wavecal_a1);
01516 }
01517 if (cpl_propertylist_has(qclist, "CD2_2")) {
01518 cpl_propertylist_update_double(qclist, "CD2_2", 1.0);
01519 } else {
01520 cpl_propertylist_insert_after_double(qclist, "CD1_1", "CD2_2", 1.0);
01521 }
01522
01523
01524 irplib_dfs_save_image(set, parlist, set, ima, CPL_BPP_IEEE_FLOAT,
01525 RECIPE_STRING, SOFI_SPC_JITTER_COMB, qclist,
01526 NULL, PACKAGE "/" PACKAGE_VERSION,
01527 RECIPE_STRING "_combined" CPL_DFS_FITS);
01528
01529
01530 if (tab != NULL) {
01531 irplib_dfs_save_table(set, parlist, set, tab, NULL, RECIPE_STRING,
01532 SOFI_SPC_JITTER_EXTR, qclist, NULL, PACKAGE "/" PACKAGE_VERSION,
01533 RECIPE_STRING "_extracted" CPL_DFS_FITS);
01534 }
01535
01536
01537
01538 plist = cpl_propertylist_load(cpl_frame_get_filename(ref_frame), 0);
01539 if (plist == NULL) {
01540 cpl_propertylist_delete(qclist);
01541 return cpl_error_set_message(cpl_func, cpl_error_get_code(), "Could "
01542 "not read header from reference frame");
01543 }
01544
01545
01546 paflist = cpl_propertylist_new();
01547 cpl_propertylist_copy_property_regexp(paflist, plist,
01548 "^(ARCFILE|MJD-OBS|INSTRUME|ESO TPL ID|ESO TPL NEXP|ESO DPR CATG|"
01549 "ESO DPR TECH|ESO DPR TYPE|DATE-OBS|ESO INS GRAT NAME|"
01550 "ESO INS GRAT WLEN|ESO INS OPTI1 ID|ESO OBS ID|ESO OBS TARG NAME)$", 0);
01551 cpl_propertylist_delete(plist);
01552
01553
01554 cpl_propertylist_copy_property_regexp(paflist, qclist, "", 0);
01555 cpl_propertylist_delete(qclist);
01556
01557
01558 cpl_dfs_save_paf("SOFI", RECIPE_STRING, paflist,
01559 RECIPE_STRING CPL_DFS_PAF);
01560 cpl_propertylist_delete(paflist);
01561
01562 return cpl_error_get_code();
01563 }
01564
01565
01573
01574 static int off_comp(double off1, double off2, double thresh)
01575 {
01576 if (((off1>thresh) && (off2<thresh)) || ((off1<thresh) && (off2>thresh)))
01577 return 1;
01578 else return 0;
01579 }
01580