00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028 #ifdef HAVE_CONFIG_H
00029 #include <config.h>
00030 #endif
00031
00032 #include <stdio.h>
00033 #include <stdlib.h>
00034 #include <string.h>
00035 #include <unistd.h>
00036 #include <math.h>
00037 #include <time.h>
00038
00039 #include <moses.h>
00040
00041
00042
00043
00044
00045
00046 float cpl_tools_get_median_float(float *, int);
00047
00048 #define MAX_COLNAME (80)
00049
00050 static double default_lines_hi[] = {
00051 5577.338,
00052 5889.953,
00053 5895.923,
00054 5915.301,
00055 5932.862,
00056 5953.420,
00057 6257.961,
00058 6287.434,
00059 6300.304,
00060 6306.869,
00061 6363.780,
00062 6498.729,
00063 6533.044,
00064 6553.617,
00065 6841.945,
00066 6863.955,
00067 6870.994,
00068 6889.288,
00069 6900.833,
00070 6912.623,
00071 6923.220,
00072 6939.521,
00073 6969.930,
00074 7003.858,
00075 7244.907,
00076 7276.405,
00077 7284.439,
00078 7316.282,
00079 7329.148,
00080 7340.885,
00081 7358.659,
00082 7571.746,
00083 7750.640,
00084 7759.996,
00085 7794.112,
00086 7808.467,
00087 7821.503,
00088 7841.266,
00089 7913.708,
00090 7949.204,
00091 7964.650,
00092 7993.332,
00093 8014.059,
00094 8310.719,
00095 8344.602,
00096 8382.392,
00097 8399.170,
00098 8415.231,
00099 8430.174,
00100 8452.250,
00101 8493.389,
00102 8791.186,
00103 8827.096,
00104 8885.850,
00105 8903.114,
00106 8943.395,
00107 8988.366
00108 };
00109
00110 static double default_lines_lo[] = {
00111 5577.338,
00112 6300.304,
00113 6863.955,
00114 7571.746,
00115 7964.650,
00116 7993.332
00117 };
00118
00119
00129
00130
00131
00132
00133
00134
00135
00136
00137
00138
00139
00140
00141
00142
00143
00144
00145
00146
00147
00148
00149
00150
00151
00152
00153
00154
00155
00156
00157
00158
00159
00160
00161
00162
00163
00164
00165
00166
00167
00168
00169
00170
00171
00172
00173
00174
00175
00176
00177
00178
00179
00180
00181
00182
00183
00184
00185
00186
00187
00188
00189 static void mos_seed(void)
00190 {
00191 srand((unsigned int)time((time_t *)0));
00192 }
00193
00194 static double mos_randg(int seme)
00195 {
00196 static int doit = 1;
00197 static int gotit = 1;
00198 double x1, x2, w, y1;
00199 static double y2;
00200
00201 if (gotit && seme) {
00202 mos_seed();
00203 gotit = 0;
00204 }
00205
00206 if (doit) {
00207 doit = 0;
00208 do {
00209 x1 = 2.0 * (double)rand() / RAND_MAX - 1.0;
00210 x2 = 2.0 * (double)rand() / RAND_MAX - 1.0;
00211 w = x1 * x1 + x2 * x2;
00212 } while (w >= 1.0 || w == 0.0);
00213
00214 w = sqrt( (-2.0 * log(w)) / w);
00215
00216 y1 = x1 * w;
00217 y2 = x2 * w;
00218 return y1;
00219 }
00220
00221 doit = 1;
00222 return y2;
00223 }
00224
00225
00226
00227
00228
00229
00230
00231
00232
00233 static cpl_image *mos_image_vertical_median_filter(cpl_image *ima_in,
00234 int filtsizey, int refrow,
00235 int above, int below, int step)
00236 {
00237
00238 const char *func = "mos_image_general_median_filter";
00239
00240 cpl_image *filt_img = NULL;
00241 int col, row;
00242 float *buf = NULL;
00243 float *data;
00244 float *fdata;
00245 int upright_y, loleft_y;
00246 int j;
00247 int yIsEven = !(filtsizey - (filtsizey/2)*2);
00248 int f2y;
00249 int nx = cpl_image_get_size_x(ima_in);
00250 int ny = cpl_image_get_size_y(ima_in);
00251 int firstRow;
00252
00253
00254 if (yIsEven) filtsizey++;
00255
00256 if (ny <= filtsizey) {
00257 cpl_msg_error(func,
00258 "Median filter size: %d, image size: %d", filtsizey, ny);
00259 return NULL;
00260 }
00261
00262 f2y = filtsizey / 2;
00263
00264 filt_img = cpl_image_duplicate(ima_in);
00265 buf = cpl_malloc(filtsizey * sizeof(float));
00266 data = cpl_image_get_data(ima_in);
00267 fdata = cpl_image_get_data(filt_img);
00268
00269 firstRow = refrow - step * (below / step);
00270 if (firstRow < f2y)
00271 firstRow += step;
00272
00273 for (col = 0; col < nx; col++) {
00274 for (row = firstRow; row < refrow + above; row += step) {
00275 if (row >= ny - f2y)
00276 break;
00277 loleft_y = row - f2y;
00278 upright_y = row + f2y + 1;
00279 for (j = loleft_y; j < upright_y; j++)
00280 buf[j - loleft_y] = data[col + j * nx];
00281
00282 fdata[col + row * nx] = cpl_tools_get_median_float(buf, filtsizey);
00283 }
00284 }
00285
00286 cpl_free(buf);
00287
00288 return filt_img;
00289
00290 }
00291
00292
00293
00294
00295
00296
00297
00298
00299
00300
00301
00302
00303
00304
00305
00306
00307
00308
00309 static int peakPosition(float *data, int size, float *position, int minPoints)
00310 {
00311 int i;
00312 int count = 0;
00313 float *copy;
00314 float max, median, level, pos, variance, uniformVariance;
00315 double sum, weights;
00316
00317
00318 if (data == NULL)
00319 return 1;
00320
00321 if (size < 5)
00322 return 1;
00323
00324
00325
00326
00327
00328
00329 copy = (float *) cpl_malloc(size*sizeof(float));
00330 for (i = 0; i < size; i++)
00331 copy[i] = data[i];
00332 median = cpl_tools_get_median_float(copy, size);
00333 cpl_free(copy);
00334
00335
00336
00337
00338
00339
00340 max = data[0];
00341 for (i = 1; i < size; i++)
00342 if (data[i] > max)
00343 max = data[i];
00344
00345
00346
00347
00348
00349
00350
00351 if (max-median < 0.00001)
00352 return 1;
00353
00354
00355
00356
00357
00358
00359
00360 level = (max + median) / 2;
00361
00362
00363
00364
00365
00366
00367
00368
00369
00370 count = 0;
00371 for (i = 0, sum = 0., weights = 0.; i < size; i++) {
00372 if (data[i] > level) {
00373 count++;
00374 weights += (data[i] - median);
00375 sum += i * (data[i] - median);
00376 }
00377 }
00378
00379
00380
00381
00382
00383
00384
00385 if (count < minPoints)
00386 return 1;
00387
00388 pos = sum / weights;
00389 for (i = 0, sum = 0., weights = 0.; i < size; i++) {
00390 if (data[i] > level) {
00391 weights++;
00392 sum += (i - pos) * (i - pos);
00393 }
00394 }
00395 variance = sqrt(sum / weights);
00396
00397
00398
00399
00400
00401
00402
00403
00404
00405 uniformVariance = sqrt(size*size/3 - pos*size + pos*pos);
00406
00407 if (variance > 0.8 * uniformVariance)
00408 return 1;
00409
00410 *position = pos + 0.5;
00411
00412 return 0;
00413 }
00414
00415
00416
00417
00418
00419
00420
00421
00422
00423
00424
00425
00426
00427
00428
00429
00430
00431
00432
00433
00434
00435
00436
00437
00438
00439
00440
00441
00442
00443
00444
00445
00446
00447
00448
00449
00450
00451
00452
00453
00454
00455
00456
00457
00458
00459
00460
00461
00462 static double values_to_dx(double v1, double v2, double v3)
00463 {
00464
00465 static double epsilon = 0.00000001;
00466 double r = 2.0;
00467
00468
00469 if (v1 > v2 || v3 > v2)
00470 return r;
00471
00472 if (2 * v2 - v1 - v3 < epsilon)
00473 return r;
00474
00475 r = 0.5 * (v3 - v1) / (2 * v2 - v3 - v1);
00476
00477 return r;
00478
00479 }
00480
00481
00482
00483
00484
00485
00486
00487 static float *min_filter(float *buffer, int length, int size)
00488 {
00489 float *minf = cpl_calloc(length, sizeof(float));
00490 float min;
00491 int start = size / 2;
00492 int end = length - size / 2;
00493 int i, j;
00494
00495
00496 for (i = start; i < end; i++) {
00497 min = buffer[i-start];
00498 for (j = i - start + 1; j <= i + start; j++)
00499 if (min > buffer[j])
00500 min = buffer[j];
00501 minf[i] = min;
00502 }
00503
00504 for (i = 0; i < start; i++)
00505 minf[i] = minf[start];
00506
00507 for (i = end; i < length; i++)
00508 minf[i] = minf[end-1];
00509
00510 return minf;
00511 }
00512
00513
00514
00515
00516
00517
00518
00519 static float *max_filter(float *buffer, int length, int size)
00520 {
00521 float *maxf = cpl_calloc(length, sizeof(float));
00522 float max;
00523 int start = size / 2;
00524 int end = length - size / 2;
00525 int i, j;
00526
00527
00528 for (i = start; i < end; i++) {
00529 max = buffer[i-start];
00530 for (j = i - start + 1; j <= i + start; j++)
00531 if (max < buffer[j])
00532 max = buffer[j];
00533 maxf[i] = max;
00534 }
00535
00536 for (i = 0; i < start; i++)
00537 maxf[i] = maxf[start];
00538
00539 for (i = end; i < length; i++)
00540 maxf[i] = maxf[end-1];
00541
00542 return maxf;
00543 }
00544
00545
00546
00547
00548
00549
00550
00551 static float *smo_filter(float *buffer, int length, int size)
00552 {
00553 float *smof = cpl_calloc(length, sizeof(float));
00554 double sum;
00555 int start = size / 2;
00556 int end = length - size / 2;
00557 int i, j;
00558
00559
00560 for (i = start; i < end; i++) {
00561 sum = 0.0;
00562 for (j = i - start; j <= i + start; j++)
00563 sum += buffer[j];
00564 smof[i] = sum / size;
00565 }
00566
00567 for (i = 0; i < start; i++)
00568 smof[i] = smof[start];
00569
00570 for (i = end; i < length; i++)
00571 smof[i] = smof[end-1];
00572
00573 return smof;
00574 }
00575
00576
00577
00578
00579
00580
00581
00582
00583
00584
00585
00586
00587
00588
00589
00590
00591
00592
00593
00594
00595 static cpl_polynomial *read_global_distortion(cpl_table *global, int row)
00596 {
00597 cpl_polynomial *poly = NULL;
00598 int p[2];
00599 int degree = 2;
00600 int null;
00601 double coeff;
00602
00603 char name[MAX_COLNAME];
00604
00605
00606 for (p[0] = 0; p[0] <= degree; p[0]++) {
00607 for (p[1] = 0; p[1] <= degree - p[0]; p[1]++) {
00608 snprintf(name, MAX_COLNAME, "a%d%d", p[0], p[1]);
00609 coeff = cpl_table_get_double(global, name, row, &null);
00610 if (null)
00611 continue;
00612 if (poly == NULL)
00613 poly = cpl_polynomial_new(2);
00614 cpl_polynomial_set_coeff(poly, p, coeff);
00615 }
00616 }
00617
00618 return poly;
00619 }
00620
00621 static cpl_table *write_global_distortion(cpl_table *global, int row,
00622 cpl_polynomial *poly)
00623 {
00624 cpl_table *table;
00625 int p[2];
00626 int degree = 2;
00627 int nrow = 10;
00628
00629 char name[MAX_COLNAME];
00630
00631
00632 if (global) {
00633 table = global;
00634 }
00635 else {
00636 table = cpl_table_new(nrow);
00637 for (p[0] = 0; p[0] <= degree; p[0]++) {
00638 for (p[1] = 0; p[1] <= degree - p[0]; p[1]++) {
00639 snprintf(name, MAX_COLNAME, "a%d%d", p[0], p[1]);
00640 cpl_table_new_column(table, name, CPL_TYPE_DOUBLE);
00641 }
00642 }
00643 }
00644
00645 if (poly) {
00646 for (p[0] = 0; p[0] <= degree; p[0]++) {
00647 for (p[1] = 0; p[1] <= degree - p[0]; p[1]++) {
00648 snprintf(name, MAX_COLNAME, "a%d%d", p[0], p[1]);
00649 cpl_table_set_double(table, name, row,
00650 cpl_polynomial_get_coeff(poly, p));
00651 }
00652 }
00653 }
00654
00655 return table;
00656 }
00657
00658
00659
00660
00661
00662
00663
00664
00665
00666
00667
00668 #define SEGNO(a,b) ((b) >= 0.0 ? fabs(a) : -fabs(a))
00669 static int robustLinearFit(cpl_bivector *list, double *a, double *b,
00670 double *abdev)
00671 {
00672 cpl_vector *vx;
00673 cpl_vector *vy;
00674 cpl_vector *va;
00675
00676 double aa, bb, bcomp, b1, b2, del, abdevt, f, f1, f2, sigb, temp, d, sum;
00677 double sx, sy, sxy, sxx, chisq;
00678 double *arr;
00679 double aa_ls, bb_ls;
00680 double *x;
00681 double *y;
00682 int np;
00683 int iter;
00684 int max_iterate = 30;
00685 int i;
00686
00687
00688 np = cpl_bivector_get_size(list);
00689 vx = cpl_bivector_get_x(list);
00690 vy = cpl_bivector_get_y(list);
00691 x = cpl_vector_get_data(vx);
00692 y = cpl_vector_get_data(vy);
00693
00694 sx = sy = sxx = sxy = 0.00;
00695 for (i = 0; i < np; i++) {
00696 sx += x[i];
00697 sy += y[i];
00698 sxy += x[i] * y[i];
00699 sxx += x[i] * x[i];
00700 }
00701
00702 del = np * sxx - sx * sx;
00703 aa_ls = aa = (sxx * sy - sx * sxy) / del;
00704 bb_ls = bb = (np * sxy - sx * sy) / del;
00705
00706 chisq = 0.00;
00707 for (i = 0; i < np; i++) {
00708 temp = y[i] - (aa+bb*x[i]);
00709 temp *= temp;
00710 chisq += temp;
00711 }
00712
00713 va = cpl_vector_new(np);
00714 arr = cpl_vector_get_data(va);
00715 sigb = sqrt(chisq/del);
00716 b1 = bb;
00717
00718 bcomp = b1;
00719 sum = 0.00;
00720 for (i = 0; i < np; i++) {
00721 arr[i] = y[i] - bcomp * x[i];
00722 }
00723 aa = cpl_vector_get_median_const(va);
00724 abdevt = 0.0;
00725 for (i = 0; i < np; i++) {
00726 d = y[i] - (bcomp * x[i] + aa);
00727 abdevt += fabs(d);
00728 if (y[i] != 0.0)
00729 d /= fabs(y[i]);
00730 if (fabs(d) > 1e-7)
00731 sum += (d >= 0.0 ? x[i] : -x[i]);
00732 }
00733 f1 = sum;
00734
00735 b2 = bb + SEGNO(3.0 * sigb, f1);
00736
00737 bcomp = b2;
00738 sum = 0.00;
00739 for (i = 0; i < np; i++) {
00740 arr[i] = y[i] - bcomp * x[i];
00741 }
00742 aa = cpl_vector_get_median_const(va);
00743 abdevt = 0.0;
00744 for (i = 0; i < np; i++) {
00745 d = y[i] - (bcomp * x[i] + aa);
00746 abdevt += fabs(d);
00747 if (y[i] != 0.0)
00748 d /= fabs(y[i]);
00749 if (fabs(d) > 1e-7)
00750 sum += (d >= 0.0 ? x[i] : -x[i]);
00751 }
00752 f2 = sum;
00753
00754 if (fabs(b2-b1)<1e-7) {
00755 *a = aa;
00756 *b = bb;
00757 *abdev = abdevt / (double)np;
00758 cpl_vector_delete(va);
00759 return 0;
00760 }
00761
00762 iter = 0;
00763 while (f1*f2 > 0.0) {
00764 bb = 2.0*b2-b1;
00765 b1 = b2;
00766 f1 = f2;
00767 b2 = bb;
00768
00769 bcomp = b2;
00770 sum = 0.00;
00771 for (i = 0; i < np; i++) {
00772 arr[i] = y[i] - bcomp * x[i];
00773 }
00774 aa = cpl_vector_get_median_const(va);
00775 abdevt = 0.0;
00776 for (i = 0; i < np; i++) {
00777 d = y[i] - (bcomp * x[i] + aa);
00778 abdevt += fabs(d);
00779 if (y[i] != 0.0)
00780 d /= fabs(y[i]);
00781 if (fabs(d) > 1e-7)
00782 sum += (d >= 0.0 ? x[i] : -x[i]);
00783 }
00784 f2 = sum;
00785 iter++;
00786 if (iter >= max_iterate)
00787 break;
00788 }
00789 if (iter >= max_iterate) {
00790 *a = aa_ls;
00791 *b = bb_ls;
00792 *abdev = -1.0;
00793 cpl_vector_delete(va);
00794 return 1;
00795 }
00796
00797 sigb = 0.01 * sigb;
00798 while (fabs(b2-b1) > sigb) {
00799 bb = 0.5 * (b1 + b2);
00800 if ((fabs(bb-b1) < 1e-7) || (fabs(bb-b2) < 1e-7))
00801 break;
00802 bcomp = bb;
00803 sum = 0.0;
00804 for (i = 0; i < np; i++) {
00805 arr[i] = y[i] - bcomp * x[i];
00806 }
00807 aa = cpl_vector_get_median_const(va);
00808 abdevt = 0.0;
00809 for (i = 0; i < np; i++) {
00810 d = y[i] - (bcomp * x[i] + aa);
00811 abdevt += fabs(d);
00812 if (y[i] != 0.0)
00813 d /= fabs(y[i]);
00814 if (fabs(d) > 1e-7)
00815 sum += (d >= 0.0 ? x[i] : -x[i]);
00816 }
00817 f = sum;
00818
00819 if (f*f1 >= 0.0) {
00820 f1=f;
00821 b1=bb;
00822 }
00823 else {
00824 f2=f;
00825 b2=bb;
00826 }
00827 }
00828 cpl_vector_delete(va);
00829 *a = aa;
00830 *b = bb;
00831 *abdev = abdevt / np;
00832 return 0;
00833 }
00834 #undef SEGNO
00835
00836
00837
00838
00839
00840
00841
00842
00843
00844
00845
00846 cpl_table *mos_hough_table(cpl_table *table, const char *x, const char *y)
00847 {
00848 cpl_table *output;
00849 double *xdata;
00850 double *ydata;
00851 double *xodata;
00852 double *yodata;
00853 int npoints;
00854 int opoints;
00855 int i, j, k;
00856
00857
00858 npoints = cpl_table_get_nrow(table);
00859 opoints = npoints*(npoints-1)/2;
00860
00861 output = cpl_table_new(opoints);
00862 cpl_table_new_column(output, "m", CPL_TYPE_DOUBLE);
00863 cpl_table_new_column(output, "q", CPL_TYPE_DOUBLE);
00864 cpl_table_fill_column_window_double(output, "m", 0, opoints, 0.0);
00865 cpl_table_fill_column_window_double(output, "q", 0, opoints, 0.0);
00866
00867 xodata = cpl_table_get_data_double(output, "m");
00868 yodata = cpl_table_get_data_double(output, "q");
00869
00870 cpl_table_cast_column(table, x, "x", CPL_TYPE_DOUBLE);
00871 cpl_table_cast_column(table, y, "y", CPL_TYPE_DOUBLE);
00872
00873 xdata = cpl_table_get_data_double(table, "x");
00874 ydata = cpl_table_get_data_double(table, "y");
00875
00876 k = 0;
00877 for (i = 0; i < npoints; i++) {
00878 for (j = i+1; j < npoints; j++) {
00879 xodata[k] = (ydata[i]-ydata[j])/(xdata[i]-xdata[j]);
00880 yodata[k] = ydata[i] - xodata[k] * xdata[i];
00881 k++;
00882 }
00883 }
00884
00885 if (k != opoints)
00886 printf("Assert k = %d, expected %d\n", k, opoints);
00887
00888 cpl_table_erase_column(table, "x");
00889 cpl_table_erase_column(table, "y");
00890
00891 return output;
00892 }
00893
00894
00895
00896
00897
00898
00899
00900 static void mos_extraction(cpl_image *sciwin, cpl_image *skywin,
00901 cpl_image *extracted, cpl_image *sky,
00902 cpl_image *error, int nobjects, int extraction,
00903 double ron, double conad, int ncomb)
00904 {
00905
00906 cpl_vector *vprofile;
00907 cpl_matrix *kernel;
00908 cpl_image *smowin;
00909
00910 int i, j;
00911 int specLen;
00912 int numRows;
00913 int index;
00914 int iter;
00915 int maxIter = 2;
00916 int smoothBox = 31;
00917 double nsigma = 5.0;
00918
00919 double sumWeight, sum, sumSky, sumProf, variance, weight;
00920 double *profile;
00921 double *buffer;
00922 float *edata;
00923 float *ekdata;
00924 float *endata;
00925 float *sdata;
00926 float *kdata;
00927 float *fdata;
00928
00929 double value;
00930
00931
00932 specLen = cpl_image_get_size_x(sciwin);
00933 numRows = cpl_image_get_size_y(sciwin);
00934
00935 edata = cpl_image_get_data(extracted);
00936 edata += nobjects * specLen;
00937
00938 ekdata = cpl_image_get_data(sky);
00939 ekdata += nobjects * specLen;
00940
00941 endata = cpl_image_get_data(error);
00942 endata += nobjects * specLen;
00943
00944 sdata = cpl_image_get_data(sciwin);
00945 kdata = cpl_image_get_data(skywin);
00946
00947
00948
00949
00950
00951
00952
00953 if (extraction && numRows > 5) {
00954 kernel = cpl_matrix_new(3, 3);
00955 cpl_matrix_fill(kernel, 1.0);
00956 smowin = cpl_image_filter_median(sciwin, kernel);
00957 cpl_matrix_delete(kernel);
00958 fdata = cpl_image_get_data(smowin);
00959 for (i = 0; i < specLen; i++)
00960 for (j = 0, edata[i] = 0.0; j < numRows; j++)
00961 edata[i] += fdata[i + j * specLen];
00962 cpl_image_delete(smowin);
00963 }
00964 else {
00965 for (i = 0; i < specLen; i++)
00966 for (j = 0, edata[i] = 0.0; j < numRows; j++)
00967 edata[i] += sdata[i + j * specLen];
00968 }
00969
00970 if (extraction) {
00971
00972 profile = cpl_calloc(specLen * numRows, sizeof(double));
00973 buffer = cpl_calloc(specLen, sizeof(double));
00974
00975 for (iter = 0; iter < maxIter; iter++) {
00976
00977
00978
00979
00980
00981 for (i = 0; i < specLen; i++) {
00982 for (j = 0; j < numRows; j++) {
00983 index = i + j * specLen;
00984
00985 if (fabs(edata[i]) > 0.00001)
00986 profile[index] = sdata[index] / edata[i];
00987 else
00988 profile[index] = 0.0;
00989 }
00990 }
00991
00992 for (j = 0; j < numRows; j++) {
00993
00994
00995
00996
00997
00998 for (i = 0; i < specLen - smoothBox; i++) {
00999 vprofile = cpl_vector_wrap(smoothBox, profile + i + j*specLen);
01000 value = cpl_vector_get_median_const(vprofile);
01001 cpl_vector_unwrap(vprofile);
01002 if (value < 0)
01003 value = 0.0;
01004 buffer[i + smoothBox / 2] = value;
01005 }
01006
01007
01008
01009
01010
01011 vprofile = cpl_vector_wrap(smoothBox / 2, profile + j*specLen);
01012 value = cpl_vector_get_mean(vprofile);
01013 cpl_vector_unwrap(vprofile);
01014
01015 if (value < 0)
01016 value = 0.0;
01017
01018 for (i = 0; i < smoothBox / 2; i++)
01019 buffer[i] = value;
01020
01021 vprofile = cpl_vector_wrap(smoothBox / 2,
01022 profile + specLen - smoothBox/2 + j*specLen);
01023 value = cpl_vector_get_mean(vprofile);
01024 cpl_vector_unwrap(vprofile);
01025
01026 if (value < 0)
01027 value = 0.0;
01028
01029 for (i = 0; i < smoothBox / 2; i++)
01030 buffer[i + specLen - smoothBox / 2] = value;
01031
01032 for (i = 0; i < specLen; i++)
01033 profile[i + j * specLen] = buffer[i];
01034
01035 }
01036
01037
01038
01039
01040
01041 for (i = 0; i < specLen; i++) {
01042 for (j = 0, value = 0.0; j < numRows; j++)
01043 value += profile[i + j * specLen];
01044 if (value > 0.00001)
01045 for (j = 0; j < numRows; j++)
01046 profile[i + j * specLen] /= value;
01047 else
01048 for (j = 0; j < numRows; j++)
01049 profile[i + j * specLen] = 0.0;
01050 }
01051
01052
01053
01054
01055
01056
01057 for (i = 0; i < specLen; i++) {
01058 sum = 0.0;
01059 sumSky = 0.0;
01060 sumWeight = 0.0;
01061 sumProf = 0.0;
01062 for (j = 0; j < numRows; j++) {
01063 index = i + j * specLen;
01064
01065
01066
01067 variance = ron*ron + fabs(edata[i] * profile[index] + kdata[index])
01068 / conad;
01069 variance /= ncomb;
01070 value = sdata[index] - edata[i] * profile[index];
01071 if (fabs(value) / sqrt(variance) < nsigma) {
01072 weight = 1000000 * profile[index] / variance;
01073 sum += weight * sdata[index];
01074 sumSky += weight * kdata[index];
01075 sumWeight += weight * profile[index];
01076 sumProf += profile[index];
01077 }
01078
01079
01080
01081 }
01082
01083 if (sumWeight > 0.00001) {
01084 edata[i] = sum / sumWeight;
01085 ekdata[i] = sumSky / sumWeight;
01086 endata[i] = 1000 * sqrt(sumProf / sumWeight);
01087 }
01088 else {
01089
01090
01091
01092
01093
01094 endata[i] = sqrt(ron*ron + fabs(edata[i] + ekdata[i]) / conad);
01095 }
01096 }
01097 }
01098 cpl_free(profile);
01099 cpl_free(buffer);
01100 }
01101 else {
01102
01103
01104
01105
01106
01107
01108 for (i = 0; i < specLen; i++)
01109 for (j = 0, ekdata[i] = 0.0; j < numRows; j++)
01110 ekdata[i] += kdata[i + j * specLen];
01111
01112
01113
01114
01115
01116 for (i = 0; i < specLen; i++)
01117 endata[i] = sqrt(ron*ron + fabs(edata[i] + ekdata[i]) / conad);
01118
01119 }
01120
01121 }
01122
01123
01170 cpl_table *mos_global_distortion(cpl_table *slits, cpl_table *maskslits,
01171 cpl_table *ids, cpl_table *crv,
01172 double reference)
01173 {
01174 const char *func = "mos_global_distortion";
01175
01176 const char *clab[6] = {"c0", "c1", "c2", "c3", "c4", "c5"};
01177
01178 cpl_table *global = NULL;
01179 cpl_table *coeff;
01180 cpl_table *dummy;
01181 cpl_vector *ci;
01182 cpl_vector *xmask;
01183 cpl_vector *ymask;
01184 cpl_bivector *mask;
01185 cpl_vector *xccd;
01186 cpl_vector *yccd;
01187 cpl_bivector *ccd;
01188 cpl_polynomial *poly;
01189 double *xtop;
01190 double *ytop;
01191 double *xbottom;
01192 double *ybottom;
01193 double *mxtop;
01194 double *mytop;
01195 double *mxbottom;
01196 double *mybottom;
01197 int *position;
01198 int *length;
01199 int *slit_id;
01200 int *mslit_id;
01201 int nslits, nmaskslits, npoints;
01202 int order;
01203 int i, j;
01204 int minslit = 6;
01205
01206
01207
01208
01209
01210 if (slits == NULL || maskslits == NULL || ids == NULL || crv == NULL) {
01211 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
01212 return NULL;
01213 }
01214
01215
01216
01217
01218 nslits = cpl_table_get_nrow(slits);
01219
01220
01221
01222
01223 if (nslits < minslit) {
01224 cpl_msg_warning(func, "Too few slits (%d < %d) for global "
01225 "distortion model determination", nslits, minslit);
01226 return NULL;
01227 }
01228
01229
01230
01231
01232 nmaskslits = cpl_table_get_nrow(maskslits);
01233
01234 length = cpl_table_get_data_int(slits, "length");
01235 position = cpl_table_get_data_int(slits, "position");
01236 slit_id = cpl_table_get_data_int(slits, "slit_id");
01237 mslit_id = cpl_table_get_data_int(maskslits, "slit_id");
01238 xtop = cpl_table_get_data_double(slits, "xtop");
01239 ytop = cpl_table_get_data_double(slits, "ytop");
01240 xbottom = cpl_table_get_data_double(slits, "xbottom");
01241 ybottom = cpl_table_get_data_double(slits, "ybottom");
01242 mxtop = cpl_table_get_data_double(maskslits, "xtop");
01243 mytop = cpl_table_get_data_double(maskslits, "ytop");
01244 mxbottom = cpl_table_get_data_double(maskslits, "xbottom");
01245 mybottom = cpl_table_get_data_double(maskslits, "ybottom");
01246
01247
01248
01249
01250
01251
01252 coeff = cpl_table_new(nslits);
01253 cpl_table_copy_structure(coeff, ids);
01254 cpl_table_new_column(coeff, "xccd", CPL_TYPE_DOUBLE);
01255 cpl_table_new_column(coeff, "yccd", CPL_TYPE_DOUBLE);
01256 cpl_table_new_column(coeff, "xmask", CPL_TYPE_DOUBLE);
01257 cpl_table_new_column(coeff, "ymask", CPL_TYPE_DOUBLE);
01258
01259
01260
01261
01262 for (i = 0; i < nslits; i++) {
01263 for (j = 0; j < nmaskslits; j++) {
01264 if (slit_id[i] == mslit_id[j]) {
01265 cpl_table_set_double(coeff, "xmask", i,
01266 (mxtop[j] + mxbottom[j]) / 2);
01267 cpl_table_set_double(coeff, "ymask", i,
01268 (mytop[j] + mybottom[j]) / 2);
01269 }
01270 }
01271 }
01272
01273 if (cpl_table_has_invalid(coeff, "xmask")) {
01274 cpl_error_set(func, CPL_ERROR_INCOMPATIBLE_INPUT);
01275 cpl_table_delete(coeff);
01276 return NULL;
01277 }
01278
01279 for (i = 0; i < nslits; i++) {
01280 cpl_table_set_double(coeff, "xccd", i, (xtop[i] + xbottom[i]) / 2);
01281 cpl_table_set_double(coeff, "yccd", i, (ytop[i] + ybottom[i]) / 2);
01282 }
01283
01284
01285
01286
01287 for (i = 0; i < nslits; i++) {
01288
01289 if (length[i] == 0)
01290 continue;
01291
01292 cpl_table_and_selected_window(ids, position[i], length[i]);
01293 dummy = cpl_table_extract_selected(ids);
01294 for (j = 0; j < 6; j++) {
01295 if (cpl_table_has_column(dummy, clab[j])) {
01296 if (length[i] - cpl_table_count_invalid(dummy, clab[j]) > 10) {
01297 cpl_table_set_double(coeff, clab[j], i,
01298 cpl_table_get_column_median(dummy, clab[j]));
01299 }
01300 }
01301 }
01302
01303 cpl_table_delete(dummy);
01304 cpl_table_select_all(ids);
01305
01306 }
01307
01308
01309
01310
01311 for (j = 0; j < 6; j++) {
01312 if (cpl_table_has_column(coeff, clab[j])) {
01313 cpl_table_and_selected_invalid(coeff, clab[j]);
01314
01315 if (cpl_table_not_selected(coeff))
01316 dummy = cpl_table_extract_selected(coeff);
01317 else
01318 break;
01319
01320 npoints = cpl_table_get_nrow(dummy);
01321
01322 if (npoints >= 6) {
01323
01324 if (npoints >= 12)
01325 order = 2;
01326 else
01327 order = 1;
01328
01329 ci = cpl_vector_wrap(npoints,
01330 cpl_table_get_data_double(dummy, clab[j]));
01331 if (j) {
01332 xccd = cpl_vector_wrap(npoints,
01333 cpl_table_get_data_double(dummy, "xccd"));
01334 yccd = cpl_vector_wrap(npoints,
01335 cpl_table_get_data_double(dummy, "yccd"));
01336 ccd = cpl_bivector_wrap_vectors(xccd, yccd);
01337
01338
01339 poly = cpl_polynomial_fit_2d_create(ccd, ci, order, NULL);
01340
01341 cpl_bivector_unwrap_vectors(ccd);
01342 cpl_vector_unwrap(xccd);
01343 cpl_vector_unwrap(yccd);
01344 cpl_vector_unwrap(ci);
01345 }
01346 else {
01347 xmask = cpl_vector_wrap(npoints,
01348 cpl_table_get_data_double(dummy, "xmask"));
01349 ymask = cpl_vector_wrap(npoints,
01350 cpl_table_get_data_double(dummy, "ymask"));
01351 mask = cpl_bivector_wrap_vectors(xmask, ymask);
01352
01353
01354 poly = cpl_polynomial_fit_2d_create(mask, ci, order, NULL);
01355
01356 cpl_bivector_unwrap_vectors(mask);
01357 cpl_vector_unwrap(xmask);
01358 cpl_vector_unwrap(ymask);
01359 cpl_vector_unwrap(ci);
01360 }
01361 }
01362 else {
01363 int p[2] = {0, 0};
01364 poly = cpl_polynomial_new(2);
01365 cpl_polynomial_set_coeff(poly, p,
01366 cpl_table_get_column_median(dummy, clab[j]));
01367 }
01368
01369 cpl_table_delete(dummy);
01370
01371 global = write_global_distortion(global, j, poly);
01372
01373 cpl_polynomial_delete(poly);
01374
01375 cpl_table_select_all(coeff);
01376 }
01377 }
01378
01379
01380
01381
01382 cpl_table_delete(coeff);
01383
01384
01385
01386
01387
01388
01389
01390
01391
01392 cpl_table_set_double(global, "a00", 6, reference);
01393
01394
01395
01396
01397
01398
01399 coeff = cpl_table_duplicate(crv);
01400 cpl_table_new_column(coeff, "xmask", CPL_TYPE_DOUBLE);
01401 cpl_table_new_column(coeff, "ymask", CPL_TYPE_DOUBLE);
01402 slit_id = cpl_table_get_data_int(coeff, "slit_id");
01403 npoints = cpl_table_get_nrow(coeff);
01404
01405
01406
01407
01408 for (i = 0; i < npoints; i++) {
01409 for (j = 0; j < nmaskslits; j++) {
01410 if (slit_id[i] == mslit_id[j]) {
01411 if (i%2) {
01412 cpl_table_set_double(coeff, "xmask", i, mxbottom[j]);
01413 cpl_table_set_double(coeff, "ymask", i, mybottom[j]);
01414 }
01415 else {
01416 cpl_table_set_double(coeff, "xmask", i, mxtop[j]);
01417 cpl_table_set_double(coeff, "ymask", i, mytop[j]);
01418 }
01419 }
01420 }
01421 }
01422
01423
01424
01425
01426 if (cpl_table_has_invalid(coeff, "xmask")) {
01427 cpl_error_set(func, CPL_ERROR_INCOMPATIBLE_INPUT);
01428 cpl_table_delete(coeff);
01429 return NULL;
01430 }
01431
01432
01433
01434
01435 for (j = 0; j < 3; j++) {
01436 if (cpl_table_has_column(coeff, clab[j])) {
01437 cpl_table_and_selected_invalid(coeff, clab[j]);
01438
01439 if (cpl_table_not_selected(coeff))
01440 dummy = cpl_table_extract_selected(coeff);
01441 else
01442 break;
01443
01444 npoints = cpl_table_get_nrow(dummy);
01445
01446 if (npoints >= 6) {
01447
01448 if (npoints >= 12)
01449 order = 2;
01450 else
01451 order = 1;
01452
01453 ci = cpl_vector_wrap(npoints,
01454 cpl_table_get_data_double(dummy, clab[j]));
01455 xmask = cpl_vector_wrap(npoints,
01456 cpl_table_get_data_double(dummy, "xmask"));
01457 ymask = cpl_vector_wrap(npoints,
01458 cpl_table_get_data_double(dummy, "ymask"));
01459 mask = cpl_bivector_wrap_vectors(xmask, ymask);
01460
01461 poly = cpl_polynomial_fit_2d_create(mask, ci, order, NULL);
01462
01463 cpl_bivector_unwrap_vectors(mask);
01464 cpl_vector_unwrap(ci);
01465 cpl_vector_unwrap(xmask);
01466 cpl_vector_unwrap(ymask);
01467 }
01468 else {
01469 int p[2] = {0, 0};
01470 poly = cpl_polynomial_new(2);
01471 cpl_polynomial_set_coeff(poly, p,
01472 cpl_table_get_column_median(dummy, clab[j]));
01473 }
01474
01475 cpl_table_delete(dummy);
01476
01477 global = write_global_distortion(global, j + 7, poly);
01478
01479 cpl_polynomial_delete(poly);
01480 cpl_table_select_all(coeff);
01481 }
01482 }
01483
01484
01485
01486
01487 cpl_table_delete(coeff);
01488
01489
01490
01491
01492 return global;
01493
01494 }
01495
01496
01534 cpl_table *mos_build_slit_location(cpl_table *global, cpl_table *maskslits,
01535 int ysize)
01536 {
01537 const char *func = "mos_build_slit_location";
01538
01539 cpl_propertylist *sort_col;
01540 cpl_polynomial *ids0;
01541 cpl_polynomial *crv[3];
01542 cpl_polynomial *loc_crv;
01543 cpl_vector *point;
01544 cpl_table *slits;
01545 int nslits;
01546 int *slit_id;
01547 double *dpoint;
01548 double *xtop;
01549 double *ytop;
01550 double *xbottom;
01551 double *ybottom;
01552 double *mxtop;
01553 double *mytop;
01554 double *mxbottom;
01555 double *mybottom;
01556 int i, j;
01557
01558
01559 if (global == NULL || maskslits == NULL) {
01560 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
01561 return NULL;
01562 }
01563
01564 nslits = cpl_table_get_nrow(maskslits);
01565 slit_id = cpl_table_get_data_int(maskslits, "slit_id");
01566 mxtop = cpl_table_get_data_double(maskslits, "xtop");
01567 mytop = cpl_table_get_data_double(maskslits, "ytop");
01568 mxbottom = cpl_table_get_data_double(maskslits, "xbottom");
01569 mybottom = cpl_table_get_data_double(maskslits, "ybottom");
01570
01571 slits = cpl_table_duplicate(maskslits);
01572
01573 xtop = cpl_table_get_data_double(slits, "xtop");
01574 ytop = cpl_table_get_data_double(slits, "ytop");
01575 xbottom = cpl_table_get_data_double(slits, "xbottom");
01576 ybottom = cpl_table_get_data_double(slits, "ybottom");
01577
01578 ids0 = read_global_distortion(global, 0);
01579 crv[0] = read_global_distortion(global, 7);
01580 crv[1] = read_global_distortion(global, 8);
01581 crv[2] = read_global_distortion(global, 9);
01582
01583 loc_crv = cpl_polynomial_new(1);
01584
01585 point = cpl_vector_new(2);
01586 dpoint = cpl_vector_get_data(point);
01587
01588 for (i = 0; i < nslits; i++) {
01589 dpoint[0] = mxtop[i];
01590 dpoint[1] = mytop[i];
01591
01592 xtop[i] = cpl_polynomial_eval(ids0, point);
01593
01594 for (j = 0; j < 3; j++)
01595 if (crv[j])
01596 cpl_polynomial_set_coeff(loc_crv, &j,
01597 cpl_polynomial_eval(crv[j], point));
01598
01599 ytop[i] = cpl_polynomial_eval_1d(loc_crv, xtop[i], NULL);
01600
01601 dpoint[0] = mxbottom[i];
01602 dpoint[1] = mybottom[i];
01603 xbottom[i] = cpl_polynomial_eval(ids0, point);
01604
01605 for (j = 0; j < 3; j++)
01606 if (crv[j])
01607 cpl_polynomial_set_coeff(loc_crv, &j,
01608 cpl_polynomial_eval(crv[j], point));
01609
01610 ybottom[i] = cpl_polynomial_eval_1d(loc_crv, xbottom[i], NULL);
01611 }
01612
01613 cpl_vector_delete(point);
01614 cpl_polynomial_delete(ids0);
01615 cpl_polynomial_delete(loc_crv);
01616 for (j = 0; j < 3; j++)
01617 cpl_polynomial_delete(crv[j]);
01618
01619 sort_col = cpl_propertylist_new();
01620 cpl_propertylist_append_bool(sort_col, "ytop", 1);
01621 cpl_table_sort(slits, sort_col);
01622 cpl_table_sort(maskslits, sort_col);
01623 cpl_propertylist_delete(sort_col);
01624
01625
01626
01627
01628
01629 cpl_table_and_selected_double(slits, "ybottom", CPL_GREATER_THAN, ysize-1);
01630 cpl_table_or_selected_double(slits, "ytop", CPL_LESS_THAN, 0);
01631 cpl_table_erase_selected(slits);
01632
01633 nslits = cpl_table_get_nrow(slits);
01634
01635 if (nslits == 0) {
01636 cpl_msg_warning(func, "No slits found on the CCD");
01637 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
01638 cpl_table_delete(slits);
01639 return NULL;
01640 }
01641
01642 if (nslits > 1)
01643 cpl_msg_info(func, "Slit location: %d slits are entirely or partially "
01644 "contained in CCD", nslits);
01645 else
01646 cpl_msg_info(func, "Slit location: %d slit is entirely or partially "
01647 "contained in CCD", nslits);
01648
01649 return slits;
01650
01651 }
01652
01653
01680 cpl_table *mos_build_curv_coeff(cpl_table *global, cpl_table *maskslits,
01681 cpl_table *slits)
01682 {
01683 const char *func = "mos_build_curv_coeff";
01684
01685 const char *clab[6] = {"c0", "c1", "c2", "c3", "c4", "c5"};
01686
01687
01688 cpl_polynomial *crv[3];
01689 cpl_vector *point;
01690 cpl_table *polytraces;
01691 double *dpoint;
01692 double *xtop;
01693 double *ytop;
01694 double *xbottom;
01695 double *ybottom;
01696 int *slit_id;
01697 int *valid_id;
01698 int nslits, nvalid;
01699 int found;
01700 int i, j, k;
01701
01702
01703 if (global == NULL || slits == NULL || maskslits == NULL) {
01704 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
01705 return NULL;
01706 }
01707
01708 nslits = cpl_table_get_nrow(maskslits);
01709 slit_id = cpl_table_get_data_int(maskslits, "slit_id");
01710 xtop = cpl_table_get_data_double(maskslits, "xtop");
01711 ytop = cpl_table_get_data_double(maskslits, "ytop");
01712 xbottom = cpl_table_get_data_double(maskslits, "xbottom");
01713 ybottom = cpl_table_get_data_double(maskslits, "ybottom");
01714
01715 polytraces = cpl_table_new(2*nslits);
01716 cpl_table_new_column(polytraces, "slit_id", CPL_TYPE_INT);
01717 for (i = 0; i < 3; i++)
01718 cpl_table_new_column(polytraces, clab[i], CPL_TYPE_DOUBLE);
01719
01720 crv[0] = read_global_distortion(global, 7);
01721 crv[1] = read_global_distortion(global, 8);
01722 crv[2] = read_global_distortion(global, 9);
01723
01724 point = cpl_vector_new(2);
01725 dpoint = cpl_vector_get_data(point);
01726
01727 for (i = 0; i < nslits; i++) {
01728 for (j = 0; j < 2; j++) {
01729
01730 cpl_table_set_int(polytraces, "slit_id", 2*i+j, slit_id[i]);
01731
01732 if (j) {
01733 dpoint[0] = xbottom[i];
01734 dpoint[1] = ybottom[i];
01735 }
01736 else {
01737 dpoint[0] = xtop[i];
01738 dpoint[1] = ytop[i];
01739 }
01740
01741 for (k = 0; k < 3; k++)
01742 if (crv[j])
01743 cpl_table_set_double(polytraces, clab[k], 2*i+j,
01744 cpl_polynomial_eval(crv[k], point));
01745 }
01746 }
01747
01748 cpl_vector_delete(point);
01749 for (j = 0; j < 3; j++)
01750 cpl_polynomial_delete(crv[j]);
01751
01752
01753
01754
01755
01756 nvalid = cpl_table_get_nrow(slits);
01757 valid_id = cpl_table_get_data_int(slits, "slit_id");
01758 cpl_table_unselect_all(polytraces);
01759 for (i = 0; i < nslits; i++) {
01760 found = 0;
01761 for (j = 0; j < nvalid; j++) {
01762 if (slit_id[i] == valid_id[j]) {
01763 found = 1;
01764 break;
01765 }
01766 }
01767 if (!found) {
01768 cpl_table_select_row(polytraces, 2*i);
01769 cpl_table_select_row(polytraces, 2*i + 1);
01770 }
01771 }
01772 cpl_table_erase_selected(polytraces);
01773
01774 nslits = cpl_table_get_nrow(polytraces);
01775
01776 if (nslits == 0) {
01777 cpl_msg_warning(func, "No slits found on the CCD");
01778 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
01779 cpl_table_delete(polytraces);
01780 return NULL;
01781 }
01782
01783 if (nslits > 2)
01784 cpl_msg_info(func, "Curvature model: %d slits are entirely or "
01785 "partially contained in CCD", nslits / 2);
01786 else
01787 cpl_msg_info(func, "Curvature model: %d slit is entirely or "
01788 "partially contained in CCD", nslits / 2);
01789
01790 return polytraces;
01791 }
01792
01793
01835 cpl_table *mos_build_disp_coeff(cpl_table *global, cpl_table *slits)
01836 {
01837 const char *func = "mos_build_disp_coeff";
01838
01839 const char *clab[6] = {"c0", "c1", "c2", "c3", "c4", "c5"};
01840
01841 cpl_polynomial *ids[6];
01842 cpl_vector *point;
01843 cpl_table *idscoeff;
01844 double *dpoint;
01845 double *xtop;
01846 double *ytop;
01847 double *xbottom;
01848 double *ybottom;
01849 int *position;
01850 int *length;
01851 int nslits;
01852 int nrows;
01853 int order;
01854 int ylow, yhig;
01855 int i, j, k;
01856
01857
01858 if (global == NULL || slits == NULL) {
01859 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
01860 return NULL;
01861 }
01862
01863 nslits = cpl_table_get_nrow(slits);
01864 position = cpl_table_get_data_int(slits, "position");
01865 length = cpl_table_get_data_int(slits, "length");
01866 xtop = cpl_table_get_data_double(slits, "xtop");
01867 ytop = cpl_table_get_data_double(slits, "ytop");
01868 xbottom = cpl_table_get_data_double(slits, "xbottom");
01869 ybottom = cpl_table_get_data_double(slits, "ybottom");
01870
01871 for (i = 0; i < 6; i++)
01872 ids[i] = read_global_distortion(global, i);
01873
01874 for (i = 0; i < 6; i++)
01875 if (ids[i] == NULL)
01876 break;
01877
01878 order = i - 1;
01879
01880 if (order < 1) {
01881 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
01882 return NULL;
01883 }
01884
01885 nrows = 0;
01886 for (i = 0; i < nslits; i++)
01887 nrows += length[i];
01888
01889 idscoeff = cpl_table_new(nrows);
01890
01891 for (j = 0; j <= order; j++)
01892 cpl_table_new_column(idscoeff, clab[j], CPL_TYPE_DOUBLE);
01893
01894 cpl_table_new_column(idscoeff, "error", CPL_TYPE_DOUBLE);
01895 cpl_table_fill_column_window_double(idscoeff, "error", 0, nrows, 0.0);
01896 cpl_table_new_column(idscoeff, "nlines", CPL_TYPE_INT);
01897 cpl_table_fill_column_window_int(idscoeff, "nlines", 0, nrows, 0);
01898
01899 point = cpl_vector_new(2);
01900 dpoint = cpl_vector_get_data(point);
01901
01902 for (i = 0; i < nslits; i++) {
01903
01904 if (length[i] == 0)
01905 continue;
01906
01907 ylow = position[i];
01908 yhig = ylow + length[i];
01909
01910 for (j = 0; j <= order; j++) {
01911 if (j) {
01912 for (k = 0; k < length[i]; k++) {
01913 dpoint[0] = xbottom[i] + k*(xtop[i]-xbottom[i])/length[i];
01914 dpoint[1] = ybottom[i] + k*(ytop[i]-ybottom[i])/length[i];
01915 cpl_table_set_double(idscoeff, clab[j], ylow + k,
01916 cpl_polynomial_eval(ids[j], point));
01917 }
01918 }
01919 else {
01920 for (k = 0; k < length[i]; k++) {
01921 cpl_table_set_double(idscoeff, clab[0], ylow + k,
01922 xbottom[i] + k*(xtop[i]-xbottom[i])/length[i]);
01923 }
01924 }
01925 }
01926 }
01927
01928 cpl_vector_delete(point);
01929 for (j = 0; j < 6; j++)
01930 cpl_polynomial_delete(ids[j]);
01931
01932 return idscoeff;
01933
01934 }
01935
01936
01959 cpl_image *mos_subtract_sky(cpl_image *science, cpl_table *slits,
01960 cpl_table *polytraces, double reference,
01961 double blue, double red, double dispersion)
01962 {
01963 const char *func = "mos_subtract_sky";
01964
01965 const char *clab[6] = {"c0", "c1", "c2", "c3", "c4", "c5"};
01966
01967
01968 cpl_image *sky;
01969 cpl_bivector *list;
01970 cpl_vector *listx;
01971 cpl_vector *listy;
01972 cpl_polynomial *polytop;
01973 cpl_polynomial *polybot;
01974 cpl_polynomial *trend;
01975
01976 int *slit_id;
01977 double *dlistx;
01978 double *dlisty;
01979 float *sdata;
01980 float *kdata;
01981 double top, bot;
01982 int itop, ibot;
01983 double coeff;
01984 double ytop, ybot;
01985 double m, q, err;
01986 int npix;
01987
01988 int pixel_above, pixel_below, refpixel, start_pixel, end_pixel;
01989 int nx, ny;
01990 int nslits;
01991 int *length;
01992 int missing_top, missing_bot;
01993 int order;
01994 int null;
01995 int window = 50;
01996 int count;
01997 int i, j, k;
01998
01999
02000 if (science == NULL || slits == NULL || polytraces == NULL) {
02001 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
02002 return NULL;
02003 }
02004
02005 if (dispersion <= 0.0) {
02006 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
02007 return NULL;
02008 }
02009
02010 if (red - blue < dispersion) {
02011 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
02012 return NULL;
02013 }
02014
02015 nx = cpl_image_get_size_x(science);
02016 ny = cpl_image_get_size_y(science);
02017
02018 sky = cpl_image_new(nx, ny, CPL_TYPE_FLOAT);
02019
02020 sdata = cpl_image_get_data(science);
02021 kdata = cpl_image_get_data(sky);
02022
02023 nslits = cpl_table_get_nrow(slits);
02024 order = cpl_table_get_ncol(polytraces) - 2;
02025 length = cpl_table_get_data_int(slits, "length");
02026 slit_id = cpl_table_get_data_int(slits, "slit_id");
02027
02028
02029
02030
02031
02032
02033 pixel_above = (red - reference) / dispersion;
02034 pixel_below = (reference - blue) / dispersion;
02035
02036 for (i = 0; i < nslits; i++) {
02037
02038 if (length[i] == 0)
02039 continue;
02040
02041
02042
02043
02044
02045
02046
02047 refpixel = cpl_table_get_double(slits, "xtop", i, NULL);
02048
02049 start_pixel = refpixel - pixel_below;
02050 if (start_pixel < 0)
02051 start_pixel = 0;
02052
02053 end_pixel = refpixel + pixel_above;
02054 if (end_pixel > nx)
02055 end_pixel = nx;
02056
02057 missing_top = 0;
02058 polytop = cpl_polynomial_new(1);
02059 for (k = 0; k <= order; k++) {
02060 coeff = cpl_table_get_double(polytraces, clab[k], 2*i, &null);
02061 if (null) {
02062 cpl_polynomial_delete(polytop);
02063 missing_top = 1;
02064 break;
02065 }
02066 cpl_polynomial_set_coeff(polytop, &k, coeff);
02067 }
02068
02069 missing_bot = 0;
02070 polybot = cpl_polynomial_new(1);
02071 for (k = 0; k <= order; k++) {
02072 coeff = cpl_table_get_double(polytraces, clab[k], 2*i+1, &null);
02073 if (null) {
02074 cpl_polynomial_delete(polybot);
02075 missing_bot = 1;
02076 break;
02077 }
02078 cpl_polynomial_set_coeff(polybot, &k, coeff);
02079 }
02080
02081 if (missing_top && missing_bot) {
02082 cpl_msg_debug(func, "Slit %d was not traced: no extraction!",
02083 slit_id[i]);
02084 continue;
02085 }
02086
02087
02088
02089
02090
02091
02092
02093 if (missing_top) {
02094 cpl_msg_debug(func, "Upper edge of slit %d was not traced: "
02095 "the spectral curvature of the lower edge "
02096 "is used instead.", slit_id[i]);
02097 polytop = cpl_polynomial_duplicate(polybot);
02098 ytop = cpl_table_get_double(slits, "ytop", i, NULL);
02099 ybot = cpl_table_get_double(slits, "ybottom", i, NULL);
02100 k = 0;
02101 coeff = cpl_polynomial_get_coeff(polybot, &k);
02102 coeff += ytop - ybot;
02103 cpl_polynomial_set_coeff(polytop, &k, coeff);
02104 }
02105
02106 if (missing_bot) {
02107 cpl_msg_debug(func, "Lower edge of slit %d was not traced: "
02108 "the spectral curvature of the upper edge "
02109 "is used instead.", slit_id[i]);
02110 polybot = cpl_polynomial_duplicate(polytop);
02111 ytop = cpl_table_get_double(slits, "ytop", i, NULL);
02112 ybot = cpl_table_get_double(slits, "ybottom", i, NULL);
02113 k = 0;
02114 coeff = cpl_polynomial_get_coeff(polytop, &k);
02115 coeff -= ytop - ybot;
02116 cpl_polynomial_set_coeff(polybot, &k, coeff);
02117 }
02118
02119
02120
02121
02122
02123
02124 for (j = start_pixel; j < end_pixel; j++) {
02125 top = cpl_polynomial_eval_1d(polytop, j, NULL);
02126 bot = cpl_polynomial_eval_1d(polybot, j, NULL);
02127 itop = floor(top + 0.5) + 1;
02128 ibot = floor(bot + 0.5);
02129 if (itop > ny)
02130 itop = ny;
02131 if (ibot < 0)
02132 ibot = 0;
02133 npix = itop - ibot;
02134 if (npix < 5)
02135 break;
02136
02137 list = cpl_bivector_new(npix);
02138 listx = cpl_bivector_get_x(list);
02139 listy = cpl_bivector_get_y(list);
02140 dlistx = cpl_vector_get_data(listx);
02141 dlisty = cpl_vector_get_data(listy);
02142
02143 for (k = 0; k < npix; k++) {
02144 dlistx[k] = k;
02145 dlisty[k] = sdata[j + (ibot + k)*nx];
02146 }
02147
02148 if (robustLinearFit(list, &q, &m, &err)) {
02149 cpl_bivector_delete(list);
02150 continue;
02151 }
02152
02153 cpl_bivector_delete(list);
02154
02155 for (k = 0; k < npix; k++) {
02156 kdata[j + (ibot + k)*nx] = m*k + q;
02157 }
02158
02159 if (npix > window) {
02160
02161
02162
02163
02164
02165 err = 3*sqrt(err);
02166
02167 count = 0;
02168 for (k = 0; k < npix; k++)
02169 if (fabs(sdata[j + (ibot + k)*nx] - m*k - q) < err)
02170 count++;
02171
02172 if (count < 10)
02173 continue;
02174
02175 list = cpl_bivector_new(count);
02176 listx = cpl_bivector_get_x(list);
02177 listy = cpl_bivector_get_y(list);
02178 dlistx = cpl_vector_get_data(listx);
02179 dlisty = cpl_vector_get_data(listy);
02180
02181 count = 0;
02182 for (k = 0; k < npix; k++) {
02183 if (fabs(sdata[j + (ibot + k)*nx] - m*k - q) < err) {
02184 dlistx[count] = k;
02185 dlisty[count] = sdata[j + (ibot + k)*nx];
02186 count++;
02187 }
02188 }
02189
02190 trend = cpl_polynomial_fit_1d_create(listx, listy, 2, &err);
02191
02192 cpl_bivector_delete(list);
02193
02194 err = 3*sqrt(err);
02195
02196 count = 0;
02197 for (k = 0; k < npix; k++)
02198 if (fabs(sdata[j + (ibot + k)*nx]
02199 - cpl_polynomial_eval_1d(trend, k, NULL)) < err)
02200 count++;
02201
02202 if (count < 10) {
02203 cpl_polynomial_delete(trend);
02204 continue;
02205 }
02206
02207 list = cpl_bivector_new(count);
02208 listx = cpl_bivector_get_x(list);
02209 listy = cpl_bivector_get_y(list);
02210 dlistx = cpl_vector_get_data(listx);
02211 dlisty = cpl_vector_get_data(listy);
02212
02213 count = 0;
02214 for (k = 0; k < npix; k++) {
02215 if (fabs(sdata[j + (ibot + k)*nx]
02216 - cpl_polynomial_eval_1d(trend, k, NULL)) < err) {
02217 dlistx[count] = k;
02218 dlisty[count] = sdata[j + (ibot + k)*nx];
02219 count++;
02220 }
02221 }
02222
02223 cpl_polynomial_delete(trend);
02224
02225 trend = cpl_polynomial_fit_1d_create(listx, listy, 3, &err);
02226
02227 cpl_bivector_delete(list);
02228
02229 for (k = 0; k < npix; k++) {
02230 kdata[j + (ibot + k)*nx] = cpl_polynomial_eval_1d(trend,
02231 k, NULL);
02232 }
02233
02234 cpl_polynomial_delete(trend);
02235 }
02236 }
02237 cpl_polynomial_delete(polytop);
02238 cpl_polynomial_delete(polybot);
02239 }
02240
02241 cpl_image_subtract(science, sky);
02242
02243 return sky;
02244 }
02245
02246
02279 cpl_image *mos_normalise_flat(cpl_image *flat, cpl_image *spatial,
02280 cpl_table *slits, cpl_table *polytraces,
02281 double reference, double blue, double red,
02282 double dispersion, int sradius, int polyorder)
02283 {
02284 const char *func = "mos_normalise_flat";
02285
02286 const char *clab[6] = {"c0", "c1", "c2", "c3", "c4", "c5"};
02287
02288
02289 cpl_image *rectified;
02290 cpl_image *smo_flat;
02291 cpl_image *exslit;
02292 cpl_vector *positions;
02293 cpl_vector *flux;
02294 cpl_vector *smo_flux;
02295 cpl_polynomial *trend;
02296 cpl_polynomial *polytop;
02297 cpl_polynomial *polybot;
02298
02299 int *slit_id;
02300 float *p;
02301 float *data;
02302 double *fdata;
02303 double *pdata;
02304 float *sdata;
02305 float *xdata;
02306 float *wdata;
02307 double vtop, vbot, value;
02308 double top, bot;
02309 double coeff;
02310 double ytop, ybot;
02311 double ypos;
02312 double fvalue;
02313 int ivalue;
02314 int yint, yprev;
02315 int npseudo;
02316
02317 int pixel_above, pixel_below, refpixel, start_pixel, end_pixel;
02318 int nx, ny, nsubx, nsuby;
02319 int xlow, ylow, xhig, yhig;
02320 int nslits;
02321 int *position;
02322 int *length;
02323 int missing_top, missing_bot;
02324 int order;
02325 int npoints;
02326 int uradius;
02327 int null;
02328 int i, j, k;
02329
02330
02331
02332
02333
02334
02335 if (flat == NULL || slits == NULL || polytraces == NULL) {
02336 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
02337 return NULL;
02338 }
02339
02340 if (dispersion <= 0.0) {
02341 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
02342 return NULL;
02343 }
02344
02345 if (red - blue < dispersion) {
02346 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
02347 return NULL;
02348 }
02349
02350 rectified = mos_spatial_calibration(flat, slits, polytraces, reference,
02351 blue, red, dispersion, 0, NULL);
02352
02353 nx = cpl_image_get_size_x(rectified);
02354 ny = cpl_image_get_size_y(rectified);
02355
02356 smo_flat = cpl_image_new(cpl_image_get_size_x(spatial),
02357 cpl_image_get_size_y(spatial), CPL_TYPE_FLOAT);
02358 wdata = cpl_image_get_data(smo_flat);
02359
02360 nslits = cpl_table_get_nrow(slits);
02361 order = cpl_table_get_ncol(polytraces) - 2;
02362 position = cpl_table_get_data_int(slits, "position");
02363 length = cpl_table_get_data_int(slits, "length");
02364 slit_id = cpl_table_get_data_int(slits, "slit_id");
02365
02366
02367
02368
02369
02370
02371 pixel_above = (red - reference) / dispersion;
02372 pixel_below = (reference - blue) / dispersion;
02373
02374 xlow = 1;
02375 xhig = nx;
02376 for (i = 0; i < nslits; i++) {
02377
02378 if (length[i] == 0)
02379 continue;
02380
02381
02382
02383
02384
02385
02386
02387
02388
02389
02390
02391 ylow = position[i] + 1;
02392 yhig = ylow + length[i] - 1;
02393
02394 exslit = cpl_image_extract(rectified, xlow, ylow, xhig, yhig);
02395
02396 if (polyorder < 0) {
02397
02398 cpl_image_turn(exslit, -1);
02399
02400 nsubx = cpl_image_get_size_x(exslit);
02401 nsuby = cpl_image_get_size_y(exslit);
02402 data = cpl_image_get_data(exslit);
02403 flux = cpl_vector_new(nsubx);
02404
02405 uradius = nsubx / 2;
02406 if (uradius > sradius)
02407 uradius = sradius;
02408
02409 for (j = 0; j < nsuby; j++) {
02410 fdata = cpl_vector_get_data(flux);
02411 p = data;
02412 for (k = 0; k < nsubx; k++)
02413 *fdata++ = *p++;
02414 smo_flux = cpl_vector_filter_median_create(flux, uradius);
02415 fdata = cpl_vector_get_data(smo_flux);
02416 p = data;
02417 for (k = 0; k < nsubx; k++)
02418 *p++ = *fdata++;
02419 cpl_vector_delete(smo_flux);
02420 data += nsubx;
02421 }
02422
02423 cpl_vector_delete(flux);
02424
02425
02426
02427
02428
02429
02430
02431
02432
02433
02434
02435
02436
02437
02438
02439
02440
02441
02442
02443
02444
02445
02446
02447
02448
02449
02450
02451
02452
02453
02454
02455
02456
02457
02458
02459 cpl_image_turn(exslit, 1);
02460 nsubx = cpl_image_get_size_x(exslit);
02461 nsuby = cpl_image_get_size_y(exslit);
02462 data = cpl_image_get_data(exslit);
02463
02464 for (j = 0; j < nsuby; j++) {
02465 flux = cpl_vector_new(nsubx);
02466 fdata = cpl_vector_get_data(flux);
02467 p = data;
02468 for (k = 0; k < nsubx; k++)
02469 *fdata++ = *p++;
02470 smo_flux = cpl_vector_filter_median_create(flux, sradius);
02471 cpl_vector_delete(flux);
02472 fdata = cpl_vector_get_data(smo_flux);
02473 p = data;
02474 for (k = 0; k < nsubx; k++)
02475 *p++ = *fdata++;
02476 cpl_vector_delete(smo_flux);
02477 data += nsubx;
02478 }
02479 }
02480 else {
02481
02482
02483
02484
02485
02486 nsubx = cpl_image_get_size_x(exslit);
02487 nsuby = cpl_image_get_size_y(exslit);
02488 data = cpl_image_get_data(exslit);
02489
02490 for (j = 0; j < nsuby; j++) {
02491
02492
02493
02494
02495
02496 npoints = 0;
02497 p = data + j*nsubx;
02498 for (k = 0; k < nsubx; k++)
02499 if (p[k] > 1.0)
02500 npoints++;
02501
02502 if (npoints > polyorder + 1) {
02503
02504
02505
02506
02507
02508 flux = cpl_vector_new(npoints);
02509 fdata = cpl_vector_get_data(flux);
02510 positions = cpl_vector_new(npoints);
02511 pdata = cpl_vector_get_data(positions);
02512
02513 npoints = 0;
02514 p = data + j*nsubx;
02515 for (k = 0; k < nsubx; k++) {
02516 if (p[k] > 1.0) {
02517 fdata[npoints] = p[k];
02518 pdata[npoints] = k;
02519 npoints++;
02520 }
02521 }
02522
02523 trend = cpl_polynomial_fit_1d_create(positions, flux,
02524 polyorder, NULL);
02525
02526 cpl_vector_delete(flux);
02527 cpl_vector_delete(positions);
02528
02529 if (trend) {
02530 p = data + j*nsubx;
02531 for (k = 0; k < nsubx; k++)
02532 if (p[k] > 1.0)
02533 p[k] = cpl_polynomial_eval_1d(trend, k, NULL);
02534 cpl_polynomial_delete(trend);
02535 }
02536 else {
02537 cpl_msg_warning(func, "Invalid flat field flux fit "
02538 "(ignored)");
02539 }
02540 }
02541 }
02542 }
02543
02544
02545
02546
02547
02548
02549
02550 refpixel = cpl_table_get_double(slits, "xtop", i, NULL);
02551
02552 start_pixel = refpixel - pixel_below;
02553 if (start_pixel < 0)
02554 start_pixel = 0;
02555
02556 end_pixel = refpixel + pixel_above;
02557 if (end_pixel > nx)
02558 end_pixel = nx;
02559
02560 missing_top = 0;
02561 polytop = cpl_polynomial_new(1);
02562 for (k = 0; k <= order; k++) {
02563 coeff = cpl_table_get_double(polytraces, clab[k], 2*i, &null);
02564 if (null) {
02565 cpl_polynomial_delete(polytop);
02566 missing_top = 1;
02567 break;
02568 }
02569 cpl_polynomial_set_coeff(polytop, &k, coeff);
02570 }
02571
02572 missing_bot = 0;
02573 polybot = cpl_polynomial_new(1);
02574 for (k = 0; k <= order; k++) {
02575 coeff = cpl_table_get_double(polytraces, clab[k], 2*i+1, &null);
02576 if (null) {
02577 cpl_polynomial_delete(polybot);
02578 missing_bot = 1;
02579 break;
02580 }
02581 cpl_polynomial_set_coeff(polybot, &k, coeff);
02582 }
02583
02584 if (missing_top && missing_bot) {
02585 cpl_msg_debug(func, "Slit %d was not traced: no extraction!",
02586 slit_id[i]);
02587 continue;
02588 }
02589
02590
02591
02592
02593
02594
02595
02596 if (missing_top) {
02597 cpl_msg_debug(func, "Upper edge of slit %d was not traced: "
02598 "the spectral curvature of the lower edge "
02599 "is used instead.", slit_id[i]);
02600 polytop = cpl_polynomial_duplicate(polybot);
02601 ytop = cpl_table_get_double(slits, "ytop", i, NULL);
02602 ybot = cpl_table_get_double(slits, "ybottom", i, NULL);
02603 k = 0;
02604 coeff = cpl_polynomial_get_coeff(polybot, &k);
02605 coeff += ytop - ybot;
02606 cpl_polynomial_set_coeff(polytop, &k, coeff);
02607 }
02608
02609 if (missing_bot) {
02610 cpl_msg_debug(func, "Lower edge of slit %d was not traced: "
02611 "the spectral curvature of the upper edge "
02612 "is used instead.", slit_id[i]);
02613 polybot = cpl_polynomial_duplicate(polytop);
02614 ytop = cpl_table_get_double(slits, "ytop", i, NULL);
02615 ybot = cpl_table_get_double(slits, "ybottom", i, NULL);
02616 k = 0;
02617 coeff = cpl_polynomial_get_coeff(polytop, &k);
02618 coeff -= ytop - ybot;
02619 cpl_polynomial_set_coeff(polybot, &k, coeff);
02620 }
02621
02622
02623
02624
02625
02626
02627
02628
02629
02630 nx = cpl_image_get_size_x(flat);
02631 ny = cpl_image_get_size_y(flat);
02632
02633 sdata = cpl_image_get_data(spatial);
02634 xdata = cpl_image_get_data(exslit);
02635 npseudo = cpl_image_get_size_y(exslit) - 1;
02636
02637
02638
02639
02640
02641 for (j = start_pixel; j < end_pixel; j++) {
02642 top = cpl_polynomial_eval_1d(polytop, j, NULL);
02643 bot = cpl_polynomial_eval_1d(polybot, j, NULL);
02644 for (k = 0; k <= npseudo; k++) {
02645 ypos = top - k*(top-bot)/npseudo;
02646 yint = ypos;
02647
02648
02649
02650
02651
02652
02653
02654
02655 if (yint < 0 || yint >= ny-1) {
02656 yprev = yint;
02657 continue;
02658 }
02659
02660 value = sdata[j + nx*yint];
02661 ivalue = value;
02662 fvalue = value - ivalue;
02663 if (ivalue < npseudo && ivalue >= 0) {
02664 vtop = xdata[j + nx*(npseudo-ivalue)];
02665 vbot = xdata[j + nx*(npseudo-ivalue-1)];
02666 wdata[j + nx*yint] = vtop*(1-fvalue) + vbot*fvalue;
02667
02668 if (k) {
02669
02670
02671
02672
02673
02674
02675
02676 if (yprev - yint > 1) {
02677 value = sdata[j + nx*(yint+1)];
02678 ivalue = value;
02679 fvalue = value - ivalue;
02680 if (ivalue < npseudo && ivalue >= 0) {
02681 vtop = xdata[j + nx*(npseudo-ivalue)];
02682 vbot = xdata[j + nx*(npseudo-ivalue-1)];
02683 wdata[j + nx*(yint+1)] = vtop*(1-fvalue)
02684 + vbot*fvalue;
02685 }
02686 }
02687 }
02688 }
02689 yprev = yint;
02690 }
02691 }
02692 cpl_polynomial_delete(polytop);
02693 cpl_polynomial_delete(polybot);
02694 cpl_image_delete(exslit);
02695 }
02696
02697 cpl_image_delete(rectified);
02698
02699 cpl_image_divide(flat, smo_flat);
02700
02701 return smo_flat;
02702 }
02703
02704
02729 cpl_image *mos_normalise_longflat(cpl_image *flat, int sradius, int dradius,
02730 int polyorder)
02731 {
02732 const char *func = "mos_normalise_longflat";
02733
02734 cpl_image *smo_flat;
02735 cpl_image *profile;
02736 cpl_vector *flux;
02737 cpl_vector *smo_flux;
02738 cpl_vector *positions;
02739 cpl_polynomial *trend;
02740
02741 float *level;
02742 float *p;
02743 float *data;
02744 double *fdata;
02745 double *pdata;
02746
02747 int nx, ny;
02748 int npoints;
02749 int i, j;
02750
02751
02752 if (flat == NULL) {
02753 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
02754 return NULL;
02755 }
02756
02757 if (sradius < 1 || dradius < 1) {
02758 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
02759 return NULL;
02760 }
02761
02762 smo_flat = cpl_image_duplicate(flat);
02763
02764 if (polyorder < 0) {
02765
02766
02767
02768
02769
02770 cpl_image_turn(smo_flat, -1);
02771
02772 nx = cpl_image_get_size_x(smo_flat);
02773 ny = cpl_image_get_size_y(smo_flat);
02774 data = cpl_image_get_data(smo_flat);
02775
02776 for (i = 0; i < ny; i++) {
02777 flux = cpl_vector_new(nx);
02778 fdata = cpl_vector_get_data(flux);
02779 p = data;
02780 for (j = 0; j < nx; j++)
02781 *fdata++ = *p++;
02782 smo_flux = cpl_vector_filter_median_create(flux, sradius);
02783 cpl_vector_delete(flux);
02784 fdata = cpl_vector_get_data(smo_flux);
02785 p = data;
02786 for (j = 0; j < nx; j++)
02787 *p++ = *fdata++;
02788 cpl_vector_delete(smo_flux);
02789 data += nx;
02790 }
02791
02792
02793
02794
02795
02796 cpl_image_turn(smo_flat, 1);
02797
02798 nx = cpl_image_get_size_x(smo_flat);
02799 ny = cpl_image_get_size_y(smo_flat);
02800 data = cpl_image_get_data(smo_flat);
02801
02802 for (i = 0; i < ny; i++) {
02803 flux = cpl_vector_new(nx);
02804 fdata = cpl_vector_get_data(flux);
02805 p = data;
02806 for (j = 0; j < nx; j++)
02807 *fdata++ = *p++;
02808 smo_flux = cpl_vector_filter_median_create(flux, sradius);
02809 cpl_vector_delete(flux);
02810 fdata = cpl_vector_get_data(smo_flux);
02811 p = data;
02812 for (j = 0; j < nx; j++)
02813 *p++ = *fdata++;
02814 cpl_vector_delete(smo_flux);
02815 data += nx;
02816 }
02817 }
02818 else {
02819
02820
02821
02822
02823
02824 cpl_image_turn(smo_flat, -1);
02825
02826 nx = cpl_image_get_size_x(smo_flat);
02827 ny = cpl_image_get_size_y(smo_flat);
02828 data = cpl_image_get_data(smo_flat);
02829
02830 profile = cpl_image_collapse_median_create(smo_flat, 1, 0, 0);
02831 level = cpl_image_get_data(profile);
02832
02833 for (i = 0; i < ny; i++) {
02834
02835
02836
02837
02838
02839
02840
02841 npoints = 0;
02842 p = data + i*nx;
02843 for (j = 0; j < nx; j++)
02844 if (fabs(p[j]/level[i] - 1) < 0.20)
02845 npoints++;
02846
02847 if (npoints > polyorder + 1) {
02848
02849
02850
02851
02852
02853 flux = cpl_vector_new(npoints);
02854 fdata = cpl_vector_get_data(flux);
02855 positions = cpl_vector_new(npoints);
02856 pdata = cpl_vector_get_data(positions);
02857
02858 npoints = 0;
02859 p = data + i*nx;
02860 for (j = 0; j < nx; j++) {
02861 if (fabs(p[j]/level[i] - 1) < 0.20) {
02862 fdata[npoints] = p[j];
02863 pdata[npoints] = j;
02864 npoints++;
02865 }
02866 }
02867
02868 trend = cpl_polynomial_fit_1d_create(positions, flux,
02869 polyorder, NULL);
02870
02871 cpl_vector_delete(flux);
02872 cpl_vector_delete(positions);
02873
02874 if (trend) {
02875 p = data + i*nx;
02876 for (j = 0; j < nx; j++)
02877 p[j] = cpl_polynomial_eval_1d(trend, j, NULL);
02878 cpl_polynomial_delete(trend);
02879 }
02880 else {
02881 cpl_msg_warning(func,
02882 "Invalid flat field flux fit (ignored)");
02883 }
02884 }
02885 }
02886
02887 cpl_image_delete(profile);
02888 cpl_image_turn(smo_flat, 1);
02889
02890 }
02891
02892 cpl_image_divide(flat, smo_flat);
02893
02894 return smo_flat;
02895 }
02896
02897
02922 cpl_error_code mos_interpolate_wavecalib(cpl_table *idscoeff,
02923 cpl_image *wavemap, int mode)
02924 {
02925 const char *func = "mos_interpolate_wavecalib";
02926
02927 const char *clab[6] = {"c0", "c1", "c2", "c3", "c4", "c5"};
02928
02929
02930 cpl_vector *wave;
02931 cpl_vector *positions;
02932 cpl_polynomial *trend;
02933
02934 float *p;
02935 float *data;
02936 double *wdata;
02937 double *pdata;
02938
02939 double c;
02940 double mse, ksigma;
02941
02942 int order;
02943 int nrows, first_row, last_row;
02944 int nx, ny;
02945 int npoints, rpoints;
02946 int null;
02947 int i, j, k;
02948
02949 int polyorder = 4;
02950
02951
02952 if (idscoeff == NULL)
02953 return cpl_error_set(func, CPL_ERROR_NULL_INPUT);
02954
02955 if (mode < 0 || mode > 2)
02956 return cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
02957
02958 if (mode == 0)
02959 return CPL_ERROR_NONE;
02960
02961 if (wavemap) {
02962
02963
02964
02965
02966
02967 cpl_image_turn(wavemap, -1);
02968
02969 nx = cpl_image_get_size_x(wavemap);
02970 ny = cpl_image_get_size_y(wavemap);
02971 data = cpl_image_get_data(wavemap);
02972
02973 for (i = 0; i < ny; i++) {
02974
02975
02976
02977
02978
02979
02980 npoints = 0;
02981 p = data + i*nx;
02982 for (j = 0; j < nx; j++)
02983 if (p[j] > 1.0)
02984 npoints++;
02985
02986 if (npoints > polyorder + 1) {
02987
02988
02989
02990
02991
02992 wave = cpl_vector_new(npoints);
02993 wdata = cpl_vector_get_data(wave);
02994 positions = cpl_vector_new(npoints);
02995 pdata = cpl_vector_get_data(positions);
02996
02997 npoints = 0;
02998 p = data + i*nx;
02999 for (j = 0; j < nx; j++) {
03000 if (p[j] > 1.0) {
03001 wdata[npoints] = p[j];
03002 pdata[npoints] = j;
03003 npoints++;
03004 }
03005 }
03006
03007 trend = cpl_polynomial_fit_1d_create(positions, wave,
03008 polyorder, &mse);
03009
03010 ksigma = 3*sqrt(mse);
03011
03012 cpl_vector_delete(wave);
03013 cpl_vector_delete(positions);
03014
03015 if (trend) {
03016
03017
03018
03019
03020
03021 rpoints = 0;
03022 p = data + i*nx;
03023 for (j = 0; j < nx; j++)
03024 if (p[j] > 1.0)
03025 if (fabs(cpl_polynomial_eval_1d(trend, j, NULL)
03026 - p[j]) < ksigma)
03027 rpoints++;
03028
03029 if (rpoints < npoints && rpoints > polyorder + 1) {
03030
03031 wave = cpl_vector_new(rpoints);
03032 wdata = cpl_vector_get_data(wave);
03033 positions = cpl_vector_new(rpoints);
03034 pdata = cpl_vector_get_data(positions);
03035
03036 npoints = 0;
03037 p = data + i*nx;
03038 for (j = 0; j < nx; j++) {
03039 if (p[j] > 1.0) {
03040 if (fabs(cpl_polynomial_eval_1d(trend,
03041 j, NULL) - p[j])
03042 < ksigma) {
03043 wdata[npoints] = p[j];
03044 pdata[npoints] = j;
03045 npoints++;
03046 }
03047 }
03048 }
03049
03050 cpl_polynomial_delete(trend);
03051 trend = cpl_polynomial_fit_1d_create(positions, wave,
03052 polyorder, NULL);
03053
03054 cpl_vector_delete(wave);
03055 cpl_vector_delete(positions);
03056 }
03057 }
03058
03059 if (trend) {
03060 p = data + i*nx;
03061 if (mode == 1) {
03062 for (j = 0; j < nx; j++)
03063 if (p[j] < 1.0)
03064 p[j] = cpl_polynomial_eval_1d(trend, j, NULL);
03065 }
03066 else if (mode == 2) {
03067 for (j = 0; j < nx; j++)
03068 p[j] = cpl_polynomial_eval_1d(trend, j, NULL);
03069 }
03070 cpl_polynomial_delete(trend);
03071 }
03072 else {
03073 cpl_msg_warning(func,
03074 "Invalid wavelength field fit (ignored)");
03075 }
03076 }
03077
03078 }
03079
03080 cpl_image_turn(wavemap, 1);
03081
03082 }
03083
03084
03085
03086
03087
03088
03089 nrows = cpl_table_get_nrow(idscoeff);
03090
03091 order = 0;
03092 while (order < 6 && cpl_table_has_column(idscoeff, clab[order]))
03093 ++order;
03094 --order;
03095
03096 first_row = 0;
03097 while (!cpl_table_is_valid(idscoeff, clab[0], first_row))
03098 first_row++;
03099
03100 last_row = nrows - 1;
03101 while (!cpl_table_is_valid(idscoeff, clab[0], last_row))
03102 last_row--;
03103
03104 for (k = 0; k <= order; k++) {
03105
03106 npoints = nrows - cpl_table_count_invalid(idscoeff, clab[k]);
03107 wave = cpl_vector_new(npoints);
03108 wdata = cpl_vector_get_data(wave);
03109 positions = cpl_vector_new(npoints);
03110 pdata = cpl_vector_get_data(positions);
03111
03112 npoints = 0;
03113 for (i = first_row; i <= last_row; i++) {
03114 c = cpl_table_get_double(idscoeff, clab[k], i, &null);
03115 if (null == 0) {
03116 wdata[npoints] = c;
03117 pdata[npoints] = i;
03118 npoints++;
03119 }
03120 }
03121
03122 trend = cpl_polynomial_fit_1d_create(positions, wave, 2, &mse);
03123
03124 ksigma = 3*sqrt(mse);
03125
03126 cpl_vector_delete(wave);
03127 cpl_vector_delete(positions);
03128
03129
03130
03131
03132
03133 if (trend) {
03134 rpoints = 0;
03135 for (i = first_row; i <= last_row; i++) {
03136 c = cpl_table_get_double(idscoeff, clab[k], i, &null);
03137 if (null == 0) {
03138 if (fabs(cpl_polynomial_eval_1d(trend, i, NULL) - c)
03139 < ksigma) {
03140 rpoints++;
03141 }
03142 }
03143 }
03144
03145 if (rpoints > 0 && rpoints < npoints) {
03146 cpl_msg_debug(func, "%d points rejected from "
03147 "wavelength calibration fit",
03148 npoints - rpoints);
03149
03150 wave = cpl_vector_new(rpoints);
03151 wdata = cpl_vector_get_data(wave);
03152 positions = cpl_vector_new(rpoints);
03153 pdata = cpl_vector_get_data(positions);
03154
03155 npoints = 0;
03156 for (i = first_row; i <= last_row; i++) {
03157 c = cpl_table_get_double(idscoeff, clab[k], i, &null);
03158 if (null == 0) {
03159 if (fabs(cpl_polynomial_eval_1d(trend, i, NULL) - c)
03160 < ksigma) {
03161 wdata[npoints] = c;
03162 pdata[npoints] = i;
03163 npoints++;
03164 }
03165 }
03166 }
03167
03168 if (npoints) {
03169 cpl_polynomial_delete(trend);
03170 trend = cpl_polynomial_fit_1d_create(positions,
03171 wave, 2, NULL);
03172 }
03173
03174 cpl_vector_delete(wave);
03175 cpl_vector_delete(positions);
03176
03177 }
03178 }
03179
03180 if (trend) {
03181 for (i = first_row; i <= last_row; i++) {
03182 if (mode == 1) {
03183 if (!cpl_table_is_valid(idscoeff, clab[k], i)) {
03184 cpl_table_set_double(idscoeff, clab[k], i,
03185 cpl_polynomial_eval_1d(trend, i,
03186 NULL));
03187 }
03188 }
03189 else if (mode == 2) {
03190 cpl_table_set_double(idscoeff, clab[k], i,
03191 cpl_polynomial_eval_1d(trend, i, NULL));
03192 }
03193 }
03194 cpl_polynomial_delete(trend);
03195 }
03196 else {
03197 cpl_msg_warning(func, "Invalid IDS coefficient fit (ignored)");
03198 }
03199
03200 }
03201
03202 return CPL_ERROR_NONE;
03203 }
03204
03205
03206
03232 cpl_image *mos_remove_bias(cpl_image *image, cpl_image *bias,
03233 cpl_table *overscans)
03234 {
03235 const char *func = "mos_remove_bias";
03236
03237 cpl_image *unbiased;
03238 cpl_image *overscan;
03239 double mean_bias_level;
03240 double mean_overscans_level;
03241 int count;
03242 int nrows;
03243 int xlow, ylow, xhig, yhig;
03244 int i;
03245
03246
03247 if (image == NULL || overscans == NULL) {
03248 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
03249 return NULL;
03250 }
03251
03252 nrows = cpl_table_get_nrow(overscans);
03253
03254 if (nrows == 0) {
03255 cpl_msg_error(func, "Empty overscan table");
03256 cpl_error_set(func, CPL_ERROR_DATA_NOT_FOUND);
03257 return NULL;
03258 }
03259
03260 if (bias) {
03261 if (nrows == 1) {
03262 unbiased = cpl_image_subtract_create(image, bias);
03263 if (unbiased == NULL) {
03264 cpl_msg_error(func, "Incompatible master bias");
03265 cpl_error_set(func, CPL_ERROR_INCOMPATIBLE_INPUT);
03266 }
03267 return unbiased;
03268 }
03269 mean_bias_level = cpl_image_get_mean(bias);
03270 }
03271 else {
03272 if (nrows == 1) {
03273 cpl_msg_error(func, "No master bias in input, and no overscan "
03274 "regions in input image: bias subtraction "
03275 "cannot be performed!");
03276 cpl_error_set(func, CPL_ERROR_DATA_NOT_FOUND);
03277 return NULL;
03278 }
03279 mean_bias_level = 0.0;
03280 }
03281
03282 mean_overscans_level = 0.0;
03283 count = 0;
03284 for (i = 0; i < nrows; i++) {
03285 xlow = cpl_table_get_int(overscans, "xlow", i, NULL);
03286 ylow = cpl_table_get_int(overscans, "ylow", i, NULL);
03287 xhig = cpl_table_get_int(overscans, "xhig", i, NULL);
03288 yhig = cpl_table_get_int(overscans, "yhig", i, NULL);
03289
03290 if (i == 0) {
03291 unbiased = cpl_image_extract(image, xlow+1, ylow+1, xhig, yhig);
03292 if (unbiased == NULL) {
03293 cpl_msg_error(func, "Incompatible overscan table");
03294 cpl_error_set(func, CPL_ERROR_INCOMPATIBLE_INPUT);
03295 return NULL;
03296 }
03297 if (bias) {
03298 if (cpl_image_subtract(unbiased, bias)) {
03299 cpl_msg_error(func, "Incompatible master bias");
03300 cpl_error_set(func, CPL_ERROR_INCOMPATIBLE_INPUT);
03301 cpl_image_delete(unbiased);
03302 return NULL;
03303 }
03304 }
03305 }
03306 else {
03307 overscan = cpl_image_extract(image, xlow+1, ylow+1, xhig, yhig);
03308 if (overscan == NULL) {
03309 cpl_msg_error(func, "Incompatible overscan table");
03310 cpl_error_set(func, CPL_ERROR_INCOMPATIBLE_INPUT);
03311 cpl_image_delete(unbiased);
03312 return NULL;
03313 }
03314
03315 mean_overscans_level += cpl_image_get_median(overscan);
03316 count++;
03317
03318
03319
03320
03321
03322
03323
03324
03325 cpl_image_delete(overscan);
03326 }
03327 }
03328
03329
03330
03331
03332
03333 mean_overscans_level /= count;
03334
03335 cpl_image_subtract_scalar(unbiased, mean_overscans_level - mean_bias_level);
03336
03337 return unbiased;
03338
03339 }
03340
03341
03400 cpl_error_code mos_arc_background_1D(float *spectrum, float *back,
03401 int length, int msize, int fsize)
03402 {
03403 const char *func = "mos_arc_background_1D";
03404
03405 float *minf;
03406 float *maxf;
03407 float *smof;
03408 int i;
03409
03410
03411 if (spectrum == NULL || back == NULL)
03412 return cpl_error_set(func, CPL_ERROR_NULL_INPUT);
03413
03414 if (msize % 2 == 0)
03415 msize++;
03416
03417 if (fsize % 2 == 0)
03418 fsize++;
03419
03420 if (msize < 3 || fsize < msize || length < 2*fsize)
03421 return cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
03422
03423
03424 minf = min_filter(spectrum, length, msize);
03425 smof = smo_filter(minf, length, fsize);
03426 cpl_free(minf);
03427 maxf = max_filter(smof, length, 2*msize+1);
03428 cpl_free(smof);
03429 smof = smo_filter(maxf, length, 2*fsize+1);
03430 cpl_free(maxf);
03431 minf = min_filter(smof, length, 2*msize+1);
03432 cpl_free(smof);
03433 smof = smo_filter(minf, length, 2*fsize+1);
03434 cpl_free(minf);
03435
03436 for (i = 0; i < length; i++)
03437 back[i] = smof[i];
03438
03439 cpl_free(smof);
03440
03441 return CPL_ERROR_NONE;
03442
03443 }
03444
03445
03502 cpl_image *mos_arc_background(cpl_image *image, int msize, int fsize)
03503 {
03504 const char *func = "mos_arc_background";
03505
03506 cpl_image *fimage;
03507 cpl_image *bimage;
03508 cpl_matrix *kernel;
03509 float *data;
03510 float *bdata;
03511 float *row;
03512 float *brow;
03513 int nx, ny;
03514 int i;
03515
03516
03517 if (image == NULL) {
03518 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
03519 return NULL;
03520 }
03521
03522 if (msize % 2 == 0)
03523 msize++;
03524
03525 if (fsize % 2 == 0)
03526 fsize++;
03527
03528 nx = cpl_image_get_size_x(image);
03529 ny = cpl_image_get_size_y(image);
03530
03531 bimage = cpl_image_new(nx, ny, CPL_TYPE_FLOAT);
03532
03533 kernel = cpl_matrix_new(3, 3);
03534 cpl_matrix_fill(kernel, 1.0);
03535 fimage = cpl_image_filter_median(image, kernel);
03536 cpl_matrix_delete(kernel);
03537
03538 data = cpl_image_get_data_float(fimage);
03539 bdata = cpl_image_get_data_float(bimage);
03540
03541 for (i = 0; i < ny; i++) {
03542 row = data + i * nx;
03543 brow = bdata + i * nx;
03544 if (mos_arc_background_1D(row, brow, nx, msize, fsize)) {
03545 cpl_error_set_where(func);
03546 cpl_image_delete(fimage);
03547 cpl_image_delete(bimage);
03548 return NULL;
03549 }
03550 }
03551
03552 cpl_image_delete(fimage);
03553
03554 return bimage;
03555 }
03556
03557
03578 int mos_lines_width(float *spectrum, int length)
03579 {
03580
03581 const char *func = "mos_lines_width";
03582
03583 double *profile1 = cpl_calloc(length - 1, sizeof(double));
03584 double *profile2 = cpl_calloc(length - 1, sizeof(double));
03585
03586 double norm, value, max;
03587 int radius = 20;
03588 int short_length = length - 2*radius - 1;
03589 int width;
03590 int i, j, k;
03591
03592
03593
03594
03595
03596
03597 for (j = 0, i = 1; i < length; j++, i++) {
03598 profile1[j] = profile2[j] = spectrum[i] - spectrum[j];
03599 if (profile1[j] < 0)
03600 profile1[j] = 0;
03601 if (profile2[j] > 0)
03602 profile2[j] = 0;
03603 else
03604 profile2[j] = -profile2[j];
03605 }
03606
03607
03608
03609
03610
03611
03612 length--;
03613
03614 norm = 0;
03615 for (i = 0; i < length; i++)
03616 if (norm < profile1[i])
03617 norm = profile1[i];
03618
03619 for (i = 0; i < length; i++) {
03620 profile1[i] /= norm;
03621 profile2[i] /= norm;
03622 }
03623
03624
03625
03626
03627
03628
03629 max = -1;
03630 for (i = 0; i <= radius; i++) {
03631 value = 0;
03632 for (j = 0; j < short_length; j++) {
03633 k = radius+j;
03634 value += profile1[k] * profile2[k+i];
03635 }
03636 if (max < value) {
03637 max = value;
03638 width = i;
03639 }
03640 }
03641
03642 cpl_free(profile1);
03643 cpl_free(profile2);
03644
03645 if (max < 0.0) {
03646 cpl_msg_debug(func, "Cannot estimate line width");
03647 width = 1;
03648 }
03649
03650 return width;
03651
03652 }
03653
03654
03681 cpl_vector *mos_peak_candidates(float *spectrum, int length, float level,
03682 float exp_width)
03683 {
03684
03685 const char *func = "mos_peak_candidates";
03686
03687 int i, j;
03688 int nint = length - 1;
03689 int n = 0;
03690 int width = 2 * ceil(exp_width / 2) + 1;
03691 int start = width / 2;
03692 int end = length - width / 2;
03693 int step;
03694 float *smo;
03695 double *data = cpl_calloc(length/2, sizeof(double));
03696
03697
03698 if (spectrum == NULL) {
03699 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
03700 return NULL;
03701 }
03702
03703
03704
03705
03706
03707
03708
03709 if (width > 7) {
03710 smo = cpl_calloc(length, sizeof(float));
03711 start = width / 2;
03712 end = length - width / 2;
03713 for (i = 0; i < start; i++)
03714 smo[i] = spectrum[i];
03715 for (i = start; i < end; i++) {
03716 for (j = i - start; j <= i + start; j++)
03717 smo[i] += spectrum[j];
03718 smo[i] /= width;
03719 }
03720 for (i = end; i < length; i++)
03721 smo[i] = spectrum[i];
03722 }
03723 else {
03724 smo = spectrum;
03725 }
03726
03727
03728
03729
03730
03731
03732 if (width > 20)
03733 step = width / 2;
03734 else
03735 step = 1;
03736
03737 for (i = step; i < nint - step + 1; i += step) {
03738 if (smo[i] > level) {
03739 if (smo[i] >= smo[i-step] && smo[i] > smo[i+step]) {
03740 if (smo[i-step] != 0.0 && smo[i+step] != 0.0) {
03741 data[n] = i + step * values_to_dx(smo[i-step], smo[i], smo[i+step]);
03742 ++n;
03743 }
03744 }
03745 }
03746 }
03747
03748 if (width > 7) {
03749 cpl_free(smo);
03750 }
03751
03752 if (n == 0) {
03753 cpl_free(data);
03754 return NULL;
03755 }
03756
03757 return cpl_vector_wrap(n, data);
03758
03759 }
03760
03761
03783 cpl_vector *mos_refine_peaks(float *spectrum, int length,
03784 cpl_vector *peaks, int sradius)
03785 {
03786
03787 const char *func = "mos_refine_peaks";
03788
03789 double *data;
03790 float pos;
03791 int npeaks;
03792 int startPos, endPos;
03793 int window = 2*sradius+1;
03794 int i, j;
03795
03796
03797 if (peaks == NULL || spectrum == NULL) {
03798 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
03799 return NULL;
03800 }
03801
03802 npeaks = cpl_vector_get_size(peaks);
03803 data = cpl_vector_unwrap(peaks);
03804
03805 for (i = 0; i < npeaks; i++) {
03806 startPos = data[i] - window/2;
03807 endPos = startPos + window;
03808 if (startPos < 0 || endPos >= length)
03809 continue;
03810
03811 if (0 == peakPosition(spectrum + startPos, window, &pos, 1)) {
03812 pos += startPos;
03813 data[i] = pos;
03814 }
03815 }
03816
03817 for (i = 1; i < npeaks; i++)
03818 if (data[i] - data[i-1] < 0.5)
03819 data[i-1] = -1.0;
03820
03821 for (i = 0, j = 0; i < npeaks; i++) {
03822 if (data[i] > 0.0) {
03823 if (i != j)
03824 data[j] = data[i];
03825 j++;
03826 }
03827 }
03828
03829 return cpl_vector_wrap(j, data);
03830
03831 }
03832
03833
03887 cpl_bivector *mos_identify_peaks(cpl_vector *peaks, cpl_vector *lines,
03888 double min_disp, double max_disp,
03889 double tolerance)
03890 {
03891
03892 int i, j, k, l;
03893 int nlint, npint;
03894 int minpos;
03895 float min;
03896 double lratio, pratio;
03897 double lo_start, lo_end, hi_start, hi_end, denom;
03898 double disp, variation, prev_variation;
03899 int max, maxpos, minl, mink;
03900 int ambiguous;
03901 int npeaks_lo, npeaks_hi;
03902 int *peak_lo;
03903 int *peak_hi;
03904 int **ident;
03905 int *nident;
03906 int *lident;
03907
03908 double *peak;
03909 double *line;
03910 int npeaks, nlines;
03911
03912 double *xpos;
03913 double *lambda;
03914 int *ilambda;
03915 double *tmp_xpos;
03916 double *tmp_lambda;
03917 int *tmp_ilambda;
03918 int *flag;
03919 int n = 0;
03920 int nn;
03921 int nseq = 0;
03922 int gap;
03923 int *seq_length;
03924 int found;
03925
03926 peak = cpl_vector_get_data(peaks);
03927 npeaks = cpl_vector_get_size(peaks);
03928 line = cpl_vector_get_data(lines);
03929 nlines = cpl_vector_get_size(lines);
03930
03931 if (npeaks < 4)
03932 return NULL;
03933
03934 peak_lo = cpl_malloc(npeaks * sizeof(int));
03935 peak_hi = cpl_malloc(npeaks * sizeof(int));
03936 nident = cpl_calloc(npeaks, sizeof(int));
03937 lident = cpl_calloc(nlines, sizeof(int));
03938 xpos = cpl_calloc(npeaks, sizeof(double));
03939 lambda = cpl_calloc(npeaks, sizeof(double));
03940 ilambda = cpl_calloc(npeaks, sizeof(int));
03941 tmp_xpos = cpl_calloc(npeaks, sizeof(double));
03942 tmp_lambda = cpl_calloc(npeaks, sizeof(double));
03943 tmp_ilambda = cpl_calloc(npeaks, sizeof(int));
03944 flag = cpl_calloc(npeaks, sizeof(int));
03945 seq_length = cpl_calloc(npeaks, sizeof(int));
03946 ident = cpl_malloc(npeaks * sizeof(int *));
03947 for (i = 0; i < npeaks; i++)
03948 ident[i] = cpl_malloc(3 * npeaks * sizeof(int));
03949
03950
03951
03952
03953
03954
03955 nlint = nlines - 1;
03956 npint = npeaks - 1;
03957
03958
03959
03960
03961
03962
03963 for (i = 1; i < nlint; i++) {
03964
03965
03966
03967
03968
03969
03970
03971
03972
03973 lratio = (line[i+1] - line[i]) / (line[i] - line[i-1]);
03974
03975
03976
03977
03978
03979
03980 for (j = 1; j < npint; j++) {
03981
03982
03983
03984
03985
03986
03987
03988
03989
03990
03991
03992
03993 lo_start = peak[j] - (line[i] - line[i-1]) / min_disp;
03994 lo_end = peak[j] - (line[i] - line[i-1]) / max_disp;
03995 hi_start = peak[j] + (line[i+1] - line[i]) / max_disp;
03996 hi_end = peak[j] + (line[i+1] - line[i]) / min_disp;
03997
03998 for (npeaks_lo = 0, k = 0; k < npeaks; k++) {
03999 if (peak[k] > lo_end)
04000 break;
04001 if (peak[k] > lo_start) {
04002 peak_lo[npeaks_lo] = k;
04003 ++npeaks_lo;
04004 }
04005 }
04006
04007 if (npeaks_lo == 0)
04008 continue;
04009
04010 for (npeaks_hi = 0, k = 0; k < npeaks; k++) {
04011 if (peak[k] > hi_end)
04012 break;
04013 if (peak[k] > hi_start) {
04014 peak_hi[npeaks_hi] = k;
04015 ++npeaks_hi;
04016 }
04017 }
04018
04019 if (npeaks_hi == 0)
04020 continue;
04021
04022
04023
04024
04025
04026
04027
04028
04029
04030
04031 prev_variation = 1000.0;
04032 minl = mink = 0;
04033
04034 for (k = 0; k < npeaks_lo; k++) {
04035 denom = peak[j] - peak[peak_lo[k]];
04036 for (l = 0; l < npeaks_hi; l++) {
04037
04038
04039
04040
04041
04042
04043
04044 pratio = (peak[peak_hi[l]] - peak[j]) / denom;
04045
04046
04047
04048
04049
04050
04051
04052
04053
04054
04055
04056
04057 variation = fabs(lratio-pratio) / pratio;
04058
04059 if (variation < tolerance) {
04060 if (variation < prev_variation) {
04061 prev_variation = variation;
04062 minl = l;
04063 mink = k;
04064 }
04065 }
04066 }
04067 }
04068 if (prev_variation < tolerance) {
04069 ident[j][nident[j]] = i;
04070 ident[peak_hi[minl]][nident[peak_hi[minl]]] = i + 1;
04071 ident[peak_lo[mink]][nident[peak_lo[mink]]] = i - 1;
04072 ++nident[j];
04073 ++nident[peak_hi[minl]];
04074 ++nident[peak_lo[mink]];
04075 }
04076 }
04077 }
04078
04079
04080
04081
04082
04083
04084
04085
04086 for (i = 0; i < npeaks; i++) {
04087
04088
04089
04090
04091
04092
04093
04094
04095 if (nident[i] > 1) {
04096
04097
04098
04099
04100
04101
04102 for (j = 0; j < nlines; j++)
04103 lident[j] = 0;
04104
04105
04106
04107
04108
04109
04110
04111 for (j = 0; j < nident[i]; j++)
04112 ++lident[ident[i][j]];
04113
04114
04115
04116
04117
04118
04119 max = 0;
04120 maxpos = 0;
04121 for (j = 0; j < nlines; j++) {
04122 if (max < lident[j]) {
04123 max = lident[j];
04124 maxpos = j;
04125 }
04126 }
04127
04128
04129
04130
04131
04132
04133
04134
04135 ambiguous = 0;
04136
04137 for (k = maxpos + 1; k < nlines; k++) {
04138 if (lident[k] == max) {
04139 ambiguous = 1;
04140 break;
04141 }
04142 }
04143
04144 if (ambiguous)
04145 continue;
04146
04147
04148
04149
04150
04151
04152
04153 tmp_xpos[n] = peak[i];
04154 tmp_lambda[n] = line[maxpos];
04155 tmp_ilambda[n] = maxpos;
04156
04157 ++n;
04158
04159 }
04160
04161 }
04162
04163
04164
04165
04166
04167
04168
04169
04170
04171
04172
04173
04174
04175
04176 if (n > 1) {
04177 nn = 0;
04178 nseq = 0;
04179 for (k = 0; k < n; k++) {
04180 if (flag[k] == 0) {
04181 flag[k] = 1;
04182 xpos[nn] = tmp_xpos[k];
04183 lambda[nn] = tmp_lambda[k];
04184 ilambda[nn] = tmp_ilambda[k];
04185 ++seq_length[nseq];
04186 ++nn;
04187
04188
04189
04190
04191
04192
04193
04194 i = k;
04195 while (i < n - 1) {
04196 found = 0;
04197 for (j = i + 1; j < n; j++) {
04198 if (flag[j] == 0) {
04199 disp = (tmp_lambda[j] - tmp_lambda[i])
04200 / (tmp_xpos[j] - tmp_xpos[i]);
04201 if (disp >= min_disp && disp <= max_disp) {
04202 flag[j] = 1;
04203 xpos[nn] = tmp_xpos[j];
04204 lambda[nn] = tmp_lambda[j];
04205 ilambda[nn] = tmp_ilambda[j];
04206 ++seq_length[nseq];
04207 ++nn;
04208 i = j;
04209 found = 1;
04210 break;
04211 }
04212 }
04213 }
04214 if (!found)
04215 break;
04216 }
04217
04218
04219
04220
04221
04222
04223 ++nseq;
04224 k = 0;
04225 }
04226 }
04227
04228
04229
04230
04231
04232
04233 max = 0;
04234 maxpos = 0;
04235 for (i = 0; i < nseq; i++) {
04236 if (seq_length[i] > max) {
04237 max = seq_length[i];
04238 maxpos = i;
04239 }
04240 }
04241
04242
04243
04244
04245
04246
04247 nn = 0;
04248 for (i = 0; i < maxpos; i++)
04249 nn += seq_length[i];
04250
04251
04252
04253
04254
04255 n = max;
04256 for (i = 0; i < n; i++, nn++) {
04257 xpos[i] = xpos[nn];
04258 lambda[i] = lambda[nn];
04259 ilambda[i] = ilambda[nn];
04260 }
04261
04262
04263
04264
04265
04266
04267 for (i = 1; i < n; i++) {
04268 gap = ilambda[i] - ilambda[i-1];
04269 for (j = 1; j < gap; j++) {
04270
04271 if (j == 1) {
04272
04273
04274
04275
04276
04277 disp = (lambda[i] - lambda[i-1]) / (xpos[i] - xpos[i-1]);
04278 }
04279
04280
04281
04282
04283
04284
04285 hi_start = xpos[i-1] + (line[ilambda[i-1] + j] - lambda[i-1]) / disp;
04286
04287
04288
04289
04290
04291
04292
04293
04294
04295
04296
04297
04298
04299 found = 0;
04300 for (k = 0; k < npeaks; k++) {
04301 if (fabs(peak[k] - hi_start) < 2) {
04302 for (l = n; l > i; l--) {
04303 xpos[l] = xpos[l-1];
04304 lambda[l] = lambda[l-1];
04305 ilambda[l] = ilambda[l-1];
04306 }
04307 xpos[i] = peak[k];
04308 lambda[i] = line[ilambda[i-1] + j];
04309 ilambda[i] = ilambda[i-1] + j;
04310 ++n;
04311 found = 1;
04312 break;
04313 }
04314 }
04315 if (found)
04316 break;
04317 }
04318 }
04319
04320
04321
04322
04323
04324
04325 found = 1;
04326 while (ilambda[n-1] < nlines - 1 && found) {
04327
04328
04329
04330
04331
04332
04333 if (n > 1)
04334 disp = (lambda[n-1] - lambda[n-2]) / (xpos[n-1] - xpos[n-2]);
04335 else
04336 disp = 0.0;
04337
04338 if (disp > max_disp || disp < min_disp)
04339 break;
04340
04341
04342
04343
04344
04345
04346
04347 hi_start = xpos[n-1] + (line[ilambda[n-1] + 1] - lambda[n-1]) / disp;
04348
04349
04350
04351
04352
04353
04354
04355
04356
04357 found = 0;
04358 min = fabs(peak[0] - hi_start);
04359 minpos = 0;
04360 for (k = 1; k < npeaks; k++) {
04361 if (min > fabs(peak[k] - hi_start)) {
04362 min = fabs(peak[k] - hi_start);
04363 minpos = k;
04364 }
04365 }
04366 if (min < 6 && fabs(peak[minpos] - xpos[n-1]) > 1.0) {
04367 xpos[n] = peak[minpos];
04368 lambda[n] = line[ilambda[n-1] + 1];
04369 ilambda[n] = ilambda[n-1] + 1;
04370 ++n;
04371 found = 1;
04372 }
04373 }
04374
04375
04376
04377
04378
04379
04380 found = 1;
04381 while (ilambda[0] > 0 && found) {
04382
04383
04384
04385
04386
04387
04388 disp = (lambda[1] - lambda[0]) / (xpos[1] - xpos[0]);
04389
04390 if (disp > max_disp || disp < min_disp)
04391 break;
04392
04393
04394
04395
04396
04397
04398
04399 hi_start = xpos[0] - (lambda[0] - line[ilambda[0] - 1]) / disp;
04400
04401
04402
04403
04404
04405
04406
04407
04408
04409
04410 found = 0;
04411 min = fabs(peak[0] - hi_start);
04412 minpos = 0;
04413 for (k = 1; k < npeaks; k++) {
04414 if (min > fabs(peak[k] - hi_start)) {
04415 min = fabs(peak[k] - hi_start);
04416 minpos = k;
04417 }
04418 }
04419 if (min < 6 && fabs(peak[minpos] - xpos[0]) > 1.0) {
04420 for (j = n; j > 0; j--) {
04421 xpos[j] = xpos[j-1];
04422 lambda[j] = lambda[j-1];
04423 ilambda[j] = ilambda[j-1];
04424 }
04425 xpos[0] = peak[minpos];
04426 lambda[0] = line[ilambda[0] - 1];
04427 ilambda[0] = ilambda[0] - 1;
04428 ++n;
04429 found = 1;
04430 }
04431 }
04432 }
04433
04434
04435
04436
04437
04438
04439
04440
04441
04442
04443
04444
04445
04446
04447
04448
04449
04450
04451
04452
04453 for (i = 0; i < npeaks; i++)
04454 cpl_free(ident[i]);
04455 cpl_free(ident);
04456 cpl_free(nident);
04457 cpl_free(lident);
04458 cpl_free(ilambda);
04459 cpl_free(tmp_xpos);
04460 cpl_free(tmp_lambda);
04461 cpl_free(tmp_ilambda);
04462 cpl_free(peak_lo);
04463 cpl_free(flag);
04464 cpl_free(seq_length);
04465 cpl_free(peak_hi);
04466
04467 if (n == 0) {
04468 cpl_free(xpos);
04469 cpl_free(lambda);
04470 return NULL;
04471 }
04472
04473 return cpl_bivector_wrap_vectors(cpl_vector_wrap(n, xpos),
04474 cpl_vector_wrap(n, lambda));
04475 }
04476
04477
04495
04496
04497
04498
04499
04500
04501
04502
04503
04504
04505
04506
04507
04508
04509
04510
04511
04512
04513
04514
04515
04516
04517
04518
04519
04520
04521
04522
04523
04524
04525
04526
04527
04528
04529
04530
04531
04532
04533
04534
04535 double mos_eval_dds(cpl_polynomial *ids, double blue, double red,
04536 double refwave, double pixel)
04537 {
04538 double yellow;
04539 double coeff;
04540 int zero = 0;
04541
04542 if (cpl_polynomial_eval_1d(ids, blue-refwave, NULL) > pixel)
04543 return 0.0;
04544
04545 if (cpl_polynomial_eval_1d(ids, red-refwave, NULL) < pixel)
04546 return 0.0;
04547
04548 yellow = (blue + red) / 2 - refwave;
04549
04550 coeff = cpl_polynomial_get_coeff(ids, &zero);
04551 cpl_polynomial_set_coeff(ids, &zero, coeff - pixel);
04552
04553 cpl_polynomial_solve_1d(ids, yellow, &yellow, 1);
04554
04555 cpl_polynomial_set_coeff(ids, &zero, coeff);
04556
04557 return yellow + refwave;
04558
04559 }
04560
04586 cpl_polynomial *mos_poly_wav2pix(cpl_bivector *pixwav, int order,
04587 double reject, int minlines,
04588 int *nlines, double *err)
04589 {
04590 const char *func = "mos_poly_wav2pix";
04591
04592 cpl_bivector *pixwav2;
04593 cpl_vector *wavel;
04594 cpl_vector *pixel;
04595 double *d_wavel;
04596 double *d_pixel;
04597 double pixpos;
04598 int fitlines;
04599 int rejection = 0;
04600 int i, j;
04601
04602 cpl_polynomial *ids;
04603
04604
04605 *nlines = 0;
04606 *err = 0;
04607
04608 if (pixwav == NULL) {
04609 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
04610 return NULL;
04611 }
04612
04613 fitlines = cpl_bivector_get_size(pixwav);
04614
04615 if (fitlines < minlines) {
04616 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
04617 return NULL;
04618 }
04619
04620
04621
04622
04623
04624
04625
04626 if (reject > 0.0)
04627 rejection = 1;
04628
04629 if (rejection)
04630 pixwav2 = cpl_bivector_duplicate(pixwav);
04631 else
04632 pixwav2 = pixwav;
04633
04634
04635
04636
04637
04638
04639
04640 pixel = cpl_bivector_get_x(pixwav2);
04641 wavel = cpl_bivector_get_y(pixwav2);
04642
04643
04644
04645
04646
04647
04648 if (rejection)
04649 cpl_bivector_unwrap_vectors(pixwav2);
04650
04651
04652
04653
04654
04655
04656 while (fitlines >= minlines) {
04657
04658 ids = cpl_polynomial_fit_1d_create(wavel, pixel, order, err);
04659 *err = sqrt(*err);
04660
04661 if (ids == NULL) {
04662 cpl_msg_debug(cpl_error_get_where(), cpl_error_get_message());
04663 cpl_msg_debug(func, "Fitting IDS");
04664 cpl_error_set_where(func);
04665 if (rejection) {
04666 cpl_vector_delete(wavel);
04667 cpl_vector_delete(pixel);
04668 }
04669 return NULL;
04670 }
04671
04672 if (rejection) {
04673
04674
04675
04676
04677
04678
04679 d_pixel = cpl_vector_unwrap(pixel);
04680 d_wavel = cpl_vector_unwrap(wavel);
04681
04682 for (i = 0, j = 0; i < fitlines; i++) {
04683 pixpos = cpl_polynomial_eval_1d(ids, d_wavel[i], NULL);
04684 if (fabs(pixpos - d_pixel[i]) < reject) {
04685 d_pixel[j] = d_pixel[i];
04686 d_wavel[j] = d_wavel[i];
04687 j++;
04688 }
04689 }
04690
04691 if (j == fitlines) {
04692 cpl_free(d_wavel);
04693 cpl_free(d_pixel);
04694 *nlines = fitlines;
04695 return ids;
04696 }
04697 else {
04698 fitlines = j;
04699 cpl_polynomial_delete(ids);
04700 if (fitlines >= minlines) {
04701 pixel = cpl_vector_wrap(fitlines, d_pixel);
04702 wavel = cpl_vector_wrap(fitlines, d_wavel);
04703 }
04704 else {
04705 cpl_free(d_wavel);
04706 cpl_free(d_pixel);
04707 cpl_error_set(func, CPL_ERROR_CONTINUE);
04708 return NULL;
04709 }
04710 }
04711 }
04712 else {
04713 *nlines = fitlines;
04714 return ids;
04715 }
04716 }
04717
04718 return ids;
04719 }
04720
04721
04746 cpl_polynomial *mos_poly_pix2wav(cpl_bivector *pixwav, int order,
04747 double reject, int minlines,
04748 int *nlines, double *err)
04749 {
04750
04751 cpl_bivector *wavpix;
04752 cpl_vector *wavel;
04753 cpl_vector *pixel;
04754
04755 cpl_polynomial *dds;
04756
04757
04758
04759
04760
04761
04762 pixel = cpl_bivector_get_x(pixwav);
04763 wavel = cpl_bivector_get_y(pixwav);
04764
04765 wavpix = cpl_bivector_wrap_vectors(wavel, pixel);
04766
04767 dds = mos_poly_wav2pix(wavpix, order, reject, minlines, nlines, err);
04768
04769 cpl_bivector_unwrap_vectors(wavpix);
04770
04771 return dds;
04772
04773 }
04774
04775
04798 cpl_bivector *mos_find_peaks(float *spectrum, int length, cpl_vector *lines,
04799 cpl_polynomial *ids, double refwave, int sradius)
04800 {
04801 const char *func = "mos_find_peaks";
04802
04803 double *data;
04804 double *d_pixel;
04805 double *d_wavel;
04806 float pos;
04807 int nlines;
04808 int pixel;
04809 int i, j;
04810
04811
04812 if (spectrum == NULL || lines == NULL || ids == NULL) {
04813 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
04814 return NULL;
04815 }
04816
04817 nlines = cpl_vector_get_size(lines);
04818
04819 if (sradius < 1 || length < 2*sradius+1 || nlines < 1) {
04820 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
04821 return NULL;
04822 }
04823
04824 d_wavel = cpl_malloc(nlines * sizeof(double));
04825 d_pixel = cpl_malloc(nlines * sizeof(double));
04826
04827 data = cpl_vector_get_data(lines);
04828
04829 for (i = 0, j = 0; i < nlines; i++) {
04830 pixel = cpl_polynomial_eval_1d(ids, data[i]-refwave, NULL) + 0.5;
04831 if (pixel - sradius < 0 || pixel + sradius >= length)
04832 continue;
04833 if (0 == peakPosition(spectrum+pixel-sradius, 2*sradius+1, &pos, 1)) {
04834 pos += pixel - sradius;
04835 d_pixel[j] = pos;
04836 d_wavel[j] = data[i];
04837 j++;
04838 }
04839 }
04840
04841 if (j > 0) {
04842 return cpl_bivector_wrap_vectors(cpl_vector_wrap(j, d_pixel),
04843 cpl_vector_wrap(j, d_wavel));
04844 }
04845 else {
04846 cpl_free(d_wavel);
04847 cpl_free(d_pixel);
04848 cpl_error_set(func, CPL_ERROR_ILLEGAL_OUTPUT);
04849 return NULL;
04850 }
04851 }
04852
04853
04971 cpl_image *mos_wavelength_calibration_raw(cpl_image *image, cpl_vector *lines,
04972 double dispersion, float level,
04973 int sradius, int order,
04974 double reject, double refwave,
04975 double *wavestart, double *waveend,
04976 int *nlines, double *error,
04977 cpl_table *idscoeff,
04978 cpl_image *calibration,
04979 cpl_image *residuals,
04980 cpl_table *restable,
04981 cpl_mask *refmask)
04982 {
04983
04984 const char *func = "mos_wavelength_calibration_raw";
04985
04986 const char *clab[6] = {"c0", "c1", "c2", "c3", "c4", "c5"};
04987
04988
04989 double tolerance = 20.0;
04990 int step = 10;
04991
04992 char name[MAX_COLNAME];
04993 cpl_image *resampled;
04994 cpl_image *bimage;
04995 cpl_bivector *output;
04996 cpl_bivector *new_output;
04997 cpl_vector *peaks;
04998 cpl_vector *wavel;
04999 cpl_polynomial *ids;
05000 cpl_polynomial *lin;
05001 cpl_matrix *kernel;
05002 double ids_err;
05003 double max_disp, min_disp;
05004 double *line;
05005 double firstLambda, lastLambda, lambda;
05006 double value, wave, pixe;
05007 cpl_binary *mdata;
05008 float *sdata;
05009 float *rdata;
05010 float *idata;
05011 float *ddata;
05012 float v1, v2, vi;
05013 float fpixel;
05014 int *have_it;
05015 int pixstart, pixend;
05016 int extrapolation;
05017 int nref;
05018 int nl, nx, ny, npix, pixel;
05019 int count;
05020 int countLines, usedLines;
05021 int uorder;
05022 int in, first, last;
05023 int width, uradius;
05024 int i, j, k;
05025
05026
05027 if (dispersion == 0.0) {
05028 cpl_msg_error(func, "The expected dispersion (A/pixel) must be given");
05029 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
05030 return NULL;
05031 }
05032
05033 if (dispersion < 0.0) {
05034 cpl_msg_error(func, "The expected dispersion must be positive");
05035 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
05036 return NULL;
05037 }
05038
05039 max_disp = dispersion + dispersion * tolerance / 100;
05040 min_disp = dispersion - dispersion * tolerance / 100;
05041
05042 if (order < 1) {
05043 cpl_msg_error(func, "The order of the fitting polynomial "
05044 "must be at least 1");
05045 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
05046 return NULL;
05047 }
05048
05049 if (image == NULL || lines == NULL) {
05050 cpl_msg_error(func, "Both spectral exposure and reference line "
05051 "catalog are required in input");
05052 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
05053 return NULL;
05054 }
05055
05056 nx = cpl_image_get_size_x(image);
05057 ny = cpl_image_get_size_y(image);
05058 sdata = cpl_image_get_data_float(image);
05059
05060 nref = cpl_vector_get_size(lines);
05061 line = cpl_vector_get_data(lines);
05062
05063 if (*wavestart < 1.0 && *waveend < 1.0) {
05064 firstLambda = line[0];
05065 lastLambda = line[nref-1];
05066 extrapolation = (lastLambda - firstLambda) / 10;
05067 firstLambda -= extrapolation;
05068 lastLambda += extrapolation;
05069 *wavestart = firstLambda;
05070 *waveend = lastLambda;
05071 }
05072 else {
05073 firstLambda = *wavestart;
05074 lastLambda = *waveend;
05075 }
05076
05077 nl = (lastLambda - firstLambda) / dispersion;
05078 resampled = cpl_image_new(nl, ny, CPL_TYPE_FLOAT);
05079 rdata = cpl_image_get_data_float(resampled);
05080
05081 if (calibration)
05082 idata = cpl_image_get_data_float(calibration);
05083
05084 if (residuals)
05085 ddata = cpl_image_get_data_float(residuals);
05086
05087 if (idscoeff)
05088 for (j = 0; j <= order; j++)
05089 cpl_table_new_column(idscoeff, clab[j], CPL_TYPE_DOUBLE);
05090
05091 if (restable) {
05092 cpl_table_set_size(restable, nref);
05093 cpl_table_new_column(restable, "wavelength", CPL_TYPE_DOUBLE);
05094 cpl_table_copy_data_double(restable, "wavelength", line);
05095 for (i = 0; i < ny; i += step) {
05096 snprintf(name, MAX_COLNAME, "r%d", i);
05097 cpl_table_new_column(restable, name, CPL_TYPE_DOUBLE);
05098 snprintf(name, MAX_COLNAME, "d%d", i);
05099 cpl_table_new_column(restable, name, CPL_TYPE_DOUBLE);
05100 snprintf(name, MAX_COLNAME, "p%d", i);
05101 cpl_table_new_column(restable, name, CPL_TYPE_DOUBLE);
05102 }
05103 }
05104
05105
05106
05107
05108
05109
05110
05111 npix = nx * ny;
05112
05113 for (i = 0; i < npix - nx; i++)
05114 if (sdata[i] == 0.0 && sdata[i + nx] == 0.0)
05115 sdata[i] = 65535.0;
05116
05117 for (i = npix - nx; i < npix; i++)
05118 if (sdata[i] == 0.0)
05119 sdata[i] = 65535.0;
05120
05121
05122
05123
05124
05125
05126
05127 for (i = 0; i < npix; i++) {
05128 if (sdata[i] >= 65535.0) {
05129 count = 0;
05130 for (j = i; j < npix; j++) {
05131 if (sdata[j] < 65535.0) {
05132 break;
05133 }
05134 else {
05135 count++;
05136 }
05137 }
05138 if (count < 30 && count > 2) {
05139 for (j = i; j < i + count/2; j++)
05140 sdata[j] = sdata[i] + 1000.0 * (j - i);
05141 if (count % 2 != 0) {
05142 sdata[j] = sdata[j-1] + 1000.0;
05143 j++;
05144 }
05145 for (k = j; k <= i + count; k++)
05146 sdata[k] = sdata[i] - 1000.0 * (k - i - count);
05147 i = k;
05148 }
05149 }
05150 }
05151
05152
05153
05154
05155
05156
05157 bimage = mos_arc_background(image, 15, 15);
05158 cpl_image_subtract(image, bimage);
05159 cpl_image_delete(bimage);
05160
05161
05162
05163
05164
05165
05166
05167
05168 for (i = 0; i < ny; i++) {
05169 width = mos_lines_width(sdata + i*nx, nx);
05170 if (sradius > 0) {
05171 if (width > sradius) {
05172 uradius = width;
05173 }
05174 else {
05175 uradius = sradius;
05176 }
05177 }
05178 if (width < 5)
05179 width = 5;
05180 peaks = mos_peak_candidates(sdata + i*nx, nx, level, width);
05181 if (peaks) {
05182 peaks = mos_refine_peaks(sdata + i*nx, nx, peaks, width);
05183 }
05184 if (peaks) {
05185 output = mos_identify_peaks(peaks, lines, min_disp, max_disp, 0.05);
05186 if (output) {
05187 countLines = cpl_bivector_get_size(output);
05188 if (countLines < 4) {
05189 cpl_bivector_delete(output);
05190 cpl_vector_delete(peaks);
05191 if (nlines)
05192 nlines[i] = 0;
05193 if (error)
05194 error[i] = 0.0;
05195 continue;
05196 }
05197
05198
05199
05200
05201
05202 wavel = cpl_bivector_get_y(output);
05203 cpl_vector_subtract_scalar(wavel, refwave);
05204
05205 uorder = countLines / 2 - 1;
05206 if (uorder > order)
05207 uorder = order;
05208
05209
05210
05211
05212
05213
05214
05215
05216
05217
05218 ids = mos_poly_wav2pix(output, uorder, reject,
05219 2 * (uorder + 1), &usedLines,
05220 &ids_err);
05221
05222 if (ids == NULL) {
05223 cpl_bivector_delete(output);
05224 cpl_vector_delete(peaks);
05225 if (nlines)
05226 nlines[i] = 0;
05227 if (error)
05228 error[i] = 0.0;
05229 cpl_error_reset();
05230 continue;
05231 }
05232
05233 if (idscoeff) {
05234
05235
05236
05237
05238
05239
05240
05241 for (k = 0; k <= order; k++) {
05242 if (k > uorder) {
05243 cpl_table_set_double(idscoeff, clab[k], i, 0.0);
05244 }
05245 else {
05246 cpl_table_set_double(idscoeff, clab[k], i,
05247 cpl_polynomial_get_coeff(ids, &k));
05248 }
05249 }
05250 }
05251
05252 if (sradius > 0) {
05253
05254
05255
05256
05257
05258 new_output = mos_find_peaks(sdata + i*nx, nx, lines,
05259 ids, refwave, uradius);
05260
05261 if (new_output) {
05262 cpl_bivector_delete(output);
05263 output = new_output;
05264 }
05265 else
05266 cpl_error_reset();
05267
05268
05269 cpl_polynomial_delete(ids);
05270
05271 countLines = cpl_bivector_get_size(output);
05272
05273 if (countLines < 4) {
05274 cpl_bivector_delete(output);
05275 cpl_vector_delete(peaks);
05276
05277
05278
05279
05280
05281
05282
05283 if (nlines)
05284 nlines[i] = 0;
05285 if (error)
05286 error[i] = 0.0;
05287 if (idscoeff)
05288 for (k = 0; k <= order; k++)
05289 cpl_table_set_invalid(idscoeff, clab[k], i);
05290 continue;
05291 }
05292
05293 wavel = cpl_bivector_get_y(output);
05294 cpl_vector_subtract_scalar(wavel, refwave);
05295
05296 uorder = countLines / 2 - 1;
05297 if (uorder > order)
05298 uorder = order;
05299
05300 ids = mos_poly_wav2pix(output, uorder, reject,
05301 2 * (uorder + 1), &usedLines,
05302 &ids_err);
05303
05304 if (ids == NULL) {
05305 cpl_bivector_delete(output);
05306 cpl_vector_delete(peaks);
05307
05308
05309
05310
05311
05312
05313
05314 if (nlines)
05315 nlines[i] = 0;
05316 if (error)
05317 error[i] = 0.0;
05318 if (idscoeff)
05319 for (k = 0; k <= order; k++)
05320 cpl_table_set_invalid(idscoeff, clab[k], i);
05321 cpl_error_reset();
05322 continue;
05323 }
05324
05325 if (idscoeff) {
05326 for (k = 0; k <= order; k++) {
05327 if (k > uorder) {
05328 cpl_table_set_double(idscoeff, clab[k], i, 0.0);
05329 }
05330 else {
05331 cpl_table_set_double(idscoeff, clab[k], i,
05332 cpl_polynomial_get_coeff(ids, &k));
05333 }
05334 }
05335 }
05336
05337 }
05338
05339 if (nlines)
05340 nlines[i] = usedLines;
05341 if (error)
05342 error[i] = ids_err / sqrt(usedLines/(uorder + 1));
05343
05344 pixstart = cpl_polynomial_eval_1d(ids,
05345 cpl_bivector_get_y_data(output)[0], NULL);
05346 pixend = cpl_polynomial_eval_1d(ids,
05347 cpl_bivector_get_y_data(output)[countLines-1], NULL);
05348 extrapolation = (pixend - pixstart) / 5;
05349 pixstart -= extrapolation;
05350 pixend += extrapolation;
05351 if (pixstart < 0)
05352 pixstart = 0;
05353 if (pixend > nx)
05354 pixend = nx;
05355
05356
05357
05358
05359
05360 if (calibration) {
05361 for (j = pixstart; j < pixend; j++) {
05362 (idata + i*nx)[j] = mos_eval_dds(ids, firstLambda,
05363 lastLambda, refwave,
05364 j);
05365 }
05366 }
05367
05368
05369
05370
05371
05372 for (j = 0; j < nl; j++) {
05373 lambda = firstLambda + j * dispersion;
05374 fpixel = cpl_polynomial_eval_1d(ids, lambda - refwave,
05375 NULL);
05376 pixel = fpixel;
05377 if (pixel >= 0 && pixel < nx-1) {
05378 v1 = (sdata + i*nx)[pixel];
05379 v2 = (sdata + i*nx)[pixel+1];
05380 vi = v1 + (v2-v1)*(fpixel-pixel);
05381 (rdata + i*nl)[j] = vi;
05382 }
05383 }
05384
05385
05386
05387
05388
05389 if (residuals || (restable && !(i%step))) {
05390 if (restable && !(i%step)) {
05391 lin = cpl_polynomial_new(1);
05392 for (k = 0; k < 2; k++)
05393 cpl_polynomial_set_coeff(lin, &k,
05394 cpl_polynomial_get_coeff(ids, &k));
05395 }
05396 for (j = 0; j < countLines; j++) {
05397 pixe = cpl_bivector_get_x_data(output)[j];
05398 wave = cpl_bivector_get_y_data(output)[j];
05399 value = pixe - cpl_polynomial_eval_1d(ids, wave, NULL);
05400 if (residuals) {
05401 pixel = pixe + 0.5;
05402 (ddata + i*nx)[pixel] = value;
05403 }
05404 if (restable && !(i%step)) {
05405 for (k = 0; k < nref; k++) {
05406 if (fabs(line[k] - refwave - wave) < 0.1) {
05407 snprintf(name, MAX_COLNAME, "r%d", i);
05408 cpl_table_set_double(restable, name,
05409 k, value);
05410 value = pixe
05411 - cpl_polynomial_eval_1d(lin, wave,
05412 NULL);
05413 snprintf(name, MAX_COLNAME, "d%d", i);
05414 cpl_table_set_double(restable, name,
05415 k, value);
05416 snprintf(name, MAX_COLNAME, "p%d", i);
05417 cpl_table_set_double(restable, name,
05418 k, pixe);
05419 break;
05420 }
05421 }
05422 }
05423 }
05424 if (restable && !(i%step)) {
05425 cpl_polynomial_delete(lin);
05426 }
05427 }
05428
05429
05430
05431
05432
05433 if (refmask) {
05434 mdata = cpl_mask_get_data(refmask);
05435 pixel = cpl_polynomial_eval_1d(ids, 0.0, NULL) + 0.5;
05436 if (pixel - 1 >= 0 && pixel + 1 < nx) {
05437 mdata[pixel-1 + i*nx] = CPL_BINARY_1;
05438 mdata[pixel + i*nx] = CPL_BINARY_1;
05439 mdata[pixel+1 + i*nx] = CPL_BINARY_1;
05440 }
05441 }
05442
05443 cpl_polynomial_delete(ids);
05444 cpl_bivector_delete(output);
05445 }
05446 cpl_vector_delete(peaks);
05447 }
05448 }
05449
05450 if (refmask) {
05451 kernel = cpl_matrix_new(3, 3);
05452 cpl_matrix_set(kernel, 0, 1, 1.0);
05453 cpl_matrix_set(kernel, 1, 1, 1.0);
05454 cpl_matrix_set(kernel, 2, 1, 1.0);
05455
05456 cpl_mask_dilation(refmask, kernel);
05457 cpl_mask_erosion(refmask, kernel);
05458 cpl_mask_erosion(refmask, kernel);
05459 cpl_mask_dilation(refmask, kernel);
05460
05461 cpl_matrix_delete(kernel);
05462
05463
05464
05465
05466
05467 mdata = cpl_mask_get_data(refmask);
05468 have_it = cpl_calloc(ny, sizeof(int));
05469
05470 for (i = 0; i < ny; i++, mdata += nx) {
05471 for (j = 0; j < nx; j++) {
05472 if (mdata[j] == CPL_BINARY_1) {
05473 have_it[i] = j;
05474 break;
05475 }
05476 }
05477 }
05478
05479 mdata = cpl_mask_get_data(refmask);
05480 in = 0;
05481 first = last = 0;
05482
05483 for (i = 0; i < ny; i++) {
05484 if (have_it[i]) {
05485 if (!in) {
05486 in = 1;
05487 if (first) {
05488 last = i;
05489 if (abs(have_it[first] - have_it[last]) < 3) {
05490 for (j = first; j < last; j++) {
05491 mdata[have_it[first] + nx*j + 0] = CPL_BINARY_1;
05492 mdata[have_it[first] + nx*j + 1] = CPL_BINARY_1;
05493 mdata[have_it[first] + nx*j + 2] = CPL_BINARY_1;
05494 }
05495 }
05496 }
05497 }
05498 }
05499 else {
05500 if (in) {
05501 in = 0;
05502 first = i - 1;
05503 }
05504 }
05505 }
05506
05507 cpl_free(have_it);
05508
05509 }
05510
05511
05512
05513
05514
05515
05516
05517
05518
05519
05520
05521 return resampled;
05522 }
05523
05524
05546
05547
05548
05549
05550
05551
05552
05553
05554
05555
05556
05557
05558
05559
05560
05561
05562
05563
05564
05565
05566
05567
05568
05569
05570
05571
05572
05573
05574
05575
05576
05577
05578
05579
05580
05581
05582
05583
05584
05585
05586
05587
05588
05589
05590
05591
05592
05593
05594
05595
05596
05597
05598
05599
05600
05601
05602
05603
05604
05605
05606
05607
05608
05609
05610
05611
05633 cpl_table *mos_locate_spectra(cpl_mask *mask)
05634 {
05635 const char *func = "mos_locate_spectra";
05636
05637 cpl_apertures *slits;
05638 cpl_image *labimage;
05639 cpl_image *refimage;
05640 cpl_table *slitpos;
05641 cpl_propertylist *sort_col;
05642 int nslits;
05643 int i;
05644
05645
05646 if (mask == NULL) {
05647 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
05648 return NULL;
05649 }
05650
05651 labimage = cpl_image_labelise_mask_create(mask, &nslits);
05652
05653 if (nslits < 1) {
05654 cpl_image_delete(labimage);
05655 cpl_error_set(func, CPL_ERROR_DATA_NOT_FOUND);
05656 return NULL;
05657 }
05658
05659 refimage = cpl_image_new_from_mask(mask);
05660
05661 slits = cpl_apertures_new_from_image(refimage, labimage);
05662
05663 cpl_image_delete(labimage);
05664 cpl_image_delete(refimage);
05665
05666 nslits = cpl_apertures_get_size(slits);
05667 if (nslits < 1) {
05668 cpl_apertures_delete(slits);
05669 cpl_error_set(func, CPL_ERROR_DATA_NOT_FOUND);
05670 return NULL;
05671 }
05672
05673 slitpos = cpl_table_new(nslits);
05674 cpl_table_new_column(slitpos, "xtop", CPL_TYPE_DOUBLE);
05675 cpl_table_new_column(slitpos, "ytop", CPL_TYPE_DOUBLE);
05676 cpl_table_new_column(slitpos, "xbottom", CPL_TYPE_DOUBLE);
05677 cpl_table_new_column(slitpos, "ybottom", CPL_TYPE_DOUBLE);
05678 cpl_table_set_column_unit(slitpos, "xtop", "pixel");
05679 cpl_table_set_column_unit(slitpos, "ytop", "pixel");
05680 cpl_table_set_column_unit(slitpos, "xbottom", "pixel");
05681 cpl_table_set_column_unit(slitpos, "ybottom", "pixel");
05682
05683 for (i = 0; i < nslits; i++) {
05684 cpl_table_set_double(slitpos, "xtop", i,
05685 cpl_apertures_get_top_x(slits, i+1) - 1);
05686 cpl_table_set_double(slitpos, "ytop", i,
05687 cpl_apertures_get_top(slits, i+1));
05688 cpl_table_set_double(slitpos, "xbottom", i,
05689 cpl_apertures_get_bottom_x(slits, i+1) - 1);
05690 cpl_table_set_double(slitpos, "ybottom", i,
05691 cpl_apertures_get_bottom(slits, i+1));
05692 }
05693
05694 cpl_apertures_delete(slits);
05695
05696 sort_col = cpl_propertylist_new();
05697 cpl_propertylist_append_bool(sort_col, "ytop", 1);
05698 cpl_table_sort(slitpos, sort_col);
05699 cpl_propertylist_delete(sort_col);
05700
05701 return slitpos;
05702
05703 }
05704
05705
05721 cpl_error_code mos_validate_slits(cpl_table *slits)
05722 {
05723 const char *func = "mos_validate_slits";
05724
05725
05726 if (slits == NULL)
05727 return cpl_error_set(func, CPL_ERROR_NULL_INPUT);
05728
05729 if (1 != cpl_table_has_column(slits, "xtop"))
05730 return cpl_error_set(func, CPL_ERROR_DATA_NOT_FOUND);
05731
05732 if (1 != cpl_table_has_column(slits, "ytop"))
05733 return cpl_error_set(func, CPL_ERROR_DATA_NOT_FOUND);
05734
05735 if (1 != cpl_table_has_column(slits, "xbottom"))
05736 return cpl_error_set(func, CPL_ERROR_DATA_NOT_FOUND);
05737
05738 if (1 != cpl_table_has_column(slits, "ybottom"))
05739 return cpl_error_set(func, CPL_ERROR_DATA_NOT_FOUND);
05740
05741 if (CPL_TYPE_DOUBLE != cpl_table_get_column_type(slits, "xtop"))
05742 return cpl_error_set(func, CPL_ERROR_INVALID_TYPE);
05743
05744 if (CPL_TYPE_DOUBLE != cpl_table_get_column_type(slits, "ytop"))
05745 return cpl_error_set(func, CPL_ERROR_INVALID_TYPE);
05746
05747 if (CPL_TYPE_DOUBLE != cpl_table_get_column_type(slits, "xbottom"))
05748 return cpl_error_set(func, CPL_ERROR_INVALID_TYPE);
05749
05750 if (CPL_TYPE_DOUBLE != cpl_table_get_column_type(slits, "ybottom"))
05751 return cpl_error_set(func, CPL_ERROR_INVALID_TYPE);
05752
05753 return CPL_ERROR_NONE;
05754 }
05755
05756
05785 cpl_error_code mos_rotate_slits(cpl_table *slits, int rotation, int nx, int ny)
05786 {
05787 const char *func = "mos_rotate_slits";
05788
05789 cpl_error_code error;
05790 char aux_name[] = "_0";
05791 int i;
05792
05793
05794 rotation %= 4;
05795 if (rotation < 0)
05796 rotation += 4;
05797
05798 if (rotation == 0)
05799 return CPL_ERROR_NONE;
05800
05801 error = mos_validate_slits(slits);
05802 if (error)
05803 return cpl_error_set(func, error);
05804
05805 if (rotation == 1 || rotation == 3) {
05806
05807
05808
05809
05810
05811 for (i = 0; i < 77; i++)
05812 if (1 == cpl_table_has_column(slits, aux_name))
05813 aux_name[1]++;
05814 if (1 == cpl_table_has_column(slits, aux_name))
05815 return cpl_error_set(func, CPL_ERROR_CONTINUE);
05816 cpl_table_name_column(slits, "xtop", aux_name);
05817 cpl_table_name_column(slits, "ytop", "xtop");
05818 cpl_table_name_column(slits, aux_name, "ytop");
05819 cpl_table_name_column(slits, "xbottom", aux_name);
05820 cpl_table_name_column(slits, "ybottom", "xbottom");
05821 cpl_table_name_column(slits, aux_name, "ybottom");
05822 }
05823
05824 if (rotation == 1 || rotation == 2) {
05825 cpl_table_multiply_scalar(slits, "xtop", -1.0);
05826 cpl_table_multiply_scalar(slits, "xbottom", -1.0);
05827 cpl_table_add_scalar(slits, "xtop", nx);
05828 cpl_table_add_scalar(slits, "xbottom", nx);
05829 }
05830
05831 if (rotation == 3 || rotation == 2) {
05832 cpl_table_multiply_scalar(slits, "ytop", -1.0);
05833 cpl_table_multiply_scalar(slits, "ybottom", -1.0);
05834 cpl_table_add_scalar(slits, "ytop", ny);
05835 cpl_table_add_scalar(slits, "ybottom", ny);
05836 }
05837
05838 return CPL_ERROR_NONE;
05839 }
05840
05841
05899 cpl_table *mos_identify_slits(cpl_table *slits, cpl_table *maskslits,
05900 cpl_table *global)
05901 {
05902 const char *func = "mos_identify_slits";
05903
05904 cpl_propertylist *sort_col;
05905 cpl_table *positions;
05906 cpl_vector *scales;
05907 cpl_vector *angles;
05908 cpl_vector *point;
05909 cpl_vector *xpos;
05910 cpl_vector *ypos;
05911 cpl_vector *xmpos;
05912 cpl_vector *ympos;
05913 cpl_bivector *mpos;
05914 cpl_polynomial *xpoly = NULL;
05915 cpl_polynomial *ypoly = NULL;
05916 cpl_error_code error;
05917 int nslits;
05918 int nmaskslits;
05919 int found_slits;
05920 int i, j, k;
05921
05922 double dist1, dist2, dist3, dist, mindist;
05923 double scale, minscale, maxscale;
05924 double angle, minangle, maxangle;
05925 double *dscale;
05926 double *dangle;
05927 double *dpoint;
05928 double *xtop;
05929 double *ytop;
05930 double *xbottom;
05931 double *ybottom;
05932 double *xcenter;
05933 double *ycenter;
05934 double *xpseudo;
05935 double *ypseudo;
05936 int *slit_id;
05937 double *xmtop;
05938 double *ymtop;
05939 double *xmbottom;
05940 double *ymbottom;
05941 double *xmcenter;
05942 double *ymcenter;
05943 double *xmpseudo;
05944 double *ympseudo;
05945 double xmse, ymse;
05946 int *mslit_id;
05947 int *good;
05948 int minpos;
05949 int degree;
05950
05951 double sradius = 0.01;
05952 int in_sradius;
05953
05954 double pi = 3.14159265358979323846;
05955
05956
05957 error = mos_validate_slits(slits);
05958 if (error) {
05959 cpl_msg_error(func, "CCD slits table validation: %s",
05960 cpl_error_get_message());
05961 cpl_error_set(func, error);
05962 return NULL;
05963 }
05964
05965 error = mos_validate_slits(maskslits);
05966 if (error) {
05967 cpl_msg_error(func, "Mask slits table validation: %s",
05968 cpl_error_get_message());
05969 cpl_error_set(func, error);
05970 return NULL;
05971 }
05972
05973 if (1 != cpl_table_has_column(maskslits, "slit_id")) {
05974 cpl_msg_error(func, "Missing slits identifiers");
05975 cpl_error_set(func, CPL_ERROR_DATA_NOT_FOUND);
05976 return NULL;
05977 }
05978
05979 if (CPL_TYPE_INT != cpl_table_get_column_type(maskslits, "slit_id")) {
05980 cpl_msg_error(func, "Wrong type used for slits identifiers");
05981 cpl_error_set(func, CPL_ERROR_INVALID_TYPE);
05982 return NULL;
05983 }
05984
05985 nslits = cpl_table_get_nrow(slits);
05986 nmaskslits = cpl_table_get_nrow(maskslits);
05987
05988 if (nslits == 0 || nmaskslits == 0) {
05989 cpl_msg_error(func, "Empty slits table");
05990 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
05991 return NULL;
05992 }
05993
05994
05995
05996
05997
05998
05999
06000 if (cpl_table_has_column(slits, "xcenter"))
06001 cpl_table_erase_column(slits, "xcenter");
06002
06003 if (cpl_table_has_column(slits, "ycenter"))
06004 cpl_table_erase_column(slits, "ycenter");
06005
06006 if (cpl_table_has_column(maskslits, "xcenter"))
06007 cpl_table_erase_column(maskslits, "xcenter");
06008
06009 if (cpl_table_has_column(maskslits, "ycenter"))
06010 cpl_table_erase_column(maskslits, "ycenter");
06011
06012 cpl_table_duplicate_column(slits, "xcenter", slits, "xtop");
06013 cpl_table_add_columns(slits, "xcenter", "xbottom");
06014 cpl_table_divide_scalar(slits, "xcenter", 2.0);
06015 cpl_table_duplicate_column(slits, "ycenter", slits, "ytop");
06016 cpl_table_add_columns(slits, "ycenter", "ybottom");
06017 cpl_table_divide_scalar(slits, "ycenter", 2.0);
06018
06019 cpl_table_duplicate_column(maskslits, "xcenter", maskslits, "xtop");
06020 cpl_table_add_columns(maskslits, "xcenter", "xbottom");
06021 cpl_table_divide_scalar(maskslits, "xcenter", 2.0);
06022 cpl_table_duplicate_column(maskslits, "ycenter", maskslits, "ytop");
06023 cpl_table_add_columns(maskslits, "ycenter", "ybottom");
06024 cpl_table_divide_scalar(maskslits, "ycenter", 2.0);
06025
06026
06027
06028
06029
06030
06031 sort_col = cpl_propertylist_new();
06032 cpl_propertylist_append_bool(sort_col, "ycenter", 1);
06033 cpl_table_sort(slits, sort_col);
06034 cpl_table_sort(maskslits, sort_col);
06035 cpl_propertylist_delete(sort_col);
06036
06037
06038
06039
06040
06041
06042 if (nslits < 3 && nmaskslits > nslits) {
06043
06044
06045
06046
06047
06048
06049
06050
06051 if (nslits > 1)
06052 cpl_msg_warning(func, "Cannot match the found CCD slit with the "
06053 "%d mask slits: process will continue using the "
06054 "detected CCD slit position", nmaskslits);
06055 else
06056 cpl_msg_warning(func, "Cannot match the %d found CCD slits with "
06057 "the %d mask slits: process will continue using "
06058 "the detected CCD slits positions", nslits,
06059 nmaskslits);
06060 return NULL;
06061 }
06062
06063 if (nslits <= 3 && nslits == nmaskslits) {
06064
06065 cpl_msg_warning(func, "Too few slits (%d) on mask and CCD", nslits);
06066 cpl_msg_warning(func, "Their detected positions are left unchanged");
06067
06068
06069
06070
06071
06072
06073
06074
06075
06076
06077 positions = cpl_table_duplicate(slits);
06078 cpl_table_erase_column(slits, "xcenter");
06079 cpl_table_erase_column(slits, "ycenter");
06080 cpl_table_duplicate_column(positions, "xmtop", maskslits, "xtop");
06081 cpl_table_duplicate_column(positions, "ymtop", maskslits, "ytop");
06082 cpl_table_duplicate_column(positions, "xmbottom", maskslits, "xbottom");
06083 cpl_table_duplicate_column(positions, "ymbottom", maskslits, "ybottom");
06084 cpl_table_duplicate_column(positions, "xmcenter", maskslits, "xcenter");
06085 cpl_table_duplicate_column(positions, "ymcenter", maskslits, "ycenter");
06086 cpl_table_duplicate_column(positions, "slit_id", maskslits, "slit_id");
06087 cpl_table_erase_column(maskslits, "xcenter");
06088 cpl_table_erase_column(maskslits, "ycenter");
06089
06090 if (nslits > 1) {
06091 xcenter = cpl_table_get_data_double(positions, "xcenter");
06092 ycenter = cpl_table_get_data_double(positions, "ycenter");
06093 xmcenter = cpl_table_get_data_double(positions, "xmcenter");
06094 ymcenter = cpl_table_get_data_double(positions, "ymcenter");
06095
06096 dist1 = (xcenter[0] - xcenter[1])*(xcenter[0] - xcenter[1])
06097 + (ycenter[0] - ycenter[1])*(ycenter[0] - ycenter[1]);
06098 dist2 = (xmcenter[0] - xmcenter[1])*(xmcenter[0] - xmcenter[1])
06099 + (ymcenter[0] - ymcenter[1])*(ymcenter[0] - ymcenter[1]);
06100 scale = sqrt(dist1/dist2);
06101
06102 if (nslits == 3) {
06103 dist1 = (xcenter[1] - xcenter[2])*(xcenter[1] - xcenter[2])
06104 + (ycenter[1] - ycenter[2])*(ycenter[1] - ycenter[2]);
06105 dist2 = (xmcenter[1] - xmcenter[2])*(xmcenter[1] - xmcenter[2])
06106 + (ymcenter[1] - ymcenter[2])*(ymcenter[1] - ymcenter[2]);
06107 scale += sqrt(dist1/dist2);
06108 scale /= 2;
06109 }
06110
06111 cpl_msg_info(func, "Platescale: %f pixel/mm", scale);
06112 }
06113
06114 return positions;
06115 }
06116
06117 if (nmaskslits < 3 && nslits > nmaskslits) {
06118
06119
06120
06121
06122
06123
06124
06125 cpl_msg_warning(func, "Cannot match the %d found CCD slits with "
06126 "the %d mask slits: process will continue using "
06127 "the detected CCD slits positions", nslits,
06128 nmaskslits);
06129 return NULL;
06130 }
06131
06132
06133
06134
06135
06136
06137
06138
06139
06140
06141
06142
06143
06144
06145
06146
06147
06148
06149
06150
06151
06152
06153
06154
06155
06156
06157
06158
06159 if (cpl_table_has_column(slits, "xpseudo"))
06160 cpl_table_erase_column(slits, "xpseudo");
06161
06162 if (cpl_table_has_column(slits, "ypseudo"))
06163 cpl_table_erase_column(slits, "ypseudo");
06164
06165 if (cpl_table_has_column(maskslits, "xpseudo"))
06166 cpl_table_erase_column(maskslits, "xpseudo");
06167
06168 if (cpl_table_has_column(maskslits, "ypseudo"))
06169 cpl_table_erase_column(maskslits, "ypseudo");
06170
06171 cpl_table_duplicate_column(slits, "xpseudo", slits, "xcenter");
06172 cpl_table_duplicate_column(slits, "ypseudo", slits, "ycenter");
06173
06174 xcenter = cpl_table_get_data_double(slits, "xcenter");
06175 ycenter = cpl_table_get_data_double(slits, "ycenter");
06176 xpseudo = cpl_table_get_data_double(slits, "xpseudo");
06177 ypseudo = cpl_table_get_data_double(slits, "ypseudo");
06178
06179 for (i = 1; i < nslits - 1; i++) {
06180 dist1 = (xcenter[i-1] - xcenter[i]) * (xcenter[i-1] - xcenter[i])
06181 + (ycenter[i-1] - ycenter[i]) * (ycenter[i-1] - ycenter[i]);
06182 dist2 = (xcenter[i-1] - xcenter[i+1]) * (xcenter[i-1] - xcenter[i+1])
06183 + (ycenter[i-1] - ycenter[i+1]) * (ycenter[i-1] - ycenter[i+1]);
06184 dist3 = (xcenter[i] - xcenter[i+1]) * (xcenter[i] - xcenter[i+1])
06185 + (ycenter[i] - ycenter[i+1]) * (ycenter[i] - ycenter[i+1]);
06186 xpseudo[i] = sqrt(dist1/dist2);
06187 ypseudo[i] = sqrt(dist3/dist2);
06188 }
06189
06190 cpl_table_set_invalid(slits, "xpseudo", 0);
06191 cpl_table_set_invalid(slits, "xpseudo", nslits-1);
06192 cpl_table_set_invalid(slits, "ypseudo", 0);
06193 cpl_table_set_invalid(slits, "ypseudo", nslits-1);
06194
06195 cpl_table_duplicate_column(maskslits, "xpseudo", maskslits, "xcenter");
06196 cpl_table_duplicate_column(maskslits, "ypseudo", maskslits, "ycenter");
06197
06198 xcenter = cpl_table_get_data_double(maskslits, "xcenter");
06199 ycenter = cpl_table_get_data_double(maskslits, "ycenter");
06200 xmpseudo = cpl_table_get_data_double(maskslits, "xpseudo");
06201 ympseudo = cpl_table_get_data_double(maskslits, "ypseudo");
06202
06203 for (i = 1; i < nmaskslits - 1; i++) {
06204 dist1 = (xcenter[i-1] - xcenter[i])*(xcenter[i-1] - xcenter[i])
06205 + (ycenter[i-1] - ycenter[i])*(ycenter[i-1] - ycenter[i]);
06206 dist2 = (xcenter[i-1] - xcenter[i+1])*(xcenter[i-1] - xcenter[i+1])
06207 + (ycenter[i-1] - ycenter[i+1])*(ycenter[i-1] - ycenter[i+1]);
06208 dist3 = (xcenter[i] - xcenter[i+1])*(xcenter[i] - xcenter[i+1])
06209 + (ycenter[i] - ycenter[i+1])*(ycenter[i] - ycenter[i+1]);
06210 xmpseudo[i] = sqrt(dist1/dist2);
06211 ympseudo[i] = sqrt(dist3/dist2);
06212 }
06213
06214 cpl_table_set_invalid(maskslits, "xpseudo", 0);
06215 cpl_table_set_invalid(maskslits, "xpseudo", nmaskslits-1);
06216 cpl_table_set_invalid(maskslits, "ypseudo", 0);
06217 cpl_table_set_invalid(maskslits, "ypseudo", nmaskslits-1);
06218
06219
06220
06221
06222
06223
06224
06225
06226
06227
06228
06229 if (cpl_table_has_column(slits, "slit_id"))
06230 cpl_table_erase_column(slits, "slit_id");
06231 cpl_table_new_column(slits, "slit_id", CPL_TYPE_INT);
06232 slit_id = cpl_table_get_data_int(maskslits, "slit_id");
06233
06234 for (i = 1; i < nmaskslits - 1; i++) {
06235 in_sradius = 0;
06236 mindist = (xmpseudo[i] - xpseudo[1]) * (xmpseudo[i] - xpseudo[1])
06237 + (ympseudo[i] - ypseudo[1]) * (ympseudo[i] - ypseudo[1]);
06238 minpos = 1;
06239 if (mindist < sradius*sradius)
06240 in_sradius++;
06241 for (j = 2; j < nslits - 1; j++) {
06242 dist = (xmpseudo[i] - xpseudo[j]) * (xmpseudo[i] - xpseudo[j])
06243 + (ympseudo[i] - ypseudo[j]) * (ympseudo[i] - ypseudo[j]);
06244 if (dist < sradius*sradius)
06245 in_sradius++;
06246 if (in_sradius > 1)
06247 break;
06248 if (mindist > dist) {
06249 mindist = dist;
06250 minpos = j;
06251 }
06252 }
06253
06254 mindist = sqrt(mindist);
06255
06256 if (mindist < sradius && in_sradius == 1) {
06257 cpl_table_set_int(slits, "slit_id", minpos-1, slit_id[i-1]);
06258 cpl_table_set_int(slits, "slit_id", minpos, slit_id[i]);
06259 cpl_table_set_int(slits, "slit_id", minpos+1, slit_id[i+1]);
06260 }
06261 }
06262
06263
06264
06265
06266
06267
06268
06269 found_slits = nslits - cpl_table_count_invalid(slits, "slit_id");
06270
06271 if (found_slits < 3) {
06272 cpl_msg_warning(func, "Too few preliminarily identified slits: "
06273 "%d out of %d", found_slits, nslits);
06274 if (nslits == nmaskslits) {
06275 cpl_msg_warning(func, "(this is not an error, it could be caused "
06276 "by a mask with regularly located slits)");
06277 cpl_msg_warning(func, "The detected slits positions are left "
06278 "unchanged");
06279
06280
06281
06282
06283
06284
06285
06286
06287 cpl_table_erase_column(slits, "slit_id");
06288 cpl_table_erase_column(slits, "xpseudo");
06289 cpl_table_erase_column(slits, "ypseudo");
06290 positions = cpl_table_duplicate(slits);
06291 cpl_table_erase_column(slits, "xcenter");
06292 cpl_table_erase_column(slits, "ycenter");
06293
06294 cpl_table_erase_column(maskslits, "xpseudo");
06295 cpl_table_erase_column(maskslits, "ypseudo");
06296 cpl_table_duplicate_column(positions, "xmtop",
06297 maskslits, "xtop");
06298 cpl_table_duplicate_column(positions, "ymtop",
06299 maskslits, "ytop");
06300 cpl_table_duplicate_column(positions, "xmbottom",
06301 maskslits, "xbottom");
06302 cpl_table_duplicate_column(positions, "ymbottom",
06303 maskslits, "ybottom");
06304 cpl_table_duplicate_column(positions, "xmcenter",
06305 maskslits, "xcenter");
06306 cpl_table_duplicate_column(positions, "ymcenter",
06307 maskslits, "ycenter");
06308 cpl_table_duplicate_column(positions, "slit_id",
06309 maskslits, "slit_id");
06310 cpl_table_erase_column(maskslits, "xcenter");
06311 cpl_table_erase_column(maskslits, "ycenter");
06312 return positions;
06313 }
06314 else {
06315 cpl_table_erase_column(slits, "slit_id");
06316 cpl_table_erase_column(slits, "xpseudo");
06317 cpl_table_erase_column(slits, "ypseudo");
06318 positions = cpl_table_duplicate(slits);
06319 cpl_table_erase_column(slits, "xcenter");
06320 cpl_table_erase_column(slits, "ycenter");
06321 cpl_msg_warning(func, "(the failure could be caused "
06322 "by a mask with regularly located slits)");
06323 return NULL;
06324 }
06325 }
06326 else {
06327 cpl_msg_info(func, "Preliminarily identified slits: %d out of %d "
06328 "candidates (%d expected)", found_slits, nslits,
06329 nmaskslits);
06330 }
06331
06332
06333
06334
06335
06336
06337
06338
06339 positions = cpl_table_new(found_slits);
06340 cpl_table_new_column(positions, "slit_id", CPL_TYPE_INT);
06341 cpl_table_new_column(positions, "xtop", CPL_TYPE_DOUBLE);
06342 cpl_table_new_column(positions, "ytop", CPL_TYPE_DOUBLE);
06343 cpl_table_new_column(positions, "xbottom", CPL_TYPE_DOUBLE);
06344 cpl_table_new_column(positions, "ybottom", CPL_TYPE_DOUBLE);
06345 cpl_table_new_column(positions, "xcenter", CPL_TYPE_DOUBLE);
06346 cpl_table_new_column(positions, "ycenter", CPL_TYPE_DOUBLE);
06347 cpl_table_new_column(positions, "xmtop", CPL_TYPE_DOUBLE);
06348 cpl_table_new_column(positions, "ymtop", CPL_TYPE_DOUBLE);
06349 cpl_table_new_column(positions, "xmbottom", CPL_TYPE_DOUBLE);
06350 cpl_table_new_column(positions, "ymbottom", CPL_TYPE_DOUBLE);
06351 cpl_table_new_column(positions, "xmcenter", CPL_TYPE_DOUBLE);
06352 cpl_table_new_column(positions, "ymcenter", CPL_TYPE_DOUBLE);
06353 cpl_table_new_column(positions, "good", CPL_TYPE_INT);
06354 cpl_table_fill_column_window_int(positions, "good", 0, found_slits, 0);
06355
06356 slit_id = cpl_table_get_data_int (slits, "slit_id");
06357 xtop = cpl_table_get_data_double(slits, "xtop");
06358 ytop = cpl_table_get_data_double(slits, "ytop");
06359 xbottom = cpl_table_get_data_double(slits, "xbottom");
06360 ybottom = cpl_table_get_data_double(slits, "ybottom");
06361 xcenter = cpl_table_get_data_double(slits, "xcenter");
06362 ycenter = cpl_table_get_data_double(slits, "ycenter");
06363
06364 mslit_id = cpl_table_get_data_int (maskslits, "slit_id");
06365 xmtop = cpl_table_get_data_double(maskslits, "xtop");
06366 ymtop = cpl_table_get_data_double(maskslits, "ytop");
06367 xmbottom = cpl_table_get_data_double(maskslits, "xbottom");
06368 ymbottom = cpl_table_get_data_double(maskslits, "ybottom");
06369 xmcenter = cpl_table_get_data_double(maskslits, "xcenter");
06370 ymcenter = cpl_table_get_data_double(maskslits, "ycenter");
06371
06372
06373
06374
06375
06376
06377
06378
06379 k = 0;
06380 cpl_table_fill_invalid_int(slits, "slit_id", 0);
06381 for (i = 0; i < nmaskslits; i++) {
06382 for (j = 0; j < nslits; j++) {
06383 if (slit_id[j] == 0)
06384 continue;
06385 if (mslit_id[i] == slit_id[j]) {
06386 cpl_table_set_int (positions, "slit_id", k, slit_id[j]);
06387
06388 cpl_table_set_double(positions, "xtop", k, xtop[j]);
06389 cpl_table_set_double(positions, "ytop", k, ytop[j]);
06390 cpl_table_set_double(positions, "xbottom", k, xbottom[j]);
06391 cpl_table_set_double(positions, "ybottom", k, ybottom[j]);
06392 cpl_table_set_double(positions, "xcenter", k, xcenter[j]);
06393 cpl_table_set_double(positions, "ycenter", k, ycenter[j]);
06394
06395 cpl_table_set_double(positions, "xmtop", k, xmtop[i]);
06396 cpl_table_set_double(positions, "ymtop", k, ymtop[i]);
06397 cpl_table_set_double(positions, "xmbottom", k, xmbottom[i]);
06398 cpl_table_set_double(positions, "ymbottom", k, ymbottom[i]);
06399 cpl_table_set_double(positions, "xmcenter", k, xmcenter[i]);
06400 cpl_table_set_double(positions, "ymcenter", k, ymcenter[i]);
06401
06402 k++;
06403
06404 break;
06405 }
06406 }
06407 }
06408
06409 found_slits = k;
06410
06411 cpl_table_erase_column(slits, "slit_id");
06412 cpl_table_erase_column(slits, "xpseudo");
06413 cpl_table_erase_column(slits, "ypseudo");
06414 cpl_table_erase_column(slits, "xcenter");
06415 cpl_table_erase_column(slits, "ycenter");
06416 cpl_table_erase_column(maskslits, "xpseudo");
06417 cpl_table_erase_column(maskslits, "ypseudo");
06418 cpl_table_erase_column(maskslits, "xcenter");
06419 cpl_table_erase_column(maskslits, "ycenter");
06420
06421
06422
06423
06424
06425
06426
06427
06428
06429 ytop = cpl_table_get_data_double(positions, "ytop");
06430 ybottom = cpl_table_get_data_double(positions, "ybottom");
06431 xcenter = cpl_table_get_data_double(positions, "xcenter");
06432 ycenter = cpl_table_get_data_double(positions, "ycenter");
06433 xmcenter = cpl_table_get_data_double(positions, "xmcenter");
06434 ymcenter = cpl_table_get_data_double(positions, "ymcenter");
06435
06436 scales = cpl_vector_new(found_slits - 1);
06437 dscale = cpl_vector_get_data(scales);
06438 angles = cpl_vector_new(found_slits - 1);
06439 dangle = cpl_vector_get_data(angles);
06440
06441 for (i = 1; i < found_slits; i++) {
06442 dist1 = (xcenter[i-1] - xcenter[i]) * (xcenter[i-1] - xcenter[i])
06443 + (ycenter[i-1] - ycenter[i]) * (ycenter[i-1] - ycenter[i]);
06444 dist2 = (xmcenter[i-1] - xmcenter[i]) * (xmcenter[i-1] - xmcenter[i])
06445 + (ymcenter[i-1] - ymcenter[i]) * (ymcenter[i-1] - ymcenter[i]);
06446 dscale[i-1] = sqrt(dist1/dist2);
06447 dangle[i-1] = atan2(ycenter[i-1] - ycenter[i],
06448 xcenter[i-1] - xcenter[i])
06449 - atan2(ymcenter[i-1] - ymcenter[i],
06450 xmcenter[i-1] - xmcenter[i]);
06451 dangle[i-1] *= 180;
06452 dangle[i-1] /= pi;
06453 }
06454
06455 minscale = cpl_vector_get_min(scales);
06456 scale = cpl_vector_get_median_const(scales);
06457 maxscale = cpl_vector_get_max(scales);
06458
06459 minangle = cpl_vector_get_min(angles);
06460 angle = cpl_vector_get_median_const(angles);
06461 maxangle = cpl_vector_get_max(angles);
06462
06463 cpl_msg_info(func, "Median platescale: %f pixel/mm", scale);
06464 cpl_msg_info(func, "Minmax platescale: %f, %f pixel/mm",
06465 minscale, maxscale);
06466
06467 cpl_msg_info(func, "Median rotation: %f degrees", angle);
06468 cpl_msg_info(func, "Minmax rotation: %f, %f degrees",
06469 minangle, maxangle);
06470
06471 good = cpl_table_get_data_int(positions, "good");
06472
06473 good[0] = good[found_slits - 1] = 1;
06474 for (i = 1; i < found_slits; i++) {
06475 if (fabs((dscale[i-1] - scale)/scale) < 0.10
06476 && fabs(dangle[i-1] - angle) < 2) {
06477 good[i-1]++;
06478 good[i]++;
06479 }
06480 }
06481
06482 for (i = 0; i < found_slits; i++) {
06483 if (good[i] < 2)
06484 good[i] = 0;
06485 else
06486 good[i] = 1;
06487 }
06488
06489
06490
06491
06492
06493
06494
06495
06496
06497
06498
06499
06500
06501
06502
06503
06504
06505
06506
06507
06508
06509
06510
06511
06512
06513
06514
06515
06516
06517
06518
06519
06520
06521
06522 cpl_vector_delete(scales);
06523 cpl_vector_delete(angles);
06524
06525 cpl_table_and_selected_int(positions, "good", CPL_EQUAL_TO, 0);
06526 cpl_table_erase_selected(positions);
06527 cpl_table_erase_column(positions, "good");
06528 found_slits = cpl_table_get_nrow(positions);
06529
06530 if (found_slits < 4) {
06531
06532
06533
06534
06535
06536
06537
06538 cpl_msg_warning(func, "Too few safely identified slits: %d out of %d "
06539 "candidates (%d expected). Process will continue "
06540 "using the detected CCD slits positions", found_slits,
06541 nslits, nmaskslits);
06542 cpl_table_delete(positions);
06543 return NULL;
06544 }
06545 else {
06546 cpl_msg_info(func, "Safely identified slits: %d out of %d "
06547 "candidates\n(%d expected)", found_slits, nslits,
06548 nmaskslits);
06549 }
06550
06551
06552
06553
06554
06555
06556
06557
06558 xpos = cpl_vector_wrap(found_slits,
06559 cpl_table_get_data_double(positions, "xcenter"));
06560 ypos = cpl_vector_wrap(found_slits,
06561 cpl_table_get_data_double(positions, "ycenter"));
06562 xmpos = cpl_vector_wrap(found_slits,
06563 cpl_table_get_data_double(positions, "xmcenter"));
06564 ympos = cpl_vector_wrap(found_slits,
06565 cpl_table_get_data_double(positions, "ymcenter"));
06566 mpos = cpl_bivector_wrap_vectors(xmpos, ympos);
06567
06568 if (found_slits < 10)
06569 degree = 1;
06570 else
06571 degree = 2;
06572
06573 xpoly = cpl_polynomial_fit_2d_create(mpos, xpos, degree, &xmse);
06574 if (xpoly != NULL)
06575 ypoly = cpl_polynomial_fit_2d_create(mpos, ypos, degree, &ymse);
06576 cpl_bivector_unwrap_vectors(mpos);
06577 cpl_vector_unwrap(xpos);
06578 cpl_vector_unwrap(ypos);
06579 cpl_vector_unwrap(xmpos);
06580 cpl_vector_unwrap(ympos);
06581 if (ypoly == NULL) {
06582 if (found_slits == nmaskslits) {
06583 cpl_msg_warning(func, "Fit failure: the accuracy of the "
06584 "identified slits positions is not improved.");
06585
06586
06587
06588
06589
06590
06591
06592
06593
06594 } else {
06595 cpl_msg_info(func, "Fit failure: not all slits have been "
06596 "identified. Process will continue using "
06597 "the detected CCD slits positions");
06598 }
06599
06600 cpl_polynomial_delete(xpoly);
06601 return positions;
06602 }
06603
06604 cpl_msg_info(func, "Fit successful: X rms = %.3g, Y rms = %.3g (pixel)",
06605 sqrt(xmse), sqrt(ymse));
06606
06607 if (global) {
06608 write_global_distortion(global, 0, xpoly);
06609 write_global_distortion(global, 7, ypoly);
06610 }
06611
06612
06613
06614
06615
06616
06617 cpl_table_delete(positions);
06618
06619 positions = cpl_table_duplicate(maskslits);
06620 cpl_table_duplicate_column(positions, "xmtop", positions, "xtop");
06621 cpl_table_duplicate_column(positions, "ymtop", positions, "ytop");
06622 cpl_table_duplicate_column(positions, "xmbottom", positions, "xbottom");
06623 cpl_table_duplicate_column(positions, "ymbottom", positions, "ybottom");
06624
06625 point = cpl_vector_new(2);
06626 dpoint = cpl_vector_get_data(point);
06627
06628 for (i = 0; i < nmaskslits; i++) {
06629 dpoint[0] = cpl_table_get_double(positions, "xmtop", i, NULL);
06630 dpoint[1] = cpl_table_get_double(positions, "ymtop", i, NULL);
06631 cpl_table_set_double(positions, "xtop", i,
06632 cpl_polynomial_eval(xpoly, point));
06633 cpl_table_set_double(positions, "ytop", i,
06634 cpl_polynomial_eval(ypoly, point));
06635 dpoint[0] = cpl_table_get_double(positions, "xmbottom", i, NULL);
06636 dpoint[1] = cpl_table_get_double(positions, "ymbottom", i, NULL);
06637 cpl_table_set_double(positions, "xbottom", i,
06638 cpl_polynomial_eval(xpoly, point));
06639 cpl_table_set_double(positions, "ybottom", i,
06640 cpl_polynomial_eval(ypoly, point));
06641 }
06642
06643 cpl_vector_delete(point);
06644 cpl_polynomial_delete(xpoly);
06645 cpl_polynomial_delete(ypoly);
06646
06647 cpl_table_erase_column(positions, "xmtop");
06648 cpl_table_erase_column(positions, "ymtop");
06649 cpl_table_erase_column(positions, "xmbottom");
06650 cpl_table_erase_column(positions, "ymbottom");
06651
06652 if (nmaskslits > nslits)
06653 cpl_msg_info(func, "Finally identified slits: %d out of %d expected\n"
06654 "(%d recovered)", nmaskslits, nmaskslits, nmaskslits - nslits);
06655 else if (nmaskslits < nslits)
06656 cpl_msg_info(func, "Finally identified slits: %d out of %d expected\n"
06657 "(%d rejected)", nmaskslits, nmaskslits, nslits - nmaskslits);
06658 else
06659 cpl_msg_info(func, "Finally identified slits: %d out of %d expected",
06660 nmaskslits, nmaskslits);
06661
06662 return positions;
06663 }
06664
06665
06707 cpl_table *mos_trace_flat(cpl_image *flat, cpl_table *slits, double reference,
06708 double blue, double red, double dispersion)
06709 {
06710
06711 const char *func = "mos_trace_flat";
06712
06713 cpl_image *gradient;
06714 cpl_image *sgradient;
06715 float *dgradient;
06716 float level = 500;
06717 cpl_vector *row;
06718 cpl_vector *srow;
06719 cpl_vector **peaks;
06720 double *peak;
06721 int *slit_id;
06722 float *g;
06723 double *r;
06724 double *xtop;
06725 double *ytop;
06726 double *xbottom;
06727 double *ybottom;
06728 double min, dist;
06729 double sradius;
06730 double tolerance;
06731 double start_y, prev_y;
06732 int minpos;
06733 int nslits;
06734 int nrows;
06735 int step = 10;
06736 int filtbox = 15;
06737 int nx, ny, npix;
06738 int pos, ypos;
06739 int npeaks;
06740 int pixel_above, pixel_below;
06741 int i, j, k, l;
06742 char trace_id[MAX_COLNAME];
06743
06744 cpl_table *traces;
06745
06746
06747 if (flat == NULL || slits == NULL) {
06748 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
06749 return NULL;
06750 }
06751
06752 if (dispersion <= 0.0) {
06753 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
06754 return NULL;
06755 }
06756
06757 if (red - blue < dispersion) {
06758 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
06759 return NULL;
06760 }
06761
06762
06763
06764
06765
06766
06767 nslits = cpl_table_get_nrow(slits);
06768 if (1 != cpl_table_has_column(slits, "slit_id")) {
06769 cpl_table_new_column(slits, "slit_id", CPL_TYPE_INT);
06770 for (i = 0; i < nslits; i++)
06771 cpl_table_set_int(slits, "slit_id", i, -(i+1));
06772 }
06773
06774 slit_id = cpl_table_get_data_int(slits, "slit_id");
06775
06776 nx = cpl_image_get_size_x(flat);
06777 ny = cpl_image_get_size_y(flat);
06778 npix = nx * ny;
06779
06780 gradient = cpl_image_duplicate(flat);
06781 dgradient = cpl_image_get_data_float(gradient);
06782
06783 for (i = 0; i < ny - 1; i++) {
06784 k = i * nx;
06785 for (j = 0; j < nx; j++) {
06786 l = k + j;
06787 dgradient[l] = fabs(dgradient[l] - dgradient[l + nx]);
06788 }
06789 }
06790
06791 npix--;
06792 for (j = 0; j < nx; j++)
06793 dgradient[npix - j] = 0.0;
06794
06795 cpl_image_turn(gradient, -1);
06796 nx = cpl_image_get_size_x(gradient);
06797 ny = cpl_image_get_size_y(gradient);
06798 sgradient = mos_image_vertical_median_filter(gradient,
06799 filtbox, 0, ny, 0, step);
06800 cpl_image_delete(gradient);
06801
06802
06803
06804
06805
06806
06807 dgradient = cpl_image_get_data_float(sgradient);
06808
06809 for (i = 1; i <= ny; i += step) {
06810 row = cpl_vector_new_from_image_row(sgradient, i);
06811 srow = cpl_vector_filter_median_create(row, filtbox);
06812 cpl_vector_subtract(row, srow);
06813 cpl_vector_delete(srow);
06814 g = dgradient + (i-1)*nx;
06815 r = cpl_vector_get_data(row);
06816 for (j = 0; j < nx; j++)
06817 g[j] = r[j];
06818 cpl_vector_delete(row);
06819 }
06820
06821
06822
06823
06824
06825
06826
06827 mos_rotate_slits(slits, 1, nx, ny);
06828 xtop = cpl_table_get_data_double(slits, "xtop");
06829 ytop = cpl_table_get_data_double(slits, "ytop");
06830 xbottom = cpl_table_get_data_double(slits, "xbottom");
06831 ybottom = cpl_table_get_data_double(slits, "ybottom");
06832
06833
06834
06835
06836
06837
06838
06839 peaks = cpl_calloc(ny, sizeof(cpl_vector *));
06840
06841 for (i = 0; i < ny; i += step) {
06842 g = dgradient + i*nx;
06843 peaks[i] = mos_peak_candidates(g, nx, level, 1.0);
06844
06845
06846
06847 if (peaks[i])
06848 cpl_vector_subtract_scalar(peaks[i], 0.5);
06849
06850 }
06851
06852 cpl_image_delete(sgradient);
06853
06854
06855
06856
06857
06858
06859
06860
06861
06862 sradius = 5.0;
06863
06864
06865
06866
06867
06868
06869
06870
06871 tolerance = 0.9;
06872
06873
06874
06875
06876
06877
06878 pixel_above = (red - reference) / dispersion;
06879 pixel_below = (reference - blue) / dispersion;
06880
06881
06882
06883
06884
06885
06886 nrows = (ny-1)/step + 1;
06887 traces = cpl_table_new(nrows);
06888 cpl_table_new_column(traces, "x", CPL_TYPE_DOUBLE);
06889 cpl_table_set_column_unit(traces, "x", "pixel");
06890 for (i = 0, j = 0; i < ny; i += step, j++)
06891 cpl_table_set(traces, "x", j, i);
06892
06893 for (i = 0; i < nslits; i++) {
06894
06895
06896
06897
06898
06899 ypos = ytop[i];
06900
06901 if (ypos < 0)
06902 ypos = 0;
06903 if (ypos >= ny)
06904 ypos = ny - 1;
06905
06906 pos = ypos / step;
06907 pos *= step;
06908
06909
06910
06911
06912
06913 if (peaks[pos]) {
06914 peak = cpl_vector_get_data(peaks[pos]);
06915 npeaks = cpl_vector_get_size(peaks[pos]);
06916
06917 min = fabs(peak[0] - xtop[i]);
06918 minpos = 0;
06919 for (j = 1; j < npeaks; j++) {
06920 dist = fabs(peak[j] - xtop[i]);
06921 if (min > dist) {
06922 min = dist;
06923 minpos = j;
06924 }
06925 }
06926 }
06927 else {
06928 npeaks = 0;
06929 }
06930
06931 snprintf(trace_id, MAX_COLNAME, "t%d", slit_id[i]);
06932 cpl_table_new_column(traces, trace_id, CPL_TYPE_DOUBLE);
06933
06934 if (min > sradius || npeaks == 0) {
06935 cpl_msg_warning(func, "Cannot find spectrum edge for "
06936 "top (or left) end of slit %d", slit_id[i]);
06937 }
06938 else {
06939
06940
06941
06942
06943
06944
06945
06946
06947
06948 cpl_table_set(traces, trace_id, pos/step, nx - peak[minpos]);
06949 start_y = peak[minpos];
06950
06951
06952
06953
06954
06955 prev_y = start_y;
06956
06957 for (j = pos + step; j < ny; j += step) {
06958 if (j - pos > pixel_above)
06959 break;
06960 if (peaks[j]) {
06961 peak = cpl_vector_get_data(peaks[j]);
06962 npeaks = cpl_vector_get_size(peaks[j]);
06963 min = fabs(peak[0] - prev_y);
06964 minpos = 0;
06965 for (k = 1; k < npeaks; k++) {
06966 dist = fabs(peak[k] - prev_y);
06967 if (min > dist) {
06968 min = dist;
06969 minpos = k;
06970 }
06971 }
06972 if (min < tolerance) {
06973 cpl_table_set(traces, trace_id, j/step,
06974 nx - peak[minpos]);
06975 prev_y = peak[minpos];
06976 }
06977 }
06978 }
06979
06980
06981
06982
06983
06984 prev_y = start_y;
06985
06986 for (j = pos - step; j >= 0; j -= step) {
06987 if (pos - j > pixel_below)
06988 break;
06989 if (peaks[j]) {
06990 peak = cpl_vector_get_data(peaks[j]);
06991 npeaks = cpl_vector_get_size(peaks[j]);
06992 min = fabs(peak[0] - prev_y);
06993 minpos = 0;
06994 for (k = 1; k < npeaks; k++) {
06995 dist = fabs(peak[k] - prev_y);
06996 if (min > dist) {
06997 min = dist;
06998 minpos = k;
06999 }
07000 }
07001 if (min < tolerance) {
07002 cpl_table_set(traces, trace_id, j/step,
07003 nx - peak[minpos]);
07004 prev_y = peak[minpos];
07005 }
07006 }
07007 }
07008 }
07009
07010
07011
07012
07013
07014
07015 if (peaks[pos]) {
07016 peak = cpl_vector_get_data(peaks[pos]);
07017 npeaks = cpl_vector_get_size(peaks[pos]);
07018
07019 min = fabs(peak[0] - xbottom[i]);
07020 minpos = 0;
07021 for (j = 1; j < npeaks; j++) {
07022 dist = fabs(peak[j] - xbottom[i]);
07023 if (min > dist) {
07024 min = dist;
07025 minpos = j;
07026 }
07027 }
07028 }
07029 else {
07030 npeaks = 0;
07031 }
07032
07033 snprintf(trace_id, MAX_COLNAME, "b%d", slit_id[i]);
07034 cpl_table_new_column(traces, trace_id, CPL_TYPE_DOUBLE);
07035
07036 if (min > sradius || npeaks == 0) {
07037 cpl_msg_warning(func, "Cannot find spectrum edge for "
07038 "bottom (or right) end of slit %d", slit_id[i]);
07039 }
07040 else {
07041
07042 cpl_table_set(traces, trace_id, pos/step, nx - peak[minpos]);
07043 start_y = peak[minpos];
07044
07045
07046
07047
07048
07049 prev_y = start_y;
07050
07051 for (j = pos + step; j < ny; j += step) {
07052 if (j - pos > pixel_above)
07053 break;
07054 if (peaks[j]) {
07055 peak = cpl_vector_get_data(peaks[j]);
07056 npeaks = cpl_vector_get_size(peaks[j]);
07057 min = fabs(peak[0] - prev_y);
07058 minpos = 0;
07059 for (k = 1; k < npeaks; k++) {
07060 dist = fabs(peak[k] - prev_y);
07061 if (min > dist) {
07062 min = dist;
07063 minpos = k;
07064 }
07065 }
07066 if (min < tolerance) {
07067 cpl_table_set(traces, trace_id, j/step,
07068 nx - peak[minpos]);
07069 prev_y = peak[minpos];
07070 }
07071 }
07072 }
07073
07074
07075
07076
07077
07078 prev_y = start_y;
07079
07080 for (j = pos - step; j >= 0; j -= step) {
07081 if (pos - j > pixel_below)
07082 break;
07083 if (peaks[j]) {
07084 peak = cpl_vector_get_data(peaks[j]);
07085 npeaks = cpl_vector_get_size(peaks[j]);
07086 min = fabs(peak[0] - prev_y);
07087 minpos = 0;
07088 for (k = 1; k < npeaks; k++) {
07089 dist = fabs(peak[k] - prev_y);
07090 if (min > dist) {
07091 min = dist;
07092 minpos = k;
07093 }
07094 }
07095 if (min < tolerance) {
07096 cpl_table_set(traces, trace_id, j/step,
07097 nx - peak[minpos]);
07098 prev_y = peak[minpos];
07099 }
07100 }
07101 }
07102 }
07103
07104 }
07105
07106 for (i = 0; i < ny; i += step)
07107 cpl_vector_delete(peaks[i]);
07108 cpl_free(peaks);
07109
07110
07111
07112
07113
07114 mos_rotate_slits(slits, -1, ny, nx);
07115
07116 return traces;
07117
07118 }
07119
07120
07141 cpl_table *mos_poly_trace(cpl_table *slits, cpl_table *traces, int order)
07142 {
07143 const char *func = "mos_poly_trace";
07144
07145 cpl_table *polytraces;
07146 cpl_table *dummy;
07147 cpl_vector *x;
07148 cpl_vector *trace;
07149 cpl_polynomial *polytrace;
07150 char trace_id[MAX_COLNAME];
07151 char trace_res[MAX_COLNAME];
07152 char trace_mod[MAX_COLNAME];
07153 const char *clab[6] = {"c0", "c1", "c2", "c3", "c4", "c5"};
07154
07155 double *xdata;
07156 int *slit_id;
07157 int nslits;
07158 int nrows;
07159 int npoints;
07160 int i, j, k;
07161
07162
07163 if (traces == NULL || slits == NULL) {
07164 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
07165 return NULL;
07166 }
07167
07168 if (order > 5) {
07169 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
07170 return NULL;
07171 }
07172
07173 nrows = cpl_table_get_nrow(traces);
07174 xdata = cpl_table_get_data_double(traces, "x");
07175 nslits = cpl_table_get_nrow(slits);
07176 slit_id = cpl_table_get_data_int(slits, "slit_id");
07177
07178 polytraces = cpl_table_new(2*nslits);
07179 cpl_table_new_column(polytraces, "slit_id", CPL_TYPE_INT);
07180 for (i = 0; i <= order; i++)
07181 cpl_table_new_column(polytraces, clab[i], CPL_TYPE_DOUBLE);
07182
07183 for (i = 0; i < nslits; i++) {
07184 for (j = 0; j < 2; j++) {
07185
07186 if (j) {
07187 snprintf(trace_id, MAX_COLNAME, "b%d", slit_id[i]);
07188 snprintf(trace_res, MAX_COLNAME, "b%d_res", slit_id[i]);
07189 snprintf(trace_mod, MAX_COLNAME, "b%d_mod", slit_id[i]);
07190 }
07191 else {
07192 snprintf(trace_id, MAX_COLNAME, "t%d", slit_id[i]);
07193 snprintf(trace_res, MAX_COLNAME, "t%d_res", slit_id[i]);
07194 snprintf(trace_mod, MAX_COLNAME, "t%d_mod", slit_id[i]);
07195 }
07196
07197 cpl_table_set_int(polytraces, "slit_id", 2*i+j, slit_id[i]);
07198
07199
07200
07201
07202
07203
07204 dummy = cpl_table_new(nrows);
07205 cpl_table_duplicate_column(dummy, "x", traces, "x");
07206 cpl_table_duplicate_column(dummy, trace_id, traces, trace_id);
07207 npoints = nrows - cpl_table_count_invalid(dummy, trace_id);
07208 if (npoints < 2 * order) {
07209 cpl_table_delete(dummy);
07210 continue;
07211 }
07212 cpl_table_erase_invalid(dummy);
07213 x = cpl_vector_wrap(npoints,
07214 cpl_table_get_data_double(dummy, "x"));
07215 trace = cpl_vector_wrap(npoints,
07216 cpl_table_get_data_double(dummy, trace_id));
07217 polytrace = cpl_polynomial_fit_1d_create(x, trace, order, NULL);
07218 cpl_vector_unwrap(x);
07219 cpl_vector_unwrap(trace);
07220 cpl_table_delete(dummy);
07221
07222
07223
07224
07225
07226
07227
07228 k = 2;
07229 if (cpl_polynomial_get_coeff(polytrace, &k) > 1.E-5) {
07230 cpl_polynomial_delete(polytrace);
07231 cpl_table_new_column(traces, trace_mod, CPL_TYPE_DOUBLE);
07232 cpl_table_duplicate_column(traces, trace_res, traces,
07233 trace_mod);
07234 if (j)
07235 cpl_msg_warning(func, "Exclude bad curvature solution "
07236 "for bottom (right) edge of slit %d", slit_id[i]);
07237 else
07238 cpl_msg_warning(func, "Exclude bad curvature solution "
07239 "for top (left) edge of slit %d", slit_id[i]);
07240 continue;
07241 }
07242
07243
07244
07245
07246
07247
07248 for (k = 0; k <= order; k++)
07249 cpl_table_set_double(polytraces, clab[k], 2*i+j,
07250 cpl_polynomial_get_coeff(polytrace, &k));
07251
07252
07253
07254
07255
07256 cpl_table_new_column(traces, trace_mod, CPL_TYPE_DOUBLE);
07257 cpl_table_set_column_unit(traces, trace_mod, "pixel");
07258
07259 for (k = 0; k < nrows; k++) {
07260 cpl_table_set_double(traces, trace_mod, k,
07261 cpl_polynomial_eval_1d(polytrace, xdata[k], NULL));
07262 }
07263
07264 cpl_polynomial_delete(polytrace);
07265
07266 cpl_table_duplicate_column(traces, trace_res, traces, trace_mod);
07267 cpl_table_subtract_columns(traces, trace_res, trace_id);
07268 cpl_table_multiply_scalar(traces, trace_res, -1.0);
07269
07270 }
07271 }
07272
07273 return polytraces;
07274
07275 }
07276
07277
07301 cpl_error_code mos_global_trace(cpl_table *slits, cpl_table *polytraces,
07302 int mode)
07303 {
07304 const char *func = "mos_global_trace";
07305
07306 const char *clab[6] = {"c0", "c1", "c2", "c3", "c4", "c5"};
07307
07308 cpl_table *table;
07309 cpl_vector *c0;
07310 cpl_vector *cn;
07311 cpl_bivector *list;
07312
07313
07314
07315
07316 double *offset;
07317 double rms, q, m;
07318
07319 int order, nrows, nslits;
07320 int i, j;
07321
07322
07323 if (polytraces == NULL) {
07324 cpl_msg_error(func, "Missing spectral curvature table");
07325 return cpl_error_set(func, CPL_ERROR_NULL_INPUT);
07326 }
07327
07328 if (slits == NULL) {
07329 cpl_msg_error(func, "Missing slits positions table");
07330 return cpl_error_set(func, CPL_ERROR_NULL_INPUT);
07331 }
07332
07333 nslits = cpl_table_get_nrow(slits);
07334
07335 table = cpl_table_duplicate(polytraces);
07336 cpl_table_erase_invalid(table);
07337
07338 nrows = cpl_table_get_nrow(table);
07339
07340 if (nrows < 4) {
07341 cpl_msg_warning(func, "Too few successful spectral curvature tracings "
07342 "(%d): the determination of a global curvature model "
07343 "failed", nrows);
07344 return CPL_ERROR_NONE;
07345 }
07346
07347 order = cpl_table_get_ncol(polytraces) - 2;
07348
07349 for (i = 0; i <= order; i++) {
07350 if (!cpl_table_has_column(table, clab[i])) {
07351 cpl_msg_error(func, "Wrong spectral curvature table");
07352 return cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
07353 }
07354 }
07355
07356
07357
07358
07359
07360
07361 for (i = 0; i < nslits; i++) {
07362 if (!cpl_table_is_valid(polytraces, clab[0], 2*i)) {
07363 cpl_table_set_double(polytraces, clab[0], 2*i,
07364 cpl_table_get_double(slits, "ytop", i, NULL));
07365 }
07366 if (!cpl_table_is_valid(polytraces, clab[0], 2*i+1)) {
07367 cpl_table_set_double(polytraces, clab[0], 2*i+1,
07368 cpl_table_get_double(slits, "ybottom", i, NULL));
07369 }
07370 }
07371
07372 offset = cpl_table_get_data_double(polytraces, clab[0]);
07373
07374
07375
07376
07377
07378
07379 c0 = cpl_vector_wrap(nrows, cpl_table_get_data_double(table, clab[0]));
07380
07381 for (i = 1; i <= order; i++) {
07382 cn = cpl_vector_wrap(nrows, cpl_table_get_data_double(table, clab[i]));
07383 list = cpl_bivector_wrap_vectors(c0, cn);
07384 robustLinearFit(list, &q, &m, &rms);
07385
07386
07387
07388 for (j = 0; j < 2*nslits; j++) {
07389 if (mode == 1)
07390 if (cpl_table_is_valid(polytraces, clab[i], j))
07391 continue;
07392 cpl_table_set_double(polytraces, clab[i], j, offset[j]*m + q);
07393
07394
07395
07396
07397 }
07398 cpl_bivector_unwrap_vectors(list);
07399
07400
07401
07402 cpl_vector_unwrap(cn);
07403 }
07404
07405 cpl_vector_unwrap(c0);
07406 cpl_table_delete(table);
07407
07408 return CPL_ERROR_NONE;
07409
07410 }
07411
07412
07482 cpl_image *mos_spatial_calibration(cpl_image *spectra, cpl_table *slits,
07483 cpl_table *polytraces, double reference,
07484 double blue, double red, double dispersion,
07485 int flux, cpl_image *calibration)
07486 {
07487 const char *func = "mos_spatial_calibration";
07488
07489 const char *clab[6] = {"c0", "c1", "c2", "c3", "c4", "c5"};
07490
07491 cpl_polynomial *polytop;
07492 cpl_polynomial *polybot;
07493 cpl_image **exslit;
07494 cpl_image *resampled;
07495 float *data;
07496 float *sdata;
07497 float *xdata;
07498 double vtop, vbot, value;
07499 double top, bot;
07500 double coeff;
07501 double ytop, ybot;
07502 double ypos, yfra;
07503 double factor;
07504 int yint, ysize, yprev;
07505 int nslits;
07506 int npseudo;
07507 int *slit_id;
07508 int *length;
07509 int nx, ny;
07510 int pixel_above, pixel_below, refpixel, start_pixel, end_pixel;
07511 int missing_top, missing_bot;
07512 int null;
07513 int order;
07514 int i, j, k;
07515
07516 int create_position = 1;
07517
07518
07519 if (spectra == NULL || slits == NULL || polytraces == NULL) {
07520 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
07521 return NULL;
07522 }
07523
07524 if (dispersion <= 0.0) {
07525 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
07526 return NULL;
07527 }
07528
07529 if (red - blue < dispersion) {
07530 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
07531 return NULL;
07532 }
07533
07534 nx = cpl_image_get_size_x(spectra);
07535 ny = cpl_image_get_size_y(spectra);
07536 sdata = cpl_image_get_data(spectra);
07537 if (calibration)
07538 data = cpl_image_get_data(calibration);
07539
07540 if (cpl_table_has_column(slits, "position"))
07541 create_position = 0;
07542
07543 if (create_position) {
07544 cpl_table_new_column(slits, "position", CPL_TYPE_INT);
07545 cpl_table_new_column(slits, "length", CPL_TYPE_INT);
07546 cpl_table_set_column_unit(slits, "position", "pixel");
07547 cpl_table_set_column_unit(slits, "length", "pixel");
07548 }
07549 else
07550 length = cpl_table_get_data_int(slits, "length");
07551
07552 nslits = cpl_table_get_nrow(slits);
07553 slit_id = cpl_table_get_data_int(slits, "slit_id");
07554 order = cpl_table_get_ncol(polytraces) - 2;
07555
07556
07557
07558
07559
07560
07561 pixel_above = (red - reference) / dispersion;
07562 pixel_below = (reference - blue) / dispersion;
07563
07564 exslit = cpl_calloc(nslits, sizeof(cpl_image *));
07565
07566 for (i = 0; i < nslits; i++) {
07567
07568 if (create_position == 0)
07569 if (length[i] == 0)
07570 continue;
07571
07572
07573
07574
07575
07576
07577
07578
07579
07580
07581
07582
07583 refpixel = cpl_table_get_double(slits, "xtop", i, NULL);
07584
07585 start_pixel = refpixel - pixel_below;
07586 if (start_pixel < 0)
07587 start_pixel = 0;
07588
07589 end_pixel = refpixel + pixel_above;
07590 if (end_pixel > nx)
07591 end_pixel = nx;
07592
07593
07594
07595
07596
07597
07598 missing_top = 0;
07599 polytop = cpl_polynomial_new(1);
07600 for (k = 0; k <= order; k++) {
07601 coeff = cpl_table_get_double(polytraces, clab[k], 2*i, &null);
07602 if (null) {
07603 cpl_polynomial_delete(polytop);
07604 missing_top = 1;
07605 break;
07606 }
07607 cpl_polynomial_set_coeff(polytop, &k, coeff);
07608 }
07609
07610 missing_bot = 0;
07611 polybot = cpl_polynomial_new(1);
07612 for (k = 0; k <= order; k++) {
07613 coeff = cpl_table_get_double(polytraces, clab[k], 2*i+1, &null);
07614 if (null) {
07615 cpl_polynomial_delete(polybot);
07616 missing_bot = 1;
07617 break;
07618 }
07619 cpl_polynomial_set_coeff(polybot, &k, coeff);
07620 }
07621
07622 if (missing_top && missing_bot) {
07623 cpl_msg_warning(func, "Spatial calibration, slit %d was not "
07624 "traced: no extraction!",
07625 slit_id[i]);
07626 continue;
07627 }
07628
07629
07630
07631
07632
07633
07634
07635 if (missing_top) {
07636 cpl_msg_warning(func, "Upper edge of slit %d was not traced: "
07637 "the spectral curvature of the lower edge "
07638 "is used instead.", slit_id[i]);
07639 polytop = cpl_polynomial_duplicate(polybot);
07640 ytop = cpl_table_get_double(slits, "ytop", i, NULL);
07641 ybot = cpl_table_get_double(slits, "ybottom", i, NULL);
07642 k = 0;
07643 coeff = cpl_polynomial_get_coeff(polybot, &k);
07644 coeff += ytop - ybot;
07645 cpl_polynomial_set_coeff(polytop, &k, coeff);
07646 }
07647
07648 if (missing_bot) {
07649 cpl_msg_warning(func, "Lower edge of slit %d was not traced: "
07650 "the spectral curvature of the upper edge "
07651 "is used instead.", slit_id[i]);
07652 polybot = cpl_polynomial_duplicate(polytop);
07653 ytop = cpl_table_get_double(slits, "ytop", i, NULL);
07654 ybot = cpl_table_get_double(slits, "ybottom", i, NULL);
07655 k = 0;
07656 coeff = cpl_polynomial_get_coeff(polytop, &k);
07657 coeff -= ytop - ybot;
07658 cpl_polynomial_set_coeff(polybot, &k, coeff);
07659 }
07660
07661
07662
07663
07664
07665 top = cpl_polynomial_eval_1d(polytop, refpixel, NULL);
07666 bot = cpl_polynomial_eval_1d(polybot, refpixel, NULL);
07667 npseudo = ceil(top-bot) + 1;
07668
07669 if (npseudo < 1) {
07670 cpl_polynomial_delete(polytop);
07671 cpl_polynomial_delete(polybot);
07672 cpl_msg_warning(func, "Slit %d was badly traced: no extraction!",
07673 slit_id[i]);
07674 continue;
07675 }
07676
07677 exslit[i] = cpl_image_new(nx, npseudo+1, CPL_TYPE_FLOAT);
07678 xdata = cpl_image_get_data(exslit[i]);
07679
07680
07681
07682
07683
07684 for (j = start_pixel; j < end_pixel; j++) {
07685 top = cpl_polynomial_eval_1d(polytop, j, NULL);
07686 bot = cpl_polynomial_eval_1d(polybot, j, NULL);
07687 factor = (top-bot)/npseudo;
07688 for (k = 0; k <= npseudo; k++) {
07689 ypos = top - k*factor;
07690 yint = ypos;
07691 yfra = ypos - yint;
07692 if (yint >= 0 && yint < ny-1) {
07693 vtop = sdata[j + nx*yint];
07694 vbot = sdata[j + nx*(yint+1)];
07695 value = vtop*(1-yfra) + vbot*yfra;
07696 if (flux)
07697 value *= factor;
07698 xdata[j + nx*(npseudo-k)] = value;
07699 if (calibration) {
07700 data[j + nx*yint] = (top-yint)/factor;
07701 if (k) {
07702
07703
07704
07705
07706
07707
07708
07709 if (yprev - yint > 1) {
07710 data[j + nx*(yint+1)] = (top-yint-1)/factor;
07711 }
07712 }
07713 }
07714 }
07715 yprev = yint;
07716 }
07717 }
07718 cpl_polynomial_delete(polytop);
07719 cpl_polynomial_delete(polybot);
07720 }
07721
07722
07723
07724
07725
07726 ysize = 0;
07727 for (i = 0; i < nslits; i++)
07728 if (exslit[i])
07729 ysize += cpl_image_get_size_y(exslit[i]);
07730
07731 resampled = cpl_image_new(nx, ysize, CPL_TYPE_FLOAT);
07732
07733 yint = -1;
07734 for (i = 0; i < nslits; i++) {
07735 if (exslit[i]) {
07736 yint += cpl_image_get_size_y(exslit[i]);
07737 cpl_image_copy(resampled, exslit[i], 1, ysize - yint);
07738 if (create_position) {
07739 cpl_table_set_int(slits, "position", i, ysize - yint - 1);
07740 cpl_table_set_int(slits, "length", i,
07741 cpl_image_get_size_y(exslit[i]));
07742 }
07743 cpl_image_delete(exslit[i]);
07744 }
07745 else if (create_position) {
07746 cpl_table_set_int(slits, "position", i, -1);
07747 cpl_table_set_int(slits, "length", i, 0);
07748 }
07749 }
07750
07751
07752
07753
07754
07755
07756
07757
07758
07759
07760
07761
07762
07763
07764
07765
07766
07767 cpl_free(exslit);
07768
07769 return resampled;
07770
07771 }
07772
07773
07880 cpl_image *mos_wavelength_calibration_final(cpl_image *image, cpl_table *slits,
07881 cpl_vector *lines,
07882 double dispersion, float level,
07883 int sradius, int order,
07884 double reject, double refwave,
07885 double *wavestart, double *waveend,
07886 int *nlines, double *error,
07887 cpl_table *idscoeff,
07888 cpl_image *calibration,
07889 cpl_image *residuals,
07890 cpl_table *restable)
07891 {
07892
07893 const char *func = "mos_wavelength_calibration_final";
07894
07895 const char *clab[6] = {"c0", "c1", "c2", "c3", "c4", "c5"};
07896
07897
07898 double tolerance = 20.0;
07899 int step = 10;
07900
07901 char name[MAX_COLNAME];
07902
07903 cpl_image *resampled;
07904 cpl_bivector *output;
07905 cpl_vector *wavel;
07906 cpl_vector *peaks;
07907 cpl_polynomial *ids;
07908 cpl_polynomial *lin;
07909 cpl_polynomial *fguess;
07910 cpl_table *coeff;
07911 double ids_err;
07912 double max_disp, min_disp;
07913 double *line;
07914 double firstLambda, lastLambda, lambda;
07915 double wave, pixe, value;
07916 double c;
07917 float *sdata;
07918 float *rdata;
07919 float *idata;
07920 float *ddata;
07921 float v1, v2, vi;
07922 float fpixel;
07923 int *length;
07924 int pixstart, pixend;
07925 int row_top, row_bot;
07926 int extrapolation;
07927 int nref;
07928 int nslits;
07929 int nfits;
07930 int nl, nx, ny, pixel;
07931 int countLines, usedLines;
07932 int uorder;
07933 int missing;
07934 int null;
07935 int width, uradius;
07936 int i, j, k, s;
07937
07938
07939 if (dispersion == 0.0) {
07940 cpl_msg_error(func, "The expected dispersion (A/pixel) must be given");
07941 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
07942 return NULL;
07943 }
07944
07945 if (dispersion < 0.0) {
07946 cpl_msg_error(func, "The expected dispersion must be positive");
07947 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
07948 return NULL;
07949 }
07950
07951 if (idscoeff == NULL) {
07952 cpl_msg_error(func, "A preallocated IDS coeff table must be given");
07953 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
07954 return NULL;
07955 }
07956
07957 max_disp = dispersion + dispersion * tolerance / 100;
07958 min_disp = dispersion - dispersion * tolerance / 100;
07959
07960 if (order < 1) {
07961 cpl_msg_error(func, "The order of the fitting polynomial "
07962 "must be at least 1");
07963 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
07964 return NULL;
07965 }
07966
07967 if (image == NULL || lines == NULL) {
07968 cpl_msg_error(func, "Both spectral exposure and reference line "
07969 "catalog are required in input");
07970 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
07971 return NULL;
07972 }
07973
07974 nx = cpl_image_get_size_x(image);
07975 ny = cpl_image_get_size_y(image);
07976 sdata = cpl_image_get_data_float(image);
07977
07978 nref = cpl_vector_get_size(lines);
07979 line = cpl_vector_get_data(lines);
07980
07981 if (*wavestart < 1.0 && *waveend < 1.0) {
07982 firstLambda = line[0];
07983 lastLambda = line[nref-1];
07984 extrapolation = (lastLambda - firstLambda) / 10;
07985 firstLambda -= extrapolation;
07986 lastLambda += extrapolation;
07987 *wavestart = firstLambda;
07988 *waveend = lastLambda;
07989 }
07990 else {
07991 firstLambda = *wavestart;
07992 lastLambda = *waveend;
07993 }
07994
07995 nl = (lastLambda - firstLambda) / dispersion;
07996 resampled = cpl_image_new(nl, ny, CPL_TYPE_FLOAT);
07997 rdata = cpl_image_get_data_float(resampled);
07998
07999
08000
08001
08002
08003 for (j = 0; j <= order; j++)
08004 cpl_table_new_column(idscoeff, clab[j], CPL_TYPE_DOUBLE);
08005
08006 if (calibration)
08007 idata = cpl_image_get_data_float(calibration);
08008
08009 if (residuals)
08010 ddata = cpl_image_get_data_float(residuals);
08011
08012 if (restable) {
08013 cpl_table_set_size(restable, nref);
08014 cpl_table_new_column(restable, "wavelength", CPL_TYPE_DOUBLE);
08015 cpl_table_copy_data_double(restable, "wavelength", line);
08016 for (i = 0; i < ny; i += step) {
08017 snprintf(name, MAX_COLNAME, "r%d", i);
08018 cpl_table_new_column(restable, name, CPL_TYPE_DOUBLE);
08019 snprintf(name, MAX_COLNAME, "d%d", i);
08020 cpl_table_new_column(restable, name, CPL_TYPE_DOUBLE);
08021 snprintf(name, MAX_COLNAME, "p%d", i);
08022 cpl_table_new_column(restable, name, CPL_TYPE_DOUBLE);
08023 }
08024 }
08025
08026
08027
08028
08029
08030
08031 nslits = cpl_table_get_nrow(slits);
08032 length = cpl_table_get_data_int(slits, "length");
08033
08034 row_top = ny;
08035 for (s = 0; s < nslits; s++) {
08036
08037 if (length[s] == 0)
08038 continue;
08039
08040
08041
08042
08043
08044
08045 row_bot = cpl_table_get_int(slits, "position", s, NULL);
08046
08047 if (sradius > 0) {
08048
08049
08050
08051
08052
08053
08054
08055
08056
08057 coeff = cpl_table_new(row_top - row_bot);
08058 for (j = 0; j <= order; j++)
08059 cpl_table_new_column(coeff, clab[j], CPL_TYPE_DOUBLE);
08060 }
08061
08062
08063
08064
08065
08066
08067 for (i = row_bot; i < row_top; i++) {
08068 width = mos_lines_width(sdata + i*nx, nx);
08069 if (width < 5)
08070 width = 5;
08071 peaks = mos_peak_candidates(sdata + i*nx, nx, level, width);
08072 if (peaks) {
08073 peaks = mos_refine_peaks(sdata + i*nx, nx, peaks, width);
08074 }
08075 if (peaks) {
08076 output = mos_identify_peaks(peaks, lines,
08077 min_disp, max_disp, 0.05);
08078 if (output) {
08079 countLines = cpl_bivector_get_size(output);
08080 if (countLines < 4) {
08081 cpl_bivector_delete(output);
08082 cpl_vector_delete(peaks);
08083 if (nlines)
08084 nlines[i] = 0;
08085 if (error)
08086 error[i] = 0.0;
08087 continue;
08088 }
08089
08090
08091
08092
08093
08094 wavel = cpl_bivector_get_y(output);
08095 cpl_vector_subtract_scalar(wavel, refwave);
08096
08097 uorder = countLines / 2 - 1;
08098 if (uorder > order)
08099 uorder = order;
08100
08101 ids = mos_poly_wav2pix(output, uorder, reject,
08102 2 * (uorder + 1), &usedLines,
08103 &ids_err);
08104
08105 if (ids == NULL) {
08106 cpl_bivector_delete(output);
08107 cpl_vector_delete(peaks);
08108 if (nlines)
08109 nlines[i] = 0;
08110 if (error)
08111 error[i] = 0.0;
08112 cpl_error_reset();
08113 continue;
08114 }
08115
08116 if (sradius > 0) {
08117 for (k = 0; k <= order; k++) {
08118 if (k > uorder) {
08119 cpl_table_set_double(coeff, clab[k],
08120 i - row_bot, 0.0);
08121 }
08122 else {
08123 cpl_table_set_double(coeff, clab[k],
08124 i - row_bot, cpl_polynomial_get_coeff(ids, &k));
08125 }
08126 }
08127 }
08128
08129 if (calibration) {
08130 pixstart = cpl_polynomial_eval_1d(ids,
08131 cpl_bivector_get_y_data(output)[0],
08132 NULL);
08133 pixend = cpl_polynomial_eval_1d(ids,
08134 cpl_bivector_get_y_data(output)[countLines-1],
08135 NULL);
08136 extrapolation = (pixend - pixstart) / 5;
08137 pixstart -= extrapolation;
08138 pixend += extrapolation;
08139 if (pixstart < 0)
08140 pixstart = 0;
08141 if (pixend > nx)
08142 pixend = nx;
08143
08144 for (j = pixstart; j < pixend; j++) {
08145 (idata + i*nx)[j] = mos_eval_dds(ids,
08146 firstLambda, lastLambda, refwave, j);
08147 }
08148 }
08149
08150
08151
08152
08153
08154 if (residuals || (restable && !(i%step))) {
08155 if (restable && !(i%step)) {
08156 lin = cpl_polynomial_new(1);
08157 for (k = 0; k < 2; k++)
08158 cpl_polynomial_set_coeff(lin, &k,
08159 cpl_polynomial_get_coeff(ids, &k));
08160 }
08161 for (j = 0; j < countLines; j++) {
08162 pixe = cpl_bivector_get_x_data(output)[j];
08163 wave = cpl_bivector_get_y_data(output)[j];
08164 value = pixe
08165 - cpl_polynomial_eval_1d(ids, wave, NULL);
08166 if (residuals) {
08167 pixel = pixe + 0.5;
08168 (ddata + i*nx)[pixel] = value;
08169 }
08170 if (restable && !(i%step)) {
08171 for (k = 0; k < nref; k++) {
08172 if (fabs(line[k]-refwave-wave) < 0.1) {
08173 snprintf(name, MAX_COLNAME,
08174 "r%d", i);
08175 cpl_table_set_double(restable, name,
08176 k, value);
08177 value = pixe
08178 - cpl_polynomial_eval_1d(lin,
08179 wave, NULL);
08180 snprintf(name, MAX_COLNAME,
08181 "d%d", i);
08182 cpl_table_set_double(restable, name,
08183 k, value);
08184 snprintf(name, MAX_COLNAME,
08185 "p%d", i);
08186 cpl_table_set_double(restable, name,
08187 k, pixe);
08188 break;
08189 }
08190 }
08191 }
08192 }
08193 if (restable && !(i%step)) {
08194 cpl_polynomial_delete(lin);
08195 }
08196
08197
08198
08199
08200
08201
08202
08203
08204
08205
08206
08207 }
08208
08209
08210
08211
08212
08213
08214
08215
08216 if (nlines)
08217 nlines[i] = usedLines;
08218 if (error)
08219 error[i] = ids_err / sqrt(usedLines/(uorder + 1));
08220
08221 for (k = 0; k <= order; k++) {
08222 if (k > uorder) {
08223 cpl_table_set_double(idscoeff, clab[k], i, 0.0);
08224 }
08225 else {
08226 cpl_table_set_double(idscoeff, clab[k], i,
08227 cpl_polynomial_get_coeff(ids, &k));
08228 }
08229 }
08230
08231 cpl_polynomial_delete(ids);
08232 cpl_bivector_delete(output);
08233 }
08234 cpl_vector_delete(peaks);
08235 }
08236 }
08237
08238
08239 if (sradius > 0) {
08240
08241
08242
08243
08244
08245 nfits = row_top - row_bot - cpl_table_count_invalid(coeff, clab[0]);
08246
08247 if (nfits) {
08248
08249
08250
08251
08252
08253 fguess = cpl_polynomial_new(1);
08254
08255 for (k = 0; k <= order; k++) {
08256 c = cpl_table_get_column_median(coeff, clab[k]);
08257 cpl_polynomial_set_coeff(fguess, &k, c);
08258 }
08259
08260 for (i = row_bot; i < row_top; i++) {
08261
08262
08263
08264
08265
08266 width = mos_lines_width(sdata + i*nx, nx);
08267 if (width > sradius) {
08268 uradius = width;
08269 }
08270 else {
08271 uradius = sradius;
08272 }
08273
08274 output = mos_find_peaks(sdata + i*nx, nx, lines,
08275 fguess, refwave, uradius);
08276
08277 if (output == NULL) {
08278 cpl_error_reset();
08279 continue;
08280 }
08281
08282 countLines = cpl_bivector_get_size(output);
08283
08284 if (countLines < 4) {
08285 cpl_bivector_delete(output);
08286 continue;
08287 }
08288
08289
08290
08291
08292
08293 wavel = cpl_bivector_get_y(output);
08294 cpl_vector_subtract_scalar(wavel, refwave);
08295
08296 uorder = countLines / 2 - 1;
08297 if (uorder > order)
08298 uorder = order;
08299
08300 ids = mos_poly_wav2pix(output, uorder, reject,
08301 2 * (uorder + 1), &usedLines,
08302 &ids_err);
08303
08304 if (ids == NULL) {
08305 cpl_error_reset();
08306 cpl_bivector_delete(output);
08307 continue;
08308 }
08309
08310 if (nlines)
08311 nlines[i] = usedLines;
08312 if (error)
08313 error[i] = ids_err / sqrt(usedLines/(uorder + 1));
08314
08315 if (calibration) {
08316 pixstart = cpl_polynomial_eval_1d(ids,
08317 cpl_bivector_get_y_data(output)[0],
08318 NULL);
08319 pixend = cpl_polynomial_eval_1d(ids,
08320 cpl_bivector_get_y_data(output)[countLines-1],
08321 NULL);
08322 extrapolation = (pixend - pixstart) / 5;
08323 pixstart -= extrapolation;
08324 pixend += extrapolation;
08325 if (pixstart < 0)
08326 pixstart = 0;
08327 if (pixend > nx)
08328 pixend = nx;
08329
08330 for (j = pixstart; j < pixend; j++) {
08331 (idata + i*nx)[j] = mos_eval_dds(ids,
08332 firstLambda, lastLambda, refwave, j);
08333 }
08334 }
08335
08336
08337
08338
08339
08340 if (residuals || (restable && !(i%step))) {
08341 if (restable && !(i%step)) {
08342 lin = cpl_polynomial_new(1);
08343 for (k = 0; k < 2; k++)
08344 cpl_polynomial_set_coeff(lin, &k,
08345 cpl_polynomial_get_coeff(ids, &k));
08346 }
08347 for (j = 0; j < countLines; j++) {
08348 pixe = cpl_bivector_get_x_data(output)[j];
08349 wave = cpl_bivector_get_y_data(output)[j];
08350 value = pixe
08351 - cpl_polynomial_eval_1d(ids, wave, NULL);
08352 if (residuals) {
08353 pixel = pixe + 0.5;
08354 (ddata + i*nx)[pixel] = value;
08355 }
08356 if (restable && !(i%step)) {
08357 for (k = 0; k < nref; k++) {
08358 if (fabs(line[k]-refwave-wave) < 0.1) {
08359 snprintf(name, MAX_COLNAME,
08360 "r%d", i);
08361 cpl_table_set_double(restable, name,
08362 k, value);
08363 value = pixe
08364 - cpl_polynomial_eval_1d(lin,
08365 wave, NULL);
08366 snprintf(name, MAX_COLNAME,
08367 "d%d", i);
08368 cpl_table_set_double(restable, name,
08369 k, value);
08370 snprintf(name, MAX_COLNAME,
08371 "p%d", i);
08372 cpl_table_set_double(restable, name,
08373 k, pixe);
08374 break;
08375 }
08376 }
08377 }
08378 }
08379 if (restable && !(i%step)) {
08380 cpl_polynomial_delete(lin);
08381 }
08382
08383
08384
08385
08386
08387
08388
08389
08390
08391
08392
08393 }
08394
08395 for (k = 0; k <= order; k++) {
08396 if (k > uorder) {
08397 cpl_table_set_double(idscoeff, clab[k], i, 0.0);
08398 }
08399 else {
08400 cpl_table_set_double(idscoeff, clab[k], i,
08401 cpl_polynomial_get_coeff(ids, &k));
08402 }
08403 }
08404
08405 cpl_bivector_delete(output);
08406 cpl_polynomial_delete(ids);
08407
08408 }
08409
08410 cpl_polynomial_delete(fguess);
08411 }
08412
08413 cpl_table_delete(coeff);
08414
08415 }
08416
08417 row_top = row_bot;
08418
08419 }
08420
08421
08422
08423
08424
08425
08426
08427
08428
08429 for (i = 0; i < ny; i++) {
08430
08431 missing = 0;
08432 ids = cpl_polynomial_new(1);
08433 for (k = 0; k <= order; k++) {
08434 c = cpl_table_get_double(idscoeff, clab[k], i, &null);
08435 if (null) {
08436 cpl_polynomial_delete(ids);
08437 missing = 1;
08438 break;
08439 }
08440 cpl_polynomial_set_coeff(ids, &k, c);
08441 }
08442 if (missing)
08443 continue;
08444
08445 pixstart = cpl_polynomial_eval_1d(ids, firstLambda - refwave, NULL);
08446 pixend = cpl_polynomial_eval_1d(ids, lastLambda - refwave, NULL);
08447 if (pixstart < 0)
08448 pixstart = 0;
08449 if (pixend > nx)
08450 pixend = nx;
08451
08452
08453
08454
08455
08456 for (j = 0; j < nl; j++) {
08457 lambda = firstLambda + j * dispersion;
08458 fpixel = cpl_polynomial_eval_1d(ids, lambda - refwave, NULL);
08459 pixel = fpixel;
08460 if (pixel >= 0 && pixel < nx-1) {
08461 v1 = (sdata + i*nx)[pixel];
08462 v2 = (sdata + i*nx)[pixel+1];
08463 vi = v1 + (v2-v1)*(fpixel-pixel);
08464 (rdata + i*nl)[j] = vi;
08465 }
08466 }
08467
08468 cpl_polynomial_delete(ids);
08469 }
08470
08471 return resampled;
08472 }
08473
08474
08501 cpl_image *mos_wavelength_calibration(cpl_image *image, double refwave,
08502 double firstLambda, double lastLambda,
08503 double dispersion, cpl_table *idscoeff,
08504 int flux)
08505 {
08506
08507 const char *func = "mos_wavelength_calibration";
08508
08509 const char *clab[6] = {"c0", "c1", "c2", "c3", "c4", "c5"};
08510
08511
08512 cpl_image *resampled;
08513 cpl_polynomial *ids;
08514 double pixel_per_lambda;
08515 double lambda;
08516 double c;
08517 float *sdata;
08518 float *rdata;
08519 float v0, v1, v2, v3, vi;
08520 float fpixel;
08521 int order;
08522 int pixstart, pixend;
08523 int nl, nx, ny, pixel;
08524 int missing;
08525 int null;
08526 int i, j, k;
08527
08528
08529 if (dispersion <= 0.0) {
08530 cpl_msg_error(func, "The resampling step must be positive");
08531 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
08532 return NULL;
08533 }
08534
08535 if (lastLambda - firstLambda < dispersion) {
08536 cpl_msg_error(func, "Invalid spectral range: %.2f to %.2f",
08537 firstLambda, lastLambda);
08538 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
08539 return NULL;
08540 }
08541
08542 if (idscoeff == NULL) {
08543 cpl_msg_error(func, "An IDS coeff table must be given");
08544 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
08545 return NULL;
08546 }
08547
08548 if (image == NULL) {
08549 cpl_msg_error(func, "A scientific spectral image must be given");
08550 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
08551 return NULL;
08552 }
08553
08554 nx = cpl_image_get_size_x(image);
08555 ny = cpl_image_get_size_y(image);
08556 sdata = cpl_image_get_data_float(image);
08557
08558 nl = (lastLambda - firstLambda) / dispersion;
08559 resampled = cpl_image_new(nl, ny, CPL_TYPE_FLOAT);
08560 rdata = cpl_image_get_data_float(resampled);
08561
08562 order = 0;
08563 while (order < 6 && cpl_table_has_column(idscoeff, clab[order]))
08564 ++order;
08565 --order;
08566
08567 for (i = 0; i < ny; i++) {
08568
08569 missing = 0;
08570 ids = cpl_polynomial_new(1);
08571 for (k = 0; k <= order; k++) {
08572 c = cpl_table_get_double(idscoeff, clab[k], i, &null);
08573 if (null) {
08574 cpl_polynomial_delete(ids);
08575 missing = 1;
08576 break;
08577 }
08578 cpl_polynomial_set_coeff(ids, &k, c);
08579 }
08580 if (missing)
08581 continue;
08582
08583 pixstart = cpl_polynomial_eval_1d(ids, firstLambda - refwave, NULL);
08584 pixend = cpl_polynomial_eval_1d(ids, lastLambda - refwave, NULL);
08585 if (pixstart < 0)
08586 pixstart = 0;
08587 if (pixend > nx)
08588 pixend = nx;
08589
08590
08591
08592
08593
08594 for (j = 0; j < nl; j++) {
08595 lambda = firstLambda + j * dispersion;
08596 fpixel = cpl_polynomial_eval_1d(ids, lambda - refwave,
08597 &pixel_per_lambda);
08598
08599
08600
08601
08602
08603
08604
08605 pixel = fpixel;
08606 if (pixel >= 1 && pixel < nx-2) {
08607 v0 = (sdata + i*nx)[pixel-1];
08608 v1 = (sdata + i*nx)[pixel];
08609 v2 = (sdata + i*nx)[pixel+1];
08610 v3 = (sdata + i*nx)[pixel+2];
08611 vi = (fpixel-pixel)*(fpixel-pixel)*(v3 - v2 - v1 + v0)
08612 + (fpixel-pixel)*(3*v2 - v3 - v1 - v0)
08613 + 2*v1;
08614 vi /= 2;
08615 if (v1 > v2) {
08616 if (vi > v1) {
08617 vi = v1;
08618 }
08619 else if (vi < v2) {
08620 vi = v2;
08621 }
08622 }
08623 else {
08624 if (vi > v2) {
08625 vi = v2;
08626 }
08627 else if (vi < v1) {
08628 vi = v1;
08629 }
08630 }
08631 if (flux)
08632 vi *= dispersion * pixel_per_lambda;
08633 (rdata + i*nl)[j] = vi;
08634 }
08635 else if (pixel >= 0 && pixel < nx-1) {
08636 v1 = (sdata + i*nx)[pixel];
08637 v2 = (sdata + i*nx)[pixel+1];
08638 vi = v1 + (v2-v1)*(fpixel-pixel);
08639 if (flux)
08640 vi *= dispersion * pixel_per_lambda;
08641 (rdata + i*nl)[j] = vi;
08642 }
08643 }
08644
08645 cpl_polynomial_delete(ids);
08646 }
08647
08648 return resampled;
08649 }
08650
08651
08718 cpl_table *mos_wavelength_align(cpl_image *image, cpl_table *slits,
08719 double refwave, double firstLambda,
08720 double lastLambda, cpl_table *idscoeff,
08721 cpl_vector *skylines, int highres, int order,
08722 cpl_image *calibration, int sradius)
08723 {
08724 const char *func = "mos_wavelength_align";
08725
08726 const char *clab[6] = {"c0", "c1", "c2", "c3", "c4", "c5"};
08727
08728 double *line;
08729 double *data;
08730 double expPos, offset;
08731 double c;
08732 double lambda1, lambda2;
08733 double rms;
08734 float pos;
08735 float *sdata;
08736 float *cdata;
08737 int *idata;
08738 int startPos, endPos;
08739 int window = 2*sradius + 1;
08740 int nlines;
08741 int nslits;
08742 int npoints;
08743 int nrows;
08744 int nx, ny;
08745 int xlow, ylow, xhig, yhig;
08746 int idsorder, uorder;
08747 int *slit_id;
08748 int *position;
08749 int *length;
08750 int missing;
08751 int null;
08752 int i, j, k;
08753
08754 char offname[MAX_COLNAME];
08755 char name[MAX_COLNAME];
08756
08757 cpl_polynomial *ids;
08758 cpl_polynomial *polycorr;
08759 cpl_image *exslit;
08760 cpl_image *sky;
08761 cpl_table *offsets;
08762 cpl_table *dummy;
08763 cpl_vector *wave;
08764 cpl_vector *offs;
08765
08766
08767 if (idscoeff == NULL) {
08768 cpl_msg_error(func, "An IDS coeff table must be given");
08769 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
08770 return NULL;
08771 }
08772
08773 if (image == NULL) {
08774 cpl_msg_error(func, "A scientific spectral image must be given");
08775 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
08776 return NULL;
08777 }
08778
08779 if (slits == NULL) {
08780 cpl_msg_error(func, "A slit position table must be given");
08781 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
08782 return NULL;
08783 }
08784
08785 if (skylines) {
08786 line = cpl_vector_get_data(skylines);
08787 nlines = cpl_vector_get_size(skylines);
08788 }
08789 else {
08790 cpl_msg_warning(func, "A catalog of sky lines wavelengths was not "
08791 "given: using internal list of reference sky lines");
08792 if (highres) {
08793 line = default_lines_hi;
08794 nlines = sizeof(default_lines_hi) / sizeof(double);
08795 }
08796 else {
08797 line = default_lines_lo;
08798 nlines = sizeof(default_lines_lo) / sizeof(double);
08799 }
08800 }
08801
08802 if (calibration)
08803 cdata = cpl_image_get_data(calibration);
08804
08805 nx = cpl_image_get_size_x(image);
08806 ny = cpl_image_get_size_y(image);
08807
08808 nslits = cpl_table_get_nrow(slits);
08809 slit_id = cpl_table_get_data_int(slits, "slit_id");
08810 position = cpl_table_get_data_int(slits, "position");
08811 length = cpl_table_get_data_int(slits, "length");
08812
08813
08814
08815
08816
08817
08818 nrows = 0;
08819 for (i = 0; i < nlines; i++)
08820 if (line[i] > firstLambda && line[i] < lastLambda)
08821 nrows++;
08822
08823 offsets = cpl_table_new(nrows);
08824 cpl_table_new_column(offsets, "wave", CPL_TYPE_DOUBLE);
08825 cpl_table_set_column_unit(offsets, "wave", "Angstrom");
08826
08827 nrows = 0;
08828 for (i = 0; i < nlines; i++) {
08829 if (line[i] > firstLambda && line[i] < lastLambda) {
08830 cpl_table_set_double(offsets, "wave", nrows, line[i]);
08831 nrows++;
08832 }
08833 }
08834
08835
08836
08837
08838
08839 line = cpl_table_get_data_double(offsets, "wave");
08840 nlines = nrows;
08841
08842 idsorder = 0;
08843 while (idsorder < 6 && cpl_table_has_column(idscoeff, clab[idsorder]))
08844 ++idsorder;
08845 --idsorder;
08846
08847 xlow = 1;
08848 xhig = nx;
08849 for (i = 0; i < nslits; i++) {
08850
08851 if (length[i] == 0)
08852 continue;
08853
08854 snprintf(offname, MAX_COLNAME, "offset%d", slit_id[i]);
08855 cpl_table_new_column(offsets, offname, CPL_TYPE_DOUBLE);
08856
08857
08858
08859
08860
08861
08862
08863
08864
08865
08866
08867 ylow = position[i] + 1;
08868 yhig = ylow + length[i] - 1;
08869
08870 exslit = cpl_image_extract(image, xlow, ylow, xhig, yhig);
08871 sky = cpl_image_collapse_median_create(exslit, 0, 0, 1);
08872 sdata = cpl_image_get_data(sky);
08873
08874 cpl_image_delete(exslit);
08875
08876
08877
08878
08879
08880
08881 ylow--;
08882
08883
08884
08885
08886
08887
08888
08889 dummy = cpl_table_new(yhig - ylow);
08890 for (j = 0; j < nlines; j++) {
08891 snprintf(name, MAX_COLNAME, "%d", j);
08892 cpl_table_new_column(dummy, name, CPL_TYPE_DOUBLE);
08893 }
08894
08895 for (j = ylow; j < yhig; j++) {
08896
08897
08898
08899
08900
08901 missing = 0;
08902 ids = cpl_polynomial_new(1);
08903 for (k = 0; k <= idsorder; k++) {
08904 c = cpl_table_get_double(idscoeff, clab[k], j, &null);
08905 if (null) {
08906 cpl_polynomial_delete(ids);
08907 missing = 1;
08908 break;
08909 }
08910 cpl_polynomial_set_coeff(ids, &k, c);
08911 }
08912 if (missing)
08913 continue;
08914
08915 for (k = 0; k < nlines; k++) {
08916 expPos = cpl_polynomial_eval_1d(ids, line[k] - refwave, NULL);
08917 startPos = expPos - sradius;
08918 endPos = startPos + window;
08919 if (startPos < 0 || endPos >= nx)
08920 continue;
08921
08922 if (0 == peakPosition(sdata + startPos, window, &pos, 1)) {
08923 pos += startPos;
08924 offset = pos - expPos;
08925 snprintf(name, MAX_COLNAME, "%d", k);
08926 cpl_table_set_double(dummy, name, j - ylow, offset);
08927 }
08928 }
08929
08930 cpl_polynomial_delete(ids);
08931 }
08932
08933 cpl_image_delete(sky);
08934
08935 for (j = 0; j < nlines; j++) {
08936 snprintf(name, MAX_COLNAME, "%d", j);
08937 if (cpl_table_has_valid(dummy, name)) {
08938 offset = cpl_table_get_column_median(dummy, name);
08939 cpl_table_set_double(offsets, offname, j, offset);
08940 }
08941 }
08942
08943 cpl_table_delete(dummy);
08944
08945 }
08946
08947
08948
08949
08950
08951
08952
08953
08954 for (i = 0; i < nslits; i++) {
08955
08956 if (length[i] == 0)
08957 continue;
08958
08959 snprintf(offname, MAX_COLNAME, "offset%d", slit_id[i]);
08960
08961
08962
08963
08964
08965
08966 dummy = cpl_table_new(nlines);
08967 cpl_table_duplicate_column(dummy, "wave", offsets, "wave");
08968 cpl_table_duplicate_column(dummy, "offset", offsets, offname);
08969
08970 npoints = nlines - cpl_table_count_invalid(dummy, "offset");
08971 if (npoints == 0) {
08972 cpl_msg_warning(func, "No sky lines alignment was possible "
08973 "for slit ID=%d: no sky line found", slit_id[i]);
08974 cpl_table_delete(dummy);
08975 continue;
08976 }
08977
08978 uorder = order;
08979 if (npoints <= uorder) {
08980 uorder = npoints - 1;
08981 if (uorder) {
08982 cpl_msg_warning(func, "Just %d sky lines detected for slit "
08983 "ID=%d, while a polynomial order %d was "
08984 "requested. Using polynomial order %d for "
08985 "this slit!", npoints, slit_id[i], order,
08986 uorder);
08987 }
08988 else {
08989 cpl_msg_warning(func, "Just %d sky lines detected for slit "
08990 "ID=%d, while a polynomial order %d was "
08991 "requested. Computing a median offset for "
08992 "this slit!", npoints, slit_id[i], order);
08993 }
08994 }
08995
08996 cpl_table_erase_invalid(dummy);
08997
08998 if (uorder > 1) {
08999
09000
09001
09002
09003
09004 wave = cpl_vector_wrap(npoints,
09005 cpl_table_get_data_double(dummy, "wave"));
09006 offs = cpl_vector_wrap(npoints,
09007 cpl_table_get_data_double(dummy, "offset"));
09008
09009
09010
09011
09012
09013 cpl_vector_subtract_scalar(wave, refwave);
09014
09015 polycorr = cpl_polynomial_fit_1d_create(wave, offs, uorder, &rms);
09016
09017 rms = sqrt(rms * (uorder + 1) / npoints);
09018
09019 cpl_vector_unwrap(wave);
09020 cpl_vector_unwrap(offs);
09021 cpl_table_delete(dummy);
09022
09023
09024
09025
09026
09027
09028 ylow = position[i];
09029 yhig = ylow + length[i];
09030
09031 for (j = 0; j <= uorder; j++) {
09032 data = cpl_table_get_data_double(idscoeff, clab[j]);
09033 c = cpl_polynomial_get_coeff(polycorr, &j);
09034 for (k = ylow; k < yhig; k++)
09035 data[k] += c;
09036 }
09037
09038 data = cpl_table_get_data_double(idscoeff, "error");
09039 for (k = ylow; k < yhig; k++)
09040 data[k] = sqrt(data[k]*data[k] + rms*rms);
09041
09042 idata = cpl_table_get_data_int(idscoeff, "nlines");
09043 for (k = ylow; k < yhig; k++)
09044 idata[k] = npoints;
09045
09046
09047
09048
09049
09050
09051 if (calibration) {
09052 for (j = ylow; j < yhig; j++) {
09053 for (k = 1; k < nx; k++) {
09054 lambda1 = cdata[k - 1 + j*nx];
09055 lambda2 = cdata[k + j*nx];
09056 if (lambda1 < 1.0 || lambda2 < 1.0)
09057 continue;
09058 offset = cpl_polynomial_eval_1d(polycorr,
09059 lambda1-refwave, NULL);
09060 cdata[k - 1 + j*nx] -= offset * (lambda2-lambda1);
09061 }
09062 }
09063 }
09064
09065 cpl_polynomial_delete(polycorr);
09066 }
09067 else if (uorder == 1) {
09068
09069
09070
09071
09072
09073 double q, m;
09074 cpl_bivector *list;
09075
09076
09077 wave = cpl_vector_wrap(npoints,
09078 cpl_table_get_data_double(dummy, "wave"));
09079 offs = cpl_vector_wrap(npoints,
09080 cpl_table_get_data_double(dummy, "offset"));
09081
09082 list = cpl_bivector_wrap_vectors(wave, offs);
09083
09084
09085
09086
09087
09088 cpl_vector_subtract_scalar(wave, refwave);
09089
09090 robustLinearFit(list, &q, &m, &rms);
09091
09092 rms = sqrt(rms * (uorder + 1) / npoints);
09093
09094 cpl_bivector_unwrap_vectors(list);
09095 cpl_vector_unwrap(wave);
09096 cpl_vector_unwrap(offs);
09097 cpl_table_delete(dummy);
09098
09099
09100
09101
09102
09103
09104 ylow = position[i];
09105 yhig = ylow + length[i];
09106
09107 for (j = 0; j <= uorder; j++) {
09108 data = cpl_table_get_data_double(idscoeff, clab[j]);
09109 if (j)
09110 c = m;
09111 else
09112 c = q;
09113 for (k = ylow; k < yhig; k++)
09114 data[k] += c;
09115 }
09116
09117 data = cpl_table_get_data_double(idscoeff, "error");
09118 for (k = ylow; k < yhig; k++)
09119 data[k] = sqrt(data[k]*data[k] + rms*rms);
09120
09121 idata = cpl_table_get_data_int(idscoeff, "nlines");
09122 for (k = ylow; k < yhig; k++)
09123 idata[k] = npoints;
09124
09125
09126
09127
09128
09129
09130 if (calibration) {
09131 for (j = ylow; j < yhig; j++) {
09132 for (k = 1; k < nx; k++) {
09133 lambda1 = cdata[k - 1 + j*nx];
09134 lambda2 = cdata[k + j*nx];
09135 if (lambda1 < 1.0 || lambda2 < 1.0)
09136 continue;
09137 offset = q + m*(lambda1-refwave);
09138 cdata[k - 1 + j*nx] -= offset * (lambda2-lambda1);
09139 }
09140 }
09141 }
09142 }
09143 else {
09144
09145
09146
09147
09148
09149 offs = cpl_vector_wrap(npoints,
09150 cpl_table_get_data_double(dummy, "offset"));
09151
09152 offset = cpl_vector_get_median_const(offs);
09153
09154 if (npoints > 1)
09155 rms = cpl_table_get_column_stdev(dummy, "offset");
09156 else
09157 rms = 0.0;
09158
09159 rms /= sqrt(npoints);
09160
09161 cpl_vector_unwrap(offs);
09162 cpl_table_delete(dummy);
09163
09164
09165
09166
09167
09168
09169 ylow = position[i];
09170 yhig = ylow + length[i];
09171
09172 data = cpl_table_get_data_double(idscoeff, clab[0]);
09173 for (k = ylow; k < yhig; k++)
09174 data[k] += offset;
09175
09176 data = cpl_table_get_data_double(idscoeff, "error");
09177 for (k = ylow; k < yhig; k++)
09178 data[k] = sqrt(data[k]*data[k] + rms*rms);
09179
09180 idata = cpl_table_get_data_int(idscoeff, "nlines");
09181 for (k = ylow; k < yhig; k++)
09182 idata[k] = npoints;
09183
09184
09185
09186
09187
09188
09189
09190 if (calibration) {
09191 for (j = ylow; j < yhig; j++) {
09192 for (k = 1; k < nx; k++) {
09193 lambda1 = cdata[k - 1 + j*nx];
09194 lambda2 = cdata[k + j*nx];
09195 if (lambda1 < 1.0 || lambda2 < 1.0)
09196 continue;
09197 cdata[k - 1 + j*nx] -= offset * (lambda2-lambda1);
09198 }
09199 }
09200 }
09201 }
09202 }
09203
09204 return offsets;
09205
09206 }
09207
09208
09270 cpl_table *mos_wavelength_align_lss(cpl_image *image, double refwave,
09271 double firstLambda, double lastLambda,
09272 cpl_table *idscoeff, cpl_vector *skylines,
09273 int highres, int order,
09274 cpl_image *calibration, int sradius)
09275 {
09276 const char *func = "mos_wavelength_align_lss";
09277
09278 const char *clab[6] = {"c0", "c1", "c2", "c3", "c4", "c5"};
09279
09280 double *line;
09281 double *data;
09282 double *wdata;
09283 double *odata;
09284 double expPos, offset;
09285 double c;
09286 double lambda1, lambda2;
09287 double rms;
09288 float pos;
09289 float *sdata;
09290 float *cdata;
09291 int *idata;
09292 int startPos, endPos;
09293 int window = 2*sradius + 1;
09294 int nlines;
09295 int npoints;
09296 int nrows;
09297 int nx, ny;
09298 int idsorder, uorder;
09299 int missing;
09300 int i, j, k;
09301
09302 char name[MAX_COLNAME];
09303 char fname[MAX_COLNAME];
09304
09305 cpl_polynomial *ids;
09306 cpl_polynomial *polycorr;
09307 cpl_table *offsets;
09308 cpl_table *fittable;
09309 cpl_table *dummy;
09310 cpl_vector *wave;
09311 cpl_vector *offs;
09312 cpl_vector *row;
09313
09314
09315 if (idscoeff == NULL) {
09316 cpl_msg_error(func, "An IDS coeff table must be given");
09317 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
09318 return NULL;
09319 }
09320
09321 if (image == NULL) {
09322 cpl_msg_error(func, "A scientific spectral image must be given");
09323 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
09324 return NULL;
09325 }
09326
09327 if (skylines) {
09328 line = cpl_vector_get_data(skylines);
09329 nlines = cpl_vector_get_size(skylines);
09330 }
09331 else {
09332 cpl_msg_warning(func, "A catalog of sky lines wavelengths was not "
09333 "given: using internal list of reference sky lines");
09334 if (highres) {
09335 line = default_lines_hi;
09336 nlines = sizeof(default_lines_hi) / sizeof(double);
09337 }
09338 else {
09339 line = default_lines_lo;
09340 nlines = sizeof(default_lines_lo) / sizeof(double);
09341 }
09342 }
09343
09344 if (calibration)
09345 cdata = cpl_image_get_data(calibration);
09346
09347 nx = cpl_image_get_size_x(image);
09348 ny = cpl_image_get_size_y(image);
09349
09350 sdata = cpl_image_get_data(image);
09351
09352
09353
09354
09355
09356
09357
09358
09359
09360
09361 nrows = 0;
09362 for (i = 0; i < nlines; i++)
09363 if (line[i] > firstLambda && line[i] < lastLambda)
09364 nrows++;
09365
09366 offsets = cpl_table_new(nrows);
09367 cpl_table_new_column(offsets, "wave", CPL_TYPE_DOUBLE);
09368 cpl_table_set_column_unit(offsets, "wave", "Angstrom");
09369
09370 nrows = 0;
09371 for (i = 0; i < nlines; i++) {
09372 if (line[i] > firstLambda && line[i] < lastLambda) {
09373 cpl_table_set_double(offsets, "wave", nrows, line[i]);
09374 nrows++;
09375 }
09376 }
09377
09378
09379
09380
09381
09382 line = cpl_table_get_data_double(offsets, "wave");
09383 nlines = nrows;
09384
09385 idsorder = 0;
09386 while (idsorder < 6 && cpl_table_has_column(idscoeff, clab[idsorder]))
09387 ++idsorder;
09388 --idsorder;
09389
09390
09391
09392
09393
09394
09395
09396 dummy = cpl_table_new(ny);
09397 for (j = 0; j < nlines; j++) {
09398 snprintf(name, MAX_COLNAME, "off_%d", (int)line[j]);
09399 snprintf(fname, MAX_COLNAME, "fit_%d", (int)line[j]);
09400 cpl_table_new_column(dummy, name, CPL_TYPE_DOUBLE);
09401 cpl_table_new_column(dummy, fname, CPL_TYPE_DOUBLE);
09402 }
09403
09404 for (j = 0; j < ny; j++, sdata += nx) {
09405
09406
09407
09408
09409
09410 missing = 0;
09411 ids = cpl_polynomial_new(1);
09412 for (k = 0; k <= idsorder; k++) {
09413 c = cpl_table_get_double(idscoeff, clab[k], j, &missing);
09414 if (missing) {
09415 cpl_polynomial_delete(ids);
09416 break;
09417 }
09418 cpl_polynomial_set_coeff(ids, &k, c);
09419 }
09420 if (missing)
09421 continue;
09422
09423 for (k = 0; k < nlines; k++) {
09424 expPos = cpl_polynomial_eval_1d(ids, line[k] - refwave, NULL);
09425 startPos = expPos - sradius;
09426 endPos = startPos + window;
09427 if (startPos < 0 || endPos >= nx)
09428 continue;
09429
09430 if (0 == peakPosition(sdata + startPos, window, &pos, 1)) {
09431 pos += startPos;
09432 offset = pos - expPos;
09433 snprintf(name, MAX_COLNAME, "off_%d", (int)line[k]);
09434 cpl_table_set_double(dummy, name, j, offset);
09435 }
09436 }
09437
09438 cpl_polynomial_delete(ids);
09439 }
09440
09441
09442
09443
09444
09445
09446
09447 for (j = 0; j < nlines; j++) {
09448 snprintf(name, MAX_COLNAME, "off_%d", (int)line[j]);
09449 snprintf(fname, MAX_COLNAME, "fit_%d", (int)line[j]);
09450 if (cpl_table_has_valid(dummy, name)) {
09451
09452
09453
09454
09455
09456
09457 double q, m;
09458 cpl_bivector *list;
09459
09460 fittable = cpl_table_new(ny);
09461 cpl_table_new_column(fittable, "row", CPL_TYPE_DOUBLE);
09462 cpl_table_set_column_unit(fittable, "row", "pixel");
09463 for (k = 0; k < ny; k++)
09464 cpl_table_set_double(fittable, "row", k, k);
09465 cpl_table_duplicate_column(fittable, "offset", dummy, name);
09466 npoints = ny - cpl_table_count_invalid(fittable, "offset");
09467 cpl_table_erase_invalid(fittable);
09468 row = cpl_vector_wrap(npoints,
09469 cpl_table_get_data_double(fittable, "row"));
09470 offs = cpl_vector_wrap(npoints,
09471 cpl_table_get_data_double(fittable, "offset"));
09472 list = cpl_bivector_wrap_vectors(row, offs);
09473 robustLinearFit(list, &q, &m, &rms);
09474 cpl_bivector_unwrap_vectors(list);
09475 cpl_vector_unwrap(row);
09476 cpl_vector_unwrap(offs);
09477 cpl_table_delete(fittable);
09478 for (k = 0; k < ny; k++)
09479 cpl_table_set_double(dummy, fname, k, q + m*k);
09480 }
09481 }
09482
09483
09484
09485
09486
09487
09488
09489
09490
09491
09492 for (i = 0; i < ny; i++) {
09493
09494 if (!cpl_table_is_valid(idscoeff, clab[0], i))
09495 continue;
09496
09497 npoints = 0;
09498 for (j = 0; j < nlines; j++) {
09499 snprintf(name, MAX_COLNAME, "fit_%d", (int)line[j]);
09500 if (cpl_table_is_valid(dummy, name, i))
09501 npoints++;
09502 }
09503
09504 if (npoints == 0)
09505 continue;
09506
09507 uorder = order;
09508 if (npoints <= uorder)
09509 uorder = npoints - 1;
09510
09511 if (uorder > 1) {
09512
09513
09514
09515
09516
09517 wave = cpl_vector_new(npoints);
09518 wdata = cpl_vector_get_data(wave);
09519 offs = cpl_vector_new(npoints);
09520 odata = cpl_vector_get_data(offs);
09521
09522 npoints = 0;
09523 for (j = 0; j < nlines; j++) {
09524 snprintf(name, MAX_COLNAME, "fit_%d", (int)line[j]);
09525 if (cpl_table_is_valid(dummy, name, i)) {
09526 wdata[npoints] = line[j] - refwave;
09527 odata[npoints] = cpl_table_get_double(dummy, name, i, NULL);
09528 npoints++;
09529 }
09530 }
09531
09532 polycorr = cpl_polynomial_fit_1d_create(wave, offs, uorder, &rms);
09533
09534 rms = sqrt(rms * (uorder + 1) / npoints);
09535
09536 cpl_vector_delete(wave);
09537 cpl_vector_delete(offs);
09538
09539
09540
09541
09542
09543
09544 for (j = 0; j <= uorder; j++) {
09545 data = cpl_table_get_data_double(idscoeff, clab[j]);
09546 c = cpl_polynomial_get_coeff(polycorr, &j);
09547 data[i] += c;
09548 }
09549
09550 data = cpl_table_get_data_double(idscoeff, "error");
09551 data[i] = sqrt(data[i]*data[i] + rms*rms);
09552
09553 idata = cpl_table_get_data_int(idscoeff, "nlines");
09554 idata[i] = npoints;
09555
09556
09557
09558
09559
09560
09561 if (calibration) {
09562 for (k = 1; k < nx; k++) {
09563 lambda1 = cdata[k - 1 + i*nx];
09564 lambda2 = cdata[k + i*nx];
09565 if (lambda1 < 1.0 || lambda2 < 1.0)
09566 continue;
09567 offset = cpl_polynomial_eval_1d(polycorr,
09568 lambda1-refwave, NULL);
09569 cdata[k - 1 + i*nx] -= offset * (lambda2-lambda1);
09570 }
09571 }
09572
09573 cpl_polynomial_delete(polycorr);
09574
09575 }
09576 else if (uorder == 1) {
09577
09578
09579
09580
09581
09582 cpl_bivector *list;
09583 double q, m;
09584
09585 wave = cpl_vector_new(npoints);
09586 wdata = cpl_vector_get_data(wave);
09587 offs = cpl_vector_new(npoints);
09588 odata = cpl_vector_get_data(offs);
09589
09590 npoints = 0;
09591 for (j = 0; j < nlines; j++) {
09592 snprintf(name, MAX_COLNAME, "fit_%d", (int)line[j]);
09593 if (cpl_table_is_valid(dummy, name, i)) {
09594 wdata[npoints] = line[j] - refwave;
09595 odata[npoints] = cpl_table_get_double(dummy, name, i, NULL);
09596 npoints++;
09597 }
09598 }
09599
09600 list = cpl_bivector_wrap_vectors(wave, offs);
09601 robustLinearFit(list, &q, &m, &rms);
09602
09603 rms = sqrt(rms * (uorder + 1) / npoints);
09604
09605 cpl_bivector_unwrap_vectors(list);
09606 cpl_vector_delete(wave);
09607 cpl_vector_delete(offs);
09608
09609
09610
09611
09612
09613
09614 for (j = 0; j <= uorder; j++) {
09615 data = cpl_table_get_data_double(idscoeff, clab[j]);
09616 if (j)
09617 c = m;
09618 else
09619 c = q;
09620 data[i] += c;
09621 }
09622
09623 data = cpl_table_get_data_double(idscoeff, "error");
09624 data[i] = sqrt(data[i]*data[i] + rms*rms);
09625
09626 idata = cpl_table_get_data_int(idscoeff, "nlines");
09627 idata[i] = npoints;
09628
09629
09630
09631
09632
09633
09634 if (calibration) {
09635 for (k = 1; k < nx; k++) {
09636 lambda1 = cdata[k - 1 + i*nx];
09637 lambda2 = cdata[k + i*nx];
09638 if (lambda1 < 1.0 || lambda2 < 1.0)
09639 continue;
09640 offset = q + m*(lambda1-refwave);
09641 cdata[k - 1 + i*nx] -= offset * (lambda2-lambda1);
09642 }
09643 }
09644 }
09645 else {
09646
09647
09648
09649
09650
09651 offs = cpl_vector_new(npoints);
09652 odata = cpl_vector_get_data(offs);
09653
09654 npoints = 0;
09655 for (j = 0; j < nlines; j++) {
09656 snprintf(name, MAX_COLNAME, "fit_%d", (int)line[j]);
09657 if (cpl_table_is_valid(dummy, name, i)) {
09658 odata[npoints] = cpl_table_get_double(dummy, name, i, NULL);
09659 npoints++;
09660 }
09661 }
09662
09663 offset = cpl_vector_get_median_const(offs);
09664
09665 if (npoints > 1) {
09666 rms = cpl_vector_get_stdev(offs);
09667 }
09668 else if (npoints == 1) {
09669 snprintf(name, MAX_COLNAME, "off_%d", (int)line[0]);
09670 if (cpl_table_has_valid(dummy, name)) {
09671 rms = cpl_table_get_column_stdev(dummy, name);
09672 rms /= sqrt(ny - cpl_table_count_invalid(dummy, name));
09673 }
09674 else {
09675 rms = 0.0;
09676 }
09677 }
09678 else {
09679 rms = 0.0;
09680 }
09681
09682 rms /= sqrt(npoints);
09683
09684 cpl_vector_delete(offs);
09685
09686
09687
09688
09689
09690
09691 data = cpl_table_get_data_double(idscoeff, clab[0]);
09692 data[i] += offset;
09693
09694 data = cpl_table_get_data_double(idscoeff, "error");
09695 data[i] = sqrt(data[i]*data[i] + rms*rms);
09696
09697 idata = cpl_table_get_data_int(idscoeff, "nlines");
09698 idata[i] = npoints;
09699
09700
09701
09702
09703
09704
09705
09706 if (calibration) {
09707 for (k = 1; k < nx; k++) {
09708 lambda1 = cdata[k - 1 + i*nx];
09709 lambda2 = cdata[k + i*nx];
09710 if (lambda1 < 1.0 || lambda2 < 1.0)
09711 continue;
09712 cdata[k - 1 + i*nx] -= offset * (lambda2-lambda1);
09713 }
09714 }
09715 }
09716 }
09717
09718 missing = 1;
09719 for (j = 0; j < nlines; j++) {
09720 snprintf(name, MAX_COLNAME, "off_%d", (int)line[j]);
09721 if (cpl_table_has_valid(dummy, name)) {
09722 missing = 0;
09723 offset = cpl_table_get_column_median(dummy, name);
09724 cpl_msg_info(func, "Median offset for %.3f: %.3f pixel",
09725 line[j], offset);
09726 }
09727 else {
09728 cpl_msg_info(func,
09729 "Median offset for %.2f: not available", line[j]);
09730 }
09731 }
09732
09733 cpl_table_delete(offsets);
09734
09735 if (missing) {
09736 cpl_table_delete(dummy);
09737 dummy = NULL;
09738 }
09739
09740 return dummy;
09741
09742 }
09743
09744
09772 double mos_distortions_rms(cpl_image *rectified, cpl_vector *lines,
09773 double wavestart, double dispersion, int radius,
09774 int highres)
09775 {
09776
09777 const char *func = "mos_distortions_rms";
09778
09779 int xlen;
09780 int ylen;
09781 int numLines;
09782 int cpix, npix, nzero;
09783 int sp, ep;
09784 int i, j, k;
09785 int npeaks, allPeaks;
09786
09787 float *profile;
09788 float peak, expectPeak, offset;
09789 double lambda;
09790
09791 double average;
09792 double rms, oneRms;
09793
09794 float *sdata;
09795 double *wdata;
09796
09797
09798 xlen = cpl_image_get_size_x(rectified);
09799 ylen = cpl_image_get_size_y(rectified);
09800 sdata = cpl_image_get_data(rectified);
09801
09802 if (lines) {
09803 wdata = cpl_vector_get_data(lines);
09804 numLines = cpl_vector_get_size(lines);
09805 }
09806 else {
09807 cpl_msg_warning(func, "A catalog of sky lines wavelengths was not "
09808 "given: using internal list of reference sky lines");
09809 if (highres) {
09810 wdata = default_lines_hi;
09811 numLines = sizeof(default_lines_hi) / sizeof(double);
09812 }
09813 else {
09814 wdata = default_lines_lo;
09815 numLines = sizeof(default_lines_lo) / sizeof(double);
09816 }
09817 }
09818
09819 npix = 2 * radius + 1;
09820 profile = cpl_calloc(npix, sizeof(float));
09821
09822 rms = 0.0;
09823 allPeaks = 0;
09824
09825 for (i = 0; i < numLines; i++) {
09826
09827
09828
09829
09830
09831 lambda = wdata[i];
09832 expectPeak = (lambda - wavestart) / dispersion;
09833 cpix = floor(expectPeak + 0.5);
09834
09835
09836
09837
09838
09839 sp = cpix - radius;
09840 ep = cpix + radius;
09841
09842 if (sp < 0 || ep > xlen)
09843 continue;
09844
09845 average = 0.0;
09846 npeaks = 0;
09847 oneRms = 0.0;
09848
09849 for (j = 0; j < ylen; j++) {
09850 nzero = 0;
09851 for (k = 0; k < npix; k++) {
09852 profile[k] = sdata[sp + k + j * xlen];
09853 if (fabs(profile[k]) < 0.0001)
09854 nzero++;
09855 }
09856 if (nzero > 0)
09857 continue;
09858
09859 if (peakPosition(profile, npix, &peak, 1) == 0) {
09860 offset = (sp + peak) - expectPeak;
09861 average += offset;
09862 rms += fabs(offset);
09863 oneRms += fabs(offset);
09864 npeaks++;
09865 allPeaks++;
09866 }
09867 }
09868
09869 if (npeaks)
09870 cpl_msg_info(func, "RMS for %.2f: %.3f pixel (%d points)",
09871 lambda, oneRms / npeaks * 1.25, npeaks);
09872 else
09873 cpl_msg_info(func, "RMS for %.2f: line not available", lambda);
09874 }
09875
09876 cpl_free(profile);
09877
09878 if (allPeaks < 10)
09879 return 0.0;
09880
09881 rms /= allPeaks;
09882 rms *= 1.25;
09883
09884 return rms;
09885
09886 }
09887
09888
09909 cpl_image *mos_map_pixel(cpl_table *idscoeff, double reference,
09910 double blue, double red, double dispersion, int trend)
09911 {
09912 const char *func = "mos_map_pixel";
09913
09914 const char *clab[6] = {"c0", "c1", "c2", "c3", "c4", "c5"};
09915
09916
09917 cpl_polynomial *ids;
09918 cpl_image *map;
09919 float *mdata;
09920 double lambda;
09921 double c;
09922 int order;
09923 int xsize, ysize;
09924 int missing;
09925 int i, j, k;
09926
09927
09928 if (idscoeff == NULL) {
09929 cpl_msg_error(func, "An IDS coeff table must be given");
09930 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
09931 return NULL;
09932 }
09933
09934 xsize = (red - blue) / dispersion;
09935 ysize = cpl_table_get_nrow(idscoeff);
09936 map = cpl_image_new(xsize, ysize, CPL_TYPE_FLOAT);
09937 mdata = cpl_image_get_data(map);
09938
09939 order = 0;
09940 while (order < 6 && cpl_table_has_column(idscoeff, clab[order]))
09941 ++order;
09942 --order;
09943
09944 for (i = 0; i < ysize; i++, mdata += xsize) {
09945
09946 missing = 0;
09947 ids = cpl_polynomial_new(1);
09948 for (k = trend; k <= order; k++) {
09949 c = cpl_table_get_double(idscoeff, clab[k], i, &missing);
09950 if (missing) {
09951 cpl_polynomial_delete(ids);
09952 break;
09953 }
09954 cpl_polynomial_set_coeff(ids, &k, c);
09955 }
09956 if (missing)
09957 continue;
09958
09959 for (j = 0; j < xsize; j++) {
09960 lambda = blue + j*dispersion;
09961 mdata[j] = cpl_polynomial_eval_1d(ids, lambda-reference, NULL);
09962 }
09963
09964 cpl_polynomial_delete(ids);
09965 }
09966
09967 return map;
09968
09969 }
09970
09971
09993 cpl_image *mos_map_idscoeff(cpl_table *idscoeff, int xsize, double reference,
09994 double blue, double red)
09995 {
09996 const char *func = "mos_map_idscoeff";
09997
09998 const char *clab[6] = {"c0", "c1", "c2", "c3", "c4", "c5"};
09999
10000
10001 cpl_polynomial *ids;
10002 cpl_image *map;
10003 float *mdata;
10004 double lambda;
10005 double c;
10006 int order;
10007 int ysize;
10008 int missing;
10009 int i, j, k;
10010
10011
10012 if (idscoeff == NULL) {
10013 cpl_msg_error(func, "An IDS coeff table must be given");
10014 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
10015 return NULL;
10016 }
10017
10018 if (xsize < 1) {
10019 cpl_msg_error(func, "Invalid image size");
10020 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
10021 return NULL;
10022 }
10023
10024 if (xsize < 20 || xsize > 5000) {
10025 cpl_msg_warning(func, "Do you really have a detector %d pixels long?",
10026 xsize);
10027 }
10028
10029 ysize = cpl_table_get_nrow(idscoeff);
10030 map = cpl_image_new(xsize, ysize, CPL_TYPE_FLOAT);
10031 mdata = cpl_image_get_data(map);
10032
10033 order = 0;
10034 while (order < 6 && cpl_table_has_column(idscoeff, clab[order]))
10035 ++order;
10036 --order;
10037
10038 for (i = 0; i < ysize; i++, mdata += xsize) {
10039
10040 missing = 0;
10041 ids = cpl_polynomial_new(1);
10042 for (k = 0; k <= order; k++) {
10043 c = cpl_table_get_double(idscoeff, clab[k], i, &missing);
10044 if (missing) {
10045 cpl_polynomial_delete(ids);
10046 break;
10047 }
10048 cpl_polynomial_set_coeff(ids, &k, c);
10049 }
10050 if (missing)
10051 continue;
10052
10053 for (j = 0; j < xsize; j++) {
10054 lambda = mos_eval_dds(ids, blue, red, reference, j);
10055 if (lambda >= blue && lambda <= red) {
10056 mdata[j] = lambda;
10057 }
10058 }
10059
10060 cpl_polynomial_delete(ids);
10061 }
10062
10063 return map;
10064
10065 }
10066
10067
10102 cpl_image *mos_map_wavelengths(cpl_image *spatial, cpl_image *calibration,
10103 cpl_table *slits, cpl_table *polytraces,
10104 double reference, double blue, double red,
10105 double dispersion)
10106 {
10107 const char *func = "mos_map_wavelengths";
10108
10109 const char *clab[6] = {"c0", "c1", "c2", "c3", "c4", "c5"};
10110
10111 cpl_polynomial *polytop;
10112 cpl_polynomial *polybot;
10113 cpl_image *remapped;
10114 float *data;
10115 float *wdata;
10116 float *sdata;
10117 float *xdata;
10118 double vtop, vbot, value;
10119 double top, bot;
10120 double coeff;
10121 double ytop, ybot;
10122 double ypos;
10123 double fvalue;
10124 int ivalue;
10125 int yint, ysize, yprev;
10126 int nslits;
10127 int npseudo;
10128 int *slit_id;
10129 int *position;
10130 int *length;
10131 int nx, ny;
10132 int pixel_above, pixel_below, refpixel, start_pixel, end_pixel;
10133 int missing_top, missing_bot;
10134 int null;
10135 int order;
10136 int i, j, k;
10137
10138
10139 if (spatial == NULL || calibration == NULL ||
10140 slits == NULL || polytraces == NULL) {
10141 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
10142 return NULL;
10143 }
10144
10145 if (dispersion <= 0.0) {
10146 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
10147 return NULL;
10148 }
10149
10150 if (red - blue < dispersion) {
10151 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
10152 return NULL;
10153 }
10154
10155 nx = cpl_image_get_size_x(spatial);
10156 ny = cpl_image_get_size_y(spatial);
10157 ysize = cpl_image_get_size_y(calibration);
10158 remapped = cpl_image_new(nx, ny, CPL_TYPE_FLOAT);
10159 data = cpl_image_get_data(remapped);
10160 sdata = cpl_image_get_data(spatial);
10161 wdata = cpl_image_get_data(calibration);
10162
10163 nslits = cpl_table_get_nrow(slits);
10164 slit_id = cpl_table_get_data_int(slits, "slit_id");
10165 order = cpl_table_get_ncol(polytraces) - 2;
10166 position = cpl_table_get_data_int(slits, "position");
10167 length = cpl_table_get_data_int(slits, "length");
10168
10169
10170
10171
10172
10173
10174 pixel_above = (red - reference) / dispersion;
10175 pixel_below = (reference - blue) / dispersion;
10176
10177 for (i = 0; i < nslits; i++) {
10178
10179 if (length[i] == 0)
10180 continue;
10181
10182
10183
10184
10185
10186
10187
10188
10189
10190
10191
10192
10193 refpixel = cpl_table_get_double(slits, "xtop", i, NULL);
10194
10195 start_pixel = refpixel - pixel_below;
10196 if (start_pixel < 0)
10197 start_pixel = 0;
10198
10199 end_pixel = refpixel + pixel_above;
10200 if (end_pixel > nx)
10201 end_pixel = nx;
10202
10203
10204
10205
10206
10207
10208 missing_top = 0;
10209 polytop = cpl_polynomial_new(1);
10210 for (k = 0; k <= order; k++) {
10211 coeff = cpl_table_get_double(polytraces, clab[k], 2*i, &null);
10212 if (null) {
10213 cpl_polynomial_delete(polytop);
10214 missing_top = 1;
10215 break;
10216 }
10217 cpl_polynomial_set_coeff(polytop, &k, coeff);
10218 }
10219
10220 missing_bot = 0;
10221 polybot = cpl_polynomial_new(1);
10222 for (k = 0; k <= order; k++) {
10223 coeff = cpl_table_get_double(polytraces, clab[k], 2*i+1, &null);
10224 if (null) {
10225 cpl_polynomial_delete(polybot);
10226 missing_bot = 1;
10227 break;
10228 }
10229 cpl_polynomial_set_coeff(polybot, &k, coeff);
10230 }
10231
10232 if (missing_top && missing_bot) {
10233 cpl_msg_debug(func, "Slit %d was not traced: no extraction!",
10234 slit_id[i]);
10235 continue;
10236 }
10237
10238
10239
10240
10241
10242
10243
10244 if (missing_top) {
10245 cpl_msg_debug(func, "Upper edge of slit %d was not traced: "
10246 "the spectral curvature of the lower edge "
10247 "is used instead.", slit_id[i]);
10248 polytop = cpl_polynomial_duplicate(polybot);
10249 ytop = cpl_table_get_double(slits, "ytop", i, NULL);
10250 ybot = cpl_table_get_double(slits, "ybottom", i, NULL);
10251 k = 0;
10252 coeff = cpl_polynomial_get_coeff(polybot, &k);
10253 coeff += ytop - ybot;
10254 cpl_polynomial_set_coeff(polytop, &k, coeff);
10255 }
10256
10257 if (missing_bot) {
10258 cpl_msg_debug(func, "Lower edge of slit %d was not traced: "
10259 "the spectral curvature of the upper edge "
10260 "is used instead.", slit_id[i]);
10261 polybot = cpl_polynomial_duplicate(polytop);
10262 ytop = cpl_table_get_double(slits, "ytop", i, NULL);
10263 ybot = cpl_table_get_double(slits, "ybottom", i, NULL);
10264 k = 0;
10265 coeff = cpl_polynomial_get_coeff(polytop, &k);
10266 coeff -= ytop - ybot;
10267 cpl_polynomial_set_coeff(polybot, &k, coeff);
10268 }
10269
10270
10271
10272
10273
10274
10275
10276
10277 xdata = wdata + nx*position[i];
10278 npseudo = length[i] - 1;
10279
10280
10281
10282
10283
10284 for (j = start_pixel; j < end_pixel; j++) {
10285 top = cpl_polynomial_eval_1d(polytop, j, NULL);
10286 bot = cpl_polynomial_eval_1d(polybot, j, NULL);
10287 for (k = 0; k <= npseudo; k++) {
10288 ypos = top - k*(top-bot)/npseudo;
10289 yint = ypos;
10290
10291
10292
10293
10294
10295
10296
10297
10298 if (yint < 0 || yint >= ny-1) {
10299 yprev = yint;
10300 continue;
10301 }
10302
10303 value = sdata[j + nx*yint];
10304 ivalue = value;
10305 fvalue = value - ivalue;
10306 if (ivalue < npseudo && ivalue >= 0) {
10307 vtop = xdata[j + nx*(npseudo-ivalue)];
10308 vbot = xdata[j + nx*(npseudo-ivalue-1)];
10309 if (vtop < 1.0) {
10310 if (vbot < 1.0) {
10311 value = 0.0;
10312 }
10313 else {
10314 value = vbot;
10315 }
10316 }
10317 else if (vbot < 1.0) {
10318 if (k)
10319 value = vtop;
10320 else
10321 value = 0.0;
10322 }
10323 else if (fabs(vbot-vtop) > 10*dispersion) {
10324 value = 0.0;
10325 }
10326 else {
10327 value = vtop*(1-fvalue) + vbot*fvalue;
10328 }
10329 data[j + nx*yint] = value;
10330
10331 if (k) {
10332
10333
10334
10335
10336
10337
10338
10339 if (yprev - yint > 1) {
10340 value = sdata[j + nx*(yint+1)];
10341 ivalue = value;
10342 fvalue = value - ivalue;
10343 if (ivalue < npseudo && ivalue >= 0) {
10344 vtop = xdata[j + nx*(npseudo-ivalue)];
10345 vbot = xdata[j + nx*(npseudo-ivalue-1)];
10346 if (vtop < 1.0) {
10347 if (vbot < 1.0) {
10348 value = data[j + nx*(yint+1)];
10349 }
10350 else {
10351 value = vbot;
10352 }
10353 }
10354 else if (vbot < 1.0) {
10355 value = vtop;
10356 }
10357 else if (fabs(vbot-vtop) > 2*dispersion) {
10358 value = vtop;
10359 }
10360 else {
10361 value = vtop*(1-fvalue) + vbot*fvalue;
10362 }
10363 data[j + nx*(yint+1)] = value;
10364 }
10365 }
10366 }
10367 }
10368 yprev = yint;
10369 }
10370 }
10371 cpl_polynomial_delete(polytop);
10372 cpl_polynomial_delete(polybot);
10373 }
10374
10375 return remapped;
10376 }
10377
10451 cpl_image *mos_map_spectrum(cpl_image *spectra, cpl_image *wavecalib,
10452 cpl_image *spatial, cpl_table *slits,
10453 cpl_table *polytraces, double reference,
10454 double blue, double red, double dispersion,
10455 int flux)
10456 {
10457 const char *func = "mos_map_spectrum";
10458
10459 const char *clab[6] = {"c0", "c1", "c2", "c3", "c4", "c5"};
10460
10461 cpl_polynomial *polytop;
10462 cpl_polynomial *polybot;
10463 cpl_image *remapped;
10464 cpl_image **exslit;
10465 float *data;
10466 float *wdata;
10467 float *sdata;
10468 float *xdata;
10469 double lambda00, lambda01, lambda10, lambda11, lambda;
10470 double space00, space01, space10, space11, space;
10471 double value00, value01, value10, value11, value0, value1, value;
10472 double dL, dS;
10473 double top, bot;
10474 double coeff;
10475 double ytop, ybot;
10476 double xfrac, yfrac;
10477 int yint, ysize;
10478 int itop, ibot;
10479 int shift;
10480 int L, S;
10481 int nslits;
10482 int npseudo;
10483 int *slit_id;
10484 int *position;
10485 int *length;
10486 int nx, ny;
10487 int x, y;
10488 int nlambda;
10489 int pixel_above, pixel_below, refpixel, start_pixel, end_pixel;
10490 int missing_top, missing_bot;
10491 int null;
10492 int order;
10493 int i, k;
10494
10495
10496 flux += flux;
10497
10498 if (spectra == NULL || spatial == NULL || wavecalib == NULL ||
10499 slits == NULL || polytraces == NULL) {
10500 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
10501 return NULL;
10502 }
10503
10504 if (dispersion <= 0.0) {
10505 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
10506 return NULL;
10507 }
10508
10509 if (red - blue < dispersion) {
10510 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
10511 return NULL;
10512 }
10513
10514 nx = cpl_image_get_size_x(spectra);
10515 ny = cpl_image_get_size_y(spectra);
10516
10517 if (nx != cpl_image_get_size_x(spatial) ||
10518 ny != cpl_image_get_size_y(spatial) ||
10519 nx != cpl_image_get_size_x(wavecalib) ||
10520 ny != cpl_image_get_size_y(wavecalib)) {
10521 cpl_error_set(func, CPL_ERROR_INCOMPATIBLE_INPUT);
10522 return NULL;
10523 }
10524
10525 nlambda = (red - blue) / dispersion;
10526 pixel_above = (red - reference) / dispersion;
10527 pixel_below = (reference - blue) / dispersion;
10528
10529 data = cpl_image_get_data(spectra);
10530 sdata = cpl_image_get_data(spatial);
10531 wdata = cpl_image_get_data(wavecalib);
10532
10533 nslits = cpl_table_get_nrow(slits);
10534 slit_id = cpl_table_get_data_int(slits, "slit_id");
10535 order = cpl_table_get_ncol(polytraces) - 2;
10536 position = cpl_table_get_data_int(slits, "position");
10537 length = cpl_table_get_data_int(slits, "length");
10538
10539 exslit = cpl_calloc(nslits, sizeof(cpl_image *));
10540
10541 for (i = 0; i < nslits; i++) {
10542
10543 if (length == 0)
10544 continue;
10545
10546
10547
10548
10549
10550
10551
10552
10553
10554
10555
10556
10557 refpixel = cpl_table_get_double(slits, "xtop", i, NULL);
10558
10559 start_pixel = refpixel - pixel_below;
10560 if (start_pixel < 1)
10561 start_pixel = 1;
10562
10563 end_pixel = refpixel + pixel_above;
10564 if (end_pixel > nx)
10565 end_pixel = nx;
10566
10567
10568
10569
10570
10571
10572 missing_top = 0;
10573 polytop = cpl_polynomial_new(1);
10574 for (k = 0; k <= order; k++) {
10575 coeff = cpl_table_get_double(polytraces, clab[k], 2*i, &null);
10576 if (null) {
10577 cpl_polynomial_delete(polytop);
10578 missing_top = 1;
10579 break;
10580 }
10581 cpl_polynomial_set_coeff(polytop, &k, coeff);
10582 }
10583
10584 missing_bot = 0;
10585 polybot = cpl_polynomial_new(1);
10586 for (k = 0; k <= order; k++) {
10587 coeff = cpl_table_get_double(polytraces, clab[k], 2*i+1, &null);
10588 if (null) {
10589 cpl_polynomial_delete(polybot);
10590 missing_bot = 1;
10591 break;
10592 }
10593 cpl_polynomial_set_coeff(polybot, &k, coeff);
10594 }
10595
10596 if (missing_top && missing_bot) {
10597 cpl_msg_debug(func, "Slit %d was not traced: no extraction!",
10598 slit_id[i]);
10599 continue;
10600 }
10601
10602
10603
10604
10605
10606
10607
10608 if (missing_top) {
10609 cpl_msg_debug(func, "Upper edge of slit %d was not traced: "
10610 "the spectral curvature of the lower edge "
10611 "is used instead.", slit_id[i]);
10612 polytop = cpl_polynomial_duplicate(polybot);
10613 ytop = cpl_table_get_double(slits, "ytop", i, NULL);
10614 ybot = cpl_table_get_double(slits, "ybottom", i, NULL);
10615 k = 0;
10616 coeff = cpl_polynomial_get_coeff(polybot, &k);
10617 coeff += ytop - ybot;
10618 cpl_polynomial_set_coeff(polytop, &k, coeff);
10619 }
10620
10621 if (missing_bot) {
10622 cpl_msg_debug(func, "Lower edge of slit %d was not traced: "
10623 "the spectral curvature of the upper edge "
10624 "is used instead.", slit_id[i]);
10625 polybot = cpl_polynomial_duplicate(polytop);
10626 ytop = cpl_table_get_double(slits, "ytop", i, NULL);
10627 ybot = cpl_table_get_double(slits, "ybottom", i, NULL);
10628 k = 0;
10629 coeff = cpl_polynomial_get_coeff(polytop, &k);
10630 coeff -= ytop - ybot;
10631 cpl_polynomial_set_coeff(polybot, &k, coeff);
10632 }
10633
10634
10635
10636
10637
10638 top = cpl_polynomial_eval_1d(polytop, refpixel, NULL);
10639 bot = cpl_polynomial_eval_1d(polybot, refpixel, NULL);
10640 npseudo = ceil(top-bot) + 1;
10641
10642 if (npseudo < 1) {
10643 cpl_polynomial_delete(polytop);
10644 cpl_polynomial_delete(polybot);
10645 cpl_msg_debug(func, "Slit %d was badly traced: no extraction!",
10646 slit_id[i]);
10647 continue;
10648 }
10649
10650 exslit[i] = cpl_image_new(nlambda, npseudo+1, CPL_TYPE_FLOAT);
10651 xdata = cpl_image_get_data(exslit[i]);
10652
10653
10654
10655
10656
10657 for (x = start_pixel; x < end_pixel; x++) {
10658 top = cpl_polynomial_eval_1d(polytop, x, NULL);
10659 bot = cpl_polynomial_eval_1d(polybot, x, NULL);
10660 itop = top + 1;
10661 ibot = bot;
10662 if (itop < 0)
10663 itop = 0;
10664 if (itop > ny - 1)
10665 itop = ny - 1;
10666 if (ibot < 0)
10667 ibot = 0;
10668 if (ibot > ny - 1)
10669 ibot = ny - 1;
10670 for (y = ibot; y < itop; y++) {
10671 lambda11 = wdata[x + y*nx];
10672 if (lambda11 < 1.0)
10673 continue;
10674 space11 = sdata[x + y*nx];
10675 if (space11 < 0.0)
10676 continue;
10677 lambda01 = wdata[x - 1 + y*nx];
10678 if (lambda01 < 1.0)
10679 continue;
10680 space01 = sdata[x - 1 + y*nx];
10681 if (space01 < 0.0)
10682 continue;
10683
10684 shift = 0;
10685
10686
10687
10688
10689
10690
10691
10692
10693
10694
10695
10696
10697
10698
10699
10700
10701
10702
10703
10704
10705
10706
10707
10708
10709
10710
10711
10712
10713 lambda10 = wdata[x + shift + (y+1)*nx];
10714 if (lambda10 < 1.0)
10715 continue;
10716 space10 = sdata[x + shift + (y+1)*nx];
10717 if (space10 < 0.0)
10718 continue;
10719 lambda00 = wdata[x - 1 + shift + (y+1)*nx];
10720 if (lambda00 < 1.0)
10721 continue;
10722 space00 = sdata[x - 1 + shift + (y+1)*nx];
10723 if (space00 < 0.0)
10724 continue;
10725
10726
10727
10728
10729
10730
10731
10732 dL = lambda11 - lambda01;
10733 dS = space11 - space10;
10734
10735
10736
10737
10738
10739
10740 L = (lambda11 - blue)/dispersion + 0.5;
10741 S = space11 + 0.5;
10742
10743 if (L < 0 || L >= nlambda)
10744 continue;
10745 if (S < 0 || S > npseudo)
10746 continue;
10747
10748
10749
10750
10751
10752 lambda = blue + L*dispersion;
10753 space = S;
10754
10755
10756
10757
10758
10759
10760
10761
10762
10763
10764 xfrac = (lambda11-lambda)/dL;
10765 yfrac = (space11-space)/dS;
10766
10767
10768
10769
10770
10771
10772
10773
10774
10775
10776 value11 = data[x + y*nx];
10777 value01 = data[x - 1 + y*nx];
10778 value10 = data[x + shift + (y+1)*nx];
10779 value00 = data[x + shift - 1 + (y+1)*nx];
10780
10781
10782
10783
10784
10785 value1 = (1-xfrac)*value11 + xfrac*value01;
10786 value0 = (1-xfrac)*value10 + xfrac*value00;
10787 value = (1-yfrac)*value1 + yfrac*value0;
10788
10789
10790
10791
10792
10793
10794 xdata[L + nlambda*(npseudo-S)] = value;
10795
10796 }
10797 }
10798 cpl_polynomial_delete(polytop);
10799 cpl_polynomial_delete(polybot);
10800 }
10801
10802
10803
10804
10805
10806 ysize = 0;
10807 for (i = 0; i < nslits; i++)
10808 if (exslit[i])
10809 ysize += cpl_image_get_size_y(exslit[i]);
10810
10811 remapped = cpl_image_new(nlambda, ysize, CPL_TYPE_FLOAT);
10812
10813 yint = -1;
10814 for (i = 0; i < nslits; i++) {
10815 if (exslit[i]) {
10816 yint += cpl_image_get_size_y(exslit[i]);
10817 cpl_image_copy(remapped, exslit[i], 1, ysize - yint);
10818 cpl_image_delete(exslit[i]);
10819 cpl_table_set_int(slits, "position", i, ysize - yint - 1);
10820 }
10821 }
10822
10823 cpl_free(exslit);
10824
10825 return remapped;
10826
10827 }
10828
10829
10862 cpl_table *mos_sky_map_super(cpl_image *spectra, cpl_image *wavemap,
10863 double dispersion, double factor, int minpoints,
10864 cpl_image *skymap)
10865 {
10866 const char *func = "mos_sky_map_super";
10867
10868 cpl_vector **vector;
10869 cpl_vector **wvector;
10870 double firstLambda, lastLambda;
10871 double lambda, lambda1, lambda2;
10872 double value, value1, value2;
10873 double frac;
10874 float min, max;
10875 int *count;
10876 int nbin, bin;
10877 int nx, ny, npix;
10878 int first_valid, valid_bins;
10879 int i, j;
10880
10881 cpl_table *sky;
10882 double *sky_spectrum;
10883 double *sky_wave;
10884 float *data;
10885 float *sdata;
10886 float *kdata;
10887
10888
10889 if (spectra == NULL || wavemap == NULL || skymap == NULL) {
10890 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
10891 return NULL;
10892 }
10893
10894 if (dispersion <= 0.0) {
10895 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
10896 cpl_msg_error(func, "Negative dispersion: %s", cpl_error_get_message());
10897 return NULL;
10898 }
10899
10900 nx = cpl_image_get_size_x(spectra);
10901 ny = cpl_image_get_size_y(spectra);
10902 npix = nx * ny;
10903
10904 if (nx != cpl_image_get_size_x(wavemap) ||
10905 ny != cpl_image_get_size_y(wavemap) ||
10906 nx != cpl_image_get_size_x(skymap) ||
10907 ny != cpl_image_get_size_y(skymap)) {
10908 cpl_error_set(func, CPL_ERROR_INCOMPATIBLE_INPUT);
10909 cpl_msg_error(func, "Image sizes: %s", cpl_error_get_message());
10910 return NULL;
10911 }
10912
10913 if (factor < 1.0) {
10914 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
10915 cpl_msg_error(func, "Undersampling (%f): %s", factor,
10916 cpl_error_get_message());
10917 return NULL;
10918 }
10919
10920 if (minpoints < 0) {
10921 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
10922 cpl_msg_error(func, "Negative threshold: %s", cpl_error_get_message());
10923 return NULL;
10924 }
10925
10926 dispersion /= factor;
10927
10928
10929
10930
10931
10932
10933 data = cpl_image_get_data(wavemap);
10934
10935 for (i = 0; i < npix; i++) {
10936 if (data[i] > 1.0) {
10937 min = max = data[i];
10938 j = i+1;
10939 break;
10940 }
10941 }
10942
10943 for (i = j; i < npix; i++) {
10944 if (data[i] < 1.0)
10945 continue;
10946 if (min > data[i])
10947 min = data[i];
10948 if (max < data[i])
10949 max = data[i];
10950 }
10951
10952 firstLambda = min;
10953 lastLambda = max;
10954
10955
10956
10957
10958
10959
10960 nbin = (lastLambda - firstLambda) / dispersion;
10961
10962
10963
10964
10965
10966
10967
10968
10969 count = cpl_calloc(nbin, sizeof(int));
10970
10971 data = cpl_image_get_data(wavemap);
10972
10973 for (i = 0; i < npix; i++) {
10974 if (data[i] < 1.0)
10975 continue;
10976 bin = (data[i] - firstLambda) / dispersion;
10977 if (bin < nbin)
10978 count[bin]++;
10979 }
10980
10981 valid_bins = 0;
10982 for (i = 0; i < nbin; i++)
10983 if (count[i] >= minpoints)
10984 valid_bins++;
10985
10986 if (valid_bins < nbin/3) {
10987 cpl_msg_warning(func, "Cannot determine a good global sky "
10988 "spectrum from input data");
10989 return NULL;
10990 }
10991
10992
10993
10994
10995
10996
10997
10998
10999
11000 vector = cpl_calloc(nbin, sizeof(cpl_vector *));
11001 wvector = cpl_calloc(nbin, sizeof(cpl_vector *));
11002 for (i = 0; i < nbin; i++) {
11003 if (count[i] >= minpoints) {
11004 vector[i] = cpl_vector_new(count[i]);
11005 wvector[i] = cpl_vector_new(count[i]);
11006 }
11007 count[i] = 0;
11008 }
11009
11010
11011
11012
11013
11014
11015
11016 data = cpl_image_get_data(wavemap);
11017 sdata = cpl_image_get_data(spectra);
11018
11019 for (i = 0; i < npix; i++) {
11020 if (data[i] < 1.0)
11021 continue;
11022 bin = (data[i] - firstLambda) / dispersion;
11023 if (bin < nbin) {
11024 if (vector[bin]) {
11025 cpl_vector_set(vector[bin], count[bin], sdata[i]);
11026 cpl_vector_set(wvector[bin], count[bin], data[i]);
11027 }
11028 count[bin]++;
11029 }
11030 }
11031
11032
11033
11034
11035
11036
11037
11038 sky_spectrum = cpl_calloc(nbin, sizeof(double));
11039 sky_wave = cpl_calloc(nbin, sizeof(double));
11040 for (i = 0; i < nbin; i++) {
11041 if (vector[i]) {
11042 sky_spectrum[i] = cpl_vector_get_median_const(vector[i]);
11043 sky_wave[i] = cpl_vector_get_median_const(wvector[i]);
11044 cpl_vector_delete(vector[i]);
11045 cpl_vector_delete(wvector[i]);
11046 }
11047 }
11048
11049 cpl_free(vector);
11050 cpl_free(wvector);
11051
11052
11053
11054
11055
11056
11057 for (i = 0; i < nbin; i++) {
11058 if (count[i] >= minpoints) {
11059 first_valid = i;
11060 break;
11061 }
11062 }
11063
11064 for (i = first_valid; i < nbin; i++) {
11065 if (count[i] < minpoints) {
11066 sky_wave[i] = firstLambda + (i+0.5)*dispersion;
11067 for (j = i+1; j < nbin; j++) {
11068 if (count[j] >= minpoints) {
11069 if (sky_wave[j] - sky_wave[i-1] < 0.1) {
11070 sky_spectrum[i] = (sky_spectrum[j] + sky_spectrum[i-1])
11071 / 2;
11072 }
11073 else {
11074 frac = (sky_wave[i] - sky_wave[i-1])
11075 / (sky_wave[j] - sky_wave[i-1]);
11076 sky_spectrum[i] = frac * sky_spectrum[j]
11077 + (1 - frac) * sky_spectrum[i-1];
11078 }
11079 }
11080 }
11081 }
11082 }
11083
11084
11085
11086
11087
11088
11089 sky = cpl_table_new(nbin);
11090 cpl_table_wrap_double(sky, sky_wave, "wavelength");
11091 cpl_table_wrap_double(sky, sky_spectrum, "sky");
11092 cpl_table_wrap_int(sky, count, "npoints");
11093
11094
11095
11096
11097
11098
11099 data = cpl_image_get_data(wavemap);
11100 sdata = cpl_image_get_data(spectra);
11101 kdata = cpl_image_get_data(skymap);
11102
11103 for (i = 0; i < npix; i++) {
11104
11105
11106
11107
11108
11109 lambda = data[i];
11110 if (lambda < 1.0)
11111 continue;
11112 bin = (lambda - firstLambda) / dispersion;
11113 lambda1 = sky_wave[bin];
11114 value1 = sky_spectrum[bin];
11115 if (lambda1 < lambda) {
11116 bin++;
11117 if (bin < nbin) {
11118 lambda2 = sky_wave[bin];
11119 value2 = sky_spectrum[bin];
11120 if (lambda2 - lambda1 < 0.1) {
11121 value = (value1 + value2) / 2;
11122 }
11123 else {
11124 frac = (lambda - lambda1) / (lambda2 - lambda1);
11125 value = frac * value2 + (1 - frac) * value1;
11126 }
11127 }
11128 else {
11129 value = value1;
11130 }
11131 }
11132 else {
11133 if (bin > 0) {
11134 bin--;
11135 lambda2 = lambda1;
11136 value2 = value1;
11137 lambda1 = sky_wave[bin];
11138 value1 = sky_spectrum[bin];
11139 if (lambda2 - lambda1 < 0.1) {
11140 value = (value1 + value2) / 2;
11141 }
11142 else {
11143 frac = (lambda - lambda1) / (lambda2 - lambda1);
11144 value = frac * value2 + (1 - frac) * value1;
11145 }
11146 }
11147 else {
11148 value = value1;
11149 }
11150 }
11151 kdata[i] = value;
11152 }
11153
11154 if (first_valid)
11155 cpl_table_erase_window(sky, 0, first_valid);
11156
11157 return sky;
11158
11159 }
11160
11161
11195 cpl_table *mos_sky_map(cpl_image *spectra, cpl_image *wavemap,
11196 double dispersion, cpl_image *skymap)
11197 {
11198 const char *func = "mos_sky_map";
11199
11200 cpl_vector **vector;
11201 double firstLambda, lastLambda;
11202 double lambda, lambda1, lambda2;
11203 double value, value1, value2;
11204 float min, max;
11205 int *count;
11206 int nbin, bin;
11207 int nx, ny, npix;
11208 int i, j;
11209
11210 cpl_table *sky;
11211 double *sky_spectrum;
11212 float *data;
11213 float *sdata;
11214 float *kdata;
11215 double *wdata;
11216
11217
11218 if (spectra == NULL || wavemap == NULL || skymap == NULL) {
11219 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
11220 return NULL;
11221 }
11222
11223 if (dispersion <= 0.0) {
11224 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
11225 return NULL;
11226 }
11227
11228 nx = cpl_image_get_size_x(spectra);
11229 ny = cpl_image_get_size_y(spectra);
11230 npix = nx * ny;
11231
11232 if (nx != cpl_image_get_size_x(wavemap) ||
11233 ny != cpl_image_get_size_y(wavemap) ||
11234 nx != cpl_image_get_size_x(skymap) ||
11235 ny != cpl_image_get_size_y(skymap)) {
11236 cpl_error_set(func, CPL_ERROR_INCOMPATIBLE_INPUT);
11237 return NULL;
11238 }
11239
11240
11241
11242
11243
11244
11245 data = cpl_image_get_data(wavemap);
11246
11247 for (i = 0; i < npix; i++) {
11248 if (data[i] > 1.0) {
11249 min = max = data[i];
11250 j = i+1;
11251 break;
11252 }
11253 }
11254
11255 for (i = j; i < npix; i++) {
11256 if (data[i] < 1.0)
11257 continue;
11258 if (min > data[i])
11259 min = data[i];
11260 if (max < data[i])
11261 max = data[i];
11262 }
11263
11264 firstLambda = min;
11265 lastLambda = max;
11266
11267
11268
11269
11270
11271
11272 nbin = (lastLambda - firstLambda) / dispersion;
11273
11274
11275
11276
11277
11278
11279
11280
11281 count = cpl_calloc(nbin, sizeof(int));
11282
11283 data = cpl_image_get_data(wavemap);
11284
11285 for (i = 0; i < npix; i++) {
11286 if (data[i] < 1.0)
11287 continue;
11288 bin = (data[i] - firstLambda) / dispersion;
11289 if (bin < nbin)
11290 count[bin]++;
11291 }
11292
11293
11294
11295
11296
11297
11298
11299
11300
11301 vector = cpl_calloc(nbin, sizeof(cpl_vector *));
11302 for (i = 0; i < nbin; i++) {
11303 if (count[i])
11304 vector[i] = cpl_vector_new(count[i]);
11305 else
11306 vector[i] = NULL;
11307 count[i] = 0;
11308 }
11309
11310
11311
11312
11313
11314
11315
11316 data = cpl_image_get_data(wavemap);
11317 sdata = cpl_image_get_data(spectra);
11318
11319 for (i = 0; i < npix; i++) {
11320 if (data[i] < 1.0)
11321 continue;
11322 bin = (data[i] - firstLambda) / dispersion;
11323 if (bin < nbin) {
11324 cpl_vector_set(vector[bin], count[bin], sdata[i]);
11325 count[bin]++;
11326 }
11327 }
11328
11329
11330
11331
11332
11333
11334
11335 sky_spectrum = cpl_calloc(nbin, sizeof(double));
11336 for (i = 0; i < nbin; i++) {
11337 if (vector[i]) {
11338 sky_spectrum[i] = cpl_vector_get_median_const(vector[i]);
11339 cpl_vector_delete(vector[i]);
11340 }
11341 }
11342
11343 cpl_free(vector);
11344
11345
11346
11347
11348
11349
11350
11351
11352
11353
11354
11355
11356
11357 sky = cpl_table_new(nbin);
11358 cpl_table_new_column(sky, "wavelength", CPL_TYPE_DOUBLE);
11359 cpl_table_set_column_unit(sky, "wavelength", "pixel");
11360 cpl_table_wrap_double(sky, sky_spectrum, "sky");
11361 cpl_table_wrap_int(sky, count, "npoints");
11362 for (i = 0; i < nbin; i++)
11363 cpl_table_set_double(sky, "wavelength", i,
11364 firstLambda + (i+0.5)*dispersion);
11365
11366
11367
11368
11369
11370
11371 data = cpl_image_get_data(wavemap);
11372 sdata = cpl_image_get_data(spectra);
11373 kdata = cpl_image_get_data(skymap);
11374 wdata = cpl_table_get_data_double(sky, "wavelength");
11375
11376 for (i = 0; i < npix; i++) {
11377
11378
11379
11380
11381
11382 lambda = data[i];
11383 if (lambda < 1.0)
11384 continue;
11385 bin = (lambda - firstLambda) / dispersion;
11386 lambda1 = wdata[bin];
11387 value1 = sky_spectrum[bin];
11388 if (lambda1 < lambda) {
11389 bin++;
11390 if (bin < nbin) {
11391 lambda2 = wdata[bin];
11392 value2 = sky_spectrum[bin];
11393 value = ((lambda2 - lambda)*value1
11394 + (lambda - lambda1)*value2) / dispersion;
11395 }
11396 else {
11397 value = value1;
11398 }
11399 }
11400 else {
11401 if (bin > 0) {
11402 bin--;
11403 lambda2 = lambda1;
11404 value2 = value1;
11405 lambda1 = wdata[bin];
11406 value1 = sky_spectrum[bin];
11407 value = ((lambda2 - lambda)*value1
11408 + (lambda - lambda1)*value2)/dispersion;
11409 }
11410 else {
11411 value = value1;
11412 }
11413 }
11414 kdata[i] = value;
11415 }
11416
11417 return sky;
11418
11419 }
11420
11421
11437 cpl_image *mos_sky_local_old(cpl_image *spectra, cpl_table *slits)
11438 {
11439 const char *func = "mos_sky_local_old";
11440
11441 cpl_image *exslit;
11442 cpl_image *sky;
11443 cpl_image *skymap;
11444 float *data;
11445 float *sdata;
11446 int nx, ny;
11447 int xlow, ylow, xhig, yhig;
11448 int nslits;
11449 int *slit_id;
11450 int *position;
11451 int *length;
11452 int i, j, k;
11453
11454
11455 if (spectra == NULL) {
11456 cpl_msg_error(func,
11457 "A scientific rectified spectral image must be given");
11458 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
11459 return NULL;
11460 }
11461
11462 if (slits == NULL) {
11463 cpl_msg_error(func, "A slits position table must be given");
11464 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
11465 return NULL;
11466 }
11467
11468 nslits = cpl_table_get_nrow(slits);
11469 slit_id = cpl_table_get_data_int(slits, "slit_id");
11470 position = cpl_table_get_data_int(slits, "position");
11471 length = cpl_table_get_data_int(slits, "length");
11472
11473 nx = cpl_image_get_size_x(spectra);
11474 ny = cpl_image_get_size_y(spectra);
11475
11476 skymap = cpl_image_new(nx, ny, CPL_TYPE_FLOAT);
11477
11478 xlow = 1;
11479 xhig = nx;
11480 for (i = 0; i < nslits; i++) {
11481
11482 if (length[i] == 0)
11483 continue;
11484
11485
11486
11487
11488
11489
11490
11491
11492
11493
11494
11495 ylow = position[i] + 1;
11496 yhig = ylow + length[i] - 1;
11497
11498 exslit = cpl_image_extract(spectra, xlow, ylow, xhig, yhig);
11499 sky = cpl_image_collapse_median_create(exslit, 0, 0, 1);
11500 cpl_image_delete(exslit);
11501
11502 data = cpl_image_get_data(skymap);
11503 data += nx * position[i];
11504
11505 for (j = 0; j < length[i]; j++) {
11506 sdata = cpl_image_get_data(sky);
11507 for (k = 0; k < nx; k++) {
11508 *data++ = *sdata++;
11509 }
11510 }
11511
11512 cpl_image_delete(sky);
11513 }
11514
11515 return skymap;
11516
11517 }
11518
11519
11539 cpl_image *mos_sky_local(cpl_image *spectra, cpl_table *slits, int order)
11540 {
11541 const char *func = "mos_sky_local";
11542
11543 char name[MAX_COLNAME];
11544
11545 cpl_polynomial *fit;
11546 cpl_vector *points;
11547 cpl_vector *values;
11548 cpl_vector *keep_points;
11549 cpl_vector *keep_values;
11550 cpl_image *exslit;
11551 cpl_image *sky;
11552 cpl_image *subtracted;
11553 cpl_image *profile;
11554 cpl_image *skymap;
11555 cpl_table *objects;
11556 float *data;
11557 float *sdata;
11558 float *xdata;
11559 double *vdata;
11560 double *pdata;
11561 double median;
11562 int nx, ny;
11563 int xlow, ylow, xhig, yhig;
11564 int nslits;
11565 int *slit_id;
11566 int *position;
11567 int *length;
11568 int *is_sky;
11569 int nsky, nbad;
11570 int maxobjects;
11571 int margin = 3;
11572 int radius = 6;
11573 int i, j, k;
11574
11575
11576 if (spectra == NULL) {
11577 cpl_msg_error(func,
11578 "A scientific rectified spectral image must be given");
11579 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
11580 return NULL;
11581 }
11582
11583 if (slits == NULL) {
11584 cpl_msg_error(func, "A slits position table must be given");
11585 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
11586 return NULL;
11587 }
11588
11589 if (order < 0) {
11590 cpl_msg_error(func, "Invalid fit order");
11591 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
11592 return NULL;
11593 }
11594
11595 nslits = cpl_table_get_nrow(slits);
11596 slit_id = cpl_table_get_data_int(slits, "slit_id");
11597 position = cpl_table_get_data_int(slits, "position");
11598 length = cpl_table_get_data_int(slits, "length");
11599
11600 nx = cpl_image_get_size_x(spectra);
11601 ny = cpl_image_get_size_y(spectra);
11602
11603 skymap = cpl_image_new(nx, ny, CPL_TYPE_FLOAT);
11604
11605 xlow = 1;
11606 xhig = nx;
11607 for (i = 0; i < nslits; i++) {
11608
11609 if (length[i] == 0)
11610 continue;
11611
11612
11613
11614
11615
11616
11617
11618
11619
11620
11621
11622 ylow = position[i] + 1;
11623 yhig = ylow + length[i] - 1;
11624
11625 exslit = cpl_image_extract(spectra, xlow, ylow, xhig, yhig);
11626 sky = cpl_image_collapse_median_create(exslit, 0, 0, 1);
11627 cpl_image_delete(exslit);
11628
11629 data = cpl_image_get_data(skymap);
11630 data += nx * position[i];
11631
11632 for (j = 0; j < length[i]; j++) {
11633 sdata = cpl_image_get_data(sky);
11634 for (k = 0; k < nx; k++) {
11635 *data++ = *sdata++;
11636 }
11637 }
11638
11639 cpl_image_delete(sky);
11640 }
11641
11642
11643
11644
11645
11646
11647 subtracted = cpl_image_duplicate(spectra);
11648 cpl_image_subtract(subtracted, skymap);
11649 cpl_image_delete(skymap);
11650
11651
11652
11653
11654
11655
11656 objects = cpl_table_duplicate(slits);
11657 profile = mos_detect_objects(subtracted, objects, margin, radius, 0);
11658 cpl_image_delete(profile);
11659 cpl_image_delete(subtracted);
11660
11661
11662
11663
11664
11665
11666
11667 maxobjects = 1;
11668 snprintf(name, MAX_COLNAME, "object_%d", maxobjects);
11669 while (cpl_table_has_column(objects, name)) {
11670 maxobjects++;
11671 snprintf(name, MAX_COLNAME, "object_%d", maxobjects);
11672 }
11673
11674 is_sky = cpl_calloc(ny, sizeof(int));
11675
11676 for (i = 0; i < nslits; i++) {
11677
11678 if (length[i] == 0)
11679 continue;
11680
11681 ylow = position[i] + margin;
11682 yhig = position[i] + length[i] - margin;
11683
11684 for (j = ylow; j < yhig; j++)
11685 is_sky[j] = 1;
11686
11687 for (j = 1; j < maxobjects; j++) {
11688 snprintf(name, MAX_COLNAME, "object_%d", j);
11689 if (cpl_table_is_valid(objects, name, i)) {
11690 snprintf(name, MAX_COLNAME, "start_%d", j);
11691 ylow = cpl_table_get_int(objects, name, i, NULL);
11692 snprintf(name, MAX_COLNAME, "end_%d", j);
11693 yhig = cpl_table_get_int(objects, name, i, NULL);
11694 for (k = ylow; k <= yhig; k++)
11695 is_sky[k] = 0;
11696 }
11697 }
11698
11699
11700
11701
11702
11703
11704 ylow = position[i] + margin + 1;
11705 yhig = position[i] + length[i] - margin - 1;
11706
11707 for (j = ylow; j < yhig; j++)
11708 if (is_sky[j])
11709 if (is_sky[j-1] == 0 && is_sky[j+1] == 0)
11710 is_sky[j] = 0;
11711
11712 }
11713
11714
11715
11716
11717
11718
11719 skymap = cpl_image_new(nx, ny, CPL_TYPE_FLOAT);
11720
11721 for (i = 0; i < nslits; i++) {
11722
11723 if (length[i] == 0)
11724 continue;
11725
11726 ylow = position[i];
11727 yhig = ylow + length[i];
11728
11729 nsky = 0;
11730 for (j = ylow; j < yhig; j++)
11731 if (is_sky[j])
11732 nsky++;
11733
11734 if (nsky > order + 1) {
11735 if (order) {
11736 points = cpl_vector_new(nsky);
11737 nsky = 0;
11738 for (j = ylow; j < yhig; j++) {
11739 if (is_sky[j]) {
11740 cpl_vector_set(points, nsky, j);
11741 nsky++;
11742 }
11743 }
11744
11745 exslit = cpl_image_extract(spectra, 1, ylow+1, nx, yhig);
11746 xdata = cpl_image_get_data(exslit);
11747 values = cpl_vector_new(nsky);
11748
11749 for (j = 0; j < nx; j++) {
11750 nsky = 0;
11751 for (k = ylow; k < yhig; k++) {
11752 if (is_sky[k]) {
11753 cpl_vector_set(values, nsky, xdata[j+(k-ylow)*nx]);
11754 nsky++;
11755 }
11756 }
11757
11758
11759
11760
11761
11762 median = cpl_vector_get_median_const(values);
11763 vdata = cpl_vector_get_data(values);
11764 pdata = cpl_vector_get_data(points);
11765 nbad = 0;
11766 for (k = 0; k < nsky; k++) {
11767 if (fabs(vdata[k] - median) < 100) {
11768 if (nbad) {
11769 vdata[k-nbad] = vdata[k];
11770 pdata[k-nbad] = pdata[k];
11771 }
11772 }
11773 else
11774 nbad++;
11775 }
11776
11777 if (nsky == nbad)
11778 continue;
11779
11780 if (nbad && nsky - nbad > order + 1) {
11781 keep_values = values;
11782 keep_points = points;
11783 values = cpl_vector_wrap(nsky-nbad, vdata);
11784 points = cpl_vector_wrap(nsky-nbad, pdata);
11785 }
11786
11787 if (nsky - nbad > order + 1) {
11788
11789 fit = cpl_polynomial_fit_1d_create(points, values,
11790 order, NULL);
11791
11792 if (fit) {
11793 for (k = ylow; k < yhig; k++) {
11794 xdata[j+(k-ylow)*nx] =
11795 cpl_polynomial_eval_1d(fit, k, NULL);
11796 }
11797
11798 cpl_polynomial_delete(fit);
11799 }
11800 else
11801 cpl_error_reset();
11802 }
11803 else {
11804 for (k = 0; k < nsky; k++) {
11805 xdata[j+k*nx] = median;
11806 }
11807 }
11808
11809 if (nbad && nsky - nbad > order + 1) {
11810 cpl_vector_unwrap(values);
11811 cpl_vector_unwrap(points);
11812 values = keep_values;
11813 points = keep_points;
11814 }
11815
11816 if (nbad) {
11817 nsky = 0;
11818 for (k = ylow; k < yhig; k++) {
11819 if (is_sky[k]) {
11820 cpl_vector_set(points, nsky, k);
11821 nsky++;
11822 }
11823 }
11824 }
11825
11826 }
11827
11828 cpl_vector_delete(values);
11829 cpl_vector_delete(points);
11830
11831 cpl_image_copy(skymap, exslit, 1, ylow+1);
11832 cpl_image_delete(exslit);
11833
11834 }
11835 else {
11836 exslit = cpl_image_extract(spectra, 1, ylow+1, nx, yhig);
11837 xdata = cpl_image_get_data(exslit);
11838 values = cpl_vector_new(nsky);
11839
11840 for (j = 0; j < nx; j++) {
11841 nsky = 0;
11842 for (k = ylow; k < yhig; k++) {
11843 if (is_sky[k]) {
11844 cpl_vector_set(values, nsky, xdata[j+(k-ylow)*nx]);
11845 nsky++;
11846 }
11847 }
11848
11849 median = cpl_vector_get_median_const(values);
11850
11851 for (k = ylow; k < yhig; k++)
11852 xdata[j+(k-ylow)*nx] = median;
11853
11854 }
11855
11856 cpl_vector_delete(values);
11857
11858 cpl_image_copy(skymap, exslit, 1, ylow+1);
11859 cpl_image_delete(exslit);
11860 }
11861 }
11862 else
11863 cpl_msg_warning(func, "Too few sky points in slit %d", i + 1);
11864 }
11865
11866 cpl_free(is_sky);
11867
11868 return skymap;
11869
11870 }
11871
11872
11894 cpl_error_code mos_clean_cosmics(cpl_image *image, float gain,
11895 float threshold, float ratio)
11896 {
11897 const char *func = "mos_clean_cosmics";
11898
11899 cpl_image *smoothImage;
11900 cpl_table *table;
11901 cpl_matrix *kernel;
11902 int *xdata;
11903 int *ydata;
11904 float *idata;
11905 float *sdata;
11906 float sigma, sum, value, smoothValue;
11907 double noise;
11908 int count;
11909 float fMax;
11910 int iMin, iMax, jMin, jMax, iPosMax, jPosMax;
11911 int xLen;
11912 int yLen;
11913 int nPix;
11914 int first = 1;
11915
11916 int pos, i, j, k, l, ii, jj, iii = 0, jjj = 0;
11917 int numCosmic = 0;
11918 int found, foundContiguousCandidate;
11919 int *cosmic;
11920
11921
11922 if (image == NULL)
11923 return cpl_error_set(func, CPL_ERROR_NULL_INPUT);
11924
11925
11926
11927
11928
11929
11930
11931
11932
11933
11934
11935
11936 xLen = cpl_image_get_size_x(image);
11937 yLen = cpl_image_get_size_y(image);
11938
11939 if (xLen < 4 || yLen < 4)
11940 return CPL_ERROR_NONE;
11941
11942 nPix = xLen * yLen;
11943
11944
11945
11946
11947
11948
11949
11950
11951
11952
11953
11954
11955
11956
11957
11958
11959
11960
11961
11962
11963
11964
11965 idata = cpl_image_get_data(image);
11966 noise = 0.0;
11967 count = 0;
11968
11969 for (i = 0; i < nPix; i++) {
11970 if (idata[i] < -0.00001) {
11971 noise -= idata[i];
11972 count++;
11973 }
11974 }
11975
11976 noise /= count;
11977 noise *= 1.25;
11978
11979 cosmic = cpl_calloc(nPix, sizeof(int));
11980
11981 if (threshold < 0.)
11982 threshold = 4.0;
11983 if (ratio < 0.)
11984 ratio = 2.0;
11985
11986 kernel = cpl_matrix_new(3, 3);
11987 cpl_matrix_fill(kernel, 1.0);
11988 cpl_matrix_set(kernel, 1, 1, 0.0);
11989 smoothImage = cpl_image_filter_median(image, kernel);
11990 cpl_matrix_delete(kernel);
11991
11992
11993
11994
11995
11996
11997
11998
11999
12000
12001 sdata = cpl_image_get_data(smoothImage);
12002
12003 for (j = 1; j < yLen - 1; j++) {
12004 for (i = 1; i < xLen - 1; i++) {
12005 value = idata[i + j * xLen];
12006 smoothValue = sdata[i + j * xLen];
12007 if (smoothValue < 1.0)
12008 smoothValue = 1.0;
12009 sigma = sqrt(noise * noise + smoothValue / gain);
12010 if (value - smoothValue >= threshold * sigma)
12011 cosmic[i + j * xLen] = -1;
12012 }
12013 }
12014
12015 cpl_image_delete(smoothImage);
12016
12017
12018
12019
12020
12021
12022 do {
12023 found = 0;
12024 for (pos = first; pos < nPix; pos++) {
12025 if (cosmic[pos] == -1) {
12026 cosmic[pos] = 2;
12027 i = pos % xLen;
12028 j = pos / xLen;
12029 first = pos;
12030 first++;
12031 found = 1;
12032 break;
12033 }
12034 }
12035
12036 if (found) {
12037
12038
12039
12040
12041
12042
12043
12044
12045 iMin = iMax = iPosMax = i;
12046 jMin = jMax = jPosMax = j;
12047 fMax = idata[i + j * xLen];
12048
12049 do {
12050 foundContiguousCandidate = 0;
12051 for (l = 0; l <= 1; l++) {
12052 for (k = 0; k <= 1; k++) {
12053
12054
12055
12056
12057
12058 ii = i + k - l;
12059 jj = j + k + l - 1;
12060 if (cosmic[ii + jj * xLen] == -1) {
12061 foundContiguousCandidate = 1;
12062 cosmic[ii + jj * xLen] = 2;
12063
12064 iii = ii;
12065 jjj = jj;
12066
12067
12068
12069
12070
12071 if (ii < iMin)
12072 iMin = ii;
12073 if (ii > iMax)
12074 iMax = ii;
12075 if (jj < jMin)
12076 jMin = jj;
12077 if (jj > jMax)
12078 jMax = jj;
12079
12080 if (idata[ii + jj * xLen] > fMax) {
12081 fMax = idata[ii + jj * xLen];
12082 iPosMax = ii;
12083 jPosMax = jj;
12084 }
12085 }
12086 }
12087 }
12088
12089
12090
12091
12092
12093
12094 cosmic[i + j * xLen] = 3;
12095
12096 if (foundContiguousCandidate) {
12097
12098
12099
12100
12101
12102
12103 i = iii;
12104 j = jjj;
12105
12106
12107
12108
12109
12110 continue;
12111 }
12112
12113
12114
12115
12116
12117
12118 for (l = jMin; l <= jMax; l++) {
12119 for (k = iMin; k <= iMax; k++) {
12120 if (cosmic[k + l * xLen] == 2) {
12121 i = k;
12122 j = l;
12123 foundContiguousCandidate = 1;
12124 break;
12125 }
12126 }
12127 if (foundContiguousCandidate)
12128 break;
12129 }
12130 } while (foundContiguousCandidate);
12131
12132
12133
12134
12135
12136
12137
12138 sum = 0.;
12139 for (l = -1; l <= 1; l++) {
12140 for (k = -1; k <= 1; k++) {
12141 if (l != 0 || k != 0) {
12142 sum += idata[iPosMax + k + (jPosMax + l) * xLen];
12143 }
12144 }
12145 }
12146
12147 sum /= 8.;
12148 if (fMax > ratio * sum) {
12149 for (l = jMin - 1; l <= jMax + 1; l++) {
12150 for (k = iMin - 1; k <= iMax + 1; k++) {
12151 if (cosmic[k + l * xLen] == 3) {
12152 cosmic[k + l * xLen] = 1;
12153 numCosmic++;
12154 }
12155 }
12156 }
12157 }
12158 else {
12159 for (l = jMin - 1; l <= jMax + 1; l++) {
12160 for (k = iMin - 1; k <= iMax + 1; k++) {
12161 if (cosmic[k + l * xLen] != -1) {
12162 if (cosmic[k + l * xLen] == 1)
12163 numCosmic--;
12164 cosmic[k + l * xLen] = 0;
12165 }
12166 }
12167 }
12168 }
12169 }
12170 } while (found);
12171
12172
12173
12174
12175
12176
12177 table = cpl_table_new(numCosmic);
12178 cpl_table_new_column(table, "x", CPL_TYPE_INT);
12179 cpl_table_new_column(table, "y", CPL_TYPE_INT);
12180 cpl_table_set_column_unit(table, "x", "pixel");
12181 cpl_table_set_column_unit(table, "y", "pixel");
12182 xdata = cpl_table_get_data_int(table, "x");
12183 ydata = cpl_table_get_data_int(table, "y");
12184
12185 for (pos = 0, i = 0; pos < nPix; pos++) {
12186 if (cosmic[pos] == 1) {
12187 xdata[i] = (pos % xLen);
12188 ydata[i] = (pos / xLen);
12189 i++;
12190 }
12191 }
12192
12193 mos_clean_bad_pixels(image, table, 1);
12194
12195 cpl_free(cosmic);
12196 cpl_table_delete(table);
12197
12198 return CPL_ERROR_NONE;
12199
12200 }
12201
12202
12203 cpl_error_code mos_clean_bad_pixels(cpl_image *image, cpl_table *table,
12204 int spectral)
12205 {
12206 const char *func = "mos_clean_cosmics";
12207
12208 float *idata;
12209 int *isBadPix;
12210 int i, j, k, d;
12211 int xlen, ylen, totPix;
12212 int nBadPixels = 0;
12213 int sign, foundFirst;
12214 int *xValue = NULL;
12215 int *yValue = NULL;
12216 float save = 0.;
12217 double sumd;
12218 int cx, cy;
12219 int nPairs;
12220 float estimate[4];
12221 int sx[] = {0, 1, 1, 1};
12222 int sy[] = {1,-1, 0, 1};
12223 int searchHorizon = 100;
12224 int percent = 15;
12225
12226
12227 if (image == NULL || table == NULL)
12228 return cpl_error_set(func, CPL_ERROR_NULL_INPUT);
12229
12230 if (1 != cpl_table_has_column(table, "x"))
12231 return cpl_error_set(func, CPL_ERROR_DATA_NOT_FOUND);
12232
12233 if (1 != cpl_table_has_column(table, "y"))
12234 return cpl_error_set(func, CPL_ERROR_DATA_NOT_FOUND);
12235
12236 if (CPL_TYPE_INT != cpl_table_get_column_type(table, "x"))
12237 return cpl_error_set(func, CPL_ERROR_INVALID_TYPE);
12238
12239 if (CPL_TYPE_INT != cpl_table_get_column_type(table, "y"))
12240 return cpl_error_set(func, CPL_ERROR_INVALID_TYPE);
12241
12242 nBadPixels = cpl_table_get_nrow(table);
12243
12244 if (nBadPixels) {
12245 xlen = cpl_image_get_size_x(image);
12246 ylen = cpl_image_get_size_y(image);
12247 idata = cpl_image_get_data(image);
12248 totPix = xlen * ylen;
12249 if (((float) nBadPixels) / ((float) totPix) < percent/100.) {
12250 isBadPix = cpl_calloc(totPix, sizeof(int));
12251 }
12252 else {
12253 cpl_msg_warning(func, "Too many bad pixels (> %d%%): "
12254 "skip bad pixel correction", percent);
12255 return cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
12256 }
12257 }
12258 else {
12259 cpl_msg_debug(func, "No pixel values to interpolate");
12260 return CPL_ERROR_NONE;
12261 }
12262
12263 xValue = cpl_table_get_data_int(table, "x");
12264 yValue = cpl_table_get_data_int(table, "y");
12265
12266 for (i = 0; i < nBadPixels; i++)
12267 isBadPix[xValue[i] + yValue[i] * xlen] = 1;
12268
12269 for (i = 0; i < nBadPixels; i++) {
12270
12271
12272
12273
12274
12275
12276
12277
12278
12279
12280
12281
12282
12283 nPairs = 0;
12284 for (j = 0; j < 4; j++) {
12285
12286 if (spectral)
12287 if (j != 2)
12288 continue;
12289
12290 estimate[nPairs] = 0.;
12291 sumd = 0.;
12292 foundFirst = 0;
12293 for (k = 0; k < 2; k++) {
12294 sign = 2 * k - 1;
12295 d = 0;
12296 cx = xValue[i];
12297 cy = yValue[i];
12298 do {
12299 cx += sign * sx[j];
12300 cy += sign * sy[j];
12301 if (cx < 0 || cx >= xlen || cy < 0 || cy >= ylen)
12302 break;
12303 d++;
12304 } while (isBadPix[cx + cy * xlen] && d < searchHorizon);
12305
12306 if (cx >= 0 && cx < xlen &&
12307 cy >= 0 && cy < ylen && d < searchHorizon) {
12308
12309
12310
12311
12312
12313 save = idata[cx + cy * xlen];
12314 estimate[nPairs] += save / d;
12315 sumd += 1. / (double) d;
12316 if (k) {
12317 estimate[nPairs] /= sumd;
12318 nPairs++;
12319 }
12320 else {
12321 foundFirst = 1;
12322 }
12323 }
12324 else {
12325
12326
12327
12328
12329
12330 if (k) {
12331 if (foundFirst) {
12332 estimate[nPairs] = save;
12333 nPairs++;
12334 }
12335 }
12336 }
12337 }
12338 }
12339
12340
12341
12342
12343
12344
12345
12346 if (nPairs > 2) {
12347 idata[xValue[i] + yValue[i] * xlen] =
12348 cpl_tools_get_median_float(estimate, nPairs);
12349 }
12350 else if (nPairs == 2) {
12351 idata[xValue[i] + yValue[i] * xlen] =
12352 (estimate[0] + estimate[1]) / 2.;
12353 }
12354 else if (nPairs == 1) {
12355 idata[xValue[i] + yValue[i] * xlen] = estimate[0];
12356 }
12357 else {
12358 cpl_msg_debug(func, "Cannot correct bad pixel %d,%d\n",
12359 xValue[i], yValue[i]);
12360 }
12361 }
12362
12363 cpl_free(isBadPix);
12364
12365 return CPL_ERROR_NONE;
12366 }
12367
12368
12398 cpl_image *mos_spatial_map(cpl_image *spectra, cpl_table *slits,
12399 cpl_table *polytraces, double reference,
12400 double blue, double red, double dispersion)
12401 {
12402 const char *func = "mos_spatial_map";
12403
12404 const char *clab[6] = {"c0", "c1", "c2", "c3", "c4", "c5"};
12405
12406 cpl_polynomial *polytop;
12407 cpl_polynomial *polybot;
12408 cpl_image *calibration;
12409 float *data;
12410 double top, bot;
12411 double coeff;
12412 double ytop, ybot;
12413 double ypos, yfra;
12414 double factor;
12415 int yint, yprev;
12416 int nslits;
12417 int npseudo;
12418 int *slit_id;
12419 int *length;
12420 int nx, ny;
12421 int pixel_above, pixel_below, refpixel, start_pixel, end_pixel;
12422 int missing_top, missing_bot;
12423 int null;
12424 int order;
12425 int i, j, k;
12426
12427
12428 if (spectra == NULL || slits == NULL || polytraces == NULL) {
12429 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
12430 return NULL;
12431 }
12432
12433 if (dispersion <= 0.0) {
12434 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
12435 return NULL;
12436 }
12437
12438 if (red - blue < dispersion) {
12439 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
12440 return NULL;
12441 }
12442
12443 nx = cpl_image_get_size_x(spectra);
12444 ny = cpl_image_get_size_y(spectra);
12445
12446 calibration = cpl_image_new(nx, ny, CPL_TYPE_FLOAT);
12447 data = cpl_image_get_data(calibration);
12448
12449 length = cpl_table_get_data_int(slits, "length");
12450 nslits = cpl_table_get_nrow(slits);
12451 slit_id = cpl_table_get_data_int(slits, "slit_id");
12452 order = cpl_table_get_ncol(polytraces) - 2;
12453
12454
12455
12456
12457
12458
12459 pixel_above = (red - reference) / dispersion;
12460 pixel_below = (reference - blue) / dispersion;
12461
12462 for (i = 0; i < nslits; i++) {
12463
12464 if (length[i] == 0)
12465 continue;
12466
12467
12468
12469
12470
12471
12472
12473
12474
12475
12476
12477
12478 refpixel = cpl_table_get_double(slits, "xtop", i, NULL);
12479
12480 start_pixel = refpixel - pixel_below;
12481 if (start_pixel < 0)
12482 start_pixel = 0;
12483
12484 end_pixel = refpixel + pixel_above;
12485 if (end_pixel > nx)
12486 end_pixel = nx;
12487
12488
12489
12490
12491
12492
12493 missing_top = 0;
12494 polytop = cpl_polynomial_new(1);
12495 for (k = 0; k <= order; k++) {
12496 coeff = cpl_table_get_double(polytraces, clab[k], 2*i, &null);
12497 if (null) {
12498 cpl_polynomial_delete(polytop);
12499 missing_top = 1;
12500 break;
12501 }
12502 cpl_polynomial_set_coeff(polytop, &k, coeff);
12503 }
12504
12505 missing_bot = 0;
12506 polybot = cpl_polynomial_new(1);
12507 for (k = 0; k <= order; k++) {
12508 coeff = cpl_table_get_double(polytraces, clab[k], 2*i+1, &null);
12509 if (null) {
12510 cpl_polynomial_delete(polybot);
12511 missing_bot = 1;
12512 break;
12513 }
12514 cpl_polynomial_set_coeff(polybot, &k, coeff);
12515 }
12516
12517 if (missing_top && missing_bot) {
12518 cpl_msg_warning(func, "Spatial map, slit %d was not traced!",
12519 slit_id[i]);
12520 continue;
12521 }
12522
12523
12524
12525
12526
12527
12528
12529 if (missing_top) {
12530 cpl_msg_warning(func, "Upper edge of slit %d was not traced: "
12531 "the spectral curvature of the lower edge "
12532 "is used instead.", slit_id[i]);
12533 polytop = cpl_polynomial_duplicate(polybot);
12534 ytop = cpl_table_get_double(slits, "ytop", i, NULL);
12535 ybot = cpl_table_get_double(slits, "ybottom", i, NULL);
12536 k = 0;
12537 coeff = cpl_polynomial_get_coeff(polybot, &k);
12538 coeff += ytop - ybot;
12539 cpl_polynomial_set_coeff(polytop, &k, coeff);
12540 }
12541
12542 if (missing_bot) {
12543 cpl_msg_warning(func, "Lower edge of slit %d was not traced: "
12544 "the spectral curvature of the upper edge "
12545 "is used instead.", slit_id[i]);
12546 polybot = cpl_polynomial_duplicate(polytop);
12547 ytop = cpl_table_get_double(slits, "ytop", i, NULL);
12548 ybot = cpl_table_get_double(slits, "ybottom", i, NULL);
12549 k = 0;
12550 coeff = cpl_polynomial_get_coeff(polytop, &k);
12551 coeff -= ytop - ybot;
12552 cpl_polynomial_set_coeff(polybot, &k, coeff);
12553 }
12554
12555 top = cpl_polynomial_eval_1d(polytop, refpixel, NULL);
12556 bot = cpl_polynomial_eval_1d(polybot, refpixel, NULL);
12557 npseudo = ceil(top-bot) + 1;
12558
12559 if (npseudo < 1) {
12560 cpl_polynomial_delete(polytop);
12561 cpl_polynomial_delete(polybot);
12562 cpl_msg_warning(func, "Slit %d was badly traced: no extraction!",
12563 slit_id[i]);
12564 continue;
12565 }
12566
12567 for (j = start_pixel; j < end_pixel; j++) {
12568 top = cpl_polynomial_eval_1d(polytop, j, NULL);
12569 bot = cpl_polynomial_eval_1d(polybot, j, NULL);
12570 factor = (top-bot)/npseudo;
12571 for (k = 0; k <= npseudo; k++) {
12572 ypos = top - k*factor;
12573 yint = ypos;
12574 yfra = ypos - yint;
12575 if (yint >= 0 && yint < ny-1) {
12576 data[j + nx*yint] = (top-yint)/factor;
12577 if (k) {
12578
12579
12580
12581
12582
12583
12584
12585 if (yprev - yint > 1) {
12586 data[j + nx*(yint+1)] = (top-yint-1)/factor;
12587 }
12588 }
12589 }
12590 yprev = yint;
12591 }
12592 }
12593 cpl_polynomial_delete(polytop);
12594 cpl_polynomial_delete(polybot);
12595 }
12596
12597 return calibration;
12598 }
12599
12600
12663 cpl_image *mos_detect_objects(cpl_image *image, cpl_table *slits, int margin,
12664 int maxradius, int conradius)
12665 {
12666 const char *func = "mos_detect_objects";
12667
12668 cpl_image *profile;
12669 float *pdata;
12670 float *p;
12671
12672 char name[MAX_COLNAME];
12673
12674 int nslits;
12675 int npeaks;
12676 int nobjects, objpos, totobj;
12677 int maxobjects;
12678 int *position;
12679 int *length;
12680 int *reject;
12681 double *place;
12682 double *bright;
12683 double mindistance;
12684 int pos, count;
12685 int up;
12686 int low, hig;
12687 int row;
12688 int i, j, k;
12689
12690 const int min_pixels = 10;
12691
12692
12693 if (cpl_error_get_code() != CPL_ERROR_NONE)
12694 return NULL;
12695
12696 if (image == NULL || slits == NULL) {
12697 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
12698 return NULL;
12699 }
12700
12701 if (margin < 0)
12702 margin = 0;
12703
12704 if (maxradius < 0) {
12705 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
12706 return NULL;
12707 }
12708
12709 if (conradius < 0) {
12710 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
12711 return NULL;
12712 }
12713
12714 nslits = cpl_table_get_nrow(slits);
12715 position = cpl_table_get_data_int(slits, "position");
12716 length = cpl_table_get_data_int(slits, "length");
12717
12718 profile = cpl_image_collapse_create(image, 1);
12719 cpl_image_divide_scalar(profile, cpl_image_get_size_x(image));
12720 pdata = cpl_image_get_data(profile);
12721
12722 row = 1;
12723 maxobjects = 0;
12724 totobj = 0;
12725 for (i = 0; i < nslits; i++) {
12726
12727 if (length[i] == 0)
12728 continue;
12729
12730 pos = position[i] + margin;
12731 count = length[i] - 2*margin;
12732
12733 if (count < min_pixels)
12734 continue;
12735
12736 p = pdata + pos;
12737
12738
12739
12740
12741
12742
12743 npeaks = 0;
12744 if (p[0] > p[1] && p[1] > p[2] && p[2] > p[3] && p[3] > 0) {
12745 npeaks++;
12746 }
12747
12748 up = 0;
12749 for (j = 0; j < count - 3; j++) {
12750 if (p[j] > 0) {
12751 if (p[j+1] > p[j]) {
12752 up++;
12753 }
12754 else {
12755 if (up > 2) {
12756 if (p[j+1] > p[j+2] && p[j+2] > 0) {
12757 if (p[j] > 5)
12758 npeaks++;
12759 }
12760 }
12761 else if (up > 1) {
12762 if (p[j+1] > p[j+2] && p[j+2] > p[j+3] && p[j+3] > 0) {
12763 if (p[j] > 5)
12764 npeaks++;
12765 }
12766 }
12767 up = 0;
12768 }
12769 }
12770 else {
12771 up = 0;
12772 }
12773 }
12774
12775 if (p[count-1] > p[count-2] && p[count-2] > p[count-3]
12776 && p[count-3] > p[count-4] && p[count-4] > 0) {
12777 npeaks++;
12778 }
12779
12780 if (npeaks == 0)
12781 continue;
12782
12783
12784
12785
12786
12787
12788 reject = cpl_calloc(npeaks, sizeof(int));
12789 bright = cpl_calloc(npeaks, sizeof(double));
12790 place = cpl_calloc(npeaks, sizeof(double));
12791
12792 npeaks = 0;
12793 if (p[0] > p[1] && p[1] > p[2] && p[2] > p[3] && p[3] > 0) {
12794 bright[0] = p[0];
12795 place[0] = position[i] + margin;
12796 npeaks++;
12797 }
12798
12799 up = 0;
12800 for (j = 0; j < count - 3; j++) {
12801 if (p[j] > 0) {
12802 if (p[j+1] > p[j]) {
12803 up++;
12804 }
12805 else {
12806 if (up > 2) {
12807 if (p[j+1] > p[j+2] && p[j+2] > 0) {
12808 if (p[j] > 5) {
12809 bright[npeaks] = p[j];
12810 place[npeaks] = position[i] + margin + j + 1
12811 + values_to_dx(p[j-1], p[j], p[j+1]);
12812 npeaks++;
12813 }
12814 }
12815 }
12816 else if (up > 1) {
12817 if (p[j+1] > p[j+2] && p[j+2] > p[j+3] && p[j+3] > 0) {
12818 if (p[j] > 5) {
12819 bright[npeaks] = p[j];
12820 place[npeaks] = position[i] + margin + j + 1
12821 + values_to_dx(p[j-1], p[j], p[j+1]);
12822 npeaks++;
12823 }
12824 }
12825 }
12826 up = 0;
12827 }
12828 }
12829 else {
12830 up = 0;
12831 }
12832 }
12833
12834 if (p[count-1] > p[count-2] && p[count-2] > p[count-3]
12835 && p[count-3] > p[count-4] && p[count-4] > 0) {
12836 bright[npeaks] = p[count-1];
12837 place[npeaks] = position[i] + count;
12838 npeaks++;
12839 }
12840
12841
12842
12843
12844
12845
12846 if (fabs(place[0] - pos) < 1.0)
12847 reject[0] = 1;
12848 if (fabs(place[npeaks-1] - pos - count) < 1.0)
12849 reject[npeaks-1] = 1;
12850 for (j = 0; j < npeaks; j++) {
12851 for (k = 0; k < npeaks; k++) {
12852 if (k == j)
12853 continue;
12854 mindistance = conradius * bright[k] / bright[j]
12855 * bright[k] / bright[j];
12856 if (fabs(place[j] - place[k]) < mindistance)
12857 reject[j] = 1;
12858 }
12859 }
12860
12861
12862 for (j = 0; j < npeaks; j++) {
12863 if (reject[j])
12864 continue;
12865 if (j) {
12866 low = (place[j-1]*bright[j] + place[j]*bright[j-1])
12867 / (bright[j-1] + bright[j]) + 1;
12868 }
12869 else {
12870 low = pos;
12871 }
12872 if (j < npeaks - 1) {
12873 hig = (place[j+1]*bright[j] + place[j]*bright[j+1])
12874 / (bright[j+1] + bright[j]) + 1;
12875 }
12876 else {
12877 hig = pos + count;
12878 }
12879
12880 if (low < pos)
12881 low = pos;
12882 if (hig > pos + count)
12883 hig = pos + count;
12884 if (place[j] - low > maxradius)
12885 low = place[j] - maxradius;
12886 if (hig - place[j] > maxradius)
12887 hig = place[j] + maxradius;
12888 if (hig == low)
12889 reject[j] = 1;
12890 }
12891
12892
12893 nobjects = npeaks;
12894 for (j = 0; j < npeaks; j++)
12895 if (reject[j])
12896 nobjects--;
12897
12898 for (j = 0; j < nobjects; j++) {
12899 snprintf(name, MAX_COLNAME, "object_%d", j+1);
12900 if (cpl_table_has_column(slits, name))
12901 continue;
12902 cpl_table_new_column(slits, name, CPL_TYPE_DOUBLE);
12903 snprintf(name, MAX_COLNAME, "start_%d", j+1);
12904 cpl_table_new_column(slits, name, CPL_TYPE_INT);
12905 cpl_table_set_column_unit(slits, name, "pixel");
12906 snprintf(name, MAX_COLNAME, "end_%d", j+1);
12907 cpl_table_new_column(slits, name, CPL_TYPE_INT);
12908 cpl_table_set_column_unit(slits, name, "pixel");
12909 snprintf(name, MAX_COLNAME, "row_%d", j+1);
12910 cpl_table_new_column(slits, name, CPL_TYPE_INT);
12911 cpl_table_set_column_unit(slits, name, "pixel");
12912 }
12913
12914 objpos = nobjects;
12915 for (j = 0; j < npeaks; j++) {
12916 if (reject[j])
12917 continue;
12918 if (j) {
12919 low = (place[j-1]*bright[j] + place[j]*bright[j-1])
12920 / (bright[j-1] + bright[j]) + 1;
12921 }
12922 else {
12923 low = pos;
12924 }
12925 if (j < npeaks - 1) {
12926 hig = (place[j+1]*bright[j] + place[j]*bright[j+1])
12927 / (bright[j+1] + bright[j]) + 1;
12928 }
12929 else {
12930 hig = pos + count;
12931 }
12932
12933 if (low < pos)
12934 low = pos;
12935 if (hig > pos + count)
12936 hig = pos + count;
12937 if (place[j] - low > maxradius)
12938 low = place[j] - maxradius;
12939 if (hig - place[j] > maxradius)
12940 hig = place[j] + maxradius;
12941
12942 snprintf(name, MAX_COLNAME, "object_%d", objpos);
12943 cpl_table_set_double(slits, name, i, place[j]);
12944 snprintf(name, MAX_COLNAME, "start_%d", objpos);
12945 cpl_table_set_int(slits, name, i, low);
12946 snprintf(name, MAX_COLNAME, "end_%d", objpos);
12947 cpl_table_set_int(slits, name, i, hig);
12948 snprintf(name, MAX_COLNAME, "row_%d", objpos);
12949 cpl_table_set_int(slits, name, i, row + objpos - 1);
12950 totobj++;
12951 objpos--;
12952 }
12953
12954 row += nobjects;
12955
12956 if (maxobjects < nobjects)
12957 maxobjects = nobjects;
12958
12959 cpl_free(reject);
12960 cpl_free(bright);
12961 cpl_free(place);
12962
12963 }
12964
12965
12966 row = cpl_table_get_nrow(slits);
12967
12968 for (i = 0; i < row; i++) {
12969 for (j = 0; j < maxobjects; j++) {
12970 snprintf(name, MAX_COLNAME, "row_%d", j+1);
12971 if (cpl_table_is_valid(slits, name, i))
12972 cpl_table_set_int(slits, name, i, totobj -
12973 cpl_table_get_int(slits, name, i, NULL));
12974 }
12975 }
12976
12977 for (i = 0; i < maxobjects; i++) {
12978 snprintf(name, MAX_COLNAME, "start_%d", i+1);
12979 cpl_table_fill_invalid_int(slits, name, -1);
12980 snprintf(name, MAX_COLNAME, "end_%d", i+1);
12981 cpl_table_fill_invalid_int(slits, name, -1);
12982 snprintf(name, MAX_COLNAME, "row_%d", i+1);
12983 cpl_table_fill_invalid_int(slits, name, -1);
12984 }
12985
12986 return profile;
12987 }
12988
12989
13014 cpl_image **mos_extract_objects(cpl_image *science, cpl_image *sky,
13015 cpl_table *objects, int extraction, double ron,
13016 double gain, int ncombined)
13017 {
13018 const char *func = "mos_extract_objects";
13019
13020 char name[MAX_COLNAME];
13021
13022 cpl_image **output;
13023 cpl_image *extracted;
13024 cpl_image *extr_sky;
13025 cpl_image *error;
13026 cpl_image *sciwin;
13027 cpl_image *skywin;
13028 int nslits;
13029 int nobjects;
13030 int maxobjects;
13031 int nx, ny;
13032 int ylow, yhig;
13033 int i, j;
13034
13035
13036 if (science == NULL || sky == NULL) {
13037 cpl_msg_error(func, "Both scientific exposures are required in input");
13038 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
13039 return NULL;
13040 }
13041
13042 if (objects == NULL) {
13043 cpl_msg_error(func, "An object table is required in input");
13044 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
13045 return NULL;
13046 }
13047
13048 if (extraction < 0 || extraction > 1) {
13049 cpl_msg_error(func, "Invalid extraction mode (%d): it should be "
13050 "either 0 or 1", extraction);
13051 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
13052 return NULL;
13053 }
13054
13055 if (ron < 0.0) {
13056 cpl_msg_error(func, "Invalid read-out-noise (%f ADU)", ron);
13057 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
13058 return NULL;
13059 }
13060
13061 if (gain < 0.1) {
13062 cpl_msg_error(func, "Invalid gain factor (%f e-/ADU)", gain);
13063 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
13064 return NULL;
13065 }
13066
13067 if (ncombined < 1) {
13068 cpl_msg_error(func, "Invalid number of combined frames (%d): "
13069 "it should be at least 1", ncombined);
13070 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
13071 return NULL;
13072 }
13073
13074
13075
13076
13077
13078
13079
13080 maxobjects = 1;
13081 snprintf(name, MAX_COLNAME, "object_%d", maxobjects);
13082 while (cpl_table_has_column(objects, name)) {
13083 maxobjects++;
13084 snprintf(name, MAX_COLNAME, "object_%d", maxobjects);
13085 }
13086
13087
13088
13089
13090
13091
13092 nobjects = 0;
13093 nslits = cpl_table_get_nrow(objects);
13094
13095 for (i = 0; i < nslits; i++) {
13096 for (j = 1; j < maxobjects; j++) {
13097 snprintf(name, MAX_COLNAME, "object_%d", j);
13098 if (cpl_table_is_valid(objects, name, i))
13099 nobjects++;
13100 }
13101 }
13102
13103 if (nobjects == 0)
13104 return NULL;
13105
13106 nx = cpl_image_get_size_x(science);
13107 ny = cpl_image_get_size_x(science);
13108
13109 output = cpl_calloc(3, sizeof(cpl_image *));
13110 extracted = output[0] = cpl_image_new(nx, nobjects, CPL_TYPE_FLOAT);
13111 extr_sky = output[1] = cpl_image_new(nx, nobjects, CPL_TYPE_FLOAT);
13112 error = output[2] = cpl_image_new(nx, nobjects, CPL_TYPE_FLOAT);
13113
13114
13115
13116
13117
13118
13119 nobjects = 0;
13120 for (i = 0; i < nslits; i++) {
13121 for (j = 1; j < maxobjects; j++) {
13122 snprintf(name, MAX_COLNAME, "object_%d", j);
13123 if (cpl_table_is_valid(objects, name, i)) {
13124 snprintf(name, MAX_COLNAME, "start_%d", j);
13125 ylow = cpl_table_get_int(objects, name, i, NULL);
13126 snprintf(name, MAX_COLNAME, "end_%d", j);
13127 yhig = cpl_table_get_int(objects, name, i, NULL);
13128 snprintf(name, MAX_COLNAME, "row_%d", j);
13129 nobjects = cpl_table_get_int(objects, name, i, NULL);
13130 sciwin = cpl_image_extract(science, 1, ylow+1, nx, yhig);
13131 skywin = cpl_image_extract(sky, 1, ylow+1, nx, yhig);
13132
13133
13134
13135
13136
13137
13138
13139
13140 mos_extraction(sciwin, skywin, extracted, extr_sky, error,
13141 nobjects, extraction, ron, gain, ncombined);
13142 cpl_image_delete(sciwin);
13143 cpl_image_delete(skywin);
13144 nobjects++;
13145 }
13146 }
13147 }
13148
13149 return output;
13150
13151 }
13152
13153
13176 int mos_spectral_resolution(cpl_image *image, double lambda, double startwave,
13177 double dispersion, int saturation,
13178 double *mfwhm, double *rmsfwhm,
13179 double *resolution, double *rmsres, int *nlines)
13180 {
13181 cpl_vector *vector;
13182
13183 int i, j, n, m;
13184 int position, maxpos;
13185 int xlen, ylen;
13186 int sp, ep;
13187 int radius;
13188 int sradius = 40;
13189 int threshold = 250;
13190
13191 int ifwhm;
13192 double fwhm;
13193 double *buffer;
13194 double min, max, halfmax;
13195 double cut = 1.5;
13196 double value, rms;
13197
13198 float *data;
13199
13200
13201 *resolution = 0.0;
13202 *rmsres = 0.0;
13203 *nlines = 0;
13204
13205 xlen = cpl_image_get_size_x(image);
13206 ylen = cpl_image_get_size_y(image);
13207 data = cpl_image_get_data(image);
13208
13209 buffer = cpl_malloc(ylen * sizeof(double));
13210
13211
13212
13213
13214
13215 position = floor((lambda - startwave) / dispersion + 0.5);
13216
13217 sp = position - sradius;
13218 ep = position + sradius;
13219
13220 if (sp < 0 || ep > xlen) {
13221 cpl_free(buffer);
13222 return 0;
13223 }
13224
13225 for (i = 0, n = 0; i < ylen; i++) {
13226
13227
13228
13229
13230
13231 radius = mos_lines_width(data + i*xlen + position - sradius,
13232 2*sradius + 1);
13233 if (radius < 5)
13234 radius = 5;
13235
13236 sp = position - radius;
13237 ep = position + radius;
13238
13239 if (sp < 0 || ep > xlen) {
13240 cpl_free(buffer);
13241 return 0;
13242 }
13243
13244
13245
13246
13247
13248
13249 maxpos = sp;
13250 min = max = data[sp + i * xlen];
13251 for (j = sp; j < ep; j++) {
13252 if (data[j + i * xlen] > max) {
13253 max = data[j + i * xlen];
13254 maxpos = j;
13255 }
13256 if (data[j + i * xlen] < min) {
13257 min = data[j + i * xlen];
13258 }
13259 }
13260
13261 if (fabs(min) < 0.0000001)
13262 continue;
13263
13264 if (max - min < threshold)
13265 continue;
13266
13267 if (max > saturation)
13268 continue;
13269
13270
13271
13272
13273
13274
13275
13276
13277 halfmax = (max + min)/ 2.0;
13278
13279 fwhm = 0.0;
13280 ifwhm = 0;
13281 for (j = maxpos; j < maxpos + radius; j++) {
13282 if (j < xlen) {
13283 if (data[j + i * xlen] < halfmax) {
13284 fwhm = ifwhm + (data[j - 1 + i * xlen] - halfmax)
13285 / (data[j - 1 + i * xlen] - data[j + i * xlen]);
13286 break;
13287 }
13288 ifwhm++;
13289 }
13290 }
13291
13292 ifwhm = 0;
13293 for (j = maxpos; j > maxpos - radius; j--) {
13294 if (j >= 0) {
13295 if (data[j + i * xlen] < halfmax) {
13296 fwhm += ifwhm + (data[j + 1 + i * xlen] - halfmax)
13297 / (data[j + 1 + i * xlen] - data[j + i * xlen]);
13298 break;
13299 }
13300 ifwhm++;
13301 }
13302 }
13303
13304 if (fwhm > 3.0) {
13305 buffer[n] = fwhm - 2.0;
13306 n++;
13307 }
13308
13309 }
13310
13311 if (n == 0) {
13312 cpl_free(buffer);
13313 return 0;
13314 }
13315
13316 vector = cpl_vector_wrap(n, buffer);
13317 value = cpl_vector_get_median_const(vector);
13318 cpl_vector_unwrap(vector);
13319
13320 rms = 0.0;
13321 for (i = 0, m = 0; i < n; i++) {
13322 if (fabs(buffer[i] - value) < cut) {
13323 rms += fabs(buffer[i] - value);
13324 m++;
13325 }
13326 }
13327
13328 cpl_free(buffer);
13329
13330 if (m < 3)
13331 return 0;
13332
13333 rms /= m;
13334 rms *= 1.25;
13335
13336 value *= dispersion;
13337 rms *= dispersion;
13338
13339 *mfwhm = value;
13340 *rmsfwhm = rms;
13341
13342 *resolution = lambda / value;
13343 *rmsres = *resolution * rms / value;
13344
13345 *nlines = m;
13346
13347 return 1;
13348 }
13349
13350
13372 cpl_table *mos_resolution_table(cpl_image *image, double startwave,
13373 double dispersion, int saturation,
13374 cpl_vector *lines)
13375 {
13376
13377 cpl_table *table;
13378 double *line;
13379 double fwhm;
13380 double rmsfwhm;
13381 double resolution;
13382 double rmsres;
13383 int nref;
13384 int nlines;
13385 int i;
13386
13387
13388 nref = cpl_vector_get_size(lines);
13389 line = cpl_vector_get_data(lines);
13390
13391 table = cpl_table_new(nref);
13392 cpl_table_new_column(table, "wavelength", CPL_TYPE_DOUBLE);
13393 cpl_table_set_column_unit(table, "wavelength", "Angstrom");
13394 cpl_table_new_column(table, "fwhm", CPL_TYPE_DOUBLE);
13395 cpl_table_set_column_unit(table, "fwhm", "Angstrom");
13396 cpl_table_new_column(table, "fwhm_rms", CPL_TYPE_DOUBLE);
13397 cpl_table_set_column_unit(table, "fwhm_rms", "Angstrom");
13398 cpl_table_new_column(table, "resolution", CPL_TYPE_DOUBLE);
13399 cpl_table_new_column(table, "resolution_rms", CPL_TYPE_DOUBLE);
13400 cpl_table_new_column(table, "nlines", CPL_TYPE_INT);
13401
13402 for (i = 0; i < nref; i++) {
13403 if (mos_spectral_resolution(image, line[i], startwave, dispersion,
13404 saturation, &fwhm, &rmsfwhm,
13405 &resolution, &rmsres, &nlines)) {
13406 cpl_table_set_double(table, "wavelength", i, line[i]);
13407 cpl_table_set_double(table, "fwhm", i, fwhm);
13408 cpl_table_set_double(table, "fwhm_rms", i, rmsfwhm);
13409 cpl_table_set_double(table, "resolution", i, resolution);
13410 cpl_table_set_double(table, "resolution_rms", i, rmsres);
13411 cpl_table_set_int(table, "nlines", i, nlines);
13412 }
13413 else
13414 cpl_table_set_int(table, "nlines", i, 0);
13415 }
13416
13417 if (cpl_table_has_valid(table, "wavelength"))
13418 return table;
13419
13420 cpl_table_delete(table);
13421
13422 return NULL;
13423
13424 }
13425
13426
13444 double mos_integrate_signal(cpl_image *image, cpl_image *wavemap,
13445 int ystart, int yend, double wstart, double wend)
13446 {
13447 const char *func = "mos_integrate_signal";
13448
13449 double sum;
13450 float *sdata;
13451 float *wdata;
13452 int nx, ny;
13453 int x, y;
13454
13455
13456 if (image == NULL || wavemap == NULL) {
13457 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
13458 return 0.0;
13459 }
13460
13461 if (ystart > yend || wstart >= wend) {
13462 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
13463 return 0.0;
13464 }
13465
13466 nx = cpl_image_get_size_x(image);
13467 ny = cpl_image_get_size_y(image);
13468
13469 if (!(nx == cpl_image_get_size_x(wavemap)
13470 && ny == cpl_image_get_size_y(wavemap))) {
13471 cpl_error_set(func, CPL_ERROR_INCOMPATIBLE_INPUT);
13472 return 0.0;
13473 }
13474
13475 if (ystart < 0 || yend > ny) {
13476 cpl_error_set(func, CPL_ERROR_ACCESS_OUT_OF_RANGE);
13477 return 0.0;
13478 }
13479
13480 sdata = cpl_image_get_data(image);
13481 wdata = cpl_image_get_data(wavemap);
13482
13483 sdata += ystart*nx;
13484 wdata += ystart*nx;
13485
13486 sum = 0.0;
13487 for (y = ystart; y < yend; y++) {
13488 for (x = 0; x < nx; x++) {
13489 if (wdata[x] < wstart || wdata[x] > wend)
13490 continue;
13491 sum += sdata[x];
13492 }
13493 sdata += nx;
13494 wdata += nx;
13495 }
13496
13497 return sum;
13498
13499 }
13500
13501
13502
13503
13504
13505
13506
13507
13508
13509
13532 cpl_table *mos_load_slits_fors_mxu(cpl_propertylist *header)
13533 {
13534 const char *func = "mos_load_slits_fors_mxu";
13535
13536 cpl_table *slits;
13537 char keyname[MAX_COLNAME];
13538 const char *instrume;
13539 const char *target_name;
13540 float slit_x;
13541 float slit_y;
13542 float length;
13543
13544 double arc2mm = 0.528;
13545 int nslits;
13546 int slit_id;
13547 int fors;
13548 int chip;
13549 int found;
13550
13551
13552
13553
13554
13555
13556
13557 float low_limit1 = 10.0;
13558 float hig_limit2 = 30.0;
13559
13560
13561 if (cpl_error_get_code() != CPL_ERROR_NONE) {
13562 return NULL;
13563 }
13564
13565 if (header == NULL) {
13566 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
13567 return NULL;
13568 }
13569
13570
13571
13572
13573
13574
13575 instrume = cpl_propertylist_get_string(header, "INSTRUME");
13576
13577 fors = 0;
13578 if (instrume[4] == '1')
13579 fors = 1;
13580 if (instrume[4] == '2')
13581 fors = 2;
13582
13583 if (fors != 2) {
13584 cpl_msg_error(func, "Wrong instrument: %s\n"
13585 "FORS2 is expected for MXU data", instrume);
13586 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
13587 return NULL;
13588 }
13589
13590
13591
13592
13593
13594
13595
13596
13597 chip = cpl_propertylist_get_int(header, "ESO DET CHIP1 Y");
13598
13599 if (cpl_error_get_code() != CPL_ERROR_NONE) {
13600 cpl_msg_error(func, "Missing keyword ESO DET CHIP1 Y "
13601 "in FITS header");
13602 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
13603 return NULL;
13604 }
13605
13606 if (chip != 1 && chip != 2) {
13607 cpl_msg_error(func, "Unexpected chip position in keyword "
13608 "ESO DET CHIP1 Y: %d", chip);
13609 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
13610 return NULL;
13611 }
13612
13613
13614
13615
13616
13617
13618
13619 nslits = 0;
13620 slit_id = 0;
13621 found = 1;
13622
13623 while (found) {
13624 slit_id++;
13625 snprintf(keyname, MAX_COLNAME, "ESO INS MOS%d YPOS", slit_id + 100);
13626 if (cpl_propertylist_has(header, keyname)) {
13627 slit_y = cpl_propertylist_get_double(header, keyname);
13628
13629 if (chip == 1)
13630 if (slit_y < low_limit1)
13631 continue;
13632 if (chip == 2)
13633 if (slit_y > hig_limit2)
13634 continue;
13635
13636 snprintf(keyname, MAX_COLNAME, "ESO INS TARG%d NAME",
13637 slit_id + 100);
13638 if (cpl_propertylist_has(header, keyname)) {
13639 target_name = cpl_propertylist_get_string(header, keyname);
13640 if (strncmp(target_name, "refslit", 7))
13641 nslits++;
13642 }
13643 else
13644 nslits++;
13645 }
13646 else
13647 found = 0;
13648 }
13649
13650 if (cpl_error_get_code() != CPL_ERROR_NONE) {
13651 cpl_msg_error(func, "%s while loading slits coordinates from "
13652 "FITS header", cpl_error_get_message());
13653 cpl_error_set_where(func);
13654 return NULL;
13655 }
13656
13657 if (nslits == 0) {
13658 cpl_msg_error(func, "No slits coordinates found in header");
13659 cpl_error_set(func, CPL_ERROR_DATA_NOT_FOUND);
13660 return NULL;
13661 }
13662
13663 slits = cpl_table_new(nslits);
13664 cpl_table_new_column(slits, "slit_id", CPL_TYPE_INT);
13665 cpl_table_new_column(slits, "xtop", CPL_TYPE_DOUBLE);
13666 cpl_table_new_column(slits, "ytop", CPL_TYPE_DOUBLE);
13667 cpl_table_new_column(slits, "xbottom", CPL_TYPE_DOUBLE);
13668 cpl_table_new_column(slits, "ybottom", CPL_TYPE_DOUBLE);
13669 cpl_table_set_column_unit(slits, "xtop", "pixel");
13670 cpl_table_set_column_unit(slits, "ytop", "pixel");
13671 cpl_table_set_column_unit(slits, "xbottom", "pixel");
13672 cpl_table_set_column_unit(slits, "ybottom", "pixel");
13673
13674 nslits = 0;
13675 slit_id = 0;
13676 found = 1;
13677 while (found) {
13678 slit_id++;
13679 snprintf(keyname, MAX_COLNAME, "ESO INS MOS%d YPOS", slit_id + 100);
13680 if (cpl_propertylist_has(header, keyname)) {
13681 slit_y = cpl_propertylist_get_double(header, keyname);
13682
13683 if (chip == 1)
13684 if (slit_y < low_limit1)
13685 continue;
13686 if (chip == 2)
13687 if (slit_y > hig_limit2)
13688 continue;
13689
13690
13691
13692
13693
13694
13695 slit_y = -slit_y;
13696
13697 snprintf(keyname, MAX_COLNAME, "ESO INS MOS%d XPOS", slit_id + 100);
13698 slit_x = cpl_propertylist_get_double(header, keyname);
13699 if (cpl_error_get_code() != CPL_ERROR_NONE) {
13700 cpl_table_delete(slits);
13701 cpl_msg_error(func, "Missing keyword %s in FITS header",
13702 keyname);
13703 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
13704 return NULL;
13705 }
13706
13707 snprintf(keyname, MAX_COLNAME, "ESO INS MOS%d LEN", slit_id + 100);
13708 length = cpl_propertylist_get_double(header, keyname);
13709 if (cpl_error_get_code() != CPL_ERROR_NONE) {
13710 cpl_table_delete(slits);
13711 cpl_msg_error(func, "Missing keyword %s in FITS header",
13712 keyname);
13713 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
13714 return NULL;
13715 }
13716
13717 length *= arc2mm;
13718
13719 snprintf(keyname, MAX_COLNAME, "ESO INS TARG%d NAME",
13720 slit_id + 100);
13721 if (cpl_propertylist_has(header, keyname)) {
13722 target_name = cpl_propertylist_get_string(header, keyname);
13723 if (strncmp(target_name, "refslit", 7)) {
13724 cpl_table_set_int(slits, "slit_id", nslits, slit_id);
13725 cpl_table_set(slits, "xtop", nslits, slit_x);
13726 cpl_table_set(slits, "ytop", nslits, slit_y + length/2);
13727 cpl_table_set(slits, "xbottom", nslits, slit_x);
13728 cpl_table_set(slits, "ybottom", nslits, slit_y - length/2);
13729 nslits++;
13730 }
13731 }
13732 else {
13733 cpl_table_set_int(slits, "slit_id", nslits, slit_id);
13734 cpl_table_set(slits, "xtop", nslits, slit_x);
13735 cpl_table_set(slits, "ytop", nslits, slit_y + length/2);
13736 cpl_table_set(slits, "xbottom", nslits, slit_x);
13737 cpl_table_set(slits, "ybottom", nslits, slit_y - length/2);
13738 nslits++;
13739 }
13740 }
13741 else
13742 found = 0;
13743 }
13744
13745 return slits;
13746 }
13747
13748
13771 cpl_table *mos_load_slits_fors_mos(cpl_propertylist *header)
13772 {
13773 const char *func = "mos_load_slits_fors_mos";
13774
13775 cpl_table *slits;
13776 char keyname[MAX_COLNAME];
13777 const char *instrume;
13778 const char *chipname;
13779 float slit_x;
13780 int first_slit, last_slit;
13781 int nslits;
13782 int slit_id;
13783 int fors;
13784 int chip;
13785 int fors_is_old;
13786
13787
13788
13789
13790
13791 float ytop[19] = { 113.9, 101.3, 89.9, 77.3, 65.9, 53.3,
13792 41.9, 29.3, 17.9, 5.3, -6.1, -18.7,
13793 -30.1, -42.7, -54.1, -66.7, -78.1, -90.7,
13794 -102.1 };
13795 float ybottom[19] = { 102.1, 90.7, 78.1, 66.7, 54.1, 42.7,
13796 30.1, 18.7, 6.1, -5.3, -17.9, -29.3,
13797 -41.9, -53.3, -65.9, -77.3, -89.9, -101.3,
13798 -113.9 };
13799
13800
13801 if (cpl_error_get_code() != CPL_ERROR_NONE) {
13802 return NULL;
13803 }
13804
13805 if (header == NULL) {
13806 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
13807 return NULL;
13808 }
13809
13810
13811
13812
13813
13814
13815 instrume = cpl_propertylist_get_string(header, "INSTRUME");
13816
13817 fors = 0;
13818 if (instrume[4] == '1')
13819 fors = 1;
13820 if (instrume[4] == '2')
13821 fors = 2;
13822
13823 if (fors == 0) {
13824 cpl_msg_error(func, "Wrong instrument found in FITS header: %s",
13825 instrume);
13826 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
13827 return NULL;
13828 }
13829
13830
13831
13832
13833
13834
13835
13836 chipname = cpl_propertylist_get_string(header, "ESO DET CHIP1 ID");
13837
13838 if (chipname[0] == 'M' || chipname[0] == 'N')
13839 fors_is_old = 0;
13840 else
13841 fors_is_old = 1;
13842
13843 if (fors == 1 && fors_is_old) {
13844 first_slit = 1;
13845 last_slit = 19;
13846 }
13847 else {
13848
13849
13850
13851
13852
13853
13854
13855 chip = cpl_propertylist_get_int(header, "ESO DET CHIP1 Y");
13856
13857 if (cpl_error_get_code() != CPL_ERROR_NONE) {
13858 cpl_msg_error(func, "Missing keyword ESO DET CHIP1 Y "
13859 "in FITS header");
13860 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
13861 return NULL;
13862 }
13863
13864 if (chip != 1 && chip != 2) {
13865 cpl_msg_error(func, "Unexpected chip position in keyword "
13866 "ESO DET CHIP1 Y: %d", chip);
13867 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
13868 return NULL;
13869 }
13870
13871 if (chip == 1) {
13872 first_slit = 12;
13873 last_slit = 19;
13874 }
13875 else {
13876 first_slit = 1;
13877 last_slit = 11;
13878 }
13879 }
13880
13881
13882
13883
13884
13885
13886
13887
13888 nslits = 0;
13889 slit_id = 0;
13890 for (slit_id = first_slit; slit_id <= last_slit; slit_id++) {
13891 snprintf(keyname, MAX_COLNAME, "ESO INS MOS%d POS", slit_id);
13892 if (cpl_propertylist_has(header, keyname)) {
13893 slit_x = cpl_propertylist_get_double(header, keyname);
13894 if (fabs(slit_x) < 115.0)
13895 nslits++;
13896 }
13897 else {
13898 cpl_msg_error(func, "Missing keyword %s in FITS header", keyname);
13899 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
13900 return NULL;
13901 }
13902 }
13903
13904 if (cpl_error_get_code() != CPL_ERROR_NONE) {
13905 cpl_msg_error(func, "%s while loading slits coordinates from "
13906 "FITS header", cpl_error_get_message());
13907 cpl_error_set_where(func);
13908 return NULL;
13909 }
13910
13911 if (nslits == 0) {
13912 cpl_msg_error(func, "No slits coordinates found in header");
13913 cpl_error_set(func, CPL_ERROR_DATA_NOT_FOUND);
13914 return NULL;
13915 }
13916
13917 slits = cpl_table_new(nslits);
13918 cpl_table_new_column(slits, "slit_id", CPL_TYPE_INT);
13919 cpl_table_new_column(slits, "xtop", CPL_TYPE_DOUBLE);
13920 cpl_table_new_column(slits, "ytop", CPL_TYPE_DOUBLE);
13921 cpl_table_new_column(slits, "xbottom", CPL_TYPE_DOUBLE);
13922 cpl_table_new_column(slits, "ybottom", CPL_TYPE_DOUBLE);
13923 cpl_table_set_column_unit(slits, "xtop", "pixel");
13924 cpl_table_set_column_unit(slits, "ytop", "pixel");
13925 cpl_table_set_column_unit(slits, "xbottom", "pixel");
13926 cpl_table_set_column_unit(slits, "ybottom", "pixel");
13927
13928 nslits = 0;
13929 slit_id = 0;
13930 for (slit_id = first_slit; slit_id <= last_slit; slit_id++) {
13931 snprintf(keyname, MAX_COLNAME, "ESO INS MOS%d POS", slit_id);
13932 slit_x = cpl_propertylist_get_double(header, keyname);
13933 if (fabs(slit_x) < 115.0) {
13934 cpl_table_set_int(slits, "slit_id", nslits, slit_id);
13935 cpl_table_set(slits, "xtop", nslits, slit_x);
13936 cpl_table_set(slits, "ytop", nslits, ytop[slit_id-1]);
13937 cpl_table_set(slits, "xbottom", nslits, slit_x);
13938 cpl_table_set(slits, "ybottom", nslits, ybottom[slit_id-1]);
13939 nslits++;
13940 }
13941 }
13942
13943 return slits;
13944 }
13945
13946
13970 cpl_table *mos_load_slits_fors_lss(cpl_propertylist *header)
13971 {
13972 const char *func = "mos_load_slits_fors_lss";
13973
13974 cpl_table *slits;
13975 char *slit_name;
13976 const char *instrume;
13977 int fors;
13978 int chip;
13979 float ytop;
13980 float ybottom;
13981
13982 if (cpl_error_get_code() != CPL_ERROR_NONE) {
13983 return NULL;
13984 }
13985
13986 if (header == NULL) {
13987 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
13988 return NULL;
13989 }
13990
13991
13992
13993
13994
13995
13996 instrume = cpl_propertylist_get_string(header, "INSTRUME");
13997
13998 fors = 0;
13999 if (instrume[4] == '1')
14000 fors = 1;
14001 if (instrume[4] == '2')
14002 fors = 2;
14003
14004 if (fors == 0) {
14005 cpl_msg_error(func, "Wrong instrument found in FITS header: %s",
14006 instrume);
14007 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
14008 return NULL;
14009 }
14010
14011 if (fors == 1) {
14012 ytop = 109.94;
14013 ybottom = -109.94;
14014 }
14015 else {
14016
14017
14018
14019
14020
14021
14022
14023 chip = cpl_propertylist_get_int(header, "ESO DET CHIP1 Y");
14024
14025 if (cpl_error_get_code() != CPL_ERROR_NONE) {
14026 cpl_msg_error(func, "Missing keyword ESO DET CHIP1 Y "
14027 "in FITS header");
14028 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
14029 return NULL;
14030 }
14031
14032 if (chip != 1 && chip != 2) {
14033 cpl_msg_error(func, "Unexpected chip position in keyword "
14034 "ESO DET CHIP1 Y: %d", chip);
14035 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
14036 return NULL;
14037 }
14038
14039 if (chip == 1) {
14040 ytop = 30.0;
14041 ybottom = -109.94;
14042 }
14043 else {
14044 ytop = 109.94;
14045 ybottom = -20.0;
14046 }
14047 }
14048
14049
14050 slits = cpl_table_new(1);
14051 cpl_table_new_column(slits, "slit_id", CPL_TYPE_INT);
14052 cpl_table_new_column(slits, "xtop", CPL_TYPE_DOUBLE);
14053 cpl_table_new_column(slits, "ytop", CPL_TYPE_DOUBLE);
14054 cpl_table_new_column(slits, "xbottom", CPL_TYPE_DOUBLE);
14055 cpl_table_new_column(slits, "ybottom", CPL_TYPE_DOUBLE);
14056 cpl_table_set_column_unit(slits, "xtop", "pixel");
14057 cpl_table_set_column_unit(slits, "ytop", "pixel");
14058 cpl_table_set_column_unit(slits, "xbottom", "pixel");
14059 cpl_table_set_column_unit(slits, "ybottom", "pixel");
14060
14061 slit_name = (char *)cpl_propertylist_get_string(header,
14062 "ESO INS SLIT NAME");
14063
14064 cpl_table_set(slits, "ytop", 0, ytop);
14065 cpl_table_set(slits, "ybottom", 0, ybottom);
14066
14067 if (!strncmp(slit_name, "lSlit0_3arcsec", 14)) {
14068 cpl_table_set_int(slits, "slit_id", 0, 1);
14069 cpl_table_set(slits, "xbottom", 0, -0.075);
14070 cpl_table_set(slits, "xtop", 0, 0.075);
14071 }
14072 else if (!strncmp(slit_name, "lSlit0_4arcsec", 14)) {
14073 cpl_table_set_int(slits, "slit_id", 0, 2);
14074 cpl_table_set(slits, "xbottom", 0, 5.895);
14075 cpl_table_set(slits, "xtop", 0, 6.105);
14076 }
14077 else if (!strncmp(slit_name, "lSlit0_5arcsec", 14)) {
14078 cpl_table_set_int(slits, "slit_id", 0, 3);
14079 cpl_table_set(slits, "xbottom", 0, -6.135);
14080 cpl_table_set(slits, "xtop", 0, -5.865);
14081 }
14082 else if (!strncmp(slit_name, "lSlit0_7arcsec", 14)) {
14083 cpl_table_set_int(slits, "slit_id", 0, 4);
14084 cpl_table_set(slits, "xbottom", 0, 11.815);
14085 cpl_table_set(slits, "xtop", 0, 12.185);
14086 }
14087 else if (!strncmp(slit_name, "lSlit1_0arcsec", 14)) {
14088 cpl_table_set_int(slits, "slit_id", 0, 5);
14089 cpl_table_set(slits, "xbottom", 0, -12.265);
14090 cpl_table_set(slits, "xtop", 0, -11.735);
14091 }
14092 else if (!strncmp(slit_name, "lSlit1_3arcsec", 14)) {
14093 cpl_table_set_int(slits, "slit_id", 0, 6);
14094 cpl_table_set(slits, "xbottom", 0, 17.655);
14095 cpl_table_set(slits, "xtop", 0, 18.345);
14096 }
14097 else if (!strncmp(slit_name, "lSlit1_6arcsec", 14)) {
14098 cpl_table_set_int(slits, "slit_id", 0, 7);
14099 cpl_table_set(slits, "xbottom", 0, -18.425);
14100 cpl_table_set(slits, "xtop", 0, -17.575);
14101 }
14102 else if (!strncmp(slit_name, "lSlit2_0arcsec", 14)) {
14103 cpl_table_set_int(slits, "slit_id", 0, 8);
14104 cpl_table_set(slits, "xbottom", 0, 23.475);
14105 cpl_table_set(slits, "xtop", 0, 24.525);
14106 }
14107 else if (!strncmp(slit_name, "lSlit2_5arcsec", 14)) {
14108 cpl_table_set_int(slits, "slit_id", 0, 9);
14109 cpl_table_set(slits, "xbottom", 0, -24.66);
14110 cpl_table_set(slits, "xtop", 0, -23.34);
14111 }
14112 else {
14113 cpl_msg_error(func, "Invalid slit %s in keyword ESO INS SLIT NAME",
14114 slit_name);
14115 cpl_error_set(func, CPL_ERROR_DATA_NOT_FOUND);
14116 cpl_table_delete(slits);
14117 return NULL;
14118 }
14119
14120 return slits;
14121 }
14122
14123
14138 double mos_get_gain_vimos(cpl_propertylist *header)
14139 {
14140 const char *func = "mos_get_gain_vimos";
14141
14142 double gain = -1.0;
14143
14144
14145 if (cpl_error_get_code() != CPL_ERROR_NONE)
14146 return gain;
14147
14148 if (header == NULL) {
14149 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
14150 return gain;
14151 }
14152
14153 gain = cpl_propertylist_get_double(header, "ESO DET OUT1 CONAD");
14154 if (cpl_error_get_code()) {
14155 cpl_error_set_where(func);
14156 gain = -1.0;
14157 }
14158
14159 return gain;
14160
14161 }
14162
14163
14183 cpl_table *mos_load_slits_vimos(cpl_propertylist *header)
14184 {
14185 const char *func = "mos_load_slits_vimos";
14186
14187 cpl_table *slits;
14188 char keyname[MAX_COLNAME];
14189 float slit_x;
14190 float slit_y;
14191 float dim_x;
14192 int nslits;
14193 int slit_id;
14194 int i;
14195
14196
14197 if (cpl_error_get_code() != CPL_ERROR_NONE) {
14198 return NULL;
14199 }
14200
14201 if (header == NULL) {
14202 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
14203 return NULL;
14204 }
14205
14206 nslits = cpl_propertylist_get_int(header, "ESO INS SLIT NO");
14207
14208 if (cpl_error_get_code() != CPL_ERROR_NONE) {
14209 cpl_error_set_where(func);
14210 return NULL;
14211 }
14212
14213 slits = cpl_table_new(nslits);
14214 cpl_table_new_column(slits, "slit_id", CPL_TYPE_INT);
14215 cpl_table_new_column(slits, "xtop", CPL_TYPE_DOUBLE);
14216 cpl_table_new_column(slits, "ytop", CPL_TYPE_DOUBLE);
14217 cpl_table_new_column(slits, "xbottom", CPL_TYPE_DOUBLE);
14218 cpl_table_new_column(slits, "ybottom", CPL_TYPE_DOUBLE);
14219 cpl_table_set_column_unit(slits, "xtop", "pixel");
14220 cpl_table_set_column_unit(slits, "ytop", "pixel");
14221 cpl_table_set_column_unit(slits, "xbottom", "pixel");
14222 cpl_table_set_column_unit(slits, "ybottom", "pixel");
14223
14224 for (i = 0; i < nslits; i++) {
14225 sprintf(keyname, "ESO INS SLIT%d ID", i+1);
14226 slit_id = cpl_propertylist_get_int(header, keyname);
14227 if (cpl_error_get_code() != CPL_ERROR_NONE) {
14228 cpl_error_set_where(func);
14229 return NULL;
14230 }
14231 sprintf(keyname, "ESO INS SLIT%d X", i+1);
14232 slit_x = cpl_propertylist_get_double(header, keyname);
14233 if (cpl_error_get_code() != CPL_ERROR_NONE) {
14234 cpl_error_set_where(func);
14235 return NULL;
14236 }
14237 sprintf(keyname, "ESO INS SLIT%d Y", i+1);
14238 slit_y = cpl_propertylist_get_double(header, keyname);
14239 if (cpl_error_get_code() != CPL_ERROR_NONE) {
14240 cpl_error_set_where(func);
14241 return NULL;
14242 }
14243 sprintf(keyname, "ESO INS SLIT%d DIMX", i+1);
14244 dim_x = cpl_propertylist_get_double(header, keyname) / 2;
14245 if (cpl_error_get_code() != CPL_ERROR_NONE) {
14246 cpl_error_set_where(func);
14247 return NULL;
14248 }
14249 cpl_table_set_int(slits, "slit_id", i, slit_id);
14250 cpl_table_set(slits, "xtop", i, slit_x - dim_x);
14251 cpl_table_set(slits, "ytop", i, slit_y);
14252 cpl_table_set(slits, "xbottom", i, slit_x + dim_x);
14253 cpl_table_set(slits, "ybottom", i, slit_y);
14254 }
14255
14256 return slits;
14257 }
14258
14259
14286 cpl_table *mos_load_overscans_vimos(cpl_propertylist *header, int check_consistency)
14287 {
14288 const char *func = "mos_load_overscans_vimos";
14289
14290 int nx = 0;
14291 int ny = 0;
14292 int px = 0;
14293 int py = 0;
14294 int ox = 0;
14295 int oy = 0;
14296 int vx = 0;
14297 int vy = 0;
14298 int nrows;
14299 cpl_table *overscans;
14300
14301
14302 if (cpl_error_get_code() != CPL_ERROR_NONE) {
14303 cpl_msg_error(func, "Reset your error: %s", cpl_error_get_message());
14304 return NULL;
14305 }
14306
14307 if (header == NULL) {
14308 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
14309 return NULL;
14310 }
14311
14312 if (cpl_propertylist_has(header, "NAXIS1"))
14313 nx = cpl_propertylist_get_int(header, "NAXIS1");
14314 if (cpl_propertylist_has(header, "NAXIS2"))
14315 ny = cpl_propertylist_get_int(header, "NAXIS2");
14316 if (cpl_propertylist_has(header, "ESO DET OUT1 PRSCX"))
14317 px = cpl_propertylist_get_int(header, "ESO DET OUT1 PRSCX");
14318 if (cpl_propertylist_has(header, "ESO DET OUT1 PRSCY"))
14319 py = cpl_propertylist_get_int(header, "ESO DET OUT1 PRSCY");
14320 if (cpl_propertylist_has(header, "ESO DET OUT1 OVSCX"))
14321 ox = cpl_propertylist_get_int(header, "ESO DET OUT1 OVSCX");
14322 if (cpl_propertylist_has(header, "ESO DET OUT1 OVSCY"))
14323 oy = cpl_propertylist_get_int(header, "ESO DET OUT1 OVSCY");
14324 if (cpl_propertylist_has(header, "ESO DET OUT1 NX"))
14325 vx = cpl_propertylist_get_int(header, "ESO DET OUT1 NX");
14326 if (cpl_propertylist_has(header, "ESO DET OUT1 NY"))
14327 vy = cpl_propertylist_get_int(header, "ESO DET OUT1 NY");
14328
14329 if (cpl_error_get_code() != CPL_ERROR_NONE) {
14330 cpl_msg_error(func, "Missing overscan keywords in header");
14331 cpl_error_set_where(func);
14332 return NULL;
14333 }
14334
14335 if (px < 0 || py < 0 || ox < 0 || oy < 0) {
14336 cpl_msg_error(func, "Missing overscan keywords in header");
14337 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
14338 return NULL;
14339 }
14340
14341 if ((px + vx + ox != nx) || (py + vy + oy != ny)) {
14342 if (check_consistency) {
14343 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
14344 return NULL;
14345 }
14346 else {
14347 cpl_msg_debug(func, "Overscans description conflicts with "
14348 "reported image sizes, "
14349 "%d + %d + %d != %d or "
14350 "%d + %d + %d != %d",
14351 px, vx, ox, nx,
14352 py, vy, oy, ny);
14353 }
14354 }
14355
14356 nrows = 0;
14357 if (px > 0)
14358 nrows++;
14359 if (ox > 0)
14360 nrows++;
14361 if (py > 0)
14362 nrows++;
14363 if (oy > 0)
14364 nrows++;
14365
14366 if (nrows > 2) {
14367 cpl_msg_error(func, "Unexpected overscan regions "
14368 "(both in X and Y direction)");
14369 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
14370 return NULL;
14371 }
14372
14373
14374
14375
14376
14377
14378
14379 nrows++;
14380
14381 overscans = cpl_table_new(nrows);
14382 cpl_table_new_column(overscans, "xlow", CPL_TYPE_INT);
14383 cpl_table_new_column(overscans, "ylow", CPL_TYPE_INT);
14384 cpl_table_new_column(overscans, "xhig", CPL_TYPE_INT);
14385 cpl_table_new_column(overscans, "yhig", CPL_TYPE_INT);
14386
14387 nrows = 0;
14388
14389 cpl_table_set_int(overscans, "xlow", nrows, px);
14390 cpl_table_set_int(overscans, "ylow", nrows, py);
14391 cpl_table_set_int(overscans, "xhig", nrows, nx - ox);
14392 cpl_table_set_int(overscans, "yhig", nrows, ny - oy);
14393 nrows++;
14394
14395 if (px > 0) {
14396 cpl_table_set_int(overscans, "xlow", nrows, 0);
14397 cpl_table_set_int(overscans, "ylow", nrows, 0);
14398 cpl_table_set_int(overscans, "xhig", nrows, px);
14399 cpl_table_set_int(overscans, "yhig", nrows, ny);
14400 nrows++;
14401 }
14402
14403 if (ox > 0) {
14404 cpl_table_set_int(overscans, "xlow", nrows, nx - ox);
14405 cpl_table_set_int(overscans, "ylow", nrows, 0);
14406 cpl_table_set_int(overscans, "xhig", nrows, nx);
14407 cpl_table_set_int(overscans, "yhig", nrows, ny);
14408 nrows++;
14409 }
14410
14411 if (py > 0) {
14412 cpl_table_set_int(overscans, "xlow", nrows, 0);
14413 cpl_table_set_int(overscans, "ylow", nrows, 0);
14414 cpl_table_set_int(overscans, "xhig", nrows, nx);
14415 cpl_table_set_int(overscans, "yhig", nrows, py);
14416 nrows++;
14417 }
14418
14419 if (oy > 0) {
14420 cpl_table_set_int(overscans, "xlow", nrows, 0);
14421 cpl_table_set_int(overscans, "ylow", nrows, ny - oy);
14422 cpl_table_set_int(overscans, "xhig", nrows, nx);
14423 cpl_table_set_int(overscans, "yhig", nrows, ny);
14424 nrows++;
14425 }
14426
14427 return overscans;
14428
14429 }
14430
14431
14463 #define READY 1
14464 #ifdef READY
14465
14466 cpl_polynomial *mos_montecarlo_polyfit(cpl_table *points, cpl_table *evaluate,
14467 int samples, int order)
14468 {
14469
14470 const char *func = "mos_montecarlo_polyfit";
14471
14472 cpl_polynomial *p;
14473 cpl_polynomial *q;
14474 cpl_vector *listx;
14475 cpl_vector *listy;
14476 double err;
14477 double *x;
14478 double *px;
14479 double *x_eval;
14480 double *px_eval;
14481 double *sigma;
14482 double *vy;
14483 double *dy;
14484 int npoints, nevaluate;
14485 int i, j;
14486
14487
14488 if (points == NULL || evaluate == NULL) {
14489 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
14490 return NULL;
14491 }
14492
14493 if (!cpl_table_has_column(points, "x")) {
14494 cpl_error_set(func, CPL_ERROR_DATA_NOT_FOUND);
14495 return NULL;
14496 }
14497
14498 if (cpl_table_get_column_type(points, "x") != CPL_TYPE_DOUBLE) {
14499 cpl_error_set(func, CPL_ERROR_INVALID_TYPE);
14500 return NULL;
14501 }
14502
14503 if (cpl_table_has_invalid(points, "x")) {
14504 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
14505 return NULL;
14506 }
14507
14508 if (!cpl_table_has_column(points, "y")) {
14509 cpl_error_set(func, CPL_ERROR_DATA_NOT_FOUND);
14510 return NULL;
14511 }
14512
14513 if (cpl_table_get_column_type(points, "y") != CPL_TYPE_DOUBLE) {
14514 cpl_error_set(func, CPL_ERROR_INVALID_TYPE);
14515 return NULL;
14516 }
14517
14518 if (cpl_table_has_invalid(points, "y")) {
14519 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
14520 return NULL;
14521 }
14522
14523 if (cpl_table_has_column(points, "y_err")) {
14524
14525 if (cpl_table_get_column_type(points, "y_err") != CPL_TYPE_DOUBLE) {
14526 cpl_error_set(func, CPL_ERROR_INVALID_TYPE);
14527 return NULL;
14528 }
14529
14530 if (cpl_table_has_invalid(points, "y_err")) {
14531 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
14532 return NULL;
14533 }
14534 }
14535
14536 if (!cpl_table_has_column(evaluate, "x")) {
14537 cpl_error_set(func, CPL_ERROR_DATA_NOT_FOUND);
14538 return NULL;
14539 }
14540
14541 if (cpl_table_get_column_type(evaluate, "x") != CPL_TYPE_DOUBLE) {
14542 cpl_error_set(func, CPL_ERROR_INVALID_TYPE);
14543 return NULL;
14544 }
14545
14546 if (cpl_table_has_invalid(evaluate, "x")) {
14547 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
14548 return NULL;
14549 }
14550
14551 if (samples < 2 || order < 0) {
14552 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
14553 return NULL;
14554 }
14555
14556 npoints = cpl_table_get_nrow(points);
14557 listx = cpl_vector_wrap(npoints, cpl_table_get_data_double(points, "x"));
14558 listy = cpl_vector_wrap(npoints, cpl_table_get_data_double(points, "y"));
14559
14560 p = cpl_polynomial_fit_1d_create(listx, listy, order, &err);
14561
14562 if (!cpl_table_has_column(points, "y_err")) {
14563 err = sqrt(err);
14564 cpl_table_new_column(points, "y_err", CPL_TYPE_DOUBLE);
14565 cpl_table_fill_column_window_double(points, "y_err", 0, npoints, err);
14566 cpl_msg_info(func, "Error column not found - set to %f\n", err);
14567 }
14568
14569
14570
14571
14572
14573 if (cpl_table_has_column(points, "px"))
14574 cpl_table_erase_column(points, "px");
14575 cpl_table_new_column(points, "px", CPL_TYPE_DOUBLE);
14576 cpl_table_fill_column_window_double(points, "px", 0, npoints, 0);
14577 x = cpl_table_get_data_double(points, "x");
14578 px = cpl_table_get_data_double(points, "px");
14579 for (i = 0; i < npoints; i++)
14580 px[i] = cpl_polynomial_eval_1d(p, x[i], NULL);
14581
14582 nevaluate = cpl_table_get_nrow(evaluate);
14583
14584 if (cpl_table_has_column(evaluate, "px"))
14585 cpl_table_erase_column(evaluate, "px");
14586 cpl_table_new_column(evaluate, "px", CPL_TYPE_DOUBLE);
14587 cpl_table_fill_column_window_double(evaluate, "px", 0, nevaluate, 0);
14588 x_eval = cpl_table_get_data_double(evaluate, "x");
14589 px_eval = cpl_table_get_data_double(evaluate, "px");
14590 for (i = 0; i < nevaluate; i++)
14591 px_eval[i] = cpl_polynomial_eval_1d(p, x_eval[i], NULL);
14592
14593
14594
14595
14596
14597 if (cpl_table_has_column(evaluate, "sigma"))
14598 cpl_table_erase_column(evaluate, "sigma");
14599 cpl_table_new_column(evaluate, "sigma", CPL_TYPE_DOUBLE);
14600 cpl_table_fill_column_window_double(evaluate, "sigma", 0, nevaluate, 0);
14601 sigma = cpl_table_get_data_double(evaluate, "sigma");
14602
14603
14604
14605
14606
14607 if (cpl_table_has_column(points, "vy"))
14608 cpl_table_erase_column(points, "vy");
14609 cpl_table_new_column(points, "vy", CPL_TYPE_DOUBLE);
14610 cpl_table_fill_column_window_double(points, "vy", 0, npoints, 0);
14611 vy = cpl_table_get_data_double(points, "vy");
14612 dy = cpl_table_get_data_double(points, "y_err");
14613 cpl_vector_unwrap(listy);
14614 listy = cpl_vector_wrap(npoints, vy);
14615
14616 for (i = 0; i < samples; i++) {
14617 for (j = 0; j < npoints; j++)
14618 vy[j] = px[j] + dy[j] * mos_randg(1);
14619 q = cpl_polynomial_fit_1d_create(listx, listy, order, NULL);
14620 for (j = 0; j < nevaluate; j++)
14621 sigma[j] += fabs(px_eval[j]
14622 - cpl_polynomial_eval_1d(q, x_eval[j], NULL));
14623 cpl_polynomial_delete(q);
14624 }
14625
14626
14627
14628
14629
14630 cpl_table_multiply_scalar(evaluate, "sigma", 1.25);
14631 cpl_table_divide_scalar(evaluate, "sigma", samples);
14632
14633 cpl_vector_unwrap(listx);
14634 cpl_vector_unwrap(listy);
14635
14636 return p;
14637 }
14638
14639 #endif
14640