39 #include <fors_utils.h>
43 static cpl_polynomial *read_global_distortion(cpl_table *global, cpl_size row);
52 float cpl_tools_get_median_float(
float *, cpl_size);
54 #define MAX_COLNAME (80)
55 #define STRETCH_FACTOR (1.20)
59 static int mos_multiplex = -1;
60 static int mos_region_size = 800;
62 static double default_lines_hi[] = {
122 static double default_lines_lo[] = {
201 static void mos_seed(
void)
203 srand((
unsigned int)time((time_t *)0));
206 static double mos_randg(
int seme)
209 static int gotit = 1;
210 double x1, x2, w, y1;
221 x1 = 2.0 * (double)rand() / RAND_MAX - 1.0;
222 x2 = 2.0 * (double)rand() / RAND_MAX - 1.0;
223 w = x1 * x1 + x2 * x2;
224 }
while (w >= 1.0 || w == 0.0);
226 w = sqrt( (-2.0 * log(w)) / w);
245 static cpl_image *mos_image_vertical_median_filter(cpl_image *ima_in,
246 int filtsizey,
int refrow,
247 int above,
int below,
int step)
250 const char *func =
"mos_image_general_median_filter";
252 cpl_image *filt_img = NULL;
257 int upright_y, loleft_y;
259 int yIsEven = !(filtsizey - (filtsizey/2)*2);
261 int nx = cpl_image_get_size_x(ima_in);
262 int ny = cpl_image_get_size_y(ima_in);
266 if (yIsEven) filtsizey++;
268 if (ny <= filtsizey) {
270 "Median filter size: %d, image size: %d", filtsizey, ny);
276 filt_img = cpl_image_duplicate(ima_in);
277 buf = cpl_malloc(filtsizey *
sizeof(
float));
278 data = cpl_image_get_data(ima_in);
279 fdata = cpl_image_get_data(filt_img);
281 firstRow = refrow - step * (below / step);
285 for (col = 0; col < nx; col++) {
286 for (row = firstRow; row < refrow + above; row += step) {
289 loleft_y = row - f2y;
290 upright_y = row + f2y + 1;
291 for (j = loleft_y; j < upright_y; j++)
292 buf[j - loleft_y] = data[col + j * nx];
294 fdata[col + row * nx] = cpl_tools_get_median_float(buf, filtsizey);
321 static int peakPosition(
const float *data,
int size,
float *position,
327 float max, median, level, pos, variance, uniformVariance;
342 copy = (
float *) cpl_malloc(size*
sizeof(
float));
343 for (i = 0; i < size; i++)
345 median = cpl_tools_get_median_float(copy, size);
354 for (i = 1; i < size; i++)
364 if (max-median < 0.00001)
373 level = (max + median) / 2;
384 for (i = 0, sum = 0., weights = 0.; i < size; i++) {
385 if (data[i] > level) {
387 weights += (data[i] - median);
388 sum += i * (data[i] - median);
398 if (count < minPoints)
402 for (i = 0, sum = 0., weights = 0.; i < size; i++) {
403 if (data[i] > level) {
405 sum += (i - pos) * (i - pos);
408 variance = sqrt(sum / weights);
418 uniformVariance = sqrt(size*size/3 - pos*size + pos*pos);
420 if (variance > 0.8 * uniformVariance)
423 *position = pos + 0.5;
475 static double values_to_dx(
double v1,
double v2,
double v3)
478 static double epsilon = 0.00000001;
482 if (v1 > v2 || v3 > v2)
485 if (2 * v2 - v1 - v3 < epsilon)
488 r = 0.5 * (v3 - v1) / (2 * v2 - v3 - v1);
500 static float *min_filter(
float *buffer,
int length,
int size)
502 float *minf = cpl_calloc(length,
sizeof(
float));
504 int start = size / 2;
505 int end = length - size / 2;
509 for (i = start; i < end; i++) {
510 min = buffer[i-start];
511 for (j = i - start + 1; j <= i + start; j++)
517 for (i = 0; i < start; i++)
518 minf[i] = minf[start];
520 for (i = end; i < length; i++)
521 minf[i] = minf[end-1];
532 static float *max_filter(
float *buffer,
int length,
int size)
534 float *maxf = cpl_calloc(length,
sizeof(
float));
536 int start = size / 2;
537 int end = length - size / 2;
541 for (i = start; i < end; i++) {
542 max = buffer[i-start];
543 for (j = i - start + 1; j <= i + start; j++)
549 for (i = 0; i < start; i++)
550 maxf[i] = maxf[start];
552 for (i = end; i < length; i++)
553 maxf[i] = maxf[end-1];
564 static float *smo_filter(
float *buffer,
int length,
int size)
566 float *smof = cpl_calloc(length,
sizeof(
float));
568 int start = size / 2;
569 int end = length - size / 2;
573 for (i = start; i < end; i++) {
575 for (j = i - start; j <= i + start; j++)
577 smof[i] = sum / size;
580 for (i = 0; i < start; i++)
581 smof[i] = smof[start];
583 for (i = end; i < length; i++)
584 smof[i] = smof[end-1];
608 static cpl_polynomial *read_global_distortion(cpl_table *global, cpl_size row)
610 cpl_polynomial *poly = NULL;
616 char name[MAX_COLNAME];
619 for (p[0] = 0; p[0] <= degree; p[0]++) {
620 for (p[1] = 0; p[1] <= degree - p[0]; p[1]++) {
621 snprintf(name, MAX_COLNAME,
"a%"CPL_SIZE_FORMAT
"%"CPL_SIZE_FORMAT
"", p[0], p[1]);
622 coeff = cpl_table_get_double(global, name, row, &null);
626 poly = cpl_polynomial_new(2);
627 cpl_polynomial_set_coeff(poly, p, coeff);
634 static cpl_table *write_global_distortion(cpl_table *global,
int row,
635 cpl_polynomial *poly)
642 char name[MAX_COLNAME];
649 table = cpl_table_new(nrow);
650 for (p[0] = 0; p[0] <= degree; p[0]++) {
651 for (p[1] = 0; p[1] <= degree - p[0]; p[1]++) {
652 snprintf(name, MAX_COLNAME,
"a%"CPL_SIZE_FORMAT
"%"CPL_SIZE_FORMAT
"", p[0], p[1]);
653 cpl_table_new_column(table, name, CPL_TYPE_DOUBLE);
659 for (p[0] = 0; p[0] <= degree; p[0]++) {
660 for (p[1] = 0; p[1] <= degree - p[0]; p[1]++) {
661 snprintf(name, MAX_COLNAME,
"a%"CPL_SIZE_FORMAT
"%"CPL_SIZE_FORMAT
"", p[0], p[1]);
662 cpl_table_set_double(table, name, row,
663 cpl_polynomial_get_coeff(poly, p));
681 #define SEGNO(a,b) ((b) >= 0.0 ? fabs(a) : -fabs(a))
682 static int robustLinearFit(cpl_bivector *
list,
double *a,
double *b,
689 double aa, bb, bcomp, b1, b2, del, abdevt, f, f1, f2, sigb, temp, d, sum;
690 double sx, sy, sxy, sxx, chisq;
697 int max_iterate = 30;
701 np = cpl_bivector_get_size(list);
702 vx = cpl_bivector_get_x(list);
703 vy = cpl_bivector_get_y(list);
704 x = cpl_vector_get_data(vx);
705 y = cpl_vector_get_data(vy);
707 sx = sy = sxx = sxy = 0.00;
708 for (i = 0; i < np; i++) {
715 del = np * sxx - sx * sx;
716 aa_ls = aa = (sxx * sy - sx * sxy) / del;
717 bb_ls = bb = (np * sxy - sx * sy) / del;
720 for (i = 0; i < np; i++) {
721 temp = y[i] - (aa+bb*x[i]);
726 va = cpl_vector_new(np);
727 arr = cpl_vector_get_data(va);
728 sigb = sqrt(chisq/del);
733 for (i = 0; i < np; i++) {
734 arr[i] = y[i] - bcomp * x[i];
736 aa = cpl_vector_get_median_const(va);
738 for (i = 0; i < np; i++) {
739 d = y[i] - (bcomp * x[i] + aa);
744 sum += (d >= 0.0 ? x[i] : -x[i]);
748 b2 = bb + SEGNO(3.0 * sigb, f1);
752 for (i = 0; i < np; i++) {
753 arr[i] = y[i] - bcomp * x[i];
755 aa = cpl_vector_get_median_const(va);
757 for (i = 0; i < np; i++) {
758 d = y[i] - (bcomp * x[i] + aa);
763 sum += (d >= 0.0 ? x[i] : -x[i]);
767 if (fabs(b2-b1)<1e-7) {
770 *abdev = abdevt / (double)np;
771 cpl_vector_delete(va);
776 while (f1*f2 > 0.0) {
784 for (i = 0; i < np; i++) {
785 arr[i] = y[i] - bcomp * x[i];
787 aa = cpl_vector_get_median_const(va);
789 for (i = 0; i < np; i++) {
790 d = y[i] - (bcomp * x[i] + aa);
795 sum += (d >= 0.0 ? x[i] : -x[i]);
799 if (iter >= max_iterate)
802 if (iter >= max_iterate) {
806 cpl_vector_delete(va);
811 while (fabs(b2-b1) > sigb) {
812 bb = 0.5 * (b1 + b2);
813 if ((fabs(bb-b1) < 1e-7) || (fabs(bb-b2) < 1e-7))
817 for (i = 0; i < np; i++) {
818 arr[i] = y[i] - bcomp * x[i];
820 aa = cpl_vector_get_median_const(va);
822 for (i = 0; i < np; i++) {
823 d = y[i] - (bcomp * x[i] + aa);
828 sum += (d >= 0.0 ? x[i] : -x[i]);
841 cpl_vector_delete(va);
844 *abdev = abdevt / np;
859 cpl_table *mos_hough_table(cpl_table *table,
const char *x,
const char *y)
871 npoints = cpl_table_get_nrow(table);
872 opoints = npoints*(npoints-1)/2;
874 output = cpl_table_new(opoints);
875 cpl_table_new_column(output,
"m", CPL_TYPE_DOUBLE);
876 cpl_table_new_column(output,
"q", CPL_TYPE_DOUBLE);
877 cpl_table_fill_column_window_double(output,
"m", 0, opoints, 0.0);
878 cpl_table_fill_column_window_double(output,
"q", 0, opoints, 0.0);
880 xodata = cpl_table_get_data_double(output,
"m");
881 yodata = cpl_table_get_data_double(output,
"q");
883 cpl_table_cast_column(table, x,
"x", CPL_TYPE_DOUBLE);
884 cpl_table_cast_column(table, y,
"y", CPL_TYPE_DOUBLE);
886 xdata = cpl_table_get_data_double(table,
"x");
887 ydata = cpl_table_get_data_double(table,
"y");
890 for (i = 0; i < npoints; i++) {
891 for (j = i+1; j < npoints; j++) {
892 xodata[k] = (ydata[i]-ydata[j])/(xdata[i]-xdata[j]);
893 yodata[k] = ydata[i] - xodata[k] * xdata[i];
899 printf(
"Assert k = %d, expected %d\n", k, opoints);
901 cpl_table_erase_column(table,
"x");
902 cpl_table_erase_column(table,
"y");
913 static void mos_extraction(cpl_image *sciwin, cpl_image *skywin,
914 cpl_image *extracted, cpl_image *sky,
915 cpl_image *error,
int nobjects,
int extraction,
916 double ron,
double conad,
int ncomb)
919 cpl_vector *vprofile;
931 double sumWeight, sum, sumSky, sumProf, variance, weight;
944 specLen = cpl_image_get_size_x(sciwin);
945 numRows = cpl_image_get_size_y(sciwin);
947 edata = cpl_image_get_data(extracted);
948 edata += nobjects * specLen;
950 ekdata = cpl_image_get_data(sky);
951 ekdata += nobjects * specLen;
953 endata = cpl_image_get_data(error);
954 endata += nobjects * specLen;
956 sdata = cpl_image_get_data(sciwin);
957 kdata = cpl_image_get_data(skywin);
965 if (extraction && numRows > 5) {
967 fdata = cpl_image_get_data(smowin);
968 for (i = 0; i < specLen; i++)
969 for (j = 0, edata[i] = 0.0; j < numRows; j++)
970 edata[i] += fdata[i + j * specLen];
971 cpl_image_delete(smowin);
974 for (i = 0; i < specLen; i++)
975 for (j = 0, edata[i] = 0.0; j < numRows; j++)
976 edata[i] += sdata[i + j * specLen];
981 profile = cpl_calloc(specLen * numRows,
sizeof(
double));
982 buffer = cpl_calloc(specLen,
sizeof(
double));
984 for (iter = 0; iter < maxIter; iter++) {
990 for (i = 0; i < specLen; i++) {
991 for (j = 0; j < numRows; j++) {
992 index = i + j * specLen;
994 if (fabs(edata[i]) > 0.00001)
995 profile[index] = sdata[index] / edata[i];
997 profile[index] = 0.0;
1001 for (j = 0; j < numRows; j++) {
1007 for (i = 0; i < specLen - smoothBox; i++) {
1008 vprofile = cpl_vector_wrap(smoothBox, profile + i + j*specLen);
1009 value = cpl_vector_get_median_const(vprofile);
1010 cpl_vector_unwrap(vprofile);
1013 buffer[i + smoothBox / 2] = value;
1020 vprofile = cpl_vector_wrap(smoothBox / 2, profile + j*specLen);
1021 value = cpl_vector_get_mean(vprofile);
1022 cpl_vector_unwrap(vprofile);
1027 for (i = 0; i < smoothBox / 2; i++)
1030 vprofile = cpl_vector_wrap(smoothBox / 2,
1031 profile + specLen - smoothBox/2 + j*specLen);
1032 value = cpl_vector_get_mean(vprofile);
1033 cpl_vector_unwrap(vprofile);
1038 for (i = 0; i < smoothBox / 2; i++)
1039 buffer[i + specLen - smoothBox / 2] = value;
1041 for (i = 0; i < specLen; i++)
1042 profile[i + j * specLen] = buffer[i];
1050 for (i = 0; i < specLen; i++) {
1051 for (j = 0, value = 0.0; j < numRows; j++)
1052 value += profile[i + j * specLen];
1053 if (value > 0.00001)
1054 for (j = 0; j < numRows; j++)
1055 profile[i + j * specLen] /= value;
1057 for (j = 0; j < numRows; j++)
1058 profile[i + j * specLen] = 0.0;
1066 for (i = 0; i < specLen; i++) {
1071 for (j = 0; j < numRows; j++) {
1072 index = i + j * specLen;
1076 variance = ron*ron + fabs(edata[i] * profile[index] + kdata[index])
1079 value = sdata[index] - edata[i] * profile[index];
1080 if (fabs(value) / sqrt(variance) < nsigma) {
1081 weight = 1000000 * profile[index] / variance;
1082 sum += weight * sdata[index];
1083 sumSky += weight * kdata[index];
1084 sumWeight += weight * profile[index];
1085 sumProf += profile[index];
1092 if (sumWeight > 0.00001) {
1093 edata[i] = sum / sumWeight;
1094 ekdata[i] = sumSky / sumWeight;
1095 endata[i] = 1000 * sqrt(sumProf / sumWeight);
1103 endata[i] = sqrt(ron*ron + fabs(edata[i] + ekdata[i]) / conad);
1117 for (i = 0; i < specLen; i++)
1118 for (j = 0, ekdata[i] = 0.0; j < numRows; j++)
1119 ekdata[i] += kdata[i + j * specLen];
1125 for (i = 0; i < specLen; i++)
1126 endata[i] = sqrt(ron*ron + fabs(edata[i] + ekdata[i]) / conad);
1180 cpl_table *ids, cpl_table *crv,
1183 const char *func =
"mos_global_distortion";
1185 const char *clab[6] = {
"c0",
"c1",
"c2",
"c3",
"c4",
"c5"};
1187 cpl_table *global = NULL;
1197 cpl_polynomial *poly;
1210 int nslits, nmaskslits, npoints;
1219 if (slits == NULL || maskslits == NULL || ids == NULL || crv == NULL) {
1220 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
1227 nslits = cpl_table_get_nrow(slits);
1232 if (nslits < minslit) {
1233 cpl_msg_warning(func,
"Too few slits (%d < %d) for global "
1234 "distortion model determination", nslits, minslit);
1241 nmaskslits = cpl_table_get_nrow(maskslits);
1243 length = cpl_table_get_data_int(slits,
"length");
1244 position = cpl_table_get_data_int(slits,
"position");
1245 slit_id = cpl_table_get_data_int(slits,
"slit_id");
1246 mslit_id = cpl_table_get_data_int(maskslits,
"slit_id");
1247 xtop = cpl_table_get_data_double(slits,
"xtop");
1248 ytop = cpl_table_get_data_double(slits,
"ytop");
1249 xbottom = cpl_table_get_data_double(slits,
"xbottom");
1250 ybottom = cpl_table_get_data_double(slits,
"ybottom");
1251 mxtop = cpl_table_get_data_double(maskslits,
"xtop");
1252 mytop = cpl_table_get_data_double(maskslits,
"ytop");
1253 mxbottom = cpl_table_get_data_double(maskslits,
"xbottom");
1254 mybottom = cpl_table_get_data_double(maskslits,
"ybottom");
1261 coeff = cpl_table_new(nslits);
1262 cpl_table_copy_structure(coeff, ids);
1263 cpl_table_new_column(coeff,
"xccd", CPL_TYPE_DOUBLE);
1264 cpl_table_new_column(coeff,
"yccd", CPL_TYPE_DOUBLE);
1265 cpl_table_new_column(coeff,
"xmask", CPL_TYPE_DOUBLE);
1266 cpl_table_new_column(coeff,
"ymask", CPL_TYPE_DOUBLE);
1271 for (i = 0; i < nslits; i++) {
1272 for (j = 0; j < nmaskslits; j++) {
1273 if (slit_id[i] == mslit_id[j]) {
1274 cpl_table_set_double(coeff,
"xmask", i,
1275 (mxtop[j] + mxbottom[j]) / 2);
1276 cpl_table_set_double(coeff,
"ymask", i,
1277 (mytop[j] + mybottom[j]) / 2);
1282 if (cpl_table_has_invalid(coeff,
"xmask")) {
1283 cpl_error_set(func, CPL_ERROR_INCOMPATIBLE_INPUT);
1284 cpl_table_delete(coeff);
1288 for (i = 0; i < nslits; i++) {
1289 cpl_table_set_double(coeff,
"xccd", i, (xtop[i] + xbottom[i]) / 2);
1290 cpl_table_set_double(coeff,
"yccd", i, (ytop[i] + ybottom[i]) / 2);
1296 for (i = 0; i < nslits; i++) {
1301 cpl_table_and_selected_window(ids, position[i], length[i]);
1302 dummy = cpl_table_extract_selected(ids);
1303 for (j = 0; j < 6; j++) {
1304 if (cpl_table_has_column(dummy, clab[j])) {
1305 if (length[i] - cpl_table_count_invalid(dummy, clab[j]) > 10) {
1306 cpl_table_set_double(coeff, clab[j], i,
1307 cpl_table_get_column_median(dummy, clab[j]));
1312 cpl_table_delete(dummy);
1313 cpl_table_select_all(ids);
1320 for (j = 0; j < 6; j++) {
1321 if (cpl_table_has_column(coeff, clab[j])) {
1322 cpl_table_and_selected_invalid(coeff, clab[j]);
1324 if (cpl_table_not_selected(coeff))
1325 dummy = cpl_table_extract_selected(coeff);
1329 npoints = cpl_table_get_nrow(dummy);
1338 ci = cpl_vector_wrap(npoints,
1339 cpl_table_get_data_double(dummy, clab[j]));
1341 xccd = cpl_vector_wrap(npoints,
1342 cpl_table_get_data_double(dummy,
"xccd"));
1343 yccd = cpl_vector_wrap(npoints,
1344 cpl_table_get_data_double(dummy,
"yccd"));
1345 ccd = cpl_bivector_wrap_vectors(xccd, yccd);
1348 poly = cpl_polynomial_fit_2d_create(ccd, ci, order, NULL);
1350 cpl_bivector_unwrap_vectors(ccd);
1351 cpl_vector_unwrap(xccd);
1352 cpl_vector_unwrap(yccd);
1353 cpl_vector_unwrap(ci);
1356 xmask = cpl_vector_wrap(npoints,
1357 cpl_table_get_data_double(dummy,
"xmask"));
1358 ymask = cpl_vector_wrap(npoints,
1359 cpl_table_get_data_double(dummy,
"ymask"));
1360 mask = cpl_bivector_wrap_vectors(xmask, ymask);
1363 poly = cpl_polynomial_fit_2d_create(mask, ci, order, NULL);
1365 cpl_bivector_unwrap_vectors(mask);
1366 cpl_vector_unwrap(xmask);
1367 cpl_vector_unwrap(ymask);
1368 cpl_vector_unwrap(ci);
1372 cpl_size p[2] = {0, 0};
1373 poly = cpl_polynomial_new(2);
1374 cpl_polynomial_set_coeff(poly, p,
1375 cpl_table_get_column_median(dummy, clab[j]));
1378 cpl_table_delete(dummy);
1380 global = write_global_distortion(global, j, poly);
1382 cpl_polynomial_delete(poly);
1384 cpl_table_select_all(coeff);
1391 cpl_table_delete(coeff);
1401 cpl_table_set_double(global,
"a00", 6, reference);
1408 coeff = cpl_table_duplicate(crv);
1409 cpl_table_new_column(coeff,
"xmask", CPL_TYPE_DOUBLE);
1410 cpl_table_new_column(coeff,
"ymask", CPL_TYPE_DOUBLE);
1411 slit_id = cpl_table_get_data_int(coeff,
"slit_id");
1412 npoints = cpl_table_get_nrow(coeff);
1417 for (i = 0; i < npoints; i++) {
1418 for (j = 0; j < nmaskslits; j++) {
1419 if (slit_id[i] == mslit_id[j]) {
1421 cpl_table_set_double(coeff,
"xmask", i, mxbottom[j]);
1422 cpl_table_set_double(coeff,
"ymask", i, mybottom[j]);
1425 cpl_table_set_double(coeff,
"xmask", i, mxtop[j]);
1426 cpl_table_set_double(coeff,
"ymask", i, mytop[j]);
1435 if (cpl_table_has_invalid(coeff,
"xmask")) {
1436 cpl_error_set(func, CPL_ERROR_INCOMPATIBLE_INPUT);
1437 cpl_table_delete(coeff);
1444 for (j = 0; j < 3; j++) {
1445 if (cpl_table_has_column(coeff, clab[j])) {
1446 cpl_table_and_selected_invalid(coeff, clab[j]);
1448 if (cpl_table_not_selected(coeff))
1449 dummy = cpl_table_extract_selected(coeff);
1453 npoints = cpl_table_get_nrow(dummy);
1462 ci = cpl_vector_wrap(npoints,
1463 cpl_table_get_data_double(dummy, clab[j]));
1464 xmask = cpl_vector_wrap(npoints,
1465 cpl_table_get_data_double(dummy,
"xmask"));
1466 ymask = cpl_vector_wrap(npoints,
1467 cpl_table_get_data_double(dummy,
"ymask"));
1468 mask = cpl_bivector_wrap_vectors(xmask, ymask);
1470 poly = cpl_polynomial_fit_2d_create(mask, ci, order, NULL);
1472 cpl_bivector_unwrap_vectors(mask);
1473 cpl_vector_unwrap(ci);
1474 cpl_vector_unwrap(xmask);
1475 cpl_vector_unwrap(ymask);
1478 cpl_size p[2] = {0, 0};
1479 poly = cpl_polynomial_new(2);
1480 cpl_polynomial_set_coeff(poly, p,
1481 cpl_table_get_column_median(dummy, clab[j]));
1484 cpl_table_delete(dummy);
1486 global = write_global_distortion(global, j + 7, poly);
1488 cpl_polynomial_delete(poly);
1489 cpl_table_select_all(coeff);
1496 cpl_table_delete(coeff);
1546 const char *func =
"mos_build_slit_location";
1548 cpl_propertylist *sort_col;
1549 cpl_polynomial *ids0;
1550 cpl_polynomial *crv[3];
1551 cpl_polynomial *loc_crv;
1569 if (global == NULL || maskslits == NULL) {
1570 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
1574 nslits = cpl_table_get_nrow(maskslits);
1575 slit_id = cpl_table_get_data_int(maskslits,
"slit_id");
1576 mxtop = cpl_table_get_data_double(maskslits,
"xtop");
1577 mytop = cpl_table_get_data_double(maskslits,
"ytop");
1578 mxbottom = cpl_table_get_data_double(maskslits,
"xbottom");
1579 mybottom = cpl_table_get_data_double(maskslits,
"ybottom");
1581 slits = cpl_table_duplicate(maskslits);
1583 xtop = cpl_table_get_data_double(slits,
"xtop");
1584 ytop = cpl_table_get_data_double(slits,
"ytop");
1585 xbottom = cpl_table_get_data_double(slits,
"xbottom");
1586 ybottom = cpl_table_get_data_double(slits,
"ybottom");
1588 ids0 = read_global_distortion(global, 0);
1589 crv[0] = read_global_distortion(global, 7);
1590 crv[1] = read_global_distortion(global, 8);
1591 crv[2] = read_global_distortion(global, 9);
1593 loc_crv = cpl_polynomial_new(1);
1595 point = cpl_vector_new(2);
1596 dpoint = cpl_vector_get_data(point);
1598 for (i = 0; i < nslits; i++) {
1599 dpoint[0] = mxtop[i];
1600 dpoint[1] = mytop[i];
1602 xtop[i] = cpl_polynomial_eval(ids0, point);
1604 for (j = 0; j < 3; j++)
1606 cpl_polynomial_set_coeff(loc_crv, &j,
1607 cpl_polynomial_eval(crv[j], point));
1609 ytop[i] = cpl_polynomial_eval_1d(loc_crv, xtop[i], NULL);
1611 dpoint[0] = mxbottom[i];
1612 dpoint[1] = mybottom[i];
1613 xbottom[i] = cpl_polynomial_eval(ids0, point);
1615 for (j = 0; j < 3; j++)
1617 cpl_polynomial_set_coeff(loc_crv, &j,
1618 cpl_polynomial_eval(crv[j], point));
1620 ybottom[i] = cpl_polynomial_eval_1d(loc_crv, xbottom[i], NULL);
1623 cpl_vector_delete(point);
1624 cpl_polynomial_delete(ids0);
1625 cpl_polynomial_delete(loc_crv);
1626 for (j = 0; j < 3; j++)
1627 cpl_polynomial_delete(crv[j]);
1629 sort_col = cpl_propertylist_new();
1630 cpl_propertylist_append_bool(sort_col,
"ytop", 1);
1631 cpl_table_sort(slits, sort_col);
1632 cpl_table_sort(maskslits, sort_col);
1633 cpl_propertylist_delete(sort_col);
1639 cpl_table_and_selected_double(slits,
"ybottom", CPL_GREATER_THAN, ysize-1);
1640 cpl_table_or_selected_double(slits,
"ytop", CPL_LESS_THAN, 0);
1641 cpl_table_erase_selected(slits);
1643 nslits = cpl_table_get_nrow(slits);
1646 cpl_msg_warning(func,
"No slits found on the CCD");
1647 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
1648 cpl_table_delete(slits);
1653 cpl_msg_info(func,
"Slit location: %"CPL_SIZE_FORMAT
" slits are entirely or partially "
1654 "contained in CCD", nslits);
1656 cpl_msg_info(func,
"Slit location: %"CPL_SIZE_FORMAT
" slit is entirely or partially "
1657 "contained in CCD", nslits);
1693 const char *func =
"mos_build_curv_coeff";
1695 const char *clab[6] = {
"c0",
"c1",
"c2",
"c3",
"c4",
"c5"};
1698 cpl_polynomial *crv[3];
1700 cpl_table *polytraces;
1713 if (global == NULL || slits == NULL || maskslits == NULL) {
1714 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
1718 nslits = cpl_table_get_nrow(maskslits);
1719 slit_id = cpl_table_get_data_int(maskslits,
"slit_id");
1720 xtop = cpl_table_get_data_double(maskslits,
"xtop");
1721 ytop = cpl_table_get_data_double(maskslits,
"ytop");
1722 xbottom = cpl_table_get_data_double(maskslits,
"xbottom");
1723 ybottom = cpl_table_get_data_double(maskslits,
"ybottom");
1725 polytraces = cpl_table_new(2*nslits);
1726 cpl_table_new_column(polytraces,
"slit_id", CPL_TYPE_INT);
1727 for (i = 0; i < 3; i++)
1728 cpl_table_new_column(polytraces, clab[i], CPL_TYPE_DOUBLE);
1730 crv[0] = read_global_distortion(global, 7);
1731 crv[1] = read_global_distortion(global, 8);
1732 crv[2] = read_global_distortion(global, 9);
1734 point = cpl_vector_new(2);
1735 dpoint = cpl_vector_get_data(point);
1737 for (i = 0; i < nslits; i++) {
1738 for (j = 0; j < 2; j++) {
1740 cpl_table_set_int(polytraces,
"slit_id", 2*i+j, slit_id[i]);
1743 dpoint[0] = xbottom[i];
1744 dpoint[1] = ybottom[i];
1747 dpoint[0] = xtop[i];
1748 dpoint[1] = ytop[i];
1751 for (k = 0; k < 3; k++)
1753 cpl_table_set_double(polytraces, clab[k], 2*i+j,
1754 cpl_polynomial_eval(crv[k], point));
1758 cpl_vector_delete(point);
1759 for (j = 0; j < 3; j++)
1760 cpl_polynomial_delete(crv[j]);
1766 nvalid = cpl_table_get_nrow(slits);
1767 valid_id = cpl_table_get_data_int(slits,
"slit_id");
1768 cpl_table_unselect_all(polytraces);
1769 for (i = 0; i < nslits; i++) {
1771 for (j = 0; j < nvalid; j++) {
1772 if (slit_id[i] == valid_id[j]) {
1778 cpl_table_select_row(polytraces, 2*i);
1779 cpl_table_select_row(polytraces, 2*i + 1);
1782 cpl_table_erase_selected(polytraces);
1784 nslits = cpl_table_get_nrow(polytraces);
1787 cpl_msg_warning(func,
"No slits found on the CCD");
1788 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
1789 cpl_table_delete(polytraces);
1794 cpl_msg_info(func,
"Curvature model: %d slits are entirely or "
1795 "partially contained in CCD", nslits / 2);
1797 cpl_msg_info(func,
"Curvature model: %d slit is entirely or "
1798 "partially contained in CCD", nslits / 2);
1847 const char *func =
"mos_build_disp_coeff";
1849 const char *clab[6] = {
"c0",
"c1",
"c2",
"c3",
"c4",
"c5"};
1851 cpl_polynomial *ids[6];
1853 cpl_table *idscoeff;
1868 if (global == NULL || slits == NULL) {
1869 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
1873 nslits = cpl_table_get_nrow(slits);
1874 position = cpl_table_get_data_int(slits,
"position");
1875 length = cpl_table_get_data_int(slits,
"length");
1876 xtop = cpl_table_get_data_double(slits,
"xtop");
1877 ytop = cpl_table_get_data_double(slits,
"ytop");
1878 xbottom = cpl_table_get_data_double(slits,
"xbottom");
1879 ybottom = cpl_table_get_data_double(slits,
"ybottom");
1881 for (i = 0; i < 6; i++)
1882 ids[i] = read_global_distortion(global, i);
1884 for (i = 0; i < 6; i++)
1891 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
1896 for (i = 0; i < nslits; i++)
1899 idscoeff = cpl_table_new(nrows);
1901 for (j = 0; j <= order; j++)
1902 cpl_table_new_column(idscoeff, clab[j], CPL_TYPE_DOUBLE);
1904 cpl_table_new_column(idscoeff,
"error", CPL_TYPE_DOUBLE);
1905 cpl_table_fill_column_window_double(idscoeff,
"error", 0, nrows, 0.0);
1906 cpl_table_new_column(idscoeff,
"nlines", CPL_TYPE_INT);
1907 cpl_table_fill_column_window_int(idscoeff,
"nlines", 0, nrows, 0);
1909 point = cpl_vector_new(2);
1910 dpoint = cpl_vector_get_data(point);
1912 for (i = 0; i < nslits; i++) {
1918 yhig = ylow + length[i];
1920 for (j = 0; j <= order; j++) {
1922 for (k = 0; k < length[i]; k++) {
1923 dpoint[0] = xbottom[i] + k*(xtop[i]-xbottom[i])/length[i];
1924 dpoint[1] = ybottom[i] + k*(ytop[i]-ybottom[i])/length[i];
1925 cpl_table_set_double(idscoeff, clab[j], ylow + k,
1926 cpl_polynomial_eval(ids[j], point));
1930 for (k = 0; k < length[i]; k++) {
1931 cpl_table_set_double(idscoeff, clab[0], ylow + k,
1932 xbottom[i] + k*(xtop[i]-xbottom[i])/length[i]);
1938 cpl_vector_delete(point);
1939 for (j = 0; j < 6; j++)
1940 cpl_polynomial_delete(ids[j]);
1970 cpl_table *polytraces,
double reference,
1971 double blue,
double red,
double dispersion)
1973 const char *func =
"mos_subtract_sky";
1975 const char *clab[6] = {
"c0",
"c1",
"c2",
"c3",
"c4",
"c5"};
1982 cpl_polynomial *polytop;
1983 cpl_polynomial *polybot;
1984 cpl_polynomial *trend;
1998 int pixel_above, pixel_below, refpixel, start_pixel, end_pixel;
2002 int missing_top, missing_bot;
2011 if (science == NULL || slits == NULL || polytraces == NULL) {
2012 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
2016 if (dispersion <= 0.0) {
2017 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
2021 if (red - blue < dispersion) {
2022 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
2026 nx = cpl_image_get_size_x(science);
2027 ny = cpl_image_get_size_y(science);
2029 sky = cpl_image_new(nx, ny, CPL_TYPE_FLOAT);
2031 sdata = cpl_image_get_data(science);
2032 kdata = cpl_image_get_data(sky);
2034 nslits = cpl_table_get_nrow(slits);
2035 order = cpl_table_get_ncol(polytraces) - 2;
2036 length = cpl_table_get_data_int(slits,
"length");
2037 slit_id = cpl_table_get_data_int(slits,
"slit_id");
2044 pixel_above = STRETCH_FACTOR * (red - reference) / dispersion;
2045 pixel_below = STRETCH_FACTOR * (reference - blue) / dispersion;
2047 for (i = 0; i < nslits; i++) {
2058 refpixel = cpl_table_get_double(slits,
"xtop", i, NULL);
2060 start_pixel = refpixel - pixel_below;
2061 if (start_pixel < 0)
2064 end_pixel = refpixel + pixel_above;
2069 polytop = cpl_polynomial_new(1);
2070 for (k = 0; k <= order; k++) {
2071 coeff = cpl_table_get_double(polytraces, clab[k], 2*i, &null);
2073 cpl_polynomial_delete(polytop);
2077 cpl_polynomial_set_coeff(polytop, &k, coeff);
2081 polybot = cpl_polynomial_new(1);
2082 for (k = 0; k <= order; k++) {
2083 coeff = cpl_table_get_double(polytraces, clab[k], 2*i+1, &null);
2085 cpl_polynomial_delete(polybot);
2089 cpl_polynomial_set_coeff(polybot, &k, coeff);
2092 if (missing_top && missing_bot) {
2093 cpl_msg_debug(func,
"Slit %d was not traced: no extraction!",
2105 cpl_msg_debug(func,
"Upper edge of slit %d was not traced: "
2106 "the spectral curvature of the lower edge "
2107 "is used instead.", slit_id[i]);
2108 polytop = cpl_polynomial_duplicate(polybot);
2109 ytop = cpl_table_get_double(slits,
"ytop", i, NULL);
2110 ybot = cpl_table_get_double(slits,
"ybottom", i, NULL);
2112 coeff = cpl_polynomial_get_coeff(polybot, &k);
2113 coeff += ytop - ybot;
2114 cpl_polynomial_set_coeff(polytop, &k, coeff);
2118 cpl_msg_debug(func,
"Lower edge of slit %d was not traced: "
2119 "the spectral curvature of the upper edge "
2120 "is used instead.", slit_id[i]);
2121 polybot = cpl_polynomial_duplicate(polytop);
2122 ytop = cpl_table_get_double(slits,
"ytop", i, NULL);
2123 ybot = cpl_table_get_double(slits,
"ybottom", i, NULL);
2125 coeff = cpl_polynomial_get_coeff(polytop, &k);
2126 coeff -= ytop - ybot;
2127 cpl_polynomial_set_coeff(polybot, &k, coeff);
2135 for (j = start_pixel; j < end_pixel; j++) {
2136 top = cpl_polynomial_eval_1d(polytop, j, NULL);
2137 bot = cpl_polynomial_eval_1d(polybot, j, NULL);
2138 itop = floor(top + 0.5) + 1;
2139 ibot = floor(bot + 0.5);
2148 list = cpl_bivector_new(npix);
2149 listx = cpl_bivector_get_x(list);
2150 listy = cpl_bivector_get_y(list);
2151 dlistx = cpl_vector_get_data(listx);
2152 dlisty = cpl_vector_get_data(listy);
2154 for (k = 0; k < npix; k++) {
2156 dlisty[k] = sdata[j + (ibot + k)*nx];
2159 if (robustLinearFit(list, &q, &m, &err)) {
2160 cpl_bivector_delete(list);
2164 cpl_bivector_delete(list);
2166 for (k = 0; k < npix; k++) {
2167 kdata[j + (ibot + k)*nx] = m*k + q;
2170 if (npix > window) {
2179 for (k = 0; k < npix; k++)
2180 if (fabs(sdata[j + (ibot + k)*nx] - m*k - q) < err)
2186 list = cpl_bivector_new(count);
2187 listx = cpl_bivector_get_x(list);
2188 listy = cpl_bivector_get_y(list);
2189 dlistx = cpl_vector_get_data(listx);
2190 dlisty = cpl_vector_get_data(listy);
2193 for (k = 0; k < npix; k++) {
2194 if (fabs(sdata[j + (ibot + k)*nx] - m*k - q) < err) {
2196 dlisty[count] = sdata[j + (ibot + k)*nx];
2201 trend = cpl_polynomial_fit_1d_create(listx, listy, 2, &err);
2203 cpl_bivector_delete(list);
2208 for (k = 0; k < npix; k++)
2209 if (fabs(sdata[j + (ibot + k)*nx]
2210 - cpl_polynomial_eval_1d(trend, k, NULL)) < err)
2214 cpl_polynomial_delete(trend);
2218 list = cpl_bivector_new(count);
2219 listx = cpl_bivector_get_x(list);
2220 listy = cpl_bivector_get_y(list);
2221 dlistx = cpl_vector_get_data(listx);
2222 dlisty = cpl_vector_get_data(listy);
2225 for (k = 0; k < npix; k++) {
2226 if (fabs(sdata[j + (ibot + k)*nx]
2227 - cpl_polynomial_eval_1d(trend, k, NULL)) < err) {
2229 dlisty[count] = sdata[j + (ibot + k)*nx];
2234 cpl_polynomial_delete(trend);
2236 trend = cpl_polynomial_fit_1d_create(listx, listy, 3, &err);
2238 cpl_bivector_delete(list);
2240 for (k = 0; k < npix; k++) {
2241 kdata[j + (ibot + k)*nx] = cpl_polynomial_eval_1d(trend,
2245 cpl_polynomial_delete(trend);
2248 cpl_polynomial_delete(polytop);
2249 cpl_polynomial_delete(polybot);
2252 cpl_image_subtract(science, sky);
2291 cpl_table *slits, cpl_table *polytraces,
2292 double reference,
double blue,
double red,
2293 double dispersion,
int sradius,
int polyorder)
2295 const char *func =
"mos_normalise_flat";
2297 const char *clab[6] = {
"c0",
"c1",
"c2",
"c3",
"c4",
"c5"};
2300 cpl_image *rectified;
2301 cpl_image *smo_flat;
2303 cpl_vector *positions;
2305 cpl_vector *smo_flux;
2306 cpl_polynomial *trend;
2307 cpl_polynomial *polytop;
2308 cpl_polynomial *polybot;
2318 double vtop, vbot, value;
2328 int pixel_above, pixel_below, refpixel, start_pixel, end_pixel;
2329 int nx, ny, nsubx, nsuby;
2330 int xlow, ylow, xhig, yhig;
2334 int missing_top, missing_bot;
2347 if (flat == NULL || slits == NULL || polytraces == NULL) {
2348 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
2352 if (dispersion <= 0.0) {
2353 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
2357 if (red - blue < dispersion) {
2358 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
2363 blue, red, dispersion, 0, NULL);
2365 nx = cpl_image_get_size_x(rectified);
2366 ny = cpl_image_get_size_y(rectified);
2368 smo_flat = cpl_image_new(cpl_image_get_size_x(spatial),
2369 cpl_image_get_size_y(spatial), CPL_TYPE_FLOAT);
2370 wdata = cpl_image_get_data(smo_flat);
2372 nslits = cpl_table_get_nrow(slits);
2373 order = cpl_table_get_ncol(polytraces) - 2;
2374 position = cpl_table_get_data_int(slits,
"position");
2375 length = cpl_table_get_data_int(slits,
"length");
2376 slit_id = cpl_table_get_data_int(slits,
"slit_id");
2383 pixel_above = STRETCH_FACTOR * (red - reference) / dispersion;
2384 pixel_below = STRETCH_FACTOR * (reference - blue) / dispersion;
2388 for (i = 0; i < nslits; i++) {
2403 ylow = position[i] + 1;
2404 yhig = ylow + length[i] - 1;
2406 exslit = cpl_image_extract(rectified, xlow, ylow, xhig, yhig);
2408 if (polyorder < 0) {
2410 cpl_image_turn(exslit, -1);
2412 nsubx = cpl_image_get_size_x(exslit);
2413 nsuby = cpl_image_get_size_y(exslit);
2414 data = cpl_image_get_data(exslit);
2415 flux = cpl_vector_new(nsubx);
2417 uradius = nsubx / 2;
2418 if (uradius > sradius)
2421 for (j = 0; j < nsuby; j++) {
2422 fdata = cpl_vector_get_data(flux);
2424 for (k = 0; k < nsubx; k++)
2426 smo_flux = cpl_vector_filter_median_create(flux, uradius);
2427 fdata = cpl_vector_get_data(smo_flux);
2429 for (k = 0; k < nsubx; k++)
2431 cpl_vector_delete(smo_flux);
2435 cpl_vector_delete(flux);
2471 cpl_image_turn(exslit, 1);
2472 nsubx = cpl_image_get_size_x(exslit);
2473 nsuby = cpl_image_get_size_y(exslit);
2474 data = cpl_image_get_data(exslit);
2476 for (j = 0; j < nsuby; j++) {
2477 flux = cpl_vector_new(nsubx);
2478 fdata = cpl_vector_get_data(flux);
2480 for (k = 0; k < nsubx; k++)
2482 smo_flux = cpl_vector_filter_median_create(flux, sradius);
2483 cpl_vector_delete(flux);
2484 fdata = cpl_vector_get_data(smo_flux);
2486 for (k = 0; k < nsubx; k++)
2488 cpl_vector_delete(smo_flux);
2498 nsubx = cpl_image_get_size_x(exslit);
2499 nsuby = cpl_image_get_size_y(exslit);
2500 data = cpl_image_get_data(exslit);
2502 for (j = 0; j < nsuby; j++) {
2510 for (k = 0; k < nsubx; k++)
2514 if (npoints > polyorder + 1) {
2520 flux = cpl_vector_new(npoints);
2521 fdata = cpl_vector_get_data(flux);
2522 positions = cpl_vector_new(npoints);
2523 pdata = cpl_vector_get_data(positions);
2527 for (k = 0; k < nsubx; k++) {
2529 fdata[npoints] = p[k];
2535 trend = cpl_polynomial_fit_1d_create(positions, flux,
2538 cpl_vector_delete(flux);
2539 cpl_vector_delete(positions);
2543 for (k = 0; k < nsubx; k++)
2545 p[k] = cpl_polynomial_eval_1d(trend, k, NULL);
2546 cpl_polynomial_delete(trend);
2549 cpl_msg_warning(func,
"Invalid flat field flux fit "
2562 refpixel = cpl_table_get_double(slits,
"xtop", i, NULL);
2564 start_pixel = refpixel - pixel_below;
2565 if (start_pixel < 0)
2568 end_pixel = refpixel + pixel_above;
2573 polytop = cpl_polynomial_new(1);
2574 for (k = 0; k <= order; k++) {
2575 coeff = cpl_table_get_double(polytraces, clab[k], 2*i, &null);
2577 cpl_polynomial_delete(polytop);
2581 cpl_polynomial_set_coeff(polytop, &k, coeff);
2585 polybot = cpl_polynomial_new(1);
2586 for (k = 0; k <= order; k++) {
2587 coeff = cpl_table_get_double(polytraces, clab[k], 2*i+1, &null);
2589 cpl_polynomial_delete(polybot);
2593 cpl_polynomial_set_coeff(polybot, &k, coeff);
2596 if (missing_top && missing_bot) {
2597 cpl_msg_debug(func,
"Slit %d was not traced: no extraction!",
2609 cpl_msg_debug(func,
"Upper edge of slit %d was not traced: "
2610 "the spectral curvature of the lower edge "
2611 "is used instead.", slit_id[i]);
2612 polytop = cpl_polynomial_duplicate(polybot);
2613 ytop = cpl_table_get_double(slits,
"ytop", i, NULL);
2614 ybot = cpl_table_get_double(slits,
"ybottom", i, NULL);
2616 coeff = cpl_polynomial_get_coeff(polybot, &k);
2617 coeff += ytop - ybot;
2618 cpl_polynomial_set_coeff(polytop, &k, coeff);
2622 cpl_msg_debug(func,
"Lower edge of slit %d was not traced: "
2623 "the spectral curvature of the upper edge "
2624 "is used instead.", slit_id[i]);
2625 polybot = cpl_polynomial_duplicate(polytop);
2626 ytop = cpl_table_get_double(slits,
"ytop", i, NULL);
2627 ybot = cpl_table_get_double(slits,
"ybottom", i, NULL);
2629 coeff = cpl_polynomial_get_coeff(polytop, &k);
2630 coeff -= ytop - ybot;
2631 cpl_polynomial_set_coeff(polybot, &k, coeff);
2642 nx = cpl_image_get_size_x(flat);
2643 ny = cpl_image_get_size_y(flat);
2645 sdata = cpl_image_get_data(spatial);
2646 xdata = cpl_image_get_data(exslit);
2647 npseudo = cpl_image_get_size_y(exslit) - 1;
2653 for (j = start_pixel; j < end_pixel; j++) {
2654 top = cpl_polynomial_eval_1d(polytop, j, NULL);
2655 bot = cpl_polynomial_eval_1d(polybot, j, NULL);
2656 for (k = 0; k <= npseudo; k++) {
2657 ypos = top - k*(top-bot)/npseudo;
2667 if (yint < 0 || yint >= ny-1) {
2672 value = sdata[j + nx*yint];
2674 fvalue = value - ivalue;
2675 if (ivalue < npseudo && ivalue >= 0) {
2676 vtop = xdata[j + nx*(npseudo-ivalue)];
2677 vbot = xdata[j + nx*(npseudo-ivalue-1)];
2678 wdata[j + nx*yint] = vtop*(1-fvalue) + vbot*fvalue;
2688 if (yprev - yint > 1) {
2689 value = sdata[j + nx*(yint+1)];
2691 fvalue = value - ivalue;
2692 if (ivalue < npseudo && ivalue >= 0) {
2693 vtop = xdata[j + nx*(npseudo-ivalue)];
2694 vbot = xdata[j + nx*(npseudo-ivalue-1)];
2695 wdata[j + nx*(yint+1)] = vtop*(1-fvalue)
2704 cpl_polynomial_delete(polytop);
2705 cpl_polynomial_delete(polybot);
2706 cpl_image_delete(exslit);
2709 cpl_image_delete(rectified);
2711 cpl_image_divide(flat, smo_flat);
2744 const char *func =
"mos_normalise_longflat";
2746 cpl_image *smo_flat;
2749 cpl_vector *smo_flux;
2750 cpl_vector *positions;
2751 cpl_polynomial *trend;
2765 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
2769 if (sradius < 1 || dradius < 1) {
2770 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
2774 smo_flat = cpl_image_duplicate(flat);
2776 if (polyorder < 0) {
2782 cpl_image_turn(smo_flat, -1);
2784 nx = cpl_image_get_size_x(smo_flat);
2785 ny = cpl_image_get_size_y(smo_flat);
2786 data = cpl_image_get_data(smo_flat);
2788 for (i = 0; i < ny; i++) {
2789 flux = cpl_vector_new(nx);
2790 fdata = cpl_vector_get_data(flux);
2792 for (j = 0; j < nx; j++)
2794 smo_flux = cpl_vector_filter_median_create(flux, sradius);
2795 cpl_vector_delete(flux);
2796 fdata = cpl_vector_get_data(smo_flux);
2798 for (j = 0; j < nx; j++)
2800 cpl_vector_delete(smo_flux);
2808 cpl_image_turn(smo_flat, 1);
2810 nx = cpl_image_get_size_x(smo_flat);
2811 ny = cpl_image_get_size_y(smo_flat);
2812 data = cpl_image_get_data(smo_flat);
2814 for (i = 0; i < ny; i++) {
2815 flux = cpl_vector_new(nx);
2816 fdata = cpl_vector_get_data(flux);
2818 for (j = 0; j < nx; j++)
2820 smo_flux = cpl_vector_filter_median_create(flux, sradius);
2821 cpl_vector_delete(flux);
2822 fdata = cpl_vector_get_data(smo_flux);
2824 for (j = 0; j < nx; j++)
2826 cpl_vector_delete(smo_flux);
2836 cpl_image_turn(smo_flat, -1);
2838 nx = cpl_image_get_size_x(smo_flat);
2839 ny = cpl_image_get_size_y(smo_flat);
2840 data = cpl_image_get_data(smo_flat);
2842 profile = cpl_image_collapse_median_create(smo_flat, 1, 0, 0);
2843 level = cpl_image_get_data(profile);
2845 for (i = 0; i < ny; i++) {
2855 for (j = 0; j < nx; j++)
2856 if (fabs(p[j]/level[i] - 1) < 0.20)
2859 if (npoints > polyorder + 1) {
2865 flux = cpl_vector_new(npoints);
2866 fdata = cpl_vector_get_data(flux);
2867 positions = cpl_vector_new(npoints);
2868 pdata = cpl_vector_get_data(positions);
2872 for (j = 0; j < nx; j++) {
2873 if (fabs(p[j]/level[i] - 1) < 0.20) {
2874 fdata[npoints] = p[j];
2880 trend = cpl_polynomial_fit_1d_create(positions, flux,
2883 cpl_vector_delete(flux);
2884 cpl_vector_delete(positions);
2888 for (j = 0; j < nx; j++)
2889 p[j] = cpl_polynomial_eval_1d(trend, j, NULL);
2890 cpl_polynomial_delete(trend);
2893 cpl_msg_warning(func,
2894 "Invalid flat field flux fit (ignored)");
2899 cpl_image_delete(profile);
2900 cpl_image_turn(smo_flat, 1);
2904 cpl_image_divide(flat, smo_flat);
2934 int order,
int global)
2936 const char *clab[6] = {
"c0",
"c1",
"c2",
"c3",
"c4",
"c5"};
2938 int nrow = cpl_table_get_nrow(slits);
2943 return CPL_ERROR_NONE;
2945 cpl_table_new_column(idscoeff,
"x", CPL_TYPE_DOUBLE);
2946 cpl_table_new_column(idscoeff,
"y", CPL_TYPE_DOUBLE);
2948 for (i = 0; i < nrow; i++) {
2949 int position = cpl_table_get_int (slits,
"position", i, NULL);
2950 int length = cpl_table_get_int (slits,
"length", i, NULL);
2951 double xtop = cpl_table_get_double(slits,
"xtop", i, NULL);
2952 double xbot = cpl_table_get_double(slits,
"xbottom", i, NULL);
2953 double ytop = cpl_table_get_double(slits,
"ytop", i, NULL);
2954 double ybot = cpl_table_get_double(slits,
"ybottom", i, NULL);
2955 double dx = xtop - xbot;
2956 double dy = ytop - ybot;
2957 cpl_table *table = cpl_table_extract(idscoeff, position, length);
2962 cpl_table_erase_window(idscoeff, position, length);
2963 cpl_table_insert(idscoeff, table, position);
2965 cpl_table_delete(table);
2967 for (j = 0; j < length; j++) {
2968 cpl_table_set_double(idscoeff,
"x", j + position,
2969 xbot + j*(dx/length));
2970 cpl_table_set_double(idscoeff,
"y", j + position,
2971 ybot + j*(dy/length));
2981 nrow = cpl_table_get_nrow(idscoeff);
2983 for (i = 0; i < 6; i++) {
2994 if (!cpl_table_has_column(idscoeff, clab[i]))
2997 npoints = nrow - cpl_table_count_invalid(idscoeff, clab[i]);
3001 dummy = cpl_table_new(nrow);
3002 cpl_table_duplicate_column(dummy,
"x", idscoeff,
"x");
3003 cpl_table_duplicate_column(dummy,
"y", idscoeff,
"y");
3004 cpl_table_duplicate_column(dummy, clab[i], idscoeff, clab[i]);
3005 cpl_table_erase_invalid(dummy);
3007 x = cpl_vector_wrap(npoints, cpl_table_get_data_double(dummy,
"x"));
3008 y = cpl_vector_wrap(npoints, cpl_table_get_data_double(dummy,
"y"));
3009 z = cpl_bivector_wrap_vectors(x, y);
3010 c = cpl_vector_wrap(npoints, cpl_table_get_data_double(dummy,
3012 p = cpl_polynomial_fit_2d_create(z, c, 2, NULL);
3013 cpl_bivector_unwrap_vectors(z);
3014 cpl_vector_unwrap(x);
3015 cpl_vector_unwrap(y);
3016 cpl_vector_unwrap(c);
3017 cpl_table_delete(dummy);
3019 point = cpl_vector_new(2);
3020 dpoint = cpl_vector_get_data(point);
3021 for (j = 0; j < nrow; j++) {
3022 dpoint[0] = cpl_table_get_double(idscoeff,
"x", j, NULL);
3023 dpoint[1] = cpl_table_get_double(idscoeff,
"y", j, NULL);
3024 cpl_table_set_double(idscoeff, clab[i], j,
3025 cpl_polynomial_eval(p, point));
3027 cpl_vector_delete(point);
3028 cpl_polynomial_delete(p);
3032 return CPL_ERROR_NONE;
3062 cpl_image *wavemap,
int mode,
3065 const char *func =
"mos_interpolate_wavecalib";
3067 const char *clab[6] = {
"c0",
"c1",
"c2",
"c3",
"c4",
"c5"};
3071 cpl_vector *positions;
3072 cpl_polynomial *trend;
3083 int nrows, first_row, last_row;
3085 int npoints, rpoints;
3092 if (idscoeff == NULL)
3093 return cpl_error_set(func, CPL_ERROR_NULL_INPUT);
3095 if (mode < 0 || mode > 2)
3096 return cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
3098 if (mode == 0 || degree < 0)
3099 return CPL_ERROR_NONE;
3107 cpl_image_turn(wavemap, -1);
3109 nx = cpl_image_get_size_x(wavemap);
3110 ny = cpl_image_get_size_y(wavemap);
3111 data = cpl_image_get_data(wavemap);
3113 for (i = 0; i < ny; i++) {
3122 for (j = 0; j < nx; j++)
3126 if (npoints > polyorder + 1) {
3132 wave = cpl_vector_new(npoints);
3133 wdata = cpl_vector_get_data(wave);
3134 positions = cpl_vector_new(npoints);
3135 pdata = cpl_vector_get_data(positions);
3139 for (j = 0; j < nx; j++) {
3141 wdata[npoints] = p[j];
3147 trend = cpl_polynomial_fit_1d_create(positions, wave,
3150 ksigma = 3*sqrt(mse);
3152 cpl_vector_delete(wave);
3153 cpl_vector_delete(positions);
3163 for (j = 0; j < nx; j++)
3165 if (fabs(cpl_polynomial_eval_1d(trend, j, NULL)
3169 if (rpoints < npoints && rpoints > polyorder + 1) {
3171 wave = cpl_vector_new(rpoints);
3172 wdata = cpl_vector_get_data(wave);
3173 positions = cpl_vector_new(rpoints);
3174 pdata = cpl_vector_get_data(positions);
3178 for (j = 0; j < nx; j++) {
3180 if (fabs(cpl_polynomial_eval_1d(trend,
3183 wdata[npoints] = p[j];
3190 cpl_polynomial_delete(trend);
3191 trend = cpl_polynomial_fit_1d_create(positions, wave,
3194 cpl_vector_delete(wave);
3195 cpl_vector_delete(positions);
3202 for (j = 0; j < nx; j++)
3204 p[j] = cpl_polynomial_eval_1d(trend, j, NULL);
3206 else if (mode == 2) {
3207 for (j = 0; j < nx; j++)
3208 p[j] = cpl_polynomial_eval_1d(trend, j, NULL);
3210 cpl_polynomial_delete(trend);
3213 cpl_msg_warning(func,
3214 "Invalid wavelength field fit (ignored)");
3220 cpl_image_turn(wavemap, 1);
3229 nrows = cpl_table_get_nrow(idscoeff);
3232 while (order < 6 && cpl_table_has_column(idscoeff, clab[order]))
3237 for (k = 0; k <= order; k++) {
3239 if (cpl_table_has_column(idscoeff, clab[k])) {
3240 m = cpl_table_get_column_median(idscoeff, clab[k]);
3241 cpl_table_fill_column_window_double(idscoeff, clab[k],
3246 return CPL_ERROR_NONE;
3250 while (!cpl_table_is_valid(idscoeff, clab[0], first_row))
3253 last_row = nrows - 1;
3254 while (!cpl_table_is_valid(idscoeff, clab[0], last_row))
3257 for (k = 0; k <= order; k++) {
3259 npoints = nrows - cpl_table_count_invalid(idscoeff, clab[k]);
3260 wave = cpl_vector_new(npoints);
3261 wdata = cpl_vector_get_data(wave);
3262 positions = cpl_vector_new(npoints);
3263 pdata = cpl_vector_get_data(positions);
3266 for (i = first_row; i <= last_row; i++) {
3267 c = cpl_table_get_double(idscoeff, clab[k], i, &null);
3285 p = cpl_vector_extract(positions, 2, npoints - 2, 1);
3286 w = cpl_vector_extract(wave, 2, npoints - 2, 1);
3293 list = cpl_bivector_wrap_vectors(p, w);
3295 robustLinearFit(list, &q, &m, &mse);
3296 cpl_bivector_unwrap_vectors(list);
3297 for (i = first_row; i <= last_row; i++)
3298 cpl_table_set_double(idscoeff, clab[k], i, q + m*i);
3301 cpl_vector_delete(p);
3302 cpl_vector_delete(w);
3310 trend = cpl_polynomial_fit_1d_create(positions, wave, degree, &mse);
3312 ksigma = 3*sqrt(mse);
3314 cpl_vector_delete(wave);
3315 cpl_vector_delete(positions);
3323 for (i = first_row; i <= last_row; i++) {
3324 c = cpl_table_get_double(idscoeff, clab[k], i, &null);
3326 if (fabs(cpl_polynomial_eval_1d(trend, i, NULL) - c)
3333 if (rpoints > 0 && rpoints < npoints) {
3334 cpl_msg_debug(func,
"%d points rejected from "
3335 "wavelength calibration fit",
3338 wave = cpl_vector_new(rpoints);
3339 wdata = cpl_vector_get_data(wave);
3340 positions = cpl_vector_new(rpoints);
3341 pdata = cpl_vector_get_data(positions);
3344 for (i = first_row; i <= last_row; i++) {
3345 c = cpl_table_get_double(idscoeff, clab[k], i, &null);
3347 if (fabs(cpl_polynomial_eval_1d(trend, i, NULL) - c)
3357 cpl_polynomial_delete(trend);
3358 trend = cpl_polynomial_fit_1d_create(positions,
3359 wave, degree, NULL);
3362 cpl_vector_delete(wave);
3363 cpl_vector_delete(positions);
3369 for (i = first_row; i <= last_row; i++) {
3371 if (!cpl_table_is_valid(idscoeff, clab[k], i)) {
3372 cpl_table_set_double(idscoeff, clab[k], i,
3373 cpl_polynomial_eval_1d(trend, i,
3377 else if (mode == 2) {
3378 cpl_table_set_double(idscoeff, clab[k], i,
3379 cpl_polynomial_eval_1d(trend, i, NULL));
3382 cpl_polynomial_delete(trend);
3385 cpl_msg_warning(func,
"Invalid IDS coefficient fit (ignored)");
3390 return CPL_ERROR_NONE;
3423 cpl_table *overscans)
3425 const char *func =
"mos_remove_bias";
3427 cpl_image *unbiased;
3428 cpl_image *overscan;
3429 double mean_bias_level;
3430 double mean_overscans_level;
3433 int xlow, ylow, xhig, yhig;
3437 if (image == NULL || overscans == NULL) {
3438 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
3442 nrows = cpl_table_get_nrow(overscans);
3445 cpl_msg_error(func,
"Empty overscan table");
3446 cpl_error_set(func, CPL_ERROR_DATA_NOT_FOUND);
3452 unbiased = cpl_image_subtract_create(image, bias);
3453 if (unbiased == NULL) {
3454 cpl_msg_error(func,
"Incompatible master bias");
3455 cpl_error_set(func, CPL_ERROR_INCOMPATIBLE_INPUT);
3459 mean_bias_level = cpl_image_get_mean(bias);
3463 cpl_msg_error(func,
"No master bias in input, and no overscan "
3464 "regions in input image: bias subtraction "
3465 "cannot be performed!");
3466 cpl_error_set(func, CPL_ERROR_DATA_NOT_FOUND);
3469 mean_bias_level = 0.0;
3472 mean_overscans_level = 0.0;
3474 for (i = 0; i < nrows; i++) {
3475 xlow = cpl_table_get_int(overscans,
"xlow", i, NULL);
3476 ylow = cpl_table_get_int(overscans,
"ylow", i, NULL);
3477 xhig = cpl_table_get_int(overscans,
"xhig", i, NULL);
3478 yhig = cpl_table_get_int(overscans,
"yhig", i, NULL);
3481 unbiased = cpl_image_extract(image, xlow+1, ylow+1, xhig, yhig);
3482 if (unbiased == NULL) {
3483 cpl_msg_error(func,
"Incompatible overscan table");
3484 cpl_error_set(func, CPL_ERROR_INCOMPATIBLE_INPUT);
3488 if (cpl_image_subtract(unbiased, bias)) {
3489 cpl_msg_error(func,
"Incompatible master bias");
3490 cpl_error_set(func, CPL_ERROR_INCOMPATIBLE_INPUT);
3491 cpl_image_delete(unbiased);
3497 overscan = cpl_image_extract(image, xlow+1, ylow+1, xhig, yhig);
3498 if (overscan == NULL) {
3499 cpl_msg_error(func,
"Incompatible overscan table");
3500 cpl_error_set(func, CPL_ERROR_INCOMPATIBLE_INPUT);
3501 cpl_image_delete(unbiased);
3505 mean_overscans_level += cpl_image_get_median(overscan);
3515 cpl_image_delete(overscan);
3523 mean_overscans_level /= count;
3525 cpl_image_subtract_scalar(unbiased, mean_overscans_level - mean_bias_level);
3527 cpl_msg_info(cpl_func,
3528 "Difference between mean overscans level "
3529 "and mean bias level: %.2f",
3530 mean_overscans_level - mean_bias_level);
3596 int length,
int msize,
int fsize)
3598 const char *func =
"mos_arc_background_1D";
3606 if (spectrum == NULL || back == NULL)
3607 return cpl_error_set(func, CPL_ERROR_NULL_INPUT);
3615 if (msize < 3 || fsize < msize || length < 2*fsize)
3616 return cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
3619 minf = min_filter(spectrum, length, msize);
3620 smof = smo_filter(minf, length, fsize);
3622 maxf = max_filter(smof, length, 2*msize+1);
3624 smof = smo_filter(maxf, length, 2*fsize+1);
3626 minf = min_filter(smof, length, 2*msize+1);
3628 smof = smo_filter(minf, length, 2*fsize+1);
3631 for (i = 0; i < length; i++)
3636 return CPL_ERROR_NONE;
3699 const char *func =
"mos_arc_background";
3712 if (image == NULL) {
3713 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
3723 nx = cpl_image_get_size_x(image);
3724 ny = cpl_image_get_size_y(image);
3726 bimage = cpl_image_new(nx, ny, CPL_TYPE_FLOAT);
3730 data = cpl_image_get_data_float(fimage);
3731 bdata = cpl_image_get_data_float(bimage);
3733 for (i = 0; i < ny; i++) {
3734 row = data + i * nx;
3735 brow = bdata + i * nx;
3737 cpl_error_set_where(func);
3738 cpl_image_delete(fimage);
3739 cpl_image_delete(bimage);
3744 cpl_image_delete(fimage);
3773 const char *func =
"mos_lines_width";
3775 double *profile1 = cpl_calloc(length - 1,
sizeof(
double));
3776 double *profile2 = cpl_calloc(length - 1,
sizeof(
double));
3778 double norm, value, max;
3780 int short_length = length - 2*radius - 1;
3789 for (j = 0, i = 1; i < length; j++, i++) {
3790 profile1[j] = profile2[j] = spectrum[i] - spectrum[j];
3791 if (profile1[j] < 0)
3793 if (profile2[j] > 0)
3796 profile2[j] = -profile2[j];
3807 for (i = 0; i < length; i++)
3808 if (norm < profile1[i])
3811 for (i = 0; i < length; i++) {
3812 profile1[i] /= norm;
3813 profile2[i] /= norm;
3822 for (i = 0; i <= radius; i++) {
3824 for (j = 0; j < short_length; j++) {
3826 value += profile1[k] * profile2[k+i];
3838 cpl_msg_debug(func,
"Cannot estimate line width");
3874 int length,
float level,
3878 const char *func =
"mos_peak_candidates";
3881 int nint = length - 1;
3883 int width = 2 * ceil(exp_width / 2) + 1;
3884 int start = width / 2;
3885 int end = length - width / 2;
3888 double *data = cpl_calloc(length/2,
sizeof(
double));
3891 if (spectrum == NULL) {
3892 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
3903 smo = cpl_calloc(length,
sizeof(
float));
3905 end = length - width / 2;
3906 for (i = 0; i < start; i++)
3907 smo[i] = spectrum[i];
3908 for (i = start; i < end; i++) {
3909 for (j = i - start; j <= i + start; j++)
3910 smo[i] += spectrum[j];
3913 for (i = end; i < length; i++)
3914 smo[i] = spectrum[i];
3917 smo = (
float *)spectrum;
3930 for (i = step; i < nint - step + 1; i += step) {
3931 if (smo[i] > level) {
3932 if (smo[i] >= smo[i-step] && smo[i] > smo[i+step]) {
3933 if (smo[i-step] != 0.0 && smo[i+step] != 0.0) {
3934 data[n] = i + step * values_to_dx(smo[i-step], smo[i], smo[i+step]);
3950 return cpl_vector_wrap(n, data);
3977 cpl_vector *peaks,
int sradius)
3980 const char *func =
"mos_refine_peaks";
3985 int startPos, endPos;
3986 int window = 2*sradius+1;
3990 if (peaks == NULL || spectrum == NULL) {
3991 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
3995 npeaks = cpl_vector_get_size(peaks);
3996 data = cpl_vector_unwrap(peaks);
3998 for (i = 0; i < npeaks; i++) {
3999 startPos = data[i] - window/2;
4000 endPos = startPos + window;
4001 if (startPos < 0 || endPos >= length)
4004 if (0 == peakPosition(spectrum + startPos, window, &pos, 1)) {
4010 for (i = 1; i < npeaks; i++)
4011 if (data[i] - data[i-1] < 0.5)
4014 for (i = 0, j = 0; i < npeaks; i++) {
4015 if (data[i] > 0.0) {
4022 return cpl_vector_wrap(j, data);
4027 void mos_set_multiplex(
int multiplex)
4029 mos_multiplex = multiplex;
4086 double min_disp,
double max_disp,
4094 double lratio, pratio;
4095 double lo_start, lo_end, hi_start, hi_end, denom;
4096 double disp, variation, prev_variation;
4097 int max, maxpos, minl, mink;
4099 int npeaks_lo, npeaks_hi;
4124 peak = cpl_vector_get_data(peaks);
4125 npeaks = cpl_vector_get_size(peaks);
4126 line = cpl_vector_get_data(lines);
4127 nlines = cpl_vector_get_size(lines);
4132 peak_lo = cpl_malloc(npeaks *
sizeof(
int));
4133 peak_hi = cpl_malloc(npeaks *
sizeof(
int));
4134 nident = cpl_calloc(npeaks,
sizeof(
int));
4135 lident = cpl_calloc(nlines,
sizeof(
int));
4136 xpos = cpl_calloc(npeaks,
sizeof(
double));
4137 lambda = cpl_calloc(npeaks,
sizeof(
double));
4138 ilambda = cpl_calloc(npeaks,
sizeof(
int));
4139 tmp_xpos = cpl_calloc(npeaks,
sizeof(
double));
4140 tmp_lambda = cpl_calloc(npeaks,
sizeof(
double));
4141 tmp_ilambda = cpl_calloc(npeaks,
sizeof(
int));
4142 flag = cpl_calloc(npeaks,
sizeof(
int));
4143 seq_length = cpl_calloc(npeaks,
sizeof(
int));
4144 ident = cpl_malloc(npeaks *
sizeof(
int *));
4145 for (i = 0; i < npeaks; i++)
4146 ident[i] = cpl_malloc(3 * npeaks *
sizeof(
int));
4161 for (i = 1; i < nlint; i++) {
4171 lratio = (line[i+1] - line[i]) / (line[i] - line[i-1]);
4178 for (j = 1; j < npint; j++) {
4191 lo_start = peak[j] - (line[i] - line[i-1]) / min_disp;
4192 lo_end = peak[j] - (line[i] - line[i-1]) / max_disp;
4193 hi_start = peak[j] + (line[i+1] - line[i]) / max_disp;
4194 hi_end = peak[j] + (line[i+1] - line[i]) / min_disp;
4196 for (npeaks_lo = 0, k = 0; k < npeaks; k++) {
4197 if (peak[k] > lo_end)
4199 if (peak[k] > lo_start) {
4200 peak_lo[npeaks_lo] = k;
4208 for (npeaks_hi = 0, k = 0; k < npeaks; k++) {
4209 if (peak[k] > hi_end)
4211 if (peak[k] > hi_start) {
4212 peak_hi[npeaks_hi] = k;
4229 prev_variation = 1000.0;
4232 for (k = 0; k < npeaks_lo; k++) {
4233 denom = peak[j] - peak[peak_lo[k]];
4234 for (l = 0; l < npeaks_hi; l++) {
4242 pratio = (peak[peak_hi[l]] - peak[j]) / denom;
4255 variation = fabs(lratio-pratio) / pratio;
4257 if (variation < tolerance) {
4258 if (variation < prev_variation) {
4259 prev_variation = variation;
4266 if (prev_variation < tolerance) {
4267 ident[j][nident[j]] = i;
4268 ident[peak_hi[minl]][nident[peak_hi[minl]]] = i + 1;
4269 ident[peak_lo[mink]][nident[peak_lo[mink]]] = i - 1;
4271 ++nident[peak_hi[minl]];
4272 ++nident[peak_lo[mink]];
4284 for (i = 0; i < npeaks; i++) {
4293 if (nident[i] > 1) {
4300 for (j = 0; j < nlines; j++)
4309 for (j = 0; j < nident[i]; j++)
4310 ++lident[ident[i][j]];
4319 for (j = 0; j < nlines; j++) {
4320 if (max < lident[j]) {
4335 for (k = maxpos + 1; k < nlines; k++) {
4336 if (lident[k] == max) {
4351 tmp_xpos[n] = peak[i];
4352 tmp_lambda[n] = line[maxpos];
4353 tmp_ilambda[n] = maxpos;
4377 for (k = 0; k < n; k++) {
4380 xpos[nn] = tmp_xpos[k];
4381 lambda[nn] = tmp_lambda[k];
4382 ilambda[nn] = tmp_ilambda[k];
4395 for (j = i + 1; j < n; j++) {
4397 disp = (tmp_lambda[j] - tmp_lambda[i])
4398 / (tmp_xpos[j] - tmp_xpos[i]);
4399 if (disp >= min_disp && disp <= max_disp) {
4401 xpos[nn] = tmp_xpos[j];
4402 lambda[nn] = tmp_lambda[j];
4403 ilambda[nn] = tmp_ilambda[j];
4433 if (mos_multiplex < 0) {
4434 for (i = 0; i < nseq; i++) {
4435 if (seq_length[i] > max) {
4436 max = seq_length[i];
4452 for (i = 0; i < nseq; i++) {
4455 cpl_array *regions = cpl_array_new(n, CPL_TYPE_INT);
4458 for (j = 0; j < n; j++)
4459 cpl_array_set_int(regions, j,
4460 ((
int)floor(xpos[nn + j])) / mos_region_size);
4462 region = (int)cpl_array_get_median(regions);
4463 cpl_array_delete(regions);
4465 if (mos_multiplex == region) {
4467 cpl_msg_debug(cpl_func,
"More than one spectrum found in "
4468 "region %d (only the first one is extracted)",
4473 max = seq_length[i];
4477 nn += seq_length[i];
4487 for (i = 0; i < maxpos; i++)
4488 nn += seq_length[i];
4495 for (i = 0; i < n; i++, nn++) {
4497 lambda[i] = lambda[nn];
4498 ilambda[i] = ilambda[nn];
4506 for (i = 1; i < n; i++) {
4507 gap = ilambda[i] - ilambda[i-1];
4508 for (j = 1; j < gap; j++) {
4516 disp = (lambda[i] - lambda[i-1]) / (xpos[i] - xpos[i-1]);
4524 hi_start = xpos[i-1] + (line[ilambda[i-1] + j] - lambda[i-1]) / disp;
4539 for (k = 0; k < npeaks; k++) {
4540 if (fabs(peak[k] - hi_start) < 2) {
4541 for (l = n; l > i; l--) {
4542 xpos[l] = xpos[l-1];
4543 lambda[l] = lambda[l-1];
4544 ilambda[l] = ilambda[l-1];
4547 lambda[i] = line[ilambda[i-1] + j];
4548 ilambda[i] = ilambda[i-1] + j;
4565 while (ilambda[n-1] < nlines - 1 && found) {
4573 disp = (lambda[n-1] - lambda[n-2]) / (xpos[n-1] - xpos[n-2]);
4577 if (disp > max_disp || disp < min_disp)
4586 hi_start = xpos[n-1] + (line[ilambda[n-1] + 1] - lambda[n-1]) / disp;
4597 min = fabs(peak[0] - hi_start);
4599 for (k = 1; k < npeaks; k++) {
4600 if (min > fabs(peak[k] - hi_start)) {
4601 min = fabs(peak[k] - hi_start);
4605 if (min < 6 && fabs(peak[minpos] - xpos[n-1]) > 1.0) {
4606 xpos[n] = peak[minpos];
4607 lambda[n] = line[ilambda[n-1] + 1];
4608 ilambda[n] = ilambda[n-1] + 1;
4620 while (ilambda[0] > 0 && found) {
4627 disp = (lambda[1] - lambda[0]) / (xpos[1] - xpos[0]);
4629 if (disp > max_disp || disp < min_disp)
4638 hi_start = xpos[0] - (lambda[0] - line[ilambda[0] - 1]) / disp;
4650 min = fabs(peak[0] - hi_start);
4652 for (k = 1; k < npeaks; k++) {
4653 if (min > fabs(peak[k] - hi_start)) {
4654 min = fabs(peak[k] - hi_start);
4658 if (min < 6 && fabs(peak[minpos] - xpos[0]) > 1.0) {
4659 for (j = n; j > 0; j--) {
4660 xpos[j] = xpos[j-1];
4661 lambda[j] = lambda[j-1];
4662 ilambda[j] = ilambda[j-1];
4664 xpos[0] = peak[minpos];
4665 lambda[0] = line[ilambda[0] - 1];
4666 ilambda[0] = ilambda[0] - 1;
4692 for (i = 0; i < npeaks; i++)
4699 cpl_free(tmp_lambda);
4700 cpl_free(tmp_ilambda);
4703 cpl_free(seq_length);
4712 return cpl_bivector_wrap_vectors(cpl_vector_wrap(n, xpos),
4713 cpl_vector_wrap(n, lambda));
4775 double refwave,
double pixel)
4781 if (cpl_polynomial_eval_1d(ids, blue-refwave, NULL) > pixel)
4784 if (cpl_polynomial_eval_1d(ids, red-refwave, NULL) < pixel)
4787 yellow = (blue + red) / 2 - refwave;
4789 coeff = cpl_polynomial_get_coeff(ids, &zero);
4790 cpl_polynomial_set_coeff(ids, &zero, coeff - pixel);
4792 cpl_polynomial_solve_1d(ids, yellow, &yellow, 1);
4793 if (cpl_error_get_code() != CPL_ERROR_NONE) {
4798 cpl_polynomial_set_coeff(ids, &zero, coeff);
4800 return yellow + refwave;
4830 double reject,
int minlines,
4831 int *nlines,
double *err)
4833 const char *func =
"mos_poly_wav2pix";
4835 cpl_bivector *pixwav2;
4845 cpl_polynomial *ids;
4851 if (pixwav == NULL) {
4852 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
4856 fitlines = cpl_bivector_get_size(pixwav);
4858 if (fitlines < minlines) {
4859 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
4873 pixwav2 = cpl_bivector_duplicate(pixwav);
4883 pixel = cpl_bivector_get_x(pixwav2);
4884 wavel = cpl_bivector_get_y(pixwav2);
4892 cpl_bivector_unwrap_vectors(pixwav2);
4899 while (fitlines >= minlines) {
4901 ids = cpl_polynomial_fit_1d_create(wavel, pixel, order, err);
4905 cpl_msg_debug(cpl_error_get_where(),
"%s", cpl_error_get_message());
4906 cpl_msg_debug(func,
"Fitting IDS");
4907 cpl_error_set_where(func);
4909 cpl_vector_delete(wavel);
4910 cpl_vector_delete(pixel);
4922 d_pixel = cpl_vector_unwrap(pixel);
4923 d_wavel = cpl_vector_unwrap(wavel);
4925 for (i = 0, j = 0; i < fitlines; i++) {
4926 pixpos = cpl_polynomial_eval_1d(ids, d_wavel[i], NULL);
4927 if (fabs(pixpos - d_pixel[i]) < reject) {
4928 d_pixel[j] = d_pixel[i];
4929 d_wavel[j] = d_wavel[i];
4934 if (j == fitlines) {
4942 cpl_polynomial_delete(ids);
4943 if (fitlines >= minlines) {
4944 pixel = cpl_vector_wrap(fitlines, d_pixel);
4945 wavel = cpl_vector_wrap(fitlines, d_wavel);
4950 cpl_error_set(func, CPL_ERROR_CONTINUE);
4990 double reject,
int minlines,
4991 int *nlines,
double *err)
4994 cpl_bivector *wavpix;
4998 cpl_polynomial *dds;
5005 pixel = cpl_bivector_get_x(pixwav);
5006 wavel = cpl_bivector_get_y(pixwav);
5008 wavpix = cpl_bivector_wrap_vectors(wavel, pixel);
5012 cpl_bivector_unwrap_vectors(wavpix);
5042 cpl_vector *lines, cpl_polynomial *ids,
5043 double refwave,
int sradius)
5045 const char *func =
"mos_find_peaks";
5056 if (spectrum == NULL || lines == NULL || ids == NULL) {
5057 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
5061 nlines = cpl_vector_get_size(lines);
5063 if (sradius < 1 || length < 2*sradius+1 || nlines < 1) {
5064 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
5068 d_wavel = cpl_malloc(nlines *
sizeof(
double));
5069 d_pixel = cpl_malloc(nlines *
sizeof(
double));
5071 data = cpl_vector_get_data(lines);
5073 for (i = 0, j = 0; i < nlines; i++) {
5074 pixel = cpl_polynomial_eval_1d(ids, data[i]-refwave, NULL) + 0.5;
5075 if (pixel < 0 || pixel - sradius < 0 || pixel + sradius >= length)
5077 if (peakPosition(spectrum+pixel-sradius, 2*sradius+1, &pos, 1) == 0) {
5078 pos += pixel - sradius;
5080 d_wavel[j] = data[i];
5086 return cpl_bivector_wrap_vectors(cpl_vector_wrap(j, d_pixel),
5087 cpl_vector_wrap(j, d_wavel));
5092 cpl_error_set(func, CPL_ERROR_ILLEGAL_OUTPUT);
5223 double dispersion,
float level,
5224 int sradius,
int order,
5225 double reject,
double refwave,
5226 double *wavestart,
double *waveend,
5227 int *nlines,
double *error,
5228 cpl_table *idscoeff,
5229 cpl_image *calibration,
5230 cpl_image *residuals,
5231 cpl_table *restable,
5233 cpl_table *detected_lines)
5236 const char *func =
"mos_wavelength_calibration_raw";
5238 const char *clab[6] = {
"c0",
"c1",
"c2",
"c3",
"c4",
"c5"};
5241 double tolerance = 20.0;
5244 char name[MAX_COLNAME];
5245 cpl_image *resampled;
5246 cpl_bivector *output;
5247 cpl_bivector *new_output;
5250 cpl_polynomial *ids;
5251 cpl_polynomial *lin;
5254 double max_disp, min_disp;
5256 double firstLambda, lastLambda, lambda;
5257 double value, wave, pixe;
5266 int pixstart, pixend;
5269 int nl, nx, ny, pixel;
5270 int countLines, usedLines;
5272 int in, first, last;
5279 if (dispersion == 0.0) {
5280 cpl_msg_error(func,
"The expected dispersion (A/pixel) must be given");
5281 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
5285 if (dispersion < 0.0) {
5286 cpl_msg_error(func,
"The expected dispersion must be positive");
5287 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
5291 max_disp = dispersion + dispersion * tolerance / 100;
5292 min_disp = dispersion - dispersion * tolerance / 100;
5295 cpl_msg_error(func,
"The order of the fitting polynomial "
5296 "must be at least 1");
5297 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
5301 if (image == NULL || lines == NULL) {
5302 cpl_msg_error(func,
"Both spectral exposure and reference line "
5303 "catalog are required in input");
5304 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
5308 nx = cpl_image_get_size_x(image);
5309 ny = cpl_image_get_size_y(image);
5310 sdata = cpl_image_get_data_float_const(image);
5312 nref = cpl_vector_get_size(lines);
5313 line = cpl_vector_get_data(lines);
5315 if (*wavestart < 1.0 && *waveend < 1.0) {
5316 firstLambda = line[0];
5317 lastLambda = line[nref-1];
5318 extrapolation = (lastLambda - firstLambda) / 10;
5319 firstLambda -= extrapolation;
5320 lastLambda += extrapolation;
5321 *wavestart = firstLambda;
5322 *waveend = lastLambda;
5325 firstLambda = *wavestart;
5326 lastLambda = *waveend;
5329 nl = (lastLambda - firstLambda) / dispersion;
5330 resampled = cpl_image_new(nl, ny, CPL_TYPE_FLOAT);
5331 rdata = cpl_image_get_data_float(resampled);
5334 idata = cpl_image_get_data_float(calibration);
5337 ddata = cpl_image_get_data_float(residuals);
5340 for (j = 0; j <= order; j++)
5341 cpl_table_new_column(idscoeff, clab[j], CPL_TYPE_DOUBLE);
5344 cpl_table_set_size(restable, nref);
5345 cpl_table_new_column(restable,
"wavelength", CPL_TYPE_DOUBLE);
5346 cpl_table_copy_data_double(restable,
"wavelength", line);
5347 for (i = 0; i < ny; i += step) {
5348 snprintf(name, MAX_COLNAME,
"r%d", i);
5349 cpl_table_new_column(restable, name, CPL_TYPE_DOUBLE);
5350 snprintf(name, MAX_COLNAME,
"d%d", i);
5351 cpl_table_new_column(restable, name, CPL_TYPE_DOUBLE);
5352 snprintf(name, MAX_COLNAME,
"p%d", i);
5353 cpl_table_new_column(restable, name, CPL_TYPE_DOUBLE);
5357 if (detected_lines) {
5358 cpl_table_set_size(detected_lines, 0);
5359 cpl_table_new_column(detected_lines,
"xpos", CPL_TYPE_DOUBLE);
5360 cpl_table_new_column(detected_lines,
"ypos", CPL_TYPE_DOUBLE);
5361 cpl_table_new_column(detected_lines,
"xpos_iter", CPL_TYPE_DOUBLE);
5362 cpl_table_new_column(detected_lines,
"ypos_iter", CPL_TYPE_DOUBLE);
5363 cpl_table_new_column(detected_lines,
"peak_flux", CPL_TYPE_DOUBLE);
5364 cpl_table_new_column(detected_lines,
"wave_ident", CPL_TYPE_DOUBLE);
5365 cpl_table_new_column(detected_lines,
"wave_ident_iter", CPL_TYPE_DOUBLE);
5366 cpl_table_new_column(detected_lines,
"xpos_fit_rect_wavecal", CPL_TYPE_DOUBLE);
5367 cpl_table_new_column(detected_lines,
"res_xpos", CPL_TYPE_DOUBLE);
5376 for (i = 0; i < ny; i++) {
5379 if (width > sradius) {
5395 countLines = cpl_bivector_get_size(output);
5396 if (countLines < 4) {
5397 cpl_bivector_delete(output);
5398 cpl_vector_delete(peaks);
5410 wavel = cpl_bivector_get_y(output);
5411 cpl_vector_subtract_scalar(wavel, refwave);
5413 uorder = countLines / 2 - 1;
5427 2 * (uorder + 1), &usedLines,
5431 cpl_bivector_delete(output);
5432 cpl_vector_delete(peaks);
5449 for (k = 0; k <= order; k++) {
5451 cpl_table_set_double(idscoeff, clab[k], i, 0.0);
5454 cpl_table_set_double(idscoeff, clab[k], i,
5455 cpl_polynomial_get_coeff(ids, &k));
5462 cpl_size newlines = cpl_vector_get_size(peaks);
5463 cpl_size oldsize = cpl_table_get_nrow(detected_lines);
5464 cpl_table_set_size(detected_lines, oldsize + newlines);
5465 for(cpl_size iline = 0; iline < newlines; ++iline)
5467 cpl_table_set_double(detected_lines,
"xpos",
5468 oldsize + iline, cpl_vector_get(peaks, iline) + 1);
5469 cpl_table_set_double(detected_lines,
"ypos",
5470 oldsize + iline, (
double)i + 1);
5471 cpl_table_set_double(detected_lines,
"peak_flux",
5473 sdata[i*nx+(
int)(cpl_vector_get(peaks, iline)+0.5)]);
5481 cpl_size nidentlines = cpl_bivector_get_size(output);
5482 cpl_size ndetectlines = cpl_vector_get_size(peaks);
5483 cpl_size totalsize = cpl_table_get_nrow(detected_lines);
5484 for(cpl_size idline = 0; idline < nidentlines; ++idline)
5486 for(cpl_size detline = 0; detline < ndetectlines; ++detline)
5488 if(cpl_vector_get(peaks, detline) ==
5489 cpl_bivector_get_x_data(output)[idline])
5491 cpl_size table_pos = totalsize - ndetectlines + detline;
5492 double wave_ident = cpl_bivector_get_y_data(output)[idline] + refwave;
5493 double xpix_fit = cpl_polynomial_eval_1d(ids,
5494 wave_ident - refwave, NULL);
5495 double xpos_det = cpl_table_get_double(detected_lines,
5498 cpl_table_set_double(detected_lines,
5502 cpl_table_set_double(detected_lines,
5503 "xpos_fit_rect_wavecal",
5506 cpl_table_set_double(detected_lines,
5509 xpos_det - xpix_fit - 1);
5523 ids, refwave, uradius);
5526 cpl_bivector_delete(output);
5527 output = new_output;
5533 cpl_polynomial_delete(ids);
5535 countLines = cpl_bivector_get_size(output);
5537 if (countLines < 4) {
5538 cpl_bivector_delete(output);
5539 cpl_vector_delete(peaks);
5552 for (k = 0; k <= order; k++)
5553 cpl_table_set_invalid(idscoeff, clab[k], i);
5557 wavel = cpl_bivector_get_y(output);
5558 cpl_vector_subtract_scalar(wavel, refwave);
5560 uorder = countLines / 2 - 1;
5565 2 * (uorder + 1), &usedLines,
5569 cpl_bivector_delete(output);
5570 cpl_vector_delete(peaks);
5583 for (k = 0; k <= order; k++)
5584 cpl_table_set_invalid(idscoeff, clab[k], i);
5590 for (k = 0; k <= order; k++) {
5592 cpl_table_set_double(idscoeff, clab[k], i, 0.0);
5595 cpl_table_set_double(idscoeff, clab[k], i,
5596 cpl_polynomial_get_coeff(ids, &k));
5604 cpl_size oldsize = cpl_table_get_nrow(detected_lines);
5605 cpl_size nidentlines = cpl_bivector_get_size(output);
5606 cpl_table_set_size(detected_lines, oldsize + nidentlines);
5607 for(cpl_size idline = 0; idline < nidentlines ; ++idline)
5609 double wave_ident = cpl_bivector_get_y_data(output)[idline] + refwave;
5610 double xpix_fit = cpl_polynomial_eval_1d(ids,
5611 wave_ident - refwave, NULL);
5612 cpl_table_set_double(detected_lines,
"xpos_iter",
5613 oldsize + idline, cpl_bivector_get_x_data(output)[idline] + 1);
5614 cpl_table_set_double(detected_lines,
"ypos_iter",
5615 oldsize + idline, (
double)i + 1);
5616 cpl_table_set_double(detected_lines,
"peak_flux",
5618 sdata[i*nx+(
int)(cpl_bivector_get_x_data(output)[idline]+0.5)]);
5619 cpl_table_set_double(detected_lines,
"wave_ident_iter",
5620 oldsize + idline, wave_ident);
5621 cpl_table_set_double(detected_lines,
"xpos_fit_rect_wavecal",
5622 oldsize + idline, xpix_fit + 1);
5629 nlines[i] = usedLines;
5631 error[i] = ids_err / sqrt(usedLines/(uorder + 1));
5633 pixstart = cpl_polynomial_eval_1d(ids,
5634 cpl_bivector_get_y_data(output)[0], NULL);
5635 pixend = cpl_polynomial_eval_1d(ids,
5636 cpl_bivector_get_y_data(output)[countLines-1], NULL);
5637 extrapolation = (pixend - pixstart) / 5;
5638 pixstart -= extrapolation;
5639 pixend += extrapolation;
5650 for (j = pixstart; j < pixend; j++) {
5652 lastLambda, refwave,
5661 for (j = 0; j < nl; j++) {
5662 lambda = firstLambda + j * dispersion;
5663 fpixel = cpl_polynomial_eval_1d(ids, lambda - refwave,
5666 if (pixel >= 0 && pixel < nx-1) {
5667 v1 = (sdata + i*nx)[pixel];
5668 v2 = (sdata + i*nx)[pixel+1];
5669 vi = v1 + (v2-v1)*(fpixel-pixel);
5670 (rdata + i*nl)[j] = vi;
5678 if (residuals || (restable && !(i%step))) {
5679 if (restable && !(i%step)) {
5680 lin = cpl_polynomial_new(1);
5681 for (k = 0; k < 2; k++)
5682 cpl_polynomial_set_coeff(lin, &k,
5683 cpl_polynomial_get_coeff(ids, &k));
5685 for (j = 0; j < countLines; j++) {
5686 pixe = cpl_bivector_get_x_data(output)[j];
5687 wave = cpl_bivector_get_y_data(output)[j];
5688 value = pixe - cpl_polynomial_eval_1d(ids, wave, NULL);
5691 (ddata + i*nx)[pixel] = value;
5693 if (restable && !(i%step)) {
5694 for (k = 0; k < nref; k++) {
5695 if (fabs(line[k] - refwave - wave) < 0.1) {
5696 snprintf(name, MAX_COLNAME,
"r%d", i);
5697 cpl_table_set_double(restable, name,
5700 - cpl_polynomial_eval_1d(lin, wave,
5702 snprintf(name, MAX_COLNAME,
"d%d", i);
5703 cpl_table_set_double(restable, name,
5705 snprintf(name, MAX_COLNAME,
"p%d", i);
5706 cpl_table_set_double(restable, name,
5713 if (restable && !(i%step)) {
5714 cpl_polynomial_delete(lin);
5723 mdata = cpl_mask_get_data(refmask);
5724 pixel = cpl_polynomial_eval_1d(ids, 0.0, NULL) + 0.5;
5725 if (pixel - 1 >= 0 && pixel + 1 < nx) {
5726 mdata[pixel-1 + i*nx] = CPL_BINARY_1;
5727 mdata[pixel + i*nx] = CPL_BINARY_1;
5728 mdata[pixel+1 + i*nx] = CPL_BINARY_1;
5732 cpl_polynomial_delete(ids);
5733 cpl_bivector_delete(output);
5735 cpl_vector_delete(peaks);
5740 kernel = cpl_matrix_new(3, 3);
5741 cpl_matrix_set(kernel, 0, 1, 1.0);
5742 cpl_matrix_set(kernel, 1, 1, 1.0);
5743 cpl_matrix_set(kernel, 2, 1, 1.0);
5745 cpl_mask_dilation(refmask, kernel);
5746 cpl_mask_erosion(refmask, kernel);
5747 cpl_mask_erosion(refmask, kernel);
5748 cpl_mask_dilation(refmask, kernel);
5750 cpl_matrix_delete(kernel);
5756 mdata = cpl_mask_get_data(refmask);
5757 have_it = cpl_calloc(ny,
sizeof(
int));
5759 for (i = 0; i < ny; i++, mdata += nx) {
5760 for (j = 0; j < nx; j++) {
5761 if (mdata[j] == CPL_BINARY_1) {
5768 mdata = cpl_mask_get_data(refmask);
5772 for (i = 0; i < ny; i++) {
5778 if (abs(have_it[first] - have_it[last]) < 3) {
5779 for (j = first; j < last; j++) {
5780 mdata[have_it[first] + nx*j + 0] = CPL_BINARY_1;
5781 mdata[have_it[first] + nx*j + 1] = CPL_BINARY_1;
5782 mdata[have_it[first] + nx*j + 2] = CPL_BINARY_1;
5924 const char *func =
"mos_locate_spectra";
5926 cpl_apertures *slits;
5927 cpl_image *labimage;
5928 cpl_image *refimage;
5930 cpl_propertylist *sort_col;
5936 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
5940 labimage = cpl_image_labelise_mask_create(mask, &nslits);
5943 cpl_image_delete(labimage);
5944 cpl_error_set(func, CPL_ERROR_DATA_NOT_FOUND);
5948 refimage = cpl_image_new_from_mask(mask);
5950 slits = cpl_apertures_new_from_image(refimage, labimage);
5952 cpl_image_delete(labimage);
5953 cpl_image_delete(refimage);
5955 nslits = cpl_apertures_get_size(slits);
5957 cpl_apertures_delete(slits);
5958 cpl_error_set(func, CPL_ERROR_DATA_NOT_FOUND);
5962 slitpos = cpl_table_new(nslits);
5963 cpl_table_new_column(slitpos,
"xtop", CPL_TYPE_DOUBLE);
5964 cpl_table_new_column(slitpos,
"ytop", CPL_TYPE_DOUBLE);
5965 cpl_table_new_column(slitpos,
"xbottom", CPL_TYPE_DOUBLE);
5966 cpl_table_new_column(slitpos,
"ybottom", CPL_TYPE_DOUBLE);
5967 cpl_table_set_column_unit(slitpos,
"xtop",
"pixel");
5968 cpl_table_set_column_unit(slitpos,
"ytop",
"pixel");
5969 cpl_table_set_column_unit(slitpos,
"xbottom",
"pixel");
5970 cpl_table_set_column_unit(slitpos,
"ybottom",
"pixel");
5972 for (i = 0; i < nslits; i++) {
5973 cpl_table_set_double(slitpos,
"xtop", i,
5974 cpl_apertures_get_top_x(slits, i+1) - 1);
5975 cpl_table_set_double(slitpos,
"ytop", i,
5976 cpl_apertures_get_top(slits, i+1));
5977 cpl_table_set_double(slitpos,
"xbottom", i,
5978 cpl_apertures_get_bottom_x(slits, i+1) - 1);
5979 cpl_table_set_double(slitpos,
"ybottom", i,
5980 cpl_apertures_get_bottom(slits, i+1));
5983 cpl_apertures_delete(slits);
5985 sort_col = cpl_propertylist_new();
5986 cpl_propertylist_append_bool(sort_col,
"ytop", 1);
5987 cpl_table_sort(slitpos, sort_col);
5988 cpl_propertylist_delete(sort_col);
6012 const char *func =
"mos_validate_slits";
6016 return cpl_error_set(func, CPL_ERROR_NULL_INPUT);
6018 if (1 != cpl_table_has_column(slits,
"xtop"))
6019 return cpl_error_set(func, CPL_ERROR_DATA_NOT_FOUND);
6021 if (1 != cpl_table_has_column(slits,
"ytop"))
6022 return cpl_error_set(func, CPL_ERROR_DATA_NOT_FOUND);
6024 if (1 != cpl_table_has_column(slits,
"xbottom"))
6025 return cpl_error_set(func, CPL_ERROR_DATA_NOT_FOUND);
6027 if (1 != cpl_table_has_column(slits,
"ybottom"))
6028 return cpl_error_set(func, CPL_ERROR_DATA_NOT_FOUND);
6030 if (CPL_TYPE_DOUBLE != cpl_table_get_column_type(slits,
"xtop"))
6031 return cpl_error_set(func, CPL_ERROR_INVALID_TYPE);
6033 if (CPL_TYPE_DOUBLE != cpl_table_get_column_type(slits,
"ytop"))
6034 return cpl_error_set(func, CPL_ERROR_INVALID_TYPE);
6036 if (CPL_TYPE_DOUBLE != cpl_table_get_column_type(slits,
"xbottom"))
6037 return cpl_error_set(func, CPL_ERROR_INVALID_TYPE);
6039 if (CPL_TYPE_DOUBLE != cpl_table_get_column_type(slits,
"ybottom"))
6040 return cpl_error_set(func, CPL_ERROR_INVALID_TYPE);
6042 return CPL_ERROR_NONE;
6076 const char *func =
"mos_rotate_slits";
6078 cpl_error_code error;
6079 char aux_name[] =
"_0";
6088 return CPL_ERROR_NONE;
6092 return cpl_error_set(func, error);
6094 if (rotation == 1 || rotation == 3) {
6100 for (i = 0; i < 77; i++)
6101 if (1 == cpl_table_has_column(slits, aux_name))
6103 if (1 == cpl_table_has_column(slits, aux_name))
6104 return cpl_error_set(func, CPL_ERROR_CONTINUE);
6105 cpl_table_name_column(slits,
"xtop", aux_name);
6106 cpl_table_name_column(slits,
"ytop",
"xtop");
6107 cpl_table_name_column(slits, aux_name,
"ytop");
6108 cpl_table_name_column(slits,
"xbottom", aux_name);
6109 cpl_table_name_column(slits,
"ybottom",
"xbottom");
6110 cpl_table_name_column(slits, aux_name,
"ybottom");
6113 if (rotation == 1 || rotation == 2) {
6114 cpl_table_multiply_scalar(slits,
"xtop", -1.0);
6115 cpl_table_multiply_scalar(slits,
"xbottom", -1.0);
6116 cpl_table_add_scalar(slits,
"xtop", nx);
6117 cpl_table_add_scalar(slits,
"xbottom", nx);
6120 if (rotation == 3 || rotation == 2) {
6121 cpl_table_multiply_scalar(slits,
"ytop", -1.0);
6122 cpl_table_multiply_scalar(slits,
"ybottom", -1.0);
6123 cpl_table_add_scalar(slits,
"ytop", ny);
6124 cpl_table_add_scalar(slits,
"ybottom", ny);
6127 return CPL_ERROR_NONE;
6191 cpl_array *top_ident = NULL;;
6192 cpl_array *bot_ident = NULL;;
6194 cpl_matrix *mpattern;
6195 cpl_matrix *top_data;
6196 cpl_matrix *top_pattern;
6197 cpl_matrix *top_mdata;
6198 cpl_matrix *top_mpattern;
6199 cpl_matrix *bot_data;
6200 cpl_matrix *bot_pattern;
6201 cpl_matrix *bot_mdata;
6202 cpl_matrix *bot_mpattern;
6203 cpl_propertylist *sort_col;
6212 double top_scale, bot_scale;
6213 double angle, top_angle, bot_angle;
6215 double xrms, top_xrms, bot_xrms;
6216 double yrms, top_yrms, bot_yrms;
6218 int nmaskslits, use_pattern;
6219 int found_slits, found_slits_top, found_slits_bot;
6221 cpl_table *positions;
6222 cpl_error_code error;
6231 cpl_polynomial *xpoly = NULL;
6232 cpl_polynomial *ypoly = NULL;
6233 cpl_polynomial *top_xpoly = NULL;
6234 cpl_polynomial *top_ypoly = NULL;
6235 cpl_polynomial *bot_xpoly = NULL;
6236 cpl_polynomial *bot_ypoly = NULL;
6238 char *msg_multiplex =
" ";
6243 cpl_msg_error(cpl_func,
"CCD slits table validation: %s",
6244 cpl_error_get_message());
6245 cpl_error_set(cpl_func, error);
6251 cpl_msg_error(cpl_func,
"Mask slits table validation: %s",
6252 cpl_error_get_message());
6253 cpl_error_set(cpl_func, error);
6257 if (1 != cpl_table_has_column(maskslits,
"slit_id")) {
6258 cpl_msg_error(cpl_func,
"Missing slits identifiers");
6259 cpl_error_set(cpl_func, CPL_ERROR_DATA_NOT_FOUND);
6263 if (CPL_TYPE_INT != cpl_table_get_column_type(maskslits,
"slit_id")) {
6264 cpl_msg_error(cpl_func,
"Wrong type used for slits identifiers");
6265 cpl_error_set(cpl_func, CPL_ERROR_INVALID_TYPE);
6269 nslits = cpl_table_get_nrow(slits);
6270 nmaskslits = cpl_table_get_nrow(maskslits);
6272 if (nslits == 0 || nmaskslits == 0) {
6273 cpl_msg_error(cpl_func,
"Empty slits table");
6274 cpl_error_set(cpl_func, CPL_ERROR_ILLEGAL_INPUT);
6278 if (nslits > 25 && mos_multiplex < 0) {
6279 cpl_msg_info(cpl_func,
"Many slits: using 'fast' pattern matching...");
6280 positions = mos_identify_slits_fast(slits, maskslits, global);
6281 if (positions == NULL)
6282 cpl_error_set_where(cpl_func);
6290 sort_col = cpl_propertylist_new();
6291 cpl_propertylist_append_bool(sort_col,
"ytop", 1);
6292 cpl_table_sort(slits, sort_col);
6293 cpl_table_sort(maskslits, sort_col);
6294 cpl_propertylist_delete(sort_col);
6300 if (nslits < 3 && nmaskslits > nslits) {
6310 cpl_msg_warning(cpl_func,
"Cannot match the %d found CCD slits "
6311 "with the %d mask slits: process will continue "
6312 "using the detected CCD slits positions", nslits,
6315 cpl_msg_warning(cpl_func,
"Cannot match the found CCD slit with "
6316 "the %d mask slits: process will continue using "
6317 "the detected CCD slit position", nmaskslits);
6321 if (nmaskslits < 3 && nslits > nmaskslits) {
6329 cpl_msg_warning(cpl_func,
"Cannot match the %d found CCD slits with "
6330 "the %d mask slits: process will continue using "
6331 "the detected CCD slits positions", nslits,
6343 xtop = cpl_table_get_data_double(slits,
"xtop");
6344 ytop = cpl_table_get_data_double(slits,
"ytop");
6345 xmtop = cpl_table_get_data_double(maskslits,
"xtop");
6346 ymtop = cpl_table_get_data_double(maskslits,
"ytop");
6348 xbot = cpl_table_get_data_double(slits,
"xbottom");
6349 ybot = cpl_table_get_data_double(slits,
"ybottom");
6350 xmbot = cpl_table_get_data_double(maskslits,
"xbottom");
6351 ymbot = cpl_table_get_data_double(maskslits,
"ybottom");
6353 top_data = cpl_matrix_new(2, nslits);
6354 top_pattern = cpl_matrix_new(2, nmaskslits);
6355 bot_data = cpl_matrix_new(2, nslits);
6356 bot_pattern = cpl_matrix_new(2, nmaskslits);
6358 for (i = 0; i < nslits; i++)
6359 cpl_matrix_set(top_data, 0, i, xtop[i]);
6361 for (i = 0; i < nslits; i++)
6362 cpl_matrix_set(top_data, 1, i, ytop[i]);
6364 for (i = 0; i < nmaskslits; i++)
6365 cpl_matrix_set(top_pattern, 0, i, xmtop[i]);
6367 for (i = 0; i < nmaskslits; i++)
6368 cpl_matrix_set(top_pattern, 1, i, ymtop[i]);
6370 for (i = 0; i < nslits; i++)
6371 cpl_matrix_set(bot_data, 0, i, xbot[i]);
6373 for (i = 0; i < nslits; i++)
6374 cpl_matrix_set(bot_data, 1, i, ybot[i]);
6376 for (i = 0; i < nmaskslits; i++)
6377 cpl_matrix_set(bot_pattern, 0, i, xmbot[i]);
6379 for (i = 0; i < nmaskslits; i++)
6380 cpl_matrix_set(bot_pattern, 1, i, ymbot[i]);
6382 if (nmaskslits > nslits)
6383 use_pattern = nslits;
6385 use_pattern = nmaskslits;
6387 top_ident = cpl_ppm_match_points(top_data, nslits, 1.0, top_pattern,
6388 use_pattern, 0.0, 0.1, 5, &top_mdata,
6389 &top_mpattern, &top_scale, &top_angle);
6391 bot_ident = cpl_ppm_match_points(bot_data, nslits, 1.0, bot_pattern,
6392 use_pattern, 0.0, 0.1, 5, &bot_mdata,
6393 &bot_mpattern, &bot_scale, &bot_angle);
6395 if (top_ident == NULL && bot_ident == NULL) {
6396 cpl_msg_warning(cpl_func,
"Pattern matching failure: cannot match "
6397 "the %d found CCD slits with the %d mask slits: "
6398 "process will continue using the detected CCD "
6399 "slits positions", nslits, nmaskslits);
6403 found_slits_top = 0;
6404 found_slits_bot = 0;
6405 if (top_ident && bot_ident) {
6406 cpl_msg_info(cpl_func,
"Median platescale: %f +/- %f pixel/mm",
6407 (top_scale + bot_scale) / 2, fabs(top_scale - bot_scale));
6408 cpl_msg_info(cpl_func,
"Median rotation: %f +/- %f degrees",
6409 (top_angle + bot_angle) / 2, fabs(top_angle - bot_angle));
6410 if (fabs(top_angle) < fabs(bot_angle))
6411 angle = fabs(top_angle);
6413 angle = fabs(bot_angle);
6414 found_slits_top = cpl_matrix_get_ncol(top_mdata);
6415 found_slits_bot = cpl_matrix_get_ncol(bot_mdata);
6417 else if (top_ident) {
6418 cpl_msg_info(cpl_func,
"Median platescale: %f pixel/mm", top_scale);
6419 cpl_msg_info(cpl_func,
"Median rotation: %f degrees", top_angle);
6420 angle = fabs(top_angle);
6421 found_slits_top = cpl_matrix_get_ncol(top_mdata);
6424 cpl_msg_info(cpl_func,
"Median platescale: %f pixel/mm", bot_scale);
6425 cpl_msg_info(cpl_func,
"Median rotation: %f degrees", bot_angle);
6426 angle = fabs(bot_angle);
6427 found_slits_bot = cpl_matrix_get_ncol(bot_mdata);
6430 cpl_array_delete(top_ident);
6431 cpl_array_delete(bot_ident);
6434 cpl_msg_warning(cpl_func,
"Uncertain pattern matching: the rotation "
6435 "angle is expected to be around zero. This match is "
6436 "rejected: the process will continue using the %d "
6437 "detected CCD slits positions", nslits);
6441 found_slits = found_slits_top;
6442 if (found_slits < found_slits_bot)
6443 found_slits = found_slits_bot;
6445 if (found_slits < 4) {
6446 cpl_msg_warning(cpl_func,
6447 "Too few safely identified slits: %d out of %d "
6448 "candidates (%d expected). Process will continue "
6449 "using the detected CCD slits positions", found_slits,
6450 nslits, nmaskslits);
6454 cpl_msg_info(cpl_func,
"Preliminary identified slits: %d out of %d "
6455 "candidates\n(%d expected)", found_slits, nslits,
6458 if (found_slits_top < 4)
6459 found_slits_top = 0;
6461 if (found_slits_bot < 4)
6462 found_slits_bot = 0;
6470 for (i = 0; i < 2; i++) {
6471 cpl_size mindeg2d[] = {0, 0};
6472 cpl_size maxdeg2d[2];
6473 cpl_vector * fitresidual;
6475 found_slits = found_slits_top;
6477 mpattern = top_mpattern;
6480 found_slits = found_slits_bot;
6482 mpattern = bot_mpattern;
6485 if (found_slits == 0)
6487 else if (found_slits < 10)
6488 maxdeg2d[0] = maxdeg2d[1] = 1;
6490 maxdeg2d[0] = maxdeg2d[1] = 2;
6492 xpos = cpl_vector_wrap(found_slits,
6493 cpl_matrix_get_data(mdata) );
6494 ypos = cpl_vector_wrap(found_slits,
6495 cpl_matrix_get_data(mdata) + found_slits);
6496 xmpos = cpl_vector_wrap(found_slits,
6497 cpl_matrix_get_data(mpattern) );
6498 ympos = cpl_vector_wrap(found_slits,
6499 cpl_matrix_get_data(mpattern) + found_slits);
6500 mpos = cpl_bivector_wrap_vectors(xmpos, ympos);
6501 fitresidual = cpl_vector_new(cpl_vector_get_size(xpos));
6502 xpoly = cpl_polynomial_new(2);
6503 cpl_polynomial_fit(xpoly, mpattern, NULL, xpos, NULL, CPL_FALSE, mindeg2d, maxdeg2d);
6504 cpl_vector_fill_polynomial_fit_residual(fitresidual, xpos, NULL, xpoly, mpattern, NULL);
6505 xmse = cpl_vector_product(fitresidual, fitresidual)
6506 / cpl_vector_get_size(fitresidual);
6507 ypoly = cpl_polynomial_new(2);
6508 cpl_polynomial_fit(ypoly, mpattern, NULL, ypos, NULL, CPL_FALSE, mindeg2d, maxdeg2d);
6509 cpl_vector_fill_polynomial_fit_residual(fitresidual, ypos, NULL, ypoly, mpattern, NULL);
6510 ymse = cpl_vector_product(fitresidual, fitresidual)
6511 / cpl_vector_get_size(fitresidual);
6513 cpl_bivector_unwrap_vectors(mpos);
6514 cpl_vector_unwrap(xpos);
6515 cpl_vector_unwrap(ypos);
6516 cpl_vector_unwrap(xmpos);
6517 cpl_vector_unwrap(ympos);
6518 cpl_matrix_delete(mdata);
6519 cpl_matrix_delete(mpattern);
6520 cpl_vector_delete(fitresidual);
6525 top_xrms = sqrt(xmse*2*maxdeg2d[0]/(found_slits - 1));
6526 top_yrms = sqrt(ymse*2*maxdeg2d[0]/(found_slits - 1));
6531 bot_xrms = sqrt(xmse*2*maxdeg2d[0]/(found_slits - 1));
6532 bot_yrms = sqrt(ymse*2*maxdeg2d[0]/(found_slits - 1));
6536 if (top_xpoly && bot_xpoly) {
6537 if (top_xrms < bot_xrms) {
6540 cpl_polynomial_delete(bot_xpoly);
6545 cpl_polynomial_delete(top_xpoly);
6548 else if (top_xpoly) {
6557 if (top_ypoly && bot_ypoly) {
6558 if (top_yrms < bot_yrms) {
6561 cpl_polynomial_delete(bot_ypoly);
6566 cpl_polynomial_delete(top_ypoly);
6569 else if (top_ypoly) {
6578 if (xpoly == NULL || ypoly == NULL) {
6579 cpl_msg_warning(cpl_func,
"Fit failure: the accuracy of the "
6580 "identified slits positions cannot be improved.");
6581 cpl_polynomial_delete(xpoly);
6582 cpl_polynomial_delete(ypoly);
6587 cpl_msg_info(cpl_func,
6588 "Fit successful: X rms = %.3g, Y rms = %.3g (pixel)",
6592 write_global_distortion(global, 0, xpoly);
6593 write_global_distortion(global, 7, ypoly);
6601 positions = cpl_table_duplicate(maskslits);
6602 cpl_table_duplicate_column(positions,
"xmtop", positions,
"xtop");
6603 cpl_table_duplicate_column(positions,
"ymtop", positions,
"ytop");
6604 cpl_table_duplicate_column(positions,
"xmbottom", positions,
"xbottom");
6605 cpl_table_duplicate_column(positions,
"ymbottom", positions,
"ybottom");
6607 point = cpl_vector_new(2);
6608 dpoint = cpl_vector_get_data(point);
6610 for (i = 0; i < nmaskslits; i++) {
6614 dpoint[0] = cpl_table_get_double(positions,
"xmtop", i, NULL);
6615 dpoint[1] = cpl_table_get_double(positions,
"ymtop", i, NULL);
6616 position_x = cpl_polynomial_eval(xpoly, point);
6623 cpl_table_set_double(positions,
"xtop", i, position_x);
6624 position_y = cpl_polynomial_eval(ypoly, point);
6625 cpl_table_set_double(positions,
"ytop", i, position_y);
6626 dpoint[0] = cpl_table_get_double(positions,
"xmbottom", i, NULL);
6627 dpoint[1] = cpl_table_get_double(positions,
"ymbottom", i, NULL);
6628 position_x = cpl_polynomial_eval(xpoly, point);
6629 cpl_table_set_double(positions,
"xbottom", i, position_x);
6630 position_y = cpl_polynomial_eval(ypoly, point);
6631 cpl_table_set_double(positions,
"ybottom", i, position_y);
6640 cpl_vector_delete(point);
6641 cpl_polynomial_delete(xpoly);
6642 cpl_polynomial_delete(ypoly);
6644 cpl_table_erase_column(positions,
"xmtop");
6645 cpl_table_erase_column(positions,
"ymtop");
6646 cpl_table_erase_column(positions,
"xmbottom");
6647 cpl_table_erase_column(positions,
"ymbottom");
6649 if (mos_multiplex >= 0) {
6651 cpl_sprintf(
"in the CCD section between %d and %d pixel",
6652 mos_multiplex * mos_region_size,
6653 (mos_multiplex + 1) * mos_region_size);
6656 if (nmaskslits > nslits)
6657 cpl_msg_info(cpl_func,
6658 "Finally identified slits: %d out of %d expected %s\n"
6659 "(%d recovered)", nmaskslits, nmaskslits, msg_multiplex,
6660 nmaskslits - nslits);
6661 else if (nmaskslits < nslits)
6662 cpl_msg_info(cpl_func,
6663 "Finally identified slits: %d out of %d expected %s\n"
6664 "(%d rejected)", nmaskslits, nmaskslits, msg_multiplex,
6665 nslits - nmaskslits);
6667 cpl_msg_info(cpl_func,
6668 "Finally identified slits: %d out of %d expected %s",
6669 nmaskslits, nmaskslits, msg_multiplex);
6671 if (mos_multiplex >= 0) {
6672 cpl_free(msg_multiplex);
6680 cpl_table *mos_identify_slits_fast(cpl_table *slits, cpl_table *maskslits,
6683 const char *func =
"mos_identify_slits_fast";
6685 cpl_propertylist *sort_col;
6686 cpl_table *positions;
6695 cpl_polynomial *xpoly = NULL;
6696 cpl_polynomial *ypoly = NULL;
6697 cpl_error_code error;
6703 double dist1, dist2, dist3, dist, mindist;
6704 double scale, minscale, maxscale;
6705 double angle, minangle, maxangle;
6732 double sradius = 0.01;
6735 double pi = 3.14159265358979323846;
6740 cpl_msg_error(func,
"CCD slits table validation: %s",
6741 cpl_error_get_message());
6742 cpl_error_set(func, error);
6748 cpl_msg_error(func,
"Mask slits table validation: %s",
6749 cpl_error_get_message());
6750 cpl_error_set(func, error);
6754 if (1 != cpl_table_has_column(maskslits,
"slit_id")) {
6755 cpl_msg_error(func,
"Missing slits identifiers");
6756 cpl_error_set(func, CPL_ERROR_DATA_NOT_FOUND);
6760 if (CPL_TYPE_INT != cpl_table_get_column_type(maskslits,
"slit_id")) {
6761 cpl_msg_error(func,
"Wrong type used for slits identifiers");
6762 cpl_error_set(func, CPL_ERROR_INVALID_TYPE);
6766 nslits = cpl_table_get_nrow(slits);
6767 nmaskslits = cpl_table_get_nrow(maskslits);
6769 if (nslits == 0 || nmaskslits == 0) {
6770 cpl_msg_error(func,
"Empty slits table");
6771 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
6781 if (cpl_table_has_column(slits,
"xcenter"))
6782 cpl_table_erase_column(slits,
"xcenter");
6784 if (cpl_table_has_column(slits,
"ycenter"))
6785 cpl_table_erase_column(slits,
"ycenter");
6787 if (cpl_table_has_column(maskslits,
"xcenter"))
6788 cpl_table_erase_column(maskslits,
"xcenter");
6790 if (cpl_table_has_column(maskslits,
"ycenter"))
6791 cpl_table_erase_column(maskslits,
"ycenter");
6793 cpl_table_duplicate_column(slits,
"xcenter", slits,
"xtop");
6794 cpl_table_add_columns(slits,
"xcenter",
"xbottom");
6795 cpl_table_divide_scalar(slits,
"xcenter", 2.0);
6796 cpl_table_duplicate_column(slits,
"ycenter", slits,
"ytop");
6797 cpl_table_add_columns(slits,
"ycenter",
"ybottom");
6798 cpl_table_divide_scalar(slits,
"ycenter", 2.0);
6800 cpl_table_duplicate_column(maskslits,
"xcenter", maskslits,
"xtop");
6801 cpl_table_add_columns(maskslits,
"xcenter",
"xbottom");
6802 cpl_table_divide_scalar(maskslits,
"xcenter", 2.0);
6803 cpl_table_duplicate_column(maskslits,
"ycenter", maskslits,
"ytop");
6804 cpl_table_add_columns(maskslits,
"ycenter",
"ybottom");
6805 cpl_table_divide_scalar(maskslits,
"ycenter", 2.0);
6812 sort_col = cpl_propertylist_new();
6813 cpl_propertylist_append_bool(sort_col,
"ycenter", 1);
6814 cpl_table_sort(slits, sort_col);
6815 cpl_table_sort(maskslits, sort_col);
6816 cpl_propertylist_delete(sort_col);
6823 if (nslits < 3 && nmaskslits > nslits) {
6833 cpl_msg_warning(func,
"Cannot match the found CCD slit with the "
6834 "%d mask slits: process will continue using the "
6835 "detected CCD slit position", nmaskslits);
6837 cpl_msg_warning(func,
"Cannot match the %d found CCD slits with "
6838 "the %d mask slits: process will continue using "
6839 "the detected CCD slits positions", nslits,
6844 if (nslits <= 3 && nslits == nmaskslits) {
6846 cpl_msg_warning(func,
"Too few slits (%d) on mask and CCD", nslits);
6847 cpl_msg_warning(func,
"Their detected positions are left unchanged");
6858 positions = cpl_table_duplicate(slits);
6859 cpl_table_erase_column(slits,
"xcenter");
6860 cpl_table_erase_column(slits,
"ycenter");
6861 cpl_table_duplicate_column(positions,
"xmtop", maskslits,
"xtop");
6862 cpl_table_duplicate_column(positions,
"ymtop", maskslits,
"ytop");
6863 cpl_table_duplicate_column(positions,
"xmbottom", maskslits,
"xbottom");
6864 cpl_table_duplicate_column(positions,
"ymbottom", maskslits,
"ybottom");
6865 cpl_table_duplicate_column(positions,
"xmcenter", maskslits,
"xcenter");
6866 cpl_table_duplicate_column(positions,
"ymcenter", maskslits,
"ycenter");
6867 cpl_table_duplicate_column(positions,
"slit_id", maskslits,
"slit_id");
6868 cpl_table_erase_column(maskslits,
"xcenter");
6869 cpl_table_erase_column(maskslits,
"ycenter");
6872 xcenter = cpl_table_get_data_double(positions,
"xcenter");
6873 ycenter = cpl_table_get_data_double(positions,
"ycenter");
6874 xmcenter = cpl_table_get_data_double(positions,
"xmcenter");
6875 ymcenter = cpl_table_get_data_double(positions,
"ymcenter");
6877 dist1 = (xcenter[0] - xcenter[1])*(xcenter[0] - xcenter[1])
6878 + (ycenter[0] - ycenter[1])*(ycenter[0] - ycenter[1]);
6879 dist2 = (xmcenter[0] - xmcenter[1])*(xmcenter[0] - xmcenter[1])
6880 + (ymcenter[0] - ymcenter[1])*(ymcenter[0] - ymcenter[1]);
6881 scale = sqrt(dist1/dist2);
6884 dist1 = (xcenter[1] - xcenter[2])*(xcenter[1] - xcenter[2])
6885 + (ycenter[1] - ycenter[2])*(ycenter[1] - ycenter[2]);
6886 dist2 = (xmcenter[1] - xmcenter[2])*(xmcenter[1] - xmcenter[2])
6887 + (ymcenter[1] - ymcenter[2])*(ymcenter[1] - ymcenter[2]);
6888 scale += sqrt(dist1/dist2);
6892 cpl_msg_info(func,
"Platescale: %f pixel/mm", scale);
6898 if (nmaskslits < 3 && nslits > nmaskslits) {
6906 cpl_msg_warning(func,
"Cannot match the %d found CCD slits with "
6907 "the %d mask slits: process will continue using "
6908 "the detected CCD slits positions", nslits,
6940 if (cpl_table_has_column(slits,
"xpseudo"))
6941 cpl_table_erase_column(slits,
"xpseudo");
6943 if (cpl_table_has_column(slits,
"ypseudo"))
6944 cpl_table_erase_column(slits,
"ypseudo");
6946 if (cpl_table_has_column(maskslits,
"xpseudo"))
6947 cpl_table_erase_column(maskslits,
"xpseudo");
6949 if (cpl_table_has_column(maskslits,
"ypseudo"))
6950 cpl_table_erase_column(maskslits,
"ypseudo");
6952 cpl_table_duplicate_column(slits,
"xpseudo", slits,
"xcenter");
6953 cpl_table_duplicate_column(slits,
"ypseudo", slits,
"ycenter");
6955 xcenter = cpl_table_get_data_double(slits,
"xcenter");
6956 ycenter = cpl_table_get_data_double(slits,
"ycenter");
6957 xpseudo = cpl_table_get_data_double(slits,
"xpseudo");
6958 ypseudo = cpl_table_get_data_double(slits,
"ypseudo");
6960 for (i = 1; i < nslits - 1; i++) {
6961 dist1 = (xcenter[i-1] - xcenter[i]) * (xcenter[i-1] - xcenter[i])
6962 + (ycenter[i-1] - ycenter[i]) * (ycenter[i-1] - ycenter[i]);
6963 dist2 = (xcenter[i-1] - xcenter[i+1]) * (xcenter[i-1] - xcenter[i+1])
6964 + (ycenter[i-1] - ycenter[i+1]) * (ycenter[i-1] - ycenter[i+1]);
6965 dist3 = (xcenter[i] - xcenter[i+1]) * (xcenter[i] - xcenter[i+1])
6966 + (ycenter[i] - ycenter[i+1]) * (ycenter[i] - ycenter[i+1]);
6967 xpseudo[i] = sqrt(dist1/dist2);
6968 ypseudo[i] = sqrt(dist3/dist2);
6971 cpl_table_set_invalid(slits,
"xpseudo", 0);
6972 cpl_table_set_invalid(slits,
"xpseudo", nslits-1);
6973 cpl_table_set_invalid(slits,
"ypseudo", 0);
6974 cpl_table_set_invalid(slits,
"ypseudo", nslits-1);
6976 cpl_table_duplicate_column(maskslits,
"xpseudo", maskslits,
"xcenter");
6977 cpl_table_duplicate_column(maskslits,
"ypseudo", maskslits,
"ycenter");
6979 xcenter = cpl_table_get_data_double(maskslits,
"xcenter");
6980 ycenter = cpl_table_get_data_double(maskslits,
"ycenter");
6981 xmpseudo = cpl_table_get_data_double(maskslits,
"xpseudo");
6982 ympseudo = cpl_table_get_data_double(maskslits,
"ypseudo");
6984 for (i = 1; i < nmaskslits - 1; i++) {
6985 dist1 = (xcenter[i-1] - xcenter[i])*(xcenter[i-1] - xcenter[i])
6986 + (ycenter[i-1] - ycenter[i])*(ycenter[i-1] - ycenter[i]);
6987 dist2 = (xcenter[i-1] - xcenter[i+1])*(xcenter[i-1] - xcenter[i+1])
6988 + (ycenter[i-1] - ycenter[i+1])*(ycenter[i-1] - ycenter[i+1]);
6989 dist3 = (xcenter[i] - xcenter[i+1])*(xcenter[i] - xcenter[i+1])
6990 + (ycenter[i] - ycenter[i+1])*(ycenter[i] - ycenter[i+1]);
6991 xmpseudo[i] = sqrt(dist1/dist2);
6992 ympseudo[i] = sqrt(dist3/dist2);
6995 cpl_table_set_invalid(maskslits,
"xpseudo", 0);
6996 cpl_table_set_invalid(maskslits,
"xpseudo", nmaskslits-1);
6997 cpl_table_set_invalid(maskslits,
"ypseudo", 0);
6998 cpl_table_set_invalid(maskslits,
"ypseudo", nmaskslits-1);
7010 if (cpl_table_has_column(slits,
"slit_id"))
7011 cpl_table_erase_column(slits,
"slit_id");
7012 cpl_table_new_column(slits,
"slit_id", CPL_TYPE_INT);
7013 slit_id = cpl_table_get_data_int(maskslits,
"slit_id");
7015 for (i = 1; i < nmaskslits - 1; i++) {
7017 mindist = (xmpseudo[i] - xpseudo[1]) * (xmpseudo[i] - xpseudo[1])
7018 + (ympseudo[i] - ypseudo[1]) * (ympseudo[i] - ypseudo[1]);
7020 if (mindist < sradius*sradius)
7022 for (j = 2; j < nslits - 1; j++) {
7023 dist = (xmpseudo[i] - xpseudo[j]) * (xmpseudo[i] - xpseudo[j])
7024 + (ympseudo[i] - ypseudo[j]) * (ympseudo[i] - ypseudo[j]);
7025 if (dist < sradius*sradius)
7029 if (mindist > dist) {
7035 mindist = sqrt(mindist);
7037 if (mindist < sradius && in_sradius == 1) {
7038 cpl_table_set_int(slits,
"slit_id", minpos-1, slit_id[i-1]);
7039 cpl_table_set_int(slits,
"slit_id", minpos, slit_id[i]);
7040 cpl_table_set_int(slits,
"slit_id", minpos+1, slit_id[i+1]);
7050 found_slits = nslits - cpl_table_count_invalid(slits,
"slit_id");
7052 if (found_slits < 3) {
7053 cpl_msg_warning(func,
"Too few preliminarily identified slits: "
7054 "%d out of %d", found_slits, nslits);
7055 if (nslits == nmaskslits) {
7056 cpl_msg_warning(func,
"(this is not an error, it could be caused "
7057 "by a mask with regularly located slits)");
7058 cpl_msg_warning(func,
"The detected slits positions are left "
7068 cpl_table_erase_column(slits,
"slit_id");
7069 cpl_table_erase_column(slits,
"xpseudo");
7070 cpl_table_erase_column(slits,
"ypseudo");
7071 positions = cpl_table_duplicate(slits);
7072 cpl_table_erase_column(slits,
"xcenter");
7073 cpl_table_erase_column(slits,
"ycenter");
7075 cpl_table_erase_column(maskslits,
"xpseudo");
7076 cpl_table_erase_column(maskslits,
"ypseudo");
7077 cpl_table_duplicate_column(positions,
"xmtop",
7079 cpl_table_duplicate_column(positions,
"ymtop",
7081 cpl_table_duplicate_column(positions,
"xmbottom",
7082 maskslits,
"xbottom");
7083 cpl_table_duplicate_column(positions,
"ymbottom",
7084 maskslits,
"ybottom");
7085 cpl_table_duplicate_column(positions,
"xmcenter",
7086 maskslits,
"xcenter");
7087 cpl_table_duplicate_column(positions,
"ymcenter",
7088 maskslits,
"ycenter");
7089 cpl_table_duplicate_column(positions,
"slit_id",
7090 maskslits,
"slit_id");
7091 cpl_table_erase_column(maskslits,
"xcenter");
7092 cpl_table_erase_column(maskslits,
"ycenter");
7096 cpl_table_erase_column(slits,
"slit_id");
7097 cpl_table_erase_column(slits,
"xpseudo");
7098 cpl_table_erase_column(slits,
"ypseudo");
7099 positions = cpl_table_duplicate(slits);
7100 cpl_table_erase_column(slits,
"xcenter");
7101 cpl_table_erase_column(slits,
"ycenter");
7102 cpl_msg_warning(func,
"(the failure could be caused "
7103 "by a mask with regularly located slits)");
7108 cpl_msg_info(func,
"Preliminarily identified slits: %d out of %d "
7109 "candidates (%d expected)", found_slits, nslits,
7120 positions = cpl_table_new(found_slits);
7121 cpl_table_new_column(positions,
"slit_id", CPL_TYPE_INT);
7122 cpl_table_new_column(positions,
"xtop", CPL_TYPE_DOUBLE);
7123 cpl_table_new_column(positions,
"ytop", CPL_TYPE_DOUBLE);
7124 cpl_table_new_column(positions,
"xbottom", CPL_TYPE_DOUBLE);
7125 cpl_table_new_column(positions,
"ybottom", CPL_TYPE_DOUBLE);
7126 cpl_table_new_column(positions,
"xcenter", CPL_TYPE_DOUBLE);
7127 cpl_table_new_column(positions,
"ycenter", CPL_TYPE_DOUBLE);
7128 cpl_table_new_column(positions,
"xmtop", CPL_TYPE_DOUBLE);
7129 cpl_table_new_column(positions,
"ymtop", CPL_TYPE_DOUBLE);
7130 cpl_table_new_column(positions,
"xmbottom", CPL_TYPE_DOUBLE);
7131 cpl_table_new_column(positions,
"ymbottom", CPL_TYPE_DOUBLE);
7132 cpl_table_new_column(positions,
"xmcenter", CPL_TYPE_DOUBLE);
7133 cpl_table_new_column(positions,
"ymcenter", CPL_TYPE_DOUBLE);
7134 cpl_table_new_column(positions,
"good", CPL_TYPE_INT);
7135 cpl_table_fill_column_window_int(positions,
"good", 0, found_slits, 0);
7137 slit_id = cpl_table_get_data_int (slits,
"slit_id");
7138 xtop = cpl_table_get_data_double(slits,
"xtop");
7139 ytop = cpl_table_get_data_double(slits,
"ytop");
7140 xbottom = cpl_table_get_data_double(slits,
"xbottom");
7141 ybottom = cpl_table_get_data_double(slits,
"ybottom");
7142 xcenter = cpl_table_get_data_double(slits,
"xcenter");
7143 ycenter = cpl_table_get_data_double(slits,
"ycenter");
7145 mslit_id = cpl_table_get_data_int (maskslits,
"slit_id");
7146 xmtop = cpl_table_get_data_double(maskslits,
"xtop");
7147 ymtop = cpl_table_get_data_double(maskslits,
"ytop");
7148 xmbottom = cpl_table_get_data_double(maskslits,
"xbottom");
7149 ymbottom = cpl_table_get_data_double(maskslits,
"ybottom");
7150 xmcenter = cpl_table_get_data_double(maskslits,
"xcenter");
7151 ymcenter = cpl_table_get_data_double(maskslits,
"ycenter");
7161 cpl_table_fill_invalid_int(slits,
"slit_id", 0);
7162 for (i = 0; i < nmaskslits; i++) {
7163 for (j = 0; j < nslits; j++) {
7164 if (slit_id[j] == 0)
7166 if (mslit_id[i] == slit_id[j]) {
7167 cpl_table_set_int (positions,
"slit_id", k, slit_id[j]);
7169 cpl_table_set_double(positions,
"xtop", k, xtop[j]);
7170 cpl_table_set_double(positions,
"ytop", k, ytop[j]);
7171 cpl_table_set_double(positions,
"xbottom", k, xbottom[j]);
7172 cpl_table_set_double(positions,
"ybottom", k, ybottom[j]);
7173 cpl_table_set_double(positions,
"xcenter", k, xcenter[j]);
7174 cpl_table_set_double(positions,
"ycenter", k, ycenter[j]);
7176 cpl_table_set_double(positions,
"xmtop", k, xmtop[i]);
7177 cpl_table_set_double(positions,
"ymtop", k, ymtop[i]);
7178 cpl_table_set_double(positions,
"xmbottom", k, xmbottom[i]);
7179 cpl_table_set_double(positions,
"ymbottom", k, ymbottom[i]);
7180 cpl_table_set_double(positions,
"xmcenter", k, xmcenter[i]);
7181 cpl_table_set_double(positions,
"ymcenter", k, ymcenter[i]);
7192 cpl_table_erase_column(slits,
"slit_id");
7193 cpl_table_erase_column(slits,
"xpseudo");
7194 cpl_table_erase_column(slits,
"ypseudo");
7195 cpl_table_erase_column(slits,
"xcenter");
7196 cpl_table_erase_column(slits,
"ycenter");
7197 cpl_table_erase_column(maskslits,
"xpseudo");
7198 cpl_table_erase_column(maskslits,
"ypseudo");
7199 cpl_table_erase_column(maskslits,
"xcenter");
7200 cpl_table_erase_column(maskslits,
"ycenter");
7210 ytop = cpl_table_get_data_double(positions,
"ytop");
7211 ybottom = cpl_table_get_data_double(positions,
"ybottom");
7212 xcenter = cpl_table_get_data_double(positions,
"xcenter");
7213 ycenter = cpl_table_get_data_double(positions,
"ycenter");
7214 xmcenter = cpl_table_get_data_double(positions,
"xmcenter");
7215 ymcenter = cpl_table_get_data_double(positions,
"ymcenter");
7217 scales = cpl_vector_new(found_slits - 1);
7218 dscale = cpl_vector_get_data(scales);
7219 angles = cpl_vector_new(found_slits - 1);
7220 dangle = cpl_vector_get_data(angles);
7222 for (i = 1; i < found_slits; i++) {
7223 dist1 = (xcenter[i-1] - xcenter[i]) * (xcenter[i-1] - xcenter[i])
7224 + (ycenter[i-1] - ycenter[i]) * (ycenter[i-1] - ycenter[i]);
7225 dist2 = (xmcenter[i-1] - xmcenter[i]) * (xmcenter[i-1] - xmcenter[i])
7226 + (ymcenter[i-1] - ymcenter[i]) * (ymcenter[i-1] - ymcenter[i]);
7227 dscale[i-1] = sqrt(dist1/dist2);
7228 dangle[i-1] = atan2(ycenter[i-1] - ycenter[i],
7229 xcenter[i-1] - xcenter[i])
7230 - atan2(ymcenter[i-1] - ymcenter[i],
7231 xmcenter[i-1] - xmcenter[i]);
7236 minscale = cpl_vector_get_min(scales);
7237 scale = cpl_vector_get_median_const(scales);
7238 maxscale = cpl_vector_get_max(scales);
7240 minangle = cpl_vector_get_min(angles);
7241 angle = cpl_vector_get_median_const(angles);
7242 maxangle = cpl_vector_get_max(angles);
7244 cpl_msg_info(func,
"Median platescale: %f pixel/mm", scale);
7245 cpl_msg_info(func,
"Minmax platescale: %f, %f pixel/mm",
7246 minscale, maxscale);
7248 cpl_msg_info(func,
"Median rotation: %f degrees", angle);
7249 cpl_msg_info(func,
"Minmax rotation: %f, %f degrees",
7250 minangle, maxangle);
7252 good = cpl_table_get_data_int(positions,
"good");
7254 good[0] = good[found_slits - 1] = 1;
7255 for (i = 1; i < found_slits; i++) {
7256 if (fabs((dscale[i-1] - scale)/scale) < 0.10
7257 && fabs(dangle[i-1] - angle) < 2) {
7263 for (i = 0; i < found_slits; i++) {
7303 cpl_vector_delete(scales);
7304 cpl_vector_delete(angles);
7306 cpl_table_and_selected_int(positions,
"good", CPL_EQUAL_TO, 0);
7307 cpl_table_erase_selected(positions);
7308 cpl_table_erase_column(positions,
"good");
7309 found_slits = cpl_table_get_nrow(positions);
7311 if (found_slits < 4) {
7319 cpl_msg_warning(func,
"Too few safely identified slits: %d out of %d "
7320 "candidates (%d expected). Process will continue "
7321 "using the detected CCD slits positions", found_slits,
7322 nslits, nmaskslits);
7323 cpl_table_delete(positions);
7327 cpl_msg_info(func,
"Safely identified slits: %d out of %d "
7328 "candidates\n(%d expected)", found_slits, nslits,
7339 xpos = cpl_vector_wrap(found_slits,
7340 cpl_table_get_data_double(positions,
"xcenter"));
7341 ypos = cpl_vector_wrap(found_slits,
7342 cpl_table_get_data_double(positions,
"ycenter"));
7343 xmpos = cpl_vector_wrap(found_slits,
7344 cpl_table_get_data_double(positions,
"xmcenter"));
7345 ympos = cpl_vector_wrap(found_slits,
7346 cpl_table_get_data_double(positions,
"ymcenter"));
7347 mpos = cpl_bivector_wrap_vectors(xmpos, ympos);
7349 if (found_slits < 10)
7354 xpoly = cpl_polynomial_fit_2d_create(mpos, xpos, degree, &xmse);
7356 ypoly = cpl_polynomial_fit_2d_create(mpos, ypos, degree, &ymse);
7357 cpl_bivector_unwrap_vectors(mpos);
7358 cpl_vector_unwrap(xpos);
7359 cpl_vector_unwrap(ypos);
7360 cpl_vector_unwrap(xmpos);
7361 cpl_vector_unwrap(ympos);
7362 if (ypoly == NULL) {
7363 if (found_slits == nmaskslits) {
7364 cpl_msg_warning(func,
"Fit failure: the accuracy of the "
7365 "identified slits positions is not improved.");
7376 cpl_msg_info(func,
"Fit failure: not all slits have been "
7377 "identified. Process will continue using "
7378 "the detected CCD slits positions");
7381 cpl_polynomial_delete(xpoly);
7385 cpl_msg_info(func,
"Fit successful: X rms = %.3g, Y rms = %.3g (pixel)",
7386 sqrt(xmse), sqrt(ymse));
7389 write_global_distortion(global, 0, xpoly);
7390 write_global_distortion(global, 7, ypoly);
7398 cpl_table_delete(positions);
7400 positions = cpl_table_duplicate(maskslits);
7401 cpl_table_duplicate_column(positions,
"xmtop", positions,
"xtop");
7402 cpl_table_duplicate_column(positions,
"ymtop", positions,
"ytop");
7403 cpl_table_duplicate_column(positions,
"xmbottom", positions,
"xbottom");
7404 cpl_table_duplicate_column(positions,
"ymbottom", positions,
"ybottom");
7406 point = cpl_vector_new(2);
7407 dpoint = cpl_vector_get_data(point);
7409 for (i = 0; i < nmaskslits; i++) {
7410 dpoint[0] = cpl_table_get_double(positions,
"xmtop", i, NULL);
7411 dpoint[1] = cpl_table_get_double(positions,
"ymtop", i, NULL);
7412 cpl_table_set_double(positions,
"xtop", i,
7413 cpl_polynomial_eval(xpoly, point));
7414 cpl_table_set_double(positions,
"ytop", i,
7415 cpl_polynomial_eval(ypoly, point));
7416 dpoint[0] = cpl_table_get_double(positions,
"xmbottom", i, NULL);
7417 dpoint[1] = cpl_table_get_double(positions,
"ymbottom", i, NULL);
7418 cpl_table_set_double(positions,
"xbottom", i,
7419 cpl_polynomial_eval(xpoly, point));
7420 cpl_table_set_double(positions,
"ybottom", i,
7421 cpl_polynomial_eval(ypoly, point));
7424 cpl_vector_delete(point);
7425 cpl_polynomial_delete(xpoly);
7426 cpl_polynomial_delete(ypoly);
7428 cpl_table_erase_column(positions,
"xmtop");
7429 cpl_table_erase_column(positions,
"ymtop");
7430 cpl_table_erase_column(positions,
"xmbottom");
7431 cpl_table_erase_column(positions,
"ymbottom");
7433 if (nmaskslits > nslits)
7434 cpl_msg_info(func,
"Finally identified slits: %d out of %d expected\n"
7435 "(%d recovered)", nmaskslits, nmaskslits, nmaskslits - nslits);
7436 else if (nmaskslits < nslits)
7437 cpl_msg_info(func,
"Finally identified slits: %d out of %d expected\n"
7438 "(%d rejected)", nmaskslits, nmaskslits, nslits - nmaskslits);
7440 cpl_msg_info(func,
"Finally identified slits: %d out of %d expected",
7441 nmaskslits, nmaskslits);
7489 double blue,
double red,
double dispersion)
7492 const char *func =
"mos_trace_flat";
7494 cpl_image *gradient;
7495 cpl_image *sgradient;
7512 double start_y, prev_y;
7521 int pixel_above, pixel_below;
7523 char trace_id[MAX_COLNAME];
7528 if (flat == NULL || slits == NULL) {
7529 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
7533 if (dispersion <= 0.0) {
7534 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
7538 if (red - blue < dispersion) {
7539 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
7548 nslits = cpl_table_get_nrow(slits);
7549 if (1 != cpl_table_has_column(slits,
"slit_id")) {
7550 cpl_table_new_column(slits,
"slit_id", CPL_TYPE_INT);
7551 for (i = 0; i < nslits; i++)
7552 cpl_table_set_int(slits,
"slit_id", i, -(i+1));
7555 slit_id = cpl_table_get_data_int(slits,
"slit_id");
7557 nx = cpl_image_get_size_x(flat);
7558 ny = cpl_image_get_size_y(flat);
7561 gradient = cpl_image_duplicate(flat);
7562 dgradient = cpl_image_get_data_float(gradient);
7564 for (i = 0; i < ny - 1; i++) {
7566 for (j = 0; j < nx; j++) {
7568 dgradient[l] = fabs(dgradient[l] - dgradient[l + nx]);
7573 for (j = 0; j < nx; j++)
7574 dgradient[npix - j] = 0.0;
7576 cpl_image_turn(gradient, -1);
7577 nx = cpl_image_get_size_x(gradient);
7578 ny = cpl_image_get_size_y(gradient);
7579 sgradient = mos_image_vertical_median_filter(gradient,
7580 filtbox, 0, ny, 0, step);
7581 cpl_image_delete(gradient);
7588 dgradient = cpl_image_get_data_float(sgradient);
7590 for (i = 1; i <= ny; i += step) {
7591 row = cpl_vector_new_from_image_row(sgradient, i);
7592 srow = cpl_vector_filter_median_create(row, filtbox);
7593 cpl_vector_subtract(row, srow);
7594 cpl_vector_delete(srow);
7595 g = dgradient + (i-1)*nx;
7596 r = cpl_vector_get_data(row);
7597 for (j = 0; j < nx; j++)
7599 cpl_vector_delete(row);
7609 xtop = cpl_table_get_data_double(slits,
"xtop");
7610 ytop = cpl_table_get_data_double(slits,
"ytop");
7611 xbottom = cpl_table_get_data_double(slits,
"xbottom");
7612 ybottom = cpl_table_get_data_double(slits,
"ybottom");
7620 peaks = cpl_calloc(ny,
sizeof(cpl_vector *));
7622 for (i = 0; i < ny; i += step) {
7623 g = dgradient + i*nx;
7629 cpl_vector_subtract_scalar(peaks[i], 0.5);
7633 cpl_image_delete(sgradient);
7659 pixel_above = STRETCH_FACTOR * (red - reference) / dispersion;
7660 pixel_below = STRETCH_FACTOR * (reference - blue) / dispersion;
7667 nrows = (ny-1)/step + 1;
7668 traces = cpl_table_new(nrows);
7669 cpl_table_new_column(traces,
"x", CPL_TYPE_DOUBLE);
7670 cpl_table_set_column_unit(traces,
"x",
"pixel");
7671 for (i = 0, j = 0; i < ny; i += step, j++)
7672 cpl_table_set(traces,
"x", j, i);
7674 for (i = 0; i < nslits; i++) {
7695 peak = cpl_vector_get_data(peaks[pos]);
7696 npeaks = cpl_vector_get_size(peaks[pos]);
7698 min = fabs(peak[0] - xtop[i]);
7700 for (j = 1; j < npeaks; j++) {
7701 dist = fabs(peak[j] - xtop[i]);
7712 snprintf(trace_id, MAX_COLNAME,
"t%d", slit_id[i]);
7713 cpl_table_new_column(traces, trace_id, CPL_TYPE_DOUBLE);
7715 if (min > sradius || npeaks == 0) {
7716 cpl_msg_warning(func,
"Cannot find spectrum edge for "
7717 "top (or left) end of slit %d", slit_id[i]);
7729 cpl_table_set(traces, trace_id, pos/step, nx - peak[minpos]);
7730 start_y = peak[minpos];
7738 for (j = pos + step; j < ny; j += step) {
7739 if (j - pos > pixel_above)
7742 peak = cpl_vector_get_data(peaks[j]);
7743 npeaks = cpl_vector_get_size(peaks[j]);
7744 min = fabs(peak[0] - prev_y);
7746 for (k = 1; k < npeaks; k++) {
7747 dist = fabs(peak[k] - prev_y);
7753 if (min < tolerance) {
7754 cpl_table_set(traces, trace_id, j/step,
7756 prev_y = peak[minpos];
7767 for (j = pos - step; j >= 0; j -= step) {
7768 if (pos - j > pixel_below)
7771 peak = cpl_vector_get_data(peaks[j]);
7772 npeaks = cpl_vector_get_size(peaks[j]);
7773 min = fabs(peak[0] - prev_y);
7775 for (k = 1; k < npeaks; k++) {
7776 dist = fabs(peak[k] - prev_y);
7782 if (min < tolerance) {
7783 cpl_table_set(traces, trace_id, j/step,
7785 prev_y = peak[minpos];
7797 peak = cpl_vector_get_data(peaks[pos]);
7798 npeaks = cpl_vector_get_size(peaks[pos]);
7800 min = fabs(peak[0] - xbottom[i]);
7802 for (j = 1; j < npeaks; j++) {
7803 dist = fabs(peak[j] - xbottom[i]);
7814 snprintf(trace_id, MAX_COLNAME,
"b%d", slit_id[i]);
7815 cpl_table_new_column(traces, trace_id, CPL_TYPE_DOUBLE);
7817 if (min > sradius || npeaks == 0) {
7818 cpl_msg_warning(func,
"Cannot find spectrum edge for "
7819 "bottom (or right) end of slit %d", slit_id[i]);
7823 cpl_table_set(traces, trace_id, pos/step, nx - peak[minpos]);
7824 start_y = peak[minpos];
7832 for (j = pos + step; j < ny; j += step) {
7833 if (j - pos > pixel_above)
7836 peak = cpl_vector_get_data(peaks[j]);
7837 npeaks = cpl_vector_get_size(peaks[j]);
7838 min = fabs(peak[0] - prev_y);
7840 for (k = 1; k < npeaks; k++) {
7841 dist = fabs(peak[k] - prev_y);
7847 if (min < tolerance) {
7848 cpl_table_set(traces, trace_id, j/step,
7850 prev_y = peak[minpos];
7861 for (j = pos - step; j >= 0; j -= step) {
7862 if (pos - j > pixel_below)
7865 peak = cpl_vector_get_data(peaks[j]);
7866 npeaks = cpl_vector_get_size(peaks[j]);
7867 min = fabs(peak[0] - prev_y);
7869 for (k = 1; k < npeaks; k++) {
7870 dist = fabs(peak[k] - prev_y);
7876 if (min < tolerance) {
7877 cpl_table_set(traces, trace_id, j/step,
7879 prev_y = peak[minpos];
7887 for (i = 0; i < ny; i += step)
7888 cpl_vector_delete(peaks[i]);
7924 const char *func =
"mos_poly_trace";
7926 cpl_table *polytraces;
7930 cpl_polynomial *polytrace;
7931 char trace_id[MAX_COLNAME];
7932 char trace_res[MAX_COLNAME];
7933 char trace_mod[MAX_COLNAME];
7934 const char *clab[6] = {
"c0",
"c1",
"c2",
"c3",
"c4",
"c5"};
7945 if (traces == NULL || slits == NULL) {
7946 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
7951 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
7955 nrows = cpl_table_get_nrow(traces);
7956 xdata = cpl_table_get_data_double(traces,
"x");
7957 nslits = cpl_table_get_nrow(slits);
7958 slit_id = cpl_table_get_data_int(slits,
"slit_id");
7960 polytraces = cpl_table_new(2*nslits);
7961 cpl_table_new_column(polytraces,
"slit_id", CPL_TYPE_INT);
7962 for (i = 0; i <= order; i++)
7963 cpl_table_new_column(polytraces, clab[i], CPL_TYPE_DOUBLE);
7965 for (i = 0; i < nslits; i++) {
7966 for (j = 0; j < 2; j++) {
7969 snprintf(trace_id, MAX_COLNAME,
"b%d", slit_id[i]);
7970 snprintf(trace_res, MAX_COLNAME,
"b%d_res", slit_id[i]);
7971 snprintf(trace_mod, MAX_COLNAME,
"b%d_mod", slit_id[i]);
7974 snprintf(trace_id, MAX_COLNAME,
"t%d", slit_id[i]);
7975 snprintf(trace_res, MAX_COLNAME,
"t%d_res", slit_id[i]);
7976 snprintf(trace_mod, MAX_COLNAME,
"t%d_mod", slit_id[i]);
7979 cpl_table_set_int(polytraces,
"slit_id", 2*i+j, slit_id[i]);
7986 dummy = cpl_table_new(nrows);
7987 cpl_table_duplicate_column(dummy,
"x", traces,
"x");
7988 cpl_table_duplicate_column(dummy, trace_id, traces, trace_id);
7989 npoints = nrows - cpl_table_count_invalid(dummy, trace_id);
7990 if (npoints < 2 * order) {
7991 cpl_table_delete(dummy);
7994 cpl_table_erase_invalid(dummy);
7995 x = cpl_vector_wrap(npoints,
7996 cpl_table_get_data_double(dummy,
"x"));
7997 trace = cpl_vector_wrap(npoints,
7998 cpl_table_get_data_double(dummy, trace_id));
7999 polytrace = cpl_polynomial_fit_1d_create(x, trace, order, NULL);
8000 cpl_vector_unwrap(x);
8001 cpl_vector_unwrap(trace);
8002 cpl_table_delete(dummy);
8011 if (fabs(cpl_polynomial_get_coeff(polytrace, &k)) > 1.E-4) {
8012 cpl_polynomial_delete(polytrace);
8013 cpl_table_new_column(traces, trace_mod, CPL_TYPE_DOUBLE);
8014 cpl_table_duplicate_column(traces, trace_res, traces,
8017 cpl_msg_warning(func,
"Exclude bad curvature solution "
8018 "for bottom (right) edge of slit %d", slit_id[i]);
8020 cpl_msg_warning(func,
"Exclude bad curvature solution "
8021 "for top (left) edge of slit %d", slit_id[i]);
8030 for (k = 0; k <= order; k++)
8031 cpl_table_set_double(polytraces, clab[k], 2*i+j,
8032 cpl_polynomial_get_coeff(polytrace, &k));
8038 cpl_table_new_column(traces, trace_mod, CPL_TYPE_DOUBLE);
8039 cpl_table_set_column_unit(traces, trace_mod,
"pixel");
8041 for (k = 0; k < nrows; k++) {
8042 cpl_table_set_double(traces, trace_mod, k,
8043 cpl_polynomial_eval_1d(polytrace, xdata[k], NULL));
8046 cpl_polynomial_delete(polytrace);
8048 cpl_table_duplicate_column(traces, trace_res, traces, trace_mod);
8049 cpl_table_subtract_columns(traces, trace_res, trace_id);
8050 cpl_table_multiply_scalar(traces, trace_res, -1.0);
8086 const char *func =
"mos_global_trace";
8088 const char *clab[6] = {
"c0",
"c1",
"c2",
"c3",
"c4",
"c5"};
8101 int order, nrows, nslits;
8105 if (polytraces == NULL) {
8106 cpl_msg_error(func,
"Missing spectral curvature table");
8107 return cpl_error_set(func, CPL_ERROR_NULL_INPUT);
8110 if (slits == NULL) {
8111 cpl_msg_error(func,
"Missing slits positions table");
8112 return cpl_error_set(func, CPL_ERROR_NULL_INPUT);
8115 nslits = cpl_table_get_nrow(slits);
8117 table = cpl_table_duplicate(polytraces);
8118 cpl_table_erase_invalid(table);
8120 nrows = cpl_table_get_nrow(table);
8123 cpl_msg_warning(func,
"Too few successful spectral curvature tracings "
8124 "(%d): the determination of a global curvature model "
8126 return CPL_ERROR_NONE;
8129 order = cpl_table_get_ncol(polytraces) - 2;
8131 for (i = 0; i <= order; i++) {
8132 if (!cpl_table_has_column(table, clab[i])) {
8133 cpl_msg_error(func,
"Wrong spectral curvature table");
8134 return cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
8143 for (i = 0; i < nslits; i++) {
8144 if (!cpl_table_is_valid(polytraces, clab[0], 2*i)) {
8145 cpl_table_set_double(polytraces, clab[0], 2*i,
8146 cpl_table_get_double(slits,
"ytop", i, NULL));
8148 if (!cpl_table_is_valid(polytraces, clab[0], 2*i+1)) {
8149 cpl_table_set_double(polytraces, clab[0], 2*i+1,
8150 cpl_table_get_double(slits,
"ybottom", i, NULL));
8154 offset = cpl_table_get_data_double(polytraces, clab[0]);
8161 c0 = cpl_vector_wrap(nrows, cpl_table_get_data_double(table, clab[0]));
8163 for (i = 1; i <= order; i++) {
8164 cn = cpl_vector_wrap(nrows, cpl_table_get_data_double(table, clab[i]));
8165 list = cpl_bivector_wrap_vectors(c0, cn);
8166 robustLinearFit(list, &q, &m, &rms);
8170 for (j = 0; j < 2*nslits; j++) {
8172 if (cpl_table_is_valid(polytraces, clab[i], j))
8174 cpl_table_set_double(polytraces, clab[i], j, offset[j]*m + q);
8180 cpl_bivector_unwrap_vectors(list);
8184 cpl_vector_unwrap(cn);
8187 cpl_vector_unwrap(c0);
8188 cpl_table_delete(table);
8190 return CPL_ERROR_NONE;
8265 cpl_table *polytraces,
double reference,
8266 double blue,
double red,
double dispersion,
8267 int flux, cpl_image *calibration)
8269 const char *func =
"mos_spatial_calibration";
8271 const char *clab[6] = {
"c0",
"c1",
"c2",
"c3",
"c4",
"c5"};
8273 cpl_polynomial *polytop;
8274 cpl_polynomial *polybot;
8276 cpl_image *resampled;
8280 double vtop, vbot, value;
8286 int yint, ysize, yprev;
8292 int pixel_above, pixel_below, refpixel, start_pixel, end_pixel;
8293 int missing_top, missing_bot;
8299 int create_position = 1;
8302 if (spectra == NULL || slits == NULL || polytraces == NULL) {
8303 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
8307 if (dispersion <= 0.0) {
8308 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
8312 if (red - blue < dispersion) {
8313 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
8317 nx = cpl_image_get_size_x(spectra);
8318 ny = cpl_image_get_size_y(spectra);
8319 sdata = cpl_image_get_data(spectra);
8321 data = cpl_image_get_data(calibration);
8323 if (cpl_table_has_column(slits,
"position"))
8324 create_position = 0;
8326 if (create_position) {
8327 cpl_table_new_column(slits,
"position", CPL_TYPE_INT);
8328 cpl_table_new_column(slits,
"length", CPL_TYPE_INT);
8329 cpl_table_set_column_unit(slits,
"position",
"pixel");
8330 cpl_table_set_column_unit(slits,
"length",
"pixel");
8333 length = cpl_table_get_data_int(slits,
"length");
8335 nslits = cpl_table_get_nrow(slits);
8336 slit_id = cpl_table_get_data_int(slits,
"slit_id");
8337 order = cpl_table_get_ncol(polytraces) - 2;
8344 pixel_above = STRETCH_FACTOR * (red - reference) / dispersion;
8345 pixel_below = STRETCH_FACTOR * (reference - blue) / dispersion;
8347 exslit = cpl_calloc(nslits,
sizeof(cpl_image *));
8349 for (i = 0; i < nslits; i++) {
8351 if (create_position == 0)
8366 refpixel = cpl_table_get_double(slits,
"xtop", i, NULL);
8368 start_pixel = refpixel - pixel_below;
8369 if (start_pixel < 0)
8372 end_pixel = refpixel + pixel_above;
8382 polytop = cpl_polynomial_new(1);
8383 for (k = 0; k <= order; k++) {
8384 coeff = cpl_table_get_double(polytraces, clab[k], 2*i, &null);
8386 cpl_polynomial_delete(polytop);
8390 cpl_polynomial_set_coeff(polytop, &k, coeff);
8394 polybot = cpl_polynomial_new(1);
8395 for (k = 0; k <= order; k++) {
8396 coeff = cpl_table_get_double(polytraces, clab[k], 2*i+1, &null);
8398 cpl_polynomial_delete(polybot);
8402 cpl_polynomial_set_coeff(polybot, &k, coeff);
8405 if (missing_top && missing_bot) {
8406 cpl_msg_warning(func,
"Spatial calibration, slit %d was not "
8407 "traced: no extraction!",
8419 cpl_msg_warning(func,
"Upper edge of slit %d was not traced: "
8420 "the spectral curvature of the lower edge "
8421 "is used instead.", slit_id[i]);
8422 polytop = cpl_polynomial_duplicate(polybot);
8423 ytop = cpl_table_get_double(slits,
"ytop", i, NULL);
8424 ybot = cpl_table_get_double(slits,
"ybottom", i, NULL);
8426 coeff = cpl_polynomial_get_coeff(polybot, &k);
8427 coeff += ytop - ybot;
8428 cpl_polynomial_set_coeff(polytop, &k, coeff);
8432 cpl_msg_warning(func,
"Lower edge of slit %d was not traced: "
8433 "the spectral curvature of the upper edge "
8434 "is used instead.", slit_id[i]);
8435 polybot = cpl_polynomial_duplicate(polytop);
8436 ytop = cpl_table_get_double(slits,
"ytop", i, NULL);
8437 ybot = cpl_table_get_double(slits,
"ybottom", i, NULL);
8439 coeff = cpl_polynomial_get_coeff(polytop, &k);
8440 coeff -= ytop - ybot;
8441 cpl_polynomial_set_coeff(polybot, &k, coeff);
8448 top = cpl_polynomial_eval_1d(polytop, refpixel, NULL);
8449 bot = cpl_polynomial_eval_1d(polybot, refpixel, NULL);
8450 npseudo = ceil(top-bot) + 1;
8453 cpl_polynomial_delete(polytop);
8454 cpl_polynomial_delete(polybot);
8455 cpl_msg_warning(func,
"Slit %d was badly traced: no extraction!",
8460 exslit[i] = cpl_image_new(nx, npseudo+1, CPL_TYPE_FLOAT);
8461 xdata = cpl_image_get_data(exslit[i]);
8467 for (j = start_pixel; j < end_pixel; j++) {
8468 top = cpl_polynomial_eval_1d(polytop, j, NULL);
8469 bot = cpl_polynomial_eval_1d(polybot, j, NULL);
8470 factor = (top-bot)/npseudo;
8471 for (k = 0; k <= npseudo; k++) {
8472 ypos = top - k*factor;
8475 if (yint >= 0 && yint < ny-1) {
8476 vtop = sdata[j + nx*yint];
8477 vbot = sdata[j + nx*(yint+1)];
8478 value = vtop*(1-yfra) + vbot*yfra;
8481 xdata[j + nx*(npseudo-k)] = value;
8483 data[j + nx*yint] = (top-yint)/factor;
8492 if (yprev - yint > 1) {
8493 data[j + nx*(yint+1)] = (top-yint-1)/factor;
8501 cpl_polynomial_delete(polytop);
8502 cpl_polynomial_delete(polybot);
8510 for (i = 0; i < nslits; i++)
8512 ysize += cpl_image_get_size_y(exslit[i]);
8514 resampled = cpl_image_new(nx, ysize, CPL_TYPE_FLOAT);
8517 for (i = 0; i < nslits; i++) {
8519 yint += cpl_image_get_size_y(exslit[i]);
8520 cpl_image_copy(resampled, exslit[i], 1, ysize - yint);
8521 if (create_position) {
8522 cpl_table_set_int(slits,
"position", i, ysize - yint - 1);
8523 cpl_table_set_int(slits,
"length", i,
8524 cpl_image_get_size_y(exslit[i]));
8526 cpl_image_delete(exslit[i]);
8528 else if (create_position) {
8529 cpl_table_set_int(slits,
"position", i, -1);
8530 cpl_table_set_int(slits,
"length", i, 0);
8671 double dispersion,
float level,
8672 int sradius,
int order,
8673 double reject,
double refwave,
8674 double *wavestart,
double *waveend,
8675 int *nlines,
double *error,
8676 cpl_table *idscoeff,
8677 cpl_image *calibration,
8678 cpl_image *residuals,
8679 cpl_table *restable,
8680 cpl_table *detected_lines)
8683 const char *func =
"mos_wavelength_calibration_final";
8685 const char *clab[6] = {
"c0",
"c1",
"c2",
"c3",
"c4",
"c5"};
8688 double tolerance = 20.0;
8691 char name[MAX_COLNAME];
8693 cpl_image *resampled;
8694 cpl_bivector *peaks_ident;
8697 cpl_polynomial *ids;
8698 cpl_polynomial *lin;
8699 cpl_polynomial *fguess;
8702 double max_disp, min_disp;
8704 double firstLambda, lastLambda, lambda;
8705 double wave, pixe, value;
8714 int pixstart, pixend;
8715 int row_top, row_bot;
8720 int nl, nx, ny, pixel;
8721 int countLines, usedLines;
8730 if (dispersion == 0.0) {
8731 cpl_msg_error(func,
"The expected dispersion (A/pixel) must be given");
8732 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
8736 if (dispersion < 0.0) {
8737 cpl_msg_error(func,
"The expected dispersion must be positive");
8738 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
8742 if (idscoeff == NULL) {
8743 cpl_msg_error(func,
"A preallocated IDS coeff table must be given");
8744 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
8748 max_disp = dispersion + dispersion * tolerance / 100;
8749 min_disp = dispersion - dispersion * tolerance / 100;
8752 cpl_msg_error(func,
"The order of the fitting polynomial "
8753 "must be at least 1");
8754 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
8758 if (image == NULL || lines == NULL) {
8759 cpl_msg_error(func,
"Both spectral exposure and reference line "
8760 "catalog are required in input");
8761 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
8765 nx = cpl_image_get_size_x(image);
8766 ny = cpl_image_get_size_y(image);
8767 sdata = cpl_image_get_data_float(image);
8769 nref = cpl_vector_get_size(lines);
8770 line = cpl_vector_get_data(lines);
8772 if (*wavestart < 1.0 && *waveend < 1.0) {
8773 firstLambda = line[0];
8774 lastLambda = line[nref-1];
8775 extrapolation = (lastLambda - firstLambda) / 10;
8776 firstLambda -= extrapolation;
8777 lastLambda += extrapolation;
8778 *wavestart = firstLambda;
8779 *waveend = lastLambda;
8782 firstLambda = *wavestart;
8783 lastLambda = *waveend;
8786 nl = (lastLambda - firstLambda) / dispersion;
8787 resampled = cpl_image_new(nl, ny, CPL_TYPE_FLOAT);
8788 rdata = cpl_image_get_data_float(resampled);
8794 for (j = 0; j <= order; j++)
8795 cpl_table_new_column(idscoeff, clab[j], CPL_TYPE_DOUBLE);
8798 idata = cpl_image_get_data_float(calibration);
8801 ddata = cpl_image_get_data_float(residuals);
8804 cpl_table_set_size(restable, nref);
8805 cpl_table_new_column(restable,
"wavelength", CPL_TYPE_DOUBLE);
8806 cpl_table_copy_data_double(restable,
"wavelength", line);
8807 for (i = 0; i < ny; i += step) {
8808 snprintf(name, MAX_COLNAME,
"r%d", i);
8809 cpl_table_new_column(restable, name, CPL_TYPE_DOUBLE);
8810 snprintf(name, MAX_COLNAME,
"d%d", i);
8811 cpl_table_new_column(restable, name, CPL_TYPE_DOUBLE);
8812 snprintf(name, MAX_COLNAME,
"p%d", i);
8813 cpl_table_new_column(restable, name, CPL_TYPE_DOUBLE);
8817 if (detected_lines) {
8818 cpl_table_set_size(detected_lines, 0);
8819 cpl_table_new_column(detected_lines,
"slit_id", CPL_TYPE_INT);
8820 cpl_table_new_column(detected_lines,
"xpos_rectified", CPL_TYPE_DOUBLE);
8821 cpl_table_new_column(detected_lines,
"ypos_rectified", CPL_TYPE_DOUBLE);
8822 cpl_table_new_column(detected_lines,
"xpos_rectified_iter", CPL_TYPE_DOUBLE);
8823 cpl_table_new_column(detected_lines,
"ypos_rectified_iter", CPL_TYPE_DOUBLE);
8824 cpl_table_new_column(detected_lines,
"peak_flux", CPL_TYPE_DOUBLE);
8825 cpl_table_new_column(detected_lines,
"wave_ident", CPL_TYPE_DOUBLE);
8826 cpl_table_new_column(detected_lines,
"wave_ident_iter", CPL_TYPE_DOUBLE);
8827 cpl_table_new_column(detected_lines,
"xpos_fit_rect_wavecal", CPL_TYPE_DOUBLE);
8828 cpl_table_new_column(detected_lines,
"res_xpos", CPL_TYPE_DOUBLE);
8836 nslits = cpl_table_get_nrow(slits);
8837 length = cpl_table_get_data_int(slits,
"length");
8840 for (s = 0; s < nslits; s++) {
8843 slit_id = cpl_table_get_int(slits,
"slit_id", s, NULL);
8853 row_bot = cpl_table_get_int(slits,
"position", s, NULL);
8865 coeff = cpl_table_new(row_top - row_bot);
8866 for (j = 0; j <= order; j++)
8867 cpl_table_new_column(coeff, clab[j], CPL_TYPE_DOUBLE);
8875 for (i = row_bot; i < row_top; i++) {
8884 int keep_multiplex = mos_multiplex;
8888 cpl_size newlines = cpl_vector_get_size(peaks);
8889 cpl_size oldsize = cpl_table_get_nrow(detected_lines);
8890 cpl_table_set_size(detected_lines, oldsize + newlines);
8891 for(cpl_size iline = 0; iline < newlines; ++iline)
8893 cpl_table_set_int(detected_lines,
"slit_id",
8894 oldsize + iline, slit_id);
8895 cpl_table_set_double(detected_lines,
"xpos_rectified",
8896 oldsize + iline, cpl_vector_get(peaks, iline) + 1);
8897 cpl_table_set_double(detected_lines,
"ypos_rectified",
8898 oldsize + iline, (
double)i + 1);
8899 cpl_table_set_double(detected_lines,
"peak_flux",
8901 sdata[i*nx+(
int)(cpl_vector_get(peaks, iline)+0.5)]);
8905 min_disp, max_disp, 0.05);
8906 mos_multiplex = keep_multiplex;
8908 countLines = cpl_bivector_get_size(peaks_ident);
8909 if (countLines < 4) {
8910 cpl_bivector_delete(peaks_ident);
8911 cpl_vector_delete(peaks);
8923 wavel = cpl_bivector_get_y(peaks_ident);
8924 cpl_vector_subtract_scalar(wavel, refwave);
8926 uorder = countLines / 2 - 1;
8931 2 * (uorder + 1), &usedLines,
8935 cpl_bivector_delete(peaks_ident);
8936 cpl_vector_delete(peaks);
8946 for (k = 0; k <= order; k++) {
8948 cpl_table_set_double(coeff, clab[k],
8952 cpl_table_set_double(coeff, clab[k],
8953 i - row_bot, cpl_polynomial_get_coeff(ids, &k));
8959 pixstart = cpl_polynomial_eval_1d(ids,
8960 cpl_bivector_get_y_data(peaks_ident)[0],
8962 pixend = cpl_polynomial_eval_1d(ids,
8963 cpl_bivector_get_y_data(peaks_ident)[countLines-1],
8965 extrapolation = (pixend - pixstart) / 5;
8966 pixstart -= extrapolation;
8967 pixend += extrapolation;
8973 for (j = pixstart; j < pixend; j++) {
8975 firstLambda, lastLambda, refwave, j);
8983 if (residuals || (restable && !(i%step))) {
8984 if (restable && !(i%step)) {
8985 lin = cpl_polynomial_new(1);
8986 for (k = 0; k < 2; k++)
8987 cpl_polynomial_set_coeff(lin, &k,
8988 cpl_polynomial_get_coeff(ids, &k));
8990 for (j = 0; j < countLines; j++) {
8991 pixe = cpl_bivector_get_x_data(peaks_ident)[j];
8992 wave = cpl_bivector_get_y_data(peaks_ident)[j];
8994 - cpl_polynomial_eval_1d(ids, wave, NULL);
8997 (ddata + i*nx)[pixel] = value;
8999 if (restable && !(i%step)) {
9000 for (k = 0; k < nref; k++) {
9001 if (fabs(line[k]-refwave-wave) < 0.1) {
9002 snprintf(name, MAX_COLNAME,
9004 cpl_table_set_double(restable, name,
9007 - cpl_polynomial_eval_1d(lin,
9009 snprintf(name, MAX_COLNAME,
9011 cpl_table_set_double(restable, name,
9013 snprintf(name, MAX_COLNAME,
9015 cpl_table_set_double(restable, name,
9022 if (restable && !(i%step)) {
9023 cpl_polynomial_delete(lin);
9040 cpl_size nidentlines = cpl_bivector_get_size(peaks_ident);
9041 cpl_size ndetectlines = cpl_vector_get_size(peaks);
9042 cpl_size totalsize = cpl_table_get_nrow(detected_lines);
9043 for(cpl_size idline = 0; idline < nidentlines; ++idline)
9045 for(cpl_size detline = 0; detline < ndetectlines; ++detline)
9047 if(cpl_vector_get(peaks, detline) ==
9048 cpl_bivector_get_x_data(peaks_ident)[idline])
9050 cpl_size table_pos = totalsize - ndetectlines + detline;
9051 double wave_ident = cpl_bivector_get_y_data(peaks_ident)[idline] + refwave;
9052 double xpix_fit = cpl_polynomial_eval_1d(ids,
9053 wave_ident - refwave, NULL);
9054 double xpos_det = cpl_table_get_double(detected_lines,
9057 cpl_table_set_double(detected_lines,
9061 cpl_table_set_double(detected_lines,
9062 "xpos_fit_rect_wavecal",
9065 cpl_table_set_double(detected_lines,
9068 xpos_det - xpix_fit - 1);
9084 nlines[i] = usedLines;
9086 error[i] = ids_err / sqrt(usedLines/(uorder + 1));
9088 for (k = 0; k <= order; k++) {
9090 cpl_table_set_double(idscoeff, clab[k], i, 0.0);
9093 cpl_table_set_double(idscoeff, clab[k], i,
9094 cpl_polynomial_get_coeff(ids, &k));
9098 cpl_polynomial_delete(ids);
9099 cpl_bivector_delete(peaks_ident);
9101 cpl_vector_delete(peaks);
9112 nfits = row_top - row_bot - cpl_table_count_invalid(coeff, clab[0]);
9117 fguess = cpl_polynomial_new(1);
9127 for (k = 0; k <= order; k++) {
9128 c = cpl_table_get_column_median(coeff, clab[k]);
9129 cpl_polynomial_set_coeff(fguess, &k, c);
9136 for (i = row_bot; i < row_top; i++) {
9143 if (width > sradius) {
9151 for (k = 0; k <= order; k++) {
9152 c = cpl_table_get_double(coeff, clab[k],
9154 cpl_polynomial_set_coeff(fguess, &k, c);
9159 fguess, refwave, uradius);
9161 if (peaks_ident == NULL) {
9166 countLines = cpl_bivector_get_size(peaks_ident);
9168 if (countLines < 4) {
9169 cpl_bivector_delete(peaks_ident);
9177 wavel = cpl_bivector_get_y(peaks_ident);
9178 cpl_vector_subtract_scalar(wavel, refwave);
9180 uorder = countLines / 2 - 1;
9185 2 * (uorder + 1), &usedLines,
9190 cpl_bivector_delete(peaks_ident);
9195 nlines[i] = usedLines;
9197 error[i] = ids_err / sqrt(usedLines/(uorder + 1));
9200 pixstart = cpl_polynomial_eval_1d(ids,
9201 cpl_bivector_get_y_data(peaks_ident)[0],
9203 pixend = cpl_polynomial_eval_1d(ids,
9204 cpl_bivector_get_y_data(peaks_ident)[countLines-1],
9206 extrapolation = (pixend - pixstart) / 5;
9207 pixstart -= extrapolation;
9208 pixend += extrapolation;
9214 for (j = pixstart; j < pixend; j++) {
9216 firstLambda, lastLambda, refwave, j);
9224 if (residuals || (restable && !(i%step))) {
9225 if (restable && !(i%step)) {
9226 lin = cpl_polynomial_new(1);
9227 for (k = 0; k < 2; k++)
9228 cpl_polynomial_set_coeff(lin, &k,
9229 cpl_polynomial_get_coeff(ids, &k));
9231 for (j = 0; j < countLines; j++) {
9232 pixe = cpl_bivector_get_x_data(peaks_ident)[j];
9233 wave = cpl_bivector_get_y_data(peaks_ident)[j];
9235 - cpl_polynomial_eval_1d(ids, wave, NULL);
9238 (ddata + i*nx)[pixel] = value;
9240 if (restable && !(i%step)) {
9241 for (k = 0; k < nref; k++) {
9242 if (fabs(line[k]-refwave-wave) < 0.1) {
9243 snprintf(name, MAX_COLNAME,
9245 cpl_table_set_double(restable, name,
9248 - cpl_polynomial_eval_1d(lin,
9250 snprintf(name, MAX_COLNAME,
9252 cpl_table_set_double(restable, name,
9254 snprintf(name, MAX_COLNAME,
9256 cpl_table_set_double(restable, name,
9263 if (restable && !(i%step)) {
9264 cpl_polynomial_delete(lin);
9281 cpl_size oldsize = cpl_table_get_nrow(detected_lines);
9282 cpl_size nidentlines = cpl_bivector_get_size(peaks_ident);
9283 cpl_table_set_size(detected_lines, oldsize + nidentlines);
9284 for(cpl_size idline = 0; idline < nidentlines ; ++idline)
9286 double wave_ident = cpl_bivector_get_y_data(peaks_ident)[idline] + refwave;
9287 double xpix_fit = cpl_polynomial_eval_1d(ids,
9288 wave_ident - refwave, NULL);
9289 cpl_table_set_int(detected_lines,
"slit_id",
9290 oldsize + idline, slit_id);
9291 cpl_table_set_double(detected_lines,
"xpos_rectified_iter",
9292 oldsize + idline, cpl_bivector_get_x_data(peaks_ident)[idline] + 1);
9293 cpl_table_set_double(detected_lines,
"ypos_rectified_iter",
9294 oldsize + idline, (
double)i + 1);
9295 cpl_table_set_double(detected_lines,
"peak_flux",
9297 sdata[i*nx+(
int)(cpl_bivector_get_x_data(peaks_ident)[idline]+0.5)]);
9298 cpl_table_set_double(detected_lines,
"wave_ident_iter",
9299 oldsize + idline, wave_ident);
9300 cpl_table_set_double(detected_lines,
"xpos_fit_rect_wavecal",
9301 oldsize + idline, xpix_fit + 1);
9306 for (k = 0; k <= order; k++) {
9308 cpl_table_set_double(idscoeff, clab[k], i, 0.0);
9311 cpl_table_set_double(idscoeff, clab[k], i,
9312 cpl_polynomial_get_coeff(ids, &k));
9316 cpl_bivector_delete(peaks_ident);
9317 cpl_polynomial_delete(ids);
9321 cpl_polynomial_delete(fguess);
9324 cpl_table_delete(coeff);
9340 for (i = 0; i < ny; i++) {
9343 ids = cpl_polynomial_new(1);
9344 for (k = 0; k <= order; k++) {
9345 c = cpl_table_get_double(idscoeff, clab[k], i, &null);
9347 cpl_polynomial_delete(ids);
9351 cpl_polynomial_set_coeff(ids, &k, c);
9356 pixstart = cpl_polynomial_eval_1d(ids, firstLambda - refwave, NULL);
9357 pixend = cpl_polynomial_eval_1d(ids, lastLambda - refwave, NULL);
9367 for (j = 0; j < nl; j++) {
9368 lambda = firstLambda + j * dispersion;
9369 fpixel = cpl_polynomial_eval_1d(ids, lambda - refwave, NULL);
9371 if (pixel >= 0 && pixel < nx-1) {
9372 v1 = (sdata + i*nx)[pixel];
9373 v2 = (sdata + i*nx)[pixel+1];
9374 vi = v1 + (v2-v1)*(fpixel-pixel);
9375 (rdata + i*nl)[j] = vi;
9379 cpl_polynomial_delete(ids);
9413 double firstLambda,
double lastLambda,
9414 double dispersion, cpl_table *idscoeff,
9418 const char *func =
"mos_wavelength_calibration";
9420 const char *clab[6] = {
"c0",
"c1",
"c2",
"c3",
"c4",
"c5"};
9423 cpl_image *resampled;
9424 cpl_polynomial *ids;
9425 double pixel_per_lambda;
9430 float v0, v1, v2, v3, vi;
9433 int pixstart, pixend;
9434 int nl, nx, ny, pixel;
9441 if (dispersion <= 0.0) {
9442 cpl_msg_error(func,
"The resampling step must be positive");
9443 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
9447 if (lastLambda - firstLambda < dispersion) {
9448 cpl_msg_error(func,
"Invalid spectral range: %.2f to %.2f",
9449 firstLambda, lastLambda);
9450 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
9454 if (idscoeff == NULL) {
9455 cpl_msg_error(func,
"An IDS coeff table must be given");
9456 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
9460 if (image == NULL) {
9461 cpl_msg_error(func,
"A scientific spectral image must be given");
9462 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
9466 nx = cpl_image_get_size_x(image);
9467 ny = cpl_image_get_size_y(image);
9468 sdata = cpl_image_get_data_float(image);
9470 nl = (lastLambda - firstLambda) / dispersion;
9471 resampled = cpl_image_new(nl, ny, CPL_TYPE_FLOAT);
9472 rdata = cpl_image_get_data_float(resampled);
9475 while (order < 6 && cpl_table_has_column(idscoeff, clab[order]))
9479 for (i = 0; i < ny; i++) {
9482 ids = cpl_polynomial_new(1);
9483 for (k = 0; k <= order; k++) {
9484 c = cpl_table_get_double(idscoeff, clab[k], i, &null);
9486 cpl_polynomial_delete(ids);
9490 cpl_polynomial_set_coeff(ids, &k, c);
9495 pixstart = cpl_polynomial_eval_1d(ids, firstLambda - refwave, NULL);
9496 pixend = cpl_polynomial_eval_1d(ids, lastLambda - refwave, NULL);
9506 for (j = 0; j < nl; j++) {
9507 lambda = firstLambda + j * dispersion;
9508 fpixel = cpl_polynomial_eval_1d(ids, lambda - refwave,
9527 if (pixel >= 1 && pixel < nx-2) {
9528 v0 = (sdata + i*nx)[pixel-1];
9529 v1 = (sdata + i*nx)[pixel];
9530 v2 = (sdata + i*nx)[pixel+1];
9531 v3 = (sdata + i*nx)[pixel+2];
9532 vi = (fpixel-pixel)*(fpixel-pixel)*(v3 - v2 - v1 + v0)
9533 + (fpixel-pixel)*(3*v2 - v3 - v1 - v0)
9553 vi *= dispersion * pixel_per_lambda;
9554 (rdata + i*nl)[j] = vi;
9556 else if (pixel >= 0 && pixel < nx-1) {
9557 v1 = (sdata + i*nx)[pixel];
9558 v2 = (sdata + i*nx)[pixel+1];
9559 vi = v1 + (v2-v1)*(fpixel-pixel);
9561 vi *= dispersion * pixel_per_lambda;
9562 (rdata + i*nl)[j] = vi;
9576 double spos = fpixel - dispersion * pixel_per_lambda / 2;
9577 double epos = fpixel + dispersion * pixel_per_lambda / 2;
9584 int epix = epos + 1;
9593 for (k = spix; k < epix; k++) {
9594 if (pixel >= 0 && pixel < nx) {
9595 vi += (sdata + i*nx)[k];
9606 vi *= dispersion * pixel_per_lambda / (epix - spix);
9614 vi *= dispersion * pixel_per_lambda;
9616 (rdata + i*nl)[j] = vi;
9620 cpl_polynomial_delete(ids);
9694 double refwave,
double firstLambda,
9695 double lastLambda, cpl_table *idscoeff,
9696 cpl_vector *skylines,
int highres,
int order,
9697 cpl_image *calibration,
int sradius)
9699 const char *func =
"mos_wavelength_align";
9701 const char *clab[6] = {
"c0",
"c1",
"c2",
"c3",
"c4",
"c5"};
9705 double expPos, offset;
9707 double lambda1, lambda2;
9713 int startPos, endPos;
9714 int window = 2*sradius + 1;
9720 int xlow, ylow, xhig, yhig;
9721 int idsorder, uorder;
9730 char offname[MAX_COLNAME];
9731 char name[MAX_COLNAME];
9733 cpl_polynomial *ids;
9734 cpl_polynomial *polycorr;
9743 if (idscoeff == NULL) {
9744 cpl_msg_error(func,
"An IDS coeff table must be given");
9745 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
9749 if (image == NULL) {
9750 cpl_msg_error(func,
"A scientific spectral image must be given");
9751 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
9755 if (slits == NULL) {
9756 cpl_msg_error(func,
"A slit position table must be given");
9757 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
9762 line = cpl_vector_get_data(skylines);
9763 nlines = cpl_vector_get_size(skylines);
9766 cpl_msg_warning(func,
"A catalog of sky lines wavelengths was not "
9767 "given: using internal list of reference sky lines");
9769 line = default_lines_hi;
9770 nlines =
sizeof(default_lines_hi) /
sizeof(
double);
9773 line = default_lines_lo;
9774 nlines =
sizeof(default_lines_lo) /
sizeof(
double);
9779 cdata = cpl_image_get_data(calibration);
9781 nx = cpl_image_get_size_x(image);
9782 ny = cpl_image_get_size_y(image);
9784 nslits = cpl_table_get_nrow(slits);
9785 slit_id = cpl_table_get_data_int(slits,
"slit_id");
9786 position = cpl_table_get_data_int(slits,
"position");
9787 length = cpl_table_get_data_int(slits,
"length");
9795 for (i = 0; i < nlines; i++)
9796 if (line[i] > firstLambda && line[i] < lastLambda)
9799 offsets = cpl_table_new(nrows);
9800 cpl_table_new_column(offsets,
"wave", CPL_TYPE_DOUBLE);
9801 cpl_table_set_column_unit(offsets,
"wave",
"Angstrom");
9804 for (i = 0; i < nlines; i++) {
9805 if (line[i] > firstLambda && line[i] < lastLambda) {
9806 cpl_table_set_double(offsets,
"wave", nrows, line[i]);
9815 line = cpl_table_get_data_double(offsets,
"wave");
9819 while (idsorder < 6 && cpl_table_has_column(idscoeff, clab[idsorder]))
9825 for (i = 0; i < nslits; i++) {
9830 snprintf(offname, MAX_COLNAME,
"offset%d", slit_id[i]);
9831 cpl_table_new_column(offsets, offname, CPL_TYPE_DOUBLE);
9843 ylow = position[i] + 1;
9844 yhig = ylow + length[i] - 1;
9846 exslit = cpl_image_extract(image, xlow, ylow, xhig, yhig);
9847 sky = cpl_image_collapse_median_create(exslit, 0, 0, 1);
9848 sdata = cpl_image_get_data(sky);
9850 cpl_image_delete(exslit);
9865 dummy = cpl_table_new(yhig - ylow);
9866 for (j = 0; j < nlines; j++) {
9867 snprintf(name, MAX_COLNAME,
"%"CPL_SIZE_FORMAT, j);
9868 cpl_table_new_column(dummy, name, CPL_TYPE_DOUBLE);
9871 for (j = ylow; j < yhig; j++) {
9878 ids = cpl_polynomial_new(1);
9879 for (k = 0; k <= idsorder; k++) {
9880 c = cpl_table_get_double(idscoeff, clab[k], j, &null);
9882 cpl_polynomial_delete(ids);
9886 cpl_polynomial_set_coeff(ids, &k, c);
9891 for (k = 0; k < nlines; k++) {
9892 expPos = cpl_polynomial_eval_1d(ids, line[k] - refwave, NULL);
9893 startPos = expPos - sradius;
9894 endPos = startPos + window;
9895 if (startPos < 0 || endPos >= nx)
9898 if (0 == peakPosition(sdata + startPos, window, &pos, 1)) {
9900 offset = pos - expPos;
9901 snprintf(name, MAX_COLNAME,
"%"CPL_SIZE_FORMAT, k);
9902 cpl_table_set_double(dummy, name, j - ylow, offset);
9906 cpl_polynomial_delete(ids);
9909 cpl_image_delete(sky);
9911 for (j = 0; j < nlines; j++) {
9912 snprintf(name, MAX_COLNAME,
"%"CPL_SIZE_FORMAT, j);
9913 if (cpl_table_has_valid(dummy, name)) {
9914 offset = cpl_table_get_column_median(dummy, name);
9915 cpl_table_set_double(offsets, offname, j, offset);
9919 cpl_table_delete(dummy);
9930 for (i = 0; i < nslits; i++) {
9935 snprintf(offname, MAX_COLNAME,
"offset%d", slit_id[i]);
9942 dummy = cpl_table_new(nlines);
9943 cpl_table_duplicate_column(dummy,
"wave", offsets,
"wave");
9944 cpl_table_duplicate_column(dummy,
"offset", offsets, offname);
9946 npoints = nlines - cpl_table_count_invalid(dummy,
"offset");
9948 cpl_msg_warning(func,
"No sky lines alignment was possible "
9949 "for slit ID=%d: no sky line found", slit_id[i]);
9950 cpl_table_delete(dummy);
9955 if (npoints <= uorder) {
9956 uorder = npoints - 1;
9958 cpl_msg_warning(func,
"Just %d sky lines detected for slit "
9959 "ID=%d, while a polynomial order %d was "
9960 "requested. Using polynomial order %d for "
9961 "this slit!", npoints, slit_id[i], order,
9965 cpl_msg_warning(func,
"Just %d sky lines detected for slit "
9966 "ID=%d, while a polynomial order %d was "
9967 "requested. Computing a median offset for "
9968 "this slit!", npoints, slit_id[i], order);
9972 cpl_table_erase_invalid(dummy);
9980 wave = cpl_vector_wrap(npoints,
9981 cpl_table_get_data_double(dummy,
"wave"));
9982 offs = cpl_vector_wrap(npoints,
9983 cpl_table_get_data_double(dummy,
"offset"));
9989 cpl_vector_subtract_scalar(wave, refwave);
9991 polycorr = cpl_polynomial_fit_1d_create(wave, offs, uorder, &rms);
9993 rms = sqrt(rms * (uorder + 1) / npoints);
9995 cpl_vector_unwrap(wave);
9996 cpl_vector_unwrap(offs);
9997 cpl_table_delete(dummy);
10004 ylow = position[i];
10005 yhig = ylow + length[i];
10007 for (j = 0; j <= uorder; j++) {
10008 data = cpl_table_get_data_double(idscoeff, clab[j]);
10009 c = cpl_polynomial_get_coeff(polycorr, &j);
10010 for (k = ylow; k < yhig; k++)
10014 data = cpl_table_get_data_double(idscoeff,
"error");
10015 for (k = ylow; k < yhig; k++)
10016 data[k] = sqrt(data[k]*data[k] + rms*rms);
10018 idata = cpl_table_get_data_int(idscoeff,
"nlines");
10019 for (k = ylow; k < yhig; k++)
10020 idata[k] = npoints;
10028 for (j = ylow; j < yhig; j++) {
10029 for (k = 1; k < nx; k++) {
10030 lambda1 = cdata[k - 1 + j*nx];
10031 lambda2 = cdata[k + j*nx];
10032 if (lambda1 < 1.0 || lambda2 < 1.0)
10034 offset = cpl_polynomial_eval_1d(polycorr,
10035 lambda1-refwave, NULL);
10036 cdata[k - 1 + j*nx] -= offset * (lambda2-lambda1);
10041 cpl_polynomial_delete(polycorr);
10043 else if (uorder == 1) {
10050 cpl_bivector *list;
10053 wave = cpl_vector_wrap(npoints,
10054 cpl_table_get_data_double(dummy,
"wave"));
10055 offs = cpl_vector_wrap(npoints,
10056 cpl_table_get_data_double(dummy,
"offset"));
10058 list = cpl_bivector_wrap_vectors(wave, offs);
10064 cpl_vector_subtract_scalar(wave, refwave);
10066 robustLinearFit(list, &q, &m, &rms);
10068 rms = sqrt(rms * (uorder + 1) / npoints);
10070 cpl_bivector_unwrap_vectors(list);
10071 cpl_vector_unwrap(wave);
10072 cpl_vector_unwrap(offs);
10073 cpl_table_delete(dummy);
10080 ylow = position[i];
10081 yhig = ylow + length[i];
10083 for (j = 0; j <= uorder; j++) {
10084 data = cpl_table_get_data_double(idscoeff, clab[j]);
10089 for (k = ylow; k < yhig; k++)
10093 data = cpl_table_get_data_double(idscoeff,
"error");
10094 for (k = ylow; k < yhig; k++)
10095 data[k] = sqrt(data[k]*data[k] + rms*rms);
10097 idata = cpl_table_get_data_int(idscoeff,
"nlines");
10098 for (k = ylow; k < yhig; k++)
10099 idata[k] = npoints;
10107 for (j = ylow; j < yhig; j++) {
10108 for (k = 1; k < nx; k++) {
10109 lambda1 = cdata[k - 1 + j*nx];
10110 lambda2 = cdata[k + j*nx];
10111 if (lambda1 < 1.0 || lambda2 < 1.0)
10113 offset = q + m*(lambda1-refwave);
10114 cdata[k - 1 + j*nx] -= offset * (lambda2-lambda1);
10125 offs = cpl_vector_wrap(npoints,
10126 cpl_table_get_data_double(dummy,
"offset"));
10128 offset = cpl_vector_get_median_const(offs);
10131 rms = cpl_table_get_column_stdev(dummy,
"offset");
10135 rms /= sqrt(npoints);
10137 cpl_vector_unwrap(offs);
10138 cpl_table_delete(dummy);
10145 ylow = position[i];
10146 yhig = ylow + length[i];
10148 data = cpl_table_get_data_double(idscoeff, clab[0]);
10149 for (k = ylow; k < yhig; k++)
10152 data = cpl_table_get_data_double(idscoeff,
"error");
10153 for (k = ylow; k < yhig; k++)
10154 data[k] = sqrt(data[k]*data[k] + rms*rms);
10156 idata = cpl_table_get_data_int(idscoeff,
"nlines");
10157 for (k = ylow; k < yhig; k++)
10158 idata[k] = npoints;
10167 for (j = ylow; j < yhig; j++) {
10168 for (k = 1; k < nx; k++) {
10169 lambda1 = cdata[k - 1 + j*nx];
10170 lambda2 = cdata[k + j*nx];
10171 if (lambda1 < 1.0 || lambda2 < 1.0)
10173 cdata[k - 1 + j*nx] -= offset * (lambda2-lambda1);
10247 double firstLambda,
double lastLambda,
10248 cpl_table *idscoeff, cpl_vector *skylines,
10249 int highres,
int order,
10250 cpl_image *calibration,
int sradius)
10252 const char *func =
"mos_wavelength_align_lss";
10254 const char *clab[6] = {
"c0",
"c1",
"c2",
"c3",
"c4",
"c5"};
10260 double expPos, offset;
10262 double lambda1, lambda2;
10268 int startPos, endPos;
10269 int window = 2*sradius + 1;
10274 int idsorder, uorder;
10279 char name[MAX_COLNAME];
10280 char fname[MAX_COLNAME];
10282 cpl_polynomial *ids;
10283 cpl_polynomial *polycorr;
10284 cpl_table *offsets;
10285 cpl_table *fittable;
10292 if (idscoeff == NULL) {
10293 cpl_msg_error(func,
"An IDS coeff table must be given");
10294 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
10298 if (image == NULL) {
10299 cpl_msg_error(func,
"A scientific spectral image must be given");
10300 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
10305 line = cpl_vector_get_data(skylines);
10306 nlines = cpl_vector_get_size(skylines);
10309 cpl_msg_warning(func,
"A catalog of sky lines wavelengths was not "
10310 "given: using internal list of reference sky lines");
10312 line = default_lines_hi;
10313 nlines =
sizeof(default_lines_hi) /
sizeof(
double);
10316 line = default_lines_lo;
10317 nlines =
sizeof(default_lines_lo) /
sizeof(
double);
10322 cdata = cpl_image_get_data(calibration);
10324 nx = cpl_image_get_size_x(image);
10325 ny = cpl_image_get_size_y(image);
10327 sdata = cpl_image_get_data(image);
10329 if (ny != cpl_table_get_nrow(idscoeff)) {
10330 cpl_error_set(func, CPL_ERROR_INCOMPATIBLE_INPUT);
10344 for (i = 0; i < nlines; i++)
10345 if (line[i] > firstLambda && line[i] < lastLambda)
10348 offsets = cpl_table_new(nrows);
10349 cpl_table_new_column(offsets,
"wave", CPL_TYPE_DOUBLE);
10350 cpl_table_set_column_unit(offsets,
"wave",
"Angstrom");
10353 for (i = 0; i < nlines; i++) {
10354 if (line[i] > firstLambda && line[i] < lastLambda) {
10355 cpl_table_set_double(offsets,
"wave", nrows, line[i]);
10364 line = cpl_table_get_data_double(offsets,
"wave");
10368 while (idsorder < 6 && cpl_table_has_column(idscoeff, clab[idsorder]))
10378 dummy = cpl_table_new(ny);
10379 for (j = 0; j < nlines; j++) {
10380 snprintf(name, MAX_COLNAME,
"off_%d", (
int)line[j]);
10381 snprintf(fname, MAX_COLNAME,
"fit_%d", (
int)line[j]);
10382 cpl_table_new_column(dummy, name, CPL_TYPE_DOUBLE);
10383 cpl_table_new_column(dummy, fname, CPL_TYPE_DOUBLE);
10386 for (j = 0; j < ny; j++, sdata += nx) {
10393 ids = cpl_polynomial_new(1);
10394 for (k = 0; k <= idsorder; k++) {
10395 c = cpl_table_get_double(idscoeff, clab[k], j, &missing);
10397 cpl_polynomial_delete(ids);
10400 cpl_polynomial_set_coeff(ids, &k, c);
10405 for (k = 0; k < nlines; k++) {
10406 expPos = cpl_polynomial_eval_1d(ids, line[k] - refwave, NULL);
10407 startPos = expPos - sradius;
10408 endPos = startPos + window;
10409 if (startPos < 0 || endPos >= nx)
10412 if (0 == peakPosition(sdata + startPos, window, &pos, 1)) {
10414 offset = pos - expPos;
10415 snprintf(name, MAX_COLNAME,
"off_%d", (
int)line[k]);
10416 cpl_table_set_double(dummy, name, j, offset);
10420 cpl_polynomial_delete(ids);
10429 for (j = 0; j < nlines; j++) {
10430 snprintf(name, MAX_COLNAME,
"off_%d", (
int)line[j]);
10431 snprintf(fname, MAX_COLNAME,
"fit_%d", (
int)line[j]);
10432 if (cpl_table_has_valid(dummy, name)) {
10440 cpl_bivector *list;
10442 fittable = cpl_table_new(ny);
10443 cpl_table_new_column(fittable,
"row", CPL_TYPE_DOUBLE);
10444 cpl_table_set_column_unit(fittable,
"row",
"pixel");
10445 for (k = 0; k < ny; k++)
10446 cpl_table_set_double(fittable,
"row", k, k);
10447 cpl_table_duplicate_column(fittable,
"offset", dummy, name);
10448 npoints = ny - cpl_table_count_invalid(fittable,
"offset");
10449 cpl_table_erase_invalid(fittable);
10450 row = cpl_vector_wrap(npoints,
10451 cpl_table_get_data_double(fittable,
"row"));
10452 offs = cpl_vector_wrap(npoints,
10453 cpl_table_get_data_double(fittable,
"offset"));
10454 list = cpl_bivector_wrap_vectors(row, offs);
10455 robustLinearFit(list, &q, &m, &rms);
10456 cpl_bivector_unwrap_vectors(list);
10457 cpl_vector_unwrap(row);
10458 cpl_vector_unwrap(offs);
10459 cpl_table_delete(fittable);
10460 for (k = 0; k < ny; k++)
10461 cpl_table_set_double(dummy, fname, k, q + m*k);
10474 for (i = 0; i < ny; i++) {
10476 if (!cpl_table_is_valid(idscoeff, clab[0], i))
10480 for (j = 0; j < nlines; j++) {
10481 snprintf(name, MAX_COLNAME,
"fit_%d", (
int)line[j]);
10482 if (cpl_table_is_valid(dummy, name, i))
10490 if (npoints <= uorder)
10491 uorder = npoints - 1;
10499 wave = cpl_vector_new(npoints);
10500 wdata = cpl_vector_get_data(wave);
10501 offs = cpl_vector_new(npoints);
10502 odata = cpl_vector_get_data(offs);
10505 for (j = 0; j < nlines; j++) {
10506 snprintf(name, MAX_COLNAME,
"fit_%d", (
int)line[j]);
10507 if (cpl_table_is_valid(dummy, name, i)) {
10508 wdata[npoints] = line[j] - refwave;
10509 odata[npoints] = cpl_table_get_double(dummy, name, i, NULL);
10514 polycorr = cpl_polynomial_fit_1d_create(wave, offs, uorder, &rms);
10516 rms = sqrt(rms * (uorder + 1) / npoints);
10518 cpl_vector_delete(wave);
10519 cpl_vector_delete(offs);
10526 for (j = 0; j <= uorder; j++) {
10527 data = cpl_table_get_data_double(idscoeff, clab[j]);
10528 c = cpl_polynomial_get_coeff(polycorr, &j);
10532 data = cpl_table_get_data_double(idscoeff,
"error");
10533 data[i] = sqrt(data[i]*data[i] + rms*rms);
10535 idata = cpl_table_get_data_int(idscoeff,
"nlines");
10536 idata[i] = npoints;
10544 for (k = 1; k < nx; k++) {
10545 lambda1 = cdata[k - 1 + i*nx];
10546 lambda2 = cdata[k + i*nx];
10547 if (lambda1 < 1.0 || lambda2 < 1.0)
10549 offset = cpl_polynomial_eval_1d(polycorr,
10550 lambda1-refwave, NULL);
10551 cdata[k - 1 + i*nx] -= offset * (lambda2-lambda1);
10555 cpl_polynomial_delete(polycorr);
10558 else if (uorder == 1) {
10564 cpl_bivector *list;
10567 wave = cpl_vector_new(npoints);
10568 wdata = cpl_vector_get_data(wave);
10569 offs = cpl_vector_new(npoints);
10570 odata = cpl_vector_get_data(offs);
10573 for (j = 0; j < nlines; j++) {
10574 snprintf(name, MAX_COLNAME,
"fit_%d", (
int)line[j]);
10575 if (cpl_table_is_valid(dummy, name, i)) {
10576 wdata[npoints] = line[j] - refwave;
10577 odata[npoints] = cpl_table_get_double(dummy, name, i, NULL);
10582 list = cpl_bivector_wrap_vectors(wave, offs);
10583 robustLinearFit(list, &q, &m, &rms);
10585 rms = sqrt(rms * (uorder + 1) / npoints);
10587 cpl_bivector_unwrap_vectors(list);
10588 cpl_vector_delete(wave);
10589 cpl_vector_delete(offs);
10596 for (j = 0; j <= uorder; j++) {
10597 data = cpl_table_get_data_double(idscoeff, clab[j]);
10605 data = cpl_table_get_data_double(idscoeff,
"error");
10606 data[i] = sqrt(data[i]*data[i] + rms*rms);
10608 idata = cpl_table_get_data_int(idscoeff,
"nlines");
10609 idata[i] = npoints;
10617 for (k = 1; k < nx; k++) {
10618 lambda1 = cdata[k - 1 + i*nx];
10619 lambda2 = cdata[k + i*nx];
10620 if (lambda1 < 1.0 || lambda2 < 1.0)
10622 offset = q + m*(lambda1-refwave);
10623 cdata[k - 1 + i*nx] -= offset * (lambda2-lambda1);
10633 offs = cpl_vector_new(npoints);
10634 odata = cpl_vector_get_data(offs);
10637 for (j = 0; j < nlines; j++) {
10638 snprintf(name, MAX_COLNAME,
"fit_%d", (
int)line[j]);
10639 if (cpl_table_is_valid(dummy, name, i)) {
10640 odata[npoints] = cpl_table_get_double(dummy, name, i, NULL);
10645 offset = cpl_vector_get_median_const(offs);
10648 rms = cpl_vector_get_stdev(offs);
10650 else if (npoints == 1) {
10651 snprintf(name, MAX_COLNAME,
"off_%d", (
int)line[0]);
10652 if (cpl_table_has_valid(dummy, name)) {
10653 rms = cpl_table_get_column_stdev(dummy, name);
10654 rms /= sqrt(ny - cpl_table_count_invalid(dummy, name));
10664 rms /= sqrt(npoints);
10666 cpl_vector_delete(offs);
10673 data = cpl_table_get_data_double(idscoeff, clab[0]);
10676 data = cpl_table_get_data_double(idscoeff,
"error");
10677 data[i] = sqrt(data[i]*data[i] + rms*rms);
10679 idata = cpl_table_get_data_int(idscoeff,
"nlines");
10680 idata[i] = npoints;
10689 for (k = 1; k < nx; k++) {
10690 lambda1 = cdata[k - 1 + i*nx];
10691 lambda2 = cdata[k + i*nx];
10692 if (lambda1 < 1.0 || lambda2 < 1.0)
10694 cdata[k - 1 + i*nx] -= offset * (lambda2-lambda1);
10701 for (j = 0; j < nlines; j++) {
10702 snprintf(name, MAX_COLNAME,
"off_%d", (
int)line[j]);
10703 if (cpl_table_has_valid(dummy, name)) {
10705 offset = cpl_table_get_column_median(dummy, name);
10706 cpl_msg_info(func,
"Median offset for %.3f: %.3f pixel",
10711 "Median offset for %.2f: not available", line[j]);
10715 cpl_table_delete(offsets);
10718 cpl_table_delete(dummy);
10755 double wavestart,
double dispersion,
int radius,
10759 const char *func =
"mos_distortions_rms";
10764 int cpix, npix, nzero;
10767 int npeaks, allPeaks;
10770 float peak, expectPeak, offset;
10774 double rms, oneRms;
10780 xlen = cpl_image_get_size_x(rectified);
10781 ylen = cpl_image_get_size_y(rectified);
10782 sdata = cpl_image_get_data(rectified);
10785 wdata = cpl_vector_get_data(lines);
10786 numLines = cpl_vector_get_size(lines);
10789 cpl_msg_warning(func,
"A catalog of sky lines wavelengths was not "
10790 "given: using internal list of reference sky lines");
10792 wdata = default_lines_hi;
10793 numLines =
sizeof(default_lines_hi) /
sizeof(
double);
10796 wdata = default_lines_lo;
10797 numLines =
sizeof(default_lines_lo) /
sizeof(
double);
10801 npix = 2 * radius + 1;
10802 profile = cpl_calloc(npix,
sizeof(
float));
10807 for (i = 0; i < numLines; i++) {
10814 expectPeak = (lambda - wavestart) / dispersion;
10815 cpix = floor(expectPeak + 0.5);
10821 sp = cpix - radius;
10822 ep = cpix + radius;
10824 if (sp < 0 || ep > xlen)
10831 for (j = 0; j < ylen; j++) {
10833 for (k = 0; k < npix; k++) {
10834 profile[k] = sdata[sp + k + j * xlen];
10835 if (fabs(profile[k]) < 0.0001)
10841 if (peakPosition(profile, npix, &peak, 1) == 0) {
10842 offset = (sp + peak) - expectPeak;
10844 rms += fabs(offset);
10845 oneRms += fabs(offset);
10852 cpl_msg_info(func,
"RMS for %.2f: %.3f pixel (%d points)",
10853 lambda, oneRms / npeaks * 1.25, npeaks);
10855 cpl_msg_info(func,
"RMS for %.2f: line not available", lambda);
10892 double blue,
double red,
double dispersion,
int trend)
10894 const char *func =
"mos_map_pixel";
10896 const char *clab[6] = {
"c0",
"c1",
"c2",
"c3",
"c4",
"c5"};
10899 cpl_polynomial *ids;
10911 if (idscoeff == NULL) {
10912 cpl_msg_error(func,
"An IDS coeff table must be given");
10913 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
10917 xsize = (red - blue) / dispersion;
10918 ysize = cpl_table_get_nrow(idscoeff);
10919 map = cpl_image_new(xsize, ysize, CPL_TYPE_FLOAT);
10920 mdata = cpl_image_get_data(map);
10923 while (order < 6 && cpl_table_has_column(idscoeff, clab[order]))
10927 for (i = 0; i < ysize; i++, mdata += xsize) {
10930 ids = cpl_polynomial_new(1);
10931 for (k = trend; k <= order; k++) {
10932 c = cpl_table_get_double(idscoeff, clab[k], i, &missing);
10934 cpl_polynomial_delete(ids);
10937 cpl_polynomial_set_coeff(ids, &k, c);
10942 for (j = 0; j < xsize; j++) {
10943 lambda = blue + j*dispersion;
10944 mdata[j] = cpl_polynomial_eval_1d(ids, lambda-reference, NULL);
10947 cpl_polynomial_delete(ids);
10977 double blue,
double red)
10979 const char *func =
"mos_map_idscoeff";
10981 const char *clab[6] = {
"c0",
"c1",
"c2",
"c3",
"c4",
"c5"};
10984 cpl_polynomial *ids;
10996 if (idscoeff == NULL) {
10997 cpl_msg_error(func,
"An IDS coeff table must be given");
10998 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
11003 cpl_msg_error(func,
"Invalid image size");
11004 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
11008 if (xsize < 20 || xsize > 5000) {
11009 cpl_msg_warning(func,
"Do you really have a detector %d pixels long?",
11013 ysize = cpl_table_get_nrow(idscoeff);
11014 map = cpl_image_new(xsize, ysize, CPL_TYPE_FLOAT);
11015 mdata = cpl_image_get_data(map);
11018 while (order < 6 && cpl_table_has_column(idscoeff, clab[order]))
11022 for (i = 0; i < ysize; i++, mdata += xsize) {
11025 ids = cpl_polynomial_new(1);
11026 for (k = 0; k <= order; k++) {
11027 c = cpl_table_get_double(idscoeff, clab[k], i, &missing);
11029 cpl_polynomial_delete(ids);
11032 cpl_polynomial_set_coeff(ids, &k, c);
11037 for (j = 0; j < xsize; j++) {
11040 if (lambda >= blue && lambda <= red) {
11045 cpl_polynomial_delete(ids);
11088 cpl_table *slits, cpl_table *polytraces,
11089 double reference,
double blue,
double red,
11092 const char *func =
"mos_map_wavelengths";
11094 const char *clab[6] = {
"c0",
"c1",
"c2",
"c3",
"c4",
"c5"};
11096 cpl_polynomial *polytop;
11097 cpl_polynomial *polybot;
11098 cpl_image *remapped;
11103 double vtop, vbot, value;
11110 int yint, ysize, yprev;
11117 int pixel_above, pixel_below, refpixel, start_pixel, end_pixel;
11118 int missing_top, missing_bot;
11125 if (spatial == NULL || calibration == NULL ||
11126 slits == NULL || polytraces == NULL) {
11127 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
11131 if (dispersion <= 0.0) {
11132 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
11136 if (red - blue < dispersion) {
11137 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
11141 nx = cpl_image_get_size_x(spatial);
11142 ny = cpl_image_get_size_y(spatial);
11143 ysize = cpl_image_get_size_y(calibration);
11144 remapped = cpl_image_new(nx, ny, CPL_TYPE_FLOAT);
11145 data = cpl_image_get_data(remapped);
11146 sdata = cpl_image_get_data(spatial);
11147 wdata = cpl_image_get_data(calibration);
11149 nslits = cpl_table_get_nrow(slits);
11150 slit_id = cpl_table_get_data_int(slits,
"slit_id");
11151 order = cpl_table_get_ncol(polytraces) - 2;
11152 position = cpl_table_get_data_int(slits,
"position");
11153 length = cpl_table_get_data_int(slits,
"length");
11160 pixel_above = STRETCH_FACTOR * (red - reference) / dispersion;
11161 pixel_below = STRETCH_FACTOR * (reference - blue) / dispersion;
11163 for (i = 0; i < nslits; i++) {
11165 if (length[i] == 0)
11179 refpixel = cpl_table_get_double(slits,
"xtop", i, NULL);
11181 start_pixel = refpixel - pixel_below;
11182 if (start_pixel < 0)
11185 end_pixel = refpixel + pixel_above;
11186 if (end_pixel > nx)
11195 polytop = cpl_polynomial_new(1);
11196 for (k = 0; k <= order; k++) {
11197 coeff = cpl_table_get_double(polytraces, clab[k], 2*i, &null);
11199 cpl_polynomial_delete(polytop);
11203 cpl_polynomial_set_coeff(polytop, &k, coeff);
11207 polybot = cpl_polynomial_new(1);
11208 for (k = 0; k <= order; k++) {
11209 coeff = cpl_table_get_double(polytraces, clab[k], 2*i+1, &null);
11211 cpl_polynomial_delete(polybot);
11215 cpl_polynomial_set_coeff(polybot, &k, coeff);
11218 if (missing_top && missing_bot) {
11219 cpl_msg_debug(func,
"Slit %d was not traced: no extraction!",
11231 cpl_msg_debug(func,
"Upper edge of slit %d was not traced: "
11232 "the spectral curvature of the lower edge "
11233 "is used instead.", slit_id[i]);
11234 polytop = cpl_polynomial_duplicate(polybot);
11235 ytop = cpl_table_get_double(slits,
"ytop", i, NULL);
11236 ybot = cpl_table_get_double(slits,
"ybottom", i, NULL);
11238 coeff = cpl_polynomial_get_coeff(polybot, &k);
11239 coeff += ytop - ybot;
11240 cpl_polynomial_set_coeff(polytop, &k, coeff);
11244 cpl_msg_debug(func,
"Lower edge of slit %d was not traced: "
11245 "the spectral curvature of the upper edge "
11246 "is used instead.", slit_id[i]);
11247 polybot = cpl_polynomial_duplicate(polytop);
11248 ytop = cpl_table_get_double(slits,
"ytop", i, NULL);
11249 ybot = cpl_table_get_double(slits,
"ybottom", i, NULL);
11251 coeff = cpl_polynomial_get_coeff(polytop, &k);
11252 coeff -= ytop - ybot;
11253 cpl_polynomial_set_coeff(polybot, &k, coeff);
11263 xdata = wdata + nx*position[i];
11264 npseudo = length[i] - 1;
11270 for (j = start_pixel; j < end_pixel; j++) {
11271 top = cpl_polynomial_eval_1d(polytop, j, NULL);
11272 bot = cpl_polynomial_eval_1d(polybot, j, NULL);
11273 for (k = 0; k <= npseudo; k++) {
11274 ypos = top - k*(top-bot)/npseudo;
11284 if (yint < 0 || yint >= ny-1) {
11289 value = sdata[j + nx*yint];
11291 fvalue = value - ivalue;
11292 if (ivalue < npseudo && ivalue >= 0) {
11293 vtop = xdata[j + nx*(npseudo-ivalue)];
11294 vbot = xdata[j + nx*(npseudo-ivalue-1)];
11303 else if (vbot < 1.0) {
11309 else if (fabs(vbot-vtop) > 10*dispersion) {
11313 value = vtop*(1-fvalue) + vbot*fvalue;
11315 data[j + nx*yint] = value;
11325 if (yprev - yint > 1) {
11326 value = sdata[j + nx*(yint+1)];
11328 fvalue = value - ivalue;
11329 if (ivalue < npseudo && ivalue >= 0) {
11330 vtop = xdata[j + nx*(npseudo-ivalue)];
11331 vbot = xdata[j + nx*(npseudo-ivalue-1)];
11334 value = data[j + nx*(yint+1)];
11340 else if (vbot < 1.0) {
11343 else if (fabs(vbot-vtop) > 2*dispersion) {
11347 value = vtop*(1-fvalue) + vbot*fvalue;
11349 data[j + nx*(yint+1)] = value;
11357 cpl_polynomial_delete(polytop);
11358 cpl_polynomial_delete(polybot);
11438 cpl_image *spatial, cpl_table *slits,
11439 cpl_table *polytraces,
double reference,
11440 double blue,
double red,
double dispersion,
11443 const char *func =
"mos_map_spectrum";
11445 const char *clab[6] = {
"c0",
"c1",
"c2",
"c3",
"c4",
"c5"};
11447 cpl_polynomial *polytop;
11448 cpl_polynomial *polybot;
11449 cpl_image *remapped;
11450 cpl_image **exslit;
11455 double lambda00, lambda01, lambda10, lambda11, lambda;
11456 double space00, space01, space10, space11, space;
11457 double value00, value01, value10, value11, value0, value1, value;
11462 double xfrac, yfrac;
11475 int pixel_above, pixel_below, refpixel, start_pixel, end_pixel;
11476 int missing_top, missing_bot;
11485 if (spectra == NULL || spatial == NULL || wavecalib == NULL ||
11486 slits == NULL || polytraces == NULL) {
11487 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
11491 if (dispersion <= 0.0) {
11492 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
11496 if (red - blue < dispersion) {
11497 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
11501 nx = cpl_image_get_size_x(spectra);
11502 ny = cpl_image_get_size_y(spectra);
11504 if (nx != cpl_image_get_size_x(spatial) ||
11505 ny != cpl_image_get_size_y(spatial) ||
11506 nx != cpl_image_get_size_x(wavecalib) ||
11507 ny != cpl_image_get_size_y(wavecalib)) {
11508 cpl_error_set(func, CPL_ERROR_INCOMPATIBLE_INPUT);
11512 nlambda = STRETCH_FACTOR * (red - blue) / dispersion;
11513 pixel_above = STRETCH_FACTOR * (red - reference) / dispersion;
11514 pixel_below = STRETCH_FACTOR * (reference - blue) / dispersion;
11516 data = cpl_image_get_data(spectra);
11517 sdata = cpl_image_get_data(spatial);
11518 wdata = cpl_image_get_data(wavecalib);
11520 nslits = cpl_table_get_nrow(slits);
11521 slit_id = cpl_table_get_data_int(slits,
"slit_id");
11522 order = cpl_table_get_ncol(polytraces) - 2;
11523 position = cpl_table_get_data_int(slits,
"position");
11524 length = cpl_table_get_data_int(slits,
"length");
11526 exslit = cpl_calloc(nslits,
sizeof(cpl_image *));
11528 for (i = 0; i < nslits; i++) {
11544 refpixel = cpl_table_get_double(slits,
"xtop", i, NULL);
11546 start_pixel = refpixel - pixel_below;
11547 if (start_pixel < 1)
11550 end_pixel = refpixel + pixel_above;
11551 if (end_pixel > nx)
11560 polytop = cpl_polynomial_new(1);
11561 for (k = 0; k <= order; k++) {
11562 coeff = cpl_table_get_double(polytraces, clab[k], 2*i, &null);
11564 cpl_polynomial_delete(polytop);
11568 cpl_polynomial_set_coeff(polytop, &k, coeff);
11572 polybot = cpl_polynomial_new(1);
11573 for (k = 0; k <= order; k++) {
11574 coeff = cpl_table_get_double(polytraces, clab[k], 2*i+1, &null);
11576 cpl_polynomial_delete(polybot);
11580 cpl_polynomial_set_coeff(polybot, &k, coeff);
11583 if (missing_top && missing_bot) {
11584 cpl_msg_debug(func,
"Slit %d was not traced: no extraction!",
11596 cpl_msg_debug(func,
"Upper edge of slit %d was not traced: "
11597 "the spectral curvature of the lower edge "
11598 "is used instead.", slit_id[i]);
11599 polytop = cpl_polynomial_duplicate(polybot);
11600 ytop = cpl_table_get_double(slits,
"ytop", i, NULL);
11601 ybot = cpl_table_get_double(slits,
"ybottom", i, NULL);
11603 coeff = cpl_polynomial_get_coeff(polybot, &k);
11604 coeff += ytop - ybot;
11605 cpl_polynomial_set_coeff(polytop, &k, coeff);
11609 cpl_msg_debug(func,
"Lower edge of slit %d was not traced: "
11610 "the spectral curvature of the upper edge "
11611 "is used instead.", slit_id[i]);
11612 polybot = cpl_polynomial_duplicate(polytop);
11613 ytop = cpl_table_get_double(slits,
"ytop", i, NULL);
11614 ybot = cpl_table_get_double(slits,
"ybottom", i, NULL);
11616 coeff = cpl_polynomial_get_coeff(polytop, &k);
11617 coeff -= ytop - ybot;
11618 cpl_polynomial_set_coeff(polybot, &k, coeff);
11625 top = cpl_polynomial_eval_1d(polytop, refpixel, NULL);
11626 bot = cpl_polynomial_eval_1d(polybot, refpixel, NULL);
11627 npseudo = ceil(top-bot) + 1;
11630 cpl_polynomial_delete(polytop);
11631 cpl_polynomial_delete(polybot);
11632 cpl_msg_debug(func,
"Slit %d was badly traced: no extraction!",
11637 exslit[i] = cpl_image_new(nlambda, npseudo+1, CPL_TYPE_FLOAT);
11638 xdata = cpl_image_get_data(exslit[i]);
11644 for (x = start_pixel; x < end_pixel; x++) {
11645 top = cpl_polynomial_eval_1d(polytop, x, NULL);
11646 bot = cpl_polynomial_eval_1d(polybot, x, NULL);
11657 for (y = ibot; y < itop; y++) {
11658 lambda11 = wdata[x + y*nx];
11659 if (lambda11 < 1.0)
11661 space11 = sdata[x + y*nx];
11664 lambda01 = wdata[x - 1 + y*nx];
11665 if (lambda01 < 1.0)
11667 space01 = sdata[x - 1 + y*nx];
11700 lambda10 = wdata[x + shift + (y+1)*nx];
11701 if (lambda10 < 1.0)
11703 space10 = sdata[x + shift + (y+1)*nx];
11706 lambda00 = wdata[x - 1 + shift + (y+1)*nx];
11707 if (lambda00 < 1.0)
11709 space00 = sdata[x - 1 + shift + (y+1)*nx];
11719 dL = lambda11 - lambda01;
11720 dS = space11 - space10;
11727 L = (lambda11 - blue)/dispersion + 0.5;
11730 if (L < 0 || L >= nlambda)
11732 if (S < 0 || S > npseudo)
11739 lambda = blue + L*dispersion;
11751 xfrac = (lambda11-lambda)/dL;
11752 yfrac = (space11-space)/dS;
11763 value11 = data[x + y*nx];
11764 value01 = data[x - 1 + y*nx];
11765 value10 = data[x + shift + (y+1)*nx];
11766 value00 = data[x + shift - 1 + (y+1)*nx];
11772 value1 = (1-xfrac)*value11 + xfrac*value01;
11773 value0 = (1-xfrac)*value10 + xfrac*value00;
11774 value = (1-yfrac)*value1 + yfrac*value0;
11781 xdata[L + nlambda*(npseudo-S)] = value;
11785 cpl_polynomial_delete(polytop);
11786 cpl_polynomial_delete(polybot);
11794 for (i = 0; i < nslits; i++)
11796 ysize += cpl_image_get_size_y(exslit[i]);
11798 remapped = cpl_image_new(nlambda, ysize, CPL_TYPE_FLOAT);
11801 for (i = 0; i < nslits; i++) {
11803 yint += cpl_image_get_size_y(exslit[i]);
11804 cpl_image_copy(remapped, exslit[i], 1, ysize - yint);
11805 cpl_image_delete(exslit[i]);
11806 cpl_table_set_int(slits,
"position", i, ysize - yint - 1);
11850 double dispersion,
double factor,
int minpoints,
11853 const char *func =
"mos_sky_map_super";
11855 cpl_vector **vector;
11856 cpl_vector **wvector;
11857 double firstLambda, lastLambda;
11858 double lambda, lambda1, lambda2;
11859 double value, value1, value2;
11865 int first_valid, valid_bins;
11869 double *sky_spectrum;
11876 if (spectra == NULL || wavemap == NULL || skymap == NULL) {
11877 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
11881 if (dispersion <= 0.0) {
11882 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
11883 cpl_msg_error(func,
"Negative dispersion: %s", cpl_error_get_message());
11887 nx = cpl_image_get_size_x(spectra);
11888 ny = cpl_image_get_size_y(spectra);
11891 if (nx != cpl_image_get_size_x(wavemap) ||
11892 ny != cpl_image_get_size_y(wavemap) ||
11893 nx != cpl_image_get_size_x(skymap) ||
11894 ny != cpl_image_get_size_y(skymap)) {
11895 cpl_error_set(func, CPL_ERROR_INCOMPATIBLE_INPUT);
11896 cpl_msg_error(func,
"Image sizes: %s", cpl_error_get_message());
11900 if (factor < 1.0) {
11901 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
11902 cpl_msg_error(func,
"Undersampling (%f): %s", factor,
11903 cpl_error_get_message());
11907 if (minpoints < 0) {
11908 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
11909 cpl_msg_error(func,
"Negative threshold: %s", cpl_error_get_message());
11913 dispersion /= factor;
11920 data = cpl_image_get_data(wavemap);
11922 for (i = 0; i < npix; i++) {
11923 if (data[i] > 1.0) {
11924 min = max = data[i];
11930 for (i = j; i < npix; i++) {
11947 nbin = (lastLambda - firstLambda) / dispersion;
11956 count = cpl_calloc(nbin,
sizeof(
int));
11958 data = cpl_image_get_data(wavemap);
11960 for (i = 0; i < npix; i++) {
11963 bin = (data[i] - firstLambda) / dispersion;
11969 for (i = 0; i < nbin; i++)
11970 if (count[i] >= minpoints)
11973 if (valid_bins < nbin/3) {
11974 cpl_msg_warning(func,
"Cannot determine a good global sky "
11975 "spectrum from input data");
11987 vector = cpl_calloc(nbin,
sizeof(cpl_vector *));
11988 wvector = cpl_calloc(nbin,
sizeof(cpl_vector *));
11989 for (i = 0; i < nbin; i++) {
11990 if (count[i] >= minpoints) {
11991 vector[i] = cpl_vector_new(count[i]);
11992 wvector[i] = cpl_vector_new(count[i]);
12003 data = cpl_image_get_data(wavemap);
12004 sdata = cpl_image_get_data(spectra);
12006 for (i = 0; i < npix; i++) {
12009 bin = (data[i] - firstLambda) / dispersion;
12012 cpl_vector_set(vector[bin], count[bin], sdata[i]);
12013 cpl_vector_set(wvector[bin], count[bin], data[i]);
12025 sky_spectrum = cpl_calloc(nbin,
sizeof(
double));
12026 sky_wave = cpl_calloc(nbin,
sizeof(
double));
12027 for (i = 0; i < nbin; i++) {
12029 sky_spectrum[i] = cpl_vector_get_median_const(vector[i]);
12030 sky_wave[i] = cpl_vector_get_median_const(wvector[i]);
12031 cpl_vector_delete(vector[i]);
12032 cpl_vector_delete(wvector[i]);
12044 for (i = 0; i < nbin; i++) {
12045 if (count[i] >= minpoints) {
12051 for (i = first_valid; i < nbin; i++) {
12052 if (count[i] < minpoints) {
12053 sky_wave[i] = firstLambda + (i+0.5)*dispersion;
12054 for (j = i+1; j < nbin; j++) {
12055 if (count[j] >= minpoints) {
12056 if (sky_wave[j] - sky_wave[i-1] < 0.1) {
12057 sky_spectrum[i] = (sky_spectrum[j] + sky_spectrum[i-1])
12061 frac = (sky_wave[i] - sky_wave[i-1])
12062 / (sky_wave[j] - sky_wave[i-1]);
12063 sky_spectrum[i] = frac * sky_spectrum[j]
12064 + (1 - frac) * sky_spectrum[i-1];
12076 sky = cpl_table_new(nbin);
12077 cpl_table_wrap_double(sky, sky_wave,
"wavelength");
12078 cpl_table_wrap_double(sky, sky_spectrum,
"sky");
12079 cpl_table_wrap_int(sky, count,
"npoints");
12086 data = cpl_image_get_data(wavemap);
12087 sdata = cpl_image_get_data(spectra);
12088 kdata = cpl_image_get_data(skymap);
12090 for (i = 0; i < npix; i++) {
12099 bin = (lambda - firstLambda) / dispersion;
12100 lambda1 = sky_wave[bin];
12101 value1 = sky_spectrum[bin];
12102 if (lambda1 < lambda) {
12105 lambda2 = sky_wave[bin];
12106 value2 = sky_spectrum[bin];
12107 if (lambda2 - lambda1 < 0.1) {
12108 value = (value1 + value2) / 2;
12111 frac = (lambda - lambda1) / (lambda2 - lambda1);
12112 value = frac * value2 + (1 - frac) * value1;
12124 lambda1 = sky_wave[bin];
12125 value1 = sky_spectrum[bin];
12126 if (lambda2 - lambda1 < 0.1) {
12127 value = (value1 + value2) / 2;
12130 frac = (lambda - lambda1) / (lambda2 - lambda1);
12131 value = frac * value2 + (1 - frac) * value1;
12142 cpl_table_erase_window(sky, 0, first_valid);
12183 double dispersion, cpl_image *skymap)
12185 const char *func =
"mos_sky_map";
12187 cpl_vector **vector;
12188 double firstLambda, lastLambda;
12189 double lambda, lambda1, lambda2;
12190 double value, value1, value2;
12198 double *sky_spectrum;
12205 if (spectra == NULL || wavemap == NULL || skymap == NULL) {
12206 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
12210 if (dispersion <= 0.0) {
12211 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
12215 nx = cpl_image_get_size_x(spectra);
12216 ny = cpl_image_get_size_y(spectra);
12219 if (nx != cpl_image_get_size_x(wavemap) ||
12220 ny != cpl_image_get_size_y(wavemap) ||
12221 nx != cpl_image_get_size_x(skymap) ||
12222 ny != cpl_image_get_size_y(skymap)) {
12223 cpl_error_set(func, CPL_ERROR_INCOMPATIBLE_INPUT);
12232 data = cpl_image_get_data(wavemap);
12234 for (i = 0; i < npix; i++) {
12235 if (data[i] > 1.0) {
12236 min = max = data[i];
12242 for (i = j; i < npix; i++) {
12259 nbin = (lastLambda - firstLambda) / dispersion;
12268 count = cpl_calloc(nbin,
sizeof(
int));
12270 data = cpl_image_get_data(wavemap);
12272 for (i = 0; i < npix; i++) {
12275 bin = (data[i] - firstLambda) / dispersion;
12288 vector = cpl_calloc(nbin,
sizeof(cpl_vector *));
12289 for (i = 0; i < nbin; i++) {
12291 vector[i] = cpl_vector_new(count[i]);
12303 data = cpl_image_get_data(wavemap);
12304 sdata = cpl_image_get_data(spectra);
12306 for (i = 0; i < npix; i++) {
12309 bin = (data[i] - firstLambda) / dispersion;
12311 cpl_vector_set(vector[bin], count[bin], sdata[i]);
12322 sky_spectrum = cpl_calloc(nbin,
sizeof(
double));
12323 for (i = 0; i < nbin; i++) {
12325 sky_spectrum[i] = cpl_vector_get_median_const(vector[i]);
12326 cpl_vector_delete(vector[i]);
12344 sky = cpl_table_new(nbin);
12345 cpl_table_new_column(sky,
"wavelength", CPL_TYPE_DOUBLE);
12346 cpl_table_set_column_unit(sky,
"wavelength",
"pixel");
12347 cpl_table_wrap_double(sky, sky_spectrum,
"sky");
12348 cpl_table_wrap_int(sky, count,
"npoints");
12349 for (i = 0; i < nbin; i++)
12350 cpl_table_set_double(sky,
"wavelength", i,
12351 firstLambda + (i+0.5)*dispersion);
12358 data = cpl_image_get_data(wavemap);
12359 sdata = cpl_image_get_data(spectra);
12360 kdata = cpl_image_get_data(skymap);
12361 wdata = cpl_table_get_data_double(sky,
"wavelength");
12363 for (i = 0; i < npix; i++) {
12372 bin = (lambda - firstLambda) / dispersion;
12373 lambda1 = wdata[bin];
12374 value1 = sky_spectrum[bin];
12375 if (lambda1 < lambda) {
12378 lambda2 = wdata[bin];
12379 value2 = sky_spectrum[bin];
12380 value = ((lambda2 - lambda)*value1
12381 + (lambda - lambda1)*value2) / dispersion;
12392 lambda1 = wdata[bin];
12393 value1 = sky_spectrum[bin];
12394 value = ((lambda2 - lambda)*value1
12395 + (lambda - lambda1)*value2)/dispersion;
12426 const char *func =
"mos_sky_local_old";
12434 int xlow, ylow, xhig, yhig;
12442 if (spectra == NULL) {
12443 cpl_msg_error(func,
12444 "A scientific rectified spectral image must be given");
12445 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
12449 if (slits == NULL) {
12450 cpl_msg_error(func,
"A slits position table must be given");
12451 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
12455 nslits = cpl_table_get_nrow(slits);
12456 slit_id = cpl_table_get_data_int(slits,
"slit_id");
12457 position = cpl_table_get_data_int(slits,
"position");
12458 length = cpl_table_get_data_int(slits,
"length");
12460 nx = cpl_image_get_size_x(spectra);
12461 ny = cpl_image_get_size_y(spectra);
12463 skymap = cpl_image_new(nx, ny, CPL_TYPE_FLOAT);
12467 for (i = 0; i < nslits; i++) {
12469 if (length[i] == 0)
12482 ylow = position[i] + 1;
12483 yhig = ylow + length[i] - 1;
12485 exslit = cpl_image_extract(spectra, xlow, ylow, xhig, yhig);
12486 sky = cpl_image_collapse_median_create(exslit, 0, 0, 1);
12487 cpl_image_delete(exslit);
12489 data = cpl_image_get_data(skymap);
12490 data += nx * position[i];
12492 for (j = 0; j < length[i]; j++) {
12493 sdata = cpl_image_get_data(sky);
12494 for (k = 0; k < nx; k++) {
12495 *data++ = *sdata++;
12499 cpl_image_delete(sky);
12528 const char *func =
"mos_sky_local";
12530 char name[MAX_COLNAME];
12532 cpl_polynomial *fit;
12533 cpl_vector *points;
12534 cpl_vector *values;
12535 cpl_vector *keep_points;
12536 cpl_vector *keep_values;
12539 cpl_image *subtracted;
12540 cpl_image *profile;
12542 cpl_table *objects;
12550 int xlow, ylow, xhig, yhig;
12563 if (spectra == NULL) {
12564 cpl_msg_error(func,
12565 "A scientific rectified spectral image must be given");
12566 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
12570 if (slits == NULL) {
12571 cpl_msg_error(func,
"A slits position table must be given");
12572 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
12577 cpl_msg_error(func,
"Invalid fit order");
12578 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
12582 nslits = cpl_table_get_nrow(slits);
12583 slit_id = cpl_table_get_data_int(slits,
"slit_id");
12584 position = cpl_table_get_data_int(slits,
"position");
12585 length = cpl_table_get_data_int(slits,
"length");
12587 nx = cpl_image_get_size_x(spectra);
12588 ny = cpl_image_get_size_y(spectra);
12590 skymap = cpl_image_new(nx, ny, CPL_TYPE_FLOAT);
12594 for (i = 0; i < nslits; i++) {
12596 if (length[i] == 0)
12609 ylow = position[i] + 1;
12610 yhig = ylow + length[i] - 1;
12612 exslit = cpl_image_extract(spectra, xlow, ylow, xhig, yhig);
12613 sky = cpl_image_collapse_median_create(exslit, 0, 0, 1);
12614 cpl_image_delete(exslit);
12616 data = cpl_image_get_data(skymap);
12617 data += nx * position[i];
12619 for (j = 0; j < length[i]; j++) {
12620 sdata = cpl_image_get_data(sky);
12621 for (k = 0; k < nx; k++) {
12622 *data++ = *sdata++;
12626 cpl_image_delete(sky);
12634 subtracted = cpl_image_duplicate(spectra);
12635 cpl_image_subtract(subtracted, skymap);
12636 cpl_image_delete(skymap);
12643 objects = cpl_table_duplicate(slits);
12645 cpl_image_delete(profile);
12646 cpl_image_delete(subtracted);
12655 snprintf(name, MAX_COLNAME,
"object_%d", maxobjects);
12656 while (cpl_table_has_column(objects, name)) {
12658 snprintf(name, MAX_COLNAME,
"object_%d", maxobjects);
12661 is_sky = cpl_calloc(ny,
sizeof(
int));
12663 for (i = 0; i < nslits; i++) {
12665 if (length[i] == 0)
12668 ylow = position[i] + margin;
12669 yhig = position[i] + length[i] - margin;
12671 for (j = ylow; j < yhig; j++)
12674 for (j = 1; j < maxobjects; j++) {
12675 snprintf(name, MAX_COLNAME,
"object_%d", j);
12676 if (cpl_table_is_valid(objects, name, i)) {
12677 snprintf(name, MAX_COLNAME,
"start_%d", j);
12678 ylow = cpl_table_get_int(objects, name, i, NULL);
12679 snprintf(name, MAX_COLNAME,
"end_%d", j);
12680 yhig = cpl_table_get_int(objects, name, i, NULL);
12681 for (k = ylow; k <= yhig; k++)
12691 ylow = position[i] + margin + 1;
12692 yhig = position[i] + length[i] - margin - 1;
12694 for (j = ylow; j < yhig; j++)
12696 if (is_sky[j-1] == 0 && is_sky[j+1] == 0)
12706 skymap = cpl_image_new(nx, ny, CPL_TYPE_FLOAT);
12708 for (i = 0; i < nslits; i++) {
12710 if (length[i] == 0)
12713 ylow = position[i];
12714 yhig = ylow + length[i];
12717 for (j = ylow; j < yhig; j++)
12721 if (nsky > order + 1) {
12723 points = cpl_vector_new(nsky);
12725 for (j = ylow; j < yhig; j++) {
12727 cpl_vector_set(points, nsky, j);
12732 exslit = cpl_image_extract(spectra, 1, ylow+1, nx, yhig);
12733 xdata = cpl_image_get_data(exslit);
12734 values = cpl_vector_new(nsky);
12736 for (j = 0; j < nx; j++) {
12738 for (k = ylow; k < yhig; k++) {
12740 cpl_vector_set(values, nsky, xdata[j+(k-ylow)*nx]);
12749 median = cpl_vector_get_median_const(values);
12750 vdata = cpl_vector_get_data(values);
12751 pdata = cpl_vector_get_data(points);
12753 for (k = 0; k < nsky; k++) {
12754 if (fabs(vdata[k] - median) < 100) {
12756 vdata[k-nbad] = vdata[k];
12757 pdata[k-nbad] = pdata[k];
12767 if (nbad && nsky - nbad > order + 1) {
12768 keep_values = values;
12769 keep_points = points;
12770 values = cpl_vector_wrap(nsky-nbad, vdata);
12771 points = cpl_vector_wrap(nsky-nbad, pdata);
12774 if (nsky - nbad > order + 1) {
12776 fit = cpl_polynomial_fit_1d_create(points, values,
12780 for (k = ylow; k < yhig; k++) {
12781 xdata[j+(k-ylow)*nx] =
12782 cpl_polynomial_eval_1d(fit, k, NULL);
12785 cpl_polynomial_delete(fit);
12791 for (k = 0; k < nsky; k++) {
12792 xdata[j+k*nx] = median;
12796 if (nbad && nsky - nbad > order + 1) {
12797 cpl_vector_unwrap(values);
12798 cpl_vector_unwrap(points);
12799 values = keep_values;
12800 points = keep_points;
12805 for (k = ylow; k < yhig; k++) {
12807 cpl_vector_set(points, nsky, k);
12815 cpl_vector_delete(values);
12816 cpl_vector_delete(points);
12818 cpl_image_copy(skymap, exslit, 1, ylow+1);
12819 cpl_image_delete(exslit);
12823 exslit = cpl_image_extract(spectra, 1, ylow+1, nx, yhig);
12824 xdata = cpl_image_get_data(exslit);
12825 values = cpl_vector_new(nsky);
12827 for (j = 0; j < nx; j++) {
12829 for (k = ylow; k < yhig; k++) {
12831 cpl_vector_set(values, nsky, xdata[j+(k-ylow)*nx]);
12836 median = cpl_vector_get_median_const(values);
12838 for (k = ylow; k < yhig; k++)
12839 xdata[j+(k-ylow)*nx] = median;
12843 cpl_vector_delete(values);
12845 cpl_image_copy(skymap, exslit, 1, ylow+1);
12846 cpl_image_delete(exslit);
12850 cpl_msg_warning(func,
"Too few sky points in slit %d", i + 1);
12882 float threshold,
float ratio)
12884 const char *func =
"mos_clean_cosmics";
12886 cpl_image *smoothImage;
12888 cpl_matrix *kernel;
12893 float sigma, sum, value, smoothValue;
12897 int iMin, iMax, jMin, jMax, iPosMax, jPosMax;
12903 int pos, i, j, k, l, ii, jj, iii = 0, jjj = 0;
12905 int found, foundContiguousCandidate;
12910 return cpl_error_set(func, CPL_ERROR_NULL_INPUT);
12923 xLen = cpl_image_get_size_x(image);
12924 yLen = cpl_image_get_size_y(image);
12926 if (xLen < 4 || yLen < 4)
12927 return CPL_ERROR_NONE;
12929 nPix = xLen * yLen;
12952 idata = cpl_image_get_data(image);
12956 for (i = 0; i < nPix; i++) {
12957 if (idata[i] < -0.00001) {
12966 cosmic = cpl_calloc(nPix,
sizeof(
int));
12968 if (threshold < 0.)
12973 kernel = cpl_matrix_new(3, 3);
12974 cpl_matrix_fill(kernel, 1.0);
12975 cpl_matrix_set(kernel, 1, 1, 0.0);
12976 smoothImage = cpl_image_filter_median(image, kernel);
12977 cpl_matrix_delete(kernel);
12988 sdata = cpl_image_get_data(smoothImage);
12990 for (j = 1; j < yLen - 1; j++) {
12991 for (i = 1; i < xLen - 1; i++) {
12992 value = idata[i + j * xLen];
12993 smoothValue = sdata[i + j * xLen];
12994 if (smoothValue < 1.0)
12996 sigma = sqrt(noise * noise + smoothValue / gain);
12997 if (value - smoothValue >= threshold * sigma)
12998 cosmic[i + j * xLen] = -1;
13002 cpl_image_delete(smoothImage);
13011 for (pos = first; pos < nPix; pos++) {
13012 if (cosmic[pos] == -1) {
13032 iMin = iMax = iPosMax = i;
13033 jMin = jMax = jPosMax = j;
13034 fMax = idata[i + j * xLen];
13037 foundContiguousCandidate = 0;
13038 for (l = 0; l <= 1; l++) {
13039 for (k = 0; k <= 1; k++) {
13046 jj = j + k + l - 1;
13047 if (cosmic[ii + jj * xLen] == -1) {
13048 foundContiguousCandidate = 1;
13049 cosmic[ii + jj * xLen] = 2;
13067 if (idata[ii + jj * xLen] > fMax) {
13068 fMax = idata[ii + jj * xLen];
13081 cosmic[i + j * xLen] = 3;
13083 if (foundContiguousCandidate) {
13105 for (l = jMin; l <= jMax; l++) {
13106 for (k = iMin; k <= iMax; k++) {
13107 if (cosmic[k + l * xLen] == 2) {
13110 foundContiguousCandidate = 1;
13114 if (foundContiguousCandidate)
13117 }
while (foundContiguousCandidate);
13126 for (l = -1; l <= 1; l++) {
13127 for (k = -1; k <= 1; k++) {
13128 if (l != 0 || k != 0) {
13129 sum += idata[iPosMax + k + (jPosMax + l) * xLen];
13135 if (fMax > ratio * sum) {
13136 for (l = jMin - 1; l <= jMax + 1; l++) {
13137 for (k = iMin - 1; k <= iMax + 1; k++) {
13138 if (cosmic[k + l * xLen] == 3) {
13139 cosmic[k + l * xLen] = 1;
13146 for (l = jMin - 1; l <= jMax + 1; l++) {
13147 for (k = iMin - 1; k <= iMax + 1; k++) {
13148 if (cosmic[k + l * xLen] != -1) {
13149 if (cosmic[k + l * xLen] == 1)
13151 cosmic[k + l * xLen] = 0;
13164 table = cpl_table_new(numCosmic);
13165 cpl_table_new_column(table,
"x", CPL_TYPE_INT);
13166 cpl_table_new_column(table,
"y", CPL_TYPE_INT);
13167 cpl_table_set_column_unit(table,
"x",
"pixel");
13168 cpl_table_set_column_unit(table,
"y",
"pixel");
13169 xdata = cpl_table_get_data_int(table,
"x");
13170 ydata = cpl_table_get_data_int(table,
"y");
13172 for (pos = 0, i = 0; pos < nPix; pos++) {
13173 if (cosmic[pos] == 1) {
13174 xdata[i] = (pos % xLen);
13175 ydata[i] = (pos / xLen);
13180 mos_clean_bad_pixels(image, table, 1);
13183 cpl_table_delete(table);
13185 return CPL_ERROR_NONE;
13190 cpl_error_code mos_clean_bad_pixels(cpl_image *image, cpl_table *table,
13193 const char *func =
"mos_clean_cosmics";
13198 int xlen, ylen, totPix;
13199 int nBadPixels = 0;
13200 int sign, foundFirst;
13201 int *xValue = NULL;
13202 int *yValue = NULL;
13208 int sx[] = {0, 1, 1, 1};
13209 int sy[] = {1,-1, 0, 1};
13210 int searchHorizon = 100;
13214 if (image == NULL || table == NULL)
13215 return cpl_error_set(func, CPL_ERROR_NULL_INPUT);
13217 if (1 != cpl_table_has_column(table,
"x"))
13218 return cpl_error_set(func, CPL_ERROR_DATA_NOT_FOUND);
13220 if (1 != cpl_table_has_column(table,
"y"))
13221 return cpl_error_set(func, CPL_ERROR_DATA_NOT_FOUND);
13223 if (CPL_TYPE_INT != cpl_table_get_column_type(table,
"x"))
13224 return cpl_error_set(func, CPL_ERROR_INVALID_TYPE);
13226 if (CPL_TYPE_INT != cpl_table_get_column_type(table,
"y"))
13227 return cpl_error_set(func, CPL_ERROR_INVALID_TYPE);
13229 nBadPixels = cpl_table_get_nrow(table);
13232 xlen = cpl_image_get_size_x(image);
13233 ylen = cpl_image_get_size_y(image);
13234 idata = cpl_image_get_data(image);
13235 totPix = xlen * ylen;
13236 if (((
float) nBadPixels) / ((
float) totPix) < percent/100.) {
13237 isBadPix = cpl_calloc(totPix,
sizeof(
int));
13240 cpl_msg_warning(func,
"Too many bad pixels (> %d%%): "
13241 "skip bad pixel correction", percent);
13242 return cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
13246 cpl_msg_debug(func,
"No pixel values to interpolate");
13247 return CPL_ERROR_NONE;
13250 xValue = cpl_table_get_data_int(table,
"x");
13251 yValue = cpl_table_get_data_int(table,
"y");
13253 for (i = 0; i < nBadPixels; i++)
13254 isBadPix[xValue[i] + yValue[i] * xlen] = 1;
13256 for (i = 0; i < nBadPixels; i++) {
13271 for (j = 0; j < 4; j++) {
13277 estimate[nPairs] = 0.;
13280 for (k = 0; k < 2; k++) {
13286 cx += sign * sx[j];
13287 cy += sign * sy[j];
13288 if (cx < 0 || cx >= xlen || cy < 0 || cy >= ylen)
13291 }
while (isBadPix[cx + cy * xlen] && d < searchHorizon);
13293 if (cx >= 0 && cx < xlen &&
13294 cy >= 0 && cy < ylen && d < searchHorizon) {
13300 save = idata[cx + cy * xlen];
13301 estimate[nPairs] += save / d;
13302 sumd += 1. / (double) d;
13304 estimate[nPairs] /= sumd;
13319 estimate[nPairs] = save;
13334 idata[xValue[i] + yValue[i] * xlen] =
13335 cpl_tools_get_median_float(estimate, nPairs);
13337 else if (nPairs == 2) {
13338 idata[xValue[i] + yValue[i] * xlen] =
13339 (estimate[0] + estimate[1]) / 2.;
13341 else if (nPairs == 1) {
13342 idata[xValue[i] + yValue[i] * xlen] = estimate[0];
13345 cpl_msg_debug(func,
"Cannot correct bad pixel %d,%d\n",
13346 xValue[i], yValue[i]);
13350 cpl_free(isBadPix);
13352 return CPL_ERROR_NONE;
13386 cpl_table *polytraces,
double reference,
13387 double blue,
double red,
double dispersion)
13389 const char *func =
"mos_spatial_map";
13391 const char *clab[6] = {
"c0",
"c1",
"c2",
"c3",
"c4",
"c5"};
13393 cpl_polynomial *polytop;
13394 cpl_polynomial *polybot;
13395 cpl_image *calibration;
13408 int pixel_above, pixel_below, refpixel, start_pixel, end_pixel;
13409 int missing_top, missing_bot;
13416 if (spectra == NULL || slits == NULL || polytraces == NULL) {
13417 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
13421 if (dispersion <= 0.0) {
13422 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
13426 if (red - blue < dispersion) {
13427 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
13431 nx = cpl_image_get_size_x(spectra);
13432 ny = cpl_image_get_size_y(spectra);
13434 calibration = cpl_image_new(nx, ny, CPL_TYPE_FLOAT);
13435 data = cpl_image_get_data(calibration);
13437 length = cpl_table_get_data_int(slits,
"length");
13438 nslits = cpl_table_get_nrow(slits);
13439 slit_id = cpl_table_get_data_int(slits,
"slit_id");
13440 order = cpl_table_get_ncol(polytraces) - 2;
13447 pixel_above = STRETCH_FACTOR * (red - reference) / dispersion;
13448 pixel_below = STRETCH_FACTOR * (reference - blue) / dispersion;
13450 for (i = 0; i < nslits; i++) {
13452 if (length[i] == 0)
13466 refpixel = cpl_table_get_double(slits,
"xtop", i, NULL);
13468 start_pixel = refpixel - pixel_below;
13469 if (start_pixel < 0)
13472 end_pixel = refpixel + pixel_above;
13473 if (end_pixel > nx)
13482 polytop = cpl_polynomial_new(1);
13483 for (k = 0; k <= order; k++) {
13484 coeff = cpl_table_get_double(polytraces, clab[k], 2*i, &null);
13486 cpl_polynomial_delete(polytop);
13490 cpl_polynomial_set_coeff(polytop, &k, coeff);
13494 polybot = cpl_polynomial_new(1);
13495 for (k = 0; k <= order; k++) {
13496 coeff = cpl_table_get_double(polytraces, clab[k], 2*i+1, &null);
13498 cpl_polynomial_delete(polybot);
13502 cpl_polynomial_set_coeff(polybot, &k, coeff);
13505 if (missing_top && missing_bot) {
13506 cpl_msg_warning(func,
"Spatial map, slit %d was not traced!",
13518 cpl_msg_warning(func,
"Upper edge of slit %d was not traced: "
13519 "the spectral curvature of the lower edge "
13520 "is used instead.", slit_id[i]);
13521 polytop = cpl_polynomial_duplicate(polybot);
13522 ytop = cpl_table_get_double(slits,
"ytop", i, NULL);
13523 ybot = cpl_table_get_double(slits,
"ybottom", i, NULL);
13525 coeff = cpl_polynomial_get_coeff(polybot, &k);
13526 coeff += ytop - ybot;
13527 cpl_polynomial_set_coeff(polytop, &k, coeff);
13531 cpl_msg_warning(func,
"Lower edge of slit %d was not traced: "
13532 "the spectral curvature of the upper edge "
13533 "is used instead.", slit_id[i]);
13534 polybot = cpl_polynomial_duplicate(polytop);
13535 ytop = cpl_table_get_double(slits,
"ytop", i, NULL);
13536 ybot = cpl_table_get_double(slits,
"ybottom", i, NULL);
13538 coeff = cpl_polynomial_get_coeff(polytop, &k);
13539 coeff -= ytop - ybot;
13540 cpl_polynomial_set_coeff(polybot, &k, coeff);
13543 top = cpl_polynomial_eval_1d(polytop, refpixel, NULL);
13544 bot = cpl_polynomial_eval_1d(polybot, refpixel, NULL);
13545 npseudo = ceil(top-bot) + 1;
13548 cpl_polynomial_delete(polytop);
13549 cpl_polynomial_delete(polybot);
13550 cpl_msg_warning(func,
"Slit %d was badly traced: no extraction!",
13555 for (j = start_pixel; j < end_pixel; j++) {
13556 top = cpl_polynomial_eval_1d(polytop, j, NULL);
13557 bot = cpl_polynomial_eval_1d(polybot, j, NULL);
13558 factor = (top-bot)/npseudo;
13559 for (k = 0; k <= npseudo; k++) {
13560 ypos = top - k*factor;
13562 yfra = ypos - yint;
13563 if (yint >= 0 && yint < ny-1) {
13564 data[j + nx*yint] = (top-yint)/factor;
13573 if (yprev - yint > 1) {
13574 data[j + nx*(yint+1)] = (top-yint-1)/factor;
13581 cpl_polynomial_delete(polytop);
13582 cpl_polynomial_delete(polybot);
13585 return calibration;
13652 int maxradius,
int conradius)
13654 const char *func =
"mos_detect_objects";
13656 cpl_image *profile;
13660 char name[MAX_COLNAME];
13664 int nobjects, objpos, totobj;
13671 double mindistance;
13678 const int min_pixels = 10;
13681 if (cpl_error_get_code() != CPL_ERROR_NONE)
13684 if (image == NULL || slits == NULL) {
13685 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
13692 if (maxradius < 0) {
13693 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
13697 if (conradius < 0) {
13698 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
13702 nslits = cpl_table_get_nrow(slits);
13703 position = cpl_table_get_data_int(slits,
"position");
13704 length = cpl_table_get_data_int(slits,
"length");
13706 profile = cpl_image_collapse_create(image, 1);
13707 cpl_image_divide_scalar(profile, cpl_image_get_size_x(image));
13708 pdata = cpl_image_get_data(profile);
13713 for (i = 0; i < nslits; i++) {
13715 if (length[i] == 0)
13718 pos = position[i] + margin;
13719 count = length[i] - 2*margin;
13721 if (count < min_pixels)
13732 if (p[0] > p[1] && p[1] > p[2] && p[2] > p[3] && p[3] > 0) {
13737 for (j = 0; j < count - 3; j++) {
13739 if (p[j+1] > p[j]) {
13744 if (p[j+1] > p[j+2] && p[j+2] > 0) {
13750 if (p[j+1] > p[j+2] && p[j+2] > p[j+3] && p[j+3] > 0) {
13763 if (p[count-1] > p[count-2] && p[count-2] > p[count-3]
13764 && p[count-3] > p[count-4] && p[count-4] > 0) {
13776 reject = cpl_calloc(npeaks,
sizeof(
int));
13777 bright = cpl_calloc(npeaks,
sizeof(
double));
13778 place = cpl_calloc(npeaks,
sizeof(
double));
13781 if (p[0] > p[1] && p[1] > p[2] && p[2] > p[3] && p[3] > 0) {
13783 place[0] = position[i] + margin;
13788 for (j = 0; j < count - 3; j++) {
13790 if (p[j+1] > p[j]) {
13795 if (p[j+1] > p[j+2] && p[j+2] > 0) {
13797 bright[npeaks] = p[j];
13798 place[npeaks] = position[i] + margin + j + 1
13799 + values_to_dx(p[j-1], p[j], p[j+1]);
13805 if (p[j+1] > p[j+2] && p[j+2] > p[j+3] && p[j+3] > 0) {
13807 bright[npeaks] = p[j];
13808 place[npeaks] = position[i] + margin + j + 1
13809 + values_to_dx(p[j-1], p[j], p[j+1]);
13822 if (p[count-1] > p[count-2] && p[count-2] > p[count-3]
13823 && p[count-3] > p[count-4] && p[count-4] > 0) {
13824 bright[npeaks] = p[count-1];
13825 place[npeaks] = position[i] + count;
13834 if (fabs(place[0] - pos) < 1.0)
13836 if (fabs(place[npeaks-1] - pos - count) < 1.0)
13837 reject[npeaks-1] = 1;
13838 for (j = 0; j < npeaks; j++) {
13839 for (k = 0; k < npeaks; k++) {
13842 mindistance = conradius * bright[k] / bright[j]
13843 * bright[k] / bright[j];
13844 if (fabs(place[j] - place[k]) < mindistance)
13850 for (j = 0; j < npeaks; j++) {
13854 low = (place[j-1]*bright[j] + place[j]*bright[j-1])
13855 / (bright[j-1] + bright[j]) + 1;
13860 if (j < npeaks - 1) {
13861 hig = (place[j+1]*bright[j] + place[j]*bright[j+1])
13862 / (bright[j+1] + bright[j]) + 1;
13870 if (hig > pos + count)
13872 if (place[j] - low > maxradius)
13873 low = place[j] - maxradius;
13874 if (hig - place[j] > maxradius)
13875 hig = place[j] + maxradius;
13882 for (j = 0; j < npeaks; j++)
13886 for (j = 0; j < nobjects; j++) {
13887 snprintf(name, MAX_COLNAME,
"object_%d", j+1);
13888 if (cpl_table_has_column(slits, name))
13890 cpl_table_new_column(slits, name, CPL_TYPE_DOUBLE);
13891 snprintf(name, MAX_COLNAME,
"start_%d", j+1);
13892 cpl_table_new_column(slits, name, CPL_TYPE_INT);
13893 cpl_table_set_column_unit(slits, name,
"pixel");
13894 snprintf(name, MAX_COLNAME,
"end_%d", j+1);
13895 cpl_table_new_column(slits, name, CPL_TYPE_INT);
13896 cpl_table_set_column_unit(slits, name,
"pixel");
13897 snprintf(name, MAX_COLNAME,
"row_%d", j+1);
13898 cpl_table_new_column(slits, name, CPL_TYPE_INT);
13899 cpl_table_set_column_unit(slits, name,
"pixel");
13903 for (j = 0; j < npeaks; j++) {
13907 low = (place[j-1]*bright[j] + place[j]*bright[j-1])
13908 / (bright[j-1] + bright[j]) + 1;
13913 if (j < npeaks - 1) {
13914 hig = (place[j+1]*bright[j] + place[j]*bright[j+1])
13915 / (bright[j+1] + bright[j]) + 1;
13923 if (hig > pos + count)
13925 if (place[j] - low > maxradius)
13926 low = place[j] - maxradius;
13927 if (hig - place[j] > maxradius)
13928 hig = place[j] + maxradius;
13930 snprintf(name, MAX_COLNAME,
"object_%d", objpos);
13931 cpl_table_set_double(slits, name, i, place[j]);
13932 snprintf(name, MAX_COLNAME,
"start_%d", objpos);
13933 cpl_table_set_int(slits, name, i, low);
13934 snprintf(name, MAX_COLNAME,
"end_%d", objpos);
13935 cpl_table_set_int(slits, name, i, hig);
13936 snprintf(name, MAX_COLNAME,
"row_%d", objpos);
13937 cpl_table_set_int(slits, name, i, row + objpos - 1);
13944 if (maxobjects < nobjects)
13945 maxobjects = nobjects;
13954 row = cpl_table_get_nrow(slits);
13956 for (i = 0; i < row; i++) {
13957 for (j = 0; j < maxobjects; j++) {
13958 snprintf(name, MAX_COLNAME,
"row_%d", j+1);
13959 if (cpl_table_is_valid(slits, name, i))
13960 cpl_table_set_int(slits, name, i, totobj -
13961 cpl_table_get_int(slits, name, i, NULL));
13965 for (i = 0; i < maxobjects; i++) {
13966 snprintf(name, MAX_COLNAME,
"start_%d", i+1);
13967 cpl_table_fill_invalid_int(slits, name, -1);
13968 snprintf(name, MAX_COLNAME,
"end_%d", i+1);
13969 cpl_table_fill_invalid_int(slits, name, -1);
13970 snprintf(name, MAX_COLNAME,
"row_%d", i+1);
13971 cpl_table_fill_invalid_int(slits, name, -1);
14003 cpl_table *objects,
int extraction,
double ron,
14004 double gain,
int ncombined)
14006 const char *func =
"mos_extract_objects";
14008 char name[MAX_COLNAME];
14010 cpl_image **output;
14011 cpl_image *extracted;
14012 cpl_image *extr_sky;
14024 if (science == NULL || sky == NULL) {
14025 cpl_msg_error(func,
"Both scientific exposures are required in input");
14026 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
14030 if (objects == NULL) {
14031 cpl_msg_error(func,
"An object table is required in input");
14032 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
14036 if (extraction < 0 || extraction > 1) {
14037 cpl_msg_error(func,
"Invalid extraction mode (%d): it should be "
14038 "either 0 or 1", extraction);
14039 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
14044 cpl_msg_error(func,
"Invalid read-out-noise (%f ADU)", ron);
14045 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
14050 cpl_msg_error(func,
"Invalid gain factor (%f e-/ADU)", gain);
14051 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
14055 if (ncombined < 1) {
14056 cpl_msg_error(func,
"Invalid number of combined frames (%d): "
14057 "it should be at least 1", ncombined);
14058 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
14069 snprintf(name, MAX_COLNAME,
"object_%d", maxobjects);
14070 while (cpl_table_has_column(objects, name)) {
14072 snprintf(name, MAX_COLNAME,
"object_%d", maxobjects);
14081 nslits = cpl_table_get_nrow(objects);
14083 for (i = 0; i < nslits; i++) {
14084 for (j = 1; j < maxobjects; j++) {
14085 snprintf(name, MAX_COLNAME,
"object_%d", j);
14086 if (cpl_table_is_valid(objects, name, i))
14094 nx = cpl_image_get_size_x(science);
14096 output = cpl_calloc(3,
sizeof(cpl_image *));
14097 extracted = output[0] = cpl_image_new(nx, nobjects, CPL_TYPE_FLOAT);
14098 extr_sky = output[1] = cpl_image_new(nx, nobjects, CPL_TYPE_FLOAT);
14099 error = output[2] = cpl_image_new(nx, nobjects, CPL_TYPE_FLOAT);
14107 for (i = 0; i < nslits; i++) {
14108 for (j = 1; j < maxobjects; j++) {
14109 snprintf(name, MAX_COLNAME,
"object_%d", j);
14110 if (cpl_table_is_valid(objects, name, i)) {
14111 snprintf(name, MAX_COLNAME,
"start_%d", j);
14112 ylow = cpl_table_get_int(objects, name, i, NULL);
14113 snprintf(name, MAX_COLNAME,
"end_%d", j);
14114 yhig = cpl_table_get_int(objects, name, i, NULL);
14115 snprintf(name, MAX_COLNAME,
"row_%d", j);
14116 nobjects = cpl_table_get_int(objects, name, i, NULL);
14117 sciwin = cpl_image_extract(science, 1, ylow+1, nx, yhig);
14118 skywin = cpl_image_extract(sky, 1, ylow+1, nx, yhig);
14127 mos_extraction(sciwin, skywin, extracted, extr_sky, error,
14128 nobjects, extraction, ron, gain, ncombined);
14135 cpl_image *total = cpl_image_add_create(sciwin, skywin);
14136 float *data = cpl_image_get_data_float(total);
14137 int size = cpl_image_get_size_x(total)
14138 * cpl_image_get_size_y(total);
14140 char *saturation_level = getenv(
"SATURATION_LEVEL");
14141 float saturation = 62000.0;
14142 char *max_saturated = getenv(
"MAX_SATURATED");
14143 int max_satur = 10;
14146 if (saturation_level)
14147 saturation = atof(saturation_level);
14150 max_satur = atoi(max_saturated);
14153 for (k = 0; k < size; k++) {
14154 if (data[k] > saturation) {
14156 if (saturated > max_satur) {
14162 if (saturated > max_satur)
14167 data = cpl_image_get_data(extracted);
14168 data[nobjects * nx] = saturated;
14171 cpl_image_delete(sciwin);
14172 cpl_image_delete(skywin);
14206 double dispersion,
int saturation,
14207 double *mfwhm,
double *rmsfwhm,
14208 double *resolution,
double *rmsres,
int *nlines)
14210 cpl_vector *vector;
14213 int position, maxpos;
14218 int threshold = 250;
14223 double min, max, halfmax;
14234 xlen = cpl_image_get_size_x(image);
14235 ylen = cpl_image_get_size_y(image);
14236 data = cpl_image_get_data(image);
14238 buffer = cpl_malloc(ylen *
sizeof(
double));
14244 position = floor((lambda - startwave) / dispersion + 0.5);
14246 sp = position - sradius;
14247 ep = position + sradius;
14249 if (sp < 0 || ep > xlen) {
14254 for (i = 0, n = 0; i < ylen; i++) {
14265 sp = position - radius;
14266 ep = position + radius;
14268 if (sp < 0 || ep > xlen) {
14279 min = max = data[sp + i * xlen];
14280 for (j = sp; j < ep; j++) {
14281 if (data[j + i * xlen] > max) {
14282 max = data[j + i * xlen];
14285 if (data[j + i * xlen] < min) {
14286 min = data[j + i * xlen];
14290 if (fabs(min) < 0.0000001)
14293 if (max - min < threshold)
14296 if (max > saturation)
14306 halfmax = (max + min)/ 2.0;
14310 for (j = maxpos; j < maxpos + radius; j++) {
14312 if (data[j + i * xlen] < halfmax) {
14313 fwhm = ifwhm + (data[j - 1 + i * xlen] - halfmax)
14314 / (data[j - 1 + i * xlen] - data[j + i * xlen]);
14322 for (j = maxpos; j > maxpos - radius; j--) {
14324 if (data[j + i * xlen] < halfmax) {
14325 fwhm += ifwhm + (data[j + 1 + i * xlen] - halfmax)
14326 / (data[j + 1 + i * xlen] - data[j + i * xlen]);
14334 buffer[n] = fwhm - 2.0;
14345 vector = cpl_vector_wrap(n, buffer);
14346 value = cpl_vector_get_median_const(vector);
14347 cpl_vector_unwrap(vector);
14350 for (i = 0, m = 0; i < n; i++) {
14351 if (fabs(buffer[i] - value) < cut) {
14352 rms += fabs(buffer[i] - value);
14365 value *= dispersion;
14371 *resolution = lambda / value;
14372 *rmsres = *resolution * rms / value;
14402 double dispersion,
int saturation,
14417 nref = cpl_vector_get_size(lines);
14418 line = cpl_vector_get_data(lines);
14420 table = cpl_table_new(nref);
14421 cpl_table_new_column(table,
"wavelength", CPL_TYPE_DOUBLE);
14422 cpl_table_set_column_unit(table,
"wavelength",
"Angstrom");
14423 cpl_table_new_column(table,
"fwhm", CPL_TYPE_DOUBLE);
14424 cpl_table_set_column_unit(table,
"fwhm",
"Angstrom");
14425 cpl_table_new_column(table,
"fwhm_rms", CPL_TYPE_DOUBLE);
14426 cpl_table_set_column_unit(table,
"fwhm_rms",
"Angstrom");
14427 cpl_table_new_column(table,
"resolution", CPL_TYPE_DOUBLE);
14428 cpl_table_new_column(table,
"resolution_rms", CPL_TYPE_DOUBLE);
14429 cpl_table_new_column(table,
"nlines", CPL_TYPE_INT);
14431 for (i = 0; i < nref; i++) {
14433 saturation, &fwhm, &rmsfwhm,
14434 &resolution, &rmsres, &nlines)) {
14435 cpl_table_set_double(table,
"wavelength", i, line[i]);
14436 cpl_table_set_double(table,
"fwhm", i, fwhm);
14437 cpl_table_set_double(table,
"fwhm_rms", i, rmsfwhm);
14438 cpl_table_set_double(table,
"resolution", i, resolution);
14439 cpl_table_set_double(table,
"resolution_rms", i, rmsres);
14440 cpl_table_set_int(table,
"nlines", i, nlines);
14443 cpl_table_set_int(table,
"nlines", i, 0);
14446 if (cpl_table_has_valid(table,
"wavelength"))
14449 cpl_table_delete(table);
14474 int ystart,
int yend,
double wstart,
double wend)
14476 const char *func =
"mos_integrate_signal";
14485 if (image == NULL || wavemap == NULL) {
14486 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
14490 if (ystart > yend || wstart >= wend) {
14491 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
14495 nx = cpl_image_get_size_x(image);
14496 ny = cpl_image_get_size_y(image);
14498 if (!(nx == cpl_image_get_size_x(wavemap)
14499 && ny == cpl_image_get_size_y(wavemap))) {
14500 cpl_error_set(func, CPL_ERROR_INCOMPATIBLE_INPUT);
14504 if (ystart < 0 || yend > ny) {
14505 cpl_error_set(func, CPL_ERROR_ACCESS_OUT_OF_RANGE);
14509 sdata = cpl_image_get_data(image);
14510 wdata = cpl_image_get_data(wavemap);
14512 sdata += ystart*nx;
14513 wdata += ystart*nx;
14516 for (y = ystart; y < yend; y++) {
14517 for (x = 0; x < nx; x++) {
14518 if (wdata[x] < wstart || wdata[x] > wend)
14563 const char *func =
"mos_load_slits_fors_mxu";
14566 char keyname[MAX_COLNAME];
14567 const char *instrume;
14568 const char *target_name;
14573 double arc2mm = 0.528;
14586 float low_limit1 = 10.0;
14587 float hig_limit2 = 30.0;
14590 if (cpl_error_get_code() != CPL_ERROR_NONE) {
14594 if (header == NULL) {
14595 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
14604 instrume = cpl_propertylist_get_string(header,
"INSTRUME");
14607 if (instrume[4] ==
'1')
14609 if (instrume[4] ==
'2')
14613 cpl_msg_error(func,
"Wrong instrument: %s\n"
14614 "FORS2 is expected for MXU data", instrume);
14615 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
14626 chip = cpl_propertylist_get_int(header,
"ESO DET CHIP1 Y");
14628 if (cpl_error_get_code() != CPL_ERROR_NONE) {
14629 cpl_msg_error(func,
"Missing keyword ESO DET CHIP1 Y "
14631 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
14635 if (chip != 1 && chip != 2) {
14636 cpl_msg_error(func,
"Unexpected chip position in keyword "
14637 "ESO DET CHIP1 Y: %d", chip);
14638 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
14654 snprintf(keyname, MAX_COLNAME,
"ESO INS MOS%d YPOS", slit_id + 100);
14655 if (cpl_propertylist_has(header, keyname)) {
14656 slit_y = cpl_propertylist_get_double(header, keyname);
14659 if (slit_y < low_limit1)
14662 if (slit_y > hig_limit2)
14665 snprintf(keyname, MAX_COLNAME,
"ESO INS TARG%d NAME",
14667 if (cpl_propertylist_has(header, keyname)) {
14668 target_name = cpl_propertylist_get_string(header, keyname);
14669 if (strncmp(target_name,
"refslit", 7))
14679 if (cpl_error_get_code() != CPL_ERROR_NONE) {
14680 cpl_msg_error(func,
"%s while loading slits coordinates from "
14681 "FITS header", cpl_error_get_message());
14682 cpl_error_set_where(func);
14687 cpl_msg_error(func,
"No slits coordinates found in header");
14688 cpl_error_set(func, CPL_ERROR_DATA_NOT_FOUND);
14692 slits = cpl_table_new(nslits);
14693 cpl_table_new_column(slits,
"slit_id", CPL_TYPE_INT);
14694 cpl_table_new_column(slits,
"xtop", CPL_TYPE_DOUBLE);
14695 cpl_table_new_column(slits,
"ytop", CPL_TYPE_DOUBLE);
14696 cpl_table_new_column(slits,
"xbottom", CPL_TYPE_DOUBLE);
14697 cpl_table_new_column(slits,
"ybottom", CPL_TYPE_DOUBLE);
14698 cpl_table_set_column_unit(slits,
"xtop",
"pixel");
14699 cpl_table_set_column_unit(slits,
"ytop",
"pixel");
14700 cpl_table_set_column_unit(slits,
"xbottom",
"pixel");
14701 cpl_table_set_column_unit(slits,
"ybottom",
"pixel");
14708 snprintf(keyname, MAX_COLNAME,
"ESO INS MOS%d YPOS", slit_id + 100);
14709 if (cpl_propertylist_has(header, keyname)) {
14710 slit_y = cpl_propertylist_get_double(header, keyname);
14713 if (slit_y < low_limit1)
14716 if (slit_y > hig_limit2)
14726 snprintf(keyname, MAX_COLNAME,
"ESO INS MOS%d XPOS", slit_id + 100);
14727 slit_x = cpl_propertylist_get_double(header, keyname);
14728 if (cpl_error_get_code() != CPL_ERROR_NONE) {
14729 cpl_table_delete(slits);
14730 cpl_msg_error(func,
"Missing keyword %s in FITS header",
14732 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
14736 snprintf(keyname, MAX_COLNAME,
"ESO INS MOS%d LEN", slit_id + 100);
14737 length = cpl_propertylist_get_double(header, keyname);
14738 if (cpl_error_get_code() != CPL_ERROR_NONE) {
14739 cpl_table_delete(slits);
14740 cpl_msg_error(func,
"Missing keyword %s in FITS header",
14742 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
14748 snprintf(keyname, MAX_COLNAME,
"ESO INS TARG%d NAME",
14750 if (cpl_propertylist_has(header, keyname)) {
14751 target_name = cpl_propertylist_get_string(header, keyname);
14752 if (strncmp(target_name,
"refslit", 7)) {
14753 cpl_table_set_int(slits,
"slit_id", nslits, slit_id);
14754 cpl_table_set(slits,
"xtop", nslits, slit_x);
14755 cpl_table_set(slits,
"ytop", nslits, slit_y + length/2);
14756 cpl_table_set(slits,
"xbottom", nslits, slit_x);
14757 cpl_table_set(slits,
"ybottom", nslits, slit_y - length/2);
14762 cpl_table_set_int(slits,
"slit_id", nslits, slit_id);
14763 cpl_table_set(slits,
"xtop", nslits, slit_x);
14764 cpl_table_set(slits,
"ytop", nslits, slit_y + length/2);
14765 cpl_table_set(slits,
"xbottom", nslits, slit_x);
14766 cpl_table_set(slits,
"ybottom", nslits, slit_y - length/2);
14802 int * nslits_out_det)
14804 const char *func =
"mos_load_slits_fors_mos";
14807 char keyname[MAX_COLNAME];
14808 const char *instrume;
14809 const char *chipname;
14811 int first_slit, last_slit;
14822 float ytop[19] = { 113.9, 101.3, 89.9, 77.3, 65.9, 53.3,
14823 41.9, 29.3, 17.9, 5.3, -6.1, -18.7,
14824 -30.1, -42.7, -54.1, -66.7, -78.1, -90.7,
14826 float ybottom[19] = { 102.1, 90.7, 78.1, 66.7, 54.1, 42.7,
14827 30.1, 18.7, 6.1, -5.3, -17.9, -29.3,
14828 -41.9, -53.3, -65.9, -77.3, -89.9, -101.3,
14832 if (cpl_error_get_code() != CPL_ERROR_NONE) {
14836 if (header == NULL) {
14837 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
14846 instrume = cpl_propertylist_get_string(header,
"INSTRUME");
14849 if (instrume[4] ==
'1')
14851 if (instrume[4] ==
'2')
14855 cpl_msg_error(func,
"Wrong instrument found in FITS header: %s",
14857 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
14867 chipname = cpl_propertylist_get_string(header,
"ESO DET CHIP1 ID");
14869 if (chipname[0] ==
'M' || chipname[0] ==
'N')
14874 if (fors == 1 && fors_is_old) {
14886 chip = cpl_propertylist_get_int(header,
"ESO DET CHIP1 Y");
14888 if (cpl_error_get_code() != CPL_ERROR_NONE) {
14889 cpl_msg_error(func,
"Missing keyword ESO DET CHIP1 Y "
14891 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
14895 if (chip != 1 && chip != 2) {
14896 cpl_msg_error(func,
"Unexpected chip position in keyword "
14897 "ESO DET CHIP1 Y: %d", chip);
14898 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
14921 for (slit_id = first_slit; slit_id <= last_slit; slit_id++) {
14922 snprintf(keyname, MAX_COLNAME,
"ESO INS MOS%d POS", slit_id);
14923 if (cpl_propertylist_has(header, keyname)) {
14924 slit_x = cpl_propertylist_get_double(header, keyname);
14925 if (fabs(slit_x) < 115.0)
14928 (*nslits_out_det)++;
14931 cpl_msg_error(func,
"Missing keyword %s in FITS header", keyname);
14932 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
14937 if (cpl_error_get_code() != CPL_ERROR_NONE) {
14938 cpl_msg_error(func,
"%s while loading slits coordinates from "
14939 "FITS header", cpl_error_get_message());
14940 cpl_error_set_where(func);
14945 cpl_msg_error(func,
"No slits coordinates found in header");
14946 cpl_error_set(func, CPL_ERROR_DATA_NOT_FOUND);
14950 slits = cpl_table_new(nslits);
14951 cpl_table_new_column(slits,
"slit_id", CPL_TYPE_INT);
14952 cpl_table_new_column(slits,
"xtop", CPL_TYPE_DOUBLE);
14953 cpl_table_new_column(slits,
"ytop", CPL_TYPE_DOUBLE);
14954 cpl_table_new_column(slits,
"xbottom", CPL_TYPE_DOUBLE);
14955 cpl_table_new_column(slits,
"ybottom", CPL_TYPE_DOUBLE);
14956 cpl_table_set_column_unit(slits,
"xtop",
"pixel");
14957 cpl_table_set_column_unit(slits,
"ytop",
"pixel");
14958 cpl_table_set_column_unit(slits,
"xbottom",
"pixel");
14959 cpl_table_set_column_unit(slits,
"ybottom",
"pixel");
14963 for (slit_id = first_slit; slit_id <= last_slit; slit_id++) {
14964 snprintf(keyname, MAX_COLNAME,
"ESO INS MOS%d POS", slit_id);
14965 slit_x = cpl_propertylist_get_double(header, keyname);
14966 if (fabs(slit_x) < 115.0) {
14967 cpl_table_set_int(slits,
"slit_id", nslits, slit_id);
14968 cpl_table_set(slits,
"xtop", nslits, slit_x);
14969 cpl_table_set(slits,
"ytop", nslits, ytop[slit_id-1]);
14970 cpl_table_set(slits,
"xbottom", nslits, slit_x);
14971 cpl_table_set(slits,
"ybottom", nslits, ybottom[slit_id-1]);
15005 const char *func =
"mos_load_slits_fors_lss";
15009 const char *instrume;
15015 if (cpl_error_get_code() != CPL_ERROR_NONE) {
15019 if (header == NULL) {
15020 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
15029 instrume = cpl_propertylist_get_string(header,
"INSTRUME");
15032 if (instrume[4] ==
'1')
15034 if (instrume[4] ==
'2')
15038 cpl_msg_error(func,
"Wrong instrument found in FITS header: %s",
15040 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
15056 chip = cpl_propertylist_get_int(header,
"ESO DET CHIP1 Y");
15058 if (cpl_error_get_code() != CPL_ERROR_NONE) {
15059 cpl_msg_error(func,
"Missing keyword ESO DET CHIP1 Y "
15061 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
15065 if (chip != 1 && chip != 2) {
15066 cpl_msg_error(func,
"Unexpected chip position in keyword "
15067 "ESO DET CHIP1 Y: %d", chip);
15068 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
15083 slits = cpl_table_new(1);
15084 cpl_table_new_column(slits,
"slit_id", CPL_TYPE_INT);
15085 cpl_table_new_column(slits,
"xtop", CPL_TYPE_DOUBLE);
15086 cpl_table_new_column(slits,
"ytop", CPL_TYPE_DOUBLE);
15087 cpl_table_new_column(slits,
"xbottom", CPL_TYPE_DOUBLE);
15088 cpl_table_new_column(slits,
"ybottom", CPL_TYPE_DOUBLE);
15089 cpl_table_set_column_unit(slits,
"xtop",
"pixel");
15090 cpl_table_set_column_unit(slits,
"ytop",
"pixel");
15091 cpl_table_set_column_unit(slits,
"xbottom",
"pixel");
15092 cpl_table_set_column_unit(slits,
"ybottom",
"pixel");
15094 slit_name = (
char *)cpl_propertylist_get_string(header,
15095 "ESO INS SLIT NAME");
15097 cpl_table_set(slits,
"ytop", 0, ytop);
15098 cpl_table_set(slits,
"ybottom", 0, ybottom);
15100 if (!strncmp(slit_name,
"lSlit0_3arcsec", 14)) {
15101 cpl_table_set_int(slits,
"slit_id", 0, 1);
15102 cpl_table_set(slits,
"xbottom", 0, -0.075);
15103 cpl_table_set(slits,
"xtop", 0, 0.075);
15105 else if (!strncmp(slit_name,
"lSlit0_4arcsec", 14)) {
15106 cpl_table_set_int(slits,
"slit_id", 0, 2);
15107 cpl_table_set(slits,
"xbottom", 0, 5.895);
15108 cpl_table_set(slits,
"xtop", 0, 6.105);
15110 else if (!strncmp(slit_name,
"lSlit0_5arcsec", 14)) {
15111 cpl_table_set_int(slits,
"slit_id", 0, 3);
15112 cpl_table_set(slits,
"xbottom", 0, -6.135);
15113 cpl_table_set(slits,
"xtop", 0, -5.865);
15115 else if (!strncmp(slit_name,
"lSlit0_7arcsec", 14)) {
15116 cpl_table_set_int(slits,
"slit_id", 0, 4);
15117 cpl_table_set(slits,
"xbottom", 0, 11.815);
15118 cpl_table_set(slits,
"xtop", 0, 12.185);
15120 else if (!strncmp(slit_name,
"lSlit1_0arcsec", 14)) {
15121 cpl_table_set_int(slits,
"slit_id", 0, 5);
15122 cpl_table_set(slits,
"xbottom", 0, -12.265);
15123 cpl_table_set(slits,
"xtop", 0, -11.735);
15125 else if (!strncmp(slit_name,
"lSlit1_3arcsec", 14)) {
15126 cpl_table_set_int(slits,
"slit_id", 0, 6);
15127 cpl_table_set(slits,
"xbottom", 0, 17.655);
15128 cpl_table_set(slits,
"xtop", 0, 18.345);
15130 else if (!strncmp(slit_name,
"lSlit1_6arcsec", 14)) {
15131 cpl_table_set_int(slits,
"slit_id", 0, 7);
15132 cpl_table_set(slits,
"xbottom", 0, -18.425);
15133 cpl_table_set(slits,
"xtop", 0, -17.575);
15135 else if (!strncmp(slit_name,
"lSlit2_0arcsec", 14)) {
15136 cpl_table_set_int(slits,
"slit_id", 0, 8);
15137 cpl_table_set(slits,
"xbottom", 0, 23.475);
15138 cpl_table_set(slits,
"xtop", 0, 24.525);
15140 else if (!strncmp(slit_name,
"lSlit2_5arcsec", 14)) {
15141 cpl_table_set_int(slits,
"slit_id", 0, 9);
15142 cpl_table_set(slits,
"xbottom", 0, -24.66);
15143 cpl_table_set(slits,
"xtop", 0, -23.34);
15146 cpl_msg_error(func,
"Invalid slit %s in keyword ESO INS SLIT NAME",
15148 cpl_error_set(func, CPL_ERROR_DATA_NOT_FOUND);
15149 cpl_table_delete(slits);
15173 const char *func =
"mos_get_gain_vimos";
15175 double gain = -1.0;
15178 if (cpl_error_get_code() != CPL_ERROR_NONE)
15181 if (header == NULL) {
15182 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
15186 gain = cpl_propertylist_get_double(header,
"ESO DET OUT1 CONAD");
15187 if (cpl_error_get_code()) {
15188 cpl_error_set_where(func);
15218 const char *func =
"mos_load_slits_vimos";
15221 char keyname[MAX_COLNAME];
15232 if (cpl_error_get_code() != CPL_ERROR_NONE) {
15236 if (header == NULL) {
15237 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
15241 nslits = cpl_propertylist_get_int(header,
"ESO INS SLIT NO");
15243 if (cpl_error_get_code() != CPL_ERROR_NONE) {
15244 cpl_error_set_where(func);
15248 slits = cpl_table_new(nslits);
15249 cpl_table_new_column(slits,
"slit_id", CPL_TYPE_INT);
15250 cpl_table_new_column(slits,
"xtop", CPL_TYPE_DOUBLE);
15251 cpl_table_new_column(slits,
"ytop", CPL_TYPE_DOUBLE);
15252 cpl_table_new_column(slits,
"xbottom", CPL_TYPE_DOUBLE);
15253 cpl_table_new_column(slits,
"ybottom", CPL_TYPE_DOUBLE);
15254 cpl_table_new_column(slits,
"xwidth", CPL_TYPE_DOUBLE);
15255 cpl_table_new_column(slits,
"ywidth", CPL_TYPE_DOUBLE);
15256 cpl_table_new_column(slits,
"curved", CPL_TYPE_INT);
15257 cpl_table_set_column_unit(slits,
"xtop",
"pixel");
15258 cpl_table_set_column_unit(slits,
"ytop",
"pixel");
15259 cpl_table_set_column_unit(slits,
"xbottom",
"pixel");
15260 cpl_table_set_column_unit(slits,
"ybottom",
"pixel");
15261 cpl_table_set_column_unit(slits,
"xwidth",
"mm");
15262 cpl_table_set_column_unit(slits,
"ywidth",
"mm");
15264 for (i = 0; i < nslits; i++) {
15265 sprintf(keyname,
"ESO INS SLIT%d ID", i+1);
15266 slit_id = cpl_propertylist_get_int(header, keyname);
15267 if (cpl_error_get_code() != CPL_ERROR_NONE) {
15268 cpl_error_set_where(func);
15271 sprintf(keyname,
"ESO INS SLIT%d X", i+1);
15272 slit_x = cpl_propertylist_get_double(header, keyname);
15273 if (cpl_error_get_code() != CPL_ERROR_NONE) {
15274 cpl_error_set_where(func);
15277 sprintf(keyname,
"ESO INS SLIT%d Y", i+1);
15278 slit_y = cpl_propertylist_get_double(header, keyname);
15279 if (cpl_error_get_code() != CPL_ERROR_NONE) {
15280 cpl_error_set_where(func);
15283 sprintf(keyname,
"ESO INS SLIT%d DIMX", i+1);
15284 dim_x = cpl_propertylist_get_double(header, keyname);
15285 if (cpl_error_get_code() != CPL_ERROR_NONE) {
15286 cpl_error_set_where(func);
15290 sprintf(keyname,
"ESO INS SLIT%d BEZIER DY", i+1);
15291 if (cpl_propertylist_has(header, keyname)) {
15295 sprintf(keyname,
"ESO INS SLIT%d DIMY", i+1);
15298 dim_y = cpl_propertylist_get_double(header, keyname);
15299 if (cpl_error_get_code() != CPL_ERROR_NONE) {
15300 cpl_error_set_where(func);
15304 cpl_table_set_int(slits,
"slit_id", i, slit_id);
15305 cpl_table_set(slits,
"xtop", i, slit_x - dim_x/2);
15306 cpl_table_set(slits,
"ytop", i, slit_y);
15307 cpl_table_set(slits,
"xbottom", i, slit_x + dim_x/2);
15308 cpl_table_set(slits,
"ybottom", i, slit_y);
15309 cpl_table_set(slits,
"xwidth", i, dim_x);
15310 cpl_table_set(slits,
"ywidth", i, dim_y);
15311 cpl_table_set_int(slits,
"curved", i, curved);
15329 cpl_propertylist *sort;
15331 int i, multiplex, xprev, xcur;
15333 double tolerance = 1.0;
15343 sort = cpl_propertylist_new();
15344 cpl_propertylist_append_bool(sort,
"xtop", 0);
15345 cpl_table_sort(slits, sort);
15346 cpl_propertylist_delete(sort);
15348 prev = cpl_table_get_double(slits,
"xtop", 0, NULL);
15349 cpl_table_new_column(slits,
"xind", CPL_TYPE_INT);
15350 cpl_table_set_int(slits,
"xind", 0, prev);
15351 nrow = cpl_table_get_nrow(slits);
15352 for (i = 1; i < nrow; i++) {
15353 cur = cpl_table_get_double(slits,
"xtop", i, NULL);
15354 if (fabs(prev - cur) > tolerance)
15356 cpl_table_set_int(slits,
"xind", i, prev);
15364 sort = cpl_propertylist_new();
15365 cpl_propertylist_append_bool(sort,
"xind", 0);
15366 cpl_propertylist_append_bool(sort,
"ytop", 0);
15367 cpl_table_sort(slits, sort);
15368 cpl_propertylist_delete(sort);
15375 cpl_table_new_column(slits,
"multiplex", CPL_TYPE_INT);
15376 xprev = cpl_table_get_int(slits,
"xind", 0, NULL);
15377 cpl_table_set_int(slits,
"multiplex", 0, multiplex);
15378 nrow = cpl_table_get_nrow(slits);
15379 for (i = 1; i < nrow; i++) {
15380 xcur = cpl_table_get_int(slits,
"xind", i, NULL);
15381 if (xcur == xprev) {
15388 cpl_table_set_int(slits,
"multiplex", i, multiplex);
15391 cpl_table_save(slits, NULL, NULL,
"multiplex.fits", CPL_IO_DEFAULT);
15393 cpl_table_erase_column(slits,
"xind");
15395 return 1 + cpl_table_get_column_max(slits,
"multiplex");
15427 int check_consistency)
15429 const char *func =
"mos_load_overscans_vimos";
15440 cpl_table *overscans;
15443 if (cpl_error_get_code() != CPL_ERROR_NONE) {
15444 cpl_msg_error(func,
"Reset your error: %s", cpl_error_get_message());
15448 if (header == NULL) {
15449 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
15453 if (cpl_propertylist_has(header,
"NAXIS1"))
15454 nx = cpl_propertylist_get_int(header,
"NAXIS1");
15455 if (cpl_propertylist_has(header,
"NAXIS2"))
15456 ny = cpl_propertylist_get_int(header,
"NAXIS2");
15457 if (cpl_propertylist_has(header,
"ESO DET OUT1 PRSCX"))
15458 px = cpl_propertylist_get_int(header,
"ESO DET OUT1 PRSCX");
15459 if (cpl_propertylist_has(header,
"ESO DET OUT1 PRSCY"))
15460 py = cpl_propertylist_get_int(header,
"ESO DET OUT1 PRSCY");
15461 if (cpl_propertylist_has(header,
"ESO DET OUT1 OVSCX"))
15462 ox = cpl_propertylist_get_int(header,
"ESO DET OUT1 OVSCX");
15463 if (cpl_propertylist_has(header,
"ESO DET OUT1 OVSCY"))
15464 oy = cpl_propertylist_get_int(header,
"ESO DET OUT1 OVSCY");
15465 if (cpl_propertylist_has(header,
"ESO DET OUT1 NX"))
15466 vx = cpl_propertylist_get_int(header,
"ESO DET OUT1 NX");
15467 if (cpl_propertylist_has(header,
"ESO DET OUT1 NY"))
15468 vy = cpl_propertylist_get_int(header,
"ESO DET OUT1 NY");
15470 if (cpl_error_get_code() != CPL_ERROR_NONE) {
15471 cpl_msg_error(func,
"Missing overscan keywords in header");
15472 cpl_error_set_where(func);
15476 if (px < 0 || py < 0 || ox < 0 || oy < 0) {
15477 cpl_msg_error(func,
"Missing overscan keywords in header");
15478 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
15482 if ((px + vx + ox != nx) || (py + vy + oy != ny)) {
15483 if (check_consistency) {
15484 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
15488 cpl_msg_debug(func,
"Overscans description conflicts with "
15489 "reported image sizes, "
15490 "%d + %d + %d != %d or "
15491 "%d + %d + %d != %d",
15508 cpl_msg_error(func,
"Unexpected overscan regions "
15509 "(both in X and Y direction)");
15510 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
15522 overscans = cpl_table_new(nrows);
15523 cpl_table_new_column(overscans,
"xlow", CPL_TYPE_INT);
15524 cpl_table_new_column(overscans,
"ylow", CPL_TYPE_INT);
15525 cpl_table_new_column(overscans,
"xhig", CPL_TYPE_INT);
15526 cpl_table_new_column(overscans,
"yhig", CPL_TYPE_INT);
15530 cpl_table_set_int(overscans,
"xlow", nrows, px);
15531 cpl_table_set_int(overscans,
"ylow", nrows, py);
15532 cpl_table_set_int(overscans,
"xhig", nrows, nx - ox);
15533 cpl_table_set_int(overscans,
"yhig", nrows, ny - oy);
15537 cpl_table_set_int(overscans,
"xlow", nrows, 0);
15538 cpl_table_set_int(overscans,
"ylow", nrows, 0);
15539 cpl_table_set_int(overscans,
"xhig", nrows, px);
15540 cpl_table_set_int(overscans,
"yhig", nrows, ny);
15545 cpl_table_set_int(overscans,
"xlow", nrows, nx - ox);
15546 cpl_table_set_int(overscans,
"ylow", nrows, 0);
15547 cpl_table_set_int(overscans,
"xhig", nrows, nx);
15548 cpl_table_set_int(overscans,
"yhig", nrows, ny);
15553 cpl_table_set_int(overscans,
"xlow", nrows, 0);
15554 cpl_table_set_int(overscans,
"ylow", nrows, 0);
15555 cpl_table_set_int(overscans,
"xhig", nrows, nx);
15556 cpl_table_set_int(overscans,
"yhig", nrows, py);
15561 cpl_table_set_int(overscans,
"xlow", nrows, 0);
15562 cpl_table_set_int(overscans,
"ylow", nrows, ny - oy);
15563 cpl_table_set_int(overscans,
"xhig", nrows, nx);
15564 cpl_table_set_int(overscans,
"yhig", nrows, ny);
15573 cpl_table *mos_load_overscans_fors(
const cpl_propertylist *header)
15575 const char *func =
"mos_load_overscans_fors";
15586 cpl_table *overscans;
15589 if (cpl_error_get_code() != CPL_ERROR_NONE) {
15590 cpl_msg_error(func,
"Reset your error: %s", cpl_error_get_message());
15594 if (header == NULL) {
15595 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
15599 if (cpl_propertylist_has(header,
"ESO DET OUTPUTS"))
15600 nports = cpl_propertylist_get_int(header,
"ESO DET OUTPUTS");
15603 cpl_propertylist_has(header,
"ESO DET OUT1 PRSCX") &&
15604 cpl_propertylist_has(header,
"ESO DET WIN1 BINX")) {
15606 rebin = cpl_propertylist_get_int(header,
"ESO DET WIN1 BINX");
15608 overscans = cpl_table_new(3);
15609 cpl_table_new_column(overscans,
"xlow", CPL_TYPE_INT);
15610 cpl_table_new_column(overscans,
"ylow", CPL_TYPE_INT);
15611 cpl_table_new_column(overscans,
"xhig", CPL_TYPE_INT);
15612 cpl_table_new_column(overscans,
"yhig", CPL_TYPE_INT);
15620 cpl_table_set_int(overscans,
"xlow", nrows, px);
15621 cpl_table_set_int(overscans,
"ylow", nrows, py);
15622 cpl_table_set_int(overscans,
"xhig", nrows, nx - ox);
15623 cpl_table_set_int(overscans,
"yhig", nrows, ny - oy);
15626 cpl_table_set_int(overscans,
"xlow", nrows, 0);
15627 cpl_table_set_int(overscans,
"ylow", nrows, 0);
15628 cpl_table_set_int(overscans,
"xhig", nrows, px);
15629 cpl_table_set_int(overscans,
"yhig", nrows, ny);
15632 cpl_table_set_int(overscans,
"xlow", nrows, nx - ox);
15633 cpl_table_set_int(overscans,
"ylow", nrows, 0);
15634 cpl_table_set_int(overscans,
"xhig", nrows, nx);
15635 cpl_table_set_int(overscans,
"yhig", nrows, ny);
15680 cpl_polynomial *mos_montecarlo_polyfit(cpl_table *points, cpl_table *evaluate,
15681 int samples,
int order)
15684 const char *func =
"mos_montecarlo_polyfit";
15698 int npoints, nevaluate;
15702 if (points == NULL || evaluate == NULL) {
15703 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
15707 if (!cpl_table_has_column(points,
"x")) {
15708 cpl_error_set(func, CPL_ERROR_DATA_NOT_FOUND);
15712 if (cpl_table_get_column_type(points,
"x") != CPL_TYPE_DOUBLE) {
15713 cpl_error_set(func, CPL_ERROR_INVALID_TYPE);
15717 if (cpl_table_has_invalid(points,
"x")) {
15718 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
15722 if (!cpl_table_has_column(points,
"y")) {
15723 cpl_error_set(func, CPL_ERROR_DATA_NOT_FOUND);
15727 if (cpl_table_get_column_type(points,
"y") != CPL_TYPE_DOUBLE) {
15728 cpl_error_set(func, CPL_ERROR_INVALID_TYPE);
15732 if (cpl_table_has_invalid(points,
"y")) {
15733 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
15737 if (cpl_table_has_column(points,
"y_err")) {
15739 if (cpl_table_get_column_type(points,
"y_err") != CPL_TYPE_DOUBLE) {
15740 cpl_error_set(func, CPL_ERROR_INVALID_TYPE);
15744 if (cpl_table_has_invalid(points,
"y_err")) {
15745 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
15750 if (!cpl_table_has_column(evaluate,
"x")) {
15751 cpl_error_set(func, CPL_ERROR_DATA_NOT_FOUND);
15755 if (cpl_table_get_column_type(evaluate,
"x") != CPL_TYPE_DOUBLE) {
15756 cpl_error_set(func, CPL_ERROR_INVALID_TYPE);
15760 if (cpl_table_has_invalid(evaluate,
"x")) {
15761 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
15765 if (samples < 2 || order < 0) {
15766 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
15770 npoints = cpl_table_get_nrow(points);
15771 listx = cpl_vector_wrap(npoints, cpl_table_get_data_double(points,
"x"));
15772 listy = cpl_vector_wrap(npoints, cpl_table_get_data_double(points,
"y"));
15774 p = cpl_polynomial_fit_1d_create(listx, listy, order, &err);
15776 if (!cpl_table_has_column(points,
"y_err")) {
15778 cpl_table_new_column(points,
"y_err", CPL_TYPE_DOUBLE);
15779 cpl_table_fill_column_window_double(points,
"y_err", 0, npoints, err);
15780 cpl_msg_info(func,
"Error column not found - set to %f\n", err);
15787 if (cpl_table_has_column(points,
"px"))
15788 cpl_table_erase_column(points,
"px");
15789 cpl_table_new_column(points,
"px", CPL_TYPE_DOUBLE);
15790 cpl_table_fill_column_window_double(points,
"px", 0, npoints, 0);
15791 x = cpl_table_get_data_double(points,
"x");
15792 px = cpl_table_get_data_double(points,
"px");
15793 for (i = 0; i < npoints; i++)
15794 px[i] = cpl_polynomial_eval_1d(p, x[i], NULL);
15796 nevaluate = cpl_table_get_nrow(evaluate);
15798 if (cpl_table_has_column(evaluate,
"px"))
15799 cpl_table_erase_column(evaluate,
"px");
15800 cpl_table_new_column(evaluate,
"px", CPL_TYPE_DOUBLE);
15801 cpl_table_fill_column_window_double(evaluate,
"px", 0, nevaluate, 0);
15802 x_eval = cpl_table_get_data_double(evaluate,
"x");
15803 px_eval = cpl_table_get_data_double(evaluate,
"px");
15804 for (i = 0; i < nevaluate; i++)
15805 px_eval[i] = cpl_polynomial_eval_1d(p, x_eval[i], NULL);
15811 if (cpl_table_has_column(evaluate,
"sigma"))
15812 cpl_table_erase_column(evaluate,
"sigma");
15813 cpl_table_new_column(evaluate,
"sigma", CPL_TYPE_DOUBLE);
15814 cpl_table_fill_column_window_double(evaluate,
"sigma", 0, nevaluate, 0);
15815 sigma = cpl_table_get_data_double(evaluate,
"sigma");
15821 if (cpl_table_has_column(points,
"vy"))
15822 cpl_table_erase_column(points,
"vy");
15823 cpl_table_new_column(points,
"vy", CPL_TYPE_DOUBLE);
15824 cpl_table_fill_column_window_double(points,
"vy", 0, npoints, 0);
15825 vy = cpl_table_get_data_double(points,
"vy");
15826 dy = cpl_table_get_data_double(points,
"y_err");
15827 cpl_vector_unwrap(listy);
15828 listy = cpl_vector_wrap(npoints, vy);
15830 for (i = 0; i < samples; i++) {
15831 for (j = 0; j < npoints; j++)
15832 vy[j] = px[j] + dy[j] * mos_randg(1);
15833 q = cpl_polynomial_fit_1d_create(listx, listy, order, NULL);
15834 for (j = 0; j < nevaluate; j++)
15835 sigma[j] += fabs(px_eval[j]
15836 - cpl_polynomial_eval_1d(q, x_eval[j], NULL));
15837 cpl_polynomial_delete(q);
15844 cpl_table_multiply_scalar(evaluate,
"sigma", 1.25);
15845 cpl_table_divide_scalar(evaluate,
"sigma", samples);
15847 cpl_vector_unwrap(listx);
15848 cpl_vector_unwrap(listy);
15878 double gain,
double bias)
15885 return cpl_error_set(cpl_func, CPL_ERROR_NULL_INPUT);
15887 if (ron < 0.0 || gain <= FLT_EPSILON)
15888 return cpl_error_set(cpl_func, CPL_ERROR_ILLEGAL_INPUT);
15890 data = cpl_image_get_data_float(image);
15891 npix = cpl_image_get_size_x(image) * cpl_image_get_size_y(image);
15894 for (i = 0; i < npix; i++) {
15895 if (data[i] < bias) {
15896 data[i] += sqrt(ron) * mos_randg(1);
15899 data[i] += sqrt(ron + (data[i] - bias) / gain) * mos_randg(1);
15903 return CPL_ERROR_NONE;
15922 cpl_image *master_flat,
15925 int nx = cpl_mask_get_size_x(refmask);
15926 int ny = cpl_mask_get_size_y(refmask);
15928 int * xpos = cpl_calloc(
sizeof(
int), ny);
15930 cpl_image * filtered = cpl_image_duplicate(master_flat);
15931 cpl_mask * kernel = cpl_mask_new(9, 3);
15932 cpl_vector * v = cpl_vector_new(ny);
15933 cpl_vector * truev;
15935 double * flats = cpl_vector_get_data(v);
15937 double median, stdev, delta;
15941 cpl_mask_not(kernel);
15942 cpl_image_filter_mask(filtered, master_flat, kernel,
15943 CPL_FILTER_MEDIAN, CPL_BORDER_COPY);
15944 cpl_mask_delete(kernel);
15946 for (i = 1; i <= ny; i++) {
15950 while (!cpl_mask_get(refmask, j, i) && j < nx);
15956 flats[nvalid] = cpl_image_get(filtered, j, i, &rejected);
15965 return cpl_error_set(cpl_func, CPL_ERROR_DATA_NOT_FOUND);
15967 truev = cpl_vector_wrap(nvalid, flats);
15969 median = cpl_vector_get_median(truev);
15972 stdev = cpl_vector_get_stdev(truev);
15974 cpl_vector_unwrap(truev);
15975 cpl_vector_delete(v);
15977 for (i = 1; i <= ny; i++) {
15978 if (xpos[i - 1] > 0) {
15980 double kappa = 1.5;
15982 delta = cpl_image_get(filtered, xpos[i - 1], i, &rejected) - median;
15985 kill = fabs(delta) > stdev * kappa;
15987 kill = delta < level;
15992 while (cpl_mask_get(refmask, xpos[i - 1] + j, i)) {
15993 cpl_mask_set(refmask, xpos[i - 1] + j, i, CPL_BINARY_0);
16000 cpl_image_delete(filtered);
16003 return cpl_error_get_code();
16015 int nx = cpl_image_get_size_x(image);
16016 int ny = cpl_image_get_size_y(image);
16017 int npix = nx * ny;
16018 float * sdata = cpl_image_get_data_float(image);
16020 int count, i, j, k;
16028 for (i = 0; i < npix - nx; i++)
16029 if (sdata[i] == 0.0 && sdata[i + nx] == 0.0)
16030 sdata[i] = 65535.0;
16032 for (i = npix - nx; i < npix; i++)
16033 if (sdata[i] == 0.0)
16034 sdata[i] = 65535.0;
16042 for (i = 0; i < npix; i++) {
16043 if (sdata[i] >= 65535.0) {
16045 for (j = i; j < npix; j++) {
16046 if (sdata[j] < 65535.0) {
16053 if (count < 30 && count > 2) {
16054 for (j = i; j < i + count/2; j++)
16055 sdata[j] = sdata[i] + 1000.0 * (j - i);
16056 if (count % 2 != 0) {
16057 sdata[j] = sdata[j-1] + 1000.0;
16060 for (k = j; k <= i + count; k++)
16061 sdata[k] = sdata[i] - 1000.0 * (k - i - count);
16067 return cpl_error_get_code();
16086 cpl_image_subtract(image, bimage);
16087 cpl_image_delete(bimage);
16089 return cpl_error_get_code();
16110 int nscience,
float tolerance)
16114 cpl_table *summary;
16115 int summary_nobjs = 0;
16120 int nslits = cpl_table_get_nrow(slitss[0]);
16124 int nstokes, sstokes;
16128 work = (cpl_table **)cpl_malloc(
sizeof(cpl_table *) * nscience);
16139 for (j = 0; j < nscience; j++) {
16142 return cpl_error_set(cpl_func, CPL_ERROR_DATA_NOT_FOUND);
16143 summary_nobjs += c_nobjs;
16146 summary = cpl_table_new(summary_nobjs);
16148 cpl_table_new_column(summary,
"offset", CPL_TYPE_DOUBLE);
16149 cpl_table_new_column(summary,
"pair", CPL_TYPE_INT);
16150 cpl_table_new_column(summary,
"absolute", CPL_TYPE_DOUBLE);
16151 cpl_table_new_column(summary,
"pos", CPL_TYPE_DOUBLE);
16160 for (j = 0; j < nscience; j++) {
16164 for (k = 0; k < nslits; k++) {
16167 for (m = 0; m < c_maxobjs; m++) {
16169 char *name = cpl_sprintf(
"object_%d", m + 1);
16170 double obj = cpl_table_get_double(slitss[j], name, k, &null);
16186 pos = cpl_table_get_int(slitss[j],
"position", k, &null);
16187 pair = cpl_table_get_int(slitss[j],
"pair_id", k, &null);
16188 cpl_table_set(summary,
"absolute", nobjs, obj);
16189 cpl_table_set(summary,
"pos", nobjs, pos);
16190 cpl_table_set(summary,
"offset", nobjs, obj - pos);
16191 cpl_table_set(summary,
"pair", nobjs, pair);
16221 for (k = 0; k < nslits; k+=2) {
16222 int slitmatches = 0;
16224 if (k + 1 < nslits ) {
16225 if (cpl_table_get_int(slitss[0],
"pair_id", k, NULL) !=
16226 cpl_table_get_int(slitss[0],
"pair_id", k + 1, NULL)) {
16239 for (m = 0; m < maxobjs; m++) {
16241 char *name = cpl_sprintf(
"object_%d", m + 1);
16242 double obj = cpl_table_get_double(slitss[0], name, k, &null);
16246 char *name_obj = NULL;
16247 char *name_start = NULL;
16248 char *name_end = NULL;
16249 char *name_row = NULL;
16250 char *name_row_s = NULL;
16252 char *name_start_o = NULL;
16253 char *name_end_o = NULL;
16254 char *name_row_o = NULL;
16255 char *name_start_v = NULL;
16256 char *name_end_v = NULL;
16257 char *name_obj_v = NULL;
16263 int v, start_v, end_v;
16264 double min_v, obj_v;
16279 pos = cpl_table_get_int(slitss[0],
"position", k, &null);
16280 pair = cpl_table_get_int(slitss[0],
"pair_id", k, &null);
16289 cpl_table_select_all(summary);
16291 cpl_table_and_selected_int(summary,
"pair", CPL_EQUAL_TO, pair);
16292 cpl_table_and_selected_double(summary,
"offset", CPL_LESS_THAN,
16293 obj - pos + tolerance);
16295 cpl_table_and_selected_double(summary,
"offset", CPL_GREATER_THAN,
16296 obj - pos - tolerance);
16306 if (selected != nscience * 2)
16327 name_obj = cpl_sprintf(
"object_%d", slitmatches);
16328 name_start = cpl_sprintf(
"start_%d", slitmatches);
16329 name_end = cpl_sprintf(
"end_%d", slitmatches);
16330 name_row = cpl_sprintf(
"row_%d", slitmatches);
16331 name_row_s = cpl_sprintf(
"row_stokes_%d", slitmatches);
16338 name_start_o = cpl_sprintf(
"start_%d", m + 1);
16339 name_end_o = cpl_sprintf(
"end_%d", m + 1);
16340 name_row_o = cpl_sprintf(
"row_%d", m + 1);
16346 if (!cpl_table_has_column(origslits, name_obj)) {
16347 cpl_table_new_column(origslits, name_obj, CPL_TYPE_DOUBLE);
16348 cpl_table_new_column(origslits, name_start, CPL_TYPE_INT);
16349 cpl_table_new_column(origslits, name_end, CPL_TYPE_INT);
16350 cpl_table_new_column(origslits, name_row, CPL_TYPE_INT);
16351 cpl_table_new_column(origslits, name_row_s, CPL_TYPE_INT);
16361 length = cpl_table_get_int(origslits,
"length", k + 1, &null);
16369 for (v = 0; v < maxobjs; v++) {
16370 char *name_v = cpl_sprintf(
"object_%d", v + 1);
16371 double obj_v = cpl_table_get_double(slitss[0], name_v,
16380 if (fabs(obj - length - obj_v) < min_v) {
16381 min_v = fabs(obj - length - obj_v);
16382 cpl_free(name_start_v);
16383 cpl_free(name_end_v);
16384 cpl_free(name_obj_v);
16385 name_start_v = cpl_sprintf(
"start_%d", v + 1);
16386 name_end_v = cpl_sprintf(
"end_%d", v + 1);
16387 name_obj_v = cpl_sprintf(
"object_%d", v + 1);
16391 min_v = fabs(obj - length - obj_v);
16392 name_start_v = cpl_sprintf(
"start_%d", v + 1);
16393 name_end_v = cpl_sprintf(
"end_%d", v + 1);
16394 name_obj_v = cpl_sprintf(
"object_%d", v + 1);
16403 start = cpl_table_get_int(slitss[0], name_start_o, k, &null);
16404 end = cpl_table_get_int(slitss[0], name_end_o, k, &null);
16410 start_v = cpl_table_get_int(slitss[0], name_start_v, k + 1, &null);
16411 end_v = cpl_table_get_int(slitss[0], name_end_v, k + 1, &null);
16412 obj_v = cpl_table_get_double(slitss[0], name_obj_v, k + 1, &null);
16423 cpl_table_set_double(origslits, name_obj, k, obj);
16424 cpl_table_set_double(origslits, name_obj, k + 1, obj_v);
16427 cpl_table_set_int(origslits, name_start, k, start);
16428 cpl_table_set_int(origslits, name_start, k + 1, start_v);
16431 cpl_table_set_int(origslits, name_end, k, end);
16432 cpl_table_set_int(origslits, name_end, k + 1, end_v);
16447 cpl_table_set_int(origslits, name_row, k, nmatches);
16449 cpl_table_set_int(origslits, name_row, k + 1, nmatches);
16452 cpl_free(name_obj);
16453 cpl_free(name_start);
16454 cpl_free(name_end);
16455 cpl_free(name_row);
16456 cpl_free(name_row_s);
16458 cpl_free(name_start_o);
16459 cpl_free(name_end_o);
16460 cpl_free(name_row_o);
16462 cpl_free(name_start_v); name_start_v = NULL;
16463 cpl_free(name_end_v); name_end_v = NULL;
16464 cpl_free(name_obj_v); name_obj_v = NULL;
16473 cpl_table_delete(summary);
16476 return cpl_error_set(cpl_func, CPL_ERROR_DATA_NOT_FOUND);
16489 nstokes = nmatches / 2;
16491 for (k = 0; k < nslits; k++) {
16499 for (m = 0; m < maxobjs; m++) {
16500 char *name = cpl_sprintf(
"row_%d", m + 1);
16501 char *namestokes = cpl_sprintf(
"row_stokes_%d", m + 1);
16503 if (!cpl_table_is_valid(origslits, name, k)) {
16505 cpl_free(namestokes);
16511 cpl_table_set_int(origslits, name, k, nmatches);
16512 cpl_table_set_int(origslits, namestokes, k, nstokes);
16516 cpl_free(namestokes);
16528 for (j = 0; j < maxobjs; j++) {
16529 char *name = cpl_sprintf(
"object_%d", j + 1);
16530 cpl_table_fill_invalid_double(origslits, name, -1);
16533 name = cpl_sprintf(
"start_%d", j + 1);
16534 cpl_table_fill_invalid_int(origslits, name, -1);
16537 name = cpl_sprintf(
"end_%d", j + 1);
16538 cpl_table_fill_invalid_int(origslits, name, -1);
16541 name = cpl_sprintf(
"row_%d", j + 1);
16542 cpl_table_fill_invalid_int(origslits, name, -1);
16545 name = cpl_sprintf(
"row_stokes_%d", j + 1);
16546 cpl_table_fill_invalid_int(origslits, name, -1);
16561 for (i = 0; i < nscience; i++) {
16564 work[i] = cpl_table_duplicate(slitss[i]);
16566 for (m = 0; m < c_maxobjs; m++) {
16567 char *object_o = cpl_sprintf(
"object_%d", m + 1);
16568 char *start_o = cpl_sprintf(
"start_%d", m + 1);
16569 char *end_o = cpl_sprintf(
"end_%d", m + 1);
16570 char *row_o = cpl_sprintf(
"row_%d", m + 1);
16572 cpl_table_erase_column(slitss[i], object_o);
16573 cpl_table_erase_column(slitss[i], start_o);
16574 cpl_table_erase_column(slitss[i], end_o);
16575 cpl_table_erase_column(slitss[i], row_o);
16583 for (k = 0; k < nslits; k++) {
16584 for (j = 0; j < maxobjs; j++) {
16585 double object_w, object_r;
16588 char *object_i = cpl_sprintf(
"object_%d", j + 1);
16589 char *start_i = cpl_sprintf(
"start_%d", j + 1);
16590 char *end_i = cpl_sprintf(
"end_%d", j + 1);
16591 char *row_i = cpl_sprintf(
"row_%d", j + 1);
16594 if (!cpl_table_is_valid(origslits, object_i, k))
16607 object_w = cpl_table_get_double(origslits, object_i, k, NULL);
16608 row_w = cpl_table_get_int (origslits, row_i, k, NULL);
16610 for (i = 0; i < nscience; i++) {
16613 double mindiff, diff;
16619 for (m = 0; m < c_maxobjs; m++) {
16620 object_o = cpl_sprintf(
"object_%d", m + 1);
16621 start_o = cpl_sprintf(
"start_%d", m + 1);
16622 end_o = cpl_sprintf(
"end_%d", m + 1);
16623 row_o = cpl_sprintf(
"row_%d", m + 1);
16625 if (!cpl_table_is_valid(work[i], object_o, k))
16628 object_r = cpl_table_get_double(work[i], object_o, k, NULL);
16631 diff = fabs(object_w - object_r);
16633 if (mindiff > diff) {
16643 cpl_free(object_o);
16649 object_o = cpl_sprintf(
"object_%d", minpos + 1);
16650 start_o = cpl_sprintf(
"start_%d", minpos + 1);
16651 end_o = cpl_sprintf(
"end_%d", minpos + 1);
16652 row_o = cpl_sprintf(
"row_%d", minpos + 1);
16654 if (!cpl_table_has_column(slitss[i], object_i)) {
16655 cpl_table_new_column(slitss[i], object_i, CPL_TYPE_DOUBLE);
16656 cpl_table_new_column(slitss[i], start_i, CPL_TYPE_INT);
16657 cpl_table_new_column(slitss[i], end_i, CPL_TYPE_INT);
16658 cpl_table_new_column(slitss[i], row_i, CPL_TYPE_INT);
16659 cpl_table_fill_invalid_double(slitss[i], object_i, -1);
16660 cpl_table_fill_invalid_int (slitss[i], start_i, -1);
16661 cpl_table_fill_invalid_int (slitss[i], end_i, -1);
16662 cpl_table_fill_invalid_int (slitss[i], row_i, -1);
16665 cpl_table_set_double(slitss[i], object_i, k,
16666 cpl_table_get_double(work[i], object_o,
16668 cpl_table_set_int(slitss[i], start_i , k,
16669 cpl_table_get_int(work[i], start_o, k, NULL));
16670 cpl_table_set_int(slitss[i], end_i , k,
16671 cpl_table_get_int(work[i], end_o, k, NULL));
16672 cpl_table_set_int(slitss[i], row_i , k, row_w);
16674 cpl_free(object_o);
16680 cpl_free(object_i);
16687 for (i = 0; i < nscience; i++)
16688 cpl_table_delete(work[i]);
16693 return cpl_error_get_code();
16708 char * colname = cpl_sprintf(
"object_%d", maxobjs);
16710 while (cpl_table_has_column(slits, colname)) {
16713 colname = cpl_sprintf(
"object_%d", maxobjs);
16734 int nslits = cpl_table_get_nrow(slits);
16739 for (k = 0; k < nslits; k++) {
16740 for (m = 0; m < maxobjs; m++) {
16741 char * name = cpl_sprintf(
"object_%d", m + 1);
16742 int null = !cpl_table_is_valid(slits, name, k);
16764 cpl_propertylist *sort;
16766 int nslits = cpl_table_get_nrow(slits);
16770 const float interval = 90.0 * rescale;
16771 const float offset = (90.0 - 5) * rescale;
16774 for (k = 0; k < nslits; k++) {
16775 double ytop = cpl_table_get_double(slits,
"ytop", k, &null);
16776 double ybottom = cpl_table_get_double(slits,
"ybottom", k, &null);
16778 double xtop = cpl_table_get_double(slits,
"xtop", k, &null);
16779 double xbottom = cpl_table_get_double(slits,
"xbottom", k, &null);
16781 int nmiss = (int)((ytop - ybottom) / interval + 0.5);
16784 cpl_msg_warning(cpl_func,
16785 "Some slits could not be properly detected. "
16786 "There might be accountable inaccuracies.");
16787 while (nmiss > 1) {
16788 cpl_table_set_size(slits, nslits + 1);
16793 cpl_table_set_double(slits,
"xtop", nslits, xtop);
16794 cpl_table_set_double(slits,
"xbottom", nslits, xbottom);
16798 cpl_table_set_double(slits,
"ybottom", nslits, ybottom);
16799 cpl_table_set_double(slits,
"ytop", nslits, ybottom
16801 ybottom += interval;
16802 cpl_table_set_double(slits,
"ybottom", k, ybottom);
16804 cpl_table_set_double(slits,
"ytop", nslits, ytop);
16805 cpl_table_set_double(slits,
"ybottom", nslits, ytop
16808 cpl_table_set_double(slits,
"ytop", k, ytop);
16816 sort = cpl_propertylist_new();
16817 cpl_propertylist_append_bool(sort,
"ytop", 1);
16818 cpl_table_sort(slits, sort);
16819 cpl_propertylist_delete(sort);
16826 k = cpl_table_get_nrow(slits) - 1;
16829 double ytop = cpl_table_get_double(slits,
"ytop", k, &null);
16830 double ybottom = cpl_table_get_double(slits,
"ybottom", k, &null);
16831 double length = (ytop - ybottom) / interval;
16833 if (length > 1.1) {
16834 cpl_table_set_double(slits,
"ybottom", k, ytop - offset);
16865 int * nslits_out_det)
16870 cpl_propertylist * sort;
16874 halfsize = cpl_table_get_nrow(slits);
16876 cpl_table_set_size(slits, 2 * halfsize);
16878 for (m = 0; m < halfsize; m++) {
16883 cpl_table_get(slits,
"ytop", m, &null) -
16884 cpl_table_get(slits,
"ybottom", m, &null);
16888 cpl_table_get(slits,
"ybottom", m - 1, &null) -
16889 cpl_table_get(slits,
"ytop", m, &null);
16891 gap = (interval - length) / 2;
16894 cpl_table_set(slits,
"slit_id", m + halfsize,
16895 cpl_table_get(slits,
"slit_id", m, &null) - 1);
16897 cpl_table_set(slits,
"xtop", m + halfsize,
16898 cpl_table_get(slits,
"xtop", m, &null));
16900 cpl_table_set(slits,
"xbottom", m + halfsize,
16901 cpl_table_get(slits,
"xbottom", m, &null));
16903 cpl_table_set(slits,
"ytop", m + halfsize,
16904 cpl_table_get(slits,
"ytop", m, &null) + gap + length);
16906 cpl_table_set(slits,
"ybottom", m + halfsize,
16907 cpl_table_get(slits,
"ytop", m, &null) + gap);
16910 for (m = 0; m < 2 * halfsize; m++) {
16911 cpl_table_set(slits,
"ytop", m,
16912 cpl_table_get(slits,
"ytop", m, &null) - 5.3);
16914 cpl_table_set(slits,
"ybottom", m,
16915 cpl_table_get(slits,
"ybottom", m, &null) - 5.3);
16919 sort = cpl_propertylist_new();
16920 cpl_propertylist_append_bool(sort,
"ytop", 1);
16921 cpl_table_sort(slits, sort);
16923 cpl_propertylist_delete(sort);
16928 int * fors_get_nobjs_perslit(cpl_table * slits)
16930 int nslits = cpl_table_get_nrow(slits);
16933 int * nobjs_per_slit = cpl_malloc(
sizeof(
int) * nslits);
16937 for (k = 0; k < nslits; k++) {
16939 for (m = 0; m < maxobjs; m++) {
16940 char * name = cpl_sprintf(
"object_%d", m + 1);
16941 int null = !cpl_table_is_valid(slits, name, k);
16949 nobjs_per_slit[k] = nobjs;
16952 return nobjs_per_slit;
16955 double fors_get_object_position(cpl_table *slits,
int slit,
int object)
16957 char *name = cpl_sprintf(
"object_%d",
object);
16960 position = cpl_table_get_double(slits, name, slit, NULL)
16961 - cpl_table_get_int(slits,
"position", slit, NULL);
16968 int mos_rebin_signal(cpl_image **image,
int rebin)
16970 cpl_image *rebinned;
16973 if (*image == NULL)
16979 rebinned = cpl_image_rebin(*image, 1, 1, rebin, 1);
16981 cpl_image_delete(*image);
16988 int mos_rebin_error(cpl_image **image,
int rebin)
16990 if (*image == NULL)
16996 cpl_image_power(*image, 2);
16997 mos_rebin_signal(image, rebin);
16998 cpl_image_power(*image, 0.5);
17020 int map_table(cpl_image *image,
double start,
double step,
17021 cpl_table *table,
char *xname,
char *yname)
17023 int length = cpl_image_get_size_x(image);
17024 int nrows = cpl_table_get_nrow(table);
17025 float *data = cpl_image_get_data_float(image);
17026 float *fdata = NULL;
17027 double *xdata = NULL;
17028 double *ydata = NULL;
17029 cpl_type xtype = cpl_table_get_column_type(table, xname);
17030 cpl_type ytype = cpl_table_get_column_type(table, yname);
17040 for (i = 0; i < length; i++)
17048 if (xtype == CPL_TYPE_FLOAT) {
17049 fdata = cpl_table_get_data_float(table, xname);
17050 xdata = cpl_malloc(nrows *
sizeof(
double));
17051 for (i = 0; i < nrows; i++) {
17052 xdata[i] = fdata[i];
17056 xdata = cpl_table_get_data_double(table, xname);
17059 if (ytype == CPL_TYPE_FLOAT) {
17060 fdata = cpl_table_get_data_float(table, yname);
17061 ydata = cpl_malloc(nrows *
sizeof(
double));
17062 for (i = 0; i < nrows; i++) {
17063 ydata[i] = fdata[i];
17067 ydata = cpl_table_get_data_double(table, yname);
17077 for (i = 0; i < length; i++) {
17078 pos = start + step * i;
17081 for (j = n; j < nrows; j++) {
17082 if (xdata[j] > pos) {
17084 data[i] = ydata[j-1]
17085 + (ydata[j] - ydata[j-1])
17086 * (pos - xdata[j-1]) / (xdata[j] - xdata[j-1]);
17092 if (xtype == CPL_TYPE_FLOAT)
17095 if (ytype == CPL_TYPE_FLOAT)
17115 static cpl_image *polysmooth(cpl_image *image,
int order,
int hw)
17122 cpl_polynomial *poly;
17123 cpl_vector *ysmooth;
17124 cpl_image *smoothed;
17129 npoints = cpl_image_get_size_x(image);
17131 if (2 * hw + 1 > npoints)
17134 x = cpl_vector_new(npoints);
17135 y = cpl_vector_new(npoints);
17136 xdata = cpl_vector_get_data(x);
17137 ydata = cpl_vector_get_data(y);
17139 smoothed = cpl_image_duplicate(image);
17140 sdata = cpl_image_get_data_float(smoothed);
17142 for (i = 0; i < npoints; i++) {
17144 ydata[i] = sdata[i];
17147 ysmooth = cpl_vector_filter_median_create(y, hw);
17148 cpl_vector_delete(y);
17150 poly = cpl_polynomial_fit_1d_create(x, ysmooth, order, NULL);
17151 cpl_vector_delete(x);
17152 cpl_vector_delete(ysmooth);
17155 for (i = 0; i < npoints; i++)
17156 sdata[i] = cpl_polynomial_eval_1d(poly, i, NULL);
17158 cpl_polynomial_delete(poly);
17161 cpl_image_delete(smoothed);
17171 cpl_image_delete(spectrum); \
17172 cpl_image_delete(flux); \
17173 cpl_image_delete(efficiency); \
17174 cpl_image_delete(smo_efficiency); \
17175 cpl_image_delete(extinction); \
17176 cpl_image_delete(response); \
17177 cpl_image_delete(smo_response); \
17178 cpl_image_delete(physical); \
17205 double dispersion,
double gain,
17206 double exptime, cpl_table *ext_table,
17207 double airmass, cpl_table *flux_table,
17211 cpl_image *spectrum = NULL;
17213 cpl_image *extinction = NULL;
17215 cpl_image *flux = NULL;
17217 cpl_image *physical = NULL;
17219 cpl_image *efficiency = NULL;
17221 cpl_image *smo_efficiency = NULL;
17222 float *smo_eff_data;
17223 cpl_image *response = NULL;
17225 cpl_image *smo_response = NULL;
17226 float *smo_res_data;
17228 cpl_image *smo_image;
17232 int ext_count, ext_pos;
17233 int eff_count, eff_pos;
17234 int flux_count, flux_pos;
17239 if (spectra == NULL || ext_table == NULL || flux_table == NULL) {
17240 cpl_error_set(cpl_func, CPL_ERROR_NULL_INPUT);
17244 if (!cpl_table_has_column(ext_table,
"WAVE")) {
17245 cpl_error_set_message(cpl_func, CPL_ERROR_DATA_NOT_FOUND,
17246 "Column WAVE in atmospheric extinction table");
17250 if (!cpl_table_has_column(ext_table,
"EXTINCTION")) {
17251 cpl_error_set_message(cpl_func, CPL_ERROR_DATA_NOT_FOUND,
17252 "Column EXTINCTION in atmospheric extinction table");
17256 if (!cpl_table_has_column(flux_table,
"WAVE")) {
17257 cpl_error_set_message(cpl_func, CPL_ERROR_DATA_NOT_FOUND,
17258 "Column WAVE in standard star flux table");
17262 if (!cpl_table_has_column(flux_table,
"FLUX")) {
17263 cpl_error_set_message(cpl_func, CPL_ERROR_DATA_NOT_FOUND,
17264 "Column FLUX in standard star flux table");
17269 cpl_error_set_message(cpl_func, CPL_ERROR_ILLEGAL_INPUT,
17270 "Invalid gain factor (%.2f)", gain);
17274 if (exptime < 0.001) {
17275 cpl_error_set_message(cpl_func, CPL_ERROR_ILLEGAL_INPUT,
17276 "Invalid exposure time (%.2f)", exptime);
17280 if (dispersion < 0.001) {
17281 cpl_error_set_message(cpl_func, CPL_ERROR_ILLEGAL_INPUT,
17282 "Invalid dispersion (%.2f)", dispersion);
17287 cpl_error_set_message(cpl_func, CPL_ERROR_ILLEGAL_INPUT,
17288 "Order of the polynomial fitting the "
17289 "instrument response must be at least 2");
17293 nx = cpl_image_get_size_x(spectra);
17294 ny = cpl_image_get_size_y(spectra);
17302 spectrum = cpl_image_duplicate(spectra);
17306 cpl_image *brights = cpl_image_collapse_create(spectra, 1);
17308 cpl_image_get_maxpos(brights, &x, &y);
17309 cpl_image_delete(brights);
17310 spectrum = cpl_image_extract(spectra, 1, y, nx, y);
17318 cpl_image_multiply_scalar(spectrum, gain / exptime / dispersion);
17326 extinction = cpl_image_duplicate(spectrum);
17327 map_table(extinction, startwave + dispersion/2, dispersion,
17328 ext_table,
"WAVE",
"EXTINCTION");
17335 cpl_image_multiply_scalar(extinction, 0.4 * airmass);
17336 cpl_image_exponential(extinction, 10.);
17343 cpl_image_multiply(spectrum, extinction);
17351 ext_data = cpl_image_get_data_float(extinction);
17355 for (i = 0; i < nx; i++) {
17356 if (ext_data[i] > 0.0) {
17357 if (ext_count == 0) {
17369 cpl_image_delete(extinction); extinction = NULL;
17377 flux = cpl_image_duplicate(spectrum);
17378 map_table(flux, startwave + dispersion/2, dispersion,
17379 flux_table,
"WAVE",
"FLUX");
17387 flux_data = cpl_image_get_data_float(flux);
17391 for (i = 0; i < nx; i++) {
17392 if (flux_data[i] > 0.0) {
17393 if (flux_count == 0) {
17410 start = ext_pos > flux_pos ? ext_pos : flux_pos;
17411 end = (ext_pos + ext_count) < (flux_pos + flux_count) ?
17412 (ext_pos + ext_count) : (flux_pos + flux_count);
17414 flux_count = end - start;
17425 physical = cpl_image_duplicate(spectrum);
17426 phys_data = cpl_image_get_data_float(physical);
17428 for (i = 0; i < nx; i++) {
17429 lambda = startwave + dispersion * (i + 0.5);
17430 phys_data[i] = 0.0026 * lambda * flux_data[i];
17433 efficiency = cpl_image_duplicate(spectrum);
17434 eff_data = cpl_image_get_data_float(efficiency);
17435 data = cpl_image_get_data_float(spectrum);
17437 for (i = 0; i < nx; i++) {
17438 if (phys_data[i] > 0.0)
17439 eff_data[i] = data[i] / phys_data[i];
17444 cpl_image_delete(physical); physical = NULL;
17454 for (i = 0; i < nx; i++) {
17455 if (eff_data[i] > 0.01) {
17456 if (eff_count == 0) {
17462 if (eff_count > 300) {
17473 start = eff_pos > flux_pos ? eff_pos : flux_pos;
17474 end = (eff_pos + eff_count) < (flux_pos + flux_count) ?
17475 (eff_pos + eff_count) : (flux_pos + flux_count);
17477 eff_count = end - start;
17479 if (eff_count < 1) {
17480 cpl_error_set_message(cpl_func, CPL_ERROR_INCOMPATIBLE_INPUT,
17481 "No overlap between catalog and spectrum");
17491 image = cpl_image_extract(efficiency, eff_pos + 1, 1,
17492 eff_pos + eff_count, 1);
17494 smo_image = polysmooth(image, order, 50);
17495 cpl_image_delete(image);
17497 smo_efficiency = cpl_image_duplicate(efficiency);
17498 smo_eff_data = cpl_image_get_data_float(smo_efficiency);
17499 cpl_image_copy(smo_efficiency, smo_image, eff_pos + 1, 1);
17501 cpl_image_delete(smo_image);
17512 response = cpl_image_duplicate(spectrum);
17513 res_data = cpl_image_get_data_float(response);
17515 for (i = 0; i < nx; i++) {
17516 if (eff_data[i] > 0.01 && flux_data[i] > 0.0)
17517 res_data[i] = data[i] / flux_data[i];
17527 image = cpl_image_extract(response, eff_pos + 1, 1, eff_pos + eff_count, 1);
17529 smo_image = polysmooth(image, order, 50);
17530 cpl_image_delete(image);
17532 smo_response = cpl_image_duplicate(response);
17533 smo_res_data = cpl_image_get_data_float(smo_response);
17534 cpl_image_copy(smo_response, smo_image, eff_pos + 1, 1);
17536 cpl_image_delete(smo_image);
17538 for (i = 0; i < nx; i++) {
17539 if (eff_data[i] > 0.01) {
17540 res_data[i] = 1 / res_data[i];
17541 smo_res_data[i] = 1 / smo_res_data[i];
17545 smo_res_data[i] = 0.0;
17554 table = cpl_table_new(nx);
17556 cpl_table_new_column(table,
"WAVE", CPL_TYPE_FLOAT);
17557 cpl_table_set_column_unit(table,
"WAVE",
"Angstrom");
17559 for (i = 0; i < nx; i++)
17560 cpl_table_set_float(table,
"WAVE", i, startwave + dispersion*(i+0.5));
17562 cpl_table_new_column(table,
"STD_FLUX", CPL_TYPE_FLOAT);
17563 cpl_table_set_column_unit(table,
"STD_FLUX",
17564 "10^(-16) erg/(cm^2 s Angstrom)");
17565 cpl_table_copy_data_float(table,
"STD_FLUX", flux_data);
17566 cpl_image_delete(flux); flux = NULL;
17568 cpl_table_new_column(table,
"OBS_FLUX", CPL_TYPE_FLOAT);
17569 cpl_table_set_column_unit(table,
"OBS_FLUX",
"electron/(s Angstrom)");
17570 cpl_table_copy_data_float(table,
"OBS_FLUX", data);
17571 cpl_image_delete(spectrum); spectrum = NULL;
17573 cpl_table_new_column(table,
"RAW_EFFICIENCY", CPL_TYPE_FLOAT);
17574 cpl_table_set_column_unit(table,
"RAW_EFFICIENCY",
"electron/photon");
17575 cpl_table_copy_data_float(table,
"RAW_EFFICIENCY", eff_data);
17576 cpl_image_delete(efficiency); efficiency = NULL;
17578 cpl_table_new_column(table,
"EFFICIENCY", CPL_TYPE_FLOAT);
17579 cpl_table_set_column_unit(table,
"EFFICIENCY",
"electron/photon");
17580 cpl_table_copy_data_float(table,
"EFFICIENCY", smo_eff_data);
17581 cpl_image_delete(smo_efficiency); smo_efficiency = NULL;
17583 cpl_table_new_column(table,
"RAW_RESPONSE", CPL_TYPE_FLOAT);
17584 cpl_table_set_column_unit(table,
"RAW_RESPONSE",
17585 "10^(-16) erg/(cm^2 electron)");
17586 cpl_table_copy_data_float(table,
"RAW_RESPONSE", res_data);
17587 cpl_image_delete(response); response = NULL;
17589 cpl_table_new_column(table,
"RESPONSE", CPL_TYPE_FLOAT);
17590 cpl_table_set_column_unit(table,
17591 "RESPONSE",
"10^(-16) erg/(cm^2 electron)");
17592 cpl_table_copy_data_float(table,
"RESPONSE", smo_res_data);
17593 cpl_image_delete(smo_response); smo_response = NULL;
17600 static double ksigma_vector(cpl_vector *values,
17601 double klow,
double khigh,
int kiter,
int *good)
17603 cpl_vector *accepted;
17605 double sigma = 0.0;
17606 double *data = cpl_vector_get_data(values);
17607 int n = cpl_vector_get_size(values);
17618 mean = cpl_vector_get_median(values);
17620 for (i = 0; i < n; i++)
17621 sigma += (mean - data[i]) * (mean - data[i]);
17623 sigma = sqrt(sigma / (n - 1));
17627 for (i = 0; i < ngood; i++) {
17628 if (data[i]-mean < khigh*sigma && mean-data[i] < klow*sigma) {
17629 data[count] = data[i];
17643 accepted = cpl_vector_wrap(count, data);
17644 mean = cpl_vector_get_mean(accepted);
17646 sigma = cpl_vector_get_stdev(accepted);
17647 cpl_vector_unwrap(accepted);
17649 if (count == ngood || count == 1)
17682 double klow,
double khigh,
int kiter,
17685 int ni, nx, ny, npix;
17686 cpl_image *out_ima;
17691 cpl_vector *time_line;
17692 double *ptime_line;
17697 ni = cpl_imagelist_get_size(imlist);
17699 image = cpl_imagelist_get(imlist, 0);
17700 nx = cpl_image_get_size_x(image);
17701 ny = cpl_image_get_size_y(image);
17704 out_ima = cpl_image_new(nx, ny, CPL_TYPE_FLOAT);
17705 pout_ima = cpl_image_get_data_float(out_ima);
17708 *good = cpl_image_new(nx, ny, CPL_TYPE_FLOAT);
17709 good_ima = cpl_image_get_data_float(*good);
17712 time_line = cpl_vector_new(ni);
17713 ptime_line = cpl_vector_get_data(time_line);
17715 data = cpl_calloc(
sizeof(
float *), ni);
17717 for (i = 0; i < ni; i++) {
17718 image = cpl_imagelist_get(imlist, i);
17719 data[i] = cpl_image_get_data_float(image);
17722 for (i = 0; i < npix; i++) {
17723 for (j = 0; j < ni; j++) {
17724 ptime_line[j] = data[j][i];
17726 pout_ima[i] = ksigma_vector(time_line, klow, khigh, kiter, &ngood);
17728 good_ima[i] = ngood;
17733 cpl_vector_delete(time_line);
17757 cpl_table *ext_table,
double startwave,
17758 double dispersion,
double gain,
17759 double exptime,
double airmass)
17761 cpl_image *extinction;
17762 cpl_image *outspectra;
17763 cpl_image *mapresponse;
17767 int tlength, xlength, ylength;
17771 if (spectra == NULL || ext_table == NULL || response == NULL) {
17772 cpl_error_set(cpl_func, CPL_ERROR_NULL_INPUT);
17776 res_data = cpl_table_get_data_float(response,
"RESPONSE");
17778 if (res_data == NULL) {
17779 cpl_error_set(cpl_func, CPL_ERROR_DATA_NOT_FOUND);
17783 tlength = cpl_table_get_nrow(response);
17784 xlength = cpl_image_get_size_x(spectra);
17785 ylength = cpl_image_get_size_y(spectra);
17787 if (xlength != tlength) {
17788 mapresponse = cpl_image_new(xlength, 1, CPL_TYPE_FLOAT);
17789 map_table(mapresponse, startwave + dispersion/2, dispersion,
17790 response,
"WAVE",
"RESPONSE");
17791 res_data = cpl_image_get_data_float(mapresponse);
17799 extinction = cpl_image_new(xlength, 1, CPL_TYPE_FLOAT);
17800 map_table(extinction, startwave + dispersion/2, dispersion,
17801 ext_table,
"WAVE",
"EXTINCTION");
17808 cpl_image_multiply_scalar(extinction, 0.4 * airmass);
17809 cpl_image_exponential(extinction, 10.);
17811 outspectra = cpl_image_duplicate(spectra);
17813 ext_data = cpl_image_get_data_float(extinction);
17814 out_data = cpl_image_get_data_float(outspectra);
17816 for (k = 0, i = 0; i < ylength; i++) {
17817 for (j = 0; j < xlength; j++, k++) {
17818 out_data[k] *= ext_data[j] * res_data[j];
17822 cpl_image_delete(extinction);
17823 if (xlength != tlength) {
17824 cpl_image_delete(mapresponse);
17827 cpl_image_multiply_scalar(outspectra, gain / exptime / dispersion);
17851 cpl_table *response,
17852 cpl_table *ext_table,
17854 double dispersion,
double gain,
17855 double exptime,
double airmass)
17857 cpl_image *extinction;
17858 cpl_image *outerrors;
17859 cpl_image *mapresponse;
17860 cpl_image *maperror;
17866 int tlength, xlength, ylength;
17870 if (errors == NULL || ext_table == NULL || response == NULL) {
17871 cpl_error_set(cpl_func, CPL_ERROR_NULL_INPUT);
17875 if (!cpl_table_has_column(response,
"ERROR")) {
17877 dispersion, gain, exptime, airmass);
17880 res_data = cpl_table_get_data_float(response,
"RESPONSE");
17882 if (res_data == NULL) {
17883 cpl_error_set(cpl_func, CPL_ERROR_DATA_NOT_FOUND);
17887 err_data = cpl_table_get_data_float(response,
"ERROR");
17889 if (err_data == NULL) {
17890 cpl_error_set(cpl_func, CPL_ERROR_DATA_NOT_FOUND);
17894 tlength = cpl_table_get_nrow(response);
17895 xlength = cpl_image_get_size_x(errors);
17896 ylength = cpl_image_get_size_y(errors);
17898 if (xlength != tlength) {
17899 mapresponse = cpl_image_new(xlength, 1, CPL_TYPE_FLOAT);
17900 map_table(mapresponse, startwave + dispersion/2, dispersion,
17901 response,
"WAVE",
"RESPONSE");
17902 res_data = cpl_image_get_data_float(mapresponse);
17904 maperror = cpl_image_new(xlength, 1, CPL_TYPE_FLOAT);
17905 map_table(maperror, startwave + dispersion/2, dispersion,
17906 response,
"WAVE",
"ERROR");
17907 err_data = cpl_image_get_data_float(maperror);
17915 extinction = cpl_image_new(xlength, 1, CPL_TYPE_FLOAT);
17916 map_table(extinction, startwave + dispersion/2, dispersion,
17917 ext_table,
"WAVE",
"EXTINCTION");
17924 cpl_image_multiply_scalar(extinction, 0.4 * airmass);
17925 cpl_image_exponential(extinction, 10.);
17927 outerrors = cpl_image_duplicate(errors);
17929 ext_data = cpl_image_get_data_float(extinction);
17930 out_data = cpl_image_get_data_float(outerrors);
17931 spe_data = cpl_image_get_data_float(spectra);
17933 for (k = 0, i = 0; i < ylength; i++) {
17934 for (j = 0; j < xlength; j++, k++) {
17935 out_data[k] = ext_data[j] *
17936 sqrt(err_data[j] * err_data[j] * spe_data[k] * spe_data[k] +
17937 res_data[j] * res_data[j] * out_data[k] * out_data[k]);
17941 cpl_image_delete(extinction);
17942 if (xlength != tlength) {
17943 cpl_image_delete(maperror);
17946 cpl_image_multiply_scalar(outerrors, gain / exptime / dispersion);
18028 cpl_image *u_image, cpl_image *u_error,
18029 double startwave,
double dispersion,
18030 double band, cpl_table *pol_sta,
18031 double ra,
double dec,
char *filter,
18033 double *p_offset,
double *p_error,
18034 double *a_offset,
double *a_error)
18036 cpl_table *standard;
18037 cpl_image *q_noise;
18038 cpl_image *q_signal;
18039 cpl_image *u_noise;
18040 cpl_image *u_signal;
18046 double arctol = 0.5;
18049 double bwave[] = {3650., 4450., 5510., 6580., 8060};
18050 char *bands =
"UBVRI";
18051 char p_label[] = {
' ',
'p',
'\0'};
18052 char dp_label[] = {
' ',
'd',
'p',
'\0'};
18053 char a_label[] = {
' ',
'a',
'\0'};
18054 char da_label[] = {
' ',
'd',
'a',
'\0'};
18055 int nbands = strlen(bands);
18057 int first, last, count, center;
18060 int i, found, closest;
18088 cpl_table_select_all(pol_sta);
18089 cpl_table_and_selected_double(pol_sta,
"RA", CPL_GREATER_THAN, ra-arctol);
18090 cpl_table_and_selected_double(pol_sta,
"RA", CPL_LESS_THAN, ra+arctol);
18091 cpl_table_and_selected_double(pol_sta,
"DEC", CPL_GREATER_THAN, dec-arctol);
18093 cpl_table_and_selected_double(pol_sta,
"DEC", CPL_LESS_THAN, dec+arctol);
18095 if (selected == 0) {
18096 cpl_msg_warning(cpl_func,
"No standard star found in FOV");
18100 if (selected > 1) {
18101 cpl_msg_warning(cpl_func,
18102 "Ambiguity: %d standard stars found in FOV", selected);
18106 standard = cpl_table_extract_selected(pol_sta);
18108 cpl_msg_info(cpl_func,
"Standard star: %s",
18109 cpl_table_get_string(standard,
"name", 0));
18115 polarised = cpl_table_get_int(standard,
"polarised", 0, NULL);
18117 cpl_msg_info(cpl_func,
"This star is%sexpected to be polarised",
18118 polarised ?
" " :
" not ");
18128 nx = cpl_image_get_size_x(q_error);
18130 noise = cpl_image_collapse_median_create(q_error, 1, 0, 0);
18131 cpl_image_get_minpos(noise, &col, &row);
18133 cpl_image_delete(noise);
18136 cpl_table_delete(standard);
18137 cpl_msg_error(cpl_func,
18138 "Assertion failure!!! col = %"CPL_SIZE_FORMAT
" (it should be 1)", col);
18142 q_signal = cpl_image_extract(q_image, 1, row, nx, row);
18143 q_noise = cpl_image_extract(q_error, 1, row, nx, row);
18144 u_signal = cpl_image_extract(u_image, 1, row, nx, row);
18145 u_noise = cpl_image_extract(u_error, 1, row, nx, row);
18147 q_sdata = cpl_image_get_data_double(q_signal);
18148 q_ndata = cpl_image_get_data_double(q_noise);
18149 u_sdata = cpl_image_get_data_double(u_signal);
18150 u_ndata = cpl_image_get_data_double(u_noise);
18158 last = nx = cpl_image_get_size_x(q_signal);
18159 for (i = 0; i < nx; i++) {
18161 if (q_ndata[i] > 0.0) {
18166 if (q_ndata[i] <= 0.0) {
18173 count = last - first + 1;
18175 if (first < 0 || count < band) {
18176 cpl_table_delete(standard);
18177 cpl_image_delete(q_signal);
18178 cpl_image_delete(q_noise);
18179 cpl_image_delete(u_signal);
18180 cpl_image_delete(u_noise);
18181 cpl_msg_warning(cpl_func,
"Too short spectrum (%d pixels)", count);
18185 center = (first + last) / 2;
18186 cwave = startwave + dispersion * center;
18194 for (i = 0; i < nbands; i++) {
18195 p_label[0] = bands[i];
18196 if (cpl_table_is_valid(standard, p_label, 0)) {
18199 mindist = fabs(bwave[i] - cwave);
18202 else if (mindist > fabs(bwave[i] - cwave)) {
18203 mindist = fabs(bwave[i] - cwave);
18210 cpl_table_delete(standard);
18211 cpl_image_delete(q_signal);
18212 cpl_image_delete(q_noise);
18213 cpl_image_delete(u_signal);
18214 cpl_image_delete(u_noise);
18215 cpl_msg_warning(cpl_func,
"No reference value available");
18219 center = (bwave[closest] - startwave) / dispersion;
18220 cwave = bwave[closest];
18228 pband = floor(band / dispersion);
18230 if (center - pband/2 < first || center + pband/2 > last) {
18231 cpl_table_delete(standard);
18232 cpl_image_delete(q_signal);
18233 cpl_image_delete(q_noise);
18234 cpl_image_delete(u_signal);
18235 cpl_image_delete(u_noise);
18236 cpl_msg_warning(cpl_func,
"No reference value available");
18240 first = center - pband/2;
18241 last = center + pband/2;
18248 p_label[0] = bands[closest];
18249 dp_label[0] = bands[closest];
18250 a_label[0] = bands[closest];
18251 da_label[0] = bands[closest];
18253 p_ref = cpl_table_get(standard, p_label, 0, NULL);
18254 dp_ref = cpl_table_get(standard, dp_label, 0, NULL);
18255 a_ref = cpl_table_get(standard, a_label, 0, NULL);
18256 da_ref = cpl_table_get(standard, da_label, 0, NULL);
18258 cpl_msg_info(cpl_func,
18259 "The expected polarisation is %.2f +- %.2f %%",
18263 cpl_msg_info(cpl_func,
18264 "The expected polarisation angle is %.2f +- %.2f degrees",
18272 q_obs = cpl_image_get_median_window(q_image, first, 1, last, 1);
18273 q_err = cpl_image_get_median_window(q_error, first, 1, last, 1);
18274 u_obs = cpl_image_get_median_window(u_image, first, 1, last, 1);
18275 u_err = cpl_image_get_median_window(u_error, first, 1, last, 1);
18281 p_obs = sqrt(q_obs * q_obs + u_obs * u_obs);
18282 p_err = CPL_MATH_SQRT1_2 * 0.5 * (q_err + u_err);
18290 if (fabs(q_obs) < 0.00001) {
18299 a_obs = 0.5 * atan(u_obs / q_obs) * 180 / CPL_MATH_PI;
18317 a_err = sqrt(q_obs*q_obs*u_err*u_err + u_obs*u_obs*q_err*q_err)
18319 * 90 / CPL_MATH_PI;
18324 cpl_msg_info(cpl_func,
18325 "The measured polarisation is %.2f +- %.2f %%",
18329 cpl_msg_info(cpl_func,
18330 "The measured polarisation angle is %.2f +- %.2f degrees",
18334 *filter = bands[closest];
18335 *polarisation = polarised;
18338 *p_offset = (p_obs - p_ref) / p_ref;
18339 *p_error = sqrt(p_err * p_err + dp_ref * dp_ref) / p_ref;
18342 *p_offset = p_obs - p_ref;
18343 *p_error = sqrt(p_err * p_err + dp_ref * dp_ref);
18346 *a_offset = a_obs - a_ref;
18347 *a_error = sqrt(a_err*a_err + da_ref*da_ref);
18387 cpl_array *offsets;
18389 int nslits = cpl_table_get_nrow(reference);
18396 cpl_error_code status = CPL_ERROR_NONE;
18401 if (nslits != cpl_table_get_nrow(objects))
18402 return CPL_ERROR_INCOMPATIBLE_INPUT;
18404 nref = fors_get_nobjs_perslit(reference);
18405 nobj = fors_get_nobjs_perslit(objects);
18408 for (i = 0; i < nslits; i++)
18409 noffset += nobj[i];
18411 if (noffset == 0) {
18414 return CPL_ERROR_DATA_NOT_FOUND;
18418 for (i = 0; i < nslits; i++)
18419 noffset += nref[i];
18421 if (noffset == 0) {
18424 return CPL_ERROR_DATA_NOT_FOUND;
18427 offsets = cpl_array_new(noffset, CPL_TYPE_DOUBLE);
18431 for (i = 0; i < nslits; i++) {
18432 if (nref[i] > 0 && nobj[i] > 0) {
18434 int length = cpl_table_get_int(objects,
"length", i, NULL);
18435 double ytop = cpl_table_get_double(objects,
"xtop", i, NULL);
18436 double ybottom = cpl_table_get_double(objects,
"xbottom", i, NULL);
18437 int *aref = cpl_calloc(length,
sizeof(
int));
18438 int *aobj = cpl_calloc(length,
sizeof(
int));
18439 float *pref = cpl_calloc(nref[i],
sizeof(
float));
18440 float *pobj = cpl_calloc(nobj[i],
sizeof(
float));
18442 for (j = 0; j < nref[i]; j++) {
18443 pref[j] = fors_get_object_position(reference, i, j + 1);
18444 aref[(int)pref[j]] = 1;
18447 for (j = 0; j < nobj[i]; j++) {
18448 pobj[j] = fors_get_object_position(objects, i, j + 1);
18449 aobj[(int)pobj[j]] = 1;
18457 aref[length - 1] = 0;
18459 aobj[length - 1] = 0;
18479 best_shift = length;
18481 for (shift = length/2, j = 0; j <= length; shift--, j++) {
18482 int rstart, ostart, count;
18487 count = length - shift;
18492 count = length + shift;
18496 for (k = 0; k < count; k++) {
18497 corr += aref[rstart + k] * aobj[ostart + k];
18500 if (maxcorr < corr) {
18502 best_shift = shift;
18506 if (best_shift == length) {
18516 for (j = 0; j < nref[i]; j++) {
18517 for (k = 0; k < nobj[i]; k++) {
18518 if (fabs(pref[j] - pobj[k] - best_shift) < 2) {
18519 double ccd_offset = (pref[j] - pobj[k])
18529 cpl_array_set(offsets, noffset, ccd_offset);
18551 *offset = cpl_array_get_median(offsets);
18554 double *a = cpl_malloc(
sizeof(
double) * noffset);
18555 for (i = 0; i < noffset; i++) {
18556 a[i] = cpl_array_get_double(offsets, i, NULL);
18564 status = CPL_ERROR_DATA_NOT_FOUND;
18567 cpl_array_delete(offsets);
18588 int nx = cpl_image_get_size_x(image);
18589 int ny = cpl_image_get_size_y(image);
18593 double xpos, ypos, xfrac, yfrac;
18597 if (fabs(dx) >= nx || fabs(dy) >= ny)
18598 return CPL_ERROR_ACCESS_OUT_OF_RANGE;
18600 source = cpl_image_duplicate(image);
18601 idata = cpl_image_get_data_float(image);
18602 sdata = cpl_image_get_data_float(source);
18608 yfrac = - dy - floor(- dy);
18609 xfrac = - dx - floor(- dx);
18611 for (pos = 0, j = 0; j < ny; j++) {
18613 yint = floor(ypos);
18614 for (i = 0; i < nx; i++) {
18616 xint = floor(xpos);
18617 if (xint < 0 || yint < 0 || xint > nx - 2 || yint > ny - 2) {
18621 idata[pos] = sdata[xint + nx*yint] * (1 - xfrac) * (1 - yfrac)
18622 + sdata[xint + 1 + nx*yint] * xfrac * (1 - yfrac)
18623 + sdata[xint + nx*(yint + 1)] * (1 - xfrac) * yfrac
18624 + sdata[xint + 1 + nx*(yint + 1)] * xfrac * yfrac;
18630 cpl_image_delete(source);
18632 return CPL_ERROR_NONE;
18648 #ifdef CPL_SIZE_FORMAT
18654 cpl_table_duplicate_column(slits,
"x", slits,
"xtop");
18655 cpl_table_add_columns(slits,
"x",
"xbottom");
18656 cpl_table_divide_scalar(slits,
"x", 2);
18657 cpl_table_subtract_scalar(slits,
"x", nx/2);
18658 cpl_table_multiply_columns(slits,
"x",
"x");
18660 cpl_table_duplicate_column(slits,
"y", slits,
"ytop");
18661 cpl_table_add_columns(slits,
"y",
"ybottom");
18662 cpl_table_divide_scalar(slits,
"y", 2);
18663 cpl_table_subtract_scalar(slits,
"y", ny/2);
18664 cpl_table_multiply_columns(slits,
"y",
"y");
18666 cpl_table_add_columns(slits,
"x",
"y");
18667 cpl_table_get_column_minpos(slits,
"x", &row);
18669 cpl_table_erase_column(slits,
"x");
18670 cpl_table_erase_column(slits,
"y");
18695 double xwidth,
double ywidth,
18696 int dx,
double gain,
double *o_flux,
double *o_err)
18698 int nx = cpl_image_get_size_x(image);
18699 int ny = cpl_image_get_size_y(image);
18701 int ytop = (int)cpl_table_get(slits,
"ytop", slit, NULL);
18702 int ybottom = (int)cpl_table_get(slits,
"ybottom", slit, NULL);
18703 int dy = ytop - ybottom;
18704 int xcenter = (int)((cpl_table_get(slits,
"xtop", slit, NULL) +
18705 cpl_table_get(slits,
"xbottom", slit, NULL)) / 2);
18706 int xleft = xcenter - dx;
18707 int xright = xcenter + dx + 1;
18708 double area = xwidth * ywidth;
18709 int npix = (2*dx + 1) * dy;
18711 float *data = cpl_image_get_data_float(image);
18713 double error = 0.0;
18718 if (cpl_table_has_column(slits,
"ywidth")) {
18719 area = cpl_table_get(slits,
"xwidth", slit, NULL)
18720 * cpl_table_get(slits,
"ywidth", slit, NULL);
18750 count = (xright - xleft) * (ytop - ybottom);
18753 return CPL_ERROR_ACCESS_OUT_OF_RANGE;
18757 for (y = ybottom; y < ytop; y++) {
18758 for (x = xleft; x < xright; x++) {
18759 double value = data[x + y * nx];
18760 if (value < satur) {
18768 return CPL_ERROR_DIVISION_BY_ZERO;
18770 error = sqrt(flux/gain);
18776 flux *= (float)npix / count;
18777 error *= (float)npix / count;
18785 return CPL_ERROR_NONE;
18812 double xwidth,
double ywidth,
18813 double lambda,
double startwave,
18814 double dispersion,
int dx,
double gain,
18815 double *o_flux,
double *o_err)
18817 int nx = cpl_image_get_size_x(image);
18818 int ny = cpl_image_get_size_y(image);
18820 int dy = (int)cpl_table_get(slits,
"length", slit, NULL);
18821 int ybottom = (int)cpl_table_get(slits,
"position", slit, NULL);
18822 int ytop = ybottom + dy;
18823 int xcenter = (int)floor((lambda - startwave) / dispersion + 0.5);
18824 int xleft = xcenter - dx;
18825 int xright = xcenter + dx + 1;
18826 double area = xwidth * ywidth;
18827 int npix = (2*dx + 1) * dy;
18829 float *data = cpl_image_get_data_float(image);
18831 double error = 0.0;
18836 if (cpl_table_has_column(slits,
"ywidth")) {
18837 area = cpl_table_get(slits,
"xwidth", slit, NULL)
18838 * cpl_table_get(slits,
"ywidth", slit, NULL);
18868 count = (xright - xleft) * (ytop - ybottom);
18871 return CPL_ERROR_ACCESS_OUT_OF_RANGE;
18875 for (y = ybottom; y < ytop; y++) {
18876 for (x = xleft; x < xright; x++) {
18877 double value = data[x + y * nx];
18878 if (value < satur) {
18886 return CPL_ERROR_DIVISION_BY_ZERO;
18888 error = sqrt(flux/gain);
18894 flux *= (float)npix / count;
18895 error *= (float)npix / count;
18903 return CPL_ERROR_NONE;
18922 char *label,
double *mvalue)
18924 int position = cpl_table_get_int(slits,
"position", slit, NULL);
18925 int length = cpl_table_get_int(slits,
"length", slit, NULL);
18926 cpl_table *tmp = cpl_table_extract(table, position, length);
18928 *mvalue = cpl_table_get_column_median(tmp, label);
18929 cpl_table_delete(tmp);
18931 if (cpl_error_get_code() != CPL_ERROR_NONE)
18951 cpl_mask *kernel = cpl_mask_new(nx, ny);
18952 cpl_image *filtered = cpl_image_new(cpl_image_get_size_x(image),
18953 cpl_image_get_size_y(image),
18954 cpl_image_get_type(image));
18956 cpl_mask_not(kernel);
18957 cpl_image_filter_mask(filtered, image, kernel,
18958 CPL_FILTER_MEDIAN, CPL_BORDER_FILTER);
18959 cpl_mask_delete(kernel);
18964 int fors_mos_is_lss_like(cpl_table *maskslits,
int nslits_out_det)
18966 int treat_as_lss = 1;
18967 double mxpos = cpl_table_get_column_median(maskslits,
"xtop");
18968 double * slit_xpos = cpl_table_get_data_double(maskslits,
"xtop");
18969 cpl_size nslits = cpl_table_get_nrow(maskslits);
18973 if(nslits_out_det != 0)
18976 cpl_msg_warning(cpl_func,
"Number of slits %"CPL_SIZE_FORMAT, nslits);
18977 for (cpl_size i = 0; i < nslits; i++) {
18978 if (fabs(mxpos-slit_xpos[i]) > 0.01) {
18983 return treat_as_lss;
cpl_image * mos_spatial_calibration(cpl_image *spectra, cpl_table *slits, cpl_table *polytraces, double reference, double blue, double red, double dispersion, int flux, cpl_image *calibration)
Spatial remapping of CCD spectra eliminating the spectral curvature.
cpl_table * mos_photometric_calibration(cpl_image *spectra, double startwave, double dispersion, double gain, double exptime, cpl_table *ext_table, double airmass, cpl_table *flux_table, int order)
Produce instrument response curve, with some ancillary information.
cpl_table * mos_build_disp_coeff(cpl_table *global, cpl_table *slits)
Build the IDS coefficients table from a global distortions table.
cpl_image * mos_map_pixel(cpl_table *idscoeff, double reference, double blue, double red, double dispersion, int trend)
Create a pixel map from an IDS coefficients table.
double mos_integrate_signal(cpl_image *image, cpl_image *wavemap, int ystart, int yend, double wstart, double wend)
Integrate signal from wavelength and spatial interval.
cpl_bivector * mos_identify_peaks(cpl_vector *peaks, cpl_vector *lines, double min_disp, double max_disp, double tolerance)
Identify peak candidates.
cpl_vector * mos_refine_peaks(const float *spectrum, int length, cpl_vector *peaks, int sradius)
Improve (when possible) accuracy of peaks candidates positions.
cpl_table * mos_sky_map(cpl_image *spectra, cpl_image *wavemap, double dispersion, cpl_image *skymap)
Create a CCD median sky map.
cpl_error_code mos_interpolate_wavecalib(cpl_table *idscoeff, cpl_image *wavemap, int mode, int degree)
Interpolate LSS wavelength calibration.
cpl_image * mos_wavelength_calibration_raw(const cpl_image *image, cpl_vector *lines, double dispersion, float level, int sradius, int order, double reject, double refwave, double *wavestart, double *waveend, int *nlines, double *error, cpl_table *idscoeff, cpl_image *calibration, cpl_image *residuals, cpl_table *restable, cpl_mask *refmask, cpl_table *detected_lines)
Derive wavelength calibration from a raw arc lamp or sky exposure.
double mos_distortions_rms(cpl_image *rectified, cpl_vector *lines, double wavestart, double dispersion, int radius, int highres)
Estimate the spectral distortion modeling goodness.
cpl_image * mos_propagate_photometry_error(cpl_image *spectra, cpl_image *errors, cpl_table *response, cpl_table *ext_table, double startwave, double dispersion, double gain, double exptime, double airmass)
Propagate errors from response curve and extracted spectra.
cpl_table * mos_load_slits_fors_mxu(cpl_propertylist *header)
Create slit location table from FITS header of FORS2-MXU data.
cpl_image ** mos_extract_objects(cpl_image *science, cpl_image *sky, cpl_table *objects, int extraction, double ron, double gain, int ncombined)
Extract detected objects from rectified scientific frame.
cpl_image * mos_normalise_flat(cpl_image *flat, cpl_image *spatial, cpl_table *slits, cpl_table *polytraces, double reference, double blue, double red, double dispersion, int sradius, int polyorder)
Normalise a flat field exposure.
int mos_get_nobjects(cpl_table *slits)
Get the total number of objects detected in a slits table.
cpl_error_code mos_rotate_slits(cpl_table *slits, int rotation, int nx, int ny)
Rotate a slit location table.
cpl_image * mos_map_wavelengths(cpl_image *spatial, cpl_image *calibration, cpl_table *slits, cpl_table *polytraces, double reference, double blue, double red, double dispersion)
Remapping of spatially rectified wavelengths to original CCD pixels.
cpl_image * mos_wavelength_calibration(cpl_image *image, double refwave, double firstLambda, double lastLambda, double dispersion, cpl_table *idscoeff, int flux)
Remap at constant wavelength step an image of rectified scientific spectra.
cpl_table * mos_identify_slits(cpl_table *slits, cpl_table *maskslits, cpl_table *global)
Identify slits listed in a slit location table.
cpl_table * mos_sky_map_super(cpl_image *spectra, cpl_image *wavemap, double dispersion, double factor, int minpoints, cpl_image *skymap)
Create a CCD median sky map.
cpl_image * mos_sky_local(cpl_image *spectra, cpl_table *slits, int order)
Local determination of sky.
double fors_tools_get_kth_double(double *a, int n, int k)
Same as cpl_tools_get_kth_double.
cpl_table * mos_load_slits_fors_mos(cpl_propertylist *header, int *nslits_out_det)
Create slit location table from FITS header of FORS1/2 MOS data.
double mos_get_gain_vimos(cpl_propertylist *header)
Return gain factor for a VIMOS exposure.
cpl_table * mos_wavelength_align(cpl_image *image, cpl_table *slits, double refwave, double firstLambda, double lastLambda, cpl_table *idscoeff, cpl_vector *skylines, int highres, int order, cpl_image *calibration, int sradius)
Modify the input wavelength solution to match reference sky lines.
cpl_error_code mos_validate_slits(cpl_table *slits)
Check validity of a slit location table.
cpl_error_code mos_subtract_background(cpl_image *image)
Subtract the background.
int mos_get_maxobjs_per_slit(cpl_table *slits)
Get the maximum possible number of objects in a slit.
cpl_error_code mos_interpolate_wavecalib_slit(cpl_table *idscoeff, cpl_table *slits, int order, int global)
Interpolate MOS wavelength calibration.
cpl_image * mos_remove_bias(cpl_image *image, cpl_image *bias, cpl_table *overscans)
Subtract the bias from a CCD exposure.
cpl_table * mos_poly_trace(cpl_table *slits, cpl_table *traces, int order)
Fit spectral traces.
cpl_image * mos_detect_objects(cpl_image *image, cpl_table *slits, int margin, int maxradius, int conradius)
Detect objects in rectified scientific frame.
cpl_image * mos_sky_local_old(cpl_image *spectra, cpl_table *slits)
Local determination of sky.
int mos_check_polarisation(cpl_image *q_image, cpl_image *q_error, cpl_image *u_image, cpl_image *u_error, double startwave, double dispersion, double band, cpl_table *pol_sta, double ra, double dec, char *filter, int *polarisation, double *p_offset, double *p_error, double *a_offset, double *a_error)
Estimate linear polarisation parameters on spectral interval.
cpl_polynomial * mos_poly_wav2pix(cpl_bivector *pixwav, int order, double reject, int minlines, int *nlines, double *err)
Fit polynomial relation from wavelengths to pixels.
cpl_error_code mos_image_shift(cpl_image *image, double dx, double dy)
Shift values in an image.
int mos_check_multiplex(cpl_table *slits)
Determining whether a VIMOS mask has spectral multplexing or not.
cpl_error_code mos_extract_flux(cpl_image *image, cpl_table *slits, double xwidth, double ywidth, int dx, double gain, double *o_flux, double *o_err)
Measure flux from spectral interval on CCD.
int mos_lines_width(const float *spectrum, int length)
Estimate lines widths (in pixel) in arc lamp spectrum.
cpl_error_code mos_global_trace(cpl_table *slits, cpl_table *polytraces, int mode)
Recompute tracing coefficients globally.
cpl_bivector * mos_find_peaks(const float *spectrum, int length, cpl_vector *lines, cpl_polynomial *ids, double refwave, int sradius)
Find the reference lines peaks using a polynomial first-guess.
cpl_vector * mos_peak_candidates(const float *spectrum, int length, float level, float exp_width)
Find positions of peaks candidates.
cpl_error_code mos_object_intersect(cpl_table **slitss, cpl_table *origslits, int nscience, float tolerance)
Intersect a number of slit tables.
cpl_table * mos_wavelength_align_lss(cpl_image *image, double refwave, double firstLambda, double lastLambda, cpl_table *idscoeff, cpl_vector *skylines, int highres, int order, cpl_image *calibration, int sradius)
Modify the input wavelength solution to match reference sky lines (LSS).
cpl_image * mos_subtract_sky(cpl_image *science, cpl_table *slits, cpl_table *polytraces, double reference, double blue, double red, double dispersion)
Subtract the sky from the scientific CCD exposure.
cpl_image * mos_map_idscoeff(cpl_table *idscoeff, int xsize, double reference, double blue, double red)
Create a wavelengths map from an IDS coefficients table.
double mos_eval_dds(cpl_polynomial *ids, double blue, double red, double refwave, double pixel)
Evaluate the wavelength of a pixel position.
cpl_table * mos_trace_flat(cpl_image *flat, cpl_table *slits, double reference, double blue, double red, double dispersion)
Trace flat field spectra.
cpl_image * mos_wavelength_calibration_final(cpl_image *image, cpl_table *slits, cpl_vector *lines, double dispersion, float level, int sradius, int order, double reject, double refwave, double *wavestart, double *waveend, int *nlines, double *error, cpl_table *idscoeff, cpl_image *calibration, cpl_image *residuals, cpl_table *restable, cpl_table *detected_lines)
Derive wavelength calibration from a rectified arc lamp or sky exposure.
int mos_check_slits(cpl_table *slits, float rescale)
Check that all slit have been detected, insert them if not.
cpl_image * mos_apply_photometry(cpl_image *spectra, cpl_table *response, cpl_table *ext_table, double startwave, double dispersion, double gain, double exptime, double airmass)
Apply response curve to extracted spectra.
cpl_error_code mos_refmask_find_gaps(cpl_mask *refmask, cpl_image *master_flat, double level)
Reconstruct the gaps required for slit location.
cpl_image * mos_ksigma_stack(cpl_imagelist *imlist, double klow, double khigh, int kiter, cpl_image **good)
Stack images using k-sigma clipping.
cpl_error_code mos_clean_cosmics(cpl_image *image, float gain, float threshold, float ratio)
Remove cosmic rays from sky-subtracted CCD spectral exposure.
cpl_table * mos_global_distortion(cpl_table *slits, cpl_table *maskslits, cpl_table *ids, cpl_table *crv, double reference)
Determine all global distortions models.
int mos_spectral_resolution(cpl_image *image, double lambda, double startwave, double dispersion, int saturation, double *mfwhm, double *rmsfwhm, double *resolution, double *rmsres, int *nlines)
Compute mean spectral resolution at a given arc lamp line.
cpl_error_code mos_arc_background_1D(float *spectrum, float *back, int length, int msize, int fsize)
Background determination on 1D emission line spectrum (arc)
cpl_table * mos_resolution_table(cpl_image *image, double startwave, double dispersion, int saturation, cpl_vector *lines)
Compute mean spectral resolution at a given arc lamp line.
cpl_table * mos_load_slits_fors_pmos(cpl_propertylist *header, int *nslits_out_det)
Create PMOS slit location table from FITS header of FORS1/2 MOS data.
cpl_table * mos_load_slits_vimos(cpl_propertylist *header)
Create slit location table from FITS header of VIMOS data.
cpl_error_code mos_randomise_image(cpl_image *image, double ron, double gain, double bias)
Randomise image.
cpl_table * mos_build_curv_coeff(cpl_table *global, cpl_table *maskslits, cpl_table *slits)
Build the curvature coefficients table from a global distortions table.
cpl_table * mos_locate_spectra(cpl_mask *mask)
Find the location of detected spectra on the CCD.
cpl_table * mos_load_slits_fors_lss(cpl_propertylist *header)
Create slit location table from FITS header of FORS1/2 LSS data.
cpl_polynomial * mos_poly_pix2wav(cpl_bivector *pixwav, int order, double reject, int minlines, int *nlines, double *err)
Fit polynomial relation from pixels to wavelengths.
cpl_image * mos_arc_background(cpl_image *image, int msize, int fsize)
Background determination on emission line spectrum (arc)
cpl_error_code mos_saturation_process(cpl_image *image)
Process saturation.
cpl_image * mos_map_spectrum(cpl_image *spectra, cpl_image *wavecalib, cpl_image *spatial, cpl_table *slits, cpl_table *polytraces, double reference, double blue, double red, double dispersion, int flux)
Remapping of slit spectra into a grid of lambda-space coordinates.
int mos_slit_closest_to_center(cpl_table *slits, int nx, int ny)
Return slit closest to CCD center.
cpl_image * mos_image_filter_median(cpl_image *image, int nx, int ny)
Convenience function for standard median filtering.
cpl_image * mos_spatial_map(cpl_image *spectra, cpl_table *slits, cpl_table *polytraces, double reference, double blue, double red, double dispersion)
Create coordinate map from spectral curvature table.
cpl_error_code mos_extract_flux_mapped(cpl_image *image, cpl_table *slits, double xwidth, double ywidth, double lambda, double startwave, double dispersion, int dx, double gain, double *o_flux, double *o_err)
Measure flux from spectral interval on remapped frame.
int mos_compute_offset(cpl_table *reference, cpl_table *objects, double *offset)
Estimate offset between two object tables.
cpl_image * mos_normalise_longflat(cpl_image *flat, int sradius, int dradius, int polyorder)
Normalise a long slit flat field exposure.
cpl_table * mos_load_overscans_vimos(const cpl_propertylist *header, int check_consistency)
Get the overscan positions from FITS header of VIMOS data.
int mos_median_in_slit(cpl_table *table, cpl_table *slits, int slit, char *label, double *mvalue)
Compute median from a table column section corresponding to a slit.
cpl_table * mos_build_slit_location(cpl_table *global, cpl_table *maskslits, int ysize)
Build the slit location table from a global distortions table.