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 *sci_var_win,
915 cpl_image *extracted, cpl_image *sky,
916 cpl_image *error,
int nobjects,
int extraction,
917 double ron,
double conad,
int ncomb)
920 cpl_vector *vprofile;
932 double sumWeight, sum, sumSky, sumProf, sumVar, variance, weight;
946 specLen = cpl_image_get_size_x(sciwin);
947 numRows = cpl_image_get_size_y(sciwin);
949 edata = cpl_image_get_data(extracted);
950 edata += nobjects * specLen;
952 ekdata = cpl_image_get_data(sky);
953 ekdata += nobjects * specLen;
955 endata = cpl_image_get_data(error);
956 endata += nobjects * specLen;
958 sdata = cpl_image_get_data(sciwin);
959 kdata = cpl_image_get_data(skywin);
960 if(sci_var_win != NULL)
961 vardata = cpl_image_get_data(sci_var_win);
968 if (extraction && numRows > 5) {
970 fdata = cpl_image_get_data(smowin);
971 for (i = 0; i < specLen; i++)
972 for (j = 0, edata[i] = 0.0; j < numRows; j++)
973 edata[i] += fdata[i + j * specLen];
974 cpl_image_delete(smowin);
977 for (i = 0; i < specLen; i++)
978 for (j = 0, edata[i] = 0.0; j < numRows; j++)
979 edata[i] += sdata[i + j * specLen];
984 profile = cpl_calloc(specLen * numRows,
sizeof(
double));
985 buffer = cpl_calloc(specLen,
sizeof(
double));
987 for (iter = 0; iter < maxIter; iter++) {
993 for (i = 0; i < specLen; i++) {
994 for (j = 0; j < numRows; j++) {
995 index = i + j * specLen;
997 if (fabs(edata[i]) > 0.00001)
998 profile[index] = sdata[index] / edata[i];
1000 profile[index] = 0.0;
1004 for (j = 0; j < numRows; j++) {
1010 for (i = 0; i < specLen - smoothBox; i++) {
1011 vprofile = cpl_vector_wrap(smoothBox, profile + i + j*specLen);
1012 value = cpl_vector_get_median_const(vprofile);
1013 cpl_vector_unwrap(vprofile);
1016 buffer[i + smoothBox / 2] = value;
1023 vprofile = cpl_vector_wrap(smoothBox / 2, profile + j*specLen);
1024 value = cpl_vector_get_mean(vprofile);
1025 cpl_vector_unwrap(vprofile);
1030 for (i = 0; i < smoothBox / 2; i++)
1033 vprofile = cpl_vector_wrap(smoothBox / 2,
1034 profile + specLen - smoothBox/2 + j*specLen);
1035 value = cpl_vector_get_mean(vprofile);
1036 cpl_vector_unwrap(vprofile);
1041 for (i = 0; i < smoothBox / 2; i++)
1042 buffer[i + specLen - smoothBox / 2] = value;
1044 for (i = 0; i < specLen; i++)
1045 profile[i + j * specLen] = buffer[i];
1053 for (i = 0; i < specLen; i++) {
1054 for (j = 0, value = 0.0; j < numRows; j++)
1055 value += profile[i + j * specLen];
1056 if (value > 0.00001)
1057 for (j = 0; j < numRows; j++)
1058 profile[i + j * specLen] /= value;
1060 for (j = 0; j < numRows; j++)
1061 profile[i + j * specLen] = 0.0;
1069 for (i = 0; i < specLen; i++) {
1075 for (j = 0; j < numRows; j++) {
1076 index = i + j * specLen;
1083 variance = ron*ron + fabs(edata[i] * profile[index] + kdata[index])
1086 value = sdata[index] - edata[i] * profile[index];
1087 if (fabs(value) / sqrt(variance) < nsigma) {
1088 weight = 1000000 * profile[index] / variance;
1089 sum += weight * sdata[index];
1090 sumSky += weight * kdata[index];
1091 sumWeight += weight * profile[index];
1092 sumProf += profile[index];
1096 if(sci_var_win != NULL)
1097 sumVar += weight * weight * vardata[index];
1101 if (sumWeight > 0.00001) {
1102 edata[i] = sum / sumWeight;
1103 ekdata[i] = sumSky / sumWeight;
1104 if(sci_var_win != NULL)
1105 endata[i] = sqrt(sumVar / sumWeight / sumWeight);
1107 endata[i] = 1000 * sqrt(sumProf / sumWeight);
1129 for (i = 0; i < specLen; i++)
1130 for (j = 0, ekdata[i] = 0.0; j < numRows; j++)
1131 ekdata[i] += kdata[i + j * specLen];
1136 for (i = 0; i < specLen; i++)
1138 if(sci_var_win != NULL)
1141 for (j = 0, endata[i] = 0.0; j < numRows; j++)
1142 endata[i] += vardata[i + j * specLen];
1143 endata[i] = sqrt(endata[i]);
1146 endata[i] = sqrt(ron*ron + fabs(edata[i] + ekdata[i]) / conad);
1201 cpl_table *ids, cpl_table *crv,
1204 const char *func =
"mos_global_distortion";
1206 const char *clab[6] = {
"c0",
"c1",
"c2",
"c3",
"c4",
"c5"};
1208 cpl_table *global = NULL;
1218 cpl_polynomial *poly;
1231 int nslits, nmaskslits, npoints;
1240 if (slits == NULL || maskslits == NULL || ids == NULL || crv == NULL) {
1241 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
1248 nslits = cpl_table_get_nrow(slits);
1253 if (nslits < minslit) {
1254 cpl_msg_warning(func,
"Too few slits (%d < %d) for global "
1255 "distortion model determination", nslits, minslit);
1262 nmaskslits = cpl_table_get_nrow(maskslits);
1264 length = cpl_table_get_data_int(slits,
"length");
1265 position = cpl_table_get_data_int(slits,
"position");
1266 slit_id = cpl_table_get_data_int(slits,
"slit_id");
1267 mslit_id = cpl_table_get_data_int(maskslits,
"slit_id");
1268 xtop = cpl_table_get_data_double(slits,
"xtop");
1269 ytop = cpl_table_get_data_double(slits,
"ytop");
1270 xbottom = cpl_table_get_data_double(slits,
"xbottom");
1271 ybottom = cpl_table_get_data_double(slits,
"ybottom");
1272 mxtop = cpl_table_get_data_double(maskslits,
"xtop");
1273 mytop = cpl_table_get_data_double(maskslits,
"ytop");
1274 mxbottom = cpl_table_get_data_double(maskslits,
"xbottom");
1275 mybottom = cpl_table_get_data_double(maskslits,
"ybottom");
1282 coeff = cpl_table_new(nslits);
1283 cpl_table_copy_structure(coeff, ids);
1284 cpl_table_new_column(coeff,
"xccd", CPL_TYPE_DOUBLE);
1285 cpl_table_new_column(coeff,
"yccd", CPL_TYPE_DOUBLE);
1286 cpl_table_new_column(coeff,
"xmask", CPL_TYPE_DOUBLE);
1287 cpl_table_new_column(coeff,
"ymask", CPL_TYPE_DOUBLE);
1292 for (i = 0; i < nslits; i++) {
1293 for (j = 0; j < nmaskslits; j++) {
1294 if (slit_id[i] == mslit_id[j]) {
1295 cpl_table_set_double(coeff,
"xmask", i,
1296 (mxtop[j] + mxbottom[j]) / 2);
1297 cpl_table_set_double(coeff,
"ymask", i,
1298 (mytop[j] + mybottom[j]) / 2);
1303 if (cpl_table_has_invalid(coeff,
"xmask")) {
1304 cpl_error_set(func, CPL_ERROR_INCOMPATIBLE_INPUT);
1305 cpl_table_delete(coeff);
1309 for (i = 0; i < nslits; i++) {
1310 cpl_table_set_double(coeff,
"xccd", i, (xtop[i] + xbottom[i]) / 2);
1311 cpl_table_set_double(coeff,
"yccd", i, (ytop[i] + ybottom[i]) / 2);
1317 for (i = 0; i < nslits; i++) {
1322 cpl_table_and_selected_window(ids, position[i], length[i]);
1323 dummy = cpl_table_extract_selected(ids);
1324 for (j = 0; j < 6; j++) {
1325 if (cpl_table_has_column(dummy, clab[j])) {
1326 if (length[i] - cpl_table_count_invalid(dummy, clab[j]) > 10) {
1327 cpl_table_set_double(coeff, clab[j], i,
1328 cpl_table_get_column_median(dummy, clab[j]));
1333 cpl_table_delete(dummy);
1334 cpl_table_select_all(ids);
1341 for (j = 0; j < 6; j++) {
1342 if (cpl_table_has_column(coeff, clab[j])) {
1343 cpl_table_and_selected_invalid(coeff, clab[j]);
1345 if (cpl_table_not_selected(coeff))
1346 dummy = cpl_table_extract_selected(coeff);
1350 npoints = cpl_table_get_nrow(dummy);
1359 ci = cpl_vector_wrap(npoints,
1360 cpl_table_get_data_double(dummy, clab[j]));
1362 xccd = cpl_vector_wrap(npoints,
1363 cpl_table_get_data_double(dummy,
"xccd"));
1364 yccd = cpl_vector_wrap(npoints,
1365 cpl_table_get_data_double(dummy,
"yccd"));
1366 ccd = cpl_bivector_wrap_vectors(xccd, yccd);
1369 poly = cpl_polynomial_fit_2d_create(ccd, ci, order, NULL);
1371 cpl_bivector_unwrap_vectors(ccd);
1372 cpl_vector_unwrap(xccd);
1373 cpl_vector_unwrap(yccd);
1374 cpl_vector_unwrap(ci);
1377 xmask = cpl_vector_wrap(npoints,
1378 cpl_table_get_data_double(dummy,
"xmask"));
1379 ymask = cpl_vector_wrap(npoints,
1380 cpl_table_get_data_double(dummy,
"ymask"));
1381 mask = cpl_bivector_wrap_vectors(xmask, ymask);
1384 poly = cpl_polynomial_fit_2d_create(mask, ci, order, NULL);
1386 cpl_bivector_unwrap_vectors(mask);
1387 cpl_vector_unwrap(xmask);
1388 cpl_vector_unwrap(ymask);
1389 cpl_vector_unwrap(ci);
1393 cpl_size p[2] = {0, 0};
1394 poly = cpl_polynomial_new(2);
1395 cpl_polynomial_set_coeff(poly, p,
1396 cpl_table_get_column_median(dummy, clab[j]));
1399 cpl_table_delete(dummy);
1401 global = write_global_distortion(global, j, poly);
1403 cpl_polynomial_delete(poly);
1405 cpl_table_select_all(coeff);
1412 cpl_table_delete(coeff);
1422 cpl_table_set_double(global,
"a00", 6, reference);
1429 coeff = cpl_table_duplicate(crv);
1430 cpl_table_new_column(coeff,
"xmask", CPL_TYPE_DOUBLE);
1431 cpl_table_new_column(coeff,
"ymask", CPL_TYPE_DOUBLE);
1432 cpl_table_new_column(coeff,
"xccd", CPL_TYPE_DOUBLE);
1433 cpl_table_new_column(coeff,
"yccd", CPL_TYPE_DOUBLE);
1434 slit_id = cpl_table_get_data_int(coeff,
"slit_id");
1435 npoints = cpl_table_get_nrow(coeff);
1440 for (i = 0; i < npoints; i++) {
1441 for (j = 0; j < nmaskslits; j++) {
1442 if (slit_id[i] == mslit_id[j]) {
1444 cpl_table_set_double(coeff,
"xmask", i, mxbottom[j]);
1445 cpl_table_set_double(coeff,
"ymask", i, mybottom[j]);
1448 cpl_table_set_double(coeff,
"xmask", i, mxtop[j]);
1449 cpl_table_set_double(coeff,
"ymask", i, mytop[j]);
1455 cpl_table_set_double(coeff,
"xccd", i, xtop[(i-1)/2]);
1456 cpl_table_set_double(coeff,
"yccd", i, ytop[(i-1)/2]);
1460 cpl_table_set_double(coeff,
"xccd", i, xbottom[i/2]);
1461 cpl_table_set_double(coeff,
"yccd", i, ybottom[i/2]);
1468 if (cpl_table_has_invalid(coeff,
"xmask")) {
1469 cpl_error_set(func, CPL_ERROR_INCOMPATIBLE_INPUT);
1470 cpl_table_delete(coeff);
1478 for (j = 0; j < 3; j++) {
1479 cpl_polynomial * poly_ccd;
1480 if (cpl_table_has_column(coeff, clab[j])) {
1481 cpl_table_and_selected_invalid(coeff, clab[j]);
1483 if (cpl_table_not_selected(coeff))
1484 dummy = cpl_table_extract_selected(coeff);
1488 npoints = cpl_table_get_nrow(dummy);
1497 ci = cpl_vector_wrap(npoints,
1498 cpl_table_get_data_double(dummy, clab[j]));
1499 xmask = cpl_vector_wrap(npoints,
1500 cpl_table_get_data_double(dummy,
"xmask"));
1501 ymask = cpl_vector_wrap(npoints,
1502 cpl_table_get_data_double(dummy,
"ymask"));
1503 mask = cpl_bivector_wrap_vectors(xmask, ymask);
1505 poly = cpl_polynomial_fit_2d_create(mask, ci, order, NULL);
1507 xccd = cpl_vector_wrap(npoints,
1508 cpl_table_get_data_double(dummy,
"xccd"));
1509 yccd = cpl_vector_wrap(npoints,
1510 cpl_table_get_data_double(dummy,
"yccd"));
1511 ccd = cpl_bivector_wrap_vectors(xccd, yccd);
1513 poly_ccd = cpl_polynomial_fit_2d_create(ccd, ci, order, NULL);
1516 cpl_bivector_unwrap_vectors(mask);
1517 cpl_vector_unwrap(ci);
1518 cpl_vector_unwrap(xmask);
1519 cpl_vector_unwrap(ymask);
1522 cpl_size p[2] = {0, 0};
1523 poly = cpl_polynomial_new(2);
1524 cpl_polynomial_set_coeff(poly, p,
1525 cpl_table_get_column_median(dummy, clab[j]));
1528 cpl_table_delete(dummy);
1530 global = write_global_distortion(global, j + 7, poly);
1531 global = write_global_distortion(global, j + 10, poly_ccd);
1533 cpl_polynomial_delete(poly);
1534 cpl_polynomial_delete(poly_ccd);
1535 cpl_table_select_all(coeff);
1539 cpl_table_delete(coeff);
1589 const char *func =
"mos_build_slit_location";
1591 cpl_propertylist *sort_col;
1592 cpl_polynomial *ids0;
1593 cpl_polynomial *crv[3];
1594 cpl_polynomial *loc_crv;
1612 if (global == NULL || maskslits == NULL) {
1613 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
1617 nslits = cpl_table_get_nrow(maskslits);
1618 slit_id = cpl_table_get_data_int(maskslits,
"slit_id");
1619 mxtop = cpl_table_get_data_double(maskslits,
"xtop");
1620 mytop = cpl_table_get_data_double(maskslits,
"ytop");
1621 mxbottom = cpl_table_get_data_double(maskslits,
"xbottom");
1622 mybottom = cpl_table_get_data_double(maskslits,
"ybottom");
1624 slits = cpl_table_duplicate(maskslits);
1626 xtop = cpl_table_get_data_double(slits,
"xtop");
1627 ytop = cpl_table_get_data_double(slits,
"ytop");
1628 xbottom = cpl_table_get_data_double(slits,
"xbottom");
1629 ybottom = cpl_table_get_data_double(slits,
"ybottom");
1631 ids0 = read_global_distortion(global, 0);
1632 crv[0] = read_global_distortion(global, 7);
1633 crv[1] = read_global_distortion(global, 8);
1634 crv[2] = read_global_distortion(global, 9);
1636 loc_crv = cpl_polynomial_new(1);
1638 point = cpl_vector_new(2);
1639 dpoint = cpl_vector_get_data(point);
1641 for (i = 0; i < nslits; i++) {
1642 dpoint[0] = mxtop[i];
1643 dpoint[1] = mytop[i];
1645 xtop[i] = cpl_polynomial_eval(ids0, point);
1647 for (j = 0; j < 3; j++)
1649 cpl_polynomial_set_coeff(loc_crv, &j,
1650 cpl_polynomial_eval(crv[j], point));
1652 ytop[i] = cpl_polynomial_eval_1d(loc_crv, xtop[i], NULL);
1654 dpoint[0] = mxbottom[i];
1655 dpoint[1] = mybottom[i];
1656 xbottom[i] = cpl_polynomial_eval(ids0, point);
1658 for (j = 0; j < 3; j++)
1660 cpl_polynomial_set_coeff(loc_crv, &j,
1661 cpl_polynomial_eval(crv[j], point));
1663 ybottom[i] = cpl_polynomial_eval_1d(loc_crv, xbottom[i], NULL);
1666 cpl_vector_delete(point);
1667 cpl_polynomial_delete(ids0);
1668 cpl_polynomial_delete(loc_crv);
1669 for (j = 0; j < 3; j++)
1670 cpl_polynomial_delete(crv[j]);
1672 sort_col = cpl_propertylist_new();
1673 cpl_propertylist_append_bool(sort_col,
"ytop", 1);
1674 cpl_table_sort(slits, sort_col);
1675 cpl_table_sort(maskslits, sort_col);
1676 cpl_propertylist_delete(sort_col);
1682 cpl_table_and_selected_double(slits,
"ybottom", CPL_GREATER_THAN, ysize-1);
1683 cpl_table_or_selected_double(slits,
"ytop", CPL_LESS_THAN, 0);
1684 cpl_table_erase_selected(slits);
1686 nslits = cpl_table_get_nrow(slits);
1689 cpl_msg_warning(func,
"No slits found on the CCD");
1690 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
1691 cpl_table_delete(slits);
1696 cpl_msg_info(func,
"Slit location: %"CPL_SIZE_FORMAT
" slits are entirely or partially "
1697 "contained in CCD", nslits);
1699 cpl_msg_info(func,
"Slit location: %"CPL_SIZE_FORMAT
" slit is entirely or partially "
1700 "contained in CCD", nslits);
1736 const char *func =
"mos_build_curv_coeff";
1738 const char *clab[6] = {
"c0",
"c1",
"c2",
"c3",
"c4",
"c5"};
1741 cpl_polynomial *crv[3];
1743 cpl_table *polytraces;
1756 if (global == NULL || slits == NULL || maskslits == NULL) {
1757 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
1761 nslits = cpl_table_get_nrow(maskslits);
1762 slit_id = cpl_table_get_data_int(maskslits,
"slit_id");
1763 xtop = cpl_table_get_data_double(maskslits,
"xtop");
1764 ytop = cpl_table_get_data_double(maskslits,
"ytop");
1765 xbottom = cpl_table_get_data_double(maskslits,
"xbottom");
1766 ybottom = cpl_table_get_data_double(maskslits,
"ybottom");
1768 polytraces = cpl_table_new(2*nslits);
1769 cpl_table_new_column(polytraces,
"slit_id", CPL_TYPE_INT);
1770 for (i = 0; i < 3; i++)
1771 cpl_table_new_column(polytraces, clab[i], CPL_TYPE_DOUBLE);
1773 crv[0] = read_global_distortion(global, 7);
1774 crv[1] = read_global_distortion(global, 8);
1775 crv[2] = read_global_distortion(global, 9);
1777 point = cpl_vector_new(2);
1778 dpoint = cpl_vector_get_data(point);
1780 for (i = 0; i < nslits; i++) {
1781 for (j = 0; j < 2; j++) {
1783 cpl_table_set_int(polytraces,
"slit_id", 2*i+j, slit_id[i]);
1786 dpoint[0] = xbottom[i];
1787 dpoint[1] = ybottom[i];
1790 dpoint[0] = xtop[i];
1791 dpoint[1] = ytop[i];
1794 for (k = 0; k < 3; k++)
1796 cpl_table_set_double(polytraces, clab[k], 2*i+j,
1797 cpl_polynomial_eval(crv[k], point));
1801 cpl_vector_delete(point);
1802 for (j = 0; j < 3; j++)
1803 cpl_polynomial_delete(crv[j]);
1809 nvalid = cpl_table_get_nrow(slits);
1810 valid_id = cpl_table_get_data_int(slits,
"slit_id");
1811 cpl_table_unselect_all(polytraces);
1812 for (i = 0; i < nslits; i++) {
1814 for (j = 0; j < nvalid; j++) {
1815 if (slit_id[i] == valid_id[j]) {
1821 cpl_table_select_row(polytraces, 2*i);
1822 cpl_table_select_row(polytraces, 2*i + 1);
1825 cpl_table_erase_selected(polytraces);
1827 nslits = cpl_table_get_nrow(polytraces);
1830 cpl_msg_warning(func,
"No slits found on the CCD");
1831 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
1832 cpl_table_delete(polytraces);
1837 cpl_msg_info(func,
"Curvature model: %d slits are entirely or "
1838 "partially contained in CCD", nslits / 2);
1840 cpl_msg_info(func,
"Curvature model: %d slit is entirely or "
1841 "partially contained in CCD", nslits / 2);
1890 const char *func =
"mos_build_disp_coeff";
1892 const char *clab[6] = {
"c0",
"c1",
"c2",
"c3",
"c4",
"c5"};
1894 cpl_polynomial *ids[6];
1896 cpl_table *idscoeff;
1911 if (global == NULL || slits == NULL) {
1912 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
1916 nslits = cpl_table_get_nrow(slits);
1917 position = cpl_table_get_data_int(slits,
"position");
1918 length = cpl_table_get_data_int(slits,
"length");
1919 xtop = cpl_table_get_data_double(slits,
"xtop");
1920 ytop = cpl_table_get_data_double(slits,
"ytop");
1921 xbottom = cpl_table_get_data_double(slits,
"xbottom");
1922 ybottom = cpl_table_get_data_double(slits,
"ybottom");
1924 for (i = 0; i < 6; i++)
1925 ids[i] = read_global_distortion(global, i);
1927 for (i = 0; i < 6; i++)
1934 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
1939 for (i = 0; i < nslits; i++)
1942 idscoeff = cpl_table_new(nrows);
1944 for (j = 0; j <= order; j++)
1945 cpl_table_new_column(idscoeff, clab[j], CPL_TYPE_DOUBLE);
1947 cpl_table_new_column(idscoeff,
"error", CPL_TYPE_DOUBLE);
1948 cpl_table_fill_column_window_double(idscoeff,
"error", 0, nrows, 0.0);
1949 cpl_table_new_column(idscoeff,
"nlines", CPL_TYPE_INT);
1950 cpl_table_fill_column_window_int(idscoeff,
"nlines", 0, nrows, 0);
1952 point = cpl_vector_new(2);
1953 dpoint = cpl_vector_get_data(point);
1955 for (i = 0; i < nslits; i++) {
1961 yhig = ylow + length[i];
1963 for (j = 0; j <= order; j++) {
1965 for (k = 0; k < length[i]; k++) {
1966 dpoint[0] = xbottom[i] + k*(xtop[i]-xbottom[i])/length[i];
1967 dpoint[1] = ybottom[i] + k*(ytop[i]-ybottom[i])/length[i];
1968 cpl_table_set_double(idscoeff, clab[j], ylow + k,
1969 cpl_polynomial_eval(ids[j], point));
1973 for (k = 0; k < length[i]; k++) {
1974 cpl_table_set_double(idscoeff, clab[0], ylow + k,
1975 xbottom[i] + k*(xtop[i]-xbottom[i])/length[i]);
1981 cpl_vector_delete(point);
1982 for (j = 0; j < 6; j++)
1983 cpl_polynomial_delete(ids[j]);
2013 cpl_table *polytraces,
double reference,
2014 double blue,
double red,
double dispersion)
2016 const char *func =
"mos_subtract_sky";
2018 const char *clab[6] = {
"c0",
"c1",
"c2",
"c3",
"c4",
"c5"};
2025 cpl_polynomial *polytop;
2026 cpl_polynomial *polybot;
2027 cpl_polynomial *trend;
2041 int pixel_above, pixel_below, refpixel, start_pixel, end_pixel;
2045 int missing_top, missing_bot;
2054 if (science == NULL || slits == NULL || polytraces == NULL) {
2055 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
2059 if (dispersion <= 0.0) {
2060 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
2064 if (red - blue < dispersion) {
2065 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
2069 nx = cpl_image_get_size_x(science);
2070 ny = cpl_image_get_size_y(science);
2072 sky = cpl_image_new(nx, ny, CPL_TYPE_FLOAT);
2074 sdata = cpl_image_get_data(science);
2075 kdata = cpl_image_get_data(sky);
2077 nslits = cpl_table_get_nrow(slits);
2078 order = cpl_table_get_ncol(polytraces) - 2;
2079 length = cpl_table_get_data_int(slits,
"length");
2080 slit_id = cpl_table_get_data_int(slits,
"slit_id");
2087 pixel_above = STRETCH_FACTOR * (red - reference) / dispersion;
2088 pixel_below = STRETCH_FACTOR * (reference - blue) / dispersion;
2090 for (i = 0; i < nslits; i++) {
2101 refpixel = cpl_table_get_double(slits,
"xtop", i, NULL);
2103 start_pixel = refpixel - pixel_below;
2104 if (start_pixel < 0)
2107 end_pixel = refpixel + pixel_above;
2112 polytop = cpl_polynomial_new(1);
2113 for (k = 0; k <= order; k++) {
2114 coeff = cpl_table_get_double(polytraces, clab[k], 2*i, &null);
2116 cpl_polynomial_delete(polytop);
2120 cpl_polynomial_set_coeff(polytop, &k, coeff);
2124 polybot = cpl_polynomial_new(1);
2125 for (k = 0; k <= order; k++) {
2126 coeff = cpl_table_get_double(polytraces, clab[k], 2*i+1, &null);
2128 cpl_polynomial_delete(polybot);
2132 cpl_polynomial_set_coeff(polybot, &k, coeff);
2135 if (missing_top && missing_bot) {
2136 cpl_msg_debug(func,
"Slit %d was not traced: no extraction!",
2148 cpl_msg_debug(func,
"Upper edge of slit %d was not traced: "
2149 "the spectral curvature of the lower edge "
2150 "is used instead.", slit_id[i]);
2151 polytop = cpl_polynomial_duplicate(polybot);
2152 ytop = cpl_table_get_double(slits,
"ytop", i, NULL);
2153 ybot = cpl_table_get_double(slits,
"ybottom", i, NULL);
2155 coeff = cpl_polynomial_get_coeff(polybot, &k);
2156 coeff += ytop - ybot;
2157 cpl_polynomial_set_coeff(polytop, &k, coeff);
2161 cpl_msg_debug(func,
"Lower edge of slit %d was not traced: "
2162 "the spectral curvature of the upper edge "
2163 "is used instead.", slit_id[i]);
2164 polybot = cpl_polynomial_duplicate(polytop);
2165 ytop = cpl_table_get_double(slits,
"ytop", i, NULL);
2166 ybot = cpl_table_get_double(slits,
"ybottom", i, NULL);
2168 coeff = cpl_polynomial_get_coeff(polytop, &k);
2169 coeff -= ytop - ybot;
2170 cpl_polynomial_set_coeff(polybot, &k, coeff);
2178 for (j = start_pixel; j < end_pixel; j++) {
2179 top = cpl_polynomial_eval_1d(polytop, j, NULL);
2180 bot = cpl_polynomial_eval_1d(polybot, j, NULL);
2181 itop = floor(top + 0.5) + 1;
2182 ibot = floor(bot + 0.5);
2191 list = cpl_bivector_new(npix);
2192 listx = cpl_bivector_get_x(list);
2193 listy = cpl_bivector_get_y(list);
2194 dlistx = cpl_vector_get_data(listx);
2195 dlisty = cpl_vector_get_data(listy);
2197 for (k = 0; k < npix; k++) {
2199 dlisty[k] = sdata[j + (ibot + k)*nx];
2202 if (robustLinearFit(list, &q, &m, &err)) {
2203 cpl_bivector_delete(list);
2207 cpl_bivector_delete(list);
2209 for (k = 0; k < npix; k++) {
2210 kdata[j + (ibot + k)*nx] = m*k + q;
2213 if (npix > window) {
2222 for (k = 0; k < npix; k++)
2223 if (fabs(sdata[j + (ibot + k)*nx] - m*k - q) < err)
2229 list = cpl_bivector_new(count);
2230 listx = cpl_bivector_get_x(list);
2231 listy = cpl_bivector_get_y(list);
2232 dlistx = cpl_vector_get_data(listx);
2233 dlisty = cpl_vector_get_data(listy);
2236 for (k = 0; k < npix; k++) {
2237 if (fabs(sdata[j + (ibot + k)*nx] - m*k - q) < err) {
2239 dlisty[count] = sdata[j + (ibot + k)*nx];
2244 trend = cpl_polynomial_fit_1d_create(listx, listy, 2, &err);
2246 cpl_bivector_delete(list);
2251 for (k = 0; k < npix; k++)
2252 if (fabs(sdata[j + (ibot + k)*nx]
2253 - cpl_polynomial_eval_1d(trend, k, NULL)) < err)
2257 cpl_polynomial_delete(trend);
2261 list = cpl_bivector_new(count);
2262 listx = cpl_bivector_get_x(list);
2263 listy = cpl_bivector_get_y(list);
2264 dlistx = cpl_vector_get_data(listx);
2265 dlisty = cpl_vector_get_data(listy);
2268 for (k = 0; k < npix; k++) {
2269 if (fabs(sdata[j + (ibot + k)*nx]
2270 - cpl_polynomial_eval_1d(trend, k, NULL)) < err) {
2272 dlisty[count] = sdata[j + (ibot + k)*nx];
2277 cpl_polynomial_delete(trend);
2279 trend = cpl_polynomial_fit_1d_create(listx, listy, 3, &err);
2281 cpl_bivector_delete(list);
2283 for (k = 0; k < npix; k++) {
2284 kdata[j + (ibot + k)*nx] = cpl_polynomial_eval_1d(trend,
2288 cpl_polynomial_delete(trend);
2291 cpl_polynomial_delete(polytop);
2292 cpl_polynomial_delete(polybot);
2295 cpl_image_subtract(science, sky);
2334 cpl_table *slits, cpl_table *polytraces,
2335 double reference,
double blue,
double red,
2336 double dispersion,
int sradius,
int polyorder)
2338 const char *func =
"mos_normalise_flat";
2340 const char *clab[6] = {
"c0",
"c1",
"c2",
"c3",
"c4",
"c5"};
2343 cpl_image *rectified;
2344 cpl_image *smo_flat;
2346 cpl_vector *positions;
2348 cpl_vector *smo_flux;
2349 cpl_polynomial *trend;
2350 cpl_polynomial *polytop;
2351 cpl_polynomial *polybot;
2361 double vtop, vbot, value;
2371 int pixel_above, pixel_below, refpixel, start_pixel, end_pixel;
2372 int nx, ny, nsubx, nsuby;
2373 int xlow, ylow, xhig, yhig;
2377 int missing_top, missing_bot;
2390 if (flat == NULL || slits == NULL || polytraces == NULL) {
2391 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
2395 if (dispersion <= 0.0) {
2396 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
2400 if (red - blue < dispersion) {
2401 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
2406 blue, red, dispersion, 0, NULL);
2408 nx = cpl_image_get_size_x(rectified);
2409 ny = cpl_image_get_size_y(rectified);
2411 smo_flat = cpl_image_new(cpl_image_get_size_x(spatial),
2412 cpl_image_get_size_y(spatial), CPL_TYPE_FLOAT);
2413 wdata = cpl_image_get_data(smo_flat);
2415 nslits = cpl_table_get_nrow(slits);
2416 order = cpl_table_get_ncol(polytraces) - 2;
2417 position = cpl_table_get_data_int(slits,
"position");
2418 length = cpl_table_get_data_int(slits,
"length");
2419 slit_id = cpl_table_get_data_int(slits,
"slit_id");
2426 pixel_above = STRETCH_FACTOR * (red - reference) / dispersion;
2427 pixel_below = STRETCH_FACTOR * (reference - blue) / dispersion;
2431 for (i = 0; i < nslits; i++) {
2446 ylow = position[i] + 1;
2447 yhig = ylow + length[i] - 1;
2449 exslit = cpl_image_extract(rectified, xlow, ylow, xhig, yhig);
2451 if (polyorder < 0) {
2453 cpl_image_turn(exslit, -1);
2455 nsubx = cpl_image_get_size_x(exslit);
2456 nsuby = cpl_image_get_size_y(exslit);
2457 data = cpl_image_get_data(exslit);
2458 flux = cpl_vector_new(nsubx);
2460 uradius = nsubx / 2;
2461 if (uradius > sradius)
2464 for (j = 0; j < nsuby; j++) {
2465 fdata = cpl_vector_get_data(flux);
2467 for (k = 0; k < nsubx; k++)
2469 smo_flux = cpl_vector_filter_median_create(flux, uradius);
2470 fdata = cpl_vector_get_data(smo_flux);
2472 for (k = 0; k < nsubx; k++)
2474 cpl_vector_delete(smo_flux);
2478 cpl_vector_delete(flux);
2514 cpl_image_turn(exslit, 1);
2515 nsubx = cpl_image_get_size_x(exslit);
2516 nsuby = cpl_image_get_size_y(exslit);
2517 data = cpl_image_get_data(exslit);
2519 for (j = 0; j < nsuby; j++) {
2520 flux = cpl_vector_new(nsubx);
2521 fdata = cpl_vector_get_data(flux);
2523 for (k = 0; k < nsubx; k++)
2525 smo_flux = cpl_vector_filter_median_create(flux, sradius);
2526 cpl_vector_delete(flux);
2527 fdata = cpl_vector_get_data(smo_flux);
2529 for (k = 0; k < nsubx; k++)
2531 cpl_vector_delete(smo_flux);
2541 nsubx = cpl_image_get_size_x(exslit);
2542 nsuby = cpl_image_get_size_y(exslit);
2543 data = cpl_image_get_data(exslit);
2545 for (j = 0; j < nsuby; j++) {
2553 for (k = 0; k < nsubx; k++)
2557 if (npoints > polyorder + 1) {
2563 flux = cpl_vector_new(npoints);
2564 fdata = cpl_vector_get_data(flux);
2565 positions = cpl_vector_new(npoints);
2566 pdata = cpl_vector_get_data(positions);
2570 for (k = 0; k < nsubx; k++) {
2572 fdata[npoints] = p[k];
2578 trend = cpl_polynomial_fit_1d_create(positions, flux,
2581 cpl_vector_delete(flux);
2582 cpl_vector_delete(positions);
2586 for (k = 0; k < nsubx; k++)
2588 p[k] = cpl_polynomial_eval_1d(trend, k, NULL);
2589 cpl_polynomial_delete(trend);
2592 cpl_msg_warning(func,
"Invalid flat field flux fit "
2605 refpixel = cpl_table_get_double(slits,
"xtop", i, NULL);
2607 start_pixel = refpixel - pixel_below;
2608 if (start_pixel < 0)
2611 end_pixel = refpixel + pixel_above;
2616 polytop = cpl_polynomial_new(1);
2617 for (k = 0; k <= order; k++) {
2618 coeff = cpl_table_get_double(polytraces, clab[k], 2*i, &null);
2620 cpl_polynomial_delete(polytop);
2624 cpl_polynomial_set_coeff(polytop, &k, coeff);
2628 polybot = cpl_polynomial_new(1);
2629 for (k = 0; k <= order; k++) {
2630 coeff = cpl_table_get_double(polytraces, clab[k], 2*i+1, &null);
2632 cpl_polynomial_delete(polybot);
2636 cpl_polynomial_set_coeff(polybot, &k, coeff);
2639 if (missing_top && missing_bot) {
2640 cpl_msg_debug(func,
"Slit %d was not traced: no extraction!",
2652 cpl_msg_debug(func,
"Upper edge of slit %d was not traced: "
2653 "the spectral curvature of the lower edge "
2654 "is used instead.", slit_id[i]);
2655 polytop = cpl_polynomial_duplicate(polybot);
2656 ytop = cpl_table_get_double(slits,
"ytop", i, NULL);
2657 ybot = cpl_table_get_double(slits,
"ybottom", i, NULL);
2659 coeff = cpl_polynomial_get_coeff(polybot, &k);
2660 coeff += ytop - ybot;
2661 cpl_polynomial_set_coeff(polytop, &k, coeff);
2665 cpl_msg_debug(func,
"Lower edge of slit %d was not traced: "
2666 "the spectral curvature of the upper edge "
2667 "is used instead.", slit_id[i]);
2668 polybot = cpl_polynomial_duplicate(polytop);
2669 ytop = cpl_table_get_double(slits,
"ytop", i, NULL);
2670 ybot = cpl_table_get_double(slits,
"ybottom", i, NULL);
2672 coeff = cpl_polynomial_get_coeff(polytop, &k);
2673 coeff -= ytop - ybot;
2674 cpl_polynomial_set_coeff(polybot, &k, coeff);
2685 nx = cpl_image_get_size_x(flat);
2686 ny = cpl_image_get_size_y(flat);
2688 sdata = cpl_image_get_data(spatial);
2689 xdata = cpl_image_get_data(exslit);
2690 npseudo = cpl_image_get_size_y(exslit) - 1;
2696 for (j = start_pixel; j < end_pixel; j++) {
2697 top = cpl_polynomial_eval_1d(polytop, j, NULL);
2698 bot = cpl_polynomial_eval_1d(polybot, j, NULL);
2699 for (k = 0; k <= npseudo; k++) {
2700 ypos = top - k*(top-bot)/npseudo;
2710 if (yint < 0 || yint >= ny-1) {
2715 value = sdata[j + nx*yint];
2717 fvalue = value - ivalue;
2718 if (ivalue < npseudo && ivalue >= 0) {
2719 vtop = xdata[j + nx*(npseudo-ivalue)];
2720 vbot = xdata[j + nx*(npseudo-ivalue-1)];
2721 wdata[j + nx*yint] = vtop*(1-fvalue) + vbot*fvalue;
2731 if (yprev - yint > 1) {
2732 value = sdata[j + nx*(yint+1)];
2734 fvalue = value - ivalue;
2735 if (ivalue < npseudo && ivalue >= 0) {
2736 vtop = xdata[j + nx*(npseudo-ivalue)];
2737 vbot = xdata[j + nx*(npseudo-ivalue-1)];
2738 wdata[j + nx*(yint+1)] = vtop*(1-fvalue)
2747 cpl_polynomial_delete(polytop);
2748 cpl_polynomial_delete(polybot);
2749 cpl_image_delete(exslit);
2752 cpl_image_delete(rectified);
2754 cpl_image_divide(flat, smo_flat);
2787 const char *func =
"mos_normalise_longflat";
2789 cpl_image *smo_flat;
2792 cpl_vector *smo_flux;
2793 cpl_vector *positions;
2794 cpl_polynomial *trend;
2808 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
2812 if (sradius < 1 || dradius < 1) {
2813 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
2817 smo_flat = cpl_image_duplicate(flat);
2819 if (polyorder < 0) {
2825 cpl_image_turn(smo_flat, -1);
2827 nx = cpl_image_get_size_x(smo_flat);
2828 ny = cpl_image_get_size_y(smo_flat);
2829 data = cpl_image_get_data(smo_flat);
2831 for (i = 0; i < ny; i++) {
2832 flux = cpl_vector_new(nx);
2833 fdata = cpl_vector_get_data(flux);
2835 for (j = 0; j < nx; j++)
2837 smo_flux = cpl_vector_filter_median_create(flux, sradius);
2838 cpl_vector_delete(flux);
2839 fdata = cpl_vector_get_data(smo_flux);
2841 for (j = 0; j < nx; j++)
2843 cpl_vector_delete(smo_flux);
2851 cpl_image_turn(smo_flat, 1);
2853 nx = cpl_image_get_size_x(smo_flat);
2854 ny = cpl_image_get_size_y(smo_flat);
2855 data = cpl_image_get_data(smo_flat);
2857 for (i = 0; i < ny; i++) {
2858 flux = cpl_vector_new(nx);
2859 fdata = cpl_vector_get_data(flux);
2861 for (j = 0; j < nx; j++)
2863 smo_flux = cpl_vector_filter_median_create(flux, sradius);
2864 cpl_vector_delete(flux);
2865 fdata = cpl_vector_get_data(smo_flux);
2867 for (j = 0; j < nx; j++)
2869 cpl_vector_delete(smo_flux);
2879 cpl_image_turn(smo_flat, -1);
2881 nx = cpl_image_get_size_x(smo_flat);
2882 ny = cpl_image_get_size_y(smo_flat);
2883 data = cpl_image_get_data(smo_flat);
2885 profile = cpl_image_collapse_median_create(smo_flat, 1, 0, 0);
2886 level = cpl_image_get_data(profile);
2888 for (i = 0; i < ny; i++) {
2898 for (j = 0; j < nx; j++)
2899 if (fabs(p[j]/level[i] - 1) < 0.20)
2902 if (npoints > polyorder + 1) {
2908 flux = cpl_vector_new(npoints);
2909 fdata = cpl_vector_get_data(flux);
2910 positions = cpl_vector_new(npoints);
2911 pdata = cpl_vector_get_data(positions);
2915 for (j = 0; j < nx; j++) {
2916 if (fabs(p[j]/level[i] - 1) < 0.20) {
2917 fdata[npoints] = p[j];
2923 trend = cpl_polynomial_fit_1d_create(positions, flux,
2926 cpl_vector_delete(flux);
2927 cpl_vector_delete(positions);
2931 for (j = 0; j < nx; j++)
2932 p[j] = cpl_polynomial_eval_1d(trend, j, NULL);
2933 cpl_polynomial_delete(trend);
2936 cpl_msg_warning(func,
2937 "Invalid flat field flux fit (ignored)");
2942 cpl_image_delete(profile);
2943 cpl_image_turn(smo_flat, 1);
2947 cpl_image_divide(flat, smo_flat);
2977 int order,
int global)
2979 const char *clab[6] = {
"c0",
"c1",
"c2",
"c3",
"c4",
"c5"};
2981 int nrow = cpl_table_get_nrow(slits);
2986 return CPL_ERROR_NONE;
2988 cpl_table_new_column(idscoeff,
"x", CPL_TYPE_DOUBLE);
2989 cpl_table_new_column(idscoeff,
"y", CPL_TYPE_DOUBLE);
2991 for (i = 0; i < nrow; i++) {
2992 int position = cpl_table_get_int (slits,
"position", i, NULL);
2993 int length = cpl_table_get_int (slits,
"length", i, NULL);
2994 double xtop = cpl_table_get_double(slits,
"xtop", i, NULL);
2995 double xbot = cpl_table_get_double(slits,
"xbottom", i, NULL);
2996 double ytop = cpl_table_get_double(slits,
"ytop", i, NULL);
2997 double ybot = cpl_table_get_double(slits,
"ybottom", i, NULL);
2998 double dx = xtop - xbot;
2999 double dy = ytop - ybot;
3000 cpl_table *table = cpl_table_extract(idscoeff, position, length);
3005 cpl_table_erase_window(idscoeff, position, length);
3006 cpl_table_insert(idscoeff, table, position);
3008 cpl_table_delete(table);
3010 for (j = 0; j < length; j++) {
3011 cpl_table_set_double(idscoeff,
"x", j + position,
3012 xbot + j*(dx/length));
3013 cpl_table_set_double(idscoeff,
"y", j + position,
3014 ybot + j*(dy/length));
3024 nrow = cpl_table_get_nrow(idscoeff);
3026 for (i = 0; i < 6; i++) {
3037 if (!cpl_table_has_column(idscoeff, clab[i]))
3040 npoints = nrow - cpl_table_count_invalid(idscoeff, clab[i]);
3044 dummy = cpl_table_new(nrow);
3045 cpl_table_duplicate_column(dummy,
"x", idscoeff,
"x");
3046 cpl_table_duplicate_column(dummy,
"y", idscoeff,
"y");
3047 cpl_table_duplicate_column(dummy, clab[i], idscoeff, clab[i]);
3048 cpl_table_erase_invalid(dummy);
3050 x = cpl_vector_wrap(npoints, cpl_table_get_data_double(dummy,
"x"));
3051 y = cpl_vector_wrap(npoints, cpl_table_get_data_double(dummy,
"y"));
3052 z = cpl_bivector_wrap_vectors(x, y);
3053 c = cpl_vector_wrap(npoints, cpl_table_get_data_double(dummy,
3055 p = cpl_polynomial_fit_2d_create(z, c, 2, NULL);
3056 cpl_bivector_unwrap_vectors(z);
3057 cpl_vector_unwrap(x);
3058 cpl_vector_unwrap(y);
3059 cpl_vector_unwrap(c);
3060 cpl_table_delete(dummy);
3062 point = cpl_vector_new(2);
3063 dpoint = cpl_vector_get_data(point);
3064 for (j = 0; j < nrow; j++) {
3065 dpoint[0] = cpl_table_get_double(idscoeff,
"x", j, NULL);
3066 dpoint[1] = cpl_table_get_double(idscoeff,
"y", j, NULL);
3067 cpl_table_set_double(idscoeff, clab[i], j,
3068 cpl_polynomial_eval(p, point));
3070 cpl_vector_delete(point);
3071 cpl_polynomial_delete(p);
3075 return CPL_ERROR_NONE;
3105 cpl_image *wavemap,
int mode,
3108 const char *func =
"mos_interpolate_wavecalib";
3110 const char *clab[6] = {
"c0",
"c1",
"c2",
"c3",
"c4",
"c5"};
3114 cpl_vector *positions;
3115 cpl_polynomial *trend;
3126 int nrows, first_row, last_row;
3128 int npoints, rpoints;
3135 if (idscoeff == NULL)
3136 return cpl_error_set(func, CPL_ERROR_NULL_INPUT);
3138 if (mode < 0 || mode > 2)
3139 return cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
3141 if (mode == 0 || degree < 0)
3142 return CPL_ERROR_NONE;
3150 cpl_image_turn(wavemap, -1);
3152 nx = cpl_image_get_size_x(wavemap);
3153 ny = cpl_image_get_size_y(wavemap);
3154 data = cpl_image_get_data(wavemap);
3156 for (i = 0; i < ny; i++) {
3165 for (j = 0; j < nx; j++)
3169 if (npoints > polyorder + 1) {
3175 wave = cpl_vector_new(npoints);
3176 wdata = cpl_vector_get_data(wave);
3177 positions = cpl_vector_new(npoints);
3178 pdata = cpl_vector_get_data(positions);
3182 for (j = 0; j < nx; j++) {
3184 wdata[npoints] = p[j];
3190 trend = cpl_polynomial_fit_1d_create(positions, wave,
3193 ksigma = 3*sqrt(mse);
3195 cpl_vector_delete(wave);
3196 cpl_vector_delete(positions);
3206 for (j = 0; j < nx; j++)
3208 if (fabs(cpl_polynomial_eval_1d(trend, j, NULL)
3212 if (rpoints < npoints && rpoints > polyorder + 1) {
3214 wave = cpl_vector_new(rpoints);
3215 wdata = cpl_vector_get_data(wave);
3216 positions = cpl_vector_new(rpoints);
3217 pdata = cpl_vector_get_data(positions);
3221 for (j = 0; j < nx; j++) {
3223 if (fabs(cpl_polynomial_eval_1d(trend,
3226 wdata[npoints] = p[j];
3233 cpl_polynomial_delete(trend);
3234 trend = cpl_polynomial_fit_1d_create(positions, wave,
3237 cpl_vector_delete(wave);
3238 cpl_vector_delete(positions);
3245 for (j = 0; j < nx; j++)
3247 p[j] = cpl_polynomial_eval_1d(trend, j, NULL);
3249 else if (mode == 2) {
3250 for (j = 0; j < nx; j++)
3251 p[j] = cpl_polynomial_eval_1d(trend, j, NULL);
3253 cpl_polynomial_delete(trend);
3256 cpl_msg_warning(func,
3257 "Invalid wavelength field fit (ignored)");
3263 cpl_image_turn(wavemap, 1);
3272 nrows = cpl_table_get_nrow(idscoeff);
3275 while (order < 6 && cpl_table_has_column(idscoeff, clab[order]))
3280 for (k = 0; k <= order; k++) {
3282 if (cpl_table_has_column(idscoeff, clab[k])) {
3283 m = cpl_table_get_column_median(idscoeff, clab[k]);
3284 cpl_table_fill_column_window_double(idscoeff, clab[k],
3289 return CPL_ERROR_NONE;
3293 while (!cpl_table_is_valid(idscoeff, clab[0], first_row))
3296 last_row = nrows - 1;
3297 while (!cpl_table_is_valid(idscoeff, clab[0], last_row))
3300 for (k = 0; k <= order; k++) {
3302 npoints = nrows - cpl_table_count_invalid(idscoeff, clab[k]);
3303 wave = cpl_vector_new(npoints);
3304 wdata = cpl_vector_get_data(wave);
3305 positions = cpl_vector_new(npoints);
3306 pdata = cpl_vector_get_data(positions);
3309 for (i = first_row; i <= last_row; i++) {
3310 c = cpl_table_get_double(idscoeff, clab[k], i, &null);
3328 p = cpl_vector_extract(positions, 2, npoints - 2, 1);
3329 w = cpl_vector_extract(wave, 2, npoints - 2, 1);
3336 list = cpl_bivector_wrap_vectors(p, w);
3338 robustLinearFit(list, &q, &m, &mse);
3339 cpl_bivector_unwrap_vectors(list);
3340 for (i = first_row; i <= last_row; i++)
3341 cpl_table_set_double(idscoeff, clab[k], i, q + m*i);
3344 cpl_vector_delete(p);
3345 cpl_vector_delete(w);
3348 cpl_vector_delete(wave);
3349 cpl_vector_delete(positions);
3356 trend = cpl_polynomial_fit_1d_create(positions, wave, degree, &mse);
3358 ksigma = 3*sqrt(mse);
3360 cpl_vector_delete(wave);
3361 cpl_vector_delete(positions);
3369 for (i = first_row; i <= last_row; i++) {
3370 c = cpl_table_get_double(idscoeff, clab[k], i, &null);
3372 if (fabs(cpl_polynomial_eval_1d(trend, i, NULL) - c)
3379 if (rpoints > 0 && rpoints < npoints) {
3380 cpl_msg_debug(func,
"%d points rejected from "
3381 "wavelength calibration fit",
3384 wave = cpl_vector_new(rpoints);
3385 wdata = cpl_vector_get_data(wave);
3386 positions = cpl_vector_new(rpoints);
3387 pdata = cpl_vector_get_data(positions);
3390 for (i = first_row; i <= last_row; i++) {
3391 c = cpl_table_get_double(idscoeff, clab[k], i, &null);
3393 if (fabs(cpl_polynomial_eval_1d(trend, i, NULL) - c)
3403 cpl_polynomial_delete(trend);
3404 trend = cpl_polynomial_fit_1d_create(positions,
3405 wave, degree, NULL);
3408 cpl_vector_delete(wave);
3409 cpl_vector_delete(positions);
3415 for (i = first_row; i <= last_row; i++) {
3417 if (!cpl_table_is_valid(idscoeff, clab[k], i)) {
3418 cpl_table_set_double(idscoeff, clab[k], i,
3419 cpl_polynomial_eval_1d(trend, i,
3423 else if (mode == 2) {
3424 cpl_table_set_double(idscoeff, clab[k], i,
3425 cpl_polynomial_eval_1d(trend, i, NULL));
3428 cpl_polynomial_delete(trend);
3431 cpl_msg_warning(func,
"Invalid IDS coefficient fit (ignored)");
3436 return CPL_ERROR_NONE;
3460 const char *func =
"mos_interpolate_wavecalib";
3462 const char *clab[6] = {
"c0",
"c1",
"c2",
"c3",
"c4",
"c5"};
3466 cpl_vector *positions;
3467 cpl_polynomial *trend;
3476 int nrows, first_row, last_row;
3477 int npoints, rpoints;
3482 if (idscoeff == NULL)
3483 return cpl_error_set(func, CPL_ERROR_NULL_INPUT);
3485 if (mode < 0 || mode > 2)
3486 return cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
3488 if (mode == 0 || degree < 0)
3489 return CPL_ERROR_NONE;
3495 nrows = cpl_table_get_nrow(idscoeff);
3498 while (order < 6 && cpl_table_has_column(idscoeff, clab[order]))
3507 for (
int k = kinit; k <= order; k++) {
3509 if (cpl_table_has_column(idscoeff, clab[k])) {
3510 m = cpl_table_get_column_median(idscoeff, clab[k]);
3511 cpl_table_fill_column_window_double(idscoeff, clab[k],
3519 while (!cpl_table_is_valid(idscoeff, clab[0], first_row))
3522 last_row = nrows - 1;
3523 while (!cpl_table_is_valid(idscoeff, clab[0], last_row))
3528 npoints = nrows - cpl_table_count_invalid(idscoeff, clab[korder]);
3529 wave = cpl_vector_new(npoints);
3530 wdata = cpl_vector_get_data(wave);
3531 positions = cpl_vector_new(npoints);
3532 pdata = cpl_vector_get_data(positions);
3535 for (i = first_row; i <= last_row; i++) {
3536 c = cpl_table_get_double(idscoeff, clab[korder], i, &null);
3554 p = cpl_vector_extract(positions, 2, npoints - 2, 1);
3555 w = cpl_vector_extract(wave, 2, npoints - 2, 1);
3562 list = cpl_bivector_wrap_vectors(p, w);
3564 robustLinearFit(list, &q, &m, &mse);
3565 cpl_bivector_unwrap_vectors(list);
3566 for (i = first_row; i <= last_row; i++)
3567 cpl_table_set_double(idscoeff, clab[korder], i, q + m*i);
3570 cpl_vector_delete(p);
3571 cpl_vector_delete(w);
3574 cpl_vector_delete(wave);
3575 cpl_vector_delete(positions);
3583 trend = cpl_polynomial_fit_1d_create(positions, wave, degree, &mse);
3585 ksigma = 3*sqrt(mse);
3587 cpl_vector_delete(wave);
3588 cpl_vector_delete(positions);
3596 for (i = first_row; i <= last_row; i++) {
3597 c = cpl_table_get_double(idscoeff, clab[korder], i, &null);
3599 if (fabs(cpl_polynomial_eval_1d(trend, i, NULL) - c)
3606 if (rpoints > 0 && rpoints < npoints) {
3607 cpl_msg_debug(func,
"%d points rejected from "
3608 "wavelength calibration fit",
3611 wave = cpl_vector_new(rpoints);
3612 wdata = cpl_vector_get_data(wave);
3613 positions = cpl_vector_new(rpoints);
3614 pdata = cpl_vector_get_data(positions);
3617 for (i = first_row; i <= last_row; i++) {
3618 c = cpl_table_get_double(idscoeff, clab[korder], i, &null);
3620 if (fabs(cpl_polynomial_eval_1d(trend, i, NULL) - c)
3630 cpl_polynomial_delete(trend);
3631 trend = cpl_polynomial_fit_1d_create(positions,
3632 wave, degree, NULL);
3635 cpl_vector_delete(wave);
3636 cpl_vector_delete(positions);
3642 for (i = first_row; i <= last_row; i++) {
3644 if (!cpl_table_is_valid(idscoeff, clab[korder], i)) {
3645 cpl_table_set_double(idscoeff, clab[korder], i,
3646 cpl_polynomial_eval_1d(trend, i,
3650 else if (mode == 2) {
3651 cpl_table_set_double(idscoeff, clab[korder], i,
3652 cpl_polynomial_eval_1d(trend, i, NULL));
3655 cpl_polynomial_delete(trend);
3658 cpl_msg_warning(func,
"Invalid IDS coefficient fit (ignored)");
3663 return CPL_ERROR_NONE;
3695 cpl_table *overscans)
3697 const char *func =
"mos_remove_bias";
3699 cpl_image *unbiased;
3700 cpl_image *overscan;
3701 double mean_bias_level;
3702 double mean_overscans_level;
3705 int xlow, ylow, xhig, yhig;
3709 if (image == NULL || overscans == NULL) {
3710 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
3714 nrows = cpl_table_get_nrow(overscans);
3717 cpl_msg_error(func,
"Empty overscan table");
3718 cpl_error_set(func, CPL_ERROR_DATA_NOT_FOUND);
3724 unbiased = cpl_image_subtract_create(image, bias);
3725 if (unbiased == NULL) {
3726 cpl_msg_error(func,
"Incompatible master bias");
3727 cpl_error_set(func, CPL_ERROR_INCOMPATIBLE_INPUT);
3731 mean_bias_level = cpl_image_get_mean(bias);
3735 cpl_msg_error(func,
"No master bias in input, and no overscan "
3736 "regions in input image: bias subtraction "
3737 "cannot be performed!");
3738 cpl_error_set(func, CPL_ERROR_DATA_NOT_FOUND);
3741 mean_bias_level = 0.0;
3744 mean_overscans_level = 0.0;
3746 for (i = 0; i < nrows; i++) {
3747 xlow = cpl_table_get_int(overscans,
"xlow", i, NULL);
3748 ylow = cpl_table_get_int(overscans,
"ylow", i, NULL);
3749 xhig = cpl_table_get_int(overscans,
"xhig", i, NULL);
3750 yhig = cpl_table_get_int(overscans,
"yhig", i, NULL);
3753 unbiased = cpl_image_extract(image, xlow+1, ylow+1, xhig, yhig);
3754 if (unbiased == NULL) {
3755 cpl_msg_error(func,
"Incompatible overscan table");
3756 cpl_error_set(func, CPL_ERROR_INCOMPATIBLE_INPUT);
3760 if (cpl_image_subtract(unbiased, bias)) {
3761 cpl_msg_error(func,
"Incompatible master bias");
3762 cpl_error_set(func, CPL_ERROR_INCOMPATIBLE_INPUT);
3763 cpl_image_delete(unbiased);
3769 overscan = cpl_image_extract(image, xlow+1, ylow+1, xhig, yhig);
3770 if (overscan == NULL) {
3771 cpl_msg_error(func,
"Incompatible overscan table");
3772 cpl_error_set(func, CPL_ERROR_INCOMPATIBLE_INPUT);
3773 cpl_image_delete(unbiased);
3777 mean_overscans_level += cpl_image_get_median(overscan);
3787 cpl_image_delete(overscan);
3795 mean_overscans_level /= count;
3797 cpl_image_subtract_scalar(unbiased, mean_overscans_level - mean_bias_level);
3799 cpl_msg_info(cpl_func,
3800 "Difference between mean overscans level "
3801 "and mean bias level: %.2f",
3802 mean_overscans_level - mean_bias_level);
3868 int length,
int msize,
int fsize)
3870 const char *func =
"mos_arc_background_1D";
3878 if (spectrum == NULL || back == NULL)
3879 return cpl_error_set(func, CPL_ERROR_NULL_INPUT);
3887 if (msize < 3 || fsize < msize || length < 2*fsize)
3888 return cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
3891 minf = min_filter(spectrum, length, msize);
3892 smof = smo_filter(minf, length, fsize);
3894 maxf = max_filter(smof, length, 2*msize+1);
3896 smof = smo_filter(maxf, length, 2*fsize+1);
3898 minf = min_filter(smof, length, 2*msize+1);
3900 smof = smo_filter(minf, length, 2*fsize+1);
3903 for (i = 0; i < length; i++)
3908 return CPL_ERROR_NONE;
3971 const char *func =
"mos_arc_background";
3983 if (image == NULL) {
3984 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
3994 nx = cpl_image_get_size_x(image);
3995 ny = cpl_image_get_size_y(image);
3997 bimage = cpl_image_new(nx, ny, CPL_TYPE_FLOAT);
4001 data = cpl_image_get_data_float(fimage);
4002 bdata = cpl_image_get_data_float(bimage);
4004 for (i = 0; i < ny; i++) {
4005 row = data + i * nx;
4006 brow = bdata + i * nx;
4008 cpl_error_set_where(func);
4009 cpl_image_delete(fimage);
4010 cpl_image_delete(bimage);
4015 cpl_image_delete(fimage);
4044 const char *func =
"mos_lines_width";
4046 double *profile1 = cpl_calloc(length - 1,
sizeof(
double));
4047 double *profile2 = cpl_calloc(length - 1,
sizeof(
double));
4049 double norm, value, max;
4051 int short_length = length - 2*radius - 1;
4060 for (j = 0, i = 1; i < length; j++, i++) {
4061 profile1[j] = profile2[j] = spectrum[i] - spectrum[j];
4062 if (profile1[j] < 0)
4064 if (profile2[j] > 0)
4067 profile2[j] = -profile2[j];
4078 for (i = 0; i < length; i++)
4079 if (norm < profile1[i])
4082 for (i = 0; i < length; i++) {
4083 profile1[i] /= norm;
4084 profile2[i] /= norm;
4093 for (i = 0; i <= radius; i++) {
4095 for (j = 0; j < short_length; j++) {
4097 value += profile1[k] * profile2[k+i];
4109 cpl_msg_debug(func,
"Cannot estimate line width");
4145 int length,
float level,
4149 const char *func =
"mos_peak_candidates";
4152 int nint = length - 1;
4154 int width = 2 * ceil(exp_width / 2) + 1;
4155 int start = width / 2;
4156 int end = length - width / 2;
4159 double *data = cpl_calloc(length/2,
sizeof(
double));
4162 if (spectrum == NULL) {
4163 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
4174 smo = cpl_calloc(length,
sizeof(
float));
4176 end = length - width / 2;
4177 for (i = 0; i < start; i++)
4178 smo[i] = spectrum[i];
4179 for (i = start; i < end; i++) {
4180 for (j = i - start; j <= i + start; j++)
4181 smo[i] += spectrum[j];
4184 for (i = end; i < length; i++)
4185 smo[i] = spectrum[i];
4188 smo = (
float *)spectrum;
4201 for (i = step; i < nint - step + 1; i += step) {
4202 if (smo[i] > level) {
4203 if (smo[i] >= smo[i-step] && smo[i] > smo[i+step]) {
4204 if (smo[i-step] != 0.0 && smo[i+step] != 0.0) {
4205 data[n] = i + step * values_to_dx(smo[i-step], smo[i], smo[i+step]);
4221 return cpl_vector_wrap(n, data);
4248 cpl_vector *peaks,
int sradius)
4251 const char *func =
"mos_refine_peaks";
4256 int startPos, endPos;
4257 int window = 2*sradius+1;
4261 if (peaks == NULL || spectrum == NULL) {
4262 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
4266 npeaks = cpl_vector_get_size(peaks);
4267 data = cpl_vector_unwrap(peaks);
4269 for (i = 0; i < npeaks; i++) {
4270 startPos = data[i] - window/2;
4271 endPos = startPos + window;
4272 if (startPos < 0 || endPos >= length)
4275 if (0 == peakPosition(spectrum + startPos, window, &pos, 1)) {
4281 for (i = 1; i < npeaks; i++)
4282 if (data[i] - data[i-1] < 0.5)
4285 for (i = 0, j = 0; i < npeaks; i++) {
4286 if (data[i] > 0.0) {
4293 return cpl_vector_wrap(j, data);
4298 void mos_set_multiplex(
int multiplex)
4300 mos_multiplex = multiplex;
4357 double min_disp,
double max_disp,
4365 double lratio, pratio;
4366 double lo_start, lo_end, hi_start, hi_end, denom;
4367 double disp, variation, prev_variation;
4368 int max, maxpos, minl, mink;
4370 int npeaks_lo, npeaks_hi;
4395 peak = cpl_vector_get_data(peaks);
4396 npeaks = cpl_vector_get_size(peaks);
4397 line = cpl_vector_get_data(lines);
4398 nlines = cpl_vector_get_size(lines);
4403 peak_lo = cpl_malloc(npeaks *
sizeof(
int));
4404 peak_hi = cpl_malloc(npeaks *
sizeof(
int));
4405 nident = cpl_calloc(npeaks,
sizeof(
int));
4406 lident = cpl_calloc(nlines,
sizeof(
int));
4407 xpos = cpl_calloc(npeaks,
sizeof(
double));
4408 lambda = cpl_calloc(npeaks,
sizeof(
double));
4409 ilambda = cpl_calloc(npeaks,
sizeof(
int));
4410 tmp_xpos = cpl_calloc(npeaks,
sizeof(
double));
4411 tmp_lambda = cpl_calloc(npeaks,
sizeof(
double));
4412 tmp_ilambda = cpl_calloc(npeaks,
sizeof(
int));
4413 flag = cpl_calloc(npeaks,
sizeof(
int));
4414 seq_length = cpl_calloc(npeaks,
sizeof(
int));
4415 ident = cpl_malloc(npeaks *
sizeof(
int *));
4416 for (i = 0; i < npeaks; i++)
4417 ident[i] = cpl_malloc(3 * npeaks *
sizeof(
int));
4432 for (i = 1; i < nlint; i++) {
4442 lratio = (line[i+1] - line[i]) / (line[i] - line[i-1]);
4449 for (j = 1; j < npint; j++) {
4462 lo_start = peak[j] - (line[i] - line[i-1]) / min_disp;
4463 lo_end = peak[j] - (line[i] - line[i-1]) / max_disp;
4464 hi_start = peak[j] + (line[i+1] - line[i]) / max_disp;
4465 hi_end = peak[j] + (line[i+1] - line[i]) / min_disp;
4467 for (npeaks_lo = 0, k = 0; k < npeaks; k++) {
4468 if (peak[k] > lo_end)
4470 if (peak[k] > lo_start) {
4471 peak_lo[npeaks_lo] = k;
4479 for (npeaks_hi = 0, k = 0; k < npeaks; k++) {
4480 if (peak[k] > hi_end)
4482 if (peak[k] > hi_start) {
4483 peak_hi[npeaks_hi] = k;
4500 prev_variation = 1000.0;
4503 for (k = 0; k < npeaks_lo; k++) {
4504 denom = peak[j] - peak[peak_lo[k]];
4505 for (l = 0; l < npeaks_hi; l++) {
4513 pratio = (peak[peak_hi[l]] - peak[j]) / denom;
4526 variation = fabs(lratio-pratio) / pratio;
4528 if (variation < tolerance) {
4529 if (variation < prev_variation) {
4530 prev_variation = variation;
4537 if (prev_variation < tolerance) {
4538 ident[j][nident[j]] = i;
4539 ident[peak_hi[minl]][nident[peak_hi[minl]]] = i + 1;
4540 ident[peak_lo[mink]][nident[peak_lo[mink]]] = i - 1;
4542 ++nident[peak_hi[minl]];
4543 ++nident[peak_lo[mink]];
4555 for (i = 0; i < npeaks; i++) {
4564 if (nident[i] > 1) {
4571 for (j = 0; j < nlines; j++)
4580 for (j = 0; j < nident[i]; j++)
4581 ++lident[ident[i][j]];
4590 for (j = 0; j < nlines; j++) {
4591 if (max < lident[j]) {
4606 for (k = maxpos + 1; k < nlines; k++) {
4607 if (lident[k] == max) {
4622 tmp_xpos[n] = peak[i];
4623 tmp_lambda[n] = line[maxpos];
4624 tmp_ilambda[n] = maxpos;
4648 for (k = 0; k < n; k++) {
4651 xpos[nn] = tmp_xpos[k];
4652 lambda[nn] = tmp_lambda[k];
4653 ilambda[nn] = tmp_ilambda[k];
4666 for (j = i + 1; j < n; j++) {
4668 disp = (tmp_lambda[j] - tmp_lambda[i])
4669 / (tmp_xpos[j] - tmp_xpos[i]);
4670 if (disp >= min_disp && disp <= max_disp) {
4672 xpos[nn] = tmp_xpos[j];
4673 lambda[nn] = tmp_lambda[j];
4674 ilambda[nn] = tmp_ilambda[j];
4704 if (mos_multiplex < 0) {
4705 for (i = 0; i < nseq; i++) {
4706 if (seq_length[i] > max) {
4707 max = seq_length[i];
4723 for (i = 0; i < nseq; i++) {
4726 cpl_array *regions = cpl_array_new(n, CPL_TYPE_INT);
4729 for (j = 0; j < n; j++)
4730 cpl_array_set_int(regions, j,
4731 ((
int)floor(xpos[nn + j])) / mos_region_size);
4733 region = (int)cpl_array_get_median(regions);
4734 cpl_array_delete(regions);
4736 if (mos_multiplex == region) {
4738 cpl_msg_debug(cpl_func,
"More than one spectrum found in "
4739 "region %d (only the first one is extracted)",
4744 max = seq_length[i];
4748 nn += seq_length[i];
4758 for (i = 0; i < maxpos; i++)
4759 nn += seq_length[i];
4766 for (i = 0; i < n; i++, nn++) {
4768 lambda[i] = lambda[nn];
4769 ilambda[i] = ilambda[nn];
4777 for (i = 1; i < n; i++) {
4778 gap = ilambda[i] - ilambda[i-1];
4779 for (j = 1; j < gap; j++) {
4787 disp = (lambda[i] - lambda[i-1]) / (xpos[i] - xpos[i-1]);
4795 hi_start = xpos[i-1] + (line[ilambda[i-1] + j] - lambda[i-1]) / disp;
4810 for (k = 0; k < npeaks; k++) {
4811 if (fabs(peak[k] - hi_start) < 2) {
4812 for (l = n; l > i; l--) {
4813 xpos[l] = xpos[l-1];
4814 lambda[l] = lambda[l-1];
4815 ilambda[l] = ilambda[l-1];
4818 lambda[i] = line[ilambda[i-1] + j];
4819 ilambda[i] = ilambda[i-1] + j;
4836 while (ilambda[n-1] < nlines - 1 && found) {
4844 disp = (lambda[n-1] - lambda[n-2]) / (xpos[n-1] - xpos[n-2]);
4848 if (disp > max_disp || disp < min_disp)
4857 hi_start = xpos[n-1] + (line[ilambda[n-1] + 1] - lambda[n-1]) / disp;
4868 min = fabs(peak[0] - hi_start);
4870 for (k = 1; k < npeaks; k++) {
4871 if (min > fabs(peak[k] - hi_start)) {
4872 min = fabs(peak[k] - hi_start);
4876 if (min < 6 && fabs(peak[minpos] - xpos[n-1]) > 1.0) {
4877 xpos[n] = peak[minpos];
4878 lambda[n] = line[ilambda[n-1] + 1];
4879 ilambda[n] = ilambda[n-1] + 1;
4891 while (ilambda[0] > 0 && found) {
4898 disp = (lambda[1] - lambda[0]) / (xpos[1] - xpos[0]);
4900 if (disp > max_disp || disp < min_disp)
4909 hi_start = xpos[0] - (lambda[0] - line[ilambda[0] - 1]) / disp;
4921 min = fabs(peak[0] - hi_start);
4923 for (k = 1; k < npeaks; k++) {
4924 if (min > fabs(peak[k] - hi_start)) {
4925 min = fabs(peak[k] - hi_start);
4929 if (min < 6 && fabs(peak[minpos] - xpos[0]) > 1.0) {
4930 for (j = n; j > 0; j--) {
4931 xpos[j] = xpos[j-1];
4932 lambda[j] = lambda[j-1];
4933 ilambda[j] = ilambda[j-1];
4935 xpos[0] = peak[minpos];
4936 lambda[0] = line[ilambda[0] - 1];
4937 ilambda[0] = ilambda[0] - 1;
4963 for (i = 0; i < npeaks; i++)
4970 cpl_free(tmp_lambda);
4971 cpl_free(tmp_ilambda);
4974 cpl_free(seq_length);
4983 return cpl_bivector_wrap_vectors(cpl_vector_wrap(n, xpos),
4984 cpl_vector_wrap(n, lambda));
5046 double refwave,
double pixel)
5052 if (cpl_polynomial_eval_1d(ids, blue-refwave, NULL) > pixel)
5055 if (cpl_polynomial_eval_1d(ids, red-refwave, NULL) < pixel)
5058 yellow = (blue + red) / 2 - refwave;
5060 coeff = cpl_polynomial_get_coeff(ids, &zero);
5061 cpl_polynomial_set_coeff(ids, &zero, coeff - pixel);
5063 cpl_polynomial_solve_1d(ids, yellow, &yellow, 1);
5064 if (cpl_error_get_code() != CPL_ERROR_NONE) {
5069 cpl_polynomial_set_coeff(ids, &zero, coeff);
5071 return yellow + refwave;
5101 double reject,
int minlines,
5102 int *nlines,
double *err)
5104 const char *func =
"mos_poly_wav2pix";
5106 cpl_bivector *pixwav2;
5116 cpl_polynomial *ids;
5122 if (pixwav == NULL) {
5123 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
5127 fitlines = cpl_bivector_get_size(pixwav);
5129 if (fitlines < minlines) {
5130 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
5144 pixwav2 = cpl_bivector_duplicate(pixwav);
5154 pixel = cpl_bivector_get_x(pixwav2);
5155 wavel = cpl_bivector_get_y(pixwav2);
5163 cpl_bivector_unwrap_vectors(pixwav2);
5170 while (fitlines >= minlines) {
5172 ids = cpl_polynomial_fit_1d_create(wavel, pixel, order, err);
5176 cpl_msg_debug(cpl_error_get_where(),
"%s", cpl_error_get_message());
5177 cpl_msg_debug(func,
"Fitting IDS");
5178 cpl_error_set_where(func);
5180 cpl_vector_delete(wavel);
5181 cpl_vector_delete(pixel);
5193 d_pixel = cpl_vector_unwrap(pixel);
5194 d_wavel = cpl_vector_unwrap(wavel);
5196 for (i = 0, j = 0; i < fitlines; i++) {
5197 pixpos = cpl_polynomial_eval_1d(ids, d_wavel[i], NULL);
5198 if (fabs(pixpos - d_pixel[i]) < reject) {
5199 d_pixel[j] = d_pixel[i];
5200 d_wavel[j] = d_wavel[i];
5205 if (j == fitlines) {
5213 cpl_polynomial_delete(ids);
5214 if (fitlines >= minlines) {
5215 pixel = cpl_vector_wrap(fitlines, d_pixel);
5216 wavel = cpl_vector_wrap(fitlines, d_wavel);
5221 cpl_error_set(func, CPL_ERROR_CONTINUE);
5261 double reject,
int minlines,
5262 int *nlines,
double *err)
5265 cpl_bivector *wavpix;
5269 cpl_polynomial *dds;
5276 pixel = cpl_bivector_get_x(pixwav);
5277 wavel = cpl_bivector_get_y(pixwav);
5279 wavpix = cpl_bivector_wrap_vectors(wavel, pixel);
5283 cpl_bivector_unwrap_vectors(wavpix);
5313 cpl_vector *lines, cpl_polynomial *ids,
5314 double refwave,
int sradius)
5316 const char *func =
"mos_find_peaks";
5327 if (spectrum == NULL || lines == NULL || ids == NULL) {
5328 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
5332 nlines = cpl_vector_get_size(lines);
5334 if (sradius < 1 || length < 2*sradius+1 || nlines < 1) {
5335 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
5339 d_wavel = cpl_malloc(nlines *
sizeof(
double));
5340 d_pixel = cpl_malloc(nlines *
sizeof(
double));
5342 data = cpl_vector_get_data(lines);
5344 for (i = 0, j = 0; i < nlines; i++) {
5345 pixel = cpl_polynomial_eval_1d(ids, data[i]-refwave, NULL) + 0.5;
5346 if (pixel < 0 || pixel - sradius < 0 || pixel + sradius >= length)
5348 if (peakPosition(spectrum+pixel-sradius, 2*sradius+1, &pos, 1) == 0) {
5349 pos += pixel - sradius;
5351 d_wavel[j] = data[i];
5357 return cpl_bivector_wrap_vectors(cpl_vector_wrap(j, d_pixel),
5358 cpl_vector_wrap(j, d_wavel));
5363 cpl_error_set(func, CPL_ERROR_ILLEGAL_OUTPUT);
5494 double dispersion,
float level,
5495 int sradius,
int order,
5496 double reject,
double refwave,
5497 double *wavestart,
double *waveend,
5498 int *nlines,
double *error,
5499 cpl_table *idscoeff,
5500 cpl_image *calibration,
5501 cpl_image *residuals,
5502 cpl_table *restable,
5504 cpl_table *detected_lines)
5507 const char *func =
"mos_wavelength_calibration_raw";
5509 const char *clab[6] = {
"c0",
"c1",
"c2",
"c3",
"c4",
"c5"};
5512 double tolerance = 20.0;
5515 char name[MAX_COLNAME];
5516 cpl_image *resampled;
5517 cpl_bivector *output;
5518 cpl_bivector *new_output;
5521 cpl_polynomial *ids;
5522 cpl_polynomial *lin;
5525 double max_disp, min_disp;
5527 double firstLambda, lastLambda, lambda;
5528 double value, wave, pixe;
5537 int pixstart, pixend;
5540 int nl, nx, ny, pixel;
5541 int countLines, usedLines;
5543 int in, first, last;
5550 if (dispersion == 0.0) {
5551 cpl_msg_error(func,
"The expected dispersion (A/pixel) must be given");
5552 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
5556 if (dispersion < 0.0) {
5557 cpl_msg_error(func,
"The expected dispersion must be positive");
5558 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
5562 max_disp = dispersion + dispersion * tolerance / 100;
5563 min_disp = dispersion - dispersion * tolerance / 100;
5566 cpl_msg_error(func,
"The order of the fitting polynomial "
5567 "must be at least 1");
5568 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
5572 if (image == NULL || lines == NULL) {
5573 cpl_msg_error(func,
"Both spectral exposure and reference line "
5574 "catalog are required in input");
5575 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
5579 nx = cpl_image_get_size_x(image);
5580 ny = cpl_image_get_size_y(image);
5581 sdata = cpl_image_get_data_float_const(image);
5583 nref = cpl_vector_get_size(lines);
5584 line = cpl_vector_get_data(lines);
5586 if (*wavestart < 1.0 && *waveend < 1.0) {
5587 firstLambda = line[0];
5588 lastLambda = line[nref-1];
5589 extrapolation = (lastLambda - firstLambda) / 10;
5590 firstLambda -= extrapolation;
5591 lastLambda += extrapolation;
5592 *wavestart = firstLambda;
5593 *waveend = lastLambda;
5596 firstLambda = *wavestart;
5597 lastLambda = *waveend;
5600 nl = (lastLambda - firstLambda) / dispersion;
5601 resampled = cpl_image_new(nl, ny, CPL_TYPE_FLOAT);
5602 rdata = cpl_image_get_data_float(resampled);
5605 idata = cpl_image_get_data_float(calibration);
5608 ddata = cpl_image_get_data_float(residuals);
5611 for (j = 0; j <= order; j++)
5612 cpl_table_new_column(idscoeff, clab[j], CPL_TYPE_DOUBLE);
5615 cpl_table_set_size(restable, nref);
5616 cpl_table_new_column(restable,
"wavelength", CPL_TYPE_DOUBLE);
5617 cpl_table_copy_data_double(restable,
"wavelength", line);
5618 for (i = 0; i < ny; i += step) {
5619 snprintf(name, MAX_COLNAME,
"r%d", i);
5620 cpl_table_new_column(restable, name, CPL_TYPE_DOUBLE);
5621 snprintf(name, MAX_COLNAME,
"d%d", i);
5622 cpl_table_new_column(restable, name, CPL_TYPE_DOUBLE);
5623 snprintf(name, MAX_COLNAME,
"p%d", i);
5624 cpl_table_new_column(restable, name, CPL_TYPE_DOUBLE);
5628 if (detected_lines) {
5629 cpl_table_set_size(detected_lines, 0);
5630 cpl_table_new_column(detected_lines,
"xpos", CPL_TYPE_DOUBLE);
5631 cpl_table_new_column(detected_lines,
"ypos", CPL_TYPE_DOUBLE);
5632 cpl_table_new_column(detected_lines,
"xpos_iter", CPL_TYPE_DOUBLE);
5633 cpl_table_new_column(detected_lines,
"ypos_iter", CPL_TYPE_DOUBLE);
5634 cpl_table_new_column(detected_lines,
"peak_flux", CPL_TYPE_DOUBLE);
5635 cpl_table_new_column(detected_lines,
"wave_ident", CPL_TYPE_DOUBLE);
5636 cpl_table_new_column(detected_lines,
"wave_ident_iter", CPL_TYPE_DOUBLE);
5637 cpl_table_new_column(detected_lines,
"xpos_fit_rect_wavecal", CPL_TYPE_DOUBLE);
5638 cpl_table_new_column(detected_lines,
"res_xpos", CPL_TYPE_DOUBLE);
5647 for (i = 0; i < ny; i++) {
5650 if (width > sradius) {
5666 countLines = cpl_bivector_get_size(output);
5667 if (countLines < 4) {
5668 cpl_bivector_delete(output);
5669 cpl_vector_delete(peaks);
5681 wavel = cpl_bivector_get_y(output);
5682 cpl_vector_subtract_scalar(wavel, refwave);
5684 uorder = countLines / 2 - 1;
5698 2 * (uorder + 1), &usedLines,
5702 cpl_bivector_delete(output);
5703 cpl_vector_delete(peaks);
5720 for (k = 0; k <= order; k++) {
5722 cpl_table_set_double(idscoeff, clab[k], i, 0.0);
5725 cpl_table_set_double(idscoeff, clab[k], i,
5726 cpl_polynomial_get_coeff(ids, &k));
5733 cpl_size newlines = cpl_vector_get_size(peaks);
5734 cpl_size oldsize = cpl_table_get_nrow(detected_lines);
5735 cpl_table_set_size(detected_lines, oldsize + newlines);
5736 for(cpl_size iline = 0; iline < newlines; ++iline)
5738 cpl_table_set_double(detected_lines,
"xpos",
5739 oldsize + iline, cpl_vector_get(peaks, iline) + 1);
5740 cpl_table_set_double(detected_lines,
"ypos",
5741 oldsize + iline, (
double)i + 1);
5742 cpl_table_set_double(detected_lines,
"peak_flux",
5744 sdata[i*nx+(
int)(cpl_vector_get(peaks, iline)+0.5)]);
5752 cpl_size nidentlines = cpl_bivector_get_size(output);
5753 cpl_size ndetectlines = cpl_vector_get_size(peaks);
5754 cpl_size totalsize = cpl_table_get_nrow(detected_lines);
5755 for(cpl_size idline = 0; idline < nidentlines; ++idline)
5757 for(cpl_size detline = 0; detline < ndetectlines; ++detline)
5759 if(cpl_vector_get(peaks, detline) ==
5760 cpl_bivector_get_x_data(output)[idline])
5762 cpl_size table_pos = totalsize - ndetectlines + detline;
5763 double wave_ident = cpl_bivector_get_y_data(output)[idline] + refwave;
5764 double xpix_fit = cpl_polynomial_eval_1d(ids,
5765 wave_ident - refwave, NULL);
5766 double xpos_det = cpl_table_get_double(detected_lines,
5769 cpl_table_set_double(detected_lines,
5773 cpl_table_set_double(detected_lines,
5774 "xpos_fit_rect_wavecal",
5777 cpl_table_set_double(detected_lines,
5780 xpos_det - xpix_fit - 1);
5794 ids, refwave, uradius);
5797 cpl_bivector_delete(output);
5798 output = new_output;
5804 cpl_polynomial_delete(ids);
5806 countLines = cpl_bivector_get_size(output);
5808 if (countLines < 4) {
5809 cpl_bivector_delete(output);
5810 cpl_vector_delete(peaks);
5823 for (k = 0; k <= order; k++)
5824 cpl_table_set_invalid(idscoeff, clab[k], i);
5828 wavel = cpl_bivector_get_y(output);
5829 cpl_vector_subtract_scalar(wavel, refwave);
5831 uorder = countLines / 2 - 1;
5836 2 * (uorder + 1), &usedLines,
5840 cpl_bivector_delete(output);
5841 cpl_vector_delete(peaks);
5854 for (k = 0; k <= order; k++)
5855 cpl_table_set_invalid(idscoeff, clab[k], i);
5861 for (k = 0; k <= order; k++) {
5863 cpl_table_set_double(idscoeff, clab[k], i, 0.0);
5866 cpl_table_set_double(idscoeff, clab[k], i,
5867 cpl_polynomial_get_coeff(ids, &k));
5875 cpl_size oldsize = cpl_table_get_nrow(detected_lines);
5876 cpl_size nidentlines = cpl_bivector_get_size(output);
5877 cpl_table_set_size(detected_lines, oldsize + nidentlines);
5878 for(cpl_size idline = 0; idline < nidentlines ; ++idline)
5880 double wave_ident = cpl_bivector_get_y_data(output)[idline] + refwave;
5881 double xpix_fit = cpl_polynomial_eval_1d(ids,
5882 wave_ident - refwave, NULL);
5883 cpl_table_set_double(detected_lines,
"xpos_iter",
5884 oldsize + idline, cpl_bivector_get_x_data(output)[idline] + 1);
5885 cpl_table_set_double(detected_lines,
"ypos_iter",
5886 oldsize + idline, (
double)i + 1);
5887 cpl_table_set_double(detected_lines,
"peak_flux",
5889 sdata[i*nx+(
int)(cpl_bivector_get_x_data(output)[idline]+0.5)]);
5890 cpl_table_set_double(detected_lines,
"wave_ident_iter",
5891 oldsize + idline, wave_ident);
5892 cpl_table_set_double(detected_lines,
"xpos_fit_rect_wavecal",
5893 oldsize + idline, xpix_fit + 1);
5900 nlines[i] = usedLines;
5902 error[i] = ids_err / sqrt(usedLines/(uorder + 1));
5904 pixstart = cpl_polynomial_eval_1d(ids,
5905 cpl_bivector_get_y_data(output)[0], NULL);
5906 pixend = cpl_polynomial_eval_1d(ids,
5907 cpl_bivector_get_y_data(output)[countLines-1], NULL);
5908 extrapolation = (pixend - pixstart) / 5;
5909 pixstart -= extrapolation;
5910 pixend += extrapolation;
5921 for (j = pixstart; j < pixend; j++) {
5923 lastLambda, refwave,
5932 for (j = 0; j < nl; j++) {
5933 lambda = firstLambda + j * dispersion;
5934 fpixel = cpl_polynomial_eval_1d(ids, lambda - refwave,
5937 if (pixel >= 0 && pixel < nx-1) {
5938 v1 = (sdata + i*nx)[pixel];
5939 v2 = (sdata + i*nx)[pixel+1];
5940 vi = v1 + (v2-v1)*(fpixel-pixel);
5941 (rdata + i*nl)[j] = vi;
5949 if (residuals || (restable && !(i%step))) {
5950 if (restable && !(i%step)) {
5951 lin = cpl_polynomial_new(1);
5952 for (k = 0; k < 2; k++)
5953 cpl_polynomial_set_coeff(lin, &k,
5954 cpl_polynomial_get_coeff(ids, &k));
5956 for (j = 0; j < countLines; j++) {
5957 pixe = cpl_bivector_get_x_data(output)[j];
5958 wave = cpl_bivector_get_y_data(output)[j];
5959 value = pixe - cpl_polynomial_eval_1d(ids, wave, NULL);
5962 (ddata + i*nx)[pixel] = value;
5964 if (restable && !(i%step)) {
5965 for (k = 0; k < nref; k++) {
5966 if (fabs(line[k] - refwave - wave) < 0.1) {
5967 snprintf(name, MAX_COLNAME,
"r%d", i);
5968 cpl_table_set_double(restable, name,
5971 - cpl_polynomial_eval_1d(lin, wave,
5973 snprintf(name, MAX_COLNAME,
"d%d", i);
5974 cpl_table_set_double(restable, name,
5976 snprintf(name, MAX_COLNAME,
"p%d", i);
5977 cpl_table_set_double(restable, name,
5984 if (restable && !(i%step)) {
5985 cpl_polynomial_delete(lin);
5994 mdata = cpl_mask_get_data(refmask);
5995 pixel = cpl_polynomial_eval_1d(ids, 0.0, NULL) + 0.5;
5996 if (pixel - 1 >= 0 && pixel + 1 < nx) {
5997 mdata[pixel-1 + i*nx] = CPL_BINARY_1;
5998 mdata[pixel + i*nx] = CPL_BINARY_1;
5999 mdata[pixel+1 + i*nx] = CPL_BINARY_1;
6003 cpl_polynomial_delete(ids);
6004 cpl_bivector_delete(output);
6006 cpl_vector_delete(peaks);
6011 kernel = cpl_matrix_new(3, 3);
6012 cpl_matrix_set(kernel, 0, 1, 1.0);
6013 cpl_matrix_set(kernel, 1, 1, 1.0);
6014 cpl_matrix_set(kernel, 2, 1, 1.0);
6016 cpl_mask_dilation(refmask, kernel);
6017 cpl_mask_erosion(refmask, kernel);
6018 cpl_mask_erosion(refmask, kernel);
6019 cpl_mask_dilation(refmask, kernel);
6021 cpl_matrix_delete(kernel);
6027 mdata = cpl_mask_get_data(refmask);
6028 have_it = cpl_calloc(ny,
sizeof(
int));
6030 for (i = 0; i < ny; i++, mdata += nx) {
6031 for (j = 0; j < nx; j++) {
6032 if (mdata[j] == CPL_BINARY_1) {
6039 mdata = cpl_mask_get_data(refmask);
6043 for (i = 0; i < ny; i++) {
6049 if (abs(have_it[first] - have_it[last]) < 3) {
6050 for (j = first; j < last; j++) {
6051 mdata[have_it[first] + nx*j + 0] = CPL_BINARY_1;
6052 mdata[have_it[first] + nx*j + 1] = CPL_BINARY_1;
6053 mdata[have_it[first] + nx*j + 2] = CPL_BINARY_1;
6195 const char *func =
"mos_locate_spectra";
6197 cpl_apertures *slits;
6198 cpl_image *labimage;
6199 cpl_image *refimage;
6201 cpl_propertylist *sort_col;
6207 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
6211 labimage = cpl_image_labelise_mask_create(mask, &nslits);
6214 cpl_image_delete(labimage);
6215 cpl_error_set(func, CPL_ERROR_DATA_NOT_FOUND);
6219 refimage = cpl_image_new_from_mask(mask);
6221 slits = cpl_apertures_new_from_image(refimage, labimage);
6223 cpl_image_delete(labimage);
6224 cpl_image_delete(refimage);
6226 nslits = cpl_apertures_get_size(slits);
6228 cpl_apertures_delete(slits);
6229 cpl_error_set(func, CPL_ERROR_DATA_NOT_FOUND);
6233 slitpos = cpl_table_new(nslits);
6234 cpl_table_new_column(slitpos,
"xtop", CPL_TYPE_DOUBLE);
6235 cpl_table_new_column(slitpos,
"ytop", CPL_TYPE_DOUBLE);
6236 cpl_table_new_column(slitpos,
"xbottom", CPL_TYPE_DOUBLE);
6237 cpl_table_new_column(slitpos,
"ybottom", CPL_TYPE_DOUBLE);
6238 cpl_table_set_column_unit(slitpos,
"xtop",
"pixel");
6239 cpl_table_set_column_unit(slitpos,
"ytop",
"pixel");
6240 cpl_table_set_column_unit(slitpos,
"xbottom",
"pixel");
6241 cpl_table_set_column_unit(slitpos,
"ybottom",
"pixel");
6243 for (i = 0; i < nslits; i++) {
6244 cpl_table_set_double(slitpos,
"xtop", i,
6245 cpl_apertures_get_top_x(slits, i+1) - 1);
6246 cpl_table_set_double(slitpos,
"ytop", i,
6247 cpl_apertures_get_top(slits, i+1));
6248 cpl_table_set_double(slitpos,
"xbottom", i,
6249 cpl_apertures_get_bottom_x(slits, i+1) - 1);
6250 cpl_table_set_double(slitpos,
"ybottom", i,
6251 cpl_apertures_get_bottom(slits, i+1));
6254 cpl_apertures_delete(slits);
6256 sort_col = cpl_propertylist_new();
6257 cpl_propertylist_append_bool(sort_col,
"ytop", 1);
6258 cpl_table_sort(slitpos, sort_col);
6259 cpl_propertylist_delete(sort_col);
6283 const char *func =
"mos_validate_slits";
6287 return cpl_error_set(func, CPL_ERROR_NULL_INPUT);
6289 if (1 != cpl_table_has_column(slits,
"xtop"))
6290 return cpl_error_set(func, CPL_ERROR_DATA_NOT_FOUND);
6292 if (1 != cpl_table_has_column(slits,
"ytop"))
6293 return cpl_error_set(func, CPL_ERROR_DATA_NOT_FOUND);
6295 if (1 != cpl_table_has_column(slits,
"xbottom"))
6296 return cpl_error_set(func, CPL_ERROR_DATA_NOT_FOUND);
6298 if (1 != cpl_table_has_column(slits,
"ybottom"))
6299 return cpl_error_set(func, CPL_ERROR_DATA_NOT_FOUND);
6301 if (CPL_TYPE_DOUBLE != cpl_table_get_column_type(slits,
"xtop"))
6302 return cpl_error_set(func, CPL_ERROR_INVALID_TYPE);
6304 if (CPL_TYPE_DOUBLE != cpl_table_get_column_type(slits,
"ytop"))
6305 return cpl_error_set(func, CPL_ERROR_INVALID_TYPE);
6307 if (CPL_TYPE_DOUBLE != cpl_table_get_column_type(slits,
"xbottom"))
6308 return cpl_error_set(func, CPL_ERROR_INVALID_TYPE);
6310 if (CPL_TYPE_DOUBLE != cpl_table_get_column_type(slits,
"ybottom"))
6311 return cpl_error_set(func, CPL_ERROR_INVALID_TYPE);
6313 return CPL_ERROR_NONE;
6347 const char *func =
"mos_rotate_slits";
6349 cpl_error_code error;
6350 char aux_name[] =
"_0";
6359 return CPL_ERROR_NONE;
6363 return cpl_error_set(func, error);
6365 if (rotation == 1 || rotation == 3) {
6371 for (i = 0; i < 77; i++)
6372 if (1 == cpl_table_has_column(slits, aux_name))
6374 if (1 == cpl_table_has_column(slits, aux_name))
6375 return cpl_error_set(func, CPL_ERROR_CONTINUE);
6376 cpl_table_name_column(slits,
"xtop", aux_name);
6377 cpl_table_name_column(slits,
"ytop",
"xtop");
6378 cpl_table_name_column(slits, aux_name,
"ytop");
6379 cpl_table_name_column(slits,
"xbottom", aux_name);
6380 cpl_table_name_column(slits,
"ybottom",
"xbottom");
6381 cpl_table_name_column(slits, aux_name,
"ybottom");
6384 if (rotation == 1 || rotation == 2) {
6385 cpl_table_multiply_scalar(slits,
"xtop", -1.0);
6386 cpl_table_multiply_scalar(slits,
"xbottom", -1.0);
6387 cpl_table_add_scalar(slits,
"xtop", nx);
6388 cpl_table_add_scalar(slits,
"xbottom", nx);
6391 if (rotation == 3 || rotation == 2) {
6392 cpl_table_multiply_scalar(slits,
"ytop", -1.0);
6393 cpl_table_multiply_scalar(slits,
"ybottom", -1.0);
6394 cpl_table_add_scalar(slits,
"ytop", ny);
6395 cpl_table_add_scalar(slits,
"ybottom", ny);
6398 return CPL_ERROR_NONE;
6462 cpl_array *top_ident = NULL;;
6463 cpl_array *bot_ident = NULL;;
6465 cpl_matrix *mpattern;
6466 cpl_matrix *top_data;
6467 cpl_matrix *top_pattern;
6468 cpl_matrix *top_mdata;
6469 cpl_matrix *top_mpattern;
6470 cpl_matrix *bot_data;
6471 cpl_matrix *bot_pattern;
6472 cpl_matrix *bot_mdata;
6473 cpl_matrix *bot_mpattern;
6474 cpl_propertylist *sort_col;
6483 double top_scale, bot_scale;
6484 double angle, top_angle, bot_angle;
6486 double xrms, top_xrms, bot_xrms;
6487 double yrms, top_yrms, bot_yrms;
6489 int nmaskslits, use_pattern;
6490 int found_slits, found_slits_top, found_slits_bot;
6492 cpl_table *positions;
6493 cpl_error_code error;
6502 cpl_polynomial *xpoly = NULL;
6503 cpl_polynomial *ypoly = NULL;
6504 cpl_polynomial *top_xpoly = NULL;
6505 cpl_polynomial *top_ypoly = NULL;
6506 cpl_polynomial *bot_xpoly = NULL;
6507 cpl_polynomial *bot_ypoly = NULL;
6509 char *msg_multiplex =
" ";
6514 cpl_msg_error(cpl_func,
"CCD slits table validation: %s",
6515 cpl_error_get_message());
6516 cpl_error_set(cpl_func, error);
6522 cpl_msg_error(cpl_func,
"Mask slits table validation: %s",
6523 cpl_error_get_message());
6524 cpl_error_set(cpl_func, error);
6528 if (1 != cpl_table_has_column(maskslits,
"slit_id")) {
6529 cpl_msg_error(cpl_func,
"Missing slits identifiers");
6530 cpl_error_set(cpl_func, CPL_ERROR_DATA_NOT_FOUND);
6534 if (CPL_TYPE_INT != cpl_table_get_column_type(maskslits,
"slit_id")) {
6535 cpl_msg_error(cpl_func,
"Wrong type used for slits identifiers");
6536 cpl_error_set(cpl_func, CPL_ERROR_INVALID_TYPE);
6540 nslits = cpl_table_get_nrow(slits);
6541 nmaskslits = cpl_table_get_nrow(maskslits);
6543 if (nslits == 0 || nmaskslits == 0) {
6544 cpl_msg_error(cpl_func,
"Empty slits table");
6545 cpl_error_set(cpl_func, CPL_ERROR_ILLEGAL_INPUT);
6549 if (nslits > 25 && mos_multiplex < 0) {
6550 cpl_msg_info(cpl_func,
"Many slits: using 'fast' pattern matching...");
6551 positions = mos_identify_slits_fast(slits, maskslits, global);
6552 if (positions == NULL)
6553 cpl_error_set_where(cpl_func);
6561 sort_col = cpl_propertylist_new();
6562 cpl_propertylist_append_bool(sort_col,
"ytop", 1);
6563 cpl_table_sort(slits, sort_col);
6564 cpl_table_sort(maskslits, sort_col);
6565 cpl_propertylist_delete(sort_col);
6571 if (nslits < 3 && nmaskslits > nslits) {
6581 cpl_msg_warning(cpl_func,
"Cannot match the %d found CCD slits "
6582 "with the %d mask slits: process will continue "
6583 "using the detected CCD slits positions", nslits,
6586 cpl_msg_warning(cpl_func,
"Cannot match the found CCD slit with "
6587 "the %d mask slits: process will continue using "
6588 "the detected CCD slit position", nmaskslits);
6592 if (nmaskslits < 3 && nslits > nmaskslits) {
6600 cpl_msg_warning(cpl_func,
"Cannot match the %d found CCD slits with "
6601 "the %d mask slits: process will continue using "
6602 "the detected CCD slits positions", nslits,
6614 xtop = cpl_table_get_data_double(slits,
"xtop");
6615 ytop = cpl_table_get_data_double(slits,
"ytop");
6616 xmtop = cpl_table_get_data_double(maskslits,
"xtop");
6617 ymtop = cpl_table_get_data_double(maskslits,
"ytop");
6619 xbot = cpl_table_get_data_double(slits,
"xbottom");
6620 ybot = cpl_table_get_data_double(slits,
"ybottom");
6621 xmbot = cpl_table_get_data_double(maskslits,
"xbottom");
6622 ymbot = cpl_table_get_data_double(maskslits,
"ybottom");
6624 top_data = cpl_matrix_new(2, nslits);
6625 top_pattern = cpl_matrix_new(2, nmaskslits);
6626 bot_data = cpl_matrix_new(2, nslits);
6627 bot_pattern = cpl_matrix_new(2, nmaskslits);
6629 for (i = 0; i < nslits; i++)
6630 cpl_matrix_set(top_data, 0, i, xtop[i]);
6632 for (i = 0; i < nslits; i++)
6633 cpl_matrix_set(top_data, 1, i, ytop[i]);
6635 for (i = 0; i < nmaskslits; i++)
6636 cpl_matrix_set(top_pattern, 0, i, xmtop[i]);
6638 for (i = 0; i < nmaskslits; i++)
6639 cpl_matrix_set(top_pattern, 1, i, ymtop[i]);
6641 for (i = 0; i < nslits; i++)
6642 cpl_matrix_set(bot_data, 0, i, xbot[i]);
6644 for (i = 0; i < nslits; i++)
6645 cpl_matrix_set(bot_data, 1, i, ybot[i]);
6647 for (i = 0; i < nmaskslits; i++)
6648 cpl_matrix_set(bot_pattern, 0, i, xmbot[i]);
6650 for (i = 0; i < nmaskslits; i++)
6651 cpl_matrix_set(bot_pattern, 1, i, ymbot[i]);
6653 if (nmaskslits > nslits)
6654 use_pattern = nslits;
6656 use_pattern = nmaskslits;
6658 top_ident = cpl_ppm_match_points(top_data, nslits, 1.0, top_pattern,
6659 use_pattern, 0.0, 0.1, 5, &top_mdata,
6660 &top_mpattern, &top_scale, &top_angle);
6662 bot_ident = cpl_ppm_match_points(bot_data, nslits, 1.0, bot_pattern,
6663 use_pattern, 0.0, 0.1, 5, &bot_mdata,
6664 &bot_mpattern, &bot_scale, &bot_angle);
6665 cpl_matrix_delete(top_data);
6666 cpl_matrix_delete(top_pattern);
6667 cpl_matrix_delete(bot_data);
6668 cpl_matrix_delete(bot_pattern);
6670 if (top_ident == NULL && bot_ident == NULL) {
6671 cpl_msg_warning(cpl_func,
"Pattern matching failure: cannot match "
6672 "the %d found CCD slits with the %d mask slits: "
6673 "process will continue using the detected CCD "
6674 "slits positions", nslits, nmaskslits);
6678 found_slits_top = 0;
6679 found_slits_bot = 0;
6680 if (top_ident && bot_ident) {
6681 cpl_msg_info(cpl_func,
"Median platescale: %f +/- %f pixel/mm",
6682 (top_scale + bot_scale) / 2, fabs(top_scale - bot_scale));
6683 cpl_msg_info(cpl_func,
"Median rotation: %f +/- %f degrees",
6684 (top_angle + bot_angle) / 2, fabs(top_angle - bot_angle));
6685 if (fabs(top_angle) < fabs(bot_angle))
6686 angle = fabs(top_angle);
6688 angle = fabs(bot_angle);
6689 found_slits_top = cpl_matrix_get_ncol(top_mdata);
6690 found_slits_bot = cpl_matrix_get_ncol(bot_mdata);
6692 else if (top_ident) {
6693 cpl_msg_info(cpl_func,
"Median platescale: %f pixel/mm", top_scale);
6694 cpl_msg_info(cpl_func,
"Median rotation: %f degrees", top_angle);
6695 angle = fabs(top_angle);
6696 found_slits_top = cpl_matrix_get_ncol(top_mdata);
6699 cpl_msg_info(cpl_func,
"Median platescale: %f pixel/mm", bot_scale);
6700 cpl_msg_info(cpl_func,
"Median rotation: %f degrees", bot_angle);
6701 angle = fabs(bot_angle);
6702 found_slits_bot = cpl_matrix_get_ncol(bot_mdata);
6705 cpl_array_delete(top_ident);
6706 cpl_array_delete(bot_ident);
6709 cpl_msg_warning(cpl_func,
"Uncertain pattern matching: the rotation "
6710 "angle is expected to be around zero. This match is "
6711 "rejected: the process will continue using the %d "
6712 "detected CCD slits positions", nslits);
6716 found_slits = found_slits_top;
6717 if (found_slits < found_slits_bot)
6718 found_slits = found_slits_bot;
6720 if (found_slits < 4) {
6721 cpl_msg_warning(cpl_func,
6722 "Too few safely identified slits: %d out of %d "
6723 "candidates (%d expected). Process will continue "
6724 "using the detected CCD slits positions", found_slits,
6725 nslits, nmaskslits);
6729 cpl_msg_info(cpl_func,
"Preliminary identified slits: %d out of %d "
6730 "candidates\n(%d expected)", found_slits, nslits,
6733 if (found_slits_top < 4)
6734 found_slits_top = 0;
6736 if (found_slits_bot < 4)
6737 found_slits_bot = 0;
6745 for (i = 0; i < 2; i++) {
6746 cpl_size mindeg2d[] = {0, 0};
6747 cpl_size maxdeg2d[2];
6748 cpl_vector * fitresidual;
6750 found_slits = found_slits_top;
6752 mpattern = top_mpattern;
6755 found_slits = found_slits_bot;
6757 mpattern = bot_mpattern;
6760 if (found_slits == 0)
6762 else if (found_slits < 10)
6763 maxdeg2d[0] = maxdeg2d[1] = 1;
6765 maxdeg2d[0] = maxdeg2d[1] = 2;
6767 xpos = cpl_vector_wrap(found_slits,
6768 cpl_matrix_get_data(mdata) );
6769 ypos = cpl_vector_wrap(found_slits,
6770 cpl_matrix_get_data(mdata) + found_slits);
6771 xmpos = cpl_vector_wrap(found_slits,
6772 cpl_matrix_get_data(mpattern) );
6773 ympos = cpl_vector_wrap(found_slits,
6774 cpl_matrix_get_data(mpattern) + found_slits);
6775 mpos = cpl_bivector_wrap_vectors(xmpos, ympos);
6776 fitresidual = cpl_vector_new(cpl_vector_get_size(xpos));
6777 xpoly = cpl_polynomial_new(2);
6778 cpl_polynomial_fit(xpoly, mpattern, NULL, xpos, NULL, CPL_FALSE, mindeg2d, maxdeg2d);
6779 cpl_vector_fill_polynomial_fit_residual(fitresidual, xpos, NULL, xpoly, mpattern, NULL);
6780 xmse = cpl_vector_product(fitresidual, fitresidual)
6781 / cpl_vector_get_size(fitresidual);
6782 ypoly = cpl_polynomial_new(2);
6783 cpl_polynomial_fit(ypoly, mpattern, NULL, ypos, NULL, CPL_FALSE, mindeg2d, maxdeg2d);
6784 cpl_vector_fill_polynomial_fit_residual(fitresidual, ypos, NULL, ypoly, mpattern, NULL);
6785 ymse = cpl_vector_product(fitresidual, fitresidual)
6786 / cpl_vector_get_size(fitresidual);
6788 cpl_bivector_unwrap_vectors(mpos);
6789 cpl_vector_unwrap(xpos);
6790 cpl_vector_unwrap(ypos);
6791 cpl_vector_unwrap(xmpos);
6792 cpl_vector_unwrap(ympos);
6793 cpl_matrix_delete(mdata);
6794 cpl_matrix_delete(mpattern);
6795 cpl_vector_delete(fitresidual);
6800 top_xrms = sqrt(xmse*2*maxdeg2d[0]/(found_slits - 1));
6801 top_yrms = sqrt(ymse*2*maxdeg2d[0]/(found_slits - 1));
6806 bot_xrms = sqrt(xmse*2*maxdeg2d[0]/(found_slits - 1));
6807 bot_yrms = sqrt(ymse*2*maxdeg2d[0]/(found_slits - 1));
6811 if (top_xpoly && bot_xpoly) {
6812 if (top_xrms < bot_xrms) {
6815 cpl_polynomial_delete(bot_xpoly);
6820 cpl_polynomial_delete(top_xpoly);
6823 else if (top_xpoly) {
6832 if (top_ypoly && bot_ypoly) {
6833 if (top_yrms < bot_yrms) {
6836 cpl_polynomial_delete(bot_ypoly);
6841 cpl_polynomial_delete(top_ypoly);
6844 else if (top_ypoly) {
6853 if (xpoly == NULL || ypoly == NULL) {
6854 cpl_msg_warning(cpl_func,
"Fit failure: the accuracy of the "
6855 "identified slits positions cannot be improved.");
6856 cpl_polynomial_delete(xpoly);
6857 cpl_polynomial_delete(ypoly);
6862 cpl_msg_info(cpl_func,
6863 "Fit successful: X rms = %.3g, Y rms = %.3g (pixel)",
6867 write_global_distortion(global, 0, xpoly);
6868 write_global_distortion(global, 7, ypoly);
6876 positions = cpl_table_duplicate(maskslits);
6877 cpl_table_duplicate_column(positions,
"xmtop", positions,
"xtop");
6878 cpl_table_duplicate_column(positions,
"ymtop", positions,
"ytop");
6879 cpl_table_duplicate_column(positions,
"xmbottom", positions,
"xbottom");
6880 cpl_table_duplicate_column(positions,
"ymbottom", positions,
"ybottom");
6882 point = cpl_vector_new(2);
6883 dpoint = cpl_vector_get_data(point);
6885 for (i = 0; i < nmaskslits; i++) {
6889 dpoint[0] = cpl_table_get_double(positions,
"xmtop", i, NULL);
6890 dpoint[1] = cpl_table_get_double(positions,
"ymtop", i, NULL);
6891 position_x = cpl_polynomial_eval(xpoly, point);
6898 cpl_table_set_double(positions,
"xtop", i, position_x);
6899 position_y = cpl_polynomial_eval(ypoly, point);
6900 cpl_table_set_double(positions,
"ytop", i, position_y);
6901 dpoint[0] = cpl_table_get_double(positions,
"xmbottom", i, NULL);
6902 dpoint[1] = cpl_table_get_double(positions,
"ymbottom", i, NULL);
6903 position_x = cpl_polynomial_eval(xpoly, point);
6904 cpl_table_set_double(positions,
"xbottom", i, position_x);
6905 position_y = cpl_polynomial_eval(ypoly, point);
6906 cpl_table_set_double(positions,
"ybottom", i, position_y);
6915 cpl_vector_delete(point);
6916 cpl_polynomial_delete(xpoly);
6917 cpl_polynomial_delete(ypoly);
6919 cpl_table_erase_column(positions,
"xmtop");
6920 cpl_table_erase_column(positions,
"ymtop");
6921 cpl_table_erase_column(positions,
"xmbottom");
6922 cpl_table_erase_column(positions,
"ymbottom");
6924 if (mos_multiplex >= 0) {
6926 cpl_sprintf(
"in the CCD section between %d and %d pixel",
6927 mos_multiplex * mos_region_size,
6928 (mos_multiplex + 1) * mos_region_size);
6931 if (nmaskslits > nslits)
6932 cpl_msg_info(cpl_func,
6933 "Finally identified slits: %d out of %d expected %s\n"
6934 "(%d recovered)", nmaskslits, nmaskslits, msg_multiplex,
6935 nmaskslits - nslits);
6936 else if (nmaskslits < nslits)
6937 cpl_msg_info(cpl_func,
6938 "Finally identified slits: %d out of %d expected %s\n"
6939 "(%d rejected)", nmaskslits, nmaskslits, msg_multiplex,
6940 nslits - nmaskslits);
6942 cpl_msg_info(cpl_func,
6943 "Finally identified slits: %d out of %d expected %s",
6944 nmaskslits, nmaskslits, msg_multiplex);
6946 if (mos_multiplex >= 0) {
6947 cpl_free(msg_multiplex);
6955 cpl_table *mos_identify_slits_fast(cpl_table *slits, cpl_table *maskslits,
6958 const char *func =
"mos_identify_slits_fast";
6960 cpl_propertylist *sort_col;
6961 cpl_table *positions;
6970 cpl_polynomial *xpoly = NULL;
6971 cpl_polynomial *ypoly = NULL;
6972 cpl_error_code error;
6978 double dist1, dist2, dist3, dist, mindist;
6979 double scale, minscale, maxscale;
6980 double angle, minangle, maxangle;
7007 double sradius = 0.01;
7010 double pi = 3.14159265358979323846;
7015 cpl_msg_error(func,
"CCD slits table validation: %s",
7016 cpl_error_get_message());
7017 cpl_error_set(func, error);
7023 cpl_msg_error(func,
"Mask slits table validation: %s",
7024 cpl_error_get_message());
7025 cpl_error_set(func, error);
7029 if (1 != cpl_table_has_column(maskslits,
"slit_id")) {
7030 cpl_msg_error(func,
"Missing slits identifiers");
7031 cpl_error_set(func, CPL_ERROR_DATA_NOT_FOUND);
7035 if (CPL_TYPE_INT != cpl_table_get_column_type(maskslits,
"slit_id")) {
7036 cpl_msg_error(func,
"Wrong type used for slits identifiers");
7037 cpl_error_set(func, CPL_ERROR_INVALID_TYPE);
7041 nslits = cpl_table_get_nrow(slits);
7042 nmaskslits = cpl_table_get_nrow(maskslits);
7044 if (nslits == 0 || nmaskslits == 0) {
7045 cpl_msg_error(func,
"Empty slits table");
7046 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
7056 if (cpl_table_has_column(slits,
"xcenter"))
7057 cpl_table_erase_column(slits,
"xcenter");
7059 if (cpl_table_has_column(slits,
"ycenter"))
7060 cpl_table_erase_column(slits,
"ycenter");
7062 if (cpl_table_has_column(maskslits,
"xcenter"))
7063 cpl_table_erase_column(maskslits,
"xcenter");
7065 if (cpl_table_has_column(maskslits,
"ycenter"))
7066 cpl_table_erase_column(maskslits,
"ycenter");
7068 cpl_table_duplicate_column(slits,
"xcenter", slits,
"xtop");
7069 cpl_table_add_columns(slits,
"xcenter",
"xbottom");
7070 cpl_table_divide_scalar(slits,
"xcenter", 2.0);
7071 cpl_table_duplicate_column(slits,
"ycenter", slits,
"ytop");
7072 cpl_table_add_columns(slits,
"ycenter",
"ybottom");
7073 cpl_table_divide_scalar(slits,
"ycenter", 2.0);
7075 cpl_table_duplicate_column(maskslits,
"xcenter", maskslits,
"xtop");
7076 cpl_table_add_columns(maskslits,
"xcenter",
"xbottom");
7077 cpl_table_divide_scalar(maskslits,
"xcenter", 2.0);
7078 cpl_table_duplicate_column(maskslits,
"ycenter", maskslits,
"ytop");
7079 cpl_table_add_columns(maskslits,
"ycenter",
"ybottom");
7080 cpl_table_divide_scalar(maskslits,
"ycenter", 2.0);
7087 sort_col = cpl_propertylist_new();
7088 cpl_propertylist_append_bool(sort_col,
"ycenter", 1);
7089 cpl_table_sort(slits, sort_col);
7090 cpl_table_sort(maskslits, sort_col);
7091 cpl_propertylist_delete(sort_col);
7098 if (nslits < 3 && nmaskslits > nslits) {
7108 cpl_msg_warning(func,
"Cannot match the found CCD slit with the "
7109 "%d mask slits: process will continue using the "
7110 "detected CCD slit position", nmaskslits);
7112 cpl_msg_warning(func,
"Cannot match the %d found CCD slits with "
7113 "the %d mask slits: process will continue using "
7114 "the detected CCD slits positions", nslits,
7119 if (nslits <= 3 && nslits == nmaskslits) {
7121 cpl_msg_warning(func,
"Too few slits (%d) on mask and CCD", nslits);
7122 cpl_msg_warning(func,
"Their detected positions are left unchanged");
7133 positions = cpl_table_duplicate(slits);
7134 cpl_table_erase_column(slits,
"xcenter");
7135 cpl_table_erase_column(slits,
"ycenter");
7136 cpl_table_duplicate_column(positions,
"xmtop", maskslits,
"xtop");
7137 cpl_table_duplicate_column(positions,
"ymtop", maskslits,
"ytop");
7138 cpl_table_duplicate_column(positions,
"xmbottom", maskslits,
"xbottom");
7139 cpl_table_duplicate_column(positions,
"ymbottom", maskslits,
"ybottom");
7140 cpl_table_duplicate_column(positions,
"xmcenter", maskslits,
"xcenter");
7141 cpl_table_duplicate_column(positions,
"ymcenter", maskslits,
"ycenter");
7142 cpl_table_duplicate_column(positions,
"slit_id", maskslits,
"slit_id");
7143 cpl_table_erase_column(maskslits,
"xcenter");
7144 cpl_table_erase_column(maskslits,
"ycenter");
7147 xcenter = cpl_table_get_data_double(positions,
"xcenter");
7148 ycenter = cpl_table_get_data_double(positions,
"ycenter");
7149 xmcenter = cpl_table_get_data_double(positions,
"xmcenter");
7150 ymcenter = cpl_table_get_data_double(positions,
"ymcenter");
7152 dist1 = (xcenter[0] - xcenter[1])*(xcenter[0] - xcenter[1])
7153 + (ycenter[0] - ycenter[1])*(ycenter[0] - ycenter[1]);
7154 dist2 = (xmcenter[0] - xmcenter[1])*(xmcenter[0] - xmcenter[1])
7155 + (ymcenter[0] - ymcenter[1])*(ymcenter[0] - ymcenter[1]);
7156 scale = sqrt(dist1/dist2);
7159 dist1 = (xcenter[1] - xcenter[2])*(xcenter[1] - xcenter[2])
7160 + (ycenter[1] - ycenter[2])*(ycenter[1] - ycenter[2]);
7161 dist2 = (xmcenter[1] - xmcenter[2])*(xmcenter[1] - xmcenter[2])
7162 + (ymcenter[1] - ymcenter[2])*(ymcenter[1] - ymcenter[2]);
7163 scale += sqrt(dist1/dist2);
7167 cpl_msg_info(func,
"Platescale: %f pixel/mm", scale);
7173 if (nmaskslits < 3 && nslits > nmaskslits) {
7181 cpl_msg_warning(func,
"Cannot match the %d found CCD slits with "
7182 "the %d mask slits: process will continue using "
7183 "the detected CCD slits positions", nslits,
7215 if (cpl_table_has_column(slits,
"xpseudo"))
7216 cpl_table_erase_column(slits,
"xpseudo");
7218 if (cpl_table_has_column(slits,
"ypseudo"))
7219 cpl_table_erase_column(slits,
"ypseudo");
7221 if (cpl_table_has_column(maskslits,
"xpseudo"))
7222 cpl_table_erase_column(maskslits,
"xpseudo");
7224 if (cpl_table_has_column(maskslits,
"ypseudo"))
7225 cpl_table_erase_column(maskslits,
"ypseudo");
7227 cpl_table_duplicate_column(slits,
"xpseudo", slits,
"xcenter");
7228 cpl_table_duplicate_column(slits,
"ypseudo", slits,
"ycenter");
7230 xcenter = cpl_table_get_data_double(slits,
"xcenter");
7231 ycenter = cpl_table_get_data_double(slits,
"ycenter");
7232 xpseudo = cpl_table_get_data_double(slits,
"xpseudo");
7233 ypseudo = cpl_table_get_data_double(slits,
"ypseudo");
7235 for (i = 1; i < nslits - 1; i++) {
7236 dist1 = (xcenter[i-1] - xcenter[i]) * (xcenter[i-1] - xcenter[i])
7237 + (ycenter[i-1] - ycenter[i]) * (ycenter[i-1] - ycenter[i]);
7238 dist2 = (xcenter[i-1] - xcenter[i+1]) * (xcenter[i-1] - xcenter[i+1])
7239 + (ycenter[i-1] - ycenter[i+1]) * (ycenter[i-1] - ycenter[i+1]);
7240 dist3 = (xcenter[i] - xcenter[i+1]) * (xcenter[i] - xcenter[i+1])
7241 + (ycenter[i] - ycenter[i+1]) * (ycenter[i] - ycenter[i+1]);
7242 xpseudo[i] = sqrt(dist1/dist2);
7243 ypseudo[i] = sqrt(dist3/dist2);
7246 cpl_table_set_invalid(slits,
"xpseudo", 0);
7247 cpl_table_set_invalid(slits,
"xpseudo", nslits-1);
7248 cpl_table_set_invalid(slits,
"ypseudo", 0);
7249 cpl_table_set_invalid(slits,
"ypseudo", nslits-1);
7251 cpl_table_duplicate_column(maskslits,
"xpseudo", maskslits,
"xcenter");
7252 cpl_table_duplicate_column(maskslits,
"ypseudo", maskslits,
"ycenter");
7254 xcenter = cpl_table_get_data_double(maskslits,
"xcenter");
7255 ycenter = cpl_table_get_data_double(maskslits,
"ycenter");
7256 xmpseudo = cpl_table_get_data_double(maskslits,
"xpseudo");
7257 ympseudo = cpl_table_get_data_double(maskslits,
"ypseudo");
7259 for (i = 1; i < nmaskslits - 1; i++) {
7260 dist1 = (xcenter[i-1] - xcenter[i])*(xcenter[i-1] - xcenter[i])
7261 + (ycenter[i-1] - ycenter[i])*(ycenter[i-1] - ycenter[i]);
7262 dist2 = (xcenter[i-1] - xcenter[i+1])*(xcenter[i-1] - xcenter[i+1])
7263 + (ycenter[i-1] - ycenter[i+1])*(ycenter[i-1] - ycenter[i+1]);
7264 dist3 = (xcenter[i] - xcenter[i+1])*(xcenter[i] - xcenter[i+1])
7265 + (ycenter[i] - ycenter[i+1])*(ycenter[i] - ycenter[i+1]);
7266 xmpseudo[i] = sqrt(dist1/dist2);
7267 ympseudo[i] = sqrt(dist3/dist2);
7270 cpl_table_set_invalid(maskslits,
"xpseudo", 0);
7271 cpl_table_set_invalid(maskslits,
"xpseudo", nmaskslits-1);
7272 cpl_table_set_invalid(maskslits,
"ypseudo", 0);
7273 cpl_table_set_invalid(maskslits,
"ypseudo", nmaskslits-1);
7285 if (cpl_table_has_column(slits,
"slit_id"))
7286 cpl_table_erase_column(slits,
"slit_id");
7287 cpl_table_new_column(slits,
"slit_id", CPL_TYPE_INT);
7288 slit_id = cpl_table_get_data_int(maskslits,
"slit_id");
7290 for (i = 1; i < nmaskslits - 1; i++) {
7292 mindist = (xmpseudo[i] - xpseudo[1]) * (xmpseudo[i] - xpseudo[1])
7293 + (ympseudo[i] - ypseudo[1]) * (ympseudo[i] - ypseudo[1]);
7295 if (mindist < sradius*sradius)
7297 for (j = 2; j < nslits - 1; j++) {
7298 dist = (xmpseudo[i] - xpseudo[j]) * (xmpseudo[i] - xpseudo[j])
7299 + (ympseudo[i] - ypseudo[j]) * (ympseudo[i] - ypseudo[j]);
7300 if (dist < sradius*sradius)
7304 if (mindist > dist) {
7310 mindist = sqrt(mindist);
7312 if (mindist < sradius && in_sradius == 1) {
7313 cpl_table_set_int(slits,
"slit_id", minpos-1, slit_id[i-1]);
7314 cpl_table_set_int(slits,
"slit_id", minpos, slit_id[i]);
7315 cpl_table_set_int(slits,
"slit_id", minpos+1, slit_id[i+1]);
7325 found_slits = nslits - cpl_table_count_invalid(slits,
"slit_id");
7327 if (found_slits < 3) {
7328 cpl_msg_warning(func,
"Too few preliminarily identified slits: "
7329 "%d out of %d", found_slits, nslits);
7330 if (nslits == nmaskslits) {
7331 cpl_msg_warning(func,
"(this is not an error, it could be caused "
7332 "by a mask with regularly located slits)");
7333 cpl_msg_warning(func,
"The detected slits positions are left "
7343 cpl_table_erase_column(slits,
"slit_id");
7344 cpl_table_erase_column(slits,
"xpseudo");
7345 cpl_table_erase_column(slits,
"ypseudo");
7346 positions = cpl_table_duplicate(slits);
7347 cpl_table_erase_column(slits,
"xcenter");
7348 cpl_table_erase_column(slits,
"ycenter");
7350 cpl_table_erase_column(maskslits,
"xpseudo");
7351 cpl_table_erase_column(maskslits,
"ypseudo");
7352 cpl_table_duplicate_column(positions,
"xmtop",
7354 cpl_table_duplicate_column(positions,
"ymtop",
7356 cpl_table_duplicate_column(positions,
"xmbottom",
7357 maskslits,
"xbottom");
7358 cpl_table_duplicate_column(positions,
"ymbottom",
7359 maskslits,
"ybottom");
7360 cpl_table_duplicate_column(positions,
"xmcenter",
7361 maskslits,
"xcenter");
7362 cpl_table_duplicate_column(positions,
"ymcenter",
7363 maskslits,
"ycenter");
7364 cpl_table_duplicate_column(positions,
"slit_id",
7365 maskslits,
"slit_id");
7366 cpl_table_erase_column(maskslits,
"xcenter");
7367 cpl_table_erase_column(maskslits,
"ycenter");
7371 cpl_table_erase_column(slits,
"slit_id");
7372 cpl_table_erase_column(slits,
"xpseudo");
7373 cpl_table_erase_column(slits,
"ypseudo");
7374 positions = cpl_table_duplicate(slits);
7375 cpl_table_erase_column(slits,
"xcenter");
7376 cpl_table_erase_column(slits,
"ycenter");
7377 cpl_msg_warning(func,
"(the failure could be caused "
7378 "by a mask with regularly located slits)");
7383 cpl_msg_info(func,
"Preliminarily identified slits: %d out of %d "
7384 "candidates (%d expected)", found_slits, nslits,
7395 positions = cpl_table_new(found_slits);
7396 cpl_table_new_column(positions,
"slit_id", CPL_TYPE_INT);
7397 cpl_table_new_column(positions,
"xtop", CPL_TYPE_DOUBLE);
7398 cpl_table_new_column(positions,
"ytop", CPL_TYPE_DOUBLE);
7399 cpl_table_new_column(positions,
"xbottom", CPL_TYPE_DOUBLE);
7400 cpl_table_new_column(positions,
"ybottom", CPL_TYPE_DOUBLE);
7401 cpl_table_new_column(positions,
"xcenter", CPL_TYPE_DOUBLE);
7402 cpl_table_new_column(positions,
"ycenter", CPL_TYPE_DOUBLE);
7403 cpl_table_new_column(positions,
"xmtop", CPL_TYPE_DOUBLE);
7404 cpl_table_new_column(positions,
"ymtop", CPL_TYPE_DOUBLE);
7405 cpl_table_new_column(positions,
"xmbottom", CPL_TYPE_DOUBLE);
7406 cpl_table_new_column(positions,
"ymbottom", CPL_TYPE_DOUBLE);
7407 cpl_table_new_column(positions,
"xmcenter", CPL_TYPE_DOUBLE);
7408 cpl_table_new_column(positions,
"ymcenter", CPL_TYPE_DOUBLE);
7409 cpl_table_new_column(positions,
"good", CPL_TYPE_INT);
7410 cpl_table_fill_column_window_int(positions,
"good", 0, found_slits, 0);
7412 slit_id = cpl_table_get_data_int (slits,
"slit_id");
7413 xtop = cpl_table_get_data_double(slits,
"xtop");
7414 ytop = cpl_table_get_data_double(slits,
"ytop");
7415 xbottom = cpl_table_get_data_double(slits,
"xbottom");
7416 ybottom = cpl_table_get_data_double(slits,
"ybottom");
7417 xcenter = cpl_table_get_data_double(slits,
"xcenter");
7418 ycenter = cpl_table_get_data_double(slits,
"ycenter");
7420 mslit_id = cpl_table_get_data_int (maskslits,
"slit_id");
7421 xmtop = cpl_table_get_data_double(maskslits,
"xtop");
7422 ymtop = cpl_table_get_data_double(maskslits,
"ytop");
7423 xmbottom = cpl_table_get_data_double(maskslits,
"xbottom");
7424 ymbottom = cpl_table_get_data_double(maskslits,
"ybottom");
7425 xmcenter = cpl_table_get_data_double(maskslits,
"xcenter");
7426 ymcenter = cpl_table_get_data_double(maskslits,
"ycenter");
7436 cpl_table_fill_invalid_int(slits,
"slit_id", 0);
7437 for (i = 0; i < nmaskslits; i++) {
7438 for (j = 0; j < nslits; j++) {
7439 if (slit_id[j] == 0)
7441 if (mslit_id[i] == slit_id[j]) {
7442 cpl_table_set_int (positions,
"slit_id", k, slit_id[j]);
7444 cpl_table_set_double(positions,
"xtop", k, xtop[j]);
7445 cpl_table_set_double(positions,
"ytop", k, ytop[j]);
7446 cpl_table_set_double(positions,
"xbottom", k, xbottom[j]);
7447 cpl_table_set_double(positions,
"ybottom", k, ybottom[j]);
7448 cpl_table_set_double(positions,
"xcenter", k, xcenter[j]);
7449 cpl_table_set_double(positions,
"ycenter", k, ycenter[j]);
7451 cpl_table_set_double(positions,
"xmtop", k, xmtop[i]);
7452 cpl_table_set_double(positions,
"ymtop", k, ymtop[i]);
7453 cpl_table_set_double(positions,
"xmbottom", k, xmbottom[i]);
7454 cpl_table_set_double(positions,
"ymbottom", k, ymbottom[i]);
7455 cpl_table_set_double(positions,
"xmcenter", k, xmcenter[i]);
7456 cpl_table_set_double(positions,
"ymcenter", k, ymcenter[i]);
7467 cpl_table_erase_column(slits,
"slit_id");
7468 cpl_table_erase_column(slits,
"xpseudo");
7469 cpl_table_erase_column(slits,
"ypseudo");
7470 cpl_table_erase_column(slits,
"xcenter");
7471 cpl_table_erase_column(slits,
"ycenter");
7472 cpl_table_erase_column(maskslits,
"xpseudo");
7473 cpl_table_erase_column(maskslits,
"ypseudo");
7474 cpl_table_erase_column(maskslits,
"xcenter");
7475 cpl_table_erase_column(maskslits,
"ycenter");
7485 ytop = cpl_table_get_data_double(positions,
"ytop");
7486 ybottom = cpl_table_get_data_double(positions,
"ybottom");
7487 xcenter = cpl_table_get_data_double(positions,
"xcenter");
7488 ycenter = cpl_table_get_data_double(positions,
"ycenter");
7489 xmcenter = cpl_table_get_data_double(positions,
"xmcenter");
7490 ymcenter = cpl_table_get_data_double(positions,
"ymcenter");
7492 scales = cpl_vector_new(found_slits - 1);
7493 dscale = cpl_vector_get_data(scales);
7494 angles = cpl_vector_new(found_slits - 1);
7495 dangle = cpl_vector_get_data(angles);
7497 for (i = 1; i < found_slits; i++) {
7498 dist1 = (xcenter[i-1] - xcenter[i]) * (xcenter[i-1] - xcenter[i])
7499 + (ycenter[i-1] - ycenter[i]) * (ycenter[i-1] - ycenter[i]);
7500 dist2 = (xmcenter[i-1] - xmcenter[i]) * (xmcenter[i-1] - xmcenter[i])
7501 + (ymcenter[i-1] - ymcenter[i]) * (ymcenter[i-1] - ymcenter[i]);
7502 dscale[i-1] = sqrt(dist1/dist2);
7503 dangle[i-1] = atan2(ycenter[i-1] - ycenter[i],
7504 xcenter[i-1] - xcenter[i])
7505 - atan2(ymcenter[i-1] - ymcenter[i],
7506 xmcenter[i-1] - xmcenter[i]);
7511 minscale = cpl_vector_get_min(scales);
7512 scale = cpl_vector_get_median_const(scales);
7513 maxscale = cpl_vector_get_max(scales);
7515 minangle = cpl_vector_get_min(angles);
7516 angle = cpl_vector_get_median_const(angles);
7517 maxangle = cpl_vector_get_max(angles);
7519 cpl_msg_info(func,
"Median platescale: %f pixel/mm", scale);
7520 cpl_msg_info(func,
"Minmax platescale: %f, %f pixel/mm",
7521 minscale, maxscale);
7523 cpl_msg_info(func,
"Median rotation: %f degrees", angle);
7524 cpl_msg_info(func,
"Minmax rotation: %f, %f degrees",
7525 minangle, maxangle);
7527 good = cpl_table_get_data_int(positions,
"good");
7529 good[0] = good[found_slits - 1] = 1;
7530 for (i = 1; i < found_slits; i++) {
7531 if (fabs((dscale[i-1] - scale)/scale) < 0.10
7532 && fabs(dangle[i-1] - angle) < 2) {
7538 for (i = 0; i < found_slits; i++) {
7578 cpl_vector_delete(scales);
7579 cpl_vector_delete(angles);
7581 cpl_table_and_selected_int(positions,
"good", CPL_EQUAL_TO, 0);
7582 cpl_table_erase_selected(positions);
7583 cpl_table_erase_column(positions,
"good");
7584 found_slits = cpl_table_get_nrow(positions);
7586 if (found_slits < 4) {
7594 cpl_msg_warning(func,
"Too few safely identified slits: %d out of %d "
7595 "candidates (%d expected). Process will continue "
7596 "using the detected CCD slits positions", found_slits,
7597 nslits, nmaskslits);
7598 cpl_table_delete(positions);
7602 cpl_msg_info(func,
"Safely identified slits: %d out of %d "
7603 "candidates\n(%d expected)", found_slits, nslits,
7614 xpos = cpl_vector_wrap(found_slits,
7615 cpl_table_get_data_double(positions,
"xcenter"));
7616 ypos = cpl_vector_wrap(found_slits,
7617 cpl_table_get_data_double(positions,
"ycenter"));
7618 xmpos = cpl_vector_wrap(found_slits,
7619 cpl_table_get_data_double(positions,
"xmcenter"));
7620 ympos = cpl_vector_wrap(found_slits,
7621 cpl_table_get_data_double(positions,
"ymcenter"));
7622 mpos = cpl_bivector_wrap_vectors(xmpos, ympos);
7624 if (found_slits < 10)
7629 xpoly = cpl_polynomial_fit_2d_create(mpos, xpos, degree, &xmse);
7631 ypoly = cpl_polynomial_fit_2d_create(mpos, ypos, degree, &ymse);
7632 cpl_bivector_unwrap_vectors(mpos);
7633 cpl_vector_unwrap(xpos);
7634 cpl_vector_unwrap(ypos);
7635 cpl_vector_unwrap(xmpos);
7636 cpl_vector_unwrap(ympos);
7637 if (ypoly == NULL) {
7638 if (found_slits == nmaskslits) {
7639 cpl_msg_warning(func,
"Fit failure: the accuracy of the "
7640 "identified slits positions is not improved.");
7651 cpl_msg_info(func,
"Fit failure: not all slits have been "
7652 "identified. Process will continue using "
7653 "the detected CCD slits positions");
7656 cpl_polynomial_delete(xpoly);
7660 cpl_msg_info(func,
"Fit successful: X rms = %.3g, Y rms = %.3g (pixel)",
7661 sqrt(xmse), sqrt(ymse));
7664 write_global_distortion(global, 0, xpoly);
7665 write_global_distortion(global, 7, ypoly);
7673 cpl_table_delete(positions);
7675 positions = cpl_table_duplicate(maskslits);
7676 cpl_table_duplicate_column(positions,
"xmtop", positions,
"xtop");
7677 cpl_table_duplicate_column(positions,
"ymtop", positions,
"ytop");
7678 cpl_table_duplicate_column(positions,
"xmbottom", positions,
"xbottom");
7679 cpl_table_duplicate_column(positions,
"ymbottom", positions,
"ybottom");
7681 point = cpl_vector_new(2);
7682 dpoint = cpl_vector_get_data(point);
7684 for (i = 0; i < nmaskslits; i++) {
7685 dpoint[0] = cpl_table_get_double(positions,
"xmtop", i, NULL);
7686 dpoint[1] = cpl_table_get_double(positions,
"ymtop", i, NULL);
7687 cpl_table_set_double(positions,
"xtop", i,
7688 cpl_polynomial_eval(xpoly, point));
7689 cpl_table_set_double(positions,
"ytop", i,
7690 cpl_polynomial_eval(ypoly, point));
7691 dpoint[0] = cpl_table_get_double(positions,
"xmbottom", i, NULL);
7692 dpoint[1] = cpl_table_get_double(positions,
"ymbottom", i, NULL);
7693 cpl_table_set_double(positions,
"xbottom", i,
7694 cpl_polynomial_eval(xpoly, point));
7695 cpl_table_set_double(positions,
"ybottom", i,
7696 cpl_polynomial_eval(ypoly, point));
7699 cpl_vector_delete(point);
7700 cpl_polynomial_delete(xpoly);
7701 cpl_polynomial_delete(ypoly);
7703 cpl_table_erase_column(positions,
"xmtop");
7704 cpl_table_erase_column(positions,
"ymtop");
7705 cpl_table_erase_column(positions,
"xmbottom");
7706 cpl_table_erase_column(positions,
"ymbottom");
7708 if (nmaskslits > nslits)
7709 cpl_msg_info(func,
"Finally identified slits: %d out of %d expected\n"
7710 "(%d recovered)", nmaskslits, nmaskslits, nmaskslits - nslits);
7711 else if (nmaskslits < nslits)
7712 cpl_msg_info(func,
"Finally identified slits: %d out of %d expected\n"
7713 "(%d rejected)", nmaskslits, nmaskslits, nslits - nmaskslits);
7715 cpl_msg_info(func,
"Finally identified slits: %d out of %d expected",
7716 nmaskslits, nmaskslits);
7764 double blue,
double red,
double dispersion)
7767 const char *func =
"mos_trace_flat";
7769 cpl_image *gradient;
7770 cpl_image *sgradient;
7787 double start_y, prev_y;
7796 int pixel_above, pixel_below;
7798 char trace_id[MAX_COLNAME];
7803 if (flat == NULL || slits == NULL) {
7804 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
7808 if (dispersion <= 0.0) {
7809 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
7813 if (red - blue < dispersion) {
7814 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
7823 nslits = cpl_table_get_nrow(slits);
7824 if (1 != cpl_table_has_column(slits,
"slit_id")) {
7825 cpl_table_new_column(slits,
"slit_id", CPL_TYPE_INT);
7826 for (i = 0; i < nslits; i++)
7827 cpl_table_set_int(slits,
"slit_id", i, -(i+1));
7830 slit_id = cpl_table_get_data_int(slits,
"slit_id");
7832 nx = cpl_image_get_size_x(flat);
7833 ny = cpl_image_get_size_y(flat);
7836 gradient = cpl_image_duplicate(flat);
7837 dgradient = cpl_image_get_data_float(gradient);
7839 for (i = 0; i < ny - 1; i++) {
7841 for (j = 0; j < nx; j++) {
7843 dgradient[l] = fabs(dgradient[l] - dgradient[l + nx]);
7848 for (j = 0; j < nx; j++)
7849 dgradient[npix - j] = 0.0;
7851 cpl_image_turn(gradient, -1);
7852 nx = cpl_image_get_size_x(gradient);
7853 ny = cpl_image_get_size_y(gradient);
7854 sgradient = mos_image_vertical_median_filter(gradient,
7855 filtbox, 0, ny, 0, step);
7856 cpl_image_delete(gradient);
7863 dgradient = cpl_image_get_data_float(sgradient);
7865 for (i = 1; i <= ny; i += step) {
7866 row = cpl_vector_new_from_image_row(sgradient, i);
7867 srow = cpl_vector_filter_median_create(row, filtbox);
7868 cpl_vector_subtract(row, srow);
7869 cpl_vector_delete(srow);
7870 g = dgradient + (i-1)*nx;
7871 r = cpl_vector_get_data(row);
7872 for (j = 0; j < nx; j++)
7874 cpl_vector_delete(row);
7884 xtop = cpl_table_get_data_double(slits,
"xtop");
7885 ytop = cpl_table_get_data_double(slits,
"ytop");
7886 xbottom = cpl_table_get_data_double(slits,
"xbottom");
7887 ybottom = cpl_table_get_data_double(slits,
"ybottom");
7895 peaks = cpl_calloc(ny,
sizeof(cpl_vector *));
7897 for (i = 0; i < ny; i += step) {
7898 g = dgradient + i*nx;
7904 cpl_vector_subtract_scalar(peaks[i], 0.5);
7908 cpl_image_delete(sgradient);
7934 pixel_above = STRETCH_FACTOR * (red - reference) / dispersion;
7935 pixel_below = STRETCH_FACTOR * (reference - blue) / dispersion;
7942 nrows = (ny-1)/step + 1;
7943 traces = cpl_table_new(nrows);
7944 cpl_table_new_column(traces,
"x", CPL_TYPE_DOUBLE);
7945 cpl_table_set_column_unit(traces,
"x",
"pixel");
7946 for (i = 0, j = 0; i < ny; i += step, j++)
7947 cpl_table_set(traces,
"x", j, i);
7949 for (i = 0; i < nslits; i++) {
7970 peak = cpl_vector_get_data(peaks[pos]);
7971 npeaks = cpl_vector_get_size(peaks[pos]);
7973 min = fabs(peak[0] - xtop[i]);
7975 for (j = 1; j < npeaks; j++) {
7976 dist = fabs(peak[j] - xtop[i]);
7987 snprintf(trace_id, MAX_COLNAME,
"t%d", slit_id[i]);
7988 cpl_table_new_column(traces, trace_id, CPL_TYPE_DOUBLE);
7990 if (min > sradius || npeaks == 0) {
7991 cpl_msg_warning(func,
"Cannot find spectrum edge for "
7992 "top (or left) end of slit %d", slit_id[i]);
8004 cpl_table_set(traces, trace_id, pos/step, nx - peak[minpos]);
8005 start_y = peak[minpos];
8013 for (j = pos + step; j < ny; j += step) {
8014 if (j - pos > pixel_above)
8017 peak = cpl_vector_get_data(peaks[j]);
8018 npeaks = cpl_vector_get_size(peaks[j]);
8019 min = fabs(peak[0] - prev_y);
8021 for (k = 1; k < npeaks; k++) {
8022 dist = fabs(peak[k] - prev_y);
8028 if (min < tolerance) {
8029 cpl_table_set(traces, trace_id, j/step,
8031 prev_y = peak[minpos];
8042 for (j = pos - step; j >= 0; j -= step) {
8043 if (pos - j > pixel_below)
8046 peak = cpl_vector_get_data(peaks[j]);
8047 npeaks = cpl_vector_get_size(peaks[j]);
8048 min = fabs(peak[0] - prev_y);
8050 for (k = 1; k < npeaks; k++) {
8051 dist = fabs(peak[k] - prev_y);
8057 if (min < tolerance) {
8058 cpl_table_set(traces, trace_id, j/step,
8060 prev_y = peak[minpos];
8072 peak = cpl_vector_get_data(peaks[pos]);
8073 npeaks = cpl_vector_get_size(peaks[pos]);
8075 min = fabs(peak[0] - xbottom[i]);
8077 for (j = 1; j < npeaks; j++) {
8078 dist = fabs(peak[j] - xbottom[i]);
8089 snprintf(trace_id, MAX_COLNAME,
"b%d", slit_id[i]);
8090 cpl_table_new_column(traces, trace_id, CPL_TYPE_DOUBLE);
8092 if (min > sradius || npeaks == 0) {
8093 cpl_msg_warning(func,
"Cannot find spectrum edge for "
8094 "bottom (or right) end of slit %d", slit_id[i]);
8098 cpl_table_set(traces, trace_id, pos/step, nx - peak[minpos]);
8099 start_y = peak[minpos];
8107 for (j = pos + step; j < ny; j += step) {
8108 if (j - pos > pixel_above)
8111 peak = cpl_vector_get_data(peaks[j]);
8112 npeaks = cpl_vector_get_size(peaks[j]);
8113 min = fabs(peak[0] - prev_y);
8115 for (k = 1; k < npeaks; k++) {
8116 dist = fabs(peak[k] - prev_y);
8122 if (min < tolerance) {
8123 cpl_table_set(traces, trace_id, j/step,
8125 prev_y = peak[minpos];
8136 for (j = pos - step; j >= 0; j -= step) {
8137 if (pos - j > pixel_below)
8140 peak = cpl_vector_get_data(peaks[j]);
8141 npeaks = cpl_vector_get_size(peaks[j]);
8142 min = fabs(peak[0] - prev_y);
8144 for (k = 1; k < npeaks; k++) {
8145 dist = fabs(peak[k] - prev_y);
8151 if (min < tolerance) {
8152 cpl_table_set(traces, trace_id, j/step,
8154 prev_y = peak[minpos];
8162 for (i = 0; i < ny; i += step)
8163 cpl_vector_delete(peaks[i]);
8199 const char *func =
"mos_poly_trace";
8201 cpl_table *polytraces;
8205 cpl_polynomial *polytrace;
8206 char trace_id[MAX_COLNAME];
8207 char trace_res[MAX_COLNAME];
8208 char trace_mod[MAX_COLNAME];
8209 const char *clab[6] = {
"c0",
"c1",
"c2",
"c3",
"c4",
"c5"};
8220 if (traces == NULL || slits == NULL) {
8221 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
8226 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
8230 nrows = cpl_table_get_nrow(traces);
8231 xdata = cpl_table_get_data_double(traces,
"x");
8232 nslits = cpl_table_get_nrow(slits);
8233 slit_id = cpl_table_get_data_int(slits,
"slit_id");
8235 polytraces = cpl_table_new(2*nslits);
8236 cpl_table_new_column(polytraces,
"slit_id", CPL_TYPE_INT);
8237 for (i = 0; i <= order; i++)
8238 cpl_table_new_column(polytraces, clab[i], CPL_TYPE_DOUBLE);
8240 for (i = 0; i < nslits; i++) {
8241 for (j = 0; j < 2; j++) {
8244 snprintf(trace_id, MAX_COLNAME,
"b%d", slit_id[i]);
8245 snprintf(trace_res, MAX_COLNAME,
"b%d_res", slit_id[i]);
8246 snprintf(trace_mod, MAX_COLNAME,
"b%d_mod", slit_id[i]);
8249 snprintf(trace_id, MAX_COLNAME,
"t%d", slit_id[i]);
8250 snprintf(trace_res, MAX_COLNAME,
"t%d_res", slit_id[i]);
8251 snprintf(trace_mod, MAX_COLNAME,
"t%d_mod", slit_id[i]);
8254 cpl_table_set_int(polytraces,
"slit_id", 2*i+j, slit_id[i]);
8261 dummy = cpl_table_new(nrows);
8262 cpl_table_duplicate_column(dummy,
"x", traces,
"x");
8263 cpl_table_duplicate_column(dummy, trace_id, traces, trace_id);
8264 npoints = nrows - cpl_table_count_invalid(dummy, trace_id);
8265 if (npoints < 2 * order) {
8266 cpl_table_delete(dummy);
8269 cpl_table_erase_invalid(dummy);
8270 x = cpl_vector_wrap(npoints,
8271 cpl_table_get_data_double(dummy,
"x"));
8272 trace = cpl_vector_wrap(npoints,
8273 cpl_table_get_data_double(dummy, trace_id));
8274 polytrace = cpl_polynomial_fit_1d_create(x, trace, order, NULL);
8275 cpl_vector_unwrap(x);
8276 cpl_vector_unwrap(trace);
8277 cpl_table_delete(dummy);
8286 if (fabs(cpl_polynomial_get_coeff(polytrace, &k)) > 1.E-4) {
8287 cpl_polynomial_delete(polytrace);
8288 cpl_table_new_column(traces, trace_mod, CPL_TYPE_DOUBLE);
8289 cpl_table_duplicate_column(traces, trace_res, traces,
8292 cpl_msg_warning(func,
"Exclude bad curvature solution "
8293 "for bottom (right) edge of slit %d", slit_id[i]);
8295 cpl_msg_warning(func,
"Exclude bad curvature solution "
8296 "for top (left) edge of slit %d", slit_id[i]);
8305 for (k = 0; k <= order; k++)
8306 cpl_table_set_double(polytraces, clab[k], 2*i+j,
8307 cpl_polynomial_get_coeff(polytrace, &k));
8313 cpl_table_new_column(traces, trace_mod, CPL_TYPE_DOUBLE);
8314 cpl_table_set_column_unit(traces, trace_mod,
"pixel");
8316 for (k = 0; k < nrows; k++) {
8317 cpl_table_set_double(traces, trace_mod, k,
8318 cpl_polynomial_eval_1d(polytrace, xdata[k], NULL));
8321 cpl_polynomial_delete(polytrace);
8323 cpl_table_duplicate_column(traces, trace_res, traces, trace_mod);
8324 cpl_table_subtract_columns(traces, trace_res, trace_id);
8325 cpl_table_multiply_scalar(traces, trace_res, -1.0);
8361 const char *func =
"mos_global_trace";
8363 const char *clab[6] = {
"c0",
"c1",
"c2",
"c3",
"c4",
"c5"};
8376 int order, nrows, nslits;
8380 if (polytraces == NULL) {
8381 cpl_msg_error(func,
"Missing spectral curvature table");
8382 return cpl_error_set(func, CPL_ERROR_NULL_INPUT);
8385 if (slits == NULL) {
8386 cpl_msg_error(func,
"Missing slits positions table");
8387 return cpl_error_set(func, CPL_ERROR_NULL_INPUT);
8390 nslits = cpl_table_get_nrow(slits);
8392 table = cpl_table_duplicate(polytraces);
8393 cpl_table_erase_invalid(table);
8395 nrows = cpl_table_get_nrow(table);
8398 cpl_msg_warning(func,
"Too few successful spectral curvature tracings "
8399 "(%d): the determination of a global curvature model "
8401 return CPL_ERROR_NONE;
8404 order = cpl_table_get_ncol(polytraces) - 2;
8406 for (i = 0; i <= order; i++) {
8407 if (!cpl_table_has_column(table, clab[i])) {
8408 cpl_msg_error(func,
"Wrong spectral curvature table");
8409 return cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
8418 for (i = 0; i < nslits; i++) {
8419 if (!cpl_table_is_valid(polytraces, clab[0], 2*i)) {
8420 cpl_table_set_double(polytraces, clab[0], 2*i,
8421 cpl_table_get_double(slits,
"ytop", i, NULL));
8423 if (!cpl_table_is_valid(polytraces, clab[0], 2*i+1)) {
8424 cpl_table_set_double(polytraces, clab[0], 2*i+1,
8425 cpl_table_get_double(slits,
"ybottom", i, NULL));
8429 offset = cpl_table_get_data_double(polytraces, clab[0]);
8436 c0 = cpl_vector_wrap(nrows, cpl_table_get_data_double(table, clab[0]));
8438 for (i = 1; i <= order; i++) {
8439 cn = cpl_vector_wrap(nrows, cpl_table_get_data_double(table, clab[i]));
8440 list = cpl_bivector_wrap_vectors(c0, cn);
8441 robustLinearFit(list, &q, &m, &rms);
8445 for (j = 0; j < 2*nslits; j++) {
8447 if (cpl_table_is_valid(polytraces, clab[i], j))
8449 cpl_table_set_double(polytraces, clab[i], j, offset[j]*m + q);
8455 cpl_bivector_unwrap_vectors(list);
8459 cpl_vector_unwrap(cn);
8462 cpl_vector_unwrap(c0);
8463 cpl_table_delete(table);
8465 return CPL_ERROR_NONE;
8540 cpl_table *polytraces,
double reference,
8541 double blue,
double red,
double dispersion,
8542 int flux, cpl_image *calibration)
8544 const char *func =
"mos_spatial_calibration";
8546 const char *clab[6] = {
"c0",
"c1",
"c2",
"c3",
"c4",
"c5"};
8548 cpl_polynomial *polytop;
8549 cpl_polynomial *polybot;
8551 cpl_image *resampled;
8555 double vtop, vbot, value;
8561 int yint, ysize, yprev;
8567 int pixel_above, pixel_below, refpixel, start_pixel, end_pixel;
8568 int missing_top, missing_bot;
8574 int create_position = 1;
8577 if (spectra == NULL || slits == NULL || polytraces == NULL) {
8578 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
8582 if (dispersion <= 0.0) {
8583 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
8587 if (red - blue < dispersion) {
8588 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
8592 nx = cpl_image_get_size_x(spectra);
8593 ny = cpl_image_get_size_y(spectra);
8594 sdata = cpl_image_get_data(spectra);
8596 data = cpl_image_get_data(calibration);
8598 if (cpl_table_has_column(slits,
"position"))
8599 create_position = 0;
8601 if (create_position) {
8602 cpl_table_new_column(slits,
"position", CPL_TYPE_INT);
8603 cpl_table_new_column(slits,
"length", CPL_TYPE_INT);
8604 cpl_table_set_column_unit(slits,
"position",
"pixel");
8605 cpl_table_set_column_unit(slits,
"length",
"pixel");
8608 length = cpl_table_get_data_int(slits,
"length");
8610 nslits = cpl_table_get_nrow(slits);
8611 slit_id = cpl_table_get_data_int(slits,
"slit_id");
8612 order = cpl_table_get_ncol(polytraces) - 2;
8619 pixel_above = STRETCH_FACTOR * (red - reference) / dispersion;
8620 pixel_below = STRETCH_FACTOR * (reference - blue) / dispersion;
8622 exslit = cpl_calloc(nslits,
sizeof(cpl_image *));
8624 for (i = 0; i < nslits; i++) {
8626 if (create_position == 0)
8641 refpixel = cpl_table_get_double(slits,
"xtop", i, NULL);
8643 start_pixel = refpixel - pixel_below;
8644 if (start_pixel < 0)
8647 end_pixel = refpixel + pixel_above;
8657 polytop = cpl_polynomial_new(1);
8658 for (k = 0; k <= order; k++) {
8659 coeff = cpl_table_get_double(polytraces, clab[k], 2*i, &null);
8661 cpl_polynomial_delete(polytop);
8665 cpl_polynomial_set_coeff(polytop, &k, coeff);
8669 polybot = cpl_polynomial_new(1);
8670 for (k = 0; k <= order; k++) {
8671 coeff = cpl_table_get_double(polytraces, clab[k], 2*i+1, &null);
8673 cpl_polynomial_delete(polybot);
8677 cpl_polynomial_set_coeff(polybot, &k, coeff);
8680 if (missing_top && missing_bot) {
8681 cpl_msg_warning(func,
"Spatial calibration, slit %d was not "
8682 "traced: no extraction!",
8694 cpl_msg_warning(func,
"Upper edge of slit %d was not traced: "
8695 "the spectral curvature of the lower edge "
8696 "is used instead.", slit_id[i]);
8697 polytop = cpl_polynomial_duplicate(polybot);
8698 ytop = cpl_table_get_double(slits,
"ytop", i, NULL);
8699 ybot = cpl_table_get_double(slits,
"ybottom", i, NULL);
8701 coeff = cpl_polynomial_get_coeff(polybot, &k);
8702 coeff += ytop - ybot;
8703 cpl_polynomial_set_coeff(polytop, &k, coeff);
8707 cpl_msg_warning(func,
"Lower edge of slit %d was not traced: "
8708 "the spectral curvature of the upper edge "
8709 "is used instead.", slit_id[i]);
8710 polybot = cpl_polynomial_duplicate(polytop);
8711 ytop = cpl_table_get_double(slits,
"ytop", i, NULL);
8712 ybot = cpl_table_get_double(slits,
"ybottom", i, NULL);
8714 coeff = cpl_polynomial_get_coeff(polytop, &k);
8715 coeff -= ytop - ybot;
8716 cpl_polynomial_set_coeff(polybot, &k, coeff);
8723 top = cpl_polynomial_eval_1d(polytop, refpixel, NULL);
8724 bot = cpl_polynomial_eval_1d(polybot, refpixel, NULL);
8725 npseudo = ceil(top-bot) + 1;
8728 cpl_polynomial_delete(polytop);
8729 cpl_polynomial_delete(polybot);
8730 cpl_msg_warning(func,
"Slit %d was badly traced: no extraction!",
8735 exslit[i] = cpl_image_new(nx, npseudo+1, CPL_TYPE_FLOAT);
8736 xdata = cpl_image_get_data(exslit[i]);
8742 for (j = start_pixel; j < end_pixel; j++) {
8743 top = cpl_polynomial_eval_1d(polytop, j, NULL);
8744 bot = cpl_polynomial_eval_1d(polybot, j, NULL);
8745 factor = (top-bot)/npseudo;
8746 for (k = 0; k <= npseudo; k++) {
8747 ypos = top - k*factor;
8750 if (yint >= 0 && yint < ny-1) {
8751 vtop = sdata[j + nx*yint];
8752 vbot = sdata[j + nx*(yint+1)];
8758 else if(vtop == FLT_MAX || vbot == FLT_MAX)
8762 value = vtop*(1-yfra) + vbot*yfra;
8766 xdata[j + nx*(npseudo-k)] = value;
8768 data[j + nx*yint] = (top-yint)/factor;
8777 if (yprev - yint > 1) {
8778 data[j + nx*(yint+1)] = (top-yint-1)/factor;
8786 cpl_polynomial_delete(polytop);
8787 cpl_polynomial_delete(polybot);
8795 for (i = 0; i < nslits; i++)
8797 ysize += cpl_image_get_size_y(exslit[i]);
8799 resampled = cpl_image_new(nx, ysize, CPL_TYPE_FLOAT);
8802 for (i = 0; i < nslits; i++) {
8804 yint += cpl_image_get_size_y(exslit[i]);
8805 cpl_image_copy(resampled, exslit[i], 1, ysize - yint);
8806 if (create_position) {
8807 cpl_table_set_int(slits,
"position", i, ysize - yint - 1);
8808 cpl_table_set_int(slits,
"length", i,
8809 cpl_image_get_size_y(exslit[i]));
8811 cpl_image_delete(exslit[i]);
8813 else if (create_position) {
8814 cpl_table_set_int(slits,
"position", i, -1);
8815 cpl_table_set_int(slits,
"length", i, 0);
8956 double dispersion,
float level,
8957 int sradius,
int order,
8958 double reject,
double refwave,
8959 double *wavestart,
double *waveend,
8960 int *nlines,
double *error,
8961 cpl_table *idscoeff,
8962 cpl_image *calibration,
8963 cpl_image *residuals,
8964 cpl_table *restable,
8965 cpl_table *detected_lines)
8968 const char *func =
"mos_wavelength_calibration_final";
8970 const char *clab[6] = {
"c0",
"c1",
"c2",
"c3",
"c4",
"c5"};
8973 double tolerance = 20.0;
8976 char name[MAX_COLNAME];
8978 cpl_image *resampled;
8979 cpl_bivector *peaks_ident;
8982 cpl_polynomial *ids;
8983 cpl_polynomial *lin;
8984 cpl_polynomial *fguess;
8987 double max_disp, min_disp;
8989 double firstLambda, lastLambda, lambda;
8990 double wave, pixe, value;
8999 int pixstart, pixend;
9000 int row_top, row_bot;
9005 int nl, nx, ny, pixel;
9006 int countLines, usedLines;
9015 if (dispersion == 0.0) {
9016 cpl_msg_error(func,
"The expected dispersion (A/pixel) must be given");
9017 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
9021 if (dispersion < 0.0) {
9022 cpl_msg_error(func,
"The expected dispersion must be positive");
9023 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
9027 if (idscoeff == NULL) {
9028 cpl_msg_error(func,
"A preallocated IDS coeff table must be given");
9029 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
9033 max_disp = dispersion + dispersion * tolerance / 100;
9034 min_disp = dispersion - dispersion * tolerance / 100;
9037 cpl_msg_error(func,
"The order of the fitting polynomial "
9038 "must be at least 1");
9039 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
9043 if (image == NULL || lines == NULL) {
9044 cpl_msg_error(func,
"Both spectral exposure and reference line "
9045 "catalog are required in input");
9046 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
9050 nx = cpl_image_get_size_x(image);
9051 ny = cpl_image_get_size_y(image);
9052 sdata = cpl_image_get_data_float(image);
9054 nref = cpl_vector_get_size(lines);
9055 line = cpl_vector_get_data(lines);
9057 if (*wavestart < 1.0 && *waveend < 1.0) {
9058 firstLambda = line[0];
9059 lastLambda = line[nref-1];
9060 extrapolation = (lastLambda - firstLambda) / 10;
9061 firstLambda -= extrapolation;
9062 lastLambda += extrapolation;
9063 *wavestart = firstLambda;
9064 *waveend = lastLambda;
9067 firstLambda = *wavestart;
9068 lastLambda = *waveend;
9071 nl = (lastLambda - firstLambda) / dispersion;
9072 resampled = cpl_image_new(nl, ny, CPL_TYPE_FLOAT);
9073 rdata = cpl_image_get_data_float(resampled);
9079 for (j = 0; j <= order; j++)
9080 cpl_table_new_column(idscoeff, clab[j], CPL_TYPE_DOUBLE);
9083 idata = cpl_image_get_data_float(calibration);
9086 ddata = cpl_image_get_data_float(residuals);
9089 cpl_table_set_size(restable, nref);
9090 cpl_table_new_column(restable,
"wavelength", CPL_TYPE_DOUBLE);
9091 cpl_table_copy_data_double(restable,
"wavelength", line);
9092 for (i = 0; i < ny; i += step) {
9093 snprintf(name, MAX_COLNAME,
"r%d", i);
9094 cpl_table_new_column(restable, name, CPL_TYPE_DOUBLE);
9095 snprintf(name, MAX_COLNAME,
"d%d", i);
9096 cpl_table_new_column(restable, name, CPL_TYPE_DOUBLE);
9097 snprintf(name, MAX_COLNAME,
"p%d", i);
9098 cpl_table_new_column(restable, name, CPL_TYPE_DOUBLE);
9102 if (detected_lines) {
9103 cpl_table_set_size(detected_lines, 0);
9104 cpl_table_new_column(detected_lines,
"slit_id", CPL_TYPE_INT);
9105 cpl_table_new_column(detected_lines,
"xpos_rectified", CPL_TYPE_DOUBLE);
9106 cpl_table_new_column(detected_lines,
"ypos_rectified", CPL_TYPE_DOUBLE);
9107 cpl_table_new_column(detected_lines,
"xpos_rectified_iter", CPL_TYPE_DOUBLE);
9108 cpl_table_new_column(detected_lines,
"ypos_rectified_iter", CPL_TYPE_DOUBLE);
9109 cpl_table_new_column(detected_lines,
"peak_flux", CPL_TYPE_DOUBLE);
9110 cpl_table_new_column(detected_lines,
"wave_ident", CPL_TYPE_DOUBLE);
9111 cpl_table_new_column(detected_lines,
"wave_ident_iter", CPL_TYPE_DOUBLE);
9112 cpl_table_new_column(detected_lines,
"xpos_fit_rect_wavecal", CPL_TYPE_DOUBLE);
9113 cpl_table_new_column(detected_lines,
"res_xpos", CPL_TYPE_DOUBLE);
9121 nslits = cpl_table_get_nrow(slits);
9122 length = cpl_table_get_data_int(slits,
"length");
9125 for (s = 0; s < nslits; s++) {
9128 slit_id = cpl_table_get_int(slits,
"slit_id", s, NULL);
9138 row_bot = cpl_table_get_int(slits,
"position", s, NULL);
9150 coeff = cpl_table_new(row_top - row_bot);
9151 for (j = 0; j <= order; j++)
9152 cpl_table_new_column(coeff, clab[j], CPL_TYPE_DOUBLE);
9160 for (i = row_bot; i < row_top; i++) {
9169 int keep_multiplex = mos_multiplex;
9173 cpl_size newlines = cpl_vector_get_size(peaks);
9174 cpl_size oldsize = cpl_table_get_nrow(detected_lines);
9175 cpl_table_set_size(detected_lines, oldsize + newlines);
9176 for(cpl_size iline = 0; iline < newlines; ++iline)
9178 cpl_table_set_int(detected_lines,
"slit_id",
9179 oldsize + iline, slit_id);
9180 cpl_table_set_double(detected_lines,
"xpos_rectified",
9181 oldsize + iline, cpl_vector_get(peaks, iline) + 1);
9182 cpl_table_set_double(detected_lines,
"ypos_rectified",
9183 oldsize + iline, (
double)i + 1);
9184 cpl_table_set_double(detected_lines,
"peak_flux",
9186 sdata[i*nx+(
int)(cpl_vector_get(peaks, iline)+0.5)]);
9190 min_disp, max_disp, 0.05);
9191 mos_multiplex = keep_multiplex;
9193 countLines = cpl_bivector_get_size(peaks_ident);
9194 if (countLines < 4) {
9195 cpl_bivector_delete(peaks_ident);
9196 cpl_vector_delete(peaks);
9208 wavel = cpl_bivector_get_y(peaks_ident);
9209 cpl_vector_subtract_scalar(wavel, refwave);
9211 uorder = countLines / 2 - 1;
9216 2 * (uorder + 1), &usedLines,
9220 cpl_bivector_delete(peaks_ident);
9221 cpl_vector_delete(peaks);
9231 for (k = 0; k <= order; k++) {
9233 cpl_table_set_double(coeff, clab[k],
9237 cpl_table_set_double(coeff, clab[k],
9238 i - row_bot, cpl_polynomial_get_coeff(ids, &k));
9244 pixstart = cpl_polynomial_eval_1d(ids,
9245 cpl_bivector_get_y_data(peaks_ident)[0],
9247 pixend = cpl_polynomial_eval_1d(ids,
9248 cpl_bivector_get_y_data(peaks_ident)[countLines-1],
9250 extrapolation = (pixend - pixstart) / 5;
9251 pixstart -= extrapolation;
9252 pixend += extrapolation;
9258 for (j = pixstart; j < pixend; j++) {
9260 firstLambda, lastLambda, refwave, j);
9268 if (residuals || (restable && !(i%step))) {
9269 if (restable && !(i%step)) {
9270 lin = cpl_polynomial_new(1);
9271 for (k = 0; k < 2; k++)
9272 cpl_polynomial_set_coeff(lin, &k,
9273 cpl_polynomial_get_coeff(ids, &k));
9275 for (j = 0; j < countLines; j++) {
9276 pixe = cpl_bivector_get_x_data(peaks_ident)[j];
9277 wave = cpl_bivector_get_y_data(peaks_ident)[j];
9279 - cpl_polynomial_eval_1d(ids, wave, NULL);
9282 (ddata + i*nx)[pixel] = value;
9284 if (restable && !(i%step)) {
9285 for (k = 0; k < nref; k++) {
9286 if (fabs(line[k]-refwave-wave) < 0.1) {
9287 snprintf(name, MAX_COLNAME,
9289 cpl_table_set_double(restable, name,
9292 - cpl_polynomial_eval_1d(lin,
9294 snprintf(name, MAX_COLNAME,
9296 cpl_table_set_double(restable, name,
9298 snprintf(name, MAX_COLNAME,
9300 cpl_table_set_double(restable, name,
9307 if (restable && !(i%step)) {
9308 cpl_polynomial_delete(lin);
9325 cpl_size nidentlines = cpl_bivector_get_size(peaks_ident);
9326 cpl_size ndetectlines = cpl_vector_get_size(peaks);
9327 cpl_size totalsize = cpl_table_get_nrow(detected_lines);
9328 for(cpl_size idline = 0; idline < nidentlines; ++idline)
9330 for(cpl_size detline = 0; detline < ndetectlines; ++detline)
9332 if(cpl_vector_get(peaks, detline) ==
9333 cpl_bivector_get_x_data(peaks_ident)[idline])
9335 cpl_size table_pos = totalsize - ndetectlines + detline;
9336 double wave_ident = cpl_bivector_get_y_data(peaks_ident)[idline] + refwave;
9337 double xpix_fit = cpl_polynomial_eval_1d(ids,
9338 wave_ident - refwave, NULL);
9339 double xpos_det = cpl_table_get_double(detected_lines,
9342 cpl_table_set_double(detected_lines,
9346 cpl_table_set_double(detected_lines,
9347 "xpos_fit_rect_wavecal",
9350 cpl_table_set_double(detected_lines,
9353 xpos_det - xpix_fit - 1);
9369 nlines[i] = usedLines;
9371 error[i] = ids_err / sqrt(usedLines/(uorder + 1));
9373 for (k = 0; k <= order; k++) {
9375 cpl_table_set_double(idscoeff, clab[k], i, 0.0);
9378 cpl_table_set_double(idscoeff, clab[k], i,
9379 cpl_polynomial_get_coeff(ids, &k));
9383 cpl_polynomial_delete(ids);
9384 cpl_bivector_delete(peaks_ident);
9386 cpl_vector_delete(peaks);
9397 nfits = row_top - row_bot - cpl_table_count_invalid(coeff, clab[0]);
9402 fguess = cpl_polynomial_new(1);
9412 for (k = 0; k <= order; k++) {
9413 c = cpl_table_get_column_median(coeff, clab[k]);
9414 cpl_polynomial_set_coeff(fguess, &k, c);
9421 for (i = row_bot; i < row_top; i++) {
9428 if (width > sradius) {
9436 for (k = 0; k <= order; k++) {
9437 c = cpl_table_get_double(coeff, clab[k],
9439 cpl_polynomial_set_coeff(fguess, &k, c);
9444 fguess, refwave, uradius);
9446 if (peaks_ident == NULL) {
9451 countLines = cpl_bivector_get_size(peaks_ident);
9453 if (countLines < 4) {
9454 cpl_bivector_delete(peaks_ident);
9462 wavel = cpl_bivector_get_y(peaks_ident);
9463 cpl_vector_subtract_scalar(wavel, refwave);
9465 uorder = countLines / 2 - 1;
9470 2 * (uorder + 1), &usedLines,
9475 cpl_bivector_delete(peaks_ident);
9480 nlines[i] = usedLines;
9482 error[i] = ids_err / sqrt(usedLines/(uorder + 1));
9485 pixstart = cpl_polynomial_eval_1d(ids,
9486 cpl_bivector_get_y_data(peaks_ident)[0],
9488 pixend = cpl_polynomial_eval_1d(ids,
9489 cpl_bivector_get_y_data(peaks_ident)[countLines-1],
9491 extrapolation = (pixend - pixstart) / 5;
9492 pixstart -= extrapolation;
9493 pixend += extrapolation;
9499 for (j = pixstart; j < pixend; j++) {
9501 firstLambda, lastLambda, refwave, j);
9509 if (residuals || (restable && !(i%step))) {
9510 if (restable && !(i%step)) {
9511 lin = cpl_polynomial_new(1);
9512 for (k = 0; k < 2; k++)
9513 cpl_polynomial_set_coeff(lin, &k,
9514 cpl_polynomial_get_coeff(ids, &k));
9516 for (j = 0; j < countLines; j++) {
9517 pixe = cpl_bivector_get_x_data(peaks_ident)[j];
9518 wave = cpl_bivector_get_y_data(peaks_ident)[j];
9520 - cpl_polynomial_eval_1d(ids, wave, NULL);
9523 (ddata + i*nx)[pixel] = value;
9525 if (restable && !(i%step)) {
9526 for (k = 0; k < nref; k++) {
9527 if (fabs(line[k]-refwave-wave) < 0.1) {
9528 snprintf(name, MAX_COLNAME,
9530 cpl_table_set_double(restable, name,
9533 - cpl_polynomial_eval_1d(lin,
9535 snprintf(name, MAX_COLNAME,
9537 cpl_table_set_double(restable, name,
9539 snprintf(name, MAX_COLNAME,
9541 cpl_table_set_double(restable, name,
9548 if (restable && !(i%step)) {
9549 cpl_polynomial_delete(lin);
9566 cpl_size oldsize = cpl_table_get_nrow(detected_lines);
9567 cpl_size nidentlines = cpl_bivector_get_size(peaks_ident);
9568 cpl_table_set_size(detected_lines, oldsize + nidentlines);
9569 for(cpl_size idline = 0; idline < nidentlines ; ++idline)
9571 double wave_ident = cpl_bivector_get_y_data(peaks_ident)[idline] + refwave;
9572 double xpix_fit = cpl_polynomial_eval_1d(ids,
9573 wave_ident - refwave, NULL);
9574 cpl_table_set_int(detected_lines,
"slit_id",
9575 oldsize + idline, slit_id);
9576 cpl_table_set_double(detected_lines,
"xpos_rectified_iter",
9577 oldsize + idline, cpl_bivector_get_x_data(peaks_ident)[idline] + 1);
9578 cpl_table_set_double(detected_lines,
"ypos_rectified_iter",
9579 oldsize + idline, (
double)i + 1);
9580 cpl_table_set_double(detected_lines,
"peak_flux",
9582 sdata[i*nx+(
int)(cpl_bivector_get_x_data(peaks_ident)[idline]+0.5)]);
9583 cpl_table_set_double(detected_lines,
"wave_ident_iter",
9584 oldsize + idline, wave_ident);
9585 cpl_table_set_double(detected_lines,
"xpos_fit_rect_wavecal",
9586 oldsize + idline, xpix_fit + 1);
9591 for (k = 0; k <= order; k++) {
9593 cpl_table_set_double(idscoeff, clab[k], i, 0.0);
9596 cpl_table_set_double(idscoeff, clab[k], i,
9597 cpl_polynomial_get_coeff(ids, &k));
9601 cpl_bivector_delete(peaks_ident);
9602 cpl_polynomial_delete(ids);
9606 cpl_polynomial_delete(fguess);
9609 cpl_table_delete(coeff);
9625 for (i = 0; i < ny; i++) {
9628 ids = cpl_polynomial_new(1);
9629 for (k = 0; k <= order; k++) {
9630 c = cpl_table_get_double(idscoeff, clab[k], i, &null);
9632 cpl_polynomial_delete(ids);
9636 cpl_polynomial_set_coeff(ids, &k, c);
9641 pixstart = cpl_polynomial_eval_1d(ids, firstLambda - refwave, NULL);
9642 pixend = cpl_polynomial_eval_1d(ids, lastLambda - refwave, NULL);
9652 for (j = 0; j < nl; j++) {
9653 lambda = firstLambda + j * dispersion;
9654 fpixel = cpl_polynomial_eval_1d(ids, lambda - refwave, NULL);
9656 if (pixel >= 0 && pixel < nx-1) {
9657 v1 = (sdata + i*nx)[pixel];
9658 v2 = (sdata + i*nx)[pixel+1];
9659 vi = v1 + (v2-v1)*(fpixel-pixel);
9660 (rdata + i*nl)[j] = vi;
9664 cpl_polynomial_delete(ids);
9698 double firstLambda,
double lastLambda,
9699 double dispersion, cpl_table *idscoeff,
9703 const char *func =
"mos_wavelength_calibration";
9705 const char *clab[6] = {
"c0",
"c1",
"c2",
"c3",
"c4",
"c5"};
9708 cpl_image *resampled;
9709 cpl_polynomial *ids;
9710 double pixel_per_lambda;
9715 float v0, v1, v2, v3, vi;
9718 int pixstart, pixend;
9719 int nl, nx, ny, pixel;
9726 if (dispersion <= 0.0) {
9727 cpl_msg_error(func,
"The resampling step must be positive");
9728 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
9732 if (lastLambda - firstLambda < dispersion) {
9733 cpl_msg_error(func,
"Invalid spectral range: %.2f to %.2f",
9734 firstLambda, lastLambda);
9735 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
9739 if (idscoeff == NULL) {
9740 cpl_msg_error(func,
"An IDS coeff table must be given");
9741 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
9745 if (image == NULL) {
9746 cpl_msg_error(func,
"A scientific spectral image must be given");
9747 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
9751 nx = cpl_image_get_size_x(image);
9752 ny = cpl_image_get_size_y(image);
9753 sdata = cpl_image_get_data_float(image);
9755 nl = (lastLambda - firstLambda) / dispersion;
9756 resampled = cpl_image_new(nl, ny, CPL_TYPE_FLOAT);
9757 rdata = cpl_image_get_data_float(resampled);
9760 while (order < 6 && cpl_table_has_column(idscoeff, clab[order]))
9764 for (i = 0; i < ny; i++) {
9767 ids = cpl_polynomial_new(1);
9768 for (k = 0; k <= order; k++) {
9769 c = cpl_table_get_double(idscoeff, clab[k], i, &null);
9771 cpl_polynomial_delete(ids);
9775 cpl_polynomial_set_coeff(ids, &k, c);
9780 pixstart = cpl_polynomial_eval_1d(ids, firstLambda - refwave, NULL);
9781 pixend = cpl_polynomial_eval_1d(ids, lastLambda - refwave, NULL);
9791 for (j = 0; j < nl; j++) {
9792 lambda = firstLambda + j * dispersion;
9793 fpixel = cpl_polynomial_eval_1d(ids, lambda - refwave,
9815 if(pixel_per_lambda <= 0)
9817 else if (fpixel < 0)
9819 else if (pixel >= 1 && pixel < nx-2) {
9820 v0 = (sdata + i*nx)[pixel-1];
9821 v1 = (sdata + i*nx)[pixel];
9822 v2 = (sdata + i*nx)[pixel+1];
9823 v3 = (sdata + i*nx)[pixel+2];
9824 vi = (fpixel-pixel)*(fpixel-pixel)*(v3 - v2 - v1 + v0)
9825 + (fpixel-pixel)*(3*v2 - v3 - v1 - v0)
9845 vi *= dispersion * pixel_per_lambda;
9847 else if (pixel >= 0 && pixel < nx-1) {
9848 v1 = (sdata + i*nx)[pixel];
9849 v2 = (sdata + i*nx)[pixel+1];
9850 vi = v1 + (v2-v1)*(fpixel-pixel);
9852 vi *= dispersion * pixel_per_lambda;
9856 (rdata + i*nl)[j] = vi;
9869 double spos = fpixel - dispersion * pixel_per_lambda / 2;
9870 double epos = fpixel + dispersion * pixel_per_lambda / 2;
9877 int epix = epos + 1;
9886 for (k = spix; k < epix; k++) {
9887 if (pixel >= 0 && pixel < nx) {
9888 vi += (sdata + i*nx)[k];
9899 vi *= dispersion * pixel_per_lambda / (epix - spix);
9907 vi *= dispersion * pixel_per_lambda;
9909 (rdata + i*nl)[j] = vi;
9913 cpl_polynomial_delete(ids);
9987 double refwave,
double firstLambda,
9988 double lastLambda, cpl_table *idscoeff,
9989 cpl_vector *skylines,
int highres,
int order,
9990 cpl_image *calibration,
int sradius)
9992 const char *func =
"mos_wavelength_align";
9994 const char *clab[6] = {
"c0",
"c1",
"c2",
"c3",
"c4",
"c5"};
9998 double expPos, offset;
10000 double lambda1, lambda2;
10006 int startPos, endPos;
10007 int window = 2*sradius + 1;
10013 int xlow, ylow, xhig, yhig;
10014 int idsorder, uorder;
10023 char offname[MAX_COLNAME];
10024 char name[MAX_COLNAME];
10026 cpl_polynomial *ids;
10027 cpl_polynomial *polycorr;
10030 cpl_table *offsets;
10036 if (idscoeff == NULL) {
10037 cpl_msg_error(func,
"An IDS coeff table must be given");
10038 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
10042 if (image == NULL) {
10043 cpl_msg_error(func,
"A scientific spectral image must be given");
10044 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
10048 if (slits == NULL) {
10049 cpl_msg_error(func,
"A slit position table must be given");
10050 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
10055 line = cpl_vector_get_data(skylines);
10056 nlines = cpl_vector_get_size(skylines);
10059 cpl_msg_warning(func,
"A catalog of sky lines wavelengths was not "
10060 "given: using internal list of reference sky lines");
10062 line = default_lines_hi;
10063 nlines =
sizeof(default_lines_hi) /
sizeof(
double);
10066 line = default_lines_lo;
10067 nlines =
sizeof(default_lines_lo) /
sizeof(
double);
10072 cdata = cpl_image_get_data(calibration);
10074 nx = cpl_image_get_size_x(image);
10075 ny = cpl_image_get_size_y(image);
10077 nslits = cpl_table_get_nrow(slits);
10078 slit_id = cpl_table_get_data_int(slits,
"slit_id");
10079 position = cpl_table_get_data_int(slits,
"position");
10080 length = cpl_table_get_data_int(slits,
"length");
10088 for (i = 0; i < nlines; i++)
10089 if (line[i] > firstLambda && line[i] < lastLambda)
10092 offsets = cpl_table_new(nrows);
10093 cpl_table_new_column(offsets,
"wave", CPL_TYPE_DOUBLE);
10094 cpl_table_set_column_unit(offsets,
"wave",
"Angstrom");
10097 for (i = 0; i < nlines; i++) {
10098 if (line[i] > firstLambda && line[i] < lastLambda) {
10099 cpl_table_set_double(offsets,
"wave", nrows, line[i]);
10108 line = cpl_table_get_data_double(offsets,
"wave");
10112 while (idsorder < 6 && cpl_table_has_column(idscoeff, clab[idsorder]))
10118 for (i = 0; i < nslits; i++) {
10120 if (length[i] == 0)
10123 snprintf(offname, MAX_COLNAME,
"offset%d", slit_id[i]);
10124 cpl_table_new_column(offsets, offname, CPL_TYPE_DOUBLE);
10136 ylow = position[i] + 1;
10137 yhig = ylow + length[i] - 1;
10139 exslit = cpl_image_extract(image, xlow, ylow, xhig, yhig);
10140 sky = cpl_image_collapse_median_create(exslit, 0, 0, 1);
10141 sdata = cpl_image_get_data(sky);
10143 cpl_image_delete(exslit);
10158 dummy = cpl_table_new(yhig - ylow);
10159 for (j = 0; j < nlines; j++) {
10160 snprintf(name, MAX_COLNAME,
"%"CPL_SIZE_FORMAT, j);
10161 cpl_table_new_column(dummy, name, CPL_TYPE_DOUBLE);
10164 for (j = ylow; j < yhig; j++) {
10171 ids = cpl_polynomial_new(1);
10172 for (k = 0; k <= idsorder; k++) {
10173 c = cpl_table_get_double(idscoeff, clab[k], j, &null);
10175 cpl_polynomial_delete(ids);
10179 cpl_polynomial_set_coeff(ids, &k, c);
10184 for (k = 0; k < nlines; k++) {
10185 expPos = cpl_polynomial_eval_1d(ids, line[k] - refwave, NULL);
10186 startPos = expPos - sradius;
10187 endPos = startPos + window;
10188 if (startPos < 0 || endPos >= nx)
10191 if (0 == peakPosition(sdata + startPos, window, &pos, 1)) {
10193 offset = pos - expPos;
10194 snprintf(name, MAX_COLNAME,
"%"CPL_SIZE_FORMAT, k);
10195 cpl_table_set_double(dummy, name, j - ylow, offset);
10199 cpl_polynomial_delete(ids);
10202 cpl_image_delete(sky);
10204 for (j = 0; j < nlines; j++) {
10205 snprintf(name, MAX_COLNAME,
"%"CPL_SIZE_FORMAT, j);
10206 if (cpl_table_has_valid(dummy, name)) {
10207 offset = cpl_table_get_column_median(dummy, name);
10208 cpl_table_set_double(offsets, offname, j, offset);
10212 cpl_table_delete(dummy);
10223 for (i = 0; i < nslits; i++) {
10225 if (length[i] == 0)
10228 snprintf(offname, MAX_COLNAME,
"offset%d", slit_id[i]);
10235 dummy = cpl_table_new(nlines);
10236 cpl_table_duplicate_column(dummy,
"wave", offsets,
"wave");
10237 cpl_table_duplicate_column(dummy,
"offset", offsets, offname);
10239 npoints = nlines - cpl_table_count_invalid(dummy,
"offset");
10240 if (npoints == 0) {
10241 cpl_msg_warning(func,
"No sky lines alignment was possible "
10242 "for slit ID=%d: no sky line found", slit_id[i]);
10243 cpl_table_delete(dummy);
10248 if (npoints <= uorder) {
10249 uorder = npoints - 1;
10251 cpl_msg_warning(func,
"Just %d sky lines detected for slit "
10252 "ID=%d, while a polynomial order %d was "
10253 "requested. Using polynomial order %d for "
10254 "this slit!", npoints, slit_id[i], order,
10258 cpl_msg_warning(func,
"Just %d sky lines detected for slit "
10259 "ID=%d, while a polynomial order %d was "
10260 "requested. Computing a median offset for "
10261 "this slit!", npoints, slit_id[i], order);
10265 cpl_table_erase_invalid(dummy);
10273 wave = cpl_vector_wrap(npoints,
10274 cpl_table_get_data_double(dummy,
"wave"));
10275 offs = cpl_vector_wrap(npoints,
10276 cpl_table_get_data_double(dummy,
"offset"));
10282 cpl_vector_subtract_scalar(wave, refwave);
10284 polycorr = cpl_polynomial_fit_1d_create(wave, offs, uorder, &rms);
10286 rms = sqrt(rms * (uorder + 1) / npoints);
10288 cpl_vector_unwrap(wave);
10289 cpl_vector_unwrap(offs);
10290 cpl_table_delete(dummy);
10297 ylow = position[i];
10298 yhig = ylow + length[i];
10300 for (j = 0; j <= uorder; j++) {
10301 data = cpl_table_get_data_double(idscoeff, clab[j]);
10302 c = cpl_polynomial_get_coeff(polycorr, &j);
10303 for (k = ylow; k < yhig; k++)
10307 data = cpl_table_get_data_double(idscoeff,
"error");
10308 for (k = ylow; k < yhig; k++)
10309 data[k] = sqrt(data[k]*data[k] + rms*rms);
10311 idata = cpl_table_get_data_int(idscoeff,
"nlines");
10312 for (k = ylow; k < yhig; k++)
10313 idata[k] = npoints;
10321 for (j = ylow; j < yhig; j++) {
10322 for (k = 1; k < nx; k++) {
10323 lambda1 = cdata[k - 1 + j*nx];
10324 lambda2 = cdata[k + j*nx];
10325 if (lambda1 < 1.0 || lambda2 < 1.0)
10327 offset = cpl_polynomial_eval_1d(polycorr,
10328 lambda1-refwave, NULL);
10329 cdata[k - 1 + j*nx] -= offset * (lambda2-lambda1);
10334 cpl_polynomial_delete(polycorr);
10336 else if (uorder == 1) {
10343 cpl_bivector *list;
10346 wave = cpl_vector_wrap(npoints,
10347 cpl_table_get_data_double(dummy,
"wave"));
10348 offs = cpl_vector_wrap(npoints,
10349 cpl_table_get_data_double(dummy,
"offset"));
10351 list = cpl_bivector_wrap_vectors(wave, offs);
10357 cpl_vector_subtract_scalar(wave, refwave);
10359 robustLinearFit(list, &q, &m, &rms);
10361 rms = sqrt(rms * (uorder + 1) / npoints);
10363 cpl_bivector_unwrap_vectors(list);
10364 cpl_vector_unwrap(wave);
10365 cpl_vector_unwrap(offs);
10366 cpl_table_delete(dummy);
10373 ylow = position[i];
10374 yhig = ylow + length[i];
10376 for (j = 0; j <= uorder; j++) {
10377 data = cpl_table_get_data_double(idscoeff, clab[j]);
10382 for (k = ylow; k < yhig; k++)
10386 data = cpl_table_get_data_double(idscoeff,
"error");
10387 for (k = ylow; k < yhig; k++)
10388 data[k] = sqrt(data[k]*data[k] + rms*rms);
10390 idata = cpl_table_get_data_int(idscoeff,
"nlines");
10391 for (k = ylow; k < yhig; k++)
10392 idata[k] = npoints;
10400 for (j = ylow; j < yhig; j++) {
10401 for (k = 1; k < nx; k++) {
10402 lambda1 = cdata[k - 1 + j*nx];
10403 lambda2 = cdata[k + j*nx];
10404 if (lambda1 < 1.0 || lambda2 < 1.0)
10406 offset = q + m*(lambda1-refwave);
10407 cdata[k - 1 + j*nx] -= offset * (lambda2-lambda1);
10418 offs = cpl_vector_wrap(npoints,
10419 cpl_table_get_data_double(dummy,
"offset"));
10421 offset = cpl_vector_get_median_const(offs);
10424 rms = cpl_table_get_column_stdev(dummy,
"offset");
10428 rms /= sqrt(npoints);
10430 cpl_vector_unwrap(offs);
10431 cpl_table_delete(dummy);
10438 ylow = position[i];
10439 yhig = ylow + length[i];
10441 data = cpl_table_get_data_double(idscoeff, clab[0]);
10442 for (k = ylow; k < yhig; k++)
10445 data = cpl_table_get_data_double(idscoeff,
"error");
10446 for (k = ylow; k < yhig; k++)
10447 data[k] = sqrt(data[k]*data[k] + rms*rms);
10449 idata = cpl_table_get_data_int(idscoeff,
"nlines");
10450 for (k = ylow; k < yhig; k++)
10451 idata[k] = npoints;
10460 for (j = ylow; j < yhig; j++) {
10461 for (k = 1; k < nx; k++) {
10462 lambda1 = cdata[k - 1 + j*nx];
10463 lambda2 = cdata[k + j*nx];
10464 if (lambda1 < 1.0 || lambda2 < 1.0)
10466 cdata[k - 1 + j*nx] -= offset * (lambda2-lambda1);
10540 double firstLambda,
double lastLambda,
10541 cpl_table *idscoeff, cpl_vector *skylines,
10542 int highres,
int order,
10543 cpl_image *calibration,
int sradius)
10545 const char *func =
"mos_wavelength_align_lss";
10547 const char *clab[6] = {
"c0",
"c1",
"c2",
"c3",
"c4",
"c5"};
10553 double expPos, offset;
10555 double lambda1, lambda2;
10561 int startPos, endPos;
10562 int window = 2*sradius + 1;
10567 int idsorder, uorder;
10572 char name[MAX_COLNAME];
10573 char fname[MAX_COLNAME];
10575 cpl_polynomial *ids;
10576 cpl_polynomial *polycorr;
10577 cpl_table *offsets;
10578 cpl_table *fittable;
10585 if (idscoeff == NULL) {
10586 cpl_msg_error(func,
"An IDS coeff table must be given");
10587 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
10591 if (image == NULL) {
10592 cpl_msg_error(func,
"A scientific spectral image must be given");
10593 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
10598 line = cpl_vector_get_data(skylines);
10599 nlines = cpl_vector_get_size(skylines);
10602 cpl_msg_warning(func,
"A catalog of sky lines wavelengths was not "
10603 "given: using internal list of reference sky lines");
10605 line = default_lines_hi;
10606 nlines =
sizeof(default_lines_hi) /
sizeof(
double);
10609 line = default_lines_lo;
10610 nlines =
sizeof(default_lines_lo) /
sizeof(
double);
10615 cdata = cpl_image_get_data(calibration);
10617 nx = cpl_image_get_size_x(image);
10618 ny = cpl_image_get_size_y(image);
10620 sdata = cpl_image_get_data(image);
10622 if (ny != cpl_table_get_nrow(idscoeff)) {
10623 cpl_error_set(func, CPL_ERROR_INCOMPATIBLE_INPUT);
10637 for (i = 0; i < nlines; i++)
10638 if (line[i] > firstLambda && line[i] < lastLambda)
10641 offsets = cpl_table_new(nrows);
10642 cpl_table_new_column(offsets,
"wave", CPL_TYPE_DOUBLE);
10643 cpl_table_set_column_unit(offsets,
"wave",
"Angstrom");
10646 for (i = 0; i < nlines; i++) {
10647 if (line[i] > firstLambda && line[i] < lastLambda) {
10648 cpl_table_set_double(offsets,
"wave", nrows, line[i]);
10657 line = cpl_table_get_data_double(offsets,
"wave");
10661 while (idsorder < 6 && cpl_table_has_column(idscoeff, clab[idsorder]))
10671 dummy = cpl_table_new(ny);
10672 for (j = 0; j < nlines; j++) {
10673 snprintf(name, MAX_COLNAME,
"off_%d", (
int)line[j]);
10674 snprintf(fname, MAX_COLNAME,
"fit_%d", (
int)line[j]);
10675 cpl_table_new_column(dummy, name, CPL_TYPE_DOUBLE);
10676 cpl_table_new_column(dummy, fname, CPL_TYPE_DOUBLE);
10679 for (j = 0; j < ny; j++, sdata += nx) {
10686 ids = cpl_polynomial_new(1);
10687 for (k = 0; k <= idsorder; k++) {
10688 c = cpl_table_get_double(idscoeff, clab[k], j, &missing);
10690 cpl_polynomial_delete(ids);
10693 cpl_polynomial_set_coeff(ids, &k, c);
10698 for (k = 0; k < nlines; k++) {
10699 expPos = cpl_polynomial_eval_1d(ids, line[k] - refwave, NULL);
10700 startPos = expPos - sradius;
10701 endPos = startPos + window;
10702 if (startPos < 0 || endPos >= nx)
10705 if (0 == peakPosition(sdata + startPos, window, &pos, 1)) {
10707 offset = pos - expPos;
10708 snprintf(name, MAX_COLNAME,
"off_%d", (
int)line[k]);
10709 cpl_table_set_double(dummy, name, j, offset);
10713 cpl_polynomial_delete(ids);
10722 for (j = 0; j < nlines; j++) {
10723 snprintf(name, MAX_COLNAME,
"off_%d", (
int)line[j]);
10724 snprintf(fname, MAX_COLNAME,
"fit_%d", (
int)line[j]);
10725 if (cpl_table_has_valid(dummy, name)) {
10733 cpl_bivector *list;
10735 fittable = cpl_table_new(ny);
10736 cpl_table_new_column(fittable,
"row", CPL_TYPE_DOUBLE);
10737 cpl_table_set_column_unit(fittable,
"row",
"pixel");
10738 for (k = 0; k < ny; k++)
10739 cpl_table_set_double(fittable,
"row", k, k);
10740 cpl_table_duplicate_column(fittable,
"offset", dummy, name);
10741 npoints = ny - cpl_table_count_invalid(fittable,
"offset");
10742 cpl_table_erase_invalid(fittable);
10743 row = cpl_vector_wrap(npoints,
10744 cpl_table_get_data_double(fittable,
"row"));
10745 offs = cpl_vector_wrap(npoints,
10746 cpl_table_get_data_double(fittable,
"offset"));
10747 list = cpl_bivector_wrap_vectors(row, offs);
10748 robustLinearFit(list, &q, &m, &rms);
10749 cpl_bivector_unwrap_vectors(list);
10750 cpl_vector_unwrap(row);
10751 cpl_vector_unwrap(offs);
10752 cpl_table_delete(fittable);
10753 for (k = 0; k < ny; k++)
10754 cpl_table_set_double(dummy, fname, k, q + m*k);
10767 for (i = 0; i < ny; i++) {
10769 if (!cpl_table_is_valid(idscoeff, clab[0], i))
10773 for (j = 0; j < nlines; j++) {
10774 snprintf(name, MAX_COLNAME,
"fit_%d", (
int)line[j]);
10775 if (cpl_table_is_valid(dummy, name, i))
10783 if (npoints <= uorder)
10784 uorder = npoints - 1;
10792 wave = cpl_vector_new(npoints);
10793 wdata = cpl_vector_get_data(wave);
10794 offs = cpl_vector_new(npoints);
10795 odata = cpl_vector_get_data(offs);
10798 for (j = 0; j < nlines; j++) {
10799 snprintf(name, MAX_COLNAME,
"fit_%d", (
int)line[j]);
10800 if (cpl_table_is_valid(dummy, name, i)) {
10801 wdata[npoints] = line[j] - refwave;
10802 odata[npoints] = cpl_table_get_double(dummy, name, i, NULL);
10807 polycorr = cpl_polynomial_fit_1d_create(wave, offs, uorder, &rms);
10809 rms = sqrt(rms * (uorder + 1) / npoints);
10811 cpl_vector_delete(wave);
10812 cpl_vector_delete(offs);
10819 for (j = 0; j <= uorder; j++) {
10820 data = cpl_table_get_data_double(idscoeff, clab[j]);
10821 c = cpl_polynomial_get_coeff(polycorr, &j);
10825 data = cpl_table_get_data_double(idscoeff,
"error");
10826 data[i] = sqrt(data[i]*data[i] + rms*rms);
10828 idata = cpl_table_get_data_int(idscoeff,
"nlines");
10829 idata[i] = npoints;
10837 for (k = 1; k < nx; k++) {
10838 lambda1 = cdata[k - 1 + i*nx];
10839 lambda2 = cdata[k + i*nx];
10840 if (lambda1 < 1.0 || lambda2 < 1.0)
10842 offset = cpl_polynomial_eval_1d(polycorr,
10843 lambda1-refwave, NULL);
10844 cdata[k - 1 + i*nx] -= offset * (lambda2-lambda1);
10848 cpl_polynomial_delete(polycorr);
10851 else if (uorder == 1) {
10857 cpl_bivector *list;
10860 wave = cpl_vector_new(npoints);
10861 wdata = cpl_vector_get_data(wave);
10862 offs = cpl_vector_new(npoints);
10863 odata = cpl_vector_get_data(offs);
10866 for (j = 0; j < nlines; j++) {
10867 snprintf(name, MAX_COLNAME,
"fit_%d", (
int)line[j]);
10868 if (cpl_table_is_valid(dummy, name, i)) {
10869 wdata[npoints] = line[j] - refwave;
10870 odata[npoints] = cpl_table_get_double(dummy, name, i, NULL);
10875 list = cpl_bivector_wrap_vectors(wave, offs);
10876 robustLinearFit(list, &q, &m, &rms);
10878 rms = sqrt(rms * (uorder + 1) / npoints);
10880 cpl_bivector_unwrap_vectors(list);
10881 cpl_vector_delete(wave);
10882 cpl_vector_delete(offs);
10889 for (j = 0; j <= uorder; j++) {
10890 data = cpl_table_get_data_double(idscoeff, clab[j]);
10898 data = cpl_table_get_data_double(idscoeff,
"error");
10899 data[i] = sqrt(data[i]*data[i] + rms*rms);
10901 idata = cpl_table_get_data_int(idscoeff,
"nlines");
10902 idata[i] = npoints;
10910 for (k = 1; k < nx; k++) {
10911 lambda1 = cdata[k - 1 + i*nx];
10912 lambda2 = cdata[k + i*nx];
10913 if (lambda1 < 1.0 || lambda2 < 1.0)
10915 offset = q + m*(lambda1-refwave);
10916 cdata[k - 1 + i*nx] -= offset * (lambda2-lambda1);
10926 offs = cpl_vector_new(npoints);
10927 odata = cpl_vector_get_data(offs);
10930 for (j = 0; j < nlines; j++) {
10931 snprintf(name, MAX_COLNAME,
"fit_%d", (
int)line[j]);
10932 if (cpl_table_is_valid(dummy, name, i)) {
10933 odata[npoints] = cpl_table_get_double(dummy, name, i, NULL);
10938 offset = cpl_vector_get_median_const(offs);
10941 rms = cpl_vector_get_stdev(offs);
10943 else if (npoints == 1) {
10944 snprintf(name, MAX_COLNAME,
"off_%d", (
int)line[0]);
10945 if (cpl_table_has_valid(dummy, name)) {
10946 rms = cpl_table_get_column_stdev(dummy, name);
10947 rms /= sqrt(ny - cpl_table_count_invalid(dummy, name));
10957 rms /= sqrt(npoints);
10959 cpl_vector_delete(offs);
10966 data = cpl_table_get_data_double(idscoeff, clab[0]);
10969 data = cpl_table_get_data_double(idscoeff,
"error");
10970 data[i] = sqrt(data[i]*data[i] + rms*rms);
10972 idata = cpl_table_get_data_int(idscoeff,
"nlines");
10973 idata[i] = npoints;
10982 for (k = 1; k < nx; k++) {
10983 lambda1 = cdata[k - 1 + i*nx];
10984 lambda2 = cdata[k + i*nx];
10985 if (lambda1 < 1.0 || lambda2 < 1.0)
10987 cdata[k - 1 + i*nx] -= offset * (lambda2-lambda1);
10994 for (j = 0; j < nlines; j++) {
10995 snprintf(name, MAX_COLNAME,
"off_%d", (
int)line[j]);
10996 if (cpl_table_has_valid(dummy, name)) {
10998 offset = cpl_table_get_column_median(dummy, name);
10999 cpl_msg_info(func,
"Median offset for %.3f: %.3f pixel",
11004 "Median offset for %.2f: not available", line[j]);
11008 cpl_table_delete(offsets);
11011 cpl_table_delete(dummy);
11048 double wavestart,
double dispersion,
int radius,
11052 const char *func =
"mos_distortions_rms";
11057 int cpix, npix, nzero;
11060 int npeaks, allPeaks;
11063 float peak, expectPeak, offset;
11067 double rms, oneRms;
11073 xlen = cpl_image_get_size_x(rectified);
11074 ylen = cpl_image_get_size_y(rectified);
11075 sdata = cpl_image_get_data(rectified);
11078 wdata = cpl_vector_get_data(lines);
11079 numLines = cpl_vector_get_size(lines);
11082 cpl_msg_warning(func,
"A catalog of sky lines wavelengths was not "
11083 "given: using internal list of reference sky lines");
11085 wdata = default_lines_hi;
11086 numLines =
sizeof(default_lines_hi) /
sizeof(
double);
11089 wdata = default_lines_lo;
11090 numLines =
sizeof(default_lines_lo) /
sizeof(
double);
11094 npix = 2 * radius + 1;
11095 profile = cpl_calloc(npix,
sizeof(
float));
11100 for (i = 0; i < numLines; i++) {
11107 expectPeak = (lambda - wavestart) / dispersion;
11108 cpix = floor(expectPeak + 0.5);
11114 sp = cpix - radius;
11115 ep = cpix + radius;
11117 if (sp < 0 || ep > xlen)
11124 for (j = 0; j < ylen; j++) {
11126 for (k = 0; k < npix; k++) {
11127 profile[k] = sdata[sp + k + j * xlen];
11128 if (fabs(profile[k]) < 0.0001)
11134 if (peakPosition(profile, npix, &peak, 1) == 0) {
11135 offset = (sp + peak) - expectPeak;
11137 rms += fabs(offset);
11138 oneRms += fabs(offset);
11145 cpl_msg_info(func,
"RMS for %.2f: %.3f pixel (%d points)",
11146 lambda, oneRms / npeaks * 1.25, npeaks);
11148 cpl_msg_info(func,
"RMS for %.2f: line not available", lambda);
11185 double blue,
double red,
double dispersion,
int trend)
11187 const char *func =
"mos_map_pixel";
11189 const char *clab[6] = {
"c0",
"c1",
"c2",
"c3",
"c4",
"c5"};
11192 cpl_polynomial *ids;
11204 if (idscoeff == NULL) {
11205 cpl_msg_error(func,
"An IDS coeff table must be given");
11206 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
11210 xsize = (red - blue) / dispersion;
11211 ysize = cpl_table_get_nrow(idscoeff);
11212 map = cpl_image_new(xsize, ysize, CPL_TYPE_FLOAT);
11213 mdata = cpl_image_get_data(map);
11216 while (order < 6 && cpl_table_has_column(idscoeff, clab[order]))
11220 for (i = 0; i < ysize; i++, mdata += xsize) {
11223 ids = cpl_polynomial_new(1);
11224 for (k = trend; k <= order; k++) {
11225 c = cpl_table_get_double(idscoeff, clab[k], i, &missing);
11227 cpl_polynomial_delete(ids);
11230 cpl_polynomial_set_coeff(ids, &k, c);
11235 for (j = 0; j < xsize; j++) {
11236 lambda = blue + j*dispersion;
11237 mdata[j] = cpl_polynomial_eval_1d(ids, lambda-reference, NULL);
11240 cpl_polynomial_delete(ids);
11270 double blue,
double red)
11272 const char *func =
"mos_map_idscoeff";
11274 const char *clab[6] = {
"c0",
"c1",
"c2",
"c3",
"c4",
"c5"};
11277 cpl_polynomial *ids;
11289 if (idscoeff == NULL) {
11290 cpl_msg_error(func,
"An IDS coeff table must be given");
11291 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
11296 cpl_msg_error(func,
"Invalid image size");
11297 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
11301 if (xsize < 20 || xsize > 5000) {
11302 cpl_msg_warning(func,
"Do you really have a detector %d pixels long?",
11306 ysize = cpl_table_get_nrow(idscoeff);
11307 map = cpl_image_new(xsize, ysize, CPL_TYPE_FLOAT);
11308 mdata = cpl_image_get_data(map);
11311 while (order < 6 && cpl_table_has_column(idscoeff, clab[order]))
11315 for (i = 0; i < ysize; i++, mdata += xsize) {
11318 ids = cpl_polynomial_new(1);
11319 for (k = 0; k <= order; k++) {
11320 c = cpl_table_get_double(idscoeff, clab[k], i, &missing);
11322 cpl_polynomial_delete(ids);
11325 cpl_polynomial_set_coeff(ids, &k, c);
11330 for (j = 0; j < xsize; j++) {
11333 if (lambda >= blue && lambda <= red) {
11338 cpl_polynomial_delete(ids);
11381 cpl_table *slits, cpl_table *polytraces,
11382 double reference,
double blue,
double red,
11385 const char *func =
"mos_map_wavelengths";
11387 const char *clab[6] = {
"c0",
"c1",
"c2",
"c3",
"c4",
"c5"};
11389 cpl_polynomial *polytop;
11390 cpl_polynomial *polybot;
11391 cpl_image *remapped;
11396 double vtop, vbot, value;
11403 int yint, ysize, yprev;
11410 int pixel_above, pixel_below, refpixel, start_pixel, end_pixel;
11411 int missing_top, missing_bot;
11418 if (spatial == NULL || calibration == NULL ||
11419 slits == NULL || polytraces == NULL) {
11420 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
11424 if (dispersion <= 0.0) {
11425 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
11429 if (red - blue < dispersion) {
11430 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
11434 nx = cpl_image_get_size_x(spatial);
11435 ny = cpl_image_get_size_y(spatial);
11436 ysize = cpl_image_get_size_y(calibration);
11437 remapped = cpl_image_new(nx, ny, CPL_TYPE_FLOAT);
11438 data = cpl_image_get_data(remapped);
11439 sdata = cpl_image_get_data(spatial);
11440 wdata = cpl_image_get_data(calibration);
11442 nslits = cpl_table_get_nrow(slits);
11443 slit_id = cpl_table_get_data_int(slits,
"slit_id");
11444 order = cpl_table_get_ncol(polytraces) - 2;
11445 position = cpl_table_get_data_int(slits,
"position");
11446 length = cpl_table_get_data_int(slits,
"length");
11453 pixel_above = STRETCH_FACTOR * (red - reference) / dispersion;
11454 pixel_below = STRETCH_FACTOR * (reference - blue) / dispersion;
11456 for (i = 0; i < nslits; i++) {
11458 if (length[i] == 0)
11472 refpixel = cpl_table_get_double(slits,
"xtop", i, NULL);
11474 start_pixel = refpixel - pixel_below;
11475 if (start_pixel < 0)
11478 end_pixel = refpixel + pixel_above;
11479 if (end_pixel > nx)
11488 polytop = cpl_polynomial_new(1);
11489 for (k = 0; k <= order; k++) {
11490 coeff = cpl_table_get_double(polytraces, clab[k], 2*i, &null);
11492 cpl_polynomial_delete(polytop);
11496 cpl_polynomial_set_coeff(polytop, &k, coeff);
11500 polybot = cpl_polynomial_new(1);
11501 for (k = 0; k <= order; k++) {
11502 coeff = cpl_table_get_double(polytraces, clab[k], 2*i+1, &null);
11504 cpl_polynomial_delete(polybot);
11508 cpl_polynomial_set_coeff(polybot, &k, coeff);
11511 if (missing_top && missing_bot) {
11512 cpl_msg_debug(func,
"Slit %d was not traced: no extraction!",
11524 cpl_msg_debug(func,
"Upper edge of slit %d was not traced: "
11525 "the spectral curvature of the lower edge "
11526 "is used instead.", slit_id[i]);
11527 polytop = cpl_polynomial_duplicate(polybot);
11528 ytop = cpl_table_get_double(slits,
"ytop", i, NULL);
11529 ybot = cpl_table_get_double(slits,
"ybottom", i, NULL);
11531 coeff = cpl_polynomial_get_coeff(polybot, &k);
11532 coeff += ytop - ybot;
11533 cpl_polynomial_set_coeff(polytop, &k, coeff);
11537 cpl_msg_debug(func,
"Lower edge of slit %d was not traced: "
11538 "the spectral curvature of the upper edge "
11539 "is used instead.", slit_id[i]);
11540 polybot = cpl_polynomial_duplicate(polytop);
11541 ytop = cpl_table_get_double(slits,
"ytop", i, NULL);
11542 ybot = cpl_table_get_double(slits,
"ybottom", i, NULL);
11544 coeff = cpl_polynomial_get_coeff(polytop, &k);
11545 coeff -= ytop - ybot;
11546 cpl_polynomial_set_coeff(polybot, &k, coeff);
11556 xdata = wdata + nx*position[i];
11557 npseudo = length[i] - 1;
11563 for (j = start_pixel; j < end_pixel; j++) {
11564 top = cpl_polynomial_eval_1d(polytop, j, NULL);
11565 bot = cpl_polynomial_eval_1d(polybot, j, NULL);
11566 for (k = 0; k <= npseudo; k++) {
11567 ypos = top - k*(top-bot)/npseudo;
11577 if (yint < 0 || yint >= ny-1) {
11582 value = sdata[j + nx*yint];
11584 fvalue = value - ivalue;
11585 if (ivalue < npseudo && ivalue >= 0) {
11586 vtop = xdata[j + nx*(npseudo-ivalue)];
11587 vbot = xdata[j + nx*(npseudo-ivalue-1)];
11596 else if (vbot < 1.0) {
11602 else if (fabs(vbot-vtop) > 10*dispersion) {
11606 value = vtop*(1-fvalue) + vbot*fvalue;
11608 data[j + nx*yint] = value;
11618 if (yprev - yint > 1) {
11619 value = sdata[j + nx*(yint+1)];
11621 fvalue = value - ivalue;
11622 if (ivalue < npseudo && ivalue >= 0) {
11623 vtop = xdata[j + nx*(npseudo-ivalue)];
11624 vbot = xdata[j + nx*(npseudo-ivalue-1)];
11627 value = data[j + nx*(yint+1)];
11633 else if (vbot < 1.0) {
11636 else if (fabs(vbot-vtop) > 2*dispersion) {
11640 value = vtop*(1-fvalue) + vbot*fvalue;
11642 data[j + nx*(yint+1)] = value;
11650 cpl_polynomial_delete(polytop);
11651 cpl_polynomial_delete(polybot);
11731 cpl_image *spatial, cpl_table *slits,
11732 cpl_table *polytraces,
double reference,
11733 double blue,
double red,
double dispersion,
11736 const char *func =
"mos_map_spectrum";
11738 const char *clab[6] = {
"c0",
"c1",
"c2",
"c3",
"c4",
"c5"};
11740 cpl_polynomial *polytop;
11741 cpl_polynomial *polybot;
11742 cpl_image *remapped;
11743 cpl_image **exslit;
11748 double lambda00, lambda01, lambda10, lambda11, lambda;
11749 double space00, space01, space10, space11, space;
11750 double value00, value01, value10, value11, value0, value1, value;
11755 double xfrac, yfrac;
11768 int pixel_above, pixel_below, refpixel, start_pixel, end_pixel;
11769 int missing_top, missing_bot;
11778 if (spectra == NULL || spatial == NULL || wavecalib == NULL ||
11779 slits == NULL || polytraces == NULL) {
11780 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
11784 if (dispersion <= 0.0) {
11785 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
11789 if (red - blue < dispersion) {
11790 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
11794 nx = cpl_image_get_size_x(spectra);
11795 ny = cpl_image_get_size_y(spectra);
11797 if (nx != cpl_image_get_size_x(spatial) ||
11798 ny != cpl_image_get_size_y(spatial) ||
11799 nx != cpl_image_get_size_x(wavecalib) ||
11800 ny != cpl_image_get_size_y(wavecalib)) {
11801 cpl_error_set(func, CPL_ERROR_INCOMPATIBLE_INPUT);
11805 nlambda = STRETCH_FACTOR * (red - blue) / dispersion;
11806 pixel_above = STRETCH_FACTOR * (red - reference) / dispersion;
11807 pixel_below = STRETCH_FACTOR * (reference - blue) / dispersion;
11809 data = cpl_image_get_data(spectra);
11810 sdata = cpl_image_get_data(spatial);
11811 wdata = cpl_image_get_data(wavecalib);
11813 nslits = cpl_table_get_nrow(slits);
11814 slit_id = cpl_table_get_data_int(slits,
"slit_id");
11815 order = cpl_table_get_ncol(polytraces) - 2;
11816 position = cpl_table_get_data_int(slits,
"position");
11817 length = cpl_table_get_data_int(slits,
"length");
11819 exslit = cpl_calloc(nslits,
sizeof(cpl_image *));
11821 for (i = 0; i < nslits; i++) {
11837 refpixel = cpl_table_get_double(slits,
"xtop", i, NULL);
11839 start_pixel = refpixel - pixel_below;
11840 if (start_pixel < 1)
11843 end_pixel = refpixel + pixel_above;
11844 if (end_pixel > nx)
11853 polytop = cpl_polynomial_new(1);
11854 for (k = 0; k <= order; k++) {
11855 coeff = cpl_table_get_double(polytraces, clab[k], 2*i, &null);
11857 cpl_polynomial_delete(polytop);
11861 cpl_polynomial_set_coeff(polytop, &k, coeff);
11865 polybot = cpl_polynomial_new(1);
11866 for (k = 0; k <= order; k++) {
11867 coeff = cpl_table_get_double(polytraces, clab[k], 2*i+1, &null);
11869 cpl_polynomial_delete(polybot);
11873 cpl_polynomial_set_coeff(polybot, &k, coeff);
11876 if (missing_top && missing_bot) {
11877 cpl_msg_debug(func,
"Slit %d was not traced: no extraction!",
11889 cpl_msg_debug(func,
"Upper edge of slit %d was not traced: "
11890 "the spectral curvature of the lower edge "
11891 "is used instead.", slit_id[i]);
11892 polytop = cpl_polynomial_duplicate(polybot);
11893 ytop = cpl_table_get_double(slits,
"ytop", i, NULL);
11894 ybot = cpl_table_get_double(slits,
"ybottom", i, NULL);
11896 coeff = cpl_polynomial_get_coeff(polybot, &k);
11897 coeff += ytop - ybot;
11898 cpl_polynomial_set_coeff(polytop, &k, coeff);
11902 cpl_msg_debug(func,
"Lower edge of slit %d was not traced: "
11903 "the spectral curvature of the upper edge "
11904 "is used instead.", slit_id[i]);
11905 polybot = cpl_polynomial_duplicate(polytop);
11906 ytop = cpl_table_get_double(slits,
"ytop", i, NULL);
11907 ybot = cpl_table_get_double(slits,
"ybottom", i, NULL);
11909 coeff = cpl_polynomial_get_coeff(polytop, &k);
11910 coeff -= ytop - ybot;
11911 cpl_polynomial_set_coeff(polybot, &k, coeff);
11918 top = cpl_polynomial_eval_1d(polytop, refpixel, NULL);
11919 bot = cpl_polynomial_eval_1d(polybot, refpixel, NULL);
11920 npseudo = ceil(top-bot) + 1;
11923 cpl_polynomial_delete(polytop);
11924 cpl_polynomial_delete(polybot);
11925 cpl_msg_debug(func,
"Slit %d was badly traced: no extraction!",
11930 exslit[i] = cpl_image_new(nlambda, npseudo+1, CPL_TYPE_FLOAT);
11931 xdata = cpl_image_get_data(exslit[i]);
11937 for (x = start_pixel; x < end_pixel; x++) {
11938 top = cpl_polynomial_eval_1d(polytop, x, NULL);
11939 bot = cpl_polynomial_eval_1d(polybot, x, NULL);
11950 for (y = ibot; y < itop; y++) {
11951 lambda11 = wdata[x + y*nx];
11952 if (lambda11 < 1.0)
11954 space11 = sdata[x + y*nx];
11957 lambda01 = wdata[x - 1 + y*nx];
11958 if (lambda01 < 1.0)
11960 space01 = sdata[x - 1 + y*nx];
11993 lambda10 = wdata[x + shift + (y+1)*nx];
11994 if (lambda10 < 1.0)
11996 space10 = sdata[x + shift + (y+1)*nx];
11999 lambda00 = wdata[x - 1 + shift + (y+1)*nx];
12000 if (lambda00 < 1.0)
12002 space00 = sdata[x - 1 + shift + (y+1)*nx];
12012 dL = lambda11 - lambda01;
12013 dS = space11 - space10;
12020 L = (lambda11 - blue)/dispersion + 0.5;
12023 if (L < 0 || L >= nlambda)
12025 if (S < 0 || S > npseudo)
12032 lambda = blue + L*dispersion;
12044 xfrac = (lambda11-lambda)/dL;
12045 yfrac = (space11-space)/dS;
12056 value11 = data[x + y*nx];
12057 value01 = data[x - 1 + y*nx];
12058 value10 = data[x + shift + (y+1)*nx];
12059 value00 = data[x + shift - 1 + (y+1)*nx];
12065 value1 = (1-xfrac)*value11 + xfrac*value01;
12066 value0 = (1-xfrac)*value10 + xfrac*value00;
12067 value = (1-yfrac)*value1 + yfrac*value0;
12074 xdata[L + nlambda*(npseudo-S)] = value;
12078 cpl_polynomial_delete(polytop);
12079 cpl_polynomial_delete(polybot);
12087 for (i = 0; i < nslits; i++)
12089 ysize += cpl_image_get_size_y(exslit[i]);
12091 remapped = cpl_image_new(nlambda, ysize, CPL_TYPE_FLOAT);
12094 for (i = 0; i < nslits; i++) {
12096 yint += cpl_image_get_size_y(exslit[i]);
12097 cpl_image_copy(remapped, exslit[i], 1, ysize - yint);
12098 cpl_image_delete(exslit[i]);
12099 cpl_table_set_int(slits,
"position", i, ysize - yint - 1);
12143 double dispersion,
double factor,
int minpoints,
12146 const char *func =
"mos_sky_map_super";
12148 cpl_vector **vector;
12149 cpl_vector **wvector;
12150 double firstLambda, lastLambda;
12151 double lambda, lambda1, lambda2;
12152 double value, value1, value2;
12158 int first_valid, valid_bins;
12162 double *sky_spectrum;
12169 if (spectra == NULL || wavemap == NULL || skymap == NULL) {
12170 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
12174 if (dispersion <= 0.0) {
12175 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
12176 cpl_msg_error(func,
"Negative dispersion: %s", cpl_error_get_message());
12180 nx = cpl_image_get_size_x(spectra);
12181 ny = cpl_image_get_size_y(spectra);
12184 if (nx != cpl_image_get_size_x(wavemap) ||
12185 ny != cpl_image_get_size_y(wavemap) ||
12186 nx != cpl_image_get_size_x(skymap) ||
12187 ny != cpl_image_get_size_y(skymap)) {
12188 cpl_error_set(func, CPL_ERROR_INCOMPATIBLE_INPUT);
12189 cpl_msg_error(func,
"Image sizes: %s", cpl_error_get_message());
12193 if (factor < 1.0) {
12194 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
12195 cpl_msg_error(func,
"Undersampling (%f): %s", factor,
12196 cpl_error_get_message());
12200 if (minpoints < 0) {
12201 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
12202 cpl_msg_error(func,
"Negative threshold: %s", cpl_error_get_message());
12206 dispersion /= factor;
12213 data = cpl_image_get_data(wavemap);
12215 for (i = 0; i < npix; i++) {
12216 if (data[i] > 1.0) {
12217 min = max = data[i];
12223 for (i = j; i < npix; i++) {
12240 nbin = (lastLambda - firstLambda) / dispersion;
12249 count = cpl_calloc(nbin,
sizeof(
int));
12251 data = cpl_image_get_data(wavemap);
12253 for (i = 0; i < npix; i++) {
12256 bin = (data[i] - firstLambda) / dispersion;
12262 for (i = 0; i < nbin; i++)
12263 if (count[i] >= minpoints)
12266 if (valid_bins < nbin/3) {
12267 cpl_msg_warning(func,
"Cannot determine a good global sky "
12268 "spectrum from input data");
12280 vector = cpl_calloc(nbin,
sizeof(cpl_vector *));
12281 wvector = cpl_calloc(nbin,
sizeof(cpl_vector *));
12282 for (i = 0; i < nbin; i++) {
12283 if (count[i] >= minpoints) {
12284 vector[i] = cpl_vector_new(count[i]);
12285 wvector[i] = cpl_vector_new(count[i]);
12296 data = cpl_image_get_data(wavemap);
12297 sdata = cpl_image_get_data(spectra);
12299 for (i = 0; i < npix; i++) {
12302 bin = (data[i] - firstLambda) / dispersion;
12305 cpl_vector_set(vector[bin], count[bin], sdata[i]);
12306 cpl_vector_set(wvector[bin], count[bin], data[i]);
12318 sky_spectrum = cpl_calloc(nbin,
sizeof(
double));
12319 sky_wave = cpl_calloc(nbin,
sizeof(
double));
12320 for (i = 0; i < nbin; i++) {
12322 sky_spectrum[i] = cpl_vector_get_median_const(vector[i]);
12323 sky_wave[i] = cpl_vector_get_median_const(wvector[i]);
12324 cpl_vector_delete(vector[i]);
12325 cpl_vector_delete(wvector[i]);
12337 for (i = 0; i < nbin; i++) {
12338 if (count[i] >= minpoints) {
12344 for (i = first_valid; i < nbin; i++) {
12345 if (count[i] < minpoints) {
12346 sky_wave[i] = firstLambda + (i+0.5)*dispersion;
12347 for (j = i+1; j < nbin; j++) {
12348 if (count[j] >= minpoints) {
12349 if (sky_wave[j] - sky_wave[i-1] < 0.1) {
12350 sky_spectrum[i] = (sky_spectrum[j] + sky_spectrum[i-1])
12354 frac = (sky_wave[i] - sky_wave[i-1])
12355 / (sky_wave[j] - sky_wave[i-1]);
12356 sky_spectrum[i] = frac * sky_spectrum[j]
12357 + (1 - frac) * sky_spectrum[i-1];
12369 sky = cpl_table_new(nbin);
12370 cpl_table_wrap_double(sky, sky_wave,
"wavelength");
12371 cpl_table_wrap_double(sky, sky_spectrum,
"sky");
12372 cpl_table_wrap_int(sky, count,
"npoints");
12379 data = cpl_image_get_data(wavemap);
12380 sdata = cpl_image_get_data(spectra);
12381 kdata = cpl_image_get_data(skymap);
12383 for (i = 0; i < npix; i++) {
12392 bin = (lambda - firstLambda) / dispersion;
12393 lambda1 = sky_wave[bin];
12394 value1 = sky_spectrum[bin];
12395 if (lambda1 < lambda) {
12398 lambda2 = sky_wave[bin];
12399 value2 = sky_spectrum[bin];
12400 if (lambda2 - lambda1 < 0.1) {
12401 value = (value1 + value2) / 2;
12404 frac = (lambda - lambda1) / (lambda2 - lambda1);
12405 value = frac * value2 + (1 - frac) * value1;
12417 lambda1 = sky_wave[bin];
12418 value1 = sky_spectrum[bin];
12419 if (lambda2 - lambda1 < 0.1) {
12420 value = (value1 + value2) / 2;
12423 frac = (lambda - lambda1) / (lambda2 - lambda1);
12424 value = frac * value2 + (1 - frac) * value1;
12435 cpl_table_erase_window(sky, 0, first_valid);
12476 double dispersion, cpl_image *skymap)
12478 const char *func =
"mos_sky_map";
12480 cpl_vector **vector;
12481 double firstLambda, lastLambda;
12482 double lambda, lambda1, lambda2;
12483 double value, value1, value2;
12491 double *sky_spectrum;
12498 if (spectra == NULL || wavemap == NULL || skymap == NULL) {
12499 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
12503 if (dispersion <= 0.0) {
12504 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
12508 nx = cpl_image_get_size_x(spectra);
12509 ny = cpl_image_get_size_y(spectra);
12512 if (nx != cpl_image_get_size_x(wavemap) ||
12513 ny != cpl_image_get_size_y(wavemap) ||
12514 nx != cpl_image_get_size_x(skymap) ||
12515 ny != cpl_image_get_size_y(skymap)) {
12516 cpl_error_set(func, CPL_ERROR_INCOMPATIBLE_INPUT);
12525 data = cpl_image_get_data(wavemap);
12527 for (i = 0; i < npix; i++) {
12528 if (data[i] > 1.0) {
12529 min = max = data[i];
12535 for (i = j; i < npix; i++) {
12552 nbin = (lastLambda - firstLambda) / dispersion;
12561 count = cpl_calloc(nbin,
sizeof(
int));
12563 data = cpl_image_get_data(wavemap);
12565 for (i = 0; i < npix; i++) {
12568 bin = (data[i] - firstLambda) / dispersion;
12581 vector = cpl_calloc(nbin,
sizeof(cpl_vector *));
12582 for (i = 0; i < nbin; i++) {
12584 vector[i] = cpl_vector_new(count[i]);
12596 data = cpl_image_get_data(wavemap);
12597 sdata = cpl_image_get_data(spectra);
12599 for (i = 0; i < npix; i++) {
12602 bin = (data[i] - firstLambda) / dispersion;
12604 cpl_vector_set(vector[bin], count[bin], sdata[i]);
12615 sky_spectrum = cpl_calloc(nbin,
sizeof(
double));
12616 for (i = 0; i < nbin; i++) {
12618 sky_spectrum[i] = cpl_vector_get_median_const(vector[i]);
12619 cpl_vector_delete(vector[i]);
12637 sky = cpl_table_new(nbin);
12638 cpl_table_new_column(sky,
"wavelength", CPL_TYPE_DOUBLE);
12639 cpl_table_set_column_unit(sky,
"wavelength",
"pixel");
12640 cpl_table_wrap_double(sky, sky_spectrum,
"sky");
12641 cpl_table_wrap_int(sky, count,
"npoints");
12642 for (i = 0; i < nbin; i++)
12643 cpl_table_set_double(sky,
"wavelength", i,
12644 firstLambda + (i+0.5)*dispersion);
12651 data = cpl_image_get_data(wavemap);
12652 sdata = cpl_image_get_data(spectra);
12653 kdata = cpl_image_get_data(skymap);
12654 wdata = cpl_table_get_data_double(sky,
"wavelength");
12656 for (i = 0; i < npix; i++) {
12665 bin = (lambda - firstLambda) / dispersion;
12666 lambda1 = wdata[bin];
12667 value1 = sky_spectrum[bin];
12668 if (lambda1 < lambda) {
12671 lambda2 = wdata[bin];
12672 value2 = sky_spectrum[bin];
12673 value = ((lambda2 - lambda)*value1
12674 + (lambda - lambda1)*value2) / dispersion;
12685 lambda1 = wdata[bin];
12686 value1 = sky_spectrum[bin];
12687 value = ((lambda2 - lambda)*value1
12688 + (lambda - lambda1)*value2)/dispersion;
12719 const char *func =
"mos_sky_local_old";
12727 int xlow, ylow, xhig, yhig;
12735 if (spectra == NULL) {
12736 cpl_msg_error(func,
12737 "A scientific rectified spectral image must be given");
12738 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
12742 if (slits == NULL) {
12743 cpl_msg_error(func,
"A slits position table must be given");
12744 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
12748 nslits = cpl_table_get_nrow(slits);
12749 slit_id = cpl_table_get_data_int(slits,
"slit_id");
12750 position = cpl_table_get_data_int(slits,
"position");
12751 length = cpl_table_get_data_int(slits,
"length");
12753 nx = cpl_image_get_size_x(spectra);
12754 ny = cpl_image_get_size_y(spectra);
12756 skymap = cpl_image_new(nx, ny, CPL_TYPE_FLOAT);
12760 for (i = 0; i < nslits; i++) {
12762 if (length[i] == 0)
12775 ylow = position[i] + 1;
12776 yhig = ylow + length[i] - 1;
12778 exslit = cpl_image_extract(spectra, xlow, ylow, xhig, yhig);
12779 sky = cpl_image_collapse_median_create(exslit, 0, 0, 1);
12780 cpl_image_delete(exslit);
12782 data = cpl_image_get_data(skymap);
12783 data += nx * position[i];
12785 for (j = 0; j < length[i]; j++) {
12786 sdata = cpl_image_get_data(sky);
12787 for (k = 0; k < nx; k++) {
12788 *data++ = *sdata++;
12792 cpl_image_delete(sky);
12821 const char *func =
"mos_sky_local";
12823 char name[MAX_COLNAME];
12825 cpl_polynomial *fit;
12826 cpl_vector *points;
12827 cpl_vector *values;
12828 cpl_vector *keep_points;
12829 cpl_vector *keep_values;
12832 cpl_image *subtracted;
12833 cpl_image *profile;
12835 cpl_table *objects;
12843 int xlow, ylow, xhig, yhig;
12856 if (spectra == NULL) {
12857 cpl_msg_error(func,
12858 "A scientific rectified spectral image must be given");
12859 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
12863 if (slits == NULL) {
12864 cpl_msg_error(func,
"A slits position table must be given");
12865 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
12870 cpl_msg_error(func,
"Invalid fit order");
12871 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
12875 nslits = cpl_table_get_nrow(slits);
12876 slit_id = cpl_table_get_data_int(slits,
"slit_id");
12877 position = cpl_table_get_data_int(slits,
"position");
12878 length = cpl_table_get_data_int(slits,
"length");
12880 nx = cpl_image_get_size_x(spectra);
12881 ny = cpl_image_get_size_y(spectra);
12883 skymap = cpl_image_new(nx, ny, CPL_TYPE_FLOAT);
12887 for (i = 0; i < nslits; i++) {
12889 if (length[i] == 0)
12902 ylow = position[i] + 1;
12903 yhig = ylow + length[i] - 1;
12905 exslit = cpl_image_extract(spectra, xlow, ylow, xhig, yhig);
12906 sky = cpl_image_collapse_median_create(exslit, 0, 0, 1);
12907 cpl_image_delete(exslit);
12909 data = cpl_image_get_data(skymap);
12910 data += nx * position[i];
12912 for (j = 0; j < length[i]; j++) {
12913 sdata = cpl_image_get_data(sky);
12914 for (k = 0; k < nx; k++) {
12915 *data++ = *sdata++;
12919 cpl_image_delete(sky);
12927 subtracted = cpl_image_duplicate(spectra);
12928 cpl_image_subtract(subtracted, skymap);
12929 cpl_image_delete(skymap);
12936 objects = cpl_table_duplicate(slits);
12938 cpl_image_delete(profile);
12939 cpl_image_delete(subtracted);
12948 snprintf(name, MAX_COLNAME,
"object_%d", maxobjects);
12949 while (cpl_table_has_column(objects, name)) {
12951 snprintf(name, MAX_COLNAME,
"object_%d", maxobjects);
12954 is_sky = cpl_calloc(ny,
sizeof(
int));
12956 for (i = 0; i < nslits; i++) {
12958 if (length[i] == 0)
12961 ylow = position[i] + margin;
12962 yhig = position[i] + length[i] - margin;
12964 for (j = ylow; j < yhig; j++)
12967 for (j = 1; j < maxobjects; j++) {
12968 snprintf(name, MAX_COLNAME,
"object_%d", j);
12969 if (cpl_table_is_valid(objects, name, i)) {
12970 snprintf(name, MAX_COLNAME,
"start_%d", j);
12971 ylow = cpl_table_get_int(objects, name, i, NULL);
12972 snprintf(name, MAX_COLNAME,
"end_%d", j);
12973 yhig = cpl_table_get_int(objects, name, i, NULL);
12974 for (k = ylow; k <= yhig; k++)
12984 ylow = position[i] + margin + 1;
12985 yhig = position[i] + length[i] - margin - 1;
12987 for (j = ylow; j < yhig; j++)
12989 if (is_sky[j-1] == 0 && is_sky[j+1] == 0)
12999 skymap = cpl_image_new(nx, ny, CPL_TYPE_FLOAT);
13001 for (i = 0; i < nslits; i++) {
13003 if (length[i] == 0)
13006 ylow = position[i];
13007 yhig = ylow + length[i];
13010 for (j = ylow; j < yhig; j++)
13014 if (nsky > order + 1) {
13016 points = cpl_vector_new(nsky);
13018 for (j = ylow; j < yhig; j++) {
13020 cpl_vector_set(points, nsky, j);
13025 exslit = cpl_image_extract(spectra, 1, ylow+1, nx, yhig);
13026 xdata = cpl_image_get_data(exslit);
13027 values = cpl_vector_new(nsky);
13029 for (j = 0; j < nx; j++) {
13031 for (k = ylow; k < yhig; k++) {
13033 cpl_vector_set(values, nsky, xdata[j+(k-ylow)*nx]);
13042 median = cpl_vector_get_median_const(values);
13043 vdata = cpl_vector_get_data(values);
13044 pdata = cpl_vector_get_data(points);
13046 for (k = 0; k < nsky; k++) {
13047 if (fabs(vdata[k] - median) < 100) {
13049 vdata[k-nbad] = vdata[k];
13050 pdata[k-nbad] = pdata[k];
13060 if (nbad && nsky - nbad > order + 1) {
13061 keep_values = values;
13062 keep_points = points;
13063 values = cpl_vector_wrap(nsky-nbad, vdata);
13064 points = cpl_vector_wrap(nsky-nbad, pdata);
13067 if (nsky - nbad > order + 1) {
13069 fit = cpl_polynomial_fit_1d_create(points, values,
13073 for (k = ylow; k < yhig; k++) {
13074 xdata[j+(k-ylow)*nx] =
13075 cpl_polynomial_eval_1d(fit, k, NULL);
13078 cpl_polynomial_delete(fit);
13084 for (k = 0; k < nsky; k++) {
13085 xdata[j+k*nx] = median;
13089 if (nbad && nsky - nbad > order + 1) {
13090 cpl_vector_unwrap(values);
13091 cpl_vector_unwrap(points);
13092 values = keep_values;
13093 points = keep_points;
13098 for (k = ylow; k < yhig; k++) {
13100 cpl_vector_set(points, nsky, k);
13108 cpl_vector_delete(values);
13109 cpl_vector_delete(points);
13111 cpl_image_copy(skymap, exslit, 1, ylow+1);
13112 cpl_image_delete(exslit);
13116 exslit = cpl_image_extract(spectra, 1, ylow+1, nx, yhig);
13117 xdata = cpl_image_get_data(exslit);
13118 values = cpl_vector_new(nsky);
13120 for (j = 0; j < nx; j++) {
13122 for (k = ylow; k < yhig; k++) {
13124 cpl_vector_set(values, nsky, xdata[j+(k-ylow)*nx]);
13129 median = cpl_vector_get_median_const(values);
13131 for (k = ylow; k < yhig; k++)
13132 xdata[j+(k-ylow)*nx] = median;
13136 cpl_vector_delete(values);
13138 cpl_image_copy(skymap, exslit, 1, ylow+1);
13139 cpl_image_delete(exslit);
13143 cpl_msg_warning(func,
"Too few sky points in slit %d", i + 1);
13175 float threshold,
float ratio)
13177 const char *func =
"mos_clean_cosmics";
13179 cpl_image *smoothImage;
13181 cpl_matrix *kernel;
13186 float sigma, sum, value, smoothValue;
13190 int iMin, iMax, jMin, jMax, iPosMax, jPosMax;
13196 int pos, i, j, k, l, ii, jj, iii = 0, jjj = 0;
13198 int found, foundContiguousCandidate;
13203 return cpl_error_set(func, CPL_ERROR_NULL_INPUT);
13216 xLen = cpl_image_get_size_x(image);
13217 yLen = cpl_image_get_size_y(image);
13219 if (xLen < 4 || yLen < 4)
13220 return CPL_ERROR_NONE;
13222 nPix = xLen * yLen;
13245 idata = cpl_image_get_data(image);
13249 for (i = 0; i < nPix; i++) {
13250 if (idata[i] < -0.00001) {
13259 cosmic = cpl_calloc(nPix,
sizeof(
int));
13261 if (threshold < 0.)
13266 kernel = cpl_matrix_new(3, 3);
13267 cpl_matrix_fill(kernel, 1.0);
13268 cpl_matrix_set(kernel, 1, 1, 0.0);
13269 smoothImage = cpl_image_filter_median(image, kernel);
13270 cpl_matrix_delete(kernel);
13281 sdata = cpl_image_get_data(smoothImage);
13283 for (j = 1; j < yLen - 1; j++) {
13284 for (i = 1; i < xLen - 1; i++) {
13285 value = idata[i + j * xLen];
13286 smoothValue = sdata[i + j * xLen];
13287 if (smoothValue < 1.0)
13289 sigma = sqrt(noise * noise + smoothValue / gain);
13290 if (value - smoothValue >= threshold * sigma)
13291 cosmic[i + j * xLen] = -1;
13295 cpl_image_delete(smoothImage);
13304 for (pos = first; pos < nPix; pos++) {
13305 if (cosmic[pos] == -1) {
13325 iMin = iMax = iPosMax = i;
13326 jMin = jMax = jPosMax = j;
13327 fMax = idata[i + j * xLen];
13330 foundContiguousCandidate = 0;
13331 for (l = 0; l <= 1; l++) {
13332 for (k = 0; k <= 1; k++) {
13339 jj = j + k + l - 1;
13340 if (cosmic[ii + jj * xLen] == -1) {
13341 foundContiguousCandidate = 1;
13342 cosmic[ii + jj * xLen] = 2;
13360 if (idata[ii + jj * xLen] > fMax) {
13361 fMax = idata[ii + jj * xLen];
13374 cosmic[i + j * xLen] = 3;
13376 if (foundContiguousCandidate) {
13398 for (l = jMin; l <= jMax; l++) {
13399 for (k = iMin; k <= iMax; k++) {
13400 if (cosmic[k + l * xLen] == 2) {
13403 foundContiguousCandidate = 1;
13407 if (foundContiguousCandidate)
13410 }
while (foundContiguousCandidate);
13419 for (l = -1; l <= 1; l++) {
13420 for (k = -1; k <= 1; k++) {
13421 if (l != 0 || k != 0) {
13422 sum += idata[iPosMax + k + (jPosMax + l) * xLen];
13428 if (fMax > ratio * sum) {
13429 for (l = jMin - 1; l <= jMax + 1; l++) {
13430 for (k = iMin - 1; k <= iMax + 1; k++) {
13431 if (cosmic[k + l * xLen] == 3) {
13432 cosmic[k + l * xLen] = 1;
13439 for (l = jMin - 1; l <= jMax + 1; l++) {
13440 for (k = iMin - 1; k <= iMax + 1; k++) {
13441 if (cosmic[k + l * xLen] != -1) {
13442 if (cosmic[k + l * xLen] == 1)
13444 cosmic[k + l * xLen] = 0;
13457 table = cpl_table_new(numCosmic);
13458 cpl_table_new_column(table,
"x", CPL_TYPE_INT);
13459 cpl_table_new_column(table,
"y", CPL_TYPE_INT);
13460 cpl_table_set_column_unit(table,
"x",
"pixel");
13461 cpl_table_set_column_unit(table,
"y",
"pixel");
13462 xdata = cpl_table_get_data_int(table,
"x");
13463 ydata = cpl_table_get_data_int(table,
"y");
13465 for (pos = 0, i = 0; pos < nPix; pos++) {
13466 if (cosmic[pos] == 1) {
13467 xdata[i] = (pos % xLen);
13468 ydata[i] = (pos / xLen);
13473 mos_clean_bad_pixels(image, table, 1);
13476 cpl_table_delete(table);
13478 return CPL_ERROR_NONE;
13483 cpl_error_code mos_clean_bad_pixels(cpl_image *image, cpl_table *table,
13486 const char *func =
"mos_clean_cosmics";
13491 int xlen, ylen, totPix;
13492 int nBadPixels = 0;
13493 int sign, foundFirst;
13494 int *xValue = NULL;
13495 int *yValue = NULL;
13501 int sx[] = {0, 1, 1, 1};
13502 int sy[] = {1,-1, 0, 1};
13503 int searchHorizon = 100;
13507 if (image == NULL || table == NULL)
13508 return cpl_error_set(func, CPL_ERROR_NULL_INPUT);
13510 if (1 != cpl_table_has_column(table,
"x"))
13511 return cpl_error_set(func, CPL_ERROR_DATA_NOT_FOUND);
13513 if (1 != cpl_table_has_column(table,
"y"))
13514 return cpl_error_set(func, CPL_ERROR_DATA_NOT_FOUND);
13516 if (CPL_TYPE_INT != cpl_table_get_column_type(table,
"x"))
13517 return cpl_error_set(func, CPL_ERROR_INVALID_TYPE);
13519 if (CPL_TYPE_INT != cpl_table_get_column_type(table,
"y"))
13520 return cpl_error_set(func, CPL_ERROR_INVALID_TYPE);
13522 nBadPixels = cpl_table_get_nrow(table);
13525 xlen = cpl_image_get_size_x(image);
13526 ylen = cpl_image_get_size_y(image);
13527 idata = cpl_image_get_data(image);
13528 totPix = xlen * ylen;
13529 if (((
float) nBadPixels) / ((
float) totPix) < percent/100.) {
13530 isBadPix = cpl_calloc(totPix,
sizeof(
int));
13533 cpl_msg_warning(func,
"Too many bad pixels (> %d%%): "
13534 "skip bad pixel correction", percent);
13535 return cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
13539 cpl_msg_debug(func,
"No pixel values to interpolate");
13540 return CPL_ERROR_NONE;
13543 xValue = cpl_table_get_data_int(table,
"x");
13544 yValue = cpl_table_get_data_int(table,
"y");
13546 for (i = 0; i < nBadPixels; i++)
13547 isBadPix[xValue[i] + yValue[i] * xlen] = 1;
13549 for (i = 0; i < nBadPixels; i++) {
13564 for (j = 0; j < 4; j++) {
13570 estimate[nPairs] = 0.;
13573 for (k = 0; k < 2; k++) {
13579 cx += sign * sx[j];
13580 cy += sign * sy[j];
13581 if (cx < 0 || cx >= xlen || cy < 0 || cy >= ylen)
13584 }
while (isBadPix[cx + cy * xlen] && d < searchHorizon);
13586 if (cx >= 0 && cx < xlen &&
13587 cy >= 0 && cy < ylen && d < searchHorizon) {
13593 save = idata[cx + cy * xlen];
13594 estimate[nPairs] += save / d;
13595 sumd += 1. / (double) d;
13597 estimate[nPairs] /= sumd;
13612 estimate[nPairs] = save;
13627 idata[xValue[i] + yValue[i] * xlen] =
13628 cpl_tools_get_median_float(estimate, nPairs);
13630 else if (nPairs == 2) {
13631 idata[xValue[i] + yValue[i] * xlen] =
13632 (estimate[0] + estimate[1]) / 2.;
13634 else if (nPairs == 1) {
13635 idata[xValue[i] + yValue[i] * xlen] = estimate[0];
13638 cpl_msg_debug(func,
"Cannot correct bad pixel %d,%d\n",
13639 xValue[i], yValue[i]);
13643 cpl_free(isBadPix);
13645 return CPL_ERROR_NONE;
13679 cpl_table *polytraces,
double reference,
13680 double blue,
double red,
double dispersion)
13682 const char *func =
"mos_spatial_map";
13684 const char *clab[6] = {
"c0",
"c1",
"c2",
"c3",
"c4",
"c5"};
13686 cpl_polynomial *polytop;
13687 cpl_polynomial *polybot;
13688 cpl_image *calibration;
13701 int pixel_above, pixel_below, refpixel, start_pixel, end_pixel;
13702 int missing_top, missing_bot;
13709 if (spectra == NULL || slits == NULL || polytraces == NULL) {
13710 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
13714 if (dispersion <= 0.0) {
13715 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
13719 if (red - blue < dispersion) {
13720 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
13724 nx = cpl_image_get_size_x(spectra);
13725 ny = cpl_image_get_size_y(spectra);
13727 calibration = cpl_image_new(nx, ny, CPL_TYPE_FLOAT);
13728 data = cpl_image_get_data(calibration);
13730 length = cpl_table_get_data_int(slits,
"length");
13731 nslits = cpl_table_get_nrow(slits);
13732 slit_id = cpl_table_get_data_int(slits,
"slit_id");
13733 order = cpl_table_get_ncol(polytraces) - 2;
13740 pixel_above = STRETCH_FACTOR * (red - reference) / dispersion;
13741 pixel_below = STRETCH_FACTOR * (reference - blue) / dispersion;
13743 for (i = 0; i < nslits; i++) {
13745 if (length[i] == 0)
13759 refpixel = cpl_table_get_double(slits,
"xtop", i, NULL);
13761 start_pixel = refpixel - pixel_below;
13762 if (start_pixel < 0)
13765 end_pixel = refpixel + pixel_above;
13766 if (end_pixel > nx)
13775 polytop = cpl_polynomial_new(1);
13776 for (k = 0; k <= order; k++) {
13777 coeff = cpl_table_get_double(polytraces, clab[k], 2*i, &null);
13779 cpl_polynomial_delete(polytop);
13783 cpl_polynomial_set_coeff(polytop, &k, coeff);
13787 polybot = cpl_polynomial_new(1);
13788 for (k = 0; k <= order; k++) {
13789 coeff = cpl_table_get_double(polytraces, clab[k], 2*i+1, &null);
13791 cpl_polynomial_delete(polybot);
13795 cpl_polynomial_set_coeff(polybot, &k, coeff);
13798 if (missing_top && missing_bot) {
13799 cpl_msg_warning(func,
"Spatial map, slit %d was not traced!",
13811 cpl_msg_warning(func,
"Upper edge of slit %d was not traced: "
13812 "the spectral curvature of the lower edge "
13813 "is used instead.", slit_id[i]);
13814 polytop = cpl_polynomial_duplicate(polybot);
13815 ytop = cpl_table_get_double(slits,
"ytop", i, NULL);
13816 ybot = cpl_table_get_double(slits,
"ybottom", i, NULL);
13818 coeff = cpl_polynomial_get_coeff(polybot, &k);
13819 coeff += ytop - ybot;
13820 cpl_polynomial_set_coeff(polytop, &k, coeff);
13824 cpl_msg_warning(func,
"Lower edge of slit %d was not traced: "
13825 "the spectral curvature of the upper edge "
13826 "is used instead.", slit_id[i]);
13827 polybot = cpl_polynomial_duplicate(polytop);
13828 ytop = cpl_table_get_double(slits,
"ytop", i, NULL);
13829 ybot = cpl_table_get_double(slits,
"ybottom", i, NULL);
13831 coeff = cpl_polynomial_get_coeff(polytop, &k);
13832 coeff -= ytop - ybot;
13833 cpl_polynomial_set_coeff(polybot, &k, coeff);
13836 top = cpl_polynomial_eval_1d(polytop, refpixel, NULL);
13837 bot = cpl_polynomial_eval_1d(polybot, refpixel, NULL);
13838 npseudo = ceil(top-bot) + 1;
13841 cpl_polynomial_delete(polytop);
13842 cpl_polynomial_delete(polybot);
13843 cpl_msg_warning(func,
"Slit %d was badly traced: no extraction!",
13848 for (j = start_pixel; j < end_pixel; j++) {
13849 top = cpl_polynomial_eval_1d(polytop, j, NULL);
13850 bot = cpl_polynomial_eval_1d(polybot, j, NULL);
13851 factor = (top-bot)/npseudo;
13852 for (k = 0; k <= npseudo; k++) {
13853 ypos = top - k*factor;
13855 yfra = ypos - yint;
13856 if (yint >= 0 && yint < ny-1) {
13857 data[j + nx*yint] = (top-yint)/factor;
13866 if (yprev - yint > 1) {
13867 data[j + nx*(yint+1)] = (top-yint-1)/factor;
13874 cpl_polynomial_delete(polytop);
13875 cpl_polynomial_delete(polybot);
13878 return calibration;
13945 int maxradius,
int conradius)
13947 const char *func =
"mos_detect_objects";
13949 cpl_image *profile;
13953 char name[MAX_COLNAME];
13957 int nobjects, objpos, totobj;
13964 double mindistance;
13971 const int min_pixels = 10;
13974 if (cpl_error_get_code() != CPL_ERROR_NONE)
13977 if (image == NULL || slits == NULL) {
13978 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
13985 if (maxradius < 0) {
13986 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
13990 if (conradius < 0) {
13991 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
13995 nslits = cpl_table_get_nrow(slits);
13996 position = cpl_table_get_data_int(slits,
"position");
13997 length = cpl_table_get_data_int(slits,
"length");
13999 profile = cpl_image_collapse_create(image, 1);
14000 cpl_image_divide_scalar(profile, cpl_image_get_size_x(image));
14001 pdata = cpl_image_get_data(profile);
14006 for (i = 0; i < nslits; i++) {
14008 if (length[i] == 0)
14011 pos = position[i] + margin;
14012 count = length[i] - 2*margin;
14014 if (count < min_pixels)
14025 if (p[0] > p[1] && p[1] > p[2] && p[2] > p[3] && p[3] > 0) {
14030 for (j = 0; j < count - 3; j++) {
14032 if (p[j+1] > p[j]) {
14037 if (p[j+1] > p[j+2] && p[j+2] > 0) {
14043 if (p[j+1] > p[j+2] && p[j+2] > p[j+3] && p[j+3] > 0) {
14056 if (p[count-1] > p[count-2] && p[count-2] > p[count-3]
14057 && p[count-3] > p[count-4] && p[count-4] > 0) {
14069 reject = cpl_calloc(npeaks,
sizeof(
int));
14070 bright = cpl_calloc(npeaks,
sizeof(
double));
14071 place = cpl_calloc(npeaks,
sizeof(
double));
14074 if (p[0] > p[1] && p[1] > p[2] && p[2] > p[3] && p[3] > 0) {
14076 place[0] = position[i] + margin;
14081 for (j = 0; j < count - 3; j++) {
14083 if (p[j+1] > p[j]) {
14088 if (p[j+1] > p[j+2] && p[j+2] > 0) {
14090 bright[npeaks] = p[j];
14091 place[npeaks] = position[i] + margin + j + 1
14092 + values_to_dx(p[j-1], p[j], p[j+1]);
14098 if (p[j+1] > p[j+2] && p[j+2] > p[j+3] && p[j+3] > 0) {
14100 bright[npeaks] = p[j];
14101 place[npeaks] = position[i] + margin + j + 1
14102 + values_to_dx(p[j-1], p[j], p[j+1]);
14115 if (p[count-1] > p[count-2] && p[count-2] > p[count-3]
14116 && p[count-3] > p[count-4] && p[count-4] > 0) {
14117 bright[npeaks] = p[count-1];
14118 place[npeaks] = position[i] + count;
14127 if (fabs(place[0] - pos) < 1.0)
14129 if (fabs(place[npeaks-1] - pos - count) < 1.0)
14130 reject[npeaks-1] = 1;
14131 for (j = 0; j < npeaks; j++) {
14132 for (k = 0; k < npeaks; k++) {
14135 mindistance = conradius * bright[k] / bright[j]
14136 * bright[k] / bright[j];
14137 if (fabs(place[j] - place[k]) < mindistance)
14143 for (j = 0; j < npeaks; j++) {
14147 low = (place[j-1]*bright[j] + place[j]*bright[j-1])
14148 / (bright[j-1] + bright[j]) + 1;
14153 if (j < npeaks - 1) {
14154 hig = (place[j+1]*bright[j] + place[j]*bright[j+1])
14155 / (bright[j+1] + bright[j]) + 1;
14163 if (hig > pos + count)
14165 if (place[j] - low > maxradius)
14166 low = place[j] - maxradius;
14167 if (hig - place[j] > maxradius)
14168 hig = place[j] + maxradius;
14175 for (j = 0; j < npeaks; j++)
14179 for (j = 0; j < nobjects; j++) {
14180 snprintf(name, MAX_COLNAME,
"object_%d", j+1);
14181 if (cpl_table_has_column(slits, name))
14183 cpl_table_new_column(slits, name, CPL_TYPE_DOUBLE);
14184 snprintf(name, MAX_COLNAME,
"start_%d", j+1);
14185 cpl_table_new_column(slits, name, CPL_TYPE_INT);
14186 cpl_table_set_column_unit(slits, name,
"pixel");
14187 snprintf(name, MAX_COLNAME,
"end_%d", j+1);
14188 cpl_table_new_column(slits, name, CPL_TYPE_INT);
14189 cpl_table_set_column_unit(slits, name,
"pixel");
14190 snprintf(name, MAX_COLNAME,
"row_%d", j+1);
14191 cpl_table_new_column(slits, name, CPL_TYPE_INT);
14192 cpl_table_set_column_unit(slits, name,
"pixel");
14196 for (j = 0; j < npeaks; j++) {
14200 low = (place[j-1]*bright[j] + place[j]*bright[j-1])
14201 / (bright[j-1] + bright[j]) + 1;
14206 if (j < npeaks - 1) {
14207 hig = (place[j+1]*bright[j] + place[j]*bright[j+1])
14208 / (bright[j+1] + bright[j]) + 1;
14216 if (hig > pos + count)
14218 if (place[j] - low > maxradius)
14219 low = place[j] - maxradius;
14220 if (hig - place[j] > maxradius)
14221 hig = place[j] + maxradius;
14223 snprintf(name, MAX_COLNAME,
"object_%d", objpos);
14224 cpl_table_set_double(slits, name, i, place[j]);
14225 snprintf(name, MAX_COLNAME,
"start_%d", objpos);
14226 cpl_table_set_int(slits, name, i, low);
14227 snprintf(name, MAX_COLNAME,
"end_%d", objpos);
14228 cpl_table_set_int(slits, name, i, hig);
14229 snprintf(name, MAX_COLNAME,
"row_%d", objpos);
14230 cpl_table_set_int(slits, name, i, row + objpos - 1);
14237 if (maxobjects < nobjects)
14238 maxobjects = nobjects;
14247 row = cpl_table_get_nrow(slits);
14249 for (i = 0; i < row; i++) {
14250 for (j = 0; j < maxobjects; j++) {
14251 snprintf(name, MAX_COLNAME,
"row_%d", j+1);
14252 if (cpl_table_is_valid(slits, name, i))
14253 cpl_table_set_int(slits, name, i, totobj -
14254 cpl_table_get_int(slits, name, i, NULL));
14258 for (i = 0; i < maxobjects; i++) {
14259 snprintf(name, MAX_COLNAME,
"start_%d", i+1);
14260 cpl_table_fill_invalid_int(slits, name, -1);
14261 snprintf(name, MAX_COLNAME,
"end_%d", i+1);
14262 cpl_table_fill_invalid_int(slits, name, -1);
14263 snprintf(name, MAX_COLNAME,
"row_%d", i+1);
14264 cpl_table_fill_invalid_int(slits, name, -1);
14297 cpl_table *objects,
int extraction,
double ron,
14298 double gain,
int ncombined)
14300 const char *func =
"mos_extract_objects";
14302 char name[MAX_COLNAME];
14304 cpl_image **output;
14305 cpl_image *extracted;
14306 cpl_image *extr_sky;
14309 cpl_image *sci_var_win = NULL;
14319 if (science == NULL || sky == NULL) {
14320 cpl_msg_error(func,
"Both scientific exposures are required in input");
14321 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
14325 if (objects == NULL) {
14326 cpl_msg_error(func,
"An object table is required in input");
14327 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
14331 if (extraction < 0 || extraction > 1) {
14332 cpl_msg_error(func,
"Invalid extraction mode (%d): it should be "
14333 "either 0 or 1", extraction);
14334 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
14339 cpl_msg_error(func,
"Invalid read-out-noise (%f ADU)", ron);
14340 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
14345 cpl_msg_error(func,
"Invalid gain factor (%f e-/ADU)", gain);
14346 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
14350 if (ncombined < 1) {
14351 cpl_msg_error(func,
"Invalid number of combined frames (%d): "
14352 "it should be at least 1", ncombined);
14353 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
14364 snprintf(name, MAX_COLNAME,
"object_%d", maxobjects);
14365 while (cpl_table_has_column(objects, name)) {
14367 snprintf(name, MAX_COLNAME,
"object_%d", maxobjects);
14376 nslits = cpl_table_get_nrow(objects);
14378 for (i = 0; i < nslits; i++) {
14379 for (j = 1; j < maxobjects; j++) {
14380 snprintf(name, MAX_COLNAME,
"object_%d", j);
14381 if (cpl_table_is_valid(objects, name, i))
14389 nx = cpl_image_get_size_x(science);
14391 output = cpl_calloc(3,
sizeof(cpl_image *));
14392 extracted = output[0] = cpl_image_new(nx, nobjects, CPL_TYPE_FLOAT);
14393 extr_sky = output[1] = cpl_image_new(nx, nobjects, CPL_TYPE_FLOAT);
14394 error = output[2] = cpl_image_new(nx, nobjects, CPL_TYPE_FLOAT);
14402 for (i = 0; i < nslits; i++) {
14403 for (j = 1; j < maxobjects; j++) {
14404 snprintf(name, MAX_COLNAME,
"object_%d", j);
14405 if (cpl_table_is_valid(objects, name, i)) {
14406 snprintf(name, MAX_COLNAME,
"start_%d", j);
14407 ylow = cpl_table_get_int(objects, name, i, NULL);
14408 snprintf(name, MAX_COLNAME,
"end_%d", j);
14409 yhig = cpl_table_get_int(objects, name, i, NULL);
14410 snprintf(name, MAX_COLNAME,
"row_%d", j);
14411 nobjects = cpl_table_get_int(objects, name, i, NULL);
14412 sciwin = cpl_image_extract(science, 1, ylow+1, nx, yhig);
14413 if(science_var != NULL)
14414 sci_var_win = cpl_image_extract(science_var, 1, ylow+1, nx, yhig);
14415 skywin = cpl_image_extract(sky, 1, ylow+1, nx, yhig);
14424 mos_extraction(sciwin, sci_var_win, skywin, extracted, extr_sky, error,
14425 nobjects, extraction, ron, gain, ncombined);
14432 cpl_image *total = cpl_image_add_create(sciwin, skywin);
14433 float *data = cpl_image_get_data_float(total);
14434 int size = cpl_image_get_size_x(total)
14435 * cpl_image_get_size_y(total);
14437 char *saturation_level = getenv(
"SATURATION_LEVEL");
14438 float saturation = 62000.0;
14439 char *max_saturated = getenv(
"MAX_SATURATED");
14440 int max_satur = 10;
14443 if (saturation_level)
14444 saturation = atof(saturation_level);
14447 max_satur = atoi(max_saturated);
14450 for (k = 0; k < size; k++) {
14451 if (data[k] > saturation) {
14453 if (saturated > max_satur) {
14459 if (saturated > max_satur)
14464 data = cpl_image_get_data(extracted);
14465 data[nobjects * nx] = saturated;
14468 cpl_image_delete(sciwin);
14469 cpl_image_delete(skywin);
14503 double dispersion,
int saturation,
14504 double *mfwhm,
double *rmsfwhm,
14505 double *resolution,
double *rmsres,
int *nlines)
14507 cpl_vector *vector;
14510 int position, maxpos;
14515 int threshold = 250;
14520 double min, max, halfmax;
14531 xlen = cpl_image_get_size_x(image);
14532 ylen = cpl_image_get_size_y(image);
14533 data = cpl_image_get_data(image);
14535 buffer = cpl_malloc(ylen *
sizeof(
double));
14541 position = floor((lambda - startwave) / dispersion + 0.5);
14543 sp = position - sradius;
14544 ep = position + sradius;
14546 if (sp < 0 || ep > xlen) {
14551 for (i = 0, n = 0; i < ylen; i++) {
14562 sp = position - radius;
14563 ep = position + radius;
14565 if (sp < 0 || ep > xlen) {
14576 min = max = data[sp + i * xlen];
14577 for (j = sp; j < ep; j++) {
14578 if (data[j + i * xlen] > max) {
14579 max = data[j + i * xlen];
14582 if (data[j + i * xlen] < min) {
14583 min = data[j + i * xlen];
14587 if (fabs(min) < 0.0000001)
14590 if (max - min < threshold)
14593 if (max > saturation)
14603 halfmax = (max + min)/ 2.0;
14607 for (j = maxpos; j < maxpos + radius; j++) {
14609 if (data[j + i * xlen] < halfmax) {
14610 fwhm = ifwhm + (data[j - 1 + i * xlen] - halfmax)
14611 / (data[j - 1 + i * xlen] - data[j + i * xlen]);
14619 for (j = maxpos; j > maxpos - radius; j--) {
14621 if (data[j + i * xlen] < halfmax) {
14622 fwhm += ifwhm + (data[j + 1 + i * xlen] - halfmax)
14623 / (data[j + 1 + i * xlen] - data[j + i * xlen]);
14631 buffer[n] = fwhm - 2.0;
14642 vector = cpl_vector_wrap(n, buffer);
14643 value = cpl_vector_get_median_const(vector);
14644 cpl_vector_unwrap(vector);
14647 for (i = 0, m = 0; i < n; i++) {
14648 if (fabs(buffer[i] - value) < cut) {
14649 rms += fabs(buffer[i] - value);
14662 value *= dispersion;
14668 *resolution = lambda / value;
14669 *rmsres = *resolution * rms / value;
14699 double dispersion,
int saturation,
14714 nref = cpl_vector_get_size(lines);
14715 line = cpl_vector_get_data(lines);
14717 table = cpl_table_new(nref);
14718 cpl_table_new_column(table,
"wavelength", CPL_TYPE_DOUBLE);
14719 cpl_table_set_column_unit(table,
"wavelength",
"Angstrom");
14720 cpl_table_new_column(table,
"fwhm", CPL_TYPE_DOUBLE);
14721 cpl_table_set_column_unit(table,
"fwhm",
"Angstrom");
14722 cpl_table_new_column(table,
"fwhm_rms", CPL_TYPE_DOUBLE);
14723 cpl_table_set_column_unit(table,
"fwhm_rms",
"Angstrom");
14724 cpl_table_new_column(table,
"resolution", CPL_TYPE_DOUBLE);
14725 cpl_table_new_column(table,
"resolution_rms", CPL_TYPE_DOUBLE);
14726 cpl_table_new_column(table,
"nlines", CPL_TYPE_INT);
14728 for (i = 0; i < nref; i++) {
14730 saturation, &fwhm, &rmsfwhm,
14731 &resolution, &rmsres, &nlines)) {
14732 cpl_table_set_double(table,
"wavelength", i, line[i]);
14733 cpl_table_set_double(table,
"fwhm", i, fwhm);
14734 cpl_table_set_double(table,
"fwhm_rms", i, rmsfwhm);
14735 cpl_table_set_double(table,
"resolution", i, resolution);
14736 cpl_table_set_double(table,
"resolution_rms", i, rmsres);
14737 cpl_table_set_int(table,
"nlines", i, nlines);
14740 cpl_table_set_int(table,
"nlines", i, 0);
14743 if (cpl_table_has_valid(table,
"wavelength"))
14746 cpl_table_delete(table);
14771 int ystart,
int yend,
double wstart,
double wend)
14773 const char *func =
"mos_integrate_signal";
14782 if (image == NULL || wavemap == NULL) {
14783 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
14787 if (ystart > yend || wstart >= wend) {
14788 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
14792 nx = cpl_image_get_size_x(image);
14793 ny = cpl_image_get_size_y(image);
14795 if (!(nx == cpl_image_get_size_x(wavemap)
14796 && ny == cpl_image_get_size_y(wavemap))) {
14797 cpl_error_set(func, CPL_ERROR_INCOMPATIBLE_INPUT);
14801 if (ystart < 0 || yend > ny) {
14802 cpl_error_set(func, CPL_ERROR_ACCESS_OUT_OF_RANGE);
14806 sdata = cpl_image_get_data(image);
14807 wdata = cpl_image_get_data(wavemap);
14809 sdata += ystart*nx;
14810 wdata += ystart*nx;
14813 for (y = ystart; y < yend; y++) {
14814 for (x = 0; x < nx; x++) {
14815 if (wdata[x] < wstart || wdata[x] > wend)
14860 const char *func =
"mos_load_slits_fors_mxu";
14863 char keyname[MAX_COLNAME];
14864 const char *instrume;
14865 const char *target_name;
14870 double arc2mm = 0.528;
14883 float low_limit1 = 10.0;
14884 float hig_limit2 = 30.0;
14887 if (cpl_error_get_code() != CPL_ERROR_NONE) {
14891 if (header == NULL) {
14892 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
14901 instrume = cpl_propertylist_get_string(header,
"INSTRUME");
14904 if (instrume[4] ==
'1')
14906 if (instrume[4] ==
'2')
14910 cpl_msg_error(func,
"Wrong instrument: %s\n"
14911 "FORS2 is expected for MXU data", instrume);
14912 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
14923 chip = cpl_propertylist_get_int(header,
"ESO DET CHIP1 Y");
14925 if (cpl_error_get_code() != CPL_ERROR_NONE) {
14926 cpl_msg_error(func,
"Missing keyword ESO DET CHIP1 Y "
14928 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
14932 if (chip != 1 && chip != 2) {
14933 cpl_msg_error(func,
"Unexpected chip position in keyword "
14934 "ESO DET CHIP1 Y: %d", chip);
14935 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
14951 snprintf(keyname, MAX_COLNAME,
"ESO INS MOS%d YPOS", slit_id + 100);
14952 if (cpl_propertylist_has(header, keyname)) {
14953 slit_y = cpl_propertylist_get_double(header, keyname);
14956 if (slit_y < low_limit1)
14959 if (slit_y > hig_limit2)
14962 snprintf(keyname, MAX_COLNAME,
"ESO INS TARG%d NAME",
14964 if (cpl_propertylist_has(header, keyname)) {
14965 target_name = cpl_propertylist_get_string(header, keyname);
14966 if (strncmp(target_name,
"refslit", 7))
14976 if (cpl_error_get_code() != CPL_ERROR_NONE) {
14977 cpl_msg_error(func,
"%s while loading slits coordinates from "
14978 "FITS header", cpl_error_get_message());
14979 cpl_error_set_where(func);
14984 cpl_msg_error(func,
"No slits coordinates found in header");
14985 cpl_error_set(func, CPL_ERROR_DATA_NOT_FOUND);
14989 slits = cpl_table_new(nslits);
14990 cpl_table_new_column(slits,
"slit_id", CPL_TYPE_INT);
14991 cpl_table_new_column(slits,
"xtop", CPL_TYPE_DOUBLE);
14992 cpl_table_new_column(slits,
"ytop", CPL_TYPE_DOUBLE);
14993 cpl_table_new_column(slits,
"xbottom", CPL_TYPE_DOUBLE);
14994 cpl_table_new_column(slits,
"ybottom", CPL_TYPE_DOUBLE);
14995 cpl_table_set_column_unit(slits,
"xtop",
"pixel");
14996 cpl_table_set_column_unit(slits,
"ytop",
"pixel");
14997 cpl_table_set_column_unit(slits,
"xbottom",
"pixel");
14998 cpl_table_set_column_unit(slits,
"ybottom",
"pixel");
15005 snprintf(keyname, MAX_COLNAME,
"ESO INS MOS%d YPOS", slit_id + 100);
15006 if (cpl_propertylist_has(header, keyname)) {
15007 slit_y = cpl_propertylist_get_double(header, keyname);
15010 if (slit_y < low_limit1)
15013 if (slit_y > hig_limit2)
15023 snprintf(keyname, MAX_COLNAME,
"ESO INS MOS%d XPOS", slit_id + 100);
15024 slit_x = cpl_propertylist_get_double(header, keyname);
15025 if (cpl_error_get_code() != CPL_ERROR_NONE) {
15026 cpl_table_delete(slits);
15027 cpl_msg_error(func,
"Missing keyword %s in FITS header",
15029 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
15033 snprintf(keyname, MAX_COLNAME,
"ESO INS MOS%d LEN", slit_id + 100);
15034 length = cpl_propertylist_get_double(header, keyname);
15035 if (cpl_error_get_code() != CPL_ERROR_NONE) {
15036 cpl_table_delete(slits);
15037 cpl_msg_error(func,
"Missing keyword %s in FITS header",
15039 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
15045 snprintf(keyname, MAX_COLNAME,
"ESO INS TARG%d NAME",
15047 if (cpl_propertylist_has(header, keyname)) {
15048 target_name = cpl_propertylist_get_string(header, keyname);
15049 if (strncmp(target_name,
"refslit", 7)) {
15050 cpl_table_set_int(slits,
"slit_id", nslits, slit_id);
15051 cpl_table_set(slits,
"xtop", nslits, slit_x);
15052 cpl_table_set(slits,
"ytop", nslits, slit_y + length/2);
15053 cpl_table_set(slits,
"xbottom", nslits, slit_x);
15054 cpl_table_set(slits,
"ybottom", nslits, slit_y - length/2);
15059 cpl_table_set_int(slits,
"slit_id", nslits, slit_id);
15060 cpl_table_set(slits,
"xtop", nslits, slit_x);
15061 cpl_table_set(slits,
"ytop", nslits, slit_y + length/2);
15062 cpl_table_set(slits,
"xbottom", nslits, slit_x);
15063 cpl_table_set(slits,
"ybottom", nslits, slit_y - length/2);
15099 int * nslits_out_det)
15101 const char *func =
"mos_load_slits_fors_mos";
15104 char keyname[MAX_COLNAME];
15105 const char *instrume;
15106 const char *chipname;
15108 int first_slit, last_slit;
15119 float ytop[19] = { 113.9, 101.3, 89.9, 77.3, 65.9, 53.3,
15120 41.9, 29.3, 17.9, 5.3, -6.1, -18.7,
15121 -30.1, -42.7, -54.1, -66.7, -78.1, -90.7,
15123 float ybottom[19] = { 102.1, 90.7, 78.1, 66.7, 54.1, 42.7,
15124 30.1, 18.7, 6.1, -5.3, -17.9, -29.3,
15125 -41.9, -53.3, -65.9, -77.3, -89.9, -101.3,
15129 if (cpl_error_get_code() != CPL_ERROR_NONE) {
15133 if (header == NULL) {
15134 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
15143 instrume = cpl_propertylist_get_string(header,
"INSTRUME");
15146 if (instrume[4] ==
'1')
15148 if (instrume[4] ==
'2')
15152 cpl_msg_error(func,
"Wrong instrument found in FITS header: %s",
15154 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
15164 chipname = cpl_propertylist_get_string(header,
"ESO DET CHIP1 ID");
15166 if (chipname[0] ==
'M' || chipname[0] ==
'N')
15171 if (fors == 1 && fors_is_old) {
15183 chip = cpl_propertylist_get_int(header,
"ESO DET CHIP1 Y");
15185 if (cpl_error_get_code() != CPL_ERROR_NONE) {
15186 cpl_msg_error(func,
"Missing keyword ESO DET CHIP1 Y "
15188 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
15192 if (chip != 1 && chip != 2) {
15193 cpl_msg_error(func,
"Unexpected chip position in keyword "
15194 "ESO DET CHIP1 Y: %d", chip);
15195 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
15218 for (slit_id = first_slit; slit_id <= last_slit; slit_id++) {
15219 snprintf(keyname, MAX_COLNAME,
"ESO INS MOS%d POS", slit_id);
15220 if (cpl_propertylist_has(header, keyname)) {
15221 slit_x = cpl_propertylist_get_double(header, keyname);
15222 if (fabs(slit_x) < 115.0)
15225 (*nslits_out_det)++;
15228 cpl_msg_error(func,
"Missing keyword %s in FITS header", keyname);
15229 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
15234 if (cpl_error_get_code() != CPL_ERROR_NONE) {
15235 cpl_msg_error(func,
"%s while loading slits coordinates from "
15236 "FITS header", cpl_error_get_message());
15237 cpl_error_set_where(func);
15242 cpl_msg_error(func,
"No slits coordinates found in header");
15243 cpl_error_set(func, CPL_ERROR_DATA_NOT_FOUND);
15247 slits = cpl_table_new(nslits);
15248 cpl_table_new_column(slits,
"slit_id", CPL_TYPE_INT);
15249 cpl_table_new_column(slits,
"xtop", CPL_TYPE_DOUBLE);
15250 cpl_table_new_column(slits,
"ytop", CPL_TYPE_DOUBLE);
15251 cpl_table_new_column(slits,
"xbottom", CPL_TYPE_DOUBLE);
15252 cpl_table_new_column(slits,
"ybottom", CPL_TYPE_DOUBLE);
15253 cpl_table_set_column_unit(slits,
"xtop",
"pixel");
15254 cpl_table_set_column_unit(slits,
"ytop",
"pixel");
15255 cpl_table_set_column_unit(slits,
"xbottom",
"pixel");
15256 cpl_table_set_column_unit(slits,
"ybottom",
"pixel");
15260 for (slit_id = first_slit; slit_id <= last_slit; slit_id++) {
15261 snprintf(keyname, MAX_COLNAME,
"ESO INS MOS%d POS", slit_id);
15262 slit_x = cpl_propertylist_get_double(header, keyname);
15263 if (fabs(slit_x) < 115.0) {
15264 cpl_table_set_int(slits,
"slit_id", nslits, slit_id);
15265 cpl_table_set(slits,
"xtop", nslits, slit_x);
15266 cpl_table_set(slits,
"ytop", nslits, ytop[slit_id-1]);
15267 cpl_table_set(slits,
"xbottom", nslits, slit_x);
15268 cpl_table_set(slits,
"ybottom", nslits, ybottom[slit_id-1]);
15302 const char *func =
"mos_load_slits_fors_lss";
15306 const char *instrume;
15312 if (cpl_error_get_code() != CPL_ERROR_NONE) {
15316 if (header == NULL) {
15317 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
15326 instrume = cpl_propertylist_get_string(header,
"INSTRUME");
15329 if (instrume[4] ==
'1')
15331 if (instrume[4] ==
'2')
15335 cpl_msg_error(func,
"Wrong instrument found in FITS header: %s",
15337 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
15353 chip = cpl_propertylist_get_int(header,
"ESO DET CHIP1 Y");
15355 if (cpl_error_get_code() != CPL_ERROR_NONE) {
15356 cpl_msg_error(func,
"Missing keyword ESO DET CHIP1 Y "
15358 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
15362 if (chip != 1 && chip != 2) {
15363 cpl_msg_error(func,
"Unexpected chip position in keyword "
15364 "ESO DET CHIP1 Y: %d", chip);
15365 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
15380 slits = cpl_table_new(1);
15381 cpl_table_new_column(slits,
"slit_id", CPL_TYPE_INT);
15382 cpl_table_new_column(slits,
"xtop", CPL_TYPE_DOUBLE);
15383 cpl_table_new_column(slits,
"ytop", CPL_TYPE_DOUBLE);
15384 cpl_table_new_column(slits,
"xbottom", CPL_TYPE_DOUBLE);
15385 cpl_table_new_column(slits,
"ybottom", CPL_TYPE_DOUBLE);
15386 cpl_table_set_column_unit(slits,
"xtop",
"pixel");
15387 cpl_table_set_column_unit(slits,
"ytop",
"pixel");
15388 cpl_table_set_column_unit(slits,
"xbottom",
"pixel");
15389 cpl_table_set_column_unit(slits,
"ybottom",
"pixel");
15391 slit_name = (
char *)cpl_propertylist_get_string(header,
15392 "ESO INS SLIT NAME");
15394 cpl_table_set(slits,
"ytop", 0, ytop);
15395 cpl_table_set(slits,
"ybottom", 0, ybottom);
15397 if (!strncmp(slit_name,
"lSlit0_3arcsec", 14)) {
15398 cpl_table_set_int(slits,
"slit_id", 0, 1);
15399 cpl_table_set(slits,
"xbottom", 0, -0.075);
15400 cpl_table_set(slits,
"xtop", 0, 0.075);
15402 else if (!strncmp(slit_name,
"lSlit0_4arcsec", 14)) {
15403 cpl_table_set_int(slits,
"slit_id", 0, 2);
15404 cpl_table_set(slits,
"xbottom", 0, 5.895);
15405 cpl_table_set(slits,
"xtop", 0, 6.105);
15407 else if (!strncmp(slit_name,
"lSlit0_5arcsec", 14)) {
15408 cpl_table_set_int(slits,
"slit_id", 0, 3);
15409 cpl_table_set(slits,
"xbottom", 0, -6.135);
15410 cpl_table_set(slits,
"xtop", 0, -5.865);
15412 else if (!strncmp(slit_name,
"lSlit0_7arcsec", 14)) {
15413 cpl_table_set_int(slits,
"slit_id", 0, 4);
15414 cpl_table_set(slits,
"xbottom", 0, 11.815);
15415 cpl_table_set(slits,
"xtop", 0, 12.185);
15417 else if (!strncmp(slit_name,
"lSlit1_0arcsec", 14)) {
15418 cpl_table_set_int(slits,
"slit_id", 0, 5);
15419 cpl_table_set(slits,
"xbottom", 0, -12.265);
15420 cpl_table_set(slits,
"xtop", 0, -11.735);
15422 else if (!strncmp(slit_name,
"lSlit1_3arcsec", 14)) {
15423 cpl_table_set_int(slits,
"slit_id", 0, 6);
15424 cpl_table_set(slits,
"xbottom", 0, 17.655);
15425 cpl_table_set(slits,
"xtop", 0, 18.345);
15427 else if (!strncmp(slit_name,
"lSlit1_6arcsec", 14)) {
15428 cpl_table_set_int(slits,
"slit_id", 0, 7);
15429 cpl_table_set(slits,
"xbottom", 0, -18.425);
15430 cpl_table_set(slits,
"xtop", 0, -17.575);
15432 else if (!strncmp(slit_name,
"lSlit2_0arcsec", 14)) {
15433 cpl_table_set_int(slits,
"slit_id", 0, 8);
15434 cpl_table_set(slits,
"xbottom", 0, 23.475);
15435 cpl_table_set(slits,
"xtop", 0, 24.525);
15437 else if (!strncmp(slit_name,
"lSlit2_5arcsec", 14)) {
15438 cpl_table_set_int(slits,
"slit_id", 0, 9);
15439 cpl_table_set(slits,
"xbottom", 0, -24.66);
15440 cpl_table_set(slits,
"xtop", 0, -23.34);
15443 cpl_msg_error(func,
"Invalid slit %s in keyword ESO INS SLIT NAME",
15445 cpl_error_set(func, CPL_ERROR_DATA_NOT_FOUND);
15446 cpl_table_delete(slits);
15470 const char *func =
"mos_get_gain_vimos";
15472 double gain = -1.0;
15475 if (cpl_error_get_code() != CPL_ERROR_NONE)
15478 if (header == NULL) {
15479 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
15483 gain = cpl_propertylist_get_double(header,
"ESO DET OUT1 CONAD");
15484 if (cpl_error_get_code()) {
15485 cpl_error_set_where(func);
15515 const char *func =
"mos_load_slits_vimos";
15518 char keyname[MAX_COLNAME];
15529 if (cpl_error_get_code() != CPL_ERROR_NONE) {
15533 if (header == NULL) {
15534 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
15538 nslits = cpl_propertylist_get_int(header,
"ESO INS SLIT NO");
15540 if (cpl_error_get_code() != CPL_ERROR_NONE) {
15541 cpl_error_set_where(func);
15545 slits = cpl_table_new(nslits);
15546 cpl_table_new_column(slits,
"slit_id", CPL_TYPE_INT);
15547 cpl_table_new_column(slits,
"xtop", CPL_TYPE_DOUBLE);
15548 cpl_table_new_column(slits,
"ytop", CPL_TYPE_DOUBLE);
15549 cpl_table_new_column(slits,
"xbottom", CPL_TYPE_DOUBLE);
15550 cpl_table_new_column(slits,
"ybottom", CPL_TYPE_DOUBLE);
15551 cpl_table_new_column(slits,
"xwidth", CPL_TYPE_DOUBLE);
15552 cpl_table_new_column(slits,
"ywidth", CPL_TYPE_DOUBLE);
15553 cpl_table_new_column(slits,
"curved", CPL_TYPE_INT);
15554 cpl_table_set_column_unit(slits,
"xtop",
"pixel");
15555 cpl_table_set_column_unit(slits,
"ytop",
"pixel");
15556 cpl_table_set_column_unit(slits,
"xbottom",
"pixel");
15557 cpl_table_set_column_unit(slits,
"ybottom",
"pixel");
15558 cpl_table_set_column_unit(slits,
"xwidth",
"mm");
15559 cpl_table_set_column_unit(slits,
"ywidth",
"mm");
15561 for (i = 0; i < nslits; i++) {
15562 sprintf(keyname,
"ESO INS SLIT%d ID", i+1);
15563 slit_id = cpl_propertylist_get_int(header, keyname);
15564 if (cpl_error_get_code() != CPL_ERROR_NONE) {
15565 cpl_error_set_where(func);
15568 sprintf(keyname,
"ESO INS SLIT%d X", i+1);
15569 slit_x = cpl_propertylist_get_double(header, keyname);
15570 if (cpl_error_get_code() != CPL_ERROR_NONE) {
15571 cpl_error_set_where(func);
15574 sprintf(keyname,
"ESO INS SLIT%d Y", i+1);
15575 slit_y = cpl_propertylist_get_double(header, keyname);
15576 if (cpl_error_get_code() != CPL_ERROR_NONE) {
15577 cpl_error_set_where(func);
15580 sprintf(keyname,
"ESO INS SLIT%d DIMX", i+1);
15581 dim_x = cpl_propertylist_get_double(header, keyname);
15582 if (cpl_error_get_code() != CPL_ERROR_NONE) {
15583 cpl_error_set_where(func);
15587 sprintf(keyname,
"ESO INS SLIT%d BEZIER DY", i+1);
15588 if (cpl_propertylist_has(header, keyname)) {
15592 sprintf(keyname,
"ESO INS SLIT%d DIMY", i+1);
15595 dim_y = cpl_propertylist_get_double(header, keyname);
15596 if (cpl_error_get_code() != CPL_ERROR_NONE) {
15597 cpl_error_set_where(func);
15601 cpl_table_set_int(slits,
"slit_id", i, slit_id);
15602 cpl_table_set(slits,
"xtop", i, slit_x - dim_x/2);
15603 cpl_table_set(slits,
"ytop", i, slit_y);
15604 cpl_table_set(slits,
"xbottom", i, slit_x + dim_x/2);
15605 cpl_table_set(slits,
"ybottom", i, slit_y);
15606 cpl_table_set(slits,
"xwidth", i, dim_x);
15607 cpl_table_set(slits,
"ywidth", i, dim_y);
15608 cpl_table_set_int(slits,
"curved", i, curved);
15626 cpl_propertylist *sort;
15628 int i, multiplex, xprev, xcur;
15630 double tolerance = 1.0;
15640 sort = cpl_propertylist_new();
15641 cpl_propertylist_append_bool(sort,
"xtop", 0);
15642 cpl_table_sort(slits, sort);
15643 cpl_propertylist_delete(sort);
15645 prev = cpl_table_get_double(slits,
"xtop", 0, NULL);
15646 cpl_table_new_column(slits,
"xind", CPL_TYPE_INT);
15647 cpl_table_set_int(slits,
"xind", 0, prev);
15648 nrow = cpl_table_get_nrow(slits);
15649 for (i = 1; i < nrow; i++) {
15650 cur = cpl_table_get_double(slits,
"xtop", i, NULL);
15651 if (fabs(prev - cur) > tolerance)
15653 cpl_table_set_int(slits,
"xind", i, prev);
15661 sort = cpl_propertylist_new();
15662 cpl_propertylist_append_bool(sort,
"xind", 0);
15663 cpl_propertylist_append_bool(sort,
"ytop", 0);
15664 cpl_table_sort(slits, sort);
15665 cpl_propertylist_delete(sort);
15672 cpl_table_new_column(slits,
"multiplex", CPL_TYPE_INT);
15673 xprev = cpl_table_get_int(slits,
"xind", 0, NULL);
15674 cpl_table_set_int(slits,
"multiplex", 0, multiplex);
15675 nrow = cpl_table_get_nrow(slits);
15676 for (i = 1; i < nrow; i++) {
15677 xcur = cpl_table_get_int(slits,
"xind", i, NULL);
15678 if (xcur == xprev) {
15685 cpl_table_set_int(slits,
"multiplex", i, multiplex);
15688 cpl_table_save(slits, NULL, NULL,
"multiplex.fits", CPL_IO_DEFAULT);
15690 cpl_table_erase_column(slits,
"xind");
15692 return 1 + cpl_table_get_column_max(slits,
"multiplex");
15724 int check_consistency)
15726 const char *func =
"mos_load_overscans_vimos";
15737 cpl_table *overscans;
15740 if (cpl_error_get_code() != CPL_ERROR_NONE) {
15741 cpl_msg_error(func,
"Reset your error: %s", cpl_error_get_message());
15745 if (header == NULL) {
15746 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
15750 if (cpl_propertylist_has(header,
"NAXIS1"))
15751 nx = cpl_propertylist_get_int(header,
"NAXIS1");
15752 if (cpl_propertylist_has(header,
"NAXIS2"))
15753 ny = cpl_propertylist_get_int(header,
"NAXIS2");
15754 if (cpl_propertylist_has(header,
"ESO DET OUT1 PRSCX"))
15755 px = cpl_propertylist_get_int(header,
"ESO DET OUT1 PRSCX");
15756 if (cpl_propertylist_has(header,
"ESO DET OUT1 PRSCY"))
15757 py = cpl_propertylist_get_int(header,
"ESO DET OUT1 PRSCY");
15758 if (cpl_propertylist_has(header,
"ESO DET OUT1 OVSCX"))
15759 ox = cpl_propertylist_get_int(header,
"ESO DET OUT1 OVSCX");
15760 if (cpl_propertylist_has(header,
"ESO DET OUT1 OVSCY"))
15761 oy = cpl_propertylist_get_int(header,
"ESO DET OUT1 OVSCY");
15762 if (cpl_propertylist_has(header,
"ESO DET OUT1 NX"))
15763 vx = cpl_propertylist_get_int(header,
"ESO DET OUT1 NX");
15764 if (cpl_propertylist_has(header,
"ESO DET OUT1 NY"))
15765 vy = cpl_propertylist_get_int(header,
"ESO DET OUT1 NY");
15767 if (cpl_error_get_code() != CPL_ERROR_NONE) {
15768 cpl_msg_error(func,
"Missing overscan keywords in header");
15769 cpl_error_set_where(func);
15773 if (px < 0 || py < 0 || ox < 0 || oy < 0) {
15774 cpl_msg_error(func,
"Missing overscan keywords in header");
15775 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
15779 if ((px + vx + ox != nx) || (py + vy + oy != ny)) {
15780 if (check_consistency) {
15781 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
15785 cpl_msg_debug(func,
"Overscans description conflicts with "
15786 "reported image sizes, "
15787 "%d + %d + %d != %d or "
15788 "%d + %d + %d != %d",
15805 cpl_msg_error(func,
"Unexpected overscan regions "
15806 "(both in X and Y direction)");
15807 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
15819 overscans = cpl_table_new(nrows);
15820 cpl_table_new_column(overscans,
"xlow", CPL_TYPE_INT);
15821 cpl_table_new_column(overscans,
"ylow", CPL_TYPE_INT);
15822 cpl_table_new_column(overscans,
"xhig", CPL_TYPE_INT);
15823 cpl_table_new_column(overscans,
"yhig", CPL_TYPE_INT);
15827 cpl_table_set_int(overscans,
"xlow", nrows, px);
15828 cpl_table_set_int(overscans,
"ylow", nrows, py);
15829 cpl_table_set_int(overscans,
"xhig", nrows, nx - ox);
15830 cpl_table_set_int(overscans,
"yhig", nrows, ny - oy);
15834 cpl_table_set_int(overscans,
"xlow", nrows, 0);
15835 cpl_table_set_int(overscans,
"ylow", nrows, 0);
15836 cpl_table_set_int(overscans,
"xhig", nrows, px);
15837 cpl_table_set_int(overscans,
"yhig", nrows, ny);
15842 cpl_table_set_int(overscans,
"xlow", nrows, nx - ox);
15843 cpl_table_set_int(overscans,
"ylow", nrows, 0);
15844 cpl_table_set_int(overscans,
"xhig", nrows, nx);
15845 cpl_table_set_int(overscans,
"yhig", nrows, ny);
15850 cpl_table_set_int(overscans,
"xlow", nrows, 0);
15851 cpl_table_set_int(overscans,
"ylow", nrows, 0);
15852 cpl_table_set_int(overscans,
"xhig", nrows, nx);
15853 cpl_table_set_int(overscans,
"yhig", nrows, py);
15858 cpl_table_set_int(overscans,
"xlow", nrows, 0);
15859 cpl_table_set_int(overscans,
"ylow", nrows, ny - oy);
15860 cpl_table_set_int(overscans,
"xhig", nrows, nx);
15861 cpl_table_set_int(overscans,
"yhig", nrows, ny);
15870 cpl_table *mos_load_overscans_fors(
const cpl_propertylist *header)
15872 const char *func =
"mos_load_overscans_fors";
15883 cpl_table *overscans;
15886 if (cpl_error_get_code() != CPL_ERROR_NONE) {
15887 cpl_msg_error(func,
"Reset your error: %s", cpl_error_get_message());
15891 if (header == NULL) {
15892 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
15896 if (cpl_propertylist_has(header,
"ESO DET OUTPUTS"))
15897 nports = cpl_propertylist_get_int(header,
"ESO DET OUTPUTS");
15900 cpl_propertylist_has(header,
"ESO DET OUT1 PRSCX") &&
15901 cpl_propertylist_has(header,
"ESO DET WIN1 BINX")) {
15903 rebin = cpl_propertylist_get_int(header,
"ESO DET WIN1 BINX");
15905 overscans = cpl_table_new(3);
15906 cpl_table_new_column(overscans,
"xlow", CPL_TYPE_INT);
15907 cpl_table_new_column(overscans,
"ylow", CPL_TYPE_INT);
15908 cpl_table_new_column(overscans,
"xhig", CPL_TYPE_INT);
15909 cpl_table_new_column(overscans,
"yhig", CPL_TYPE_INT);
15917 cpl_table_set_int(overscans,
"xlow", nrows, px);
15918 cpl_table_set_int(overscans,
"ylow", nrows, py);
15919 cpl_table_set_int(overscans,
"xhig", nrows, nx - ox);
15920 cpl_table_set_int(overscans,
"yhig", nrows, ny - oy);
15923 cpl_table_set_int(overscans,
"xlow", nrows, 0);
15924 cpl_table_set_int(overscans,
"ylow", nrows, 0);
15925 cpl_table_set_int(overscans,
"xhig", nrows, px);
15926 cpl_table_set_int(overscans,
"yhig", nrows, ny);
15929 cpl_table_set_int(overscans,
"xlow", nrows, nx - ox);
15930 cpl_table_set_int(overscans,
"ylow", nrows, 0);
15931 cpl_table_set_int(overscans,
"xhig", nrows, nx);
15932 cpl_table_set_int(overscans,
"yhig", nrows, ny);
15977 cpl_polynomial *mos_montecarlo_polyfit(cpl_table *points, cpl_table *evaluate,
15978 int samples,
int order)
15981 const char *func =
"mos_montecarlo_polyfit";
15995 int npoints, nevaluate;
15999 if (points == NULL || evaluate == NULL) {
16000 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
16004 if (!cpl_table_has_column(points,
"x")) {
16005 cpl_error_set(func, CPL_ERROR_DATA_NOT_FOUND);
16009 if (cpl_table_get_column_type(points,
"x") != CPL_TYPE_DOUBLE) {
16010 cpl_error_set(func, CPL_ERROR_INVALID_TYPE);
16014 if (cpl_table_has_invalid(points,
"x")) {
16015 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
16019 if (!cpl_table_has_column(points,
"y")) {
16020 cpl_error_set(func, CPL_ERROR_DATA_NOT_FOUND);
16024 if (cpl_table_get_column_type(points,
"y") != CPL_TYPE_DOUBLE) {
16025 cpl_error_set(func, CPL_ERROR_INVALID_TYPE);
16029 if (cpl_table_has_invalid(points,
"y")) {
16030 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
16034 if (cpl_table_has_column(points,
"y_err")) {
16036 if (cpl_table_get_column_type(points,
"y_err") != CPL_TYPE_DOUBLE) {
16037 cpl_error_set(func, CPL_ERROR_INVALID_TYPE);
16041 if (cpl_table_has_invalid(points,
"y_err")) {
16042 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
16047 if (!cpl_table_has_column(evaluate,
"x")) {
16048 cpl_error_set(func, CPL_ERROR_DATA_NOT_FOUND);
16052 if (cpl_table_get_column_type(evaluate,
"x") != CPL_TYPE_DOUBLE) {
16053 cpl_error_set(func, CPL_ERROR_INVALID_TYPE);
16057 if (cpl_table_has_invalid(evaluate,
"x")) {
16058 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
16062 if (samples < 2 || order < 0) {
16063 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
16067 npoints = cpl_table_get_nrow(points);
16068 listx = cpl_vector_wrap(npoints, cpl_table_get_data_double(points,
"x"));
16069 listy = cpl_vector_wrap(npoints, cpl_table_get_data_double(points,
"y"));
16071 p = cpl_polynomial_fit_1d_create(listx, listy, order, &err);
16073 if (!cpl_table_has_column(points,
"y_err")) {
16075 cpl_table_new_column(points,
"y_err", CPL_TYPE_DOUBLE);
16076 cpl_table_fill_column_window_double(points,
"y_err", 0, npoints, err);
16077 cpl_msg_info(func,
"Error column not found - set to %f\n", err);
16084 if (cpl_table_has_column(points,
"px"))
16085 cpl_table_erase_column(points,
"px");
16086 cpl_table_new_column(points,
"px", CPL_TYPE_DOUBLE);
16087 cpl_table_fill_column_window_double(points,
"px", 0, npoints, 0);
16088 x = cpl_table_get_data_double(points,
"x");
16089 px = cpl_table_get_data_double(points,
"px");
16090 for (i = 0; i < npoints; i++)
16091 px[i] = cpl_polynomial_eval_1d(p, x[i], NULL);
16093 nevaluate = cpl_table_get_nrow(evaluate);
16095 if (cpl_table_has_column(evaluate,
"px"))
16096 cpl_table_erase_column(evaluate,
"px");
16097 cpl_table_new_column(evaluate,
"px", CPL_TYPE_DOUBLE);
16098 cpl_table_fill_column_window_double(evaluate,
"px", 0, nevaluate, 0);
16099 x_eval = cpl_table_get_data_double(evaluate,
"x");
16100 px_eval = cpl_table_get_data_double(evaluate,
"px");
16101 for (i = 0; i < nevaluate; i++)
16102 px_eval[i] = cpl_polynomial_eval_1d(p, x_eval[i], NULL);
16108 if (cpl_table_has_column(evaluate,
"sigma"))
16109 cpl_table_erase_column(evaluate,
"sigma");
16110 cpl_table_new_column(evaluate,
"sigma", CPL_TYPE_DOUBLE);
16111 cpl_table_fill_column_window_double(evaluate,
"sigma", 0, nevaluate, 0);
16112 sigma = cpl_table_get_data_double(evaluate,
"sigma");
16118 if (cpl_table_has_column(points,
"vy"))
16119 cpl_table_erase_column(points,
"vy");
16120 cpl_table_new_column(points,
"vy", CPL_TYPE_DOUBLE);
16121 cpl_table_fill_column_window_double(points,
"vy", 0, npoints, 0);
16122 vy = cpl_table_get_data_double(points,
"vy");
16123 dy = cpl_table_get_data_double(points,
"y_err");
16124 cpl_vector_unwrap(listy);
16125 listy = cpl_vector_wrap(npoints, vy);
16127 for (i = 0; i < samples; i++) {
16128 for (j = 0; j < npoints; j++)
16129 vy[j] = px[j] + dy[j] * mos_randg(1);
16130 q = cpl_polynomial_fit_1d_create(listx, listy, order, NULL);
16131 for (j = 0; j < nevaluate; j++)
16132 sigma[j] += fabs(px_eval[j]
16133 - cpl_polynomial_eval_1d(q, x_eval[j], NULL));
16134 cpl_polynomial_delete(q);
16141 cpl_table_multiply_scalar(evaluate,
"sigma", 1.25);
16142 cpl_table_divide_scalar(evaluate,
"sigma", samples);
16144 cpl_vector_unwrap(listx);
16145 cpl_vector_unwrap(listy);
16175 double gain,
double bias)
16182 return cpl_error_set(cpl_func, CPL_ERROR_NULL_INPUT);
16184 if (ron < 0.0 || gain <= FLT_EPSILON)
16185 return cpl_error_set(cpl_func, CPL_ERROR_ILLEGAL_INPUT);
16187 data = cpl_image_get_data_float(image);
16188 npix = cpl_image_get_size_x(image) * cpl_image_get_size_y(image);
16191 for (i = 0; i < npix; i++) {
16192 if (data[i] < bias) {
16193 data[i] += sqrt(ron) * mos_randg(1);
16196 data[i] += sqrt(ron + (data[i] - bias) / gain) * mos_randg(1);
16200 return CPL_ERROR_NONE;
16219 cpl_image *master_flat,
16222 int nx = cpl_mask_get_size_x(refmask);
16223 int ny = cpl_mask_get_size_y(refmask);
16225 int * xpos = cpl_calloc(
sizeof(
int), ny);
16227 cpl_image * filtered = cpl_image_duplicate(master_flat);
16228 cpl_mask * kernel = cpl_mask_new(9, 3);
16229 cpl_vector * v = cpl_vector_new(ny);
16230 cpl_vector * truev;
16232 double * flats = cpl_vector_get_data(v);
16234 double median, stdev, delta;
16238 cpl_mask_not(kernel);
16239 cpl_image_filter_mask(filtered, master_flat, kernel,
16240 CPL_FILTER_MEDIAN, CPL_BORDER_COPY);
16241 cpl_mask_delete(kernel);
16243 for (i = 1; i <= ny; i++) {
16247 while (!cpl_mask_get(refmask, j, i) && j < nx);
16253 flats[nvalid] = cpl_image_get(filtered, j, i, &rejected);
16262 return cpl_error_set(cpl_func, CPL_ERROR_DATA_NOT_FOUND);
16264 truev = cpl_vector_wrap(nvalid, flats);
16266 median = cpl_vector_get_median(truev);
16269 stdev = cpl_vector_get_stdev(truev);
16271 cpl_vector_unwrap(truev);
16272 cpl_vector_delete(v);
16274 for (i = 1; i <= ny; i++) {
16275 if (xpos[i - 1] > 0) {
16277 double kappa = 1.5;
16279 delta = cpl_image_get(filtered, xpos[i - 1], i, &rejected) - median;
16282 kill = fabs(delta) > stdev * kappa;
16284 kill = delta < level;
16289 while (cpl_mask_get(refmask, xpos[i - 1] + j, i)) {
16290 cpl_mask_set(refmask, xpos[i - 1] + j, i, CPL_BINARY_0);
16297 cpl_image_delete(filtered);
16300 return cpl_error_get_code();
16312 int nx = cpl_image_get_size_x(image);
16313 int ny = cpl_image_get_size_y(image);
16314 int npix = nx * ny;
16315 float * sdata = cpl_image_get_data_float(image);
16317 int count, i, j, k;
16341 for (i = 0; i < npix; i++) {
16342 if (sdata[i] >= 65535.0) {
16344 for (j = i; j < npix; j++) {
16345 if (sdata[j] < 65535.0) {
16352 if (count < 30 && count > 2) {
16353 for (j = i; j < i + count/2; j++)
16354 sdata[j] = sdata[i] + 1000.0 * (j - i);
16355 if (count % 2 != 0) {
16356 sdata[j] = sdata[j-1] + 1000.0;
16359 for (k = j; k <= i + count; k++)
16360 sdata[k] = sdata[i] - 1000.0 * (k - i - count);
16366 return cpl_error_get_code();
16385 cpl_image_subtract(image, bimage);
16386 cpl_image_delete(bimage);
16388 return cpl_error_get_code();
16409 int nscience,
float tolerance)
16413 cpl_table *summary;
16414 int summary_nobjs = 0;
16419 int nslits = cpl_table_get_nrow(slitss[0]);
16423 int nstokes, sstokes;
16427 work = (cpl_table **)cpl_malloc(
sizeof(cpl_table *) * nscience);
16438 for (j = 0; j < nscience; j++) {
16441 return cpl_error_set(cpl_func, CPL_ERROR_DATA_NOT_FOUND);
16442 summary_nobjs += c_nobjs;
16445 summary = cpl_table_new(summary_nobjs);
16447 cpl_table_new_column(summary,
"offset", CPL_TYPE_DOUBLE);
16448 cpl_table_new_column(summary,
"pair", CPL_TYPE_INT);
16449 cpl_table_new_column(summary,
"absolute", CPL_TYPE_DOUBLE);
16450 cpl_table_new_column(summary,
"pos", CPL_TYPE_DOUBLE);
16459 for (j = 0; j < nscience; j++) {
16463 for (k = 0; k < nslits; k++) {
16466 for (m = 0; m < c_maxobjs; m++) {
16468 char *name = cpl_sprintf(
"object_%d", m + 1);
16469 double obj = cpl_table_get_double(slitss[j], name, k, &null);
16485 pos = cpl_table_get_int(slitss[j],
"position", k, &null);
16486 pair = cpl_table_get_int(slitss[j],
"pair_id", k, &null);
16487 cpl_table_set(summary,
"absolute", nobjs, obj);
16488 cpl_table_set(summary,
"pos", nobjs, pos);
16489 cpl_table_set(summary,
"offset", nobjs, obj - pos);
16490 cpl_table_set(summary,
"pair", nobjs, pair);
16520 for (k = 0; k < nslits; k+=2) {
16521 int slitmatches = 0;
16523 if (k + 1 < nslits ) {
16524 if (cpl_table_get_int(slitss[0],
"pair_id", k, NULL) !=
16525 cpl_table_get_int(slitss[0],
"pair_id", k + 1, NULL)) {
16538 for (m = 0; m < maxobjs; m++) {
16540 char *name = cpl_sprintf(
"object_%d", m + 1);
16541 double obj = cpl_table_get_double(slitss[0], name, k, &null);
16545 char *name_obj = NULL;
16546 char *name_start = NULL;
16547 char *name_end = NULL;
16548 char *name_row = NULL;
16549 char *name_row_s = NULL;
16551 char *name_start_o = NULL;
16552 char *name_end_o = NULL;
16553 char *name_row_o = NULL;
16554 char *name_start_v = NULL;
16555 char *name_end_v = NULL;
16556 char *name_obj_v = NULL;
16562 int v, start_v, end_v;
16563 double min_v, obj_v;
16578 pos = cpl_table_get_int(slitss[0],
"position", k, &null);
16579 pair = cpl_table_get_int(slitss[0],
"pair_id", k, &null);
16588 cpl_table_select_all(summary);
16590 cpl_table_and_selected_int(summary,
"pair", CPL_EQUAL_TO, pair);
16591 cpl_table_and_selected_double(summary,
"offset", CPL_LESS_THAN,
16592 obj - pos + tolerance);
16594 cpl_table_and_selected_double(summary,
"offset", CPL_GREATER_THAN,
16595 obj - pos - tolerance);
16605 if (selected != nscience * 2)
16626 name_obj = cpl_sprintf(
"object_%d", slitmatches);
16627 name_start = cpl_sprintf(
"start_%d", slitmatches);
16628 name_end = cpl_sprintf(
"end_%d", slitmatches);
16629 name_row = cpl_sprintf(
"row_%d", slitmatches);
16630 name_row_s = cpl_sprintf(
"row_stokes_%d", slitmatches);
16637 name_start_o = cpl_sprintf(
"start_%d", m + 1);
16638 name_end_o = cpl_sprintf(
"end_%d", m + 1);
16639 name_row_o = cpl_sprintf(
"row_%d", m + 1);
16645 if (!cpl_table_has_column(origslits, name_obj)) {
16646 cpl_table_new_column(origslits, name_obj, CPL_TYPE_DOUBLE);
16647 cpl_table_new_column(origslits, name_start, CPL_TYPE_INT);
16648 cpl_table_new_column(origslits, name_end, CPL_TYPE_INT);
16649 cpl_table_new_column(origslits, name_row, CPL_TYPE_INT);
16650 cpl_table_new_column(origslits, name_row_s, CPL_TYPE_INT);
16660 length = cpl_table_get_int(origslits,
"length", k + 1, &null);
16668 for (v = 0; v < maxobjs; v++) {
16669 char *name_v = cpl_sprintf(
"object_%d", v + 1);
16670 double obj_v = cpl_table_get_double(slitss[0], name_v,
16679 if (fabs(obj - length - obj_v) < min_v) {
16680 min_v = fabs(obj - length - obj_v);
16681 cpl_free(name_start_v);
16682 cpl_free(name_end_v);
16683 cpl_free(name_obj_v);
16684 name_start_v = cpl_sprintf(
"start_%d", v + 1);
16685 name_end_v = cpl_sprintf(
"end_%d", v + 1);
16686 name_obj_v = cpl_sprintf(
"object_%d", v + 1);
16690 min_v = fabs(obj - length - obj_v);
16691 name_start_v = cpl_sprintf(
"start_%d", v + 1);
16692 name_end_v = cpl_sprintf(
"end_%d", v + 1);
16693 name_obj_v = cpl_sprintf(
"object_%d", v + 1);
16702 start = cpl_table_get_int(slitss[0], name_start_o, k, &null);
16703 end = cpl_table_get_int(slitss[0], name_end_o, k, &null);
16709 start_v = cpl_table_get_int(slitss[0], name_start_v, k + 1, &null);
16710 end_v = cpl_table_get_int(slitss[0], name_end_v, k + 1, &null);
16711 obj_v = cpl_table_get_double(slitss[0], name_obj_v, k + 1, &null);
16722 cpl_table_set_double(origslits, name_obj, k, obj);
16723 cpl_table_set_double(origslits, name_obj, k + 1, obj_v);
16726 cpl_table_set_int(origslits, name_start, k, start);
16727 cpl_table_set_int(origslits, name_start, k + 1, start_v);
16730 cpl_table_set_int(origslits, name_end, k, end);
16731 cpl_table_set_int(origslits, name_end, k + 1, end_v);
16746 cpl_table_set_int(origslits, name_row, k, nmatches);
16748 cpl_table_set_int(origslits, name_row, k + 1, nmatches);
16751 cpl_free(name_obj);
16752 cpl_free(name_start);
16753 cpl_free(name_end);
16754 cpl_free(name_row);
16755 cpl_free(name_row_s);
16757 cpl_free(name_start_o);
16758 cpl_free(name_end_o);
16759 cpl_free(name_row_o);
16761 cpl_free(name_start_v); name_start_v = NULL;
16762 cpl_free(name_end_v); name_end_v = NULL;
16763 cpl_free(name_obj_v); name_obj_v = NULL;
16772 cpl_table_delete(summary);
16775 return cpl_error_set(cpl_func, CPL_ERROR_DATA_NOT_FOUND);
16788 nstokes = nmatches / 2;
16790 for (k = 0; k < nslits; k++) {
16798 for (m = 0; m < maxobjs; m++) {
16799 char *name = cpl_sprintf(
"row_%d", m + 1);
16800 char *namestokes = cpl_sprintf(
"row_stokes_%d", m + 1);
16802 if (!cpl_table_is_valid(origslits, name, k)) {
16804 cpl_free(namestokes);
16810 cpl_table_set_int(origslits, name, k, nmatches);
16811 cpl_table_set_int(origslits, namestokes, k, nstokes);
16815 cpl_free(namestokes);
16827 for (j = 0; j < maxobjs; j++) {
16828 char *name = cpl_sprintf(
"object_%d", j + 1);
16829 cpl_table_fill_invalid_double(origslits, name, -1);
16832 name = cpl_sprintf(
"start_%d", j + 1);
16833 cpl_table_fill_invalid_int(origslits, name, -1);
16836 name = cpl_sprintf(
"end_%d", j + 1);
16837 cpl_table_fill_invalid_int(origslits, name, -1);
16840 name = cpl_sprintf(
"row_%d", j + 1);
16841 cpl_table_fill_invalid_int(origslits, name, -1);
16844 name = cpl_sprintf(
"row_stokes_%d", j + 1);
16845 cpl_table_fill_invalid_int(origslits, name, -1);
16860 for (i = 0; i < nscience; i++) {
16863 work[i] = cpl_table_duplicate(slitss[i]);
16865 for (m = 0; m < c_maxobjs; m++) {
16866 char *object_o = cpl_sprintf(
"object_%d", m + 1);
16867 char *start_o = cpl_sprintf(
"start_%d", m + 1);
16868 char *end_o = cpl_sprintf(
"end_%d", m + 1);
16869 char *row_o = cpl_sprintf(
"row_%d", m + 1);
16871 cpl_table_erase_column(slitss[i], object_o);
16872 cpl_table_erase_column(slitss[i], start_o);
16873 cpl_table_erase_column(slitss[i], end_o);
16874 cpl_table_erase_column(slitss[i], row_o);
16882 for (k = 0; k < nslits; k++) {
16883 for (j = 0; j < maxobjs; j++) {
16884 double object_w, object_r;
16887 char *object_i = cpl_sprintf(
"object_%d", j + 1);
16888 char *start_i = cpl_sprintf(
"start_%d", j + 1);
16889 char *end_i = cpl_sprintf(
"end_%d", j + 1);
16890 char *row_i = cpl_sprintf(
"row_%d", j + 1);
16893 if (!cpl_table_is_valid(origslits, object_i, k))
16906 object_w = cpl_table_get_double(origslits, object_i, k, NULL);
16907 row_w = cpl_table_get_int (origslits, row_i, k, NULL);
16909 for (i = 0; i < nscience; i++) {
16912 double mindiff, diff;
16918 for (m = 0; m < c_maxobjs; m++) {
16919 object_o = cpl_sprintf(
"object_%d", m + 1);
16920 start_o = cpl_sprintf(
"start_%d", m + 1);
16921 end_o = cpl_sprintf(
"end_%d", m + 1);
16922 row_o = cpl_sprintf(
"row_%d", m + 1);
16924 if (!cpl_table_is_valid(work[i], object_o, k))
16927 object_r = cpl_table_get_double(work[i], object_o, k, NULL);
16930 diff = fabs(object_w - object_r);
16932 if (mindiff > diff) {
16942 cpl_free(object_o);
16948 object_o = cpl_sprintf(
"object_%d", minpos + 1);
16949 start_o = cpl_sprintf(
"start_%d", minpos + 1);
16950 end_o = cpl_sprintf(
"end_%d", minpos + 1);
16951 row_o = cpl_sprintf(
"row_%d", minpos + 1);
16953 if (!cpl_table_has_column(slitss[i], object_i)) {
16954 cpl_table_new_column(slitss[i], object_i, CPL_TYPE_DOUBLE);
16955 cpl_table_new_column(slitss[i], start_i, CPL_TYPE_INT);
16956 cpl_table_new_column(slitss[i], end_i, CPL_TYPE_INT);
16957 cpl_table_new_column(slitss[i], row_i, CPL_TYPE_INT);
16958 cpl_table_fill_invalid_double(slitss[i], object_i, -1);
16959 cpl_table_fill_invalid_int (slitss[i], start_i, -1);
16960 cpl_table_fill_invalid_int (slitss[i], end_i, -1);
16961 cpl_table_fill_invalid_int (slitss[i], row_i, -1);
16964 cpl_table_set_double(slitss[i], object_i, k,
16965 cpl_table_get_double(work[i], object_o,
16967 cpl_table_set_int(slitss[i], start_i , k,
16968 cpl_table_get_int(work[i], start_o, k, NULL));
16969 cpl_table_set_int(slitss[i], end_i , k,
16970 cpl_table_get_int(work[i], end_o, k, NULL));
16971 cpl_table_set_int(slitss[i], row_i , k, row_w);
16973 cpl_free(object_o);
16979 cpl_free(object_i);
16986 for (i = 0; i < nscience; i++)
16987 cpl_table_delete(work[i]);
16992 return cpl_error_get_code();
17007 char * colname = cpl_sprintf(
"object_%d", maxobjs);
17009 while (cpl_table_has_column(slits, colname)) {
17012 colname = cpl_sprintf(
"object_%d", maxobjs);
17033 int nslits = cpl_table_get_nrow(slits);
17038 for (k = 0; k < nslits; k++) {
17039 for (m = 0; m < maxobjs; m++) {
17040 char * name = cpl_sprintf(
"object_%d", m + 1);
17041 int null = !cpl_table_is_valid(slits, name, k);
17063 cpl_propertylist *sort;
17065 int nslits = cpl_table_get_nrow(slits);
17069 const float interval = 90.0 * rescale;
17070 const float offset = (90.0 - 5) * rescale;
17073 for (k = 0; k < nslits; k++) {
17074 double ytop = cpl_table_get_double(slits,
"ytop", k, &null);
17075 double ybottom = cpl_table_get_double(slits,
"ybottom", k, &null);
17077 double xtop = cpl_table_get_double(slits,
"xtop", k, &null);
17078 double xbottom = cpl_table_get_double(slits,
"xbottom", k, &null);
17080 int nmiss = (int)((ytop - ybottom) / interval + 0.5);
17083 cpl_msg_warning(cpl_func,
17084 "Some slits could not be properly detected. "
17085 "There might be accountable inaccuracies.");
17086 while (nmiss > 1) {
17087 cpl_table_set_size(slits, nslits + 1);
17092 cpl_table_set_double(slits,
"xtop", nslits, xtop);
17093 cpl_table_set_double(slits,
"xbottom", nslits, xbottom);
17097 cpl_table_set_double(slits,
"ybottom", nslits, ybottom);
17098 cpl_table_set_double(slits,
"ytop", nslits, ybottom
17100 ybottom += interval;
17101 cpl_table_set_double(slits,
"ybottom", k, ybottom);
17103 cpl_table_set_double(slits,
"ytop", nslits, ytop);
17104 cpl_table_set_double(slits,
"ybottom", nslits, ytop
17107 cpl_table_set_double(slits,
"ytop", k, ytop);
17115 sort = cpl_propertylist_new();
17116 cpl_propertylist_append_bool(sort,
"ytop", 1);
17117 cpl_table_sort(slits, sort);
17118 cpl_propertylist_delete(sort);
17125 k = cpl_table_get_nrow(slits) - 1;
17128 double ytop = cpl_table_get_double(slits,
"ytop", k, &null);
17129 double ybottom = cpl_table_get_double(slits,
"ybottom", k, &null);
17130 double length = (ytop - ybottom) / interval;
17132 if (length > 1.1) {
17133 cpl_table_set_double(slits,
"ybottom", k, ytop - offset);
17164 int * nslits_out_det)
17169 cpl_propertylist * sort;
17173 halfsize = cpl_table_get_nrow(slits);
17175 cpl_table_set_size(slits, 2 * halfsize);
17177 for (m = 0; m < halfsize; m++) {
17182 cpl_table_get(slits,
"ytop", m, &null) -
17183 cpl_table_get(slits,
"ybottom", m, &null);
17187 cpl_table_get(slits,
"ybottom", m - 1, &null) -
17188 cpl_table_get(slits,
"ytop", m, &null);
17190 gap = (interval - length) / 2;
17193 cpl_table_set(slits,
"slit_id", m + halfsize,
17194 cpl_table_get(slits,
"slit_id", m, &null) - 1);
17196 cpl_table_set(slits,
"xtop", m + halfsize,
17197 cpl_table_get(slits,
"xtop", m, &null));
17199 cpl_table_set(slits,
"xbottom", m + halfsize,
17200 cpl_table_get(slits,
"xbottom", m, &null));
17202 cpl_table_set(slits,
"ytop", m + halfsize,
17203 cpl_table_get(slits,
"ytop", m, &null) + gap + length);
17205 cpl_table_set(slits,
"ybottom", m + halfsize,
17206 cpl_table_get(slits,
"ytop", m, &null) + gap);
17209 for (m = 0; m < 2 * halfsize; m++) {
17210 cpl_table_set(slits,
"ytop", m,
17211 cpl_table_get(slits,
"ytop", m, &null) - 5.3);
17213 cpl_table_set(slits,
"ybottom", m,
17214 cpl_table_get(slits,
"ybottom", m, &null) - 5.3);
17218 sort = cpl_propertylist_new();
17219 cpl_propertylist_append_bool(sort,
"ytop", 1);
17220 cpl_table_sort(slits, sort);
17222 cpl_propertylist_delete(sort);
17227 int * fors_get_nobjs_perslit(cpl_table * slits)
17229 int nslits = cpl_table_get_nrow(slits);
17232 int * nobjs_per_slit = cpl_malloc(
sizeof(
int) * nslits);
17236 for (k = 0; k < nslits; k++) {
17238 for (m = 0; m < maxobjs; m++) {
17239 char * name = cpl_sprintf(
"object_%d", m + 1);
17240 int null = !cpl_table_is_valid(slits, name, k);
17248 nobjs_per_slit[k] = nobjs;
17251 return nobjs_per_slit;
17254 double fors_get_object_position(cpl_table *slits,
int slit,
int object)
17256 char *name = cpl_sprintf(
"object_%d",
object);
17259 position = cpl_table_get_double(slits, name, slit, NULL)
17260 - cpl_table_get_int(slits,
"position", slit, NULL);
17267 int mos_rebin_signal(cpl_image **image,
int rebin)
17269 cpl_image *rebinned;
17272 if (*image == NULL)
17278 rebinned = cpl_image_rebin(*image, 1, 1, rebin, 1);
17280 cpl_image_delete(*image);
17287 int mos_rebin_error(cpl_image **image,
int rebin)
17289 if (*image == NULL)
17295 cpl_image_power(*image, 2);
17296 mos_rebin_signal(image, rebin);
17297 cpl_image_power(*image, 0.5);
17319 int map_table(cpl_image *image,
double start,
double step,
17320 cpl_table *table,
const char *xname,
const char *yname)
17322 int length = cpl_image_get_size_x(image);
17323 int nrows = cpl_table_get_nrow(table);
17324 float *data = cpl_image_get_data_float(image);
17325 float *fdata = NULL;
17326 double *xdata = NULL;
17327 double *ydata = NULL;
17328 cpl_type xtype = cpl_table_get_column_type(table, xname);
17329 cpl_type ytype = cpl_table_get_column_type(table, yname);
17339 for (i = 0; i < length; i++)
17347 if (xtype == CPL_TYPE_FLOAT) {
17348 fdata = cpl_table_get_data_float(table, xname);
17349 xdata = cpl_malloc(nrows *
sizeof(
double));
17350 for (i = 0; i < nrows; i++) {
17351 xdata[i] = fdata[i];
17355 xdata = cpl_table_get_data_double(table, xname);
17358 if (ytype == CPL_TYPE_FLOAT) {
17359 fdata = cpl_table_get_data_float(table, yname);
17360 ydata = cpl_malloc(nrows *
sizeof(
double));
17361 for (i = 0; i < nrows; i++) {
17362 ydata[i] = fdata[i];
17366 ydata = cpl_table_get_data_double(table, yname);
17376 for (i = 0; i < length; i++) {
17377 pos = start + step * i;
17380 for (j = n; j < nrows; j++) {
17381 if (xdata[j] > pos) {
17383 data[i] = ydata[j-1]
17384 + (ydata[j] - ydata[j-1])
17385 * (pos - xdata[j-1]) / (xdata[j] - xdata[j-1]);
17391 if (xtype == CPL_TYPE_FLOAT)
17394 if (ytype == CPL_TYPE_FLOAT)
17414 static cpl_image *polysmooth(cpl_image *image,
int order,
int hw)
17421 cpl_polynomial *poly;
17422 cpl_vector *ysmooth;
17423 cpl_image *smoothed;
17428 npoints = cpl_image_get_size_x(image);
17430 if (2 * hw + 1 > npoints)
17433 x = cpl_vector_new(npoints);
17434 y = cpl_vector_new(npoints);
17435 xdata = cpl_vector_get_data(x);
17436 ydata = cpl_vector_get_data(y);
17438 smoothed = cpl_image_duplicate(image);
17439 sdata = cpl_image_get_data_float(smoothed);
17441 for (i = 0; i < npoints; i++) {
17443 ydata[i] = sdata[i];
17446 ysmooth = cpl_vector_filter_median_create(y, hw);
17447 cpl_vector_delete(y);
17449 poly = cpl_polynomial_fit_1d_create(x, ysmooth, order, NULL);
17450 cpl_vector_delete(x);
17451 cpl_vector_delete(ysmooth);
17454 for (i = 0; i < npoints; i++)
17455 sdata[i] = cpl_polynomial_eval_1d(poly, i, NULL);
17457 cpl_polynomial_delete(poly);
17460 cpl_image_delete(smoothed);
17470 cpl_image_delete(spectrum); \
17471 cpl_image_delete(flux); \
17472 cpl_image_delete(efficiency); \
17473 cpl_image_delete(smo_efficiency); \
17474 cpl_image_delete(extinction); \
17475 cpl_image_delete(response); \
17476 cpl_image_delete(smo_response); \
17477 cpl_image_delete(physical); \
17504 double dispersion,
double gain,
17505 double exptime, cpl_table *ext_table,
17506 double airmass, cpl_table *flux_table,
17510 cpl_image *spectrum = NULL;
17512 cpl_image *extinction = NULL;
17514 cpl_image *flux = NULL;
17516 cpl_image *physical = NULL;
17518 cpl_image *efficiency = NULL;
17520 cpl_image *smo_efficiency = NULL;
17521 float *smo_eff_data;
17522 cpl_image *response = NULL;
17524 cpl_image *smo_response = NULL;
17525 float *smo_res_data;
17527 cpl_image *smo_image;
17531 int ext_count, ext_pos;
17532 int eff_count, eff_pos;
17533 int flux_count, flux_pos;
17538 if (spectra == NULL || ext_table == NULL || flux_table == NULL) {
17539 cpl_error_set(cpl_func, CPL_ERROR_NULL_INPUT);
17543 if (!cpl_table_has_column(ext_table,
"WAVE")) {
17544 cpl_error_set_message(cpl_func, CPL_ERROR_DATA_NOT_FOUND,
17545 "Column WAVE in atmospheric extinction table");
17549 if (!cpl_table_has_column(ext_table,
"EXTINCTION")) {
17550 cpl_error_set_message(cpl_func, CPL_ERROR_DATA_NOT_FOUND,
17551 "Column EXTINCTION in atmospheric extinction table");
17555 if (!cpl_table_has_column(flux_table,
"WAVE")) {
17556 cpl_error_set_message(cpl_func, CPL_ERROR_DATA_NOT_FOUND,
17557 "Column WAVE in standard star flux table");
17561 if (!cpl_table_has_column(flux_table,
"FLUX")) {
17562 cpl_error_set_message(cpl_func, CPL_ERROR_DATA_NOT_FOUND,
17563 "Column FLUX in standard star flux table");
17568 cpl_error_set_message(cpl_func, CPL_ERROR_ILLEGAL_INPUT,
17569 "Invalid gain factor (%.2f)", gain);
17573 if (exptime < 0.001) {
17574 cpl_error_set_message(cpl_func, CPL_ERROR_ILLEGAL_INPUT,
17575 "Invalid exposure time (%.2f)", exptime);
17579 if (dispersion < 0.001) {
17580 cpl_error_set_message(cpl_func, CPL_ERROR_ILLEGAL_INPUT,
17581 "Invalid dispersion (%.2f)", dispersion);
17586 cpl_error_set_message(cpl_func, CPL_ERROR_ILLEGAL_INPUT,
17587 "Order of the polynomial fitting the "
17588 "instrument response must be at least 2");
17592 nx = cpl_image_get_size_x(spectra);
17593 ny = cpl_image_get_size_y(spectra);
17601 spectrum = cpl_image_duplicate(spectra);
17605 cpl_image *brights = cpl_image_collapse_create(spectra, 1);
17607 cpl_image_get_maxpos(brights, &x, &y);
17608 cpl_image_delete(brights);
17609 spectrum = cpl_image_extract(spectra, 1, y, nx, y);
17617 cpl_image_multiply_scalar(spectrum, gain / exptime / dispersion);
17625 extinction = cpl_image_duplicate(spectrum);
17626 map_table(extinction, startwave + dispersion/2, dispersion,
17627 ext_table,
"WAVE",
"EXTINCTION");
17634 cpl_image_multiply_scalar(extinction, 0.4 * airmass);
17635 cpl_image_exponential(extinction, 10.);
17642 cpl_image_multiply(spectrum, extinction);
17650 ext_data = cpl_image_get_data_float(extinction);
17654 for (i = 0; i < nx; i++) {
17655 if (ext_data[i] > 0.0) {
17656 if (ext_count == 0) {
17668 cpl_image_delete(extinction); extinction = NULL;
17676 flux = cpl_image_duplicate(spectrum);
17677 map_table(flux, startwave + dispersion/2, dispersion,
17678 flux_table,
"WAVE",
"FLUX");
17686 flux_data = cpl_image_get_data_float(flux);
17690 for (i = 0; i < nx; i++) {
17691 if (flux_data[i] > 0.0) {
17692 if (flux_count == 0) {
17709 start = ext_pos > flux_pos ? ext_pos : flux_pos;
17710 end = (ext_pos + ext_count) < (flux_pos + flux_count) ?
17711 (ext_pos + ext_count) : (flux_pos + flux_count);
17713 flux_count = end - start;
17724 physical = cpl_image_duplicate(spectrum);
17725 phys_data = cpl_image_get_data_float(physical);
17727 for (i = 0; i < nx; i++) {
17728 lambda = startwave + dispersion * (i + 0.5);
17729 phys_data[i] = 0.0026 * lambda * flux_data[i];
17732 efficiency = cpl_image_duplicate(spectrum);
17733 eff_data = cpl_image_get_data_float(efficiency);
17734 data = cpl_image_get_data_float(spectrum);
17736 for (i = 0; i < nx; i++) {
17737 if (phys_data[i] > 0.0)
17738 eff_data[i] = data[i] / phys_data[i];
17743 cpl_image_delete(physical); physical = NULL;
17753 for (i = 0; i < nx; i++) {
17754 if (eff_data[i] > 0.01) {
17755 if (eff_count == 0) {
17761 if (eff_count > 300) {
17772 start = eff_pos > flux_pos ? eff_pos : flux_pos;
17773 end = (eff_pos + eff_count) < (flux_pos + flux_count) ?
17774 (eff_pos + eff_count) : (flux_pos + flux_count);
17776 eff_count = end - start;
17778 if (eff_count < 1) {
17779 cpl_error_set_message(cpl_func, CPL_ERROR_INCOMPATIBLE_INPUT,
17780 "No overlap between catalog and spectrum");
17790 image = cpl_image_extract(efficiency, eff_pos + 1, 1,
17791 eff_pos + eff_count, 1);
17793 smo_image = polysmooth(image, order, 50);
17794 cpl_image_delete(image);
17796 smo_efficiency = cpl_image_duplicate(efficiency);
17797 smo_eff_data = cpl_image_get_data_float(smo_efficiency);
17798 cpl_image_copy(smo_efficiency, smo_image, eff_pos + 1, 1);
17800 cpl_image_delete(smo_image);
17811 response = cpl_image_duplicate(spectrum);
17812 res_data = cpl_image_get_data_float(response);
17814 for (i = 0; i < nx; i++) {
17815 if (eff_data[i] > 0.01 && flux_data[i] > 0.0)
17816 res_data[i] = data[i] / flux_data[i];
17826 image = cpl_image_extract(response, eff_pos + 1, 1, eff_pos + eff_count, 1);
17828 smo_image = polysmooth(image, order, 50);
17829 cpl_image_delete(image);
17831 smo_response = cpl_image_duplicate(response);
17832 smo_res_data = cpl_image_get_data_float(smo_response);
17833 cpl_image_copy(smo_response, smo_image, eff_pos + 1, 1);
17835 cpl_image_delete(smo_image);
17837 for (i = 0; i < nx; i++) {
17838 if (eff_data[i] > 0.01) {
17839 res_data[i] = 1 / res_data[i];
17840 smo_res_data[i] = 1 / smo_res_data[i];
17844 smo_res_data[i] = 0.0;
17853 table = cpl_table_new(nx);
17855 cpl_table_new_column(table,
"WAVE", CPL_TYPE_FLOAT);
17856 cpl_table_set_column_unit(table,
"WAVE",
"Angstrom");
17858 for (i = 0; i < nx; i++)
17859 cpl_table_set_float(table,
"WAVE", i, startwave + dispersion*(i+0.5));
17861 cpl_table_new_column(table,
"STD_FLUX", CPL_TYPE_FLOAT);
17862 cpl_table_set_column_unit(table,
"STD_FLUX",
17863 "10^(-16) erg/(cm^2 s Angstrom)");
17864 cpl_table_copy_data_float(table,
"STD_FLUX", flux_data);
17865 cpl_image_delete(flux); flux = NULL;
17867 cpl_table_new_column(table,
"OBS_FLUX", CPL_TYPE_FLOAT);
17868 cpl_table_set_column_unit(table,
"OBS_FLUX",
"electron/(s Angstrom)");
17869 cpl_table_copy_data_float(table,
"OBS_FLUX", data);
17870 cpl_image_delete(spectrum); spectrum = NULL;
17872 cpl_table_new_column(table,
"RAW_EFFICIENCY", CPL_TYPE_FLOAT);
17873 cpl_table_set_column_unit(table,
"RAW_EFFICIENCY",
"electron/photon");
17874 cpl_table_copy_data_float(table,
"RAW_EFFICIENCY", eff_data);
17875 cpl_image_delete(efficiency); efficiency = NULL;
17877 cpl_table_new_column(table,
"EFFICIENCY", CPL_TYPE_FLOAT);
17878 cpl_table_set_column_unit(table,
"EFFICIENCY",
"electron/photon");
17879 cpl_table_copy_data_float(table,
"EFFICIENCY", smo_eff_data);
17880 cpl_image_delete(smo_efficiency); smo_efficiency = NULL;
17882 cpl_table_new_column(table,
"RAW_RESPONSE", CPL_TYPE_FLOAT);
17883 cpl_table_set_column_unit(table,
"RAW_RESPONSE",
17884 "10^(-16) erg/(cm^2 electron)");
17885 cpl_table_copy_data_float(table,
"RAW_RESPONSE", res_data);
17886 cpl_image_delete(response); response = NULL;
17888 cpl_table_new_column(table,
"RESPONSE", CPL_TYPE_FLOAT);
17889 cpl_table_set_column_unit(table,
17890 "RESPONSE",
"10^(-16) erg/(cm^2 electron)");
17891 cpl_table_copy_data_float(table,
"RESPONSE", smo_res_data);
17892 cpl_image_delete(smo_response); smo_response = NULL;
17899 static double ksigma_vector(cpl_vector *values,
17900 double klow,
double khigh,
int kiter,
int *good)
17902 cpl_vector *accepted;
17904 double sigma = 0.0;
17905 double *data = cpl_vector_get_data(values);
17906 int n = cpl_vector_get_size(values);
17917 mean = cpl_vector_get_median(values);
17919 for (i = 0; i < n; i++)
17920 sigma += (mean - data[i]) * (mean - data[i]);
17922 sigma = sqrt(sigma / (n - 1));
17926 for (i = 0; i < ngood; i++) {
17927 if (data[i]-mean < khigh*sigma && mean-data[i] < klow*sigma) {
17928 data[count] = data[i];
17942 accepted = cpl_vector_wrap(count, data);
17943 mean = cpl_vector_get_mean(accepted);
17945 sigma = cpl_vector_get_stdev(accepted);
17946 cpl_vector_unwrap(accepted);
17948 if (count == ngood || count == 1)
17981 double klow,
double khigh,
int kiter,
17984 int ni, nx, ny, npix;
17985 cpl_image *out_ima;
17990 cpl_vector *time_line;
17991 double *ptime_line;
17996 ni = cpl_imagelist_get_size(imlist);
17998 image = cpl_imagelist_get(imlist, 0);
17999 nx = cpl_image_get_size_x(image);
18000 ny = cpl_image_get_size_y(image);
18003 out_ima = cpl_image_new(nx, ny, CPL_TYPE_FLOAT);
18004 pout_ima = cpl_image_get_data_float(out_ima);
18007 *good = cpl_image_new(nx, ny, CPL_TYPE_FLOAT);
18008 good_ima = cpl_image_get_data_float(*good);
18011 time_line = cpl_vector_new(ni);
18012 ptime_line = cpl_vector_get_data(time_line);
18014 data = cpl_calloc(
sizeof(
float *), ni);
18016 for (i = 0; i < ni; i++) {
18017 image = cpl_imagelist_get(imlist, i);
18018 data[i] = cpl_image_get_data_float(image);
18021 for (i = 0; i < npix; i++) {
18022 for (j = 0; j < ni; j++) {
18023 ptime_line[j] = data[j][i];
18025 pout_ima[i] = ksigma_vector(time_line, klow, khigh, kiter, &ngood);
18027 good_ima[i] = ngood;
18032 cpl_vector_delete(time_line);
18056 cpl_table *ext_table,
double startwave,
18057 double dispersion,
double gain,
18058 double exptime,
double airmass)
18060 cpl_image *extinction;
18061 cpl_image *outspectra;
18062 cpl_image *mapresponse;
18066 int tlength, xlength, ylength;
18070 if (spectra == NULL || ext_table == NULL || response == NULL) {
18071 cpl_error_set(cpl_func, CPL_ERROR_NULL_INPUT);
18075 if(cpl_table_has_column(response,
"RESPONSE"))
18076 cpl_table_cast_column(response,
"RESPONSE",
"RESPONSE_F", CPL_TYPE_FLOAT);
18077 else if(cpl_table_has_column(response,
"RESPONSE_FFSED"))
18078 cpl_table_cast_column(response,
"RESPONSE_FFSED",
"RESPONSE_F", CPL_TYPE_FLOAT);
18082 res_data = cpl_table_get_data_float(response,
"RESPONSE_F");
18084 if (res_data == NULL) {
18085 cpl_error_set(cpl_func, CPL_ERROR_DATA_NOT_FOUND);
18089 tlength = cpl_table_get_nrow(response);
18090 xlength = cpl_image_get_size_x(spectra);
18091 ylength = cpl_image_get_size_y(spectra);
18093 if (xlength != tlength) {
18094 mapresponse = cpl_image_new(xlength, 1, CPL_TYPE_FLOAT);
18095 map_table(mapresponse, startwave + dispersion/2, dispersion,
18096 response,
"WAVE",
"RESPONSE_F");
18097 res_data = cpl_image_get_data_float(mapresponse);
18105 extinction = cpl_image_new(xlength, 1, CPL_TYPE_FLOAT);
18106 map_table(extinction, startwave + dispersion/2, dispersion,
18107 ext_table,
"WAVE",
"EXTINCTION");
18114 cpl_image_multiply_scalar(extinction, 0.4 * airmass);
18115 cpl_image_exponential(extinction, 10.);
18117 outspectra = cpl_image_duplicate(spectra);
18119 ext_data = cpl_image_get_data_float(extinction);
18120 out_data = cpl_image_get_data_float(outspectra);
18122 for (k = 0, i = 0; i < ylength; i++) {
18123 for (j = 0; j < xlength; j++, k++) {
18124 out_data[k] *= ext_data[j] * res_data[j];
18128 cpl_image_delete(extinction);
18129 if (xlength != tlength) {
18130 cpl_image_delete(mapresponse);
18133 cpl_image_multiply_scalar(outspectra, gain / exptime / dispersion);
18135 cpl_table_erase_column(response,
"RESPONSE_F");
18159 cpl_table *response,
18160 cpl_table *ext_table,
18162 double dispersion,
double gain,
18163 double exptime,
double airmass)
18165 cpl_image *extinction;
18166 cpl_image *outerrors;
18167 cpl_image *mapresponse;
18168 cpl_image *maperror;
18174 int tlength, xlength, ylength;
18178 if (errors == NULL || ext_table == NULL || response == NULL) {
18179 cpl_error_set(cpl_func, CPL_ERROR_NULL_INPUT);
18183 if (!cpl_table_has_column(response,
"ERROR")) {
18185 dispersion, gain, exptime, airmass);
18188 cpl_table_cast_column(response,
"RESPONSE",
"RESPONSE_F", CPL_TYPE_FLOAT);
18189 res_data = cpl_table_get_data_float(response,
"RESPONSE_F");
18191 if (res_data == NULL) {
18192 cpl_error_set(cpl_func, CPL_ERROR_DATA_NOT_FOUND);
18196 err_data = cpl_table_get_data_float(response,
"ERROR");
18198 if (err_data == NULL) {
18199 cpl_error_set(cpl_func, CPL_ERROR_DATA_NOT_FOUND);
18203 tlength = cpl_table_get_nrow(response);
18204 xlength = cpl_image_get_size_x(errors);
18205 ylength = cpl_image_get_size_y(errors);
18207 if (xlength != tlength) {
18208 mapresponse = cpl_image_new(xlength, 1, CPL_TYPE_FLOAT);
18209 map_table(mapresponse, startwave + dispersion/2, dispersion,
18210 response,
"WAVE",
"RESPONSE_F");
18211 res_data = cpl_image_get_data_float(mapresponse);
18213 maperror = cpl_image_new(xlength, 1, CPL_TYPE_FLOAT);
18214 map_table(maperror, startwave + dispersion/2, dispersion,
18215 response,
"WAVE",
"ERROR");
18216 err_data = cpl_image_get_data_float(maperror);
18224 extinction = cpl_image_new(xlength, 1, CPL_TYPE_FLOAT);
18225 map_table(extinction, startwave + dispersion/2, dispersion,
18226 ext_table,
"WAVE",
"EXTINCTION");
18233 cpl_image_multiply_scalar(extinction, 0.4 * airmass);
18234 cpl_image_exponential(extinction, 10.);
18236 outerrors = cpl_image_duplicate(errors);
18238 ext_data = cpl_image_get_data_float(extinction);
18239 out_data = cpl_image_get_data_float(outerrors);
18240 spe_data = cpl_image_get_data_float(spectra);
18242 for (k = 0, i = 0; i < ylength; i++) {
18243 for (j = 0; j < xlength; j++, k++) {
18244 out_data[k] = ext_data[j] *
18245 sqrt(err_data[j] * err_data[j] * spe_data[k] * spe_data[k] +
18246 res_data[j] * res_data[j] * out_data[k] * out_data[k]);
18250 cpl_image_delete(extinction);
18251 if (xlength != tlength) {
18252 cpl_image_delete(maperror);
18255 cpl_image_multiply_scalar(outerrors, gain / exptime / dispersion);
18257 cpl_table_erase_column(response,
"RESPONSE_F");
18338 cpl_image *u_image, cpl_image *u_error,
18339 double startwave,
double dispersion,
18340 double band, cpl_table *pol_sta,
18341 double ra,
double dec,
char *filter,
18343 double *p_offset,
double *p_error,
18344 double *a_offset,
double *a_error)
18346 cpl_table *standard;
18347 cpl_image *q_noise;
18348 cpl_image *q_signal;
18349 cpl_image *u_noise;
18350 cpl_image *u_signal;
18356 double arctol = 0.5;
18359 double bwave[] = {3650., 4450., 5510., 6580., 8060};
18360 char *bands =
"UBVRI";
18361 char p_label[] = {
' ',
'p',
'\0'};
18362 char dp_label[] = {
' ',
'd',
'p',
'\0'};
18363 char a_label[] = {
' ',
'a',
'\0'};
18364 char da_label[] = {
' ',
'd',
'a',
'\0'};
18365 int nbands = strlen(bands);
18367 int first, last, count, center;
18370 int i, found, closest;
18398 cpl_table_select_all(pol_sta);
18399 cpl_table_and_selected_double(pol_sta,
"RA", CPL_GREATER_THAN, ra-arctol);
18400 cpl_table_and_selected_double(pol_sta,
"RA", CPL_LESS_THAN, ra+arctol);
18401 cpl_table_and_selected_double(pol_sta,
"DEC", CPL_GREATER_THAN, dec-arctol);
18403 cpl_table_and_selected_double(pol_sta,
"DEC", CPL_LESS_THAN, dec+arctol);
18405 if (selected == 0) {
18406 cpl_msg_warning(cpl_func,
"No standard star found in FOV");
18410 if (selected > 1) {
18411 cpl_msg_warning(cpl_func,
18412 "Ambiguity: %d standard stars found in FOV", selected);
18416 standard = cpl_table_extract_selected(pol_sta);
18418 cpl_msg_info(cpl_func,
"Standard star: %s",
18419 cpl_table_get_string(standard,
"name", 0));
18425 polarised = cpl_table_get_int(standard,
"polarised", 0, NULL);
18427 cpl_msg_info(cpl_func,
"This star is%sexpected to be polarised",
18428 polarised ?
" " :
" not ");
18438 nx = cpl_image_get_size_x(q_error);
18440 noise = cpl_image_collapse_median_create(q_error, 1, 0, 0);
18441 cpl_image_get_minpos(noise, &col, &row);
18443 cpl_image_delete(noise);
18446 cpl_table_delete(standard);
18447 cpl_msg_error(cpl_func,
18448 "Assertion failure!!! col = %"CPL_SIZE_FORMAT
" (it should be 1)", col);
18452 q_signal = cpl_image_extract(q_image, 1, row, nx, row);
18453 q_noise = cpl_image_extract(q_error, 1, row, nx, row);
18454 u_signal = cpl_image_extract(u_image, 1, row, nx, row);
18455 u_noise = cpl_image_extract(u_error, 1, row, nx, row);
18457 q_sdata = cpl_image_get_data_double(q_signal);
18458 q_ndata = cpl_image_get_data_double(q_noise);
18459 u_sdata = cpl_image_get_data_double(u_signal);
18460 u_ndata = cpl_image_get_data_double(u_noise);
18468 last = nx = cpl_image_get_size_x(q_signal);
18469 for (i = 0; i < nx; i++) {
18471 if (q_ndata[i] > 0.0) {
18476 if (q_ndata[i] <= 0.0) {
18483 count = last - first + 1;
18485 if (first < 0 || count < band) {
18486 cpl_table_delete(standard);
18487 cpl_image_delete(q_signal);
18488 cpl_image_delete(q_noise);
18489 cpl_image_delete(u_signal);
18490 cpl_image_delete(u_noise);
18491 cpl_msg_warning(cpl_func,
"Too short spectrum (%d pixels)", count);
18495 center = (first + last) / 2;
18496 cwave = startwave + dispersion * center;
18504 for (i = 0; i < nbands; i++) {
18505 p_label[0] = bands[i];
18506 if (cpl_table_is_valid(standard, p_label, 0)) {
18509 mindist = fabs(bwave[i] - cwave);
18512 else if (mindist > fabs(bwave[i] - cwave)) {
18513 mindist = fabs(bwave[i] - cwave);
18520 cpl_table_delete(standard);
18521 cpl_image_delete(q_signal);
18522 cpl_image_delete(q_noise);
18523 cpl_image_delete(u_signal);
18524 cpl_image_delete(u_noise);
18525 cpl_msg_warning(cpl_func,
"No reference value available");
18529 center = (bwave[closest] - startwave) / dispersion;
18530 cwave = bwave[closest];
18538 pband = floor(band / dispersion);
18540 if (center - pband/2 < first || center + pband/2 > last) {
18541 cpl_table_delete(standard);
18542 cpl_image_delete(q_signal);
18543 cpl_image_delete(q_noise);
18544 cpl_image_delete(u_signal);
18545 cpl_image_delete(u_noise);
18546 cpl_msg_warning(cpl_func,
"No reference value available");
18550 first = center - pband/2;
18551 last = center + pband/2;
18558 p_label[0] = bands[closest];
18559 dp_label[0] = bands[closest];
18560 a_label[0] = bands[closest];
18561 da_label[0] = bands[closest];
18563 p_ref = cpl_table_get(standard, p_label, 0, NULL);
18564 dp_ref = cpl_table_get(standard, dp_label, 0, NULL);
18565 a_ref = cpl_table_get(standard, a_label, 0, NULL);
18566 da_ref = cpl_table_get(standard, da_label, 0, NULL);
18568 cpl_msg_info(cpl_func,
18569 "The expected polarisation is %.2f +- %.2f %%",
18573 cpl_msg_info(cpl_func,
18574 "The expected polarisation angle is %.2f +- %.2f degrees",
18582 q_obs = cpl_image_get_median_window(q_image, first, 1, last, 1);
18583 q_err = cpl_image_get_median_window(q_error, first, 1, last, 1);
18584 u_obs = cpl_image_get_median_window(u_image, first, 1, last, 1);
18585 u_err = cpl_image_get_median_window(u_error, first, 1, last, 1);
18591 p_obs = sqrt(q_obs * q_obs + u_obs * u_obs);
18592 p_err = CPL_MATH_SQRT1_2 * 0.5 * (q_err + u_err);
18600 if (fabs(q_obs) < 0.00001) {
18609 a_obs = 0.5 * atan(u_obs / q_obs) * 180 / CPL_MATH_PI;
18627 a_err = sqrt(q_obs*q_obs*u_err*u_err + u_obs*u_obs*q_err*q_err)
18629 * 90 / CPL_MATH_PI;
18634 cpl_msg_info(cpl_func,
18635 "The measured polarisation is %.2f +- %.2f %%",
18639 cpl_msg_info(cpl_func,
18640 "The measured polarisation angle is %.2f +- %.2f degrees",
18644 *filter = bands[closest];
18645 *polarisation = polarised;
18648 *p_offset = (p_obs - p_ref) / p_ref;
18649 *p_error = sqrt(p_err * p_err + dp_ref * dp_ref) / p_ref;
18652 *p_offset = p_obs - p_ref;
18653 *p_error = sqrt(p_err * p_err + dp_ref * dp_ref);
18656 *a_offset = a_obs - a_ref;
18657 *a_error = sqrt(a_err*a_err + da_ref*da_ref);
18697 cpl_array *offsets;
18699 int nslits = cpl_table_get_nrow(reference);
18706 cpl_error_code status = CPL_ERROR_NONE;
18711 if (objects == NULL)
18712 return CPL_ERROR_NULL_INPUT;
18714 if (nslits != cpl_table_get_nrow(objects))
18715 return CPL_ERROR_INCOMPATIBLE_INPUT;
18717 nref = fors_get_nobjs_perslit(reference);
18718 nobj = fors_get_nobjs_perslit(objects);
18721 for (i = 0; i < nslits; i++)
18722 noffset += nobj[i];
18724 if (noffset == 0) {
18727 return CPL_ERROR_DATA_NOT_FOUND;
18731 for (i = 0; i < nslits; i++)
18732 noffset += nref[i];
18734 if (noffset == 0) {
18737 return CPL_ERROR_DATA_NOT_FOUND;
18740 offsets = cpl_array_new(noffset, CPL_TYPE_DOUBLE);
18744 for (i = 0; i < nslits; i++) {
18745 if (nref[i] > 0 && nobj[i] > 0) {
18747 int length = cpl_table_get_int(objects,
"length", i, NULL);
18748 double ytop = cpl_table_get_double(objects,
"xtop", i, NULL);
18749 double ybottom = cpl_table_get_double(objects,
"xbottom", i, NULL);
18750 int *aref = cpl_calloc(length,
sizeof(
int));
18751 int *aobj = cpl_calloc(length,
sizeof(
int));
18752 float *pref = cpl_calloc(nref[i],
sizeof(
float));
18753 float *pobj = cpl_calloc(nobj[i],
sizeof(
float));
18755 for (j = 0; j < nref[i]; j++) {
18756 pref[j] = fors_get_object_position(reference, i, j + 1);
18757 aref[(int)pref[j]] = 1;
18760 for (j = 0; j < nobj[i]; j++) {
18761 pobj[j] = fors_get_object_position(objects, i, j + 1);
18762 aobj[(int)pobj[j]] = 1;
18770 aref[length - 1] = 0;
18772 aobj[length - 1] = 0;
18792 best_shift = length;
18794 for (shift = length/2, j = 0; j <= length; shift--, j++) {
18795 int rstart, ostart, count;
18800 count = length - shift;
18805 count = length + shift;
18809 for (k = 0; k < count; k++) {
18810 corr += aref[rstart + k] * aobj[ostart + k];
18813 if (maxcorr < corr) {
18815 best_shift = shift;
18819 if (best_shift == length) {
18829 for (j = 0; j < nref[i]; j++) {
18830 for (k = 0; k < nobj[i]; k++) {
18831 if (fabs(pref[j] - pobj[k] - best_shift) < 2) {
18832 double ccd_offset = (pref[j] - pobj[k])
18842 cpl_array_set(offsets, noffset, ccd_offset);
18864 *offset = cpl_array_get_median(offsets);
18867 double *a = cpl_malloc(
sizeof(
double) * noffset);
18868 for (i = 0; i < noffset; i++) {
18869 a[i] = cpl_array_get_double(offsets, i, NULL);
18877 status = CPL_ERROR_DATA_NOT_FOUND;
18880 cpl_array_delete(offsets);
18901 int nx = cpl_image_get_size_x(image);
18902 int ny = cpl_image_get_size_y(image);
18906 double xpos, ypos, xfrac, yfrac;
18910 if (fabs(dx) >= nx || fabs(dy) >= ny)
18911 return CPL_ERROR_ACCESS_OUT_OF_RANGE;
18913 source = cpl_image_duplicate(image);
18914 idata = cpl_image_get_data_float(image);
18915 sdata = cpl_image_get_data_float(source);
18921 yfrac = - dy - floor(- dy);
18922 xfrac = - dx - floor(- dx);
18924 for (pos = 0, j = 0; j < ny; j++) {
18926 yint = floor(ypos);
18927 for (i = 0; i < nx; i++) {
18929 xint = floor(xpos);
18930 if (xint < 0 || yint < 0 || xint > nx - 2 || yint > ny - 2) {
18934 idata[pos] = sdata[xint + nx*yint] * (1 - xfrac) * (1 - yfrac)
18935 + sdata[xint + 1 + nx*yint] * xfrac * (1 - yfrac)
18936 + sdata[xint + nx*(yint + 1)] * (1 - xfrac) * yfrac
18937 + sdata[xint + 1 + nx*(yint + 1)] * xfrac * yfrac;
18943 cpl_image_delete(source);
18945 return CPL_ERROR_NONE;
18961 #ifdef CPL_SIZE_FORMAT
18967 cpl_table_duplicate_column(slits,
"x", slits,
"xtop");
18968 cpl_table_add_columns(slits,
"x",
"xbottom");
18969 cpl_table_divide_scalar(slits,
"x", 2);
18970 cpl_table_subtract_scalar(slits,
"x", nx/2);
18971 cpl_table_multiply_columns(slits,
"x",
"x");
18973 cpl_table_duplicate_column(slits,
"y", slits,
"ytop");
18974 cpl_table_add_columns(slits,
"y",
"ybottom");
18975 cpl_table_divide_scalar(slits,
"y", 2);
18976 cpl_table_subtract_scalar(slits,
"y", ny/2);
18977 cpl_table_multiply_columns(slits,
"y",
"y");
18979 cpl_table_add_columns(slits,
"x",
"y");
18980 cpl_table_get_column_minpos(slits,
"x", &row);
18982 cpl_table_erase_column(slits,
"x");
18983 cpl_table_erase_column(slits,
"y");
19008 double xwidth,
double ywidth,
19009 int dx,
double gain,
double *o_flux,
double *o_err)
19011 int nx = cpl_image_get_size_x(image);
19012 int ny = cpl_image_get_size_y(image);
19014 int ytop = (int)cpl_table_get(slits,
"ytop", slit, NULL);
19015 int ybottom = (int)cpl_table_get(slits,
"ybottom", slit, NULL);
19016 int dy = ytop - ybottom;
19017 int xcenter = (int)((cpl_table_get(slits,
"xtop", slit, NULL) +
19018 cpl_table_get(slits,
"xbottom", slit, NULL)) / 2);
19019 int xleft = xcenter - dx;
19020 int xright = xcenter + dx + 1;
19021 double area = xwidth * ywidth;
19022 int npix = (2*dx + 1) * dy;
19024 float *data = cpl_image_get_data_float(image);
19026 double error = 0.0;
19031 if (cpl_table_has_column(slits,
"ywidth")) {
19032 area = cpl_table_get(slits,
"xwidth", slit, NULL)
19033 * cpl_table_get(slits,
"ywidth", slit, NULL);
19063 count = (xright - xleft) * (ytop - ybottom);
19066 return CPL_ERROR_ACCESS_OUT_OF_RANGE;
19070 for (y = ybottom; y < ytop; y++) {
19071 for (x = xleft; x < xright; x++) {
19072 double value = data[x + y * nx];
19073 if (value < satur) {
19081 return CPL_ERROR_DIVISION_BY_ZERO;
19083 error = sqrt(flux/gain);
19089 flux *= (float)npix / count;
19090 error *= (float)npix / count;
19098 return CPL_ERROR_NONE;
19125 double xwidth,
double ywidth,
19126 double lambda,
double startwave,
19127 double dispersion,
int dx,
double gain,
19128 double *o_flux,
double *o_err)
19130 int nx = cpl_image_get_size_x(image);
19131 int ny = cpl_image_get_size_y(image);
19133 int dy = (int)cpl_table_get(slits,
"length", slit, NULL);
19134 int ybottom = (int)cpl_table_get(slits,
"position", slit, NULL);
19135 int ytop = ybottom + dy;
19136 int xcenter = (int)floor((lambda - startwave) / dispersion + 0.5);
19137 int xleft = xcenter - dx;
19138 int xright = xcenter + dx + 1;
19139 double area = xwidth * ywidth;
19140 int npix = (2*dx + 1) * dy;
19142 float *data = cpl_image_get_data_float(image);
19144 double error = 0.0;
19149 if (cpl_table_has_column(slits,
"ywidth")) {
19150 area = cpl_table_get(slits,
"xwidth", slit, NULL)
19151 * cpl_table_get(slits,
"ywidth", slit, NULL);
19181 count = (xright - xleft) * (ytop - ybottom);
19184 return CPL_ERROR_ACCESS_OUT_OF_RANGE;
19188 for (y = ybottom; y < ytop; y++) {
19189 for (x = xleft; x < xright; x++) {
19190 double value = data[x + y * nx];
19191 if (value < satur) {
19199 return CPL_ERROR_DIVISION_BY_ZERO;
19201 error = sqrt(flux/gain);
19207 flux *= (float)npix / count;
19208 error *= (float)npix / count;
19216 return CPL_ERROR_NONE;
19235 char *label,
double *mvalue)
19237 int position = cpl_table_get_int(slits,
"position", slit, NULL);
19238 int length = cpl_table_get_int(slits,
"length", slit, NULL);
19239 cpl_table *tmp = cpl_table_extract(table, position, length);
19241 *mvalue = cpl_table_get_column_median(tmp, label);
19242 cpl_table_delete(tmp);
19244 if (cpl_error_get_code() != CPL_ERROR_NONE)
19264 cpl_mask *kernel = cpl_mask_new(nx, ny);
19265 cpl_image *filtered = cpl_image_new(cpl_image_get_size_x(image),
19266 cpl_image_get_size_y(image),
19267 cpl_image_get_type(image));
19269 cpl_mask_not(kernel);
19270 cpl_image_filter_mask(filtered, image, kernel,
19271 CPL_FILTER_MEDIAN, CPL_BORDER_FILTER);
19272 cpl_mask_delete(kernel);
19277 int fors_mos_is_lss_like(cpl_table *maskslits,
int nslits_out_det)
19279 int treat_as_lss = 1;
19280 double mxpos = cpl_table_get_column_median(maskslits,
"xtop");
19281 double * slit_xpos = cpl_table_get_data_double(maskslits,
"xtop");
19282 cpl_size nslits = cpl_table_get_nrow(maskslits);
19286 if(nslits_out_det != 0)
19289 for (cpl_size i = 0; i < nslits; i++) {
19290 if (fabs(mxpos-slit_xpos[i]) > 0.01) {
19295 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_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_image ** mos_extract_objects(cpl_image *science, cpl_image *science_var, cpl_image *sky, cpl_table *objects, int extraction, double ron, double gain, int ncombined)
Extract detected objects from rectified scientific frame.
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_error_code mos_interpolate_wavecalib_mos(cpl_table *idscoeff, int mode, int degree)
Interpolate wavelength calibration for a single MOS slit.
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.