28#include <cxmessages.h>
30#include <cxstrutils.h>
40#include "gilinedata.h"
41#include "giwlsolution.h"
43#include "gimessages.h"
44#include "gifiberutils.h"
46#include "giwlcalibration.h"
64 GI_LINETYPE_UNDEFINED,
69typedef enum GiLineType GiLineType;
110 OPTM_FLENGTH = 1 << 0,
111 OPTM_GCAMERA = 1 << 1,
123enum GiOpticalModelInfo {
124 GI_OPTM_PARAMETER_VALUES,
125 GI_OPTM_PARAMETER_ERRORS,
126 GI_OPTM_PARAMETER_STATUS
129typedef enum GiOpticalModelInfo GiOpticalModelInfo;
153typedef struct GiLineParams GiLineParams;
160struct GiOpticalModelParams {
167typedef struct GiOpticalModelParams GiOpticalModelParams;
174struct GiSCFitParams {
187typedef struct GiSCFitParams GiSCFitParams;
206typedef struct GiWCalInfo GiWCalInfo;
210_giraffe_window_compare(cxcptr first, cxcptr second)
213 cxint *_first = (cxint *)first;
214 cxint *_second = (cxint *)second;
216 return *_second - *_first;
221inline static GiLineParams *
222_giraffe_lineparams_create(GiLineType type,
const GiGrating *grating,
226 GiLineParams *self = NULL;
229 cx_assert(grating != NULL);
230 cx_assert(config != NULL);
232 self = cx_calloc(1,
sizeof(GiLineParams));
243 self->grwid = 1. / grating->
band * (grating->
wlen0 / grating->
resol);
261_giraffe_lineparams_delete(GiLineParams *self)
267 cx_free((cxptr)self->model);
279inline static cxdouble
280_giraffe_get_fiber_position(
const cpl_image *locy, cxint cs, cxdouble xccd)
283 cxint xlower = (cxint)floor(xccd);
284 cxint xupper = (cxint)ceil(xccd);
286 const cxdouble *ldata = cpl_image_get_data_const(locy);
288 cxdouble ylower = 0.;
289 cxdouble yupper = 0.;
292 cx_assert(ldata != NULL);
294 ylower = ldata[xlower * cpl_image_get_size_x(locy) + cs];
295 yupper = ldata[xupper * cpl_image_get_size_x(locy) + cs];
297 return giraffe_interpolate_linear(xccd, xlower, ylower, xupper, yupper);
303_giraffe_subslit_get_max(
const cpl_table *fibers)
306 return cpl_table_get_column_max((cpl_table *)fibers,
"SSN");
311inline static cpl_table *
312_giraffe_subslit_get(
const cpl_table *fibers, cxint ssn)
320 cx_assert(fibers != NULL);
321 cx_assert(cpl_table_has_column((cpl_table *)fibers,
"SSN"));
323 ssn_max = _giraffe_subslit_get_max(fibers);
325 if (ssn < 0 || ssn > ssn_max) {
329 cpl_table_unselect_all((cpl_table *)fibers);
330 cpl_table_or_selected_int((cpl_table *)fibers,
"SSN", CPL_EQUAL_TO, ssn);
332 _fibers = cpl_table_extract_selected((cpl_table *)fibers);
340_giraffe_subslit_range(
const cpl_table *subslit,
const cpl_image *locy,
341 const cpl_image *locw, cxdouble *ymin, cxdouble *ymax)
344 const cxchar *idx = NULL;
350 const cxdouble *_locy = NULL;
351 const cxdouble *_locw = NULL;
353 cxdouble _ymin = CX_MAXDOUBLE;
356 cx_assert(subslit != NULL);
357 cx_assert(locy != NULL);
358 cx_assert(locw != NULL);
362 ns = cpl_image_get_size_x(locy);
363 nx = cpl_image_get_size_y(locy);
365 _locy = cpl_image_get_data_const(locy);
366 _locw = cpl_image_get_data_const(locw);
368 for (i = 0; i < cpl_table_get_nrow((cpl_table *)subslit); i++) {
371 cxint cs = cpl_table_get_int((cpl_table *)subslit, idx, i, NULL) - 1;
373 for (j = 0; j < nx; j++) {
375 register cxint k = j * ns + cs;
377 cxdouble ylower = _locy[k] - _locw[k];
378 cxdouble yupper = _locy[k] + _locw[k];
380 _ymin = CX_MIN(_ymin, ylower);
381 _ymax = CX_MAX(_ymax, yupper);
405_giraffe_get_residuals(cpl_image *residuals,
const cpl_image *positions,
406 const cpl_image *fit)
414 const cxdouble *_positions = NULL;
415 const cxdouble *_fit = NULL;
417 cxdouble *_residuals = NULL;
420 cx_assert(residuals != NULL);
421 cx_assert(positions != NULL);
422 cx_assert(fit != NULL);
424 nfibers = cpl_image_get_size_x(positions);
425 nlines = cpl_image_get_size_y(positions);
426 nx = cpl_image_get_size_y(fit);
428 cx_assert(nfibers == cpl_image_get_size_x(residuals));
429 cx_assert(nlines == cpl_image_get_size_y(residuals));
431 _residuals = cpl_image_get_data(residuals);
432 _positions = cpl_image_get_data_const(positions);
433 _fit = cpl_image_get_data_const(fit);
435 for (i = 0; i < nlines; i++) {
439 for (j = 0; j < nfibers; j++) {
441 register cxdouble line_pos = _positions[i * nfibers + j];
443 line_pos = CX_MIN(CX_MAX(line_pos, 0.), nx - 1);
444 _residuals[i * nfibers + j] = _fit[(cxint)line_pos * nfibers + j];
456_giraffe_apply_residuals(cpl_image *xccd,
const cpl_image *residuals,
457 const cpl_image *lflags, cxdouble value)
460 cx_assert(xccd != NULL);
461 cx_assert(residuals != NULL);
463 cpl_image_subtract(xccd, residuals);
465 if (lflags != NULL) {
467 const cxint *_lflags = cpl_image_get_data_const(lflags);
470 cxint nfibers = cpl_image_get_size_x(xccd);
471 cxint nlines = cpl_image_get_size_y(xccd);
473 cxdouble *_xccd = cpl_image_get_data(xccd);
476 cx_assert(nfibers == cpl_image_get_size_x(lflags));
477 cx_assert(nlines == cpl_image_get_size_y(lflags));
479 for (i = 0; i < nlines; i++) {
483 for (j = 0; j < nfibers; j++) {
485 if (_lflags[i * nfibers + j] > 0) {
486 _xccd[i * nfibers + j] = value;
501_giraffe_linelist_setup(GiTable *lines,
GiGrating *grating,
505 const cxchar *
const fctid =
"_giraffe_linelist_setup";
508 const cxdouble fraction = 500.;
516 cxdouble margin = 0.;
518 cpl_table *_lines = NULL;
522 cx_assert(lines != NULL);
523 cx_assert(grating != NULL);
524 cx_assert(config != NULL);
529 if (_lines == NULL) {
533 if (!cpl_table_has_column(_lines,
"WLEN") ||
534 !cpl_table_has_column(_lines,
"FLUX")) {
544 nlines = cpl_table_get_nrow(_lines);
545 cpl_table_unselect_all(_lines);
560 margin = (wlmax - wlmin) / fraction;
562 cpl_msg_debug(fctid,
"Selecting wavelength range [%.4f, %.4f[ [nm] with "
563 "margin %.4f nm.", wlmin, wlmax, margin);
565 cpl_table_or_selected_double(_lines,
"WLEN", CPL_LESS_THAN,
567 cpl_table_or_selected_double(_lines,
"WLEN", CPL_NOT_LESS_THAN,
570 cpl_table_erase_selected(_lines);
572 if (cpl_table_get_nrow(_lines) <= 0) {
573 cpl_msg_debug(fctid,
"Invalid line list! All lines have been "
578 nreject = nlines - cpl_table_get_nrow(_lines);
579 cpl_msg_debug(fctid,
"%d of %d lines rejected because of wavelength "
580 "range.", nreject, nlines);
587 nlines = cpl_table_get_nrow(_lines);
594 cpl_propertylist *sorting_order = NULL;
597 if (line_count > nlines) {
598 cpl_msg_debug(fctid,
"Too few lines in line list for brightness "
605 cpl_msg_debug(fctid,
"Skipping brightness selection!");
610 sorting_order = cpl_propertylist_new();
611 cpl_propertylist_append_bool(sorting_order,
"FLUX", 1);
613 cpl_table_sort(_lines, sorting_order);
615 cpl_propertylist_delete(sorting_order);
616 sorting_order = NULL;
618 cpl_table_select_all(_lines);
620 for (i = 0; i < line_count; i++) {
621 cpl_table_unselect_row(_lines, i);
624 cpl_table_erase_selected(_lines);
626 if (cpl_table_get_nrow(_lines) <= 0) {
630 sorting_order = cpl_propertylist_new();
631 cpl_propertylist_append_bool(sorting_order,
"WLEN", 0);
633 cpl_table_sort(_lines, sorting_order);
635 cpl_propertylist_delete(sorting_order);
636 sorting_order = NULL;
642 cpl_table_select_all(_lines);
643 cpl_table_and_selected_double(_lines,
"FLUX", CPL_NOT_GREATER_THAN,
646 cpl_table_erase_selected(_lines);
648 if (cpl_table_get_nrow(_lines) <= 0) {
649 cpl_msg_debug(fctid,
"Invalid line brightness! All lines have "
656 nreject = nlines - cpl_table_get_nrow(_lines);
657 cpl_msg_debug(fctid,
"%d of %d lines rejected because brightness "
658 "criteria.", nreject, nlines);
666inline static cpl_table *
667_giraffe_linelist_select(
const GiTable *lines,
const GiImage *spectra,
668 const GiGrating *grating, cxdouble width,
672 const cxchar *
const fctid =
"_giraffe_linelist_select";
680 cxdouble separation = 0.;
682 cpl_image *_spectra = NULL;
684 cpl_table *_lines = NULL;
687 cx_assert(lines != NULL);
688 cx_assert(spectra != NULL);
689 cx_assert(grating != NULL);
690 cx_assert(config != NULL);
693 cx_assert(_spectra != NULL);
697 if (_lines == NULL) {
701 nlines = cpl_table_get_nrow(_lines);
709 scale = fabs((
double) cpl_image_get_size_y(_spectra)) / grating->
band;
712 cpl_msg_debug(fctid,
"Estimated wavelength scale: %.4e nm/pxl",
714 cpl_msg_debug(fctid,
"Minimum required line separation: %.4f nm (%.4f "
715 "pxl)", separation, separation * scale);
731 cpl_table_unselect_all(_lines);
733 for (i = 0; i < cpl_table_get_nrow(_lines); i++) {
737 register cxdouble w = cpl_table_get(_lines,
"WLEN", i, NULL);
738 register cxdouble f = cpl_table_get(_lines,
"FLUX", i, NULL);
741 for (j = 0; j < cpl_table_get_nrow(_lines); j++) {
745 register cxdouble _w = cpl_table_get(_lines,
"WLEN", j, NULL);
746 register cxdouble _f = cpl_table_get(_lines,
"FLUX", j, NULL);
749 if (fabs(w - _w) < separation &&
750 f / _f < config->line_fluxratio) {
752 cpl_table_select_row(_lines, i);
763 cpl_table_erase_selected(_lines);
765 if (cpl_table_get_nrow(_lines) <= 0) {
766 cpl_table_delete(_lines);
770 nreject = nlines - cpl_table_get_nrow(_lines);
771 cpl_msg_debug(fctid,
"%d of %d lines rejected due to crowding.",
784 cpl_msg_debug(fctid,
"Removing lines with non-zero line quality.");
786 nlines = cpl_table_get_nrow(_lines);
787 cpl_table_unselect_all(_lines);
789 if (cpl_table_has_column(_lines,
"FLAGS")) {
791 cpl_table_or_selected_int(_lines,
"FLAGS", CPL_NOT_EQUAL_TO, 0);
796 if (cpl_table_has_column(_lines,
"COMMENT")) {
798 for (i = 0; i < nlines; i++) {
800 cxchar *s = cx_strdup(cpl_table_get_string(_lines,
803 if (strlen(cx_strstrip(s)) > 3) {
804 cpl_table_select_row(_lines, i);
814 cpl_msg_debug(fctid,
"No comments found in line list! No line "
815 "quality checks will be done!");
821 cpl_table_erase_selected(_lines);
823 if (cpl_table_get_nrow(_lines) <= 0) {
824 cpl_msg_debug(fctid,
"Invalid line list! All lines have been "
826 cpl_table_delete(_lines);
830 nreject = nlines - cpl_table_get_nrow(_lines);
831 cpl_msg_debug(fctid,
"%d of %d lines rejected because of line quality.",
840inline static cpl_image *
841_giraffe_line_abscissa(
const cpl_table *lines,
const GiTable *slitgeometry,
842 const GiTable *fibers,
const GiWlSolution *solution,
843 const GiLocalization *localization, cxbool residuals)
846 const cxchar *
const fctid =
"_giraffe_line_abscissa";
849 const cxchar *idx = NULL;
855 cpl_table *_lines = NULL;
856 cpl_table *_fibers = NULL;
857 cpl_table *_slitgeometry = NULL;
859 cpl_image *abscissa = NULL;
862 cx_assert(lines != NULL);
863 cx_assert(slitgeometry != NULL);
864 cx_assert(fibers != NULL);
865 cx_assert(solution != NULL);
867 _lines = (cpl_table *)lines;
870 cx_assert(_fibers != NULL);
873 cx_assert(_slitgeometry != NULL);
876 nlines = cpl_table_get_nrow(_lines);
877 nfibers = cpl_table_get_nrow(_fibers);
879 if (nfibers != cpl_table_get_nrow(_slitgeometry)) {
880 cpl_error_set(fctid, CPL_ERROR_ILLEGAL_INPUT);
888 cpl_error_set(fctid, CPL_ERROR_ILLEGAL_INPUT);
893 if (residuals == TRUE) {
895 if (localization == NULL) {
896 cpl_error_set(fctid, CPL_ERROR_ILLEGAL_INPUT);
900 if (localization->locy == NULL || localization->locw == NULL) {
901 cpl_error_set(fctid, CPL_ERROR_DATA_NOT_FOUND);
906 if (giraffe_wlsolution_get_residuals(solution) == NULL) {
907 cpl_error_set(fctid, CPL_ERROR_DATA_NOT_FOUND);
914 abscissa = cpl_image_new(nfibers, nlines, CPL_TYPE_DOUBLE);
916 for (i = 0; i < nfibers; i++) {
920 cxdouble xf = cpl_table_get(_slitgeometry,
"XF", i, NULL);
921 cxdouble yf = cpl_table_get(_slitgeometry,
"YF", i, NULL);
922 cxdouble *data = cpl_image_get_data(abscissa);
925 for (j = 0; j < nlines; j++) {
929 cxdouble lambda = cpl_table_get(_lines,
"WLEN", j, NULL);
934 xccd = giraffe_wlsolution_compute_pixel(solution, lambda, xf, yf,
938 cpl_image_delete(abscissa);
942 if (residuals == TRUE) {
944 cxint cs = cpl_table_get_int(_fibers, idx, i, NULL) - 1;
951 cx_assert(_locy != NULL);
953 if (xccd > 0. && ceil(xccd) < cpl_image_get_size_y(_locy)) {
957 yccd = _giraffe_get_fiber_position(_locy, cs, xccd);
958 xres = giraffe_wlsolution_compute_residual(solution,
966 data[j * nfibers + i] = xccd;
983_giraffe_line_fit_setup(GiModel *model, cxdouble width, cxint xmin,
984 const cpl_matrix *y,
const cpl_matrix *sigma,
985 const GiLineParams *setup, cxint *lflags)
992 cxdouble amplitude = 0.;
993 cxdouble background = 0.;
994 cxdouble _sigma = 0.;
996 cpl_matrix *_y = NULL;
999 cx_assert(model != NULL);
1000 cx_assert(y != NULL);
1001 cx_assert(setup != NULL);
1002 cx_assert(lflags != NULL);
1005 if (*lflags != LF_R_NONE) {
1020 for (k = 0; k < cpl_matrix_get_nrow((cpl_matrix*)y); k++) {
1021 if (cpl_matrix_get((cpl_matrix *)y, k, 0) >= amplitude) {
1024 amplitude = cpl_matrix_get((cpl_matrix *)y, k, 0);
1031 _y = cpl_matrix_duplicate((cpl_matrix *)y);
1035 background = 0.5 * (cpl_matrix_get(_y, 0, 0) + cpl_matrix_get(_y, 1, 0));
1036 cpl_matrix_delete(_y);
1046 _sigma = cpl_matrix_get((cpl_matrix *)sigma, xline, 0) * setup->thres;
1048 if (amplitude <= _sigma || amplitude > setup->satlv) {
1049 *lflags |= LF_R_AMPLI;
1053 giraffe_model_set_parameter(model,
"Amplitude", amplitude - background);
1054 giraffe_model_set_parameter(model,
"Center", center);
1055 giraffe_model_set_parameter(model,
"Background", background);
1056 giraffe_model_set_parameter(model,
"Width1", width);
1058 if (strncmp(giraffe_model_get_name(model),
"psfexp", 6) == 0) {
1060 cxdouble width2 = setup->psfexp < 0. ? -setup->psfexp : setup->psfexp;
1062 giraffe_model_set_parameter(model,
"Width2", width2);
1070 if (setup->psfexp >= 0.) {
1071 giraffe_model_freeze_parameter(model,
"Width2");
1074 giraffe_model_thaw_parameter(model,
"Width2");
1085_giraffe_line_fit(GiLineData *lines,
const cpl_image *positions, cxint width,
1086 const GiExtraction *extraction,
const GiTable *fibers,
1087 const GiImage *locy,
const GiLineParams *setup)
1090 const cxchar *
const fctid =
"_giraffe_line_fit";
1093 const cxchar *idx = NULL;
1099 const cxdouble LOG2 = log(2.);
1100 const cxdouble fwhm_ratio = 2. * sqrt(2. * LOG2);
1102 cpl_image *_spectra = NULL;
1103 cpl_image *_errors = NULL;
1104 cpl_image *_locy = NULL;
1106 cpl_matrix *x = NULL;
1107 cpl_matrix *y = NULL;
1108 cpl_matrix *sigma = NULL;
1110 cpl_table *_fibers = NULL;
1112 GiModel *model = NULL;
1115 cx_assert(positions != NULL);
1116 cx_assert(width > 0);
1118 cx_assert(extraction != NULL);
1119 cx_assert(extraction->spectra != NULL && extraction->error != NULL);
1121 cx_assert(fibers != NULL);
1122 cx_assert(locy != NULL);
1123 cx_assert(setup != NULL);
1127 cx_assert(_fibers != NULL);
1130 cx_assert(_spectra != NULL);
1133 cx_assert(_errors != NULL);
1136 cx_assert(_locy != NULL);
1138 nfibers = cpl_table_get_nrow(_fibers);
1140 cx_assert(nfibers == cpl_image_get_size_x(_spectra));
1141 cx_assert(nfibers == cpl_image_get_size_x(_errors));
1148 cx_assert(idx != NULL);
1150 nlines = cpl_image_get_size_y(positions);
1157 if (strcmp(setup->model,
"gaussian") != 0 &&
1158 strcmp(setup->model,
"psfexp") != 0 &&
1159 strcmp(setup->model,
"psfexp2") != 0) {
1160 cpl_error_set(fctid, CPL_ERROR_ILLEGAL_INPUT);
1164 model = giraffe_model_new(setup->model);
1166 if (giraffe_model_get_type(model) != GI_MODEL_LINE) {
1167 giraffe_model_delete(model);
1171 giraffe_model_thaw(model);
1173 giraffe_model_set_iterations(model, setup->fit.iterations);
1174 giraffe_model_set_tests(model, setup->fit.tests);
1175 giraffe_model_set_delta(model, setup->fit.delta);
1182 x = cpl_matrix_new(width, 1);
1183 y = cpl_matrix_new(width, 1);
1184 sigma = cpl_matrix_new(width, 1);
1186 for (i = 0; i < nfibers; i++) {
1190 for (j = 0; j < nlines; j++) {
1193 cxint lflags = LF_R_NONE;
1194 cxint iterations = 0;
1198 cxint nx = cpl_image_get_size_y(_spectra);
1202 cxdouble lwidth = 0.;
1203 cxdouble amplitude = 0.;
1204 cxdouble background = 0.;
1205 cxdouble center = 0.;
1206 cxdouble width1 = 0.;
1207 cxdouble exponent = 0.;
1208 cxdouble error = 0.;
1209 cxdouble gwidth = 0.;
1211 const cxdouble *_positions = cpl_image_get_data_const(positions);
1218 xccd = _positions[j * nfibers + i];
1223 if (0 < xccd && ceil(xccd) < nx) {
1225 cxint cs = cpl_table_get_int(_fibers, idx, i, NULL) - 1;
1233 xmin = (cxint)(xccd - 0.5 * width + 0.5);
1234 xmax = (cxint)(xccd + 0.5 * width + 0.5);
1236 xmin = CX_MAX(CX_MIN(xmin, nx - 1), 0);
1237 xmax = CX_MAX(CX_MIN(xmax, nx - 1), 0);
1239 ndata = xmax - xmin;
1246 yccd = _giraffe_get_fiber_position(_locy, cs, xccd);
1257 lflags |= LF_R_XCCD;
1265 if (ndata != cpl_matrix_get_nrow(x)) {
1266 cpl_matrix_set_size(x, ndata, 1);
1267 cpl_matrix_set_size(y, ndata, 1);
1268 cpl_matrix_set_size(sigma, ndata, 1);
1271 for (k = 0; k < ndata; k++) {
1275 cxdouble *sdata = cpl_image_get_data(_spectra);
1276 cxdouble *edata = cpl_image_get_data(_errors);
1278 cpl_matrix_set(x, k, 0, xmin + k);
1279 cpl_matrix_set(y, k, 0, sdata[l * nfibers + i]);
1280 cpl_matrix_set(sigma, k, 0, edata[l * nfibers + i]);
1297 if (strcmp(setup->model,
"psfexp") == 0) {
1299 exponent = fabs(setup->psfexp);
1301 lwidth = pow(0.5 * setup->grwid * nx, exponent) / LOG2;
1304 else if (strcmp(setup->model,
"psfexp2") == 0) {
1306 exponent = fabs(setup->psfexp);
1308 lwidth = setup->grwid * nx / (2. * pow(LOG2, 1. / exponent));
1311 else if (strcmp(setup->model,
"gaussian") == 0) {
1313 lwidth = setup->grwid * nx / fwhm_ratio;
1322 gi_error(
"Unsupported line model encountered!");
1333 _giraffe_line_fit_setup(model, lwidth, xmin, y, sigma, setup,
1337 if (lflags == LF_R_NONE) {
1339 cxint xline = giraffe_model_get_parameter(model,
"Center");
1341 cxdouble hwidth = 0.;
1350 status = giraffe_model_fit(model, x, y, sigma);
1353 amplitude = giraffe_model_get_parameter(model,
"Amplitude");
1354 background = giraffe_model_get_parameter(model,
"Background");
1355 center = giraffe_model_get_parameter(model,
"Center");
1363 if (strcmp(setup->model,
"psfexp") == 0) {
1365 width1 = giraffe_model_get_parameter(model,
"Width1");
1366 exponent = giraffe_model_get_parameter(model,
"Width2");
1369 gwidth = 2. * pow(width1 * LOG2, 1. / exponent);
1372 else if (strcmp(setup->model,
"psfexp2") == 0) {
1374 width1 = giraffe_model_get_parameter(model,
"Width1");
1375 exponent = giraffe_model_get_parameter(model,
"Width2");
1378 gwidth = 2. * pow(LOG2, 1. / exponent) * width1;
1381 else if (strcmp(setup->model,
"gaussian") == 0) {
1383 width1 = giraffe_model_get_parameter(model,
"Width1");
1386 gwidth = width1 * fwhm_ratio;
1395 gi_error(
"Unsupported line model encountered!");
1399 hwidth = gwidth / 2.;
1400 iterations = giraffe_model_get_position(model);
1411 lflags |= LF_R_ERROR;
1415 if (iterations >= giraffe_model_get_iterations(model)) {
1418 lflags |= LF_R_NITER;
1422 if (xmin > center || center > xmax) {
1425 lflags |= LF_R_CENTR;
1429 if ((center - hwidth) < xmin) {
1432 lflags |= LF_R_LEFT;
1436 if ((center + hwidth) > xmax) {
1439 lflags |= LF_R_RIGHT;
1443 if ((center - xline) >= setup->offst) {
1446 lflags |= LF_R_OFFST;
1450 if (width1 < 0. || exponent < 0.) {
1453 lflags |= LF_R_BADLN;
1457 if (gwidth > (xmax - xmin)) {
1460 lflags |= LF_R_WIDTH;
1464 if (gwidth < (setup->grwid * nx * setup->wfact)) {
1467 lflags |= LF_R_RESOL;
1471 if (gwidth > (setup->grwid * nx / setup->wfact)) {
1474 lflags |= LF_R_RESOL;
1487 giraffe_linedata_set_status(lines, i, j, lflags);
1489 giraffe_linedata_set(lines,
"Iterations", i, j,iterations);
1490 giraffe_linedata_set(lines,
"Chi-square", i, j,
1491 giraffe_model_get_chisq(model));
1492 giraffe_linedata_set(lines,
"DoF", i, j,
1493 giraffe_model_get_df(model));
1494 giraffe_linedata_set(lines,
"R-square", i, j,
1495 giraffe_model_get_rsquare(model));
1496 giraffe_linedata_set(lines,
"Xccd", i, j, xccd);
1497 giraffe_linedata_set(lines,
"Yccd", i, j, yccd);
1507 giraffe_linedata_set(lines,
"Amplitude", i, j, amplitude);
1508 giraffe_linedata_set(lines,
"Background", i, j, background);
1509 giraffe_linedata_set(lines,
"Center", i, j, center);
1510 giraffe_linedata_set(lines,
"Width1", i, j, width1);
1512 if (strncmp(setup->model,
"psfexp", 6) == 0) {
1513 giraffe_linedata_set(lines,
"Width2", i, j, exponent);
1516 giraffe_linedata_set(lines,
"FWHM", i, j, gwidth);
1520 error = giraffe_model_get_sigma(model,
"Amplitude");
1521 giraffe_linedata_set(lines,
"dAmplitude", i, j, error);
1523 error = giraffe_model_get_sigma(model,
"Center");
1524 giraffe_linedata_set(lines,
"dCenter", i, j, error);
1526 error = giraffe_model_get_sigma(model,
"Background");
1527 giraffe_linedata_set(lines,
"dBackground", i, j, error);
1529 error = giraffe_model_get_sigma(model,
"Width1");
1530 giraffe_linedata_set(lines,
"dWidth1", i, j, error);
1532 if (strncmp(setup->model,
"psfexp", 6) == 0) {
1533 error = giraffe_model_get_sigma(model,
"Width2");
1534 giraffe_linedata_set(lines,
"dWidth2", i, j, error);
1541 cpl_matrix_delete(x);
1542 cpl_matrix_delete(y);
1543 cpl_matrix_delete(sigma);
1545 giraffe_model_delete(model);
1552inline static cpl_image *
1553_giraffe_psf_fit(GiLineData *lines,
const GiLocalization *localization,
1554 GiTable *fibers, GiTable *slitgeometry, GiSCFitParams *setup)
1557 const cxchar *
const fctid =
"_giraffe_psf_fit";
1563 cxint nsubslits = 1;
1566 cpl_table *_fibers = NULL;
1568 cpl_image *locy = NULL;
1569 cpl_image *locw = NULL;
1570 cpl_image *psfwidth = NULL;
1573 cx_assert(lines != NULL);
1574 cx_assert(localization != NULL);
1575 cx_assert(fibers != NULL);
1576 cx_assert(slitgeometry != NULL);
1577 cx_assert(setup != NULL);
1580 cx_assert(_fibers != NULL);
1583 cx_assert(locy != NULL);
1586 cx_assert(locw != NULL);
1588 nx = cpl_image_get_size_y(locy);
1589 nlines = giraffe_linedata_lines(lines);
1591 psfwidth = cpl_image_new(cpl_table_get_nrow(_fibers), nx,
1594 if (setup->subslits == TRUE) {
1595 nsubslits = _giraffe_subslit_get_max(_fibers);
1598 for (i = 0; i < nsubslits; i++) {
1605 cxint iterations = 0;
1611 cxdouble ratio = 1.;
1613 cpl_matrix *xss = NULL;
1614 cpl_matrix *yss = NULL;
1615 cpl_matrix *wss = NULL;
1616 cpl_matrix *sss = NULL;
1617 cpl_matrix *nss = NULL;
1618 cpl_matrix *lss = NULL;
1619 cpl_matrix *base = NULL;
1620 cpl_matrix *fit = NULL;
1621 cpl_matrix *coeff = NULL;
1622 cpl_matrix *chebyshev = NULL;
1624 cpl_table *subslit = NULL;
1626 GiChebyshev2D *psffit = NULL;
1629 if (setup->subslits == TRUE) {
1630 subslit = _giraffe_subslit_get(_fibers, i + 1);
1631 ssn = cpl_table_get_int(subslit,
"SSN", 0, NULL);
1633 cx_assert(ssn == i + 1);
1636 subslit = cpl_table_duplicate(_fibers);
1640 if (subslit == NULL) {
1644 _giraffe_subslit_range(subslit, locy, locw, &ymin, &ymax);
1646 nfibers = cpl_table_get_nrow(subslit);
1647 ndata = nfibers * nlines;
1650 xss = cpl_matrix_new(ndata, 1);
1651 yss = cpl_matrix_new(ndata, 1);
1652 wss = cpl_matrix_new(1, ndata);
1653 sss = cpl_matrix_new(ndata, 1);
1654 nss = cpl_matrix_new(ndata, 1);
1655 lss = cpl_matrix_new(ndata, 1);
1665 for (j = 0; j < nfibers; j++) {
1668 cxint n = cpl_table_get_int(subslit,
"INDEX", j, NULL) - 1;
1670 for (l = 0; l < nlines; l++) {
1672 cxdouble value = 0.;
1673 cxdouble yccd = giraffe_linedata_get(lines,
"Yccd", n, l);
1675 if (giraffe_linedata_get_status(lines, n, l) != 0) {
1679 if (yccd < ymin || yccd > ymax) {
1683 value = giraffe_linedata_get(lines,
"Xccd", n, l);
1684 cpl_matrix_set(xss, k, 0, value);
1686 cpl_matrix_set(yss, k, 0, yccd);
1695 value = giraffe_linedata_get(lines,
"FWHM", n, l);
1696 cpl_matrix_set(wss, 0, k, value);
1698 value = giraffe_linedata_get(lines,
"dWidth1", n, l);
1699 cpl_matrix_set(sss, k, 0, value);
1701 cpl_matrix_set(nss, k, 0, n);
1702 cpl_matrix_set(lss, k, 0, l);
1711 cpl_msg_debug(fctid,
"Skipping subslit %d: No input lines left! "
1712 "All lines have non-zero status or are beyond the "
1713 "subslit boundaries (%.4f, %.4f).", ssn, ymin, ymax);
1721 cpl_matrix_set_size(xss, k, 1);
1722 cpl_matrix_set_size(yss, k, 1);
1723 cpl_matrix_set_size(wss, 1, k);
1724 cpl_matrix_set_size(sss, k, 1);
1725 cpl_matrix_set_size(nss, k, 1);
1726 cpl_matrix_set_size(lss, k, 1);
1735 accepted = cpl_matrix_get_ncol(wss);
1738 while (accepted > 0 && iterations < setup->clip.iterations &&
1739 ratio > setup->clip.fraction) {
1741 base = giraffe_chebyshev_base2d(0., ymin, nx, ymax - ymin + 1.,
1742 setup->fit.xorder + 1,
1743 setup->fit.yorder + 1, xss, yss);
1745 if (coeff != NULL) {
1746 cpl_matrix_delete(coeff);
1752 if (coeff == NULL) {
1753 cpl_msg_debug(fctid,
"Error solving linear system for "
1754 "subslit %d, skipping subslit.", ssn);
1758 fit = cpl_matrix_product_create(coeff, base);
1762 for (j = 0; j < cpl_matrix_get_ncol(fit); j++) {
1764 cxdouble _fit = cpl_matrix_get(fit, 0, j);
1765 cxdouble _wss = cpl_matrix_get(wss, 0, j);
1766 cxdouble _sss = cpl_matrix_get(sss, j, 0);
1768 if (fabs(_fit - _wss) >= setup->clip.level * _sss) {
1770 cxint n = (cxint)cpl_matrix_get(nss, j, 0);
1771 cxint l = (cxint)cpl_matrix_get(lss, j, 0);
1777 giraffe_linedata_set_status(lines, n, l, LF_R_PSFIT);
1782 cpl_matrix_set(xss, k, 0, cpl_matrix_get(xss, j, 0));
1783 cpl_matrix_set(yss, k, 0, cpl_matrix_get(yss, j, 0));
1784 cpl_matrix_set(wss, 0, k, cpl_matrix_get(wss, 0, j));
1785 cpl_matrix_set(sss, k, 0, cpl_matrix_get(sss, j, 0));
1786 cpl_matrix_set(nss, k, 0, cpl_matrix_get(nss, j, 0));
1787 cpl_matrix_set(lss, k, 0, cpl_matrix_get(lss, j, 0));
1792 cpl_matrix_delete(base);
1793 cpl_matrix_delete(fit);
1795 if (k == accepted) {
1805 ratio = (cxdouble)accepted / (cxdouble)total;
1807 cpl_matrix_set_size(xss, k, 1);
1808 cpl_matrix_set_size(yss, k, 1);
1809 cpl_matrix_set_size(wss, 1, k);
1810 cpl_matrix_set_size(sss, k, 1);
1811 cpl_matrix_set_size(nss, k, 1);
1812 cpl_matrix_set_size(lss, k, 1);
1820 if (accepted == 0) {
1821 cpl_msg_debug(fctid,
"Subslit %d: All lines rejected.", ssn);
1825 if (coeff == NULL) {
1830 cpl_matrix_delete(xss);
1831 cpl_matrix_delete(yss);
1832 cpl_matrix_delete(wss);
1833 cpl_matrix_delete(sss);
1834 cpl_matrix_delete(nss);
1835 cpl_matrix_delete(lss);
1842 xss = cpl_matrix_new(nx * nfibers, 1);
1843 yss = cpl_matrix_new(nx * nfibers, 1);
1845 giraffe_compute_image_coordinates(nx, nfibers, xss, NULL);
1847 for (j = 0; j < cpl_table_get_nrow(subslit); j++) {
1852 cxint ns = cpl_image_get_size_x(locy);
1853 cxint cs = cpl_table_get_int(subslit, idx, j, NULL) - 1;
1855 cxdouble *data = cpl_image_get_data(locy);
1858 for (l = 0; l < nx; l++) {
1859 cpl_matrix_set(yss, l * nfibers + j, 0, data[l * ns + cs]);
1869 base = giraffe_chebyshev_base2d(0., ymin, nx, ymax - ymin + 1.,
1870 setup->fit.xorder + 1,
1871 setup->fit.yorder + 1, xss, yss);
1873 fit = cpl_matrix_product_create(coeff, base);
1875 cpl_matrix_delete(xss);
1878 cpl_matrix_delete(yss);
1891 chebyshev = cpl_matrix_wrap(setup->fit.xorder + 1,
1892 setup->fit.yorder + 1,
1893 cpl_matrix_get_data(coeff));
1895 psffit = giraffe_chebyshev2d_new(setup->fit.xorder, setup->fit.yorder);
1896 status = giraffe_chebyshev2d_set(psffit, 0., nx, ymin, ymax,
1901 giraffe_chebyshev2d_delete(psffit);
1903 cpl_matrix_unwrap(chebyshev);
1905 cpl_matrix_delete(base);
1906 cpl_matrix_delete(coeff);
1907 cpl_matrix_delete(fit);
1909 cpl_table_delete(subslit);
1911 cpl_image_delete(psfwidth);
1917 cpl_matrix_unwrap(chebyshev);
1920 giraffe_chebyshev2d_delete(psffit);
1928 for (j = 0; j < cpl_table_get_nrow(subslit); j++) {
1931 cxint n = cpl_table_get_int(subslit,
"INDEX", j, NULL) - 1;
1932 cxint ns = cpl_table_get_nrow(_fibers);
1934 cxdouble *data = cpl_image_get_data(psfwidth);
1936 for (l = 0; l < nx; l++) {
1937 data[l * ns + n] = cpl_matrix_get(fit, 0, l * nfibers + j);
1942 cpl_matrix_delete(base);
1943 cpl_matrix_delete(coeff);
1944 cpl_matrix_delete(fit);
1946 cpl_table_delete(subslit);
1956_giraffe_opticalmodel_fit(GiWlSolution *solution, GiLineData *lines,
1957 GiTable *fibers, GiTable *slitgeometry,
1958 GiOpticalModelParams *setup)
1961 const cxchar *
const fctid =
"_giraffe_opticalmodel_fit";
1970 cpl_matrix *x = NULL;
1971 cpl_matrix *y = NULL;
1972 cpl_matrix *sigma = NULL;
1974 cpl_table *_fibers = NULL;
1975 cpl_table *_slitgeometry = NULL;
1977 GiModel *model = NULL;
1980 cx_assert(solution != NULL);
1981 cx_assert(lines != NULL);
1982 cx_assert(fibers != NULL);
1983 cx_assert(slitgeometry != NULL);
1984 cx_assert(setup != NULL);
1987 cx_assert(_fibers != NULL);
1990 cx_assert(_slitgeometry != NULL);
1992 model = giraffe_wlsolution_model(solution);
1999 ndata = giraffe_linedata_lines(lines) * giraffe_linedata_fibers(lines);
2001 x = cpl_matrix_new(ndata, giraffe_model_count_arguments(model));
2002 y = cpl_matrix_new(ndata, 1);
2003 sigma = cpl_matrix_new(ndata, 1);
2005 for (i = 0; i < giraffe_linedata_fibers(lines); i++) {
2009 cxdouble xf = cpl_table_get(_slitgeometry,
"XF", i, NULL);
2010 cxdouble yf = cpl_table_get(_slitgeometry,
"YF", i, NULL);
2013 for (j = 0; j < giraffe_linedata_lines(lines); j++) {
2015 if (giraffe_linedata_get_status(lines, i, j) != 0) {
2022 if (giraffe_linedata_get(lines,
"dCenter", i, j) <= 0.) {
2026 cpl_matrix_set(x, ngood, 0,
2027 giraffe_linedata_get_wavelength(lines, j));
2028 cpl_matrix_set(x, ngood, 1, xf);
2029 cpl_matrix_set(x, ngood, 2, yf);
2031 cpl_matrix_set(y, ngood, 0,
2032 giraffe_linedata_get(lines,
"Center", i, j));
2033 cpl_matrix_set(sigma, ngood, 0,
2034 giraffe_linedata_get(lines,
"dCenter", i, j));
2042 cpl_msg_debug(fctid,
"Using %d of %d line positions for optical "
2043 "model fit.", ngood, ndata);
2047 cpl_matrix_delete(x);
2048 cpl_matrix_delete(y);
2049 cpl_matrix_delete(sigma);
2059 cpl_matrix_set_size(x, ngood, giraffe_model_count_arguments(model));
2060 cpl_matrix_set_size(y, ngood, 1);
2061 cpl_matrix_set_size(sigma, ngood, 1);
2068 giraffe_model_freeze(model);
2070 if (setup->flags & OPTM_FLENGTH) {
2071 giraffe_model_thaw_parameter(model,
"FocalLength");
2074 if (setup->flags & OPTM_GCAMERA) {
2075 giraffe_model_thaw_parameter(model,
"Magnification");
2078 if (setup->flags & OPTM_THETA) {
2079 giraffe_model_thaw_parameter(model,
"Angle");
2082 if (strcmp(giraffe_model_get_name(model),
"xoptmod2") == 0) {
2083 if (setup->flags & OPTM_SX) {
2084 giraffe_model_thaw_parameter(model,
"Sdx");
2087 if (setup->flags & OPTM_SY) {
2088 giraffe_model_thaw_parameter(model,
"Sdy");
2091 if (setup->flags & OPTM_SPHI) {
2092 giraffe_model_thaw_parameter(model,
"Sphi");
2096 giraffe_model_set_iterations(model, setup->fit.iterations);
2097 giraffe_model_set_tests(model, setup->fit.tests);
2098 giraffe_model_set_delta(model, setup->fit.delta);
2105 status = giraffe_model_fit(model, x, y, sigma);
2109 cpl_matrix_delete(x);
2110 cpl_matrix_delete(y);
2111 cpl_matrix_delete(sigma);
2117 cpl_matrix_delete(x);
2118 cpl_matrix_delete(y);
2119 cpl_matrix_delete(sigma);
2127_giraffe_opticalmodel_format(cx_string *s,
const GiModel *model,
2128 GiOpticalModelInfo info)
2131 const cxchar *name = NULL;
2133 cxbool offsets = FALSE;
2138 cx_assert(s != NULL);
2140 if (model == NULL) {
2144 name = giraffe_model_get_name(model);
2146 if (name == NULL || strncmp(name,
"xoptmod", 7) != 0) {
2150 if (strncmp(name,
"xoptmod2", 8) == 0) {
2157 case GI_OPTM_PARAMETER_VALUES:
2160 cxdouble fcoll = 0.;
2162 cxdouble theta = 0.;
2164 fcoll = giraffe_model_get_parameter(model,
"FocalLength");
2165 gcam = giraffe_model_get_parameter(model,
"Magnification");
2166 theta = giraffe_model_get_parameter(model,
"Angle");
2168 cx_string_sprintf(s,
"focal length = %.6f, camera "
2169 "magnification = %.6f, grating angle = %.9f",
2170 fcoll, gcam, theta);
2172 if (offsets == TRUE) {
2178 cx_string *_s = cx_string_new();
2180 sdx = giraffe_model_get_parameter(model,
"Sdx");
2181 sdy = giraffe_model_get_parameter(model,
"Sdy");
2182 sphi = giraffe_model_get_parameter(model,
"Sphi");
2184 cx_string_sprintf(_s,
", slit x-shift = %.9f, slit "
2185 "y-shift = %.9f, slit rotation = %.9f",
2187 cx_string_append(s, cx_string_get(_s));
2189 cx_string_delete(_s);
2197 case GI_OPTM_PARAMETER_ERRORS:
2200 cxdouble fcoll = 0.;
2202 cxdouble theta = 0.;
2204 fcoll = giraffe_model_get_sigma(model,
"FocalLength");
2205 gcam = giraffe_model_get_sigma(model,
"Magnification");
2206 theta = giraffe_model_get_sigma(model,
"Angle");
2208 cx_string_sprintf(s,
"focal length = %.6f, camera "
2209 "magnification = %.6f, grating angle = %.9f",
2210 fcoll, gcam, theta);
2212 if (offsets == TRUE) {
2218 cx_string *_s = cx_string_new();
2220 sdx = giraffe_model_get_sigma(model,
"Sdx");
2221 sdy = giraffe_model_get_sigma(model,
"Sdy");
2222 sphi = giraffe_model_get_sigma(model,
"Sphi");
2224 cx_string_sprintf(_s,
", slit x-shift = %.9f, slit "
2225 "y-shift = %.9f, slit rotation = %.9f",
2227 cx_string_append(s, cx_string_get(_s));
2229 cx_string_delete(_s);
2237 case GI_OPTM_PARAMETER_STATUS:
2240 const cxchar *
const s_free =
"free";
2241 const cxchar *
const s_frozen =
"frozen";
2242 const cxchar *t = NULL;
2244 cx_string *buffer = cx_string_new();
2247 t = giraffe_model_frozen_parameter(model,
"FocalLength") ?
2249 cx_string_sprintf(buffer,
"focal length = %s", t);
2250 cx_string_set(s, cx_string_get(buffer));
2252 t = giraffe_model_frozen_parameter(model,
"Magnification") ?
2254 cx_string_sprintf(buffer,
", camera magnification = %s", t);
2255 cx_string_append(s, cx_string_get(buffer));
2257 t = giraffe_model_frozen_parameter(model,
"Angle") ?
2259 cx_string_sprintf(buffer,
", grating angle = %s", t);
2260 cx_string_append(s, cx_string_get(buffer));
2263 if (offsets == TRUE) {
2265 t = giraffe_model_frozen_parameter(model,
"Sdx") ?
2267 cx_string_sprintf(buffer,
", slit x-shift = %s", t);
2268 cx_string_append(s, cx_string_get(buffer));
2270 t = giraffe_model_frozen_parameter(model,
"Sdy") ?
2272 cx_string_sprintf(buffer,
", slit y-shift = %s", t);
2273 cx_string_append(s, cx_string_get(buffer));
2275 t = giraffe_model_frozen_parameter(model,
"Sphi") ?
2277 cx_string_sprintf(buffer,
", slit rotation = %s", t);
2278 cx_string_append(s, cx_string_get(buffer));
2282 cx_string_delete(buffer);
2299inline static cpl_image *
2300_giraffe_residuals_fit(GiWlResiduals *residuals, GiLineData *lines,
2301 const GiLocalization *localization, GiTable *fibers,
2302 GiTable *slitgeometry, GiSCFitParams *setup)
2305 const cxchar *
const fctid =
"_giraffe_residuals_fit";
2311 cxint nsubslits = 1;
2314 cpl_table *_fibers = NULL;
2316 cpl_image *locy = NULL;
2317 cpl_image *locw = NULL;
2318 cpl_image *xresiduals = NULL;
2321 cx_assert(lines != NULL);
2322 cx_assert(localization != NULL);
2323 cx_assert(fibers != NULL);
2324 cx_assert(slitgeometry != NULL);
2325 cx_assert(setup != NULL);
2328 cx_assert(_fibers != NULL);
2331 cx_assert(locy != NULL);
2334 cx_assert(locw != NULL);
2336 nx = cpl_image_get_size_y(locy);
2337 nlines = giraffe_linedata_lines(lines);
2339 xresiduals = cpl_image_new(cpl_table_get_nrow(_fibers), nx,
2342 if (setup->subslits == TRUE) {
2343 nsubslits = _giraffe_subslit_get_max(_fibers);
2346 for (i = 0; i < nsubslits; i++) {
2353 cxint iterations = 0;
2359 cxdouble ratio = 1.;
2360 cxdouble sigma = 0.;
2362 cpl_matrix *xss = NULL;
2363 cpl_matrix *yss = NULL;
2364 cpl_matrix *rss = NULL;
2365 cpl_matrix *sss = NULL;
2366 cpl_matrix *nss = NULL;
2367 cpl_matrix *lss = NULL;
2368 cpl_matrix *base = NULL;
2369 cpl_matrix *fit = NULL;
2370 cpl_matrix *coeff = NULL;
2371 cpl_matrix *chebyshev = NULL;
2373 cpl_table *subslit = NULL;
2375 GiChebyshev2D *xwsfit = NULL;
2378 if (setup->subslits == TRUE) {
2379 subslit = _giraffe_subslit_get(_fibers, i + 1);
2380 ssn = cpl_table_get_int(subslit,
"SSN", 0, NULL);
2382 cx_assert(ssn == i + 1);
2385 subslit = cpl_table_duplicate(_fibers);
2389 if (subslit == NULL) {
2393 _giraffe_subslit_range(subslit, locy, locw, &ymin, &ymax);
2395 nfibers = cpl_table_get_nrow(subslit);
2396 ndata = nfibers * nlines;
2399 xss = cpl_matrix_new(ndata, 1);
2400 yss = cpl_matrix_new(ndata, 1);
2401 rss = cpl_matrix_new(1, ndata);
2402 sss = cpl_matrix_new(ndata, 1);
2403 nss = cpl_matrix_new(ndata, 1);
2404 lss = cpl_matrix_new(ndata, 1);
2414 for (j = 0; j < nfibers; j++) {
2417 cxint n = cpl_table_get_int(subslit,
"INDEX", j, NULL) - 1;
2419 for (l = 0; l < nlines; l++) {
2421 cxdouble value = 0.;
2422 cxdouble xccd = giraffe_linedata_get(lines,
"Xccd", n, l);
2423 cxdouble yccd = giraffe_linedata_get(lines,
"Yccd", n, l);
2425 if (giraffe_linedata_get_status(lines, n, l) != 0) {
2429 if (yccd < ymin || yccd > ymax) {
2433 cpl_matrix_set(xss, k, 0, xccd);
2434 cpl_matrix_set(yss, k, 0, yccd);
2436 value = xccd - giraffe_linedata_get(lines,
"Center", n, l);
2438 cpl_matrix_set(rss, 0, k, value);
2439 giraffe_linedata_set(lines,
"Xoff", n, l, value);
2441 value = giraffe_linedata_get(lines,
"dCenter", n, l);
2442 cpl_matrix_set(sss, k, 0, value);
2444 cpl_matrix_set(nss, k, 0, n);
2445 cpl_matrix_set(lss, k, 0, l);
2454 cpl_msg_debug(fctid,
"Skipping subslit %d: No input lines left! "
2455 "All lines have non-zero status or are beyond the "
2456 "subslit boundaries (%.4f, %.4f).", ssn, ymin, ymax);
2464 cpl_matrix_set_size(xss, k, 1);
2465 cpl_matrix_set_size(yss, k, 1);
2466 cpl_matrix_set_size(rss, 1, k);
2467 cpl_matrix_set_size(sss, k, 1);
2468 cpl_matrix_set_size(nss, k, 1);
2469 cpl_matrix_set_size(lss, k, 1);
2477 sigma = cpl_matrix_get_median(sss);
2486 accepted = cpl_matrix_get_ncol(rss);
2489 while (accepted > 0 && iterations < setup->clip.iterations &&
2490 ratio > setup->clip.fraction) {
2492 base = giraffe_chebyshev_base2d(0., ymin, nx, ymax - ymin + 1.,
2493 setup->fit.xorder + 1,
2494 setup->fit.yorder + 1, xss, yss);
2496 if (coeff != NULL) {
2497 cpl_matrix_delete(coeff);
2503 if (coeff == NULL) {
2504 cpl_msg_debug(fctid,
"Error solving linear system for "
2505 "subslit %d, skipping subslit.", ssn);
2509 fit = cpl_matrix_product_create(coeff, base);
2513 for (j = 0; j < cpl_matrix_get_ncol(fit); j++) {
2515 cxdouble _fit = cpl_matrix_get(fit, 0, j);
2516 cxdouble _rss = cpl_matrix_get(rss, 0, j);
2518 if (fabs(_fit - _rss) >= setup->clip.level * sigma) {
2520 cxint n = (cxint)cpl_matrix_get(nss, j, 0);
2521 cxint l = (cxint)cpl_matrix_get(lss, j, 0);
2527 giraffe_linedata_set_status(lines, n, l, LF_R_XRFIT);
2532 cpl_matrix_set(xss, k, 0, cpl_matrix_get(xss, j, 0));
2533 cpl_matrix_set(yss, k, 0, cpl_matrix_get(yss, j, 0));
2534 cpl_matrix_set(rss, 0, k, cpl_matrix_get(rss, 0, j));
2535 cpl_matrix_set(sss, k, 0, cpl_matrix_get(sss, j, 0));
2536 cpl_matrix_set(nss, k, 0, cpl_matrix_get(nss, j, 0));
2537 cpl_matrix_set(lss, k, 0, cpl_matrix_get(lss, j, 0));
2542 cpl_matrix_delete(base);
2543 cpl_matrix_delete(fit);
2545 if (k == accepted) {
2555 ratio = (cxdouble)accepted / (cxdouble)total;
2557 cpl_matrix_set_size(xss, k, 1);
2558 cpl_matrix_set_size(yss, k, 1);
2559 cpl_matrix_set_size(rss, 1, k);
2560 cpl_matrix_set_size(sss, k, 1);
2561 cpl_matrix_set_size(nss, k, 1);
2562 cpl_matrix_set_size(lss, k, 1);
2570 if (accepted == 0) {
2571 cpl_msg_debug(fctid,
"Subslit %d: All lines rejected.", ssn);
2575 if (coeff == NULL) {
2580 cpl_matrix_delete(xss);
2581 cpl_matrix_delete(yss);
2582 cpl_matrix_delete(rss);
2583 cpl_matrix_delete(sss);
2584 cpl_matrix_delete(nss);
2585 cpl_matrix_delete(lss);
2592 xss = cpl_matrix_new(nx * nfibers, 1);
2593 yss = cpl_matrix_new(nx * nfibers, 1);
2595 giraffe_compute_image_coordinates(nx, nfibers, xss, NULL);
2597 for (j = 0; j < cpl_table_get_nrow(subslit); j++) {
2602 cxint ns = cpl_image_get_size_x(locy);
2603 cxint cs = cpl_table_get_int(subslit, idx, j, NULL) - 1;
2605 cxdouble *data = cpl_image_get_data(locy);
2608 for (l = 0; l < nx; l++) {
2609 cpl_matrix_set(yss, l * nfibers + j, 0, data[l * ns + cs]);
2619 base = giraffe_chebyshev_base2d(0., ymin, nx, ymax - ymin + 1.,
2620 setup->fit.xorder + 1,
2621 setup->fit.yorder + 1, xss, yss);
2623 fit = cpl_matrix_product_create(coeff, base);
2625 cpl_matrix_delete(xss);
2628 cpl_matrix_delete(yss);
2643 chebyshev = cpl_matrix_wrap(setup->fit.xorder + 1,
2644 setup->fit.yorder + 1,
2645 cpl_matrix_get_data(coeff));
2647 xwsfit = giraffe_chebyshev2d_new(setup->fit.xorder, setup->fit.yorder);
2648 status = giraffe_chebyshev2d_set(xwsfit, 0., nx, ymin, ymax,
2653 giraffe_chebyshev2d_delete(xwsfit);
2655 cpl_matrix_unwrap(chebyshev);
2657 cpl_matrix_delete(base);
2658 cpl_matrix_delete(coeff);
2659 cpl_matrix_delete(fit);
2661 cpl_table_delete(subslit);
2663 cpl_image_delete(xresiduals);
2669 cpl_matrix_unwrap(chebyshev);
2672 giraffe_wlresiduals_set(residuals, ssn, xwsfit);
2680 for (j = 0; j < cpl_table_get_nrow(subslit); j++) {
2683 cxint n = cpl_table_get_int(subslit,
"INDEX", j, NULL) - 1;
2684 cxint ns = cpl_table_get_nrow(_fibers);
2686 cxdouble *data = cpl_image_get_data(xresiduals);
2688 for (l = 0; l < nx; l++) {
2689 data[l * ns + n] = cpl_matrix_get(fit, 0, l * nfibers + j);
2694 cpl_matrix_delete(base);
2695 cpl_matrix_delete(coeff);
2696 cpl_matrix_delete(fit);
2698 cpl_table_delete(subslit);
2707inline static cxdouble
2708_giraffe_compute_statistics(
const GiLineData *lines,
const cpl_image *xwsfit,
2709 const cpl_image *lflags)
2720 cpl_image *xccd = NULL;
2723 cx_assert(lines != NULL);
2726 nlines = giraffe_linedata_lines(lines);
2727 nfibers = giraffe_linedata_fibers(lines);
2729 xccd = cpl_image_duplicate(giraffe_linedata_get_data(lines,
"Xccd"));
2731 if (xwsfit != NULL) {
2733 cpl_image *residuals = NULL;
2736 cx_assert(lflags != NULL);
2738 residuals = cpl_image_new(giraffe_linedata_fibers(lines),
2739 giraffe_linedata_lines(lines),
2742 _giraffe_get_residuals(residuals, xccd, xwsfit);
2743 _giraffe_apply_residuals(xccd, residuals, lflags, 0.);
2745 cpl_image_delete(residuals);
2750 _xccd = cpl_image_get_data(xccd);
2752 for (i = 0; i < nfibers; i++) {
2756 for (j = 0; j < nlines; j++) {
2758 if (giraffe_linedata_get_status(lines, i, j) == LF_R_NONE) {
2760 cxdouble center = giraffe_linedata_get(lines,
"Center", i, j);
2762 sum += pow(center - _xccd[j * nfibers + i], 2.);
2770 cpl_image_delete(xccd);
2772 rms = sqrt(sum / CX_MAX(giraffe_linedata_accepted(lines), 1.));
2780_giraffe_convert_wlsolution(GiTable *result,
const GiWlSolution *solution,
2781 const GiImage *spectra,
const GiGrating *setup,
2789 cxdouble value = 0.;
2790 cxdouble scale = 0.;
2791 cxdouble xccd[2] = {0., 0.};
2793 cx_string *s = NULL;
2795 cpl_propertylist *properties = NULL;
2797 cpl_table *coeffs = NULL;
2799 const GiModel *model = NULL;
2801 const GiWlResiduals *residuals = NULL;
2804 cx_assert(result != NULL);
2805 cx_assert(solution != NULL);
2807 s = cx_string_new();
2816 cpl_propertylist_erase(properties,
"NAXIS1");
2817 cpl_propertylist_erase(properties,
"NAXIS2");
2818 cpl_propertylist_erase(properties, GIALIAS_DATAMIN);
2819 cpl_propertylist_erase(properties, GIALIAS_DATAMAX);
2820 cpl_propertylist_erase(properties, GIALIAS_EXTNAME);
2822 cpl_propertylist_erase(properties, GIALIAS_PROCATG);
2823 cpl_propertylist_erase(properties, GIALIAS_PROTYPE);
2824 cpl_propertylist_erase(properties, GIALIAS_DATAMEAN);
2825 cpl_propertylist_erase(properties, GIALIAS_DATAMEDI);
2826 cpl_propertylist_erase(properties, GIALIAS_DATASIG);
2828 cpl_propertylist_update_string(properties, GIALIAS_GIRFTYPE,
2830 cpl_propertylist_set_comment(properties, GIALIAS_GIRFTYPE,
2831 "Giraffe frame type.");
2855 cpl_propertylist_update_string(properties, GIALIAS_WSOL_LMNAME,
2857 cpl_propertylist_set_comment(properties, GIALIAS_WSOL_LMNAME,
2858 "Line profile model");
2860 cpl_propertylist_update_bool(properties, GIALIAS_WSOL_LMRES, info->residuals);
2861 cpl_propertylist_set_comment(properties, GIALIAS_WSOL_LMRES,
2862 "Line detection optical model residuals flag");
2864 cpl_propertylist_update_int(properties, GIALIAS_WSOL_LMWIDTH, info->width);
2865 cpl_propertylist_set_comment(properties, GIALIAS_WSOL_LMWIDTH,
2866 "Line detection window size [pxl]");
2868 cpl_propertylist_update_double(properties, GIALIAS_WSOL_LMTHRESH,
2870 cpl_propertylist_set_comment(properties, GIALIAS_WSOL_LMTHRESH,
2871 "Calibration line threshold");
2873 cpl_propertylist_update_int(properties, GIALIAS_WSOL_LMITER,
2875 cpl_propertylist_set_comment(properties, GIALIAS_WSOL_LMITER,
2876 "Line profile fit maximum number "
2879 cpl_propertylist_update_int(properties, GIALIAS_WSOL_LMTEST,
2881 cpl_propertylist_set_comment(properties, GIALIAS_WSOL_LMTEST,
2882 "Line profile fit maximum number "
2883 "of chi-square tests");
2885 cpl_propertylist_update_double(properties, GIALIAS_WSOL_LMDCHISQ,
2887 cpl_propertylist_set_comment(properties, GIALIAS_WSOL_LMDCHISQ,
2888 "Line profile fit minimum delta "
2898 cpl_propertylist_update_string(properties, GIALIAS_WSOL_PWORDER,
2900 cpl_propertylist_set_comment(properties, GIALIAS_WSOL_PWORDER,
2901 "PSF width fit polynomial order");
2903 cpl_propertylist_update_double(properties, GIALIAS_WSOL_PWSIGMA,
2905 cpl_propertylist_set_comment(properties, GIALIAS_WSOL_PWSIGMA,
2906 "PSF width fit sigma clipping level");
2908 cpl_propertylist_update_int(properties, GIALIAS_WSOL_PWITER,
2910 cpl_propertylist_set_comment(properties, GIALIAS_WSOL_PWITER,
2911 "PSF width fit maximum number of "
2914 cpl_propertylist_update_double(properties, GIALIAS_WSOL_PWFRAC,
2916 cpl_propertylist_set_comment(properties, GIALIAS_WSOL_PWFRAC,
2917 "PSF width fit minimum fraction of "
2925 cpl_propertylist_update_bool(properties, GIALIAS_WSOL_OMFIT,
2927 cpl_propertylist_set_comment(properties, GIALIAS_WSOL_OMFIT,
2928 "Optical model fit flag");
2930 cpl_propertylist_update_string(properties, GIALIAS_WSOL_OMNAME,
2931 giraffe_wlsolution_name(solution));
2932 cpl_propertylist_set_comment(properties, GIALIAS_WSOL_OMNAME,
2933 "Optical model name");
2935 model = giraffe_wlsolution_model(solution);
2937 sign = giraffe_model_get_parameter(model,
"Orientation") < 0 ? -1 : 1;
2938 cpl_propertylist_update_int(properties, GIALIAS_WSOL_OMDIR, sign);
2939 cpl_propertylist_set_comment(properties, GIALIAS_WSOL_OMDIR,
2940 "Optical model orientation");
2942 value = giraffe_model_get_parameter(model,
"FocalLength");
2943 cpl_propertylist_update_double(properties, GIALIAS_WSOL_OMFCOLL, value);
2944 cpl_propertylist_set_comment(properties, GIALIAS_WSOL_OMFCOLL,
2945 "Optical model focal length");
2947 value = giraffe_model_get_parameter(model,
"Magnification");
2948 cpl_propertylist_update_double(properties, GIALIAS_WSOL_OMGCAM, value);
2949 cpl_propertylist_set_comment(properties, GIALIAS_WSOL_OMGCAM,
2950 "Optical model camera factor");
2952 value = giraffe_model_get_parameter(model,
"Angle");
2953 cpl_propertylist_update_double(properties, GIALIAS_WSOL_OMGTHETA, value);
2954 cpl_propertylist_set_comment(properties, GIALIAS_WSOL_OMGTHETA,
2955 "Optical model grating angle");
2957 if (strcmp(giraffe_wlsolution_name(solution),
"xoptmod2") == 0) {
2959 value = giraffe_model_get_parameter(model,
"Sdx");
2960 cpl_propertylist_update_double(properties, GIALIAS_WSOL_OMSDX, value);
2961 cpl_propertylist_set_comment(properties, GIALIAS_WSOL_OMSDX,
2962 "Optical model slit x-offset");
2964 value = giraffe_model_get_parameter(model,
"Sdy");
2965 cpl_propertylist_update_double(properties, GIALIAS_WSOL_OMSDY, value);
2966 cpl_propertylist_set_comment(properties, GIALIAS_WSOL_OMSDY,
2967 "Optical model slit y-offset");
2969 value = giraffe_model_get_parameter(model,
"Sphi");
2970 cpl_propertylist_update_double(properties, GIALIAS_WSOL_OMSPHI, value);
2971 cpl_propertylist_set_comment(properties, GIALIAS_WSOL_OMSPHI,
2972 "Optical model slit rotation");
2982 residuals = giraffe_wlsolution_get_residuals(solution);
2984 cpl_propertylist_update_bool(properties, GIALIAS_WSOL_SUBSLITS,
2985 giraffe_wlsolution_get_subslits(solution));
2986 cpl_propertylist_set_comment(properties, GIALIAS_WSOL_SUBSLITS,
2987 "Subslit fit flag");
2990 cpl_propertylist_update_int(properties, GIALIAS_WSOL_XRSSN,
2991 giraffe_wlresiduals_get_size(residuals));
2992 cpl_propertylist_set_comment(properties, GIALIAS_WSOL_XRSSN,
2993 "Number of subslits");
2998 cpl_propertylist_update_string(properties, GIALIAS_WSOL_XRORDER,
3000 cpl_propertylist_set_comment(properties, GIALIAS_WSOL_XRORDER,
3001 "Residual fit polynomial order");
3004 cpl_propertylist_update_double(properties, GIALIAS_WSOL_XRSIGMA,
3006 cpl_propertylist_set_comment(properties, GIALIAS_WSOL_XRSIGMA,
3007 "Residual fit sigma clipping level");
3009 cpl_propertylist_update_int(properties, GIALIAS_WSOL_XRITER,
3011 cpl_propertylist_set_comment(properties, GIALIAS_WSOL_XRITER,
3012 "Residual fit maximum number of "
3015 cpl_propertylist_update_double(properties, GIALIAS_WSOL_XRFRAC,
3017 cpl_propertylist_set_comment(properties, GIALIAS_WSOL_XRFRAC,
3018 "Residual fit minimum fraction of "
3021 cpl_propertylist_update_int(properties, GIALIAS_WSOL_NLINES,
3023 cpl_propertylist_set_comment(properties, GIALIAS_WSOL_NLINES,
3024 "Number of calibration lines used.");
3026 cpl_propertylist_update_int(properties, GIALIAS_WSOL_NACCEPT,
3028 cpl_propertylist_set_comment(properties, GIALIAS_WSOL_NACCEPT,
3029 "Number of accepted lines");
3031 cpl_propertylist_update_int(properties, GIALIAS_WSOL_NREJECT,
3033 cpl_propertylist_set_comment(properties, GIALIAS_WSOL_NREJECT,
3034 "Number of rejected lines");
3036 cpl_propertylist_update_double(properties, GIALIAS_WSOL_RMS,
3038 cpl_propertylist_set_comment(properties, GIALIAS_WSOL_RMS,
3039 "Average RMS [pxl] of fitted line "
3048 xccd[0] = giraffe_wlsolution_compute_pixel(solution, setup->
wlenmin,
3050 xccd[1] = giraffe_wlsolution_compute_pixel(solution, setup->
wlenmax,
3056 cpl_propertylist_update_double(properties, GIALIAS_WSOL_WLMIN,
3058 cpl_propertylist_set_comment(properties, GIALIAS_WSOL_WLMIN,
3059 "Wavelength solution minimum wavelength");
3061 cpl_propertylist_update_double(properties, GIALIAS_WSOL_WLMAX,
3063 cpl_propertylist_set_comment(properties, GIALIAS_WSOL_WLMAX,
3064 "Wavelength solution maximum wavelength");
3066 cpl_propertylist_update_double(properties, GIALIAS_WSOL_SCALE, scale);
3067 cpl_propertylist_set_comment(properties, GIALIAS_WSOL_SCALE,
3068 "Approximate wavelength scale [nm/pxl]");
3071 cx_string_delete(s);
3079 for (i = 0; (cxsize)i < giraffe_wlresiduals_get_size(residuals); i++) {
3081 const GiChebyshev2D *fit = giraffe_wlresiduals_get(residuals, i);
3090 giraffe_chebyshev2d_get_order(fit, &xorder, &yorder);
3094 gi_error(
"Invalid wavelength solution. Inconsistent residual "
3095 "fit polynomial order!");
3108 coeffs = giraffe_wlresiduals_table(residuals);
3110 if (coeffs == NULL) {
3111 cpl_propertylist_delete(properties);
3116 cpl_propertylist_delete(properties);
3121 cpl_table_delete(coeffs);
3130giraffe_wcaldata_new(
void)
3133 GiWCalData *self = cx_calloc(1,
sizeof *self);
3135 self->coeffs = NULL;
3137 self->linedata = NULL;
3145giraffe_wcaldata_delete(GiWCalData *self)
3152 self->coeffs = NULL;
3160 if (self->linedata) {
3161 giraffe_linedata_delete(self->linedata);
3162 self->linedata = NULL;
3197 GiLocalization *localization, GiTable *fibers,
3198 GiTable *slitgeometry, GiTable *grating,
3199 GiTable *lines, GiTable *initial,
3203 const cxchar *fctid =
"giraffe_calibrate_wavelength";
3206 cxbool residuals = FALSE;
3215 cpl_image *psf_fit = NULL;
3216 cpl_image *xws_fit = NULL;
3218 GiTable *tsolution = NULL;
3222 GiSCFitParams psf_setup;
3223 GiSCFitParams xws_setup;
3225 GiLineParams *line_setup = NULL;
3227 GiLineData *line_data = NULL;
3229 GiWlSolution *solution = NULL;
3234 if (extraction == NULL) {
3238 if (extraction->spectra == NULL || extraction->error == NULL) {
3243 if (fibers == NULL) {
3247 if (slitgeometry == NULL) {
3251 if (grating == NULL) {
3255 if (lines == NULL) {
3266 if (setup == NULL) {
3267 cpl_msg_error(fctid,
"Cannot initialize grating setup parameters!");
3285 cpl_msg_info(fctid,
"Setting initial slit offsets: x-shift = %.9f, "
3286 "y-shift = %.9f, rotation = %.9f", setup->
sdx,
3301 line_setup = _giraffe_lineparams_create(GI_LINETYPE_THARNE, setup,
3304 if (line_setup == NULL) {
3305 cpl_msg_error(fctid,
"Cannot initialize line fit setup parameters!");
3317 if (initial == NULL) {
3320 cxdouble pixelsize = 0.;
3322 cpl_propertylist *properties = NULL;
3324 cpl_image *spectra = NULL;
3328 cx_assert(properties != NULL);
3331 cx_assert(spectra != NULL);
3333 pixelsize = cpl_propertylist_get_double(properties, GIALIAS_PIXSIZY);
3334 npixel = cpl_image_get_size_y(spectra);
3336 solution = giraffe_wlsolution_new(config->
opt_model,
3340 if (solution == NULL) {
3341 cpl_msg_error(fctid,
"Cannot initialize initial wavelength "
3346 _giraffe_lineparams_delete(line_setup);
3354 const cpl_propertylist* _properties =
3373 if (cpl_propertylist_has(_properties, GIALIAS_WSOL_WLMIN) == TRUE) {
3375 setup->
wlenmin = cpl_propertylist_get_double(_properties,
3376 GIALIAS_WSOL_WLMIN);
3378 cpl_msg_debug(fctid,
"Using minimum wavelength %.2f from "
3379 "initial solution", setup->
wlenmin);
3383 if (cpl_propertylist_has(_properties, GIALIAS_WSOL_WLMAX) == TRUE) {
3385 setup->
wlenmax = cpl_propertylist_get_double(_properties,
3386 GIALIAS_WSOL_WLMAX);
3388 cpl_msg_debug(fctid,
"Using maximum wavelength %.2f from "
3389 "initial solution", setup->
wlenmax);
3395 giraffe_wlsolution_set_subslits(solution, config->
opt_subslits);
3398 cpl_msg_info(fctid,
"Computing line positions on the CCD using "
3399 "model `%s'", giraffe_wlsolution_name(solution));
3408 if (giraffe_wlsolution_get_residuals(solution) == NULL) {
3410 cpl_msg_error(fctid,
"Initial wavelength solution does not "
3411 "provide optical model residuals!");
3415 _giraffe_lineparams_delete(line_setup);
3417 giraffe_wlsolution_delete(solution);
3429 residuals = giraffe_wlsolution_get_residuals(solution) != NULL;
3431 if (residuals == TRUE) {
3432 cpl_msg_info(fctid,
"Using wavelength solution residuals when "
3433 "computing line positions.");
3448 status = _giraffe_linelist_setup(lines, setup, config);
3451 cpl_msg_error(fctid,
"Line list creation failed!");
3455 _giraffe_lineparams_delete(line_setup);
3457 giraffe_wlsolution_delete(solution);
3463 cpl_msg_info(fctid,
"%d lines have been selected from the line list.",
3471 line_data = giraffe_linedata_new();
3480 cpl_table *_lines = NULL;
3483 cpl_image *xccd = NULL;
3484 cpl_image *xres = NULL;
3485 cpl_image *line_status = NULL;
3487 GiWlResiduals *xws_coeffs = NULL;
3493 cpl_msg_info(fctid,
"Current search window width: %d pxl", width);
3494 cpl_msg_info(fctid,
"Applying crowding criterium to line list.");
3496 _lines = _giraffe_linelist_select(lines, extraction->spectra, setup,
3498 if (_lines == NULL) {
3499 cpl_msg_error(fctid,
"Removing crowded lines from line list "
3500 "for search window width %d pxl failed!", width);
3504 _giraffe_lineparams_delete(line_setup);
3506 giraffe_wlsolution_delete(solution);
3511 _nlines = cpl_table_get_nrow(_lines);
3514 cpl_msg_info(fctid,
"%d lines used for fit. %d of %d lines rejected "
3515 "due to crowding.", _nlines, nlines - _nlines, nlines);
3517 cpl_msg_info(fctid,
"%d lines used for fit. %d of %d lines "
3518 "rejected due to crowding and line quality.",
3519 _nlines, nlines - _nlines, nlines);
3527 xccd = _giraffe_line_abscissa(_lines, slitgeometry, fibers,
3528 solution, localization, residuals);
3530 _nfibers = cpl_image_get_size_x(xccd);
3531 _nlines = cpl_image_get_size_y(xccd);
3538 cpl_msg_info(fctid,
"Fitting %d line profiles for %d spectra using "
3539 "line model `%s'", _nlines, _nfibers , line_setup->model);
3541 cpl_msg_info(fctid,
"Total number of lines to fit: %d (%d x %d)",
3542 _nlines * _nfibers, _nfibers, _nlines);
3545 status = giraffe_linedata_reset(line_data, _lines, _fibers,
3550 cpl_msg_error(fctid,
"Line profile fit failed!");
3552 cpl_image_delete(xccd);
3554 cpl_table_delete(_lines);
3555 giraffe_linedata_delete(line_data);
3559 _giraffe_lineparams_delete(line_setup);
3561 giraffe_wlsolution_delete(solution);
3567 status = _giraffe_line_fit(line_data, xccd, width, extraction, fibers,
3568 localization->locy, line_setup);
3572 cpl_msg_error(fctid,
"Line profile fit failed!");
3574 cpl_image_delete(xccd);
3576 cpl_table_delete(_lines);
3577 giraffe_linedata_delete(line_data);
3581 _giraffe_lineparams_delete(line_setup);
3583 giraffe_wlsolution_delete(solution);
3589 cpl_image_delete(xccd);
3592 if (giraffe_linedata_accepted(line_data) == 0) {
3593 cpl_msg_error(fctid,
"No lines left after line profile fit!");
3595 cpl_table_delete(_lines);
3596 giraffe_linedata_delete(line_data);
3600 _giraffe_lineparams_delete(line_setup);
3602 giraffe_wlsolution_delete(solution);
3608 _nreject = giraffe_linedata_rejected(line_data);
3609 _ngood = giraffe_linedata_accepted(line_data);
3611 cpl_msg_info(fctid,
"Number of good lines: %d. %d of %d lines "
3612 "rejected due to line profile fit.", _ngood, _nreject,
3619 line_status = giraffe_linedata_status(line_data);
3626 cpl_msg_info(fctid,
"Fit of the line profile PSF width variation.");
3628 psf_setup.subslits = giraffe_wlsolution_get_subslits(solution);
3632 cpl_msg_info(fctid,
"Chebyshev polynomial order is (%d, %d).",
3633 psf_setup.fit.xorder, psf_setup.fit.yorder);
3639 cpl_msg_info(fctid,
"Sigma clipping: iterations = %d, level = %.4f, "
3640 "fraction = %.4f", psf_setup.clip.iterations,
3641 psf_setup.clip.level, psf_setup.clip.fraction);
3644 psf_fit = _giraffe_psf_fit(line_data, localization, fibers,
3645 slitgeometry, &psf_setup);
3648 if (psf_fit == NULL) {
3650 cpl_msg_error(fctid,
"Fit of the line profile PSF width "
3651 "variation failed!");
3653 cpl_table_delete(_lines);
3654 cpl_image_delete(line_status);
3655 giraffe_linedata_delete(line_data);
3659 _giraffe_lineparams_delete(line_setup);
3661 giraffe_wlsolution_delete(solution);
3672 cpl_image_delete(psf_fit);
3676 if (giraffe_linedata_accepted(line_data) == 0) {
3677 cpl_msg_error(fctid,
"No lines left after line profile PSF "
3680 cpl_table_delete(_lines);
3681 cpl_image_delete(line_status);
3682 giraffe_linedata_delete(line_data);
3686 _giraffe_lineparams_delete(line_setup);
3688 giraffe_wlsolution_delete(solution);
3694 cpl_msg_info(fctid,
"Number of good lines: %"
3695 CX_PRINTF_FORMAT_SIZE_TYPE
". %"
3696 CX_PRINTF_FORMAT_SIZE_TYPE
" of %d lines "
3697 "rejected due to line profile PSF width fit.",
3698 giraffe_linedata_accepted(line_data),
3699 giraffe_linedata_rejected(line_data) - _nreject, _ngood);
3701 _ngood = giraffe_linedata_accepted(line_data);
3702 _nreject = giraffe_linedata_rejected(line_data);
3712 cxint iterations = 0;
3715 cxdouble chisq = 0.;
3716 cxdouble rsquare = 0.;
3718 cx_string *s = NULL;
3720 GiOpticalModelParams om_setup;
3722 GiModel *guess = NULL;
3723 GiModel *model = giraffe_wlsolution_model(solution);
3730 guess = giraffe_model_clone(model);
3732 om_setup.fit.iterations = config->
opt_niter;
3737 cpl_msg_info(fctid,
"Optical model fit setup: iterations = %d, "
3738 "tests = %d, delta = %.4f", om_setup.fit.iterations,
3739 om_setup.fit.tests, om_setup.fit.delta);
3741 status = _giraffe_opticalmodel_fit(solution, line_data, fibers,
3742 slitgeometry, &om_setup);
3745 cpl_msg_error(fctid,
"Optical model fit failed!");
3747 giraffe_model_delete(guess);
3749 cpl_table_delete(_lines);
3750 cpl_image_delete(line_status);
3751 giraffe_linedata_delete(line_data);
3755 _giraffe_lineparams_delete(line_setup);
3757 giraffe_wlsolution_delete(solution);
3768 cpl_msg_info(fctid,
"Optical model parameters:");
3770 s = cx_string_new();
3772 _giraffe_opticalmodel_format(s, guess, GI_OPTM_PARAMETER_VALUES);
3773 cpl_msg_info(fctid,
"Initial: %s", cx_string_get(s));
3775 _giraffe_opticalmodel_format(s, model, GI_OPTM_PARAMETER_VALUES);
3776 cpl_msg_info(fctid,
" Fitted: %s", cx_string_get(s));
3778 _giraffe_opticalmodel_format(s, model, GI_OPTM_PARAMETER_ERRORS);
3779 cpl_msg_info(fctid,
" Sigma: %s", cx_string_get(s));
3781 _giraffe_opticalmodel_format(s, model, GI_OPTM_PARAMETER_STATUS);
3782 cpl_msg_info(fctid,
" Status: %s", cx_string_get(s));
3784 cx_string_delete(s);
3788 if (strcmp(giraffe_model_get_name(model),
"xoptmod2") == 0) {
3790 cxdouble flength = 0.;
3795 cx_string *s = cx_string_new();
3798 flength = giraffe_model_get_parameter(guess,
"FocalLength");
3799 sdx = giraffe_model_get_parameter(guess,
"Sdx");
3800 sdy = giraffe_model_get_parameter(guess,
"Sdy");
3801 sphi = giraffe_model_get_parameter(guess,
"Sphi");
3803 cx_string_sprintf(s,
"Initial: focal length = %.6f, slit "
3804 "x-shift = %.9f, slit y-shift = %.9f, "
3805 "slit rotation = %.9f", flength, sdx, sdy,
3807 cpl_msg_info(fctid,
"%s", cx_string_get(s));
3810 flength = giraffe_model_get_parameter(model,
"FocalLength");
3811 sdx = giraffe_model_get_parameter(model,
"Sdx");
3812 sdy = giraffe_model_get_parameter(model,
"Sdy");
3813 sphi = giraffe_model_get_parameter(model,
"Sphi");
3815 cx_string_sprintf(s,
" Fitted: focal length = %.6f, slit "
3816 "x-shift = %.9f, slit y-shift = %.9f, "
3817 "slit rotation = %.9f", flength, sdx, sdy,
3819 cpl_msg_info(fctid,
"%s", cx_string_get(s));
3822 flength = giraffe_model_get_sigma(model,
"FocalLength");
3823 sdx = giraffe_model_get_sigma(model,
"Sdx");
3824 sdy = giraffe_model_get_sigma(model,
"Sdy");
3825 sphi = giraffe_model_get_sigma(model,
"Sphi");
3827 cx_string_sprintf(s,
" Sigma: focal length = %.6f, slit "
3828 "x-shift = %.9f, slit y-shift = %.9f, "
3829 "slit rotation = %.9f", flength, sdx, sdy,
3831 cpl_msg_info(fctid,
"%s", cx_string_get(s));
3833 cx_string_delete(s);
3838 cxdouble flength = 0.;
3840 cx_string *s = cx_string_new();
3843 flength = giraffe_model_get_parameter(guess,
"FocalLength");
3845 cx_string_sprintf(s,
"Initial: focal length = %.6f", flength);
3846 cpl_msg_info(fctid,
"%s", cx_string_get(s));
3849 flength = giraffe_model_get_parameter(model,
"FocalLength");
3851 cx_string_sprintf(s,
" Fitted: focal length = %.6f", flength);
3852 cpl_msg_info(fctid,
"%s", cx_string_get(s));
3855 flength = giraffe_model_get_sigma(model,
"FocalLength");
3857 cx_string_sprintf(s,
" Sigma: focal length = %.6f", flength);
3858 cpl_msg_info(fctid,
"%s", cx_string_get(s));
3860 cx_string_delete(s);
3865 giraffe_model_delete(guess);
3868 iterations = giraffe_model_get_position(model);
3869 df = giraffe_model_get_df(model);
3871 chisq = giraffe_model_get_chisq(model);
3872 rsquare = giraffe_model_get_rsquare(model);
3874 cpl_msg_info(fctid,
"Optical model fit statistics: iterations = "
3875 "%d, DoF = %d, Chi-square = %.6g, Chi-square/DoF = "
3876 "%.6g, R-square = %.6g", iterations, df, chisq,
3877 chisq / df, rsquare);
3885 setup->
fcoll = giraffe_model_get_parameter(model,
"FocalLength");
3886 setup->
gcam = giraffe_model_get_parameter(model,
"Magnification");
3887 setup->
theta = giraffe_model_get_parameter(model,
"Angle");
3888 setup->
order = giraffe_model_get_parameter(model,
"Order");
3889 setup->
space = giraffe_model_get_parameter(model,
"Spacing");
3891 if (strcmp(giraffe_model_get_name(model),
"xoptmod2") == 0) {
3892 setup->
sdx = giraffe_model_get_parameter(model,
"Sdx");
3893 setup->
sdy = giraffe_model_get_parameter(model,
"Sdy");
3894 setup->
sphi = giraffe_model_get_parameter(model,
"Sphi");
3909 cpl_msg_info(fctid,
"Re-computing line positions with updated "
3912 xccd = _giraffe_line_abscissa(_lines, slitgeometry, fibers,
3913 solution, localization, FALSE);
3915 giraffe_linedata_set_data(line_data,
"Xccd", xccd);
3921 cx_string *s = cx_string_new();
3923 GiModel *model = giraffe_wlsolution_model(solution);
3926 _giraffe_opticalmodel_format(s, model, GI_OPTM_PARAMETER_VALUES);
3927 cpl_msg_info(fctid,
"Optical model: %s", cx_string_get(s));
3929 cx_string_delete(s);
3934 rms = _giraffe_compute_statistics(line_data, NULL, NULL);
3936 cpl_msg_info(fctid,
"Average RMS [pxl] of line positions using "
3937 "%d of %d lines: %.4f", _ngood, _nlines * _nfibers,
3946 cpl_msg_info(fctid,
"Fit of the wavelength solution coefficients "
3947 "using %" CX_PRINTF_FORMAT_SIZE_TYPE
" lines",
3948 giraffe_linedata_accepted(line_data));
3950 xws_setup.subslits = giraffe_wlsolution_get_subslits(solution);
3954 cpl_msg_info(fctid,
"Chebyshev polynomial order is (%d, %d).",
3955 xws_setup.fit.xorder, xws_setup.fit.yorder);
3961 cpl_msg_info(fctid,
"Sigma clipping: iterations = %d, level = %.4f, "
3962 "fraction = %.4f", xws_setup.clip.iterations,
3963 xws_setup.clip.level, xws_setup.clip.fraction);
3965 xws_coeffs = giraffe_wlresiduals_new();
3967 xws_fit = _giraffe_residuals_fit(xws_coeffs, line_data, localization,
3968 fibers, slitgeometry, &xws_setup);
3971 if (xws_fit == NULL) {
3973 cpl_msg_error(fctid,
"Fit of the wavelength solution "
3974 "coefficients failed!");
3976 giraffe_wlresiduals_delete(xws_coeffs);
3978 cpl_table_delete(_lines);
3979 cpl_image_delete(line_status);
3980 giraffe_linedata_delete(line_data);
3984 _giraffe_lineparams_delete(line_setup);
3986 giraffe_wlsolution_delete(solution);
3998 xres = cpl_image_new(giraffe_linedata_fibers(line_data),
3999 giraffe_linedata_lines(line_data),
4002 _giraffe_get_residuals(xres,
4003 giraffe_linedata_get_data(line_data,
"Xccd"),
4005 giraffe_linedata_set_data(line_data,
"Xres", xres);
4008 if (giraffe_linedata_accepted(line_data) == 0) {
4009 cpl_msg_error(fctid,
"No lines left after wavelength solution "
4010 "coefficients fit!");
4012 giraffe_wlresiduals_delete(xws_coeffs);
4014 cpl_table_delete(_lines);
4015 cpl_image_delete(line_status);
4016 cpl_image_delete(xws_fit);
4017 giraffe_linedata_delete(line_data);
4021 _giraffe_lineparams_delete(line_setup);
4023 giraffe_wlsolution_delete(solution);
4029 cpl_msg_info(fctid,
"Number of good lines: %"
4030 CX_PRINTF_FORMAT_SIZE_TYPE
". %"
4031 CX_PRINTF_FORMAT_SIZE_TYPE
" of %d lines "
4032 "rejected due to wavelength solution coefficients fit.",
4033 giraffe_linedata_accepted(line_data),
4034 giraffe_linedata_rejected(line_data) - _nreject, _ngood);
4036 _ngood = giraffe_linedata_accepted(line_data);
4037 _nreject = giraffe_linedata_rejected(line_data);
4044 giraffe_wlsolution_set_residuals(solution, xws_coeffs);
4054 rms = _giraffe_compute_statistics(line_data, xws_fit, line_status);
4056 cpl_msg_info(fctid,
"Average RMS [pxl] of line positions using "
4057 "%d of %d lines: %.4f", _ngood, _nlines * _nfibers,
4067 info.residuals = residuals;
4069 info.nlines = _nlines;
4070 info.nfibers = _nfibers;
4072 info.ngood = _ngood;
4073 info.nreject = _nreject;
4082 cpl_image_delete(xws_fit);
4084 cpl_table_delete(_lines);
4085 cpl_image_delete(line_status);
4097 status = _giraffe_convert_wlsolution(tsolution, solution,
4098 extraction->spectra, setup,
4107 _giraffe_lineparams_delete(line_setup);
4109 giraffe_wlsolution_delete(solution);
4120 result->coeffs = tsolution;
4123 result->linedata = line_data;
4131 giraffe_wlsolution_delete(solution);
4133 _giraffe_lineparams_delete(line_setup);
4154 const cxchar *s = NULL;
4155 const cpl_parameter *p = NULL;
4164 config = cx_calloc(1,
sizeof *config);
4179 p = cpl_parameterlist_find(list,
"giraffe.wlcalibration.line.widths");
4180 s = cpl_parameter_get_string(p);
4184 cxchar **values = cx_strsplit(s,
",", -1);
4187 if (values == NULL) {
4200 while (values[n] != NULL) {
4205 config->
line_widths = cx_malloc(n *
sizeof(cxint));
4209 while (values[n] != NULL) {
4211 cxint w = strtol(values[n], &last, 10);
4213 if (*last !=
'\0') {
4214 cx_strfreev(values);
4227 sizeof(cxint), _giraffe_window_compare);
4230 cx_strfreev(values);
4238 p = cpl_parameterlist_find(list,
"giraffe.wlcalibration.line.separation");
4241 p = cpl_parameterlist_find(list,
"giraffe.wlcalibration.line.fluxratio");
4244 p = cpl_parameterlist_find(list,
"giraffe.wlcalibration.line.brightness");
4247 p = cpl_parameterlist_find(list,
"giraffe.wlcalibration.line.count");
4248 config->
line_count = cpl_parameter_get_int(p);
4250 p = cpl_parameterlist_find(list,
"giraffe.wlcalibration.line.wrange");
4251 s = cpl_parameter_get_string(p);
4255 cxchar **values = cx_strsplit(s,
",", 3);
4257 if (values == NULL) {
4267 cxdouble lower = 0.;
4268 cxdouble upper = 0.;
4271 lower = strtod(values[0], &last);
4273 if (*last !=
'\0') {
4275 cx_strfreev(values);
4282 lower = lower >= 0. ? lower : 0.;
4285 if (values[1] != NULL) {
4287 upper = strtod(values[1], &last);
4289 if (*last !=
'\0') {
4291 cx_strfreev(values);
4298 upper = upper > lower ? upper : 0.;
4307 cx_strfreev(values);
4313 p = cpl_parameterlist_find(list,
"giraffe.wlcalibration.line.model");
4314 s = cpl_parameter_get_string(p);
4316 if (strcmp(s,
"psfexp") != 0 &&
4317 strcmp(s,
"psfexp2") != 0 &&
4318 strcmp(s,
"gaussian") != 0) {
4329 p = cpl_parameterlist_find(list,
"giraffe.wlcalibration.line.residuals");
4330 s = cpl_parameter_get_string(p);
4332 if (strcmp(s,
"auto") != 0 &&
4333 strcmp(s,
"enable") != 0 &&
4334 strcmp(s,
"disable") != 0) {
4345 p = cpl_parameterlist_find(list,
"giraffe.wlcalibration.line.threshold");
4348 p = cpl_parameterlist_find(list,
"giraffe.wlcalibration.line.offset");
4349 config->
line_offset = cpl_parameter_get_double(p);
4351 p = cpl_parameterlist_find(list,
"giraffe.wlcalibration.line.iterations");
4352 config->
line_niter = cpl_parameter_get_int(p);
4354 p = cpl_parameterlist_find(list,
"giraffe.wlcalibration.line.tests");
4355 config->
line_ntest = cpl_parameter_get_int(p);
4357 p = cpl_parameterlist_find(list,
"giraffe.wlcalibration.line.dchisquare");
4358 config->
line_dchisq = cpl_parameter_get_double(p);
4360 p = cpl_parameterlist_find(list,
"giraffe.wlcalibration.line.rwidthratio");
4363 p = cpl_parameterlist_find(list,
"giraffe.wlcalibration.line.exponent");
4367 p = cpl_parameterlist_find(list,
"giraffe.wlcalibration.slit.offset");
4368 s = cpl_parameter_get_string(p);
4370 cx_assert(s != NULL);
4372 if (cx_strncasecmp(s,
"setup", 5) != 0) {
4374 cxchar **values = cx_strsplit(s,
",", 4);
4382 if (values == NULL || values[0] == NULL) {
4392 if (*values[0] !=
'\0') {
4395 cxdouble sdx = strtod(values[0], &last);
4397 if (*last !=
'\0') {
4398 cx_strfreev(values);
4411 if (values[1] == NULL) {
4416 if (*values[1] !=
'\0') {
4419 cxdouble sdy = strtod(values[1], &last);
4421 if (*last !=
'\0') {
4422 cx_strfreev(values);
4437 if (!eol && values[2] != NULL) {
4439 if (*values[2] !=
'\0') {
4442 cxdouble sphi = strtod(values[2], &last);
4444 if (*last !=
'\0') {
4445 cx_strfreev(values);
4460 cx_strfreev(values);
4468 p = cpl_parameterlist_find(list,
"giraffe.wlcalibration.opt.model");
4469 s = cpl_parameter_get_string(p);
4471 if (strcmp(s,
"xoptmod") != 0 && strcmp(s,
"xoptmod2") != 0) {
4482 p = cpl_parameterlist_find(list,
"giraffe.wlcalibration.opt.direction");
4485 p = cpl_parameterlist_find(list,
"giraffe.wlcalibration.opt.solution");
4488 p = cpl_parameterlist_find(list,
"giraffe.wlcalibration.opt.subslits");
4491 p = cpl_parameterlist_find(list,
"giraffe.wlcalibration.opt.flags");
4492 s = cpl_parameter_get_string(p);
4496 cxchar **values = cx_strsplit(s,
",", -1);
4498 if (values == NULL) {
4511 while (values[i] != NULL) {
4513 if (strncmp(values[i],
"fcoll", 5) == 0) {
4517 else if (strncmp(values[i],
"gcam", 4) == 0) {
4521 else if (strncmp(values[i],
"theta", 5) == 0) {
4525 else if (strncmp(values[i],
"sdx", 3) == 0) {
4529 else if (strncmp(values[i],
"sdy", 3) == 0) {
4533 else if (strncmp(values[i],
"sphi", 4) == 0) {
4542 cx_strfreev(values);
4560 p = cpl_parameterlist_find(list,
"giraffe.wlcalibration.opt.iterations");
4561 config->
opt_niter = cpl_parameter_get_int(p);
4563 p = cpl_parameterlist_find(list,
"giraffe.wlcalibration.opt.tests");
4564 config->
opt_ntest = cpl_parameter_get_int(p);
4566 p = cpl_parameterlist_find(list,
"giraffe.wlcalibration.opt.dchisquare");
4567 config->
opt_dchisq = cpl_parameter_get_double(p);
4570 p = cpl_parameterlist_find(list,
"giraffe.wlcalibration.psf.sigma");
4573 p = cpl_parameterlist_find(list,
"giraffe.wlcalibration.psf.iterations");
4576 p = cpl_parameterlist_find(list,
"giraffe.wlcalibration.psf.fraction");
4579 p = cpl_parameterlist_find(list,
"giraffe.wlcalibration.psf.order");
4580 s = cpl_parameter_get_string(p);
4584 cxchar **values = cx_strsplit(s,
",", 3);
4586 if (values == NULL || values[1] == NULL) {
4597 config->
pxw_xorder = strtol(values[0], &last, 10);
4599 if (*last !=
'\0') {
4601 cx_strfreev(values);
4608 config->
pxw_yorder = strtol(values[1], &last, 10);
4610 if (*last !=
'\0') {
4612 cx_strfreev(values);
4621 cx_strfreev(values);
4627 p = cpl_parameterlist_find(list,
"giraffe.wlcalibration.wsol.sigma");
4630 p = cpl_parameterlist_find(list,
"giraffe.wlcalibration.wsol.iterations");
4633 p = cpl_parameterlist_find(list,
"giraffe.wlcalibration.wsol.fraction");
4636 p = cpl_parameterlist_find(list,
"giraffe.wlcalibration.wsol.order");
4637 s = cpl_parameter_get_string(p);
4641 cxchar **values = cx_strsplit(s,
",", 3);
4643 if (values == NULL || values[1] == NULL) {
4654 config->
xws_xorder = strtol(values[0], &last, 10);
4656 if (*last !=
'\0') {
4658 cx_strfreev(values);
4665 config->
xws_yorder = strtol(values[1], &last, 10);
4667 if (*last !=
'\0') {
4669 cx_strfreev(values);
4678 cx_strfreev(values);
4760 p = cpl_parameter_new_value(
"giraffe.wlcalibration.line.widths",
4762 "List of window widths [pxl] used for line "
4763 "detection and fit (e.g. '60,40,15').",
4764 "giraffe.wlcalibration",
4766 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"wcal-lswidth");
4767 cpl_parameterlist_append(list, p);
4770 p = cpl_parameter_new_value(
"giraffe.wlcalibration.line.separation",
4772 "Factor used to compute the minimum line "
4773 "separation from the window width.",
4774 "giraffe.wlcalibration",
4776 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"wcal-lssep");
4777 cpl_parameterlist_append(list, p);
4780 p = cpl_parameter_new_value(
"giraffe.wlcalibration.line.fluxratio",
4782 "Selects only lines whose neighbours have "
4783 "a relative intensity less than "
4785 "giraffe.wlcalibration",
4788 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"wcal-lsfxratio");
4789 cpl_parameterlist_append(list, p);
4792 p = cpl_parameter_new_value(
"giraffe.wlcalibration.line.brightness",
4794 "Selects lines having an intensity greater "
4795 "or equal to the given intensity.",
4796 "giraffe.wlcalibration",
4799 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"wcal-lsbright");
4800 cpl_parameterlist_append(list, p);
4803 p = cpl_parameter_new_value(
"giraffe.wlcalibration.line.count",
4805 "Sets the minimum number of lines to select; "
4806 "selected are lines with the highest nominal "
4807 "intensity. A value of 0 turns this selection "
4808 "off. If the value is less than 0 the "
4809 "selection is skipped if the line list does "
4810 "not contain enough lines.",
4811 "giraffe.wlcalibration",
4814 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"wcal-lscount");
4815 cpl_parameterlist_append(list, p);
4818 p = cpl_parameter_new_value(
"giraffe.wlcalibration.line.wrange",
4820 "Selects only lines within the given "
4821 "wavelength range [nm].",
4822 "giraffe.wlcalibration",
4825 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"wcal-lswrange");
4826 cpl_parameterlist_append(list, p);
4833 p = cpl_parameter_new_enum(
"giraffe.wlcalibration.line.model",
4835 "Line profile model.",
4836 "giraffe.wlcalibration",
4837 "psfexp", 3,
"psfexp",
"psfexp2",
"gaussian");
4839 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"wcal-lfmodel");
4840 cpl_parameterlist_append(list, p);
4843 p = cpl_parameter_new_enum(
"giraffe.wlcalibration.line.residuals",
4845 "Use optical model residuals for line "
4847 "giraffe.wlcalibration",
4848 "auto", 3,
"auto",
"enable",
"disable");
4850 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"wcal-lfres");
4851 cpl_parameterlist_append(list, p);
4854 p = cpl_parameter_new_value(
"giraffe.wlcalibration.line.threshold",
4856 "Line detection threshold during the "
4857 "line fitting (multiple of bias sigma)",
4858 "giraffe.wlcalibration",
4861 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"wcal-lfthreshold");
4862 cpl_parameterlist_append(list, p);
4865 p = cpl_parameter_new_value(
"giraffe.wlcalibration.line.offset",
4867 "Maximum allowed difference between the "
4868 "fitted and raw line peak position.",
4869 "giraffe.wlcalibration",
4872 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"wcal-lfoffset");
4873 cpl_parameterlist_append(list, p);
4876 p = cpl_parameter_new_value(
"giraffe.wlcalibration.line.iterations",
4878 "Line detection fit maximum number of "
4880 "giraffe.wlcalibration",
4883 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"wcal-lfniter");
4884 cpl_parameterlist_append(list, p);
4887 p = cpl_parameter_new_value(
"giraffe.wlcalibration.line.tests",
4889 "Line detection fit maximum number of "
4891 "giraffe.wlcalibration",
4894 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"wcal-lfntest");
4895 cpl_parameterlist_append(list, p);
4898 p = cpl_parameter_new_value(
"giraffe.wlcalibration.line.dchisquare",
4900 "Line detection fit minimum chi-square "
4902 "giraffe.wlcalibration",
4905 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"wcal-lfdchisq");
4906 cpl_parameterlist_append(list, p);
4909 p = cpl_parameter_new_value(
"giraffe.wlcalibration.line.rwidthratio",
4911 "Line width/resolution width factor.",
4912 "giraffe.wlcalibration",
4915 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"wcal-lfreswid");
4916 cpl_parameterlist_append(list, p);
4919 p = cpl_parameter_new_value(
"giraffe.wlcalibration.line.exponent",
4921 "Exponential line profile exponent; it will "
4922 "not be fitted if it is larger than 0.",
4923 "giraffe.wlcalibration",
4926 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"wcal-lfexpwid");
4927 cpl_parameterlist_append(list, p);
4935 p = cpl_parameter_new_value(
"giraffe.wlcalibration.slit.offset",
4937 "Initial slit position offsets along the "
4938 "x and y direction and rotation angle.",
4939 "giraffe.wlcalibration",
4942 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"wcal-soffset");
4943 cpl_parameterlist_append(list, p);
4950 p = cpl_parameter_new_enum(
"giraffe.wlcalibration.opt.model",
4953 "giraffe.wlcalibration",
4954 "xoptmod2", 2,
"xoptmod",
"xoptmod2");
4956 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"wcal-ommodel");
4957 cpl_parameterlist_append(list, p);
4960 p = cpl_parameter_new_value(
"giraffe.wlcalibration.opt.direction",
4962 "Dispersion direction flag.",
4963 "giraffe.wlcalibration",
4966 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"wcal-omdir");
4967 cpl_parameterlist_append(list, p);
4970 p = cpl_parameter_new_value(
"giraffe.wlcalibration.opt.solution",
4972 "Controls optical model parameter fitting.",
4973 "giraffe.wlcalibration",
4976 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"wcal-omsol");
4977 cpl_parameterlist_append(list, p);
4980 p = cpl_parameter_new_value(
"giraffe.wlcalibration.opt.flags",
4982 "List of flags defining the set of free "
4983 "parameters used for fitting the optical "
4984 "model. Possible values are: fcoll, gcam, "
4985 "theta, sdx, sdy, sphi",
4986 "giraffe.wlcalibration",
4989 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"wcal-omflags");
4990 cpl_parameterlist_append(list, p);
4993 p = cpl_parameter_new_value(
"giraffe.wlcalibration.opt.subslits",
4995 "Controls subslit geometry usage in the "
4996 "optical model fit; subslits are used if "
4998 "giraffe.wlcalibration",
5001 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"wcal-omsslits");
5002 cpl_parameterlist_append(list, p);
5005 p = cpl_parameter_new_value(
"giraffe.wlcalibration.opt.iterations",
5007 "Optical model fit maximum number of "
5009 "giraffe.wlcalibration",
5012 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"wcal-omniter");
5013 cpl_parameterlist_append(list, p);
5016 p = cpl_parameter_new_value(
"giraffe.wlcalibration.opt.tests",
5018 "Optical model fit maximum number of "
5020 "giraffe.wlcalibration",
5023 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"wcal-omntest");
5024 cpl_parameterlist_append(list, p);
5027 p = cpl_parameter_new_value(
"giraffe.wlcalibration.opt.dchisquare",
5029 "Optical model fit minimum chi-square "
5031 "giraffe.wlcalibration",
5034 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"wcal-omdchisq");
5035 cpl_parameterlist_append(list, p);
5042 p = cpl_parameter_new_value(
"giraffe.wlcalibration.psf.sigma",
5044 "PSF width fit sigma clipping factor.",
5045 "giraffe.wlcalibration",
5048 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"wcal-xwsigma");
5049 cpl_parameterlist_append(list, p);
5052 p = cpl_parameter_new_value(
"giraffe.wlcalibration.psf.iterations",
5054 "PSF width fit sigma clipping maximum "
5055 "number of iterations.",
5056 "giraffe.wlcalibration",
5059 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"wcal-xwniter");
5060 cpl_parameterlist_append(list, p);
5063 p = cpl_parameter_new_range(
"giraffe.wlcalibration.psf.fraction",
5065 "PSF width fit sigma clipping minimum "
5066 "fraction of points accepted/total.",
5067 "giraffe.wlcalibration",
5070 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"wcal-xwmfrac");
5071 cpl_parameterlist_append(list, p);
5074 p = cpl_parameter_new_value(
"giraffe.wlcalibration.psf.order",
5076 "X and Y polynomial orders for PSF x-width "
5078 "giraffe.wlcalibration",
5081 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"wcal-xworder");
5082 cpl_parameterlist_append(list, p);
5089 p = cpl_parameter_new_value(
"giraffe.wlcalibration.wsol.sigma",
5091 "Chebyshev correction sigma clipping factor.",
5092 "giraffe.wlcalibration",
5095 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"wcal-wssigma");
5096 cpl_parameterlist_append(list, p);
5099 p = cpl_parameter_new_value(
"giraffe.wlcalibration.wsol.iterations",
5101 "Chebyshev correction sigma clipping "
5102 "maximum number of iterations",
5103 "giraffe.wlcalibration",
5106 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"wcal-wsniter");
5107 cpl_parameterlist_append(list, p);
5110 p = cpl_parameter_new_range(
"giraffe.wlcalibration.wsol.fraction",
5112 "Chebyshev correction sigma clipping "
5113 "minimum fraction of points accepted/total.",
5114 "giraffe.wlcalibration",
5117 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"wcal-wsmfrac");
5118 cpl_parameterlist_append(list, p);
5121 p = cpl_parameter_new_value(
"giraffe.wlcalibration.wsol.order",
5123 "X and Y polynomial orders for the wavelength "
5124 "solution Chebyshev correction.",
5125 "giraffe.wlcalibration",
5128 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"wcal-wsorder");
5129 cpl_parameterlist_append(list, p);
const cxchar * giraffe_fiberlist_query_index(const cpl_table *fibers)
Query a fiber list for the name of the fiber reference index column.
GiGrating * giraffe_grating_create(const GiImage *spectra, const GiTable *grating)
Create a GiGrating from a reference image.
void giraffe_grating_delete(GiGrating *self)
Destroys an GiGrating object.
cpl_image * giraffe_image_get(const GiImage *self)
Gets the image data.
cpl_propertylist * giraffe_image_get_properties(const GiImage *self)
Get the properties of an image.
cpl_matrix * giraffe_matrix_leastsq(const cpl_matrix *mA, const cpl_matrix *mB)
Computes the solution of an equation using a pseudo-inverse.
cxint giraffe_matrix_sort(cpl_matrix *mA)
Sort in place the matrix elements in ascending order.
void gi_error(const cxchar *format,...)
Log an error message.
void giraffe_range_delete(GiRange *self)
Destroys a range object.
cxdouble giraffe_range_get_min(const GiRange *const self)
Get the minimum of a range.
cxdouble giraffe_range_get_max(const GiRange *const self)
Get the maximum of a range.
GiRange * giraffe_range_create(cxdouble min, cxdouble max)
Creates a new range from the given minimum and maximum values.
cxint giraffe_table_set(GiTable *self, cpl_table *table)
Sets the table data.
GiTable * giraffe_table_new(void)
Creates a new, empty Giraffe table.
void giraffe_table_delete(GiTable *self)
Destroys a Giraffe table.
cpl_table * giraffe_table_get(const GiTable *self)
Get the table data from a Giraffe table.
cpl_propertylist * giraffe_table_get_properties(const GiTable *self)
Gets the table properties.
cxint giraffe_table_set_properties(GiTable *self, cpl_propertylist *properties)
Attaches a property list to an table.
void giraffe_wlcalibration_config_add(cpl_parameterlist *list)
Adds parameters for the wavelength calibration.
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.
GiWCalConfig * giraffe_wlcalibration_config_create(cpl_parameterlist *list)
Creates a setup structure for the wavelength calibration.
void giraffe_wlcalibration_config_destroy(GiWCalConfig *config)
Destroys a wavelength calibration setup structure.
GiWlSolution * giraffe_wlsolution_create(GiTable *solution, GiImage *spectra, GiGrating *grating)
Create a new wavelength solution from a wavelength solution table.
Structure to handle Grating Information.
Wavelength calibration configuration data structure.
cxdouble line_widthexponent
cxdouble line_rwidthratio