37 #include <cxstrutils.h>
39 #include <cpl_error.h>
45 #include "gigrating.h"
47 #include "gilinedata.h"
48 #include "giwlsolution.h"
50 #include "gimessages.h"
51 #include "gifiberutils.h"
53 #include "giwlcalibration.h"
71 GI_LINETYPE_UNDEFINED,
76 typedef enum GiLineType GiLineType;
117 OPTM_FLENGTH = 1 << 0,
118 OPTM_GCAMERA = 1 << 1,
130 enum GiOpticalModelInfo {
131 GI_OPTM_PARAMETER_VALUES,
132 GI_OPTM_PARAMETER_ERRORS,
133 GI_OPTM_PARAMETER_STATUS
136 typedef enum GiOpticalModelInfo GiOpticalModelInfo;
143 struct GiLineParams {
160 typedef struct GiLineParams GiLineParams;
167 struct GiOpticalModelParams {
174 typedef struct GiOpticalModelParams GiOpticalModelParams;
181 struct GiSCFitParams {
194 typedef struct GiSCFitParams GiSCFitParams;
213 typedef struct GiWCalInfo GiWCalInfo;
217 _giraffe_window_compare(cxcptr first, cxcptr second)
220 cxint *_first = (cxint *)first;
221 cxint *_second = (cxint *)second;
223 return *_second - *_first;
228 inline static GiLineParams *
229 _giraffe_lineparams_create(GiLineType type,
const GiGrating *grating,
233 GiLineParams *
self = NULL;
236 cx_assert(grating != NULL);
237 cx_assert(config != NULL);
239 self = cx_calloc(1,
sizeof(GiLineParams));
250 self->grwid = 1. / grating->
band * (grating->
wlen0 / grating->
resol);
268 _giraffe_lineparams_delete(GiLineParams *
self)
274 cx_free((cxptr)self->model);
286 inline static cxdouble
287 _giraffe_get_fiber_position(
const cpl_image *locy, cxint cs, cxdouble xccd)
290 cxint xlower = (cxint)floor(xccd);
291 cxint xupper = (cxint)ceil(xccd);
293 const cxdouble *ldata = cpl_image_get_data_const(locy);
295 cxdouble ylower = 0.;
296 cxdouble yupper = 0.;
299 cx_assert(ldata != NULL);
301 ylower = ldata[xlower * cpl_image_get_size_x(locy) + cs];
302 yupper = ldata[xupper * cpl_image_get_size_x(locy) + cs];
304 return giraffe_interpolate_linear(xccd, xlower, ylower, xupper, yupper);
310 _giraffe_subslit_get_max(
const cpl_table *fibers)
313 return cpl_table_get_column_max((cpl_table *)fibers,
"SSN");
318 inline static cpl_table *
319 _giraffe_subslit_get(
const cpl_table *fibers, cxint ssn)
327 cx_assert(fibers != NULL);
328 cx_assert(cpl_table_has_column((cpl_table *)fibers,
"SSN"));
330 ssn_max = _giraffe_subslit_get_max(fibers);
332 if (ssn < 0 || ssn > ssn_max) {
336 cpl_table_unselect_all((cpl_table *)fibers);
337 cpl_table_or_selected_int((cpl_table *)fibers,
"SSN", CPL_EQUAL_TO, ssn);
339 _fibers = cpl_table_extract_selected((cpl_table *)fibers);
347 _giraffe_subslit_range(
const cpl_table *subslit,
const cpl_image *locy,
348 const cpl_image *locw, cxdouble *ymin, cxdouble *ymax)
351 const cxchar *idx = NULL;
357 const cxdouble *_locy = NULL;
358 const cxdouble *_locw = NULL;
360 cxdouble _ymin = CX_MAXDOUBLE;
363 cx_assert(subslit != NULL);
364 cx_assert(locy != NULL);
365 cx_assert(locw != NULL);
369 ns = cpl_image_get_size_x(locy);
370 nx = cpl_image_get_size_y(locy);
372 _locy = cpl_image_get_data_const(locy);
373 _locw = cpl_image_get_data_const(locw);
375 for (i = 0; i < cpl_table_get_nrow((cpl_table *)subslit); i++) {
378 cxint cs = cpl_table_get_int((cpl_table *)subslit, idx, i, NULL) - 1;
380 for (j = 0; j < nx; j++) {
382 register cxint k = j * ns + cs;
384 cxdouble ylower = _locy[k] - _locw[k];
385 cxdouble yupper = _locy[k] + _locw[k];
387 _ymin = CX_MIN(_ymin, ylower);
388 _ymax = CX_MAX(_ymax, yupper);
412 _giraffe_get_residuals(cpl_image *residuals,
const cpl_image *positions,
413 const cpl_image *fit)
421 const cxdouble *_positions = NULL;
422 const cxdouble *_fit = NULL;
424 cxdouble *_residuals = NULL;
427 cx_assert(residuals != NULL);
428 cx_assert(positions != NULL);
429 cx_assert(fit != NULL);
431 nfibers = cpl_image_get_size_x(positions);
432 nlines = cpl_image_get_size_y(positions);
433 nx = cpl_image_get_size_y(fit);
435 cx_assert(nfibers == cpl_image_get_size_x(residuals));
436 cx_assert(nlines == cpl_image_get_size_y(residuals));
438 _residuals = cpl_image_get_data(residuals);
439 _positions = cpl_image_get_data_const(positions);
440 _fit = cpl_image_get_data_const(fit);
442 for (i = 0; i < nlines; i++) {
446 for (j = 0; j < nfibers; j++) {
448 register cxdouble line_pos = _positions[i * nfibers + j];
450 line_pos = CX_MIN(CX_MAX(line_pos, 0.), nx - 1);
451 _residuals[i * nfibers + j] = _fit[(cxint)line_pos * nfibers + j];
463 _giraffe_apply_residuals(cpl_image *xccd,
const cpl_image *residuals,
464 const cpl_image *lflags, cxdouble value)
467 cx_assert(xccd != NULL);
468 cx_assert(residuals != NULL);
470 cpl_image_subtract(xccd, residuals);
472 if (lflags != NULL) {
474 const cxint *_lflags = cpl_image_get_data_const(lflags);
477 cxint nfibers = cpl_image_get_size_x(xccd);
478 cxint nlines = cpl_image_get_size_y(xccd);
480 cxdouble *_xccd = cpl_image_get_data(xccd);
483 cx_assert(nfibers == cpl_image_get_size_x(lflags));
484 cx_assert(nlines == cpl_image_get_size_y(lflags));
486 for (i = 0; i < nlines; i++) {
490 for (j = 0; j < nfibers; j++) {
492 if (_lflags[i * nfibers + j] > 0) {
493 _xccd[i * nfibers + j] = value;
508 _giraffe_linelist_setup(GiTable *lines,
GiGrating *grating,
512 const cxchar *
const fctid =
"_giraffe_linelist_setup";
515 const cxdouble fraction = 500.;
523 cxdouble margin = 0.;
525 cpl_table *_lines = NULL;
529 cx_assert(lines != NULL);
530 cx_assert(grating != NULL);
531 cx_assert(config != NULL);
536 if (_lines == NULL) {
540 if (!cpl_table_has_column(_lines,
"WLEN") ||
541 !cpl_table_has_column(_lines,
"FLUX")) {
551 nlines = cpl_table_get_nrow(_lines);
552 cpl_table_unselect_all(_lines);
567 margin = (wlmax - wlmin) / fraction;
569 cpl_msg_debug(fctid,
"Selecting wavelength range [%.4f, %.4f[ [nm] with "
570 "margin %.4f nm.", wlmin, wlmax, margin);
572 cpl_table_or_selected_double(_lines,
"WLEN", CPL_LESS_THAN,
574 cpl_table_or_selected_double(_lines,
"WLEN", CPL_NOT_LESS_THAN,
577 cpl_table_erase_selected(_lines);
579 if (cpl_table_get_nrow(_lines) <= 0) {
580 cpl_msg_debug(fctid,
"Invalid line list! All lines have been "
585 nreject = nlines - cpl_table_get_nrow(_lines);
586 cpl_msg_debug(fctid,
"%d of %d lines rejected because of wavelength "
587 "range.", nreject, nlines);
594 nlines = cpl_table_get_nrow(_lines);
601 cpl_propertylist *sorting_order = NULL;
604 if (line_count > nlines) {
605 cpl_msg_debug(fctid,
"Too few lines in line list for brightness "
612 cpl_msg_debug(fctid,
"Skipping brightness selection!");
617 sorting_order = cpl_propertylist_new();
618 cpl_propertylist_append_bool(sorting_order,
"FLUX", 1);
620 cpl_table_sort(_lines, sorting_order);
622 cpl_propertylist_delete(sorting_order);
623 sorting_order = NULL;
625 cpl_table_select_all(_lines);
627 for (i = 0; i < line_count; i++) {
628 cpl_table_unselect_row(_lines, i);
631 cpl_table_erase_selected(_lines);
633 if (cpl_table_get_nrow(_lines) <= 0) {
637 sorting_order = cpl_propertylist_new();
638 cpl_propertylist_append_bool(sorting_order,
"WLEN", 0);
640 cpl_table_sort(_lines, sorting_order);
642 cpl_propertylist_delete(sorting_order);
643 sorting_order = NULL;
649 cpl_table_select_all(_lines);
650 cpl_table_and_selected_double(_lines,
"FLUX", CPL_NOT_GREATER_THAN,
653 cpl_table_erase_selected(_lines);
655 if (cpl_table_get_nrow(_lines) <= 0) {
656 cpl_msg_debug(fctid,
"Invalid line brightness! All lines have "
663 nreject = nlines - cpl_table_get_nrow(_lines);
664 cpl_msg_debug(fctid,
"%d of %d lines rejected because brightness "
665 "criteria.", nreject, nlines);
673 inline static cpl_table *
674 _giraffe_linelist_select(
const GiTable *lines,
const GiImage *spectra,
675 const GiGrating *grating, cxdouble width,
679 const cxchar *
const fctid =
"_giraffe_linelist_select";
687 cxdouble separation = 0.;
689 cpl_image *_spectra = NULL;
691 cpl_table *_lines = NULL;
694 cx_assert(lines != NULL);
695 cx_assert(spectra != NULL);
696 cx_assert(grating != NULL);
697 cx_assert(config != NULL);
700 cx_assert(_spectra != NULL);
704 if (_lines == NULL) {
708 nlines = cpl_table_get_nrow(_lines);
716 scale = fabs(cpl_image_get_size_y(_spectra)) / grating->
band;
719 cpl_msg_debug(fctid,
"Estimated wavelength scale: %.4e nm/pxl",
721 cpl_msg_debug(fctid,
"Minimum required line separation: %.4f nm (%.4f "
722 "pxl)", separation, separation * scale);
738 cpl_table_unselect_all(_lines);
740 for (i = 0; i < cpl_table_get_nrow(_lines); i++) {
744 register cxdouble w = cpl_table_get(_lines,
"WLEN", i, NULL);
745 register cxdouble f = cpl_table_get(_lines,
"FLUX", i, NULL);
748 for (j = 0; j < cpl_table_get_nrow(_lines); j++) {
752 register cxdouble _w = cpl_table_get(_lines,
"WLEN", j, NULL);
753 register cxdouble _f = cpl_table_get(_lines,
"FLUX", j, NULL);
756 if (fabs(w - _w) < separation &&
757 f / _f < config->line_fluxratio) {
759 cpl_table_select_row(_lines, i);
770 cpl_table_erase_selected(_lines);
772 if (cpl_table_get_nrow(_lines) <= 0) {
773 cpl_table_delete(_lines);
777 nreject = nlines - cpl_table_get_nrow(_lines);
778 cpl_msg_debug(fctid,
"%d of %d lines rejected due to crowding.",
791 cpl_msg_debug(fctid,
"Removing lines with non-zero line quality.");
793 nlines = cpl_table_get_nrow(_lines);
794 cpl_table_unselect_all(_lines);
796 if (cpl_table_has_column(_lines,
"FLAGS")) {
798 cpl_table_or_selected_int(_lines,
"FLAGS", CPL_NOT_EQUAL_TO, 0);
803 if (cpl_table_has_column(_lines,
"COMMENT")) {
805 for (i = 0; i < nlines; i++) {
807 cxchar *s = cx_strdup(cpl_table_get_string(_lines,
810 if (strlen(cx_strstrip(s)) > 3) {
811 cpl_table_select_row(_lines, i);
821 cpl_msg_debug(fctid,
"No comments found in line list! No line "
822 "quality checks will be done!");
828 cpl_table_erase_selected(_lines);
830 if (cpl_table_get_nrow(_lines) <= 0) {
831 cpl_msg_debug(fctid,
"Invalid line list! All lines have been "
833 cpl_table_delete(_lines);
837 nreject = nlines - cpl_table_get_nrow(_lines);
838 cpl_msg_debug(fctid,
"%d of %d lines rejected because of line quality.",
847 inline static cpl_image *
848 _giraffe_line_abscissa(
const cpl_table *lines,
const GiTable *slitgeometry,
849 const GiTable *fibers,
const GiWlSolution *solution,
850 const GiLocalization *localization, cxbool residuals)
853 const cxchar *
const fctid =
"_giraffe_line_abscissa";
856 const cxchar *idx = NULL;
862 cpl_table *_lines = NULL;
863 cpl_table *_fibers = NULL;
864 cpl_table *_slitgeometry = NULL;
866 cpl_image *abscissa = NULL;
869 cx_assert(lines != NULL);
870 cx_assert(slitgeometry != NULL);
871 cx_assert(fibers != NULL);
872 cx_assert(solution != NULL);
874 _lines = (cpl_table *)lines;
877 cx_assert(_fibers != NULL);
880 cx_assert(_slitgeometry != NULL);
883 nlines = cpl_table_get_nrow(_lines);
884 nfibers = cpl_table_get_nrow(_fibers);
886 if (nfibers != cpl_table_get_nrow(_slitgeometry)) {
887 cpl_error_set(fctid, CPL_ERROR_ILLEGAL_INPUT);
895 cpl_error_set(fctid, CPL_ERROR_ILLEGAL_INPUT);
900 if (residuals == TRUE) {
902 if (localization == NULL) {
903 cpl_error_set(fctid, CPL_ERROR_ILLEGAL_INPUT);
907 if (localization->locy == NULL || localization->locw == NULL) {
908 cpl_error_set(fctid, CPL_ERROR_DATA_NOT_FOUND);
913 if (giraffe_wlsolution_get_residuals(solution) == NULL) {
914 cpl_error_set(fctid, CPL_ERROR_DATA_NOT_FOUND);
921 abscissa = cpl_image_new(nfibers, nlines, CPL_TYPE_DOUBLE);
923 for (i = 0; i < nfibers; i++) {
927 cxdouble xf = cpl_table_get(_slitgeometry,
"XF", i, NULL);
928 cxdouble yf = cpl_table_get(_slitgeometry,
"YF", i, NULL);
929 cxdouble *data = cpl_image_get_data(abscissa);
932 for (j = 0; j < nlines; j++) {
936 cxdouble lambda = cpl_table_get(_lines,
"WLEN", j, NULL);
941 xccd = giraffe_wlsolution_compute_pixel(solution, lambda, xf, yf,
945 cpl_image_delete(abscissa);
949 if (residuals == TRUE) {
951 cxint cs = cpl_table_get_int(_fibers, idx, i, NULL) - 1;
958 cx_assert(_locy != NULL);
960 if (xccd > 0. && xccd < cpl_image_get_size_y(_locy)) {
964 yccd = _giraffe_get_fiber_position(_locy, cs, xccd);
965 xres = giraffe_wlsolution_compute_residual(solution,
973 data[j * nfibers + i] = xccd;
984 inline static cpl_image *
985 _giraffe_line_ordinate(GiTable *lines,
const GiTable *slitgeometry,
986 const GiWlSolution *solution)
1005 _giraffe_line_fit_setup(GiModel *model, cxdouble width, cxint xmin,
1006 const cpl_matrix *y,
const cpl_matrix *sigma,
1007 const GiLineParams *setup, cxint *lflags)
1014 cxdouble amplitude = 0.;
1015 cxdouble background = 0.;
1016 cxdouble _sigma = 0.;
1018 cpl_matrix *_y = NULL;
1021 cx_assert(model != NULL);
1022 cx_assert(y != NULL);
1023 cx_assert(setup != NULL);
1024 cx_assert(lflags != NULL);
1027 if (*lflags != LF_R_NONE) {
1042 for (k = 0; k < cpl_matrix_get_nrow((cpl_matrix*)y); k++) {
1043 if (cpl_matrix_get((cpl_matrix *)y, k, 0) >= amplitude) {
1046 amplitude = cpl_matrix_get((cpl_matrix *)y, k, 0);
1053 _y = cpl_matrix_duplicate((cpl_matrix *)y);
1057 background = 0.5 * (cpl_matrix_get(_y, 0, 0) + cpl_matrix_get(_y, 1, 0));
1058 cpl_matrix_delete(_y);
1068 _sigma = cpl_matrix_get((cpl_matrix *)sigma, xline, 0) * setup->thres;
1070 if (amplitude <= _sigma || amplitude > setup->satlv) {
1071 *lflags |= LF_R_AMPLI;
1075 giraffe_model_set_parameter(model,
"Amplitude", amplitude - background);
1076 giraffe_model_set_parameter(model,
"Center", center);
1077 giraffe_model_set_parameter(model,
"Background", background);
1078 giraffe_model_set_parameter(model,
"Width1", width);
1080 if (strncmp(giraffe_model_get_name(model),
"psfexp", 6) == 0) {
1082 cxdouble width2 = setup->psfexp < 0. ? -setup->psfexp : setup->psfexp;
1084 giraffe_model_set_parameter(model,
"Width2", width2);
1092 if (setup->psfexp >= 0.) {
1093 giraffe_model_freeze_parameter(model,
"Width2");
1096 giraffe_model_thaw_parameter(model,
"Width2");
1107 _giraffe_line_fit(GiLineData *lines,
const cpl_image *positions, cxint width,
1108 const GiExtraction *extraction,
const GiTable *fibers,
1109 const GiImage *locy,
const GiLineParams *setup)
1112 const cxchar *
const fctid =
"_giraffe_line_fit";
1115 const cxchar *idx = NULL;
1121 const cxdouble LOG2 = log(2.);
1122 const cxdouble fwhm_ratio = 2. * sqrt(2. * LOG2);
1124 cpl_image *_spectra = NULL;
1125 cpl_image *_errors = NULL;
1126 cpl_image *_locy = NULL;
1128 cpl_matrix *x = NULL;
1129 cpl_matrix *y = NULL;
1130 cpl_matrix *sigma = NULL;
1132 cpl_table *_fibers = NULL;
1134 GiModel *model = NULL;
1137 cx_assert(positions != NULL);
1138 cx_assert(width > 0);
1140 cx_assert(extraction != NULL);
1141 cx_assert(extraction->spectra != NULL && extraction->error != NULL);
1143 cx_assert(fibers != NULL);
1144 cx_assert(locy != NULL);
1145 cx_assert(setup != NULL);
1149 cx_assert(_fibers != NULL);
1152 cx_assert(_spectra != NULL);
1155 cx_assert(_errors != NULL);
1158 cx_assert(_locy != NULL);
1160 nfibers = cpl_table_get_nrow(_fibers);
1162 cx_assert(nfibers == cpl_image_get_size_x(_spectra));
1163 cx_assert(nfibers == cpl_image_get_size_x(_errors));
1170 cx_assert(idx != NULL);
1172 nlines = cpl_image_get_size_y(positions);
1179 if (strcmp(setup->model,
"gaussian") != 0 &&
1180 strcmp(setup->model,
"psfexp") != 0 &&
1181 strcmp(setup->model,
"psfexp2") != 0) {
1182 cpl_error_set(fctid, CPL_ERROR_ILLEGAL_INPUT);
1186 model = giraffe_model_new(setup->model);
1188 if (giraffe_model_get_type(model) != GI_MODEL_LINE) {
1189 giraffe_model_delete(model);
1193 giraffe_model_thaw(model);
1195 giraffe_model_set_iterations(model, setup->fit.iterations);
1196 giraffe_model_set_tests(model, setup->fit.tests);
1197 giraffe_model_set_delta(model, setup->fit.delta);
1204 x = cpl_matrix_new(width, 1);
1205 y = cpl_matrix_new(width, 1);
1206 sigma = cpl_matrix_new(width, 1);
1208 for (i = 0; i < nfibers; i++) {
1212 for (j = 0; j < nlines; j++) {
1215 cxint lflags = LF_R_NONE;
1216 cxint iterations = 0;
1220 cxint nx = cpl_image_get_size_y(_spectra);
1224 cxdouble lwidth = 0.;
1225 cxdouble amplitude = 0.;
1226 cxdouble background = 0.;
1227 cxdouble center = 0.;
1228 cxdouble width1 = 0.;
1229 cxdouble exponent = 0.;
1230 cxdouble error = 0.;
1231 cxdouble gwidth = 0.;
1233 const cxdouble *_positions = cpl_image_get_data_const(positions);
1240 xccd = _positions[j * nfibers + i];
1245 if (0 < xccd && xccd < nx) {
1247 cxint cs = cpl_table_get_int(_fibers, idx, i, NULL) - 1;
1255 xmin = (cxint)(xccd - 0.5 * width + 0.5);
1256 xmax = (cxint)(xccd + 0.5 * width + 0.5);
1258 xmin = CX_MAX(CX_MIN(xmin, nx - 1), 0);
1259 xmax = CX_MAX(CX_MIN(xmax, nx - 1), 0);
1261 ndata = xmax - xmin;
1268 yccd = _giraffe_get_fiber_position(_locy, cs, xccd);
1279 lflags |= LF_R_XCCD;
1287 if (ndata != cpl_matrix_get_nrow(x)) {
1288 cpl_matrix_set_size(x, ndata, 1);
1289 cpl_matrix_set_size(y, ndata, 1);
1290 cpl_matrix_set_size(sigma, ndata, 1);
1293 for (k = 0; k < ndata; k++) {
1297 cxdouble *sdata = cpl_image_get_data(_spectra);
1298 cxdouble *edata = cpl_image_get_data(_errors);
1300 cpl_matrix_set(x, k, 0, xmin + k);
1301 cpl_matrix_set(y, k, 0, sdata[l * nfibers + i]);
1302 cpl_matrix_set(sigma, k, 0, edata[l * nfibers + i]);
1319 if (strcmp(setup->model,
"psfexp") == 0) {
1321 exponent = fabs(setup->psfexp);
1323 lwidth = pow(0.5 * setup->grwid * nx, exponent) / LOG2;
1326 else if (strcmp(setup->model,
"psfexp2") == 0) {
1328 exponent = fabs(setup->psfexp);
1330 lwidth = setup->grwid * nx / (2. * pow(LOG2, 1. / exponent));
1333 else if (strcmp(setup->model,
"gaussian") == 0) {
1335 lwidth = setup->grwid * nx / fwhm_ratio;
1344 gi_error(
"Unsupported line model encountered!");
1355 _giraffe_line_fit_setup(model, lwidth, xmin, y, sigma, setup,
1359 if (lflags == LF_R_NONE) {
1361 cxint xline = giraffe_model_get_parameter(model,
"Center");
1363 cxdouble hwidth = 0.;
1372 status = giraffe_model_fit(model, x, y, sigma);
1375 amplitude = giraffe_model_get_parameter(model,
"Amplitude");
1376 background = giraffe_model_get_parameter(model,
"Background");
1377 center = giraffe_model_get_parameter(model,
"Center");
1385 if (strcmp(setup->model,
"psfexp") == 0) {
1387 width1 = giraffe_model_get_parameter(model,
"Width1");
1388 exponent = giraffe_model_get_parameter(model,
"Width2");
1391 gwidth = 2. * pow(width1 * LOG2, 1. / exponent);
1394 else if (strcmp(setup->model,
"psfexp2") == 0) {
1396 width1 = giraffe_model_get_parameter(model,
"Width1");
1397 exponent = giraffe_model_get_parameter(model,
"Width2");
1400 gwidth = 2. * pow(LOG2, 1. / exponent) * width1;
1403 else if (strcmp(setup->model,
"gaussian") == 0) {
1405 width1 = giraffe_model_get_parameter(model,
"Width1");
1408 gwidth = width1 * fwhm_ratio;
1417 gi_error(
"Unsupported line model encountered!");
1421 hwidth = gwidth / 2.;
1422 iterations = giraffe_model_get_position(model);
1433 lflags |= LF_R_ERROR;
1437 if (iterations >= giraffe_model_get_iterations(model)) {
1440 lflags |= LF_R_NITER;
1444 if (xmin > center || center > xmax) {
1447 lflags |= LF_R_CENTR;
1451 if ((center - hwidth) < xmin) {
1454 lflags |= LF_R_LEFT;
1458 if ((center + hwidth) > xmax) {
1461 lflags |= LF_R_RIGHT;
1465 if ((center - xline) >= setup->offst) {
1468 lflags |= LF_R_OFFST;
1472 if (width1 < 0. || exponent < 0.) {
1475 lflags |= LF_R_BADLN;
1479 if (gwidth > (xmax - xmin)) {
1482 lflags |= LF_R_WIDTH;
1486 if (gwidth < (setup->grwid * nx * setup->wfact)) {
1489 lflags |= LF_R_RESOL;
1493 if (gwidth > (setup->grwid * nx / setup->wfact)) {
1496 lflags |= LF_R_RESOL;
1509 giraffe_linedata_set_status(lines, i, j, lflags);
1511 giraffe_linedata_set(lines,
"Iterations", i, j,iterations);
1512 giraffe_linedata_set(lines,
"Chi-square", i, j,
1513 giraffe_model_get_chisq(model));
1514 giraffe_linedata_set(lines,
"DoF", i, j,
1515 giraffe_model_get_df(model));
1516 giraffe_linedata_set(lines,
"R-square", i, j,
1517 giraffe_model_get_rsquare(model));
1518 giraffe_linedata_set(lines,
"Xccd", i, j, xccd);
1519 giraffe_linedata_set(lines,
"Yccd", i, j, yccd);
1529 giraffe_linedata_set(lines,
"Amplitude", i, j, amplitude);
1530 giraffe_linedata_set(lines,
"Background", i, j, background);
1531 giraffe_linedata_set(lines,
"Center", i, j, center);
1532 giraffe_linedata_set(lines,
"Width1", i, j, width1);
1534 if (strncmp(setup->model,
"psfexp", 6) == 0) {
1535 giraffe_linedata_set(lines,
"Width2", i, j, exponent);
1538 giraffe_linedata_set(lines,
"FWHM", i, j, gwidth);
1542 error = giraffe_model_get_sigma(model,
"Amplitude");
1543 giraffe_linedata_set(lines,
"dAmplitude", i, j, error);
1545 error = giraffe_model_get_sigma(model,
"Center");
1546 giraffe_linedata_set(lines,
"dCenter", i, j, error);
1548 error = giraffe_model_get_sigma(model,
"Background");
1549 giraffe_linedata_set(lines,
"dBackground", i, j, error);
1551 error = giraffe_model_get_sigma(model,
"Width1");
1552 giraffe_linedata_set(lines,
"dWidth1", i, j, error);
1554 if (strncmp(setup->model,
"psfexp", 6) == 0) {
1555 error = giraffe_model_get_sigma(model,
"Width2");
1556 giraffe_linedata_set(lines,
"dWidth2", i, j, error);
1563 cpl_matrix_delete(x);
1564 cpl_matrix_delete(y);
1565 cpl_matrix_delete(sigma);
1567 giraffe_model_delete(model);
1574 inline static cpl_image *
1575 _giraffe_psf_fit(GiLineData *lines,
const GiLocalization *localization,
1576 GiTable *fibers, GiTable *slitgeometry, GiSCFitParams *setup)
1579 const cxchar *
const fctid =
"_giraffe_psf_fit";
1586 cxint nsubslits = 1;
1589 cpl_table *_fibers = NULL;
1591 cpl_image *locy = NULL;
1592 cpl_image *locw = NULL;
1593 cpl_image *psfwidth = NULL;
1596 cx_assert(lines != NULL);
1597 cx_assert(localization != NULL);
1598 cx_assert(fibers != NULL);
1599 cx_assert(slitgeometry != NULL);
1600 cx_assert(setup != NULL);
1603 cx_assert(_fibers != NULL);
1606 cx_assert(locy != NULL);
1609 cx_assert(locw != NULL);
1611 nx = cpl_image_get_size_y(locy);
1612 nlines = giraffe_linedata_lines(lines);
1614 psfwidth = cpl_image_new(cpl_table_get_nrow(_fibers), nx,
1617 if (setup->subslits == TRUE) {
1618 nsubslits = _giraffe_subslit_get_max(_fibers);
1621 for (i = 0; i < nsubslits; i++) {
1628 cxint iterations = 0;
1634 cxdouble ratio = 1.;
1636 cpl_matrix *xss = NULL;
1637 cpl_matrix *yss = NULL;
1638 cpl_matrix *wss = NULL;
1639 cpl_matrix *sss = NULL;
1640 cpl_matrix *nss = NULL;
1641 cpl_matrix *lss = NULL;
1642 cpl_matrix *base = NULL;
1643 cpl_matrix *fit = NULL;
1644 cpl_matrix *coeff = NULL;
1645 cpl_matrix *chebyshev = NULL;
1647 cpl_table *subslit = NULL;
1649 GiChebyshev2D *psffit = NULL;
1652 if (setup->subslits == TRUE) {
1653 subslit = _giraffe_subslit_get(_fibers, i + 1);
1654 ssn = cpl_table_get_int(subslit,
"SSN", 0, NULL);
1656 cx_assert(ssn == i + 1);
1659 subslit = cpl_table_duplicate(_fibers);
1663 if (subslit == NULL) {
1667 _giraffe_subslit_range(subslit, locy, locw, &ymin, &ymax);
1669 nfibers = cpl_table_get_nrow(subslit);
1670 ndata = nfibers * nlines;
1673 xss = cpl_matrix_new(ndata, 1);
1674 yss = cpl_matrix_new(ndata, 1);
1675 wss = cpl_matrix_new(1, ndata);
1676 sss = cpl_matrix_new(ndata, 1);
1677 nss = cpl_matrix_new(ndata, 1);
1678 lss = cpl_matrix_new(ndata, 1);
1688 for (j = 0; j < nfibers; j++) {
1691 cxint n = cpl_table_get_int(subslit,
"INDEX", j, NULL) - 1;
1693 for (l = 0; l < nlines; l++) {
1695 cxdouble value = 0.;
1696 cxdouble yccd = giraffe_linedata_get(lines,
"Yccd", n, l);
1698 if (giraffe_linedata_get_status(lines, n, l) != 0) {
1702 if (yccd < ymin || yccd > ymax) {
1706 value = giraffe_linedata_get(lines,
"Xccd", n, l);
1707 cpl_matrix_set(xss, k, 0, value);
1709 cpl_matrix_set(yss, k, 0, yccd);
1718 value = giraffe_linedata_get(lines,
"FWHM", n, l);
1719 cpl_matrix_set(wss, 0, k, value);
1721 value = giraffe_linedata_get(lines,
"dWidth1", n, l);
1722 cpl_matrix_set(sss, k, 0, value);
1724 cpl_matrix_set(nss, k, 0, n);
1725 cpl_matrix_set(lss, k, 0, l);
1734 cpl_msg_debug(fctid,
"Skipping subslit %d: No input lines left! "
1735 "All lines have non-zero status or are beyond the "
1736 "subslit boundaries (%.4f, %.4f).", ssn, ymin, ymax);
1744 cpl_matrix_set_size(xss, k, 1);
1745 cpl_matrix_set_size(yss, k, 1);
1746 cpl_matrix_set_size(wss, 1, k);
1747 cpl_matrix_set_size(sss, k, 1);
1748 cpl_matrix_set_size(nss, k, 1);
1749 cpl_matrix_set_size(lss, k, 1);
1758 accepted = cpl_matrix_get_ncol(wss);
1761 while (accepted > 0 && iterations < setup->clip.iterations &&
1762 ratio > setup->clip.fraction) {
1764 base = giraffe_chebyshev_base2d(0., ymin, nx, ymax - ymin + 1.,
1765 setup->fit.xorder + 1,
1766 setup->fit.yorder + 1, xss, yss);
1768 if (coeff != NULL) {
1769 cpl_matrix_delete(coeff);
1775 if (coeff == NULL) {
1776 cpl_msg_debug(fctid,
"Error solving linear system for "
1777 "subslit %d, skipping subslit.", ssn);
1781 fit = cpl_matrix_product_create(coeff, base);
1785 for (j = 0; j < cpl_matrix_get_ncol(fit); j++) {
1787 cxdouble _fit = cpl_matrix_get(fit, 0, j);
1788 cxdouble _wss = cpl_matrix_get(wss, 0, j);
1789 cxdouble _sss = cpl_matrix_get(sss, j, 0);
1791 if (fabs(_fit - _wss) >= setup->clip.level * _sss) {
1793 cxint n = (cxint)cpl_matrix_get(nss, j, 0);
1794 cxint l = (cxint)cpl_matrix_get(lss, j, 0);
1800 giraffe_linedata_set_status(lines, n, l, LF_R_PSFIT);
1805 cpl_matrix_set(xss, k, 0, cpl_matrix_get(xss, j, 0));
1806 cpl_matrix_set(yss, k, 0, cpl_matrix_get(yss, j, 0));
1807 cpl_matrix_set(wss, 0, k, cpl_matrix_get(wss, 0, j));
1808 cpl_matrix_set(sss, k, 0, cpl_matrix_get(sss, j, 0));
1809 cpl_matrix_set(nss, k, 0, cpl_matrix_get(nss, j, 0));
1810 cpl_matrix_set(lss, k, 0, cpl_matrix_get(lss, j, 0));
1815 cpl_matrix_delete(base);
1816 cpl_matrix_delete(fit);
1818 if (k == accepted) {
1828 ratio = (cxdouble)accepted / (cxdouble)total;
1830 cpl_matrix_set_size(xss, k, 1);
1831 cpl_matrix_set_size(yss, k, 1);
1832 cpl_matrix_set_size(wss, 1, k);
1833 cpl_matrix_set_size(sss, k, 1);
1834 cpl_matrix_set_size(nss, k, 1);
1835 cpl_matrix_set_size(lss, k, 1);
1843 if (accepted == 0) {
1844 cpl_msg_debug(fctid,
"Subslit %d: All lines rejected.", ssn);
1848 if (coeff == NULL) {
1854 cpl_matrix_delete(xss);
1855 cpl_matrix_delete(yss);
1856 cpl_matrix_delete(wss);
1857 cpl_matrix_delete(sss);
1858 cpl_matrix_delete(nss);
1859 cpl_matrix_delete(lss);
1866 xss = cpl_matrix_new(nx * nfibers, 1);
1867 yss = cpl_matrix_new(nx * nfibers, 1);
1869 giraffe_compute_image_coordinates(nx, nfibers, xss, NULL);
1871 for (j = 0; j < cpl_table_get_nrow(subslit); j++) {
1876 cxint ns = cpl_image_get_size_x(locy);
1877 cxint cs = cpl_table_get_int(subslit, idx, j, NULL) - 1;
1879 cxdouble *data = cpl_image_get_data(locy);
1882 for (l = 0; l < nx; l++) {
1883 cpl_matrix_set(yss, l * nfibers + j, 0, data[l * ns + cs]);
1893 base = giraffe_chebyshev_base2d(0., ymin, nx, ymax - ymin + 1.,
1894 setup->fit.xorder + 1,
1895 setup->fit.yorder + 1, xss, yss);
1897 fit = cpl_matrix_product_create(coeff, base);
1899 cpl_matrix_delete(xss);
1902 cpl_matrix_delete(yss);
1915 chebyshev = cpl_matrix_wrap(setup->fit.xorder + 1,
1916 setup->fit.yorder + 1,
1917 cpl_matrix_get_data(coeff));
1919 psffit = giraffe_chebyshev2d_new(setup->fit.xorder, setup->fit.yorder);
1920 status = giraffe_chebyshev2d_set(psffit, 0., nx, ymin, ymax,
1925 giraffe_chebyshev2d_delete(psffit);
1927 cpl_matrix_unwrap(chebyshev);
1929 cpl_matrix_delete(base);
1930 cpl_matrix_delete(coeff);
1931 cpl_matrix_delete(fit);
1933 cpl_table_delete(subslit);
1935 cpl_image_delete(psfwidth);
1941 cpl_matrix_unwrap(chebyshev);
1944 giraffe_chebyshev2d_delete(psffit);
1952 for (j = 0; j < cpl_table_get_nrow(subslit); j++) {
1955 cxint n = cpl_table_get_int(subslit,
"INDEX", j, NULL) - 1;
1956 cxint ns = cpl_table_get_nrow(_fibers);
1958 cxdouble *data = cpl_image_get_data(psfwidth);
1960 for (l = 0; l < nx; l++) {
1961 data[l * ns + n] = cpl_matrix_get(fit, 0, l * nfibers + j);
1966 cpl_matrix_delete(base);
1967 cpl_matrix_delete(coeff);
1968 cpl_matrix_delete(fit);
1970 cpl_table_delete(subslit);
1980 _giraffe_opticalmodel_fit(GiWlSolution *solution, GiLineData *lines,
1981 GiTable *fibers, GiTable *slitgeometry,
1982 GiOpticalModelParams *setup)
1985 const cxchar *
const fctid =
"_giraffe_opticalmodel_fit";
1994 cpl_matrix *x = NULL;
1995 cpl_matrix *y = NULL;
1996 cpl_matrix *sigma = NULL;
1998 cpl_table *_fibers = NULL;
1999 cpl_table *_slitgeometry = NULL;
2001 GiModel *model = NULL;
2004 cx_assert(solution != NULL);
2005 cx_assert(lines != NULL);
2006 cx_assert(fibers != NULL);
2007 cx_assert(slitgeometry != NULL);
2008 cx_assert(setup != NULL);
2011 cx_assert(_fibers != NULL);
2014 cx_assert(_slitgeometry != NULL);
2016 model = giraffe_wlsolution_model(solution);
2023 ndata = giraffe_linedata_lines(lines) * giraffe_linedata_fibers(lines);
2025 x = cpl_matrix_new(ndata, giraffe_model_count_arguments(model));
2026 y = cpl_matrix_new(ndata, 1);
2027 sigma = cpl_matrix_new(ndata, 1);
2029 for (i = 0; i < giraffe_linedata_fibers(lines); i++) {
2033 cxdouble xf = cpl_table_get(_slitgeometry,
"XF", i, NULL);
2034 cxdouble yf = cpl_table_get(_slitgeometry,
"YF", i, NULL);
2037 for (j = 0; j < giraffe_linedata_lines(lines); j++) {
2039 if (giraffe_linedata_get_status(lines, i, j) != 0) {
2046 if (giraffe_linedata_get(lines,
"dCenter", i, j) <= 0.) {
2050 cpl_matrix_set(x, ngood, 0,
2051 giraffe_linedata_get_wavelength(lines, j));
2052 cpl_matrix_set(x, ngood, 1, xf);
2053 cpl_matrix_set(x, ngood, 2, yf);
2055 cpl_matrix_set(y, ngood, 0,
2056 giraffe_linedata_get(lines,
"Center", i, j));
2057 cpl_matrix_set(sigma, ngood, 0,
2058 giraffe_linedata_get(lines,
"dCenter", i, j));
2066 cpl_msg_debug(fctid,
"Using %d of %d line positions for optical "
2067 "model fit.", ngood, ndata);
2071 cpl_matrix_delete(x);
2072 cpl_matrix_delete(y);
2073 cpl_matrix_delete(sigma);
2083 cpl_matrix_set_size(x, ngood, giraffe_model_count_arguments(model));
2084 cpl_matrix_set_size(y, ngood, 1);
2085 cpl_matrix_set_size(sigma, ngood, 1);
2092 giraffe_model_freeze(model);
2094 if (setup->flags & OPTM_FLENGTH) {
2095 giraffe_model_thaw_parameter(model,
"FocalLength");
2098 if (setup->flags & OPTM_GCAMERA) {
2099 giraffe_model_thaw_parameter(model,
"Magnification");
2102 if (setup->flags & OPTM_THETA) {
2103 giraffe_model_thaw_parameter(model,
"Angle");
2106 if (strcmp(giraffe_model_get_name(model),
"xoptmod2") == 0) {
2107 if (setup->flags & OPTM_SX) {
2108 giraffe_model_thaw_parameter(model,
"Sdx");
2111 if (setup->flags & OPTM_SY) {
2112 giraffe_model_thaw_parameter(model,
"Sdy");
2115 if (setup->flags & OPTM_SPHI) {
2116 giraffe_model_thaw_parameter(model,
"Sphi");
2120 giraffe_model_set_iterations(model, setup->fit.iterations);
2121 giraffe_model_set_tests(model, setup->fit.tests);
2122 giraffe_model_set_delta(model, setup->fit.delta);
2129 status = giraffe_model_fit(model, x, y, sigma);
2133 cpl_matrix_delete(x);
2134 cpl_matrix_delete(y);
2135 cpl_matrix_delete(sigma);
2141 cpl_matrix_delete(x);
2142 cpl_matrix_delete(y);
2143 cpl_matrix_delete(sigma);
2151 _giraffe_opticalmodel_format(cx_string *s,
const GiModel *model,
2152 GiOpticalModelInfo info)
2155 const cxchar *name = NULL;
2157 cxbool offsets = FALSE;
2162 cx_assert(s != NULL);
2164 if (model == NULL) {
2168 name = giraffe_model_get_name(model);
2170 if (name == NULL || strncmp(name,
"xoptmod", 7) != 0) {
2174 if (strncmp(name,
"xoptmod2", 8) == 0) {
2181 case GI_OPTM_PARAMETER_VALUES:
2184 cxdouble fcoll = 0.;
2186 cxdouble theta = 0.;
2188 fcoll = giraffe_model_get_parameter(model,
"FocalLength");
2189 gcam = giraffe_model_get_parameter(model,
"Magnification");
2190 theta = giraffe_model_get_parameter(model,
"Angle");
2192 cx_string_sprintf(s,
"focal length = %.6f, camera "
2193 "magnification = %.6f, grating angle = %.9f",
2194 fcoll, gcam, theta);
2196 if (offsets == TRUE) {
2202 cx_string *_s = cx_string_new();
2204 sdx = giraffe_model_get_parameter(model,
"Sdx");
2205 sdy = giraffe_model_get_parameter(model,
"Sdy");
2206 sphi = giraffe_model_get_parameter(model,
"Sphi");
2208 cx_string_sprintf(_s,
", slit x-shift = %.9f, slit "
2209 "y-shift = %.9f, slit rotation = %.9f",
2211 cx_string_append(s, cx_string_get(_s));
2213 cx_string_delete(_s);
2221 case GI_OPTM_PARAMETER_ERRORS:
2224 cxdouble fcoll = 0.;
2226 cxdouble theta = 0.;
2228 fcoll = giraffe_model_get_sigma(model,
"FocalLength");
2229 gcam = giraffe_model_get_sigma(model,
"Magnification");
2230 theta = giraffe_model_get_sigma(model,
"Angle");
2232 cx_string_sprintf(s,
"focal length = %.6f, camera "
2233 "magnification = %.6f, grating angle = %.9f",
2234 fcoll, gcam, theta);
2236 if (offsets == TRUE) {
2242 cx_string *_s = cx_string_new();
2244 sdx = giraffe_model_get_sigma(model,
"Sdx");
2245 sdy = giraffe_model_get_sigma(model,
"Sdy");
2246 sphi = giraffe_model_get_sigma(model,
"Sphi");
2248 cx_string_sprintf(_s,
", slit x-shift = %.9f, slit "
2249 "y-shift = %.9f, slit rotation = %.9f",
2251 cx_string_append(s, cx_string_get(_s));
2253 cx_string_delete(_s);
2261 case GI_OPTM_PARAMETER_STATUS:
2264 const cxchar *
const s_free =
"free";
2265 const cxchar *
const s_frozen =
"frozen";
2266 const cxchar *t = NULL;
2268 cx_string *buffer = cx_string_new();
2271 t = giraffe_model_frozen_parameter(model,
"FocalLength") ?
2273 cx_string_sprintf(buffer,
"focal length = %s", t);
2274 cx_string_set(s, cx_string_get(buffer));
2276 t = giraffe_model_frozen_parameter(model,
"Magnification") ?
2278 cx_string_sprintf(buffer,
", camera magnification = %s", t);
2279 cx_string_append(s, cx_string_get(buffer));
2281 t = giraffe_model_frozen_parameter(model,
"Angle") ?
2283 cx_string_sprintf(buffer,
", grating angle = %s", t);
2284 cx_string_append(s, cx_string_get(buffer));
2287 if (offsets == TRUE) {
2289 t = giraffe_model_frozen_parameter(model,
"Sdx") ?
2291 cx_string_sprintf(buffer,
", slit x-shift = %s", t);
2292 cx_string_append(s, cx_string_get(buffer));
2294 t = giraffe_model_frozen_parameter(model,
"Sdy") ?
2296 cx_string_sprintf(buffer,
", slit y-shift = %s", t);
2297 cx_string_append(s, cx_string_get(buffer));
2299 t = giraffe_model_frozen_parameter(model,
"Sphi") ?
2301 cx_string_sprintf(buffer,
", slit rotation = %s", t);
2302 cx_string_append(s, cx_string_get(buffer));
2306 cx_string_delete(buffer);
2323 inline static cpl_image *
2324 _giraffe_residuals_fit(GiWlResiduals *residuals, GiLineData *lines,
2325 const GiLocalization *localization, GiTable *fibers,
2326 GiTable *slitgeometry, GiSCFitParams *setup)
2329 const cxchar *
const fctid =
"_giraffe_residuals_fit";
2336 cxint nsubslits = 1;
2339 cpl_table *_fibers = NULL;
2341 cpl_image *locy = NULL;
2342 cpl_image *locw = NULL;
2343 cpl_image *xresiduals = NULL;
2346 cx_assert(lines != NULL);
2347 cx_assert(localization != NULL);
2348 cx_assert(fibers != NULL);
2349 cx_assert(slitgeometry != NULL);
2350 cx_assert(setup != NULL);
2353 cx_assert(_fibers != NULL);
2356 cx_assert(locy != NULL);
2359 cx_assert(locw != NULL);
2361 nx = cpl_image_get_size_y(locy);
2362 nlines = giraffe_linedata_lines(lines);
2364 xresiduals = cpl_image_new(cpl_table_get_nrow(_fibers), nx,
2367 if (setup->subslits == TRUE) {
2368 nsubslits = _giraffe_subslit_get_max(_fibers);
2371 for (i = 0; i < nsubslits; i++) {
2378 cxint iterations = 0;
2384 cxdouble ratio = 1.;
2385 cxdouble sigma = 0.;
2387 cpl_matrix *xss = NULL;
2388 cpl_matrix *yss = NULL;
2389 cpl_matrix *rss = NULL;
2390 cpl_matrix *sss = NULL;
2391 cpl_matrix *nss = NULL;
2392 cpl_matrix *lss = NULL;
2393 cpl_matrix *base = NULL;
2394 cpl_matrix *fit = NULL;
2395 cpl_matrix *coeff = NULL;
2396 cpl_matrix *chebyshev = NULL;
2398 cpl_table *subslit = NULL;
2400 GiChebyshev2D *xwsfit = NULL;
2403 if (setup->subslits == TRUE) {
2404 subslit = _giraffe_subslit_get(_fibers, i + 1);
2405 ssn = cpl_table_get_int(subslit,
"SSN", 0, NULL);
2407 cx_assert(ssn == i + 1);
2410 subslit = cpl_table_duplicate(_fibers);
2414 if (subslit == NULL) {
2418 _giraffe_subslit_range(subslit, locy, locw, &ymin, &ymax);
2420 nfibers = cpl_table_get_nrow(subslit);
2421 ndata = nfibers * nlines;
2424 xss = cpl_matrix_new(ndata, 1);
2425 yss = cpl_matrix_new(ndata, 1);
2426 rss = cpl_matrix_new(1, ndata);
2427 sss = cpl_matrix_new(ndata, 1);
2428 nss = cpl_matrix_new(ndata, 1);
2429 lss = cpl_matrix_new(ndata, 1);
2439 for (j = 0; j < nfibers; j++) {
2442 cxint n = cpl_table_get_int(subslit,
"INDEX", j, NULL) - 1;
2444 for (l = 0; l < nlines; l++) {
2446 cxdouble value = 0.;
2447 cxdouble xccd = giraffe_linedata_get(lines,
"Xccd", n, l);
2448 cxdouble yccd = giraffe_linedata_get(lines,
"Yccd", n, l);
2450 if (giraffe_linedata_get_status(lines, n, l) != 0) {
2454 if (yccd < ymin || yccd > ymax) {
2458 cpl_matrix_set(xss, k, 0, xccd);
2459 cpl_matrix_set(yss, k, 0, yccd);
2461 value = xccd - giraffe_linedata_get(lines,
"Center", n, l);
2463 cpl_matrix_set(rss, 0, k, value);
2464 giraffe_linedata_set(lines,
"Xoff", n, l, value);
2466 value = giraffe_linedata_get(lines,
"dCenter", n, l);
2467 cpl_matrix_set(sss, k, 0, value);
2469 cpl_matrix_set(nss, k, 0, n);
2470 cpl_matrix_set(lss, k, 0, l);
2479 cpl_msg_debug(fctid,
"Skipping subslit %d: No input lines left! "
2480 "All lines have non-zero status or are beyond the "
2481 "subslit boundaries (%.4f, %.4f).", ssn, ymin, ymax);
2489 cpl_matrix_set_size(xss, k, 1);
2490 cpl_matrix_set_size(yss, k, 1);
2491 cpl_matrix_set_size(rss, 1, k);
2492 cpl_matrix_set_size(sss, k, 1);
2493 cpl_matrix_set_size(nss, k, 1);
2494 cpl_matrix_set_size(lss, k, 1);
2502 sigma = cpl_matrix_get_median(sss);
2511 accepted = cpl_matrix_get_ncol(rss);
2514 while (accepted > 0 && iterations < setup->clip.iterations &&
2515 ratio > setup->clip.fraction) {
2517 base = giraffe_chebyshev_base2d(0., ymin, nx, ymax - ymin + 1.,
2518 setup->fit.xorder + 1,
2519 setup->fit.yorder + 1, xss, yss);
2521 if (coeff != NULL) {
2522 cpl_matrix_delete(coeff);
2528 if (coeff == NULL) {
2529 cpl_msg_debug(fctid,
"Error solving linear system for "
2530 "subslit %d, skipping subslit.", ssn);
2534 fit = cpl_matrix_product_create(coeff, base);
2538 for (j = 0; j < cpl_matrix_get_ncol(fit); j++) {
2540 cxdouble _fit = cpl_matrix_get(fit, 0, j);
2541 cxdouble _rss = cpl_matrix_get(rss, 0, j);
2543 if (fabs(_fit - _rss) >= setup->clip.level * sigma) {
2545 cxint n = (cxint)cpl_matrix_get(nss, j, 0);
2546 cxint l = (cxint)cpl_matrix_get(lss, j, 0);
2552 giraffe_linedata_set_status(lines, n, l, LF_R_XRFIT);
2557 cpl_matrix_set(xss, k, 0, cpl_matrix_get(xss, j, 0));
2558 cpl_matrix_set(yss, k, 0, cpl_matrix_get(yss, j, 0));
2559 cpl_matrix_set(rss, 0, k, cpl_matrix_get(rss, 0, j));
2560 cpl_matrix_set(sss, k, 0, cpl_matrix_get(sss, j, 0));
2561 cpl_matrix_set(nss, k, 0, cpl_matrix_get(nss, j, 0));
2562 cpl_matrix_set(lss, k, 0, cpl_matrix_get(lss, j, 0));
2567 cpl_matrix_delete(base);
2568 cpl_matrix_delete(fit);
2570 if (k == accepted) {
2580 ratio = (cxdouble)accepted / (cxdouble)total;
2582 cpl_matrix_set_size(xss, k, 1);
2583 cpl_matrix_set_size(yss, k, 1);
2584 cpl_matrix_set_size(rss, 1, k);
2585 cpl_matrix_set_size(sss, k, 1);
2586 cpl_matrix_set_size(nss, k, 1);
2587 cpl_matrix_set_size(lss, k, 1);
2595 if (accepted == 0) {
2596 cpl_msg_debug(fctid,
"Subslit %d: All lines rejected.", ssn);
2600 if (coeff == NULL) {
2606 cpl_matrix_delete(xss);
2607 cpl_matrix_delete(yss);
2608 cpl_matrix_delete(rss);
2609 cpl_matrix_delete(sss);
2610 cpl_matrix_delete(nss);
2611 cpl_matrix_delete(lss);
2618 xss = cpl_matrix_new(nx * nfibers, 1);
2619 yss = cpl_matrix_new(nx * nfibers, 1);
2621 giraffe_compute_image_coordinates(nx, nfibers, xss, NULL);
2623 for (j = 0; j < cpl_table_get_nrow(subslit); j++) {
2628 cxint ns = cpl_image_get_size_x(locy);
2629 cxint cs = cpl_table_get_int(subslit, idx, j, NULL) - 1;
2631 cxdouble *data = cpl_image_get_data(locy);
2634 for (l = 0; l < nx; l++) {
2635 cpl_matrix_set(yss, l * nfibers + j, 0, data[l * ns + cs]);
2645 base = giraffe_chebyshev_base2d(0., ymin, nx, ymax - ymin + 1.,
2646 setup->fit.xorder + 1,
2647 setup->fit.yorder + 1, xss, yss);
2649 fit = cpl_matrix_product_create(coeff, base);
2651 cpl_matrix_delete(xss);
2654 cpl_matrix_delete(yss);
2669 chebyshev = cpl_matrix_wrap(setup->fit.xorder + 1,
2670 setup->fit.yorder + 1,
2671 cpl_matrix_get_data(coeff));
2673 xwsfit = giraffe_chebyshev2d_new(setup->fit.xorder, setup->fit.yorder);
2674 status = giraffe_chebyshev2d_set(xwsfit, 0., nx, ymin, ymax,
2679 giraffe_chebyshev2d_delete(xwsfit);
2681 cpl_matrix_unwrap(chebyshev);
2683 cpl_matrix_delete(base);
2684 cpl_matrix_delete(coeff);
2685 cpl_matrix_delete(fit);
2687 cpl_table_delete(subslit);
2689 cpl_image_delete(xresiduals);
2695 cpl_matrix_unwrap(chebyshev);
2698 giraffe_wlresiduals_set(residuals, ssn, xwsfit);
2706 for (j = 0; j < cpl_table_get_nrow(subslit); j++) {
2709 cxint n = cpl_table_get_int(subslit,
"INDEX", j, NULL) - 1;
2710 cxint ns = cpl_table_get_nrow(_fibers);
2712 cxdouble *data = cpl_image_get_data(xresiduals);
2714 for (l = 0; l < nx; l++) {
2715 data[l * ns + n] = cpl_matrix_get(fit, 0, l * nfibers + j);
2720 cpl_matrix_delete(base);
2721 cpl_matrix_delete(coeff);
2722 cpl_matrix_delete(fit);
2724 cpl_table_delete(subslit);
2733 inline static cxdouble
2734 _giraffe_compute_statistics(
const GiLineData *lines,
const cpl_image *xwsfit,
2735 const cpl_image *lflags)
2746 cpl_image *xccd = NULL;
2749 cx_assert(lines != NULL);
2752 nlines = giraffe_linedata_lines(lines);
2753 nfibers = giraffe_linedata_fibers(lines);
2755 xccd = cpl_image_duplicate(giraffe_linedata_get_data(lines,
"Xccd"));
2757 if (xwsfit != NULL) {
2759 cpl_image *residuals = NULL;
2762 cx_assert(lflags != NULL);
2764 residuals = cpl_image_new(giraffe_linedata_fibers(lines),
2765 giraffe_linedata_lines(lines),
2768 _giraffe_get_residuals(residuals, xccd, xwsfit);
2769 _giraffe_apply_residuals(xccd, residuals, lflags, 0.);
2771 cpl_image_delete(residuals);
2776 _xccd = cpl_image_get_data(xccd);
2778 for (i = 0; i < nfibers; i++) {
2782 for (j = 0; j < nlines; j++) {
2784 if (giraffe_linedata_get_status(lines, i, j) == LF_R_NONE) {
2786 cxdouble center = giraffe_linedata_get(lines,
"Center", i, j);
2788 sum += pow(center - _xccd[j * nfibers + i], 2.);
2796 cpl_image_delete(xccd);
2798 rms = sqrt(sum / CX_MAX(giraffe_linedata_accepted(lines), 1.));
2806 _giraffe_convert_wlsolution(GiTable *result,
const GiWlSolution *solution,
2807 const GiImage *spectra,
const GiGrating *setup,
2815 cxdouble value = 0.;
2816 cxdouble scale = 0.;
2817 cxdouble xccd[2] = {0., 0.};
2819 cx_string *s = NULL;
2821 cpl_propertylist *properties = NULL;
2823 cpl_table *coeffs = NULL;
2825 const GiModel *model = NULL;
2827 const GiWlResiduals *residuals = NULL;
2830 cx_assert(result != NULL);
2831 cx_assert(solution != NULL);
2833 s = cx_string_new();
2842 cpl_propertylist_erase(properties,
"NAXIS1");
2843 cpl_propertylist_erase(properties,
"NAXIS2");
2844 cpl_propertylist_erase(properties, GIALIAS_DATAMIN);
2845 cpl_propertylist_erase(properties, GIALIAS_DATAMAX);
2846 cpl_propertylist_erase(properties, GIALIAS_EXTNAME);
2848 cpl_propertylist_erase(properties, GIALIAS_PROCATG);
2849 cpl_propertylist_erase(properties, GIALIAS_PROTYPE);
2850 cpl_propertylist_erase(properties, GIALIAS_DATAMEAN);
2851 cpl_propertylist_erase(properties, GIALIAS_DATAMEDI);
2852 cpl_propertylist_erase(properties, GIALIAS_DATASIG);
2854 cpl_propertylist_update_string(properties, GIALIAS_GIRFTYPE,
2856 cpl_propertylist_set_comment(properties, GIALIAS_GIRFTYPE,
2857 "Giraffe frame type.");
2881 cpl_propertylist_update_string(properties, GIALIAS_WSOL_LMNAME,
2883 cpl_propertylist_set_comment(properties, GIALIAS_WSOL_LMNAME,
2884 "Line profile model");
2886 cpl_propertylist_update_bool(properties, GIALIAS_WSOL_LMRES, info->residuals);
2887 cpl_propertylist_set_comment(properties, GIALIAS_WSOL_LMRES,
2888 "Line detection optical model residuals flag");
2890 cpl_propertylist_update_int(properties, GIALIAS_WSOL_LMWIDTH, info->width);
2891 cpl_propertylist_set_comment(properties, GIALIAS_WSOL_LMWIDTH,
2892 "Line detection window size [pxl]");
2894 cpl_propertylist_update_double(properties, GIALIAS_WSOL_LMTHRESH,
2896 cpl_propertylist_set_comment(properties, GIALIAS_WSOL_LMTHRESH,
2897 "Calibration line threshold");
2899 cpl_propertylist_update_int(properties, GIALIAS_WSOL_LMITER,
2901 cpl_propertylist_set_comment(properties, GIALIAS_WSOL_LMITER,
2902 "Line profile fit maximum number "
2905 cpl_propertylist_update_int(properties, GIALIAS_WSOL_LMTEST,
2907 cpl_propertylist_set_comment(properties, GIALIAS_WSOL_LMTEST,
2908 "Line profile fit maximum number "
2909 "of chi-square tests");
2911 cpl_propertylist_update_double(properties, GIALIAS_WSOL_LMDCHISQ,
2913 cpl_propertylist_set_comment(properties, GIALIAS_WSOL_LMDCHISQ,
2914 "Line profile fit minimum delta "
2924 cpl_propertylist_update_string(properties, GIALIAS_WSOL_PWORDER,
2926 cpl_propertylist_set_comment(properties, GIALIAS_WSOL_PWORDER,
2927 "PSF width fit polynomial order");
2929 cpl_propertylist_update_double(properties, GIALIAS_WSOL_PWSIGMA,
2931 cpl_propertylist_set_comment(properties, GIALIAS_WSOL_PWSIGMA,
2932 "PSF width fit sigma clipping level");
2934 cpl_propertylist_update_int(properties, GIALIAS_WSOL_PWITER,
2936 cpl_propertylist_set_comment(properties, GIALIAS_WSOL_PWITER,
2937 "PSF width fit maximum number of "
2940 cpl_propertylist_update_double(properties, GIALIAS_WSOL_PWFRAC,
2942 cpl_propertylist_set_comment(properties, GIALIAS_WSOL_PWFRAC,
2943 "PSF width fit minimum fraction of "
2951 cpl_propertylist_update_bool(properties, GIALIAS_WSOL_OMFIT,
2953 cpl_propertylist_set_comment(properties, GIALIAS_WSOL_OMFIT,
2954 "Optical model fit flag");
2956 cpl_propertylist_update_string(properties, GIALIAS_WSOL_OMNAME,
2957 giraffe_wlsolution_name(solution));
2958 cpl_propertylist_set_comment(properties, GIALIAS_WSOL_OMNAME,
2959 "Optical model name");
2961 model = giraffe_wlsolution_model(solution);
2963 sign = giraffe_model_get_parameter(model,
"Orientation") < 0 ? -1 : 1;
2964 cpl_propertylist_update_int(properties, GIALIAS_WSOL_OMDIR, sign);
2965 cpl_propertylist_set_comment(properties, GIALIAS_WSOL_OMDIR,
2966 "Optical model orientation");
2968 value = giraffe_model_get_parameter(model,
"FocalLength");
2969 cpl_propertylist_update_double(properties, GIALIAS_WSOL_OMFCOLL, value);
2970 cpl_propertylist_set_comment(properties, GIALIAS_WSOL_OMFCOLL,
2971 "Optical model focal length");
2973 value = giraffe_model_get_parameter(model,
"Magnification");
2974 cpl_propertylist_update_double(properties, GIALIAS_WSOL_OMGCAM, value);
2975 cpl_propertylist_set_comment(properties, GIALIAS_WSOL_OMGCAM,
2976 "Optical model camera factor");
2978 value = giraffe_model_get_parameter(model,
"Angle");
2979 cpl_propertylist_update_double(properties, GIALIAS_WSOL_OMGTHETA, value);
2980 cpl_propertylist_set_comment(properties, GIALIAS_WSOL_OMGTHETA,
2981 "Optical model grating angle");
2983 if (strcmp(giraffe_wlsolution_name(solution),
"xoptmod2") == 0) {
2985 value = giraffe_model_get_parameter(model,
"Sdx");
2986 cpl_propertylist_update_double(properties, GIALIAS_WSOL_OMSDX, value);
2987 cpl_propertylist_set_comment(properties, GIALIAS_WSOL_OMSDX,
2988 "Optical model slit x-offset");
2990 value = giraffe_model_get_parameter(model,
"Sdy");
2991 cpl_propertylist_update_double(properties, GIALIAS_WSOL_OMSDY, value);
2992 cpl_propertylist_set_comment(properties, GIALIAS_WSOL_OMSDY,
2993 "Optical model slit y-offset");
2995 value = giraffe_model_get_parameter(model,
"Sphi");
2996 cpl_propertylist_update_double(properties, GIALIAS_WSOL_OMSPHI, value);
2997 cpl_propertylist_set_comment(properties, GIALIAS_WSOL_OMSPHI,
2998 "Optical model slit rotation");
3008 residuals = giraffe_wlsolution_get_residuals(solution);
3010 cpl_propertylist_update_bool(properties, GIALIAS_WSOL_SUBSLITS,
3011 giraffe_wlsolution_get_subslits(solution));
3012 cpl_propertylist_set_comment(properties, GIALIAS_WSOL_SUBSLITS,
3013 "Subslit fit flag");
3016 cpl_propertylist_update_int(properties, GIALIAS_WSOL_XRSSN,
3017 giraffe_wlresiduals_get_size(residuals));
3018 cpl_propertylist_set_comment(properties, GIALIAS_WSOL_XRSSN,
3019 "Number of subslits");
3024 cpl_propertylist_update_string(properties, GIALIAS_WSOL_XRORDER,
3026 cpl_propertylist_set_comment(properties, GIALIAS_WSOL_XRORDER,
3027 "Residual fit polynomial order");
3030 cpl_propertylist_update_double(properties, GIALIAS_WSOL_XRSIGMA,
3032 cpl_propertylist_set_comment(properties, GIALIAS_WSOL_XRSIGMA,
3033 "Residual fit sigma clipping level");
3035 cpl_propertylist_update_int(properties, GIALIAS_WSOL_XRITER,
3037 cpl_propertylist_set_comment(properties, GIALIAS_WSOL_XRITER,
3038 "Residual fit maximum number of "
3041 cpl_propertylist_update_double(properties, GIALIAS_WSOL_XRFRAC,
3043 cpl_propertylist_set_comment(properties, GIALIAS_WSOL_XRFRAC,
3044 "Residual fit minimum fraction of "
3047 cpl_propertylist_update_int(properties, GIALIAS_WSOL_NLINES,
3049 cpl_propertylist_set_comment(properties, GIALIAS_WSOL_NLINES,
3050 "Number of calibration lines used.");
3052 cpl_propertylist_update_int(properties, GIALIAS_WSOL_NACCEPT,
3054 cpl_propertylist_set_comment(properties, GIALIAS_WSOL_NACCEPT,
3055 "Number of accepted lines");
3057 cpl_propertylist_update_int(properties, GIALIAS_WSOL_NREJECT,
3059 cpl_propertylist_set_comment(properties, GIALIAS_WSOL_NREJECT,
3060 "Number of rejected lines");
3062 cpl_propertylist_update_double(properties, GIALIAS_WSOL_RMS,
3064 cpl_propertylist_set_comment(properties, GIALIAS_WSOL_RMS,
3065 "Average RMS [pxl] of fitted line "
3074 xccd[0] = giraffe_wlsolution_compute_pixel(solution, setup->
wlenmin,
3076 xccd[1] = giraffe_wlsolution_compute_pixel(solution, setup->
wlenmax,
3082 cpl_propertylist_update_double(properties, GIALIAS_WSOL_WLMIN,
3084 cpl_propertylist_set_comment(properties, GIALIAS_WSOL_WLMIN,
3085 "Wavelength solution minimum wavelength");
3087 cpl_propertylist_update_double(properties, GIALIAS_WSOL_WLMAX,
3089 cpl_propertylist_set_comment(properties, GIALIAS_WSOL_WLMAX,
3090 "Wavelength solution maximum wavelength");
3092 cpl_propertylist_update_double(properties, GIALIAS_WSOL_SCALE, scale);
3093 cpl_propertylist_set_comment(properties, GIALIAS_WSOL_SCALE,
3094 "Approximate wavelength scale [nm/pxl]");
3097 cx_string_delete(s);
3105 for (i = 0; (cxsize)i < giraffe_wlresiduals_get_size(residuals); i++) {
3107 const GiChebyshev2D *fit = giraffe_wlresiduals_get(residuals, i);
3116 giraffe_chebyshev2d_get_order(fit, &xorder, &yorder);
3120 gi_error(
"Invalid wavelength solution. Inconsistent residual "
3121 "fit polynomial order!");
3134 coeffs = giraffe_wlresiduals_table(residuals);
3136 if (coeffs == NULL) {
3137 cpl_propertylist_delete(properties);
3142 cpl_propertylist_delete(properties);
3147 cpl_table_delete(coeffs);
3156 giraffe_wcaldata_new(
void)
3159 GiWCalData *
self = cx_calloc(1,
sizeof *
self);
3161 self->coeffs = NULL;
3163 self->linedata = NULL;
3171 giraffe_wcaldata_delete(GiWCalData *
self)
3178 self->coeffs = NULL;
3186 if (self->linedata) {
3187 giraffe_linedata_delete(self->linedata);
3188 self->linedata = NULL;
3223 GiLocalization *localization, GiTable *fibers,
3224 GiTable *slitgeometry, GiTable *grating,
3225 GiTable *lines, GiTable *initial,
3229 const cxchar *fctid =
"giraffe_calibrate_wavelength";
3232 cxbool residuals = FALSE;
3241 cpl_image *psf_fit = NULL;
3242 cpl_image *xws_fit = NULL;
3244 GiTable *tsolution = NULL;
3248 GiSCFitParams psf_setup;
3249 GiSCFitParams xws_setup;
3251 GiLineParams *line_setup = NULL;
3253 GiLineData *line_data = NULL;
3255 GiWlSolution *solution = NULL;
3260 if (extraction == NULL) {
3264 if (extraction->spectra == NULL || extraction->error == NULL) {
3269 if (fibers == NULL) {
3273 if (slitgeometry == NULL) {
3277 if (grating == NULL) {
3281 if (lines == NULL) {
3292 if (setup == NULL) {
3293 cpl_msg_error(fctid,
"Cannot initialize grating setup parameters!");
3311 cpl_msg_info(fctid,
"Setting initial slit offsets: x-shift = %.9f, "
3312 "y-shift = %.9f, rotation = %.9f", setup->
sdx,
3327 line_setup = _giraffe_lineparams_create(GI_LINETYPE_THARNE, setup,
3330 if (line_setup == NULL) {
3331 cpl_msg_error(fctid,
"Cannot initialize line fit setup parameters!");
3343 if (initial == NULL) {
3346 cxdouble pixelsize = 0.;
3348 cpl_propertylist *properties = NULL;
3350 cpl_image *spectra = NULL;
3354 cx_assert(properties != NULL);
3357 cx_assert(spectra != NULL);
3359 pixelsize = cpl_propertylist_get_double(properties, GIALIAS_PIXSIZY);
3360 npixel = cpl_image_get_size_y(spectra);
3362 solution = giraffe_wlsolution_new(config->
opt_model,
3366 if (solution == NULL) {
3367 cpl_msg_error(fctid,
"Cannot initialize initial wavelength "
3372 _giraffe_lineparams_delete(line_setup);
3380 const cpl_propertylist* _properties =
3399 if (cpl_propertylist_has(_properties, GIALIAS_WSOL_WLMIN) == TRUE) {
3401 setup->
wlenmin = cpl_propertylist_get_double(_properties,
3402 GIALIAS_WSOL_WLMIN);
3404 cpl_msg_debug(fctid,
"Using minimum wavelength %.2f from "
3405 "initial solution", setup->
wlenmin);
3409 if (cpl_propertylist_has(_properties, GIALIAS_WSOL_WLMAX) == TRUE) {
3411 setup->
wlenmax = cpl_propertylist_get_double(_properties,
3412 GIALIAS_WSOL_WLMAX);
3414 cpl_msg_debug(fctid,
"Using maximum wavelength %.2f from "
3415 "initial solution", setup->
wlenmax);
3421 giraffe_wlsolution_set_subslits(solution, config->
opt_subslits);
3424 cpl_msg_info(fctid,
"Computing line positions on the CCD using "
3425 "model `%s'", giraffe_wlsolution_name(solution));
3434 if (giraffe_wlsolution_get_residuals(solution) == NULL) {
3436 cpl_msg_error(fctid,
"Initial wavelength solution does not "
3437 "provide optical model residuals!");
3441 _giraffe_lineparams_delete(line_setup);
3443 giraffe_wlsolution_delete(solution);
3455 residuals = giraffe_wlsolution_get_residuals(solution) != NULL;
3457 if (residuals == TRUE) {
3458 cpl_msg_info(fctid,
"Using wavelength solution residuals when "
3459 "computing line positions.");
3474 status = _giraffe_linelist_setup(lines, setup, config);
3477 cpl_msg_error(fctid,
"Line list creation failed!");
3481 _giraffe_lineparams_delete(line_setup);
3483 giraffe_wlsolution_delete(solution);
3489 cpl_msg_info(fctid,
"%d lines have been selected from the line list.",
3497 line_data = giraffe_linedata_new();
3506 cpl_table *_lines = NULL;
3509 cpl_image *xccd = NULL;
3510 cpl_image *xres = NULL;
3511 cpl_image *line_status = NULL;
3513 GiWlResiduals *xws_coeffs = NULL;
3519 cpl_msg_info(fctid,
"Current search window width: %d pxl", width);
3520 cpl_msg_info(fctid,
"Applying crowding criterium to line list.");
3522 _lines = _giraffe_linelist_select(lines, extraction->spectra, setup,
3524 if (_lines == NULL) {
3525 cpl_msg_error(fctid,
"Removing crowded lines from line list "
3526 "for search window width %d pxl failed!", width);
3530 _giraffe_lineparams_delete(line_setup);
3532 giraffe_wlsolution_delete(solution);
3537 _nlines = cpl_table_get_nrow(_lines);
3540 cpl_msg_info(fctid,
"%d lines used for fit. %d of %d lines rejected "
3541 "due to crowding.", _nlines, nlines - _nlines, nlines);
3543 cpl_msg_info(fctid,
"%d lines used for fit. %d of %d lines "
3544 "rejected due to crowding and line quality.",
3545 _nlines, nlines - _nlines, nlines);
3553 xccd = _giraffe_line_abscissa(_lines, slitgeometry, fibers,
3554 solution, localization, residuals);
3556 _nfibers = cpl_image_get_size_x(xccd);
3557 _nlines = cpl_image_get_size_y(xccd);
3564 cpl_msg_info(fctid,
"Fitting %d line profiles for %d spectra using "
3565 "line model `%s'", _nlines, _nfibers , line_setup->model);
3567 cpl_msg_info(fctid,
"Total number of lines to fit: %d (%d x %d)",
3568 _nlines * _nfibers, _nfibers, _nlines);
3571 status = giraffe_linedata_reset(line_data, _lines, _fibers,
3576 cpl_msg_error(fctid,
"Line profile fit failed!");
3578 cpl_image_delete(xccd);
3580 cpl_table_delete(_lines);
3581 giraffe_linedata_delete(line_data);
3585 _giraffe_lineparams_delete(line_setup);
3587 giraffe_wlsolution_delete(solution);
3593 status = _giraffe_line_fit(line_data, xccd, width, extraction, fibers,
3594 localization->locy, line_setup);
3598 cpl_msg_error(fctid,
"Line profile fit failed!");
3600 cpl_image_delete(xccd);
3602 cpl_table_delete(_lines);
3603 giraffe_linedata_delete(line_data);
3607 _giraffe_lineparams_delete(line_setup);
3609 giraffe_wlsolution_delete(solution);
3615 cpl_image_delete(xccd);
3618 if (giraffe_linedata_accepted(line_data) == 0) {
3619 cpl_msg_error(fctid,
"No lines left after line profile fit!");
3621 cpl_table_delete(_lines);
3622 giraffe_linedata_delete(line_data);
3626 _giraffe_lineparams_delete(line_setup);
3628 giraffe_wlsolution_delete(solution);
3634 _nreject = giraffe_linedata_rejected(line_data);
3635 _ngood = giraffe_linedata_accepted(line_data);
3637 cpl_msg_info(fctid,
"Number of good lines: %d. %d of %d lines "
3638 "rejected due to line profile fit.", _ngood, _nreject,
3645 line_status = giraffe_linedata_status(line_data);
3652 cpl_msg_info(fctid,
"Fit of the line profile PSF width variation.");
3654 psf_setup.subslits = giraffe_wlsolution_get_subslits(solution);
3658 cpl_msg_info(fctid,
"Chebyshev polynomial order is (%d, %d).",
3659 psf_setup.fit.xorder, psf_setup.fit.yorder);
3665 cpl_msg_info(fctid,
"Sigma clipping: iterations = %d, level = %.4f, "
3666 "fraction = %.4f", psf_setup.clip.iterations,
3667 psf_setup.clip.level, psf_setup.clip.fraction);
3670 psf_fit = _giraffe_psf_fit(line_data, localization, fibers,
3671 slitgeometry, &psf_setup);
3674 if (psf_fit == NULL) {
3676 cpl_msg_error(fctid,
"Fit of the line profile PSF width "
3677 "variation failed!");
3679 cpl_table_delete(_lines);
3680 cpl_image_delete(line_status);
3681 giraffe_linedata_delete(line_data);
3685 _giraffe_lineparams_delete(line_setup);
3687 giraffe_wlsolution_delete(solution);
3698 cpl_image_delete(psf_fit);
3702 if (giraffe_linedata_accepted(line_data) == 0) {
3703 cpl_msg_error(fctid,
"No lines left after line profile PSF "
3706 cpl_table_delete(_lines);
3707 cpl_image_delete(line_status);
3708 giraffe_linedata_delete(line_data);
3712 _giraffe_lineparams_delete(line_setup);
3714 giraffe_wlsolution_delete(solution);
3720 cpl_msg_info(fctid,
"Number of good lines: %"
3721 CX_PRINTF_FORMAT_SIZE_TYPE
". %"
3722 CX_PRINTF_FORMAT_SIZE_TYPE
" of %d lines "
3723 "rejected due to line profile PSF width fit.",
3724 giraffe_linedata_accepted(line_data),
3725 giraffe_linedata_rejected(line_data) - _nreject, _ngood);
3727 _ngood = giraffe_linedata_accepted(line_data);
3728 _nreject = giraffe_linedata_rejected(line_data);
3738 cxint iterations = 0;
3741 cxdouble chisq = 0.;
3742 cxdouble rsquare = 0.;
3744 cx_string *s = NULL;
3746 GiOpticalModelParams om_setup;
3748 GiModel *guess = NULL;
3749 GiModel *model = giraffe_wlsolution_model(solution);
3756 guess = giraffe_model_clone(model);
3758 om_setup.fit.iterations = config->
opt_niter;
3763 cpl_msg_info(fctid,
"Optical model fit setup: iterations = %d, "
3764 "tests = %d, delta = %.4f", om_setup.fit.iterations,
3765 om_setup.fit.tests, om_setup.fit.delta);
3767 status = _giraffe_opticalmodel_fit(solution, line_data, fibers,
3768 slitgeometry, &om_setup);
3771 cpl_msg_error(fctid,
"Optical model fit failed!");
3773 giraffe_model_delete(guess);
3775 cpl_table_delete(_lines);
3776 cpl_image_delete(line_status);
3777 giraffe_linedata_delete(line_data);
3781 _giraffe_lineparams_delete(line_setup);
3783 giraffe_wlsolution_delete(solution);
3794 cpl_msg_info(fctid,
"Optical model parameters:");
3796 s = cx_string_new();
3798 _giraffe_opticalmodel_format(s, guess, GI_OPTM_PARAMETER_VALUES);
3799 cpl_msg_info(fctid,
"Initial: %s", cx_string_get(s));
3801 _giraffe_opticalmodel_format(s, model, GI_OPTM_PARAMETER_VALUES);
3802 cpl_msg_info(fctid,
" Fitted: %s", cx_string_get(s));
3804 _giraffe_opticalmodel_format(s, model, GI_OPTM_PARAMETER_ERRORS);
3805 cpl_msg_info(fctid,
" Sigma: %s", cx_string_get(s));
3807 _giraffe_opticalmodel_format(s, model, GI_OPTM_PARAMETER_STATUS);
3808 cpl_msg_info(fctid,
" Status: %s", cx_string_get(s));
3810 cx_string_delete(s);
3814 if (strcmp(giraffe_model_get_name(model),
"xoptmod2") == 0) {
3816 cxdouble flength = 0.;
3821 cx_string *s = cx_string_new();
3824 flength = giraffe_model_get_parameter(guess,
"FocalLength");
3825 sdx = giraffe_model_get_parameter(guess,
"Sdx");
3826 sdy = giraffe_model_get_parameter(guess,
"Sdy");
3827 sphi = giraffe_model_get_parameter(guess,
"Sphi");
3829 cx_string_sprintf(s,
"Initial: focal length = %.6f, slit "
3830 "x-shift = %.9f, slit y-shift = %.9f, "
3831 "slit rotation = %.9f", flength, sdx, sdy,
3833 cpl_msg_info(fctid,
"%s", cx_string_get(s));
3836 flength = giraffe_model_get_parameter(model,
"FocalLength");
3837 sdx = giraffe_model_get_parameter(model,
"Sdx");
3838 sdy = giraffe_model_get_parameter(model,
"Sdy");
3839 sphi = giraffe_model_get_parameter(model,
"Sphi");
3841 cx_string_sprintf(s,
" Fitted: focal length = %.6f, slit "
3842 "x-shift = %.9f, slit y-shift = %.9f, "
3843 "slit rotation = %.9f", flength, sdx, sdy,
3845 cpl_msg_info(fctid,
"%s", cx_string_get(s));
3848 flength = giraffe_model_get_sigma(model,
"FocalLength");
3849 sdx = giraffe_model_get_sigma(model,
"Sdx");
3850 sdy = giraffe_model_get_sigma(model,
"Sdy");
3851 sphi = giraffe_model_get_sigma(model,
"Sphi");
3853 cx_string_sprintf(s,
" Sigma: focal length = %.6f, slit "
3854 "x-shift = %.9f, slit y-shift = %.9f, "
3855 "slit rotation = %.9f", flength, sdx, sdy,
3857 cpl_msg_info(fctid,
"%s", cx_string_get(s));
3859 cx_string_delete(s);
3864 cxdouble flength = 0.;
3866 cx_string *s = cx_string_new();
3869 flength = giraffe_model_get_parameter(guess,
"FocalLength");
3871 cx_string_sprintf(s,
"Initial: focal length = %.6f", flength);
3872 cpl_msg_info(fctid,
"%s", cx_string_get(s));
3875 flength = giraffe_model_get_parameter(model,
"FocalLength");
3877 cx_string_sprintf(s,
" Fitted: focal length = %.6f", flength);
3878 cpl_msg_info(fctid,
"%s", cx_string_get(s));
3881 flength = giraffe_model_get_sigma(model,
"FocalLength");
3883 cx_string_sprintf(s,
" Sigma: focal length = %.6f", flength);
3884 cpl_msg_info(fctid,
"%s", cx_string_get(s));
3886 cx_string_delete(s);
3891 giraffe_model_delete(guess);
3894 iterations = giraffe_model_get_position(model);
3895 df = giraffe_model_get_df(model);
3897 chisq = giraffe_model_get_chisq(model);
3898 rsquare = giraffe_model_get_rsquare(model);
3900 cpl_msg_info(fctid,
"Optical model fit statistics: iterations = "
3901 "%d, DoF = %d, Chi-square = %.6g, Chi-square/DoF = "
3902 "%.6g, R-square = %.6g", iterations, df, chisq,
3903 chisq / df, rsquare);
3911 setup->
fcoll = giraffe_model_get_parameter(model,
"FocalLength");
3912 setup->
gcam = giraffe_model_get_parameter(model,
"Magnification");
3913 setup->
theta = giraffe_model_get_parameter(model,
"Angle");
3914 setup->
order = giraffe_model_get_parameter(model,
"Order");
3915 setup->
space = giraffe_model_get_parameter(model,
"Spacing");
3917 if (strcmp(giraffe_model_get_name(model),
"xoptmod2") == 0) {
3918 setup->
sdx = giraffe_model_get_parameter(model,
"Sdx");
3919 setup->
sdy = giraffe_model_get_parameter(model,
"Sdy");
3920 setup->
sphi = giraffe_model_get_parameter(model,
"Sphi");
3935 cpl_msg_info(fctid,
"Re-computing line positions with updated "
3938 xccd = _giraffe_line_abscissa(_lines, slitgeometry, fibers,
3939 solution, localization, FALSE);
3941 giraffe_linedata_set_data(line_data,
"Xccd", xccd);
3947 cx_string *s = cx_string_new();
3949 GiModel *model = giraffe_wlsolution_model(solution);
3952 _giraffe_opticalmodel_format(s, model, GI_OPTM_PARAMETER_VALUES);
3953 cpl_msg_info(fctid,
"Optical model: %s", cx_string_get(s));
3955 cx_string_delete(s);
3960 rms = _giraffe_compute_statistics(line_data, NULL, NULL);
3962 cpl_msg_info(fctid,
"Average RMS [pxl] of line positions using "
3963 "%d of %d lines: %.4f", _ngood, _nlines * _nfibers,
3972 cpl_msg_info(fctid,
"Fit of the wavelength solution coefficients "
3973 "using %" CX_PRINTF_FORMAT_SIZE_TYPE
" lines",
3974 giraffe_linedata_accepted(line_data));
3976 xws_setup.subslits = giraffe_wlsolution_get_subslits(solution);
3980 cpl_msg_info(fctid,
"Chebyshev polynomial order is (%d, %d).",
3981 xws_setup.fit.xorder, xws_setup.fit.yorder);
3987 cpl_msg_info(fctid,
"Sigma clipping: iterations = %d, level = %.4f, "
3988 "fraction = %.4f", xws_setup.clip.iterations,
3989 xws_setup.clip.level, xws_setup.clip.fraction);
3991 xws_coeffs = giraffe_wlresiduals_new();
3993 xws_fit = _giraffe_residuals_fit(xws_coeffs, line_data, localization,
3994 fibers, slitgeometry, &xws_setup);
3997 if (xws_fit == NULL) {
3999 cpl_msg_error(fctid,
"Fit of the wavelength solution "
4000 "coefficients failed!");
4002 giraffe_wlresiduals_delete(xws_coeffs);
4004 cpl_table_delete(_lines);
4005 cpl_image_delete(line_status);
4006 giraffe_linedata_delete(line_data);
4010 _giraffe_lineparams_delete(line_setup);
4012 giraffe_wlsolution_delete(solution);
4024 xres = cpl_image_new(giraffe_linedata_fibers(line_data),
4025 giraffe_linedata_lines(line_data),
4028 _giraffe_get_residuals(xres,
4029 giraffe_linedata_get_data(line_data,
"Xccd"),
4031 giraffe_linedata_set_data(line_data,
"Xres", xres);
4034 if (giraffe_linedata_accepted(line_data) == 0) {
4035 cpl_msg_error(fctid,
"No lines left after wavelength solution "
4036 "coefficients fit!");
4038 giraffe_wlresiduals_delete(xws_coeffs);
4040 cpl_table_delete(_lines);
4041 cpl_image_delete(line_status);
4042 cpl_image_delete(xws_fit);
4043 giraffe_linedata_delete(line_data);
4047 _giraffe_lineparams_delete(line_setup);
4049 giraffe_wlsolution_delete(solution);
4055 cpl_msg_info(fctid,
"Number of good lines: %"
4056 CX_PRINTF_FORMAT_SIZE_TYPE
". %"
4057 CX_PRINTF_FORMAT_SIZE_TYPE
" of %d lines "
4058 "rejected due to wavelength solution coefficients fit.",
4059 giraffe_linedata_accepted(line_data),
4060 giraffe_linedata_rejected(line_data) - _nreject, _ngood);
4062 _ngood = giraffe_linedata_accepted(line_data);
4063 _nreject = giraffe_linedata_rejected(line_data);
4070 giraffe_wlsolution_set_residuals(solution, xws_coeffs);
4080 rms = _giraffe_compute_statistics(line_data, xws_fit, line_status);
4082 cpl_msg_info(fctid,
"Average RMS [pxl] of line positions using "
4083 "%d of %d lines: %.4f", _ngood, _nlines * _nfibers,
4093 info.residuals = residuals;
4095 info.nlines = _nlines;
4096 info.nfibers = _nfibers;
4098 info.ngood = _ngood;
4099 info.nreject = _nreject;
4108 cpl_image_delete(xws_fit);
4110 cpl_table_delete(_lines);
4111 cpl_image_delete(line_status);
4123 status = _giraffe_convert_wlsolution(tsolution, solution,
4124 extraction->spectra, setup,
4133 _giraffe_lineparams_delete(line_setup);
4135 giraffe_wlsolution_delete(solution);
4146 result->coeffs = tsolution;
4149 result->linedata = line_data;
4157 giraffe_wlsolution_delete(solution);
4159 _giraffe_lineparams_delete(line_setup);
4180 const cxchar *s = NULL;
4181 const cpl_parameter *p = NULL;
4190 config = cx_calloc(1,
sizeof *config);
4205 p = cpl_parameterlist_find(list,
"giraffe.wlcalibration.line.widths");
4206 s = cpl_parameter_get_string(p);
4210 cxchar **values = cx_strsplit(s,
",", -1);
4213 if (values == NULL) {
4226 while (values[n] != NULL) {
4231 config->
line_widths = cx_malloc(n *
sizeof(cxint));
4235 while (values[n] != NULL) {
4237 cxint w = strtol(values[n], &last, 10);
4239 if (*last !=
'\0') {
4240 cx_strfreev(values);
4253 sizeof(cxint), _giraffe_window_compare);
4256 cx_strfreev(values);
4264 p = cpl_parameterlist_find(list,
"giraffe.wlcalibration.line.separation");
4267 p = cpl_parameterlist_find(list,
"giraffe.wlcalibration.line.fluxratio");
4270 p = cpl_parameterlist_find(list,
"giraffe.wlcalibration.line.brightness");
4273 p = cpl_parameterlist_find(list,
"giraffe.wlcalibration.line.count");
4274 config->
line_count = cpl_parameter_get_int(p);
4276 p = cpl_parameterlist_find(list,
"giraffe.wlcalibration.line.wrange");
4277 s = cpl_parameter_get_string(p);
4281 cxchar **values = cx_strsplit(s,
",", 3);
4283 if (values == NULL) {
4293 cxdouble lower = 0.;
4294 cxdouble upper = 0.;
4297 lower = strtod(values[0], &last);
4299 if (*last !=
'\0') {
4301 cx_strfreev(values);
4308 lower = lower >= 0. ? lower : 0.;
4311 if (values[1] != NULL) {
4313 upper = strtod(values[1], &last);
4315 if (*last !=
'\0') {
4317 cx_strfreev(values);
4324 upper = upper > lower ? upper : 0.;
4333 cx_strfreev(values);
4339 p = cpl_parameterlist_find(list,
"giraffe.wlcalibration.line.model");
4340 s = cpl_parameter_get_string(p);
4342 if (strcmp(s,
"psfexp") != 0 &&
4343 strcmp(s,
"psfexp2") != 0 &&
4344 strcmp(s,
"gaussian") != 0) {
4355 p = cpl_parameterlist_find(list,
"giraffe.wlcalibration.line.residuals");
4356 s = cpl_parameter_get_string(p);
4358 if (strcmp(s,
"auto") != 0 &&
4359 strcmp(s,
"enable") != 0 &&
4360 strcmp(s,
"disable") != 0) {
4371 p = cpl_parameterlist_find(list,
"giraffe.wlcalibration.line.threshold");
4374 p = cpl_parameterlist_find(list,
"giraffe.wlcalibration.line.offset");
4375 config->
line_offset = cpl_parameter_get_double(p);
4377 p = cpl_parameterlist_find(list,
"giraffe.wlcalibration.line.iterations");
4378 config->
line_niter = cpl_parameter_get_int(p);
4380 p = cpl_parameterlist_find(list,
"giraffe.wlcalibration.line.tests");
4381 config->
line_ntest = cpl_parameter_get_int(p);
4383 p = cpl_parameterlist_find(list,
"giraffe.wlcalibration.line.dchisquare");
4384 config->
line_dchisq = cpl_parameter_get_double(p);
4386 p = cpl_parameterlist_find(list,
"giraffe.wlcalibration.line.rwidthratio");
4389 p = cpl_parameterlist_find(list,
"giraffe.wlcalibration.line.exponent");
4393 p = cpl_parameterlist_find(list,
"giraffe.wlcalibration.slit.offset");
4394 s = cpl_parameter_get_string(p);
4396 cx_assert(s != NULL);
4398 if (cx_strncasecmp(s,
"setup", 5) != 0) {
4400 cxchar **values = cx_strsplit(s,
",", 4);
4408 if (values == NULL || values[0] == NULL) {
4418 if (*values[0] !=
'\0') {
4421 cxdouble sdx = strtod(values[0], &last);
4423 if (*last !=
'\0') {
4424 cx_strfreev(values);
4437 if (values[1] == NULL) {
4442 if (*values[1] !=
'\0') {
4445 cxdouble sdy = strtod(values[1], &last);
4447 if (*last !=
'\0') {
4448 cx_strfreev(values);
4463 if (!eol && values[2] != NULL) {
4465 if (*values[2] !=
'\0') {
4468 cxdouble sphi = strtod(values[2], &last);
4470 if (*last !=
'\0') {
4471 cx_strfreev(values);
4486 cx_strfreev(values);
4494 p = cpl_parameterlist_find(list,
"giraffe.wlcalibration.opt.model");
4495 s = cpl_parameter_get_string(p);
4497 if (strcmp(s,
"xoptmod") != 0 && strcmp(s,
"xoptmod2") != 0) {
4508 p = cpl_parameterlist_find(list,
"giraffe.wlcalibration.opt.direction");
4511 p = cpl_parameterlist_find(list,
"giraffe.wlcalibration.opt.solution");
4514 p = cpl_parameterlist_find(list,
"giraffe.wlcalibration.opt.subslits");
4517 p = cpl_parameterlist_find(list,
"giraffe.wlcalibration.opt.flags");
4518 s = cpl_parameter_get_string(p);
4522 cxchar **values = cx_strsplit(s,
",", -1);
4524 if (values == NULL) {
4537 while (values[i] != NULL) {
4539 if (strncmp(values[i],
"fcoll", 5) == 0) {
4543 else if (strncmp(values[i],
"gcam", 4) == 0) {
4547 else if (strncmp(values[i],
"theta", 5) == 0) {
4551 else if (strncmp(values[i],
"sdx", 3) == 0) {
4555 else if (strncmp(values[i],
"sdy", 3) == 0) {
4559 else if (strncmp(values[i],
"sphi", 4) == 0) {
4568 cx_strfreev(values);
4586 p = cpl_parameterlist_find(list,
"giraffe.wlcalibration.opt.iterations");
4587 config->
opt_niter = cpl_parameter_get_int(p);
4589 p = cpl_parameterlist_find(list,
"giraffe.wlcalibration.opt.tests");
4590 config->
opt_ntest = cpl_parameter_get_int(p);
4592 p = cpl_parameterlist_find(list,
"giraffe.wlcalibration.opt.dchisquare");
4593 config->
opt_dchisq = cpl_parameter_get_double(p);
4596 p = cpl_parameterlist_find(list,
"giraffe.wlcalibration.psf.sigma");
4599 p = cpl_parameterlist_find(list,
"giraffe.wlcalibration.psf.iterations");
4602 p = cpl_parameterlist_find(list,
"giraffe.wlcalibration.psf.fraction");
4605 p = cpl_parameterlist_find(list,
"giraffe.wlcalibration.psf.order");
4606 s = cpl_parameter_get_string(p);
4610 cxchar **values = cx_strsplit(s,
",", 3);
4612 if (values == NULL || values[1] == NULL) {
4623 config->
pxw_xorder = strtol(values[0], &last, 10);
4625 if (*last !=
'\0') {
4627 cx_strfreev(values);
4634 config->
pxw_yorder = strtol(values[1], &last, 10);
4636 if (*last !=
'\0') {
4638 cx_strfreev(values);
4647 cx_strfreev(values);
4653 p = cpl_parameterlist_find(list,
"giraffe.wlcalibration.wsol.sigma");
4656 p = cpl_parameterlist_find(list,
"giraffe.wlcalibration.wsol.iterations");
4659 p = cpl_parameterlist_find(list,
"giraffe.wlcalibration.wsol.fraction");
4662 p = cpl_parameterlist_find(list,
"giraffe.wlcalibration.wsol.order");
4663 s = cpl_parameter_get_string(p);
4667 cxchar **values = cx_strsplit(s,
",", 3);
4669 if (values == NULL || values[1] == NULL) {
4680 config->
xws_xorder = strtol(values[0], &last, 10);
4682 if (*last !=
'\0') {
4684 cx_strfreev(values);
4691 config->
xws_yorder = strtol(values[1], &last, 10);
4693 if (*last !=
'\0') {
4695 cx_strfreev(values);
4704 cx_strfreev(values);
4786 p = cpl_parameter_new_value(
"giraffe.wlcalibration.line.widths",
4788 "List of window widths [pxl] used for line "
4789 "detection and fit (e.g. '60,40,15').",
4790 "giraffe.wlcalibration",
4792 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"wcal-lswidth");
4793 cpl_parameterlist_append(list, p);
4796 p = cpl_parameter_new_value(
"giraffe.wlcalibration.line.separation",
4798 "Factor used to compute the minimum line "
4799 "separation from the window width.",
4800 "giraffe.wlcalibration",
4802 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"wcal-lssep");
4803 cpl_parameterlist_append(list, p);
4806 p = cpl_parameter_new_value(
"giraffe.wlcalibration.line.fluxratio",
4808 "Selects only lines whose neighbours have "
4809 "a relative intensity less than "
4811 "giraffe.wlcalibration",
4814 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"wcal-lsfxratio");
4815 cpl_parameterlist_append(list, p);
4818 p = cpl_parameter_new_value(
"giraffe.wlcalibration.line.brightness",
4820 "Selects lines having an intensity greater "
4821 "or equal to the given intensity.",
4822 "giraffe.wlcalibration",
4825 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"wcal-lsbright");
4826 cpl_parameterlist_append(list, p);
4829 p = cpl_parameter_new_value(
"giraffe.wlcalibration.line.count",
4831 "Sets the minimum number of lines to select; "
4832 "selected are lines with the highest nominal "
4833 "intensity. A value of 0 turns this selection "
4834 "off. If the value is less than 0 the "
4835 "selection is skipped if the line list does "
4836 "not contain enough lines.",
4837 "giraffe.wlcalibration",
4840 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"wcal-lscount");
4841 cpl_parameterlist_append(list, p);
4844 p = cpl_parameter_new_value(
"giraffe.wlcalibration.line.wrange",
4846 "Selects only lines within the given "
4847 "wavelength range [nm].",
4848 "giraffe.wlcalibration",
4851 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"wcal-lswrange");
4852 cpl_parameterlist_append(list, p);
4859 p = cpl_parameter_new_enum(
"giraffe.wlcalibration.line.model",
4861 "Line profile model.",
4862 "giraffe.wlcalibration",
4863 "psfexp", 3,
"psfexp",
"psfexp2",
"gaussian");
4865 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"wcal-lfmodel");
4866 cpl_parameterlist_append(list, p);
4869 p = cpl_parameter_new_enum(
"giraffe.wlcalibration.line.residuals",
4871 "Use optical model residuals for line "
4873 "giraffe.wlcalibration",
4874 "auto", 3,
"auto",
"enable",
"disable");
4876 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"wcal-lfres");
4877 cpl_parameterlist_append(list, p);
4880 p = cpl_parameter_new_value(
"giraffe.wlcalibration.line.threshold",
4882 "Line detection threshold during the "
4883 "line fitting (multiple of bias sigma)",
4884 "giraffe.wlcalibration",
4887 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"wcal-lfthreshold");
4888 cpl_parameterlist_append(list, p);
4891 p = cpl_parameter_new_value(
"giraffe.wlcalibration.line.offset",
4893 "Maximum allowed difference between the "
4894 "fitted and raw line peak position.",
4895 "giraffe.wlcalibration",
4898 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"wcal-lfoffset");
4899 cpl_parameterlist_append(list, p);
4902 p = cpl_parameter_new_value(
"giraffe.wlcalibration.line.iterations",
4904 "Line detection fit maximum number of "
4906 "giraffe.wlcalibration",
4909 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"wcal-lfniter");
4910 cpl_parameterlist_append(list, p);
4913 p = cpl_parameter_new_value(
"giraffe.wlcalibration.line.tests",
4915 "Line detection fit maximum number of "
4917 "giraffe.wlcalibration",
4920 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"wcal-lfntest");
4921 cpl_parameterlist_append(list, p);
4924 p = cpl_parameter_new_value(
"giraffe.wlcalibration.line.dchisquare",
4926 "Line detection fit minimum chi-square "
4928 "giraffe.wlcalibration",
4931 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"wcal-lfdchisq");
4932 cpl_parameterlist_append(list, p);
4935 p = cpl_parameter_new_value(
"giraffe.wlcalibration.line.rwidthratio",
4937 "Line width/resolution width factor.",
4938 "giraffe.wlcalibration",
4941 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"wcal-lfreswid");
4942 cpl_parameterlist_append(list, p);
4945 p = cpl_parameter_new_value(
"giraffe.wlcalibration.line.exponent",
4947 "Exponential line profile exponent; it will "
4948 "not be fitted if it is larger than 0.",
4949 "giraffe.wlcalibration",
4952 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"wcal-lfexpwid");
4953 cpl_parameterlist_append(list, p);
4961 p = cpl_parameter_new_value(
"giraffe.wlcalibration.slit.offset",
4963 "Initial slit position offsets along the "
4964 "x and y direction and rotation angle.",
4965 "giraffe.wlcalibration",
4968 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"wcal-soffset");
4969 cpl_parameterlist_append(list, p);
4976 p = cpl_parameter_new_enum(
"giraffe.wlcalibration.opt.model",
4979 "giraffe.wlcalibration",
4980 "xoptmod2", 2,
"xoptmod",
"xoptmod2");
4982 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"wcal-ommodel");
4983 cpl_parameterlist_append(list, p);
4986 p = cpl_parameter_new_value(
"giraffe.wlcalibration.opt.direction",
4988 "Dispersion direction flag.",
4989 "giraffe.wlcalibration",
4992 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"wcal-omdir");
4993 cpl_parameterlist_append(list, p);
4996 p = cpl_parameter_new_value(
"giraffe.wlcalibration.opt.solution",
4998 "Controls optical model parameter fitting.",
4999 "giraffe.wlcalibration",
5002 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"wcal-omsol");
5003 cpl_parameterlist_append(list, p);
5006 p = cpl_parameter_new_value(
"giraffe.wlcalibration.opt.flags",
5008 "List of flags defining the set of free "
5009 "parameters used for fitting the optical "
5010 "model. Possible values are: fcoll, gcam, "
5011 "theta, sdx, sdy, sphi",
5012 "giraffe.wlcalibration",
5015 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"wcal-omflags");
5016 cpl_parameterlist_append(list, p);
5019 p = cpl_parameter_new_value(
"giraffe.wlcalibration.opt.subslits",
5021 "Controls subslit geometry usage in the "
5022 "optical model fit; subslits are used if "
5024 "giraffe.wlcalibration",
5027 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"wcal-omsslits");
5028 cpl_parameterlist_append(list, p);
5031 p = cpl_parameter_new_value(
"giraffe.wlcalibration.opt.iterations",
5033 "Optical model fit maximum number of "
5035 "giraffe.wlcalibration",
5038 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"wcal-omniter");
5039 cpl_parameterlist_append(list, p);
5042 p = cpl_parameter_new_value(
"giraffe.wlcalibration.opt.tests",
5044 "Optical model fit maximum number of "
5046 "giraffe.wlcalibration",
5049 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"wcal-omntest");
5050 cpl_parameterlist_append(list, p);
5053 p = cpl_parameter_new_value(
"giraffe.wlcalibration.opt.dchisquare",
5055 "Optical model fit minimum chi-square "
5057 "giraffe.wlcalibration",
5060 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"wcal-omdchisq");
5061 cpl_parameterlist_append(list, p);
5068 p = cpl_parameter_new_value(
"giraffe.wlcalibration.psf.sigma",
5070 "PSF width fit sigma clipping factor.",
5071 "giraffe.wlcalibration",
5074 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"wcal-xwsigma");
5075 cpl_parameterlist_append(list, p);
5078 p = cpl_parameter_new_value(
"giraffe.wlcalibration.psf.iterations",
5080 "PSF width fit sigma clipping maximum "
5081 "number of iterations.",
5082 "giraffe.wlcalibration",
5085 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"wcal-xwniter");
5086 cpl_parameterlist_append(list, p);
5089 p = cpl_parameter_new_range(
"giraffe.wlcalibration.psf.fraction",
5091 "PSF width fit sigma clipping minimum "
5092 "fraction of points accepted/total.",
5093 "giraffe.wlcalibration",
5096 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"wcal-xwmfrac");
5097 cpl_parameterlist_append(list, p);
5100 p = cpl_parameter_new_value(
"giraffe.wlcalibration.psf.order",
5102 "X and Y polynomial orders for PSF x-width "
5104 "giraffe.wlcalibration",
5107 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"wcal-xworder");
5108 cpl_parameterlist_append(list, p);
5115 p = cpl_parameter_new_value(
"giraffe.wlcalibration.wsol.sigma",
5117 "Chebyshev correction sigma clipping factor.",
5118 "giraffe.wlcalibration",
5121 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"wcal-wssigma");
5122 cpl_parameterlist_append(list, p);
5125 p = cpl_parameter_new_value(
"giraffe.wlcalibration.wsol.iterations",
5127 "Chebyshev correction sigma clipping "
5128 "maximum number of iterations",
5129 "giraffe.wlcalibration",
5132 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"wcal-wsniter");
5133 cpl_parameterlist_append(list, p);
5136 p = cpl_parameter_new_range(
"giraffe.wlcalibration.wsol.fraction",
5138 "Chebyshev correction sigma clipping "
5139 "minimum fraction of points accepted/total.",
5140 "giraffe.wlcalibration",
5143 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"wcal-wsmfrac");
5144 cpl_parameterlist_append(list, p);
5147 p = cpl_parameter_new_value(
"giraffe.wlcalibration.wsol.order",
5149 "X and Y polynomial orders for the wavelength "
5150 "solution Chebyshev correction.",
5151 "giraffe.wlcalibration",
5154 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"wcal-wsorder");
5155 cpl_parameterlist_append(list, p);
cxdouble giraffe_range_get_min(const GiRange *const self)
Get the minimum of a range.
GiWCalConfig * giraffe_wlcalibration_config_create(cpl_parameterlist *list)
Creates a setup structure for the wavelength calibration.
GiGrating * giraffe_grating_create(const GiImage *spectra, const GiTable *grating)
Create a GiGrating from a reference image.
cpl_table * giraffe_table_get(const GiTable *self)
Get the table data from a Giraffe table.
Wavelength calibration configuration data structure.
cxint giraffe_table_set(GiTable *self, cpl_table *table)
Sets the table data.
void giraffe_table_delete(GiTable *self)
Destroys a Giraffe table.
GiRange * giraffe_range_create(cxdouble min, cxdouble max)
Creates a new range from the given minimum and maximum values.
const cxchar * giraffe_fiberlist_query_index(const cpl_table *fibers)
Query a fiber list for the name of the fiber reference index column.
GiTable * giraffe_table_new(void)
Creates a new, empty Giraffe table.
GiWlSolution * giraffe_wlsolution_create(GiTable *solution, GiImage *spectra, GiGrating *grating)
Create a new wavelength solution from a wavelength solution table.
void gi_error(const cxchar *format,...)
Log an error message.
cxdouble line_widthexponent
cxint giraffe_table_set_properties(GiTable *self, cpl_propertylist *properties)
Attaches a property list to an table.
cxdouble line_rwidthratio
cxint giraffe_matrix_sort(cpl_matrix *mA)
Sort in place the matrix elements in ascending order.
void giraffe_wlcalibration_config_add(cpl_parameterlist *list)
Adds parameters for the wavelength calibration.
Structure to handle Grating Information.
void giraffe_grating_delete(GiGrating *self)
Destroys an GiGrating object.
cpl_image * giraffe_image_get(const GiImage *self)
Gets the image data.
cpl_matrix * giraffe_matrix_leastsq(const cpl_matrix *mA, const cpl_matrix *mB)
Computes the solution of an equation using a pseudo-inverse.
void giraffe_wlcalibration_config_destroy(GiWCalConfig *config)
Destroys a wavelength calibration setup structure.
cpl_propertylist * giraffe_table_get_properties(const GiTable *self)
Gets the table properties.
cxint giraffe_calibrate_wavelength(GiWCalData *result, GiExtraction *extraction, GiLocalization *localization, GiTable *fibers, GiTable *slitgeometry, GiTable *grating, GiTable *lines, GiTable *initial, GiWCalConfig *config)
Compute the wavelength solution for the given extracted arc-lamp spectra.
void giraffe_range_delete(GiRange *self)
Destroys a range object.
cpl_propertylist * giraffe_image_get_properties(const GiImage *self)
Get the properties of an image.
cxdouble giraffe_range_get_max(const GiRange *const self)
Get the maximum of a range.