742 cpl_bivector ** spectra,
743 cpl_bivector ** spectra_err,
744 cpl_polynomial ** wavesol_init,
745 cpl_array ** wavesol_init_err,
753 cpl_array ** wavelength_error,
754 cpl_table ** line_diagnostics)
756 const cpl_vector * in;
758 cpl_vector * peaks_new;
762 cpl_polynomial * poly;
767 cpl_vector ** heights;
768 cpl_vector ** sigmas;
769 cpl_vector ** fit_errors;
770 cpl_vector ** fpe_xobs;
771 cpl_vector ** fpe_wobs;
772 cpl_vector ** fpe_freq;
773 cpl_vector ** fpe_mord;
774 cpl_vector ** fpe_cord;
775 cpl_polynomial * result;
779 cpl_vector * tmp_vec;
781 cpl_size degree_2d[2];
782 cpl_size i, j, k, deg, npeaks, npeaks_total, npoints, setting_deg;
783 double wave, gap, tmp;
786 cpl_table * lines_diagnostics_loc;
791 if (spectra==NULL || spectra_err==NULL || wavesol_init==NULL ||
794 for (i=0 ; i<ninputs ; i++) {
795 if (spectra[i]==NULL || spectra_err[i]==NULL || wavesol_init[i]==NULL)
798 *wavelength_error = NULL;
802 tmp = cpl_polynomial_get_coeff(wavesol_init[0], °);
803 switch ((
int)(tmp/100))
808 gap = CR2RES_ETALON_GAP_Y;
809 setting_deg = CR2RES_ETALON_DEGREE_Y;
814 gap = CR2RES_ETALON_GAP_J;
815 setting_deg = CR2RES_ETALON_DEGREE_J;
820 gap = CR2RES_ETALON_GAP_H;
821 setting_deg = CR2RES_ETALON_DEGREE_H;
826 gap = CR2RES_ETALON_GAP_K;
827 setting_deg = CR2RES_ETALON_DEGREE_K;
836 fpe_xobs = cpl_malloc(ninputs *
sizeof(cpl_vector *));
837 fpe_wobs = cpl_malloc(ninputs *
sizeof(cpl_vector *));
838 fpe_freq = cpl_malloc(ninputs *
sizeof(cpl_vector *));
839 fpe_mord = cpl_malloc(ninputs *
sizeof(cpl_vector *));
840 fpe_cord = cpl_malloc(ninputs *
sizeof(cpl_vector *));
842 heights = cpl_malloc(ninputs *
sizeof(cpl_vector *));
843 sigmas = cpl_malloc(ninputs *
sizeof(cpl_vector *));
844 fit_errors = cpl_malloc(ninputs *
sizeof(cpl_vector *));
849 for (i = 0; i < ninputs; i++){
850 if (spectra[i] == NULL){
859 fit_errors[i] = NULL;
863 in = cpl_bivector_get_y_const(spectra[i]);
873 fit_errors[i] = NULL;
878 if ((peaks_new = cr2res_etalon_get_peaks_gaussian(spectra[i], spectra_err[i],
879 wavesol_init[i], wavesol_init_err[i], peaks, display,
880 &sigmas[i], &heights[i], &fit_errors[i])) == NULL){
881 cpl_vector_delete(peaks);
889 fit_errors[i] = NULL;
892 cpl_vector_delete(peaks);
893 npeaks = cpl_vector_get_size(peaks_new);
894 npeaks_total += npeaks;
922 freq = cpl_vector_new(npeaks);
923 wcen = cpl_vector_new(npeaks);
924 for ( j = 0; j < npeaks; j++)
926 wave = cpl_polynomial_eval_1d(wavesol_init[i],
927 cpl_vector_get(peaks_new, j), NULL);
928 cpl_vector_set(freq, j, SPEED_OF_LIGHT / wave);
929 cpl_vector_set(wcen, j, wave);
933 tmp_vec = cpl_vector_new(npeaks - 1);
934 for ( j = 0; j < npeaks - 1; j++)
936 cpl_vector_set(tmp_vec, j,
937 cpl_vector_get(freq, j + 1)
938 - cpl_vector_get(freq, j));
940 fr = fabs(cpl_vector_get_median(tmp_vec));
941 cpl_vector_delete(tmp_vec);
944 tmp_vec = cpl_vector_new(npeaks);
945 for (j = 0; j < npeaks; j++)
947 cpl_vector_set(tmp_vec, j,
948 modulo(cpl_vector_get(freq, j), fr));
950 f0 = cpl_vector_get_median(tmp_vec);
951 cpl_vector_delete(tmp_vec);
955 px = cpl_matrix_new(1, npeaks);
956 for (j = 0; j < npeaks; j++)
958 m = (cpl_vector_get(freq, j) - f0) / fr;
959 cpl_matrix_set(px, 0, j, round(m));
963 poly = cpl_polynomial_new(1);
964 cpl_polynomial_fit(poly, px, NULL, freq, NULL, CPL_FALSE, NULL, °);
966 for ( j = 0; j < npeaks; j++)
968 m = cpl_matrix_get(px, 0, j);
970 wave = cpl_polynomial_eval_1d(poly, m, NULL);
971 cpl_vector_set(freq, j, wave);
972 cpl_vector_set(wcen, j, SPEED_OF_LIGHT / wave);
978 cpl_polynomial_delete(poly);
980 mpos = cpl_vector_new(npeaks);
981 for ( j = 0; j < npeaks; j++)
985 m = cpl_matrix_get(px, 0, j);
986 cpl_vector_set(mpos, j, round(m));
992 cpl_matrix_delete(px);
995 tmp_vec = cpl_vector_new(npeaks);
996 for (j = 1; j < npeaks; j++){
997 m = cpl_vector_get(wcen, j-1)/
998 fabs(cpl_vector_get(wcen, j) - cpl_vector_get(wcen, j-1));
999 cpl_vector_set(tmp_vec, j, m - cpl_vector_get(mpos, j));
1001 offset = cpl_vector_get_median(tmp_vec);
1002 cpl_vector_add_scalar(mpos, round(offset));
1003 cpl_vector_delete(tmp_vec);
1006 fpe_xobs[i] = peaks_new;
1011 fpe_cord[i] = cpl_vector_new(npeaks);
1012 cpl_vector_fill(fpe_cord[i], orders[i] + zp_order);
1015 if (npeaks_total == 0){
1016 cpl_msg_error(__func__,
"No peaks found for Etalon wavecal");
1017 for (i = 0; i < ninputs; i++)
1019 if (fpe_mord[i] == NULL)
continue;
1020 cpl_vector_delete(fpe_xobs[i]);
1021 cpl_vector_delete(fpe_wobs[i]);
1022 cpl_vector_delete(fpe_freq[i]);
1023 cpl_vector_delete(fpe_mord[i]);
1024 cpl_vector_delete(fpe_cord[i]);
1025 cpl_vector_delete(heights[i]);
1026 cpl_vector_delete(sigmas[i]);
1027 cpl_vector_delete(fit_errors[i]);
1036 cpl_free(fit_errors);
1040 if (cpl_msg_get_level() == CPL_MSG_DEBUG){
1041 path = cpl_sprintf(
"debug_etalon_mord.fits");
1042 cpl_vector_save(fpe_mord[0], path, CPL_TYPE_DOUBLE, NULL, CPL_IO_CREATE);
1043 for (i = 1; i < ninputs; i++)
1045 cpl_vector_save(fpe_mord[i], path, CPL_TYPE_DOUBLE, NULL, CPL_IO_EXTEND);
1048 path = cpl_sprintf(
"debug_etalon_wobs.fits");
1049 cpl_vector_save(fpe_wobs[0], path, CPL_TYPE_DOUBLE, NULL, CPL_IO_CREATE);
1050 for (i = 1; i < ninputs; i++)
1052 cpl_vector_save(fpe_wobs[i], path, CPL_TYPE_DOUBLE, NULL, CPL_IO_EXTEND);
1065 cpl_vector * fpe_gap;
1067 fpe_gap = cpl_vector_new(npeaks_total);
1068 for (i = 0; i < ninputs; i++)
1070 if (fpe_mord[i] == NULL)
continue;
1071 for (j = 0; j < cpl_vector_get_size(fpe_mord[i]); j++)
1073 cpl_vector_set(fpe_gap, k,
1074 cpl_vector_get(fpe_mord[i], j)
1075 * cpl_vector_get(fpe_wobs[i], j));
1079 gap = cpl_vector_get_median(fpe_gap);
1080 cpl_vector_delete(fpe_gap);
1081 cpl_msg_debug(__func__,
"Median gap is: %g", gap);
1085 corr = cpl_vector_new(ninputs);
1086 for (i = 0; i < ninputs; i++)
1088 if (fpe_mord[i] == NULL)
continue;
1089 tmp_vec = cpl_vector_new(cpl_vector_get_size(fpe_mord[i]));
1090 for (j = 0; j < cpl_vector_get_size(fpe_mord[i]); j++)
1092 m = cpl_vector_get(fpe_mord[i], j);
1093 wave = cpl_vector_get(fpe_wobs[i], j);
1094 tmp = gap / wave - m;
1095 cpl_vector_set(tmp_vec, j, tmp);
1097 cpl_vector_set(corr, i, round(cpl_vector_get_median(tmp_vec)));
1098 cpl_vector_delete(tmp_vec);
1100 cpl_vector_add_scalar(fpe_mord[i], cpl_vector_get(corr, i));
1102 cpl_vector_delete(corr);
1107 pad = min(2, ninputs-2);
1108 for (i = pad; i < ninputs - pad; i++)
1110 if (fpe_mord[i] == NULL)
continue;
1111 npoints += cpl_vector_get_size(fpe_mord[i]);
1114 py = cpl_vector_new(npoints);
1115 px = cpl_matrix_new(1, npoints);
1117 for (i = pad; i < ninputs - pad; i++)
1119 if (fpe_mord[i] == NULL)
continue;
1120 for (j = 0; j < cpl_vector_get_size(fpe_mord[i]); j++)
1122 wave = cpl_vector_get(fpe_wobs[i], j);
1123 m = cpl_vector_get(fpe_mord[i], j);
1124 cpl_matrix_set(px, 0, k, m);
1125 cpl_vector_set(py, k, m * wave);
1129 poly = cpl_polynomial_new(1);
1131 cpl_polynomial_fit(poly, px, NULL, py, NULL, CPL_FALSE, NULL, °);
1132 cpl_matrix_delete(px);
1133 cpl_vector_delete(py);
1136 corr = cpl_vector_new(ninputs);
1137 for (i = 0; i < ninputs; i++)
1139 if (fpe_mord[i] == NULL)
continue;
1140 npeaks = cpl_vector_get_size(fpe_mord[i]);
1141 tmp_vec = cpl_vector_new(npeaks);
1142 for (j = 0; j < npeaks; j++)
1144 m = cpl_vector_get(fpe_mord[i], j);
1145 wave = cpl_vector_get(fpe_wobs[i], j);
1146 gap = cpl_polynomial_eval_1d(poly, m, NULL);
1147 tmp = gap / wave - m;
1148 cpl_vector_set(tmp_vec, j, tmp);
1150 cpl_vector_set(corr, i, round(cpl_vector_get_median(tmp_vec)));
1151 cpl_vector_delete(tmp_vec);
1153 cpl_vector_add_scalar(fpe_mord[i], cpl_vector_get(corr, i));
1155 cpl_vector_delete(corr);
1156 cpl_polynomial_delete(poly);
1162 py = cpl_vector_new(npeaks_total);
1163 px = cpl_matrix_new(1, npeaks_total);
1165 for (i = 0; i < ninputs; i++)
1167 if (fpe_mord[i] == NULL)
continue;
1168 for (j = 0; j < cpl_vector_get_size(fpe_mord[i]); j++)
1170 wave = cpl_vector_get(fpe_wobs[i], j);
1171 m = cpl_vector_get(fpe_mord[i], j);
1172 cpl_matrix_set(px, 0, k, m);
1173 cpl_vector_set(py, k, m * wave);
1178 if (setting_deg == 1){
1180 cpl_matrix * px_tmp;
1181 cpl_vector * py_tmp;
1183 double m0, ymax, ymin;
1188 px_tmp = cpl_matrix_duplicate(px);
1189 py_tmp = cpl_vector_duplicate(py);
1191 m0 = cpl_matrix_get_min(px_tmp);
1192 cpl_matrix_subtract_scalar(px_tmp, m0);
1193 ymin = cpl_vector_get_min(py_tmp);
1194 cpl_vector_subtract_scalar(py_tmp, ymin);
1195 ymax = cpl_vector_get_max(py_tmp);
1196 cpl_vector_divide_scalar(py_tmp, ymax);
1197 poly = cr2res_robust_polynomial_fit(px_tmp, py_tmp);
1199 cpl_matrix_delete(px_tmp);
1200 cpl_vector_delete(py_tmp);
1204 for (i = 0; i < ninputs; i++)
1207 if (fpe_mord[i] == NULL)
continue;
1210 for (j = 0; j < cpl_vector_get_size(fpe_mord[i]); j++)
1212 m = cpl_vector_get(fpe_mord[i], j);
1213 wave = cpl_vector_get(fpe_wobs[i], j);
1216 tmp1 /= cpl_vector_get_size(fpe_mord[i]);
1220 for (j = 0; j < cpl_vector_get_size(fpe_mord[i]); j++)
1222 m = cpl_vector_get(fpe_mord[i], j);
1224 tmp2 += cpl_polynomial_eval_1d(poly, m - m0, NULL) * ymax + ymin;
1226 tmp2 /= cpl_vector_get_size(fpe_mord[i]);
1228 cpl_msg_debug(__func__,
1229 "Difference between measured and expected in order %lli: %f",
1230 i, fabs(tmp1 - tmp2));
1232 for (j = 0; j < cpl_vector_get_size(fpe_mord[i]); j++)
1234 wave = cpl_vector_get(fpe_wobs[i], j);
1235 m = cpl_vector_get(fpe_mord[i], j);
1236 wave += (tmp2 - tmp1) / m;
1237 cpl_vector_set(py, k, m * wave);
1238 cpl_vector_set(fpe_wobs[i], j, wave);
1239 cpl_vector_set(fpe_freq[i], j, SPEED_OF_LIGHT / wave);
1243 cpl_polynomial_delete(poly);
1249 poly = cpl_polynomial_new(1);
1250 cpl_polynomial_fit(poly, px, NULL, py, NULL, CPL_FALSE, NULL, °);
1252 cpl_matrix_delete(px);
1253 cpl_vector_delete(py);
1255 for (i = 0; i < ninputs; i++)
1257 if (fpe_mord[i] == NULL)
continue;
1258 for (j = 0; j < cpl_vector_get_size(fpe_mord[i]); j++)
1260 m = cpl_vector_get(fpe_mord[i], j);
1261 wave = cpl_polynomial_eval_1d(poly, m, NULL) / m;
1262 cpl_vector_set(fpe_freq[i], j, SPEED_OF_LIGHT / wave);
1263 cpl_vector_set(fpe_wobs[i], j, wave);
1266 cpl_polynomial_delete(poly);
1270 pxa = cpl_vector_new(npeaks_total);
1271 pxb = cpl_vector_new(npeaks_total);
1272 py = cpl_vector_new(npeaks_total);
1274 for (i = 0; i < ninputs; i++)
1276 if (fpe_mord[i] == NULL)
continue;
1277 npeaks = cpl_vector_get_size(fpe_mord[i]);
1278 for (j = 0; j < npeaks; j++){
1279 cpl_vector_set(pxa, k, cpl_vector_get(fpe_xobs[i], j));
1280 cpl_vector_set(pxb, k, orders[i] + zp_order);
1281 cpl_vector_set(py, k, cpl_vector_get(fpe_wobs[i], j));
1286 degree_2d[0] = degree_x ;
1287 degree_2d[1] = degree_y ;
1288 result = cr2res_polyfit_2d(pxa, pxb, py, degree_2d);
1291 if (result == NULL){
1292 cpl_msg_error(__func__,
"Error in Etalon polynomial fit");
1294 cpl_vector_delete(pxa);
1295 cpl_vector_delete(pxb);
1296 cpl_vector_delete(py);
1297 for (i = 0; i < ninputs; i++)
1299 if (fpe_mord[i] == NULL)
continue;
1300 cpl_vector_delete(fpe_xobs[i]);
1301 cpl_vector_delete(fpe_wobs[i]);
1302 cpl_vector_delete(fpe_freq[i]);
1303 cpl_vector_delete(fpe_mord[i]);
1304 cpl_vector_delete(fpe_cord[i]);
1305 cpl_vector_delete(heights[i]);
1306 cpl_vector_delete(sigmas[i]);
1307 cpl_vector_delete(fit_errors[i]);
1316 cpl_free(fit_errors);
1320 if (cpl_msg_get_level() == CPL_MSG_DEBUG){
1321 cpl_table * tmp_table;
1322 path = cpl_sprintf(
"debug_etalon_final_mord.fits");
1323 cpl_vector_save(fpe_mord[0], path, CPL_TYPE_DOUBLE, NULL, CPL_IO_CREATE);
1324 for (i = 1; i < ninputs; i++)
1326 cpl_vector_save(fpe_mord[i], path, CPL_TYPE_DOUBLE, NULL, CPL_IO_EXTEND);
1329 path = cpl_sprintf(
"debug_etalon_final_wobs.fits");
1330 cpl_vector_save(fpe_wobs[0], path, CPL_TYPE_DOUBLE, NULL, CPL_IO_CREATE);
1331 for (i = 1; i < ninputs; i++)
1333 cpl_vector_save(fpe_wobs[i], path, CPL_TYPE_DOUBLE, NULL, CPL_IO_EXTEND);
1336 path = cpl_sprintf(
"debug_etalon_final_xobs.fits");
1337 cpl_vector_save(fpe_xobs[0], path, CPL_TYPE_DOUBLE, NULL, CPL_IO_CREATE);
1338 for (i = 1; i < ninputs; i++)
1340 cpl_vector_save(fpe_xobs[i], path, CPL_TYPE_DOUBLE, NULL, CPL_IO_EXTEND);
1343 path = cpl_sprintf(
"debug_etalon_final_cord.fits");
1344 cpl_vector_save(fpe_cord[0], path, CPL_TYPE_DOUBLE, NULL, CPL_IO_CREATE);
1345 for (i = 1; i < ninputs; i++)
1347 cpl_vector_save(fpe_cord[i], path, CPL_TYPE_DOUBLE, NULL, CPL_IO_EXTEND);
1351 tmp_table = cpl_table_new((degree_x + 1) * (degree_y + 1));
1352 cpl_table_new_column(tmp_table,
"DEGREE_X", CPL_TYPE_INT);
1353 cpl_table_new_column(tmp_table,
"DEGREE_Y", CPL_TYPE_INT);
1354 cpl_table_new_column(tmp_table,
"COEFFICIENT", CPL_TYPE_DOUBLE);
1356 for (i = 0; i <= degree_x; i++)
1358 for (j = 0; j <= degree_y; j++)
1362 tmp = cpl_polynomial_get_coeff(result, °ree_2d[0]);
1363 cpl_table_set_int(tmp_table,
"DEGREE_X", k, i);
1364 cpl_table_set_int(tmp_table,
"DEGREE_Y", k, j);
1365 cpl_table_set_double(tmp_table,
"COEFFICIENT", k, tmp);
1369 path = cpl_sprintf(
"debug_etalon_final_poly.fits");
1370 cpl_table_save(tmp_table, NULL, NULL, path, CPL_IO_CREATE);
1371 cpl_table_delete(tmp_table);
1376 if (line_diagnostics != NULL) {
1377 *line_diagnostics = NULL;
1378 cpl_msg_debug(__func__,
"Number of lines: %"CPL_SIZE_FORMAT, npeaks_total);
1379 for (i = 0; i < ninputs; i++)
1381 cpl_polynomial * wavesol_loc;
1382 if (fpe_mord[i] == NULL)
continue;
1383 npeaks = cpl_vector_get_size(fpe_mord[i]);
1385 lines_diagnostics_loc =
1388 orders[i] + zp_order);
1390 for (j=0 ; j < npeaks ; j++) {
1391 double pix_pos, lambda_cat, lambda_meas, line_width, line_intens, fit_error;
1392 pix_pos = cpl_vector_get(fpe_xobs[i], j);
1393 lambda_cat = cpl_vector_get(fpe_wobs[i], j) ;
1394 lambda_meas = cpl_polynomial_eval_1d(wavesol_loc, pix_pos,
1396 line_width = cpl_vector_get(sigmas[i], j) ;
1397 line_intens = cpl_vector_get(heights[i], j) ;
1398 fit_error = cpl_vector_get(fit_errors[i], j) ;
1399 m = cpl_vector_get(fpe_mord[i], j);
1400 cpl_table_set_int(lines_diagnostics_loc,
1401 CR2RES_COL_ORDER, j, orders[i]) ;
1402 cpl_table_set_int(lines_diagnostics_loc,
1403 CR2RES_COL_TRACENB, j, traces_nb[i]) ;
1404 cpl_table_set_double(lines_diagnostics_loc,
1405 CR2RES_COL_MEASURED_LAMBDA, j, lambda_meas) ;
1406 cpl_table_set_double(lines_diagnostics_loc,
1407 CR2RES_COL_CATALOG_LAMBDA, j, lambda_cat);
1408 cpl_table_set_double(lines_diagnostics_loc,
1409 CR2RES_COL_DELTA_LAMBDA, j, lambda_cat-lambda_meas);
1410 cpl_table_set_double(lines_diagnostics_loc,
1411 CR2RES_COL_MEASURED_PIXEL, j, pix_pos);
1412 cpl_table_set_double(lines_diagnostics_loc,
1413 CR2RES_COL_LINE_WIDTH, j, line_width) ;
1414 cpl_table_set_double(lines_diagnostics_loc,
1415 CR2RES_COL_FIT_QUALITY, j, fit_error) ;
1416 cpl_table_set_double(lines_diagnostics_loc,
1417 CR2RES_COL_INTENSITY, j, line_intens) ;
1418 cpl_table_set_double(lines_diagnostics_loc,
1419 CR2RES_COL_FPET_M, j, m) ;
1421 cpl_polynomial_delete(wavesol_loc);
1423 if (*line_diagnostics == NULL) {
1424 *line_diagnostics = lines_diagnostics_loc ;
1425 lines_diagnostics_loc = NULL ;
1426 }
else if (lines_diagnostics_loc != NULL) {
1428 cpl_table_insert(*line_diagnostics, lines_diagnostics_loc,
1429 cpl_table_get_nrow(*line_diagnostics)) ;
1430 cpl_table_delete(lines_diagnostics_loc) ;
1434 cpl_msg_debug(__func__,
"%s",cpl_error_get_where());
1435 npeaks = cpl_vector_get_size(py);
1439 diff = cpl_vector_new(npeaks);
1440 pos = cpl_vector_new(2);
1441 for (i = 0; i < npeaks; i++){
1442 cpl_vector_set(pos, 0, cpl_vector_get(pxa, i));
1443 cpl_vector_set(pos, 1, cpl_vector_get(pxb, i));
1444 cpl_vector_set(diff, i, fabs(
1445 cpl_polynomial_eval(result, pos)
1446 - cpl_vector_get(py, i)));
1449 if (*wavelength_error == NULL)
1450 *wavelength_error = cpl_array_new(2, CPL_TYPE_DOUBLE);
1451 cpl_array_set_double(*wavelength_error, 0,
1452 cpl_vector_get_mean(diff));
1453 cpl_array_set_double(*wavelength_error, 1,
1454 cpl_vector_get_max(diff));
1456 cpl_vector_delete(diff);
1457 cpl_vector_delete(pos);
1459 cpl_vector_delete(pxa);
1460 cpl_vector_delete(pxb);
1461 cpl_vector_delete(py);
1463 for (i = 0; i < ninputs; i++)
1465 if (fpe_mord[i] == NULL)
continue;
1466 cpl_vector_delete(fpe_xobs[i]);
1467 cpl_vector_delete(fpe_wobs[i]);
1468 cpl_vector_delete(fpe_freq[i]);
1469 cpl_vector_delete(fpe_mord[i]);
1470 cpl_vector_delete(fpe_cord[i]);
1471 cpl_vector_delete(heights[i]);
1472 cpl_vector_delete(sigmas[i]);
1473 cpl_vector_delete(fit_errors[i]);
1482 cpl_free(fit_errors);