29 #include <cxstrutils.h>
31 #include <cpl_error.h>
37 #include "gigrating.h"
39 #include "gilinedata.h"
40 #include "giwlsolution.h"
42 #include "gimessages.h"
43 #include "gifiberutils.h"
45 #include "giwlcalibration.h"
63 GI_LINETYPE_UNDEFINED,
68 typedef enum GiLineType GiLineType;
109 OPTM_FLENGTH = 1 << 0,
110 OPTM_GCAMERA = 1 << 1,
122 enum GiOpticalModelInfo {
123 GI_OPTM_PARAMETER_VALUES,
124 GI_OPTM_PARAMETER_ERRORS,
125 GI_OPTM_PARAMETER_STATUS
128 typedef enum GiOpticalModelInfo GiOpticalModelInfo;
135 struct GiLineParams {
152 typedef struct GiLineParams GiLineParams;
159 struct GiOpticalModelParams {
166 typedef struct GiOpticalModelParams GiOpticalModelParams;
173 struct GiSCFitParams {
186 typedef struct GiSCFitParams GiSCFitParams;
205 typedef struct GiWCalInfo GiWCalInfo;
209 _giraffe_window_compare(cxcptr first, cxcptr second)
212 cxint *_first = (cxint *)first;
213 cxint *_second = (cxint *)second;
215 return *_second - *_first;
220 inline static GiLineParams *
221 _giraffe_lineparams_create(GiLineType type,
const GiGrating *grating,
225 GiLineParams *
self = NULL;
228 cx_assert(grating != NULL);
229 cx_assert(config != NULL);
231 self = cx_calloc(1,
sizeof(GiLineParams));
242 self->grwid = 1. / grating->
band * (grating->
wlen0 / grating->
resol);
260 _giraffe_lineparams_delete(GiLineParams *
self)
266 cx_free((cxptr)self->model);
278 inline static cxdouble
279 _giraffe_get_fiber_position(
const cpl_image *locy, cxint cs, cxdouble xccd)
282 cxint xlower = (cxint)floor(xccd);
283 cxint xupper = (cxint)ceil(xccd);
285 const cxdouble *ldata = cpl_image_get_data_const(locy);
287 cxdouble ylower = 0.;
288 cxdouble yupper = 0.;
291 cx_assert(ldata != NULL);
293 ylower = ldata[xlower * cpl_image_get_size_x(locy) + cs];
294 yupper = ldata[xupper * cpl_image_get_size_x(locy) + cs];
296 return giraffe_interpolate_linear(xccd, xlower, ylower, xupper, yupper);
302 _giraffe_subslit_get_max(
const cpl_table *fibers)
305 return cpl_table_get_column_max((cpl_table *)fibers,
"SSN");
310 inline static cpl_table *
311 _giraffe_subslit_get(
const cpl_table *fibers, cxint ssn)
319 cx_assert(fibers != NULL);
320 cx_assert(cpl_table_has_column((cpl_table *)fibers,
"SSN"));
322 ssn_max = _giraffe_subslit_get_max(fibers);
324 if (ssn < 0 || ssn > ssn_max) {
328 cpl_table_unselect_all((cpl_table *)fibers);
329 cpl_table_or_selected_int((cpl_table *)fibers,
"SSN", CPL_EQUAL_TO, ssn);
331 _fibers = cpl_table_extract_selected((cpl_table *)fibers);
339 _giraffe_subslit_range(
const cpl_table *subslit,
const cpl_image *locy,
340 const cpl_image *locw, cxdouble *ymin, cxdouble *ymax)
343 const cxchar *idx = NULL;
349 const cxdouble *_locy = NULL;
350 const cxdouble *_locw = NULL;
352 cxdouble _ymin = CX_MAXDOUBLE;
355 cx_assert(subslit != NULL);
356 cx_assert(locy != NULL);
357 cx_assert(locw != NULL);
361 ns = cpl_image_get_size_x(locy);
362 nx = cpl_image_get_size_y(locy);
364 _locy = cpl_image_get_data_const(locy);
365 _locw = cpl_image_get_data_const(locw);
367 for (i = 0; i < cpl_table_get_nrow((cpl_table *)subslit); i++) {
370 cxint cs = cpl_table_get_int((cpl_table *)subslit, idx, i, NULL) - 1;
372 for (j = 0; j < nx; j++) {
374 register cxint k = j * ns + cs;
376 cxdouble ylower = _locy[k] - _locw[k];
377 cxdouble yupper = _locy[k] + _locw[k];
379 _ymin = CX_MIN(_ymin, ylower);
380 _ymax = CX_MAX(_ymax, yupper);
404 _giraffe_get_residuals(cpl_image *residuals,
const cpl_image *positions,
405 const cpl_image *fit)
413 const cxdouble *_positions = NULL;
414 const cxdouble *_fit = NULL;
416 cxdouble *_residuals = NULL;
419 cx_assert(residuals != NULL);
420 cx_assert(positions != NULL);
421 cx_assert(fit != NULL);
423 nfibers = cpl_image_get_size_x(positions);
424 nlines = cpl_image_get_size_y(positions);
425 nx = cpl_image_get_size_y(fit);
427 cx_assert(nfibers == cpl_image_get_size_x(residuals));
428 cx_assert(nlines == cpl_image_get_size_y(residuals));
430 _residuals = cpl_image_get_data(residuals);
431 _positions = cpl_image_get_data_const(positions);
432 _fit = cpl_image_get_data_const(fit);
434 for (i = 0; i < nlines; i++) {
438 for (j = 0; j < nfibers; j++) {
440 register cxdouble line_pos = _positions[i * nfibers + j];
442 line_pos = CX_MIN(CX_MAX(line_pos, 0.), nx - 1);
443 _residuals[i * nfibers + j] = _fit[(cxint)line_pos * nfibers + j];
455 _giraffe_apply_residuals(cpl_image *xccd,
const cpl_image *residuals,
456 const cpl_image *lflags, cxdouble value)
459 cx_assert(xccd != NULL);
460 cx_assert(residuals != NULL);
462 cpl_image_subtract(xccd, residuals);
464 if (lflags != NULL) {
466 const cxint *_lflags = cpl_image_get_data_const(lflags);
469 cxint nfibers = cpl_image_get_size_x(xccd);
470 cxint nlines = cpl_image_get_size_y(xccd);
472 cxdouble *_xccd = cpl_image_get_data(xccd);
475 cx_assert(nfibers == cpl_image_get_size_x(lflags));
476 cx_assert(nlines == cpl_image_get_size_y(lflags));
478 for (i = 0; i < nlines; i++) {
482 for (j = 0; j < nfibers; j++) {
484 if (_lflags[i * nfibers + j] > 0) {
485 _xccd[i * nfibers + j] = value;
500 _giraffe_linelist_setup(GiTable *lines,
GiGrating *grating,
504 const cxchar *
const fctid =
"_giraffe_linelist_setup";
507 const cxdouble fraction = 500.;
515 cxdouble margin = 0.;
517 cpl_table *_lines = NULL;
521 cx_assert(lines != NULL);
522 cx_assert(grating != NULL);
523 cx_assert(config != NULL);
528 if (_lines == NULL) {
532 if (!cpl_table_has_column(_lines,
"WLEN") ||
533 !cpl_table_has_column(_lines,
"FLUX")) {
543 nlines = cpl_table_get_nrow(_lines);
544 cpl_table_unselect_all(_lines);
559 margin = (wlmax - wlmin) / fraction;
561 cpl_msg_debug(fctid,
"Selecting wavelength range [%.4f, %.4f[ [nm] with "
562 "margin %.4f nm.", wlmin, wlmax, margin);
564 cpl_table_or_selected_double(_lines,
"WLEN", CPL_LESS_THAN,
566 cpl_table_or_selected_double(_lines,
"WLEN", CPL_NOT_LESS_THAN,
569 cpl_table_erase_selected(_lines);
571 if (cpl_table_get_nrow(_lines) <= 0) {
572 cpl_msg_debug(fctid,
"Invalid line list! All lines have been "
577 nreject = nlines - cpl_table_get_nrow(_lines);
578 cpl_msg_debug(fctid,
"%d of %d lines rejected because of wavelength "
579 "range.", nreject, nlines);
586 nlines = cpl_table_get_nrow(_lines);
593 cpl_propertylist *sorting_order = NULL;
596 if (line_count > nlines) {
597 cpl_msg_debug(fctid,
"Too few lines in line list for brightness "
604 cpl_msg_debug(fctid,
"Skipping brightness selection!");
609 sorting_order = cpl_propertylist_new();
610 cpl_propertylist_append_bool(sorting_order,
"FLUX", 1);
612 cpl_table_sort(_lines, sorting_order);
614 cpl_propertylist_delete(sorting_order);
615 sorting_order = NULL;
617 cpl_table_select_all(_lines);
619 for (i = 0; i < line_count; i++) {
620 cpl_table_unselect_row(_lines, i);
623 cpl_table_erase_selected(_lines);
625 if (cpl_table_get_nrow(_lines) <= 0) {
629 sorting_order = cpl_propertylist_new();
630 cpl_propertylist_append_bool(sorting_order,
"WLEN", 0);
632 cpl_table_sort(_lines, sorting_order);
634 cpl_propertylist_delete(sorting_order);
635 sorting_order = NULL;
641 cpl_table_select_all(_lines);
642 cpl_table_and_selected_double(_lines,
"FLUX", CPL_NOT_GREATER_THAN,
645 cpl_table_erase_selected(_lines);
647 if (cpl_table_get_nrow(_lines) <= 0) {
648 cpl_msg_debug(fctid,
"Invalid line brightness! All lines have "
655 nreject = nlines - cpl_table_get_nrow(_lines);
656 cpl_msg_debug(fctid,
"%d of %d lines rejected because brightness "
657 "criteria.", nreject, nlines);
665 inline static cpl_table *
666 _giraffe_linelist_select(
const GiTable *lines,
const GiImage *spectra,
667 const GiGrating *grating, cxdouble width,
671 const cxchar *
const fctid =
"_giraffe_linelist_select";
679 cxdouble separation = 0.;
681 cpl_image *_spectra = NULL;
683 cpl_table *_lines = NULL;
686 cx_assert(lines != NULL);
687 cx_assert(spectra != NULL);
688 cx_assert(grating != NULL);
689 cx_assert(config != NULL);
692 cx_assert(_spectra != NULL);
696 if (_lines == NULL) {
700 nlines = cpl_table_get_nrow(_lines);
708 scale = fabs(cpl_image_get_size_y(_spectra)) / grating->
band;
711 cpl_msg_debug(fctid,
"Estimated wavelength scale: %.4e nm/pxl",
713 cpl_msg_debug(fctid,
"Minimum required line separation: %.4f nm (%.4f "
714 "pxl)", separation, separation * scale);
730 cpl_table_unselect_all(_lines);
732 for (i = 0; i < cpl_table_get_nrow(_lines); i++) {
736 register cxdouble w = cpl_table_get(_lines,
"WLEN", i, NULL);
737 register cxdouble f = cpl_table_get(_lines,
"FLUX", i, NULL);
740 for (j = 0; j < cpl_table_get_nrow(_lines); j++) {
744 register cxdouble _w = cpl_table_get(_lines,
"WLEN", j, NULL);
745 register cxdouble _f = cpl_table_get(_lines,
"FLUX", j, NULL);
748 if (fabs(w - _w) < separation &&
749 f / _f < config->line_fluxratio) {
751 cpl_table_select_row(_lines, i);
762 cpl_table_erase_selected(_lines);
764 if (cpl_table_get_nrow(_lines) <= 0) {
765 cpl_table_delete(_lines);
769 nreject = nlines - cpl_table_get_nrow(_lines);
770 cpl_msg_debug(fctid,
"%d of %d lines rejected due to crowding.",
783 cpl_msg_debug(fctid,
"Removing lines with non-zero line quality.");
785 nlines = cpl_table_get_nrow(_lines);
786 cpl_table_unselect_all(_lines);
788 if (cpl_table_has_column(_lines,
"FLAGS")) {
790 cpl_table_or_selected_int(_lines,
"FLAGS", CPL_NOT_EQUAL_TO, 0);
795 if (cpl_table_has_column(_lines,
"COMMENT")) {
797 for (i = 0; i < nlines; i++) {
799 cxchar *s = cx_strdup(cpl_table_get_string(_lines,
802 if (strlen(cx_strstrip(s)) > 3) {
803 cpl_table_select_row(_lines, i);
813 cpl_msg_debug(fctid,
"No comments found in line list! No line "
814 "quality checks will be done!");
820 cpl_table_erase_selected(_lines);
822 if (cpl_table_get_nrow(_lines) <= 0) {
823 cpl_msg_debug(fctid,
"Invalid line list! All lines have been "
825 cpl_table_delete(_lines);
829 nreject = nlines - cpl_table_get_nrow(_lines);
830 cpl_msg_debug(fctid,
"%d of %d lines rejected because of line quality.",
839 inline static cpl_image *
840 _giraffe_line_abscissa(
const cpl_table *lines,
const GiTable *slitgeometry,
841 const GiTable *fibers,
const GiWlSolution *solution,
842 const GiLocalization *localization, cxbool residuals)
845 const cxchar *
const fctid =
"_giraffe_line_abscissa";
848 const cxchar *idx = NULL;
854 cpl_table *_lines = NULL;
855 cpl_table *_fibers = NULL;
856 cpl_table *_slitgeometry = NULL;
858 cpl_image *abscissa = NULL;
861 cx_assert(lines != NULL);
862 cx_assert(slitgeometry != NULL);
863 cx_assert(fibers != NULL);
864 cx_assert(solution != NULL);
866 _lines = (cpl_table *)lines;
869 cx_assert(_fibers != NULL);
872 cx_assert(_slitgeometry != NULL);
875 nlines = cpl_table_get_nrow(_lines);
876 nfibers = cpl_table_get_nrow(_fibers);
878 if (nfibers != cpl_table_get_nrow(_slitgeometry)) {
879 cpl_error_set(fctid, CPL_ERROR_ILLEGAL_INPUT);
887 cpl_error_set(fctid, CPL_ERROR_ILLEGAL_INPUT);
892 if (residuals == TRUE) {
894 if (localization == NULL) {
895 cpl_error_set(fctid, CPL_ERROR_ILLEGAL_INPUT);
899 if (localization->locy == NULL || localization->locw == NULL) {
900 cpl_error_set(fctid, CPL_ERROR_DATA_NOT_FOUND);
905 if (giraffe_wlsolution_get_residuals(solution) == NULL) {
906 cpl_error_set(fctid, CPL_ERROR_DATA_NOT_FOUND);
913 abscissa = cpl_image_new(nfibers, nlines, CPL_TYPE_DOUBLE);
915 for (i = 0; i < nfibers; i++) {
919 cxdouble xf = cpl_table_get(_slitgeometry,
"XF", i, NULL);
920 cxdouble yf = cpl_table_get(_slitgeometry,
"YF", i, NULL);
921 cxdouble *data = cpl_image_get_data(abscissa);
924 for (j = 0; j < nlines; j++) {
928 cxdouble lambda = cpl_table_get(_lines,
"WLEN", j, NULL);
933 xccd = giraffe_wlsolution_compute_pixel(solution, lambda, xf, yf,
937 cpl_image_delete(abscissa);
941 if (residuals == TRUE) {
943 cxint cs = cpl_table_get_int(_fibers, idx, i, NULL) - 1;
950 cx_assert(_locy != NULL);
952 if (xccd > 0. && xccd < cpl_image_get_size_y(_locy)) {
956 yccd = _giraffe_get_fiber_position(_locy, cs, xccd);
957 xres = giraffe_wlsolution_compute_residual(solution,
965 data[j * nfibers + i] = xccd;
976 inline static cpl_image *
977 _giraffe_line_ordinate(GiTable *lines,
const GiTable *slitgeometry,
978 const GiWlSolution *solution)
997 _giraffe_line_fit_setup(GiModel *model, cxdouble width, cxint xmin,
998 const cpl_matrix *y,
const cpl_matrix *sigma,
999 const GiLineParams *setup, cxint *lflags)
1006 cxdouble amplitude = 0.;
1007 cxdouble background = 0.;
1008 cxdouble _sigma = 0.;
1010 cpl_matrix *_y = NULL;
1013 cx_assert(model != NULL);
1014 cx_assert(y != NULL);
1015 cx_assert(setup != NULL);
1016 cx_assert(lflags != NULL);
1019 if (*lflags != LF_R_NONE) {
1034 for (k = 0; k < cpl_matrix_get_nrow((cpl_matrix*)y); k++) {
1035 if (cpl_matrix_get((cpl_matrix *)y, k, 0) >= amplitude) {
1038 amplitude = cpl_matrix_get((cpl_matrix *)y, k, 0);
1045 _y = cpl_matrix_duplicate((cpl_matrix *)y);
1049 background = 0.5 * (cpl_matrix_get(_y, 0, 0) + cpl_matrix_get(_y, 1, 0));
1050 cpl_matrix_delete(_y);
1060 _sigma = cpl_matrix_get((cpl_matrix *)sigma, xline, 0) * setup->thres;
1062 if (amplitude <= _sigma || amplitude > setup->satlv) {
1063 *lflags |= LF_R_AMPLI;
1067 giraffe_model_set_parameter(model,
"Amplitude", amplitude - background);
1068 giraffe_model_set_parameter(model,
"Center", center);
1069 giraffe_model_set_parameter(model,
"Background", background);
1070 giraffe_model_set_parameter(model,
"Width1", width);
1072 if (strncmp(giraffe_model_get_name(model),
"psfexp", 6) == 0) {
1074 cxdouble width2 = setup->psfexp < 0. ? -setup->psfexp : setup->psfexp;
1076 giraffe_model_set_parameter(model,
"Width2", width2);
1084 if (setup->psfexp >= 0.) {
1085 giraffe_model_freeze_parameter(model,
"Width2");
1088 giraffe_model_thaw_parameter(model,
"Width2");
1099 _giraffe_line_fit(GiLineData *lines,
const cpl_image *positions, cxint width,
1100 const GiExtraction *extraction,
const GiTable *fibers,
1101 const GiImage *locy,
const GiLineParams *setup)
1104 const cxchar *
const fctid =
"_giraffe_line_fit";
1107 const cxchar *idx = NULL;
1113 const cxdouble LOG2 = log(2.);
1114 const cxdouble fwhm_ratio = 2. * sqrt(2. * LOG2);
1116 cpl_image *_spectra = NULL;
1117 cpl_image *_errors = NULL;
1118 cpl_image *_locy = NULL;
1120 cpl_matrix *x = NULL;
1121 cpl_matrix *y = NULL;
1122 cpl_matrix *sigma = NULL;
1124 cpl_table *_fibers = NULL;
1126 GiModel *model = NULL;
1129 cx_assert(positions != NULL);
1130 cx_assert(width > 0);
1132 cx_assert(extraction != NULL);
1133 cx_assert(extraction->spectra != NULL && extraction->error != NULL);
1135 cx_assert(fibers != NULL);
1136 cx_assert(locy != NULL);
1137 cx_assert(setup != NULL);
1141 cx_assert(_fibers != NULL);
1144 cx_assert(_spectra != NULL);
1147 cx_assert(_errors != NULL);
1150 cx_assert(_locy != NULL);
1152 nfibers = cpl_table_get_nrow(_fibers);
1154 cx_assert(nfibers == cpl_image_get_size_x(_spectra));
1155 cx_assert(nfibers == cpl_image_get_size_x(_errors));
1162 cx_assert(idx != NULL);
1164 nlines = cpl_image_get_size_y(positions);
1171 if (strcmp(setup->model,
"gaussian") != 0 &&
1172 strcmp(setup->model,
"psfexp") != 0 &&
1173 strcmp(setup->model,
"psfexp2") != 0) {
1174 cpl_error_set(fctid, CPL_ERROR_ILLEGAL_INPUT);
1178 model = giraffe_model_new(setup->model);
1180 if (giraffe_model_get_type(model) != GI_MODEL_LINE) {
1181 giraffe_model_delete(model);
1185 giraffe_model_thaw(model);
1187 giraffe_model_set_iterations(model, setup->fit.iterations);
1188 giraffe_model_set_tests(model, setup->fit.tests);
1189 giraffe_model_set_delta(model, setup->fit.delta);
1196 x = cpl_matrix_new(width, 1);
1197 y = cpl_matrix_new(width, 1);
1198 sigma = cpl_matrix_new(width, 1);
1200 for (i = 0; i < nfibers; i++) {
1204 for (j = 0; j < nlines; j++) {
1207 cxint lflags = LF_R_NONE;
1208 cxint iterations = 0;
1212 cxint nx = cpl_image_get_size_y(_spectra);
1216 cxdouble lwidth = 0.;
1217 cxdouble amplitude = 0.;
1218 cxdouble background = 0.;
1219 cxdouble center = 0.;
1220 cxdouble width1 = 0.;
1221 cxdouble exponent = 0.;
1222 cxdouble error = 0.;
1223 cxdouble gwidth = 0.;
1225 const cxdouble *_positions = cpl_image_get_data_const(positions);
1232 xccd = _positions[j * nfibers + i];
1237 if (0 < xccd && xccd < nx) {
1239 cxint cs = cpl_table_get_int(_fibers, idx, i, NULL) - 1;
1247 xmin = (cxint)(xccd - 0.5 * width + 0.5);
1248 xmax = (cxint)(xccd + 0.5 * width + 0.5);
1250 xmin = CX_MAX(CX_MIN(xmin, nx - 1), 0);
1251 xmax = CX_MAX(CX_MIN(xmax, nx - 1), 0);
1253 ndata = xmax - xmin;
1260 yccd = _giraffe_get_fiber_position(_locy, cs, xccd);
1271 lflags |= LF_R_XCCD;
1279 if (ndata != cpl_matrix_get_nrow(x)) {
1280 cpl_matrix_set_size(x, ndata, 1);
1281 cpl_matrix_set_size(y, ndata, 1);
1282 cpl_matrix_set_size(sigma, ndata, 1);
1285 for (k = 0; k < ndata; k++) {
1289 cxdouble *sdata = cpl_image_get_data(_spectra);
1290 cxdouble *edata = cpl_image_get_data(_errors);
1292 cpl_matrix_set(x, k, 0, xmin + k);
1293 cpl_matrix_set(y, k, 0, sdata[l * nfibers + i]);
1294 cpl_matrix_set(sigma, k, 0, edata[l * nfibers + i]);
1311 if (strcmp(setup->model,
"psfexp") == 0) {
1313 exponent = fabs(setup->psfexp);
1315 lwidth = pow(0.5 * setup->grwid * nx, exponent) / LOG2;
1318 else if (strcmp(setup->model,
"psfexp2") == 0) {
1320 exponent = fabs(setup->psfexp);
1322 lwidth = setup->grwid * nx / (2. * pow(LOG2, 1. / exponent));
1325 else if (strcmp(setup->model,
"gaussian") == 0) {
1327 lwidth = setup->grwid * nx / fwhm_ratio;
1336 gi_error(
"Unsupported line model encountered!");
1347 _giraffe_line_fit_setup(model, lwidth, xmin, y, sigma, setup,
1351 if (lflags == LF_R_NONE) {
1353 cxint xline = giraffe_model_get_parameter(model,
"Center");
1355 cxdouble hwidth = 0.;
1364 status = giraffe_model_fit(model, x, y, sigma);
1367 amplitude = giraffe_model_get_parameter(model,
"Amplitude");
1368 background = giraffe_model_get_parameter(model,
"Background");
1369 center = giraffe_model_get_parameter(model,
"Center");
1377 if (strcmp(setup->model,
"psfexp") == 0) {
1379 width1 = giraffe_model_get_parameter(model,
"Width1");
1380 exponent = giraffe_model_get_parameter(model,
"Width2");
1383 gwidth = 2. * pow(width1 * LOG2, 1. / exponent);
1386 else if (strcmp(setup->model,
"psfexp2") == 0) {
1388 width1 = giraffe_model_get_parameter(model,
"Width1");
1389 exponent = giraffe_model_get_parameter(model,
"Width2");
1392 gwidth = 2. * pow(LOG2, 1. / exponent) * width1;
1395 else if (strcmp(setup->model,
"gaussian") == 0) {
1397 width1 = giraffe_model_get_parameter(model,
"Width1");
1400 gwidth = width1 * fwhm_ratio;
1409 gi_error(
"Unsupported line model encountered!");
1413 hwidth = gwidth / 2.;
1414 iterations = giraffe_model_get_position(model);
1425 lflags |= LF_R_ERROR;
1429 if (iterations >= giraffe_model_get_iterations(model)) {
1432 lflags |= LF_R_NITER;
1436 if (xmin > center || center > xmax) {
1439 lflags |= LF_R_CENTR;
1443 if ((center - hwidth) < xmin) {
1446 lflags |= LF_R_LEFT;
1450 if ((center + hwidth) > xmax) {
1453 lflags |= LF_R_RIGHT;
1457 if ((center - xline) >= setup->offst) {
1460 lflags |= LF_R_OFFST;
1464 if (width1 < 0. || exponent < 0.) {
1467 lflags |= LF_R_BADLN;
1471 if (gwidth > (xmax - xmin)) {
1474 lflags |= LF_R_WIDTH;
1478 if (gwidth < (setup->grwid * nx * setup->wfact)) {
1481 lflags |= LF_R_RESOL;
1485 if (gwidth > (setup->grwid * nx / setup->wfact)) {
1488 lflags |= LF_R_RESOL;
1501 giraffe_linedata_set_status(lines, i, j, lflags);
1503 giraffe_linedata_set(lines,
"Iterations", i, j,iterations);
1504 giraffe_linedata_set(lines,
"Chi-square", i, j,
1505 giraffe_model_get_chisq(model));
1506 giraffe_linedata_set(lines,
"DoF", i, j,
1507 giraffe_model_get_df(model));
1508 giraffe_linedata_set(lines,
"R-square", i, j,
1509 giraffe_model_get_rsquare(model));
1510 giraffe_linedata_set(lines,
"Xccd", i, j, xccd);
1511 giraffe_linedata_set(lines,
"Yccd", i, j, yccd);
1521 giraffe_linedata_set(lines,
"Amplitude", i, j, amplitude);
1522 giraffe_linedata_set(lines,
"Background", i, j, background);
1523 giraffe_linedata_set(lines,
"Center", i, j, center);
1524 giraffe_linedata_set(lines,
"Width1", i, j, width1);
1526 if (strncmp(setup->model,
"psfexp", 6) == 0) {
1527 giraffe_linedata_set(lines,
"Width2", i, j, exponent);
1530 giraffe_linedata_set(lines,
"FWHM", i, j, gwidth);
1534 error = giraffe_model_get_sigma(model,
"Amplitude");
1535 giraffe_linedata_set(lines,
"dAmplitude", i, j, error);
1537 error = giraffe_model_get_sigma(model,
"Center");
1538 giraffe_linedata_set(lines,
"dCenter", i, j, error);
1540 error = giraffe_model_get_sigma(model,
"Background");
1541 giraffe_linedata_set(lines,
"dBackground", i, j, error);
1543 error = giraffe_model_get_sigma(model,
"Width1");
1544 giraffe_linedata_set(lines,
"dWidth1", i, j, error);
1546 if (strncmp(setup->model,
"psfexp", 6) == 0) {
1547 error = giraffe_model_get_sigma(model,
"Width2");
1548 giraffe_linedata_set(lines,
"dWidth2", i, j, error);
1555 cpl_matrix_delete(x);
1556 cpl_matrix_delete(y);
1557 cpl_matrix_delete(sigma);
1559 giraffe_model_delete(model);
1566 inline static cpl_image *
1567 _giraffe_psf_fit(GiLineData *lines,
const GiLocalization *localization,
1568 GiTable *fibers, GiTable *slitgeometry, GiSCFitParams *setup)
1571 const cxchar *
const fctid =
"_giraffe_psf_fit";
1578 cxint nsubslits = 1;
1581 cpl_table *_fibers = NULL;
1583 cpl_image *locy = NULL;
1584 cpl_image *locw = NULL;
1585 cpl_image *psfwidth = NULL;
1588 cx_assert(lines != NULL);
1589 cx_assert(localization != NULL);
1590 cx_assert(fibers != NULL);
1591 cx_assert(slitgeometry != NULL);
1592 cx_assert(setup != NULL);
1595 cx_assert(_fibers != NULL);
1598 cx_assert(locy != NULL);
1601 cx_assert(locw != NULL);
1603 nx = cpl_image_get_size_y(locy);
1604 nlines = giraffe_linedata_lines(lines);
1606 psfwidth = cpl_image_new(cpl_table_get_nrow(_fibers), nx,
1609 if (setup->subslits == TRUE) {
1610 nsubslits = _giraffe_subslit_get_max(_fibers);
1613 for (i = 0; i < nsubslits; i++) {
1620 cxint iterations = 0;
1626 cxdouble ratio = 1.;
1628 cpl_matrix *xss = NULL;
1629 cpl_matrix *yss = NULL;
1630 cpl_matrix *wss = NULL;
1631 cpl_matrix *sss = NULL;
1632 cpl_matrix *nss = NULL;
1633 cpl_matrix *lss = NULL;
1634 cpl_matrix *base = NULL;
1635 cpl_matrix *fit = NULL;
1636 cpl_matrix *coeff = NULL;
1637 cpl_matrix *chebyshev = NULL;
1639 cpl_table *subslit = NULL;
1641 GiChebyshev2D *psffit = NULL;
1644 if (setup->subslits == TRUE) {
1645 subslit = _giraffe_subslit_get(_fibers, i + 1);
1646 ssn = cpl_table_get_int(subslit,
"SSN", 0, NULL);
1648 cx_assert(ssn == i + 1);
1651 subslit = cpl_table_duplicate(_fibers);
1655 if (subslit == NULL) {
1659 _giraffe_subslit_range(subslit, locy, locw, &ymin, &ymax);
1661 nfibers = cpl_table_get_nrow(subslit);
1662 ndata = nfibers * nlines;
1665 xss = cpl_matrix_new(ndata, 1);
1666 yss = cpl_matrix_new(ndata, 1);
1667 wss = cpl_matrix_new(1, ndata);
1668 sss = cpl_matrix_new(ndata, 1);
1669 nss = cpl_matrix_new(ndata, 1);
1670 lss = cpl_matrix_new(ndata, 1);
1680 for (j = 0; j < nfibers; j++) {
1683 cxint n = cpl_table_get_int(subslit,
"INDEX", j, NULL) - 1;
1685 for (l = 0; l < nlines; l++) {
1687 cxdouble value = 0.;
1688 cxdouble yccd = giraffe_linedata_get(lines,
"Yccd", n, l);
1690 if (giraffe_linedata_get_status(lines, n, l) != 0) {
1694 if (yccd < ymin || yccd > ymax) {
1698 value = giraffe_linedata_get(lines,
"Xccd", n, l);
1699 cpl_matrix_set(xss, k, 0, value);
1701 cpl_matrix_set(yss, k, 0, yccd);
1710 value = giraffe_linedata_get(lines,
"FWHM", n, l);
1711 cpl_matrix_set(wss, 0, k, value);
1713 value = giraffe_linedata_get(lines,
"dWidth1", n, l);
1714 cpl_matrix_set(sss, k, 0, value);
1716 cpl_matrix_set(nss, k, 0, n);
1717 cpl_matrix_set(lss, k, 0, l);
1726 cpl_msg_debug(fctid,
"Skipping subslit %d: No input lines left! "
1727 "All lines have non-zero status or are beyond the "
1728 "subslit boundaries (%.4f, %.4f).", ssn, ymin, ymax);
1736 cpl_matrix_set_size(xss, k, 1);
1737 cpl_matrix_set_size(yss, k, 1);
1738 cpl_matrix_set_size(wss, 1, k);
1739 cpl_matrix_set_size(sss, k, 1);
1740 cpl_matrix_set_size(nss, k, 1);
1741 cpl_matrix_set_size(lss, k, 1);
1750 accepted = cpl_matrix_get_ncol(wss);
1753 while (accepted > 0 && iterations < setup->clip.iterations &&
1754 ratio > setup->clip.fraction) {
1756 base = giraffe_chebyshev_base2d(0., ymin, nx, ymax - ymin + 1.,
1757 setup->fit.xorder + 1,
1758 setup->fit.yorder + 1, xss, yss);
1760 if (coeff != NULL) {
1761 cpl_matrix_delete(coeff);
1767 if (coeff == NULL) {
1768 cpl_msg_debug(fctid,
"Error solving linear system for "
1769 "subslit %d, skipping subslit.", ssn);
1773 fit = cpl_matrix_product_create(coeff, base);
1777 for (j = 0; j < cpl_matrix_get_ncol(fit); j++) {
1779 cxdouble _fit = cpl_matrix_get(fit, 0, j);
1780 cxdouble _wss = cpl_matrix_get(wss, 0, j);
1781 cxdouble _sss = cpl_matrix_get(sss, j, 0);
1783 if (fabs(_fit - _wss) >= setup->clip.level * _sss) {
1785 cxint n = (cxint)cpl_matrix_get(nss, j, 0);
1786 cxint l = (cxint)cpl_matrix_get(lss, j, 0);
1792 giraffe_linedata_set_status(lines, n, l, LF_R_PSFIT);
1797 cpl_matrix_set(xss, k, 0, cpl_matrix_get(xss, j, 0));
1798 cpl_matrix_set(yss, k, 0, cpl_matrix_get(yss, j, 0));
1799 cpl_matrix_set(wss, 0, k, cpl_matrix_get(wss, 0, j));
1800 cpl_matrix_set(sss, k, 0, cpl_matrix_get(sss, j, 0));
1801 cpl_matrix_set(nss, k, 0, cpl_matrix_get(nss, j, 0));
1802 cpl_matrix_set(lss, k, 0, cpl_matrix_get(lss, j, 0));
1807 cpl_matrix_delete(base);
1808 cpl_matrix_delete(fit);
1810 if (k == accepted) {
1820 ratio = (cxdouble)accepted / (cxdouble)total;
1822 cpl_matrix_set_size(xss, k, 1);
1823 cpl_matrix_set_size(yss, k, 1);
1824 cpl_matrix_set_size(wss, 1, k);
1825 cpl_matrix_set_size(sss, k, 1);
1826 cpl_matrix_set_size(nss, k, 1);
1827 cpl_matrix_set_size(lss, k, 1);
1835 if (accepted == 0) {
1836 cpl_msg_debug(fctid,
"Subslit %d: All lines rejected.", ssn);
1840 if (coeff == NULL) {
1846 cpl_matrix_delete(xss);
1847 cpl_matrix_delete(yss);
1848 cpl_matrix_delete(wss);
1849 cpl_matrix_delete(sss);
1850 cpl_matrix_delete(nss);
1851 cpl_matrix_delete(lss);
1858 xss = cpl_matrix_new(nx * nfibers, 1);
1859 yss = cpl_matrix_new(nx * nfibers, 1);
1861 giraffe_compute_image_coordinates(nx, nfibers, xss, NULL);
1863 for (j = 0; j < cpl_table_get_nrow(subslit); j++) {
1868 cxint ns = cpl_image_get_size_x(locy);
1869 cxint cs = cpl_table_get_int(subslit, idx, j, NULL) - 1;
1871 cxdouble *data = cpl_image_get_data(locy);
1874 for (l = 0; l < nx; l++) {
1875 cpl_matrix_set(yss, l * nfibers + j, 0, data[l * ns + cs]);
1885 base = giraffe_chebyshev_base2d(0., ymin, nx, ymax - ymin + 1.,
1886 setup->fit.xorder + 1,
1887 setup->fit.yorder + 1, xss, yss);
1889 fit = cpl_matrix_product_create(coeff, base);
1891 cpl_matrix_delete(xss);
1894 cpl_matrix_delete(yss);
1907 chebyshev = cpl_matrix_wrap(setup->fit.xorder + 1,
1908 setup->fit.yorder + 1,
1909 cpl_matrix_get_data(coeff));
1911 psffit = giraffe_chebyshev2d_new(setup->fit.xorder, setup->fit.yorder);
1912 status = giraffe_chebyshev2d_set(psffit, 0., nx, ymin, ymax,
1917 giraffe_chebyshev2d_delete(psffit);
1919 cpl_matrix_unwrap(chebyshev);
1921 cpl_matrix_delete(base);
1922 cpl_matrix_delete(coeff);
1923 cpl_matrix_delete(fit);
1925 cpl_table_delete(subslit);
1927 cpl_image_delete(psfwidth);
1933 cpl_matrix_unwrap(chebyshev);
1936 giraffe_chebyshev2d_delete(psffit);
1944 for (j = 0; j < cpl_table_get_nrow(subslit); j++) {
1947 cxint n = cpl_table_get_int(subslit,
"INDEX", j, NULL) - 1;
1948 cxint ns = cpl_table_get_nrow(_fibers);
1950 cxdouble *data = cpl_image_get_data(psfwidth);
1952 for (l = 0; l < nx; l++) {
1953 data[l * ns + n] = cpl_matrix_get(fit, 0, l * nfibers + j);
1958 cpl_matrix_delete(base);
1959 cpl_matrix_delete(coeff);
1960 cpl_matrix_delete(fit);
1962 cpl_table_delete(subslit);
1972 _giraffe_opticalmodel_fit(GiWlSolution *solution, GiLineData *lines,
1973 GiTable *fibers, GiTable *slitgeometry,
1974 GiOpticalModelParams *setup)
1977 const cxchar *
const fctid =
"_giraffe_opticalmodel_fit";
1986 cpl_matrix *x = NULL;
1987 cpl_matrix *y = NULL;
1988 cpl_matrix *sigma = NULL;
1990 cpl_table *_fibers = NULL;
1991 cpl_table *_slitgeometry = NULL;
1993 GiModel *model = NULL;
1996 cx_assert(solution != NULL);
1997 cx_assert(lines != NULL);
1998 cx_assert(fibers != NULL);
1999 cx_assert(slitgeometry != NULL);
2000 cx_assert(setup != NULL);
2003 cx_assert(_fibers != NULL);
2006 cx_assert(_slitgeometry != NULL);
2008 model = giraffe_wlsolution_model(solution);
2015 ndata = giraffe_linedata_lines(lines) * giraffe_linedata_fibers(lines);
2017 x = cpl_matrix_new(ndata, giraffe_model_count_arguments(model));
2018 y = cpl_matrix_new(ndata, 1);
2019 sigma = cpl_matrix_new(ndata, 1);
2021 for (i = 0; i < giraffe_linedata_fibers(lines); i++) {
2025 cxdouble xf = cpl_table_get(_slitgeometry,
"XF", i, NULL);
2026 cxdouble yf = cpl_table_get(_slitgeometry,
"YF", i, NULL);
2029 for (j = 0; j < giraffe_linedata_lines(lines); j++) {
2031 if (giraffe_linedata_get_status(lines, i, j) != 0) {
2038 if (giraffe_linedata_get(lines,
"dCenter", i, j) <= 0.) {
2042 cpl_matrix_set(x, ngood, 0,
2043 giraffe_linedata_get_wavelength(lines, j));
2044 cpl_matrix_set(x, ngood, 1, xf);
2045 cpl_matrix_set(x, ngood, 2, yf);
2047 cpl_matrix_set(y, ngood, 0,
2048 giraffe_linedata_get(lines,
"Center", i, j));
2049 cpl_matrix_set(sigma, ngood, 0,
2050 giraffe_linedata_get(lines,
"dCenter", i, j));
2058 cpl_msg_debug(fctid,
"Using %d of %d line positions for optical "
2059 "model fit.", ngood, ndata);
2063 cpl_matrix_delete(x);
2064 cpl_matrix_delete(y);
2065 cpl_matrix_delete(sigma);
2075 cpl_matrix_set_size(x, ngood, giraffe_model_count_arguments(model));
2076 cpl_matrix_set_size(y, ngood, 1);
2077 cpl_matrix_set_size(sigma, ngood, 1);
2084 giraffe_model_freeze(model);
2086 if (setup->flags & OPTM_FLENGTH) {
2087 giraffe_model_thaw_parameter(model,
"FocalLength");
2090 if (setup->flags & OPTM_GCAMERA) {
2091 giraffe_model_thaw_parameter(model,
"Magnification");
2094 if (setup->flags & OPTM_THETA) {
2095 giraffe_model_thaw_parameter(model,
"Angle");
2098 if (strcmp(giraffe_model_get_name(model),
"xoptmod2") == 0) {
2099 if (setup->flags & OPTM_SX) {
2100 giraffe_model_thaw_parameter(model,
"Sdx");
2103 if (setup->flags & OPTM_SY) {
2104 giraffe_model_thaw_parameter(model,
"Sdy");
2107 if (setup->flags & OPTM_SPHI) {
2108 giraffe_model_thaw_parameter(model,
"Sphi");
2112 giraffe_model_set_iterations(model, setup->fit.iterations);
2113 giraffe_model_set_tests(model, setup->fit.tests);
2114 giraffe_model_set_delta(model, setup->fit.delta);
2121 status = giraffe_model_fit(model, x, y, sigma);
2125 cpl_matrix_delete(x);
2126 cpl_matrix_delete(y);
2127 cpl_matrix_delete(sigma);
2133 cpl_matrix_delete(x);
2134 cpl_matrix_delete(y);
2135 cpl_matrix_delete(sigma);
2143 _giraffe_opticalmodel_format(cx_string *s,
const GiModel *model,
2144 GiOpticalModelInfo info)
2147 const cxchar *name = NULL;
2149 cxbool offsets = FALSE;
2154 cx_assert(s != NULL);
2156 if (model == NULL) {
2160 name = giraffe_model_get_name(model);
2162 if (name == NULL || strncmp(name,
"xoptmod", 7) != 0) {
2166 if (strncmp(name,
"xoptmod2", 8) == 0) {
2173 case GI_OPTM_PARAMETER_VALUES:
2176 cxdouble fcoll = 0.;
2178 cxdouble theta = 0.;
2180 fcoll = giraffe_model_get_parameter(model,
"FocalLength");
2181 gcam = giraffe_model_get_parameter(model,
"Magnification");
2182 theta = giraffe_model_get_parameter(model,
"Angle");
2184 cx_string_sprintf(s,
"focal length = %.6f, camera "
2185 "magnification = %.6f, grating angle = %.9f",
2186 fcoll, gcam, theta);
2188 if (offsets == TRUE) {
2194 cx_string *_s = cx_string_new();
2196 sdx = giraffe_model_get_parameter(model,
"Sdx");
2197 sdy = giraffe_model_get_parameter(model,
"Sdy");
2198 sphi = giraffe_model_get_parameter(model,
"Sphi");
2200 cx_string_sprintf(_s,
", slit x-shift = %.9f, slit "
2201 "y-shift = %.9f, slit rotation = %.9f",
2203 cx_string_append(s, cx_string_get(_s));
2205 cx_string_delete(_s);
2213 case GI_OPTM_PARAMETER_ERRORS:
2216 cxdouble fcoll = 0.;
2218 cxdouble theta = 0.;
2220 fcoll = giraffe_model_get_sigma(model,
"FocalLength");
2221 gcam = giraffe_model_get_sigma(model,
"Magnification");
2222 theta = giraffe_model_get_sigma(model,
"Angle");
2224 cx_string_sprintf(s,
"focal length = %.6f, camera "
2225 "magnification = %.6f, grating angle = %.9f",
2226 fcoll, gcam, theta);
2228 if (offsets == TRUE) {
2234 cx_string *_s = cx_string_new();
2236 sdx = giraffe_model_get_sigma(model,
"Sdx");
2237 sdy = giraffe_model_get_sigma(model,
"Sdy");
2238 sphi = giraffe_model_get_sigma(model,
"Sphi");
2240 cx_string_sprintf(_s,
", slit x-shift = %.9f, slit "
2241 "y-shift = %.9f, slit rotation = %.9f",
2243 cx_string_append(s, cx_string_get(_s));
2245 cx_string_delete(_s);
2253 case GI_OPTM_PARAMETER_STATUS:
2256 const cxchar *
const s_free =
"free";
2257 const cxchar *
const s_frozen =
"frozen";
2258 const cxchar *t = NULL;
2260 cx_string *buffer = cx_string_new();
2263 t = giraffe_model_frozen_parameter(model,
"FocalLength") ?
2265 cx_string_sprintf(buffer,
"focal length = %s", t);
2266 cx_string_set(s, cx_string_get(buffer));
2268 t = giraffe_model_frozen_parameter(model,
"Magnification") ?
2270 cx_string_sprintf(buffer,
", camera magnification = %s", t);
2271 cx_string_append(s, cx_string_get(buffer));
2273 t = giraffe_model_frozen_parameter(model,
"Angle") ?
2275 cx_string_sprintf(buffer,
", grating angle = %s", t);
2276 cx_string_append(s, cx_string_get(buffer));
2279 if (offsets == TRUE) {
2281 t = giraffe_model_frozen_parameter(model,
"Sdx") ?
2283 cx_string_sprintf(buffer,
", slit x-shift = %s", t);
2284 cx_string_append(s, cx_string_get(buffer));
2286 t = giraffe_model_frozen_parameter(model,
"Sdy") ?
2288 cx_string_sprintf(buffer,
", slit y-shift = %s", t);
2289 cx_string_append(s, cx_string_get(buffer));
2291 t = giraffe_model_frozen_parameter(model,
"Sphi") ?
2293 cx_string_sprintf(buffer,
", slit rotation = %s", t);
2294 cx_string_append(s, cx_string_get(buffer));
2298 cx_string_delete(buffer);
2315 inline static cpl_image *
2316 _giraffe_residuals_fit(GiWlResiduals *residuals, GiLineData *lines,
2317 const GiLocalization *localization, GiTable *fibers,
2318 GiTable *slitgeometry, GiSCFitParams *setup)
2321 const cxchar *
const fctid =
"_giraffe_residuals_fit";
2328 cxint nsubslits = 1;
2331 cpl_table *_fibers = NULL;
2333 cpl_image *locy = NULL;
2334 cpl_image *locw = NULL;
2335 cpl_image *xresiduals = NULL;
2338 cx_assert(lines != NULL);
2339 cx_assert(localization != NULL);
2340 cx_assert(fibers != NULL);
2341 cx_assert(slitgeometry != NULL);
2342 cx_assert(setup != NULL);
2345 cx_assert(_fibers != NULL);
2348 cx_assert(locy != NULL);
2351 cx_assert(locw != NULL);
2353 nx = cpl_image_get_size_y(locy);
2354 nlines = giraffe_linedata_lines(lines);
2356 xresiduals = cpl_image_new(cpl_table_get_nrow(_fibers), nx,
2359 if (setup->subslits == TRUE) {
2360 nsubslits = _giraffe_subslit_get_max(_fibers);
2363 for (i = 0; i < nsubslits; i++) {
2370 cxint iterations = 0;
2376 cxdouble ratio = 1.;
2377 cxdouble sigma = 0.;
2379 cpl_matrix *xss = NULL;
2380 cpl_matrix *yss = NULL;
2381 cpl_matrix *rss = NULL;
2382 cpl_matrix *sss = NULL;
2383 cpl_matrix *nss = NULL;
2384 cpl_matrix *lss = NULL;
2385 cpl_matrix *base = NULL;
2386 cpl_matrix *fit = NULL;
2387 cpl_matrix *coeff = NULL;
2388 cpl_matrix *chebyshev = NULL;
2390 cpl_table *subslit = NULL;
2392 GiChebyshev2D *xwsfit = NULL;
2395 if (setup->subslits == TRUE) {
2396 subslit = _giraffe_subslit_get(_fibers, i + 1);
2397 ssn = cpl_table_get_int(subslit,
"SSN", 0, NULL);
2399 cx_assert(ssn == i + 1);
2402 subslit = cpl_table_duplicate(_fibers);
2406 if (subslit == NULL) {
2410 _giraffe_subslit_range(subslit, locy, locw, &ymin, &ymax);
2412 nfibers = cpl_table_get_nrow(subslit);
2413 ndata = nfibers * nlines;
2416 xss = cpl_matrix_new(ndata, 1);
2417 yss = cpl_matrix_new(ndata, 1);
2418 rss = cpl_matrix_new(1, ndata);
2419 sss = cpl_matrix_new(ndata, 1);
2420 nss = cpl_matrix_new(ndata, 1);
2421 lss = cpl_matrix_new(ndata, 1);
2431 for (j = 0; j < nfibers; j++) {
2434 cxint n = cpl_table_get_int(subslit,
"INDEX", j, NULL) - 1;
2436 for (l = 0; l < nlines; l++) {
2438 cxdouble value = 0.;
2439 cxdouble xccd = giraffe_linedata_get(lines,
"Xccd", n, l);
2440 cxdouble yccd = giraffe_linedata_get(lines,
"Yccd", n, l);
2442 if (giraffe_linedata_get_status(lines, n, l) != 0) {
2446 if (yccd < ymin || yccd > ymax) {
2450 cpl_matrix_set(xss, k, 0, xccd);
2451 cpl_matrix_set(yss, k, 0, yccd);
2453 value = xccd - giraffe_linedata_get(lines,
"Center", n, l);
2455 cpl_matrix_set(rss, 0, k, value);
2456 giraffe_linedata_set(lines,
"Xoff", n, l, value);
2458 value = giraffe_linedata_get(lines,
"dCenter", n, l);
2459 cpl_matrix_set(sss, k, 0, value);
2461 cpl_matrix_set(nss, k, 0, n);
2462 cpl_matrix_set(lss, k, 0, l);
2471 cpl_msg_debug(fctid,
"Skipping subslit %d: No input lines left! "
2472 "All lines have non-zero status or are beyond the "
2473 "subslit boundaries (%.4f, %.4f).", ssn, ymin, ymax);
2481 cpl_matrix_set_size(xss, k, 1);
2482 cpl_matrix_set_size(yss, k, 1);
2483 cpl_matrix_set_size(rss, 1, k);
2484 cpl_matrix_set_size(sss, k, 1);
2485 cpl_matrix_set_size(nss, k, 1);
2486 cpl_matrix_set_size(lss, k, 1);
2494 sigma = cpl_matrix_get_median(sss);
2503 accepted = cpl_matrix_get_ncol(rss);
2506 while (accepted > 0 && iterations < setup->clip.iterations &&
2507 ratio > setup->clip.fraction) {
2509 base = giraffe_chebyshev_base2d(0., ymin, nx, ymax - ymin + 1.,
2510 setup->fit.xorder + 1,
2511 setup->fit.yorder + 1, xss, yss);
2513 if (coeff != NULL) {
2514 cpl_matrix_delete(coeff);
2520 if (coeff == NULL) {
2521 cpl_msg_debug(fctid,
"Error solving linear system for "
2522 "subslit %d, skipping subslit.", ssn);
2526 fit = cpl_matrix_product_create(coeff, base);
2530 for (j = 0; j < cpl_matrix_get_ncol(fit); j++) {
2532 cxdouble _fit = cpl_matrix_get(fit, 0, j);
2533 cxdouble _rss = cpl_matrix_get(rss, 0, j);
2535 if (fabs(_fit - _rss) >= setup->clip.level * sigma) {
2537 cxint n = (cxint)cpl_matrix_get(nss, j, 0);
2538 cxint l = (cxint)cpl_matrix_get(lss, j, 0);
2544 giraffe_linedata_set_status(lines, n, l, LF_R_XRFIT);
2549 cpl_matrix_set(xss, k, 0, cpl_matrix_get(xss, j, 0));
2550 cpl_matrix_set(yss, k, 0, cpl_matrix_get(yss, j, 0));
2551 cpl_matrix_set(rss, 0, k, cpl_matrix_get(rss, 0, j));
2552 cpl_matrix_set(sss, k, 0, cpl_matrix_get(sss, j, 0));
2553 cpl_matrix_set(nss, k, 0, cpl_matrix_get(nss, j, 0));
2554 cpl_matrix_set(lss, k, 0, cpl_matrix_get(lss, j, 0));
2559 cpl_matrix_delete(base);
2560 cpl_matrix_delete(fit);
2562 if (k == accepted) {
2572 ratio = (cxdouble)accepted / (cxdouble)total;
2574 cpl_matrix_set_size(xss, k, 1);
2575 cpl_matrix_set_size(yss, k, 1);
2576 cpl_matrix_set_size(rss, 1, k);
2577 cpl_matrix_set_size(sss, k, 1);
2578 cpl_matrix_set_size(nss, k, 1);
2579 cpl_matrix_set_size(lss, k, 1);
2587 if (accepted == 0) {
2588 cpl_msg_debug(fctid,
"Subslit %d: All lines rejected.", ssn);
2592 if (coeff == NULL) {
2598 cpl_matrix_delete(xss);
2599 cpl_matrix_delete(yss);
2600 cpl_matrix_delete(rss);
2601 cpl_matrix_delete(sss);
2602 cpl_matrix_delete(nss);
2603 cpl_matrix_delete(lss);
2610 xss = cpl_matrix_new(nx * nfibers, 1);
2611 yss = cpl_matrix_new(nx * nfibers, 1);
2613 giraffe_compute_image_coordinates(nx, nfibers, xss, NULL);
2615 for (j = 0; j < cpl_table_get_nrow(subslit); j++) {
2620 cxint ns = cpl_image_get_size_x(locy);
2621 cxint cs = cpl_table_get_int(subslit, idx, j, NULL) - 1;
2623 cxdouble *data = cpl_image_get_data(locy);
2626 for (l = 0; l < nx; l++) {
2627 cpl_matrix_set(yss, l * nfibers + j, 0, data[l * ns + cs]);
2637 base = giraffe_chebyshev_base2d(0., ymin, nx, ymax - ymin + 1.,
2638 setup->fit.xorder + 1,
2639 setup->fit.yorder + 1, xss, yss);
2641 fit = cpl_matrix_product_create(coeff, base);
2643 cpl_matrix_delete(xss);
2646 cpl_matrix_delete(yss);
2661 chebyshev = cpl_matrix_wrap(setup->fit.xorder + 1,
2662 setup->fit.yorder + 1,
2663 cpl_matrix_get_data(coeff));
2665 xwsfit = giraffe_chebyshev2d_new(setup->fit.xorder, setup->fit.yorder);
2666 status = giraffe_chebyshev2d_set(xwsfit, 0., nx, ymin, ymax,
2671 giraffe_chebyshev2d_delete(xwsfit);
2673 cpl_matrix_unwrap(chebyshev);
2675 cpl_matrix_delete(base);
2676 cpl_matrix_delete(coeff);
2677 cpl_matrix_delete(fit);
2679 cpl_table_delete(subslit);
2681 cpl_image_delete(xresiduals);
2687 cpl_matrix_unwrap(chebyshev);
2690 giraffe_wlresiduals_set(residuals, ssn, xwsfit);
2698 for (j = 0; j < cpl_table_get_nrow(subslit); j++) {
2701 cxint n = cpl_table_get_int(subslit,
"INDEX", j, NULL) - 1;
2702 cxint ns = cpl_table_get_nrow(_fibers);
2704 cxdouble *data = cpl_image_get_data(xresiduals);
2706 for (l = 0; l < nx; l++) {
2707 data[l * ns + n] = cpl_matrix_get(fit, 0, l * nfibers + j);
2712 cpl_matrix_delete(base);
2713 cpl_matrix_delete(coeff);
2714 cpl_matrix_delete(fit);
2716 cpl_table_delete(subslit);
2725 inline static cxdouble
2726 _giraffe_compute_statistics(
const GiLineData *lines,
const cpl_image *xwsfit,
2727 const cpl_image *lflags)
2738 cpl_image *xccd = NULL;
2741 cx_assert(lines != NULL);
2744 nlines = giraffe_linedata_lines(lines);
2745 nfibers = giraffe_linedata_fibers(lines);
2747 xccd = cpl_image_duplicate(giraffe_linedata_get_data(lines,
"Xccd"));
2749 if (xwsfit != NULL) {
2751 cpl_image *residuals = NULL;
2754 cx_assert(lflags != NULL);
2756 residuals = cpl_image_new(giraffe_linedata_fibers(lines),
2757 giraffe_linedata_lines(lines),
2760 _giraffe_get_residuals(residuals, xccd, xwsfit);
2761 _giraffe_apply_residuals(xccd, residuals, lflags, 0.);
2763 cpl_image_delete(residuals);
2768 _xccd = cpl_image_get_data(xccd);
2770 for (i = 0; i < nfibers; i++) {
2774 for (j = 0; j < nlines; j++) {
2776 if (giraffe_linedata_get_status(lines, i, j) == LF_R_NONE) {
2778 cxdouble center = giraffe_linedata_get(lines,
"Center", i, j);
2780 sum += pow(center - _xccd[j * nfibers + i], 2.);
2788 cpl_image_delete(xccd);
2790 rms = sqrt(sum / CX_MAX(giraffe_linedata_accepted(lines), 1.));
2798 _giraffe_convert_wlsolution(GiTable *result,
const GiWlSolution *solution,
2799 const GiImage *spectra,
const GiGrating *setup,
2807 cxdouble value = 0.;
2808 cxdouble scale = 0.;
2809 cxdouble xccd[2] = {0., 0.};
2811 cx_string *s = NULL;
2813 cpl_propertylist *properties = NULL;
2815 cpl_table *coeffs = NULL;
2817 const GiModel *model = NULL;
2819 const GiWlResiduals *residuals = NULL;
2822 cx_assert(result != NULL);
2823 cx_assert(solution != NULL);
2825 s = cx_string_new();
2834 cpl_propertylist_erase(properties,
"NAXIS1");
2835 cpl_propertylist_erase(properties,
"NAXIS2");
2836 cpl_propertylist_erase(properties, GIALIAS_DATAMIN);
2837 cpl_propertylist_erase(properties, GIALIAS_DATAMAX);
2838 cpl_propertylist_erase(properties, GIALIAS_EXTNAME);
2840 cpl_propertylist_erase(properties, GIALIAS_PROCATG);
2841 cpl_propertylist_erase(properties, GIALIAS_PROTYPE);
2842 cpl_propertylist_erase(properties, GIALIAS_DATAMEAN);
2843 cpl_propertylist_erase(properties, GIALIAS_DATAMEDI);
2844 cpl_propertylist_erase(properties, GIALIAS_DATASIG);
2846 cpl_propertylist_update_string(properties, GIALIAS_GIRFTYPE,
2848 cpl_propertylist_set_comment(properties, GIALIAS_GIRFTYPE,
2849 "Giraffe frame type.");
2873 cpl_propertylist_update_string(properties, GIALIAS_WSOL_LMNAME,
2875 cpl_propertylist_set_comment(properties, GIALIAS_WSOL_LMNAME,
2876 "Line profile model");
2878 cpl_propertylist_update_bool(properties, GIALIAS_WSOL_LMRES, info->residuals);
2879 cpl_propertylist_set_comment(properties, GIALIAS_WSOL_LMRES,
2880 "Line detection optical model residuals flag");
2882 cpl_propertylist_update_int(properties, GIALIAS_WSOL_LMWIDTH, info->width);
2883 cpl_propertylist_set_comment(properties, GIALIAS_WSOL_LMWIDTH,
2884 "Line detection window size [pxl]");
2886 cpl_propertylist_update_double(properties, GIALIAS_WSOL_LMTHRESH,
2888 cpl_propertylist_set_comment(properties, GIALIAS_WSOL_LMTHRESH,
2889 "Calibration line threshold");
2891 cpl_propertylist_update_int(properties, GIALIAS_WSOL_LMITER,
2893 cpl_propertylist_set_comment(properties, GIALIAS_WSOL_LMITER,
2894 "Line profile fit maximum number "
2897 cpl_propertylist_update_int(properties, GIALIAS_WSOL_LMTEST,
2899 cpl_propertylist_set_comment(properties, GIALIAS_WSOL_LMTEST,
2900 "Line profile fit maximum number "
2901 "of chi-square tests");
2903 cpl_propertylist_update_double(properties, GIALIAS_WSOL_LMDCHISQ,
2905 cpl_propertylist_set_comment(properties, GIALIAS_WSOL_LMDCHISQ,
2906 "Line profile fit minimum delta "
2916 cpl_propertylist_update_string(properties, GIALIAS_WSOL_PWORDER,
2918 cpl_propertylist_set_comment(properties, GIALIAS_WSOL_PWORDER,
2919 "PSF width fit polynomial order");
2921 cpl_propertylist_update_double(properties, GIALIAS_WSOL_PWSIGMA,
2923 cpl_propertylist_set_comment(properties, GIALIAS_WSOL_PWSIGMA,
2924 "PSF width fit sigma clipping level");
2926 cpl_propertylist_update_int(properties, GIALIAS_WSOL_PWITER,
2928 cpl_propertylist_set_comment(properties, GIALIAS_WSOL_PWITER,
2929 "PSF width fit maximum number of "
2932 cpl_propertylist_update_double(properties, GIALIAS_WSOL_PWFRAC,
2934 cpl_propertylist_set_comment(properties, GIALIAS_WSOL_PWFRAC,
2935 "PSF width fit minimum fraction of "
2943 cpl_propertylist_update_bool(properties, GIALIAS_WSOL_OMFIT,
2945 cpl_propertylist_set_comment(properties, GIALIAS_WSOL_OMFIT,
2946 "Optical model fit flag");
2948 cpl_propertylist_update_string(properties, GIALIAS_WSOL_OMNAME,
2949 giraffe_wlsolution_name(solution));
2950 cpl_propertylist_set_comment(properties, GIALIAS_WSOL_OMNAME,
2951 "Optical model name");
2953 model = giraffe_wlsolution_model(solution);
2955 sign = giraffe_model_get_parameter(model,
"Orientation") < 0 ? -1 : 1;
2956 cpl_propertylist_update_int(properties, GIALIAS_WSOL_OMDIR, sign);
2957 cpl_propertylist_set_comment(properties, GIALIAS_WSOL_OMDIR,
2958 "Optical model orientation");
2960 value = giraffe_model_get_parameter(model,
"FocalLength");
2961 cpl_propertylist_update_double(properties, GIALIAS_WSOL_OMFCOLL, value);
2962 cpl_propertylist_set_comment(properties, GIALIAS_WSOL_OMFCOLL,
2963 "Optical model focal length");
2965 value = giraffe_model_get_parameter(model,
"Magnification");
2966 cpl_propertylist_update_double(properties, GIALIAS_WSOL_OMGCAM, value);
2967 cpl_propertylist_set_comment(properties, GIALIAS_WSOL_OMGCAM,
2968 "Optical model camera factor");
2970 value = giraffe_model_get_parameter(model,
"Angle");
2971 cpl_propertylist_update_double(properties, GIALIAS_WSOL_OMGTHETA, value);
2972 cpl_propertylist_set_comment(properties, GIALIAS_WSOL_OMGTHETA,
2973 "Optical model grating angle");
2975 if (strcmp(giraffe_wlsolution_name(solution),
"xoptmod2") == 0) {
2977 value = giraffe_model_get_parameter(model,
"Sdx");
2978 cpl_propertylist_update_double(properties, GIALIAS_WSOL_OMSDX, value);
2979 cpl_propertylist_set_comment(properties, GIALIAS_WSOL_OMSDX,
2980 "Optical model slit x-offset");
2982 value = giraffe_model_get_parameter(model,
"Sdy");
2983 cpl_propertylist_update_double(properties, GIALIAS_WSOL_OMSDY, value);
2984 cpl_propertylist_set_comment(properties, GIALIAS_WSOL_OMSDY,
2985 "Optical model slit y-offset");
2987 value = giraffe_model_get_parameter(model,
"Sphi");
2988 cpl_propertylist_update_double(properties, GIALIAS_WSOL_OMSPHI, value);
2989 cpl_propertylist_set_comment(properties, GIALIAS_WSOL_OMSPHI,
2990 "Optical model slit rotation");
3000 residuals = giraffe_wlsolution_get_residuals(solution);
3002 cpl_propertylist_update_bool(properties, GIALIAS_WSOL_SUBSLITS,
3003 giraffe_wlsolution_get_subslits(solution));
3004 cpl_propertylist_set_comment(properties, GIALIAS_WSOL_SUBSLITS,
3005 "Subslit fit flag");
3008 cpl_propertylist_update_int(properties, GIALIAS_WSOL_XRSSN,
3009 giraffe_wlresiduals_get_size(residuals));
3010 cpl_propertylist_set_comment(properties, GIALIAS_WSOL_XRSSN,
3011 "Number of subslits");
3016 cpl_propertylist_update_string(properties, GIALIAS_WSOL_XRORDER,
3018 cpl_propertylist_set_comment(properties, GIALIAS_WSOL_XRORDER,
3019 "Residual fit polynomial order");
3022 cpl_propertylist_update_double(properties, GIALIAS_WSOL_XRSIGMA,
3024 cpl_propertylist_set_comment(properties, GIALIAS_WSOL_XRSIGMA,
3025 "Residual fit sigma clipping level");
3027 cpl_propertylist_update_int(properties, GIALIAS_WSOL_XRITER,
3029 cpl_propertylist_set_comment(properties, GIALIAS_WSOL_XRITER,
3030 "Residual fit maximum number of "
3033 cpl_propertylist_update_double(properties, GIALIAS_WSOL_XRFRAC,
3035 cpl_propertylist_set_comment(properties, GIALIAS_WSOL_XRFRAC,
3036 "Residual fit minimum fraction of "
3039 cpl_propertylist_update_int(properties, GIALIAS_WSOL_NLINES,
3041 cpl_propertylist_set_comment(properties, GIALIAS_WSOL_NLINES,
3042 "Number of calibration lines used.");
3044 cpl_propertylist_update_int(properties, GIALIAS_WSOL_NACCEPT,
3046 cpl_propertylist_set_comment(properties, GIALIAS_WSOL_NACCEPT,
3047 "Number of accepted lines");
3049 cpl_propertylist_update_int(properties, GIALIAS_WSOL_NREJECT,
3051 cpl_propertylist_set_comment(properties, GIALIAS_WSOL_NREJECT,
3052 "Number of rejected lines");
3054 cpl_propertylist_update_double(properties, GIALIAS_WSOL_RMS,
3056 cpl_propertylist_set_comment(properties, GIALIAS_WSOL_RMS,
3057 "Average RMS [pxl] of fitted line "
3066 xccd[0] = giraffe_wlsolution_compute_pixel(solution, setup->
wlenmin,
3068 xccd[1] = giraffe_wlsolution_compute_pixel(solution, setup->
wlenmax,
3074 cpl_propertylist_update_double(properties, GIALIAS_WSOL_WLMIN,
3076 cpl_propertylist_set_comment(properties, GIALIAS_WSOL_WLMIN,
3077 "Wavelength solution minimum wavelength");
3079 cpl_propertylist_update_double(properties, GIALIAS_WSOL_WLMAX,
3081 cpl_propertylist_set_comment(properties, GIALIAS_WSOL_WLMAX,
3082 "Wavelength solution maximum wavelength");
3084 cpl_propertylist_update_double(properties, GIALIAS_WSOL_SCALE, scale);
3085 cpl_propertylist_set_comment(properties, GIALIAS_WSOL_SCALE,
3086 "Approximate wavelength scale [nm/pxl]");
3089 cx_string_delete(s);
3097 for (i = 0; (cxsize)i < giraffe_wlresiduals_get_size(residuals); i++) {
3099 const GiChebyshev2D *fit = giraffe_wlresiduals_get(residuals, i);
3108 giraffe_chebyshev2d_get_order(fit, &xorder, &yorder);
3112 gi_error(
"Invalid wavelength solution. Inconsistent residual "
3113 "fit polynomial order!");
3126 coeffs = giraffe_wlresiduals_table(residuals);
3128 if (coeffs == NULL) {
3129 cpl_propertylist_delete(properties);
3134 cpl_propertylist_delete(properties);
3139 cpl_table_delete(coeffs);
3148 giraffe_wcaldata_new(
void)
3151 GiWCalData *
self = cx_calloc(1,
sizeof *
self);
3153 self->coeffs = NULL;
3155 self->linedata = NULL;
3163 giraffe_wcaldata_delete(GiWCalData *
self)
3170 self->coeffs = NULL;
3178 if (self->linedata) {
3179 giraffe_linedata_delete(self->linedata);
3180 self->linedata = NULL;
3215 GiLocalization *localization, GiTable *fibers,
3216 GiTable *slitgeometry, GiTable *grating,
3217 GiTable *lines, GiTable *initial,
3221 const cxchar *fctid =
"giraffe_calibrate_wavelength";
3224 cxbool residuals = FALSE;
3233 cpl_image *psf_fit = NULL;
3234 cpl_image *xws_fit = NULL;
3236 GiTable *tsolution = NULL;
3240 GiSCFitParams psf_setup;
3241 GiSCFitParams xws_setup;
3243 GiLineParams *line_setup = NULL;
3245 GiLineData *line_data = NULL;
3247 GiWlSolution *solution = NULL;
3252 if (extraction == NULL) {
3256 if (extraction->spectra == NULL || extraction->error == NULL) {
3261 if (fibers == NULL) {
3265 if (slitgeometry == NULL) {
3269 if (grating == NULL) {
3273 if (lines == NULL) {
3284 if (setup == NULL) {
3285 cpl_msg_error(fctid,
"Cannot initialize grating setup parameters!");
3303 cpl_msg_info(fctid,
"Setting initial slit offsets: x-shift = %.9f, "
3304 "y-shift = %.9f, rotation = %.9f", setup->
sdx,
3319 line_setup = _giraffe_lineparams_create(GI_LINETYPE_THARNE, setup,
3322 if (line_setup == NULL) {
3323 cpl_msg_error(fctid,
"Cannot initialize line fit setup parameters!");
3335 if (initial == NULL) {
3338 cxdouble pixelsize = 0.;
3340 cpl_propertylist *properties = NULL;
3342 cpl_image *spectra = NULL;
3346 cx_assert(properties != NULL);
3349 cx_assert(spectra != NULL);
3351 pixelsize = cpl_propertylist_get_double(properties, GIALIAS_PIXSIZY);
3352 npixel = cpl_image_get_size_y(spectra);
3354 solution = giraffe_wlsolution_new(config->
opt_model,
3358 if (solution == NULL) {
3359 cpl_msg_error(fctid,
"Cannot initialize initial wavelength "
3364 _giraffe_lineparams_delete(line_setup);
3372 const cpl_propertylist* _properties =
3391 if (cpl_propertylist_has(_properties, GIALIAS_WSOL_WLMIN) == TRUE) {
3393 setup->
wlenmin = cpl_propertylist_get_double(_properties,
3394 GIALIAS_WSOL_WLMIN);
3396 cpl_msg_debug(fctid,
"Using minimum wavelength %.2f from "
3397 "initial solution", setup->
wlenmin);
3401 if (cpl_propertylist_has(_properties, GIALIAS_WSOL_WLMAX) == TRUE) {
3403 setup->
wlenmax = cpl_propertylist_get_double(_properties,
3404 GIALIAS_WSOL_WLMAX);
3406 cpl_msg_debug(fctid,
"Using maximum wavelength %.2f from "
3407 "initial solution", setup->
wlenmax);
3413 giraffe_wlsolution_set_subslits(solution, config->
opt_subslits);
3416 cpl_msg_info(fctid,
"Computing line positions on the CCD using "
3417 "model `%s'", giraffe_wlsolution_name(solution));
3426 if (giraffe_wlsolution_get_residuals(solution) == NULL) {
3428 cpl_msg_error(fctid,
"Initial wavelength solution does not "
3429 "provide optical model residuals!");
3433 _giraffe_lineparams_delete(line_setup);
3435 giraffe_wlsolution_delete(solution);
3447 residuals = giraffe_wlsolution_get_residuals(solution) != NULL;
3449 if (residuals == TRUE) {
3450 cpl_msg_info(fctid,
"Using wavelength solution residuals when "
3451 "computing line positions.");
3466 status = _giraffe_linelist_setup(lines, setup, config);
3469 cpl_msg_error(fctid,
"Line list creation failed!");
3473 _giraffe_lineparams_delete(line_setup);
3475 giraffe_wlsolution_delete(solution);
3481 cpl_msg_info(fctid,
"%d lines have been selected from the line list.",
3489 line_data = giraffe_linedata_new();
3498 cpl_table *_lines = NULL;
3501 cpl_image *xccd = NULL;
3502 cpl_image *xres = NULL;
3503 cpl_image *line_status = NULL;
3505 GiWlResiduals *xws_coeffs = NULL;
3511 cpl_msg_info(fctid,
"Current search window width: %d pxl", width);
3512 cpl_msg_info(fctid,
"Applying crowding criterium to line list.");
3514 _lines = _giraffe_linelist_select(lines, extraction->spectra, setup,
3516 if (_lines == NULL) {
3517 cpl_msg_error(fctid,
"Removing crowded lines from line list "
3518 "for search window width %d pxl failed!", width);
3522 _giraffe_lineparams_delete(line_setup);
3524 giraffe_wlsolution_delete(solution);
3529 _nlines = cpl_table_get_nrow(_lines);
3532 cpl_msg_info(fctid,
"%d lines used for fit. %d of %d lines rejected "
3533 "due to crowding.", _nlines, nlines - _nlines, nlines);
3535 cpl_msg_info(fctid,
"%d lines used for fit. %d of %d lines "
3536 "rejected due to crowding and line quality.",
3537 _nlines, nlines - _nlines, nlines);
3545 xccd = _giraffe_line_abscissa(_lines, slitgeometry, fibers,
3546 solution, localization, residuals);
3548 _nfibers = cpl_image_get_size_x(xccd);
3549 _nlines = cpl_image_get_size_y(xccd);
3556 cpl_msg_info(fctid,
"Fitting %d line profiles for %d spectra using "
3557 "line model `%s'", _nlines, _nfibers , line_setup->model);
3559 cpl_msg_info(fctid,
"Total number of lines to fit: %d (%d x %d)",
3560 _nlines * _nfibers, _nfibers, _nlines);
3563 status = giraffe_linedata_reset(line_data, _lines, _fibers,
3568 cpl_msg_error(fctid,
"Line profile fit failed!");
3570 cpl_image_delete(xccd);
3572 cpl_table_delete(_lines);
3573 giraffe_linedata_delete(line_data);
3577 _giraffe_lineparams_delete(line_setup);
3579 giraffe_wlsolution_delete(solution);
3585 status = _giraffe_line_fit(line_data, xccd, width, extraction, fibers,
3586 localization->locy, line_setup);
3590 cpl_msg_error(fctid,
"Line profile fit failed!");
3592 cpl_image_delete(xccd);
3594 cpl_table_delete(_lines);
3595 giraffe_linedata_delete(line_data);
3599 _giraffe_lineparams_delete(line_setup);
3601 giraffe_wlsolution_delete(solution);
3607 cpl_image_delete(xccd);
3610 if (giraffe_linedata_accepted(line_data) == 0) {
3611 cpl_msg_error(fctid,
"No lines left after line profile fit!");
3613 cpl_table_delete(_lines);
3614 giraffe_linedata_delete(line_data);
3618 _giraffe_lineparams_delete(line_setup);
3620 giraffe_wlsolution_delete(solution);
3626 _nreject = giraffe_linedata_rejected(line_data);
3627 _ngood = giraffe_linedata_accepted(line_data);
3629 cpl_msg_info(fctid,
"Number of good lines: %d. %d of %d lines "
3630 "rejected due to line profile fit.", _ngood, _nreject,
3637 line_status = giraffe_linedata_status(line_data);
3644 cpl_msg_info(fctid,
"Fit of the line profile PSF width variation.");
3646 psf_setup.subslits = giraffe_wlsolution_get_subslits(solution);
3650 cpl_msg_info(fctid,
"Chebyshev polynomial order is (%d, %d).",
3651 psf_setup.fit.xorder, psf_setup.fit.yorder);
3657 cpl_msg_info(fctid,
"Sigma clipping: iterations = %d, level = %.4f, "
3658 "fraction = %.4f", psf_setup.clip.iterations,
3659 psf_setup.clip.level, psf_setup.clip.fraction);
3662 psf_fit = _giraffe_psf_fit(line_data, localization, fibers,
3663 slitgeometry, &psf_setup);
3666 if (psf_fit == NULL) {
3668 cpl_msg_error(fctid,
"Fit of the line profile PSF width "
3669 "variation failed!");
3671 cpl_table_delete(_lines);
3672 cpl_image_delete(line_status);
3673 giraffe_linedata_delete(line_data);
3677 _giraffe_lineparams_delete(line_setup);
3679 giraffe_wlsolution_delete(solution);
3690 cpl_image_delete(psf_fit);
3694 if (giraffe_linedata_accepted(line_data) == 0) {
3695 cpl_msg_error(fctid,
"No lines left after line profile PSF "
3698 cpl_table_delete(_lines);
3699 cpl_image_delete(line_status);
3700 giraffe_linedata_delete(line_data);
3704 _giraffe_lineparams_delete(line_setup);
3706 giraffe_wlsolution_delete(solution);
3712 cpl_msg_info(fctid,
"Number of good lines: %"
3713 CX_PRINTF_FORMAT_SIZE_TYPE
". %"
3714 CX_PRINTF_FORMAT_SIZE_TYPE
" of %d lines "
3715 "rejected due to line profile PSF width fit.",
3716 giraffe_linedata_accepted(line_data),
3717 giraffe_linedata_rejected(line_data) - _nreject, _ngood);
3719 _ngood = giraffe_linedata_accepted(line_data);
3720 _nreject = giraffe_linedata_rejected(line_data);
3730 cxint iterations = 0;
3733 cxdouble chisq = 0.;
3734 cxdouble rsquare = 0.;
3736 cx_string *s = NULL;
3738 GiOpticalModelParams om_setup;
3740 GiModel *guess = NULL;
3741 GiModel *model = giraffe_wlsolution_model(solution);
3748 guess = giraffe_model_clone(model);
3750 om_setup.fit.iterations = config->
opt_niter;
3755 cpl_msg_info(fctid,
"Optical model fit setup: iterations = %d, "
3756 "tests = %d, delta = %.4f", om_setup.fit.iterations,
3757 om_setup.fit.tests, om_setup.fit.delta);
3759 status = _giraffe_opticalmodel_fit(solution, line_data, fibers,
3760 slitgeometry, &om_setup);
3763 cpl_msg_error(fctid,
"Optical model fit failed!");
3765 giraffe_model_delete(guess);
3767 cpl_table_delete(_lines);
3768 cpl_image_delete(line_status);
3769 giraffe_linedata_delete(line_data);
3773 _giraffe_lineparams_delete(line_setup);
3775 giraffe_wlsolution_delete(solution);
3786 cpl_msg_info(fctid,
"Optical model parameters:");
3788 s = cx_string_new();
3790 _giraffe_opticalmodel_format(s, guess, GI_OPTM_PARAMETER_VALUES);
3791 cpl_msg_info(fctid,
"Initial: %s", cx_string_get(s));
3793 _giraffe_opticalmodel_format(s, model, GI_OPTM_PARAMETER_VALUES);
3794 cpl_msg_info(fctid,
" Fitted: %s", cx_string_get(s));
3796 _giraffe_opticalmodel_format(s, model, GI_OPTM_PARAMETER_ERRORS);
3797 cpl_msg_info(fctid,
" Sigma: %s", cx_string_get(s));
3799 _giraffe_opticalmodel_format(s, model, GI_OPTM_PARAMETER_STATUS);
3800 cpl_msg_info(fctid,
" Status: %s", cx_string_get(s));
3802 cx_string_delete(s);
3806 if (strcmp(giraffe_model_get_name(model),
"xoptmod2") == 0) {
3808 cxdouble flength = 0.;
3813 cx_string *s = cx_string_new();
3816 flength = giraffe_model_get_parameter(guess,
"FocalLength");
3817 sdx = giraffe_model_get_parameter(guess,
"Sdx");
3818 sdy = giraffe_model_get_parameter(guess,
"Sdy");
3819 sphi = giraffe_model_get_parameter(guess,
"Sphi");
3821 cx_string_sprintf(s,
"Initial: focal length = %.6f, slit "
3822 "x-shift = %.9f, slit y-shift = %.9f, "
3823 "slit rotation = %.9f", flength, sdx, sdy,
3825 cpl_msg_info(fctid,
"%s", cx_string_get(s));
3828 flength = giraffe_model_get_parameter(model,
"FocalLength");
3829 sdx = giraffe_model_get_parameter(model,
"Sdx");
3830 sdy = giraffe_model_get_parameter(model,
"Sdy");
3831 sphi = giraffe_model_get_parameter(model,
"Sphi");
3833 cx_string_sprintf(s,
" Fitted: focal length = %.6f, slit "
3834 "x-shift = %.9f, slit y-shift = %.9f, "
3835 "slit rotation = %.9f", flength, sdx, sdy,
3837 cpl_msg_info(fctid,
"%s", cx_string_get(s));
3840 flength = giraffe_model_get_sigma(model,
"FocalLength");
3841 sdx = giraffe_model_get_sigma(model,
"Sdx");
3842 sdy = giraffe_model_get_sigma(model,
"Sdy");
3843 sphi = giraffe_model_get_sigma(model,
"Sphi");
3845 cx_string_sprintf(s,
" Sigma: focal length = %.6f, slit "
3846 "x-shift = %.9f, slit y-shift = %.9f, "
3847 "slit rotation = %.9f", flength, sdx, sdy,
3849 cpl_msg_info(fctid,
"%s", cx_string_get(s));
3851 cx_string_delete(s);
3856 cxdouble flength = 0.;
3858 cx_string *s = cx_string_new();
3861 flength = giraffe_model_get_parameter(guess,
"FocalLength");
3863 cx_string_sprintf(s,
"Initial: focal length = %.6f", flength);
3864 cpl_msg_info(fctid,
"%s", cx_string_get(s));
3867 flength = giraffe_model_get_parameter(model,
"FocalLength");
3869 cx_string_sprintf(s,
" Fitted: focal length = %.6f", flength);
3870 cpl_msg_info(fctid,
"%s", cx_string_get(s));
3873 flength = giraffe_model_get_sigma(model,
"FocalLength");
3875 cx_string_sprintf(s,
" Sigma: focal length = %.6f", flength);
3876 cpl_msg_info(fctid,
"%s", cx_string_get(s));
3878 cx_string_delete(s);
3883 giraffe_model_delete(guess);
3886 iterations = giraffe_model_get_position(model);
3887 df = giraffe_model_get_df(model);
3889 chisq = giraffe_model_get_chisq(model);
3890 rsquare = giraffe_model_get_rsquare(model);
3892 cpl_msg_info(fctid,
"Optical model fit statistics: iterations = "
3893 "%d, DoF = %d, Chi-square = %.6g, Chi-square/DoF = "
3894 "%.6g, R-square = %.6g", iterations, df, chisq,
3895 chisq / df, rsquare);
3903 setup->
fcoll = giraffe_model_get_parameter(model,
"FocalLength");
3904 setup->
gcam = giraffe_model_get_parameter(model,
"Magnification");
3905 setup->
theta = giraffe_model_get_parameter(model,
"Angle");
3906 setup->
order = giraffe_model_get_parameter(model,
"Order");
3907 setup->
space = giraffe_model_get_parameter(model,
"Spacing");
3909 if (strcmp(giraffe_model_get_name(model),
"xoptmod2") == 0) {
3910 setup->
sdx = giraffe_model_get_parameter(model,
"Sdx");
3911 setup->
sdy = giraffe_model_get_parameter(model,
"Sdy");
3912 setup->
sphi = giraffe_model_get_parameter(model,
"Sphi");
3927 cpl_msg_info(fctid,
"Re-computing line positions with updated "
3930 xccd = _giraffe_line_abscissa(_lines, slitgeometry, fibers,
3931 solution, localization, FALSE);
3933 giraffe_linedata_set_data(line_data,
"Xccd", xccd);
3939 cx_string *s = cx_string_new();
3941 GiModel *model = giraffe_wlsolution_model(solution);
3944 _giraffe_opticalmodel_format(s, model, GI_OPTM_PARAMETER_VALUES);
3945 cpl_msg_info(fctid,
"Optical model: %s", cx_string_get(s));
3947 cx_string_delete(s);
3952 rms = _giraffe_compute_statistics(line_data, NULL, NULL);
3954 cpl_msg_info(fctid,
"Average RMS [pxl] of line positions using "
3955 "%d of %d lines: %.4f", _ngood, _nlines * _nfibers,
3964 cpl_msg_info(fctid,
"Fit of the wavelength solution coefficients "
3965 "using %" CX_PRINTF_FORMAT_SIZE_TYPE
" lines",
3966 giraffe_linedata_accepted(line_data));
3968 xws_setup.subslits = giraffe_wlsolution_get_subslits(solution);
3972 cpl_msg_info(fctid,
"Chebyshev polynomial order is (%d, %d).",
3973 xws_setup.fit.xorder, xws_setup.fit.yorder);
3979 cpl_msg_info(fctid,
"Sigma clipping: iterations = %d, level = %.4f, "
3980 "fraction = %.4f", xws_setup.clip.iterations,
3981 xws_setup.clip.level, xws_setup.clip.fraction);
3983 xws_coeffs = giraffe_wlresiduals_new();
3985 xws_fit = _giraffe_residuals_fit(xws_coeffs, line_data, localization,
3986 fibers, slitgeometry, &xws_setup);
3989 if (xws_fit == NULL) {
3991 cpl_msg_error(fctid,
"Fit of the wavelength solution "
3992 "coefficients failed!");
3994 giraffe_wlresiduals_delete(xws_coeffs);
3996 cpl_table_delete(_lines);
3997 cpl_image_delete(line_status);
3998 giraffe_linedata_delete(line_data);
4002 _giraffe_lineparams_delete(line_setup);
4004 giraffe_wlsolution_delete(solution);
4016 xres = cpl_image_new(giraffe_linedata_fibers(line_data),
4017 giraffe_linedata_lines(line_data),
4020 _giraffe_get_residuals(xres,
4021 giraffe_linedata_get_data(line_data,
"Xccd"),
4023 giraffe_linedata_set_data(line_data,
"Xres", xres);
4026 if (giraffe_linedata_accepted(line_data) == 0) {
4027 cpl_msg_error(fctid,
"No lines left after wavelength solution "
4028 "coefficients fit!");
4030 giraffe_wlresiduals_delete(xws_coeffs);
4032 cpl_table_delete(_lines);
4033 cpl_image_delete(line_status);
4034 cpl_image_delete(xws_fit);
4035 giraffe_linedata_delete(line_data);
4039 _giraffe_lineparams_delete(line_setup);
4041 giraffe_wlsolution_delete(solution);
4047 cpl_msg_info(fctid,
"Number of good lines: %"
4048 CX_PRINTF_FORMAT_SIZE_TYPE
". %"
4049 CX_PRINTF_FORMAT_SIZE_TYPE
" of %d lines "
4050 "rejected due to wavelength solution coefficients fit.",
4051 giraffe_linedata_accepted(line_data),
4052 giraffe_linedata_rejected(line_data) - _nreject, _ngood);
4054 _ngood = giraffe_linedata_accepted(line_data);
4055 _nreject = giraffe_linedata_rejected(line_data);
4062 giraffe_wlsolution_set_residuals(solution, xws_coeffs);
4072 rms = _giraffe_compute_statistics(line_data, xws_fit, line_status);
4074 cpl_msg_info(fctid,
"Average RMS [pxl] of line positions using "
4075 "%d of %d lines: %.4f", _ngood, _nlines * _nfibers,
4085 info.residuals = residuals;
4087 info.nlines = _nlines;
4088 info.nfibers = _nfibers;
4090 info.ngood = _ngood;
4091 info.nreject = _nreject;
4100 cpl_image_delete(xws_fit);
4102 cpl_table_delete(_lines);
4103 cpl_image_delete(line_status);
4115 status = _giraffe_convert_wlsolution(tsolution, solution,
4116 extraction->spectra, setup,
4125 _giraffe_lineparams_delete(line_setup);
4127 giraffe_wlsolution_delete(solution);
4138 result->coeffs = tsolution;
4141 result->linedata = line_data;
4149 giraffe_wlsolution_delete(solution);
4151 _giraffe_lineparams_delete(line_setup);
4172 const cxchar *s = NULL;
4173 const cpl_parameter *p = NULL;
4182 config = cx_calloc(1,
sizeof *config);
4197 p = cpl_parameterlist_find(list,
"giraffe.wlcalibration.line.widths");
4198 s = cpl_parameter_get_string(p);
4202 cxchar **values = cx_strsplit(s,
",", -1);
4205 if (values == NULL) {
4218 while (values[n] != NULL) {
4223 config->
line_widths = cx_malloc(n *
sizeof(cxint));
4227 while (values[n] != NULL) {
4229 cxint w = strtol(values[n], &last, 10);
4231 if (*last !=
'\0') {
4232 cx_strfreev(values);
4245 sizeof(cxint), _giraffe_window_compare);
4248 cx_strfreev(values);
4256 p = cpl_parameterlist_find(list,
"giraffe.wlcalibration.line.separation");
4259 p = cpl_parameterlist_find(list,
"giraffe.wlcalibration.line.fluxratio");
4262 p = cpl_parameterlist_find(list,
"giraffe.wlcalibration.line.brightness");
4265 p = cpl_parameterlist_find(list,
"giraffe.wlcalibration.line.count");
4266 config->
line_count = cpl_parameter_get_int(p);
4268 p = cpl_parameterlist_find(list,
"giraffe.wlcalibration.line.wrange");
4269 s = cpl_parameter_get_string(p);
4273 cxchar **values = cx_strsplit(s,
",", 3);
4275 if (values == NULL) {
4285 cxdouble lower = 0.;
4286 cxdouble upper = 0.;
4289 lower = strtod(values[0], &last);
4291 if (*last !=
'\0') {
4293 cx_strfreev(values);
4300 lower = lower >= 0. ? lower : 0.;
4303 if (values[1] != NULL) {
4305 upper = strtod(values[1], &last);
4307 if (*last !=
'\0') {
4309 cx_strfreev(values);
4316 upper = upper > lower ? upper : 0.;
4325 cx_strfreev(values);
4331 p = cpl_parameterlist_find(list,
"giraffe.wlcalibration.line.model");
4332 s = cpl_parameter_get_string(p);
4334 if (strcmp(s,
"psfexp") != 0 &&
4335 strcmp(s,
"psfexp2") != 0 &&
4336 strcmp(s,
"gaussian") != 0) {
4347 p = cpl_parameterlist_find(list,
"giraffe.wlcalibration.line.residuals");
4348 s = cpl_parameter_get_string(p);
4350 if (strcmp(s,
"auto") != 0 &&
4351 strcmp(s,
"enable") != 0 &&
4352 strcmp(s,
"disable") != 0) {
4363 p = cpl_parameterlist_find(list,
"giraffe.wlcalibration.line.threshold");
4366 p = cpl_parameterlist_find(list,
"giraffe.wlcalibration.line.offset");
4367 config->
line_offset = cpl_parameter_get_double(p);
4369 p = cpl_parameterlist_find(list,
"giraffe.wlcalibration.line.iterations");
4370 config->
line_niter = cpl_parameter_get_int(p);
4372 p = cpl_parameterlist_find(list,
"giraffe.wlcalibration.line.tests");
4373 config->
line_ntest = cpl_parameter_get_int(p);
4375 p = cpl_parameterlist_find(list,
"giraffe.wlcalibration.line.dchisquare");
4376 config->
line_dchisq = cpl_parameter_get_double(p);
4378 p = cpl_parameterlist_find(list,
"giraffe.wlcalibration.line.rwidthratio");
4381 p = cpl_parameterlist_find(list,
"giraffe.wlcalibration.line.exponent");
4385 p = cpl_parameterlist_find(list,
"giraffe.wlcalibration.slit.offset");
4386 s = cpl_parameter_get_string(p);
4388 cx_assert(s != NULL);
4390 if (cx_strncasecmp(s,
"setup", 5) != 0) {
4392 cxchar **values = cx_strsplit(s,
",", 4);
4400 if (values == NULL || values[0] == NULL) {
4410 if (*values[0] !=
'\0') {
4413 cxdouble sdx = strtod(values[0], &last);
4415 if (*last !=
'\0') {
4416 cx_strfreev(values);
4429 if (values[1] == NULL) {
4434 if (*values[1] !=
'\0') {
4437 cxdouble sdy = strtod(values[1], &last);
4439 if (*last !=
'\0') {
4440 cx_strfreev(values);
4455 if (!eol && values[2] != NULL) {
4457 if (*values[2] !=
'\0') {
4460 cxdouble sphi = strtod(values[2], &last);
4462 if (*last !=
'\0') {
4463 cx_strfreev(values);
4478 cx_strfreev(values);
4486 p = cpl_parameterlist_find(list,
"giraffe.wlcalibration.opt.model");
4487 s = cpl_parameter_get_string(p);
4489 if (strcmp(s,
"xoptmod") != 0 && strcmp(s,
"xoptmod2") != 0) {
4500 p = cpl_parameterlist_find(list,
"giraffe.wlcalibration.opt.direction");
4503 p = cpl_parameterlist_find(list,
"giraffe.wlcalibration.opt.solution");
4506 p = cpl_parameterlist_find(list,
"giraffe.wlcalibration.opt.subslits");
4509 p = cpl_parameterlist_find(list,
"giraffe.wlcalibration.opt.flags");
4510 s = cpl_parameter_get_string(p);
4514 cxchar **values = cx_strsplit(s,
",", -1);
4516 if (values == NULL) {
4529 while (values[i] != NULL) {
4531 if (strncmp(values[i],
"fcoll", 5) == 0) {
4535 else if (strncmp(values[i],
"gcam", 4) == 0) {
4539 else if (strncmp(values[i],
"theta", 5) == 0) {
4543 else if (strncmp(values[i],
"sdx", 3) == 0) {
4547 else if (strncmp(values[i],
"sdy", 3) == 0) {
4551 else if (strncmp(values[i],
"sphi", 4) == 0) {
4560 cx_strfreev(values);
4578 p = cpl_parameterlist_find(list,
"giraffe.wlcalibration.opt.iterations");
4579 config->
opt_niter = cpl_parameter_get_int(p);
4581 p = cpl_parameterlist_find(list,
"giraffe.wlcalibration.opt.tests");
4582 config->
opt_ntest = cpl_parameter_get_int(p);
4584 p = cpl_parameterlist_find(list,
"giraffe.wlcalibration.opt.dchisquare");
4585 config->
opt_dchisq = cpl_parameter_get_double(p);
4588 p = cpl_parameterlist_find(list,
"giraffe.wlcalibration.psf.sigma");
4591 p = cpl_parameterlist_find(list,
"giraffe.wlcalibration.psf.iterations");
4594 p = cpl_parameterlist_find(list,
"giraffe.wlcalibration.psf.fraction");
4597 p = cpl_parameterlist_find(list,
"giraffe.wlcalibration.psf.order");
4598 s = cpl_parameter_get_string(p);
4602 cxchar **values = cx_strsplit(s,
",", 3);
4604 if (values == NULL || values[1] == NULL) {
4615 config->
pxw_xorder = strtol(values[0], &last, 10);
4617 if (*last !=
'\0') {
4619 cx_strfreev(values);
4626 config->
pxw_yorder = strtol(values[1], &last, 10);
4628 if (*last !=
'\0') {
4630 cx_strfreev(values);
4639 cx_strfreev(values);
4645 p = cpl_parameterlist_find(list,
"giraffe.wlcalibration.wsol.sigma");
4648 p = cpl_parameterlist_find(list,
"giraffe.wlcalibration.wsol.iterations");
4651 p = cpl_parameterlist_find(list,
"giraffe.wlcalibration.wsol.fraction");
4654 p = cpl_parameterlist_find(list,
"giraffe.wlcalibration.wsol.order");
4655 s = cpl_parameter_get_string(p);
4659 cxchar **values = cx_strsplit(s,
",", 3);
4661 if (values == NULL || values[1] == NULL) {
4672 config->
xws_xorder = strtol(values[0], &last, 10);
4674 if (*last !=
'\0') {
4676 cx_strfreev(values);
4683 config->
xws_yorder = strtol(values[1], &last, 10);
4685 if (*last !=
'\0') {
4687 cx_strfreev(values);
4696 cx_strfreev(values);
4778 p = cpl_parameter_new_value(
"giraffe.wlcalibration.line.widths",
4780 "List of window widths [pxl] used for line "
4781 "detection and fit (e.g. '60,40,15').",
4782 "giraffe.wlcalibration",
4784 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"wcal-lswidth");
4785 cpl_parameterlist_append(list, p);
4788 p = cpl_parameter_new_value(
"giraffe.wlcalibration.line.separation",
4790 "Factor used to compute the minimum line "
4791 "separation from the window width.",
4792 "giraffe.wlcalibration",
4794 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"wcal-lssep");
4795 cpl_parameterlist_append(list, p);
4798 p = cpl_parameter_new_value(
"giraffe.wlcalibration.line.fluxratio",
4800 "Selects only lines whose neighbours have "
4801 "a relative intensity less than "
4803 "giraffe.wlcalibration",
4806 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"wcal-lsfxratio");
4807 cpl_parameterlist_append(list, p);
4810 p = cpl_parameter_new_value(
"giraffe.wlcalibration.line.brightness",
4812 "Selects lines having an intensity greater "
4813 "or equal to the given intensity.",
4814 "giraffe.wlcalibration",
4817 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"wcal-lsbright");
4818 cpl_parameterlist_append(list, p);
4821 p = cpl_parameter_new_value(
"giraffe.wlcalibration.line.count",
4823 "Sets the minimum number of lines to select; "
4824 "selected are lines with the highest nominal "
4825 "intensity. A value of 0 turns this selection "
4826 "off. If the value is less than 0 the "
4827 "selection is skipped if the line list does "
4828 "not contain enough lines.",
4829 "giraffe.wlcalibration",
4832 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"wcal-lscount");
4833 cpl_parameterlist_append(list, p);
4836 p = cpl_parameter_new_value(
"giraffe.wlcalibration.line.wrange",
4838 "Selects only lines within the given "
4839 "wavelength range [nm].",
4840 "giraffe.wlcalibration",
4843 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"wcal-lswrange");
4844 cpl_parameterlist_append(list, p);
4851 p = cpl_parameter_new_enum(
"giraffe.wlcalibration.line.model",
4853 "Line profile model.",
4854 "giraffe.wlcalibration",
4855 "psfexp", 3,
"psfexp",
"psfexp2",
"gaussian");
4857 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"wcal-lfmodel");
4858 cpl_parameterlist_append(list, p);
4861 p = cpl_parameter_new_enum(
"giraffe.wlcalibration.line.residuals",
4863 "Use optical model residuals for line "
4865 "giraffe.wlcalibration",
4866 "auto", 3,
"auto",
"enable",
"disable");
4868 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"wcal-lfres");
4869 cpl_parameterlist_append(list, p);
4872 p = cpl_parameter_new_value(
"giraffe.wlcalibration.line.threshold",
4874 "Line detection threshold during the "
4875 "line fitting (multiple of bias sigma)",
4876 "giraffe.wlcalibration",
4879 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"wcal-lfthreshold");
4880 cpl_parameterlist_append(list, p);
4883 p = cpl_parameter_new_value(
"giraffe.wlcalibration.line.offset",
4885 "Maximum allowed difference between the "
4886 "fitted and raw line peak position.",
4887 "giraffe.wlcalibration",
4890 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"wcal-lfoffset");
4891 cpl_parameterlist_append(list, p);
4894 p = cpl_parameter_new_value(
"giraffe.wlcalibration.line.iterations",
4896 "Line detection fit maximum number of "
4898 "giraffe.wlcalibration",
4901 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"wcal-lfniter");
4902 cpl_parameterlist_append(list, p);
4905 p = cpl_parameter_new_value(
"giraffe.wlcalibration.line.tests",
4907 "Line detection fit maximum number of "
4909 "giraffe.wlcalibration",
4912 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"wcal-lfntest");
4913 cpl_parameterlist_append(list, p);
4916 p = cpl_parameter_new_value(
"giraffe.wlcalibration.line.dchisquare",
4918 "Line detection fit minimum chi-square "
4920 "giraffe.wlcalibration",
4923 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"wcal-lfdchisq");
4924 cpl_parameterlist_append(list, p);
4927 p = cpl_parameter_new_value(
"giraffe.wlcalibration.line.rwidthratio",
4929 "Line width/resolution width factor.",
4930 "giraffe.wlcalibration",
4933 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"wcal-lfreswid");
4934 cpl_parameterlist_append(list, p);
4937 p = cpl_parameter_new_value(
"giraffe.wlcalibration.line.exponent",
4939 "Exponential line profile exponent; it will "
4940 "not be fitted if it is larger than 0.",
4941 "giraffe.wlcalibration",
4944 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"wcal-lfexpwid");
4945 cpl_parameterlist_append(list, p);
4953 p = cpl_parameter_new_value(
"giraffe.wlcalibration.slit.offset",
4955 "Initial slit position offsets along the "
4956 "x and y direction and rotation angle.",
4957 "giraffe.wlcalibration",
4960 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"wcal-soffset");
4961 cpl_parameterlist_append(list, p);
4968 p = cpl_parameter_new_enum(
"giraffe.wlcalibration.opt.model",
4971 "giraffe.wlcalibration",
4972 "xoptmod2", 2,
"xoptmod",
"xoptmod2");
4974 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"wcal-ommodel");
4975 cpl_parameterlist_append(list, p);
4978 p = cpl_parameter_new_value(
"giraffe.wlcalibration.opt.direction",
4980 "Dispersion direction flag.",
4981 "giraffe.wlcalibration",
4984 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"wcal-omdir");
4985 cpl_parameterlist_append(list, p);
4988 p = cpl_parameter_new_value(
"giraffe.wlcalibration.opt.solution",
4990 "Controls optical model parameter fitting.",
4991 "giraffe.wlcalibration",
4994 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"wcal-omsol");
4995 cpl_parameterlist_append(list, p);
4998 p = cpl_parameter_new_value(
"giraffe.wlcalibration.opt.flags",
5000 "List of flags defining the set of free "
5001 "parameters used for fitting the optical "
5002 "model. Possible values are: fcoll, gcam, "
5003 "theta, sdx, sdy, sphi",
5004 "giraffe.wlcalibration",
5007 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"wcal-omflags");
5008 cpl_parameterlist_append(list, p);
5011 p = cpl_parameter_new_value(
"giraffe.wlcalibration.opt.subslits",
5013 "Controls subslit geometry usage in the "
5014 "optical model fit; subslits are used if "
5016 "giraffe.wlcalibration",
5019 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"wcal-omsslits");
5020 cpl_parameterlist_append(list, p);
5023 p = cpl_parameter_new_value(
"giraffe.wlcalibration.opt.iterations",
5025 "Optical model fit maximum number of "
5027 "giraffe.wlcalibration",
5030 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"wcal-omniter");
5031 cpl_parameterlist_append(list, p);
5034 p = cpl_parameter_new_value(
"giraffe.wlcalibration.opt.tests",
5036 "Optical model fit maximum number of "
5038 "giraffe.wlcalibration",
5041 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"wcal-omntest");
5042 cpl_parameterlist_append(list, p);
5045 p = cpl_parameter_new_value(
"giraffe.wlcalibration.opt.dchisquare",
5047 "Optical model fit minimum chi-square "
5049 "giraffe.wlcalibration",
5052 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"wcal-omdchisq");
5053 cpl_parameterlist_append(list, p);
5060 p = cpl_parameter_new_value(
"giraffe.wlcalibration.psf.sigma",
5062 "PSF width fit sigma clipping factor.",
5063 "giraffe.wlcalibration",
5066 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"wcal-xwsigma");
5067 cpl_parameterlist_append(list, p);
5070 p = cpl_parameter_new_value(
"giraffe.wlcalibration.psf.iterations",
5072 "PSF width fit sigma clipping maximum "
5073 "number of iterations.",
5074 "giraffe.wlcalibration",
5077 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"wcal-xwniter");
5078 cpl_parameterlist_append(list, p);
5081 p = cpl_parameter_new_range(
"giraffe.wlcalibration.psf.fraction",
5083 "PSF width fit sigma clipping minimum "
5084 "fraction of points accepted/total.",
5085 "giraffe.wlcalibration",
5088 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"wcal-xwmfrac");
5089 cpl_parameterlist_append(list, p);
5092 p = cpl_parameter_new_value(
"giraffe.wlcalibration.psf.order",
5094 "X and Y polynomial orders for PSF x-width "
5096 "giraffe.wlcalibration",
5099 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"wcal-xworder");
5100 cpl_parameterlist_append(list, p);
5107 p = cpl_parameter_new_value(
"giraffe.wlcalibration.wsol.sigma",
5109 "Chebyshev correction sigma clipping factor.",
5110 "giraffe.wlcalibration",
5113 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"wcal-wssigma");
5114 cpl_parameterlist_append(list, p);
5117 p = cpl_parameter_new_value(
"giraffe.wlcalibration.wsol.iterations",
5119 "Chebyshev correction sigma clipping "
5120 "maximum number of iterations",
5121 "giraffe.wlcalibration",
5124 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"wcal-wsniter");
5125 cpl_parameterlist_append(list, p);
5128 p = cpl_parameter_new_range(
"giraffe.wlcalibration.wsol.fraction",
5130 "Chebyshev correction sigma clipping "
5131 "minimum fraction of points accepted/total.",
5132 "giraffe.wlcalibration",
5135 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"wcal-wsmfrac");
5136 cpl_parameterlist_append(list, p);
5139 p = cpl_parameter_new_value(
"giraffe.wlcalibration.wsol.order",
5141 "X and Y polynomial orders for the wavelength "
5142 "solution Chebyshev correction.",
5143 "giraffe.wlcalibration",
5146 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"wcal-wsorder");
5147 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.
void giraffe_grating_delete(GiGrating *self)
Destroys an GiGrating object.
GiGrating * giraffe_grating_create(const GiImage *spectra, const GiTable *grating)
Create a GiGrating from a reference image.
cpl_propertylist * giraffe_image_get_properties(const GiImage *self)
Get the properties of an image.
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.
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.
GiRange * giraffe_range_create(cxdouble min, cxdouble max)
Creates a new range from the given minimum and maximum values.
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.
cxint giraffe_table_set(GiTable *self, cpl_table *table)
Sets the table data.
cpl_propertylist * giraffe_table_get_properties(const GiTable *self)
Gets the table properties.
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.
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