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;
1237 if (slits == NULL || maskslits == NULL || ids == NULL || crv == NULL) {
1238 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
1242 nslits = cpl_table_get_nrow(slits);
1244 if (nslits < minslit) {
1245 cpl_msg_warning(func,
"Too few slits (%d < %d) for global " 1246 "distortion model determination", nslits, minslit);
1250 nmaskslits = cpl_table_get_nrow(maskslits);
1252 length = cpl_table_get_data_int(slits,
"length");
1253 position = cpl_table_get_data_int(slits,
"position");
1254 slit_id = cpl_table_get_data_int(slits,
"slit_id");
1255 mslit_id = cpl_table_get_data_int(maskslits,
"slit_id");
1256 xtop = cpl_table_get_data_double(slits,
"xtop");
1257 ytop = cpl_table_get_data_double(slits,
"ytop");
1258 xbottom = cpl_table_get_data_double(slits,
"xbottom");
1259 ybottom = cpl_table_get_data_double(slits,
"ybottom");
1260 mxtop = cpl_table_get_data_double(maskslits,
"xtop");
1261 mytop = cpl_table_get_data_double(maskslits,
"ytop");
1262 mxbottom = cpl_table_get_data_double(maskslits,
"xbottom");
1263 mybottom = cpl_table_get_data_double(maskslits,
"ybottom");
1270 coeff = cpl_table_new(nslits);
1271 cpl_table_copy_structure(coeff, ids);
1272 cpl_table_new_column(coeff,
"xccd", CPL_TYPE_DOUBLE);
1273 cpl_table_new_column(coeff,
"yccd", CPL_TYPE_DOUBLE);
1274 cpl_table_new_column(coeff,
"xmask", CPL_TYPE_DOUBLE);
1275 cpl_table_new_column(coeff,
"ymask", CPL_TYPE_DOUBLE);
1277 for (i = 0; i < nslits; i++) {
1278 for (j = 0; j < nmaskslits; j++) {
1279 if (slit_id[i] == mslit_id[j]) {
1280 cpl_table_set_double(coeff,
"xmask", i,
1281 (mxtop[j] + mxbottom[j]) / 2);
1282 cpl_table_set_double(coeff,
"ymask", i,
1283 (mytop[j] + mybottom[j]) / 2);
1288 if (cpl_table_has_invalid(coeff,
"xmask")) {
1289 cpl_error_set(func, CPL_ERROR_INCOMPATIBLE_INPUT);
1290 cpl_table_delete(coeff);
1294 for (i = 0; i < nslits; i++) {
1295 cpl_table_set_double(coeff,
"xccd", i, (xtop[i] + xbottom[i]) / 2);
1296 cpl_table_set_double(coeff,
"yccd", i, (ytop[i] + ybottom[i]) / 2);
1299 for (i = 0; i < nslits; i++) {
1304 cpl_table_and_selected_window(ids, position[i], length[i]);
1305 dummy = cpl_table_extract_selected(ids);
1306 for (j = 0; j < 6; j++) {
1307 if (cpl_table_has_column(dummy, clab[j])) {
1308 if (length[i] - cpl_table_count_invalid(dummy, clab[j]) > 10) {
1309 cpl_table_set_double(coeff, clab[j], i,
1310 cpl_table_get_column_median(dummy, clab[j]));
1315 cpl_table_delete(dummy);
1316 cpl_table_select_all(ids);
1320 for (j = 0; j < 6; j++) {
1321 if (cpl_table_has_column(coeff, clab[j])) {
1322 cpl_table_and_selected_invalid(coeff, clab[j]);
1324 if (cpl_table_not_selected(coeff))
1325 dummy = cpl_table_extract_selected(coeff);
1329 npoints = cpl_table_get_nrow(dummy);
1338 ci = cpl_vector_wrap(npoints,
1339 cpl_table_get_data_double(dummy, clab[j]));
1341 xccd = cpl_vector_wrap(npoints,
1342 cpl_table_get_data_double(dummy,
"xccd"));
1343 yccd = cpl_vector_wrap(npoints,
1344 cpl_table_get_data_double(dummy,
"yccd"));
1345 ccd = cpl_bivector_wrap_vectors(xccd, yccd);
1348 poly = cpl_polynomial_fit_2d_create(ccd, ci, order, NULL);
1350 cpl_bivector_unwrap_vectors(ccd);
1351 cpl_vector_unwrap(xccd);
1352 cpl_vector_unwrap(yccd);
1353 cpl_vector_unwrap(ci);
1356 xmask = cpl_vector_wrap(npoints,
1357 cpl_table_get_data_double(dummy,
"xmask"));
1358 ymask = cpl_vector_wrap(npoints,
1359 cpl_table_get_data_double(dummy,
"ymask"));
1360 mask = cpl_bivector_wrap_vectors(xmask, ymask);
1363 poly = cpl_polynomial_fit_2d_create(mask, ci, order, NULL);
1365 cpl_bivector_unwrap_vectors(mask);
1366 cpl_vector_unwrap(xmask);
1367 cpl_vector_unwrap(ymask);
1368 cpl_vector_unwrap(ci);
1372 cpl_size p[2] = {0, 0};
1373 poly = cpl_polynomial_new(2);
1374 cpl_polynomial_set_coeff(poly, p,
1375 cpl_table_get_column_median(dummy, clab[j]));
1378 cpl_table_delete(dummy);
1380 global = write_global_distortion(global, j, poly);
1382 cpl_polynomial_delete(poly);
1384 cpl_table_select_all(coeff);
1388 cpl_table_delete(coeff);
1395 cpl_table_set_double(global,
"a00", 6, reference);
1402 coeff = cpl_table_duplicate(crv);
1403 cpl_table_new_column(coeff,
"xmask", CPL_TYPE_DOUBLE);
1404 cpl_table_new_column(coeff,
"ymask", CPL_TYPE_DOUBLE);
1405 cpl_table_new_column(coeff,
"xccd", CPL_TYPE_DOUBLE);
1406 cpl_table_new_column(coeff,
"yccd", CPL_TYPE_DOUBLE);
1407 slit_id = cpl_table_get_data_int(coeff,
"slit_id");
1408 npoints = cpl_table_get_nrow(coeff);
1410 for (i = 0; i < npoints; i++) {
1411 for (j = 0; j < nmaskslits; j++) {
1412 if (slit_id[i] == mslit_id[j]) {
1414 cpl_table_set_double(coeff,
"xmask", i, mxbottom[j]);
1415 cpl_table_set_double(coeff,
"ymask", i, mybottom[j]);
1418 cpl_table_set_double(coeff,
"xmask", i, mxtop[j]);
1419 cpl_table_set_double(coeff,
"ymask", i, mytop[j]);
1425 cpl_table_set_double(coeff,
"xccd", i, xtop[(i-1)/2]);
1426 cpl_table_set_double(coeff,
"yccd", i, ytop[(i-1)/2]);
1430 cpl_table_set_double(coeff,
"xccd", i, xbottom[i/2]);
1431 cpl_table_set_double(coeff,
"yccd", i, ybottom[i/2]);
1435 if (cpl_table_has_invalid(coeff,
"xmask")) {
1436 cpl_error_set(func, CPL_ERROR_INCOMPATIBLE_INPUT);
1437 cpl_table_delete(coeff);
1441 for (j = 0; j < 3; j++) {
1442 cpl_polynomial * poly_ccd;
1443 if (cpl_table_has_column(coeff, clab[j])) {
1444 cpl_table_and_selected_invalid(coeff, clab[j]);
1446 if (cpl_table_not_selected(coeff))
1447 dummy = cpl_table_extract_selected(coeff);
1451 npoints = cpl_table_get_nrow(dummy);
1460 ci = cpl_vector_wrap(npoints,
1461 cpl_table_get_data_double(dummy, clab[j]));
1462 xmask = cpl_vector_wrap(npoints,
1463 cpl_table_get_data_double(dummy,
"xmask"));
1464 ymask = cpl_vector_wrap(npoints,
1465 cpl_table_get_data_double(dummy,
"ymask"));
1466 mask = cpl_bivector_wrap_vectors(xmask, ymask);
1468 poly = cpl_polynomial_fit_2d_create(mask, ci, order, NULL);
1470 xccd = cpl_vector_wrap(npoints,
1471 cpl_table_get_data_double(dummy,
"xccd"));
1472 yccd = cpl_vector_wrap(npoints,
1473 cpl_table_get_data_double(dummy,
"yccd"));
1474 ccd = cpl_bivector_wrap_vectors(xccd, yccd);
1476 poly_ccd = cpl_polynomial_fit_2d_create(ccd, ci, order, NULL);
1479 cpl_bivector_unwrap_vectors(mask);
1480 cpl_vector_unwrap(ci);
1481 cpl_vector_unwrap(xmask);
1482 cpl_vector_unwrap(ymask);
1485 cpl_size p[2] = {0, 0};
1486 poly = cpl_polynomial_new(2);
1487 cpl_polynomial_set_coeff(poly, p,
1488 cpl_table_get_column_median(dummy, clab[j]));
1491 cpl_table_delete(dummy);
1493 global = write_global_distortion(global, j + 7, poly);
1494 global = write_global_distortion(global, j + 10, poly_ccd);
1496 cpl_polynomial_delete(poly);
1497 cpl_polynomial_delete(poly_ccd);
1498 cpl_table_select_all(coeff);
1502 cpl_table_delete(coeff);
1549 const char *func =
"mos_build_slit_location";
1551 cpl_propertylist *sort_col;
1552 cpl_polynomial *ids0;
1553 cpl_polynomial *crv[3];
1554 cpl_polynomial *loc_crv;
1572 if (global == NULL || maskslits == NULL) {
1573 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
1577 nslits = cpl_table_get_nrow(maskslits);
1578 slit_id = cpl_table_get_data_int(maskslits,
"slit_id");
1579 mxtop = cpl_table_get_data_double(maskslits,
"xtop");
1580 mytop = cpl_table_get_data_double(maskslits,
"ytop");
1581 mxbottom = cpl_table_get_data_double(maskslits,
"xbottom");
1582 mybottom = cpl_table_get_data_double(maskslits,
"ybottom");
1584 slits = cpl_table_duplicate(maskslits);
1586 xtop = cpl_table_get_data_double(slits,
"xtop");
1587 ytop = cpl_table_get_data_double(slits,
"ytop");
1588 xbottom = cpl_table_get_data_double(slits,
"xbottom");
1589 ybottom = cpl_table_get_data_double(slits,
"ybottom");
1591 ids0 = read_global_distortion(global, 0);
1592 crv[0] = read_global_distortion(global, 7);
1593 crv[1] = read_global_distortion(global, 8);
1594 crv[2] = read_global_distortion(global, 9);
1596 loc_crv = cpl_polynomial_new(1);
1598 point = cpl_vector_new(2);
1599 dpoint = cpl_vector_get_data(point);
1601 for (i = 0; i < nslits; i++) {
1602 dpoint[0] = mxtop[i];
1603 dpoint[1] = mytop[i];
1605 xtop[i] = cpl_polynomial_eval(ids0, point);
1607 for (j = 0; j < 3; j++)
1609 cpl_polynomial_set_coeff(loc_crv, &j,
1610 cpl_polynomial_eval(crv[j], point));
1612 ytop[i] = cpl_polynomial_eval_1d(loc_crv, xtop[i], NULL);
1614 dpoint[0] = mxbottom[i];
1615 dpoint[1] = mybottom[i];
1616 xbottom[i] = cpl_polynomial_eval(ids0, point);
1618 for (j = 0; j < 3; j++)
1620 cpl_polynomial_set_coeff(loc_crv, &j,
1621 cpl_polynomial_eval(crv[j], point));
1623 ybottom[i] = cpl_polynomial_eval_1d(loc_crv, xbottom[i], NULL);
1626 cpl_vector_delete(point);
1627 cpl_polynomial_delete(ids0);
1628 cpl_polynomial_delete(loc_crv);
1629 for (j = 0; j < 3; j++)
1630 cpl_polynomial_delete(crv[j]);
1632 sort_col = cpl_propertylist_new();
1633 cpl_propertylist_append_bool(sort_col,
"ytop", 1);
1634 cpl_table_sort(slits, sort_col);
1635 cpl_table_sort(maskslits, sort_col);
1636 cpl_propertylist_delete(sort_col);
1642 cpl_table_and_selected_double(slits,
"ybottom", CPL_GREATER_THAN, ysize-1);
1643 cpl_table_or_selected_double(slits,
"ytop", CPL_LESS_THAN, 0);
1644 cpl_table_erase_selected(slits);
1646 nslits = cpl_table_get_nrow(slits);
1649 cpl_msg_warning(func,
"No slits found on the CCD");
1650 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
1651 cpl_table_delete(slits);
1656 cpl_msg_info(func,
"Slit location: %"CPL_SIZE_FORMAT
" slits are entirely or partially " 1657 "contained in CCD", nslits);
1659 cpl_msg_info(func,
"Slit location: %"CPL_SIZE_FORMAT
" slit is entirely or partially " 1660 "contained in CCD", nslits);
1696 const char *func =
"mos_build_curv_coeff";
1698 const char *clab[6] = {
"c0",
"c1",
"c2",
"c3",
"c4",
"c5"};
1701 cpl_polynomial *crv[3];
1703 cpl_table *polytraces;
1716 if (global == NULL || slits == NULL || maskslits == NULL) {
1717 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
1721 nslits = cpl_table_get_nrow(maskslits);
1722 slit_id = cpl_table_get_data_int(maskslits,
"slit_id");
1723 xtop = cpl_table_get_data_double(maskslits,
"xtop");
1724 ytop = cpl_table_get_data_double(maskslits,
"ytop");
1725 xbottom = cpl_table_get_data_double(maskslits,
"xbottom");
1726 ybottom = cpl_table_get_data_double(maskslits,
"ybottom");
1728 polytraces = cpl_table_new(2*nslits);
1729 cpl_table_new_column(polytraces,
"slit_id", CPL_TYPE_INT);
1730 for (i = 0; i < 3; i++)
1731 cpl_table_new_column(polytraces, clab[i], CPL_TYPE_DOUBLE);
1733 crv[0] = read_global_distortion(global, 7);
1734 crv[1] = read_global_distortion(global, 8);
1735 crv[2] = read_global_distortion(global, 9);
1737 point = cpl_vector_new(2);
1738 dpoint = cpl_vector_get_data(point);
1740 for (i = 0; i < nslits; i++) {
1741 for (j = 0; j < 2; j++) {
1743 cpl_table_set_int(polytraces,
"slit_id", 2*i+j, slit_id[i]);
1746 dpoint[0] = xbottom[i];
1747 dpoint[1] = ybottom[i];
1750 dpoint[0] = xtop[i];
1751 dpoint[1] = ytop[i];
1754 for (k = 0; k < 3; k++)
1756 cpl_table_set_double(polytraces, clab[k], 2*i+j,
1757 cpl_polynomial_eval(crv[k], point));
1761 cpl_vector_delete(point);
1762 for (j = 0; j < 3; j++)
1763 cpl_polynomial_delete(crv[j]);
1769 nvalid = cpl_table_get_nrow(slits);
1770 valid_id = cpl_table_get_data_int(slits,
"slit_id");
1771 cpl_table_unselect_all(polytraces);
1772 for (i = 0; i < nslits; i++) {
1774 for (j = 0; j < nvalid; j++) {
1775 if (slit_id[i] == valid_id[j]) {
1781 cpl_table_select_row(polytraces, 2*i);
1782 cpl_table_select_row(polytraces, 2*i + 1);
1785 cpl_table_erase_selected(polytraces);
1787 nslits = cpl_table_get_nrow(polytraces);
1790 cpl_msg_warning(func,
"No slits found on the CCD");
1791 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
1792 cpl_table_delete(polytraces);
1797 cpl_msg_info(func,
"Curvature model: %d slits are entirely or " 1798 "partially contained in CCD", nslits / 2);
1800 cpl_msg_info(func,
"Curvature model: %d slit is entirely or " 1801 "partially contained in CCD", nslits / 2);
1850 const char *func =
"mos_build_disp_coeff";
1852 const char *clab[6] = {
"c0",
"c1",
"c2",
"c3",
"c4",
"c5"};
1854 cpl_polynomial *ids[6];
1856 cpl_table *idscoeff;
1871 if (global == NULL || slits == NULL) {
1872 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
1876 nslits = cpl_table_get_nrow(slits);
1877 position = cpl_table_get_data_int(slits,
"position");
1878 length = cpl_table_get_data_int(slits,
"length");
1879 xtop = cpl_table_get_data_double(slits,
"xtop");
1880 ytop = cpl_table_get_data_double(slits,
"ytop");
1881 xbottom = cpl_table_get_data_double(slits,
"xbottom");
1882 ybottom = cpl_table_get_data_double(slits,
"ybottom");
1884 for (i = 0; i < 6; i++)
1885 ids[i] = read_global_distortion(global, i);
1887 for (i = 0; i < 6; i++)
1894 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
1899 for (i = 0; i < nslits; i++)
1902 idscoeff = cpl_table_new(nrows);
1904 for (j = 0; j <= order; j++)
1905 cpl_table_new_column(idscoeff, clab[j], CPL_TYPE_DOUBLE);
1907 cpl_table_new_column(idscoeff,
"error", CPL_TYPE_DOUBLE);
1908 cpl_table_fill_column_window_double(idscoeff,
"error", 0, nrows, 0.0);
1909 cpl_table_new_column(idscoeff,
"nlines", CPL_TYPE_INT);
1910 cpl_table_fill_column_window_int(idscoeff,
"nlines", 0, nrows, 0);
1912 point = cpl_vector_new(2);
1913 dpoint = cpl_vector_get_data(point);
1915 for (i = 0; i < nslits; i++) {
1921 yhig = ylow + length[i];
1923 for (j = 0; j <= order; j++) {
1925 for (k = 0; k < length[i]; k++) {
1926 dpoint[0] = xbottom[i] + k*(xtop[i]-xbottom[i])/length[i];
1927 dpoint[1] = ybottom[i] + k*(ytop[i]-ybottom[i])/length[i];
1928 cpl_table_set_double(idscoeff, clab[j], ylow + k,
1929 cpl_polynomial_eval(ids[j], point));
1933 for (k = 0; k < length[i]; k++) {
1934 cpl_table_set_double(idscoeff, clab[0], ylow + k,
1935 xbottom[i] + k*(xtop[i]-xbottom[i])/length[i]);
1941 cpl_vector_delete(point);
1942 for (j = 0; j < 6; j++)
1943 cpl_polynomial_delete(ids[j]);
1973 cpl_table *polytraces,
double reference,
1974 double blue,
double red,
double dispersion)
1976 const char *func =
"mos_subtract_sky";
1978 const char *clab[6] = {
"c0",
"c1",
"c2",
"c3",
"c4",
"c5"};
1985 cpl_polynomial *polytop;
1986 cpl_polynomial *polybot;
1987 cpl_polynomial *trend;
2001 int pixel_above, pixel_below, refpixel, start_pixel, end_pixel;
2005 int missing_top, missing_bot;
2014 if (science == NULL || slits == NULL || polytraces == NULL) {
2015 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
2019 if (dispersion <= 0.0) {
2020 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
2024 if (red - blue < dispersion) {
2025 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
2029 nx = cpl_image_get_size_x(science);
2030 ny = cpl_image_get_size_y(science);
2032 sky = cpl_image_new(nx, ny, CPL_TYPE_FLOAT);
2034 sdata = cpl_image_get_data(science);
2035 kdata = cpl_image_get_data(sky);
2037 nslits = cpl_table_get_nrow(slits);
2038 order = cpl_table_get_ncol(polytraces) - 2;
2039 length = cpl_table_get_data_int(slits,
"length");
2040 slit_id = cpl_table_get_data_int(slits,
"slit_id");
2047 pixel_above = STRETCH_FACTOR * (red - reference) / dispersion;
2048 pixel_below = STRETCH_FACTOR * (reference - blue) / dispersion;
2050 for (i = 0; i < nslits; i++) {
2061 refpixel = cpl_table_get_double(slits,
"xtop", i, NULL);
2063 start_pixel = refpixel - pixel_below;
2064 if (start_pixel < 0)
2067 end_pixel = refpixel + pixel_above;
2072 polytop = cpl_polynomial_new(1);
2073 for (k = 0; k <= order; k++) {
2074 coeff = cpl_table_get_double(polytraces, clab[k], 2*i, &null);
2076 cpl_polynomial_delete(polytop);
2080 cpl_polynomial_set_coeff(polytop, &k, coeff);
2084 polybot = cpl_polynomial_new(1);
2085 for (k = 0; k <= order; k++) {
2086 coeff = cpl_table_get_double(polytraces, clab[k], 2*i+1, &null);
2088 cpl_polynomial_delete(polybot);
2092 cpl_polynomial_set_coeff(polybot, &k, coeff);
2095 if (missing_top && missing_bot) {
2096 cpl_msg_debug(func,
"Slit %d was not traced: no extraction!",
2108 cpl_msg_debug(func,
"Upper edge of slit %d was not traced: " 2109 "the spectral curvature of the lower edge " 2110 "is used instead.", slit_id[i]);
2111 polytop = cpl_polynomial_duplicate(polybot);
2112 ytop = cpl_table_get_double(slits,
"ytop", i, NULL);
2113 ybot = cpl_table_get_double(slits,
"ybottom", i, NULL);
2115 coeff = cpl_polynomial_get_coeff(polybot, &k);
2116 coeff += ytop - ybot;
2117 cpl_polynomial_set_coeff(polytop, &k, coeff);
2121 cpl_msg_debug(func,
"Lower edge of slit %d was not traced: " 2122 "the spectral curvature of the upper edge " 2123 "is used instead.", slit_id[i]);
2124 polybot = cpl_polynomial_duplicate(polytop);
2125 ytop = cpl_table_get_double(slits,
"ytop", i, NULL);
2126 ybot = cpl_table_get_double(slits,
"ybottom", i, NULL);
2128 coeff = cpl_polynomial_get_coeff(polytop, &k);
2129 coeff -= ytop - ybot;
2130 cpl_polynomial_set_coeff(polybot, &k, coeff);
2138 for (j = start_pixel; j < end_pixel; j++) {
2139 top = cpl_polynomial_eval_1d(polytop, j, NULL);
2140 bot = cpl_polynomial_eval_1d(polybot, j, NULL);
2141 itop = floor(top + 0.5) + 1;
2142 ibot = floor(bot + 0.5);
2151 list = cpl_bivector_new(npix);
2152 listx = cpl_bivector_get_x(list);
2153 listy = cpl_bivector_get_y(list);
2154 dlistx = cpl_vector_get_data(listx);
2155 dlisty = cpl_vector_get_data(listy);
2157 for (k = 0; k < npix; k++) {
2159 dlisty[k] = sdata[j + (ibot + k)*nx];
2162 if (robustLinearFit(list, &q, &m, &err)) {
2163 cpl_bivector_delete(list);
2167 cpl_bivector_delete(list);
2169 for (k = 0; k < npix; k++) {
2170 kdata[j + (ibot + k)*nx] = m*k + q;
2173 if (npix > window) {
2182 for (k = 0; k < npix; k++)
2183 if (fabs(sdata[j + (ibot + k)*nx] - m*k - q) < err)
2189 list = cpl_bivector_new(count);
2190 listx = cpl_bivector_get_x(list);
2191 listy = cpl_bivector_get_y(list);
2192 dlistx = cpl_vector_get_data(listx);
2193 dlisty = cpl_vector_get_data(listy);
2196 for (k = 0; k < npix; k++) {
2197 if (fabs(sdata[j + (ibot + k)*nx] - m*k - q) < err) {
2199 dlisty[count] = sdata[j + (ibot + k)*nx];
2204 trend = cpl_polynomial_fit_1d_create(listx, listy, 2, &err);
2206 cpl_bivector_delete(list);
2211 for (k = 0; k < npix; k++)
2212 if (fabs(sdata[j + (ibot + k)*nx]
2213 - cpl_polynomial_eval_1d(trend, k, NULL)) < err)
2217 cpl_polynomial_delete(trend);
2221 list = cpl_bivector_new(count);
2222 listx = cpl_bivector_get_x(list);
2223 listy = cpl_bivector_get_y(list);
2224 dlistx = cpl_vector_get_data(listx);
2225 dlisty = cpl_vector_get_data(listy);
2228 for (k = 0; k < npix; k++) {
2229 if (fabs(sdata[j + (ibot + k)*nx]
2230 - cpl_polynomial_eval_1d(trend, k, NULL)) < err) {
2232 dlisty[count] = sdata[j + (ibot + k)*nx];
2237 cpl_polynomial_delete(trend);
2239 trend = cpl_polynomial_fit_1d_create(listx, listy, 3, &err);
2241 cpl_bivector_delete(list);
2243 for (k = 0; k < npix; k++) {
2244 kdata[j + (ibot + k)*nx] = cpl_polynomial_eval_1d(trend,
2248 cpl_polynomial_delete(trend);
2251 cpl_polynomial_delete(polytop);
2252 cpl_polynomial_delete(polybot);
2255 cpl_image_subtract(science, sky);
2294 cpl_table *slits, cpl_table *polytraces,
2295 double reference,
double blue,
double red,
2296 double dispersion,
int sradius,
int polyorder)
2298 const char *func =
"mos_normalise_flat";
2300 const char *clab[6] = {
"c0",
"c1",
"c2",
"c3",
"c4",
"c5"};
2303 cpl_image *rectified;
2304 cpl_image *smo_flat;
2306 cpl_vector *positions;
2308 cpl_vector *smo_flux;
2309 cpl_polynomial *trend;
2310 cpl_polynomial *polytop;
2311 cpl_polynomial *polybot;
2321 double vtop, vbot, value;
2331 int pixel_above, pixel_below, refpixel, start_pixel, end_pixel;
2332 int nx, ny, nsubx, nsuby;
2333 int xlow, ylow, xhig, yhig;
2337 int missing_top, missing_bot;
2350 if (flat == NULL || slits == NULL || polytraces == NULL) {
2351 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
2355 if (dispersion <= 0.0) {
2356 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
2360 if (red - blue < dispersion) {
2361 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
2366 blue, red, dispersion, 0, NULL);
2368 nx = cpl_image_get_size_x(rectified);
2369 ny = cpl_image_get_size_y(rectified);
2371 smo_flat = cpl_image_new(cpl_image_get_size_x(spatial),
2372 cpl_image_get_size_y(spatial), CPL_TYPE_FLOAT);
2373 wdata = cpl_image_get_data(smo_flat);
2375 nslits = cpl_table_get_nrow(slits);
2376 order = cpl_table_get_ncol(polytraces) - 2;
2377 position = cpl_table_get_data_int(slits,
"position");
2378 length = cpl_table_get_data_int(slits,
"length");
2379 slit_id = cpl_table_get_data_int(slits,
"slit_id");
2386 pixel_above = STRETCH_FACTOR * (red - reference) / dispersion;
2387 pixel_below = STRETCH_FACTOR * (reference - blue) / dispersion;
2391 for (i = 0; i < nslits; i++) {
2406 ylow = position[i] + 1;
2407 yhig = ylow + length[i] - 1;
2409 exslit = cpl_image_extract(rectified, xlow, ylow, xhig, yhig);
2411 if (polyorder < 0) {
2413 cpl_image_turn(exslit, -1);
2415 nsubx = cpl_image_get_size_x(exslit);
2416 nsuby = cpl_image_get_size_y(exslit);
2417 data = cpl_image_get_data(exslit);
2418 flux = cpl_vector_new(nsubx);
2420 uradius = nsubx / 2;
2421 if (uradius > sradius)
2424 for (j = 0; j < nsuby; j++) {
2425 fdata = cpl_vector_get_data(flux);
2427 for (k = 0; k < nsubx; k++)
2429 smo_flux = cpl_vector_filter_median_create(flux, uradius);
2430 fdata = cpl_vector_get_data(smo_flux);
2432 for (k = 0; k < nsubx; k++)
2434 cpl_vector_delete(smo_flux);
2438 cpl_vector_delete(flux);
2474 cpl_image_turn(exslit, 1);
2475 nsubx = cpl_image_get_size_x(exslit);
2476 nsuby = cpl_image_get_size_y(exslit);
2477 data = cpl_image_get_data(exslit);
2479 for (j = 0; j < nsuby; j++) {
2480 flux = cpl_vector_new(nsubx);
2481 fdata = cpl_vector_get_data(flux);
2483 for (k = 0; k < nsubx; k++)
2485 smo_flux = cpl_vector_filter_median_create(flux, sradius);
2486 cpl_vector_delete(flux);
2487 fdata = cpl_vector_get_data(smo_flux);
2489 for (k = 0; k < nsubx; k++)
2491 cpl_vector_delete(smo_flux);
2501 nsubx = cpl_image_get_size_x(exslit);
2502 nsuby = cpl_image_get_size_y(exslit);
2503 data = cpl_image_get_data(exslit);
2505 for (j = 0; j < nsuby; j++) {
2513 for (k = 0; k < nsubx; k++)
2517 if (npoints > polyorder + 1) {
2523 flux = cpl_vector_new(npoints);
2524 fdata = cpl_vector_get_data(flux);
2525 positions = cpl_vector_new(npoints);
2526 pdata = cpl_vector_get_data(positions);
2530 for (k = 0; k < nsubx; k++) {
2532 fdata[npoints] = p[k];
2538 trend = cpl_polynomial_fit_1d_create(positions, flux,
2541 cpl_vector_delete(flux);
2542 cpl_vector_delete(positions);
2546 for (k = 0; k < nsubx; k++)
2548 p[k] = cpl_polynomial_eval_1d(trend, k, NULL);
2549 cpl_polynomial_delete(trend);
2552 cpl_msg_warning(func,
"Invalid flat field flux fit " 2565 refpixel = cpl_table_get_double(slits,
"xtop", i, NULL);
2567 start_pixel = refpixel - pixel_below;
2568 if (start_pixel < 0)
2571 end_pixel = refpixel + pixel_above;
2576 polytop = cpl_polynomial_new(1);
2577 for (k = 0; k <= order; k++) {
2578 coeff = cpl_table_get_double(polytraces, clab[k], 2*i, &null);
2580 cpl_polynomial_delete(polytop);
2584 cpl_polynomial_set_coeff(polytop, &k, coeff);
2588 polybot = cpl_polynomial_new(1);
2589 for (k = 0; k <= order; k++) {
2590 coeff = cpl_table_get_double(polytraces, clab[k], 2*i+1, &null);
2592 cpl_polynomial_delete(polybot);
2596 cpl_polynomial_set_coeff(polybot, &k, coeff);
2599 if (missing_top && missing_bot) {
2600 cpl_msg_debug(func,
"Slit %d was not traced: no extraction!",
2612 cpl_msg_debug(func,
"Upper edge of slit %d was not traced: " 2613 "the spectral curvature of the lower edge " 2614 "is used instead.", slit_id[i]);
2615 polytop = cpl_polynomial_duplicate(polybot);
2616 ytop = cpl_table_get_double(slits,
"ytop", i, NULL);
2617 ybot = cpl_table_get_double(slits,
"ybottom", i, NULL);
2619 coeff = cpl_polynomial_get_coeff(polybot, &k);
2620 coeff += ytop - ybot;
2621 cpl_polynomial_set_coeff(polytop, &k, coeff);
2625 cpl_msg_debug(func,
"Lower edge of slit %d was not traced: " 2626 "the spectral curvature of the upper edge " 2627 "is used instead.", slit_id[i]);
2628 polybot = cpl_polynomial_duplicate(polytop);
2629 ytop = cpl_table_get_double(slits,
"ytop", i, NULL);
2630 ybot = cpl_table_get_double(slits,
"ybottom", i, NULL);
2632 coeff = cpl_polynomial_get_coeff(polytop, &k);
2633 coeff -= ytop - ybot;
2634 cpl_polynomial_set_coeff(polybot, &k, coeff);
2645 nx = cpl_image_get_size_x(flat);
2646 ny = cpl_image_get_size_y(flat);
2648 sdata = cpl_image_get_data(spatial);
2649 xdata = cpl_image_get_data(exslit);
2650 npseudo = cpl_image_get_size_y(exslit) - 1;
2656 for (j = start_pixel; j < end_pixel; j++) {
2657 top = cpl_polynomial_eval_1d(polytop, j, NULL);
2658 bot = cpl_polynomial_eval_1d(polybot, j, NULL);
2659 for (k = 0; k <= npseudo; k++) {
2660 ypos = top - k*(top-bot)/npseudo;
2670 if (yint < 0 || yint >= ny-1) {
2675 value = sdata[j + nx*yint];
2677 fvalue = value - ivalue;
2678 if (ivalue < npseudo && ivalue >= 0) {
2679 vtop = xdata[j + nx*(npseudo-ivalue)];
2680 vbot = xdata[j + nx*(npseudo-ivalue-1)];
2681 wdata[j + nx*yint] = vtop*(1-fvalue) + vbot*fvalue;
2691 if (yprev - yint > 1) {
2692 value = sdata[j + nx*(yint+1)];
2694 fvalue = value - ivalue;
2695 if (ivalue < npseudo && ivalue >= 0) {
2696 vtop = xdata[j + nx*(npseudo-ivalue)];
2697 vbot = xdata[j + nx*(npseudo-ivalue-1)];
2698 wdata[j + nx*(yint+1)] = vtop*(1-fvalue)
2707 cpl_polynomial_delete(polytop);
2708 cpl_polynomial_delete(polybot);
2709 cpl_image_delete(exslit);
2712 cpl_image_delete(rectified);
2714 cpl_image_divide(flat, smo_flat);
2747 const char *func =
"mos_normalise_longflat";
2749 cpl_image *smo_flat;
2752 cpl_vector *smo_flux;
2753 cpl_vector *positions;
2754 cpl_polynomial *trend;
2768 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
2772 if (sradius < 1 || dradius < 1) {
2773 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
2777 smo_flat = cpl_image_duplicate(flat);
2779 if (polyorder < 0) {
2785 cpl_image_turn(smo_flat, -1);
2787 nx = cpl_image_get_size_x(smo_flat);
2788 ny = cpl_image_get_size_y(smo_flat);
2789 data = cpl_image_get_data(smo_flat);
2791 for (i = 0; i < ny; i++) {
2792 flux = cpl_vector_new(nx);
2793 fdata = cpl_vector_get_data(flux);
2795 for (j = 0; j < nx; j++)
2797 smo_flux = cpl_vector_filter_median_create(flux, sradius);
2798 cpl_vector_delete(flux);
2799 fdata = cpl_vector_get_data(smo_flux);
2801 for (j = 0; j < nx; j++)
2803 cpl_vector_delete(smo_flux);
2811 cpl_image_turn(smo_flat, 1);
2813 nx = cpl_image_get_size_x(smo_flat);
2814 ny = cpl_image_get_size_y(smo_flat);
2815 data = cpl_image_get_data(smo_flat);
2817 for (i = 0; i < ny; i++) {
2818 flux = cpl_vector_new(nx);
2819 fdata = cpl_vector_get_data(flux);
2821 for (j = 0; j < nx; j++)
2823 smo_flux = cpl_vector_filter_median_create(flux, sradius);
2824 cpl_vector_delete(flux);
2825 fdata = cpl_vector_get_data(smo_flux);
2827 for (j = 0; j < nx; j++)
2829 cpl_vector_delete(smo_flux);
2839 cpl_image_turn(smo_flat, -1);
2841 nx = cpl_image_get_size_x(smo_flat);
2842 ny = cpl_image_get_size_y(smo_flat);
2843 data = cpl_image_get_data(smo_flat);
2845 profile = cpl_image_collapse_median_create(smo_flat, 1, 0, 0);
2846 level = cpl_image_get_data(profile);
2848 for (i = 0; i < ny; i++) {
2858 for (j = 0; j < nx; j++)
2859 if (fabs(p[j]/level[i] - 1) < 0.20)
2862 if (npoints > polyorder + 1) {
2868 flux = cpl_vector_new(npoints);
2869 fdata = cpl_vector_get_data(flux);
2870 positions = cpl_vector_new(npoints);
2871 pdata = cpl_vector_get_data(positions);
2875 for (j = 0; j < nx; j++) {
2876 if (fabs(p[j]/level[i] - 1) < 0.20) {
2877 fdata[npoints] = p[j];
2883 trend = cpl_polynomial_fit_1d_create(positions, flux,
2886 cpl_vector_delete(flux);
2887 cpl_vector_delete(positions);
2891 for (j = 0; j < nx; j++)
2892 p[j] = cpl_polynomial_eval_1d(trend, j, NULL);
2893 cpl_polynomial_delete(trend);
2896 cpl_msg_warning(func,
2897 "Invalid flat field flux fit (ignored)");
2902 cpl_image_delete(profile);
2903 cpl_image_turn(smo_flat, 1);
2907 cpl_image_divide(flat, smo_flat);
2937 int order,
int global)
2939 const char *clab[6] = {
"c0",
"c1",
"c2",
"c3",
"c4",
"c5"};
2941 int nrow = cpl_table_get_nrow(slits);
2946 return CPL_ERROR_NONE;
2948 cpl_table_new_column(idscoeff,
"x", CPL_TYPE_DOUBLE);
2949 cpl_table_new_column(idscoeff,
"y", CPL_TYPE_DOUBLE);
2951 for (i = 0; i < nrow; i++) {
2952 int position = cpl_table_get_int (slits,
"position", i, NULL);
2953 int length = cpl_table_get_int (slits,
"length", i, NULL);
2954 double xtop = cpl_table_get_double(slits,
"xtop", i, NULL);
2955 double xbot = cpl_table_get_double(slits,
"xbottom", i, NULL);
2956 double ytop = cpl_table_get_double(slits,
"ytop", i, NULL);
2957 double ybot = cpl_table_get_double(slits,
"ybottom", i, NULL);
2958 double dx = xtop - xbot;
2959 double dy = ytop - ybot;
2960 cpl_table *table = cpl_table_extract(idscoeff, position, length);
2965 cpl_table_erase_window(idscoeff, position, length);
2966 cpl_table_insert(idscoeff, table, position);
2968 cpl_table_delete(table);
2970 for (j = 0; j < length; j++) {
2971 cpl_table_set_double(idscoeff,
"x", j + position,
2972 xbot + j*(dx/length));
2973 cpl_table_set_double(idscoeff,
"y", j + position,
2974 ybot + j*(dy/length));
2984 nrow = cpl_table_get_nrow(idscoeff);
2986 for (i = 0; i < 6; i++) {
2997 if (!cpl_table_has_column(idscoeff, clab[i]))
3000 npoints = nrow - cpl_table_count_invalid(idscoeff, clab[i]);
3004 dummy = cpl_table_new(nrow);
3005 cpl_table_duplicate_column(dummy,
"x", idscoeff,
"x");
3006 cpl_table_duplicate_column(dummy,
"y", idscoeff,
"y");
3007 cpl_table_duplicate_column(dummy, clab[i], idscoeff, clab[i]);
3008 cpl_table_erase_invalid(dummy);
3010 x = cpl_vector_wrap(npoints, cpl_table_get_data_double(dummy,
"x"));
3011 y = cpl_vector_wrap(npoints, cpl_table_get_data_double(dummy,
"y"));
3012 z = cpl_bivector_wrap_vectors(x, y);
3013 c = cpl_vector_wrap(npoints, cpl_table_get_data_double(dummy,
3015 p = cpl_polynomial_fit_2d_create(z, c, 2, NULL);
3016 cpl_bivector_unwrap_vectors(z);
3017 cpl_vector_unwrap(x);
3018 cpl_vector_unwrap(y);
3019 cpl_vector_unwrap(c);
3020 cpl_table_delete(dummy);
3022 point = cpl_vector_new(2);
3023 dpoint = cpl_vector_get_data(point);
3024 for (j = 0; j < nrow; j++) {
3025 dpoint[0] = cpl_table_get_double(idscoeff,
"x", j, NULL);
3026 dpoint[1] = cpl_table_get_double(idscoeff,
"y", j, NULL);
3027 cpl_table_set_double(idscoeff, clab[i], j,
3028 cpl_polynomial_eval(p, point));
3030 cpl_vector_delete(point);
3031 cpl_polynomial_delete(p);
3035 return CPL_ERROR_NONE;
3065 cpl_image *wavemap,
int mode,
3068 const char *func =
"mos_interpolate_wavecalib";
3070 const char *clab[6] = {
"c0",
"c1",
"c2",
"c3",
"c4",
"c5"};
3074 cpl_vector *positions;
3075 cpl_polynomial *trend;
3086 int nrows, first_row, last_row;
3088 int npoints, rpoints;
3095 if (idscoeff == NULL)
3096 return cpl_error_set(func, CPL_ERROR_NULL_INPUT);
3098 if (mode < 0 || mode > 2)
3099 return cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
3101 if (mode == 0 || degree < 0)
3102 return CPL_ERROR_NONE;
3110 cpl_image_turn(wavemap, -1);
3112 nx = cpl_image_get_size_x(wavemap);
3113 ny = cpl_image_get_size_y(wavemap);
3114 data = cpl_image_get_data(wavemap);
3116 for (i = 0; i < ny; i++) {
3125 for (j = 0; j < nx; j++)
3129 if (npoints > polyorder + 1) {
3135 wave = cpl_vector_new(npoints);
3136 wdata = cpl_vector_get_data(wave);
3137 positions = cpl_vector_new(npoints);
3138 pdata = cpl_vector_get_data(positions);
3142 for (j = 0; j < nx; j++) {
3144 wdata[npoints] = p[j];
3150 trend = cpl_polynomial_fit_1d_create(positions, wave,
3153 ksigma = 3*sqrt(mse);
3155 cpl_vector_delete(wave);
3156 cpl_vector_delete(positions);
3166 for (j = 0; j < nx; j++)
3168 if (fabs(cpl_polynomial_eval_1d(trend, j, NULL)
3172 if (rpoints < npoints && rpoints > polyorder + 1) {
3174 wave = cpl_vector_new(rpoints);
3175 wdata = cpl_vector_get_data(wave);
3176 positions = cpl_vector_new(rpoints);
3177 pdata = cpl_vector_get_data(positions);
3181 for (j = 0; j < nx; j++) {
3183 if (fabs(cpl_polynomial_eval_1d(trend,
3186 wdata[npoints] = p[j];
3193 cpl_polynomial_delete(trend);
3194 trend = cpl_polynomial_fit_1d_create(positions, wave,
3197 cpl_vector_delete(wave);
3198 cpl_vector_delete(positions);
3205 for (j = 0; j < nx; j++)
3207 p[j] = cpl_polynomial_eval_1d(trend, j, NULL);
3209 else if (mode == 2) {
3210 for (j = 0; j < nx; j++)
3211 p[j] = cpl_polynomial_eval_1d(trend, j, NULL);
3213 cpl_polynomial_delete(trend);
3216 cpl_msg_warning(func,
3217 "Invalid wavelength field fit (ignored)");
3223 cpl_image_turn(wavemap, 1);
3232 nrows = cpl_table_get_nrow(idscoeff);
3235 while (order < 6 && cpl_table_has_column(idscoeff, clab[order]))
3240 for (k = 0; k <= order; k++) {
3242 if (cpl_table_has_column(idscoeff, clab[k])) {
3243 m = cpl_table_get_column_median(idscoeff, clab[k]);
3244 cpl_table_fill_column_window_double(idscoeff, clab[k],
3249 return CPL_ERROR_NONE;
3253 while (!cpl_table_is_valid(idscoeff, clab[0], first_row))
3256 last_row = nrows - 1;
3257 while (!cpl_table_is_valid(idscoeff, clab[0], last_row))
3260 for (k = 0; k <= order; k++) {
3262 npoints = nrows - cpl_table_count_invalid(idscoeff, clab[k]);
3263 wave = cpl_vector_new(npoints);
3264 wdata = cpl_vector_get_data(wave);
3265 positions = cpl_vector_new(npoints);
3266 pdata = cpl_vector_get_data(positions);
3269 for (i = first_row; i <= last_row; i++) {
3270 c = cpl_table_get_double(idscoeff, clab[k], i, &null);
3288 p = cpl_vector_extract(positions, 2, npoints - 2, 1);
3289 w = cpl_vector_extract(wave, 2, npoints - 2, 1);
3296 list = cpl_bivector_wrap_vectors(p, w);
3298 robustLinearFit(list, &q, &m, &mse);
3299 cpl_bivector_unwrap_vectors(list);
3300 for (i = first_row; i <= last_row; i++)
3301 cpl_table_set_double(idscoeff, clab[k], i, q + m*i);
3304 cpl_vector_delete(p);
3305 cpl_vector_delete(w);
3308 cpl_vector_delete(wave);
3309 cpl_vector_delete(positions);
3316 trend = cpl_polynomial_fit_1d_create(positions, wave, degree, &mse);
3318 ksigma = 3*sqrt(mse);
3320 cpl_vector_delete(wave);
3321 cpl_vector_delete(positions);
3329 for (i = first_row; i <= last_row; i++) {
3330 c = cpl_table_get_double(idscoeff, clab[k], i, &null);
3332 if (fabs(cpl_polynomial_eval_1d(trend, i, NULL) - c)
3339 if (rpoints > 0 && rpoints < npoints) {
3340 cpl_msg_debug(func,
"%d points rejected from " 3341 "wavelength calibration fit",
3344 wave = cpl_vector_new(rpoints);
3345 wdata = cpl_vector_get_data(wave);
3346 positions = cpl_vector_new(rpoints);
3347 pdata = cpl_vector_get_data(positions);
3350 for (i = first_row; i <= last_row; i++) {
3351 c = cpl_table_get_double(idscoeff, clab[k], i, &null);
3353 if (fabs(cpl_polynomial_eval_1d(trend, i, NULL) - c)
3363 cpl_polynomial_delete(trend);
3364 trend = cpl_polynomial_fit_1d_create(positions,
3365 wave, degree, NULL);
3368 cpl_vector_delete(wave);
3369 cpl_vector_delete(positions);
3375 for (i = first_row; i <= last_row; i++) {
3377 if (!cpl_table_is_valid(idscoeff, clab[k], i)) {
3378 cpl_table_set_double(idscoeff, clab[k], i,
3379 cpl_polynomial_eval_1d(trend, i,
3383 else if (mode == 2) {
3384 cpl_table_set_double(idscoeff, clab[k], i,
3385 cpl_polynomial_eval_1d(trend, i, NULL));
3388 cpl_polynomial_delete(trend);
3391 cpl_msg_warning(func,
"Invalid IDS coefficient fit (ignored)");
3396 return CPL_ERROR_NONE;
3420 const char *func =
"mos_interpolate_wavecalib";
3422 const char *clab[6] = {
"c0",
"c1",
"c2",
"c3",
"c4",
"c5"};
3426 cpl_vector *positions;
3427 cpl_polynomial *trend;
3436 int nrows, first_row, last_row;
3437 int npoints, rpoints;
3442 if (idscoeff == NULL)
3443 return cpl_error_set(func, CPL_ERROR_NULL_INPUT);
3445 if (mode < 0 || mode > 2)
3446 return cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
3448 if (mode == 0 || degree < 0)
3449 return CPL_ERROR_NONE;
3455 nrows = cpl_table_get_nrow(idscoeff);
3458 while (order < 6 && cpl_table_has_column(idscoeff, clab[order]))
3467 for (
int k = kinit; k <= order; k++) {
3469 if (cpl_table_has_column(idscoeff, clab[k])) {
3470 m = cpl_table_get_column_median(idscoeff, clab[k]);
3471 cpl_table_fill_column_window_double(idscoeff, clab[k],
3479 while (!cpl_table_is_valid(idscoeff, clab[0], first_row))
3482 last_row = nrows - 1;
3483 while (!cpl_table_is_valid(idscoeff, clab[0], last_row))
3488 npoints = nrows - cpl_table_count_invalid(idscoeff, clab[korder]);
3489 wave = cpl_vector_new(npoints);
3490 wdata = cpl_vector_get_data(wave);
3491 positions = cpl_vector_new(npoints);
3492 pdata = cpl_vector_get_data(positions);
3495 for (i = first_row; i <= last_row; i++) {
3496 c = cpl_table_get_double(idscoeff, clab[korder], i, &null);
3514 p = cpl_vector_extract(positions, 2, npoints - 2, 1);
3515 w = cpl_vector_extract(wave, 2, npoints - 2, 1);
3522 list = cpl_bivector_wrap_vectors(p, w);
3524 robustLinearFit(list, &q, &m, &mse);
3525 cpl_bivector_unwrap_vectors(list);
3526 for (i = first_row; i <= last_row; i++)
3527 cpl_table_set_double(idscoeff, clab[korder], i, q + m*i);
3530 cpl_vector_delete(p);
3531 cpl_vector_delete(w);
3534 cpl_vector_delete(wave);
3535 cpl_vector_delete(positions);
3543 trend = cpl_polynomial_fit_1d_create(positions, wave, degree, &mse);
3545 ksigma = 3*sqrt(mse);
3547 cpl_vector_delete(wave);
3548 cpl_vector_delete(positions);
3556 for (i = first_row; i <= last_row; i++) {
3557 c = cpl_table_get_double(idscoeff, clab[korder], i, &null);
3559 if (fabs(cpl_polynomial_eval_1d(trend, i, NULL) - c)
3566 if (rpoints > 0 && rpoints < npoints) {
3567 cpl_msg_debug(func,
"%d points rejected from " 3568 "wavelength calibration fit",
3571 wave = cpl_vector_new(rpoints);
3572 wdata = cpl_vector_get_data(wave);
3573 positions = cpl_vector_new(rpoints);
3574 pdata = cpl_vector_get_data(positions);
3577 for (i = first_row; i <= last_row; i++) {
3578 c = cpl_table_get_double(idscoeff, clab[korder], i, &null);
3580 if (fabs(cpl_polynomial_eval_1d(trend, i, NULL) - c)
3590 cpl_polynomial_delete(trend);
3591 trend = cpl_polynomial_fit_1d_create(positions,
3592 wave, degree, NULL);
3595 cpl_vector_delete(wave);
3596 cpl_vector_delete(positions);
3602 for (i = first_row; i <= last_row; i++) {
3604 if (!cpl_table_is_valid(idscoeff, clab[korder], i)) {
3605 cpl_table_set_double(idscoeff, clab[korder], i,
3606 cpl_polynomial_eval_1d(trend, i,
3610 else if (mode == 2) {
3611 cpl_table_set_double(idscoeff, clab[korder], i,
3612 cpl_polynomial_eval_1d(trend, i, NULL));
3615 cpl_polynomial_delete(trend);
3618 cpl_msg_warning(func,
"Invalid IDS coefficient fit (ignored)");
3623 return CPL_ERROR_NONE;
3655 cpl_table *overscans)
3657 const char *func =
"mos_remove_bias";
3659 cpl_image *unbiased;
3660 cpl_image *overscan;
3661 double mean_bias_level;
3662 double mean_overscans_level;
3665 int xlow, ylow, xhig, yhig;
3669 if (image == NULL || overscans == NULL) {
3670 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
3674 nrows = cpl_table_get_nrow(overscans);
3677 cpl_msg_error(func,
"Empty overscan table");
3678 cpl_error_set(func, CPL_ERROR_DATA_NOT_FOUND);
3684 unbiased = cpl_image_subtract_create(image, bias);
3685 if (unbiased == NULL) {
3686 cpl_msg_error(func,
"Incompatible master bias");
3687 cpl_error_set(func, CPL_ERROR_INCOMPATIBLE_INPUT);
3691 mean_bias_level = cpl_image_get_mean(bias);
3695 cpl_msg_error(func,
"No master bias in input, and no overscan " 3696 "regions in input image: bias subtraction " 3697 "cannot be performed!");
3698 cpl_error_set(func, CPL_ERROR_DATA_NOT_FOUND);
3701 mean_bias_level = 0.0;
3704 mean_overscans_level = 0.0;
3706 for (i = 0; i < nrows; i++) {
3707 xlow = cpl_table_get_int(overscans,
"xlow", i, NULL);
3708 ylow = cpl_table_get_int(overscans,
"ylow", i, NULL);
3709 xhig = cpl_table_get_int(overscans,
"xhig", i, NULL);
3710 yhig = cpl_table_get_int(overscans,
"yhig", i, NULL);
3713 unbiased = cpl_image_extract(image, xlow+1, ylow+1, xhig, yhig);
3714 if (unbiased == NULL) {
3715 cpl_msg_error(func,
"Incompatible overscan table");
3716 cpl_error_set(func, CPL_ERROR_INCOMPATIBLE_INPUT);
3720 if (cpl_image_subtract(unbiased, bias)) {
3721 cpl_msg_error(func,
"Incompatible master bias");
3722 cpl_error_set(func, CPL_ERROR_INCOMPATIBLE_INPUT);
3723 cpl_image_delete(unbiased);
3729 overscan = cpl_image_extract(image, xlow+1, ylow+1, xhig, yhig);
3730 if (overscan == NULL) {
3731 cpl_msg_error(func,
"Incompatible overscan table");
3732 cpl_error_set(func, CPL_ERROR_INCOMPATIBLE_INPUT);
3733 cpl_image_delete(unbiased);
3737 mean_overscans_level += cpl_image_get_median(overscan);
3747 cpl_image_delete(overscan);
3755 mean_overscans_level /= count;
3757 cpl_image_subtract_scalar(unbiased, mean_overscans_level - mean_bias_level);
3759 cpl_msg_info(cpl_func,
3760 "Difference between mean overscans level " 3761 "and mean bias level: %.2f",
3762 mean_overscans_level - mean_bias_level);
3828 int length,
int msize,
int fsize)
3830 const char *func =
"mos_arc_background_1D";
3838 if (spectrum == NULL || back == NULL)
3839 return cpl_error_set(func, CPL_ERROR_NULL_INPUT);
3847 if (msize < 3 || fsize < msize || length < 2*fsize)
3848 return cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
3851 minf = min_filter(spectrum, length, msize);
3852 smof = smo_filter(minf, length, fsize);
3854 maxf = max_filter(smof, length, 2*msize+1);
3856 smof = smo_filter(maxf, length, 2*fsize+1);
3858 minf = min_filter(smof, length, 2*msize+1);
3860 smof = smo_filter(minf, length, 2*fsize+1);
3863 for (i = 0; i < length; i++)
3868 return CPL_ERROR_NONE;
3931 const char *func =
"mos_arc_background";
3943 if (image == NULL) {
3944 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
3954 nx = cpl_image_get_size_x(image);
3955 ny = cpl_image_get_size_y(image);
3957 bimage = cpl_image_new(nx, ny, CPL_TYPE_FLOAT);
3961 data = cpl_image_get_data_float(fimage);
3962 bdata = cpl_image_get_data_float(bimage);
3964 for (i = 0; i < ny; i++) {
3965 row = data + i * nx;
3966 brow = bdata + i * nx;
3968 cpl_error_set_where(func);
3969 cpl_image_delete(fimage);
3970 cpl_image_delete(bimage);
3975 cpl_image_delete(fimage);
4004 const char *func =
"mos_lines_width";
4006 double *profile1 = cpl_calloc(length - 1,
sizeof(
double));
4007 double *profile2 = cpl_calloc(length - 1,
sizeof(
double));
4009 double norm, value, max;
4011 int short_length = length - 2*radius - 1;
4020 for (j = 0, i = 1; i < length; j++, i++) {
4021 profile1[j] = profile2[j] = spectrum[i] - spectrum[j];
4022 if (profile1[j] < 0)
4024 if (profile2[j] > 0)
4027 profile2[j] = -profile2[j];
4038 for (i = 0; i < length; i++)
4039 if (norm < profile1[i])
4042 for (i = 0; i < length; i++) {
4043 profile1[i] /= norm;
4044 profile2[i] /= norm;
4053 for (i = 0; i <= radius; i++) {
4055 for (j = 0; j < short_length; j++) {
4057 value += profile1[k] * profile2[k+i];
4069 cpl_msg_debug(func,
"Cannot estimate line width");
4105 int length,
float level,
4109 const char *func =
"mos_peak_candidates";
4112 int nint = length - 1;
4114 int width = 2 * ceil(exp_width / 2) + 1;
4115 int start = width / 2;
4116 int end = length - width / 2;
4119 double *data = cpl_calloc(length/2,
sizeof(
double));
4122 if (spectrum == NULL) {
4123 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
4134 smo = cpl_calloc(length,
sizeof(
float));
4136 end = length - width / 2;
4137 for (i = 0; i < start; i++)
4138 smo[i] = spectrum[i];
4139 for (i = start; i < end; i++) {
4140 for (j = i - start; j <= i + start; j++)
4141 smo[i] += spectrum[j];
4144 for (i = end; i < length; i++)
4145 smo[i] = spectrum[i];
4148 smo = (
float *)spectrum;
4161 for (i = step; i < nint - step + 1; i += step) {
4162 if (smo[i] > level) {
4163 if (smo[i] >= smo[i-step] && smo[i] > smo[i+step]) {
4164 if (smo[i-step] != 0.0 && smo[i+step] != 0.0) {
4165 data[n] = i + step * values_to_dx(smo[i-step], smo[i], smo[i+step]);
4181 return cpl_vector_wrap(n, data);
4208 cpl_vector *peaks,
int sradius)
4211 const char *func =
"mos_refine_peaks";
4216 int startPos, endPos;
4217 int window = 2*sradius+1;
4221 if (peaks == NULL || spectrum == NULL) {
4222 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
4226 npeaks = cpl_vector_get_size(peaks);
4227 data = cpl_vector_unwrap(peaks);
4229 for (i = 0; i < npeaks; i++) {
4230 startPos = data[i] - window/2;
4231 endPos = startPos + window;
4232 if (startPos < 0 || endPos >= length)
4235 if (0 == peakPosition(spectrum + startPos, window, &pos, 1)) {
4241 for (i = 1; i < npeaks; i++)
4242 if (data[i] - data[i-1] < 0.5)
4245 for (i = 0, j = 0; i < npeaks; i++) {
4246 if (data[i] > 0.0) {
4253 return cpl_vector_wrap(j, data);
4258 void mos_set_multiplex(
int multiplex)
4260 mos_multiplex = multiplex;
4317 double min_disp,
double max_disp,
4325 double lratio, pratio;
4326 double lo_start, lo_end, hi_start, hi_end, denom;
4327 double disp, variation, prev_variation;
4328 int max, maxpos, minl, mink;
4330 int npeaks_lo, npeaks_hi;
4355 peak = cpl_vector_get_data(peaks);
4356 npeaks = cpl_vector_get_size(peaks);
4357 line = cpl_vector_get_data(lines);
4358 nlines = cpl_vector_get_size(lines);
4363 peak_lo = cpl_malloc(npeaks *
sizeof(
int));
4364 peak_hi = cpl_malloc(npeaks *
sizeof(
int));
4365 nident = cpl_calloc(npeaks,
sizeof(
int));
4366 lident = cpl_calloc(nlines,
sizeof(
int));
4367 xpos = cpl_calloc(npeaks,
sizeof(
double));
4368 lambda = cpl_calloc(npeaks,
sizeof(
double));
4369 ilambda = cpl_calloc(npeaks,
sizeof(
int));
4370 tmp_xpos = cpl_calloc(npeaks,
sizeof(
double));
4371 tmp_lambda = cpl_calloc(npeaks,
sizeof(
double));
4372 tmp_ilambda = cpl_calloc(npeaks,
sizeof(
int));
4373 flag = cpl_calloc(npeaks,
sizeof(
int));
4374 seq_length = cpl_calloc(npeaks,
sizeof(
int));
4375 ident = cpl_malloc(npeaks *
sizeof(
int *));
4379 for (i = 0; i < npeaks; i++)
4380 ident[i] = cpl_malloc(npeaks * npeaks *
sizeof(
int));
4395 for (i = 1; i < nlint; i++) {
4405 lratio = (line[i+1] - line[i]) / (line[i] - line[i-1]);
4412 for (j = 1; j < npint; j++) {
4425 lo_start = peak[j] - (line[i] - line[i-1]) / min_disp;
4426 lo_end = peak[j] - (line[i] - line[i-1]) / max_disp;
4427 hi_start = peak[j] + (line[i+1] - line[i]) / max_disp;
4428 hi_end = peak[j] + (line[i+1] - line[i]) / min_disp;
4430 for (npeaks_lo = 0, k = 0; k < npeaks; k++) {
4431 if (peak[k] > lo_end)
4433 if (peak[k] > lo_start) {
4434 peak_lo[npeaks_lo] = k;
4442 for (npeaks_hi = 0, k = 0; k < npeaks; k++) {
4443 if (peak[k] > hi_end)
4445 if (peak[k] > hi_start) {
4446 peak_hi[npeaks_hi] = k;
4463 prev_variation = 1000.0;
4466 for (k = 0; k < npeaks_lo; k++) {
4467 denom = peak[j] - peak[peak_lo[k]];
4468 for (l = 0; l < npeaks_hi; l++) {
4476 pratio = (peak[peak_hi[l]] - peak[j]) / denom;
4489 variation = fabs(lratio-pratio) / pratio;
4491 if (variation < tolerance) {
4492 if (variation < prev_variation) {
4493 prev_variation = variation;
4500 if (prev_variation < tolerance) {
4501 ident[j][nident[j]] = i;
4502 ident[peak_hi[minl]][nident[peak_hi[minl]]] = i + 1;
4503 ident[peak_lo[mink]][nident[peak_lo[mink]]] = i - 1;
4505 ++nident[peak_hi[minl]];
4506 ++nident[peak_lo[mink]];
4518 for (i = 0; i < npeaks; i++) {
4527 if (nident[i] > 1) {
4534 for (j = 0; j < nlines; j++)
4543 for (j = 0; j < nident[i]; j++)
4544 ++lident[ident[i][j]];
4553 for (j = 0; j < nlines; j++) {
4554 if (max < lident[j]) {
4569 for (k = maxpos + 1; k < nlines; k++) {
4570 if (lident[k] == max) {
4585 tmp_xpos[n] = peak[i];
4586 tmp_lambda[n] = line[maxpos];
4587 tmp_ilambda[n] = maxpos;
4611 for (k = 0; k < n; k++) {
4614 xpos[nn] = tmp_xpos[k];
4615 lambda[nn] = tmp_lambda[k];
4616 ilambda[nn] = tmp_ilambda[k];
4629 for (j = i + 1; j < n; j++) {
4631 disp = (tmp_lambda[j] - tmp_lambda[i])
4632 / (tmp_xpos[j] - tmp_xpos[i]);
4633 if (disp >= min_disp && disp <= max_disp) {
4635 xpos[nn] = tmp_xpos[j];
4636 lambda[nn] = tmp_lambda[j];
4637 ilambda[nn] = tmp_ilambda[j];
4667 if (mos_multiplex < 0) {
4668 for (i = 0; i < nseq; i++) {
4669 if (seq_length[i] > max) {
4670 max = seq_length[i];
4686 for (i = 0; i < nseq; i++) {
4689 cpl_array *regions = cpl_array_new(n, CPL_TYPE_INT);
4692 for (j = 0; j < n; j++)
4693 cpl_array_set_int(regions, j,
4694 ((
int)floor(xpos[nn + j])) / mos_region_size);
4696 region = (int)cpl_array_get_median(regions);
4697 cpl_array_delete(regions);
4699 if (mos_multiplex == region) {
4701 cpl_msg_debug(cpl_func,
"More than one spectrum found in " 4702 "region %d (only the first one is extracted)",
4707 max = seq_length[i];
4711 nn += seq_length[i];
4721 for (i = 0; i < maxpos; i++)
4722 nn += seq_length[i];
4729 for (i = 0; i < n; i++, nn++) {
4731 lambda[i] = lambda[nn];
4732 ilambda[i] = ilambda[nn];
4740 for (i = 1; i < n; i++) {
4741 gap = ilambda[i] - ilambda[i-1];
4742 for (j = 1; j < gap; j++) {
4750 disp = (lambda[i] - lambda[i-1]) / (xpos[i] - xpos[i-1]);
4758 hi_start = xpos[i-1] + (line[ilambda[i-1] + j] - lambda[i-1]) / disp;
4773 for (k = 0; k < npeaks; k++) {
4774 if (fabs(peak[k] - hi_start) < 2) {
4775 for (l = n; l > i; l--) {
4776 xpos[l] = xpos[l-1];
4777 lambda[l] = lambda[l-1];
4778 ilambda[l] = ilambda[l-1];
4781 lambda[i] = line[ilambda[i-1] + j];
4782 ilambda[i] = ilambda[i-1] + j;
4799 while (ilambda[n-1] < nlines - 1 && found) {
4807 disp = (lambda[n-1] - lambda[n-2]) / (xpos[n-1] - xpos[n-2]);
4811 if (disp > max_disp || disp < min_disp)
4820 hi_start = xpos[n-1] + (line[ilambda[n-1] + 1] - lambda[n-1]) / disp;
4831 min = fabs(peak[0] - hi_start);
4833 for (k = 1; k < npeaks; k++) {
4834 if (min > fabs(peak[k] - hi_start)) {
4835 min = fabs(peak[k] - hi_start);
4839 if (min < 6 && fabs(peak[minpos] - xpos[n-1]) > 1.0) {
4840 xpos[n] = peak[minpos];
4841 lambda[n] = line[ilambda[n-1] + 1];
4842 ilambda[n] = ilambda[n-1] + 1;
4854 while (ilambda[0] > 0 && found) {
4861 disp = (lambda[1] - lambda[0]) / (xpos[1] - xpos[0]);
4863 if (disp > max_disp || disp < min_disp)
4872 hi_start = xpos[0] - (lambda[0] - line[ilambda[0] - 1]) / disp;
4884 min = fabs(peak[0] - hi_start);
4886 for (k = 1; k < npeaks; k++) {
4887 if (min > fabs(peak[k] - hi_start)) {
4888 min = fabs(peak[k] - hi_start);
4892 if (min < 6 && fabs(peak[minpos] - xpos[0]) > 1.0) {
4893 for (j = n; j > 0; j--) {
4894 xpos[j] = xpos[j-1];
4895 lambda[j] = lambda[j-1];
4896 ilambda[j] = ilambda[j-1];
4898 xpos[0] = peak[minpos];
4899 lambda[0] = line[ilambda[0] - 1];
4900 ilambda[0] = ilambda[0] - 1;
4926 for (i = 0; i < npeaks; i++)
4933 cpl_free(tmp_lambda);
4934 cpl_free(tmp_ilambda);
4937 cpl_free(seq_length);
4946 return cpl_bivector_wrap_vectors(cpl_vector_wrap(n, xpos),
4947 cpl_vector_wrap(n, lambda));
5009 double refwave,
double pixel)
5015 if (cpl_polynomial_eval_1d(ids, blue-refwave, NULL) > pixel)
5018 if (cpl_polynomial_eval_1d(ids, red-refwave, NULL) < pixel)
5021 yellow = (blue + red) / 2 - refwave;
5023 coeff = cpl_polynomial_get_coeff(ids, &zero);
5024 cpl_polynomial_set_coeff(ids, &zero, coeff - pixel);
5026 cpl_polynomial_solve_1d(ids, yellow, &yellow, 1);
5027 if (cpl_error_get_code() != CPL_ERROR_NONE) {
5032 cpl_polynomial_set_coeff(ids, &zero, coeff);
5034 return yellow + refwave;
5064 double reject,
int minlines,
5065 int *nlines,
double *err,
5066 cpl_bivector **pixwav_used)
5068 const char *func =
"mos_poly_wav2pix";
5070 cpl_bivector *pixwav2;
5080 cpl_polynomial *ids;
5086 if (pixwav == NULL) {
5087 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
5091 fitlines = cpl_bivector_get_size(pixwav);
5093 if (fitlines < minlines) {
5094 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
5108 pixwav2 = cpl_bivector_duplicate(pixwav);
5118 pixel = cpl_bivector_get_x(pixwav2);
5119 wavel = cpl_bivector_get_y(pixwav2);
5127 cpl_bivector_unwrap_vectors(pixwav2);
5134 while (fitlines >= minlines) {
5136 ids = cpl_polynomial_fit_1d_create(wavel, pixel, order, err);
5140 cpl_msg_debug(cpl_error_get_where(),
"%s", cpl_error_get_message());
5141 cpl_msg_debug(func,
"Fitting IDS");
5142 cpl_error_set_where(func);
5144 cpl_vector_delete(wavel);
5145 cpl_vector_delete(pixel);
5151 cpl_vector * wavel_used = cpl_vector_duplicate(wavel);
5152 cpl_vector * pixel_used = cpl_vector_duplicate(pixel);
5159 d_pixel = cpl_vector_unwrap(pixel);
5160 d_wavel = cpl_vector_unwrap(wavel);
5162 for (i = 0, j = 0; i < fitlines; i++) {
5163 pixpos = cpl_polynomial_eval_1d(ids, d_wavel[i], NULL);
5164 if (fabs(pixpos - d_pixel[i]) < reject) {
5165 d_pixel[j] = d_pixel[i];
5166 d_wavel[j] = d_wavel[i];
5171 if (j == fitlines) {
5172 cpl_bivector * pixwav_used_temp =
5173 cpl_bivector_wrap_vectors(pixel_used, wavel_used);
5174 *pixwav_used = cpl_bivector_duplicate(pixwav_used_temp);
5175 cpl_bivector_unwrap_vectors(pixwav_used_temp);
5176 cpl_vector_delete(wavel_used);
5177 cpl_vector_delete(pixel_used);
5185 cpl_polynomial_delete(ids);
5186 if (fitlines >= minlines) {
5187 pixel = cpl_vector_wrap(fitlines, d_pixel);
5188 wavel = cpl_vector_wrap(fitlines, d_wavel);
5193 cpl_error_set(func, CPL_ERROR_CONTINUE);
5197 cpl_vector_delete(wavel_used);
5198 cpl_vector_delete(pixel_used);
5202 *pixwav_used = cpl_bivector_duplicate(pixwav2);
5236 double reject,
int minlines,
5237 int *nlines,
double *err)
5240 cpl_bivector *wavpix;
5244 cpl_polynomial *dds;
5246 cpl_bivector *wavepix_used;
5253 pixel = cpl_bivector_get_x(pixwav);
5254 wavel = cpl_bivector_get_y(pixwav);
5256 wavpix = cpl_bivector_wrap_vectors(wavel, pixel);
5261 cpl_bivector_unwrap_vectors(wavpix);
5263 cpl_bivector_delete(wavepix_used);
5293 cpl_vector *lines, cpl_polynomial *ids,
5294 double refwave,
int sradius)
5296 const char *func =
"mos_find_peaks";
5307 if (spectrum == NULL || lines == NULL || ids == NULL) {
5308 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
5312 nlines = cpl_vector_get_size(lines);
5314 if (sradius < 1 || length < 2*sradius+1 || nlines < 1) {
5315 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
5319 d_wavel = cpl_malloc(nlines *
sizeof(
double));
5320 d_pixel = cpl_malloc(nlines *
sizeof(
double));
5322 data = cpl_vector_get_data(lines);
5324 for (i = 0, j = 0; i < nlines; i++) {
5325 pixel = cpl_polynomial_eval_1d(ids, data[i]-refwave, NULL) + 0.5;
5326 if (pixel < 0 || pixel - sradius < 0 || pixel + sradius >= length)
5328 if (peakPosition(spectrum+pixel-sradius, 2*sradius+1, &pos, 1) == 0) {
5329 pos += pixel - sradius;
5331 d_wavel[j] = data[i];
5337 return cpl_bivector_wrap_vectors(cpl_vector_wrap(j, d_pixel),
5338 cpl_vector_wrap(j, d_wavel));
5343 cpl_error_set(func, CPL_ERROR_ILLEGAL_OUTPUT);
5474 double dispersion,
float level,
5475 int sradius,
int order,
5476 double reject,
double refwave,
5477 double *wavestart,
double *waveend,
5478 int *nlines,
double *error,
5479 cpl_table *idscoeff,
5480 cpl_image *calibration,
5481 cpl_image *residuals,
5482 cpl_table *restable,
5484 cpl_table *detected_lines)
5487 const char *func =
"mos_wavelength_calibration_raw";
5489 const char *clab[6] = {
"c0",
"c1",
"c2",
"c3",
"c4",
"c5"};
5492 double tolerance = 20.0;
5495 char name[MAX_COLNAME];
5496 cpl_image *resampled;
5497 cpl_bivector *output;
5498 cpl_bivector *new_output;
5501 cpl_polynomial *ids;
5502 cpl_polynomial *lin;
5505 double max_disp, min_disp;
5507 double firstLambda, lastLambda, lambda;
5508 double value, wave, pixe;
5517 int pixstart, pixend;
5520 int nl, nx, ny, pixel;
5521 int countLines, usedLines;
5523 int in, first, last;
5530 if (dispersion == 0.0) {
5531 cpl_msg_error(func,
"The expected dispersion (A/pixel) must be given");
5532 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
5536 if (dispersion < 0.0) {
5537 cpl_msg_error(func,
"The expected dispersion must be positive");
5538 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
5542 max_disp = dispersion + dispersion * tolerance / 100;
5543 min_disp = dispersion - dispersion * tolerance / 100;
5546 cpl_msg_error(func,
"The order of the fitting polynomial " 5547 "must be at least 1");
5548 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
5552 if (image == NULL || lines == NULL) {
5553 cpl_msg_error(func,
"Both spectral exposure and reference line " 5554 "catalog are required in input");
5555 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
5559 nx = cpl_image_get_size_x(image);
5560 ny = cpl_image_get_size_y(image);
5561 sdata = cpl_image_get_data_float_const(image);
5563 nref = cpl_vector_get_size(lines);
5564 line = cpl_vector_get_data(lines);
5566 if (*wavestart < 1.0 && *waveend < 1.0) {
5567 firstLambda = line[0];
5568 lastLambda = line[nref-1];
5569 extrapolation = (lastLambda - firstLambda) / 10;
5570 firstLambda -= extrapolation;
5571 lastLambda += extrapolation;
5572 *wavestart = firstLambda;
5573 *waveend = lastLambda;
5576 firstLambda = *wavestart;
5577 lastLambda = *waveend;
5580 nl = (lastLambda - firstLambda) / dispersion;
5581 resampled = cpl_image_new(nl, ny, CPL_TYPE_FLOAT);
5582 rdata = cpl_image_get_data_float(resampled);
5585 idata = cpl_image_get_data_float(calibration);
5588 ddata = cpl_image_get_data_float(residuals);
5591 for (j = 0; j <= order; j++)
5592 cpl_table_new_column(idscoeff, clab[j], CPL_TYPE_DOUBLE);
5595 cpl_table_set_size(restable, nref);
5596 cpl_table_new_column(restable,
"wavelength", CPL_TYPE_DOUBLE);
5597 cpl_table_copy_data_double(restable,
"wavelength", line);
5598 for (i = 0; i < ny; i += step) {
5599 snprintf(name, MAX_COLNAME,
"r%d", i);
5600 cpl_table_new_column(restable, name, CPL_TYPE_DOUBLE);
5601 snprintf(name, MAX_COLNAME,
"d%d", i);
5602 cpl_table_new_column(restable, name, CPL_TYPE_DOUBLE);
5603 snprintf(name, MAX_COLNAME,
"p%d", i);
5604 cpl_table_new_column(restable, name, CPL_TYPE_DOUBLE);
5608 if (detected_lines) {
5609 cpl_table_set_size(detected_lines, 0);
5610 cpl_table_new_column(detected_lines,
"xpos", CPL_TYPE_DOUBLE);
5611 cpl_table_new_column(detected_lines,
"ypos", CPL_TYPE_DOUBLE);
5612 cpl_table_new_column(detected_lines,
"xpos_iter", CPL_TYPE_DOUBLE);
5613 cpl_table_new_column(detected_lines,
"ypos_iter", CPL_TYPE_DOUBLE);
5614 cpl_table_new_column(detected_lines,
"peak_flux", CPL_TYPE_DOUBLE);
5615 cpl_table_new_column(detected_lines,
"wave_ident", CPL_TYPE_DOUBLE);
5616 cpl_table_new_column(detected_lines,
"wave_ident_iter", CPL_TYPE_DOUBLE);
5617 cpl_table_new_column(detected_lines,
"xpos_fit_rect_wavecal", CPL_TYPE_DOUBLE);
5618 cpl_table_new_column(detected_lines,
"res_xpos", CPL_TYPE_DOUBLE);
5619 cpl_table_new_column(detected_lines,
"fit_used", CPL_TYPE_INT);
5628 for (i = 0; i < ny; i++) {
5631 if (width > sradius) {
5647 cpl_bivector * peaks_ident_used_fit;
5648 countLines = cpl_bivector_get_size(output);
5649 if (countLines < 4) {
5650 cpl_bivector_delete(output);
5651 cpl_vector_delete(peaks);
5663 wavel = cpl_bivector_get_y(output);
5664 cpl_vector_subtract_scalar(wavel, refwave);
5666 uorder = countLines / 2 - 1;
5680 2 * (uorder + 1), &usedLines,
5681 &ids_err, &peaks_ident_used_fit);
5684 cpl_bivector_delete(output);
5685 cpl_vector_delete(peaks);
5702 for (k = 0; k <= order; k++) {
5704 cpl_table_set_double(idscoeff, clab[k], i, 0.0);
5707 cpl_table_set_double(idscoeff, clab[k], i,
5708 cpl_polynomial_get_coeff(ids, &k));
5715 cpl_size newlines = cpl_vector_get_size(peaks);
5716 cpl_size oldsize = cpl_table_get_nrow(detected_lines);
5717 cpl_table_set_size(detected_lines, oldsize + newlines);
5718 for(cpl_size iline = 0; iline < newlines; ++iline)
5720 cpl_table_set_double(detected_lines,
"xpos",
5721 oldsize + iline, cpl_vector_get(peaks, iline) + 1);
5722 cpl_table_set_double(detected_lines,
"ypos",
5723 oldsize + iline, (
double)i + 1);
5724 cpl_table_set_double(detected_lines,
"peak_flux",
5726 sdata[i*nx+(
int)(cpl_vector_get(peaks, iline)+0.5)]);
5727 cpl_table_set_int(detected_lines,
5729 oldsize + iline, 0);
5737 cpl_size nidentlines = cpl_bivector_get_size(output);
5738 cpl_size ndetectlines = cpl_vector_get_size(peaks);
5739 cpl_size totalsize = cpl_table_get_nrow(detected_lines);
5740 for(cpl_size idline = 0; idline < nidentlines; ++idline)
5742 for(cpl_size detline = 0; detline < ndetectlines; ++detline)
5744 if(cpl_vector_get(peaks, detline) ==
5745 cpl_bivector_get_x_data(output)[idline])
5747 cpl_size table_pos = totalsize - ndetectlines + detline;
5748 double wave_ident = cpl_bivector_get_y_data(output)[idline] + refwave;
5749 double xpix_fit = cpl_polynomial_eval_1d(ids,
5750 wave_ident - refwave, NULL);
5751 double xpos_det = cpl_table_get_double(detected_lines,
5754 cpl_table_set_double(detected_lines,
5758 cpl_table_set_double(detected_lines,
5759 "xpos_fit_rect_wavecal",
5762 cpl_table_set_double(detected_lines,
5765 xpos_det - xpix_fit - 1);
5766 cpl_table_set_int(detected_lines,
5769 for(cpl_size i_used = 0; i_used < cpl_bivector_get_size(peaks_ident_used_fit); ++i_used)
5771 if(cpl_bivector_get_x_data(output)[idline] == cpl_bivector_get_x_data(peaks_ident_used_fit)[i_used])
5772 cpl_table_set_int(detected_lines,
5782 cpl_bivector * peaks_ident_used_fit;
5789 ids, refwave, uradius);
5792 cpl_bivector_delete(output);
5793 output = new_output;
5799 cpl_polynomial_delete(ids);
5801 countLines = cpl_bivector_get_size(output);
5803 if (countLines < 4) {
5804 cpl_bivector_delete(output);
5805 cpl_vector_delete(peaks);
5818 for (k = 0; k <= order; k++)
5819 cpl_table_set_invalid(idscoeff, clab[k], i);
5823 wavel = cpl_bivector_get_y(output);
5824 cpl_vector_subtract_scalar(wavel, refwave);
5826 uorder = countLines / 2 - 1;
5831 2 * (uorder + 1), &usedLines,
5832 &ids_err, &peaks_ident_used_fit);
5835 cpl_bivector_delete(output);
5836 cpl_vector_delete(peaks);
5849 for (k = 0; k <= order; k++)
5850 cpl_table_set_invalid(idscoeff, clab[k], i);
5856 for (k = 0; k <= order; k++) {
5858 cpl_table_set_double(idscoeff, clab[k], i, 0.0);
5861 cpl_table_set_double(idscoeff, clab[k], i,
5862 cpl_polynomial_get_coeff(ids, &k));
5870 cpl_size oldsize = cpl_table_get_nrow(detected_lines);
5871 cpl_size nidentlines = cpl_bivector_get_size(output);
5872 cpl_table_set_size(detected_lines, oldsize + nidentlines);
5873 for(cpl_size idline = 0; idline < nidentlines ; ++idline)
5875 double wave_ident = cpl_bivector_get_y_data(output)[idline] + refwave;
5876 double xpix_fit = cpl_polynomial_eval_1d(ids,
5877 wave_ident - refwave, NULL);
5878 cpl_table_set_double(detected_lines,
"xpos_iter",
5879 oldsize + idline, cpl_bivector_get_x_data(output)[idline] + 1);
5880 cpl_table_set_double(detected_lines,
"ypos_iter",
5881 oldsize + idline, (
double)i + 1);
5882 cpl_table_set_double(detected_lines,
"peak_flux",
5884 sdata[i*nx+(
int)(cpl_bivector_get_x_data(output)[idline]+0.5)]);
5885 cpl_table_set_double(detected_lines,
"wave_ident_iter",
5886 oldsize + idline, wave_ident);
5887 cpl_table_set_double(detected_lines,
"xpos_fit_rect_wavecal",
5888 oldsize + idline, xpix_fit + 1);
5895 nlines[i] = usedLines;
5897 error[i] = ids_err / sqrt(usedLines/(uorder + 1));
5899 pixstart = cpl_polynomial_eval_1d(ids,
5900 cpl_bivector_get_y_data(output)[0], NULL);
5901 pixend = cpl_polynomial_eval_1d(ids,
5902 cpl_bivector_get_y_data(output)[countLines-1], NULL);
5903 extrapolation = (pixend - pixstart) / 5;
5904 pixstart -= extrapolation;
5905 pixend += extrapolation;
5916 for (j = pixstart; j < pixend; j++) {
5918 lastLambda, refwave,
5927 for (j = 0; j < nl; j++) {
5928 lambda = firstLambda + j * dispersion;
5929 fpixel = cpl_polynomial_eval_1d(ids, lambda - refwave,
5932 if (pixel >= 0 && pixel < nx-1) {
5933 v1 = (sdata + i*nx)[pixel];
5934 v2 = (sdata + i*nx)[pixel+1];
5935 vi = v1 + (v2-v1)*(fpixel-pixel);
5936 (rdata + i*nl)[j] = vi;
5944 if (residuals || (restable && !(i%step))) {
5945 if (restable && !(i%step)) {
5946 lin = cpl_polynomial_new(1);
5947 for (k = 0; k < 2; k++)
5948 cpl_polynomial_set_coeff(lin, &k,
5949 cpl_polynomial_get_coeff(ids, &k));
5951 for (j = 0; j < countLines; j++) {
5952 pixe = cpl_bivector_get_x_data(output)[j];
5953 wave = cpl_bivector_get_y_data(output)[j];
5954 value = pixe - cpl_polynomial_eval_1d(ids, wave, NULL);
5957 (ddata + i*nx)[pixel] = value;
5959 if (restable && !(i%step)) {
5960 for (k = 0; k < nref; k++) {
5961 if (fabs(line[k] - refwave - wave) < 0.1) {
5962 snprintf(name, MAX_COLNAME,
"r%d", i);
5963 cpl_table_set_double(restable, name,
5966 - cpl_polynomial_eval_1d(lin, wave,
5968 snprintf(name, MAX_COLNAME,
"d%d", i);
5969 cpl_table_set_double(restable, name,
5971 snprintf(name, MAX_COLNAME,
"p%d", i);
5972 cpl_table_set_double(restable, name,
5979 if (restable && !(i%step)) {
5980 cpl_polynomial_delete(lin);
5989 mdata = cpl_mask_get_data(refmask);
5990 pixel = cpl_polynomial_eval_1d(ids, 0.0, NULL) + 0.5;
5991 if (pixel - 1 >= 0 && pixel + 1 < nx) {
5992 mdata[pixel-1 + i*nx] = CPL_BINARY_1;
5993 mdata[pixel + i*nx] = CPL_BINARY_1;
5994 mdata[pixel+1 + i*nx] = CPL_BINARY_1;
5998 cpl_polynomial_delete(ids);
5999 cpl_bivector_delete(output);
6001 cpl_vector_delete(peaks);
6006 kernel = cpl_matrix_new(3, 3);
6007 cpl_matrix_set(kernel, 0, 1, 1.0);
6008 cpl_matrix_set(kernel, 1, 1, 1.0);
6009 cpl_matrix_set(kernel, 2, 1, 1.0);
6011 cpl_mask_dilation(refmask, kernel);
6012 cpl_mask_erosion(refmask, kernel);
6013 cpl_mask_erosion(refmask, kernel);
6014 cpl_mask_dilation(refmask, kernel);
6016 cpl_matrix_delete(kernel);
6022 mdata = cpl_mask_get_data(refmask);
6023 have_it = cpl_calloc(ny,
sizeof(
int));
6025 for (i = 0; i < ny; i++, mdata += nx) {
6026 for (j = 0; j < nx; j++) {
6027 if (mdata[j] == CPL_BINARY_1) {
6034 mdata = cpl_mask_get_data(refmask);
6038 for (i = 0; i < ny; i++) {
6044 if (abs(have_it[first] - have_it[last]) < 3) {
6045 for (j = first; j < last; j++) {
6046 mdata[have_it[first] + nx*j + 0] = CPL_BINARY_1;
6047 mdata[have_it[first] + nx*j + 1] = CPL_BINARY_1;
6048 mdata[have_it[first] + nx*j + 2] = CPL_BINARY_1;
6070 cpl_table_fill_invalid_int(detected_lines,
"fit_used", -1);
6196 const char *func =
"mos_locate_spectra";
6198 cpl_apertures *slits;
6199 cpl_image *labimage;
6200 cpl_image *refimage;
6202 cpl_propertylist *sort_col;
6208 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
6212 labimage = cpl_image_labelise_mask_create(mask, &nslits);
6215 cpl_image_delete(labimage);
6216 cpl_error_set(func, CPL_ERROR_DATA_NOT_FOUND);
6220 refimage = cpl_image_new_from_mask(mask);
6222 slits = cpl_apertures_new_from_image(refimage, labimage);
6224 cpl_image_delete(labimage);
6225 cpl_image_delete(refimage);
6227 nslits = cpl_apertures_get_size(slits);
6229 cpl_apertures_delete(slits);
6230 cpl_error_set(func, CPL_ERROR_DATA_NOT_FOUND);
6234 slitpos = cpl_table_new(nslits);
6235 cpl_table_new_column(slitpos,
"xtop", CPL_TYPE_DOUBLE);
6236 cpl_table_new_column(slitpos,
"ytop", CPL_TYPE_DOUBLE);
6237 cpl_table_new_column(slitpos,
"xbottom", CPL_TYPE_DOUBLE);
6238 cpl_table_new_column(slitpos,
"ybottom", CPL_TYPE_DOUBLE);
6239 cpl_table_set_column_unit(slitpos,
"xtop",
"pixel");
6240 cpl_table_set_column_unit(slitpos,
"ytop",
"pixel");
6241 cpl_table_set_column_unit(slitpos,
"xbottom",
"pixel");
6242 cpl_table_set_column_unit(slitpos,
"ybottom",
"pixel");
6244 for (i = 0; i < nslits; i++) {
6245 cpl_table_set_double(slitpos,
"xtop", i,
6246 cpl_apertures_get_top_x(slits, i+1) - 1);
6247 cpl_table_set_double(slitpos,
"ytop", i,
6248 cpl_apertures_get_top(slits, i+1));
6249 cpl_table_set_double(slitpos,
"xbottom", i,
6250 cpl_apertures_get_bottom_x(slits, i+1) - 1);
6251 cpl_table_set_double(slitpos,
"ybottom", i,
6252 cpl_apertures_get_bottom(slits, i+1));
6255 cpl_apertures_delete(slits);
6257 sort_col = cpl_propertylist_new();
6258 cpl_propertylist_append_bool(sort_col,
"ytop", 1);
6259 cpl_table_sort(slitpos, sort_col);
6260 cpl_propertylist_delete(sort_col);
6284 const char *func =
"mos_validate_slits";
6288 return cpl_error_set(func, CPL_ERROR_NULL_INPUT);
6290 if (1 != cpl_table_has_column(slits,
"xtop"))
6291 return cpl_error_set(func, CPL_ERROR_DATA_NOT_FOUND);
6293 if (1 != cpl_table_has_column(slits,
"ytop"))
6294 return cpl_error_set(func, CPL_ERROR_DATA_NOT_FOUND);
6296 if (1 != cpl_table_has_column(slits,
"xbottom"))
6297 return cpl_error_set(func, CPL_ERROR_DATA_NOT_FOUND);
6299 if (1 != cpl_table_has_column(slits,
"ybottom"))
6300 return cpl_error_set(func, CPL_ERROR_DATA_NOT_FOUND);
6302 if (CPL_TYPE_DOUBLE != cpl_table_get_column_type(slits,
"xtop"))
6303 return cpl_error_set(func, CPL_ERROR_INVALID_TYPE);
6305 if (CPL_TYPE_DOUBLE != cpl_table_get_column_type(slits,
"ytop"))
6306 return cpl_error_set(func, CPL_ERROR_INVALID_TYPE);
6308 if (CPL_TYPE_DOUBLE != cpl_table_get_column_type(slits,
"xbottom"))
6309 return cpl_error_set(func, CPL_ERROR_INVALID_TYPE);
6311 if (CPL_TYPE_DOUBLE != cpl_table_get_column_type(slits,
"ybottom"))
6312 return cpl_error_set(func, CPL_ERROR_INVALID_TYPE);
6314 return CPL_ERROR_NONE;
6348 const char *func =
"mos_rotate_slits";
6350 cpl_error_code error;
6351 char aux_name[] =
"_0";
6360 return CPL_ERROR_NONE;
6364 return cpl_error_set(func, error);
6366 if (rotation == 1 || rotation == 3) {
6372 for (i = 0; i < 77; i++)
6373 if (1 == cpl_table_has_column(slits, aux_name))
6375 if (1 == cpl_table_has_column(slits, aux_name))
6376 return cpl_error_set(func, CPL_ERROR_CONTINUE);
6377 cpl_table_name_column(slits,
"xtop", aux_name);
6378 cpl_table_name_column(slits,
"ytop",
"xtop");
6379 cpl_table_name_column(slits, aux_name,
"ytop");
6380 cpl_table_name_column(slits,
"xbottom", aux_name);
6381 cpl_table_name_column(slits,
"ybottom",
"xbottom");
6382 cpl_table_name_column(slits, aux_name,
"ybottom");
6385 if (rotation == 1 || rotation == 2) {
6386 cpl_table_multiply_scalar(slits,
"xtop", -1.0);
6387 cpl_table_multiply_scalar(slits,
"xbottom", -1.0);
6388 cpl_table_add_scalar(slits,
"xtop", nx);
6389 cpl_table_add_scalar(slits,
"xbottom", nx);
6392 if (rotation == 3 || rotation == 2) {
6393 cpl_table_multiply_scalar(slits,
"ytop", -1.0);
6394 cpl_table_multiply_scalar(slits,
"ybottom", -1.0);
6395 cpl_table_add_scalar(slits,
"ytop", ny);
6396 cpl_table_add_scalar(slits,
"ybottom", ny);
6399 return CPL_ERROR_NONE;
6463 cpl_array *top_ident = NULL;;
6464 cpl_array *bot_ident = NULL;;
6466 cpl_matrix *mpattern;
6467 cpl_matrix *top_data;
6468 cpl_matrix *top_pattern;
6469 cpl_matrix *top_mdata;
6470 cpl_matrix *top_mpattern;
6471 cpl_matrix *bot_data;
6472 cpl_matrix *bot_pattern;
6473 cpl_matrix *bot_mdata;
6474 cpl_matrix *bot_mpattern;
6475 cpl_propertylist *sort_col;
6484 double top_scale, bot_scale;
6485 double angle, top_angle, bot_angle;
6487 double xrms, top_xrms, bot_xrms;
6488 double yrms, top_yrms, bot_yrms;
6490 int nmaskslits, use_pattern;
6491 int found_slits, found_slits_top, found_slits_bot;
6493 cpl_table *positions;
6494 cpl_error_code error;
6503 cpl_polynomial *xpoly = NULL;
6504 cpl_polynomial *ypoly = NULL;
6505 cpl_polynomial *top_xpoly = NULL;
6506 cpl_polynomial *top_ypoly = NULL;
6507 cpl_polynomial *bot_xpoly = NULL;
6508 cpl_polynomial *bot_ypoly = NULL;
6510 char *msg_multiplex =
" ";
6515 cpl_msg_error(cpl_func,
"CCD slits table validation: %s",
6516 cpl_error_get_message());
6517 cpl_error_set(cpl_func, error);
6523 cpl_msg_error(cpl_func,
"Mask slits table validation: %s",
6524 cpl_error_get_message());
6525 cpl_error_set(cpl_func, error);
6529 if (1 != cpl_table_has_column(maskslits,
"slit_id")) {
6530 cpl_msg_error(cpl_func,
"Missing slits identifiers");
6531 cpl_error_set(cpl_func, CPL_ERROR_DATA_NOT_FOUND);
6535 if (CPL_TYPE_INT != cpl_table_get_column_type(maskslits,
"slit_id")) {
6536 cpl_msg_error(cpl_func,
"Wrong type used for slits identifiers");
6537 cpl_error_set(cpl_func, CPL_ERROR_INVALID_TYPE);
6541 nslits = cpl_table_get_nrow(slits);
6542 nmaskslits = cpl_table_get_nrow(maskslits);
6544 if (nslits == 0 || nmaskslits == 0) {
6545 cpl_msg_error(cpl_func,
"Empty slits table");
6546 cpl_error_set(cpl_func, CPL_ERROR_ILLEGAL_INPUT);
6550 if (nslits > 100 && mos_multiplex < 0) {
6551 cpl_msg_info(cpl_func,
"Many slits: using 'fast' pattern matching...");
6552 positions = mos_identify_slits_fast(slits, maskslits, global);
6553 if (positions == NULL)
6554 cpl_error_set_where(cpl_func);
6562 sort_col = cpl_propertylist_new();
6563 cpl_propertylist_append_bool(sort_col,
"ytop", 1);
6564 cpl_table_sort(slits, sort_col);
6565 cpl_table_sort(maskslits, sort_col);
6566 cpl_propertylist_delete(sort_col);
6572 if (nslits < 3 && nmaskslits > nslits) {
6582 cpl_msg_warning(cpl_func,
"Cannot match the %d found CCD slits " 6583 "with the %d mask slits: process will continue " 6584 "using the detected CCD slits positions", nslits,
6587 cpl_msg_warning(cpl_func,
"Cannot match the found CCD slit with " 6588 "the %d mask slits: process will continue using " 6589 "the detected CCD slit position", nmaskslits);
6593 if (nmaskslits < 3 && nslits > nmaskslits) {
6601 cpl_msg_warning(cpl_func,
"Cannot match the %d found CCD slits with " 6602 "the %d mask slits: process will continue using " 6603 "the detected CCD slits positions", nslits,
6615 xtop = cpl_table_get_data_double(slits,
"xtop");
6616 ytop = cpl_table_get_data_double(slits,
"ytop");
6617 xmtop = cpl_table_get_data_double(maskslits,
"xtop");
6618 ymtop = cpl_table_get_data_double(maskslits,
"ytop");
6620 xbot = cpl_table_get_data_double(slits,
"xbottom");
6621 ybot = cpl_table_get_data_double(slits,
"ybottom");
6622 xmbot = cpl_table_get_data_double(maskslits,
"xbottom");
6623 ymbot = cpl_table_get_data_double(maskslits,
"ybottom");
6625 top_data = cpl_matrix_new(2, nslits);
6626 top_pattern = cpl_matrix_new(2, nmaskslits);
6627 bot_data = cpl_matrix_new(2, nslits);
6628 bot_pattern = cpl_matrix_new(2, nmaskslits);
6630 for (i = 0; i < nslits; i++)
6631 cpl_matrix_set(top_data, 0, i, xtop[i]);
6633 for (i = 0; i < nslits; i++)
6634 cpl_matrix_set(top_data, 1, i, ytop[i]);
6636 for (i = 0; i < nmaskslits; i++)
6637 cpl_matrix_set(top_pattern, 0, i, xmtop[i]);
6639 for (i = 0; i < nmaskslits; i++)
6640 cpl_matrix_set(top_pattern, 1, i, ymtop[i]);
6642 for (i = 0; i < nslits; i++)
6643 cpl_matrix_set(bot_data, 0, i, xbot[i]);
6645 for (i = 0; i < nslits; i++)
6646 cpl_matrix_set(bot_data, 1, i, ybot[i]);
6648 for (i = 0; i < nmaskslits; i++)
6649 cpl_matrix_set(bot_pattern, 0, i, xmbot[i]);
6651 for (i = 0; i < nmaskslits; i++)
6652 cpl_matrix_set(bot_pattern, 1, i, ymbot[i]);
6654 if (nmaskslits > nslits)
6655 use_pattern = nslits;
6657 use_pattern = nmaskslits;
6659 top_ident = cpl_ppm_match_points(top_data, nslits, 1.0, top_pattern,
6660 use_pattern, 0.0, 0.1, 5, &top_mdata,
6661 &top_mpattern, &top_scale, &top_angle);
6663 bot_ident = cpl_ppm_match_points(bot_data, nslits, 1.0, bot_pattern,
6664 use_pattern, 0.0, 0.1, 5, &bot_mdata,
6665 &bot_mpattern, &bot_scale, &bot_angle);
6666 cpl_matrix_delete(top_data);
6667 cpl_matrix_delete(top_pattern);
6668 cpl_matrix_delete(bot_data);
6669 cpl_matrix_delete(bot_pattern);
6671 if (top_ident == NULL && bot_ident == NULL) {
6672 cpl_msg_warning(cpl_func,
"Pattern matching failure: cannot match " 6673 "the %d found CCD slits with the %d mask slits: " 6674 "process will continue using the detected CCD " 6675 "slits positions", nslits, nmaskslits);
6679 found_slits_top = 0;
6680 found_slits_bot = 0;
6681 if (top_ident && bot_ident) {
6682 cpl_msg_info(cpl_func,
"Median platescale: %f +/- %f pixel/mm",
6683 (top_scale + bot_scale) / 2, fabs(top_scale - bot_scale));
6684 cpl_msg_info(cpl_func,
"Median rotation: %f +/- %f degrees",
6685 (top_angle + bot_angle) / 2, fabs(top_angle - bot_angle));
6686 if (fabs(top_angle) < fabs(bot_angle))
6687 angle = fabs(top_angle);
6689 angle = fabs(bot_angle);
6690 found_slits_top = cpl_matrix_get_ncol(top_mdata);
6691 found_slits_bot = cpl_matrix_get_ncol(bot_mdata);
6693 else if (top_ident) {
6694 cpl_msg_info(cpl_func,
"Median platescale: %f pixel/mm", top_scale);
6695 cpl_msg_info(cpl_func,
"Median rotation: %f degrees", top_angle);
6696 angle = fabs(top_angle);
6697 found_slits_top = cpl_matrix_get_ncol(top_mdata);
6700 cpl_msg_info(cpl_func,
"Median platescale: %f pixel/mm", bot_scale);
6701 cpl_msg_info(cpl_func,
"Median rotation: %f degrees", bot_angle);
6702 angle = fabs(bot_angle);
6703 found_slits_bot = cpl_matrix_get_ncol(bot_mdata);
6706 cpl_array_delete(top_ident);
6707 cpl_array_delete(bot_ident);
6710 cpl_msg_warning(cpl_func,
"Uncertain pattern matching: the rotation " 6711 "angle is expected to be around zero. This match is " 6712 "rejected: the process will continue using the %d " 6713 "detected CCD slits positions", nslits);
6717 found_slits = found_slits_top;
6718 if (found_slits < found_slits_bot)
6719 found_slits = found_slits_bot;
6721 if (found_slits < 4) {
6722 cpl_msg_warning(cpl_func,
6723 "Too few safely identified slits: %d out of %d " 6724 "candidates (%d expected). Process will continue " 6725 "using the detected CCD slits positions", found_slits,
6726 nslits, nmaskslits);
6730 cpl_msg_info(cpl_func,
"Preliminary identified slits: %d out of %d " 6731 "candidates\n(%d expected)", found_slits, nslits,
6734 if (found_slits_top < 4)
6735 found_slits_top = 0;
6737 if (found_slits_bot < 4)
6738 found_slits_bot = 0;
6746 for (i = 0; i < 2; i++) {
6747 cpl_size mindeg2d[] = {0, 0};
6748 cpl_size maxdeg2d[2];
6749 cpl_vector * fitresidual;
6751 found_slits = found_slits_top;
6753 mpattern = top_mpattern;
6756 found_slits = found_slits_bot;
6758 mpattern = bot_mpattern;
6761 if (found_slits == 0)
6763 else if (found_slits < 10)
6764 maxdeg2d[0] = maxdeg2d[1] = 1;
6766 maxdeg2d[0] = maxdeg2d[1] = 2;
6768 xpos = cpl_vector_wrap(found_slits,
6769 cpl_matrix_get_data(mdata) );
6770 ypos = cpl_vector_wrap(found_slits,
6771 cpl_matrix_get_data(mdata) + found_slits);
6772 xmpos = cpl_vector_wrap(found_slits,
6773 cpl_matrix_get_data(mpattern) );
6774 ympos = cpl_vector_wrap(found_slits,
6775 cpl_matrix_get_data(mpattern) + found_slits);
6776 mpos = cpl_bivector_wrap_vectors(xmpos, ympos);
6777 fitresidual = cpl_vector_new(cpl_vector_get_size(xpos));
6778 xpoly = cpl_polynomial_new(2);
6779 cpl_polynomial_fit(xpoly, mpattern, NULL, xpos, NULL, CPL_FALSE, mindeg2d, maxdeg2d);
6780 cpl_vector_fill_polynomial_fit_residual(fitresidual, xpos, NULL, xpoly, mpattern, NULL);
6781 xmse = cpl_vector_product(fitresidual, fitresidual)
6782 / cpl_vector_get_size(fitresidual);
6783 ypoly = cpl_polynomial_new(2);
6784 cpl_polynomial_fit(ypoly, mpattern, NULL, ypos, NULL, CPL_FALSE, mindeg2d, maxdeg2d);
6785 cpl_vector_fill_polynomial_fit_residual(fitresidual, ypos, NULL, ypoly, mpattern, NULL);
6786 ymse = cpl_vector_product(fitresidual, fitresidual)
6787 / cpl_vector_get_size(fitresidual);
6789 cpl_bivector_unwrap_vectors(mpos);
6790 cpl_vector_unwrap(xpos);
6791 cpl_vector_unwrap(ypos);
6792 cpl_vector_unwrap(xmpos);
6793 cpl_vector_unwrap(ympos);
6794 cpl_matrix_delete(mdata);
6795 cpl_matrix_delete(mpattern);
6796 cpl_vector_delete(fitresidual);
6801 top_xrms = sqrt(xmse*2*maxdeg2d[0]/(found_slits - 1));
6802 top_yrms = sqrt(ymse*2*maxdeg2d[0]/(found_slits - 1));
6807 bot_xrms = sqrt(xmse*2*maxdeg2d[0]/(found_slits - 1));
6808 bot_yrms = sqrt(ymse*2*maxdeg2d[0]/(found_slits - 1));
6812 if (top_xpoly && bot_xpoly) {
6813 if (top_xrms < bot_xrms) {
6816 cpl_polynomial_delete(bot_xpoly);
6821 cpl_polynomial_delete(top_xpoly);
6824 else if (top_xpoly) {
6833 if (top_ypoly && bot_ypoly) {
6834 if (top_yrms < bot_yrms) {
6837 cpl_polynomial_delete(bot_ypoly);
6842 cpl_polynomial_delete(top_ypoly);
6845 else if (top_ypoly) {
6854 if (xpoly == NULL || ypoly == NULL) {
6855 cpl_msg_warning(cpl_func,
"Fit failure: the accuracy of the " 6856 "identified slits positions cannot be improved.");
6857 cpl_polynomial_delete(xpoly);
6858 cpl_polynomial_delete(ypoly);
6863 cpl_msg_info(cpl_func,
6864 "Fit successful: X rms = %.3g, Y rms = %.3g (pixel)",
6868 write_global_distortion(global, 0, xpoly);
6869 write_global_distortion(global, 7, ypoly);
6877 positions = cpl_table_duplicate(maskslits);
6878 cpl_table_duplicate_column(positions,
"xmtop", positions,
"xtop");
6879 cpl_table_duplicate_column(positions,
"ymtop", positions,
"ytop");
6880 cpl_table_duplicate_column(positions,
"xmbottom", positions,
"xbottom");
6881 cpl_table_duplicate_column(positions,
"ymbottom", positions,
"ybottom");
6883 point = cpl_vector_new(2);
6884 dpoint = cpl_vector_get_data(point);
6886 for (i = 0; i < nmaskslits; i++) {
6890 dpoint[0] = cpl_table_get_double(positions,
"xmtop", i, NULL);
6891 dpoint[1] = cpl_table_get_double(positions,
"ymtop", i, NULL);
6892 position_x = cpl_polynomial_eval(xpoly, point);
6899 cpl_table_set_double(positions,
"xtop", i, position_x);
6900 position_y = cpl_polynomial_eval(ypoly, point);
6901 cpl_table_set_double(positions,
"ytop", i, position_y);
6902 dpoint[0] = cpl_table_get_double(positions,
"xmbottom", i, NULL);
6903 dpoint[1] = cpl_table_get_double(positions,
"ymbottom", i, NULL);
6904 position_x = cpl_polynomial_eval(xpoly, point);
6905 cpl_table_set_double(positions,
"xbottom", i, position_x);
6906 position_y = cpl_polynomial_eval(ypoly, point);
6907 cpl_table_set_double(positions,
"ybottom", i, position_y);
6916 cpl_vector_delete(point);
6917 cpl_polynomial_delete(xpoly);
6918 cpl_polynomial_delete(ypoly);
6920 cpl_table_erase_column(positions,
"xmtop");
6921 cpl_table_erase_column(positions,
"ymtop");
6922 cpl_table_erase_column(positions,
"xmbottom");
6923 cpl_table_erase_column(positions,
"ymbottom");
6925 if (mos_multiplex >= 0) {
6927 cpl_sprintf(
"in the CCD section between %d and %d pixel",
6928 mos_multiplex * mos_region_size,
6929 (mos_multiplex + 1) * mos_region_size);
6932 if (nmaskslits > nslits)
6933 cpl_msg_info(cpl_func,
6934 "Finally identified slits: %d out of %d expected %s\n" 6935 "(%d recovered)", nmaskslits, nmaskslits, msg_multiplex,
6936 nmaskslits - nslits);
6937 else if (nmaskslits < nslits)
6938 cpl_msg_info(cpl_func,
6939 "Finally identified slits: %d out of %d expected %s\n" 6940 "(%d rejected)", nmaskslits, nmaskslits, msg_multiplex,
6941 nslits - nmaskslits);
6943 cpl_msg_info(cpl_func,
6944 "Finally identified slits: %d out of %d expected %s",
6945 nmaskslits, nmaskslits, msg_multiplex);
6947 if (mos_multiplex >= 0) {
6948 cpl_free(msg_multiplex);
6956 cpl_table *mos_identify_slits_fast(cpl_table *slits, cpl_table *maskslits,
6959 const char *func =
"mos_identify_slits_fast";
6961 cpl_propertylist *sort_col;
6962 cpl_table *positions;
6971 cpl_polynomial *xpoly = NULL;
6972 cpl_polynomial *ypoly = NULL;
6973 cpl_error_code error;
6979 double dist1, dist2, dist3, dist, mindist;
6980 double scale, minscale, maxscale;
6981 double angle, minangle, maxangle;
7008 double sradius = 0.01;
7011 double pi = 3.14159265358979323846;
7016 cpl_msg_error(func,
"CCD slits table validation: %s",
7017 cpl_error_get_message());
7018 cpl_error_set(func, error);
7024 cpl_msg_error(func,
"Mask slits table validation: %s",
7025 cpl_error_get_message());
7026 cpl_error_set(func, error);
7030 if (1 != cpl_table_has_column(maskslits,
"slit_id")) {
7031 cpl_msg_error(func,
"Missing slits identifiers");
7032 cpl_error_set(func, CPL_ERROR_DATA_NOT_FOUND);
7036 if (CPL_TYPE_INT != cpl_table_get_column_type(maskslits,
"slit_id")) {
7037 cpl_msg_error(func,
"Wrong type used for slits identifiers");
7038 cpl_error_set(func, CPL_ERROR_INVALID_TYPE);
7042 nslits = cpl_table_get_nrow(slits);
7043 nmaskslits = cpl_table_get_nrow(maskslits);
7045 if (nslits == 0 || nmaskslits == 0) {
7046 cpl_msg_error(func,
"Empty slits table");
7047 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
7057 if (cpl_table_has_column(slits,
"xcenter"))
7058 cpl_table_erase_column(slits,
"xcenter");
7060 if (cpl_table_has_column(slits,
"ycenter"))
7061 cpl_table_erase_column(slits,
"ycenter");
7063 if (cpl_table_has_column(maskslits,
"xcenter"))
7064 cpl_table_erase_column(maskslits,
"xcenter");
7066 if (cpl_table_has_column(maskslits,
"ycenter"))
7067 cpl_table_erase_column(maskslits,
"ycenter");
7069 cpl_table_duplicate_column(slits,
"xcenter", slits,
"xtop");
7070 cpl_table_add_columns(slits,
"xcenter",
"xbottom");
7071 cpl_table_divide_scalar(slits,
"xcenter", 2.0);
7072 cpl_table_duplicate_column(slits,
"ycenter", slits,
"ytop");
7073 cpl_table_add_columns(slits,
"ycenter",
"ybottom");
7074 cpl_table_divide_scalar(slits,
"ycenter", 2.0);
7076 cpl_table_duplicate_column(maskslits,
"xcenter", maskslits,
"xtop");
7077 cpl_table_add_columns(maskslits,
"xcenter",
"xbottom");
7078 cpl_table_divide_scalar(maskslits,
"xcenter", 2.0);
7079 cpl_table_duplicate_column(maskslits,
"ycenter", maskslits,
"ytop");
7080 cpl_table_add_columns(maskslits,
"ycenter",
"ybottom");
7081 cpl_table_divide_scalar(maskslits,
"ycenter", 2.0);
7088 sort_col = cpl_propertylist_new();
7089 cpl_propertylist_append_bool(sort_col,
"ycenter", 1);
7090 cpl_table_sort(slits, sort_col);
7091 cpl_table_sort(maskslits, sort_col);
7092 cpl_propertylist_delete(sort_col);
7099 if (nslits < 3 && nmaskslits > nslits) {
7109 cpl_msg_warning(func,
"Cannot match the found CCD slit with the " 7110 "%d mask slits: process will continue using the " 7111 "detected CCD slit position", nmaskslits);
7113 cpl_msg_warning(func,
"Cannot match the %d found CCD slits with " 7114 "the %d mask slits: process will continue using " 7115 "the detected CCD slits positions", nslits,
7120 if (nslits <= 3 && nslits == nmaskslits) {
7122 cpl_msg_warning(func,
"Too few slits (%d) on mask and CCD", nslits);
7123 cpl_msg_warning(func,
"Their detected positions are left unchanged");
7134 positions = cpl_table_duplicate(slits);
7135 cpl_table_erase_column(slits,
"xcenter");
7136 cpl_table_erase_column(slits,
"ycenter");
7137 cpl_table_duplicate_column(positions,
"xmtop", maskslits,
"xtop");
7138 cpl_table_duplicate_column(positions,
"ymtop", maskslits,
"ytop");
7139 cpl_table_duplicate_column(positions,
"xmbottom", maskslits,
"xbottom");
7140 cpl_table_duplicate_column(positions,
"ymbottom", maskslits,
"ybottom");
7141 cpl_table_duplicate_column(positions,
"xmcenter", maskslits,
"xcenter");
7142 cpl_table_duplicate_column(positions,
"ymcenter", maskslits,
"ycenter");
7143 cpl_table_duplicate_column(positions,
"slit_id", maskslits,
"slit_id");
7144 cpl_table_erase_column(maskslits,
"xcenter");
7145 cpl_table_erase_column(maskslits,
"ycenter");
7148 xcenter = cpl_table_get_data_double(positions,
"xcenter");
7149 ycenter = cpl_table_get_data_double(positions,
"ycenter");
7150 xmcenter = cpl_table_get_data_double(positions,
"xmcenter");
7151 ymcenter = cpl_table_get_data_double(positions,
"ymcenter");
7153 dist1 = (xcenter[0] - xcenter[1])*(xcenter[0] - xcenter[1])
7154 + (ycenter[0] - ycenter[1])*(ycenter[0] - ycenter[1]);
7155 dist2 = (xmcenter[0] - xmcenter[1])*(xmcenter[0] - xmcenter[1])
7156 + (ymcenter[0] - ymcenter[1])*(ymcenter[0] - ymcenter[1]);
7157 scale = sqrt(dist1/dist2);
7160 dist1 = (xcenter[1] - xcenter[2])*(xcenter[1] - xcenter[2])
7161 + (ycenter[1] - ycenter[2])*(ycenter[1] - ycenter[2]);
7162 dist2 = (xmcenter[1] - xmcenter[2])*(xmcenter[1] - xmcenter[2])
7163 + (ymcenter[1] - ymcenter[2])*(ymcenter[1] - ymcenter[2]);
7164 scale += sqrt(dist1/dist2);
7168 cpl_msg_info(func,
"Platescale: %f pixel/mm", scale);
7174 if (nmaskslits < 3 && nslits > nmaskslits) {
7182 cpl_msg_warning(func,
"Cannot match the %d found CCD slits with " 7183 "the %d mask slits: process will continue using " 7184 "the detected CCD slits positions", nslits,
7216 if (cpl_table_has_column(slits,
"xpseudo"))
7217 cpl_table_erase_column(slits,
"xpseudo");
7219 if (cpl_table_has_column(slits,
"ypseudo"))
7220 cpl_table_erase_column(slits,
"ypseudo");
7222 if (cpl_table_has_column(maskslits,
"xpseudo"))
7223 cpl_table_erase_column(maskslits,
"xpseudo");
7225 if (cpl_table_has_column(maskslits,
"ypseudo"))
7226 cpl_table_erase_column(maskslits,
"ypseudo");
7228 cpl_table_duplicate_column(slits,
"xpseudo", slits,
"xcenter");
7229 cpl_table_duplicate_column(slits,
"ypseudo", slits,
"ycenter");
7231 xcenter = cpl_table_get_data_double(slits,
"xcenter");
7232 ycenter = cpl_table_get_data_double(slits,
"ycenter");
7233 xpseudo = cpl_table_get_data_double(slits,
"xpseudo");
7234 ypseudo = cpl_table_get_data_double(slits,
"ypseudo");
7236 for (i = 1; i < nslits - 1; i++) {
7237 dist1 = (xcenter[i-1] - xcenter[i]) * (xcenter[i-1] - xcenter[i])
7238 + (ycenter[i-1] - ycenter[i]) * (ycenter[i-1] - ycenter[i]);
7239 dist2 = (xcenter[i-1] - xcenter[i+1]) * (xcenter[i-1] - xcenter[i+1])
7240 + (ycenter[i-1] - ycenter[i+1]) * (ycenter[i-1] - ycenter[i+1]);
7241 dist3 = (xcenter[i] - xcenter[i+1]) * (xcenter[i] - xcenter[i+1])
7242 + (ycenter[i] - ycenter[i+1]) * (ycenter[i] - ycenter[i+1]);
7243 xpseudo[i] = sqrt(dist1/dist2);
7244 ypseudo[i] = sqrt(dist3/dist2);
7247 cpl_table_set_invalid(slits,
"xpseudo", 0);
7248 cpl_table_set_invalid(slits,
"xpseudo", nslits-1);
7249 cpl_table_set_invalid(slits,
"ypseudo", 0);
7250 cpl_table_set_invalid(slits,
"ypseudo", nslits-1);
7252 cpl_table_duplicate_column(maskslits,
"xpseudo", maskslits,
"xcenter");
7253 cpl_table_duplicate_column(maskslits,
"ypseudo", maskslits,
"ycenter");
7255 xcenter = cpl_table_get_data_double(maskslits,
"xcenter");
7256 ycenter = cpl_table_get_data_double(maskslits,
"ycenter");
7257 xmpseudo = cpl_table_get_data_double(maskslits,
"xpseudo");
7258 ympseudo = cpl_table_get_data_double(maskslits,
"ypseudo");
7260 for (i = 1; i < nmaskslits - 1; i++) {
7261 dist1 = (xcenter[i-1] - xcenter[i])*(xcenter[i-1] - xcenter[i])
7262 + (ycenter[i-1] - ycenter[i])*(ycenter[i-1] - ycenter[i]);
7263 dist2 = (xcenter[i-1] - xcenter[i+1])*(xcenter[i-1] - xcenter[i+1])
7264 + (ycenter[i-1] - ycenter[i+1])*(ycenter[i-1] - ycenter[i+1]);
7265 dist3 = (xcenter[i] - xcenter[i+1])*(xcenter[i] - xcenter[i+1])
7266 + (ycenter[i] - ycenter[i+1])*(ycenter[i] - ycenter[i+1]);
7267 xmpseudo[i] = sqrt(dist1/dist2);
7268 ympseudo[i] = sqrt(dist3/dist2);
7271 cpl_table_set_invalid(maskslits,
"xpseudo", 0);
7272 cpl_table_set_invalid(maskslits,
"xpseudo", nmaskslits-1);
7273 cpl_table_set_invalid(maskslits,
"ypseudo", 0);
7274 cpl_table_set_invalid(maskslits,
"ypseudo", nmaskslits-1);
7286 if (cpl_table_has_column(slits,
"slit_id"))
7287 cpl_table_erase_column(slits,
"slit_id");
7288 cpl_table_new_column(slits,
"slit_id", CPL_TYPE_INT);
7289 slit_id = cpl_table_get_data_int(maskslits,
"slit_id");
7291 for (i = 1; i < nmaskslits - 1; i++) {
7293 mindist = (xmpseudo[i] - xpseudo[1]) * (xmpseudo[i] - xpseudo[1])
7294 + (ympseudo[i] - ypseudo[1]) * (ympseudo[i] - ypseudo[1]);
7296 if (mindist < sradius*sradius)
7298 for (j = 2; j < nslits - 1; j++) {
7299 dist = (xmpseudo[i] - xpseudo[j]) * (xmpseudo[i] - xpseudo[j])
7300 + (ympseudo[i] - ypseudo[j]) * (ympseudo[i] - ypseudo[j]);
7301 if (dist < sradius*sradius)
7305 if (mindist > dist) {
7311 mindist = sqrt(mindist);
7313 if (mindist < sradius && in_sradius == 1) {
7314 cpl_table_set_int(slits,
"slit_id", minpos-1, slit_id[i-1]);
7315 cpl_table_set_int(slits,
"slit_id", minpos, slit_id[i]);
7316 cpl_table_set_int(slits,
"slit_id", minpos+1, slit_id[i+1]);
7326 found_slits = nslits - cpl_table_count_invalid(slits,
"slit_id");
7328 if (found_slits < 3) {
7329 cpl_msg_warning(func,
"Too few preliminarily identified slits: " 7330 "%d out of %d", found_slits, nslits);
7331 if (nslits == nmaskslits) {
7332 cpl_msg_warning(func,
"(this is not an error, it could be caused " 7333 "by a mask with regularly located slits)");
7334 cpl_msg_warning(func,
"The detected slits positions are left " 7344 cpl_table_erase_column(slits,
"slit_id");
7345 cpl_table_erase_column(slits,
"xpseudo");
7346 cpl_table_erase_column(slits,
"ypseudo");
7347 positions = cpl_table_duplicate(slits);
7348 cpl_table_erase_column(slits,
"xcenter");
7349 cpl_table_erase_column(slits,
"ycenter");
7351 cpl_table_erase_column(maskslits,
"xpseudo");
7352 cpl_table_erase_column(maskslits,
"ypseudo");
7353 cpl_table_duplicate_column(positions,
"xmtop",
7355 cpl_table_duplicate_column(positions,
"ymtop",
7357 cpl_table_duplicate_column(positions,
"xmbottom",
7358 maskslits,
"xbottom");
7359 cpl_table_duplicate_column(positions,
"ymbottom",
7360 maskslits,
"ybottom");
7361 cpl_table_duplicate_column(positions,
"xmcenter",
7362 maskslits,
"xcenter");
7363 cpl_table_duplicate_column(positions,
"ymcenter",
7364 maskslits,
"ycenter");
7365 cpl_table_duplicate_column(positions,
"slit_id",
7366 maskslits,
"slit_id");
7367 cpl_table_erase_column(maskslits,
"xcenter");
7368 cpl_table_erase_column(maskslits,
"ycenter");
7372 cpl_table_erase_column(slits,
"slit_id");
7373 cpl_table_erase_column(slits,
"xpseudo");
7374 cpl_table_erase_column(slits,
"ypseudo");
7375 positions = cpl_table_duplicate(slits);
7376 cpl_table_erase_column(slits,
"xcenter");
7377 cpl_table_erase_column(slits,
"ycenter");
7378 cpl_msg_warning(func,
"(the failure could be caused " 7379 "by a mask with regularly located slits)");
7384 cpl_msg_info(func,
"Preliminarily identified slits: %d out of %d " 7385 "candidates (%d expected)", found_slits, nslits,
7396 positions = cpl_table_new(found_slits);
7397 cpl_table_new_column(positions,
"slit_id", CPL_TYPE_INT);
7398 cpl_table_new_column(positions,
"xtop", CPL_TYPE_DOUBLE);
7399 cpl_table_new_column(positions,
"ytop", CPL_TYPE_DOUBLE);
7400 cpl_table_new_column(positions,
"xbottom", CPL_TYPE_DOUBLE);
7401 cpl_table_new_column(positions,
"ybottom", CPL_TYPE_DOUBLE);
7402 cpl_table_new_column(positions,
"xcenter", CPL_TYPE_DOUBLE);
7403 cpl_table_new_column(positions,
"ycenter", CPL_TYPE_DOUBLE);
7404 cpl_table_new_column(positions,
"xmtop", CPL_TYPE_DOUBLE);
7405 cpl_table_new_column(positions,
"ymtop", CPL_TYPE_DOUBLE);
7406 cpl_table_new_column(positions,
"xmbottom", CPL_TYPE_DOUBLE);
7407 cpl_table_new_column(positions,
"ymbottom", CPL_TYPE_DOUBLE);
7408 cpl_table_new_column(positions,
"xmcenter", CPL_TYPE_DOUBLE);
7409 cpl_table_new_column(positions,
"ymcenter", CPL_TYPE_DOUBLE);
7410 cpl_table_new_column(positions,
"good", CPL_TYPE_INT);
7411 cpl_table_fill_column_window_int(positions,
"good", 0, found_slits, 0);
7413 slit_id = cpl_table_get_data_int (slits,
"slit_id");
7414 xtop = cpl_table_get_data_double(slits,
"xtop");
7415 ytop = cpl_table_get_data_double(slits,
"ytop");
7416 xbottom = cpl_table_get_data_double(slits,
"xbottom");
7417 ybottom = cpl_table_get_data_double(slits,
"ybottom");
7418 xcenter = cpl_table_get_data_double(slits,
"xcenter");
7419 ycenter = cpl_table_get_data_double(slits,
"ycenter");
7421 mslit_id = cpl_table_get_data_int (maskslits,
"slit_id");
7422 xmtop = cpl_table_get_data_double(maskslits,
"xtop");
7423 ymtop = cpl_table_get_data_double(maskslits,
"ytop");
7424 xmbottom = cpl_table_get_data_double(maskslits,
"xbottom");
7425 ymbottom = cpl_table_get_data_double(maskslits,
"ybottom");
7426 xmcenter = cpl_table_get_data_double(maskslits,
"xcenter");
7427 ymcenter = cpl_table_get_data_double(maskslits,
"ycenter");
7437 cpl_table_fill_invalid_int(slits,
"slit_id", 0);
7438 for (i = 0; i < nmaskslits; i++) {
7439 for (j = 0; j < nslits; j++) {
7440 if (slit_id[j] == 0)
7442 if (mslit_id[i] == slit_id[j]) {
7443 cpl_table_set_int (positions,
"slit_id", k, slit_id[j]);
7445 cpl_table_set_double(positions,
"xtop", k, xtop[j]);
7446 cpl_table_set_double(positions,
"ytop", k, ytop[j]);
7447 cpl_table_set_double(positions,
"xbottom", k, xbottom[j]);
7448 cpl_table_set_double(positions,
"ybottom", k, ybottom[j]);
7449 cpl_table_set_double(positions,
"xcenter", k, xcenter[j]);
7450 cpl_table_set_double(positions,
"ycenter", k, ycenter[j]);
7452 cpl_table_set_double(positions,
"xmtop", k, xmtop[i]);
7453 cpl_table_set_double(positions,
"ymtop", k, ymtop[i]);
7454 cpl_table_set_double(positions,
"xmbottom", k, xmbottom[i]);
7455 cpl_table_set_double(positions,
"ymbottom", k, ymbottom[i]);
7456 cpl_table_set_double(positions,
"xmcenter", k, xmcenter[i]);
7457 cpl_table_set_double(positions,
"ymcenter", k, ymcenter[i]);
7468 cpl_table_erase_column(slits,
"slit_id");
7469 cpl_table_erase_column(slits,
"xpseudo");
7470 cpl_table_erase_column(slits,
"ypseudo");
7471 cpl_table_erase_column(slits,
"xcenter");
7472 cpl_table_erase_column(slits,
"ycenter");
7473 cpl_table_erase_column(maskslits,
"xpseudo");
7474 cpl_table_erase_column(maskslits,
"ypseudo");
7475 cpl_table_erase_column(maskslits,
"xcenter");
7476 cpl_table_erase_column(maskslits,
"ycenter");
7486 ytop = cpl_table_get_data_double(positions,
"ytop");
7487 ybottom = cpl_table_get_data_double(positions,
"ybottom");
7488 xcenter = cpl_table_get_data_double(positions,
"xcenter");
7489 ycenter = cpl_table_get_data_double(positions,
"ycenter");
7490 xmcenter = cpl_table_get_data_double(positions,
"xmcenter");
7491 ymcenter = cpl_table_get_data_double(positions,
"ymcenter");
7493 scales = cpl_vector_new(found_slits - 1);
7494 dscale = cpl_vector_get_data(scales);
7495 angles = cpl_vector_new(found_slits - 1);
7496 dangle = cpl_vector_get_data(angles);
7498 for (i = 1; i < found_slits; i++) {
7499 dist1 = (xcenter[i-1] - xcenter[i]) * (xcenter[i-1] - xcenter[i])
7500 + (ycenter[i-1] - ycenter[i]) * (ycenter[i-1] - ycenter[i]);
7501 dist2 = (xmcenter[i-1] - xmcenter[i]) * (xmcenter[i-1] - xmcenter[i])
7502 + (ymcenter[i-1] - ymcenter[i]) * (ymcenter[i-1] - ymcenter[i]);
7503 dscale[i-1] = sqrt(dist1/dist2);
7504 dangle[i-1] = atan2(ycenter[i-1] - ycenter[i],
7505 xcenter[i-1] - xcenter[i])
7506 - atan2(ymcenter[i-1] - ymcenter[i],
7507 xmcenter[i-1] - xmcenter[i]);
7512 minscale = cpl_vector_get_min(scales);
7513 scale = cpl_vector_get_median_const(scales);
7514 maxscale = cpl_vector_get_max(scales);
7516 minangle = cpl_vector_get_min(angles);
7517 angle = cpl_vector_get_median_const(angles);
7518 maxangle = cpl_vector_get_max(angles);
7520 cpl_msg_info(func,
"Median platescale: %f pixel/mm", scale);
7521 cpl_msg_info(func,
"Minmax platescale: %f, %f pixel/mm",
7522 minscale, maxscale);
7524 cpl_msg_info(func,
"Median rotation: %f degrees", angle);
7525 cpl_msg_info(func,
"Minmax rotation: %f, %f degrees",
7526 minangle, maxangle);
7528 good = cpl_table_get_data_int(positions,
"good");
7530 good[0] = good[found_slits - 1] = 1;
7531 for (i = 1; i < found_slits; i++) {
7532 if (fabs((dscale[i-1] - scale)/scale) < 0.10
7533 && fabs(dangle[i-1] - angle) < 2) {
7539 for (i = 0; i < found_slits; i++) {
7579 cpl_vector_delete(scales);
7580 cpl_vector_delete(angles);
7582 cpl_table_and_selected_int(positions,
"good", CPL_EQUAL_TO, 0);
7583 cpl_table_erase_selected(positions);
7584 cpl_table_erase_column(positions,
"good");
7585 found_slits = cpl_table_get_nrow(positions);
7587 if (found_slits < 4) {
7595 cpl_msg_warning(func,
"Too few safely identified slits: %d out of %d " 7596 "candidates (%d expected). Process will continue " 7597 "using the detected CCD slits positions", found_slits,
7598 nslits, nmaskslits);
7599 cpl_table_delete(positions);
7603 cpl_msg_info(func,
"Safely identified slits: %d out of %d " 7604 "candidates\n(%d expected)", found_slits, nslits,
7615 xpos = cpl_vector_wrap(found_slits,
7616 cpl_table_get_data_double(positions,
"xcenter"));
7617 ypos = cpl_vector_wrap(found_slits,
7618 cpl_table_get_data_double(positions,
"ycenter"));
7619 xmpos = cpl_vector_wrap(found_slits,
7620 cpl_table_get_data_double(positions,
"xmcenter"));
7621 ympos = cpl_vector_wrap(found_slits,
7622 cpl_table_get_data_double(positions,
"ymcenter"));
7623 mpos = cpl_bivector_wrap_vectors(xmpos, ympos);
7625 if (found_slits < 10)
7630 xpoly = cpl_polynomial_fit_2d_create(mpos, xpos, degree, &xmse);
7632 ypoly = cpl_polynomial_fit_2d_create(mpos, ypos, degree, &ymse);
7633 cpl_bivector_unwrap_vectors(mpos);
7634 cpl_vector_unwrap(xpos);
7635 cpl_vector_unwrap(ypos);
7636 cpl_vector_unwrap(xmpos);
7637 cpl_vector_unwrap(ympos);
7638 if (ypoly == NULL) {
7639 if (found_slits == nmaskslits) {
7640 cpl_msg_warning(func,
"Fit failure: the accuracy of the " 7641 "identified slits positions is not improved.");
7652 cpl_msg_info(func,
"Fit failure: not all slits have been " 7653 "identified. Process will continue using " 7654 "the detected CCD slits positions");
7657 cpl_polynomial_delete(xpoly);
7661 cpl_msg_info(func,
"Fit successful: X rms = %.3g, Y rms = %.3g (pixel)",
7662 sqrt(xmse), sqrt(ymse));
7665 write_global_distortion(global, 0, xpoly);
7666 write_global_distortion(global, 7, ypoly);
7674 cpl_table_delete(positions);
7676 positions = cpl_table_duplicate(maskslits);
7677 cpl_table_duplicate_column(positions,
"xmtop", positions,
"xtop");
7678 cpl_table_duplicate_column(positions,
"ymtop", positions,
"ytop");
7679 cpl_table_duplicate_column(positions,
"xmbottom", positions,
"xbottom");
7680 cpl_table_duplicate_column(positions,
"ymbottom", positions,
"ybottom");
7682 point = cpl_vector_new(2);
7683 dpoint = cpl_vector_get_data(point);
7685 for (i = 0; i < nmaskslits; i++) {
7686 dpoint[0] = cpl_table_get_double(positions,
"xmtop", i, NULL);
7687 dpoint[1] = cpl_table_get_double(positions,
"ymtop", i, NULL);
7688 cpl_table_set_double(positions,
"xtop", i,
7689 cpl_polynomial_eval(xpoly, point));
7690 cpl_table_set_double(positions,
"ytop", i,
7691 cpl_polynomial_eval(ypoly, point));
7692 dpoint[0] = cpl_table_get_double(positions,
"xmbottom", i, NULL);
7693 dpoint[1] = cpl_table_get_double(positions,
"ymbottom", i, NULL);
7694 cpl_table_set_double(positions,
"xbottom", i,
7695 cpl_polynomial_eval(xpoly, point));
7696 cpl_table_set_double(positions,
"ybottom", i,
7697 cpl_polynomial_eval(ypoly, point));
7700 cpl_vector_delete(point);
7701 cpl_polynomial_delete(xpoly);
7702 cpl_polynomial_delete(ypoly);
7704 cpl_table_erase_column(positions,
"xmtop");
7705 cpl_table_erase_column(positions,
"ymtop");
7706 cpl_table_erase_column(positions,
"xmbottom");
7707 cpl_table_erase_column(positions,
"ymbottom");
7709 if (nmaskslits > nslits)
7710 cpl_msg_info(func,
"Finally identified slits: %d out of %d expected\n" 7711 "(%d recovered)", nmaskslits, nmaskslits, nmaskslits - nslits);
7712 else if (nmaskslits < nslits)
7713 cpl_msg_info(func,
"Finally identified slits: %d out of %d expected\n" 7714 "(%d rejected)", nmaskslits, nmaskslits, nslits - nmaskslits);
7716 cpl_msg_info(func,
"Finally identified slits: %d out of %d expected",
7717 nmaskslits, nmaskslits);
7765 double blue,
double red,
double dispersion)
7768 const char *func =
"mos_trace_flat";
7770 cpl_image *gradient;
7771 cpl_image *sgradient;
7788 double start_y, prev_y;
7797 int pixel_above, pixel_below;
7799 char trace_id[MAX_COLNAME];
7804 if (flat == NULL || slits == NULL) {
7805 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
7809 if (dispersion <= 0.0) {
7810 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
7814 if (red - blue < dispersion) {
7815 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
7824 nslits = cpl_table_get_nrow(slits);
7825 if (1 != cpl_table_has_column(slits,
"slit_id")) {
7826 cpl_table_new_column(slits,
"slit_id", CPL_TYPE_INT);
7827 for (i = 0; i < nslits; i++)
7828 cpl_table_set_int(slits,
"slit_id", i, -(i+1));
7831 slit_id = cpl_table_get_data_int(slits,
"slit_id");
7833 nx = cpl_image_get_size_x(flat);
7834 ny = cpl_image_get_size_y(flat);
7837 gradient = cpl_image_duplicate(flat);
7838 dgradient = cpl_image_get_data_float(gradient);
7840 for (i = 0; i < ny - 1; i++) {
7842 for (j = 0; j < nx; j++) {
7844 dgradient[l] = fabs(dgradient[l] - dgradient[l + nx]);
7849 for (j = 0; j < nx; j++)
7850 dgradient[npix - j] = 0.0;
7852 cpl_image_turn(gradient, -1);
7853 nx = cpl_image_get_size_x(gradient);
7854 ny = cpl_image_get_size_y(gradient);
7855 sgradient = mos_image_vertical_median_filter(gradient,
7856 filtbox, 0, ny, 0, step);
7857 cpl_image_delete(gradient);
7864 dgradient = cpl_image_get_data_float(sgradient);
7866 for (i = 1; i <= ny; i += step) {
7867 row = cpl_vector_new_from_image_row(sgradient, i);
7868 srow = cpl_vector_filter_median_create(row, filtbox);
7869 cpl_vector_subtract(row, srow);
7870 cpl_vector_delete(srow);
7871 g = dgradient + (i-1)*nx;
7872 r = cpl_vector_get_data(row);
7873 for (j = 0; j < nx; j++)
7875 cpl_vector_delete(row);
7885 xtop = cpl_table_get_data_double(slits,
"xtop");
7886 ytop = cpl_table_get_data_double(slits,
"ytop");
7887 xbottom = cpl_table_get_data_double(slits,
"xbottom");
7888 ybottom = cpl_table_get_data_double(slits,
"ybottom");
7896 peaks = cpl_calloc(ny,
sizeof(cpl_vector *));
7898 for (i = 0; i < ny; i += step) {
7899 g = dgradient + i*nx;
7905 cpl_vector_subtract_scalar(peaks[i], 0.5);
7909 cpl_image_delete(sgradient);
7935 pixel_above = STRETCH_FACTOR * (red - reference) / dispersion;
7936 pixel_below = STRETCH_FACTOR * (reference - blue) / dispersion;
7943 nrows = (ny-1)/step + 1;
7944 traces = cpl_table_new(nrows);
7945 cpl_table_new_column(traces,
"x", CPL_TYPE_DOUBLE);
7946 cpl_table_set_column_unit(traces,
"x",
"pixel");
7947 for (i = 0, j = 0; i < ny; i += step, j++)
7948 cpl_table_set(traces,
"x", j, i);
7950 for (i = 0; i < nslits; i++) {
7971 peak = cpl_vector_get_data(peaks[pos]);
7972 npeaks = cpl_vector_get_size(peaks[pos]);
7974 min = fabs(peak[0] - xtop[i]);
7976 for (j = 1; j < npeaks; j++) {
7977 dist = fabs(peak[j] - xtop[i]);
7988 snprintf(trace_id, MAX_COLNAME,
"t%d", slit_id[i]);
7989 cpl_table_new_column(traces, trace_id, CPL_TYPE_DOUBLE);
7991 if (min > sradius || npeaks == 0) {
7992 cpl_msg_warning(func,
"Cannot find spectrum edge for " 7993 "top (or left) end of slit %d", slit_id[i]);
8005 cpl_table_set(traces, trace_id, pos/step, nx - peak[minpos]);
8006 start_y = peak[minpos];
8014 for (j = pos + step; j < ny; j += step) {
8015 if (j - pos > pixel_above)
8018 peak = cpl_vector_get_data(peaks[j]);
8019 npeaks = cpl_vector_get_size(peaks[j]);
8020 min = fabs(peak[0] - prev_y);
8022 for (k = 1; k < npeaks; k++) {
8023 dist = fabs(peak[k] - prev_y);
8029 if (min < tolerance) {
8030 cpl_table_set(traces, trace_id, j/step,
8032 prev_y = peak[minpos];
8043 for (j = pos - step; j >= 0; j -= step) {
8044 if (pos - j > pixel_below)
8047 peak = cpl_vector_get_data(peaks[j]);
8048 npeaks = cpl_vector_get_size(peaks[j]);
8049 min = fabs(peak[0] - prev_y);
8051 for (k = 1; k < npeaks; k++) {
8052 dist = fabs(peak[k] - prev_y);
8058 if (min < tolerance) {
8059 cpl_table_set(traces, trace_id, j/step,
8061 prev_y = peak[minpos];
8073 peak = cpl_vector_get_data(peaks[pos]);
8074 npeaks = cpl_vector_get_size(peaks[pos]);
8076 min = fabs(peak[0] - xbottom[i]);
8078 for (j = 1; j < npeaks; j++) {
8079 dist = fabs(peak[j] - xbottom[i]);
8090 snprintf(trace_id, MAX_COLNAME,
"b%d", slit_id[i]);
8091 cpl_table_new_column(traces, trace_id, CPL_TYPE_DOUBLE);
8093 if (min > sradius || npeaks == 0) {
8094 cpl_msg_warning(func,
"Cannot find spectrum edge for " 8095 "bottom (or right) end of slit %d", slit_id[i]);
8099 cpl_table_set(traces, trace_id, pos/step, nx - peak[minpos]);
8100 start_y = peak[minpos];
8108 for (j = pos + step; j < ny; j += step) {
8109 if (j - pos > pixel_above)
8112 peak = cpl_vector_get_data(peaks[j]);
8113 npeaks = cpl_vector_get_size(peaks[j]);
8114 min = fabs(peak[0] - prev_y);
8116 for (k = 1; k < npeaks; k++) {
8117 dist = fabs(peak[k] - prev_y);
8123 if (min < tolerance) {
8124 cpl_table_set(traces, trace_id, j/step,
8126 prev_y = peak[minpos];
8137 for (j = pos - step; j >= 0; j -= step) {
8138 if (pos - j > pixel_below)
8141 peak = cpl_vector_get_data(peaks[j]);
8142 npeaks = cpl_vector_get_size(peaks[j]);
8143 min = fabs(peak[0] - prev_y);
8145 for (k = 1; k < npeaks; k++) {
8146 dist = fabs(peak[k] - prev_y);
8152 if (min < tolerance) {
8153 cpl_table_set(traces, trace_id, j/step,
8155 prev_y = peak[minpos];
8163 for (i = 0; i < ny; i += step)
8164 cpl_vector_delete(peaks[i]);
8200 const char *func =
"mos_poly_trace";
8202 cpl_table *polytraces;
8206 cpl_polynomial *polytrace;
8207 char trace_id[MAX_COLNAME];
8208 char trace_res[MAX_COLNAME];
8209 char trace_mod[MAX_COLNAME];
8210 const char *clab[6] = {
"c0",
"c1",
"c2",
"c3",
"c4",
"c5"};
8221 if (traces == NULL || slits == NULL) {
8222 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
8227 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
8231 nrows = cpl_table_get_nrow(traces);
8232 xdata = cpl_table_get_data_double(traces,
"x");
8233 nslits = cpl_table_get_nrow(slits);
8234 slit_id = cpl_table_get_data_int(slits,
"slit_id");
8236 polytraces = cpl_table_new(2*nslits);
8237 cpl_table_new_column(polytraces,
"slit_id", CPL_TYPE_INT);
8238 for (i = 0; i <= order; i++)
8239 cpl_table_new_column(polytraces, clab[i], CPL_TYPE_DOUBLE);
8241 for (i = 0; i < nslits; i++) {
8242 for (j = 0; j < 2; j++) {
8245 snprintf(trace_id, MAX_COLNAME,
"b%d", slit_id[i]);
8246 snprintf(trace_res, MAX_COLNAME,
"b%d_res", slit_id[i]);
8247 snprintf(trace_mod, MAX_COLNAME,
"b%d_mod", slit_id[i]);
8250 snprintf(trace_id, MAX_COLNAME,
"t%d", slit_id[i]);
8251 snprintf(trace_res, MAX_COLNAME,
"t%d_res", slit_id[i]);
8252 snprintf(trace_mod, MAX_COLNAME,
"t%d_mod", slit_id[i]);
8255 cpl_table_set_int(polytraces,
"slit_id", 2*i+j, slit_id[i]);
8262 dummy = cpl_table_new(nrows);
8263 cpl_table_duplicate_column(dummy,
"x", traces,
"x");
8264 cpl_table_duplicate_column(dummy, trace_id, traces, trace_id);
8265 npoints = nrows - cpl_table_count_invalid(dummy, trace_id);
8266 if (npoints < 2 * order) {
8267 cpl_table_delete(dummy);
8270 cpl_table_erase_invalid(dummy);
8271 x = cpl_vector_wrap(npoints,
8272 cpl_table_get_data_double(dummy,
"x"));
8273 trace = cpl_vector_wrap(npoints,
8274 cpl_table_get_data_double(dummy, trace_id));
8275 polytrace = cpl_polynomial_fit_1d_create(x, trace, order, NULL);
8276 cpl_vector_unwrap(x);
8277 cpl_vector_unwrap(trace);
8278 cpl_table_delete(dummy);
8287 if (fabs(cpl_polynomial_get_coeff(polytrace, &k)) > 1.E-4) {
8288 cpl_polynomial_delete(polytrace);
8289 cpl_table_new_column(traces, trace_mod, CPL_TYPE_DOUBLE);
8290 cpl_table_duplicate_column(traces, trace_res, traces,
8293 cpl_msg_warning(func,
"Exclude bad curvature solution " 8294 "for bottom (right) edge of slit %d", slit_id[i]);
8296 cpl_msg_warning(func,
"Exclude bad curvature solution " 8297 "for top (left) edge of slit %d", slit_id[i]);
8306 for (k = 0; k <= order; k++)
8307 cpl_table_set_double(polytraces, clab[k], 2*i+j,
8308 cpl_polynomial_get_coeff(polytrace, &k));
8314 cpl_table_new_column(traces, trace_mod, CPL_TYPE_DOUBLE);
8315 cpl_table_set_column_unit(traces, trace_mod,
"pixel");
8317 for (k = 0; k < nrows; k++) {
8318 cpl_table_set_double(traces, trace_mod, k,
8319 cpl_polynomial_eval_1d(polytrace, xdata[k], NULL));
8322 cpl_polynomial_delete(polytrace);
8324 cpl_table_duplicate_column(traces, trace_res, traces, trace_mod);
8325 cpl_table_subtract_columns(traces, trace_res, trace_id);
8326 cpl_table_multiply_scalar(traces, trace_res, -1.0);
8362 const char *func =
"mos_global_trace";
8364 const char *clab[6] = {
"c0",
"c1",
"c2",
"c3",
"c4",
"c5"};
8377 int order, nrows, nslits;
8381 if (polytraces == NULL) {
8382 cpl_msg_error(func,
"Missing spectral curvature table");
8383 return cpl_error_set(func, CPL_ERROR_NULL_INPUT);
8386 if (slits == NULL) {
8387 cpl_msg_error(func,
"Missing slits positions table");
8388 return cpl_error_set(func, CPL_ERROR_NULL_INPUT);
8391 nslits = cpl_table_get_nrow(slits);
8393 table = cpl_table_duplicate(polytraces);
8394 cpl_table_erase_invalid(table);
8396 nrows = cpl_table_get_nrow(table);
8399 cpl_msg_warning(func,
"Too few successful spectral curvature tracings " 8400 "(%d): the determination of a global curvature model " 8402 return CPL_ERROR_NONE;
8405 order = cpl_table_get_ncol(polytraces) - 2;
8407 for (i = 0; i <= order; i++) {
8408 if (!cpl_table_has_column(table, clab[i])) {
8409 cpl_msg_error(func,
"Wrong spectral curvature table");
8410 return cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
8419 for (i = 0; i < nslits; i++) {
8420 if (!cpl_table_is_valid(polytraces, clab[0], 2*i)) {
8421 cpl_table_set_double(polytraces, clab[0], 2*i,
8422 cpl_table_get_double(slits,
"ytop", i, NULL));
8424 if (!cpl_table_is_valid(polytraces, clab[0], 2*i+1)) {
8425 cpl_table_set_double(polytraces, clab[0], 2*i+1,
8426 cpl_table_get_double(slits,
"ybottom", i, NULL));
8430 offset = cpl_table_get_data_double(polytraces, clab[0]);
8437 c0 = cpl_vector_wrap(nrows, cpl_table_get_data_double(table, clab[0]));
8439 for (i = 1; i <= order; i++) {
8440 cn = cpl_vector_wrap(nrows, cpl_table_get_data_double(table, clab[i]));
8441 list = cpl_bivector_wrap_vectors(c0, cn);
8442 robustLinearFit(list, &q, &m, &rms);
8446 for (j = 0; j < 2*nslits; j++) {
8448 if (cpl_table_is_valid(polytraces, clab[i], j))
8450 cpl_table_set_double(polytraces, clab[i], j, offset[j]*m + q);
8456 cpl_bivector_unwrap_vectors(list);
8460 cpl_vector_unwrap(cn);
8463 cpl_vector_unwrap(c0);
8464 cpl_table_delete(table);
8466 return CPL_ERROR_NONE;
8541 cpl_table *polytraces,
double reference,
8542 double blue,
double red,
double dispersion,
8543 int flux, cpl_image *calibration)
8545 const char *func =
"mos_spatial_calibration";
8547 const char *clab[6] = {
"c0",
"c1",
"c2",
"c3",
"c4",
"c5"};
8549 cpl_polynomial *polytop;
8550 cpl_polynomial *polybot;
8552 cpl_image *resampled;
8556 double vtop, vbot, value;
8562 int yint, ysize, yprev;
8568 int pixel_above, pixel_below, refpixel, start_pixel, end_pixel;
8569 int missing_top, missing_bot;
8575 int create_position = 1;
8578 if (spectra == NULL || slits == NULL || polytraces == NULL) {
8579 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
8583 if (dispersion <= 0.0) {
8584 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
8588 if (red - blue < dispersion) {
8589 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
8593 nx = cpl_image_get_size_x(spectra);
8594 ny = cpl_image_get_size_y(spectra);
8595 sdata = cpl_image_get_data(spectra);
8597 data = cpl_image_get_data(calibration);
8599 if (cpl_table_has_column(slits,
"position"))
8600 create_position = 0;
8602 if (create_position) {
8603 cpl_table_new_column(slits,
"position", CPL_TYPE_INT);
8604 cpl_table_new_column(slits,
"length", CPL_TYPE_INT);
8605 cpl_table_set_column_unit(slits,
"position",
"pixel");
8606 cpl_table_set_column_unit(slits,
"length",
"pixel");
8609 length = cpl_table_get_data_int(slits,
"length");
8611 nslits = cpl_table_get_nrow(slits);
8612 slit_id = cpl_table_get_data_int(slits,
"slit_id");
8613 order = cpl_table_get_ncol(polytraces) - 2;
8620 pixel_above = STRETCH_FACTOR * (red - reference) / dispersion;
8621 pixel_below = STRETCH_FACTOR * (reference - blue) / dispersion;
8623 exslit = cpl_calloc(nslits,
sizeof(cpl_image *));
8625 for (i = 0; i < nslits; i++) {
8627 if (create_position == 0)
8642 refpixel = cpl_table_get_double(slits,
"xtop", i, NULL);
8644 start_pixel = refpixel - pixel_below;
8645 if (start_pixel < 0)
8648 end_pixel = refpixel + pixel_above;
8658 polytop = cpl_polynomial_new(1);
8659 for (k = 0; k <= order; k++) {
8660 coeff = cpl_table_get_double(polytraces, clab[k], 2*i, &null);
8662 cpl_polynomial_delete(polytop);
8666 cpl_polynomial_set_coeff(polytop, &k, coeff);
8670 polybot = cpl_polynomial_new(1);
8671 for (k = 0; k <= order; k++) {
8672 coeff = cpl_table_get_double(polytraces, clab[k], 2*i+1, &null);
8674 cpl_polynomial_delete(polybot);
8678 cpl_polynomial_set_coeff(polybot, &k, coeff);
8681 if (missing_top && missing_bot) {
8682 cpl_msg_warning(func,
"Spatial calibration, slit %d was not " 8683 "traced: no extraction!",
8695 cpl_msg_warning(func,
"Upper edge of slit %d was not traced: " 8696 "the spectral curvature of the lower edge " 8697 "is used instead.", slit_id[i]);
8698 polytop = cpl_polynomial_duplicate(polybot);
8699 ytop = cpl_table_get_double(slits,
"ytop", i, NULL);
8700 ybot = cpl_table_get_double(slits,
"ybottom", i, NULL);
8702 coeff = cpl_polynomial_get_coeff(polybot, &k);
8703 coeff += ytop - ybot;
8704 cpl_polynomial_set_coeff(polytop, &k, coeff);
8708 cpl_msg_warning(func,
"Lower edge of slit %d was not traced: " 8709 "the spectral curvature of the upper edge " 8710 "is used instead.", slit_id[i]);
8711 polybot = cpl_polynomial_duplicate(polytop);
8712 ytop = cpl_table_get_double(slits,
"ytop", i, NULL);
8713 ybot = cpl_table_get_double(slits,
"ybottom", i, NULL);
8715 coeff = cpl_polynomial_get_coeff(polytop, &k);
8716 coeff -= ytop - ybot;
8717 cpl_polynomial_set_coeff(polybot, &k, coeff);
8724 top = cpl_polynomial_eval_1d(polytop, refpixel, NULL);
8725 bot = cpl_polynomial_eval_1d(polybot, refpixel, NULL);
8726 npseudo = ceil(top-bot) + 1;
8729 cpl_polynomial_delete(polytop);
8730 cpl_polynomial_delete(polybot);
8731 cpl_msg_warning(func,
"Slit %d was badly traced: no extraction!",
8736 exslit[i] = cpl_image_new(nx, npseudo+1, CPL_TYPE_FLOAT);
8737 xdata = cpl_image_get_data(exslit[i]);
8743 for (j = start_pixel; j < end_pixel; j++) {
8744 top = cpl_polynomial_eval_1d(polytop, j, NULL);
8745 bot = cpl_polynomial_eval_1d(polybot, j, NULL);
8746 factor = (top-bot)/npseudo;
8747 for (k = 0; k <= npseudo; k++) {
8748 ypos = top - k*factor;
8751 if (yint >= 0 && yint < ny-1) {
8752 vtop = sdata[j + nx*yint];
8753 vbot = sdata[j + nx*(yint+1)];
8759 else if(vtop == FLT_MAX || vbot == FLT_MAX)
8763 value = vtop*(1-yfra) + vbot*yfra;
8767 xdata[j + nx*(npseudo-k)] = value;
8769 data[j + nx*yint] = (top-yint)/factor;
8778 if (yprev - yint > 1) {
8779 data[j + nx*(yint+1)] = (top-yint-1)/factor;
8787 cpl_polynomial_delete(polytop);
8788 cpl_polynomial_delete(polybot);
8796 for (i = 0; i < nslits; i++)
8798 ysize += cpl_image_get_size_y(exslit[i]);
8803 resampled = cpl_image_new(nx, ysize, CPL_TYPE_FLOAT);
8806 for (i = 0; i < nslits; i++) {
8808 yint += cpl_image_get_size_y(exslit[i]);
8809 cpl_image_copy(resampled, exslit[i], 1, ysize - yint);
8810 if (create_position) {
8811 cpl_table_set_int(slits,
"position", i, ysize - yint - 1);
8812 cpl_table_set_int(slits,
"length", i,
8813 cpl_image_get_size_y(exslit[i]));
8815 cpl_image_delete(exslit[i]);
8817 else if (create_position) {
8818 cpl_table_set_int(slits,
"position", i, -1);
8819 cpl_table_set_int(slits,
"length", i, 0);
8960 double dispersion,
float level,
8961 int sradius,
int order,
8962 double reject,
double refwave,
8963 double *wavestart,
double *waveend,
8964 int *nlines,
double *error,
8965 cpl_table *idscoeff,
8966 cpl_image *calibration,
8967 cpl_image *residuals,
8968 cpl_table *restable,
8969 cpl_table *detected_lines)
8972 const char *func =
"mos_wavelength_calibration_final";
8974 const char *clab[6] = {
"c0",
"c1",
"c2",
"c3",
"c4",
"c5"};
8977 double tolerance = 20.0;
8980 char name[MAX_COLNAME];
8982 cpl_image *resampled;
8983 cpl_bivector *peaks_ident;
8986 cpl_polynomial *ids;
8987 cpl_polynomial *lin;
8988 cpl_polynomial *fguess;
8991 double max_disp, min_disp;
8993 double firstLambda, lastLambda, lambda;
8994 double wave, pixe, value;
9003 int pixstart, pixend;
9004 int row_top, row_bot;
9009 int nl, nx, ny, pixel;
9010 int countLines, usedLines;
9019 if (dispersion == 0.0) {
9020 cpl_msg_error(func,
"The expected dispersion (A/pixel) must be given");
9021 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
9025 if (dispersion < 0.0) {
9026 cpl_msg_error(func,
"The expected dispersion must be positive");
9027 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
9031 if (idscoeff == NULL) {
9032 cpl_msg_error(func,
"A preallocated IDS coeff table must be given");
9033 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
9037 max_disp = dispersion + dispersion * tolerance / 100;
9038 min_disp = dispersion - dispersion * tolerance / 100;
9041 cpl_msg_error(func,
"The order of the fitting polynomial " 9042 "must be at least 1");
9043 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
9047 if (image == NULL || lines == NULL) {
9048 cpl_msg_error(func,
"Both spectral exposure and reference line " 9049 "catalog are required in input");
9050 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
9054 nx = cpl_image_get_size_x(image);
9055 ny = cpl_image_get_size_y(image);
9056 sdata = cpl_image_get_data_float(image);
9058 nref = cpl_vector_get_size(lines);
9059 line = cpl_vector_get_data(lines);
9061 if (*wavestart < 1.0 && *waveend < 1.0) {
9062 firstLambda = line[0];
9063 lastLambda = line[nref-1];
9064 extrapolation = (lastLambda - firstLambda) / 10;
9065 firstLambda -= extrapolation;
9066 lastLambda += extrapolation;
9067 *wavestart = firstLambda;
9068 *waveend = lastLambda;
9071 firstLambda = *wavestart;
9072 lastLambda = *waveend;
9075 nl = (lastLambda - firstLambda) / dispersion;
9076 resampled = cpl_image_new(nl, ny, CPL_TYPE_FLOAT);
9077 rdata = cpl_image_get_data_float(resampled);
9083 for (j = 0; j <= order; j++)
9084 cpl_table_new_column(idscoeff, clab[j], CPL_TYPE_DOUBLE);
9087 idata = cpl_image_get_data_float(calibration);
9090 ddata = cpl_image_get_data_float(residuals);
9093 cpl_table_set_size(restable, nref);
9094 cpl_table_new_column(restable,
"wavelength", CPL_TYPE_DOUBLE);
9095 cpl_table_copy_data_double(restable,
"wavelength", line);
9096 for (i = 0; i < ny; i += step) {
9097 snprintf(name, MAX_COLNAME,
"r%d", i);
9098 cpl_table_new_column(restable, name, CPL_TYPE_DOUBLE);
9099 snprintf(name, MAX_COLNAME,
"d%d", i);
9100 cpl_table_new_column(restable, name, CPL_TYPE_DOUBLE);
9101 snprintf(name, MAX_COLNAME,
"p%d", i);
9102 cpl_table_new_column(restable, name, CPL_TYPE_DOUBLE);
9106 if (detected_lines) {
9107 cpl_table_set_size(detected_lines, 0);
9108 cpl_table_new_column(detected_lines,
"slit_id", CPL_TYPE_INT);
9109 cpl_table_new_column(detected_lines,
"xpos_rectified", CPL_TYPE_DOUBLE);
9110 cpl_table_new_column(detected_lines,
"ypos_rectified", CPL_TYPE_DOUBLE);
9111 cpl_table_new_column(detected_lines,
"xpos_rectified_iter", CPL_TYPE_DOUBLE);
9112 cpl_table_new_column(detected_lines,
"ypos_rectified_iter", CPL_TYPE_DOUBLE);
9113 cpl_table_new_column(detected_lines,
"peak_flux", CPL_TYPE_DOUBLE);
9114 cpl_table_new_column(detected_lines,
"wave_ident", CPL_TYPE_DOUBLE);
9115 cpl_table_new_column(detected_lines,
"wave_ident_iter", CPL_TYPE_DOUBLE);
9116 cpl_table_new_column(detected_lines,
"xpos_fit_rect_wavecal", CPL_TYPE_DOUBLE);
9117 cpl_table_new_column(detected_lines,
"res_xpos", CPL_TYPE_DOUBLE);
9118 cpl_table_new_column(detected_lines,
"fit_used", CPL_TYPE_INT);
9126 nslits = cpl_table_get_nrow(slits);
9127 length = cpl_table_get_data_int(slits,
"length");
9130 for (s = 0; s < nslits; s++) {
9133 slit_id = cpl_table_get_int(slits,
"slit_id", s, NULL);
9143 row_bot = cpl_table_get_int(slits,
"position", s, NULL);
9155 coeff = cpl_table_new(row_top - row_bot);
9156 for (j = 0; j <= order; j++)
9157 cpl_table_new_column(coeff, clab[j], CPL_TYPE_DOUBLE);
9165 for (i = row_bot; i < row_top; i++) {
9174 int keep_multiplex = mos_multiplex;
9178 cpl_size newlines = cpl_vector_get_size(peaks);
9179 cpl_size oldsize = cpl_table_get_nrow(detected_lines);
9180 cpl_table_set_size(detected_lines, oldsize + newlines);
9181 for(cpl_size iline = 0; iline < newlines; ++iline)
9183 cpl_table_set_int(detected_lines,
"slit_id",
9184 oldsize + iline, slit_id);
9185 cpl_table_set_double(detected_lines,
"xpos_rectified",
9186 oldsize + iline, cpl_vector_get(peaks, iline) + 1);
9187 cpl_table_set_double(detected_lines,
"ypos_rectified",
9188 oldsize + iline, (
double)i + 1);
9189 cpl_table_set_double(detected_lines,
"peak_flux",
9191 sdata[i*nx+(
int)(cpl_vector_get(peaks, iline)+0.5)]);
9192 cpl_table_set_int(detected_lines,
9194 oldsize + iline, 0);
9198 min_disp, max_disp, 0.05);
9199 mos_multiplex = keep_multiplex;
9201 cpl_bivector * peaks_ident_used_fit;
9202 countLines = cpl_bivector_get_size(peaks_ident);
9203 if (countLines < 4) {
9204 cpl_bivector_delete(peaks_ident);
9205 cpl_vector_delete(peaks);
9217 wavel = cpl_bivector_get_y(peaks_ident);
9218 cpl_vector_subtract_scalar(wavel, refwave);
9220 uorder = countLines / 2 - 1;
9225 2 * (uorder + 1), &usedLines,
9226 &ids_err, &peaks_ident_used_fit);
9229 cpl_bivector_delete(peaks_ident);
9230 cpl_vector_delete(peaks);
9240 for (k = 0; k <= order; k++) {
9242 cpl_table_set_double(coeff, clab[k],
9246 cpl_table_set_double(coeff, clab[k],
9247 i - row_bot, cpl_polynomial_get_coeff(ids, &k));
9253 pixstart = cpl_polynomial_eval_1d(ids,
9254 cpl_bivector_get_y_data(peaks_ident)[0],
9256 pixend = cpl_polynomial_eval_1d(ids,
9257 cpl_bivector_get_y_data(peaks_ident)[countLines-1],
9259 extrapolation = (pixend - pixstart) / 5;
9260 pixstart -= extrapolation;
9261 pixend += extrapolation;
9267 for (j = pixstart; j < pixend; j++) {
9269 firstLambda, lastLambda, refwave, j);
9277 if (residuals || (restable && !(i%step))) {
9278 if (restable && !(i%step)) {
9279 lin = cpl_polynomial_new(1);
9280 for (k = 0; k < 2; k++)
9281 cpl_polynomial_set_coeff(lin, &k,
9282 cpl_polynomial_get_coeff(ids, &k));
9284 for (j = 0; j < countLines; j++) {
9285 pixe = cpl_bivector_get_x_data(peaks_ident)[j];
9286 wave = cpl_bivector_get_y_data(peaks_ident)[j];
9288 - cpl_polynomial_eval_1d(ids, wave, NULL);
9291 (ddata + i*nx)[pixel] = value;
9293 if (restable && !(i%step)) {
9294 for (k = 0; k < nref; k++) {
9295 if (fabs(line[k]-refwave-wave) < 0.1) {
9296 snprintf(name, MAX_COLNAME,
9298 cpl_table_set_double(restable, name,
9301 - cpl_polynomial_eval_1d(lin,
9303 snprintf(name, MAX_COLNAME,
9305 cpl_table_set_double(restable, name,
9307 snprintf(name, MAX_COLNAME,
9309 cpl_table_set_double(restable, name,
9316 if (restable && !(i%step)) {
9317 cpl_polynomial_delete(lin);
9334 cpl_size nidentlines = cpl_bivector_get_size(peaks_ident);
9335 cpl_size ndetectlines = cpl_vector_get_size(peaks);
9336 cpl_size totalsize = cpl_table_get_nrow(detected_lines);
9337 for(cpl_size idline = 0; idline < nidentlines; ++idline)
9339 for(cpl_size detline = 0; detline < ndetectlines; ++detline)
9341 if(cpl_vector_get(peaks, detline) ==
9342 cpl_bivector_get_x_data(peaks_ident)[idline])
9344 cpl_size table_pos = totalsize - ndetectlines + detline;
9345 double wave_ident = cpl_bivector_get_y_data(peaks_ident)[idline] + refwave;
9346 double xpix_fit = cpl_polynomial_eval_1d(ids,
9347 wave_ident - refwave, NULL);
9348 double xpos_det = cpl_table_get_double(detected_lines,
9351 cpl_table_set_double(detected_lines,
9355 cpl_table_set_double(detected_lines,
9356 "xpos_fit_rect_wavecal",
9359 cpl_table_set_double(detected_lines,
9362 xpos_det - xpix_fit - 1);
9363 cpl_table_set_int(detected_lines,
9366 for(cpl_size i_used = 0; i_used < cpl_bivector_get_size(peaks_ident_used_fit); ++i_used)
9368 if(cpl_bivector_get_x_data(peaks_ident)[idline] == cpl_bivector_get_x_data(peaks_ident_used_fit)[i_used])
9369 cpl_table_set_int(detected_lines,
9388 nlines[i] = usedLines;
9390 error[i] = ids_err / sqrt(usedLines/(uorder + 1));
9392 for (k = 0; k <= order; k++) {
9394 cpl_table_set_double(idscoeff, clab[k], i, 0.0);
9397 cpl_table_set_double(idscoeff, clab[k], i,
9398 cpl_polynomial_get_coeff(ids, &k));
9402 cpl_polynomial_delete(ids);
9403 cpl_bivector_delete(peaks_ident);
9405 cpl_vector_delete(peaks);
9416 nfits = row_top - row_bot - cpl_table_count_invalid(coeff, clab[0]);
9421 fguess = cpl_polynomial_new(1);
9431 for (k = 0; k <= order; k++) {
9432 c = cpl_table_get_column_median(coeff, clab[k]);
9433 cpl_polynomial_set_coeff(fguess, &k, c);
9440 for (i = row_bot; i < row_top; i++) {
9441 cpl_bivector * peaks_ident_used_fit;
9448 if (width > sradius) {
9456 for (k = 0; k <= order; k++) {
9457 c = cpl_table_get_double(coeff, clab[k],
9459 cpl_polynomial_set_coeff(fguess, &k, c);
9464 fguess, refwave, uradius);
9466 if (peaks_ident == NULL) {
9471 countLines = cpl_bivector_get_size(peaks_ident);
9473 if (countLines < 4) {
9474 cpl_bivector_delete(peaks_ident);
9482 wavel = cpl_bivector_get_y(peaks_ident);
9483 cpl_vector_subtract_scalar(wavel, refwave);
9485 uorder = countLines / 2 - 1;
9490 2 * (uorder + 1), &usedLines,
9491 &ids_err, &peaks_ident_used_fit);
9495 cpl_bivector_delete(peaks_ident);
9500 nlines[i] = usedLines;
9502 error[i] = ids_err / sqrt(usedLines/(uorder + 1));
9505 pixstart = cpl_polynomial_eval_1d(ids,
9506 cpl_bivector_get_y_data(peaks_ident)[0],
9508 pixend = cpl_polynomial_eval_1d(ids,
9509 cpl_bivector_get_y_data(peaks_ident)[countLines-1],
9511 extrapolation = (pixend - pixstart) / 5;
9512 pixstart -= extrapolation;
9513 pixend += extrapolation;
9519 for (j = pixstart; j < pixend; j++) {
9521 firstLambda, lastLambda, refwave, j);
9529 if (residuals || (restable && !(i%step))) {
9530 if (restable && !(i%step)) {
9531 lin = cpl_polynomial_new(1);
9532 for (k = 0; k < 2; k++)
9533 cpl_polynomial_set_coeff(lin, &k,
9534 cpl_polynomial_get_coeff(ids, &k));
9536 for (j = 0; j < countLines; j++) {
9537 pixe = cpl_bivector_get_x_data(peaks_ident)[j];
9538 wave = cpl_bivector_get_y_data(peaks_ident)[j];
9540 - cpl_polynomial_eval_1d(ids, wave, NULL);
9543 (ddata + i*nx)[pixel] = value;
9545 if (restable && !(i%step)) {
9546 for (k = 0; k < nref; k++) {
9547 if (fabs(line[k]-refwave-wave) < 0.1) {
9548 snprintf(name, MAX_COLNAME,
9550 cpl_table_set_double(restable, name,
9553 - cpl_polynomial_eval_1d(lin,
9555 snprintf(name, MAX_COLNAME,
9557 cpl_table_set_double(restable, name,
9559 snprintf(name, MAX_COLNAME,
9561 cpl_table_set_double(restable, name,
9568 if (restable && !(i%step)) {
9569 cpl_polynomial_delete(lin);
9586 cpl_size oldsize = cpl_table_get_nrow(detected_lines);
9587 cpl_size nidentlines = cpl_bivector_get_size(peaks_ident);
9588 cpl_table_set_size(detected_lines, oldsize + nidentlines);
9589 for(cpl_size idline = 0; idline < nidentlines ; ++idline)
9591 double wave_ident = cpl_bivector_get_y_data(peaks_ident)[idline] + refwave;
9592 double xpix_fit = cpl_polynomial_eval_1d(ids,
9593 wave_ident - refwave, NULL);
9594 cpl_table_set_int(detected_lines,
"slit_id",
9595 oldsize + idline, slit_id);
9596 cpl_table_set_double(detected_lines,
"xpos_rectified_iter",
9597 oldsize + idline, cpl_bivector_get_x_data(peaks_ident)[idline] + 1);
9598 cpl_table_set_double(detected_lines,
"ypos_rectified_iter",
9599 oldsize + idline, (
double)i + 1);
9600 cpl_table_set_double(detected_lines,
"peak_flux",
9602 sdata[i*nx+(
int)(cpl_bivector_get_x_data(peaks_ident)[idline]+0.5)]);
9603 cpl_table_set_double(detected_lines,
"wave_ident_iter",
9604 oldsize + idline, wave_ident);
9605 cpl_table_set_double(detected_lines,
"xpos_fit_rect_wavecal",
9606 oldsize + idline, xpix_fit + 1);
9607 cpl_table_set_int(detected_lines,
9609 oldsize + idline, 0);
9610 for(cpl_size i_used = 0; i_used < cpl_bivector_get_size(peaks_ident_used_fit); ++i_used)
9612 if(cpl_bivector_get_x_data(peaks_ident)[idline] == cpl_bivector_get_x_data(peaks_ident_used_fit)[i_used])
9613 cpl_table_set_int(detected_lines,
9615 oldsize + idline, 1);
9621 for (k = 0; k <= order; k++) {
9623 cpl_table_set_double(idscoeff, clab[k], i, 0.0);
9626 cpl_table_set_double(idscoeff, clab[k], i,
9627 cpl_polynomial_get_coeff(ids, &k));
9631 cpl_bivector_delete(peaks_ident);
9632 cpl_polynomial_delete(ids);
9636 cpl_polynomial_delete(fguess);
9639 cpl_table_delete(coeff);
9655 for (i = 0; i < ny; i++) {
9658 ids = cpl_polynomial_new(1);
9659 for (k = 0; k <= order; k++) {
9660 c = cpl_table_get_double(idscoeff, clab[k], i, &null);
9662 cpl_polynomial_delete(ids);
9666 cpl_polynomial_set_coeff(ids, &k, c);
9671 pixstart = cpl_polynomial_eval_1d(ids, firstLambda - refwave, NULL);
9672 pixend = cpl_polynomial_eval_1d(ids, lastLambda - refwave, NULL);
9682 for (j = 0; j < nl; j++) {
9683 lambda = firstLambda + j * dispersion;
9684 fpixel = cpl_polynomial_eval_1d(ids, lambda - refwave, NULL);
9686 if (pixel >= 0 && pixel < nx-1) {
9687 v1 = (sdata + i*nx)[pixel];
9688 v2 = (sdata + i*nx)[pixel+1];
9689 vi = v1 + (v2-v1)*(fpixel-pixel);
9690 (rdata + i*nl)[j] = vi;
9694 cpl_polynomial_delete(ids);
9728 double firstLambda,
double lastLambda,
9729 double dispersion, cpl_table *idscoeff,
9733 const char *func =
"mos_wavelength_calibration";
9735 const char *clab[6] = {
"c0",
"c1",
"c2",
"c3",
"c4",
"c5"};
9738 cpl_image *resampled;
9739 cpl_polynomial *ids;
9740 double pixel_per_lambda;
9745 float v0, v1, v2, v3, vi;
9748 int pixstart, pixend;
9749 int nl, nx, ny, pixel;
9756 if (dispersion <= 0.0) {
9757 cpl_msg_error(func,
"The resampling step must be positive");
9758 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
9762 if (lastLambda - firstLambda < dispersion) {
9763 cpl_msg_error(func,
"Invalid spectral range: %.2f to %.2f",
9764 firstLambda, lastLambda);
9765 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
9769 if (idscoeff == NULL) {
9770 cpl_msg_error(func,
"An IDS coeff table must be given");
9771 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
9775 if (image == NULL) {
9776 cpl_msg_error(func,
"A scientific spectral image must be given");
9777 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
9781 nx = cpl_image_get_size_x(image);
9782 ny = cpl_image_get_size_y(image);
9783 sdata = cpl_image_get_data_float(image);
9785 nl = (lastLambda - firstLambda) / dispersion;
9786 resampled = cpl_image_new(nl, ny, CPL_TYPE_FLOAT);
9787 rdata = cpl_image_get_data_float(resampled);
9790 while (order < 6 && cpl_table_has_column(idscoeff, clab[order]))
9794 for (i = 0; i < ny; i++) {
9797 ids = cpl_polynomial_new(1);
9798 for (k = 0; k <= order; k++) {
9799 c = cpl_table_get_double(idscoeff, clab[k], i, &null);
9801 cpl_polynomial_delete(ids);
9805 cpl_polynomial_set_coeff(ids, &k, c);
9810 pixstart = cpl_polynomial_eval_1d(ids, firstLambda - refwave, NULL);
9811 pixend = cpl_polynomial_eval_1d(ids, lastLambda - refwave, NULL);
9821 for (j = 0; j < nl; j++) {
9822 lambda = firstLambda + j * dispersion;
9823 fpixel = cpl_polynomial_eval_1d(ids, lambda - refwave,
9845 if(pixel_per_lambda <= 0)
9847 else if (fpixel < 0)
9849 else if (pixel >= 1 && pixel < nx-2) {
9850 v0 = (sdata + i*nx)[pixel-1];
9851 v1 = (sdata + i*nx)[pixel];
9852 v2 = (sdata + i*nx)[pixel+1];
9853 v3 = (sdata + i*nx)[pixel+2];
9854 vi = (fpixel-pixel)*(fpixel-pixel)*(v3 - v2 - v1 + v0)
9855 + (fpixel-pixel)*(3*v2 - v3 - v1 - v0)
9875 vi *= dispersion * pixel_per_lambda;
9877 else if (pixel >= 0 && pixel < nx-1) {
9878 v1 = (sdata + i*nx)[pixel];
9879 v2 = (sdata + i*nx)[pixel+1];
9880 vi = v1 + (v2-v1)*(fpixel-pixel);
9882 vi *= dispersion * pixel_per_lambda;
9886 (rdata + i*nl)[j] = vi;
9899 double spos = fpixel - dispersion * pixel_per_lambda / 2;
9900 double epos = fpixel + dispersion * pixel_per_lambda / 2;
9907 int epix = epos + 1;
9916 for (k = spix; k < epix; k++) {
9917 if (pixel >= 0 && pixel < nx) {
9918 vi += (sdata + i*nx)[k];
9929 vi *= dispersion * pixel_per_lambda / (epix - spix);
9937 vi *= dispersion * pixel_per_lambda;
9939 (rdata + i*nl)[j] = vi;
9943 cpl_polynomial_delete(ids);
10017 double refwave,
double firstLambda,
10018 double lastLambda, cpl_table *idscoeff,
10019 cpl_vector *skylines,
int highres,
int order,
10020 cpl_image *calibration,
int sradius)
10022 const char *func =
"mos_wavelength_align";
10024 const char *clab[6] = {
"c0",
"c1",
"c2",
"c3",
"c4",
"c5"};
10028 double expPos, offset;
10030 double lambda1, lambda2;
10036 int startPos, endPos;
10037 int window = 2*sradius + 1;
10043 int xlow, ylow, xhig, yhig;
10044 int idsorder, uorder;
10053 char offname[MAX_COLNAME];
10054 char name[MAX_COLNAME];
10056 cpl_polynomial *ids;
10057 cpl_polynomial *polycorr;
10060 cpl_table *offsets;
10066 if (idscoeff == NULL) {
10067 cpl_msg_error(func,
"An IDS coeff table must be given");
10068 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
10072 if (image == NULL) {
10073 cpl_msg_error(func,
"A scientific spectral image must be given");
10074 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
10078 if (slits == NULL) {
10079 cpl_msg_error(func,
"A slit position table must be given");
10080 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
10085 line = cpl_vector_get_data(skylines);
10086 nlines = cpl_vector_get_size(skylines);
10089 cpl_msg_warning(func,
"A catalog of sky lines wavelengths was not " 10090 "given: using internal list of reference sky lines");
10092 line = default_lines_hi;
10093 nlines =
sizeof(default_lines_hi) /
sizeof(
double);
10096 line = default_lines_lo;
10097 nlines =
sizeof(default_lines_lo) /
sizeof(
double);
10102 cdata = cpl_image_get_data(calibration);
10104 nx = cpl_image_get_size_x(image);
10105 ny = cpl_image_get_size_y(image);
10107 nslits = cpl_table_get_nrow(slits);
10108 slit_id = cpl_table_get_data_int(slits,
"slit_id");
10109 position = cpl_table_get_data_int(slits,
"position");
10110 length = cpl_table_get_data_int(slits,
"length");
10118 for (i = 0; i < nlines; i++)
10119 if (line[i] > firstLambda && line[i] < lastLambda)
10122 offsets = cpl_table_new(nrows);
10123 cpl_table_new_column(offsets,
"wave", CPL_TYPE_DOUBLE);
10124 cpl_table_set_column_unit(offsets,
"wave",
"Angstrom");
10127 for (i = 0; i < nlines; i++) {
10128 if (line[i] > firstLambda && line[i] < lastLambda) {
10129 cpl_table_set_double(offsets,
"wave", nrows, line[i]);
10138 line = cpl_table_get_data_double(offsets,
"wave");
10142 while (idsorder < 6 && cpl_table_has_column(idscoeff, clab[idsorder]))
10148 for (i = 0; i < nslits; i++) {
10150 if (length[i] == 0)
10153 snprintf(offname, MAX_COLNAME,
"offset%d", slit_id[i]);
10154 cpl_table_new_column(offsets, offname, CPL_TYPE_DOUBLE);
10166 ylow = position[i] + 1;
10167 yhig = ylow + length[i] - 1;
10169 exslit = cpl_image_extract(image, xlow, ylow, xhig, yhig);
10170 sky = cpl_image_collapse_median_create(exslit, 0, 0, 1);
10171 sdata = cpl_image_get_data(sky);
10173 cpl_image_delete(exslit);
10188 dummy = cpl_table_new(yhig - ylow);
10189 for (j = 0; j < nlines; j++) {
10190 snprintf(name, MAX_COLNAME,
"%"CPL_SIZE_FORMAT, j);
10191 cpl_table_new_column(dummy, name, CPL_TYPE_DOUBLE);
10194 for (j = ylow; j < yhig; j++) {
10201 ids = cpl_polynomial_new(1);
10202 for (k = 0; k <= idsorder; k++) {
10203 c = cpl_table_get_double(idscoeff, clab[k], j, &null);
10205 cpl_polynomial_delete(ids);
10209 cpl_polynomial_set_coeff(ids, &k, c);
10214 for (k = 0; k < nlines; k++) {
10215 expPos = cpl_polynomial_eval_1d(ids, line[k] - refwave, NULL);
10216 startPos = expPos - sradius;
10217 endPos = startPos + window;
10218 if (startPos < 0 || endPos >= nx)
10221 if (0 == peakPosition(sdata + startPos, window, &pos, 1)) {
10223 offset = pos - expPos;
10224 snprintf(name, MAX_COLNAME,
"%"CPL_SIZE_FORMAT, k);
10225 cpl_table_set_double(dummy, name, j - ylow, offset);
10229 cpl_polynomial_delete(ids);
10232 cpl_image_delete(sky);
10234 for (j = 0; j < nlines; j++) {
10235 snprintf(name, MAX_COLNAME,
"%"CPL_SIZE_FORMAT, j);
10236 if (cpl_table_has_valid(dummy, name)) {
10237 offset = cpl_table_get_column_median(dummy, name);
10238 cpl_table_set_double(offsets, offname, j, offset);
10242 cpl_table_delete(dummy);
10253 for (i = 0; i < nslits; i++) {
10255 if (length[i] == 0)
10258 snprintf(offname, MAX_COLNAME,
"offset%d", slit_id[i]);
10265 dummy = cpl_table_new(nlines);
10266 cpl_table_duplicate_column(dummy,
"wave", offsets,
"wave");
10267 cpl_table_duplicate_column(dummy,
"offset", offsets, offname);
10269 npoints = nlines - cpl_table_count_invalid(dummy,
"offset");
10270 if (npoints == 0) {
10271 cpl_msg_warning(func,
"No sky lines alignment was possible " 10272 "for slit ID=%d: no sky line found", slit_id[i]);
10273 cpl_table_delete(dummy);
10278 if (npoints <= uorder) {
10279 uorder = npoints - 1;
10281 cpl_msg_warning(func,
"Just %d sky lines detected for slit " 10282 "ID=%d, while a polynomial order %d was " 10283 "requested. Using polynomial order %d for " 10284 "this slit!", npoints, slit_id[i], order,
10288 cpl_msg_warning(func,
"Just %d sky lines detected for slit " 10289 "ID=%d, while a polynomial order %d was " 10290 "requested. Computing a median offset for " 10291 "this slit!", npoints, slit_id[i], order);
10295 cpl_table_erase_invalid(dummy);
10303 wave = cpl_vector_wrap(npoints,
10304 cpl_table_get_data_double(dummy,
"wave"));
10305 offs = cpl_vector_wrap(npoints,
10306 cpl_table_get_data_double(dummy,
"offset"));
10312 cpl_vector_subtract_scalar(wave, refwave);
10314 polycorr = cpl_polynomial_fit_1d_create(wave, offs, uorder, &rms);
10316 rms = sqrt(rms * (uorder + 1) / npoints);
10318 cpl_vector_unwrap(wave);
10319 cpl_vector_unwrap(offs);
10320 cpl_table_delete(dummy);
10327 ylow = position[i];
10328 yhig = ylow + length[i];
10330 for (j = 0; j <= uorder; j++) {
10331 data = cpl_table_get_data_double(idscoeff, clab[j]);
10332 c = cpl_polynomial_get_coeff(polycorr, &j);
10333 for (k = ylow; k < yhig; k++)
10337 data = cpl_table_get_data_double(idscoeff,
"error");
10338 for (k = ylow; k < yhig; k++)
10339 data[k] = sqrt(data[k]*data[k] + rms*rms);
10341 idata = cpl_table_get_data_int(idscoeff,
"nlines");
10342 for (k = ylow; k < yhig; k++)
10343 idata[k] = npoints;
10351 for (j = ylow; j < yhig; j++) {
10352 for (k = 1; k < nx; k++) {
10353 lambda1 = cdata[k - 1 + j*nx];
10354 lambda2 = cdata[k + j*nx];
10355 if (lambda1 < 1.0 || lambda2 < 1.0)
10357 offset = cpl_polynomial_eval_1d(polycorr,
10358 lambda1-refwave, NULL);
10359 cdata[k - 1 + j*nx] -= offset * (lambda2-lambda1);
10364 cpl_polynomial_delete(polycorr);
10366 else if (uorder == 1) {
10373 cpl_bivector *list;
10376 wave = cpl_vector_wrap(npoints,
10377 cpl_table_get_data_double(dummy,
"wave"));
10378 offs = cpl_vector_wrap(npoints,
10379 cpl_table_get_data_double(dummy,
"offset"));
10381 list = cpl_bivector_wrap_vectors(wave, offs);
10387 cpl_vector_subtract_scalar(wave, refwave);
10389 robustLinearFit(list, &q, &m, &rms);
10391 rms = sqrt(rms * (uorder + 1) / npoints);
10393 cpl_bivector_unwrap_vectors(list);
10394 cpl_vector_unwrap(wave);
10395 cpl_vector_unwrap(offs);
10396 cpl_table_delete(dummy);
10403 ylow = position[i];
10404 yhig = ylow + length[i];
10406 for (j = 0; j <= uorder; j++) {
10407 data = cpl_table_get_data_double(idscoeff, clab[j]);
10412 for (k = ylow; k < yhig; k++)
10416 data = cpl_table_get_data_double(idscoeff,
"error");
10417 for (k = ylow; k < yhig; k++)
10418 data[k] = sqrt(data[k]*data[k] + rms*rms);
10420 idata = cpl_table_get_data_int(idscoeff,
"nlines");
10421 for (k = ylow; k < yhig; k++)
10422 idata[k] = npoints;
10430 for (j = ylow; j < yhig; j++) {
10431 for (k = 1; k < nx; k++) {
10432 lambda1 = cdata[k - 1 + j*nx];
10433 lambda2 = cdata[k + j*nx];
10434 if (lambda1 < 1.0 || lambda2 < 1.0)
10436 offset = q + m*(lambda1-refwave);
10437 cdata[k - 1 + j*nx] -= offset * (lambda2-lambda1);
10448 offs = cpl_vector_wrap(npoints,
10449 cpl_table_get_data_double(dummy,
"offset"));
10451 offset = cpl_vector_get_median_const(offs);
10454 rms = cpl_table_get_column_stdev(dummy,
"offset");
10458 rms /= sqrt(npoints);
10460 cpl_vector_unwrap(offs);
10461 cpl_table_delete(dummy);
10468 ylow = position[i];
10469 yhig = ylow + length[i];
10471 data = cpl_table_get_data_double(idscoeff, clab[0]);
10472 for (k = ylow; k < yhig; k++)
10475 data = cpl_table_get_data_double(idscoeff,
"error");
10476 for (k = ylow; k < yhig; k++)
10477 data[k] = sqrt(data[k]*data[k] + rms*rms);
10479 idata = cpl_table_get_data_int(idscoeff,
"nlines");
10480 for (k = ylow; k < yhig; k++)
10481 idata[k] = npoints;
10490 for (j = ylow; j < yhig; j++) {
10491 for (k = 1; k < nx; k++) {
10492 lambda1 = cdata[k - 1 + j*nx];
10493 lambda2 = cdata[k + j*nx];
10494 if (lambda1 < 1.0 || lambda2 < 1.0)
10496 cdata[k - 1 + j*nx] -= offset * (lambda2-lambda1);
10570 double firstLambda,
double lastLambda,
10571 cpl_table *idscoeff, cpl_vector *skylines,
10572 int highres,
int order,
10573 cpl_image *calibration,
int sradius)
10575 const char *func =
"mos_wavelength_align_lss";
10577 const char *clab[6] = {
"c0",
"c1",
"c2",
"c3",
"c4",
"c5"};
10583 double expPos, offset;
10585 double lambda1, lambda2;
10591 int startPos, endPos;
10592 int window = 2*sradius + 1;
10597 int idsorder, uorder;
10602 char name[MAX_COLNAME];
10603 char fname[MAX_COLNAME];
10605 cpl_polynomial *ids;
10606 cpl_polynomial *polycorr;
10607 cpl_table *offsets;
10608 cpl_table *fittable;
10615 if (idscoeff == NULL) {
10616 cpl_msg_error(func,
"An IDS coeff table must be given");
10617 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
10621 if (image == NULL) {
10622 cpl_msg_error(func,
"A scientific spectral image must be given");
10623 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
10628 line = cpl_vector_get_data(skylines);
10629 nlines = cpl_vector_get_size(skylines);
10632 cpl_msg_warning(func,
"A catalog of sky lines wavelengths was not " 10633 "given: using internal list of reference sky lines");
10635 line = default_lines_hi;
10636 nlines =
sizeof(default_lines_hi) /
sizeof(
double);
10639 line = default_lines_lo;
10640 nlines =
sizeof(default_lines_lo) /
sizeof(
double);
10645 cdata = cpl_image_get_data(calibration);
10647 nx = cpl_image_get_size_x(image);
10648 ny = cpl_image_get_size_y(image);
10650 sdata = cpl_image_get_data(image);
10652 if (ny != cpl_table_get_nrow(idscoeff)) {
10653 cpl_error_set(func, CPL_ERROR_INCOMPATIBLE_INPUT);
10667 for (i = 0; i < nlines; i++)
10668 if (line[i] > firstLambda && line[i] < lastLambda)
10671 offsets = cpl_table_new(nrows);
10672 cpl_table_new_column(offsets,
"wave", CPL_TYPE_DOUBLE);
10673 cpl_table_set_column_unit(offsets,
"wave",
"Angstrom");
10676 for (i = 0; i < nlines; i++) {
10677 if (line[i] > firstLambda && line[i] < lastLambda) {
10678 cpl_table_set_double(offsets,
"wave", nrows, line[i]);
10687 line = cpl_table_get_data_double(offsets,
"wave");
10691 while (idsorder < 6 && cpl_table_has_column(idscoeff, clab[idsorder]))
10701 dummy = cpl_table_new(ny);
10702 for (j = 0; j < nlines; j++) {
10703 snprintf(name, MAX_COLNAME,
"off_%d", (
int)line[j]);
10704 snprintf(fname, MAX_COLNAME,
"fit_%d", (
int)line[j]);
10705 cpl_table_new_column(dummy, name, CPL_TYPE_DOUBLE);
10706 cpl_table_new_column(dummy, fname, CPL_TYPE_DOUBLE);
10709 for (j = 0; j < ny; j++, sdata += nx) {
10716 ids = cpl_polynomial_new(1);
10717 for (k = 0; k <= idsorder; k++) {
10718 c = cpl_table_get_double(idscoeff, clab[k], j, &missing);
10720 cpl_polynomial_delete(ids);
10723 cpl_polynomial_set_coeff(ids, &k, c);
10728 for (k = 0; k < nlines; k++) {
10729 expPos = cpl_polynomial_eval_1d(ids, line[k] - refwave, NULL);
10730 startPos = expPos - sradius;
10731 endPos = startPos + window;
10732 if (startPos < 0 || endPos >= nx)
10735 if (0 == peakPosition(sdata + startPos, window, &pos, 1)) {
10737 offset = pos - expPos;
10738 snprintf(name, MAX_COLNAME,
"off_%d", (
int)line[k]);
10739 cpl_table_set_double(dummy, name, j, offset);
10743 cpl_polynomial_delete(ids);
10752 for (j = 0; j < nlines; j++) {
10753 snprintf(name, MAX_COLNAME,
"off_%d", (
int)line[j]);
10754 snprintf(fname, MAX_COLNAME,
"fit_%d", (
int)line[j]);
10755 if (cpl_table_has_valid(dummy, name)) {
10763 cpl_bivector *list;
10765 fittable = cpl_table_new(ny);
10766 cpl_table_new_column(fittable,
"row", CPL_TYPE_DOUBLE);
10767 cpl_table_set_column_unit(fittable,
"row",
"pixel");
10768 for (k = 0; k < ny; k++)
10769 cpl_table_set_double(fittable,
"row", k, k);
10770 cpl_table_duplicate_column(fittable,
"offset", dummy, name);
10771 npoints = ny - cpl_table_count_invalid(fittable,
"offset");
10772 cpl_table_erase_invalid(fittable);
10773 row = cpl_vector_wrap(npoints,
10774 cpl_table_get_data_double(fittable,
"row"));
10775 offs = cpl_vector_wrap(npoints,
10776 cpl_table_get_data_double(fittable,
"offset"));
10777 list = cpl_bivector_wrap_vectors(row, offs);
10778 robustLinearFit(list, &q, &m, &rms);
10779 cpl_bivector_unwrap_vectors(list);
10780 cpl_vector_unwrap(row);
10781 cpl_vector_unwrap(offs);
10782 cpl_table_delete(fittable);
10783 for (k = 0; k < ny; k++)
10784 cpl_table_set_double(dummy, fname, k, q + m*k);
10797 for (i = 0; i < ny; i++) {
10799 if (!cpl_table_is_valid(idscoeff, clab[0], i))
10803 for (j = 0; j < nlines; j++) {
10804 snprintf(name, MAX_COLNAME,
"fit_%d", (
int)line[j]);
10805 if (cpl_table_is_valid(dummy, name, i))
10813 if (npoints <= uorder)
10814 uorder = npoints - 1;
10822 wave = cpl_vector_new(npoints);
10823 wdata = cpl_vector_get_data(wave);
10824 offs = cpl_vector_new(npoints);
10825 odata = cpl_vector_get_data(offs);
10828 for (j = 0; j < nlines; j++) {
10829 snprintf(name, MAX_COLNAME,
"fit_%d", (
int)line[j]);
10830 if (cpl_table_is_valid(dummy, name, i)) {
10831 wdata[npoints] = line[j] - refwave;
10832 odata[npoints] = cpl_table_get_double(dummy, name, i, NULL);
10837 polycorr = cpl_polynomial_fit_1d_create(wave, offs, uorder, &rms);
10839 rms = sqrt(rms * (uorder + 1) / npoints);
10841 cpl_vector_delete(wave);
10842 cpl_vector_delete(offs);
10849 for (j = 0; j <= uorder; j++) {
10850 data = cpl_table_get_data_double(idscoeff, clab[j]);
10851 c = cpl_polynomial_get_coeff(polycorr, &j);
10855 data = cpl_table_get_data_double(idscoeff,
"error");
10856 data[i] = sqrt(data[i]*data[i] + rms*rms);
10858 idata = cpl_table_get_data_int(idscoeff,
"nlines");
10859 idata[i] = npoints;
10867 for (k = 1; k < nx; k++) {
10868 lambda1 = cdata[k - 1 + i*nx];
10869 lambda2 = cdata[k + i*nx];
10870 if (lambda1 < 1.0 || lambda2 < 1.0)
10872 offset = cpl_polynomial_eval_1d(polycorr,
10873 lambda1-refwave, NULL);
10874 cdata[k - 1 + i*nx] -= offset * (lambda2-lambda1);
10878 cpl_polynomial_delete(polycorr);
10881 else if (uorder == 1) {
10887 cpl_bivector *list;
10890 wave = cpl_vector_new(npoints);
10891 wdata = cpl_vector_get_data(wave);
10892 offs = cpl_vector_new(npoints);
10893 odata = cpl_vector_get_data(offs);
10896 for (j = 0; j < nlines; j++) {
10897 snprintf(name, MAX_COLNAME,
"fit_%d", (
int)line[j]);
10898 if (cpl_table_is_valid(dummy, name, i)) {
10899 wdata[npoints] = line[j] - refwave;
10900 odata[npoints] = cpl_table_get_double(dummy, name, i, NULL);
10905 list = cpl_bivector_wrap_vectors(wave, offs);
10906 robustLinearFit(list, &q, &m, &rms);
10908 rms = sqrt(rms * (uorder + 1) / npoints);
10910 cpl_bivector_unwrap_vectors(list);
10911 cpl_vector_delete(wave);
10912 cpl_vector_delete(offs);
10919 for (j = 0; j <= uorder; j++) {
10920 data = cpl_table_get_data_double(idscoeff, clab[j]);
10928 data = cpl_table_get_data_double(idscoeff,
"error");
10929 data[i] = sqrt(data[i]*data[i] + rms*rms);
10931 idata = cpl_table_get_data_int(idscoeff,
"nlines");
10932 idata[i] = npoints;
10940 for (k = 1; k < nx; k++) {
10941 lambda1 = cdata[k - 1 + i*nx];
10942 lambda2 = cdata[k + i*nx];
10943 if (lambda1 < 1.0 || lambda2 < 1.0)
10945 offset = q + m*(lambda1-refwave);
10946 cdata[k - 1 + i*nx] -= offset * (lambda2-lambda1);
10956 offs = cpl_vector_new(npoints);
10957 odata = cpl_vector_get_data(offs);
10960 for (j = 0; j < nlines; j++) {
10961 snprintf(name, MAX_COLNAME,
"fit_%d", (
int)line[j]);
10962 if (cpl_table_is_valid(dummy, name, i)) {
10963 odata[npoints] = cpl_table_get_double(dummy, name, i, NULL);
10968 offset = cpl_vector_get_median_const(offs);
10971 rms = cpl_vector_get_stdev(offs);
10973 else if (npoints == 1) {
10974 snprintf(name, MAX_COLNAME,
"off_%d", (
int)line[0]);
10975 if (cpl_table_has_valid(dummy, name)) {
10976 rms = cpl_table_get_column_stdev(dummy, name);
10977 rms /= sqrt(ny - cpl_table_count_invalid(dummy, name));
10987 rms /= sqrt(npoints);
10989 cpl_vector_delete(offs);
10996 data = cpl_table_get_data_double(idscoeff, clab[0]);
10999 data = cpl_table_get_data_double(idscoeff,
"error");
11000 data[i] = sqrt(data[i]*data[i] + rms*rms);
11002 idata = cpl_table_get_data_int(idscoeff,
"nlines");
11003 idata[i] = npoints;
11012 for (k = 1; k < nx; k++) {
11013 lambda1 = cdata[k - 1 + i*nx];
11014 lambda2 = cdata[k + i*nx];
11015 if (lambda1 < 1.0 || lambda2 < 1.0)
11017 cdata[k - 1 + i*nx] -= offset * (lambda2-lambda1);
11024 for (j = 0; j < nlines; j++) {
11025 snprintf(name, MAX_COLNAME,
"off_%d", (
int)line[j]);
11026 if (cpl_table_has_valid(dummy, name)) {
11028 offset = cpl_table_get_column_median(dummy, name);
11029 cpl_msg_info(func,
"Median offset for %.3f: %.3f pixel",
11034 "Median offset for %.2f: not available", line[j]);
11038 cpl_table_delete(offsets);
11041 cpl_table_delete(dummy);
11078 double wavestart,
double dispersion,
int radius,
11082 const char *func =
"mos_distortions_rms";
11087 int cpix, npix, nzero;
11090 int npeaks, allPeaks;
11093 float peak, expectPeak, offset;
11097 double rms, oneRms;
11103 xlen = cpl_image_get_size_x(rectified);
11104 ylen = cpl_image_get_size_y(rectified);
11105 sdata = cpl_image_get_data(rectified);
11108 wdata = cpl_vector_get_data(lines);
11109 numLines = cpl_vector_get_size(lines);
11112 cpl_msg_warning(func,
"A catalog of sky lines wavelengths was not " 11113 "given: using internal list of reference sky lines");
11115 wdata = default_lines_hi;
11116 numLines =
sizeof(default_lines_hi) /
sizeof(
double);
11119 wdata = default_lines_lo;
11120 numLines =
sizeof(default_lines_lo) /
sizeof(
double);
11124 npix = 2 * radius + 1;
11125 profile = cpl_calloc(npix,
sizeof(
float));
11130 for (i = 0; i < numLines; i++) {
11137 expectPeak = (lambda - wavestart) / dispersion;
11138 cpix = floor(expectPeak + 0.5);
11144 sp = cpix - radius;
11145 ep = cpix + radius;
11147 if (sp < 0 || ep > xlen)
11154 for (j = 0; j < ylen; j++) {
11156 for (k = 0; k < npix; k++) {
11157 profile[k] = sdata[sp + k + j * xlen];
11158 if (fabs(profile[k]) < 0.0001)
11164 if (peakPosition(profile, npix, &peak, 1) == 0) {
11165 offset = (sp + peak) - expectPeak;
11167 rms += fabs(offset);
11168 oneRms += fabs(offset);
11175 cpl_msg_info(func,
"RMS for %.2f: %.3f pixel (%d points)",
11176 lambda, oneRms / npeaks * 1.25, npeaks);
11178 cpl_msg_info(func,
"RMS for %.2f: line not available", lambda);
11215 double blue,
double red,
double dispersion,
int trend)
11217 const char *func =
"mos_map_pixel";
11219 const char *clab[6] = {
"c0",
"c1",
"c2",
"c3",
"c4",
"c5"};
11222 cpl_polynomial *ids;
11234 if (idscoeff == NULL) {
11235 cpl_msg_error(func,
"An IDS coeff table must be given");
11236 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
11240 xsize = (red - blue) / dispersion;
11241 ysize = cpl_table_get_nrow(idscoeff);
11242 map = cpl_image_new(xsize, ysize, CPL_TYPE_FLOAT);
11243 mdata = cpl_image_get_data(map);
11246 while (order < 6 && cpl_table_has_column(idscoeff, clab[order]))
11250 for (i = 0; i < ysize; i++, mdata += xsize) {
11253 ids = cpl_polynomial_new(1);
11254 for (k = trend; k <= order; k++) {
11255 c = cpl_table_get_double(idscoeff, clab[k], i, &missing);
11257 cpl_polynomial_delete(ids);
11260 cpl_polynomial_set_coeff(ids, &k, c);
11265 for (j = 0; j < xsize; j++) {
11266 lambda = blue + j*dispersion;
11267 mdata[j] = cpl_polynomial_eval_1d(ids, lambda-reference, NULL);
11270 cpl_polynomial_delete(ids);
11300 double blue,
double red)
11302 const char *func =
"mos_map_idscoeff";
11304 const char *clab[6] = {
"c0",
"c1",
"c2",
"c3",
"c4",
"c5"};
11307 cpl_polynomial *ids;
11319 if (idscoeff == NULL) {
11320 cpl_msg_error(func,
"An IDS coeff table must be given");
11321 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
11326 cpl_msg_error(func,
"Invalid image size");
11327 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
11331 if (xsize < 20 || xsize > 5000) {
11332 cpl_msg_warning(func,
"Do you really have a detector %d pixels long?",
11336 ysize = cpl_table_get_nrow(idscoeff);
11337 map = cpl_image_new(xsize, ysize, CPL_TYPE_FLOAT);
11338 mdata = cpl_image_get_data(map);
11341 while (order < 6 && cpl_table_has_column(idscoeff, clab[order]))
11345 for (i = 0; i < ysize; i++, mdata += xsize) {
11348 ids = cpl_polynomial_new(1);
11349 for (k = 0; k <= order; k++) {
11350 c = cpl_table_get_double(idscoeff, clab[k], i, &missing);
11352 cpl_polynomial_delete(ids);
11355 cpl_polynomial_set_coeff(ids, &k, c);
11360 for (j = 0; j < xsize; j++) {
11363 if (lambda >= blue && lambda <= red) {
11368 cpl_polynomial_delete(ids);
11411 cpl_table *slits, cpl_table *polytraces,
11412 double reference,
double blue,
double red,
11415 const char *func =
"mos_map_wavelengths";
11417 const char *clab[6] = {
"c0",
"c1",
"c2",
"c3",
"c4",
"c5"};
11419 cpl_polynomial *polytop;
11420 cpl_polynomial *polybot;
11421 cpl_image *remapped;
11426 double vtop, vbot, value;
11433 int yint, ysize, yprev;
11440 int pixel_above, pixel_below, refpixel, start_pixel, end_pixel;
11441 int missing_top, missing_bot;
11448 if (spatial == NULL || calibration == NULL ||
11449 slits == NULL || polytraces == NULL) {
11450 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
11454 if (dispersion <= 0.0) {
11455 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
11459 if (red - blue < dispersion) {
11460 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
11464 nx = cpl_image_get_size_x(spatial);
11465 ny = cpl_image_get_size_y(spatial);
11466 ysize = cpl_image_get_size_y(calibration);
11467 remapped = cpl_image_new(nx, ny, CPL_TYPE_FLOAT);
11468 data = cpl_image_get_data(remapped);
11469 sdata = cpl_image_get_data(spatial);
11470 wdata = cpl_image_get_data(calibration);
11472 nslits = cpl_table_get_nrow(slits);
11473 slit_id = cpl_table_get_data_int(slits,
"slit_id");
11474 order = cpl_table_get_ncol(polytraces) - 2;
11475 position = cpl_table_get_data_int(slits,
"position");
11476 length = cpl_table_get_data_int(slits,
"length");
11483 pixel_above = STRETCH_FACTOR * (red - reference) / dispersion;
11484 pixel_below = STRETCH_FACTOR * (reference - blue) / dispersion;
11486 for (i = 0; i < nslits; i++) {
11488 if (length[i] == 0)
11502 refpixel = cpl_table_get_double(slits,
"xtop", i, NULL);
11504 start_pixel = refpixel - pixel_below;
11505 if (start_pixel < 0)
11508 end_pixel = refpixel + pixel_above;
11509 if (end_pixel > nx)
11518 polytop = cpl_polynomial_new(1);
11519 for (k = 0; k <= order; k++) {
11520 coeff = cpl_table_get_double(polytraces, clab[k], 2*i, &null);
11522 cpl_polynomial_delete(polytop);
11526 cpl_polynomial_set_coeff(polytop, &k, coeff);
11530 polybot = cpl_polynomial_new(1);
11531 for (k = 0; k <= order; k++) {
11532 coeff = cpl_table_get_double(polytraces, clab[k], 2*i+1, &null);
11534 cpl_polynomial_delete(polybot);
11538 cpl_polynomial_set_coeff(polybot, &k, coeff);
11541 if (missing_top && missing_bot) {
11542 cpl_msg_debug(func,
"Slit %d was not traced: no extraction!",
11554 cpl_msg_debug(func,
"Upper edge of slit %d was not traced: " 11555 "the spectral curvature of the lower edge " 11556 "is used instead.", slit_id[i]);
11557 polytop = cpl_polynomial_duplicate(polybot);
11558 ytop = cpl_table_get_double(slits,
"ytop", i, NULL);
11559 ybot = cpl_table_get_double(slits,
"ybottom", i, NULL);
11561 coeff = cpl_polynomial_get_coeff(polybot, &k);
11562 coeff += ytop - ybot;
11563 cpl_polynomial_set_coeff(polytop, &k, coeff);
11567 cpl_msg_debug(func,
"Lower edge of slit %d was not traced: " 11568 "the spectral curvature of the upper edge " 11569 "is used instead.", slit_id[i]);
11570 polybot = cpl_polynomial_duplicate(polytop);
11571 ytop = cpl_table_get_double(slits,
"ytop", i, NULL);
11572 ybot = cpl_table_get_double(slits,
"ybottom", i, NULL);
11574 coeff = cpl_polynomial_get_coeff(polytop, &k);
11575 coeff -= ytop - ybot;
11576 cpl_polynomial_set_coeff(polybot, &k, coeff);
11586 xdata = wdata + nx*position[i];
11587 npseudo = length[i] - 1;
11593 for (j = start_pixel; j < end_pixel; j++) {
11594 top = cpl_polynomial_eval_1d(polytop, j, NULL);
11595 bot = cpl_polynomial_eval_1d(polybot, j, NULL);
11596 for (k = 0; k <= npseudo; k++) {
11597 ypos = top - k*(top-bot)/npseudo;
11607 if (yint < 0 || yint >= ny-1) {
11612 value = sdata[j + nx*yint];
11614 fvalue = value - ivalue;
11615 if (ivalue < npseudo && ivalue >= 0) {
11616 vtop = xdata[j + nx*(npseudo-ivalue)];
11617 vbot = xdata[j + nx*(npseudo-ivalue-1)];
11626 else if (vbot < 1.0) {
11632 else if (fabs(vbot-vtop) > 10*dispersion) {
11636 value = vtop*(1-fvalue) + vbot*fvalue;
11638 data[j + nx*yint] = value;
11648 if (yprev - yint > 1) {
11649 value = sdata[j + nx*(yint+1)];
11651 fvalue = value - ivalue;
11652 if (ivalue < npseudo && ivalue >= 0) {
11653 vtop = xdata[j + nx*(npseudo-ivalue)];
11654 vbot = xdata[j + nx*(npseudo-ivalue-1)];
11657 value = data[j + nx*(yint+1)];
11663 else if (vbot < 1.0) {
11666 else if (fabs(vbot-vtop) > 2*dispersion) {
11670 value = vtop*(1-fvalue) + vbot*fvalue;
11672 data[j + nx*(yint+1)] = value;
11680 cpl_polynomial_delete(polytop);
11681 cpl_polynomial_delete(polybot);
11761 cpl_image *spatial, cpl_table *slits,
11762 cpl_table *polytraces,
double reference,
11763 double blue,
double red,
double dispersion,
11766 const char *func =
"mos_map_spectrum";
11768 const char *clab[6] = {
"c0",
"c1",
"c2",
"c3",
"c4",
"c5"};
11770 cpl_polynomial *polytop;
11771 cpl_polynomial *polybot;
11772 cpl_image *remapped;
11773 cpl_image **exslit;
11778 double lambda00, lambda01, lambda10, lambda11, lambda;
11779 double space00, space01, space10, space11, space;
11780 double value00, value01, value10, value11, value0, value1, value;
11785 double xfrac, yfrac;
11798 int pixel_above, pixel_below, refpixel, start_pixel, end_pixel;
11799 int missing_top, missing_bot;
11808 if (spectra == NULL || spatial == NULL || wavecalib == NULL ||
11809 slits == NULL || polytraces == NULL) {
11810 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
11814 if (dispersion <= 0.0) {
11815 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
11819 if (red - blue < dispersion) {
11820 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
11824 nx = cpl_image_get_size_x(spectra);
11825 ny = cpl_image_get_size_y(spectra);
11827 if (nx != cpl_image_get_size_x(spatial) ||
11828 ny != cpl_image_get_size_y(spatial) ||
11829 nx != cpl_image_get_size_x(wavecalib) ||
11830 ny != cpl_image_get_size_y(wavecalib)) {
11831 cpl_error_set(func, CPL_ERROR_INCOMPATIBLE_INPUT);
11835 nlambda = STRETCH_FACTOR * (red - blue) / dispersion;
11836 pixel_above = STRETCH_FACTOR * (red - reference) / dispersion;
11837 pixel_below = STRETCH_FACTOR * (reference - blue) / dispersion;
11839 data = cpl_image_get_data(spectra);
11840 sdata = cpl_image_get_data(spatial);
11841 wdata = cpl_image_get_data(wavecalib);
11843 nslits = cpl_table_get_nrow(slits);
11844 slit_id = cpl_table_get_data_int(slits,
"slit_id");
11845 order = cpl_table_get_ncol(polytraces) - 2;
11846 position = cpl_table_get_data_int(slits,
"position");
11847 length = cpl_table_get_data_int(slits,
"length");
11849 exslit = cpl_calloc(nslits,
sizeof(cpl_image *));
11851 for (i = 0; i < nslits; i++) {
11867 refpixel = cpl_table_get_double(slits,
"xtop", i, NULL);
11869 start_pixel = refpixel - pixel_below;
11870 if (start_pixel < 1)
11873 end_pixel = refpixel + pixel_above;
11874 if (end_pixel > nx)
11883 polytop = cpl_polynomial_new(1);
11884 for (k = 0; k <= order; k++) {
11885 coeff = cpl_table_get_double(polytraces, clab[k], 2*i, &null);
11887 cpl_polynomial_delete(polytop);
11891 cpl_polynomial_set_coeff(polytop, &k, coeff);
11895 polybot = cpl_polynomial_new(1);
11896 for (k = 0; k <= order; k++) {
11897 coeff = cpl_table_get_double(polytraces, clab[k], 2*i+1, &null);
11899 cpl_polynomial_delete(polybot);
11903 cpl_polynomial_set_coeff(polybot, &k, coeff);
11906 if (missing_top && missing_bot) {
11907 cpl_msg_debug(func,
"Slit %d was not traced: no extraction!",
11919 cpl_msg_debug(func,
"Upper edge of slit %d was not traced: " 11920 "the spectral curvature of the lower edge " 11921 "is used instead.", slit_id[i]);
11922 polytop = cpl_polynomial_duplicate(polybot);
11923 ytop = cpl_table_get_double(slits,
"ytop", i, NULL);
11924 ybot = cpl_table_get_double(slits,
"ybottom", i, NULL);
11926 coeff = cpl_polynomial_get_coeff(polybot, &k);
11927 coeff += ytop - ybot;
11928 cpl_polynomial_set_coeff(polytop, &k, coeff);
11932 cpl_msg_debug(func,
"Lower edge of slit %d was not traced: " 11933 "the spectral curvature of the upper edge " 11934 "is used instead.", slit_id[i]);
11935 polybot = cpl_polynomial_duplicate(polytop);
11936 ytop = cpl_table_get_double(slits,
"ytop", i, NULL);
11937 ybot = cpl_table_get_double(slits,
"ybottom", i, NULL);
11939 coeff = cpl_polynomial_get_coeff(polytop, &k);
11940 coeff -= ytop - ybot;
11941 cpl_polynomial_set_coeff(polybot, &k, coeff);
11948 top = cpl_polynomial_eval_1d(polytop, refpixel, NULL);
11949 bot = cpl_polynomial_eval_1d(polybot, refpixel, NULL);
11950 npseudo = ceil(top-bot) + 1;
11953 cpl_polynomial_delete(polytop);
11954 cpl_polynomial_delete(polybot);
11955 cpl_msg_debug(func,
"Slit %d was badly traced: no extraction!",
11960 exslit[i] = cpl_image_new(nlambda, npseudo+1, CPL_TYPE_FLOAT);
11961 xdata = cpl_image_get_data(exslit[i]);
11967 for (x = start_pixel; x < end_pixel; x++) {
11968 top = cpl_polynomial_eval_1d(polytop, x, NULL);
11969 bot = cpl_polynomial_eval_1d(polybot, x, NULL);
11980 for (y = ibot; y < itop; y++) {
11981 lambda11 = wdata[x + y*nx];
11982 if (lambda11 < 1.0)
11984 space11 = sdata[x + y*nx];
11987 lambda01 = wdata[x - 1 + y*nx];
11988 if (lambda01 < 1.0)
11990 space01 = sdata[x - 1 + y*nx];
12023 lambda10 = wdata[x + shift + (y+1)*nx];
12024 if (lambda10 < 1.0)
12026 space10 = sdata[x + shift + (y+1)*nx];
12029 lambda00 = wdata[x - 1 + shift + (y+1)*nx];
12030 if (lambda00 < 1.0)
12032 space00 = sdata[x - 1 + shift + (y+1)*nx];
12042 dL = lambda11 - lambda01;
12043 dS = space11 - space10;
12050 L = (lambda11 - blue)/dispersion + 0.5;
12053 if (L < 0 || L >= nlambda)
12055 if (S < 0 || S > npseudo)
12062 lambda = blue + L*dispersion;
12074 xfrac = (lambda11-lambda)/dL;
12075 yfrac = (space11-space)/dS;
12086 value11 = data[x + y*nx];
12087 value01 = data[x - 1 + y*nx];
12088 value10 = data[x + shift + (y+1)*nx];
12089 value00 = data[x + shift - 1 + (y+1)*nx];
12095 value1 = (1-xfrac)*value11 + xfrac*value01;
12096 value0 = (1-xfrac)*value10 + xfrac*value00;
12097 value = (1-yfrac)*value1 + yfrac*value0;
12104 xdata[L + nlambda*(npseudo-S)] = value;
12108 cpl_polynomial_delete(polytop);
12109 cpl_polynomial_delete(polybot);
12117 for (i = 0; i < nslits; i++)
12119 ysize += cpl_image_get_size_y(exslit[i]);
12121 remapped = cpl_image_new(nlambda, ysize, CPL_TYPE_FLOAT);
12124 for (i = 0; i < nslits; i++) {
12126 yint += cpl_image_get_size_y(exslit[i]);
12127 cpl_image_copy(remapped, exslit[i], 1, ysize - yint);
12128 cpl_image_delete(exslit[i]);
12129 cpl_table_set_int(slits,
"position", i, ysize - yint - 1);
12173 double dispersion,
double factor,
int minpoints,
12176 const char *func =
"mos_sky_map_super";
12178 cpl_vector **vector;
12179 cpl_vector **wvector;
12180 double firstLambda, lastLambda;
12181 double lambda, lambda1, lambda2;
12182 double value, value1, value2;
12188 int first_valid, valid_bins;
12192 double *sky_spectrum;
12199 if (spectra == NULL || wavemap == NULL || skymap == NULL) {
12200 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
12204 if (dispersion <= 0.0) {
12205 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
12206 cpl_msg_error(func,
"Negative dispersion: %s", cpl_error_get_message());
12210 nx = cpl_image_get_size_x(spectra);
12211 ny = cpl_image_get_size_y(spectra);
12214 if (nx != cpl_image_get_size_x(wavemap) ||
12215 ny != cpl_image_get_size_y(wavemap) ||
12216 nx != cpl_image_get_size_x(skymap) ||
12217 ny != cpl_image_get_size_y(skymap)) {
12218 cpl_error_set(func, CPL_ERROR_INCOMPATIBLE_INPUT);
12219 cpl_msg_error(func,
"Image sizes: %s", cpl_error_get_message());
12223 if (factor < 1.0) {
12224 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
12225 cpl_msg_error(func,
"Undersampling (%f): %s", factor,
12226 cpl_error_get_message());
12230 if (minpoints < 0) {
12231 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
12232 cpl_msg_error(func,
"Negative threshold: %s", cpl_error_get_message());
12236 dispersion /= factor;
12243 data = cpl_image_get_data(wavemap);
12245 for (i = 0; i < npix; i++) {
12246 if (data[i] > 1.0) {
12247 min = max = data[i];
12253 for (i = j; i < npix; i++) {
12270 nbin = (lastLambda - firstLambda) / dispersion;
12279 count = cpl_calloc(nbin,
sizeof(
int));
12281 data = cpl_image_get_data(wavemap);
12283 for (i = 0; i < npix; i++) {
12286 bin = (data[i] - firstLambda) / dispersion;
12292 for (i = 0; i < nbin; i++)
12293 if (count[i] >= minpoints)
12296 if (valid_bins < nbin/3) {
12297 cpl_msg_warning(func,
"Cannot determine a good global sky " 12298 "spectrum from input data");
12310 vector = cpl_calloc(nbin,
sizeof(cpl_vector *));
12311 wvector = cpl_calloc(nbin,
sizeof(cpl_vector *));
12312 for (i = 0; i < nbin; i++) {
12313 if (count[i] >= minpoints) {
12314 vector[i] = cpl_vector_new(count[i]);
12315 wvector[i] = cpl_vector_new(count[i]);
12326 data = cpl_image_get_data(wavemap);
12327 sdata = cpl_image_get_data(spectra);
12329 for (i = 0; i < npix; i++) {
12332 bin = (data[i] - firstLambda) / dispersion;
12335 cpl_vector_set(vector[bin], count[bin], sdata[i]);
12336 cpl_vector_set(wvector[bin], count[bin], data[i]);
12348 sky_spectrum = cpl_calloc(nbin,
sizeof(
double));
12349 sky_wave = cpl_calloc(nbin,
sizeof(
double));
12350 for (i = 0; i < nbin; i++) {
12352 sky_spectrum[i] = cpl_vector_get_median_const(vector[i]);
12353 sky_wave[i] = cpl_vector_get_median_const(wvector[i]);
12354 cpl_vector_delete(vector[i]);
12355 cpl_vector_delete(wvector[i]);
12367 for (i = 0; i < nbin; i++) {
12368 if (count[i] >= minpoints) {
12374 for (i = first_valid; i < nbin; i++) {
12375 if (count[i] < minpoints) {
12376 sky_wave[i] = firstLambda + (i+0.5)*dispersion;
12377 for (j = i+1; j < nbin; j++) {
12378 if (count[j] >= minpoints) {
12379 if (sky_wave[j] - sky_wave[i-1] < 0.1) {
12380 sky_spectrum[i] = (sky_spectrum[j] + sky_spectrum[i-1])
12384 frac = (sky_wave[i] - sky_wave[i-1])
12385 / (sky_wave[j] - sky_wave[i-1]);
12386 sky_spectrum[i] = frac * sky_spectrum[j]
12387 + (1 - frac) * sky_spectrum[i-1];
12399 sky = cpl_table_new(nbin);
12400 cpl_table_wrap_double(sky, sky_wave,
"wavelength");
12401 cpl_table_wrap_double(sky, sky_spectrum,
"sky");
12402 cpl_table_wrap_int(sky, count,
"npoints");
12409 data = cpl_image_get_data(wavemap);
12410 sdata = cpl_image_get_data(spectra);
12411 kdata = cpl_image_get_data(skymap);
12413 for (i = 0; i < npix; i++) {
12422 bin = (lambda - firstLambda) / dispersion;
12423 lambda1 = sky_wave[bin];
12424 value1 = sky_spectrum[bin];
12425 if (lambda1 < lambda) {
12428 lambda2 = sky_wave[bin];
12429 value2 = sky_spectrum[bin];
12430 if (lambda2 - lambda1 < 0.1) {
12431 value = (value1 + value2) / 2;
12434 frac = (lambda - lambda1) / (lambda2 - lambda1);
12435 value = frac * value2 + (1 - frac) * value1;
12447 lambda1 = sky_wave[bin];
12448 value1 = sky_spectrum[bin];
12449 if (lambda2 - lambda1 < 0.1) {
12450 value = (value1 + value2) / 2;
12453 frac = (lambda - lambda1) / (lambda2 - lambda1);
12454 value = frac * value2 + (1 - frac) * value1;
12465 cpl_table_erase_window(sky, 0, first_valid);
12506 double dispersion, cpl_image *skymap)
12508 const char *func =
"mos_sky_map";
12510 cpl_vector **vector;
12511 double firstLambda, lastLambda;
12512 double lambda, lambda1, lambda2;
12513 double value, value1, value2;
12521 double *sky_spectrum;
12528 if (spectra == NULL || wavemap == NULL || skymap == NULL) {
12529 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
12533 if (dispersion <= 0.0) {
12534 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
12538 nx = cpl_image_get_size_x(spectra);
12539 ny = cpl_image_get_size_y(spectra);
12542 if (nx != cpl_image_get_size_x(wavemap) ||
12543 ny != cpl_image_get_size_y(wavemap) ||
12544 nx != cpl_image_get_size_x(skymap) ||
12545 ny != cpl_image_get_size_y(skymap)) {
12546 cpl_error_set(func, CPL_ERROR_INCOMPATIBLE_INPUT);
12555 data = cpl_image_get_data(wavemap);
12557 for (i = 0; i < npix; i++) {
12558 if (data[i] > 1.0) {
12559 min = max = data[i];
12565 for (i = j; i < npix; i++) {
12582 nbin = (lastLambda - firstLambda) / dispersion;
12591 count = cpl_calloc(nbin,
sizeof(
int));
12593 data = cpl_image_get_data(wavemap);
12595 for (i = 0; i < npix; i++) {
12598 bin = (data[i] - firstLambda) / dispersion;
12611 vector = cpl_calloc(nbin,
sizeof(cpl_vector *));
12612 for (i = 0; i < nbin; i++) {
12614 vector[i] = cpl_vector_new(count[i]);
12626 data = cpl_image_get_data(wavemap);
12627 sdata = cpl_image_get_data(spectra);
12629 for (i = 0; i < npix; i++) {
12632 bin = (data[i] - firstLambda) / dispersion;
12634 cpl_vector_set(vector[bin], count[bin], sdata[i]);
12645 sky_spectrum = cpl_calloc(nbin,
sizeof(
double));
12646 for (i = 0; i < nbin; i++) {
12648 sky_spectrum[i] = cpl_vector_get_median_const(vector[i]);
12649 cpl_vector_delete(vector[i]);
12667 sky = cpl_table_new(nbin);
12668 cpl_table_new_column(sky,
"wavelength", CPL_TYPE_DOUBLE);
12669 cpl_table_set_column_unit(sky,
"wavelength",
"pixel");
12670 cpl_table_wrap_double(sky, sky_spectrum,
"sky");
12671 cpl_table_wrap_int(sky, count,
"npoints");
12672 for (i = 0; i < nbin; i++)
12673 cpl_table_set_double(sky,
"wavelength", i,
12674 firstLambda + (i+0.5)*dispersion);
12681 data = cpl_image_get_data(wavemap);
12682 sdata = cpl_image_get_data(spectra);
12683 kdata = cpl_image_get_data(skymap);
12684 wdata = cpl_table_get_data_double(sky,
"wavelength");
12686 for (i = 0; i < npix; i++) {
12695 bin = (lambda - firstLambda) / dispersion;
12696 lambda1 = wdata[bin];
12697 value1 = sky_spectrum[bin];
12698 if (lambda1 < lambda) {
12701 lambda2 = wdata[bin];
12702 value2 = sky_spectrum[bin];
12703 value = ((lambda2 - lambda)*value1
12704 + (lambda - lambda1)*value2) / dispersion;
12715 lambda1 = wdata[bin];
12716 value1 = sky_spectrum[bin];
12717 value = ((lambda2 - lambda)*value1
12718 + (lambda - lambda1)*value2)/dispersion;
12749 const char *func =
"mos_sky_local_old";
12757 int xlow, ylow, xhig, yhig;
12765 if (spectra == NULL) {
12766 cpl_msg_error(func,
12767 "A scientific rectified spectral image must be given");
12768 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
12772 if (slits == NULL) {
12773 cpl_msg_error(func,
"A slits position table must be given");
12774 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
12778 nslits = cpl_table_get_nrow(slits);
12779 slit_id = cpl_table_get_data_int(slits,
"slit_id");
12780 position = cpl_table_get_data_int(slits,
"position");
12781 length = cpl_table_get_data_int(slits,
"length");
12783 nx = cpl_image_get_size_x(spectra);
12784 ny = cpl_image_get_size_y(spectra);
12786 skymap = cpl_image_new(nx, ny, CPL_TYPE_FLOAT);
12790 for (i = 0; i < nslits; i++) {
12792 if (length[i] == 0)
12805 ylow = position[i] + 1;
12806 yhig = ylow + length[i] - 1;
12808 exslit = cpl_image_extract(spectra, xlow, ylow, xhig, yhig);
12809 sky = cpl_image_collapse_median_create(exslit, 0, 0, 1);
12810 cpl_image_delete(exslit);
12812 data = cpl_image_get_data(skymap);
12813 data += nx * position[i];
12815 for (j = 0; j < length[i]; j++) {
12816 sdata = cpl_image_get_data(sky);
12817 for (k = 0; k < nx; k++) {
12818 *data++ = *sdata++;
12822 cpl_image_delete(sky);
12851 const char *func =
"mos_sky_local";
12853 char name[MAX_COLNAME];
12855 cpl_polynomial *fit;
12856 cpl_vector *points;
12857 cpl_vector *values;
12858 cpl_vector *keep_points;
12859 cpl_vector *keep_values;
12862 cpl_image *subtracted;
12863 cpl_image *profile;
12865 cpl_table *objects;
12873 int xlow, ylow, xhig, yhig;
12886 if (spectra == NULL) {
12887 cpl_msg_error(func,
12888 "A scientific rectified spectral image must be given");
12889 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
12893 if (slits == NULL) {
12894 cpl_msg_error(func,
"A slits position table must be given");
12895 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
12900 cpl_msg_error(func,
"Invalid fit order");
12901 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
12905 nslits = cpl_table_get_nrow(slits);
12906 slit_id = cpl_table_get_data_int(slits,
"slit_id");
12907 position = cpl_table_get_data_int(slits,
"position");
12908 length = cpl_table_get_data_int(slits,
"length");
12910 nx = cpl_image_get_size_x(spectra);
12911 ny = cpl_image_get_size_y(spectra);
12913 skymap = cpl_image_new(nx, ny, CPL_TYPE_FLOAT);
12917 for (i = 0; i < nslits; i++) {
12919 if (length[i] == 0)
12932 ylow = position[i] + 1;
12933 yhig = ylow + length[i] - 1;
12935 exslit = cpl_image_extract(spectra, xlow, ylow, xhig, yhig);
12936 sky = cpl_image_collapse_median_create(exslit, 0, 0, 1);
12937 cpl_image_delete(exslit);
12939 data = cpl_image_get_data(skymap);
12940 data += nx * position[i];
12942 for (j = 0; j < length[i]; j++) {
12943 sdata = cpl_image_get_data(sky);
12944 for (k = 0; k < nx; k++) {
12945 *data++ = *sdata++;
12949 cpl_image_delete(sky);
12957 subtracted = cpl_image_duplicate(spectra);
12958 cpl_image_subtract(subtracted, skymap);
12959 cpl_image_delete(skymap);
12966 objects = cpl_table_duplicate(slits);
12968 cpl_image_delete(profile);
12969 cpl_image_delete(subtracted);
12978 snprintf(name, MAX_COLNAME,
"object_%d", maxobjects);
12979 while (cpl_table_has_column(objects, name)) {
12981 snprintf(name, MAX_COLNAME,
"object_%d", maxobjects);
12984 is_sky = cpl_calloc(ny,
sizeof(
int));
12986 for (i = 0; i < nslits; i++) {
12988 if (length[i] == 0)
12991 ylow = position[i] + margin;
12992 yhig = position[i] + length[i] - margin;
12994 for (j = ylow; j < yhig; j++)
12997 for (j = 1; j < maxobjects; j++) {
12998 snprintf(name, MAX_COLNAME,
"object_%d", j);
12999 if (cpl_table_is_valid(objects, name, i)) {
13000 snprintf(name, MAX_COLNAME,
"start_%d", j);
13001 ylow = cpl_table_get_int(objects, name, i, NULL);
13002 snprintf(name, MAX_COLNAME,
"end_%d", j);
13003 yhig = cpl_table_get_int(objects, name, i, NULL);
13004 for (k = ylow; k <= yhig; k++)
13014 ylow = position[i] + margin + 1;
13015 yhig = position[i] + length[i] - margin - 1;
13017 for (j = ylow; j < yhig; j++)
13019 if (is_sky[j-1] == 0 && is_sky[j+1] == 0)
13029 skymap = cpl_image_new(nx, ny, CPL_TYPE_FLOAT);
13031 for (i = 0; i < nslits; i++) {
13033 if (length[i] == 0)
13036 ylow = position[i];
13037 yhig = ylow + length[i];
13040 for (j = ylow; j < yhig; j++)
13044 if (nsky > order + 1) {
13046 points = cpl_vector_new(nsky);
13048 for (j = ylow; j < yhig; j++) {
13050 cpl_vector_set(points, nsky, j);
13055 exslit = cpl_image_extract(spectra, 1, ylow+1, nx, yhig);
13056 xdata = cpl_image_get_data(exslit);
13057 values = cpl_vector_new(nsky);
13059 for (j = 0; j < nx; j++) {
13061 for (k = ylow; k < yhig; k++) {
13063 cpl_vector_set(values, nsky, xdata[j+(k-ylow)*nx]);
13072 median = cpl_vector_get_median_const(values);
13073 vdata = cpl_vector_get_data(values);
13074 pdata = cpl_vector_get_data(points);
13076 for (k = 0; k < nsky; k++) {
13077 if (fabs(vdata[k] - median) < 100) {
13079 vdata[k-nbad] = vdata[k];
13080 pdata[k-nbad] = pdata[k];
13090 if (nbad && nsky - nbad > order + 1) {
13091 keep_values = values;
13092 keep_points = points;
13093 values = cpl_vector_wrap(nsky-nbad, vdata);
13094 points = cpl_vector_wrap(nsky-nbad, pdata);
13097 if (nsky - nbad > order + 1) {
13099 fit = cpl_polynomial_fit_1d_create(points, values,
13103 for (k = ylow; k < yhig; k++) {
13104 xdata[j+(k-ylow)*nx] =
13105 cpl_polynomial_eval_1d(fit, k, NULL);
13108 cpl_polynomial_delete(fit);
13114 for (k = 0; k < nsky; k++) {
13115 xdata[j+k*nx] = median;
13119 if (nbad && nsky - nbad > order + 1) {
13120 cpl_vector_unwrap(values);
13121 cpl_vector_unwrap(points);
13122 values = keep_values;
13123 points = keep_points;
13128 for (k = ylow; k < yhig; k++) {
13130 cpl_vector_set(points, nsky, k);
13138 cpl_vector_delete(values);
13139 cpl_vector_delete(points);
13141 cpl_image_copy(skymap, exslit, 1, ylow+1);
13142 cpl_image_delete(exslit);
13146 exslit = cpl_image_extract(spectra, 1, ylow+1, nx, yhig);
13147 xdata = cpl_image_get_data(exslit);
13148 values = cpl_vector_new(nsky);
13150 for (j = 0; j < nx; j++) {
13152 for (k = ylow; k < yhig; k++) {
13154 cpl_vector_set(values, nsky, xdata[j+(k-ylow)*nx]);
13159 median = cpl_vector_get_median_const(values);
13161 for (k = ylow; k < yhig; k++)
13162 xdata[j+(k-ylow)*nx] = median;
13166 cpl_vector_delete(values);
13168 cpl_image_copy(skymap, exslit, 1, ylow+1);
13169 cpl_image_delete(exslit);
13173 cpl_msg_warning(func,
"Too few sky points in slit %d", i + 1);
13205 float threshold,
float ratio)
13207 const char *func =
"mos_clean_cosmics";
13209 cpl_image *smoothImage;
13211 cpl_matrix *kernel;
13216 float sigma, sum, value, smoothValue;
13220 int iMin, iMax, jMin, jMax, iPosMax, jPosMax;
13226 int pos, i, j, k, l, ii, jj, iii = 0, jjj = 0;
13228 int found, foundContiguousCandidate;
13233 return cpl_error_set(func, CPL_ERROR_NULL_INPUT);
13246 xLen = cpl_image_get_size_x(image);
13247 yLen = cpl_image_get_size_y(image);
13249 if (xLen < 4 || yLen < 4)
13250 return CPL_ERROR_NONE;
13252 nPix = xLen * yLen;
13275 idata = cpl_image_get_data(image);
13279 for (i = 0; i < nPix; i++) {
13280 if (idata[i] < -0.00001) {
13289 cosmic = cpl_calloc(nPix,
sizeof(
int));
13291 if (threshold < 0.)
13296 kernel = cpl_matrix_new(3, 3);
13297 cpl_matrix_fill(kernel, 1.0);
13298 cpl_matrix_set(kernel, 1, 1, 0.0);
13299 smoothImage = cpl_image_filter_median(image, kernel);
13300 cpl_matrix_delete(kernel);
13311 sdata = cpl_image_get_data(smoothImage);
13313 for (j = 1; j < yLen - 1; j++) {
13314 for (i = 1; i < xLen - 1; i++) {
13315 value = idata[i + j * xLen];
13316 smoothValue = sdata[i + j * xLen];
13317 if (smoothValue < 1.0)
13319 sigma = sqrt(noise * noise + smoothValue / gain);
13320 if (value - smoothValue >= threshold * sigma)
13321 cosmic[i + j * xLen] = -1;
13325 cpl_image_delete(smoothImage);
13334 for (pos = first; pos < nPix; pos++) {
13335 if (cosmic[pos] == -1) {
13355 iMin = iMax = iPosMax = i;
13356 jMin = jMax = jPosMax = j;
13357 fMax = idata[i + j * xLen];
13360 foundContiguousCandidate = 0;
13361 for (l = 0; l <= 1; l++) {
13362 for (k = 0; k <= 1; k++) {
13369 jj = j + k + l - 1;
13370 if (cosmic[ii + jj * xLen] == -1) {
13371 foundContiguousCandidate = 1;
13372 cosmic[ii + jj * xLen] = 2;
13390 if (idata[ii + jj * xLen] > fMax) {
13391 fMax = idata[ii + jj * xLen];
13404 cosmic[i + j * xLen] = 3;
13406 if (foundContiguousCandidate) {
13428 for (l = jMin; l <= jMax; l++) {
13429 for (k = iMin; k <= iMax; k++) {
13430 if (cosmic[k + l * xLen] == 2) {
13433 foundContiguousCandidate = 1;
13437 if (foundContiguousCandidate)
13440 }
while (foundContiguousCandidate);
13449 for (l = -1; l <= 1; l++) {
13450 for (k = -1; k <= 1; k++) {
13451 if (l != 0 || k != 0) {
13452 sum += idata[iPosMax + k + (jPosMax + l) * xLen];
13458 if (fMax > ratio * sum) {
13459 for (l = jMin - 1; l <= jMax + 1; l++) {
13460 for (k = iMin - 1; k <= iMax + 1; k++) {
13461 if (cosmic[k + l * xLen] == 3) {
13462 cosmic[k + l * xLen] = 1;
13469 for (l = jMin - 1; l <= jMax + 1; l++) {
13470 for (k = iMin - 1; k <= iMax + 1; k++) {
13471 if (cosmic[k + l * xLen] != -1) {
13472 if (cosmic[k + l * xLen] == 1)
13474 cosmic[k + l * xLen] = 0;
13487 table = cpl_table_new(numCosmic);
13488 cpl_table_new_column(table,
"x", CPL_TYPE_INT);
13489 cpl_table_new_column(table,
"y", CPL_TYPE_INT);
13490 cpl_table_set_column_unit(table,
"x",
"pixel");
13491 cpl_table_set_column_unit(table,
"y",
"pixel");
13492 xdata = cpl_table_get_data_int(table,
"x");
13493 ydata = cpl_table_get_data_int(table,
"y");
13495 for (pos = 0, i = 0; pos < nPix; pos++) {
13496 if (cosmic[pos] == 1) {
13497 xdata[i] = (pos % xLen);
13498 ydata[i] = (pos / xLen);
13503 mos_clean_bad_pixels(image, table, 1);
13506 cpl_table_delete(table);
13508 return CPL_ERROR_NONE;
13513 cpl_error_code mos_clean_bad_pixels(cpl_image *image, cpl_table *table,
13516 const char *func =
"mos_clean_cosmics";
13521 int xlen, ylen, totPix;
13522 int nBadPixels = 0;
13523 int sign, foundFirst;
13524 int *xValue = NULL;
13525 int *yValue = NULL;
13531 int sx[] = {0, 1, 1, 1};
13532 int sy[] = {1,-1, 0, 1};
13533 int searchHorizon = 100;
13537 if (image == NULL || table == NULL)
13538 return cpl_error_set(func, CPL_ERROR_NULL_INPUT);
13540 if (1 != cpl_table_has_column(table,
"x"))
13541 return cpl_error_set(func, CPL_ERROR_DATA_NOT_FOUND);
13543 if (1 != cpl_table_has_column(table,
"y"))
13544 return cpl_error_set(func, CPL_ERROR_DATA_NOT_FOUND);
13546 if (CPL_TYPE_INT != cpl_table_get_column_type(table,
"x"))
13547 return cpl_error_set(func, CPL_ERROR_INVALID_TYPE);
13549 if (CPL_TYPE_INT != cpl_table_get_column_type(table,
"y"))
13550 return cpl_error_set(func, CPL_ERROR_INVALID_TYPE);
13552 nBadPixels = cpl_table_get_nrow(table);
13555 xlen = cpl_image_get_size_x(image);
13556 ylen = cpl_image_get_size_y(image);
13557 idata = cpl_image_get_data(image);
13558 totPix = xlen * ylen;
13559 if (((
float) nBadPixels) / ((
float) totPix) < percent/100.) {
13560 isBadPix = cpl_calloc(totPix,
sizeof(
int));
13563 cpl_msg_warning(func,
"Too many bad pixels (> %d%%): " 13564 "skip bad pixel correction", percent);
13565 return cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
13569 cpl_msg_debug(func,
"No pixel values to interpolate");
13570 return CPL_ERROR_NONE;
13573 xValue = cpl_table_get_data_int(table,
"x");
13574 yValue = cpl_table_get_data_int(table,
"y");
13576 for (i = 0; i < nBadPixels; i++)
13577 isBadPix[xValue[i] + yValue[i] * xlen] = 1;
13579 for (i = 0; i < nBadPixels; i++) {
13594 for (j = 0; j < 4; j++) {
13600 estimate[nPairs] = 0.;
13603 for (k = 0; k < 2; k++) {
13609 cx += sign * sx[j];
13610 cy += sign * sy[j];
13611 if (cx < 0 || cx >= xlen || cy < 0 || cy >= ylen)
13614 }
while (isBadPix[cx + cy * xlen] && d < searchHorizon);
13616 if (cx >= 0 && cx < xlen &&
13617 cy >= 0 && cy < ylen && d < searchHorizon) {
13623 save = idata[cx + cy * xlen];
13624 estimate[nPairs] += save / d;
13625 sumd += 1. / (double) d;
13627 estimate[nPairs] /= sumd;
13642 estimate[nPairs] = save;
13657 idata[xValue[i] + yValue[i] * xlen] =
13658 cpl_tools_get_median_float(estimate, nPairs);
13660 else if (nPairs == 2) {
13661 idata[xValue[i] + yValue[i] * xlen] =
13662 (estimate[0] + estimate[1]) / 2.;
13664 else if (nPairs == 1) {
13665 idata[xValue[i] + yValue[i] * xlen] = estimate[0];
13668 cpl_msg_debug(func,
"Cannot correct bad pixel %d,%d\n",
13669 xValue[i], yValue[i]);
13673 cpl_free(isBadPix);
13675 return CPL_ERROR_NONE;
13709 cpl_table *polytraces,
double reference,
13710 double blue,
double red,
double dispersion)
13712 const char *func =
"mos_spatial_map";
13714 const char *clab[6] = {
"c0",
"c1",
"c2",
"c3",
"c4",
"c5"};
13716 cpl_polynomial *polytop;
13717 cpl_polynomial *polybot;
13718 cpl_image *calibration;
13731 int pixel_above, pixel_below, refpixel, start_pixel, end_pixel;
13732 int missing_top, missing_bot;
13739 if (spectra == NULL || slits == NULL || polytraces == NULL) {
13740 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
13744 if (dispersion <= 0.0) {
13745 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
13749 if (red - blue < dispersion) {
13750 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
13754 nx = cpl_image_get_size_x(spectra);
13755 ny = cpl_image_get_size_y(spectra);
13757 calibration = cpl_image_new(nx, ny, CPL_TYPE_FLOAT);
13758 data = cpl_image_get_data(calibration);
13760 length = cpl_table_get_data_int(slits,
"length");
13761 nslits = cpl_table_get_nrow(slits);
13762 slit_id = cpl_table_get_data_int(slits,
"slit_id");
13763 order = cpl_table_get_ncol(polytraces) - 2;
13770 pixel_above = STRETCH_FACTOR * (red - reference) / dispersion;
13771 pixel_below = STRETCH_FACTOR * (reference - blue) / dispersion;
13773 for (i = 0; i < nslits; i++) {
13775 if (length[i] == 0)
13789 refpixel = cpl_table_get_double(slits,
"xtop", i, NULL);
13791 start_pixel = refpixel - pixel_below;
13792 if (start_pixel < 0)
13795 end_pixel = refpixel + pixel_above;
13796 if (end_pixel > nx)
13805 polytop = cpl_polynomial_new(1);
13806 for (k = 0; k <= order; k++) {
13807 coeff = cpl_table_get_double(polytraces, clab[k], 2*i, &null);
13809 cpl_polynomial_delete(polytop);
13813 cpl_polynomial_set_coeff(polytop, &k, coeff);
13817 polybot = cpl_polynomial_new(1);
13818 for (k = 0; k <= order; k++) {
13819 coeff = cpl_table_get_double(polytraces, clab[k], 2*i+1, &null);
13821 cpl_polynomial_delete(polybot);
13825 cpl_polynomial_set_coeff(polybot, &k, coeff);
13828 if (missing_top && missing_bot) {
13829 cpl_msg_warning(func,
"Spatial map, slit %d was not traced!",
13841 cpl_msg_warning(func,
"Upper edge of slit %d was not traced: " 13842 "the spectral curvature of the lower edge " 13843 "is used instead.", slit_id[i]);
13844 polytop = cpl_polynomial_duplicate(polybot);
13845 ytop = cpl_table_get_double(slits,
"ytop", i, NULL);
13846 ybot = cpl_table_get_double(slits,
"ybottom", i, NULL);
13848 coeff = cpl_polynomial_get_coeff(polybot, &k);
13849 coeff += ytop - ybot;
13850 cpl_polynomial_set_coeff(polytop, &k, coeff);
13854 cpl_msg_warning(func,
"Lower edge of slit %d was not traced: " 13855 "the spectral curvature of the upper edge " 13856 "is used instead.", slit_id[i]);
13857 polybot = cpl_polynomial_duplicate(polytop);
13858 ytop = cpl_table_get_double(slits,
"ytop", i, NULL);
13859 ybot = cpl_table_get_double(slits,
"ybottom", i, NULL);
13861 coeff = cpl_polynomial_get_coeff(polytop, &k);
13862 coeff -= ytop - ybot;
13863 cpl_polynomial_set_coeff(polybot, &k, coeff);
13866 top = cpl_polynomial_eval_1d(polytop, refpixel, NULL);
13867 bot = cpl_polynomial_eval_1d(polybot, refpixel, NULL);
13868 npseudo = ceil(top-bot) + 1;
13871 cpl_polynomial_delete(polytop);
13872 cpl_polynomial_delete(polybot);
13873 cpl_msg_warning(func,
"Slit %d was badly traced: no extraction!",
13878 for (j = start_pixel; j < end_pixel; j++) {
13879 top = cpl_polynomial_eval_1d(polytop, j, NULL);
13880 bot = cpl_polynomial_eval_1d(polybot, j, NULL);
13881 factor = (top-bot)/npseudo;
13882 for (k = 0; k <= npseudo; k++) {
13883 ypos = top - k*factor;
13885 yfra = ypos - yint;
13886 if (yint >= 0 && yint < ny-1) {
13887 data[j + nx*yint] = (top-yint)/factor;
13896 if (yprev - yint > 1) {
13897 data[j + nx*(yint+1)] = (top-yint-1)/factor;
13904 cpl_polynomial_delete(polytop);
13905 cpl_polynomial_delete(polybot);
13908 return calibration;
13975 int maxradius,
int conradius)
13977 const char *func =
"mos_detect_objects";
13979 cpl_image *profile;
13983 char name[MAX_COLNAME];
13987 int nobjects, objpos, totobj;
13994 double mindistance;
14001 const int min_pixels = 10;
14004 if (cpl_error_get_code() != CPL_ERROR_NONE)
14007 if (image == NULL || slits == NULL) {
14008 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
14015 if (maxradius < 0) {
14016 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
14020 if (conradius < 0) {
14021 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
14025 nslits = cpl_table_get_nrow(slits);
14026 position = cpl_table_get_data_int(slits,
"position");
14027 length = cpl_table_get_data_int(slits,
"length");
14029 profile = cpl_image_collapse_create(image, 1);
14030 cpl_image_divide_scalar(profile, cpl_image_get_size_x(image));
14031 pdata = cpl_image_get_data(profile);
14036 for (i = 0; i < nslits; i++) {
14038 if (length[i] == 0)
14041 pos = position[i] + margin;
14042 count = length[i] - 2*margin;
14044 if (count < min_pixels)
14055 if (p[0] > p[1] && p[1] > p[2] && p[2] > p[3] && p[3] > 0) {
14060 for (j = 0; j < count - 3; j++) {
14062 if (p[j+1] > p[j]) {
14067 if (p[j+1] > p[j+2] && p[j+2] > 0) {
14073 if (p[j+1] > p[j+2] && p[j+2] > p[j+3] && p[j+3] > 0) {
14086 if (p[count-1] > p[count-2] && p[count-2] > p[count-3]
14087 && p[count-3] > p[count-4] && p[count-4] > 0) {
14099 reject = cpl_calloc(npeaks,
sizeof(
int));
14100 bright = cpl_calloc(npeaks,
sizeof(
double));
14101 place = cpl_calloc(npeaks,
sizeof(
double));
14104 if (p[0] > p[1] && p[1] > p[2] && p[2] > p[3] && p[3] > 0) {
14106 place[0] = position[i] + margin;
14111 for (j = 0; j < count - 3; j++) {
14113 if (p[j+1] > p[j]) {
14118 if (p[j+1] > p[j+2] && p[j+2] > 0) {
14120 bright[npeaks] = p[j];
14121 place[npeaks] = position[i] + margin + j + 1
14122 + values_to_dx(p[j-1], p[j], p[j+1]);
14128 if (p[j+1] > p[j+2] && p[j+2] > p[j+3] && p[j+3] > 0) {
14130 bright[npeaks] = p[j];
14131 place[npeaks] = position[i] + margin + j + 1
14132 + values_to_dx(p[j-1], p[j], p[j+1]);
14145 if (p[count-1] > p[count-2] && p[count-2] > p[count-3]
14146 && p[count-3] > p[count-4] && p[count-4] > 0) {
14147 bright[npeaks] = p[count-1];
14148 place[npeaks] = position[i] + count;
14157 if (fabs(place[0] - pos) < 1.0)
14159 if (fabs(place[npeaks-1] - pos - count) < 1.0)
14160 reject[npeaks-1] = 1;
14161 for (j = 0; j < npeaks; j++) {
14162 for (k = 0; k < npeaks; k++) {
14165 mindistance = conradius * bright[k] / bright[j]
14166 * bright[k] / bright[j];
14167 if (fabs(place[j] - place[k]) < mindistance)
14173 for (j = 0; j < npeaks; j++) {
14177 low = (place[j-1]*bright[j] + place[j]*bright[j-1])
14178 / (bright[j-1] + bright[j]) + 1;
14183 if (j < npeaks - 1) {
14184 hig = (place[j+1]*bright[j] + place[j]*bright[j+1])
14185 / (bright[j+1] + bright[j]) + 1;
14193 if (hig > pos + count)
14195 if (place[j] - low > maxradius)
14196 low = place[j] - maxradius;
14197 if (hig - place[j] > maxradius)
14198 hig = place[j] + maxradius;
14205 for (j = 0; j < npeaks; j++)
14209 for (j = 0; j < nobjects; j++) {
14210 snprintf(name, MAX_COLNAME,
"object_%d", j+1);
14211 if (cpl_table_has_column(slits, name))
14213 cpl_table_new_column(slits, name, CPL_TYPE_DOUBLE);
14214 snprintf(name, MAX_COLNAME,
"start_%d", j+1);
14215 cpl_table_new_column(slits, name, CPL_TYPE_INT);
14216 cpl_table_set_column_unit(slits, name,
"pixel");
14217 snprintf(name, MAX_COLNAME,
"end_%d", j+1);
14218 cpl_table_new_column(slits, name, CPL_TYPE_INT);
14219 cpl_table_set_column_unit(slits, name,
"pixel");
14220 snprintf(name, MAX_COLNAME,
"row_%d", j+1);
14221 cpl_table_new_column(slits, name, CPL_TYPE_INT);
14222 cpl_table_set_column_unit(slits, name,
"pixel");
14226 for (j = 0; j < npeaks; j++) {
14230 low = (place[j-1]*bright[j] + place[j]*bright[j-1])
14231 / (bright[j-1] + bright[j]) + 1;
14236 if (j < npeaks - 1) {
14237 hig = (place[j+1]*bright[j] + place[j]*bright[j+1])
14238 / (bright[j+1] + bright[j]) + 1;
14246 if (hig > pos + count)
14248 if (place[j] - low > maxradius)
14249 low = place[j] - maxradius;
14250 if (hig - place[j] > maxradius)
14251 hig = place[j] + maxradius;
14253 snprintf(name, MAX_COLNAME,
"object_%d", objpos);
14254 cpl_table_set_double(slits, name, i, place[j]);
14255 snprintf(name, MAX_COLNAME,
"start_%d", objpos);
14256 cpl_table_set_int(slits, name, i, low);
14257 snprintf(name, MAX_COLNAME,
"end_%d", objpos);
14258 cpl_table_set_int(slits, name, i, hig);
14259 snprintf(name, MAX_COLNAME,
"row_%d", objpos);
14260 cpl_table_set_int(slits, name, i, row + objpos - 1);
14267 if (maxobjects < nobjects)
14268 maxobjects = nobjects;
14277 row = cpl_table_get_nrow(slits);
14279 for (i = 0; i < row; i++) {
14280 for (j = 0; j < maxobjects; j++) {
14281 snprintf(name, MAX_COLNAME,
"row_%d", j+1);
14282 if (cpl_table_is_valid(slits, name, i))
14283 cpl_table_set_int(slits, name, i, totobj -
14284 cpl_table_get_int(slits, name, i, NULL));
14288 for (i = 0; i < maxobjects; i++) {
14289 snprintf(name, MAX_COLNAME,
"start_%d", i+1);
14290 cpl_table_fill_invalid_int(slits, name, -1);
14291 snprintf(name, MAX_COLNAME,
"end_%d", i+1);
14292 cpl_table_fill_invalid_int(slits, name, -1);
14293 snprintf(name, MAX_COLNAME,
"row_%d", i+1);
14294 cpl_table_fill_invalid_int(slits, name, -1);
14327 cpl_table *objects,
int extraction,
double ron,
14328 double gain,
int ncombined)
14330 const char *func =
"mos_extract_objects";
14332 char name[MAX_COLNAME];
14334 cpl_image **output;
14335 cpl_image *extracted;
14336 cpl_image *extr_sky;
14339 cpl_image *sci_var_win = NULL;
14349 if (science == NULL || sky == NULL) {
14350 cpl_msg_error(func,
"Both scientific exposures are required in input");
14351 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
14355 if (objects == NULL) {
14356 cpl_msg_error(func,
"An object table is required in input");
14357 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
14361 if (extraction < 0 || extraction > 1) {
14362 cpl_msg_error(func,
"Invalid extraction mode (%d): it should be " 14363 "either 0 or 1", extraction);
14364 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
14369 cpl_msg_error(func,
"Invalid read-out-noise (%f ADU)", ron);
14370 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
14375 cpl_msg_error(func,
"Invalid gain factor (%f e-/ADU)", gain);
14376 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
14380 if (ncombined < 1) {
14381 cpl_msg_error(func,
"Invalid number of combined frames (%d): " 14382 "it should be at least 1", ncombined);
14383 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
14394 snprintf(name, MAX_COLNAME,
"object_%d", maxobjects);
14395 while (cpl_table_has_column(objects, name)) {
14397 snprintf(name, MAX_COLNAME,
"object_%d", maxobjects);
14406 nslits = cpl_table_get_nrow(objects);
14408 for (i = 0; i < nslits; i++) {
14409 for (j = 1; j < maxobjects; j++) {
14410 snprintf(name, MAX_COLNAME,
"object_%d", j);
14411 if (cpl_table_is_valid(objects, name, i))
14419 nx = cpl_image_get_size_x(science);
14421 output = cpl_calloc(3,
sizeof(cpl_image *));
14422 extracted = output[0] = cpl_image_new(nx, nobjects, CPL_TYPE_FLOAT);
14423 extr_sky = output[1] = cpl_image_new(nx, nobjects, CPL_TYPE_FLOAT);
14424 error = output[2] = cpl_image_new(nx, nobjects, CPL_TYPE_FLOAT);
14432 for (i = 0; i < nslits; i++) {
14433 for (j = 1; j < maxobjects; j++) {
14434 snprintf(name, MAX_COLNAME,
"object_%d", j);
14435 if (cpl_table_is_valid(objects, name, i)) {
14436 snprintf(name, MAX_COLNAME,
"start_%d", j);
14437 ylow = cpl_table_get_int(objects, name, i, NULL);
14438 snprintf(name, MAX_COLNAME,
"end_%d", j);
14439 yhig = cpl_table_get_int(objects, name, i, NULL);
14440 snprintf(name, MAX_COLNAME,
"row_%d", j);
14441 nobjects = cpl_table_get_int(objects, name, i, NULL);
14442 sciwin = cpl_image_extract(science, 1, ylow+1, nx, yhig);
14443 if(science_var != NULL)
14444 sci_var_win = cpl_image_extract(science_var, 1, ylow+1, nx, yhig);
14445 skywin = cpl_image_extract(sky, 1, ylow+1, nx, yhig);
14454 mos_extraction(sciwin, sci_var_win, skywin, extracted, extr_sky, error,
14455 nobjects, extraction, ron, gain, ncombined);
14462 cpl_image *total = cpl_image_add_create(sciwin, skywin);
14463 float *data = cpl_image_get_data_float(total);
14464 int size = cpl_image_get_size_x(total)
14465 * cpl_image_get_size_y(total);
14467 char *saturation_level = getenv(
"SATURATION_LEVEL");
14468 float saturation = 62000.0;
14469 char *max_saturated = getenv(
"MAX_SATURATED");
14470 int max_satur = 10;
14473 if (saturation_level)
14474 saturation = atof(saturation_level);
14477 max_satur = atoi(max_saturated);
14480 for (k = 0; k < size; k++) {
14481 if (data[k] > saturation) {
14483 if (saturated > max_satur) {
14489 if (saturated > max_satur)
14494 data = cpl_image_get_data(extracted);
14495 data[nobjects * nx] = saturated;
14498 cpl_image_delete(sciwin);
14499 cpl_image_delete(skywin);
14533 double dispersion,
int saturation,
14534 double *mfwhm,
double *rmsfwhm,
14535 double *resolution,
double *rmsres,
int *nlines)
14537 cpl_vector *vector;
14540 int position, maxpos;
14545 int threshold = 250;
14550 double min, max, halfmax;
14561 xlen = cpl_image_get_size_x(image);
14562 ylen = cpl_image_get_size_y(image);
14563 data = cpl_image_get_data(image);
14565 buffer = cpl_malloc(ylen *
sizeof(
double));
14571 position = floor((lambda - startwave) / dispersion + 0.5);
14573 sp = position - sradius;
14574 ep = position + sradius;
14576 if (sp < 0 || ep > xlen) {
14581 for (i = 0, n = 0; i < ylen; i++) {
14592 sp = position - radius;
14593 ep = position + radius;
14595 if (sp < 0 || ep > xlen) {
14606 min = max = data[sp + i * xlen];
14607 for (j = sp; j < ep; j++) {
14608 if (data[j + i * xlen] > max) {
14609 max = data[j + i * xlen];
14612 if (data[j + i * xlen] < min) {
14613 min = data[j + i * xlen];
14617 if (fabs(min) < 0.0000001)
14620 if (max - min < threshold)
14623 if (max > saturation)
14633 halfmax = (max + min)/ 2.0;
14637 for (j = maxpos; j < maxpos + radius; j++) {
14639 if (data[j + i * xlen] < halfmax) {
14640 fwhm = ifwhm + (data[j - 1 + i * xlen] - halfmax)
14641 / (data[j - 1 + i * xlen] - data[j + i * xlen]);
14649 for (j = maxpos; j > maxpos - radius; j--) {
14651 if (data[j + i * xlen] < halfmax) {
14652 fwhm += ifwhm + (data[j + 1 + i * xlen] - halfmax)
14653 / (data[j + 1 + i * xlen] - data[j + i * xlen]);
14661 buffer[n] = fwhm - 2.0;
14672 vector = cpl_vector_wrap(n, buffer);
14673 value = cpl_vector_get_median_const(vector);
14674 cpl_vector_unwrap(vector);
14677 for (i = 0, m = 0; i < n; i++) {
14678 if (fabs(buffer[i] - value) < cut) {
14679 rms += fabs(buffer[i] - value);
14692 value *= dispersion;
14698 *resolution = lambda / value;
14699 *rmsres = *resolution * rms / value;
14729 double dispersion,
int saturation,
14744 nref = cpl_vector_get_size(lines);
14745 line = cpl_vector_get_data(lines);
14747 table = cpl_table_new(nref);
14748 cpl_table_new_column(table,
"wavelength", CPL_TYPE_DOUBLE);
14749 cpl_table_set_column_unit(table,
"wavelength",
"Angstrom");
14750 cpl_table_new_column(table,
"fwhm", CPL_TYPE_DOUBLE);
14751 cpl_table_set_column_unit(table,
"fwhm",
"Angstrom");
14752 cpl_table_new_column(table,
"fwhm_rms", CPL_TYPE_DOUBLE);
14753 cpl_table_set_column_unit(table,
"fwhm_rms",
"Angstrom");
14754 cpl_table_new_column(table,
"resolution", CPL_TYPE_DOUBLE);
14755 cpl_table_new_column(table,
"resolution_rms", CPL_TYPE_DOUBLE);
14756 cpl_table_new_column(table,
"nlines", CPL_TYPE_INT);
14758 for (i = 0; i < nref; i++) {
14760 saturation, &fwhm, &rmsfwhm,
14761 &resolution, &rmsres, &nlines)) {
14762 cpl_table_set_double(table,
"wavelength", i, line[i]);
14763 cpl_table_set_double(table,
"fwhm", i, fwhm);
14764 cpl_table_set_double(table,
"fwhm_rms", i, rmsfwhm);
14765 cpl_table_set_double(table,
"resolution", i, resolution);
14766 cpl_table_set_double(table,
"resolution_rms", i, rmsres);
14767 cpl_table_set_int(table,
"nlines", i, nlines);
14770 cpl_table_set_int(table,
"nlines", i, 0);
14773 if (cpl_table_has_valid(table,
"wavelength"))
14776 cpl_table_delete(table);
14801 int ystart,
int yend,
double wstart,
double wend)
14803 const char *func =
"mos_integrate_signal";
14812 if (image == NULL || wavemap == NULL) {
14813 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
14817 if (ystart > yend || wstart >= wend) {
14818 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
14822 nx = cpl_image_get_size_x(image);
14823 ny = cpl_image_get_size_y(image);
14825 if (!(nx == cpl_image_get_size_x(wavemap)
14826 && ny == cpl_image_get_size_y(wavemap))) {
14827 cpl_error_set(func, CPL_ERROR_INCOMPATIBLE_INPUT);
14831 if (ystart < 0 || yend > ny) {
14832 cpl_error_set(func, CPL_ERROR_ACCESS_OUT_OF_RANGE);
14836 sdata = cpl_image_get_data(image);
14837 wdata = cpl_image_get_data(wavemap);
14839 sdata += ystart*nx;
14840 wdata += ystart*nx;
14843 for (y = ystart; y < yend; y++) {
14844 for (x = 0; x < nx; x++) {
14845 if (wdata[x] < wstart || wdata[x] > wend)
14890 const char *func =
"mos_load_slits_fors_mxu";
14893 char keyname[MAX_COLNAME];
14894 const char *instrume;
14895 const char *target_name;
14901 double arc2mm = 0.528;
14914 float low_limit1 = 10.0;
14915 float hig_limit2 = 30.0;
14918 if (cpl_error_get_code() != CPL_ERROR_NONE) {
14922 if (header == NULL) {
14923 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
14932 instrume = cpl_propertylist_get_string(header,
"INSTRUME");
14935 if (instrume[4] ==
'1')
14937 if (instrume[4] ==
'2')
14941 cpl_msg_error(func,
"Wrong instrument: %s\n" 14942 "FORS2 is expected for MXU data", instrume);
14943 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
14954 chip = cpl_propertylist_get_int(header,
"ESO DET CHIP1 Y");
14956 if (cpl_error_get_code() != CPL_ERROR_NONE) {
14957 cpl_msg_error(func,
"Missing keyword ESO DET CHIP1 Y " 14959 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
14963 if (chip != 1 && chip != 2) {
14964 cpl_msg_error(func,
"Unexpected chip position in keyword " 14965 "ESO DET CHIP1 Y: %d", chip);
14966 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
14982 snprintf(keyname, MAX_COLNAME,
"ESO INS MOS%d YPOS", slit_id + 100);
14983 if (cpl_propertylist_has(header, keyname)) {
14984 slit_y = cpl_propertylist_get_double(header, keyname);
14987 if (slit_y < low_limit1)
14990 if (slit_y > hig_limit2)
14993 snprintf(keyname, MAX_COLNAME,
"ESO INS TARG%d NAME",
14995 if (cpl_propertylist_has(header, keyname)) {
14996 target_name = cpl_propertylist_get_string(header, keyname);
14997 if (strncmp(target_name,
"refslit", 7))
15007 if (cpl_error_get_code() != CPL_ERROR_NONE) {
15008 cpl_msg_error(func,
"%s while loading slits coordinates from " 15009 "FITS header", cpl_error_get_message());
15010 cpl_error_set_where(func);
15015 cpl_msg_error(func,
"No slits coordinates found in header");
15016 cpl_error_set(func, CPL_ERROR_DATA_NOT_FOUND);
15020 slits = cpl_table_new(nslits);
15021 cpl_table_new_column(slits,
"slit_id", CPL_TYPE_INT);
15022 cpl_table_new_column(slits,
"xtop", CPL_TYPE_DOUBLE);
15023 cpl_table_new_column(slits,
"ytop", CPL_TYPE_DOUBLE);
15024 cpl_table_new_column(slits,
"xbottom", CPL_TYPE_DOUBLE);
15025 cpl_table_new_column(slits,
"ybottom", CPL_TYPE_DOUBLE);
15026 cpl_table_new_column(slits,
"xwidth", CPL_TYPE_DOUBLE);
15027 cpl_table_set_column_unit(slits,
"xtop",
"pixel");
15028 cpl_table_set_column_unit(slits,
"ytop",
"pixel");
15029 cpl_table_set_column_unit(slits,
"xbottom",
"pixel");
15030 cpl_table_set_column_unit(slits,
"ybottom",
"pixel");
15031 cpl_table_set_column_unit(slits,
"xwidth" ,
"mm");
15038 snprintf(keyname, MAX_COLNAME,
"ESO INS MOS%d YPOS", slit_id + 100);
15039 if (cpl_propertylist_has(header, keyname)) {
15040 slit_y = cpl_propertylist_get_double(header, keyname);
15043 if (slit_y < low_limit1)
15046 if (slit_y > hig_limit2)
15056 snprintf(keyname, MAX_COLNAME,
"ESO INS MOS%d XPOS", slit_id + 100);
15057 slit_x = cpl_propertylist_get_double(header, keyname);
15058 if (cpl_error_get_code() != CPL_ERROR_NONE) {
15059 cpl_table_delete(slits);
15060 cpl_msg_error(func,
"Missing keyword %s in FITS header",
15062 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
15066 snprintf(keyname, MAX_COLNAME,
"ESO INS MOS%d LEN", slit_id + 100);
15067 length = cpl_propertylist_get_double(header, keyname);
15068 if (cpl_error_get_code() != CPL_ERROR_NONE) {
15069 cpl_table_delete(slits);
15070 cpl_msg_error(func,
"Missing keyword %s in FITS header",
15072 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
15078 snprintf(keyname, MAX_COLNAME,
"ESO INS MOS%d WIDTH", slit_id + 100);
15079 slit_width = cpl_propertylist_get_double(header, keyname);
15080 if (cpl_error_get_code() != CPL_ERROR_NONE) {
15081 cpl_table_delete(slits);
15082 cpl_msg_error(func,
"Missing keyword %s in FITS header",
15084 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
15088 snprintf(keyname, MAX_COLNAME,
"ESO INS TARG%d NAME",
15090 if (cpl_propertylist_has(header, keyname)) {
15091 target_name = cpl_propertylist_get_string(header, keyname);
15092 if (strncmp(target_name,
"refslit", 7)) {
15093 cpl_table_set_int(slits,
"slit_id", nslits, slit_id);
15094 cpl_table_set(slits,
"xtop", nslits, slit_x);
15095 cpl_table_set(slits,
"ytop", nslits, slit_y + length/2);
15096 cpl_table_set(slits,
"xbottom", nslits, slit_x);
15097 cpl_table_set(slits,
"ybottom", nslits, slit_y - length/2);
15098 cpl_table_set(slits,
"xwidth", nslits, slit_width);
15103 cpl_table_set_int(slits,
"slit_id", nslits, slit_id);
15104 cpl_table_set(slits,
"xtop", nslits, slit_x);
15105 cpl_table_set(slits,
"ytop", nslits, slit_y + length/2);
15106 cpl_table_set(slits,
"xbottom", nslits, slit_x);
15107 cpl_table_set(slits,
"ybottom", nslits, slit_y - length/2);
15108 cpl_table_set(slits,
"xwidth", nslits, slit_width);
15144 int * nslits_out_det)
15146 const char *func =
"mos_load_slits_fors_mos";
15149 char keyname[MAX_COLNAME];
15150 const char *instrume;
15151 const char *chipname;
15153 int first_slit, last_slit;
15164 float ytop[19] = { 113.9, 101.3, 89.9, 77.3, 65.9, 53.3,
15165 41.9, 29.3, 17.9, 5.3, -6.1, -18.7,
15166 -30.1, -42.7, -54.1, -66.7, -78.1, -90.7,
15168 float ybottom[19] = { 102.1, 90.7, 78.1, 66.7, 54.1, 42.7,
15169 30.1, 18.7, 6.1, -5.3, -17.9, -29.3,
15170 -41.9, -53.3, -65.9, -77.3, -89.9, -101.3,
15174 if (cpl_error_get_code() != CPL_ERROR_NONE) {
15178 if (header == NULL) {
15179 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
15188 instrume = cpl_propertylist_get_string(header,
"INSTRUME");
15191 if (instrume[4] ==
'1')
15193 if (instrume[4] ==
'2')
15197 cpl_msg_error(func,
"Wrong instrument found in FITS header: %s",
15199 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
15209 chipname = cpl_propertylist_get_string(header,
"ESO DET CHIP1 ID");
15211 if (chipname[0] ==
'M' || chipname[0] ==
'N')
15216 if (fors == 1 && fors_is_old) {
15228 chip = cpl_propertylist_get_int(header,
"ESO DET CHIP1 Y");
15230 if (cpl_error_get_code() != CPL_ERROR_NONE) {
15231 cpl_msg_error(func,
"Missing keyword ESO DET CHIP1 Y " 15233 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
15237 if (chip != 1 && chip != 2) {
15238 cpl_msg_error(func,
"Unexpected chip position in keyword " 15239 "ESO DET CHIP1 Y: %d", chip);
15240 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
15263 for (slit_id = first_slit; slit_id <= last_slit; slit_id++) {
15264 snprintf(keyname, MAX_COLNAME,
"ESO INS MOS%d POS", slit_id);
15265 if (cpl_propertylist_has(header, keyname)) {
15266 slit_x = cpl_propertylist_get_double(header, keyname);
15267 if (fabs(slit_x) < 115.0)
15270 (*nslits_out_det)++;
15273 cpl_msg_error(func,
"Missing keyword %s in FITS header", keyname);
15274 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
15279 if (cpl_error_get_code() != CPL_ERROR_NONE) {
15280 cpl_msg_error(func,
"%s while loading slits coordinates from " 15281 "FITS header", cpl_error_get_message());
15282 cpl_error_set_where(func);
15287 cpl_msg_error(func,
"No slits coordinates found in header");
15288 cpl_error_set(func, CPL_ERROR_DATA_NOT_FOUND);
15292 slits = cpl_table_new(nslits);
15293 cpl_table_new_column(slits,
"slit_id", CPL_TYPE_INT);
15294 cpl_table_new_column(slits,
"xtop", CPL_TYPE_DOUBLE);
15295 cpl_table_new_column(slits,
"ytop", CPL_TYPE_DOUBLE);
15296 cpl_table_new_column(slits,
"xbottom", CPL_TYPE_DOUBLE);
15297 cpl_table_new_column(slits,
"ybottom", CPL_TYPE_DOUBLE);
15298 cpl_table_new_column(slits,
"xwidth", CPL_TYPE_DOUBLE);
15299 cpl_table_set_column_unit(slits,
"xtop",
"pixel");
15300 cpl_table_set_column_unit(slits,
"ytop",
"pixel");
15301 cpl_table_set_column_unit(slits,
"xbottom",
"pixel");
15302 cpl_table_set_column_unit(slits,
"ybottom",
"pixel");
15303 cpl_table_set_column_unit(slits,
"xwidth" ,
"mm");
15307 for (slit_id = first_slit; slit_id <= last_slit; slit_id++) {
15308 snprintf(keyname, MAX_COLNAME,
"ESO INS MOS%d POS", slit_id);
15309 slit_x = cpl_propertylist_get_double(header, keyname);
15310 if (fabs(slit_x) < 115.0) {
15311 cpl_table_set_int(slits,
"slit_id", nslits, slit_id);
15312 cpl_table_set(slits,
"xtop", nslits, slit_x);
15313 cpl_table_set(slits,
"ytop", nslits, ytop[slit_id-1]);
15314 cpl_table_set(slits,
"xbottom", nslits, slit_x);
15315 cpl_table_set(slits,
"ybottom", nslits, ybottom[slit_id-1]);
15316 snprintf(keyname, MAX_COLNAME,
"ESO INS MOS%d WIDTH", slit_id);
15317 double slit_width = cpl_propertylist_get_double(header, keyname);
15318 cpl_table_set(slits,
"xwidth", nslits, slit_width);
15352 const char *func =
"mos_load_slits_fors_lss";
15356 const char *instrume;
15362 if (cpl_error_get_code() != CPL_ERROR_NONE) {
15366 if (header == NULL) {
15367 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
15376 instrume = cpl_propertylist_get_string(header,
"INSTRUME");
15379 if (instrume[4] ==
'1')
15381 if (instrume[4] ==
'2')
15385 cpl_msg_error(func,
"Wrong instrument found in FITS header: %s",
15387 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
15403 chip = cpl_propertylist_get_int(header,
"ESO DET CHIP1 Y");
15405 if (cpl_error_get_code() != CPL_ERROR_NONE) {
15406 cpl_msg_error(func,
"Missing keyword ESO DET CHIP1 Y " 15408 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
15412 if (chip != 1 && chip != 2) {
15413 cpl_msg_error(func,
"Unexpected chip position in keyword " 15414 "ESO DET CHIP1 Y: %d", chip);
15415 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
15430 slits = cpl_table_new(1);
15431 cpl_table_new_column(slits,
"slit_id", CPL_TYPE_INT);
15432 cpl_table_new_column(slits,
"xtop", CPL_TYPE_DOUBLE);
15433 cpl_table_new_column(slits,
"ytop", CPL_TYPE_DOUBLE);
15434 cpl_table_new_column(slits,
"xbottom", CPL_TYPE_DOUBLE);
15435 cpl_table_new_column(slits,
"ybottom", CPL_TYPE_DOUBLE);
15436 cpl_table_set_column_unit(slits,
"xtop",
"pixel");
15437 cpl_table_set_column_unit(slits,
"ytop",
"pixel");
15438 cpl_table_set_column_unit(slits,
"xbottom",
"pixel");
15439 cpl_table_set_column_unit(slits,
"ybottom",
"pixel");
15441 slit_name = (
char *)cpl_propertylist_get_string(header,
15442 "ESO INS SLIT NAME");
15444 cpl_table_set(slits,
"ytop", 0, ytop);
15445 cpl_table_set(slits,
"ybottom", 0, ybottom);
15447 if (!strncmp(slit_name,
"lSlit0_3arcsec", 14)) {
15448 cpl_table_set_int(slits,
"slit_id", 0, 1);
15449 cpl_table_set(slits,
"xbottom", 0, -0.075);
15450 cpl_table_set(slits,
"xtop", 0, 0.075);
15452 else if (!strncmp(slit_name,
"lSlit0_4arcsec", 14)) {
15453 cpl_table_set_int(slits,
"slit_id", 0, 2);
15454 cpl_table_set(slits,
"xbottom", 0, 5.895);
15455 cpl_table_set(slits,
"xtop", 0, 6.105);
15457 else if (!strncmp(slit_name,
"lSlit0_5arcsec", 14)) {
15458 cpl_table_set_int(slits,
"slit_id", 0, 3);
15459 cpl_table_set(slits,
"xbottom", 0, -6.135);
15460 cpl_table_set(slits,
"xtop", 0, -5.865);
15462 else if (!strncmp(slit_name,
"lSlit0_7arcsec", 14)) {
15463 cpl_table_set_int(slits,
"slit_id", 0, 4);
15464 cpl_table_set(slits,
"xbottom", 0, 11.815);
15465 cpl_table_set(slits,
"xtop", 0, 12.185);
15467 else if (!strncmp(slit_name,
"lSlit1_0arcsec", 14)) {
15468 cpl_table_set_int(slits,
"slit_id", 0, 5);
15469 cpl_table_set(slits,
"xbottom", 0, -12.265);
15470 cpl_table_set(slits,
"xtop", 0, -11.735);
15472 else if (!strncmp(slit_name,
"lSlit1_3arcsec", 14)) {
15473 cpl_table_set_int(slits,
"slit_id", 0, 6);
15474 cpl_table_set(slits,
"xbottom", 0, 17.655);
15475 cpl_table_set(slits,
"xtop", 0, 18.345);
15477 else if (!strncmp(slit_name,
"lSlit1_6arcsec", 14)) {
15478 cpl_table_set_int(slits,
"slit_id", 0, 7);
15479 cpl_table_set(slits,
"xbottom", 0, -18.425);
15480 cpl_table_set(slits,
"xtop", 0, -17.575);
15482 else if (!strncmp(slit_name,
"lSlit2_0arcsec", 14)) {
15483 cpl_table_set_int(slits,
"slit_id", 0, 8);
15484 cpl_table_set(slits,
"xbottom", 0, 23.475);
15485 cpl_table_set(slits,
"xtop", 0, 24.525);
15487 else if (!strncmp(slit_name,
"lSlit2_5arcsec", 14)) {
15488 cpl_table_set_int(slits,
"slit_id", 0, 9);
15489 cpl_table_set(slits,
"xbottom", 0, -24.66);
15490 cpl_table_set(slits,
"xtop", 0, -23.34);
15493 cpl_msg_error(func,
"Invalid slit %s in keyword ESO INS SLIT NAME",
15495 cpl_error_set(func, CPL_ERROR_DATA_NOT_FOUND);
15496 cpl_table_delete(slits);
15520 const char *func =
"mos_get_gain_vimos";
15522 double gain = -1.0;
15525 if (cpl_error_get_code() != CPL_ERROR_NONE)
15528 if (header == NULL) {
15529 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
15533 gain = cpl_propertylist_get_double(header,
"ESO DET OUT1 CONAD");
15534 if (cpl_error_get_code()) {
15535 cpl_error_set_where(func);
15565 const char *func =
"mos_load_slits_vimos";
15568 char keyname[MAX_COLNAME];
15579 if (cpl_error_get_code() != CPL_ERROR_NONE) {
15583 if (header == NULL) {
15584 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
15588 nslits = cpl_propertylist_get_int(header,
"ESO INS SLIT NO");
15590 if (cpl_error_get_code() != CPL_ERROR_NONE) {
15591 cpl_error_set_where(func);
15595 slits = cpl_table_new(nslits);
15596 cpl_table_new_column(slits,
"slit_id", CPL_TYPE_INT);
15597 cpl_table_new_column(slits,
"xtop", CPL_TYPE_DOUBLE);
15598 cpl_table_new_column(slits,
"ytop", CPL_TYPE_DOUBLE);
15599 cpl_table_new_column(slits,
"xbottom", CPL_TYPE_DOUBLE);
15600 cpl_table_new_column(slits,
"ybottom", CPL_TYPE_DOUBLE);
15601 cpl_table_new_column(slits,
"xwidth", CPL_TYPE_DOUBLE);
15602 cpl_table_new_column(slits,
"ywidth", CPL_TYPE_DOUBLE);
15603 cpl_table_new_column(slits,
"curved", CPL_TYPE_INT);
15604 cpl_table_set_column_unit(slits,
"xtop",
"pixel");
15605 cpl_table_set_column_unit(slits,
"ytop",
"pixel");
15606 cpl_table_set_column_unit(slits,
"xbottom",
"pixel");
15607 cpl_table_set_column_unit(slits,
"ybottom",
"pixel");
15608 cpl_table_set_column_unit(slits,
"xwidth",
"mm");
15609 cpl_table_set_column_unit(slits,
"ywidth",
"mm");
15611 for (i = 0; i < nslits; i++) {
15612 sprintf(keyname,
"ESO INS SLIT%d ID", i+1);
15613 slit_id = cpl_propertylist_get_int(header, keyname);
15614 if (cpl_error_get_code() != CPL_ERROR_NONE) {
15615 cpl_error_set_where(func);
15618 sprintf(keyname,
"ESO INS SLIT%d X", i+1);
15619 slit_x = cpl_propertylist_get_double(header, keyname);
15620 if (cpl_error_get_code() != CPL_ERROR_NONE) {
15621 cpl_error_set_where(func);
15624 sprintf(keyname,
"ESO INS SLIT%d Y", i+1);
15625 slit_y = cpl_propertylist_get_double(header, keyname);
15626 if (cpl_error_get_code() != CPL_ERROR_NONE) {
15627 cpl_error_set_where(func);
15630 sprintf(keyname,
"ESO INS SLIT%d DIMX", i+1);
15631 dim_x = cpl_propertylist_get_double(header, keyname);
15632 if (cpl_error_get_code() != CPL_ERROR_NONE) {
15633 cpl_error_set_where(func);
15637 sprintf(keyname,
"ESO INS SLIT%d BEZIER DY", i+1);
15638 if (cpl_propertylist_has(header, keyname)) {
15642 sprintf(keyname,
"ESO INS SLIT%d DIMY", i+1);
15645 dim_y = cpl_propertylist_get_double(header, keyname);
15646 if (cpl_error_get_code() != CPL_ERROR_NONE) {
15647 cpl_error_set_where(func);
15651 cpl_table_set_int(slits,
"slit_id", i, slit_id);
15652 cpl_table_set(slits,
"xtop", i, slit_x - dim_x/2);
15653 cpl_table_set(slits,
"ytop", i, slit_y);
15654 cpl_table_set(slits,
"xbottom", i, slit_x + dim_x/2);
15655 cpl_table_set(slits,
"ybottom", i, slit_y);
15656 cpl_table_set(slits,
"xwidth", i, dim_x);
15657 cpl_table_set(slits,
"ywidth", i, dim_y);
15658 cpl_table_set_int(slits,
"curved", i, curved);
15676 cpl_propertylist *sort;
15678 int i, multiplex, xprev, xcur;
15680 double tolerance = 1.0;
15690 sort = cpl_propertylist_new();
15691 cpl_propertylist_append_bool(sort,
"xtop", 0);
15692 cpl_table_sort(slits, sort);
15693 cpl_propertylist_delete(sort);
15695 prev = cpl_table_get_double(slits,
"xtop", 0, NULL);
15696 cpl_table_new_column(slits,
"xind", CPL_TYPE_INT);
15697 cpl_table_set_int(slits,
"xind", 0, prev);
15698 nrow = cpl_table_get_nrow(slits);
15699 for (i = 1; i < nrow; i++) {
15700 cur = cpl_table_get_double(slits,
"xtop", i, NULL);
15701 if (fabs(prev - cur) > tolerance)
15703 cpl_table_set_int(slits,
"xind", i, prev);
15711 sort = cpl_propertylist_new();
15712 cpl_propertylist_append_bool(sort,
"xind", 0);
15713 cpl_propertylist_append_bool(sort,
"ytop", 0);
15714 cpl_table_sort(slits, sort);
15715 cpl_propertylist_delete(sort);
15722 cpl_table_new_column(slits,
"multiplex", CPL_TYPE_INT);
15723 xprev = cpl_table_get_int(slits,
"xind", 0, NULL);
15724 cpl_table_set_int(slits,
"multiplex", 0, multiplex);
15725 nrow = cpl_table_get_nrow(slits);
15726 for (i = 1; i < nrow; i++) {
15727 xcur = cpl_table_get_int(slits,
"xind", i, NULL);
15728 if (xcur == xprev) {
15735 cpl_table_set_int(slits,
"multiplex", i, multiplex);
15738 cpl_table_save(slits, NULL, NULL,
"multiplex.fits", CPL_IO_DEFAULT);
15740 cpl_table_erase_column(slits,
"xind");
15742 return 1 + cpl_table_get_column_max(slits,
"multiplex");
15774 int check_consistency)
15776 const char *func =
"mos_load_overscans_vimos";
15787 cpl_table *overscans;
15790 if (cpl_error_get_code() != CPL_ERROR_NONE) {
15791 cpl_msg_error(func,
"Reset your error: %s", cpl_error_get_message());
15795 if (header == NULL) {
15796 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
15800 if (cpl_propertylist_has(header,
"NAXIS1"))
15801 nx = cpl_propertylist_get_int(header,
"NAXIS1");
15802 if (cpl_propertylist_has(header,
"NAXIS2"))
15803 ny = cpl_propertylist_get_int(header,
"NAXIS2");
15804 if (cpl_propertylist_has(header,
"ESO DET OUT1 PRSCX"))
15805 px = cpl_propertylist_get_int(header,
"ESO DET OUT1 PRSCX");
15806 if (cpl_propertylist_has(header,
"ESO DET OUT1 PRSCY"))
15807 py = cpl_propertylist_get_int(header,
"ESO DET OUT1 PRSCY");
15808 if (cpl_propertylist_has(header,
"ESO DET OUT1 OVSCX"))
15809 ox = cpl_propertylist_get_int(header,
"ESO DET OUT1 OVSCX");
15810 if (cpl_propertylist_has(header,
"ESO DET OUT1 OVSCY"))
15811 oy = cpl_propertylist_get_int(header,
"ESO DET OUT1 OVSCY");
15812 if (cpl_propertylist_has(header,
"ESO DET OUT1 NX"))
15813 vx = cpl_propertylist_get_int(header,
"ESO DET OUT1 NX");
15814 if (cpl_propertylist_has(header,
"ESO DET OUT1 NY"))
15815 vy = cpl_propertylist_get_int(header,
"ESO DET OUT1 NY");
15817 if (cpl_error_get_code() != CPL_ERROR_NONE) {
15818 cpl_msg_error(func,
"Missing overscan keywords in header");
15819 cpl_error_set_where(func);
15823 if (px < 0 || py < 0 || ox < 0 || oy < 0) {
15824 cpl_msg_error(func,
"Missing overscan keywords in header");
15825 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
15829 if ((px + vx + ox != nx) || (py + vy + oy != ny)) {
15830 if (check_consistency) {
15831 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
15835 cpl_msg_debug(func,
"Overscans description conflicts with " 15836 "reported image sizes, " 15837 "%d + %d + %d != %d or " 15838 "%d + %d + %d != %d",
15855 cpl_msg_error(func,
"Unexpected overscan regions " 15856 "(both in X and Y direction)");
15857 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
15869 overscans = cpl_table_new(nrows);
15870 cpl_table_new_column(overscans,
"xlow", CPL_TYPE_INT);
15871 cpl_table_new_column(overscans,
"ylow", CPL_TYPE_INT);
15872 cpl_table_new_column(overscans,
"xhig", CPL_TYPE_INT);
15873 cpl_table_new_column(overscans,
"yhig", CPL_TYPE_INT);
15877 cpl_table_set_int(overscans,
"xlow", nrows, px);
15878 cpl_table_set_int(overscans,
"ylow", nrows, py);
15879 cpl_table_set_int(overscans,
"xhig", nrows, nx - ox);
15880 cpl_table_set_int(overscans,
"yhig", nrows, ny - oy);
15884 cpl_table_set_int(overscans,
"xlow", nrows, 0);
15885 cpl_table_set_int(overscans,
"ylow", nrows, 0);
15886 cpl_table_set_int(overscans,
"xhig", nrows, px);
15887 cpl_table_set_int(overscans,
"yhig", nrows, ny);
15892 cpl_table_set_int(overscans,
"xlow", nrows, nx - ox);
15893 cpl_table_set_int(overscans,
"ylow", nrows, 0);
15894 cpl_table_set_int(overscans,
"xhig", nrows, nx);
15895 cpl_table_set_int(overscans,
"yhig", nrows, ny);
15900 cpl_table_set_int(overscans,
"xlow", nrows, 0);
15901 cpl_table_set_int(overscans,
"ylow", nrows, 0);
15902 cpl_table_set_int(overscans,
"xhig", nrows, nx);
15903 cpl_table_set_int(overscans,
"yhig", nrows, py);
15908 cpl_table_set_int(overscans,
"xlow", nrows, 0);
15909 cpl_table_set_int(overscans,
"ylow", nrows, ny - oy);
15910 cpl_table_set_int(overscans,
"xhig", nrows, nx);
15911 cpl_table_set_int(overscans,
"yhig", nrows, ny);
15920 cpl_table *mos_load_overscans_fors(
const cpl_propertylist *header)
15922 const char *func =
"mos_load_overscans_fors";
15933 cpl_table *overscans;
15936 if (cpl_error_get_code() != CPL_ERROR_NONE) {
15937 cpl_msg_error(func,
"Reset your error: %s", cpl_error_get_message());
15941 if (header == NULL) {
15942 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
15946 if (cpl_propertylist_has(header,
"ESO DET OUTPUTS"))
15947 nports = cpl_propertylist_get_int(header,
"ESO DET OUTPUTS");
15950 cpl_propertylist_has(header,
"ESO DET OUT1 PRSCX") &&
15951 cpl_propertylist_has(header,
"ESO DET WIN1 BINX")) {
15953 rebin = cpl_propertylist_get_int(header,
"ESO DET WIN1 BINX");
15955 overscans = cpl_table_new(3);
15956 cpl_table_new_column(overscans,
"xlow", CPL_TYPE_INT);
15957 cpl_table_new_column(overscans,
"ylow", CPL_TYPE_INT);
15958 cpl_table_new_column(overscans,
"xhig", CPL_TYPE_INT);
15959 cpl_table_new_column(overscans,
"yhig", CPL_TYPE_INT);
15967 cpl_table_set_int(overscans,
"xlow", nrows, px);
15968 cpl_table_set_int(overscans,
"ylow", nrows, py);
15969 cpl_table_set_int(overscans,
"xhig", nrows, nx - ox);
15970 cpl_table_set_int(overscans,
"yhig", nrows, ny - oy);
15973 cpl_table_set_int(overscans,
"xlow", nrows, 0);
15974 cpl_table_set_int(overscans,
"ylow", nrows, 0);
15975 cpl_table_set_int(overscans,
"xhig", nrows, px);
15976 cpl_table_set_int(overscans,
"yhig", nrows, ny);
15979 cpl_table_set_int(overscans,
"xlow", nrows, nx - ox);
15980 cpl_table_set_int(overscans,
"ylow", nrows, 0);
15981 cpl_table_set_int(overscans,
"xhig", nrows, nx);
15982 cpl_table_set_int(overscans,
"yhig", nrows, ny);
16027 cpl_polynomial *mos_montecarlo_polyfit(cpl_table *points, cpl_table *evaluate,
16028 int samples,
int order)
16031 const char *func =
"mos_montecarlo_polyfit";
16045 int npoints, nevaluate;
16049 if (points == NULL || evaluate == NULL) {
16050 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
16054 if (!cpl_table_has_column(points,
"x")) {
16055 cpl_error_set(func, CPL_ERROR_DATA_NOT_FOUND);
16059 if (cpl_table_get_column_type(points,
"x") != CPL_TYPE_DOUBLE) {
16060 cpl_error_set(func, CPL_ERROR_INVALID_TYPE);
16064 if (cpl_table_has_invalid(points,
"x")) {
16065 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
16069 if (!cpl_table_has_column(points,
"y")) {
16070 cpl_error_set(func, CPL_ERROR_DATA_NOT_FOUND);
16074 if (cpl_table_get_column_type(points,
"y") != CPL_TYPE_DOUBLE) {
16075 cpl_error_set(func, CPL_ERROR_INVALID_TYPE);
16079 if (cpl_table_has_invalid(points,
"y")) {
16080 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
16084 if (cpl_table_has_column(points,
"y_err")) {
16086 if (cpl_table_get_column_type(points,
"y_err") != CPL_TYPE_DOUBLE) {
16087 cpl_error_set(func, CPL_ERROR_INVALID_TYPE);
16091 if (cpl_table_has_invalid(points,
"y_err")) {
16092 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
16097 if (!cpl_table_has_column(evaluate,
"x")) {
16098 cpl_error_set(func, CPL_ERROR_DATA_NOT_FOUND);
16102 if (cpl_table_get_column_type(evaluate,
"x") != CPL_TYPE_DOUBLE) {
16103 cpl_error_set(func, CPL_ERROR_INVALID_TYPE);
16107 if (cpl_table_has_invalid(evaluate,
"x")) {
16108 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
16112 if (samples < 2 || order < 0) {
16113 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
16117 npoints = cpl_table_get_nrow(points);
16118 listx = cpl_vector_wrap(npoints, cpl_table_get_data_double(points,
"x"));
16119 listy = cpl_vector_wrap(npoints, cpl_table_get_data_double(points,
"y"));
16121 p = cpl_polynomial_fit_1d_create(listx, listy, order, &err);
16123 if (!cpl_table_has_column(points,
"y_err")) {
16125 cpl_table_new_column(points,
"y_err", CPL_TYPE_DOUBLE);
16126 cpl_table_fill_column_window_double(points,
"y_err", 0, npoints, err);
16127 cpl_msg_info(func,
"Error column not found - set to %f\n", err);
16134 if (cpl_table_has_column(points,
"px"))
16135 cpl_table_erase_column(points,
"px");
16136 cpl_table_new_column(points,
"px", CPL_TYPE_DOUBLE);
16137 cpl_table_fill_column_window_double(points,
"px", 0, npoints, 0);
16138 x = cpl_table_get_data_double(points,
"x");
16139 px = cpl_table_get_data_double(points,
"px");
16140 for (i = 0; i < npoints; i++)
16141 px[i] = cpl_polynomial_eval_1d(p, x[i], NULL);
16143 nevaluate = cpl_table_get_nrow(evaluate);
16145 if (cpl_table_has_column(evaluate,
"px"))
16146 cpl_table_erase_column(evaluate,
"px");
16147 cpl_table_new_column(evaluate,
"px", CPL_TYPE_DOUBLE);
16148 cpl_table_fill_column_window_double(evaluate,
"px", 0, nevaluate, 0);
16149 x_eval = cpl_table_get_data_double(evaluate,
"x");
16150 px_eval = cpl_table_get_data_double(evaluate,
"px");
16151 for (i = 0; i < nevaluate; i++)
16152 px_eval[i] = cpl_polynomial_eval_1d(p, x_eval[i], NULL);
16158 if (cpl_table_has_column(evaluate,
"sigma"))
16159 cpl_table_erase_column(evaluate,
"sigma");
16160 cpl_table_new_column(evaluate,
"sigma", CPL_TYPE_DOUBLE);
16161 cpl_table_fill_column_window_double(evaluate,
"sigma", 0, nevaluate, 0);
16162 sigma = cpl_table_get_data_double(evaluate,
"sigma");
16168 if (cpl_table_has_column(points,
"vy"))
16169 cpl_table_erase_column(points,
"vy");
16170 cpl_table_new_column(points,
"vy", CPL_TYPE_DOUBLE);
16171 cpl_table_fill_column_window_double(points,
"vy", 0, npoints, 0);
16172 vy = cpl_table_get_data_double(points,
"vy");
16173 dy = cpl_table_get_data_double(points,
"y_err");
16174 cpl_vector_unwrap(listy);
16175 listy = cpl_vector_wrap(npoints, vy);
16177 for (i = 0; i < samples; i++) {
16178 for (j = 0; j < npoints; j++)
16179 vy[j] = px[j] + dy[j] * mos_randg(1);
16180 q = cpl_polynomial_fit_1d_create(listx, listy, order, NULL);
16181 for (j = 0; j < nevaluate; j++)
16182 sigma[j] += fabs(px_eval[j]
16183 - cpl_polynomial_eval_1d(q, x_eval[j], NULL));
16184 cpl_polynomial_delete(q);
16191 cpl_table_multiply_scalar(evaluate,
"sigma", 1.25);
16192 cpl_table_divide_scalar(evaluate,
"sigma", samples);
16194 cpl_vector_unwrap(listx);
16195 cpl_vector_unwrap(listy);
16225 double gain,
double bias)
16232 return cpl_error_set(cpl_func, CPL_ERROR_NULL_INPUT);
16234 if (ron < 0.0 || gain <= FLT_EPSILON)
16235 return cpl_error_set(cpl_func, CPL_ERROR_ILLEGAL_INPUT);
16237 data = cpl_image_get_data_float(image);
16238 npix = cpl_image_get_size_x(image) * cpl_image_get_size_y(image);
16241 for (i = 0; i < npix; i++) {
16242 if (data[i] < bias) {
16243 data[i] += sqrt(ron) * mos_randg(1);
16246 data[i] += sqrt(ron + (data[i] - bias) / gain) * mos_randg(1);
16250 return CPL_ERROR_NONE;
16269 cpl_image *master_flat,
16272 int nx = cpl_mask_get_size_x(refmask);
16273 int ny = cpl_mask_get_size_y(refmask);
16275 int * xpos = cpl_calloc(
sizeof(
int), ny);
16277 cpl_image * filtered = cpl_image_duplicate(master_flat);
16278 cpl_mask * kernel = cpl_mask_new(9, 3);
16279 cpl_vector * v = cpl_vector_new(ny);
16280 cpl_vector * truev;
16282 double * flats = cpl_vector_get_data(v);
16284 double median, stdev, delta;
16288 cpl_mask_not(kernel);
16289 cpl_image_filter_mask(filtered, master_flat, kernel,
16290 CPL_FILTER_MEDIAN, CPL_BORDER_COPY);
16291 cpl_mask_delete(kernel);
16293 for (i = 1; i <= ny; i++) {
16297 while (!cpl_mask_get(refmask, j, i) && j < nx);
16303 flats[nvalid] = cpl_image_get(filtered, j, i, &rejected);
16312 return cpl_error_set(cpl_func, CPL_ERROR_DATA_NOT_FOUND);
16314 truev = cpl_vector_wrap(nvalid, flats);
16316 median = cpl_vector_get_median(truev);
16319 stdev = cpl_vector_get_stdev(truev);
16321 cpl_vector_unwrap(truev);
16322 cpl_vector_delete(v);
16324 for (i = 1; i <= ny; i++) {
16325 if (xpos[i - 1] > 0) {
16327 double kappa = 1.5;
16329 delta = cpl_image_get(filtered, xpos[i - 1], i, &rejected) - median;
16332 kill = fabs(delta) > stdev * kappa;
16334 kill = delta < level;
16339 while (cpl_mask_get(refmask, xpos[i - 1] + j, i)) {
16340 cpl_mask_set(refmask, xpos[i - 1] + j, i, CPL_BINARY_0);
16347 cpl_image_delete(filtered);
16350 return cpl_error_get_code();
16362 int nx = cpl_image_get_size_x(image);
16363 int ny = cpl_image_get_size_y(image);
16364 int npix = nx * ny;
16365 float * sdata = cpl_image_get_data_float(image);
16367 int count, i, j, k;
16391 for (i = 0; i < npix; i++) {
16392 if (sdata[i] >= 65535.0) {
16394 for (j = i; j < npix; j++) {
16395 if (sdata[j] < 65535.0) {
16402 if (count < 30 && count > 2) {
16403 for (j = i; j < i + count/2; j++)
16404 sdata[j] = sdata[i] + 1000.0 * (j - i);
16405 if (count % 2 != 0) {
16406 sdata[j] = sdata[j-1] + 1000.0;
16409 for (k = j; k <= i + count; k++)
16410 sdata[k] = sdata[i] - 1000.0 * (k - i - count);
16416 return cpl_error_get_code();
16435 cpl_image_subtract(image, bimage);
16436 cpl_image_delete(bimage);
16438 return cpl_error_get_code();
16459 int nscience,
float tolerance)
16463 cpl_table *summary;
16464 int summary_nobjs = 0;
16469 int nslits = cpl_table_get_nrow(slitss[0]);
16473 int nstokes, sstokes;
16477 work = (cpl_table **)cpl_malloc(
sizeof(cpl_table *) * nscience);
16488 for (j = 0; j < nscience; j++) {
16491 return cpl_error_set(cpl_func, CPL_ERROR_DATA_NOT_FOUND);
16492 summary_nobjs += c_nobjs;
16495 summary = cpl_table_new(summary_nobjs);
16497 cpl_table_new_column(summary,
"offset", CPL_TYPE_DOUBLE);
16498 cpl_table_new_column(summary,
"pair", CPL_TYPE_INT);
16499 cpl_table_new_column(summary,
"absolute", CPL_TYPE_DOUBLE);
16500 cpl_table_new_column(summary,
"pos", CPL_TYPE_DOUBLE);
16509 for (j = 0; j < nscience; j++) {
16513 for (k = 0; k < nslits; k++) {
16516 for (m = 0; m < c_maxobjs; m++) {
16518 char *name = cpl_sprintf(
"object_%d", m + 1);
16519 double obj = cpl_table_get_double(slitss[j], name, k, &null);
16535 pos = cpl_table_get_int(slitss[j],
"position", k, &null);
16536 pair = cpl_table_get_int(slitss[j],
"pair_id", k, &null);
16537 cpl_table_set(summary,
"absolute", nobjs, obj);
16538 cpl_table_set(summary,
"pos", nobjs, pos);
16539 cpl_table_set(summary,
"offset", nobjs, obj - pos);
16540 cpl_table_set(summary,
"pair", nobjs, pair);
16570 for (k = 0; k < nslits; k+=2) {
16571 int slitmatches = 0;
16573 if (k + 1 < nslits ) {
16574 if (cpl_table_get_int(slitss[0],
"pair_id", k, NULL) !=
16575 cpl_table_get_int(slitss[0],
"pair_id", k + 1, NULL)) {
16588 for (m = 0; m < maxobjs; m++) {
16590 char *name = cpl_sprintf(
"object_%d", m + 1);
16591 double obj = cpl_table_get_double(slitss[0], name, k, &null);
16595 char *name_obj = NULL;
16596 char *name_start = NULL;
16597 char *name_end = NULL;
16598 char *name_row = NULL;
16599 char *name_row_s = NULL;
16601 char *name_start_o = NULL;
16602 char *name_end_o = NULL;
16603 char *name_row_o = NULL;
16604 char *name_start_v = NULL;
16605 char *name_end_v = NULL;
16606 char *name_obj_v = NULL;
16612 int v, start_v, end_v;
16613 double min_v, obj_v;
16628 pos = cpl_table_get_int(slitss[0],
"position", k, &null);
16629 pair = cpl_table_get_int(slitss[0],
"pair_id", k, &null);
16638 cpl_table_select_all(summary);
16640 cpl_table_and_selected_int(summary,
"pair", CPL_EQUAL_TO, pair);
16641 cpl_table_and_selected_double(summary,
"offset", CPL_LESS_THAN,
16642 obj - pos + tolerance);
16644 cpl_table_and_selected_double(summary,
"offset", CPL_GREATER_THAN,
16645 obj - pos - tolerance);
16655 if (selected != nscience * 2)
16676 name_obj = cpl_sprintf(
"object_%d", slitmatches);
16677 name_start = cpl_sprintf(
"start_%d", slitmatches);
16678 name_end = cpl_sprintf(
"end_%d", slitmatches);
16679 name_row = cpl_sprintf(
"row_%d", slitmatches);
16680 name_row_s = cpl_sprintf(
"row_stokes_%d", slitmatches);
16687 name_start_o = cpl_sprintf(
"start_%d", m + 1);
16688 name_end_o = cpl_sprintf(
"end_%d", m + 1);
16689 name_row_o = cpl_sprintf(
"row_%d", m + 1);
16695 if (!cpl_table_has_column(origslits, name_obj)) {
16696 cpl_table_new_column(origslits, name_obj, CPL_TYPE_DOUBLE);
16697 cpl_table_new_column(origslits, name_start, CPL_TYPE_INT);
16698 cpl_table_new_column(origslits, name_end, CPL_TYPE_INT);
16699 cpl_table_new_column(origslits, name_row, CPL_TYPE_INT);
16700 cpl_table_new_column(origslits, name_row_s, CPL_TYPE_INT);
16710 length = cpl_table_get_int(origslits,
"length", k + 1, &null);
16718 for (v = 0; v < maxobjs; v++) {
16719 char *name_v = cpl_sprintf(
"object_%d", v + 1);
16720 double obj_v = cpl_table_get_double(slitss[0], name_v,
16729 if (fabs(obj - length - obj_v) < min_v) {
16730 min_v = fabs(obj - length - obj_v);
16731 cpl_free(name_start_v);
16732 cpl_free(name_end_v);
16733 cpl_free(name_obj_v);
16734 name_start_v = cpl_sprintf(
"start_%d", v + 1);
16735 name_end_v = cpl_sprintf(
"end_%d", v + 1);
16736 name_obj_v = cpl_sprintf(
"object_%d", v + 1);
16740 min_v = fabs(obj - length - obj_v);
16741 name_start_v = cpl_sprintf(
"start_%d", v + 1);
16742 name_end_v = cpl_sprintf(
"end_%d", v + 1);
16743 name_obj_v = cpl_sprintf(
"object_%d", v + 1);
16752 start = cpl_table_get_int(slitss[0], name_start_o, k, &null);
16753 end = cpl_table_get_int(slitss[0], name_end_o, k, &null);
16759 start_v = cpl_table_get_int(slitss[0], name_start_v, k + 1, &null);
16760 end_v = cpl_table_get_int(slitss[0], name_end_v, k + 1, &null);
16761 obj_v = cpl_table_get_double(slitss[0], name_obj_v, k + 1, &null);
16772 cpl_table_set_double(origslits, name_obj, k, obj);
16773 cpl_table_set_double(origslits, name_obj, k + 1, obj_v);
16776 cpl_table_set_int(origslits, name_start, k, start);
16777 cpl_table_set_int(origslits, name_start, k + 1, start_v);
16780 cpl_table_set_int(origslits, name_end, k, end);
16781 cpl_table_set_int(origslits, name_end, k + 1, end_v);
16796 cpl_table_set_int(origslits, name_row, k, nmatches);
16798 cpl_table_set_int(origslits, name_row, k + 1, nmatches);
16801 cpl_free(name_obj);
16802 cpl_free(name_start);
16803 cpl_free(name_end);
16804 cpl_free(name_row);
16805 cpl_free(name_row_s);
16807 cpl_free(name_start_o);
16808 cpl_free(name_end_o);
16809 cpl_free(name_row_o);
16811 cpl_free(name_start_v); name_start_v = NULL;
16812 cpl_free(name_end_v); name_end_v = NULL;
16813 cpl_free(name_obj_v); name_obj_v = NULL;
16822 cpl_table_delete(summary);
16825 return cpl_error_set(cpl_func, CPL_ERROR_DATA_NOT_FOUND);
16838 nstokes = nmatches / 2;
16840 for (k = 0; k < nslits; k++) {
16848 for (m = 0; m < maxobjs; m++) {
16849 char *name = cpl_sprintf(
"row_%d", m + 1);
16850 char *namestokes = cpl_sprintf(
"row_stokes_%d", m + 1);
16852 if (!cpl_table_is_valid(origslits, name, k)) {
16854 cpl_free(namestokes);
16860 cpl_table_set_int(origslits, name, k, nmatches);
16861 cpl_table_set_int(origslits, namestokes, k, nstokes);
16865 cpl_free(namestokes);
16877 for (j = 0; j < maxobjs; j++) {
16878 char *name = cpl_sprintf(
"object_%d", j + 1);
16879 cpl_table_fill_invalid_double(origslits, name, -1);
16882 name = cpl_sprintf(
"start_%d", j + 1);
16883 cpl_table_fill_invalid_int(origslits, name, -1);
16886 name = cpl_sprintf(
"end_%d", j + 1);
16887 cpl_table_fill_invalid_int(origslits, name, -1);
16890 name = cpl_sprintf(
"row_%d", j + 1);
16891 cpl_table_fill_invalid_int(origslits, name, -1);
16894 name = cpl_sprintf(
"row_stokes_%d", j + 1);
16895 cpl_table_fill_invalid_int(origslits, name, -1);
16910 for (i = 0; i < nscience; i++) {
16913 work[i] = cpl_table_duplicate(slitss[i]);
16915 for (m = 0; m < c_maxobjs; m++) {
16916 char *object_o = cpl_sprintf(
"object_%d", m + 1);
16917 char *start_o = cpl_sprintf(
"start_%d", m + 1);
16918 char *end_o = cpl_sprintf(
"end_%d", m + 1);
16919 char *row_o = cpl_sprintf(
"row_%d", m + 1);
16921 cpl_table_erase_column(slitss[i], object_o);
16922 cpl_table_erase_column(slitss[i], start_o);
16923 cpl_table_erase_column(slitss[i], end_o);
16924 cpl_table_erase_column(slitss[i], row_o);
16932 for (k = 0; k < nslits; k++) {
16933 for (j = 0; j < maxobjs; j++) {
16934 double object_w, object_r;
16937 char *object_i = cpl_sprintf(
"object_%d", j + 1);
16938 char *start_i = cpl_sprintf(
"start_%d", j + 1);
16939 char *end_i = cpl_sprintf(
"end_%d", j + 1);
16940 char *row_i = cpl_sprintf(
"row_%d", j + 1);
16943 if (!cpl_table_is_valid(origslits, object_i, k))
16956 object_w = cpl_table_get_double(origslits, object_i, k, NULL);
16957 row_w = cpl_table_get_int (origslits, row_i, k, NULL);
16959 for (i = 0; i < nscience; i++) {
16962 double mindiff, diff;
16968 for (m = 0; m < c_maxobjs; m++) {
16969 object_o = cpl_sprintf(
"object_%d", m + 1);
16970 start_o = cpl_sprintf(
"start_%d", m + 1);
16971 end_o = cpl_sprintf(
"end_%d", m + 1);
16972 row_o = cpl_sprintf(
"row_%d", m + 1);
16974 if (!cpl_table_is_valid(work[i], object_o, k))
16977 object_r = cpl_table_get_double(work[i], object_o, k, NULL);
16980 diff = fabs(object_w - object_r);
16982 if (mindiff > diff) {
16992 cpl_free(object_o);
16998 object_o = cpl_sprintf(
"object_%d", minpos + 1);
16999 start_o = cpl_sprintf(
"start_%d", minpos + 1);
17000 end_o = cpl_sprintf(
"end_%d", minpos + 1);
17001 row_o = cpl_sprintf(
"row_%d", minpos + 1);
17003 if (!cpl_table_has_column(slitss[i], object_i)) {
17004 cpl_table_new_column(slitss[i], object_i, CPL_TYPE_DOUBLE);
17005 cpl_table_new_column(slitss[i], start_i, CPL_TYPE_INT);
17006 cpl_table_new_column(slitss[i], end_i, CPL_TYPE_INT);
17007 cpl_table_new_column(slitss[i], row_i, CPL_TYPE_INT);
17008 cpl_table_fill_invalid_double(slitss[i], object_i, -1);
17009 cpl_table_fill_invalid_int (slitss[i], start_i, -1);
17010 cpl_table_fill_invalid_int (slitss[i], end_i, -1);
17011 cpl_table_fill_invalid_int (slitss[i], row_i, -1);
17014 cpl_table_set_double(slitss[i], object_i, k,
17015 cpl_table_get_double(work[i], object_o,
17017 cpl_table_set_int(slitss[i], start_i , k,
17018 cpl_table_get_int(work[i], start_o, k, NULL));
17019 cpl_table_set_int(slitss[i], end_i , k,
17020 cpl_table_get_int(work[i], end_o, k, NULL));
17021 cpl_table_set_int(slitss[i], row_i , k, row_w);
17023 cpl_free(object_o);
17029 cpl_free(object_i);
17036 for (i = 0; i < nscience; i++)
17037 cpl_table_delete(work[i]);
17042 return cpl_error_get_code();
17057 char * colname = cpl_sprintf(
"object_%d", maxobjs);
17059 while (cpl_table_has_column(slits, colname)) {
17062 colname = cpl_sprintf(
"object_%d", maxobjs);
17083 int nslits = cpl_table_get_nrow(slits);
17088 for (k = 0; k < nslits; k++) {
17089 for (m = 0; m < maxobjs; m++) {
17090 char * name = cpl_sprintf(
"object_%d", m + 1);
17091 int null = !cpl_table_is_valid(slits, name, k);
17113 cpl_propertylist *sort;
17115 int nslits = cpl_table_get_nrow(slits);
17119 const float interval = 90.0 * rescale;
17120 const float offset = (90.0 - 5) * rescale;
17123 for (k = 0; k < nslits; k++) {
17124 double ytop = cpl_table_get_double(slits,
"ytop", k, &null);
17125 double ybottom = cpl_table_get_double(slits,
"ybottom", k, &null);
17127 double xtop = cpl_table_get_double(slits,
"xtop", k, &null);
17128 double xbottom = cpl_table_get_double(slits,
"xbottom", k, &null);
17130 int nmiss = (int)((ytop - ybottom) / interval + 0.5);
17133 cpl_msg_warning(cpl_func,
17134 "Some slits could not be properly detected. " 17135 "There might be accountable inaccuracies.");
17136 while (nmiss > 1) {
17137 cpl_table_set_size(slits, nslits + 1);
17142 cpl_table_set_double(slits,
"xtop", nslits, xtop);
17143 cpl_table_set_double(slits,
"xbottom", nslits, xbottom);
17147 cpl_table_set_double(slits,
"ybottom", nslits, ybottom);
17148 cpl_table_set_double(slits,
"ytop", nslits, ybottom
17150 ybottom += interval;
17151 cpl_table_set_double(slits,
"ybottom", k, ybottom);
17153 cpl_table_set_double(slits,
"ytop", nslits, ytop);
17154 cpl_table_set_double(slits,
"ybottom", nslits, ytop
17157 cpl_table_set_double(slits,
"ytop", k, ytop);
17165 sort = cpl_propertylist_new();
17166 cpl_propertylist_append_bool(sort,
"ytop", 1);
17167 cpl_table_sort(slits, sort);
17168 cpl_propertylist_delete(sort);
17175 k = cpl_table_get_nrow(slits) - 1;
17178 double ytop = cpl_table_get_double(slits,
"ytop", k, &null);
17179 double ybottom = cpl_table_get_double(slits,
"ybottom", k, &null);
17180 double length = (ytop - ybottom) / interval;
17182 if (length > 1.1) {
17183 cpl_table_set_double(slits,
"ybottom", k, ytop - offset);
17214 int * nslits_out_det)
17219 cpl_propertylist * sort;
17223 halfsize = cpl_table_get_nrow(slits);
17225 cpl_table_set_size(slits, 2 * halfsize);
17227 for (m = 0; m < halfsize; m++) {
17232 cpl_table_get(slits,
"ytop", m, &null) -
17233 cpl_table_get(slits,
"ybottom", m, &null);
17237 cpl_table_get(slits,
"ybottom", m - 1, &null) -
17238 cpl_table_get(slits,
"ytop", m, &null);
17240 gap = (interval - length) / 2;
17243 cpl_table_set(slits,
"slit_id", m + halfsize,
17244 cpl_table_get(slits,
"slit_id", m, &null) - 1);
17246 cpl_table_set(slits,
"xtop", m + halfsize,
17247 cpl_table_get(slits,
"xtop", m, &null));
17249 cpl_table_set(slits,
"xbottom", m + halfsize,
17250 cpl_table_get(slits,
"xbottom", m, &null));
17252 cpl_table_set(slits,
"ytop", m + halfsize,
17253 cpl_table_get(slits,
"ytop", m, &null) + gap + length);
17255 cpl_table_set(slits,
"ybottom", m + halfsize,
17256 cpl_table_get(slits,
"ytop", m, &null) + gap);
17259 for (m = 0; m < 2 * halfsize; m++) {
17260 cpl_table_set(slits,
"ytop", m,
17261 cpl_table_get(slits,
"ytop", m, &null) - 5.3);
17263 cpl_table_set(slits,
"ybottom", m,
17264 cpl_table_get(slits,
"ybottom", m, &null) - 5.3);
17268 sort = cpl_propertylist_new();
17269 cpl_propertylist_append_bool(sort,
"ytop", 1);
17270 cpl_table_sort(slits, sort);
17272 cpl_propertylist_delete(sort);
17277 int * fors_get_nobjs_perslit(cpl_table * slits)
17279 int nslits = cpl_table_get_nrow(slits);
17282 int * nobjs_per_slit = cpl_malloc(
sizeof(
int) * nslits);
17286 for (k = 0; k < nslits; k++) {
17288 for (m = 0; m < maxobjs; m++) {
17289 char * name = cpl_sprintf(
"object_%d", m + 1);
17290 int null = !cpl_table_is_valid(slits, name, k);
17298 nobjs_per_slit[k] = nobjs;
17301 return nobjs_per_slit;
17304 double fors_get_object_position(cpl_table *slits,
int slit,
int object)
17306 char *name = cpl_sprintf(
"object_%d",
object);
17309 position = cpl_table_get_double(slits, name, slit, NULL)
17310 - cpl_table_get_int(slits,
"position", slit, NULL);
17317 int mos_rebin_signal(cpl_image **image,
int rebin)
17319 cpl_image *rebinned;
17322 if (*image == NULL)
17328 rebinned = cpl_image_rebin(*image, 1, 1, rebin, 1);
17330 cpl_image_delete(*image);
17337 int mos_rebin_error(cpl_image **image,
int rebin)
17339 if (*image == NULL)
17345 cpl_image_power(*image, 2);
17346 mos_rebin_signal(image, rebin);
17347 cpl_image_power(*image, 0.5);
17369 int map_table(cpl_image *image,
double start,
double step,
17370 cpl_table *table,
const char *xname,
const char *yname)
17372 int length = cpl_image_get_size_x(image);
17373 int nrows = cpl_table_get_nrow(table);
17374 float *data = cpl_image_get_data_float(image);
17375 float *fdata = NULL;
17376 double *xdata = NULL;
17377 double *ydata = NULL;
17378 cpl_type xtype = cpl_table_get_column_type(table, xname);
17379 cpl_type ytype = cpl_table_get_column_type(table, yname);
17389 for (i = 0; i < length; i++)
17397 if (xtype == CPL_TYPE_FLOAT) {
17398 fdata = cpl_table_get_data_float(table, xname);
17399 xdata = cpl_malloc(nrows *
sizeof(
double));
17400 for (i = 0; i < nrows; i++) {
17401 xdata[i] = fdata[i];
17405 xdata = cpl_table_get_data_double(table, xname);
17408 if (ytype == CPL_TYPE_FLOAT) {
17409 fdata = cpl_table_get_data_float(table, yname);
17410 ydata = cpl_malloc(nrows *
sizeof(
double));
17411 for (i = 0; i < nrows; i++) {
17412 ydata[i] = fdata[i];
17416 ydata = cpl_table_get_data_double(table, yname);
17426 for (i = 0; i < length; i++) {
17427 pos = start + step * i;
17430 for (j = n; j < nrows; j++) {
17431 if (xdata[j] > pos) {
17433 data[i] = ydata[j-1]
17434 + (ydata[j] - ydata[j-1])
17435 * (pos - xdata[j-1]) / (xdata[j] - xdata[j-1]);
17441 if (xtype == CPL_TYPE_FLOAT)
17444 if (ytype == CPL_TYPE_FLOAT)
17464 static cpl_image *polysmooth(cpl_image *image,
int order,
int hw)
17471 cpl_polynomial *poly;
17472 cpl_vector *ysmooth;
17473 cpl_image *smoothed;
17478 npoints = cpl_image_get_size_x(image);
17480 if (2 * hw + 1 > npoints)
17483 x = cpl_vector_new(npoints);
17484 y = cpl_vector_new(npoints);
17485 xdata = cpl_vector_get_data(x);
17486 ydata = cpl_vector_get_data(y);
17488 smoothed = cpl_image_duplicate(image);
17489 sdata = cpl_image_get_data_float(smoothed);
17491 for (i = 0; i < npoints; i++) {
17493 ydata[i] = sdata[i];
17496 ysmooth = cpl_vector_filter_median_create(y, hw);
17497 cpl_vector_delete(y);
17499 poly = cpl_polynomial_fit_1d_create(x, ysmooth, order, NULL);
17500 cpl_vector_delete(x);
17501 cpl_vector_delete(ysmooth);
17504 for (i = 0; i < npoints; i++)
17505 sdata[i] = cpl_polynomial_eval_1d(poly, i, NULL);
17507 cpl_polynomial_delete(poly);
17510 cpl_image_delete(smoothed);
17520 cpl_image_delete(spectrum); \ 17521 cpl_image_delete(flux); \ 17522 cpl_image_delete(efficiency); \ 17523 cpl_image_delete(smo_efficiency); \ 17524 cpl_image_delete(extinction); \ 17525 cpl_image_delete(response); \ 17526 cpl_image_delete(smo_response); \ 17527 cpl_image_delete(physical); \ 17554 double dispersion,
double gain,
17555 double exptime, cpl_table *ext_table,
17556 double airmass, cpl_table *flux_table,
17560 cpl_image *spectrum = NULL;
17562 cpl_image *extinction = NULL;
17564 cpl_image *flux = NULL;
17566 cpl_image *physical = NULL;
17568 cpl_image *efficiency = NULL;
17570 cpl_image *smo_efficiency = NULL;
17571 float *smo_eff_data;
17572 cpl_image *response = NULL;
17574 cpl_image *smo_response = NULL;
17575 float *smo_res_data;
17577 cpl_image *smo_image;
17581 int ext_count, ext_pos;
17582 int eff_count, eff_pos;
17583 int flux_count, flux_pos;
17588 if (spectra == NULL || ext_table == NULL || flux_table == NULL) {
17589 cpl_error_set(cpl_func, CPL_ERROR_NULL_INPUT);
17593 if (!cpl_table_has_column(ext_table,
"WAVE")) {
17594 cpl_error_set_message(cpl_func, CPL_ERROR_DATA_NOT_FOUND,
17595 "Column WAVE in atmospheric extinction table");
17599 if (!cpl_table_has_column(ext_table,
"EXTINCTION")) {
17600 cpl_error_set_message(cpl_func, CPL_ERROR_DATA_NOT_FOUND,
17601 "Column EXTINCTION in atmospheric extinction table");
17605 if (!cpl_table_has_column(flux_table,
"WAVE")) {
17606 cpl_error_set_message(cpl_func, CPL_ERROR_DATA_NOT_FOUND,
17607 "Column WAVE in standard star flux table");
17611 if (!cpl_table_has_column(flux_table,
"FLUX")) {
17612 cpl_error_set_message(cpl_func, CPL_ERROR_DATA_NOT_FOUND,
17613 "Column FLUX in standard star flux table");
17618 cpl_error_set_message(cpl_func, CPL_ERROR_ILLEGAL_INPUT,
17619 "Invalid gain factor (%.2f)", gain);
17623 if (exptime < 0.001) {
17624 cpl_error_set_message(cpl_func, CPL_ERROR_ILLEGAL_INPUT,
17625 "Invalid exposure time (%.2f)", exptime);
17629 if (dispersion < 0.001) {
17630 cpl_error_set_message(cpl_func, CPL_ERROR_ILLEGAL_INPUT,
17631 "Invalid dispersion (%.2f)", dispersion);
17636 cpl_error_set_message(cpl_func, CPL_ERROR_ILLEGAL_INPUT,
17637 "Order of the polynomial fitting the " 17638 "instrument response must be at least 2");
17642 nx = cpl_image_get_size_x(spectra);
17643 ny = cpl_image_get_size_y(spectra);
17651 spectrum = cpl_image_duplicate(spectra);
17655 cpl_image *brights = cpl_image_collapse_create(spectra, 1);
17657 cpl_image_get_maxpos(brights, &x, &y);
17658 cpl_image_delete(brights);
17659 spectrum = cpl_image_extract(spectra, 1, y, nx, y);
17667 cpl_image_multiply_scalar(spectrum, gain / exptime / dispersion);
17675 extinction = cpl_image_duplicate(spectrum);
17676 map_table(extinction, startwave + dispersion/2, dispersion,
17677 ext_table,
"WAVE",
"EXTINCTION");
17684 cpl_image_multiply_scalar(extinction, 0.4 * airmass);
17685 cpl_image_exponential(extinction, 10.);
17692 cpl_image_multiply(spectrum, extinction);
17700 ext_data = cpl_image_get_data_float(extinction);
17704 for (i = 0; i < nx; i++) {
17705 if (ext_data[i] > 0.0) {
17706 if (ext_count == 0) {
17718 cpl_image_delete(extinction); extinction = NULL;
17726 flux = cpl_image_duplicate(spectrum);
17727 map_table(flux, startwave + dispersion/2, dispersion,
17728 flux_table,
"WAVE",
"FLUX");
17736 flux_data = cpl_image_get_data_float(flux);
17740 for (i = 0; i < nx; i++) {
17741 if (flux_data[i] > 0.0) {
17742 if (flux_count == 0) {
17759 start = ext_pos > flux_pos ? ext_pos : flux_pos;
17760 end = (ext_pos + ext_count) < (flux_pos + flux_count) ?
17761 (ext_pos + ext_count) : (flux_pos + flux_count);
17763 flux_count = end - start;
17774 physical = cpl_image_duplicate(spectrum);
17775 phys_data = cpl_image_get_data_float(physical);
17777 for (i = 0; i < nx; i++) {
17778 lambda = startwave + dispersion * (i + 0.5);
17779 phys_data[i] = 0.0026 * lambda * flux_data[i];
17782 efficiency = cpl_image_duplicate(spectrum);
17783 eff_data = cpl_image_get_data_float(efficiency);
17784 data = cpl_image_get_data_float(spectrum);
17786 for (i = 0; i < nx; i++) {
17787 if (phys_data[i] > 0.0)
17788 eff_data[i] = data[i] / phys_data[i];
17793 cpl_image_delete(physical); physical = NULL;
17803 for (i = 0; i < nx; i++) {
17804 if (eff_data[i] > 0.01) {
17805 if (eff_count == 0) {
17811 if (eff_count > 300) {
17822 start = eff_pos > flux_pos ? eff_pos : flux_pos;
17823 end = (eff_pos + eff_count) < (flux_pos + flux_count) ?
17824 (eff_pos + eff_count) : (flux_pos + flux_count);
17826 eff_count = end - start;
17828 if (eff_count < 1) {
17829 cpl_error_set_message(cpl_func, CPL_ERROR_INCOMPATIBLE_INPUT,
17830 "No overlap between catalog and spectrum");
17840 image = cpl_image_extract(efficiency, eff_pos + 1, 1,
17841 eff_pos + eff_count, 1);
17843 smo_image = polysmooth(image, order, 50);
17844 cpl_image_delete(image);
17846 smo_efficiency = cpl_image_duplicate(efficiency);
17847 smo_eff_data = cpl_image_get_data_float(smo_efficiency);
17848 cpl_image_copy(smo_efficiency, smo_image, eff_pos + 1, 1);
17850 cpl_image_delete(smo_image);
17861 response = cpl_image_duplicate(spectrum);
17862 res_data = cpl_image_get_data_float(response);
17864 for (i = 0; i < nx; i++) {
17865 if (eff_data[i] > 0.01 && flux_data[i] > 0.0)
17866 res_data[i] = data[i] / flux_data[i];
17876 image = cpl_image_extract(response, eff_pos + 1, 1, eff_pos + eff_count, 1);
17878 smo_image = polysmooth(image, order, 50);
17879 cpl_image_delete(image);
17881 smo_response = cpl_image_duplicate(response);
17882 smo_res_data = cpl_image_get_data_float(smo_response);
17883 cpl_image_copy(smo_response, smo_image, eff_pos + 1, 1);
17885 cpl_image_delete(smo_image);
17887 for (i = 0; i < nx; i++) {
17888 if (eff_data[i] > 0.01) {
17889 res_data[i] = 1 / res_data[i];
17890 smo_res_data[i] = 1 / smo_res_data[i];
17894 smo_res_data[i] = 0.0;
17903 table = cpl_table_new(nx);
17905 cpl_table_new_column(table,
"WAVE", CPL_TYPE_FLOAT);
17906 cpl_table_set_column_unit(table,
"WAVE",
"Angstrom");
17908 for (i = 0; i < nx; i++)
17909 cpl_table_set_float(table,
"WAVE", i, startwave + dispersion*(i+0.5));
17911 cpl_table_new_column(table,
"STD_FLUX", CPL_TYPE_FLOAT);
17912 cpl_table_set_column_unit(table,
"STD_FLUX",
17913 "10^(-16) erg/(cm^2 s Angstrom)");
17914 cpl_table_copy_data_float(table,
"STD_FLUX", flux_data);
17915 cpl_image_delete(flux); flux = NULL;
17917 cpl_table_new_column(table,
"OBS_FLUX", CPL_TYPE_FLOAT);
17918 cpl_table_set_column_unit(table,
"OBS_FLUX",
"electron/(s Angstrom)");
17919 cpl_table_copy_data_float(table,
"OBS_FLUX", data);
17920 cpl_image_delete(spectrum); spectrum = NULL;
17922 cpl_table_new_column(table,
"RAW_EFFICIENCY", CPL_TYPE_FLOAT);
17923 cpl_table_set_column_unit(table,
"RAW_EFFICIENCY",
"electron/photon");
17924 cpl_table_copy_data_float(table,
"RAW_EFFICIENCY", eff_data);
17925 cpl_image_delete(efficiency); efficiency = NULL;
17927 cpl_table_new_column(table,
"EFFICIENCY", CPL_TYPE_FLOAT);
17928 cpl_table_set_column_unit(table,
"EFFICIENCY",
"electron/photon");
17929 cpl_table_copy_data_float(table,
"EFFICIENCY", smo_eff_data);
17930 cpl_image_delete(smo_efficiency); smo_efficiency = NULL;
17932 cpl_table_new_column(table,
"RAW_RESPONSE", CPL_TYPE_FLOAT);
17933 cpl_table_set_column_unit(table,
"RAW_RESPONSE",
17934 "10^(-16) erg/(cm^2 electron)");
17935 cpl_table_copy_data_float(table,
"RAW_RESPONSE", res_data);
17936 cpl_image_delete(response); response = NULL;
17938 cpl_table_new_column(table,
"RESPONSE", CPL_TYPE_FLOAT);
17939 cpl_table_set_column_unit(table,
17940 "RESPONSE",
"10^(-16) erg/(cm^2 electron)");
17941 cpl_table_copy_data_float(table,
"RESPONSE", smo_res_data);
17942 cpl_image_delete(smo_response); smo_response = NULL;
17949 static double ksigma_vector(cpl_vector *values,
17950 double klow,
double khigh,
int kiter,
int *good)
17952 cpl_vector *accepted;
17954 double sigma = 0.0;
17955 double *data = cpl_vector_get_data(values);
17956 int n = cpl_vector_get_size(values);
17967 mean = cpl_vector_get_median(values);
17969 for (i = 0; i < n; i++)
17970 sigma += (mean - data[i]) * (mean - data[i]);
17972 sigma = sqrt(sigma / (n - 1));
17976 for (i = 0; i < ngood; i++) {
17977 if (data[i]-mean < khigh*sigma && mean-data[i] < klow*sigma) {
17978 data[count] = data[i];
17992 accepted = cpl_vector_wrap(count, data);
17993 mean = cpl_vector_get_mean(accepted);
17995 sigma = cpl_vector_get_stdev(accepted);
17996 cpl_vector_unwrap(accepted);
17998 if (count == ngood || count == 1)
18031 double klow,
double khigh,
int kiter,
18034 int ni, nx, ny, npix;
18035 cpl_image *out_ima;
18040 cpl_vector *time_line;
18041 double *ptime_line;
18046 ni = cpl_imagelist_get_size(imlist);
18048 image = cpl_imagelist_get(imlist, 0);
18049 nx = cpl_image_get_size_x(image);
18050 ny = cpl_image_get_size_y(image);
18053 out_ima = cpl_image_new(nx, ny, CPL_TYPE_FLOAT);
18054 pout_ima = cpl_image_get_data_float(out_ima);
18057 *good = cpl_image_new(nx, ny, CPL_TYPE_FLOAT);
18058 good_ima = cpl_image_get_data_float(*good);
18061 time_line = cpl_vector_new(ni);
18062 ptime_line = cpl_vector_get_data(time_line);
18064 data = cpl_calloc(
sizeof(
float *), ni);
18066 for (i = 0; i < ni; i++) {
18067 image = cpl_imagelist_get(imlist, i);
18068 data[i] = cpl_image_get_data_float(image);
18071 for (i = 0; i < npix; i++) {
18072 for (j = 0; j < ni; j++) {
18073 ptime_line[j] = data[j][i];
18075 pout_ima[i] = ksigma_vector(time_line, klow, khigh, kiter, &ngood);
18077 good_ima[i] = ngood;
18082 cpl_vector_delete(time_line);
18106 cpl_table *ext_table,
double startwave,
18107 double dispersion,
double gain,
18108 double exptime,
double airmass)
18110 cpl_image *extinction;
18111 cpl_image *outspectra;
18112 cpl_image *mapresponse;
18116 int tlength, xlength, ylength;
18118 double resp_startwave;
18119 double resp_endwave;
18123 if (spectra == NULL || ext_table == NULL || response == NULL) {
18124 cpl_error_set(cpl_func, CPL_ERROR_NULL_INPUT);
18132 if(cpl_table_has_column(response,
"RESPONSE"))
18133 cpl_table_cast_column(response,
"RESPONSE",
"RESPONSE_F", CPL_TYPE_FLOAT);
18134 else if(cpl_table_has_column(response,
"RESPONSE_FFSED"))
18135 cpl_table_cast_column(response,
"RESPONSE_FFSED",
"RESPONSE_F", CPL_TYPE_FLOAT);
18139 res_data = cpl_table_get_data_float(response,
"RESPONSE_F");
18141 if (res_data == NULL) {
18142 cpl_error_set(cpl_func, CPL_ERROR_DATA_NOT_FOUND);
18146 tlength = cpl_table_get_nrow(response);
18147 xlength = cpl_image_get_size_x(spectra);
18148 ylength = cpl_image_get_size_y(spectra);
18151 mapresponse = cpl_image_new(xlength, 1, CPL_TYPE_FLOAT);
18152 map_table(mapresponse, startwave + dispersion/2, dispersion,
18153 response,
"WAVE",
"RESPONSE_F");
18154 res_data = cpl_image_get_data_float(mapresponse);
18161 extinction = cpl_image_new(xlength, 1, CPL_TYPE_FLOAT);
18162 map_table(extinction, startwave + dispersion/2, dispersion,
18163 ext_table,
"WAVE",
"EXTINCTION");
18170 cpl_image_multiply_scalar(extinction, 0.4 * airmass);
18171 cpl_image_exponential(extinction, 10.);
18173 outspectra = cpl_image_duplicate(spectra);
18175 ext_data = cpl_image_get_data_float(extinction);
18176 out_data = cpl_image_get_data_float(outspectra);
18178 for (k = 0, i = 0; i < ylength; i++) {
18179 for (j = 0; j < xlength; j++, k++)
18180 out_data[k] *= ext_data[j] * res_data[j];
18183 cpl_image_delete(extinction);
18184 cpl_image_delete(mapresponse);
18186 cpl_image_multiply_scalar(outspectra, gain / exptime / dispersion);
18191 resp_startwave = cpl_table_get(response,
"WAVE", 0, &null);
18192 resp_endwave = cpl_table_get(response,
"WAVE",
18193 cpl_table_get_nrow(response) -1, &null);
18194 for (j = 0; j < xlength; j++) {
18195 double this_wave = startwave + j * dispersion;
18196 if(this_wave < resp_startwave ||this_wave > resp_endwave)
18198 for (i = 0; i < ylength; i++)
18199 out_data[j + xlength * i] = -1;
18203 cpl_table_erase_column(response,
"RESPONSE_F");
18227 cpl_table *response,
18228 cpl_table *ext_table,
18230 double dispersion,
double gain,
18231 double exptime,
double airmass)
18233 cpl_image *extinction;
18234 cpl_image *outerrors;
18235 cpl_image *mapresponse;
18236 cpl_image *maperror;
18242 int tlength, xlength, ylength;
18246 if (errors == NULL || ext_table == NULL || response == NULL) {
18247 cpl_error_set(cpl_func, CPL_ERROR_NULL_INPUT);
18251 if (!cpl_table_has_column(response,
"ERROR")) {
18253 dispersion, gain, exptime, airmass);
18256 cpl_table_cast_column(response,
"RESPONSE",
"RESPONSE_F", CPL_TYPE_FLOAT);
18257 res_data = cpl_table_get_data_float(response,
"RESPONSE_F");
18259 if (res_data == NULL) {
18260 cpl_error_set(cpl_func, CPL_ERROR_DATA_NOT_FOUND);
18264 err_data = cpl_table_get_data_float(response,
"ERROR");
18266 if (err_data == NULL) {
18267 cpl_error_set(cpl_func, CPL_ERROR_DATA_NOT_FOUND);
18271 tlength = cpl_table_get_nrow(response);
18272 xlength = cpl_image_get_size_x(errors);
18273 ylength = cpl_image_get_size_y(errors);
18275 if (xlength != tlength) {
18276 mapresponse = cpl_image_new(xlength, 1, CPL_TYPE_FLOAT);
18277 map_table(mapresponse, startwave + dispersion/2, dispersion,
18278 response,
"WAVE",
"RESPONSE_F");
18279 res_data = cpl_image_get_data_float(mapresponse);
18281 maperror = cpl_image_new(xlength, 1, CPL_TYPE_FLOAT);
18282 map_table(maperror, startwave + dispersion/2, dispersion,
18283 response,
"WAVE",
"ERROR");
18284 err_data = cpl_image_get_data_float(maperror);
18292 extinction = cpl_image_new(xlength, 1, CPL_TYPE_FLOAT);
18293 map_table(extinction, startwave + dispersion/2, dispersion,
18294 ext_table,
"WAVE",
"EXTINCTION");
18301 cpl_image_multiply_scalar(extinction, 0.4 * airmass);
18302 cpl_image_exponential(extinction, 10.);
18304 outerrors = cpl_image_duplicate(errors);
18306 ext_data = cpl_image_get_data_float(extinction);
18307 out_data = cpl_image_get_data_float(outerrors);
18308 spe_data = cpl_image_get_data_float(spectra);
18310 for (k = 0, i = 0; i < ylength; i++) {
18311 for (j = 0; j < xlength; j++, k++) {
18312 out_data[k] = ext_data[j] *
18313 sqrt(err_data[j] * err_data[j] * spe_data[k] * spe_data[k] +
18314 res_data[j] * res_data[j] * out_data[k] * out_data[k]);
18318 cpl_image_delete(extinction);
18319 if (xlength != tlength) {
18320 cpl_image_delete(maperror);
18323 cpl_image_multiply_scalar(outerrors, gain / exptime / dispersion);
18325 cpl_table_erase_column(response,
"RESPONSE_F");
18406 cpl_image *u_image, cpl_image *u_error,
18407 double startwave,
double dispersion,
18408 double band, cpl_table *pol_sta,
18409 double ra,
double dec,
char *filter,
18411 double *p_offset,
double *p_error,
18412 double *a_offset,
double *a_error)
18414 cpl_table *standard;
18415 cpl_image *q_noise;
18416 cpl_image *q_signal;
18417 cpl_image *u_noise;
18418 cpl_image *u_signal;
18424 double arctol = 0.5;
18427 double bwave[] = {3650., 4450., 5510., 6580., 8060};
18428 char *bands =
"UBVRI";
18429 char p_label[] = {
' ',
'p',
'\0'};
18430 char dp_label[] = {
' ',
'd',
'p',
'\0'};
18431 char a_label[] = {
' ',
'a',
'\0'};
18432 char da_label[] = {
' ',
'd',
'a',
'\0'};
18433 int nbands = strlen(bands);
18435 int first, last, count, center;
18438 int i, found, closest;
18466 cpl_table_select_all(pol_sta);
18467 cpl_table_and_selected_double(pol_sta,
"COORD_RA", CPL_GREATER_THAN,
18469 cpl_table_and_selected_double(pol_sta,
"COORD_RA", CPL_LESS_THAN,
18471 cpl_table_and_selected_double(pol_sta,
"COORD_DEC", CPL_GREATER_THAN,
18474 cpl_table_and_selected_double(pol_sta,
"COORD_DEC", CPL_LESS_THAN,
18477 if (selected == 0) {
18478 cpl_msg_warning(cpl_func,
"No standard star found in FOV");
18482 if (selected > 1) {
18483 cpl_msg_warning(cpl_func,
18484 "Ambiguity: %d standard stars found in FOV", selected);
18488 standard = cpl_table_extract_selected(pol_sta);
18490 cpl_msg_info(cpl_func,
"Standard star: %s",
18491 cpl_table_get_string(standard,
"name", 0));
18497 polarised = cpl_table_get_int(standard,
"polarised", 0, NULL);
18499 cpl_msg_info(cpl_func,
"This star is%sexpected to be polarised",
18500 polarised ?
" " :
" not ");
18510 nx = cpl_image_get_size_x(q_error);
18512 noise = cpl_image_collapse_median_create(q_error, 1, 0, 0);
18513 cpl_image_get_minpos(noise, &col, &row);
18515 cpl_image_delete(noise);
18518 cpl_table_delete(standard);
18519 cpl_msg_error(cpl_func,
18520 "Assertion failure!!! col = %"CPL_SIZE_FORMAT
" (it should be 1)", col);
18524 q_signal = cpl_image_extract(q_image, 1, row, nx, row);
18525 q_noise = cpl_image_extract(q_error, 1, row, nx, row);
18526 u_signal = cpl_image_extract(u_image, 1, row, nx, row);
18527 u_noise = cpl_image_extract(u_error, 1, row, nx, row);
18529 q_sdata = cpl_image_get_data_double(q_signal);
18530 q_ndata = cpl_image_get_data_double(q_noise);
18531 u_sdata = cpl_image_get_data_double(u_signal);
18532 u_ndata = cpl_image_get_data_double(u_noise);
18540 last = nx = cpl_image_get_size_x(q_signal);
18541 for (i = 0; i < nx; i++) {
18543 if (q_ndata[i] > 0.0) {
18548 if (q_ndata[i] <= 0.0) {
18555 count = last - first + 1;
18557 if (first < 0 || count < band) {
18558 cpl_table_delete(standard);
18559 cpl_image_delete(q_signal);
18560 cpl_image_delete(q_noise);
18561 cpl_image_delete(u_signal);
18562 cpl_image_delete(u_noise);
18563 cpl_msg_warning(cpl_func,
"Too short spectrum (%d pixels)", count);
18567 center = (first + last) / 2;
18568 cwave = startwave + dispersion * center;
18576 for (i = 0; i < nbands; i++) {
18577 p_label[0] = bands[i];
18578 if (cpl_table_is_valid(standard, p_label, 0)) {
18581 mindist = fabs(bwave[i] - cwave);
18584 else if (mindist > fabs(bwave[i] - cwave)) {
18585 mindist = fabs(bwave[i] - cwave);
18592 cpl_table_delete(standard);
18593 cpl_image_delete(q_signal);
18594 cpl_image_delete(q_noise);
18595 cpl_image_delete(u_signal);
18596 cpl_image_delete(u_noise);
18597 cpl_msg_warning(cpl_func,
"No reference value available");
18601 center = (bwave[closest] - startwave) / dispersion;
18602 cwave = bwave[closest];
18610 pband = floor(band / dispersion);
18612 if (center - pband/2 < first || center + pband/2 > last) {
18613 cpl_table_delete(standard);
18614 cpl_image_delete(q_signal);
18615 cpl_image_delete(q_noise);
18616 cpl_image_delete(u_signal);
18617 cpl_image_delete(u_noise);
18618 cpl_msg_warning(cpl_func,
"No reference value available");
18622 first = center - pband/2;
18623 last = center + pband/2;
18630 p_label[0] = bands[closest];
18631 dp_label[0] = bands[closest];
18632 a_label[0] = bands[closest];
18633 da_label[0] = bands[closest];
18635 p_ref = cpl_table_get(standard, p_label, 0, NULL);
18636 dp_ref = cpl_table_get(standard, dp_label, 0, NULL);
18637 a_ref = cpl_table_get(standard, a_label, 0, NULL);
18638 da_ref = cpl_table_get(standard, da_label, 0, NULL);
18640 cpl_msg_info(cpl_func,
18641 "The expected polarisation is %.2f +- %.2f %%",
18645 cpl_msg_info(cpl_func,
18646 "The expected polarisation angle is %.2f +- %.2f degrees",
18654 q_obs = cpl_image_get_median_window(q_image, first, 1, last, 1);
18655 q_err = cpl_image_get_median_window(q_error, first, 1, last, 1);
18656 u_obs = cpl_image_get_median_window(u_image, first, 1, last, 1);
18657 u_err = cpl_image_get_median_window(u_error, first, 1, last, 1);
18663 p_obs = sqrt(q_obs * q_obs + u_obs * u_obs);
18664 p_err = CPL_MATH_SQRT1_2 * 0.5 * (q_err + u_err);
18672 if (fabs(q_obs) < 0.00001) {
18681 a_obs = 0.5 * atan(u_obs / q_obs) * 180 / CPL_MATH_PI;
18699 a_err = sqrt(q_obs*q_obs*u_err*u_err + u_obs*u_obs*q_err*q_err)
18701 * 90 / CPL_MATH_PI;
18706 cpl_msg_info(cpl_func,
18707 "The measured polarisation is %.2f +- %.2f %%",
18711 cpl_msg_info(cpl_func,
18712 "The measured polarisation angle is %.2f +- %.2f degrees",
18716 *filter = bands[closest];
18717 *polarisation = polarised;
18720 *p_offset = (p_obs - p_ref) / p_ref;
18721 *p_error = sqrt(p_err * p_err + dp_ref * dp_ref) / p_ref;
18724 *p_offset = p_obs - p_ref;
18725 *p_error = sqrt(p_err * p_err + dp_ref * dp_ref);
18728 *a_offset = a_obs - a_ref;
18729 *a_error = sqrt(a_err*a_err + da_ref*da_ref);
18769 cpl_array *offsets;
18771 int nslits = cpl_table_get_nrow(reference);
18778 cpl_error_code status = CPL_ERROR_NONE;
18783 if (objects == NULL)
18784 return CPL_ERROR_NULL_INPUT;
18786 if (nslits != cpl_table_get_nrow(objects))
18787 return CPL_ERROR_INCOMPATIBLE_INPUT;
18789 nref = fors_get_nobjs_perslit(reference);
18790 nobj = fors_get_nobjs_perslit(objects);
18793 for (i = 0; i < nslits; i++)
18794 noffset += nobj[i];
18796 if (noffset == 0) {
18799 return CPL_ERROR_DATA_NOT_FOUND;
18803 for (i = 0; i < nslits; i++)
18804 noffset += nref[i];
18806 if (noffset == 0) {
18809 return CPL_ERROR_DATA_NOT_FOUND;
18812 offsets = cpl_array_new(noffset, CPL_TYPE_DOUBLE);
18816 for (i = 0; i < nslits; i++) {
18817 if (nref[i] > 0 && nobj[i] > 0) {
18819 int length = cpl_table_get_int(objects,
"length", i, NULL);
18820 double ytop = cpl_table_get_double(objects,
"xtop", i, NULL);
18821 double ybottom = cpl_table_get_double(objects,
"xbottom", i, NULL);
18822 int *aref = cpl_calloc(length,
sizeof(
int));
18823 int *aobj = cpl_calloc(length,
sizeof(
int));
18824 float *pref = cpl_calloc(nref[i],
sizeof(
float));
18825 float *pobj = cpl_calloc(nobj[i],
sizeof(
float));
18827 for (j = 0; j < nref[i]; j++) {
18828 pref[j] = fors_get_object_position(reference, i, j + 1);
18829 aref[(int)pref[j]] = 1;
18832 for (j = 0; j < nobj[i]; j++) {
18833 pobj[j] = fors_get_object_position(objects, i, j + 1);
18834 aobj[(int)pobj[j]] = 1;
18842 aref[length - 1] = 0;
18844 aobj[length - 1] = 0;
18864 best_shift = length;
18866 for (shift = length/2, j = 0; j <= length; shift--, j++) {
18867 int rstart, ostart, count;
18872 count = length - shift;
18877 count = length + shift;
18881 for (k = 0; k < count; k++) {
18882 corr += aref[rstart + k] * aobj[ostart + k];
18885 if (maxcorr < corr) {
18887 best_shift = shift;
18891 if (best_shift == length) {
18901 for (j = 0; j < nref[i]; j++) {
18902 for (k = 0; k < nobj[i]; k++) {
18903 if (fabs(pref[j] - pobj[k] - best_shift) < 2) {
18904 double ccd_offset = (pref[j] - pobj[k])
18914 cpl_array_set(offsets, noffset, ccd_offset);
18936 *offset = cpl_array_get_median(offsets);
18939 double *a = cpl_malloc(
sizeof(
double) * noffset);
18940 for (i = 0; i < noffset; i++) {
18941 a[i] = cpl_array_get_double(offsets, i, NULL);
18949 status = CPL_ERROR_DATA_NOT_FOUND;
18952 cpl_array_delete(offsets);
18973 int nx = cpl_image_get_size_x(image);
18974 int ny = cpl_image_get_size_y(image);
18978 double xpos, ypos, xfrac, yfrac;
18982 if (fabs(dx) >= nx || fabs(dy) >= ny)
18983 return CPL_ERROR_ACCESS_OUT_OF_RANGE;
18985 source = cpl_image_duplicate(image);
18986 idata = cpl_image_get_data_float(image);
18987 sdata = cpl_image_get_data_float(source);
18993 yfrac = - dy - floor(- dy);
18994 xfrac = - dx - floor(- dx);
18996 for (pos = 0, j = 0; j < ny; j++) {
18998 yint = floor(ypos);
18999 for (i = 0; i < nx; i++) {
19001 xint = floor(xpos);
19002 if (xint < 0 || yint < 0 || xint > nx - 2 || yint > ny - 2) {
19006 idata[pos] = sdata[xint + nx*yint] * (1 - xfrac) * (1 - yfrac)
19007 + sdata[xint + 1 + nx*yint] * xfrac * (1 - yfrac)
19008 + sdata[xint + nx*(yint + 1)] * (1 - xfrac) * yfrac
19009 + sdata[xint + 1 + nx*(yint + 1)] * xfrac * yfrac;
19015 cpl_image_delete(source);
19017 return CPL_ERROR_NONE;
19033 #ifdef CPL_SIZE_FORMAT 19039 cpl_table_duplicate_column(slits,
"x", slits,
"xtop");
19040 cpl_table_add_columns(slits,
"x",
"xbottom");
19041 cpl_table_divide_scalar(slits,
"x", 2);
19042 cpl_table_subtract_scalar(slits,
"x", nx/2);
19043 cpl_table_multiply_columns(slits,
"x",
"x");
19045 cpl_table_duplicate_column(slits,
"y", slits,
"ytop");
19046 cpl_table_add_columns(slits,
"y",
"ybottom");
19047 cpl_table_divide_scalar(slits,
"y", 2);
19048 cpl_table_subtract_scalar(slits,
"y", ny/2);
19049 cpl_table_multiply_columns(slits,
"y",
"y");
19051 cpl_table_add_columns(slits,
"x",
"y");
19052 cpl_table_get_column_minpos(slits,
"x", &row);
19054 cpl_table_erase_column(slits,
"x");
19055 cpl_table_erase_column(slits,
"y");
19080 double xwidth,
double ywidth,
19081 int dx,
double gain,
double *o_flux,
double *o_err)
19083 int nx = cpl_image_get_size_x(image);
19084 int ny = cpl_image_get_size_y(image);
19086 int ytop = (int)cpl_table_get(slits,
"ytop", slit, NULL);
19087 int ybottom = (int)cpl_table_get(slits,
"ybottom", slit, NULL);
19088 int dy = ytop - ybottom;
19089 int xcenter = (int)((cpl_table_get(slits,
"xtop", slit, NULL) +
19090 cpl_table_get(slits,
"xbottom", slit, NULL)) / 2);
19091 int xleft = xcenter - dx;
19092 int xright = xcenter + dx + 1;
19093 double area = xwidth * ywidth;
19094 int npix = (2*dx + 1) * dy;
19096 float *data = cpl_image_get_data_float(image);
19098 double error = 0.0;
19103 if (cpl_table_has_column(slits,
"ywidth")) {
19104 area = cpl_table_get(slits,
"xwidth", slit, NULL)
19105 * cpl_table_get(slits,
"ywidth", slit, NULL);
19135 count = (xright - xleft) * (ytop - ybottom);
19138 return CPL_ERROR_ACCESS_OUT_OF_RANGE;
19142 for (y = ybottom; y < ytop; y++) {
19143 for (x = xleft; x < xright; x++) {
19144 double value = data[x + y * nx];
19145 if (value < satur) {
19153 return CPL_ERROR_DIVISION_BY_ZERO;
19155 error = sqrt(flux/gain);
19161 flux *= (float)npix / count;
19162 error *= (float)npix / count;
19170 return CPL_ERROR_NONE;
19197 double xwidth,
double ywidth,
19198 double lambda,
double startwave,
19199 double dispersion,
int dx,
double gain,
19200 double *o_flux,
double *o_err)
19202 int nx = cpl_image_get_size_x(image);
19203 int ny = cpl_image_get_size_y(image);
19205 int dy = (int)cpl_table_get(slits,
"length", slit, NULL);
19206 int ybottom = (int)cpl_table_get(slits,
"position", slit, NULL);
19207 int ytop = ybottom + dy;
19208 int xcenter = (int)floor((lambda - startwave) / dispersion + 0.5);
19209 int xleft = xcenter - dx;
19210 int xright = xcenter + dx + 1;
19211 double area = xwidth * ywidth;
19212 int npix = (2*dx + 1) * dy;
19214 float *data = cpl_image_get_data_float(image);
19216 double error = 0.0;
19221 if (cpl_table_has_column(slits,
"ywidth")) {
19222 area = cpl_table_get(slits,
"xwidth", slit, NULL)
19223 * cpl_table_get(slits,
"ywidth", slit, NULL);
19253 count = (xright - xleft) * (ytop - ybottom);
19256 return CPL_ERROR_ACCESS_OUT_OF_RANGE;
19260 for (y = ybottom; y < ytop; y++) {
19261 for (x = xleft; x < xright; x++) {
19262 double value = data[x + y * nx];
19263 if (value < satur) {
19271 return CPL_ERROR_DIVISION_BY_ZERO;
19273 error = sqrt(flux/gain);
19279 flux *= (float)npix / count;
19280 error *= (float)npix / count;
19288 return CPL_ERROR_NONE;
19307 char *label,
double *mvalue)
19309 int position = cpl_table_get_int(slits,
"position", slit, NULL);
19310 int length = cpl_table_get_int(slits,
"length", slit, NULL);
19311 cpl_table *tmp = cpl_table_extract(table, position, length);
19313 *mvalue = cpl_table_get_column_median(tmp, label);
19314 cpl_table_delete(tmp);
19316 if (cpl_error_get_code() != CPL_ERROR_NONE)
19336 cpl_mask *kernel = cpl_mask_new(nx, ny);
19337 cpl_image *filtered = cpl_image_new(cpl_image_get_size_x(image),
19338 cpl_image_get_size_y(image),
19339 cpl_image_get_type(image));
19341 cpl_mask_not(kernel);
19342 cpl_image_filter_mask(filtered, image, kernel,
19343 CPL_FILTER_MEDIAN, CPL_BORDER_FILTER);
19344 cpl_mask_delete(kernel);
19349 int fors_mos_is_lss_like(cpl_table *maskslits,
int nslits_out_det)
19351 int treat_as_lss = 1;
19352 double mxpos = cpl_table_get_column_median(maskslits,
"xtop");
19353 double * slit_xpos = cpl_table_get_data_double(maskslits,
"xtop");
19354 cpl_size nslits = cpl_table_get_nrow(maskslits);
19358 if(nslits_out_det != 0)
19361 for (cpl_size i = 0; i < nslits; i++) {
19362 if (fabs(mxpos-slit_xpos[i]) > 0.01) {
19367 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_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_polynomial * mos_poly_wav2pix(cpl_bivector *pixwav, int order, double reject, int minlines, int *nlines, double *err, cpl_bivector **pixwav_used)
Fit polynomial relation from wavelengths to pixels.
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.